@@ -24,11 +24,13 @@ export default function EventCardGrid({
2424 const [ error , setError ] = useState < string | null > ( null ) ;
2525 const [ busyId , setBusyId ] = useState < Event [ "event_id" ] | null > ( null ) ;
2626
27+ const PAGE_SIZE = 4 ;
28+ const [ page , setPage ] = useState ( 1 ) ;
29+
2730 const doFetch : Fetcher =
2831 fetcher ?? ( typeof fetch !== "undefined" ? fetch : ( async ( ) => new Response ( ) ) as any ) ;
2932
3033 function handleUpdated ( updated : Event ) {
31- // อัปเดต event ที่ถูกแก้ไขใน state ของ items
3234 setItems ( prev => prev . map ( it => it . event_id === updated . event_id ? updated : it ) ) ;
3335 }
3436
@@ -53,24 +55,31 @@ export default function EventCardGrid({
5355 if ( alive ) setLoading ( false ) ;
5456 }
5557 } ) ( ) ;
56- return ( ) => {
57- alive = false ;
58- } ;
58+ return ( ) => { alive = false ; } ;
5959 } , [ endpoint , doFetch ] ) ;
6060
61- /** รวมค่าปัจจุบัน + ที่จะเปลี่ยน แล้วยิง PUT */
61+ /** --- Pagination --- */
62+ const total = items . length ;
63+ const totalPages = Math . max ( 1 , Math . ceil ( total / PAGE_SIZE ) ) ;
64+ const start = ( page - 1 ) * PAGE_SIZE ;
65+ const end = Math . min ( start + PAGE_SIZE , total ) ;
66+ const pageItems = items . slice ( start , end ) ;
67+
68+ useEffect ( ( ) => {
69+ if ( page > totalPages ) setPage ( totalPages ) ;
70+ } , [ totalPages ] ) ;
71+
72+ /** --- PUT / Toggle functions --- */
6273 async function putMerged ( id : number , patch : Partial < Pick < Event , "sensitivity" | "priority" | "status" > > ) {
63- // หา current
6474 const cur = items . find ( x => x . event_id === id ) ;
6575 if ( ! cur ) return ;
6676
6777 const merged : Pick < Event , "sensitivity" | "priority" | "status" > = {
68- sensitivity : ( patch . sensitivity ?? cur . sensitivity ) as any ,
69- priority : ( patch . priority ?? cur . priority ) as any ,
70- status : ( patch . status ?? cur . status ) as boolean ,
78+ sensitivity : patch . sensitivity ?? cur . sensitivity ,
79+ priority : patch . priority ?? cur . priority ,
80+ status : patch . status ?? cur . status ,
7181 } ;
7282
73- // optimistic
7483 setItems ( prev => prev . map ( it => it . event_id === id ? { ...it , ...merged } : it ) ) ;
7584
7685 try {
@@ -79,39 +88,24 @@ export default function EventCardGrid({
7988 method : "PUT" ,
8089 credentials : "include" ,
8190 cache : "no-store" ,
82- headers : {
83- "Content-Type" : "application/json" ,
84- Accept : "application/json" ,
85- } ,
86- body : JSON . stringify ( {
87- sensitivity : merged . sensitivity ,
88- priority : merged . priority ,
89- status : merged . status ,
90- } ) ,
91+ headers : { "Content-Type" : "application/json" , Accept : "application/json" } ,
92+ body : JSON . stringify ( merged ) ,
9193 } ) ;
9294 if ( ! res . ok ) throw new Error ( `HTTP ${ res . status } ` ) ;
9395 } catch ( err ) {
94- // rollback ง่ายๆด้วยการดึงของเดิมจาก cur
9596 setItems ( prev => prev . map ( it => it . event_id === id ? cur : it ) ) ;
9697 console . error ( err ) ;
9798 } finally {
9899 setBusyId ( null ) ;
99100 }
100101 }
101102
102- // Toggle → เรียก PUT พร้อมรวมค่าปัจจุบันของ sensitivity/priority
103103 async function toggleEnabled ( id : Event [ "event_id" ] , next : boolean ) {
104104 await putMerged ( id , { status : next } ) ;
105105 }
106106
107- // จาก dropdown → onEdit ส่ง item ทั้งตัวมา เราใช้เฉพาะ field ที่เกี่ยวแล้ว PUT
108107 async function updateItem ( next : Event ) {
109- const patch : Partial < Pick < Event , "sensitivity" | "priority" | "status" > > = { } ;
110- // เราถือว่า next คือค่าที่ “ถูกแก้แล้ว” จากการ์ด
111- patch . sensitivity = next . sensitivity ;
112- patch . priority = next . priority ;
113- patch . status = next . status ;
114- await putMerged ( next . event_id , patch ) ;
108+ await putMerged ( next . event_id , { sensitivity : next . sensitivity , priority : next . priority , status : next . status } ) ;
115109 }
116110
117111 const gridCols = useMemo (
@@ -138,22 +132,53 @@ export default function EventCardGrid({
138132 }
139133
140134 return (
141- < div className = { `${ gridCols } ${ className ?? "" } ` } >
142- { items . map ( ( it ) => (
143- < EventCard
144- key = { it . event_id }
145- item = { it }
146- onToggle = { toggleEnabled }
147- onEdit = { ( v ) => ( onEdit ? onEdit ( v ) : updateItem ( v ) ) }
148- onUpdated = { handleUpdated }
149- onDelete = { ( deletedItem : Event ) => {
150- setItems ( prev => prev . filter ( x => x . event_id !== deletedItem . event_id ) ) ;
151- onDelete ?.( deletedItem ) ;
152- } }
153- disabled = { busyId === it . event_id }
154- />
155- ) ) }
156- </ div >
135+ < >
136+ < div className = { `${ gridCols } ${ className ?? "" } ` } >
137+ { pageItems . map ( it => (
138+ < EventCard
139+ key = { it . event_id }
140+ item = { it }
141+ onToggle = { toggleEnabled }
142+ onEdit = { ( v ) => ( onEdit ? onEdit ( v ) : updateItem ( v ) ) }
143+ onUpdated = { handleUpdated }
144+ onDelete = { ( deletedItem : Event ) => {
145+ setItems ( prev => prev . filter ( x => x . event_id !== deletedItem . event_id ) ) ;
146+ onDelete ?.( deletedItem ) ;
147+ } }
148+ disabled = { busyId === it . event_id }
149+ />
150+ ) ) }
151+ </ div >
157152
153+ { /* --- Pagination bar --- */ }
154+ < div className = "mt-4 flex items-center justify-between" >
155+ < div className = "text-xs text-gray-500" >
156+ Showing < span className = "font-medium" > { total ? start + 1 : 0 } </ span > –
157+ < span className = "font-medium" > { end } </ span > of < span className = "font-medium" > { total } </ span >
158+ </ div >
159+
160+ < div className = "flex items-center gap-2" >
161+ < button
162+ onClick = { ( ) => setPage ( p => Math . max ( 1 , p - 1 ) ) }
163+ disabled = { page <= 1 }
164+ className = { `px-3 py-1 rounded-md border text-sm ${ page <= 1 ? "text-gray-400 border-gray-200" : "text-gray-700 border-gray-300 hover:bg-gray-50" } ` }
165+ >
166+ Previous
167+ </ button >
168+
169+ < div className = "text-sm tabular-nums" >
170+ { page } / { totalPages }
171+ </ div >
172+
173+ < button
174+ onClick = { ( ) => setPage ( p => Math . min ( totalPages , p + 1 ) ) }
175+ disabled = { page >= totalPages }
176+ className = { `px-3 py-1 rounded-md border text-sm ${ page >= totalPages ? "text-gray-400 border-gray-200" : "text-gray-700 border-gray-300 hover:bg-gray-50" } ` }
177+ >
178+ Next
179+ </ button >
180+ </ div >
181+ </ div >
182+ </ >
158183 ) ;
159184}
0 commit comments