From cb78ec4990251f915b2d095607c7128a0a17269f Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 23 Dec 2025 21:58:28 +0700 Subject: [PATCH] feat(FE-316,317): Enhance UniformityTable with selection and actions --- .../pages/uniformity/UniformityTable.tsx | 380 +++++++++++++++++- 1 file changed, 370 insertions(+), 10 deletions(-) diff --git a/src/components/pages/uniformity/UniformityTable.tsx b/src/components/pages/uniformity/UniformityTable.tsx index dbf5163f..91816751 100644 --- a/src/components/pages/uniformity/UniformityTable.tsx +++ b/src/components/pages/uniformity/UniformityTable.tsx @@ -1,18 +1,182 @@ 'use client'; +import React, { useCallback, useState, useEffect } from 'react'; +import useSWR from 'swr'; +import { Icon } from '@iconify/react'; +import { SortingState, CellContext } from '@tanstack/react-table'; +import { cn } from '@/lib/helper'; import Button from '@/components/Button'; import UniformityChart from '@/components/pages/uniformity/UniformityChart'; import UniformityStat from '@/components/pages/uniformity/UniformityStat'; -import { Icon } from '@iconify/react'; +import { useTableFilter } from '@/services/hooks/useTableFilter'; +import { UniformityApi } from '@/services/api/uniformity'; +import { type Uniformity } from '@/types/api/uniformity/uniformity'; +import { isResponseSuccess } from '@/lib/api-helper'; +import Table from '@/components/Table'; +import Badge from '@/components/Badge'; +import CheckboxInput from '@/components/input/CheckboxInput'; +import RowDropdownOptions from '@/components/table/RowDropdownOptions'; +import RowCollapseOptions from '@/components/table/RowCollapseOptions'; +import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import { useModal } from '@/components/Modal'; +import ConfirmationModal from '@/components/modal/ConfirmationModal'; +import toast from 'react-hot-toast'; +import Card from '@/components/Card'; + +const RowOptionsMenu = ({ + type = 'dropdown', + props, + deleteClickHandler, +}: { + type: 'dropdown' | 'collapse'; + props: CellContext; + deleteClickHandler: () => void; +}) => { + return ( + + + + + + ); +}; const UniformityTable = ({ refresh }: { refresh?: () => void }) => { + const { + state: tableFilterState, + setPage, + toQueryString: getTableFilterQueryString, + } = useTableFilter({ + initial: { + search: '', + }, + paramMap: { + page: 'page', + pageSize: 'limit', + search: 'search', + }, + }); + + const [sorting, setSorting] = useState([]); + const [rowSelection, setRowSelection] = useState>({}); + const [selectedUniformity, setSelectedUniformity] = useState< + Uniformity | undefined + >(undefined); + const [isDeleteLoading, setIsDeleteLoading] = useState(false); + + const singleDeleteModal = useModal(); + + const { + data: uniformities, + isLoading, + mutate: refreshUniformities, + } = useSWR( + `${UniformityApi.basePath}${getTableFilterQueryString()}`, + UniformityApi.getAllFetcher + ); + + const isUniformityLocked = useCallback((uniformity: Uniformity): boolean => { + return uniformity.status === 'APPROVED' || uniformity.status === 'REJECTED'; + }, []); + + const singleDeleteHandler = async () => { + setIsDeleteLoading(true); + + await UniformityApi.delete(selectedUniformity?.id as number); + refreshUniformities(); + + singleDeleteModal.closeModal(); + toast.success('Successfully delete Uniformity!'); + setIsDeleteLoading(false); + }; + + useEffect(() => { + if (isResponseSuccess(uniformities) && uniformities.data) { + const newSelection: Record = {}; + + Object.entries(rowSelection).forEach(([rowId, isSelected]) => { + if (isSelected) { + const uniformity = uniformities.data.find( + (r) => r.id === parseInt(rowId) + ); + if (uniformity && !isUniformityLocked(uniformity)) { + newSelection[rowId] = true; + } + } + }); + + if ( + Object.keys(newSelection).length !== Object.keys(rowSelection).length + ) { + setRowSelection(newSelection); + } + } + }, [uniformities, rowSelection, isUniformityLocked, setRowSelection]); + + const getStatusColor = (status: string) => { + switch (status) { + case 'APPROVED': + return 'success'; + case 'REJECTED': + return 'error'; + case 'CREATED': + return 'info'; + default: + return 'info'; + } + }; + + const getStatusText = (status: string) => { + switch (status) { + case 'APPROVED': + return 'Disetujui'; + case 'REJECTED': + return 'Ditolak'; + case 'CREATED': + return 'Pengajuan'; + default: + return status; + } + }; + return ( <>
- +
+ +