'use client'; import { useState } from 'react'; import { Eye, CheckCircle, XCircle, Search, Trash2, Edit, Loader2, } from 'lucide-react'; import { Card, CardContent } from '@/figma-make/components/base/card'; import { Button } from '@/figma-make/components/base/button'; import { Badge } from '@/figma-make/components/base/badge'; import { Label } from '@/figma-make/components/base/label'; import { Textarea } from '@/figma-make/components/base/textarea'; import { DateRangePicker } from '@/figma-make/components/base/date-range-picker'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/figma-make/components/base/select'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '@/figma-make/components/base/dialog'; import { toast } from 'sonner'; import { useRouter } from 'next/navigation'; import useSWR from 'swr'; import { DailyChecklistApi } from '@/services/api/daily-checklist/daily-checklist'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import Table from '@/components/Table'; import { DailyChecklist } from '@/types/api/daily-checklist/daily-checklist'; import { cn } from '@/lib/helper'; import { ColumnDef } from '@tanstack/react-table'; import { useSelect } from '@/components/input/SelectInput'; import DebouncedTextInput from '@/components/input/DebouncedTextInput'; import RequirePermission from '@/components/helper/RequirePermission'; import { DailyChecklistKandangApi } from '@/services/api/daily-checklist/kandang'; const STATUS_OPTIONS = [ { value: 'ALL', label: 'Semua Status' }, { value: 'DRAFT', label: 'Draft' }, { value: 'SUBMITTED', label: 'Submitted' }, { value: 'APPROVED', label: 'Approved' }, { value: 'REJECTED', label: 'Rejected' }, ]; const CATEGORY_LABELS: { [key: string]: string } = { pullet_open: 'Pullet Open', pullet_close: 'Pullet Close', produksi_open: 'Produksi Open', produksi_close: 'Produksi Close', }; export function ListDailyChecklistContent() { const router = useRouter(); const { state: tableFilterState, updateFilter, setPage, setPageSize, toQueryString: getTableFilterQueryString, } = useTableFilter({ initial: { date_from: '', date_to: '', search: '', kandang_id: '', status: '', }, paramMap: { page: 'page', pageSize: 'limit', search: 'search', kandang_id: 'kandang_id', status: 'status', date_from: 'date_from', date_to: 'date_to', }, }); const { data: checklistListRes, isLoading: isLoadingChecklistList, mutate: refreshChecklistList, } = useSWR( `${DailyChecklistApi.basePath}${getTableFilterQueryString()}`, DailyChecklistApi.getAllFetcher, { keepPreviousData: true, } ); const { options: kandangOptions, isLoadingMore: isLoadingMoreKandang, loadMore: loadMoreKandang, } = useSelect(DailyChecklistKandangApi.basePath, 'id', 'name'); const checklistList = isResponseSuccess(checklistListRes) ? checklistListRes.data || [] : []; const handleKandangScroll = (e: React.UIEvent) => { const target = e.target as HTMLDivElement; if (target.scrollHeight - target.scrollTop <= target.clientHeight + 10) { if (!isLoadingMoreKandang) { loadMoreKandang(); } } }; // Modals const [showApproveModal, setShowApproveModal] = useState(false); const [showRejectModal, setShowRejectModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [selectedItem, setSelectedItem] = useState(null); const [rejectReason, setRejectReason] = useState(''); const [actionLoading, setActionLoading] = useState(false); const handleDetail = (item: DailyChecklist) => { router.push( `/daily-checklist/list-daily-checklist/detail?checklistId=${item.id}` ); }; const handleEdit = (item: DailyChecklist) => { const formattedDate = new Date(item.date).toISOString().split('T')[0]; const kandangId = item.kandang.id; const category = item.category; router.push( `/daily-checklist/daily-checklist?date=${formattedDate}&kandang_id=${kandangId}&category=${category}` ); }; const handleApprove = (item: DailyChecklist) => { setSelectedItem(item); setShowApproveModal(true); }; const handleReject = (item: DailyChecklist) => { setSelectedItem(item); setRejectReason(''); setShowRejectModal(true); }; const handleDelete = (item: DailyChecklist) => { // ✅ VALIDATION: Only DRAFT can be deleted if (item.status !== 'DRAFT') { toast.error('Hanya checklist dengan status DRAFT yang bisa dihapus', { description: `Status saat ini: ${item.status}`, }); return; } setSelectedItem(item); setShowDeleteModal(true); }; const confirmApprove = async () => { if (!selectedItem) return; try { setActionLoading(true); const approveRes = await DailyChecklistApi.approve( String(selectedItem.id) ); if (isResponseError(approveRes)) { toast.error('Gagal approve checklist: ' + approveRes.message); return; } refreshChecklistList(); toast.success('Checklist berhasil di-approve'); setShowApproveModal(false); setSelectedItem(null); } catch (error) { console.error('Error approving checklist:', error); toast.error('Terjadi kesalahan'); } finally { setActionLoading(false); } }; const confirmReject = async () => { if (!selectedItem) return; if (!rejectReason.trim()) { toast.error('Alasan reject harus diisi'); return; } try { setActionLoading(true); const rejectRes = await DailyChecklistApi.reject( String(selectedItem.id), rejectReason ); if (isResponseError(rejectRes)) { toast.error('Gagal reject checklist: ' + rejectRes.message); return; } refreshChecklistList(); toast.success('Checklist berhasil di-reject'); setShowRejectModal(false); setSelectedItem(null); setRejectReason(''); } catch (error) { console.error('Error rejecting checklist:', error); toast.error('Terjadi kesalahan'); } finally { setActionLoading(false); } }; const confirmDelete = async () => { if (!selectedItem) return; try { setActionLoading(true); const deleteRes = await DailyChecklistApi.delete(selectedItem.id); if (isResponseError(deleteRes)) { toast.error('Gagal hapus checklist: ' + deleteRes.message); return; } refreshChecklistList(); toast.success('Checklist berhasil dihapus'); setShowDeleteModal(false); setSelectedItem(null); } catch (error) { console.error('Error deleting checklist:', error); toast.error('Terjadi kesalahan'); } finally { setActionLoading(false); } }; const getStatusBadge = (status: string) => { switch (status) { case 'DRAFT': return ( Draft ); case 'SUBMITTED': return ( Submitted ); case 'APPROVED': return ( Approved ); case 'REJECTED': return ( Rejected ); default: return ( {status} ); } }; const formatDate = (dateString: string) => { const date = new Date(dateString); return date.toLocaleDateString('id-ID', { day: '2-digit', month: 'short', year: 'numeric', }); }; const formatDateTime = (dateString: string) => { const date = new Date(dateString); return date.toLocaleString('id-ID', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', }); }; const checklistListColumns: ColumnDef[] = [ { accessorKey: 'date', header: 'Tanggal', enableSorting: false, cell: ({ row }) => formatDate(row.original.date), }, { accessorKey: 'kandang', header: 'Kandang', enableSorting: false, cell: ({ row }) => row.original.kandang.name, }, { accessorKey: 'category', header: 'Kategori', enableSorting: false, cell: ({ row }) => CATEGORY_LABELS[row.original.category] || row.original.category, }, { accessorKey: 'status', header: 'Status', enableSorting: false, cell: ({ row }) => getStatusBadge(row.original.status), }, { accessorKey: 'total_phase', header: 'Total Phase', enableSorting: false, }, { accessorKey: 'total_activity', header: 'Total Aktivitas', enableSorting: false, }, { accessorKey: 'progress', header: 'Progress', enableSorting: false, cell: ({ row }) => (
{row.original.progress}%
), }, { accessorKey: 'updated_at', header: 'Diperbarui', enableSorting: false, cell: ({ row }) => formatDateTime(row.original.updated_at), }, { id: 'action', header: 'Aksi', accessorKey: 'action', enableSorting: false, cell: ({ row }) => (
{row.original.status === 'DRAFT' && ( )} {row.original.status === 'SUBMITTED' && ( )} {row.original.status === 'DRAFT' && ( )}
), }, ]; return (
{/* Page Title */}

List Daily Checklist

Daftar semua checklist harian

{/* Main Card */} {/* Filters Section */}
{ updateFilter('date_from', from); updateFilter('date_to', to); }} />
updateFilter('search', e.target.value)} className={{ wrapper: 'w-full border-gray-200', inputWrapper: 'px-3 py-2 h-fit rounded-md', input: 'text-sm', }} startAdornment={ } />
{/* Table Section */} data={checklistList} columns={checklistListColumns} pageSize={tableFilterState.pageSize} onPageSizeChange={setPageSize} rowOptions={[10, 20, 50, 100]} page={ isResponseSuccess(checklistListRes) ? checklistListRes?.meta?.page : 0 } totalItems={ isResponseSuccess(checklistListRes) ? checklistListRes?.meta?.total_results : 0 } onPageChange={setPage} isLoading={isLoadingChecklistList} className={{ containerClassName: cn({ 'w-full mb-20': isResponseSuccess(checklistListRes) && checklistListRes?.data?.length === 0, }), tableWrapperClassName: 'overflow-x-auto border border-solid border-base-content/10 rounded-none', headerRowClassName: 'bg-gray-50/50', headerColumnClassName: 'text-left py-3.5 px-6 text-sm font-semibold text-gray-700', paginationClassName: 'px-4', }} />
{/* Approve Modal */} Approve Checklist Apakah Anda yakin ingin approve checklist ini? {selectedItem && (
Tanggal: {formatDate(selectedItem.date)}
Kandang: {selectedItem.kandang.name}
Kategori: {CATEGORY_LABELS[selectedItem.category] || selectedItem.category}
Progress: {selectedItem.progress}%
)}
{/* Reject Modal */} Reject Checklist Berikan alasan reject untuk checklist ini {selectedItem && (
Tanggal: {formatDate(selectedItem.date)}
Kandang: {selectedItem.kandang.name}
Kategori: {CATEGORY_LABELS[selectedItem.category] || selectedItem.category}
)}