feat: implement server-side sorting

This commit is contained in:
ValdiANS
2026-05-08 16:25:51 +07:00
parent 3b1e7e3b03
commit 7643645643
@@ -1,6 +1,5 @@
'use client';
import axios from 'axios';
import Button from '@/components/Button';
import CheckboxInput from '@/components/input/CheckboxInput';
import DateInput from '@/components/input/DateInput';
@@ -27,7 +26,13 @@ import {
MarketingFilter,
} from '@/types/api/marketing/marketing';
import { Icon } from '@iconify/react';
import { CellContext, ColumnDef, Row } from '@tanstack/react-table';
import {
CellContext,
ColumnDef,
Row,
SortingState,
Updater,
} from '@tanstack/react-table';
import { useRouter } from 'next/navigation';
import { ChangeEventHandler, useCallback, useMemo, useState } from 'react';
import toast from 'react-hot-toast';
@@ -198,6 +203,8 @@ const MarketingTable = () => {
project_flock_name: '',
project_flock_kandang_id: '',
project_flock_kandang_name: '',
sort_by: '',
order_by: '',
},
paramMap: {
page: 'page',
@@ -207,6 +214,8 @@ const MarketingTable = () => {
customer_id: 'customer_id',
project_flock_id: 'project_flock_id',
project_flock_kandang_id: 'project_flock_kandang_id',
sort_by: 'sort_by',
order_by: 'sort_order',
},
excludeKeysFromUrl: [
'product_names',
@@ -220,6 +229,26 @@ const MarketingTable = () => {
storeName: 'marketing-table',
});
const sorting: SortingState = tableFilterState.sort_by
? [
{
id: tableFilterState.sort_by,
desc: tableFilterState.order_by === 'desc',
},
]
: [];
const handleSortingChange = (updater: Updater<SortingState>) => {
const next = typeof updater === 'function' ? updater(sorting) : updater;
if (next.length > 0) {
updateFilter('sort_by', next[0].id, true);
updateFilter('order_by', next[0].desc ? 'desc' : 'asc', true);
} else {
updateFilter('sort_by', '', true);
updateFilter('order_by', '', true);
}
};
// ===== FETCH DATA =====
const {
data: marketing,
@@ -359,55 +388,50 @@ const MarketingTable = () => {
? 'DELIVERY_ORDER'
: null;
const marketingFilterInitialValues = useMemo(() => {
const productIds = tableFilterState.product_ids
? tableFilterState.product_ids
.split(',')
.map((item) => item.trim())
.filter(Boolean)
: [];
const productIds = tableFilterState.product_ids
? tableFilterState.product_ids
.split(',')
.map((item) => item.trim())
.filter(Boolean)
: [];
const productLabels = tableFilterState.product_names
? tableFilterState.product_names
.split(',')
.map((item) => item.trim())
.filter(Boolean)
: [];
const productLabels = tableFilterState.product_names
? tableFilterState.product_names
.split(',')
.map((item) => item.trim())
.filter(Boolean)
: [];
return {
product_ids: productIds.map((value, idx) => ({
value: Number(value),
label: productLabels[idx] || '-',
})),
status: tableFilterState.status
? {
value: tableFilterState.status,
label: tableFilterState.status_name,
}
: null,
customer: tableFilterState.customer_id
? {
value: Number(tableFilterState.customer_id),
label: tableFilterState.customer_name,
}
: null,
project_flock: tableFilterState.project_flock_id
? {
value: Number(tableFilterState.project_flock_id),
label: tableFilterState.project_flock_name,
}
: null,
project_flock_kandang: tableFilterState.project_flock_kandang_id
? {
value: Number(tableFilterState.project_flock_kandang_id),
label: tableFilterState.project_flock_kandang_name,
}
: null,
};
}, [tableFilterState]);
const marketingFilterInitialValues = {
product_ids: productIds.map((value, idx) => ({
value: Number(value),
label: productLabels[idx] || '-',
})),
status: tableFilterState.status
? {
value: tableFilterState.status,
label: tableFilterState.status_name,
}
: null,
customer: tableFilterState.customer_id
? {
value: Number(tableFilterState.customer_id),
label: tableFilterState.customer_name,
}
: null,
project_flock: tableFilterState.project_flock_id
? {
value: Number(tableFilterState.project_flock_id),
label: tableFilterState.project_flock_name,
}
: null,
project_flock_kandang: tableFilterState.project_flock_kandang_id
? {
value: Number(tableFilterState.project_flock_kandang_id),
label: tableFilterState.project_flock_kandang_name,
}
: null,
};
const approveMarketingHandler = async (notes: string) => {
if (idsToProcess.length === 0) {
@@ -542,27 +566,29 @@ const MarketingTable = () => {
setIsLoadingExportingToExcel(false);
};
const resetExportProgressForm = useCallback(() => {
const resetExportProgressForm = () => {
setExportProgressStartDate('');
setExportProgressEndDate('');
}, []);
};
const exportProgressStartDateChangeHandler: ChangeEventHandler<HTMLInputElement> =
useCallback((e) => {
setExportProgressStartDate(e.target.value);
}, []);
const exportProgressStartDateChangeHandler: ChangeEventHandler<
HTMLInputElement
> = (e) => {
setExportProgressStartDate(e.target.value);
};
const exportProgressEndDateChangeHandler: ChangeEventHandler<HTMLInputElement> =
useCallback((e) => {
setExportProgressEndDate(e.target.value);
}, []);
const exportProgressEndDateChangeHandler: ChangeEventHandler<
HTMLInputElement
> = (e) => {
setExportProgressEndDate(e.target.value);
};
const exportProgressInputToExcelClickHandler = useCallback(() => {
const exportProgressInputToExcelClickHandler = () => {
resetExportProgressForm();
exportProgressInputModal.openModal();
}, [exportProgressInputModal, resetExportProgressForm]);
};
const submitExportProgressInputHandler = useCallback(async () => {
const submitExportProgressInputHandler = async () => {
if (!exportProgressStartDate || !exportProgressEndDate) {
return;
}
@@ -585,12 +611,7 @@ const MarketingTable = () => {
} finally {
setIsExportProgressLoading(false);
}
}, [
exportProgressEndDate,
exportProgressInputModal,
exportProgressStartDate,
resetExportProgressForm,
]);
};
const columns = useMemo<ColumnDef<Marketing>[]>(() => {
return [
@@ -656,7 +677,7 @@ const MarketingTable = () => {
},
},
{
accessorKey: 'so_do_number',
accessorKey: 'so_number',
header: 'No. Order',
cell: (props) => {
return props.row.original.do_number
@@ -672,7 +693,7 @@ const MarketingTable = () => {
},
},
{
accessorKey: 'approval.step_name',
accessorKey: 'status',
header: 'Status',
cell: (props) => {
const approval = props.row.original.latest_approval;
@@ -707,10 +728,12 @@ const MarketingTable = () => {
},
},
{
accessorKey: 'customer.name',
accessorKey: 'customer',
header: 'Customer',
cell: (props) => props.row.original.customer.name,
},
{
accessorKey: 'grand_total',
accessorFn: (row) =>
row.sales_order
?.map((product) => product.total_price)
@@ -727,6 +750,7 @@ const MarketingTable = () => {
{
accessorKey: 'marketing_products.length',
header: 'Product Details',
enableSorting: false,
cell: (props) => {
if (props?.row?.original?.sales_order?.length) {
if (props?.row?.original?.sales_order?.length > 1) {
@@ -949,6 +973,8 @@ const MarketingTable = () => {
columns={columns}
pageSize={tableFilterState.pageSize}
page={isResponseSuccess(marketing) ? marketing?.meta?.page : 1}
sorting={sorting}
setSorting={handleSortingChange}
totalItems={
isResponseSuccess(marketing)
? marketing?.meta?.total_results