'use client'; import { ChangeEventHandler, useCallback, useEffect, useMemo, useState, } from 'react'; import { usePathname } from 'next/navigation'; import useSWR from 'swr'; import { CellContext, ColumnDef, SortingState } from '@tanstack/react-table'; import toast from 'react-hot-toast'; import { useFormik } from 'formik'; import { Icon } from '@iconify/react'; import Table from '@/components/Table'; import DebouncedTextInput from '@/components/input/DebouncedTextInput'; import Button from '@/components/Button'; import Modal, { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import RequirePermission from '@/components/helper/RequirePermission'; import PopoverButton from '@/components/popover/PopoverButton'; import PopoverContent from '@/components/popover/PopoverContent'; import KandangTableSkeleton from '@/components/pages/master-data/kandang/skeleton/KandangTableSkeleton'; import SelectInput, { useSelect } from '@/components/input/SelectInput'; import { OptionType } from '@/components/input/SelectInput'; import ButtonFilter from '@/components/helper/ButtonFilter'; import { Kandang } from '@/types/api/master-data/kandang'; import { Location } from '@/types/api/master-data/location'; import { KandangApi, LocationApi } from '@/services/api/master-data'; import { UserApi } from '@/services/api/user'; import { User } from '@/types/api/api-general'; import { formatNumber } from '@/lib/helper'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { useUiStore } from '@/stores/ui/ui.store'; import { KandangFilterSchema, KandangFilterType, } from '@/components/pages/master-data/kandang/filter/KandangFilter'; import SelectInputRadio from '@/components/input/SelectInputRadio'; const RowOptionsMenu = ({ popoverPosition = 'bottom', props, deleteClickHandler, }: { popoverPosition: 'bottom' | 'top'; props: CellContext; deleteClickHandler: () => void; }) => { const popoverId = `kandang#${props.row.original.id}`; const popoverAnchorName = `--anchor-kandang#${props.row.original.id}`; const closePopover = () => { document.getElementById(popoverId)?.hidePopover(); }; return (
); }; const KandangsTable = () => { const { searchValue, setSearchValue, setTableState } = useUiStore(); const pathname = usePathname(); const { state: tableFilterState, updateFilter, setPage, setPageSize, toQueryString: getTableFilterQueryString, } = useTableFilter({ initial: { search: '', locationFilter: '', picFilter: '', }, paramMap: { page: 'page', pageSize: 'limit', locationFilter: 'location_id', picFilter: 'pic_id', }, }); // ===== FILTER MODAL STATE ===== const filterModal = useModal(); // ===== FORMIK SETUP ===== const formik = useFormik({ initialValues: { location_id: null, pic_id: null, }, validationSchema: KandangFilterSchema, onSubmit: (values, { setSubmitting }) => { updateFilter('locationFilter', values.location_id || ''); updateFilter('picFilter', values.pic_id || ''); filterModal.closeModal(); setSubmitting(false); }, onReset: () => { updateFilter('locationFilter', ''); updateFilter('picFilter', ''); }, }); // ===== LOCATION OPTIONS ===== const { setInputValue: setLocationInputValue, options: locationOptions, isLoadingOptions: isLoadingLocationOptions, loadMore: loadMoreLocations, } = useSelect( filterModal.open ? LocationApi.basePath : null, 'id', 'name', 'search' ); // ===== PIC OPTIONS ===== const { setInputValue: setPicInputValue, options: picOptions, isLoadingOptions: isLoadingPicOptions, loadMore: loadMorePics, } = useSelect( filterModal.open ? UserApi.basePath : null, 'id', 'name', 'search' ); // ===== FILTER HANDLERS ===== const handleFilterLocationChange = useCallback( (val: OptionType | OptionType[] | null) => { const location = val as OptionType | null; const locationId = location?.value ? String(location.value) : null; formik.setFieldValue('location_id', locationId); }, [formik] ); const handleFilterPicChange = useCallback( (val: OptionType | OptionType[] | null) => { const pic = val as OptionType | null; const picId = pic?.value ? String(pic.value) : null; formik.setFieldValue('pic_id', picId); }, [formik] ); // ===== FILTER HELPERS ===== const locationIdValue = useMemo(() => { if (!formik.values.location_id) return null; return ( locationOptions.find( (opt) => String(opt.value) === formik.values.location_id ) || null ); }, [formik.values.location_id, locationOptions]); const picIdValue = useMemo(() => { if (!formik.values.pic_id) return null; return ( picOptions.find((opt) => String(opt.value) === formik.values.pic_id) || null ); }, [formik.values.pic_id, picOptions]); // ===== HANDLE FILTER MODAL OPEN ===== const handleFilterModalOpen = () => { filterModal.openModal(); formik.validateForm(); }; const [sorting, setSorting] = useState([]); const { data: kandangs, isLoading, mutate: refreshKandangs, } = useSWR( `${KandangApi.basePath}${getTableFilterQueryString()}`, KandangApi.getAllFetcher ); const deleteModal = useModal(); const [selectedKandang, setSelectedKandang] = useState( undefined ); const [isDeleteLoading, setIsDeleteLoading] = useState(false); useEffect(() => { updateFilter('search', searchValue); }, [searchValue, updateFilter]); useEffect(() => { setTableState('kandangs-table', pathname); }, [pathname, setTableState]); const searchChangeHandler: ChangeEventHandler = (e) => { setSearchValue(e.target.value); updateFilter('search', e.target.value); }; const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); const deleteResponse = await KandangApi.delete( selectedKandang?.id as number ); if (isResponseError(deleteResponse)) { toast.error(deleteResponse.message); setIsDeleteLoading(false); return; } refreshKandangs(); deleteModal.closeModal(); toast.success('Successfully delete Kandang!'); setIsDeleteLoading(false); }; const kandangsColumns: ColumnDef[] = useMemo( () => [ { header: 'No', cell: (props) => tableFilterState.pageSize * (tableFilterState.page - 1) + props.row.index + 1, }, { accessorKey: 'name', header: 'Nama', }, { accessorFn: (row) => row.location?.name ?? '-', header: 'Lokasi', }, { accessorKey: 'capacity', header: 'Kapasitas', cell: (props) => formatNumber(props.row.original.capacity ?? 0), }, { accessorFn: (row) => row.pic?.name ?? '-', header: 'PIC', }, { accessorFn: (row) => row.kandang_group?.name ?? '-', header: 'Kandang Group', }, { header: 'Aksi', cell: (props: CellContext) => { 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 = () => { setSelectedKandang(props.row.original); deleteModal.openModal(); }; return ( ); }, }, ], [tableFilterState.pageSize, tableFilterState.page, deleteModal] ); return ( <>
{/* Header Section */}
{/* Action Buttons */}
{/* Search and Filter */}
} 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', }} />
{/* Table Section */}
{isLoading ? (
) : !isResponseSuccess(kandangs) || kandangs.data?.length === 0 ? (
} />
) : ( data={kandangs?.data} columns={kandangsColumns} pageSize={tableFilterState.pageSize} page={kandangs?.meta?.page ?? 0} totalItems={kandangs?.meta?.total_results ?? 0} onPageChange={setPage} onPageSizeChange={setPageSize} isLoading={false} sorting={sorting} setSorting={setSorting} className={{ containerClassName: 'p-3 mb-0', headerColumnClassName: 'text-nowrap', }} /> )}
{/* Filter Modal */} {/* Modal Header */}

Filter Data

{/* Modal Footer */}
); }; export default KandangsTable;