From 5bf3d3263685c9cfcb7341df5a59fda096f0d471 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 20 Apr 2026 16:21:17 +0700 Subject: [PATCH 01/21] feat: implement bulk approve & reject --- .../ListDailyChecklistContent.tsx | 308 +++++++++++++++++- 1 file changed, 300 insertions(+), 8 deletions(-) diff --git a/src/figma-make/components/pages/list-daily-checklist/ListDailyChecklistContent.tsx b/src/figma-make/components/pages/list-daily-checklist/ListDailyChecklistContent.tsx index 01e567d3..7c4befee 100644 --- a/src/figma-make/components/pages/list-daily-checklist/ListDailyChecklistContent.tsx +++ b/src/figma-make/components/pages/list-daily-checklist/ListDailyChecklistContent.tsx @@ -40,11 +40,12 @@ 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 { ColumnDef, Row } 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'; +import CheckboxInput from '@/components/input/CheckboxInput'; const STATUS_OPTIONS = [ { value: 'ALL', label: 'Semua Status' }, @@ -122,12 +123,29 @@ export function ListDailyChecklistContent() { // Modals const [showApproveModal, setShowApproveModal] = useState(false); + const [showBulkApproveModal, setShowBulkApproveModal] = useState(false); const [showRejectModal, setShowRejectModal] = useState(false); + const [showBulkRejectModal, setShowBulkRejectModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [selectedItem, setSelectedItem] = useState(null); const [rejectReason, setRejectReason] = useState(''); const [actionLoading, setActionLoading] = useState(false); + const [rowSelection, setRowSelection] = useState>({}); + const selectedRowIds = Object.keys(rowSelection); + + const selectedRowItems = selectedRowIds.map((itemId) => + checklistList.find((item) => item.id === parseInt(itemId)) + ); + + const tableEnableRowSelectionHandler: ( + row: Row + ) => boolean = (row) => { + return ( + row.original.status !== 'APPROVED' && row.original.status !== 'REJECTED' + ); + }; + const handleDetail = (item: DailyChecklist) => { router.push( `/daily-checklist/list-daily-checklist/detail?checklistId=${item.id}` @@ -149,12 +167,21 @@ export function ListDailyChecklistContent() { setShowApproveModal(true); }; + const handleBulkApprove = () => { + setShowBulkApproveModal(true); + }; + const handleReject = (item: DailyChecklist) => { setSelectedItem(item); setRejectReason(''); setShowRejectModal(true); }; + const handleBulkReject = () => { + setRejectReason(''); + setShowBulkRejectModal(true); + }; + const handleDelete = (item: DailyChecklist) => { // ✅ VALIDATION: Only DRAFT can be deleted if (item.status !== 'DRAFT') { @@ -195,6 +222,31 @@ export function ListDailyChecklistContent() { } }; + const confirmBulkApprove = async () => { + if (!selectedRowIds.length) return; + + try { + setActionLoading(true); + + const approveRes = await DailyChecklistApi.bulkApprove(selectedRowIds); + + if (isResponseError(approveRes)) { + toast.error('Gagal approve checklist: ' + approveRes.message); + return; + } + + refreshChecklistList(); + toast.success('Checklist berhasil di-approve'); + setShowBulkApproveModal(false); + setRowSelection({}); + } catch (error) { + console.error('Error approving checklist:', error); + toast.error('Terjadi kesalahan'); + } finally { + setActionLoading(false); + } + }; + const confirmReject = async () => { if (!selectedItem) return; @@ -229,6 +281,40 @@ export function ListDailyChecklistContent() { } }; + const confirmBulkReject = async () => { + if (!selectedRowIds.length) return; + + if (!rejectReason.trim()) { + toast.error('Alasan reject harus diisi'); + return; + } + + try { + setActionLoading(true); + + const rejectRes = await DailyChecklistApi.bulkReject( + selectedRowIds, + rejectReason + ); + + if (isResponseError(rejectRes)) { + toast.error('Gagal reject checklist: ' + rejectRes.message); + return; + } + + refreshChecklistList(); + toast.success('Checklist berhasil di-reject'); + setShowBulkRejectModal(false); + setRowSelection({}); + setRejectReason(''); + } catch (error) { + console.error('Error rejecting checklist:', error); + toast.error('Terjadi kesalahan'); + } finally { + setActionLoading(false); + } + }; + const confirmDelete = async () => { if (!selectedItem) return; @@ -325,6 +411,37 @@ export function ListDailyChecklistContent() { }; const checklistListColumns: ColumnDef[] = [ + { + id: 'select', + header: ({ table }) => ( +
+ +
+ ), + cell: ({ row }) => { + const isCheckboxDisabled = + !row.getCanSelect() || + row.original.status === 'APPROVED' || + row.original.status === 'REJECTED'; + + return ( +
+ +
+ ); + }, + }, { accessorKey: 'date', header: 'Tanggal', @@ -459,13 +576,39 @@ export function ListDailyChecklistContent() {
{/* Page Title */} -
-

- List Daily Checklist -

-

- Daftar semua checklist harian -

+
+
+

+ List Daily Checklist +

+

+ Daftar semua checklist harian +

+
+ + + {selectedRowIds.length > 0 && ( +
+ + +
+ )} +
{/* Main Card */} @@ -588,6 +731,10 @@ export function ListDailyChecklistContent() { } onPageChange={setPage} isLoading={isLoadingChecklistList} + rowSelection={rowSelection} + setRowSelection={setRowSelection} + enableRowSelection={tableEnableRowSelectionHandler} + withCheckbox className={{ containerClassName: cn({ 'w-full mb-20': @@ -666,6 +813,76 @@ export function ListDailyChecklistContent() { + {/* Bulk Approve Modal */} + + + + Approve Checklist + + Apakah Anda yakin ingin approve {selectedRowIds.length} checklist + ini? + + + +
+ {selectedRowItems.map((item) => ( +
+
+ Tanggal: + + {formatDate(item?.date ?? '')} + +
+
+ Kandang: + + {item?.kandang?.name ?? '-'} + +
+
+ Kategori: + + {item?.category + ? (CATEGORY_LABELS[item.category] ?? item?.category) + : item?.category} + +
+
+ Progress: + + {item?.progress}% + +
+
+ ))} +
+ + + + + +
+
+ {/* Reject Modal */} @@ -735,6 +952,81 @@ export function ListDailyChecklistContent() { + {/* Bulk Reject Modal */} + + + + Reject Checklist + + Berikan alasan reject untuk checklist ini + + + +
+ {selectedRowItems.map((item) => ( +
+
+ Tanggal: + + {formatDate(item?.date ?? '')} + +
+
+ Kandang: + + {item?.kandang?.name ?? '-'} + +
+
+ Kategori: + + {item?.category + ? CATEGORY_LABELS[item.category] || item?.category + : item?.category} + +
+
+ ))} +
+ +
+ +