diff --git a/src/app/flock/recording/detail/edit/page.tsx b/src/app/flock/recording/detail/edit/page.tsx index e69de29b..0718731c 100644 --- a/src/app/flock/recording/detail/edit/page.tsx +++ b/src/app/flock/recording/detail/edit/page.tsx @@ -0,0 +1,47 @@ +'use client'; + +import { useRouter, useSearchParams } from 'next/navigation'; +import useSWR from 'swr'; +import RecordingForm from '@/components/pages/flock/recording/form/RecordingForm'; +import { RecordingApi } from '@/services/api/flock'; // Import RecordingApi +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; + +const RecordingEdit = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + const recordingId = searchParams.get('recordingId'); + + const { data: recording, isLoading: isLoadingRecording } = useSWR( + recordingId, + (id: number) => RecordingApi.getSingle(id) // Gunakan RecordingApi + ); + + if (!recordingId) { + router.back(); + + return ( +
+ +
+ ); + } + + if (!isLoadingRecording && (!recording || isResponseError(recording))) { + router.replace('/404'); + return; + } + + return ( +
+ {isLoadingRecording && ( + + )} + {!isLoadingRecording && isResponseSuccess(recording) && ( + + )} +
+ ); +}; + +export default RecordingEdit; diff --git a/src/app/flock/recording/detail/page.tsx b/src/app/flock/recording/detail/page.tsx index e69de29b..a25fe998 100644 --- a/src/app/flock/recording/detail/page.tsx +++ b/src/app/flock/recording/detail/page.tsx @@ -0,0 +1,47 @@ +'use client'; + +import { useRouter, useSearchParams } from 'next/navigation'; +import useSWR from 'swr'; +import RecordingForm from '@/components/pages/flock/recording/form/RecordingForm'; +import { RecordingApi } from '@/services/api/flock'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; + +const RecordingDetail = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + const recordingId = searchParams.get('recordingId'); + + const { data: recording, isLoading: isLoadingRecording } = useSWR( + recordingId, + (id: number) => RecordingApi.getSingle(id) + ); + + if (!recordingId) { + router.back(); + + return ( +
+ +
+ ); + } + + if (!isLoadingRecording && (!recording || isResponseError(recording))) { + router.replace('/404'); + return; + } + + return ( +
+ {isLoadingRecording && ( + + )} + {!isLoadingRecording && isResponseSuccess(recording) && ( + + )} +
+ ); +}; + +export default RecordingDetail; diff --git a/src/app/flock/recording/page.tsx b/src/app/flock/recording/page.tsx index 01154025..06f42789 100644 --- a/src/app/flock/recording/page.tsx +++ b/src/app/flock/recording/page.tsx @@ -1,9 +1,11 @@ -import Link from 'next/link'; +import RecordingTable from '@/components/pages/flock/recording/RecordingTable'; -export default function Page() { +const Recording = () => { return ( - <> - Recording - +
+ +
); -} +}; + +export default Recording; diff --git a/src/components/pages/flock/recording/RecordingTable.tsx b/src/components/pages/flock/recording/RecordingTable.tsx index e69de29b..ea7967a8 100644 --- a/src/components/pages/flock/recording/RecordingTable.tsx +++ b/src/components/pages/flock/recording/RecordingTable.tsx @@ -0,0 +1,358 @@ +'use client'; + +import { useCallback, useMemo, useState } from 'react'; +import { Icon } from '@iconify/react'; +import { SortingState } from '@tanstack/react-table'; +import { cn } from '@/lib/helper'; +import { useModal } from '@/components/Modal'; +import Button from '@/components/Button'; +import ConfirmationModal from '@/components/modal/ConfirmationModal'; +import { OptionType } from '@/components/input/SelectInput'; +import { ROWS_OPTIONS } from '@/config/constant'; +import { TableToolbar } from '@/components/table/TableToolbar'; +import { TableRowSizeSelector } from '@/components/table/TableRowSizeSelector'; +import Table from '@/components/Table'; +import RowDropdownOptions from '@/components/table/RowDropdownOptions'; +import RowCollapseOptions from '@/components/table/RowCollapseOptions'; +import { type CellContext } from '@tanstack/react-table'; +import { type Recording } from '@/types/api/flock/recording'; + +const dummyRecordings: Recording[] = [ + { + id: 1, + flock: { + id: 1, + name: 'Flock A', + created_at: '2024-01-01', + updated_at: '2024-01-01', + created_user: { + id: 1, + id_user: 1, + email: 'admin@example.com', + name: 'Admin', + }, + }, + recording_date: '2024-01-01', + location: { + id: 1, + name: 'Location 1', + address: 'Jl. Contoh No. 1', + area: { + id: 1, + name: 'Area 1', + }, + created_at: '2024-01-01', + updated_at: '2024-01-01', + created_user: { + id: 1, + id_user: 1, + email: 'admin@example.com', + name: 'Admin', + }, + }, + coop: { + id: 1, + name: 'Coop 1', + location: { + id: 1, + name: 'Location 1', + address: 'Jl. Contoh No. 1', + area: { + id: 1, + name: 'Area 1', + }, + }, + pic: { + id: 1, + id_user: 1, + email: 'pic@example.com', + name: 'PIC User', + }, + created_at: '2024-01-01', + updated_at: '2024-01-01', + created_user: { + id: 1, + id_user: 1, + email: 'admin@example.com', + name: 'Admin', + }, + }, + feed_data: [ + { + feed_name: 'Feed 1', + feed_qty: 100, + feed_stock: 500, + }, + ], + body_weight: [ + { + chicken_weight: 2.5, + chicken_count: 1000, + average_chicken_weight: 2.5, + }, + ], + vaccination: [ + { + vaccine_name: 'Vaccine 1', + total_stock: 200, + used_stock: 150, + }, + ], + mortality: [ + { + condition: 'NORMAL', + count: 5, + }, + ], + created_at: '2024-01-01', + updated_at: '2024-01-01', + created_user: { + id: 1, + id_user: 1, + email: 'admin@example.com', + name: 'Admin', + }, + }, +]; + +const RowOptionsMenu = ({ + type = 'dropdown', + props, + deleteClickHandler, +}: { + type: 'dropdown' | 'collapse'; + props: CellContext; + deleteClickHandler: () => void; +}) => { + return ( +
+ + + +
+ ); +}; + +const RecordingTable = () => { + const [search, setSearch] = useState(''); + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [sorting, setSorting] = useState([]); + const [, setSelectedRecording] = useState(undefined); + const [isDeleteLoading, setIsDeleteLoading] = useState(false); + + const deleteModal = useModal(); + + const searchChangeHandler = useCallback( + (e: React.ChangeEvent) => { + setSearch(e.target.value); + setPage(1); + }, + [] + ); + + const pageSizeChangeHandler = useCallback( + (val: OptionType | OptionType[] | null) => { + const newVal = val as OptionType; + setPageSize(newVal.value as number); + setPage(1); + }, + [] + ); + + const confirmationModalDeleteClickHandler = async () => { + setIsDeleteLoading(true); + setTimeout(() => { + setIsDeleteLoading(false); + deleteModal.closeModal(); + }, 1000); + }; + + const paginatedData = useMemo(() => { + const filteredData = dummyRecordings.filter( + (recording) => + recording.flock.name.toLowerCase().includes(search.toLowerCase()) || + recording.location.name.toLowerCase().includes(search.toLowerCase()) || + recording.coop.name.toLowerCase().includes(search.toLowerCase()) + ); + const start = (page - 1) * pageSize; + return filteredData.slice(start, start + pageSize); + }, [page, pageSize, search]); + + return ( +
+
+ + +
+ + pageSize * (page - 1) + props.row.index + 1, + }, + { + accessorKey: 'flock.name', + header: 'Flock', + }, + { + accessorKey: 'recording_date', + header: 'Tanggal Recording', + cell: (props) => + new Date(props.row.original.recording_date).toLocaleDateString(), + }, + { + accessorKey: 'location.name', + header: 'Lokasi', + }, + { + accessorKey: 'coop.name', + header: 'Kandang', + }, + { + accessorKey: 'mortality', + header: 'Total Mortality', + cell: (props) => + props.row.original.mortality.reduce( + (acc, curr) => acc + curr.count, + 0 + ), + }, + { + header: 'Aksi', + cell: (props: CellContext) => { + const currentPageSize = + props.table.getPaginationRowModel().rows.length; + const currentPageRows = + props.table.getPaginationRowModel().flatRows; + const currentRowRelativeIndex = + currentPageRows.findIndex((r) => r.id === props.row.id) + 1; + + const isLast2Rows = currentRowRelativeIndex > currentPageSize - 2; + + const deleteClickHandler = () => { + setSelectedRecording(props.row.original); + deleteModal.openModal(); + }; + + return ( + <> + {currentPageSize > 2 && ( + + + + )} + + {currentPageSize <= 2 && ( + + + + )} + + ); + }, + }, + ]} + pageSize={pageSize} + page={page} + totalItems={dummyRecordings.length} + onPageChange={setPage} + isLoading={false} + sorting={sorting} + setSorting={setSorting} + className={{ + containerClassName: cn({ + 'mb-20': paginatedData.length === 0, + }), + tableWrapperClassName: 'overflow-x-auto min-h-full!', + tableClassName: 'font-inter w-full table-auto min-h-full!', + headerRowClassName: 'border-b border-b-gray-200', + headerColumnClassName: + 'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end', + bodyRowClassName: 'border-b border-b-gray-200', + bodyColumnClassName: + 'px-6 py-3 last:flex last:flex-row last:justify-end', + }} + /> + + + + ); +}; + +export default RecordingTable; diff --git a/src/config/constant.ts b/src/config/constant.ts index 87dcd927..668d7209 100644 --- a/src/config/constant.ts +++ b/src/config/constant.ts @@ -203,5 +203,4 @@ export const RECORDING_FLAG_OPTIONS = [ { label: 'Ayam Afkir', value: 'Ayam Afkir' }, { label: 'Ayam Culling', value: 'Ayam Culling' }, { label: 'Ayam Mati', value: 'Ayam Mati' }, - { label: 'DOC', value: 'DOC' }, ];