mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-137): integrate SWR for fetching recordings and update table to display API data
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
import useSWR from 'swr';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
import { SortingState } from '@tanstack/react-table';
|
import { SortingState } from '@tanstack/react-table';
|
||||||
import { cn } from '@/lib/helper';
|
import { cn } from '@/lib/helper';
|
||||||
@@ -18,52 +19,21 @@ import RowCollapseOptions from '@/components/table/RowCollapseOptions';
|
|||||||
import { type CellContext } from '@tanstack/react-table';
|
import { type CellContext } from '@tanstack/react-table';
|
||||||
import { type Recording } from '@/types/api/production/recording';
|
import { type Recording } from '@/types/api/production/recording';
|
||||||
import { type ProjectFlock } from '@/types/api/production/project-flock';
|
import { type ProjectFlock } from '@/types/api/production/project-flock';
|
||||||
|
import { RecordingApi } from '@/services/api/production';
|
||||||
|
import { type BaseApiResponse } from '@/types/api/api-general';
|
||||||
|
|
||||||
// Extended type that includes related data
|
// Extended type that includes related data
|
||||||
type RecordingWithRelations = Recording & {
|
type RecordingWithRelations = Recording & {
|
||||||
project_flock?: ProjectFlock;
|
project_flock?: ProjectFlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
const dummyRecordings: RecordingWithRelations[] = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
project_flock_kandang_id: 1,
|
|
||||||
record_date: '2024-01-01',
|
|
||||||
ontime: true,
|
|
||||||
day: 10,
|
|
||||||
status: 1,
|
|
||||||
total_depletion: 10,
|
|
||||||
cum_depletion_rate: 1.0,
|
|
||||||
daily_gain: 50,
|
|
||||||
avg_daily_gain: 5.0,
|
|
||||||
cum_intake: 200,
|
|
||||||
fcr_value: 1.5,
|
|
||||||
total_chick: 1000,
|
|
||||||
daily_depletion_rate: 0.5,
|
|
||||||
cum_depletion: 20,
|
|
||||||
record_datetime: '2024-01-01T08:00:00Z',
|
|
||||||
created_at: '2024-01-01',
|
|
||||||
updated_at: '2024-01-01',
|
|
||||||
created_user: {
|
|
||||||
id: 1,
|
|
||||||
id_user: 1,
|
|
||||||
email: 'admin@example.com',
|
|
||||||
name: 'Admin',
|
|
||||||
image: null,
|
|
||||||
npk: '0001',
|
|
||||||
created_at: '2024-01-01',
|
|
||||||
updated_at: '2024-01-01',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const RowOptionsMenu = ({
|
const RowOptionsMenu = ({
|
||||||
type = 'dropdown',
|
type = 'dropdown',
|
||||||
props,
|
props,
|
||||||
deleteClickHandler,
|
deleteClickHandler,
|
||||||
}: {
|
}: {
|
||||||
type: 'dropdown' | 'collapse';
|
type: 'dropdown' | 'collapse';
|
||||||
props: CellContext<RecordingWithRelations, unknown>;
|
props: CellContext<Recording, unknown>;
|
||||||
deleteClickHandler: () => void;
|
deleteClickHandler: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
@@ -119,7 +89,7 @@ const RecordingTable = () => {
|
|||||||
const [pageSize, setPageSize] = useState(10);
|
const [pageSize, setPageSize] = useState(10);
|
||||||
const [sorting, setSorting] = useState<SortingState>([]);
|
const [sorting, setSorting] = useState<SortingState>([]);
|
||||||
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
|
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
|
||||||
const [, setSelectedRecording] = useState<RecordingWithRelations | undefined>(undefined);
|
const [, setSelectedRecording] = useState<Recording | undefined>(undefined);
|
||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
const [isBulkApproveLoading, setIsBulkApproveLoading] = useState(false);
|
const [isBulkApproveLoading, setIsBulkApproveLoading] = useState(false);
|
||||||
const [isBulkRejectLoading, setIsBulkRejectLoading] = useState(false);
|
const [isBulkRejectLoading, setIsBulkRejectLoading] = useState(false);
|
||||||
@@ -128,6 +98,16 @@ const RecordingTable = () => {
|
|||||||
const bulkApproveModal = useModal();
|
const bulkApproveModal = useModal();
|
||||||
const bulkRejectModal = useModal();
|
const bulkRejectModal = useModal();
|
||||||
|
|
||||||
|
// Fetch recordings using SWR
|
||||||
|
const {
|
||||||
|
data: recordings,
|
||||||
|
isLoading,
|
||||||
|
mutate: refreshRecordings,
|
||||||
|
} = useSWR(
|
||||||
|
`${RecordingApi.basePath}?page=${page}&limit=${pageSize}`,
|
||||||
|
RecordingApi.getAllFetcher
|
||||||
|
);
|
||||||
|
|
||||||
const searchChangeHandler = useCallback(
|
const searchChangeHandler = useCallback(
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setSearch(e.target.value);
|
setSearch(e.target.value);
|
||||||
@@ -146,20 +126,18 @@ const RecordingTable = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const paginatedData = useMemo(() => {
|
const paginatedData = useMemo(() => {
|
||||||
const filteredData = dummyRecordings.filter(
|
if (!recordings || recordings.status !== 'success') return [];
|
||||||
(recording: RecordingWithRelations) => {
|
|
||||||
const projectName = recording.project_flock?.name || '';
|
|
||||||
const locationName = recording.project_flock?.location?.name || '';
|
|
||||||
const coopName = recording.project_flock?.kandangs?.[0]?.name || '';
|
|
||||||
|
|
||||||
return projectName.toLowerCase().includes(search.toLowerCase()) ||
|
return recordings.data.filter(
|
||||||
locationName.toLowerCase().includes(search.toLowerCase()) ||
|
(recording: Recording) => {
|
||||||
coopName.toLowerCase().includes(search.toLowerCase());
|
// For now, we don't have project_flock relation data in the API response
|
||||||
|
// So we'll filter by basic recording data
|
||||||
|
return recording.project_flock_kandang_id.toString().includes(search.toLowerCase()) ||
|
||||||
|
recording.record_date.includes(search.toLowerCase()) ||
|
||||||
|
recording.created_user.name.toLowerCase().includes(search.toLowerCase());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const start = (page - 1) * pageSize;
|
}, [recordings, search]);
|
||||||
return filteredData.slice(start, start + pageSize);
|
|
||||||
}, [page, pageSize, search]);
|
|
||||||
|
|
||||||
const selectedRowIds = Object.keys(rowSelection).map((item) => parseInt(item));
|
const selectedRowIds = Object.keys(rowSelection).map((item) => parseInt(item));
|
||||||
|
|
||||||
@@ -308,8 +286,8 @@ const RecordingTable = () => {
|
|||||||
cell: (props) => pageSize * (page - 1) + props.row.index + 1,
|
cell: (props) => pageSize * (page - 1) + props.row.index + 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Flock',
|
header: 'Flock Kandang ID',
|
||||||
cell: (props) => props.row.original.project_flock?.name || '-',
|
cell: (props) => props.row.original.project_flock_kandang_id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'record_date',
|
accessorKey: 'record_date',
|
||||||
@@ -318,24 +296,25 @@ const RecordingTable = () => {
|
|||||||
new Date(props.row.original.record_date).toLocaleDateString(),
|
new Date(props.row.original.record_date).toLocaleDateString(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Lokasi',
|
header: 'Day',
|
||||||
cell: (props) => props.row.original.project_flock?.location?.name || '-',
|
cell: (props) => props.row.original.day,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Kandang',
|
header: 'Status',
|
||||||
cell: (props) => {
|
cell: (props) => props.row.original.status,
|
||||||
const coopName = props.row.original.project_flock?.kandangs?.[0]?.name;
|
|
||||||
return coopName || '-';
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'total_depletion',
|
accessorKey: 'total_depletion',
|
||||||
header: 'Total Depletion',
|
header: 'Total Depletion',
|
||||||
cell: (props) => props.row.original.total_depletion,
|
cell: (props) => props.row.original.total_depletion,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: 'Created By',
|
||||||
|
cell: (props) => props.row.original.created_user.name,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: 'Aksi',
|
header: 'Aksi',
|
||||||
cell: (props: CellContext<RecordingWithRelations, unknown>) => {
|
cell: (props: CellContext<Recording, unknown>) => {
|
||||||
const currentPageSize =
|
const currentPageSize =
|
||||||
props.table.getPaginationRowModel().rows.length;
|
props.table.getPaginationRowModel().rows.length;
|
||||||
const currentPageRows =
|
const currentPageRows =
|
||||||
@@ -377,10 +356,10 @@ const RecordingTable = () => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
pageSize={pageSize}
|
pageSize={pageSize}
|
||||||
page={page}
|
page={recordings?.status === 'success' ? recordings.meta?.page : page}
|
||||||
totalItems={dummyRecordings.length}
|
totalItems={recordings?.status === 'success' ? recordings.meta?.total_results : 0}
|
||||||
onPageChange={setPage}
|
onPageChange={setPage}
|
||||||
isLoading={false}
|
isLoading={isLoading}
|
||||||
sorting={sorting}
|
sorting={sorting}
|
||||||
setSorting={setSorting}
|
setSorting={setSorting}
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
|
|||||||
Reference in New Issue
Block a user