From 8569730ad51437a73451295c1ac6e67e5072c9ba Mon Sep 17 00:00:00 2001 From: Yi-Jyun Pan Date: Fri, 19 Sep 2025 11:27:18 +0800 Subject: [PATCH 1/2] refactor: simplify pagination design Always use the forward direction, and record cursors in the admin page. --- .../events/_components/data-table.tsx | 28 +++++++++---------- .../points/_components/data-table.tsx | 28 +++++++++---------- .../submissions/_components/data-table.tsx | 28 +++++++++---------- .../questions/_components/data-table.tsx | 28 +++++++++---------- .../users/_components/data-table.tsx | 28 +++++++++---------- 5 files changed, 70 insertions(+), 70 deletions(-) diff --git a/app/(admin)/(activity-management)/events/_components/data-table.tsx b/app/(admin)/(activity-management)/events/_components/data-table.tsx index 4bdfece..3ab21a7 100644 --- a/app/(admin)/(activity-management)/events/_components/data-table.tsx +++ b/app/(admin)/(activity-management)/events/_components/data-table.tsx @@ -9,13 +9,11 @@ import { EVENTS_TABLE_QUERY } from "./query"; export function EventsDataTable() { const PAGE_SIZE = 10; - const [after, setAfter] = useState(null); - const [before, setBefore] = useState(null); - const [direction, setDirection] = useState("backward"); + const [cursors, setCursors] = useState<(string | null)[]>([null]); + const [currentIndex, setCurrentIndex] = useState(0); - const variables = direction === "backward" - ? { first: PAGE_SIZE, after, last: undefined, before: undefined } - : { last: PAGE_SIZE, before, first: undefined, after: undefined }; + const after = cursors[currentIndex]; + const variables = { first: PAGE_SIZE, after }; const { data } = useSuspenseQuery(EVENTS_TABLE_QUERY, { variables, @@ -42,13 +40,15 @@ export function EventsDataTable() { const handlePageChange = (direction: Direction) => { if (!pageInfo) return; if (direction === "forward" && pageInfo.hasNextPage) { - setAfter(pageInfo.endCursor ?? null); - setBefore(null); - setDirection("forward"); - } else if (direction === "backward" && pageInfo.hasPreviousPage) { - setBefore(pageInfo.startCursor ?? null); - setAfter(null); - setDirection("backward"); + const nextCursor = pageInfo.endCursor ?? null; + setCursors(prev => { + const newCursors = prev.slice(0, currentIndex + 1); + newCursors.push(nextCursor); + return newCursors; + }); + setCurrentIndex(currentIndex + 1); + } else if (direction === "backward" && currentIndex > 0) { + setCurrentIndex(currentIndex - 1); } }; @@ -58,7 +58,7 @@ export function EventsDataTable() { data={eventList} totalCount={data?.events.totalCount ?? 0} hasNextPage={!!pageInfo?.hasNextPage} - hasPreviousPage={!!pageInfo?.hasPreviousPage} + hasPreviousPage={currentIndex > 0} onPageChange={handlePageChange} /> ); diff --git a/app/(admin)/(activity-management)/points/_components/data-table.tsx b/app/(admin)/(activity-management)/points/_components/data-table.tsx index 5df8679..36ff67a 100644 --- a/app/(admin)/(activity-management)/points/_components/data-table.tsx +++ b/app/(admin)/(activity-management)/points/_components/data-table.tsx @@ -9,13 +9,11 @@ import { POINTS_TABLE_QUERY } from "./query"; export function PointsDataTable() { const PAGE_SIZE = 10; - const [after, setAfter] = useState(null); - const [before, setBefore] = useState(null); - const [direction, setDirection] = useState("backward"); + const [cursors, setCursors] = useState<(string | null)[]>([null]); + const [currentIndex, setCurrentIndex] = useState(0); - const variables = direction === "backward" - ? { first: PAGE_SIZE, after, last: undefined, before: undefined } - : { last: PAGE_SIZE, before, first: undefined, after: undefined }; + const after = cursors[currentIndex]; + const variables = { first: PAGE_SIZE, after }; const { data } = useSuspenseQuery(POINTS_TABLE_QUERY, { variables, @@ -43,13 +41,15 @@ export function PointsDataTable() { const handlePageChange = (direction: Direction) => { if (!pageInfo) return; if (direction === "forward" && pageInfo.hasNextPage) { - setAfter(pageInfo.endCursor ?? null); - setBefore(null); - setDirection("forward"); - } else if (direction === "backward" && pageInfo.hasPreviousPage) { - setBefore(pageInfo.startCursor ?? null); - setAfter(null); - setDirection("backward"); + const nextCursor = pageInfo.endCursor ?? null; + setCursors(prev => { + const newCursors = prev.slice(0, currentIndex + 1); + newCursors.push(nextCursor); + return newCursors; + }); + setCurrentIndex(currentIndex + 1); + } else if (direction === "backward" && currentIndex > 0) { + setCurrentIndex(currentIndex - 1); } }; @@ -59,7 +59,7 @@ export function PointsDataTable() { data={pointsList} totalCount={data?.points.totalCount ?? 0} hasNextPage={!!pageInfo?.hasNextPage} - hasPreviousPage={!!pageInfo?.hasPreviousPage} + hasPreviousPage={currentIndex > 0} onPageChange={handlePageChange} /> ); diff --git a/app/(admin)/(activity-management)/submissions/_components/data-table.tsx b/app/(admin)/(activity-management)/submissions/_components/data-table.tsx index 76b7b44..2a76235 100644 --- a/app/(admin)/(activity-management)/submissions/_components/data-table.tsx +++ b/app/(admin)/(activity-management)/submissions/_components/data-table.tsx @@ -9,13 +9,11 @@ import { SUBMISSIONS_TABLE_QUERY } from "./query"; export function SubmissionsDataTable() { const PAGE_SIZE = 10; - const [after, setAfter] = useState(null); - const [before, setBefore] = useState(null); - const [direction, setDirection] = useState("backward"); + const [cursors, setCursors] = useState<(string | null)[]>([null]); + const [currentIndex, setCurrentIndex] = useState(0); - const variables = direction === "backward" - ? { first: PAGE_SIZE, after, last: undefined, before: undefined } - : { last: PAGE_SIZE, before, first: undefined, after: undefined }; + const after = cursors[currentIndex]; + const variables = { first: PAGE_SIZE, after }; const { data } = useSuspenseQuery(SUBMISSIONS_TABLE_QUERY, { variables, @@ -46,13 +44,15 @@ export function SubmissionsDataTable() { const handlePageChange = (direction: Direction) => { if (!pageInfo) return; if (direction === "forward" && pageInfo.hasNextPage) { - setAfter(pageInfo.endCursor ?? null); - setBefore(null); - setDirection("forward"); - } else if (direction === "backward" && pageInfo.hasPreviousPage) { - setBefore(pageInfo.startCursor ?? null); - setAfter(null); - setDirection("backward"); + const nextCursor = pageInfo.endCursor ?? null; + setCursors(prev => { + const newCursors = prev.slice(0, currentIndex + 1); + newCursors.push(nextCursor); + return newCursors; + }); + setCurrentIndex(currentIndex + 1); + } else if (direction === "backward" && currentIndex > 0) { + setCurrentIndex(currentIndex - 1); } }; @@ -62,7 +62,7 @@ export function SubmissionsDataTable() { data={submissionList} totalCount={data?.submissions.totalCount ?? 0} hasNextPage={!!pageInfo?.hasNextPage} - hasPreviousPage={!!pageInfo?.hasPreviousPage} + hasPreviousPage={currentIndex > 0} onPageChange={handlePageChange} /> ); diff --git a/app/(admin)/(question-management)/questions/_components/data-table.tsx b/app/(admin)/(question-management)/questions/_components/data-table.tsx index cb57659..8f551f3 100644 --- a/app/(admin)/(question-management)/questions/_components/data-table.tsx +++ b/app/(admin)/(question-management)/questions/_components/data-table.tsx @@ -9,13 +9,11 @@ import { QUESTIONS_TABLE_QUERY } from "./query"; export function QuestionsDataTable() { const PAGE_SIZE = 5; - const [after, setAfter] = useState(null); - const [before, setBefore] = useState(null); - const [direction, setDirection] = useState("backward"); + const [cursors, setCursors] = useState<(string | null)[]>([null]); + const [currentIndex, setCurrentIndex] = useState(0); - const variables = direction === "backward" - ? { first: PAGE_SIZE, after, last: undefined, before: undefined } - : { last: PAGE_SIZE, before, first: undefined, after: undefined }; + const after = cursors[currentIndex]; + const variables = { first: PAGE_SIZE, after }; const { data } = useSuspenseQuery(QUESTIONS_TABLE_QUERY, { variables, @@ -42,13 +40,15 @@ export function QuestionsDataTable() { const handlePageChange = (direction: Direction) => { if (!pageInfo) return; if (direction === "forward" && pageInfo.hasNextPage) { - setAfter(pageInfo.endCursor ?? null); - setBefore(null); - setDirection("forward"); - } else if (direction === "backward" && pageInfo.hasPreviousPage) { - setBefore(pageInfo.startCursor ?? null); - setAfter(null); - setDirection("backward"); + const nextCursor = pageInfo.endCursor ?? null; + setCursors(prev => { + const newCursors = prev.slice(0, currentIndex + 1); + newCursors.push(nextCursor); + return newCursors; + }); + setCurrentIndex(currentIndex + 1); + } else if (direction === "backward" && currentIndex > 0) { + setCurrentIndex(currentIndex - 1); } }; @@ -58,7 +58,7 @@ export function QuestionsDataTable() { data={questionList} totalCount={data?.questions.totalCount ?? 0} hasNextPage={!!pageInfo?.hasNextPage} - hasPreviousPage={!!pageInfo?.hasPreviousPage} + hasPreviousPage={currentIndex > 0} onPageChange={handlePageChange} /> ); diff --git a/app/(admin)/(user-management)/users/_components/data-table.tsx b/app/(admin)/(user-management)/users/_components/data-table.tsx index 7f3baec..0127159 100644 --- a/app/(admin)/(user-management)/users/_components/data-table.tsx +++ b/app/(admin)/(user-management)/users/_components/data-table.tsx @@ -9,13 +9,11 @@ import { USERS_TABLE_QUERY } from "./query"; export function UsersDataTable() { const PAGE_SIZE = 5; - const [after, setAfter] = useState(null); - const [before, setBefore] = useState(null); - const [direction, setDirection] = useState("backward"); + const [cursors, setCursors] = useState<(string | null)[]>([null]); + const [currentIndex, setCurrentIndex] = useState(0); - const variables = direction === "backward" - ? { first: PAGE_SIZE, after, last: undefined, before: undefined } - : { last: PAGE_SIZE, before, first: undefined, after: undefined }; + const after = cursors[currentIndex]; + const variables = { first: PAGE_SIZE, after }; const { data } = useSuspenseQuery(USERS_TABLE_QUERY, { variables, @@ -45,13 +43,15 @@ export function UsersDataTable() { const handlePageChange = (direction: Direction) => { if (!pageInfo) return; if (direction === "forward" && pageInfo.hasNextPage) { - setAfter(pageInfo.endCursor ?? null); - setBefore(null); - setDirection("forward"); - } else if (direction === "backward" && pageInfo.hasPreviousPage) { - setBefore(pageInfo.startCursor ?? null); - setAfter(null); - setDirection("backward"); + const nextCursor = pageInfo.endCursor ?? null; + setCursors(prev => { + const newCursors = prev.slice(0, currentIndex + 1); + newCursors.push(nextCursor); + return newCursors; + }); + setCurrentIndex(currentIndex + 1); + } else if (direction === "backward" && currentIndex > 0) { + setCurrentIndex(currentIndex - 1); } }; @@ -61,7 +61,7 @@ export function UsersDataTable() { data={userList} totalCount={data?.users.totalCount ?? 0} hasNextPage={!!pageInfo?.hasNextPage} - hasPreviousPage={!!pageInfo?.hasPreviousPage} + hasPreviousPage={currentIndex > 0} onPageChange={handlePageChange} /> ); From 719cd912a0c26792a3eb5e3b13a0d21bd7d73038 Mon Sep 17 00:00:00 2001 From: Yi-Jyun Pan Date: Fri, 19 Sep 2025 11:49:49 +0800 Subject: [PATCH 2/2] fix: table not getting re-rendered https://github.com/TanStack/table/issues/5567 --- components/data-table/cursor.tsx | 2 ++ components/data-table/table.tsx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/components/data-table/cursor.tsx b/components/data-table/cursor.tsx index cc5b9cb..3f01b37 100644 --- a/components/data-table/cursor.tsx +++ b/components/data-table/cursor.tsx @@ -20,6 +20,8 @@ export function CursorDataTable({ hasPreviousPage, onPageChange, }: CursorDataTableProps) { + "use no memo"; + const table = useReactTable({ data, columns, diff --git a/components/data-table/table.tsx b/components/data-table/table.tsx index 00c0340..fe7ddd4 100644 --- a/components/data-table/table.tsx +++ b/components/data-table/table.tsx @@ -8,6 +8,8 @@ export interface DataTableProps { } export function DataTableMain({ table, columns }: DataTableProps) { + "use no memo"; + return (