'use client'; import { ChangeEventHandler, useEffect, useState } from 'react'; import useSWR from 'swr'; import { CellContext, ColumnDef, Row, SortingState, } from '@tanstack/react-table'; import toast from 'react-hot-toast'; import { Icon } from '@iconify/react'; import Table from '@/components/Table'; import Button from '@/components/Button'; import { useModal } from '@/components/Modal'; import CheckboxInput from '@/components/input/CheckboxInput'; import RequirePermission from '@/components/helper/RequirePermission'; import PopoverButton from '@/components/popover/PopoverButton'; import PopoverContent from '@/components/popover/PopoverContent'; import Dropdown from '@/components/Dropdown'; import StatusBadge from '@/components/helper/StatusBadge'; import TransferToLayingFilterModal from '@/components/pages/production/transfer-to-laying/TransferToLayingFilterModal'; import TransferToLayingConfirmationModal from '@/components/pages/production/transfer-to-laying/TransferToLayingConfirmationModal'; import { TransferToLaying, TransferToLayingFilter, } from '@/types/api/production/transfer-to-laying'; import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying'; import { cn, formatDate, formatNumber } from '@/lib/helper'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { Color } from '@/types/theme'; import DebouncedTextInput from '@/components/input/DebouncedTextInput'; import ButtonFilter from '@/components/helper/ButtonFilter'; const RowOptionsMenu = ({ props, popoverPosition = 'bottom', deleteClickHandler, }: { props: CellContext; popoverPosition: 'bottom' | 'top'; deleteClickHandler: () => void; }) => { const showEditButton = props.row.original.approval.action !== 'APPROVED' && props.row.original.approval.action !== 'REJECTED'; const showDeleteButton = showEditButton; const popoverId = `transferToLaying#${props.row.original.id}`; const popoverAnchorName = `--anchor-transferToLaying#${props.row.original.id}`; return (
{showEditButton && ( )} {showDeleteButton && (
)}
); }; const TransferToLayingsTable = () => { const { state: tableFilterState, updateFilter, setPage, setPageSize, toQueryString: getTableFilterQueryString, } = useTableFilter({ initial: { search: '', startDate: '', endDate: '', flockSource: '', flockDestination: '', status: '', filter_by: '', sort_by: '', }, paramMap: { page: 'page', pageSize: 'limit', startDate: 'start_date', endDate: 'end_date', flockSource: 'flock_source', flockDestination: 'flock_destination', status: 'status', filter_by: 'filter_by', sort_by: 'sort_by', }, }); const { data: transferToLayings, isLoading, mutate: refreshTransferToLayings, } = useSWR( `${TransferToLayingApi.basePath}${getTableFilterQueryString()}`, TransferToLayingApi.getAllFetcher ); const [isLoadingExportingToExcel, setIsLoadingExportingToExcel] = useState(false); // Modal hooks const filterModal = useModal(); const deleteModal = useModal(); const approveModal = useModal(); const rejectModal = useModal(); const [selectedTransferToLaying, setSelectedTransferToLaying] = useState< TransferToLaying | undefined >(undefined); // Modal loading state const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isApproveLoading, setIsApproveLoading] = useState(false); const [isRejectLoading, setIsRejectLoading] = useState(false); const [sorting, setSorting] = useState([]); const [rowSelection, setRowSelection] = useState>({}); const selectedRowIds = Object.keys(rowSelection).map((item) => parseInt(item) ); const transferToLayingsColumns: ColumnDef[] = [ { id: 'select', header: ({ table }) => (
), cell: ({ row }) => { const isCheckboxDisabled = !row.getCanSelect() || row.original.approval.action === 'APPROVED' || row.original.approval.action === 'REJECTED'; return (
); }, }, { accessorKey: 'transfer_date', header: 'Tanggal Transfer', cell: (props) => formatDate(props.getValue() as string, 'DD MMM YYYY'), }, { accessorKey: 'transfer_number', header: 'No. Transfer', }, { accessorKey: 'flock_source', header: 'Flock Asal', cell: (props) => props.row.original.from_project_flock.flock_name, }, { accessorKey: 'flock_destination', header: 'Flock Tujuan', cell: (props) => props.row.original.to_project_flock.flock_name, }, { accessorKey: 'usage_qty', header: 'Kuantitas', cell: (props) => { const totalQuantity = props.row.original.targets.reduce( (total, target) => total + target.qty, 0 ); return formatNumber(totalQuantity, 'en-US'); }, }, { accessorKey: 'notes', header: 'Alasan Transfer', enableSorting: false, cell: (props) => { return ( {props.row.original.notes} ); }, }, { header: 'Status', cell: (props) => { const isLatestApprovalRejected = props.row.original.approval.action === 'REJECTED'; let latestApprovalStepName = props.row.original.approval.step_name; let badgeColor: Color = 'neutral'; switch (latestApprovalStepName.toLowerCase()) { case 'pengajuan': badgeColor = 'neutral'; break; case 'disetujui': badgeColor = 'success'; break; } if (isLatestApprovalRejected) { badgeColor = 'error'; latestApprovalStepName = 'Ditolak'; } return ; }, }, { id: 'actions', cell: (props) => { const currentPageSize = props.table.getPaginationRowModel().rows.length; const currentPageRows = props.table.getPaginationRowModel().flatRows; const currentRowRelativeIndex = currentPageRows.findIndex((r) => r.id === props.row.id) + 1; const isLast2Rows = currentRowRelativeIndex > currentPageSize - 2; const deleteClickHandler = () => { setSelectedTransferToLaying(props.row.original); // Set row selection setRowSelection({ [String(props.row.original.id)]: true, }); deleteModal.openModal(); }; return ( ); }, }, ]; const tableEnableRowSelectionHandler: ( row: Row ) => boolean = (row) => { return ( row.original.approval.action !== 'APPROVED' && row.original.approval.action !== 'REJECTED' ); }; const bulkApproveClickHandler = () => { approveModal.openModal(); }; const bulkRejectClickHandler = () => { rejectModal.openModal(); }; // Modal confirm click handler const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); const deleteResponse = await TransferToLayingApi.delete( selectedTransferToLaying?.id as number ); if (isResponseError(deleteResponse)) { toast.error(deleteResponse.message); setIsDeleteLoading(false); return; } refreshTransferToLayings(); setRowSelection({}); setSelectedTransferToLaying(undefined); deleteModal.closeModal(); toast.success('Berhasil menghapus data transfer ke laying!'); setIsDeleteLoading(false); }; const confirmationModalApproveClickHandler = async (notes: string) => { setIsApproveLoading(true); const bulkApproveResponse = await TransferToLayingApi.bulkApprove( selectedRowIds, notes ); if (isResponseSuccess(bulkApproveResponse)) { refreshTransferToLayings(); approveModal.closeModal(); toast.success( `Berhasil approve ${selectedRowIds.length} data transfer ke laying!` ); setRowSelection({}); } else { approveModal.closeModal(); toast.error( `Gagal approve ${selectedRowIds.length} data transfer ke laying!` ); } setIsApproveLoading(false); }; const confirmationModalRejectClickHandler = async (notes: string) => { setIsRejectLoading(true); const bulkRejectResponse = await TransferToLayingApi.bulkReject( selectedRowIds, notes ); if (isResponseSuccess(bulkRejectResponse)) { refreshTransferToLayings(); rejectModal.closeModal(); toast.success( `Berhasil reject ${selectedRowIds.length} data transfer ke laying!` ); setRowSelection({}); } else { rejectModal.closeModal(); toast.error( `Gagal reject ${selectedRowIds.length} data transfer ke laying!` ); } setIsRejectLoading(false); }; const searchChangeHandler: ChangeEventHandler = (e) => { updateFilter('search', e.target.value); }; const filterSubmitHandler = (values: TransferToLayingFilter) => { updateFilter('startDate', values.startDate); updateFilter('endDate', values.endDate); updateFilter('flockSource', values.flockSource.join(',')); updateFilter('flockDestination', values.flockDestination.join(',')); updateFilter('status', values.status.join(',')); }; const filterResetHandler = () => { updateFilter('startDate', ''); updateFilter('endDate', ''); updateFilter('flockSource', ''); updateFilter('flockDestination', ''); updateFilter('status', ''); }; const exportToExcelHandler = async () => { setIsLoadingExportingToExcel(true); await TransferToLayingApi.exportToExcel(getTableFilterQueryString()); setIsLoadingExportingToExcel(false); }; useEffect(() => { if (sorting.length === 1) { updateFilter('filter_by', sorting[0].id); updateFilter('sort_by', sorting[0].desc ? 'desc' : 'asc'); } else { updateFilter('filter_by', ''); updateFilter('sort_by', ''); } }, [sorting]); return ( <>
{selectedRowIds.length > 0 && ( <>
)}
} className={{ wrapper: 'w-full min-w-24 max-w-3xs', inputWrapper: 'rounded-xl! shadow-button-soft', input: 'placeholder:font-semibold placeholder:text-base-content/50', }} />
Export
} >
data={ isResponseSuccess(transferToLayings) ? transferToLayings?.data : [] } columns={transferToLayingsColumns} pageSize={tableFilterState.pageSize} page={ isResponseSuccess(transferToLayings) ? transferToLayings?.meta?.page : 0 } totalItems={ isResponseSuccess(transferToLayings) ? transferToLayings?.meta?.total_results : 0 } onPageChange={setPage} onPageSizeChange={setPageSize} isLoading={isLoading} sorting={sorting} setSorting={setSorting} rowSelection={rowSelection} setRowSelection={setRowSelection} enableRowSelection={tableEnableRowSelectionHandler} withCheckbox className={{ containerClassName: cn('p-3', { 'w-full mb-20': isResponseSuccess(transferToLayings) && transferToLayings?.data?.length === 0, }), headerColumnClassName: 'text-nowrap', }} />
{ setRowSelection({}); deleteModal.closeModal(); }, }} /> {/* Approve Modal */} { setRowSelection({}); approveModal.closeModal(); }, }} /> {/* Reject Modal */} { setRowSelection({}); rejectModal.closeModal(); }, }} primaryButton={{ text: 'Reject', isLoading: isRejectLoading, color: 'error', onClick: confirmationModalRejectClickHandler, }} /> ); }; export default TransferToLayingsTable;