From dfac7f84ff7af96b5a5276600c7e77ade50ad037 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 12 Jan 2026 14:42:14 +0700 Subject: [PATCH] feat: create MasterConfigurationContent component --- .../MasterConfigurationContent.tsx | 564 ++++++++++++++++++ 1 file changed, 564 insertions(+) create mode 100644 src/figma-make/components/pages/master-data/configuration/MasterConfigurationContent.tsx diff --git a/src/figma-make/components/pages/master-data/configuration/MasterConfigurationContent.tsx b/src/figma-make/components/pages/master-data/configuration/MasterConfigurationContent.tsx new file mode 100644 index 00000000..1358d6ba --- /dev/null +++ b/src/figma-make/components/pages/master-data/configuration/MasterConfigurationContent.tsx @@ -0,0 +1,564 @@ +'use client'; + +import { useState } from 'react'; +import { Plus, MoreVertical, Pencil, Trash2 } 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 { + 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 Table from '@/components/Table'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; +import { cn, formatDate } from '@/lib/helper'; +import { useTableFilter } from '@/services/hooks/useTableFilter'; +import { ColumnDef } from '@tanstack/react-table'; +import { DailyChecklistConfiguration } from '@/types/api/daily-checklist/configuration'; +import { DailyChecklistConfigurationApi } from '@/services/api/daily-checklist/configuration'; +import { DatePicker } from '@/figma-make/components/base/date-picker'; + +export function MasterConfigurationContent() { + const { + state: tableFilterState, + setPage, + setPageSize, + toQueryString: getTableFilterQueryString, + } = useTableFilter({ + initial: { + search: '', + }, + paramMap: { + page: 'page', + pageSize: 'limit', + }, + }); + + const { + data: dailyChecklistConfigurations, + isLoading: isLoadingDailyChecklistConfigurations, + mutate: refreshDailyChecklistConfigurations, + } = useSWR( + `${DailyChecklistConfigurationApi.basePath}${getTableFilterQueryString()}`, + DailyChecklistConfigurationApi.getAllFetcher, + { + keepPreviousData: true, + } + ); + + const [showModal, setShowModal] = useState(false); + const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); + const [configurationToDelete, setConfigurationToDelete] = useState< + number | null + >(null); + const [loading, setLoading] = useState(false); + const [modalMode, setModalMode] = useState<'create' | 'edit'>('create'); + const [configurationForm, setConfigurationForm] = useState({ + id: 0, + date: '', + percentage_threshold_bad: '', + percentage_threshold_enough: '', + }); + + const configurationColumns: ColumnDef[] = [ + { + id: 'date', + header: 'Tanggal', + accessorKey: 'date', + enableSorting: false, + cell: ({ row }) => formatDate(row.original.date, 'DD MMM YYYY'), + }, + { + id: 'percentage_threshold_bad', + header: 'Threshold Bad', + accessorKey: 'percentage_threshold_bad', + enableSorting: false, + cell: ({ row }) => `${row.original.percentage_threshold_bad}%`, + }, + { + id: 'percentage_threshold_enough', + header: 'Threshold Enough', + accessorKey: 'percentage_threshold_enough', + enableSorting: false, + cell: ({ row }) => `${row.original.percentage_threshold_enough}%`, + }, + { + 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'); + setConfigurationForm({ + id: 0, + date: '', + percentage_threshold_bad: '', + percentage_threshold_enough: '', + }); + setShowModal(true); + }; + + const handleEdit = (configuration: DailyChecklistConfiguration) => { + setModalMode('edit'); + setConfigurationForm({ + id: configuration.id, + date: configuration.date, + percentage_threshold_bad: String(configuration.percentage_threshold_bad), + percentage_threshold_enough: String( + configuration.percentage_threshold_enough + ), + }); + setShowModal(true); + }; + + const handleSave = async () => { + if ( + !configurationForm.date.trim() || + Number(configurationForm.percentage_threshold_bad) === 0 || + Number(configurationForm.percentage_threshold_enough) === 0 + ) { + toast.error('Tanggal dan persentase harus diisi'); + return; + } + + setLoading(true); + + try { + if (modalMode === 'create') { + const createConfigurationResponse = + await DailyChecklistConfigurationApi.create({ + date: formatDate(configurationForm.date, 'YYYY-MM-DD'), + percentage_threshold_bad: Number( + configurationForm.percentage_threshold_bad + ), + percentage_threshold_enough: Number( + configurationForm.percentage_threshold_enough + ), + }); + + if (isResponseError(createConfigurationResponse)) { + console.error( + 'Error creating configuration:', + createConfigurationResponse.message + ); + toast.error('Gagal menambahkan konfigurasi'); + return; + } + + refreshDailyChecklistConfigurations(); + toast.success('Konfigurasi berhasil ditambahkan'); + } else { + const updateConfigurationResponse = + await DailyChecklistConfigurationApi.update(configurationForm.id, { + date: formatDate(configurationForm.date, 'YYYY-MM-DD'), + percentage_threshold_bad: Number( + configurationForm.percentage_threshold_bad + ), + percentage_threshold_enough: Number( + configurationForm.percentage_threshold_enough + ), + }); + + if (isResponseError(updateConfigurationResponse)) { + console.error( + 'Error updating configuration:', + updateConfigurationResponse.message + ); + toast.error('Gagal mengubah konfigurasi'); + return; + } + + refreshDailyChecklistConfigurations(); + toast.success('Konfigurasi berhasil diubah'); + } + + setShowModal(false); + setConfigurationForm({ + id: 0, + date: '', + percentage_threshold_bad: '', + percentage_threshold_enough: '', + }); + } catch (error) { + console.error('Error saving configuration:', error); + toast.error('Terjadi kesalahan saat menyimpan konfigurasi'); + } finally { + setLoading(false); + } + }; + + const handleDeleteClick = (configurationId: number) => { + setConfigurationToDelete(configurationId); + setShowDeleteConfirm(true); + }; + + const handleConfirmDelete = async () => { + if (!configurationToDelete) return; + + setLoading(true); + + try { + const deleteConfigurationResponse = + await DailyChecklistConfigurationApi.delete(configurationToDelete); + + if (isResponseError(deleteConfigurationResponse)) { + console.error( + 'Error deleting configuration:', + deleteConfigurationResponse.message + ); + toast.error('Gagal menghapus konfigurasi'); + return; + } + + refreshDailyChecklistConfigurations(); + toast.success('Konfigurasi berhasil dihapus'); + setShowDeleteConfirm(false); + setConfigurationToDelete(null); + } catch (error) { + console.error('Error deleting employee:', error); + toast.error('Terjadi kesalahan saat menghapus konfigurasi'); + } finally { + setLoading(false); + } + }; + + const handleExport = (format: string) => { + toast.success(`Data berhasil diekspor ke ${format}`); + }; + + if (isLoadingDailyChecklistConfigurations && !dailyChecklistConfigurations) { + return ( +
+
+
+

+ Master Konfigurasi +

+

+ Master Data • Konfigurasi +

+
+ + + Memuat data... + + +
+
+ ); + } + + const formatDateForDisplay = (dateStr: string) => { + if (!dateStr) return 'Pilih tanggal'; + const [year, month, day] = dateStr.split('-'); + const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day)); + return date.toLocaleDateString('id-ID', { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric', + }); + }; + + return ( +
+
+ {/* Page Title */} +
+

+ Master Konfigurasi +

+

+ Master Data • Konfigurasi +

+
+ + {/* Main Card */} + + + {/* Single Toolbar Row */} +
+
+ +
+
+ + {/* Table */} + + data={ + isResponseSuccess(dailyChecklistConfigurations) + ? dailyChecklistConfigurations?.data + : [] + } + columns={configurationColumns} + pageSize={tableFilterState.pageSize} + onPageSizeChange={setPageSize} + rowOptions={[10, 20, 50, 100]} + page={ + isResponseSuccess(dailyChecklistConfigurations) + ? dailyChecklistConfigurations?.meta?.page + : 0 + } + totalItems={ + isResponseSuccess(dailyChecklistConfigurations) + ? dailyChecklistConfigurations?.meta?.total_results + : 0 + } + onPageChange={setPage} + isLoading={isLoadingDailyChecklistConfigurations} + className={{ + containerClassName: cn({ + 'w-full mb-20': + isResponseSuccess(dailyChecklistConfigurations) && + dailyChecklistConfigurations?.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 Konfigurasi' + : 'Edit Konfigurasi'} + + + {modalMode === 'create' + ? 'Masukkan detail konfigurasi baru' + : 'Ubah detail konfigurasi'} + + +
+
+ +
+ + setConfigurationForm({ + ...configurationForm, + date: e, + }) + } + disabled={loading} + placeholder='Pilih tanggal' + formatDisplay={formatDateForDisplay} + /> +
+
+ +
+ +
+ +
+ + +
+ + + {'<='} + + + setConfigurationForm({ + ...configurationForm, + percentage_threshold_bad: e.target.value, + }) + } + placeholder='Kurang' + className='w-20' + disabled={loading} + max={100} + /> +
+
+ +
+ + +
+ + + {'<='} + + + setConfigurationForm({ + ...configurationForm, + percentage_threshold_enough: e.target.value, + }) + } + placeholder='Cukup' + className='w-20' + disabled={loading} + min={Number(configurationForm.percentage_threshold_bad) + 1} + max={100} + /> +
+
+ +
+ + +
+ + + {'<='} + + +
+
+
+ + + + +
+
+ + {/* Delete Confirmation */} + + + + Hapus konfigurasi? + + Data konfigurasi akan dihapus secara permanen. + + + + Batal + + {loading ? 'Menghapus...' : 'Hapus'} + + + + +
+ ); +}