diff --git a/src/components/helper/form/FormErrors.tsx b/src/components/helper/form/FormErrors.tsx
new file mode 100644
index 00000000..a351227f
--- /dev/null
+++ b/src/components/helper/form/FormErrors.tsx
@@ -0,0 +1,46 @@
+import Alert from '@/components/Alert';
+import Button from '@/components/Button';
+import { Icon } from '@iconify/react';
+
+/**
+ * Alert Unique Error List
+ * @param formErrorList - Array of error messages
+ * @param onClose - Function to close the alert
+ */
+const AlertErrorList = ({
+ formErrorList,
+ onClose,
+}: {
+ formErrorList: string[];
+ onClose: () => void;
+}) => {
+ return (
+
+
+
+
+
+ Terdapat {formErrorList.length} error pada form:
+
+
+
+
+
+ {formErrorList.map((error, index) => (
+ -
+ {error}
+
+ ))}
+
+
+ );
+};
+
+export default AlertErrorList;
diff --git a/src/components/pages/ApprovalSteps.tsx b/src/components/pages/ApprovalSteps.tsx
index 6ae7c13a..27d03da3 100644
--- a/src/components/pages/ApprovalSteps.tsx
+++ b/src/components/pages/ApprovalSteps.tsx
@@ -309,7 +309,7 @@ const useApprovalSteps = ({
moduleId: string;
params?: {
page?: number;
- limit: number;
+ limit: number | string;
search?: string;
group_step_number?: boolean;
};
diff --git a/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.tsx b/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.tsx
index f134369e..525b81bb 100644
--- a/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.tsx
+++ b/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.tsx
@@ -125,6 +125,7 @@ const InventoryAdjustmentForm = ({
const warehouseUrl = `${WarehouseApi.basePath}?${new URLSearchParams({
search: '',
+ limit: '100',
}).toString()}`;
const { data: warehouses, isLoading: isLoadingWarehouses } = useSWR(
warehouseUrl,
diff --git a/src/components/pages/production/chickin/form/ChickinForm.tsx b/src/components/pages/production/chickin/form/ChickinForm.tsx
index 8c613737..b5b1dc4d 100644
--- a/src/components/pages/production/chickin/form/ChickinForm.tsx
+++ b/src/components/pages/production/chickin/form/ChickinForm.tsx
@@ -18,6 +18,7 @@ import { Icon } from '@iconify/react';
import Badge from '@/components/Badge';
import { CHICKINS_APPROVAL_LINE } from '@/config/approval-line';
import RequirePermission from '@/components/helper/RequirePermission';
+import { BaseApproval } from '@/types/api/api-general';
const ChickinFormKandang = ({
formType = 'add',
initialValues,
@@ -33,11 +34,16 @@ const ChickinFormKandang = ({
approvals,
isLoading: approvalsLoading,
refresh: refreshApprovals,
+ rawDataApprovals,
} = useApprovalSteps({
latestApproval: initialValues?.chickin_approval,
approvalLines: CHICKINS_APPROVAL_LINE,
moduleName: 'CHICKINS',
moduleId: initialValues?.id.toString() ?? '',
+ params: {
+ limit: 'limit',
+ group_step_number: false,
+ },
});
const afterSubmitFormChickin = () => {
@@ -180,6 +186,7 @@ const ChickinFormKandang = ({
{openChickin && (
diff --git a/src/components/pages/production/chickin/form/tabs/ChickLogsView.tsx b/src/components/pages/production/chickin/form/tabs/ChickLogsView.tsx
index 80846565..e800ee68 100644
--- a/src/components/pages/production/chickin/form/tabs/ChickLogsView.tsx
+++ b/src/components/pages/production/chickin/form/tabs/ChickLogsView.tsx
@@ -8,6 +8,7 @@ import PillBadge from '@/components/PillBadge';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { formatDate, formatNumber } from '@/lib/helper';
import { ChickinApi } from '@/services/api/production/chickin';
+import { BaseApproval } from '@/types/api/api-general';
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
import { Icon } from '@iconify/react';
import { useState } from 'react';
@@ -16,9 +17,11 @@ import toast from 'react-hot-toast';
const ChickinLogsView = ({
initialValues,
afterSubmit,
+ rawDataApprovals,
}: {
initialValues: ProjectFlockKandang;
afterSubmit?: () => void;
+ rawDataApprovals: BaseApproval[];
}) => {
const confirmModal = useModal();
const [isApproveLoading, setIsApproveLoading] = useState(false);
@@ -60,9 +63,15 @@ const ChickinLogsView = ({
) : (
(initialValues?.chickins || []).map((chickin, index) => {
+ const latestApproval = rawDataApprovals[0];
const isApproved =
- initialValues.chickin_approval?.step_number === 2;
- const isPending = initialValues.chickin_approval?.step_number === 1;
+ index == (initialValues?.chickins || []).length - 1
+ ? latestApproval?.step_number === 2
+ : true;
+ const isPending =
+ index == (initialValues?.chickins || []).length - 1
+ ? latestApproval?.step_number === 1
+ : false;
const quantity = isApproved
? chickin.usage_qty
: isPending
@@ -82,7 +91,7 @@ const ChickinLogsView = ({
{/* Header with Status Badge */}
- Chick In #{index + 1}
+ Chick In #{index + 1} - {latestApproval?.step_number}
=
diff --git a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx
index 20a8aff4..7e90c94b 100644
--- a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx
+++ b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx
@@ -6,6 +6,8 @@ import SelectInput, {
useSelect,
} from '@/components/input/SelectInput';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+import { getUniqueFormikErrors } from '@/lib/formik-helper';
+import AlertErrorList from '@/components/helper/form/FormErrors';
import {
AreaApi,
FcrApi,
@@ -64,6 +66,7 @@ const ProjectFlockForm = ({
const [projectFlockFormErrorMessage, setProjectFlockFormErrorMessage] =
useState('');
+ const [formErrorList, setFormErrorList] = useState([]);
const [selectedArea, setSelectedArea] = useState('');
const [selectedLocation, setSelectedLocation] = useState('');
const [selectedCategory, setSelectedCategory] = useState('');
@@ -134,6 +137,7 @@ const ProjectFlockForm = ({
const kandangUrl = `${KandangApi.basePath}?${new URLSearchParams({
search: '',
location_id: selectedLocation == '' ? '0' : selectedLocation,
+ limit: 'limit',
}).toString()}`;
const {
data: kandang,
@@ -638,6 +642,17 @@ const ProjectFlockForm = ({
return !isNonstockAlreadyInBudgets;
});
+ const handleValidateForm = async () => {
+ const errors = await formik.validateForm();
+
+ if (Object.keys(errors).length > 0) {
+ // Parse and display errors
+ const errorMessages = getUniqueFormikErrors(errors);
+ setFormErrorList(errorMessages);
+ return; // Stop submission
+ }
+ };
+
return (
<>
@@ -697,7 +712,11 @@ const ProjectFlockForm = ({
+ {/* Error List Alert */}
+ {formErrorList.length > 0 && (
+ setFormErrorList([])}
+ />
+ )}
+
{formType !== 'detail' && (
(
+ errors: FormikErrors,
+ parentKey: string = ''
+): ErrorMessage[] {
+ const errorList: ErrorMessage[] = [];
+
+ Object.keys(errors).forEach((key) => {
+ const value = errors[key as keyof typeof errors];
+ const fullKey = parentKey ? `${parentKey}.${key}` : key;
+
+ if (typeof value === 'string') {
+ // Direct error message
+ errorList.push({ key: fullKey, message: value });
+ } else if (Array.isArray(value)) {
+ // Array of errors
+ value.forEach((item, index) => {
+ if (typeof item === 'string') {
+ errorList.push({ key: `${fullKey}[${index}]`, message: item });
+ } else if (item && typeof item === 'object') {
+ // Nested object in array
+ const nestedErrors = parseFormikErrors(
+ item as FormikErrors,
+ `${fullKey}[${index}]`
+ );
+ errorList.push(...nestedErrors);
+ }
+ });
+ } else if (value && typeof value === 'object') {
+ // Nested object
+ const nestedErrors = parseFormikErrors(
+ value as FormikErrors,
+ fullKey
+ );
+ errorList.push(...nestedErrors);
+ }
+ });
+
+ return errorList;
+}
+
+/**
+ * Get unique error messages from Formik errors
+ * @param errors - Formik errors object
+ * @returns Array of unique error messages
+ */
+export function getUniqueFormikErrors(errors: FormikErrors): string[] {
+ const errorList = parseFormikErrors(errors);
+ return Array.from(new Set(errorList.map((e) => e.message)));
+}
+
+/**
+ * Get all error messages from Formik errors
+ * @param errors - Formik errors object
+ * @returns Array of error messages
+ */
+export function getAllFormikErrors(errors: FormikErrors): ErrorMessage[] {
+ return parseFormikErrors(errors);
+}