From fb9e863862a9697086b3547183e2362bbad0d4f5 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 9 Mar 2026 12:29:20 +0700 Subject: [PATCH] feat(FE): create MasterKandangContent component --- .../kandang/MasterKandangContent.tsx | 679 ++++++++++++++++++ 1 file changed, 679 insertions(+) create mode 100644 src/figma-make/components/pages/master-data/kandang/MasterKandangContent.tsx diff --git a/src/figma-make/components/pages/master-data/kandang/MasterKandangContent.tsx b/src/figma-make/components/pages/master-data/kandang/MasterKandangContent.tsx new file mode 100644 index 00000000..831fdacc --- /dev/null +++ b/src/figma-make/components/pages/master-data/kandang/MasterKandangContent.tsx @@ -0,0 +1,679 @@ +'use client'; + +import { useState } from 'react'; +import { Plus, MoreVertical, Pencil, Trash2, Search } from 'lucide-react'; +import { Card, CardContent } from '@/figma-make/components/base/card'; +import { Button } from '@/figma-make/components/base/button'; +import { Label } from '@/figma-make/components/base/label'; +import { Input } from '@/figma-make/components/base/input'; +import { Badge } from '@/figma-make/components/base/badge'; +import { MultiSelect } from '@/figma-make/components/base/multi-select'; +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 { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/figma-make/components/base/alert-dialog'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/figma-make/components/base/dropdown-menu'; +import { toast } from 'sonner'; +import useSWR from 'swr'; +import { DailyChecklistKandangApi } from '@/services/api/daily-checklist/kandang'; +import Table from '@/components/Table'; +import { DailyChecklistKandang } from '@/types/api/daily-checklist/kandang'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; +import { cn } from '@/lib/helper'; +import { useTableFilter } from '@/services/hooks/useTableFilter'; +import { ColumnDef } from '@tanstack/react-table'; +import { useSelect } from '@/components/input/SelectInput'; +import { KandangApi, LocationApi } from '@/services/api/master-data'; +import DebouncedTextInput from '@/components/input/DebouncedTextInput'; +import { BaseDailyChecklistKandang } from '@/types/api/daily-checklist/kandang'; +import { UserApi } from '@/services/api/user'; + +export function MasterKandangContent() { + const { + state: tableFilterState, + updateFilter, + setPage, + setPageSize, + toQueryString: getTableFilterQueryString, + } = useTableFilter({ + initial: { + search: '', + location_id: '', + status: '', + }, + paramMap: { + page: 'page', + pageSize: 'limit', + search: 'search', + location_id: 'location_id', + }, + }); + + const { + data: dailyChecklistKandangs, + isLoading: isLoadingDailyChecklistKandangs, + mutate: refreshDailyChecklistKandangs, + } = useSWR( + `${DailyChecklistKandangApi.basePath}${getTableFilterQueryString()}`, + DailyChecklistKandangApi.getAllFetcher, + { + keepPreviousData: true, + } + ); + const { options: locationOptions } = useSelect( + LocationApi.basePath, + 'id', + 'name', + 'search', + { + page: '1', + limit: '100', + } + ); + + const { options: picOptions } = useSelect( + UserApi.basePath, + 'id', + 'name', + 'search', + { + page: '1', + limit: '100', + } + ); + + const { + options: kandangOptions, + isLoadingMore: isLoadingKandangOptionsMore, + loadMore: loadMoreKandang, + } = useSelect(KandangApi.basePath, 'id', 'name'); + + const [showModal, setShowModal] = useState(false); + const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); + const [kandangToDelete, setKandangToDelete] = useState(null); + const [loading, setLoading] = useState(false); + const [modalMode, setModalMode] = useState<'create' | 'edit'>('create'); + const [kandangForm, setKandangForm] = useState({ + id: 0, + name: '', + location_id: 0, + pic_id: 0, + // recording_kandangs: [] as number[], + }); + + const dailyChecklistKandangColumns: ColumnDef[] = [ + { + id: 'name', + header: 'Nama', + accessorKey: 'name', + enableSorting: false, + }, + { + id: 'location', + header: 'Lokasi', + accessorKey: 'location', + enableSorting: false, + cell: ({ row }) => row.original.location.name ?? '-', + }, + { + id: 'pic', + header: 'PIC', + accessorKey: 'pic', + enableSorting: false, + cell: ({ row }) => row.original.pic.name ?? '-', + }, + { + id: 'recording_kandangs', + header: 'Kandang Recording', + accessorKey: 'recording_kandangs', + enableSorting: false, + cell: ({ row }) => + row.original.recording_kandangs?.length > 0 + ? row.original.recording_kandangs.map((item) => item.name).join(', ') + : '-', + }, + { + id: 'action', + header: 'Aksi', + accessorKey: 'action', + enableSorting: false, + cell: ({ row }) => ( + + + + + + handleEdit(row.original)}> + + Edit + + handleDeleteClick(row.original.id)} + className='text-red-600' + > + + Hapus + + + + ), + }, + ]; + + const handleAdd = () => { + setModalMode('create'); + setKandangForm({ + id: 0, + name: '', + location_id: 0, + pic_id: 0, + // recording_kandangs: [] + }); + setShowModal(true); + }; + + const handleEdit = (dailyChecklistKandang: DailyChecklistKandang) => { + setModalMode('edit'); + setKandangForm({ + id: dailyChecklistKandang.id, + name: dailyChecklistKandang.name, + location_id: dailyChecklistKandang.location.id, + pic_id: dailyChecklistKandang.pic.id, + // recording_kandangs: + // dailyChecklistKandang.recording_kandangs.map((item) => item.id) ?? [], + }); + setShowModal(true); + }; + + const handleSave = async () => { + if (!kandangForm.name.trim()) { + toast.error('Nama harus diisi'); + return; + } + + if (!kandangForm.location_id) { + toast.error('Lokasi wajib diisi'); + return; + } + + // if (!kandangForm.recording_kandangs.length) { + // toast.error('Kandang recording wajib diisi'); + // return; + // } + + setLoading(true); + + try { + if (modalMode === 'create') { + const createDailyChecklistKandangResponse = + await DailyChecklistKandangApi.create({ + name: kandangForm.name.trim(), + location_id: kandangForm.location_id, + pic_id: kandangForm.pic_id, + // recording_kandang_ids: kandangForm.recording_kandangs, + }); + + if (isResponseError(createDailyChecklistKandangResponse)) { + console.error( + 'Error creating kandang:', + createDailyChecklistKandangResponse.message + ); + toast.error('Gagal menambahkan kandang'); + return; + } + + refreshDailyChecklistKandangs(); + toast.success('Kandang berhasil ditambahkan'); + } else { + const updateDailyChecklistKandangResponse = + await DailyChecklistKandangApi.update(kandangForm.id, { + name: kandangForm.name.trim(), + location_id: kandangForm.location_id, + pic_id: kandangForm.pic_id, + // recording_kandang_ids: kandangForm.recording_kandangs, + }); + + if (isResponseError(updateDailyChecklistKandangResponse)) { + console.error( + 'Error updating kandang:', + updateDailyChecklistKandangResponse.message + ); + toast.error('Gagal menambahkan Kandang'); + return; + } + + refreshDailyChecklistKandangs(); + toast.success('Kandang berhasil diubah'); + } + + setShowModal(false); + setKandangForm({ + id: 0, + name: '', + location_id: 0, + pic_id: 0, + // recording_kandangs: [], + }); + } catch (error) { + console.error('Error saving kandang:', error); + toast.error('Terjadi kesalahan saat menyimpan kandang'); + } finally { + setLoading(false); + } + }; + + const handleDeleteClick = (kandangId: number) => { + setKandangToDelete(kandangId); + setShowDeleteConfirm(true); + }; + + const handleConfirmDelete = async () => { + if (!kandangToDelete) return; + + setLoading(true); + + try { + const deleteKandangResponse = + await DailyChecklistKandangApi.delete(kandangToDelete); + + if (isResponseError(deleteKandangResponse)) { + console.error('Error deleting kandang:', deleteKandangResponse.message); + toast.error('Gagal menghapus kandang'); + return; + } + + refreshDailyChecklistKandangs(); + toast.success('Kandang berhasil dihapus'); + setShowDeleteConfirm(false); + setKandangToDelete(null); + } catch (error) { + console.error('Error deleting kandang:', error); + toast.error('Terjadi kesalahan saat menghapus kandang'); + } finally { + setLoading(false); + } + }; + + if (isLoadingDailyChecklistKandangs && !dailyChecklistKandangs) { + return ( +
+
+
+

+ Master Kandang +

+

+ Master Data • Kandang +

+
+ + + Memuat data... + + +
+
+ ); + } + + return ( +
+
+ {/* Page Title */} +
+

+ Master Kandang +

+

+ Master Data • Kandang +

+
+ + {/* Main Card */} + + + {/* Single Toolbar Row */} +
+ {/* LEFT: Search + Filters */} +
+
+ + + updateFilter('search', e.target.value)} + className={{ + wrapper: 'w-full sm:w-[280px] border-gray-200', + inputWrapper: 'px-3 py-2 h-fit rounded-md', + input: 'text-sm', + }} + startAdornment={ + + } + /> +
+ + + + {/* */} +
+ + {/* RIGHT: Export + Add */} +
+ +
+
+ + {/* Table */} + + data={ + isResponseSuccess(dailyChecklistKandangs) + ? dailyChecklistKandangs?.data + : [] + } + columns={dailyChecklistKandangColumns} + pageSize={tableFilterState.pageSize} + onPageSizeChange={setPageSize} + rowOptions={[10, 20, 50, 100]} + page={ + isResponseSuccess(dailyChecklistKandangs) + ? dailyChecklistKandangs?.meta?.page + : 0 + } + totalItems={ + isResponseSuccess(dailyChecklistKandangs) + ? dailyChecklistKandangs?.meta?.total_results + : 0 + } + onPageChange={setPage} + isLoading={isLoadingDailyChecklistKandangs} + className={{ + containerClassName: cn({ + 'w-full mb-20': + isResponseSuccess(dailyChecklistKandangs) && + dailyChecklistKandangs?.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', + }} + /> +
+
+
+ + {/* Add/Edit Modal */} + + + + + {modalMode === 'create' ? 'Tambah Kandang' : 'Edit Kandang'} + + + {modalMode === 'create' + ? 'Masukkan detail Kandang baru' + : 'Ubah detail Kandang'} + + +
+
+ + + setKandangForm({ ...kandangForm, name: e.target.value }) + } + placeholder='Masukkan nama Kandang' + className='mt-1.5' + disabled={loading} + /> +
+
+ + +
+ +
+ + +
+ + {/*
+ + ({ + value: String(k.value), + label: k.label, + }))} + selected={kandangForm.recording_kandangs.map((id) => + String(id) + )} + onChange={(selected) => + setKandangForm({ + ...kandangForm, + recording_kandangs: selected.map((id) => Number(id)), + }) + } + placeholder='Pilih kandang' + isLoadingMore={isLoadingKandangOptionsMore} + onLoadMore={loadMoreKandang} + className='mt-1.5' + /> +
*/} + + {/*
+ + ({ + value: String(k.value), + label: k.label, + }))} + selected={kandangForm.kandang_ids.map((id) => String(id))} + onChange={(selected) => + setKandangForm({ + ...kandangForm, + kandang_ids: selected.map((id) => Number(id)), + }) + } + placeholder='Pilih kandang' + className='mt-1.5' + /> +
*/} + {/*
+ + +
*/} +
+ + + + +
+
+ + {/* Delete Confirmation */} + + + + Hapus Kandang? + + Data Kandang akan dihapus secara permanen. + + + + Batal + + {loading ? 'Menghapus...' : 'Hapus'} + + + + +
+ ); +}