From 36b167dafb69c0e25ac32d0583324fd94265c1d6 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Mon, 12 Jan 2026 15:13:02 +0700 Subject: [PATCH 1/3] fix(FE): add production standard in detail project flock --- .../detail/ProjectFlockDetail.tsx | 26 +++++++++---------- src/types/api/production/project-flock.d.ts | 1 + 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx b/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx index 9835c244..4a998c83 100644 --- a/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx +++ b/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx @@ -209,20 +209,6 @@ const ProjectFlockDetail = ({ - {/*
- History -
-
- -
*/} - {/* BARIS 1 */}
{projectFlock?.fcr?.name}
+
+ {' '} + Standard +
+
+ {projectFlock?.production_standard?.name ?? '-'} +
+ {/* BARIS 3 (Terakhir - TIDAK PERLU garis di bawahnya) */}
{' '} diff --git a/src/types/api/production/project-flock.d.ts b/src/types/api/production/project-flock.d.ts index 1aeb2005..66cc39ed 100644 --- a/src/types/api/production/project-flock.d.ts +++ b/src/types/api/production/project-flock.d.ts @@ -5,6 +5,7 @@ import { Kandang } from '@/types/api/master-data/kandang'; import { Location } from '@/types/api/master-data/location'; import { BaseApproval, BaseMetadata } from '@/types/api/api-general'; import { Nonstock } from '@/types/api/master-data/nonstock'; +import { ProductionStandard } from '@/types/api/master-data/production-standard'; export type BaseProjectFlock = { id: number; From 0f9849c0acf506e9c7978bc6a1eca25661e42a14 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Mon, 12 Jan 2026 15:38:07 +0700 Subject: [PATCH 2/3] fix(FE): fixing sapronak calculation get kandangId state --- src/components/pages/closing/ClosingDetail.tsx | 2 -- .../closing/ClosingSapronakCalculationTabContent.tsx | 3 --- .../closing/ClosingSapronakCalculationTable.tsx | 12 +++++++----- src/types/api/closing.d.ts | 1 + 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/pages/closing/ClosingDetail.tsx b/src/components/pages/closing/ClosingDetail.tsx index d1dd8ef6..41db6b1c 100644 --- a/src/components/pages/closing/ClosingDetail.tsx +++ b/src/components/pages/closing/ClosingDetail.tsx @@ -22,7 +22,6 @@ import HppExpeditionReportTable from './hpp-ekspedisi/HppExpeditionReportTable'; import ClosingKandangList from '@/components/pages/closing/ClosingKandangList'; import { ProjectFlock } from '@/types/api/production/project-flock'; import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang'; - interface ClosingDetailProps { id: number; initialValue?: ClosingGeneralInformation; @@ -56,7 +55,6 @@ const ClosingDetail: React.FC = ({ ), }, diff --git a/src/components/pages/closing/ClosingSapronakCalculationTabContent.tsx b/src/components/pages/closing/ClosingSapronakCalculationTabContent.tsx index cae2d406..b8add15b 100644 --- a/src/components/pages/closing/ClosingSapronakCalculationTabContent.tsx +++ b/src/components/pages/closing/ClosingSapronakCalculationTabContent.tsx @@ -5,13 +5,11 @@ import { ClosingGeneralInformation } from '@/types/api/closing'; interface ClosingSapronakCalculationTabContentProps { projectFlockId?: number; - projectKandangId?: number; closingGeneralInformation?: ClosingGeneralInformation; } const ClosingSapronakCalculationTabContent = ({ projectFlockId, - projectKandangId, closingGeneralInformation, }: ClosingSapronakCalculationTabContentProps) => { return ( @@ -21,7 +19,6 @@ const ClosingSapronakCalculationTabContent = ({ )} diff --git a/src/components/pages/closing/ClosingSapronakCalculationTable.tsx b/src/components/pages/closing/ClosingSapronakCalculationTable.tsx index 17527959..77cef803 100644 --- a/src/components/pages/closing/ClosingSapronakCalculationTable.tsx +++ b/src/components/pages/closing/ClosingSapronakCalculationTable.tsx @@ -14,21 +14,23 @@ import useSWR from 'swr'; import { ClosingApi } from '@/services/api/closing'; import { isResponseSuccess } from '@/lib/api-helper'; import { ClosingGeneralInformation } from '@/types/api/closing'; +import { useSearchParams } from 'next/navigation'; interface ClosingSapronakCalculationTableProps { projectFlockId: number; - projectKandangId?: number; closingGeneralInformation?: ClosingGeneralInformation; } const ClosingSapronakCalculationTable = ({ projectFlockId, closingGeneralInformation, - projectKandangId, }: ClosingSapronakCalculationTableProps) => { + const searchParams = useSearchParams(); + const kandangId = searchParams.get('kandangId'); + const { data: sapronakCalculation, isLoading } = useSWR( - `/closing/sapronak-calculation/${projectFlockId}${projectKandangId ? `/${projectKandangId}` : ''}`, - () => ClosingApi.getPerhitunganSapronak(projectFlockId, projectKandangId), + `/closing/sapronak-calculation/${projectFlockId}${kandangId ? `/${kandangId}` : ''}`, + () => ClosingApi.getPerhitunganSapronak(projectFlockId, Number(kandangId)), { keepPreviousData: true, } @@ -180,7 +182,7 @@ const ClosingSapronakCalculationTable = ({ {/* Table DOC jika kategori Project Flock Growing */} Date: Mon, 12 Jan 2026 17:19:16 +0700 Subject: [PATCH 3/3] fix(FE): create hooks for formik error list and integrate alert error list for finance and master data modules --- src/components/helper/form/FormErrors.tsx | 5 +- .../pages/dashboard/DashboardProduction.tsx | 31 ++-------- .../pages/finance/add/FormFinanceAdd.tsx | 9 ++- .../FormFinanceAddInitialBalance.tsx | 13 ++-- .../add/injection/FormFinanceInjection.tsx | 13 ++-- .../adjustment/InventoryAdjustmentTable.tsx | 1 + .../form/InventoryAdjustmentForm.schema.ts | 44 ++++++++----- .../form/InventoryAdjustmentForm.tsx | 14 +++-- .../pages/marketing/form/MarketingForm.tsx | 29 ++------- .../delivery-order/DeliverOrderProduct.tsx | 27 ++------ .../sales-order/SalesOrderProductForm.tsx | 30 ++------- .../pages/master-data/area/form/AreaForm.tsx | 11 +++- .../pages/master-data/bank/form/BankForm.tsx | 11 +++- .../customer/form/CustomerForm.tsx | 11 +++- .../pages/master-data/fcr/form/FcrForm.tsx | 11 +++- .../master-data/flock/form/FlockForm.tsx | 11 +++- .../master-data/kandang/form/KandangForm.tsx | 11 +++- .../location/form/LocationForm.tsx | 11 +++- .../nonstock/form/NonstockForm.tsx | 11 +++- .../form/ProductCategoryForm.tsx | 28 ++------- .../master-data/product/form/ProductForm.tsx | 27 ++------ .../form/ProductionStandardForm.tsx | 39 +++++++----- .../supplier/form/SupplierForm.tsx | 11 +++- .../pages/master-data/uom/form/UomForm.tsx | 11 +++- .../warehouse/form/WarehouseForm.tsx | 11 +++- .../project-flock/form/ProjectFlockForm.tsx | 29 ++------- src/services/hooks/useFormikErrorList.ts | 62 +++++++++++++++++++ 27 files changed, 280 insertions(+), 242 deletions(-) create mode 100644 src/services/hooks/useFormikErrorList.ts diff --git a/src/components/helper/form/FormErrors.tsx b/src/components/helper/form/FormErrors.tsx index a351227f..4b97d033 100644 --- a/src/components/helper/form/FormErrors.tsx +++ b/src/components/helper/form/FormErrors.tsx @@ -1,6 +1,7 @@ import Alert from '@/components/Alert'; import Button from '@/components/Button'; import { Icon } from '@iconify/react'; +import { useState } from 'react'; /** * Alert Unique Error List @@ -14,8 +15,10 @@ const AlertErrorList = ({ formErrorList: string[]; onClose: () => void; }) => { + if (formErrorList.length === 0) return null; + return ( - +
diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index f561e96d..b65508cb 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -14,10 +14,8 @@ import { DashboardApi } from '@/services/api/dashboard'; import { useFormik } from 'formik'; import { ProjectFlockApi } from '@/services/api/production'; import { KandangApi, LocationApi } from '@/services/api/master-data'; -import Alert from '@/components/Alert'; import { - DashboardFilterSchema, DashboardFilterType, getDashboardFilterSchema, } from '@/components/pages/dashboard/filter/DashboardProductionFilter.schema'; @@ -31,7 +29,7 @@ import { import DashboardStats from '@/components/pages/dashboard/chart/DashboardStats'; import { isResponseSuccess } from '@/lib/api-helper'; import AlertErrorList from '@/components/helper/form/FormErrors'; -import { getUniqueFormikErrors } from '@/lib/formik-helper'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; // Helper function to normalize values to array const normalizeToArray = ( @@ -51,7 +49,6 @@ const DashboardProduction = () => { ); const [endpointUrl, setEndpointUrl] = useState('/dashboards'); const [selectedLocationIds, setSelectedLocationIds] = useState([]); - const [formErrorList, setFormErrorList] = useState([]); // ===== FETCH DATA ===== const { @@ -149,22 +146,8 @@ const DashboardProduction = () => { formik.resetForm(); }; - 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 - } - }; - - const handleFormSubmit = (e: React.FormEvent) => { - e.preventDefault(); - handleValidateForm(); - formik.handleSubmit(); - }; + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); if (isLoadingDashboardProductionData) { return ( @@ -482,13 +465,7 @@ const DashboardProduction = () => {
)} - {/* Error List Alert */} - {formErrorList.length > 0 && ( - setFormErrorList([])} - /> - )} + {/* Action Buttons */}
diff --git a/src/components/pages/finance/add/FormFinanceAdd.tsx b/src/components/pages/finance/add/FormFinanceAdd.tsx index c835740e..a94fabd9 100644 --- a/src/components/pages/finance/add/FormFinanceAdd.tsx +++ b/src/components/pages/finance/add/FormFinanceAdd.tsx @@ -1,7 +1,7 @@ 'use client'; import Button from '@/components/Button'; -import Card from '@/components/Card'; +import AlertErrorList from '@/components/helper/form/FormErrors'; import { FormHeader } from '@/components/helper/form/FormHeader'; import DateInput from '@/components/input/DateInput'; import NumberInput from '@/components/input/NumberInput'; @@ -21,6 +21,7 @@ import { } from '@/config/constant'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { formatDate, formatTitleCase } from '@/lib/helper'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; import { FinanceApi } from '@/services/api/finance'; import { BankApi, CustomerApi, SupplierApi } from '@/services/api/master-data'; import { @@ -104,6 +105,9 @@ const FormFinanceAdd = ({ }, }); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + // ===== Options ===== const { options: partyOptions, @@ -180,7 +184,7 @@ const FormFinanceAdd = ({ title={`${type === 'add' ? 'Tambah' : 'Ubah'} Data Keuangan`} backUrl='/finance' /> -
+ +
+
{type !== 'detail' && (
@@ -405,11 +411,7 @@ const InventoryAdjustmentForm = ({ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={ - !formik.isValid || - formik.isSubmitting || - formik.values.product == undefined - } + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/marketing/form/MarketingForm.tsx b/src/components/pages/marketing/form/MarketingForm.tsx index 51c20d8e..2fbca835 100644 --- a/src/components/pages/marketing/form/MarketingForm.tsx +++ b/src/components/pages/marketing/form/MarketingForm.tsx @@ -48,8 +48,8 @@ import DeliveryOrderProductForm from '@/components/pages/marketing/form/repeater import { SalesOrderProductFormValues } from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema'; import { DeliveryOrderProductFormValues } from '@/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.schema'; import RequirePermission from '@/components/helper/RequirePermission'; -import { getUniqueFormikErrors } from '@/lib/formik-helper'; import AlertErrorList from '@/components/helper/form/FormErrors'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; const MemoizedSalesOrderProductTable = memo(SalesOrderProductTable); const MemoizedSalesOrderProductForm = memo(SalesOrderProductForm); @@ -219,7 +219,6 @@ const MarketingForm = ({ const [deliveryFormState, setDeliveryFormState] = useState<'add' | 'edit'>( 'add' ); - const [formErrorList, setFormErrorList] = useState([]); const [deliveryOrderValues, setDeliveryOrderValues] = useState< DeliveryOrderProductFormValues[] >( @@ -561,22 +560,8 @@ const MarketingForm = ({ ); }, [memoSalesOrder]); - 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 - } - }; - - const handleFormSubmit = (e: React.FormEvent) => { - e.preventDefault(); - handleValidateForm(); - formik.handleSubmit(); - }; + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); return ( <> @@ -686,13 +671,7 @@ const MarketingForm = ({
- {/* Error List Alert */} - {formErrorList.length > 0 && ( - setFormErrorList([])} - /> - )} + {/* Form Actions */}
diff --git a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx index 84f9e443..25a20982 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -16,8 +16,8 @@ import Badge from '@/components/Badge'; import { SalesProductToFieldValues } from '@/components/pages/marketing/form/MarketingForm'; import * as Yup from 'yup'; import { isResponseSuccess } from '@/lib/api-helper'; -import { getUniqueFormikErrors } from '@/lib/formik-helper'; import AlertErrorList from '@/components/helper/form/FormErrors'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; const DeliveryOrderProductForm = ({ formState, @@ -42,7 +42,6 @@ const DeliveryOrderProductForm = ({ null ); const [currentInput, setCurrentInput] = useState(''); - const [formErrorList, setFormErrorList] = useState([]); const salesOrder = salesOrders.find( (item) => item.id === initialValues?.marketing_product_id @@ -168,21 +167,8 @@ const DeliveryOrderProductForm = ({ } }, [initialValues]); - const handleValidateForm = () => { - formik.validateForm(); - const formErrorList = getUniqueFormikErrors(formik.errors); - setFormErrorList(formErrorList); - if (formErrorList.length > 0) { - return; - } - }; - - const handleFormSubmit = (e: React.FormEvent) => { - e.preventDefault(); - handleBlurField(currentInput); - handleValidateForm(); - formik.handleSubmit(e); - }; + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); return ( <> @@ -388,12 +374,7 @@ const DeliveryOrderProductForm = ({ />
- {formErrorList.length > 0 && ( - setFormErrorList([])} - /> - )} +
- {/* Error List Alert */} - {formErrorList.length > 0 && ( - setFormErrorList([])} - /> - )} +
)} + + {type !== 'detail' && (
{ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/master-data/bank/form/BankForm.tsx b/src/components/pages/master-data/bank/form/BankForm.tsx index ac5cc531..13c85422 100644 --- a/src/components/pages/master-data/bank/form/BankForm.tsx +++ b/src/components/pages/master-data/bank/form/BankForm.tsx @@ -25,6 +25,8 @@ import { } from '@/types/api/master-data/bank'; import { BankApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; +import AlertErrorList from '@/components/helper/form/FormErrors'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; interface BankFormProps { type?: 'add' | 'edit' | 'detail'; @@ -124,6 +126,9 @@ const BankForm = ({ type = 'add', initialValues }: BankFormProps) => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + return ( <>
@@ -145,7 +150,7 @@ const BankForm = ({ type = 'add', initialValues }: BankFormProps) => { @@ -247,6 +252,8 @@ const BankForm = ({ type = 'add', initialValues }: BankFormProps) => {
)} + + {type !== 'detail' && (
{ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/master-data/customer/form/CustomerForm.tsx b/src/components/pages/master-data/customer/form/CustomerForm.tsx index fd3cea6f..0a629b36 100644 --- a/src/components/pages/master-data/customer/form/CustomerForm.tsx +++ b/src/components/pages/master-data/customer/form/CustomerForm.tsx @@ -28,6 +28,8 @@ import useSWR from 'swr'; import { UserApi } from '@/services/api/user'; import { TYPE_OPTIONS } from '@/config/constant'; import RequirePermission from '@/components/helper/RequirePermission'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; +import AlertErrorList from '@/components/helper/form/FormErrors'; interface CustomerFormProps { formType?: 'add' | 'edit' | 'detail'; @@ -191,6 +193,9 @@ const CustomerForm = ({ formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + // Render return ( <> @@ -213,7 +218,7 @@ const CustomerForm = ({ @@ -358,6 +363,8 @@ const CustomerForm = ({
)} + + {formType !== 'detail' && (
Submit diff --git a/src/components/pages/master-data/fcr/form/FcrForm.tsx b/src/components/pages/master-data/fcr/form/FcrForm.tsx index f30ec7e9..807e7e45 100644 --- a/src/components/pages/master-data/fcr/form/FcrForm.tsx +++ b/src/components/pages/master-data/fcr/form/FcrForm.tsx @@ -26,6 +26,8 @@ import { } from '@/types/api/master-data/fcr'; import { FcrApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; +import AlertErrorList from '@/components/helper/form/FormErrors'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; interface FcrFormProps { type?: 'add' | 'edit' | 'detail'; @@ -158,6 +160,9 @@ const FcrForm = ({ type = 'add', initialValues }: FcrFormProps) => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + return ( <>
@@ -179,7 +184,7 @@ const FcrForm = ({ type = 'add', initialValues }: FcrFormProps) => { @@ -294,6 +299,8 @@ const FcrForm = ({ type = 'add', initialValues }: FcrFormProps) => { )}
+ +
{type !== 'add' && (
@@ -349,7 +356,7 @@ const FcrForm = ({ type = 'add', initialValues }: FcrFormProps) => { type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/master-data/flock/form/FlockForm.tsx b/src/components/pages/master-data/flock/form/FlockForm.tsx index 5db61656..51ed4325 100644 --- a/src/components/pages/master-data/flock/form/FlockForm.tsx +++ b/src/components/pages/master-data/flock/form/FlockForm.tsx @@ -17,6 +17,8 @@ import TextInput from '@/components/input/TextInput'; import { cn } from '@/lib/helper'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import RequirePermission from '@/components/helper/RequirePermission'; +import AlertErrorList from '@/components/helper/form/FormErrors'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; interface FlockCustomProps { formType?: 'add' | 'edit' | 'detail'; @@ -86,6 +88,9 @@ const FlockForm = ({ formType = 'add', initialValues }: FlockCustomProps) => { formikSetValues(formikInitialValue); }, [formikSetValues, formikInitialValue]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + // Render return ( <> @@ -107,7 +112,7 @@ const FlockForm = ({ formType = 'add', initialValues }: FlockCustomProps) => { @@ -168,6 +173,8 @@ const FlockForm = ({ formType = 'add', initialValues }: FlockCustomProps) => {
)} + + {formType !== 'detail' && (
{ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/master-data/kandang/form/KandangForm.tsx b/src/components/pages/master-data/kandang/form/KandangForm.tsx index 81911ab0..ffea5718 100644 --- a/src/components/pages/master-data/kandang/form/KandangForm.tsx +++ b/src/components/pages/master-data/kandang/form/KandangForm.tsx @@ -29,6 +29,8 @@ import { LocationApi, KandangApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; import { UserApi } from '@/services/api/user'; import NumberInput from '@/components/input/NumberInput'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; +import AlertErrorList from '@/components/helper/form/FormErrors'; interface KandangFormProps { type?: 'add' | 'edit' | 'detail'; @@ -198,6 +200,9 @@ const KandangForm = ({ type = 'add', initialValues }: KandangFormProps) => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + return ( <>
@@ -219,7 +224,7 @@ const KandangForm = ({ type = 'add', initialValues }: KandangFormProps) => { @@ -324,6 +329,8 @@ const KandangForm = ({ type = 'add', initialValues }: KandangFormProps) => {
)} + + {type !== 'detail' && (
{ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/master-data/location/form/LocationForm.tsx b/src/components/pages/master-data/location/form/LocationForm.tsx index 68a10527..9f77cf86 100644 --- a/src/components/pages/master-data/location/form/LocationForm.tsx +++ b/src/components/pages/master-data/location/form/LocationForm.tsx @@ -27,6 +27,8 @@ import { } from '@/types/api/master-data/location'; import { AreaApi, LocationApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; +import AlertErrorList from '@/components/helper/form/FormErrors'; interface LocationFormProps { type?: 'add' | 'edit' | 'detail'; @@ -160,6 +162,9 @@ const LocationForm = ({ type = 'add', initialValues }: LocationFormProps) => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + return ( <>
@@ -181,7 +186,7 @@ const LocationForm = ({ type = 'add', initialValues }: LocationFormProps) => { @@ -268,6 +273,8 @@ const LocationForm = ({ type = 'add', initialValues }: LocationFormProps) => {
)} + + {type !== 'detail' && (
{ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/master-data/nonstock/form/NonstockForm.tsx b/src/components/pages/master-data/nonstock/form/NonstockForm.tsx index af72f22f..7d8b8784 100644 --- a/src/components/pages/master-data/nonstock/form/NonstockForm.tsx +++ b/src/components/pages/master-data/nonstock/form/NonstockForm.tsx @@ -29,6 +29,8 @@ import { NonstockApi, SupplierApi, UomApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; import { flags } from '@/types/api/api-general'; import { SUPPLIER_FLAG_OPTIONS } from '@/config/constant'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; +import AlertErrorList from '@/components/helper/form/FormErrors'; interface NonstockFormProps { type?: 'add' | 'edit' | 'detail'; @@ -213,6 +215,9 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + return ( <>
@@ -234,7 +239,7 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { @@ -337,6 +342,8 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => {
)} + + {type !== 'detail' && (
{ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/master-data/product-category/form/ProductCategoryForm.tsx b/src/components/pages/master-data/product-category/form/ProductCategoryForm.tsx index d241a3dd..1e61879c 100644 --- a/src/components/pages/master-data/product-category/form/ProductCategoryForm.tsx +++ b/src/components/pages/master-data/product-category/form/ProductCategoryForm.tsx @@ -11,7 +11,6 @@ import TextInput from '@/components/input/TextInput'; import { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import RequirePermission from '@/components/helper/RequirePermission'; -import { getUniqueFormikErrors } from '@/lib/formik-helper'; import AlertErrorList from '@/components/helper/form/FormErrors'; import { @@ -27,6 +26,7 @@ import { } from '@/types/api/master-data/product-category'; import { ProductCategoryApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; interface ProductCategoryFormProps { type?: 'add' | 'edit' | 'detail'; @@ -41,7 +41,6 @@ const ProductCategoryForm = ({ const deleteModal = useModal(); const [formErrorMessage, setFormErrorMessage] = useState(''); - const [formErrorList, setFormErrorList] = useState([]); const [isDeleteLoading, setIsDeleteLoading] = useState(false); const createProductCategoryHandler = useCallback( @@ -132,21 +131,8 @@ const ProductCategoryForm = ({ formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); - const handleValidateForm = async () => { - const errors = await formik.validateForm(); - - if (Object.keys(errors).length > 0) { - const errorMessages = getUniqueFormikErrors(errors); - setFormErrorList(errorMessages); - return; - } - }; - - const handleFormSubmit = (e: React.FormEvent) => { - e.preventDefault(); - handleValidateForm(); - formik.handleSubmit(e); - }; + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); return ( <> @@ -184,13 +170,7 @@ const ProductCategoryForm = ({
)} - {/* Error List Alert */} - {formErrorList.length > 0 && ( - setFormErrorList([])} - /> - )} +
{ const deleteModal = useModal(); const [productFormErrorMessage, setProductFormErrorMessage] = useState(''); - const [formErrorList, setFormErrorList] = useState([]); const [isDeleteLoading, setIsDeleteLoading] = useState(false); const createProductHandler = useCallback( @@ -204,21 +204,8 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); - const handleValidateForm = async () => { - const errors = await formik.validateForm(); - - if (Object.keys(errors).length > 0) { - const errorMessages = getUniqueFormikErrors(errors); - setFormErrorList(errorMessages); - return; - } - }; - - const handleFormSubmit = (e: React.FormEvent) => { - e.preventDefault(); - handleValidateForm(); - formik.handleSubmit(e); - }; + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); return ( <> @@ -254,13 +241,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
)} - {/* Error List Alert */} - {formErrorList.length > 0 && ( - setFormErrorList([])} - /> - )} +
{ switch (formType) { case 'add': @@ -723,7 +727,8 @@ const ProductionStandardForm = ({ router.push('/master-data/production-standard'); }; - // ===== Function ===== + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); return ( <> @@ -1210,9 +1215,26 @@ const ProductionStandardForm = ({ return null; }} /> + + + + {productionStandardFormErrorMessage && ( + +
+ + {productionStandardFormErrorMessage} +
+ setProductionStandardFormErrorMessage('')} + className='ms-auto' + /> +
+ )} + {formType === 'detail' && (
@@ -1293,19 +1315,6 @@ const ProductionStandardForm = ({
)} - {productionStandardFormErrorMessage && ( - -
- - {productionStandardFormErrorMessage} -
- setProductionStandardFormErrorMessage('')} - className='ms-auto' - /> -
- )}
@@ -221,7 +226,7 @@ const SupplierForm = ({
@@ -444,6 +449,8 @@ const SupplierForm = ({
)} + + {formType !== 'detail' && (
Submit diff --git a/src/components/pages/master-data/uom/form/UomForm.tsx b/src/components/pages/master-data/uom/form/UomForm.tsx index 50576eef..366f9682 100644 --- a/src/components/pages/master-data/uom/form/UomForm.tsx +++ b/src/components/pages/master-data/uom/form/UomForm.tsx @@ -25,6 +25,8 @@ import { } from '@/types/api/master-data/uom'; import { UomApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; +import AlertErrorList from '@/components/helper/form/FormErrors'; interface UomFormProps { type?: 'add' | 'edit' | 'detail'; @@ -118,6 +120,9 @@ const UomForm = ({ type = 'add', initialValues }: UomFormProps) => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + return ( <>
@@ -139,7 +144,7 @@ const UomForm = ({ type = 'add', initialValues }: UomFormProps) => { @@ -199,6 +204,8 @@ const UomForm = ({ type = 'add', initialValues }: UomFormProps) => {
)} + + {type !== 'detail' && (
{ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/master-data/warehouse/form/WarehouseForm.tsx b/src/components/pages/master-data/warehouse/form/WarehouseForm.tsx index 227af3c6..0fb55a2a 100644 --- a/src/components/pages/master-data/warehouse/form/WarehouseForm.tsx +++ b/src/components/pages/master-data/warehouse/form/WarehouseForm.tsx @@ -33,6 +33,8 @@ import { } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; import { WAREHOUSE_TYPE_OPTIONS } from '@/config/constant'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; +import AlertErrorList from '@/components/helper/form/FormErrors'; interface WarehouseFormProps { type?: 'add' | 'edit' | 'detail'; @@ -323,6 +325,9 @@ const WarehouseForm = ({ type = 'add', initialValues }: WarehouseFormProps) => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + return ( <>
@@ -344,7 +349,7 @@ const WarehouseForm = ({ type = 'add', initialValues }: WarehouseFormProps) => { @@ -474,6 +479,8 @@ const WarehouseForm = ({ type = 'add', initialValues }: WarehouseFormProps) => {
)} + + {type !== 'detail' && (
{ type='submit' color='primary' isLoading={formik.isSubmitting} - disabled={!formik.isValid || formik.isSubmitting} + disabled={formik.isSubmitting} className='px-4' > Submit diff --git a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx index 7e90c94b..745a6b1e 100644 --- a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx +++ b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx @@ -6,7 +6,6 @@ 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, @@ -47,6 +46,7 @@ import { Nonstock } from '@/types/api/master-data/nonstock'; import { useUiStore } from '@/stores/ui/ui.store'; import RequirePermission from '@/components/helper/RequirePermission'; import DrawerHeader from '@/components/helper/drawer/DrawerHeader'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; interface ProjectFlockFormProps { formType?: 'add' | 'edit' | 'detail'; @@ -66,7 +66,6 @@ const ProjectFlockForm = ({ const [projectFlockFormErrorMessage, setProjectFlockFormErrorMessage] = useState(''); - const [formErrorList, setFormErrorList] = useState([]); const [selectedArea, setSelectedArea] = useState(''); const [selectedLocation, setSelectedLocation] = useState(''); const [selectedCategory, setSelectedCategory] = useState(''); @@ -642,16 +641,8 @@ 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 - } - }; + // ===== Formik Error List ===== + const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); return ( <> @@ -712,11 +703,7 @@ const ProjectFlockForm = ({ { - e.preventDefault(); - handleValidateForm(); - formik.handleSubmit(e); - }} + onSubmit={handleFormSubmit} onReset={formik.handleReset} > {/* Form Informasi Umum */} @@ -1082,13 +1069,7 @@ const ProjectFlockForm = ({
- {/* Error List Alert */} - {formErrorList.length > 0 && ( - setFormErrorList([])} - /> - )} +
{formType !== 'detail' && ( diff --git a/src/services/hooks/useFormikErrorList.ts b/src/services/hooks/useFormikErrorList.ts new file mode 100644 index 00000000..9d299322 --- /dev/null +++ b/src/services/hooks/useFormikErrorList.ts @@ -0,0 +1,62 @@ +import { getUniqueFormikErrors } from '@/lib/formik-helper'; +import { FormikProps } from 'formik'; +import { useState } from 'react'; + +interface UseFormikErrorListOptions { + onBeforeSubmit?: (e: React.FormEvent) => boolean | void; + onAfterValidation?: () => void | Promise; +} + +export const useFormikErrorList = ( + formik: FormikProps, + options?: UseFormikErrorListOptions +) => { + const [formErrorList, setFormErrorList] = useState([]); + + const handleValidateForm = async () => { + const errors = await formik.validateForm(); + + if (Object.keys(errors).length > 0) { + const errorMessages = getUniqueFormikErrors(errors); + setFormErrorList(errorMessages); + return false; + } + + return true; + }; + + const handleFormSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + // Call onBeforeSubmit callback + if (options?.onBeforeSubmit) { + const shouldContinue = options.onBeforeSubmit(e); + if (shouldContinue === false) { + return; // Cancel submit + } + } + + // Validate form + const isValid = await handleValidateForm(); + + // Call onAfterValidation callback if validation passed + if (options?.onAfterValidation) { + await options.onAfterValidation(); + } + + // Submit form + formik.handleSubmit(); + }; + + const close = () => { + setFormErrorList([]); + }; + + return { + formErrorList, + setFormErrorList, + close, + handleValidateForm, + handleFormSubmit, + }; +};