diff --git a/.husky/pre-commit b/.husky/pre-commit
index 66ff6a67..e7bb3165 100644
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,2 +1,3 @@
+npm run format
npm run lint
npm run build
diff --git a/package-lock.json b/package-lock.json
index 33b7c640..2cac4bc7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,6 +17,7 @@
"moment": "^2.30.1",
"next": "15.5.3",
"react": "19.1.0",
+ "react-day-picker": "^9.11.1",
"react-dom": "19.1.0",
"react-hot-toast": "^2.6.0",
"react-number-format": "^5.4.4",
@@ -196,6 +197,12 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@date-fns/tz": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz",
+ "integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==",
+ "license": "MIT"
+ },
"node_modules/@emnapi/core": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.6.0.tgz",
@@ -2873,6 +2880,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/date-fns": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
+ "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/kossnocorp"
+ }
+ },
+ "node_modules/date-fns-jalali": {
+ "version": "4.1.0-0",
+ "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz",
+ "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==",
+ "license": "MIT"
+ },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -5749,6 +5772,27 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-day-picker": {
+ "version": "9.11.1",
+ "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.11.1.tgz",
+ "integrity": "sha512-l3ub6o8NlchqIjPKrRFUCkTUEq6KwemQlfv3XZzzwpUeGwmDJ+0u0Upmt38hJyd7D/vn2dQoOoLV/qAp0o3uUw==",
+ "license": "MIT",
+ "dependencies": {
+ "@date-fns/tz": "^1.4.1",
+ "date-fns": "^4.1.0",
+ "date-fns-jalali": "^4.1.0-0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/sponsors/gpbl"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
"node_modules/react-dom": {
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
diff --git a/package.json b/package.json
index 10fe9598..033c2963 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"moment": "^2.30.1",
"next": "15.5.3",
"react": "19.1.0",
+ "react-day-picker": "^9.11.1",
"react-dom": "19.1.0",
"react-hot-toast": "^2.6.0",
"react-number-format": "^5.4.4",
diff --git a/src/app/production/transfer-to-laying/detail/edit/page.tsx b/src/app/production/transfer-to-laying/detail/edit/page.tsx
index 9003dbba..d5498e08 100644
--- a/src/app/production/transfer-to-laying/detail/edit/page.tsx
+++ b/src/app/production/transfer-to-laying/detail/edit/page.tsx
@@ -8,91 +8,6 @@ import TransferToLayingForm from '@/components/pages/production/transfer-to-layi
import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
-import { TransferToLaying } from '@/types/api/production/transfer-to-laying';
-
-// TODO: delete dummy data
-const DUMMY_TRANSFER_TO_LAYING_EDIT: TransferToLaying = {
- id: 1,
- transfer_date: '2025-10-14',
- flock_source: {
- id: 1,
- name: 'Flock asal test',
- },
- flock_destination: {
- id: 2,
- name: 'Flock tujuan destination',
- },
- quantity: 10,
- kandangs: [
- {
- kandang: {
- id: 1,
- name: 'Kandang test',
- status: 'ACTIVE',
- location: {
- id: 1,
- name: 'test location',
- address: 'test address 1',
- area: { id: 1, name: 'test area 1' },
- },
- pic: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_user: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_at: '14-10-2025',
- updated_at: '14-10-2025',
- },
- quantity: 8,
- },
- {
- kandang: {
- id: 1,
- name: 'Kandang test 2',
- status: 'ACTIVE',
- location: {
- id: 1,
- name: 'test location',
- address: 'test address 1',
- area: { id: 1, name: 'test area 1' },
- },
- pic: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_user: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_at: '14-10-2025',
- updated_at: '14-10-2025',
- },
- quantity: 2,
- },
- ],
- reason: 'Test alasan',
-
- created_user: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_at: '14-10-2025',
- updated_at: '14-10-2025',
-};
-
const TransferToLayingEdit = () => {
const router = useRouter();
const searchParams = useSearchParams();
@@ -114,33 +29,33 @@ const TransferToLayingEdit = () => {
);
}
- // TODO: remove dummy data and integrate with real API
if (
!isLoadingTransferToLaying &&
- (!transferToLaying ||
- (isResponseError(transferToLaying) && !DUMMY_TRANSFER_TO_LAYING_EDIT))
+ (!transferToLaying || isResponseError(transferToLaying))
) {
router.replace('/404');
return;
}
+ if (
+ isResponseSuccess(transferToLaying) &&
+ transferToLaying.data.approval.step_number === 2
+ ) {
+ router.replace('/production/transfer-to-laying');
+ return;
+ }
+
return (
{isLoadingTransferToLaying && (
)}
- {/* {!isLoadingTransferToLaying && isResponseSuccess(transferToLaying) && (
+ {!isLoadingTransferToLaying && isResponseSuccess(transferToLaying) && (
- )} */}
-
- {/* TODO: remove this dummy data and integrate to real API */}
-
+ )}
);
};
diff --git a/src/app/production/transfer-to-laying/detail/page.tsx b/src/app/production/transfer-to-laying/detail/page.tsx
index de5426c8..9ff6ed5e 100644
--- a/src/app/production/transfer-to-laying/detail/page.tsx
+++ b/src/app/production/transfer-to-laying/detail/page.tsx
@@ -8,91 +8,6 @@ import TransferToLayingForm from '@/components/pages/production/transfer-to-layi
import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
-import { TransferToLaying } from '@/types/api/production/transfer-to-laying';
-
-// TODO: delete dummy data
-const DUMMY_TRANSFER_TO_LAYING_DETAIL: TransferToLaying = {
- id: 1,
- transfer_date: '2025-10-14',
- flock_source: {
- id: 1,
- name: 'Flock asal test',
- },
- flock_destination: {
- id: 2,
- name: 'Flock tujuan destination',
- },
- quantity: 10,
- kandangs: [
- {
- kandang: {
- id: 1,
- name: 'Kandang test',
- status: 'ACTIVE',
- location: {
- id: 1,
- name: 'test location',
- address: 'test address 1',
- area: { id: 1, name: 'test area 1' },
- },
- pic: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_user: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_at: '14-10-2025',
- updated_at: '14-10-2025',
- },
- quantity: 8,
- },
- {
- kandang: {
- id: 1,
- name: 'Kandang test 2',
- status: 'ACTIVE',
- location: {
- id: 1,
- name: 'test location',
- address: 'test address 1',
- area: { id: 1, name: 'test area 1' },
- },
- pic: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_user: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_at: '14-10-2025',
- updated_at: '14-10-2025',
- },
- quantity: 2,
- },
- ],
- reason: 'Test alasan',
-
- created_user: {
- id: 1,
- id_user: 2,
- email: 'test@gmail.com',
- name: 'test',
- },
- created_at: '14-10-2025',
- updated_at: '14-10-2025',
-};
-
const TransferToLayingDetail = () => {
const router = useRouter();
const searchParams = useSearchParams();
@@ -114,11 +29,9 @@ const TransferToLayingDetail = () => {
);
}
- // TODO: remove dummy data and integrate with real API
if (
!isLoadingTransferToLaying &&
- (!transferToLaying ||
- (isResponseError(transferToLaying) && !DUMMY_TRANSFER_TO_LAYING_DETAIL))
+ (!transferToLaying || isResponseError(transferToLaying))
) {
router.replace('/404');
return;
@@ -129,18 +42,13 @@ const TransferToLayingDetail = () => {
{isLoadingTransferToLaying && (
)}
- {/* {!isLoadingTransferToLaying && isResponseSuccess(transferToLaying) && (
+
+ {!isLoadingTransferToLaying && isResponseSuccess(transferToLaying) && (
- )} */}
-
- {/* TODO: remove this dummy data and integrate to real API */}
-
+ )}
);
};
diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx
index a84c1827..a242b1e4 100644
--- a/src/components/Modal.tsx
+++ b/src/components/Modal.tsx
@@ -1,6 +1,13 @@
'use client';
-import { ReactNode, RefObject, useCallback, useRef, useState } from 'react';
+import {
+ ReactNode,
+ RefObject,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react';
import { cn } from '@/lib/helper';
export const useModal = () => {
@@ -8,31 +15,34 @@ export const useModal = () => {
const [open, setOpen] = useState(false);
const openModal = useCallback(() => {
+ if (!ref.current) return;
+ ref.current.show();
setOpen(true);
-
- ref.current?.showModal();
}, []);
const closeModal = useCallback(() => {
+ if (!ref.current) return;
+ ref.current.close();
setOpen(false);
- ref.current?.close();
}, []);
const toggle = useCallback(() => {
- if (open) {
- closeModal();
- } else {
- openModal();
- }
+ open ? closeModal() : openModal();
}, [open, closeModal, openModal]);
- if (ref.current) {
- ref.current.addEventListener('close', () => {
- closeModal();
- });
- }
+ useEffect(() => {
+ const dialog = ref.current;
+ if (!dialog) return;
- return { ref, open, setOpen, openModal, closeModal, toggle } as const;
+ const handleClose = () => setOpen(false);
+ dialog.addEventListener('close', handleClose);
+
+ return () => {
+ dialog.removeEventListener('close', handleClose);
+ };
+ }, []);
+
+ return { ref, open, openModal, closeModal, toggle } as const;
};
interface ModalProps {
@@ -46,15 +56,19 @@ interface ModalProps {
}
const Modal = ({ ref, children, closeOnBackdrop, className }: ModalProps) => {
- return (
-