From 0b63dcb532c5e7025694ac6e436f51e6c1d6f791 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 18 May 2026 11:37:40 +0700 Subject: [PATCH] feat: implement server-side sorting in FinanceTable --- src/components/pages/finance/FinanceTable.tsx | 84 +++++++++++++++---- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/components/pages/finance/FinanceTable.tsx b/src/components/pages/finance/FinanceTable.tsx index 998193e7..211af1f7 100644 --- a/src/components/pages/finance/FinanceTable.tsx +++ b/src/components/pages/finance/FinanceTable.tsx @@ -1,7 +1,12 @@ 'use client'; import React, { useEffect, useMemo, useState } from 'react'; -import { CellContext, ColumnDef } from '@tanstack/react-table'; +import { + CellContext, + ColumnDef, + SortingState, + Updater, +} from '@tanstack/react-table'; import useSWR from 'swr'; import { Icon } from '@iconify/react'; import { useFormik } from 'formik'; @@ -183,7 +188,8 @@ const FinanceTable = () => { bankIds: '', customerIds: '', supplierIds: '', - sortBy: '', + sort_by: '', + orderBy: '', startDate: '', endDate: '', bankNames: '', @@ -197,7 +203,8 @@ const FinanceTable = () => { bankIds: 'bank_ids', customerIds: 'customer_ids', supplierIds: 'supplier_ids', - sortBy: 'sort_date', + sort_by: 'sort_by', + orderBy: 'sort_order', startDate: 'start_date', endDate: 'end_date', }, @@ -248,7 +255,7 @@ const FinanceTable = () => { updateFilter('bankIds', values.bank_ids, true); updateFilter('customerIds', values.customer_ids, true); updateFilter('supplierIds', values.supplier_ids, true); - updateFilter('sortBy', values.sort_by, true); + updateFilter('sort_by', values.sort_by, true); updateFilter('startDate', values.start_date, true); updateFilter('endDate', values.end_date, true); // Save display names for restoration on modal reopen @@ -276,7 +283,8 @@ const FinanceTable = () => { updateFilter('bankIds', '', true); updateFilter('customerIds', '', true); updateFilter('supplierIds', '', true); - updateFilter('sortBy', '', true); + updateFilter('sort_by', '', true); + updateFilter('orderBy', '', true); updateFilter('startDate', '', true); updateFilter('endDate', '', true); updateFilter('bankNames', '', true); @@ -394,6 +402,26 @@ const FinanceTable = () => { ); }; + const sorting: SortingState = tableFilterState.sort_by + ? [ + { + id: tableFilterState.sort_by, + desc: tableFilterState.orderBy === 'desc', + }, + ] + : []; + + const handleSortingChange = (updater: Updater) => { + const next = typeof updater === 'function' ? updater(sorting) : updater; + if (next.length > 0) { + updateFilter('sort_by', next[0].id, true); + updateFilter('orderBy', next[0].desc ? 'desc' : 'asc', true); + } else { + updateFilter('sort_by', '', true); + updateFilter('orderBy', '', true); + } + }; + const startDateChangeHandler = (e: React.ChangeEvent) => { const value = e.target.value; const endDate = filterFormik.values.end_date; @@ -505,7 +533,7 @@ const FinanceTable = () => { // Restore sort by const restoredSortBy = sortByOptions.find( - (opt) => String(opt.value) === tableFilterState.sortBy + (opt) => String(opt.value) === tableFilterState.sort_by ) || null; setSelectedSortBy(restoredSortBy); @@ -516,7 +544,7 @@ const FinanceTable = () => { bank_ids: tableFilterState.bankIds || '', customer_ids: tableFilterState.customerIds || '', supplier_ids: tableFilterState.supplierIds || '', - sort_by: tableFilterState.sortBy || '', + sort_by: tableFilterState.sort_by || '', start_date: tableFilterState.startDate || '', end_date: tableFilterState.endDate || '', }); @@ -540,10 +568,12 @@ const FinanceTable = () => { { header: 'ID', accessorKey: 'payment_code', + enableSorting: true, }, { header: 'References Number', accessorKey: 'reference_number', + enableSorting: true, cell: (props: CellContext) => { const value = props.row.original.reference_number; return {value ?? '-'}; @@ -552,6 +582,7 @@ const FinanceTable = () => { { header: 'Jenis Transaksi', accessorKey: 'transaction_type', + enableSorting: true, cell: (props: CellContext) => { const value = props.row.original.transaction_type .split('_') @@ -561,7 +592,8 @@ const FinanceTable = () => { }, { header: 'Pihak', - accessorFn: (finance: Finance) => finance.party?.name, + accessorKey: 'customer_name', + enableSorting: true, cell: (props: CellContext) => { if (props.row.original.party?.id) { return {props.row.original.party?.name}; @@ -571,16 +603,22 @@ const FinanceTable = () => { }, { header: 'Tanggal Pembayaran', - accessorFn: (finance: Finance) => - formatDate(finance.payment_date, 'DD MMM YYYY'), + accessorKey: 'payment_date', + enableSorting: true, + cell: (props) => + formatDate(props.row.original.payment_date, 'DD MMM YYYY'), }, { header: 'Tanggal Dibuat', - accessorFn: (finance) => formatDate(finance.created_at, 'DD MMM YYYY'), + accessorKey: 'created_at', + enableSorting: true, + cell: (props) => + formatDate(props.row.original.created_at, 'DD MMM YYYY'), }, { header: 'Metode Pembayaran', accessorKey: 'payment_method', + enableSorting: true, cell: (props: CellContext) => { const value = props.row.original.payment_method.split('_').join(' '); return {formatTitleCase(value)}; @@ -588,20 +626,26 @@ const FinanceTable = () => { }, { header: 'Bank', - accessorFn: (finance: Finance) => - finance.bank - ? `${finance.bank?.alias} - ${finance.bank?.account_number} - ${finance.bank?.owner}` + accessorKey: 'bank', + enableSorting: true, + cell: (props) => + props.row.original.bank + ? `${props.row.original.bank?.alias} - ${props.row.original.bank?.account_number} - ${props.row.original.bank?.owner}` : '-', }, { header: 'Pengeluaran (Rp)', - accessorFn: (finance: Finance) => - formatCurrency(Math.abs(finance.expense_amount)), + accessorKey: 'expense_amount', + enableSorting: true, + cell: (props) => + formatCurrency(Math.abs(props.row.original.expense_amount)), }, { header: 'Pemasukan (Rp)', - accessorFn: (finance: Finance) => - formatCurrency(Math.abs(finance.income_amount)), + accessorKey: 'income_amount', + enableSorting: true, + cell: (props) => + formatCurrency(Math.abs(props.row.original.income_amount)), }, { header: 'Aksi', @@ -707,6 +751,7 @@ const FinanceTable = () => { 'page', 'pageSize', 'search', + 'orderBy', 'bankNames', 'customerNames', 'supplierNames', @@ -749,6 +794,9 @@ const FinanceTable = () => { onPageChange={setPage} onPageSizeChange={setPageSize} isLoading={isLoading} + sorting={sorting} + setSorting={handleSortingChange} + manualSorting className={{ containerClassName: cn('p-3 mb-0'), headerColumnClassName: 'text-nowrap',