diff --git a/src/components/pages/closing/ClosingIncomingSapronaksTable.tsx b/src/components/pages/closing/ClosingIncomingSapronaksTable.tsx index 53e45710..eda7e756 100644 --- a/src/components/pages/closing/ClosingIncomingSapronaksTable.tsx +++ b/src/components/pages/closing/ClosingIncomingSapronaksTable.tsx @@ -1,6 +1,7 @@ 'use client'; import { ChangeEventHandler, useEffect, useState } from 'react'; +import { useSearchParams } from 'next/navigation'; import useSWR from 'swr'; import { ColumnDef, SortingState } from '@tanstack/react-table'; @@ -23,6 +24,9 @@ interface ClosingIncomingSapronaksTableProps { const ClosingIncomingSapronaksTable = ({ projectFlockId, }: ClosingIncomingSapronaksTableProps) => { + const searchParams = useSearchParams(); + const kandangId = searchParams.get('kandangId'); + const { state: tableFilterState, updateFilter, @@ -43,7 +47,7 @@ const ClosingIncomingSapronaksTable = ({ const { data: incomingSapronaks, isLoading: isLoadingIncomingSapronaks } = useSWR( - `${ClosingApi.basePath}/${projectFlockId}/sapronak${getTableFilterQueryString()}&type=incoming`, + `${ClosingApi.basePath}/${projectFlockId}/sapronak${getTableFilterQueryString()}&type=incoming&kandang_id=${kandangId ? `${kandangId}` : ''}`, ClosingApi.getAllIncomingSapronakFetcher, { keepPreviousData: true, diff --git a/src/components/pages/closing/ClosingOutgoingSapronaksTable.tsx b/src/components/pages/closing/ClosingOutgoingSapronaksTable.tsx index 5662cff1..ac918561 100644 --- a/src/components/pages/closing/ClosingOutgoingSapronaksTable.tsx +++ b/src/components/pages/closing/ClosingOutgoingSapronaksTable.tsx @@ -1,6 +1,7 @@ 'use client'; import { ChangeEventHandler, useEffect, useState } from 'react'; +import { useSearchParams } from 'next/navigation'; import useSWR from 'swr'; import { ColumnDef, SortingState } from '@tanstack/react-table'; @@ -23,6 +24,9 @@ interface ClosingOutgoingSapronaksTableProps { const ClosingOutgoingSapronaksTable = ({ projectFlockId, }: ClosingOutgoingSapronaksTableProps) => { + const searchParams = useSearchParams(); + const kandangId = searchParams.get('kandangId'); + const { state: tableFilterState, updateFilter, @@ -43,7 +47,7 @@ const ClosingOutgoingSapronaksTable = ({ const { data: outgoingSapronaks, isLoading: isLoadingOutgoingSapronaks } = useSWR( - `${ClosingApi.basePath}/${projectFlockId}/sapronak${getTableFilterQueryString()}&type=outgoing`, + `${ClosingApi.basePath}/${projectFlockId}/sapronak${getTableFilterQueryString()}&type=outgoing&kandang_id=${kandangId ? `${kandangId}` : ''}`, ClosingApi.getAllOutgoingSapronakFetcher, { keepPreviousData: true, diff --git a/src/components/pages/closing/ClosingProductionDataTabContent.tsx b/src/components/pages/closing/ClosingProductionDataTabContent.tsx index 0f15d5b9..9295d283 100644 --- a/src/components/pages/closing/ClosingProductionDataTabContent.tsx +++ b/src/components/pages/closing/ClosingProductionDataTabContent.tsx @@ -1,5 +1,6 @@ 'use client'; +import { useSearchParams } from 'next/navigation'; import useSWR from 'swr'; import { ClosingApi } from '@/services/api/closing'; import { isResponseSuccess } from '@/lib/api-helper'; @@ -12,9 +13,12 @@ interface ClosingProductionDataTabContentProps { const ClosingProductionDataTabContent = ({ projectFlockId, }: ClosingProductionDataTabContentProps) => { + const searchParams = useSearchParams(); + const kandangId = searchParams.get('kandangId'); + const { data: productionData, isLoading } = useSWR( - `${ClosingApi.basePath}/${projectFlockId}/production-data`, - () => ClosingApi.getProductionData(projectFlockId) + `${ClosingApi.basePath}/${projectFlockId}/production-data?kandang_id=${kandangId ? `${kandangId}` : ''}`, + () => ClosingApi.getProductionData(projectFlockId, Number(kandangId)) ); if (isLoading) { diff --git a/src/components/pages/marketing/form/MarketingForm.schema.ts b/src/components/pages/marketing/form/MarketingForm.schema.ts index d81cdb9c..b09129c3 100644 --- a/src/components/pages/marketing/form/MarketingForm.schema.ts +++ b/src/components/pages/marketing/form/MarketingForm.schema.ts @@ -11,6 +11,13 @@ import { type MarketingSchemaType = { customer_id: number | undefined; sales_person_id: number | undefined; + sales_person: + | { + value: number; + label: string; + } + | undefined + | null; customer: | { value: number; @@ -33,7 +40,11 @@ type DeliveryOrderSchemaType = { export const SalesOrderSchema: Yup.ObjectSchema = Yup.object({ customer_id: Yup.number().required('Customer wajib diisi!'), - sales_person_id: Yup.number().required('Sales Person wajib diisi!'), + sales_person_id: Yup.number().required('Sales wajib diisi!'), + sales_person: Yup.object({ + value: Yup.number().required(), + label: Yup.string().required(), + }).nullable(), customer: Yup.object({ value: Yup.number().required(), label: Yup.string().required(), diff --git a/src/components/pages/marketing/form/MarketingForm.tsx b/src/components/pages/marketing/form/MarketingForm.tsx index 2fbca835..be4367cb 100644 --- a/src/components/pages/marketing/form/MarketingForm.tsx +++ b/src/components/pages/marketing/form/MarketingForm.tsx @@ -50,6 +50,8 @@ import { DeliveryOrderProductFormValues } from '@/components/pages/marketing/for import RequirePermission from '@/components/helper/RequirePermission'; import AlertErrorList from '@/components/helper/form/FormErrors'; import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; +import { CreatedUser } from '@/types/api/api-general'; +import { UserApi } from '@/services/api/user'; const MemoizedSalesOrderProductTable = memo(SalesOrderProductTable); const MemoizedSalesOrderProductForm = memo(SalesOrderProductForm); @@ -244,7 +246,15 @@ const MarketingForm = ({ const { options: customerOptions, isLoadingOptions: isLoadingCustomerOptions, + setInputValue: setInputCustomerValue, + loadMore: loadMoreCustomer, } = useSelect(CustomerApi.basePath, 'id', 'name'); + const { + options: salesOptions, + isLoadingOptions: isLoadingSalesOptions, + setInputValue: setInputSalesValue, + loadMore: loadMoreSales, + } = useSelect(UserApi.basePath, 'id', 'name'); // ================== SETUP FORMIK ================== const formikInitialValues = useMemo< @@ -255,6 +265,12 @@ const MarketingForm = ({ notes: initialValues?.notes || undefined, customer_id: initialValues?.customer?.id || undefined, sales_person_id: initialValues?.sales_person?.id || 1, + sales_person: initialValues?.sales_person + ? { + value: initialValues.sales_person.id, + label: initialValues.sales_person.name, + } + : null, customer: initialValues?.customer ? { value: initialValues.customer.id, @@ -443,6 +459,13 @@ const MarketingForm = ({ }, [] ); + const handleChangeSalesPerson = useCallback( + (val: OptionType | OptionType[] | null) => { + formik.setFieldValue('sales_person_id', (val as OptionType)?.value); + formik.setFieldValue('sales_person', val as OptionType); + }, + [] + ); const handleDelete = useCallback(() => { deleteModal.openModal(); }, [deleteModal]); @@ -580,6 +603,7 @@ const MarketingForm = ({ className={{ wrapper: 'bg-white w-full', }} + variant='bordered' >
- -
+
+ + +
+
Total Penjualan {formatCurrency(grandTotal)}{' '} 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 25a20982..da3b2fee 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -18,6 +18,11 @@ import * as Yup from 'yup'; import { isResponseSuccess } from '@/lib/api-helper'; import AlertErrorList from '@/components/helper/form/FormErrors'; import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; +import useSWR from 'swr'; +import { ProductApi } from '@/services/api/master-data'; + +const roundWeight = (value: number) => Number(value.toFixed(2)); +const roundPrice = (value: number) => Math.round(value); const DeliveryOrderProductForm = ({ formState, @@ -43,6 +48,17 @@ const DeliveryOrderProductForm = ({ ); const [currentInput, setCurrentInput] = useState(''); + // ============ Fetch Data ============ + const { data: productData } = useSWR( + selectedProduct?.value + ? ProductApi.basePath + '/' + selectedProduct?.value + : null, + () => + selectedProduct?.value + ? ProductApi.getSingle(Number(selectedProduct?.value)) + : undefined + ); + const salesOrder = salesOrders.find( (item) => item.id === initialValues?.marketing_product_id ); @@ -113,22 +129,60 @@ const DeliveryOrderProductForm = ({ const handleBlurField = (field: string) => { setCurrentInput(field); - const { qty, unit_price, total_price, avg_weight, total_weight } = - formik.values; - if (field === 'unit_price' || field === 'total_price' || field === 'qty') { - if (qty && unit_price && (field === 'unit_price' || field === 'qty')) { - formik.setFieldValue('total_price', Number(qty) * Number(unit_price)); - } else if (qty && total_price && field === 'total_price') { - formik.setFieldValue('unit_price', Number(total_price) / Number(qty)); + const qty = Number(formik.values.qty || 0); + const avgWeight = Number(formik.values.avg_weight || 0); + const totalWeight = Number(formik.values.total_weight || 0); + const unitPrice = Number(formik.values.unit_price || 0); + const totalPrice = Number(formik.values.total_price || 0); + + if (qty <= 0) return; + + switch (field) { + // ===== SOURCE FIELDS ===== + case 'qty': { + if (avgWeight > 0) { + formik.setFieldValue('total_weight', roundWeight(qty * avgWeight)); + } + + if (unitPrice > 0) { + formik.setFieldValue('total_price', roundPrice(qty * unitPrice)); + } + break; } - } - if (field === 'avg_weight' || field === 'total_weight' || field === 'qty') { - if (qty && avg_weight && (field === 'avg_weight' || field === 'qty')) { - formik.setFieldValue('total_weight', Number(qty) * Number(avg_weight)); - } else if (qty && total_weight && field === 'total_weight') { - formik.setFieldValue('avg_weight', Number(total_weight) / Number(qty)); + case 'avg_weight': { + if (avgWeight > 0) { + const tw = roundWeight(qty * avgWeight); + formik.setFieldValue('total_weight', tw); + + if (unitPrice > 0) { + formik.setFieldValue('total_price', roundPrice(qty * unitPrice)); + } + } + break; + } + + case 'unit_price': { + if (unitPrice > 0) { + formik.setFieldValue('total_price', roundPrice(qty * unitPrice)); + } + break; + } + + // ===== TOTAL EDITABLE ===== + case 'total_weight': { + if (totalWeight > 0) { + formik.setFieldValue('avg_weight', roundWeight(totalWeight / qty)); + } + break; + } + + case 'total_price': { + if (totalPrice > 0) { + formik.setFieldValue('unit_price', roundPrice(totalPrice / qty)); + } + break; } } }; @@ -183,7 +237,7 @@ const DeliveryOrderProductForm = ({
)} -
+
- +
+
+
+ + {isResponseSuccess(productData) + ? productData?.data?.uom.name + : ''} + +
+ } bottomLabel={ formik.values.marketing_product_id ? 'Stok dijual: ' + salesOrders?.find( (item) => item.id === formik.values.marketing_product_id - )?.qty + )?.qty + + ' ' + + (isResponseSuccess(productData) + ? productData?.data?.uom.name + : '') : '' } /> -
-
-
- { - formik.handleChange(e); - setCurrentInput(e.target.name); - }} - onBlur={() => handleBlurField('avg_weight')} - isError={Boolean(formik.errors.avg_weight)} - errorMessage={formik.errors.avg_weight} - placeholder='Masukan Bobot Rata-rata' - /> - - + { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} + onBlur={() => handleBlurField('avg_weight')} + isError={Boolean(formik.errors.avg_weight)} + errorMessage={formik.errors.avg_weight} + placeholder='Masukan Bobot Rata-rata' + /> Number(value.toFixed(2)); +const roundPrice = (value: number) => Math.round(value); const SalesOrderProductForm = ({ initialValues, @@ -39,6 +43,19 @@ const SalesOrderProductForm = ({ }) => { const [formErrorMessage, setFormErrorMessage] = useState(''); const [currentInput, setCurrentInput] = useState(''); + const [selectedProductWarehouse, setSelectedProductWarehouse] = + useState(null); + + // ============ Fetch Data ============ + const { data: productData } = useSWR( + selectedProductWarehouse?.product_id + ? ProductApi.basePath + '/' + selectedProductWarehouse?.product_id + : null, + () => + selectedProductWarehouse?.product_id + ? ProductApi.getSingle(selectedProductWarehouse?.product_id) + : undefined + ); // ============ Formik ============ const formik = useFormik({ @@ -69,17 +86,21 @@ const SalesOrderProductForm = ({ const { options: kandangSourceOptions, isLoadingOptions: isLoadingKandangSourceOptions, + setInputValue: setKandangInputValue, + loadMore: loadMoreKandang, } = useSelect(WarehouseApi.basePath, 'id', 'name'); const { options: warehouseSourceOptions, rawData: warehouseSourceRawData, isLoadingOptions: isLoadingWarehouseSourceOptions, + setInputValue: setWarehouseInputValue, + loadMore: loadMoreWarehouse, } = useSelect( ProductWarehouseApi.basePath, 'id', 'product.name', - 'search', + '', { warehouse_id: formik.values.kandang_id?.toString() ?? '', } @@ -112,6 +133,7 @@ const SalesOrderProductForm = ({ const productWarehouse = warehouseSourceRawData?.data.find( (item: ProductWarehouse) => item.id === newId ); + setSelectedProductWarehouse(productWarehouse || null); formik.setFieldValue('qty', productWarehouse?.quantity); handleBlurField('qty'); } else { @@ -139,34 +161,60 @@ const SalesOrderProductForm = ({ const handleBlurField = (field: string) => { setCurrentInput(field); - const { qty, unit_price, total_price, avg_weight, total_weight } = - formik.values; - if (field === 'unit_price' || field === 'total_price' || field === 'qty') { - if (qty && unit_price && (field === 'unit_price' || field === 'qty')) { - formik.setFieldValue( - 'total_price', - (qty as number) * (unit_price as number) - ); - } else if (qty && total_price && field === 'total_price') { - formik.setFieldValue( - 'unit_price', - (total_price as number) / (qty as number) - ); + const qty = Number(formik.values.qty || 0); + const avgWeight = Number(formik.values.avg_weight || 0); + const totalWeight = Number(formik.values.total_weight || 0); + const unitPrice = Number(formik.values.unit_price || 0); + const totalPrice = Number(formik.values.total_price || 0); + + if (qty <= 0) return; + + switch (field) { + // ===== SOURCE FIELDS ===== + case 'qty': { + if (avgWeight > 0) { + formik.setFieldValue('total_weight', roundWeight(qty * avgWeight)); + } + + if (unitPrice > 0) { + formik.setFieldValue('total_price', roundPrice(qty * unitPrice)); + } + break; } - } - if (field === 'avg_weight' || field === 'total_weight' || field === 'qty') { - if (qty && avg_weight && (field === 'avg_weight' || field === 'qty')) { - formik.setFieldValue( - 'total_weight', - (qty as number) * (avg_weight as number) - ); - } else if (qty && total_weight && field === 'total_weight') { - formik.setFieldValue( - 'avg_weight', - (total_weight as number) / (qty as number) - ); + case 'avg_weight': { + if (avgWeight > 0) { + const tw = roundWeight(qty * avgWeight); + formik.setFieldValue('total_weight', tw); + + if (unitPrice > 0) { + formik.setFieldValue('total_price', roundPrice(qty * unitPrice)); + } + } + break; + } + + case 'unit_price': { + if (unitPrice > 0) { + formik.setFieldValue('total_price', roundPrice(qty * unitPrice)); + } + break; + } + + // ===== TOTAL EDITABLE ===== + case 'total_weight': { + if (totalWeight > 0) { + formik.setFieldValue('avg_weight', roundWeight(totalWeight / qty)); + } + break; + } + + case 'total_price': { + if (totalPrice > 0) { + formik.setFieldValue('unit_price', roundPrice(totalPrice / qty)); + } + break; } } }; @@ -188,7 +236,7 @@ const SalesOrderProductForm = ({
)} -
+
+
+
+
+ + {isResponseSuccess(productData) + ? productData?.data?.uom.name + : ''} + +
+ } bottomLabel={ isResponseSuccess(warehouseSourceRawData) && formik.values.product_warehouse_id @@ -264,32 +328,13 @@ const SalesOrderProductForm = ({ (item) => item.id === formik.values.product_warehouse_id )?.quantity ?? 0 )} ${ - warehouseSourceRawData?.data?.find( - (item) => item.id === formik.values.product_warehouse_id - )?.product?.uom?.name ?? '' + isResponseSuccess(productData) + ? productData?.data?.uom.name + : '' }` : '' } /> -
-
-
- { - formik.handleChange(e); - setCurrentInput(e.target.name); - }} - onBlur={() => handleBlurField('avg_weight')} - isError={ - formik.touched.avg_weight && Boolean(formik.errors.avg_weight) - } - errorMessage={formik.errors.avg_weight} - placeholder='Masukan Bobot Rata-rata' - /> + { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} + onBlur={() => handleBlurField('avg_weight')} + isError={ + formik.touched.avg_weight && Boolean(formik.errors.avg_weight) + } + errorMessage={formik.errors.avg_weight} + placeholder='Masukan Bobot Rata-rata' + /> { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await AreaApi.delete(selectedArea?.id as number); + const deleteResponse = await AreaApi.delete(selectedArea?.id as number); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshAreas(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/bank/BanksTable.tsx b/src/components/pages/master-data/bank/BanksTable.tsx index f28f4bd0..c5a564fe 100644 --- a/src/components/pages/master-data/bank/BanksTable.tsx +++ b/src/components/pages/master-data/bank/BanksTable.tsx @@ -20,7 +20,7 @@ import RequirePermission from '@/components/helper/RequirePermission'; import { Bank } from '@/types/api/master-data/bank'; import { BankApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { ROWS_OPTIONS } from '@/config/constant'; @@ -177,7 +177,14 @@ const BanksTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await BankApi.delete(selectedBank?.id as number); + const deleteResponse = await BankApi.delete(selectedBank?.id as number); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshBanks(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/customer/CustomersTable.tsx b/src/components/pages/master-data/customer/CustomersTable.tsx index 3e442620..e605d9f7 100644 --- a/src/components/pages/master-data/customer/CustomersTable.tsx +++ b/src/components/pages/master-data/customer/CustomersTable.tsx @@ -11,7 +11,7 @@ import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; import RequirePermission from '@/components/helper/RequirePermission'; import { ROWS_OPTIONS } from '@/config/constant'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { cn } from '@/lib/helper'; import { CustomerApi } from '@/services/api/master-data'; import { useTableFilter } from '@/services/hooks/useTableFilter'; @@ -186,7 +186,16 @@ const CustomersTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await CustomerApi.delete(selectedCustomer?.id as number); + const deleteResponse = await CustomerApi.delete( + selectedCustomer?.id as number + ); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshCustomers(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/fcr/FcrsTable.tsx b/src/components/pages/master-data/fcr/FcrsTable.tsx index 2d65a406..2eb8d8da 100644 --- a/src/components/pages/master-data/fcr/FcrsTable.tsx +++ b/src/components/pages/master-data/fcr/FcrsTable.tsx @@ -20,7 +20,7 @@ import RequirePermission from '@/components/helper/RequirePermission'; import { Fcr } from '@/types/api/master-data/fcr'; import { FcrApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { ROWS_OPTIONS } from '@/config/constant'; @@ -164,7 +164,14 @@ const FcrsTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await FcrApi.delete(selectedFcr?.id as number); + const deleteResponse = await FcrApi.delete(selectedFcr?.id as number); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshFcrs(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/flock/FlocksTable.tsx b/src/components/pages/master-data/flock/FlocksTable.tsx index ce8f701a..baeaa69e 100644 --- a/src/components/pages/master-data/flock/FlocksTable.tsx +++ b/src/components/pages/master-data/flock/FlocksTable.tsx @@ -19,7 +19,7 @@ import DebouncedTextInput from '@/components/input/DebouncedTextInput'; import SelectInput, { OptionType } from '@/components/input/SelectInput'; import { ROWS_OPTIONS } from '@/config/constant'; import Table from '@/components/Table'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; const RowsOptions = ({ @@ -182,7 +182,14 @@ const FlockTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await FlockApi.delete(selectedFlock?.id as number); + const deleteResponse = await FlockApi.delete(selectedFlock?.id as number); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshFlocks(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/kandang/KandangsTable.tsx b/src/components/pages/master-data/kandang/KandangsTable.tsx index 1bd7badb..7d79d456 100644 --- a/src/components/pages/master-data/kandang/KandangsTable.tsx +++ b/src/components/pages/master-data/kandang/KandangsTable.tsx @@ -25,7 +25,7 @@ import RequirePermission from '@/components/helper/RequirePermission'; import { Kandang } from '@/types/api/master-data/kandang'; import { KandangApi } from '@/services/api/master-data'; import { cn, formatNumber } from '@/lib/helper'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { ROWS_OPTIONS } from '@/config/constant'; @@ -199,7 +199,16 @@ const KandangsTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await KandangApi.delete(selectedKandang?.id as number); + const deleteResponse = await KandangApi.delete( + selectedKandang?.id as number + ); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshKandangs(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/kandang/form/KandangForm.tsx b/src/components/pages/master-data/kandang/form/KandangForm.tsx index acced3c5..22ad91f8 100644 --- a/src/components/pages/master-data/kandang/form/KandangForm.tsx +++ b/src/components/pages/master-data/kandang/form/KandangForm.tsx @@ -215,7 +215,7 @@ const KandangForm = ({ type = 'add', initialValues }: KandangFormProps) => { required label='Nama' name='name' - placeholder='Masukkan nama lokasi' + placeholder='Masukkan nama kandang' value={formik.values.name} onChange={formik.handleChange} onBlur={formik.handleBlur} diff --git a/src/components/pages/master-data/location/LocationsTable.tsx b/src/components/pages/master-data/location/LocationsTable.tsx index 10fe46c9..a35ffd09 100644 --- a/src/components/pages/master-data/location/LocationsTable.tsx +++ b/src/components/pages/master-data/location/LocationsTable.tsx @@ -25,7 +25,7 @@ import RequirePermission from '@/components/helper/RequirePermission'; import { Location } from '@/types/api/master-data/location'; import { LocationApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { ROWS_OPTIONS } from '@/config/constant'; @@ -186,7 +186,16 @@ const LocationsTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await LocationApi.delete(selectedLocation?.id as number); + const deleteResponse = await LocationApi.delete( + selectedLocation?.id as number + ); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshLocations(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/nonstock/NonstocksTable.tsx b/src/components/pages/master-data/nonstock/NonstocksTable.tsx index 7066c19a..6aeb3f99 100644 --- a/src/components/pages/master-data/nonstock/NonstocksTable.tsx +++ b/src/components/pages/master-data/nonstock/NonstocksTable.tsx @@ -25,7 +25,7 @@ import RequirePermission from '@/components/helper/RequirePermission'; import { Nonstock } from '@/types/api/master-data/nonstock'; import { NonstockApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { ROWS_OPTIONS } from '@/config/constant'; @@ -198,7 +198,16 @@ const NonstocksTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await NonstockApi.delete(selectedNonstock?.id as number); + const deleteResponse = await NonstockApi.delete( + selectedNonstock?.id as number + ); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshNonstocks(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/nonstock/form/NonstockForm.tsx b/src/components/pages/master-data/nonstock/form/NonstockForm.tsx index cd2c361b..bfe88c0e 100644 --- a/src/components/pages/master-data/nonstock/form/NonstockForm.tsx +++ b/src/components/pages/master-data/nonstock/form/NonstockForm.tsx @@ -83,7 +83,7 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { const formikInitialValues = useMemo(() => { return { name: initialValues?.name ?? '', - uomId: initialValues?.uom_id ?? 0, + uomId: initialValues?.uom?.id ?? 0, uom: initialValues?.uom ? { value: initialValues?.uom?.id, @@ -229,7 +229,7 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { required label='Nama' name='name' - placeholder='Masukkan nama lokasi' + placeholder='Masukkan nama nonstock' value={formik.values.name} onChange={formik.handleChange} onBlur={formik.handleBlur} diff --git a/src/components/pages/master-data/product-category/ProductCategoryTable.tsx b/src/components/pages/master-data/product-category/ProductCategoryTable.tsx index a9b98bcb..e25dfd56 100644 --- a/src/components/pages/master-data/product-category/ProductCategoryTable.tsx +++ b/src/components/pages/master-data/product-category/ProductCategoryTable.tsx @@ -20,7 +20,7 @@ import RequirePermission from '@/components/helper/RequirePermission'; import { ProductCategory } from '@/types/api/master-data/product-category'; import { ProductCategoryApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { ROWS_OPTIONS } from '@/config/constant'; @@ -170,7 +170,16 @@ const ProductCategoryTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await ProductCategoryApi.delete(selectedProductCategory?.id as number); + const deleteResponse = await ProductCategoryApi.delete( + selectedProductCategory?.id as number + ); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshProductCategories(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/product/ProductTable.tsx b/src/components/pages/master-data/product/ProductTable.tsx index 957d0551..74137a14 100644 --- a/src/components/pages/master-data/product/ProductTable.tsx +++ b/src/components/pages/master-data/product/ProductTable.tsx @@ -25,7 +25,7 @@ import RequirePermission from '@/components/helper/RequirePermission'; import { Product } from '@/types/api/master-data/product'; import { ProductApi } from '@/services/api/master-data'; import { cn } from '@/lib/helper'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { ROWS_OPTIONS } from '@/config/constant'; @@ -230,8 +230,19 @@ const ProductsTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await ProductApi.delete(selectedProduct?.id as number); + + const deleteResponse = await ProductApi.delete( + selectedProduct?.id as number + ); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshProducts(); + deleteModal.closeModal(); toast.success('Successfully delete Product!'); setIsDeleteLoading(false); diff --git a/src/components/pages/master-data/product/form/ProductForm.schema.ts b/src/components/pages/master-data/product/form/ProductForm.schema.ts index 9dcf713e..8a1d3de2 100644 --- a/src/components/pages/master-data/product/form/ProductForm.schema.ts +++ b/src/components/pages/master-data/product/form/ProductForm.schema.ts @@ -3,7 +3,7 @@ import * as Yup from 'yup'; type ProductFormSchemaType = { name: string; brand: string; - sku: string; + sku?: string; uom?: { value: number; label: string; @@ -15,10 +15,16 @@ type ProductFormSchemaType = { } | null; product_category_id: number; product_price: number | string; - selling_price: number | string; - tax: number | string; - expiry_period: number | string; - supplier_ids: number[]; + selling_price?: number | string; + tax?: number | string; + expiry_period?: number | string; + suppliers: { + supplier: { + value: number; + label: string; + } | null; + price: number; + }[]; flags: string[]; }; @@ -26,7 +32,7 @@ export const ProductFormSchema: Yup.ObjectSchema = Yup.object({ name: Yup.string().required('Nama wajib diisi!'), brand: Yup.string().required('Merek wajib diisi!'), - sku: Yup.string().required('SKU wajib diisi!'), + sku: Yup.string(), uom: Yup.object({ value: Yup.number() @@ -58,24 +64,34 @@ export const ProductFormSchema: Yup.ObjectSchema = .min(1, 'Harga produk tidak boleh kurang dari 1!'), selling_price: Yup.number() - .required('Harga jual wajib diisi!') - .typeError('Harga jual wajib diisi!') + .typeError('Harga hanya boleh angka!') .min(1, 'Harga jual tidak boleh kurang dari 1!'), tax: Yup.number() - .required('Pajak wajib diisi!') - .typeError('Pajak wajib diisi!') + .typeError('Pajak hanya boleh angka!') .min(0, 'Pajak tidak boleh kurang dari 0!') .max(100, 'Pajak tidak boleh lebih dari 100%!'), expiry_period: Yup.number() - .required('Periode kadaluarsa wajib diisi!') - .typeError('Periode kadaluarsa wajib diisi!') + .typeError('Periode kadaluarsa hanya boleh angka!') .min(1, 'Periode kadaluarsa tidak boleh kurang dari 1 hari!'), - supplier_ids: Yup.array() - .of(Yup.number().required().typeError('Supplier tidak valid!')) - .min(1, 'Minimal harus ada 1 supplier!') + suppliers: Yup.array() + .of( + Yup.object({ + supplier: Yup.object({ + value: Yup.number() + .min(1, 'Supplier wajib dipilih!') + .required('Supplier wajib dipilih!') + .typeError('Supplier wajib dipilih!'), + label: Yup.string().required('Supplier wajib dipilih!'), + }).required('Supplier wajib dipilih!'), + price: Yup.number() + .min(1, 'Harga tidak boleh kurang dari 1!') + .required('Harga wajib diisi!') + .typeError('Harga wajib diisi!'), + }) + ) .required('Supplier wajib diisi!'), flags: Yup.array() diff --git a/src/components/pages/master-data/product/form/ProductForm.tsx b/src/components/pages/master-data/product/form/ProductForm.tsx index 2fc3b267..8c04d594 100644 --- a/src/components/pages/master-data/product/form/ProductForm.tsx +++ b/src/components/pages/master-data/product/form/ProductForm.tsx @@ -41,6 +41,8 @@ import { cn } from '@/lib/helper'; import { PRODUCT_FLAG_OPTIONS } from '@/config/constant'; import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; import { Supplier } from '@/types/api/master-data/supplier'; +import Card from '@/components/Card'; +import { removeArrayItemAndSync } from '@/lib/utils/formik'; interface ProductFormProps { type?: 'add' | 'edit' | 'detail'; @@ -101,7 +103,15 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { selling_price: initialValues?.selling_price ?? '', tax: initialValues?.tax ?? '', expiry_period: initialValues?.expiry_period ?? '', - supplier_ids: initialValues?.suppliers?.map((s) => s.id) ?? [], + suppliers: initialValues?.suppliers + ? initialValues.suppliers.map((supplier) => ({ + supplier: { + value: supplier.id, + label: supplier.name, + }, + price: supplier.price, + })) + : [], flags: initialValues?.flags ?? [], }), [initialValues] @@ -120,12 +130,17 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { uom_id: values.uom_id, product_category_id: values.product_category_id, product_price: parseInt(values.product_price.toString()) || 0, - selling_price: parseInt(values.selling_price.toString()) || 0, - tax: parseInt(values.tax.toString()) || 0, - expiry_period: parseInt(values.expiry_period.toString()) || 0, - supplier_ids: values.supplier_ids.filter( - (id): id is number => typeof id === 'number' - ), + selling_price: values.selling_price + ? parseInt(values.selling_price.toString()) || 0 + : undefined, + tax: values.tax ? parseInt(values.tax.toString()) || 0 : undefined, + expiry_period: values.expiry_period + ? parseInt(values.expiry_period.toString()) || 0 + : undefined, + suppliers: values.suppliers.map((s) => ({ + supplier_id: s.supplier?.value as number, + price: parseInt(s.price.toString()) || 0, + })), flags: values.flags.filter((f): f is string => typeof f === 'string'), }; switch (type) { @@ -179,13 +194,29 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { category: 'SAPRONAK', }); - const supplierChangeHandler = (val: OptionType | OptionType[] | null) => { - const arr = Array.isArray(val) ? val : val ? [val] : []; - formik.setFieldTouched('supplier_ids', true); - formik.setFieldValue( - 'supplier_ids', - arr.map((v) => (v as OptionType).value) - ); + const filteredSupplierOptions = useMemo(() => { + return supplierOptions.filter((opt) => { + return !formik.values.suppliers.some( + (s) => s.supplier?.value === opt.value + ); + }); + }, [supplierOptions, formik.values.suppliers]); + + const addSupplierHandler = () => { + formik.setFieldValue('suppliers', [ + ...formik.values.suppliers, + { + supplier_id: '', + price: formik.values.product_price, + }, + ]); + }; + + const deleteSupplierItemHandler = (idx: number) => { + const path = 'suppliers'; + + // trims values, errors, and touched at idx + removeArrayItemAndSync(formik, path, idx); }; const deleteProductClickHandler = () => { @@ -201,6 +232,19 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { router.push('/master-data/product'); }; + const isSupplierRepeaterError = ( + column: 'supplier' | 'price', + supplierIdx: number + ) => { + return ( + formik.touched.suppliers?.[supplierIdx]?.[column] && + Boolean( + formik.errors.suppliers?.[supplierIdx] instanceof Object && + formik.errors.suppliers?.[supplierIdx]?.[column] + ) + ); + }; + useEffect(() => { formikSetValues(formikInitialValues); }, [formikSetValues, formikInitialValues]); @@ -271,7 +315,6 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { readOnly={type === 'detail'} /> { readOnly={type === 'detail'} /> {
{ readOnly={type === 'detail'} /> { readOnly={type === 'detail'} />
-
- - (formik.values.supplier_ids || []).includes(opt.value) - )} - onChange={supplierChangeHandler} - options={supplierOptions} - onInputChange={setSupplierSelectInputValue} - onMenuScrollToBottom={loadMoreSuppliers} - isLoading={isLoadingSuppliers} - isError={ - formik.touched.supplier_ids && - Boolean(formik.errors.supplier_ids) - } - errorMessage={formik.errors.supplier_ids as string} - isDisabled={type === 'detail'} - isClearable - /> +
{ isClearable />
+ +
+ {type !== 'detail' && formik.values.suppliers.length === 0 && ( + + )} + + {formik.values.suppliers.length > 0 && ( + +
+

Supplier

+
+ +
+ + + + + + + + + + + {formik.values.suppliers.map((supplier, idx) => ( + + + + {type !== 'detail' && ( + + )} + + ))} + +
+ Supplier + + Harga + Aksi
+ { + formik.setFieldValue( + `suppliers.${idx}.supplier`, + val + ); + }} + isError={isSupplierRepeaterError( + 'supplier', + idx + )} + isClearable + isDisabled={type === 'detail'} + className={{ + wrapper: 'min-w-48 w-full', + }} + /> + + + + +
+
+ + {type !== 'detail' && ( +
+ +
+ )} +
+ )} +
{type !== 'add' && ( diff --git a/src/components/pages/master-data/production-standard/ProductionStandardTable.tsx b/src/components/pages/master-data/production-standard/ProductionStandardTable.tsx index afa41295..b56e31bd 100644 --- a/src/components/pages/master-data/production-standard/ProductionStandardTable.tsx +++ b/src/components/pages/master-data/production-standard/ProductionStandardTable.tsx @@ -7,7 +7,7 @@ import { ProductionStandard } from '@/types/api/master-data/production-standard' import { Icon } from '@iconify/react'; import useSWR from 'swr'; import { ProductionStandardApi } from '@/services/api/master-data'; -import { isResponseSuccess } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; import { CellContext } from '@tanstack/react-table'; import { useModal } from '@/components/Modal'; @@ -94,9 +94,16 @@ const ProductionStandardTable = () => { const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); - await ProductionStandardApi.delete( + const deleteResponse = await ProductionStandardApi.delete( selectedProductionStandard?.id as number ); + + if (isResponseError(deleteResponse)) { + toast.error(deleteResponse.message); + setIsDeleteLoading(false); + return; + } + refreshProductionStandards(); deleteModal.closeModal(); diff --git a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts index 13183e71..eb59a9c0 100644 --- a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts +++ b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts @@ -2,34 +2,30 @@ import * as Yup from 'yup'; // Schema for LAYING category (production_standard_details is required) const LayingRepeaterFormSchema = Yup.object({ - week: Yup.number().required('Minggu wajib diisi!'), + week: Yup.number().required('Wajib diisi!'), production_standard_uniformity_details: Yup.object({ - target_mean_bw: Yup.number().required('Berat rata-rata wajib diisi!'), - max_depletion: Yup.number().required('Maksimal depletion wajib diisi!'), - min_uniformity: Yup.number().required('Minimal uniformitas wajib diisi!'), - feed_intake: Yup.number().required('Pengambilan makanan wajib diisi!'), + target_mean_bw: Yup.number().required('Wajib diisi!'), + max_depletion: Yup.number().required('Wajib diisi!'), + min_uniformity: Yup.number().required('Wajib diisi!'), + feed_intake: Yup.number().required('Wajib diisi!'), }), production_standard_details: Yup.object({ - target_hen_day_production: Yup.number().required( - 'Produksi telur per hari wajib diisi!' - ), - target_hen_house_production: Yup.number().required( - 'Produksi telur per kandang wajib diisi!' - ), - target_egg_weight: Yup.number().required('Berat telur wajib diisi!'), - target_egg_mass: Yup.number().required('Massa telur wajib diisi!'), - standard_fcr: Yup.number().required('FCR wajib diisi!'), + target_hen_day_production: Yup.number().required('Wajib diisi!'), + target_hen_house_production: Yup.number().required('Wajib diisi!'), + target_egg_weight: Yup.number().required('Wajib diisi!'), + target_egg_mass: Yup.number().required('Wajib diisi!'), + standard_fcr: Yup.number().required('Wajib diisi!'), }).required(), }); // Schema for GROWING category (production_standard_details is optional) const GrowingRepeaterFormSchema = Yup.object({ - week: Yup.number().required('Minggu wajib diisi!'), + week: Yup.number().required('Wajib diisi!'), production_standard_uniformity_details: Yup.object({ - target_mean_bw: Yup.number().required('Berat rata-rata wajib diisi!'), - max_depletion: Yup.number().required('Maksimal depletion wajib diisi!'), - min_uniformity: Yup.number().required('Minimal uniformitas wajib diisi!'), - feed_intake: Yup.number().required('Pengambilan makanan wajib diisi!'), + target_mean_bw: Yup.number().required('Wajib diisi!'), + max_depletion: Yup.number().required('Wajib diisi!'), + min_uniformity: Yup.number().required('Wajib diisi!'), + feed_intake: Yup.number().required('Wajib diisi!'), }), production_standard_details: Yup.object({ target_hen_day_production: Yup.number().optional(), diff --git a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx index 8dfc5f45..4512f474 100644 --- a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx +++ b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx @@ -344,7 +344,7 @@ const ProductionStandardForm = ({ const columns = useMemo[]>(() => { const baseColumns: ColumnDef[] = [ { - header: 'Minggu', + header: 'Week', accessorKey: 'week', enableSorting: false, }, @@ -358,30 +358,40 @@ const ProductionStandardForm = ({ header: 'Hen Day', accessorFn: (row) => row.production_standard_details?.target_hen_day_production, + cell: ({ row }) => + `${row.original.production_standard_details?.target_hen_day_production}%`, enableSorting: false, }, { header: 'Hen House', accessorFn: (row) => row.production_standard_details?.target_hen_house_production, + cell: ({ row }) => + `${row.original.production_standard_details?.target_hen_house_production} pc`, enableSorting: false, }, { header: 'Egg Weight', accessorFn: (row) => row.production_standard_details?.target_egg_weight, + cell: ({ row }) => + `${row.original.production_standard_details?.target_egg_weight} g`, enableSorting: false, }, { header: 'Egg Mass', accessorFn: (row) => row.production_standard_details?.target_egg_mass, + cell: ({ row }) => + `${row.original.production_standard_details?.target_egg_mass} g`, enableSorting: false, }, { header: 'FCR', accessorFn: (row) => row.production_standard_details?.standard_fcr, + cell: ({ row }) => + `${row.original.production_standard_details?.standard_fcr} g`, enableSorting: false, }, ] @@ -393,24 +403,32 @@ const ProductionStandardForm = ({ header: 'Mean BW', accessorFn: (row) => row.production_standard_uniformity_details?.target_mean_bw, + cell: ({ row }) => + `${row.original.production_standard_uniformity_details?.target_mean_bw} g`, enableSorting: false, }, { header: 'Max Depletion', accessorFn: (row) => row.production_standard_uniformity_details?.max_depletion, + cell: ({ row }) => + `${row.original.production_standard_uniformity_details?.max_depletion}%`, enableSorting: false, }, { header: 'Min Uniformity', accessorFn: (row) => row.production_standard_uniformity_details?.min_uniformity, + cell: ({ row }) => + `${row.original.production_standard_uniformity_details?.min_uniformity}%`, enableSorting: false, }, { header: 'Feed Intake', accessorFn: (row) => row.production_standard_uniformity_details?.feed_intake, + cell: ({ row }) => + `${row.original.production_standard_uniformity_details?.feed_intake} g`, enableSorting: false, }, ]; @@ -728,7 +746,52 @@ const ProductionStandardForm = ({ }; // ===== Formik Error List ===== - const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); + const { formErrorList, close, handleFormSubmit } = useFormikErrorList( + formik, + { + onBeforeSubmit: (e) => { + e.preventDefault(); + + // For GROWING category, clear production_standard_details errors and set default values + if (formik.values.project_category === 'GROWING') { + // Set default values for production_standard_details + formik.values.details?.forEach((detail) => { + detail.production_standard_details = { + target_hen_day_production: 0, + target_hen_house_production: 0, + target_egg_weight: 0, + target_egg_mass: 0, + standard_fcr: 0, + }; + }); + + // Clear any errors related to production_standard_details + const currentErrors = { ...formik.errors }; + if (currentErrors.details && Array.isArray(currentErrors.details)) { + const cleanedDetails = currentErrors.details + .map((detailError) => { + if (detailError && typeof detailError === 'object') { + const { production_standard_details, ...rest } = detailError; + return Object.keys(rest).length > 0 ? rest : undefined; + } + return detailError; + }) + .filter( + (error): error is Exclude => + error !== undefined + ); + + currentErrors.details = ( + cleanedDetails.length > 0 ? cleanedDetails : undefined + ) as typeof currentErrors.details; + } + formik.setErrors(currentErrors); + } + + return true; + }, + } + ); return ( <> @@ -821,19 +884,20 @@ const ProductionStandardForm = ({ key={`row-${row.index}`} className='sticky bottom-0 bg-base-100 shadow-lg' > - +
} + bottomLabel='Persen (%)' errorMessage={getProductionDetailsError( repeaterFormik.errors .production_standard_details, @@ -894,11 +958,7 @@ const ProductionStandardForm = ({ } onChange={repeaterFormik.handleChange} onBlur={repeaterFormik.handleBlur} - endAdornment={ -
- Butir -
- } + bottomLabel='Butir (pc)' errorMessage={getProductionDetailsError( repeaterFormik.errors .production_standard_details, @@ -930,11 +990,7 @@ const ProductionStandardForm = ({ } onChange={repeaterFormik.handleChange} onBlur={repeaterFormik.handleBlur} - endAdornment={ -
- gr -
- } + bottomLabel='Gram (g)' errorMessage={getProductionDetailsError( repeaterFormik.errors .production_standard_details, @@ -959,17 +1015,13 @@ const ProductionStandardForm = ({ name='production_standard_details.target_egg_mass' label='Egg Mass' placeholder='1' + bottomLabel='Gram (g)' value={ repeaterFormik.values .production_standard_details?.target_egg_mass } onChange={repeaterFormik.handleChange} onBlur={repeaterFormik.handleBlur} - endAdornment={ -
- gr -
- } errorMessage={getProductionDetailsError( repeaterFormik.errors .production_standard_details, @@ -1000,11 +1052,7 @@ const ProductionStandardForm = ({ } onChange={repeaterFormik.handleChange} onBlur={repeaterFormik.handleBlur} - endAdornment={ -
- gr -
- } + bottomLabel='Gram (g)' errorMessage={getProductionDetailsError( repeaterFormik.errors .production_standard_details, @@ -1038,11 +1086,7 @@ const ProductionStandardForm = ({ } onChange={repeaterFormik.handleChange} onBlur={repeaterFormik.handleBlur} - endAdornment={ -
- gr -
- } + bottomLabel='Gram (g)' errorMessage={ repeaterFormik.errors .production_standard_uniformity_details @@ -1072,7 +1116,7 @@ const ProductionStandardForm = ({ } onChange={repeaterFormik.handleChange} onBlur={repeaterFormik.handleBlur} - endAdornment={} + bottomLabel='Persen (%)' errorMessage={ repeaterFormik.errors .production_standard_uniformity_details @@ -1102,7 +1146,7 @@ const ProductionStandardForm = ({ } onChange={repeaterFormik.handleChange} onBlur={repeaterFormik.handleBlur} - endAdornment={} + bottomLabel='Persen (%)' errorMessage={ repeaterFormik.errors .production_standard_uniformity_details @@ -1132,11 +1176,8 @@ const ProductionStandardForm = ({ } onChange={repeaterFormik.handleChange} onBlur={repeaterFormik.handleBlur} - endAdornment={ -
- gr/ekor -
- } + bottomLabel='Gram/Ekor (g)' + endAdornment errorMessage={ repeaterFormik.errors .production_standard_uniformity_details @@ -1162,7 +1203,7 @@ const ProductionStandardForm = ({ type='button' color='error' variant='outline' - className='min-w-24' + className='min-w-xs' onClick={handleCancelEdit} > Batal @@ -1178,7 +1219,7 @@ const ProductionStandardForm = ({