From db4d9ad38c72690775af264049015e662f1ddeb7 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Thu, 8 Jan 2026 09:40:02 +0700 Subject: [PATCH] feat: integrate MasterEmployeeContent component to API --- .../employee/MasterEmployeeContent.tsx | 481 ++++++++---------- 1 file changed, 217 insertions(+), 264 deletions(-) diff --git a/src/figma-make/components/pages/master-data/employee/MasterEmployeeContent.tsx b/src/figma-make/components/pages/master-data/employee/MasterEmployeeContent.tsx index 6a40547c..3a5f0972 100644 --- a/src/figma-make/components/pages/master-data/employee/MasterEmployeeContent.tsx +++ b/src/figma-make/components/pages/master-data/employee/MasterEmployeeContent.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useEffect } from 'react'; +import { useState } from 'react'; import { Plus, Download, @@ -48,124 +48,132 @@ import { DropdownMenuTrigger, } from '@/figma-make/components/base/dropdown-menu'; import { toast } from 'sonner'; -import { supabase, isSupabaseConfigured } from '@/figma-make/lib/supabase'; import useSWR from 'swr'; import { EmployeeApi } from '@/services/api/daily-checklist/employee'; - -interface Employee { - id: string; - name: string; - kandang_id: string; - is_active: boolean; - kandang?: { - id: string; - name: string; - }; -} - -interface Kandang { - id: string; - name: string; -} +import Table from '@/components/Table'; +import { Employee } from '@/types/api/daily-checklist/employee'; +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 } from '@/services/api/master-data'; +import DebouncedTextInput from '@/components/input/DebouncedTextInput'; export function MasterEmployeeContent() { - const { data: employeesTest, isLoading: isLoadingEmployees } = useSWR( - EmployeeApi.basePath, + const { + state: tableFilterState, + updateFilter, + setPage, + setPageSize, + toQueryString: getTableFilterQueryString, + } = useTableFilter({ + initial: { + search: '', + kandang_id: '', + status: '', + }, + paramMap: { + page: 'page', + pageSize: 'limit', + search: 'search', + kandang_id: 'kandang_id', + status: 'is_active', + }, + }); + + const { + data: employees, + isLoading: isLoadingEmployees, + mutate: refreshEmployees, + } = useSWR( + `${EmployeeApi.basePath}${getTableFilterQueryString()}`, EmployeeApi.getAllFetcher, { keepPreviousData: true, } ); + const { options: kandangOptions, isLoadingOptions: isLoadingKandangs } = + useSelect(KandangApi.basePath, 'id', 'name', 'search', { + page: '1', + limit: '100', + }); - const [employees, setEmployees] = useState([]); - const [kandangList, setKandangList] = useState([]); const [showModal, setShowModal] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); - const [employeeToDelete, setEmployeeToDelete] = useState(null); + const [employeeToDelete, setEmployeeToDelete] = useState(null); const [loading, setLoading] = useState(false); - const [initialLoading, setInitialLoading] = useState(true); - const [searchQuery, setSearchQuery] = useState(''); - const [kandangFilter, setKandangFilter] = useState('all'); - const [statusFilter, setStatusFilter] = useState('all'); const [modalMode, setModalMode] = useState<'create' | 'edit'>('create'); const [employeeForm, setEmployeeForm] = useState({ - id: '', + id: 0, name: '', - kandang_ids: [] as string[], + kandang_ids: [] as number[], status: 'Active' as 'Active' | 'Non Active', }); - const fetchEmployees = async () => { - if (!isSupabaseConfigured()) { - console.warn( - 'Supabase not configured. Please add environment variables.' - ); - setInitialLoading(false); - return; - } - - try { - const { data, error } = await supabase - .from('employees') - .select( - ` - id, - name, - kandang_id, - is_active, - kandang:kandang_id ( - id, - name - ) - ` - ) - .order('name', { ascending: true }); - - if (error) { - console.error('Error fetching employees:', error); - toast.error('Gagal memuat data ABK'); - return; - } - - setEmployees((data as unknown as Employee[]) || []); - } catch (error) { - console.error('Error fetching employees:', error); - toast.error('Gagal memuat data ABK'); - } finally { - setInitialLoading(false); - } - }; - - const fetchKandang = async () => { - if (!isSupabaseConfigured()) { - return; - } - - try { - const { data, error } = await supabase - .from('kandang') - .select('id, name') - .order('name', { ascending: true }); - - if (error) { - console.error('Error fetching kandang:', error); - return; - } - - setKandangList(data || []); - } catch (error) { - console.error('Error fetching kandang:', error); - } - }; - - useEffect(() => { - fetchEmployees(); - fetchKandang(); - }, []); + const employeeColumns: ColumnDef[] = [ + { + id: 'name', + header: 'Nama ABK', + accessorKey: 'name', + enableSorting: false, + }, + { + id: 'kandang', + header: 'Kandang', + accessorKey: 'kandangs', + enableSorting: false, + cell: ({ row }) => + row.original.kandangs.map((kandang) => kandang.name).join(', '), + }, + { + id: 'status', + header: 'Status', + accessorKey: 'is_active', + enableSorting: false, + cell: ({ row }) => ( + + {row.original.is_active ? 'Active' : 'Non Active'} + + ), + }, + { + 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'); - setEmployeeForm({ id: '', name: '', kandang_ids: [], status: 'Active' }); + setEmployeeForm({ id: 0, name: '', kandang_ids: [], status: 'Active' }); setShowModal(true); }; @@ -174,7 +182,7 @@ export function MasterEmployeeContent() { setEmployeeForm({ id: employee.id, name: employee.name, - kandang_ids: employee.kandang_id ? [employee.kandang_id] : [], + kandang_ids: employee.kandangs ? employee.kandangs.map((k) => k.id) : [], status: employee.is_active ? 'Active' : 'Non Active', }); setShowModal(true); @@ -186,58 +194,52 @@ export function MasterEmployeeContent() { return; } - if (!isSupabaseConfigured()) { - toast.error( - 'Supabase belum dikonfigurasi. Tambahkan environment variables.' - ); - return; - } - setLoading(true); try { - // Create payload - taking the first selected kandang for now as schema supports single FK - // TODO: Support multiple kandangs in backend - const kandangIdToSave = employeeForm.kandang_ids[0]; - if (modalMode === 'create') { - const { error } = await supabase.from('employees').insert([ - { - name: employeeForm.name.trim(), - kandang_id: kandangIdToSave, - is_active: employeeForm.status === 'Active', - }, - ]); + const createEmployeeResponse = await EmployeeApi.create({ + is_active: employeeForm.status === 'Active', + kandang_ids: employeeForm.kandang_ids, + name: employeeForm.name.trim(), + }); - if (error) { - console.error('Error creating employee:', error); + if (isResponseError(createEmployeeResponse)) { + console.error( + 'Error creating employee:', + createEmployeeResponse.message + ); toast.error('Gagal menambahkan ABK'); return; } + refreshEmployees(); toast.success('ABK berhasil ditambahkan'); } else { - const { error } = await supabase - .from('employees') - .update({ - name: employeeForm.name.trim(), - kandang_id: kandangIdToSave, + const updateEmployeeResponse = await EmployeeApi.update( + employeeForm.id, + { is_active: employeeForm.status === 'Active', - }) - .eq('id', employeeForm.id); + kandang_ids: employeeForm.kandang_ids, + name: employeeForm.name.trim(), + } + ); - if (error) { - console.error('Error updating employee:', error); - toast.error('Gagal mengubah ABK'); + if (isResponseError(updateEmployeeResponse)) { + console.error( + 'Error updating employee:', + updateEmployeeResponse.message + ); + toast.error('Gagal menambahkan ABK'); return; } + refreshEmployees(); toast.success('ABK berhasil diubah'); } setShowModal(false); - setEmployeeForm({ id: '', name: '', kandang_ids: [], status: 'Active' }); - await fetchEmployees(); + setEmployeeForm({ id: 0, name: '', kandang_ids: [], status: 'Active' }); } catch (error) { console.error('Error saving employee:', error); toast.error('Terjadi kesalahan saat menyimpan ABK'); @@ -246,7 +248,7 @@ export function MasterEmployeeContent() { } }; - const handleDeleteClick = (employeeId: string) => { + const handleDeleteClick = (employeeId: number) => { setEmployeeToDelete(employeeId); setShowDeleteConfirm(true); }; @@ -257,21 +259,22 @@ export function MasterEmployeeContent() { setLoading(true); try { - const { error } = await supabase - .from('employees') - .delete() - .eq('id', employeeToDelete); + const deleteEmployeeResponse = await EmployeeApi.delete(employeeToDelete); - if (error) { - console.error('Error deleting employee:', error); + if (isResponseError(deleteEmployeeResponse)) { + console.error( + 'Error deleting employee:', + deleteEmployeeResponse.message + ); toast.error('Gagal menghapus ABK'); return; } + refreshEmployees(); toast.success('ABK berhasil dihapus'); setShowDeleteConfirm(false); setEmployeeToDelete(null); - await fetchEmployees(); + // await fetchEmployees(); } catch (error) { console.error('Error deleting employee:', error); toast.error('Terjadi kesalahan saat menghapus ABK'); @@ -284,22 +287,7 @@ export function MasterEmployeeContent() { toast.success(`Data berhasil diekspor ke ${format}`); }; - const filteredEmployees = employees.filter((emp) => { - const kandangName = emp.kandang?.name || ''; - const matchesSearch = - emp.name.toLowerCase().includes(searchQuery.toLowerCase()) || - kandangName.toLowerCase().includes(searchQuery.toLowerCase()); - - const matchesKandang = - kandangFilter === 'all' || emp.kandang_id === kandangFilter; - - const matchesStatus = - statusFilter === 'all' || emp.is_active === (statusFilter === 'active'); - - return matchesSearch && matchesKandang && matchesStatus; - }); - - if (initialLoading) { + if (isLoadingEmployees && !employees) { return (
@@ -339,48 +327,75 @@ export function MasterEmployeeContent() { {/* Single Toolbar Row */} -
+
{/* LEFT: Search + Filters */} -
+
- setSearchQuery(e.target.value)} + value={tableFilterState.search} + onChange={(e) => updateFilter('search', e.target.value)} className='pl-10 w-[280px] border-gray-200' + /> */} + updateFilter('search', e.target.value)} + className={{ + wrapper: 'w-[280px] border-gray-200', + inputWrapper: 'px-3 py-2 h-fit rounded-md', + input: 'text-sm', + }} + startAdornment={ + + } />
- + updateFilter('kandang_id', value === 'all' ? '' : value) + } + > Semua Kandang - {kandangList.map((kandang) => ( - - {kandang.name} + {kandangOptions.map((kandang) => ( + + {kandang.label} ))} - { + updateFilter('status', value === 'all' ? '' : value); + }} + > Semua Status - Active - Non Active + Active + Non Active
{/* RIGHT: Export + Add */} -
+
@@ -538,19 +493,17 @@ export function MasterEmployeeContent() { Kandang * ({ - value: k.id, - label: k.name, + options={kandangOptions.map((k) => ({ + value: String(k.value), + label: k.label, }))} - selected={employeeForm.kandang_ids} + selected={employeeForm.kandang_ids.map((id) => String(id))} onChange={(selected) => - setEmployeeForm({ ...employeeForm, kandang_ids: selected }) + setEmployeeForm({ + ...employeeForm, + kandang_ids: selected.map((id) => Number(id)), + }) } - // onSearchChange={(val) => - // console.log({ - // test: val, - // }) - // } placeholder='Pilih kandang' className='mt-1.5' />