diff --git a/package.json b/package.json index edd750f6..34c07ec3 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "start": "next start", "lint": "eslint", "prepare": "husky", - "format": "prettier --write ." + "format": "prettier --write .", + "pre-commit": "npm run format && npm run lint && npx tsc --noEmit && npm run build" }, "dependencies": { "@react-pdf/renderer": "^4.3.1", diff --git a/src/app/daily-checklist/master-data/kandang/page.tsx b/src/app/daily-checklist/master-data/kandang/page.tsx new file mode 100644 index 00000000..dd2b3142 --- /dev/null +++ b/src/app/daily-checklist/master-data/kandang/page.tsx @@ -0,0 +1,11 @@ +import { MasterKandangContent } from '@/figma-make/components/pages/master-data/kandang/MasterKandangContent'; + +const MasterKandangPage = () => { + return ( +
+ +
+ ); +}; + +export default MasterKandangPage; diff --git a/src/components/pages/master-data/kandang/KandangsTable.tsx b/src/components/pages/master-data/kandang/KandangsTable.tsx index 9d923cbe..698d3a96 100644 --- a/src/components/pages/master-data/kandang/KandangsTable.tsx +++ b/src/components/pages/master-data/kandang/KandangsTable.tsx @@ -314,6 +314,10 @@ const KandangsTable = () => { accessorFn: (row) => row.pic?.name ?? '-', header: 'PIC', }, + { + accessorFn: (row) => row.kandang_group?.name ?? '-', + header: 'Kandang Group', + }, { header: 'Aksi', cell: (props: CellContext) => { diff --git a/src/components/pages/master-data/kandang/form/KandangForm.schema.ts b/src/components/pages/master-data/kandang/form/KandangForm.schema.ts index 3da93aef..39f9a632 100644 --- a/src/components/pages/master-data/kandang/form/KandangForm.schema.ts +++ b/src/components/pages/master-data/kandang/form/KandangForm.schema.ts @@ -1,3 +1,4 @@ +import { OptionType } from '@/components/input/SelectInput'; import * as Yup from 'yup'; type KandangFormSchemaType = { @@ -19,6 +20,7 @@ type KandangFormSchemaType = { } | undefined | null; + group?: OptionType; }; export const KandangFormSchema: Yup.ObjectSchema = @@ -42,6 +44,11 @@ export const KandangFormSchema: Yup.ObjectSchema = value: Yup.number().min(1).required(), label: Yup.string().required(), }).nullable(), + + group: Yup.object({ + value: Yup.number().min(1).required('Kandang Grup wajib diisi!'), + label: Yup.string().required('Kandang Grup wajib diisi!'), + }).required('Kandang Grup wajib diisi!'), }); export const UpdateKandangFormSchema = KandangFormSchema; diff --git a/src/components/pages/master-data/kandang/form/KandangForm.tsx b/src/components/pages/master-data/kandang/form/KandangForm.tsx index 87ddfd70..9f2d0e88 100644 --- a/src/components/pages/master-data/kandang/form/KandangForm.tsx +++ b/src/components/pages/master-data/kandang/form/KandangForm.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useRouter } from 'next/navigation'; -import { useFormik } from 'formik'; +import { getIn, useFormik } from 'formik'; import { toast } from 'react-hot-toast'; import { Icon } from '@iconify/react'; @@ -34,6 +34,8 @@ import NumberInput from '@/components/input/NumberInput'; import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; import AlertErrorList from '@/components/helper/form/FormErrors'; import { User } from '@/types/api/api-general'; +import { DailyChecklistKandang } from '@/types/api/daily-checklist/kandang'; +import { DailyChecklistKandangApi } from '@/services/api/daily-checklist/kandang'; interface KandangFormProps { type?: 'add' | 'edit' | 'detail'; @@ -96,6 +98,12 @@ const KandangForm = ({ type = 'add', initialValues }: KandangFormProps) => { label: initialValues.pic.name, } : null, + group: initialValues?.kandang_group + ? { + value: initialValues.kandang_group.id, + label: initialValues.kandang_group.name, + } + : undefined, }; }, [initialValues]); @@ -111,6 +119,7 @@ const KandangForm = ({ type = 'add', initialValues }: KandangFormProps) => { location_id: values.locationId!, capacity: values.capacity ? parseInt(values.capacity.toString()) : 0, pic_id: values.picId!, + group_id: values.group?.value as number, }; switch (type) { @@ -162,6 +171,23 @@ const KandangForm = ({ type = 'add', initialValues }: KandangFormProps) => { formik.setFieldValue('picId', (val as OptionType)?.value); }; + // Kandang Group + const { + setInputValue: setKandangGroupSelectInputValue, + options: kandangGroupOptions, + isLoadingOptions: isLoadingKandangGroupOptions, + loadMore: loadMoreKandangGroups, + } = useSelect( + DailyChecklistKandangApi.basePath, + 'id', + 'name' + ); + + const kandangGroupChangeHandler = (val: OptionType | OptionType[] | null) => { + formik.setFieldTouched('group', true); + formik.setFieldValue('group', val); + }; + const deleteKandangClickHandler = () => { deleteModal.openModal(); }; @@ -269,6 +295,24 @@ const KandangForm = ({ type = 'add', initialValues }: KandangFormProps) => { isDisabled={type === 'detail'} isClearable /> + +
diff --git a/src/config/constant.ts b/src/config/constant.ts index 99c5ff9d..ca0682b4 100644 --- a/src/config/constant.ts +++ b/src/config/constant.ts @@ -20,6 +20,7 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ 'lti.daily_checklist.master_data.employee', 'lti.daily_checklist.master_data.activity', 'lti.daily_checklist.master_data.configuration', + 'lti.daily_checklist.master_data.kandang', ], submenu: [ { @@ -66,6 +67,11 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ link: '/daily-checklist/master-data/activity', permission: ['lti.daily_checklist.master_data.activity'], }, + { + text: 'Kandang', + link: '/daily-checklist/master-data/kandang', + permission: ['lti.daily_checklist.master_data.kandang'], + }, { text: 'Konfigurasi', link: '/daily-checklist/master-data/configuration', diff --git a/src/config/route-permission.ts b/src/config/route-permission.ts index dc638b29..8c65a611 100644 --- a/src/config/route-permission.ts +++ b/src/config/route-permission.ts @@ -21,6 +21,9 @@ export const ROUTE_PERMISSIONS: Record = { '/daily-checklist/master-data/configuration/': [ 'lti.daily_checklist.master_data.configuration', ], + '/daily-checklist/master-data/kandang/': [ + 'lti.daily_checklist.master_data.kandang', + ], // Production // Production - Project Flock diff --git a/src/figma-make/components/base/multi-select.tsx b/src/figma-make/components/base/multi-select.tsx index 63ebdd36..656073c6 100644 --- a/src/figma-make/components/base/multi-select.tsx +++ b/src/figma-make/components/base/multi-select.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; -import { Check, ChevronsUpDown, X } from 'lucide-react'; +import { Check, ChevronsUpDown, X, Loader2 } from 'lucide-react'; import { cn } from '@/lib/helper'; import { Button } from '@/figma-make/components/base/button'; import { @@ -29,6 +29,8 @@ interface MultiSelectProps { selected: string[]; onChange: (selected: string[]) => void; onSearchChange?: (value: string) => void; + onLoadMore?: () => void; + isLoadingMore?: boolean; placeholder?: string; className?: string; disabled?: boolean; @@ -39,6 +41,8 @@ export function MultiSelect({ selected, onChange, onSearchChange, + onLoadMore, + isLoadingMore, placeholder = 'Select items...', className, disabled, @@ -115,7 +119,18 @@ export function MultiSelect({ onValueChange={onSearchChange} /> No item found. - + { + const target = e.currentTarget; + if ( + target.scrollHeight - target.scrollTop <= + target.clientHeight + 1 + ) { + onLoadMore?.(); + } + }} + > {options.map((option) => ( ))} + {isLoadingMore && ( +
+ +
+ )}
diff --git a/src/figma-make/components/base/select.tsx b/src/figma-make/components/base/select.tsx index 625cf3d7..16725c04 100644 --- a/src/figma-make/components/base/select.tsx +++ b/src/figma-make/components/base/select.tsx @@ -55,7 +55,11 @@ function SelectContent({ children, position = 'popper', ...props -}: React.ComponentProps) { +}: React.ComponentProps & { + onScroll?: React.UIEventHandler; +}) { + const { onScroll, ...restProps } = props; + return ( {children} diff --git a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx index 601025ad..1a9b4406 100644 --- a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx +++ b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx @@ -2,7 +2,16 @@ import * as React from 'react'; import { useState, useEffect } from 'react'; -import { Plus, X, Save, Send, Info, FilePlus, ListChecks } from 'lucide-react'; +import { + Plus, + X, + Save, + Send, + Info, + FilePlus, + ListChecks, + Loader2, +} 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'; @@ -26,7 +35,6 @@ import { import { DatePicker } from '@/figma-make/components/base/date-picker'; import { toast } from 'sonner'; import { useSelect } from '@/components/input/SelectInput'; -import { KandangApi } from '@/services/api/master-data'; import { DailyChecklistApi } from '@/services/api/daily-checklist/daily-checklist'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import useSWR from 'swr'; @@ -43,6 +51,7 @@ import DropFileInput from '@/components/input/DropFileInput'; import Link from 'next/link'; import { useRouter, useSearchParams, usePathname } from 'next/navigation'; import { Icon } from '@iconify/react'; +import { DailyChecklistKandangApi } from '@/services/api/daily-checklist/kandang'; // Static categories const CATEGORIES = [ @@ -86,16 +95,11 @@ export function DailyChecklistContent() { searchParams.get('category') || '' ); - const { options: kandangOptions } = useSelect( - KandangApi.basePath, - 'id', - 'name', - 'search', - { - page: '1', - limit: '100', - } - ); + const { + options: kandangOptions, + isLoadingMore: isLoadingMoreKandang, + loadMore: loadMoreKandang, + } = useSelect(DailyChecklistKandangApi.basePath, 'id', 'name'); const { data: phases } = useSWR< BaseApiResponse, @@ -168,6 +172,16 @@ export function DailyChecklistContent() { const [documents, setDocuments] = useState([]); const [deletedDocumentIds, setDeletedDocumentIds] = useState([]); + const handleKandangScroll = (e: React.UIEvent) => { + const target = e.target as HTMLDivElement; + + if (target.scrollHeight - target.scrollTop <= target.clientHeight + 10) { + if (!isLoadingMoreKandang) { + loadMoreKandang(); + } + } + }; + // Sync state to URL query params useEffect(() => { const params = new URLSearchParams(searchParams.toString()); @@ -994,7 +1008,7 @@ export function DailyChecklistContent() { > - + {kandangOptions.map((kandang) => ( ))} + + {isLoadingMoreKandang && ( +
+ +
+ )}
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 6509a91d..e6127cf0 100644 --- a/src/figma-make/components/pages/list-daily-checklist/ListDailyChecklistContent.tsx +++ b/src/figma-make/components/pages/list-daily-checklist/ListDailyChecklistContent.tsx @@ -1,7 +1,15 @@ 'use client'; import { useState } from 'react'; -import { Eye, CheckCircle, XCircle, Search, Trash2, Edit } from 'lucide-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'; @@ -34,9 +42,9 @@ 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 { KandangApi } from '@/services/api/master-data'; 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' }, @@ -93,21 +101,25 @@ export function ListDailyChecklistContent() { } ); - const { options: kandangOptions } = useSelect( - KandangApi.basePath, - 'id', - 'name', - 'search', - { - page: '1', - limit: '100', - } - ); + 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); @@ -490,7 +502,7 @@ export function ListDailyChecklistContent() { > - + Semua Kandang {kandangOptions.map((kandang) => ( ))} + {isLoadingMoreKandang && ( +
+ +
+ )}
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..3d3ba1c2 --- /dev/null +++ b/src/figma-make/components/pages/master-data/kandang/MasterKandangContent.tsx @@ -0,0 +1,585 @@ +'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} + /> +
+
+ + +
+ +
+ + +
+
+ + + + +
+
+ + {/* Delete Confirmation */} + + + + Hapus Kandang? + + Data Kandang akan dihapus secara permanen. + + + + Batal + + {loading ? 'Menghapus...' : 'Hapus'} + + + + +
+ ); +} diff --git a/src/services/api/daily-checklist/kandang.ts b/src/services/api/daily-checklist/kandang.ts new file mode 100644 index 00000000..e92ccd50 --- /dev/null +++ b/src/services/api/daily-checklist/kandang.ts @@ -0,0 +1,20 @@ +import { BaseApiService } from '@/services/api/base'; +import { + DailyChecklistKandang, + CreateDailyChecklistKandangPayload, + UpdateDailyChecklistKandangPayload, +} from '@/types/api/daily-checklist/kandang'; + +export class DailyChecklistKandangApiService extends BaseApiService< + DailyChecklistKandang, + CreateDailyChecklistKandangPayload, + UpdateDailyChecklistKandangPayload +> { + constructor(basePath: string = '/master-data/kandang-groups') { + super(basePath); + } +} + +export const DailyChecklistKandangApi = new DailyChecklistKandangApiService( + '/master-data/kandang-groups' +); diff --git a/src/types/api/daily-checklist/kandang.d.ts b/src/types/api/daily-checklist/kandang.d.ts new file mode 100644 index 00000000..a67344b0 --- /dev/null +++ b/src/types/api/daily-checklist/kandang.d.ts @@ -0,0 +1,24 @@ +import { BaseMetadata } from '@/types/api/api-general'; +import { BaseKandang } from '@/types/api/master-data/kandang'; +import { BaseLocation } from '@/types/api/master-data/location'; +import { BaseUser } from '@/types/api/user'; + +export type BaseDailyChecklistKandang = { + id: number; + name: string; + location: BaseLocation; + recording_kandangs: Pick[]; + pic: BaseUser; +}; + +export type DailyChecklistKandang = BaseMetadata & BaseDailyChecklistKandang; + +export type CreateDailyChecklistKandangPayload = { + name: string; + location_id: number; + pic_id: number; + // recording_kandang_ids: number[]; +}; + +export type UpdateDailyChecklistKandangPayload = + CreateDailyChecklistKandangPayload; diff --git a/src/types/api/master-data/kandang.d.ts b/src/types/api/master-data/kandang.d.ts index eafa0334..032f67a4 100644 --- a/src/types/api/master-data/kandang.d.ts +++ b/src/types/api/master-data/kandang.d.ts @@ -1,6 +1,7 @@ import { BaseMetadata } from '@/types/api/api-general'; import { BaseLocation } from '@/types/api/master-data/location'; import { BaseUser } from '@/types/api/user'; +import { BaseDailyChecklistKandang } from '@/types/api/daily-checklist/kandang'; export type BaseKandang = { id: number; @@ -10,6 +11,7 @@ export type BaseKandang = { capacity: number; pic: BaseUser; project_flock_kandang_id?: number; + kandang_group: Pick; }; export type Kandang = BaseMetadata & BaseKandang; @@ -19,6 +21,7 @@ export type CreateKandangPayload = { location_id: number; capacity: number; pic_id: number; + group_id: number; }; export type UpdateKandangPayload = CreateKandangPayload;