diff --git a/src/components/pages/marketing/MarketingTable.tsx b/src/components/pages/marketing/MarketingTable.tsx index 115d4e63..d1d5940a 100644 --- a/src/components/pages/marketing/MarketingTable.tsx +++ b/src/components/pages/marketing/MarketingTable.tsx @@ -2,7 +2,7 @@ import Button from '@/components/Button'; import CheckboxInput from '@/components/input/CheckboxInput'; -import { OptionType } from '@/components/input/SelectInput'; +import SelectInput, { OptionType } from '@/components/input/SelectInput'; import Modal, { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes'; @@ -280,11 +280,6 @@ const MarketingTable = () => { placeholder: 'Cari Sales Order', }} /> -
+ + {/* select multiple product */} + + {/* select status */} + + {/* select customer */} + + )} - {initialValues?.latest_approval?.step_number == 2 && ( + {initialValues?.latest_approval?.step_number != 1 && ( )} @@ -405,14 +412,16 @@ const MarketingDetail = ({ )}
- + {initialValues?.latest_approval?.step_number != 3 && ( + + )}
@@ -725,7 +807,9 @@ const MarketingForm = ({
; - -// "marketing_product_id": 3, -// "qty": 20, -// "unit_price": 1000, -// "avg_weight": 1.1, -// "total_weight": 220, -// "total_price": 20000, -// "delivery_date": "2025-11-09", -// "vehicle_number": "D 4321 XXX" 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 e08044f7..b11d643f 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -15,15 +15,20 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import { SalesOrderProductFormValues } from '../sales-order/SalesOrderProduct.schema'; import { BaseSalesOrder } from '@/types/api/marketing/marketing'; import Badge from '@/components/Badge'; +import { SalesProductToFieldValues } from '../../MarketingForm'; const DeliveryOrderProductForm = ({ + formState, salesOrders, initialValues, + exisitingValues, onSubmitForm, onUpdateForm, }: { + formState: 'add' | 'edit'; salesOrders: BaseSalesOrder[]; initialValues?: DeliveryOrderProductFormValues; + exisitingValues?: DeliveryOrderProductFormValues[]; onSubmitForm?: (value: DeliveryOrderProductFormValues) => Promise; onUpdateForm?: ( id: number, @@ -34,6 +39,7 @@ const DeliveryOrderProductForm = ({ const [selectedProduct, setSelectedProduct] = useState( null ); + const [currentInput, setCurrentInput] = useState(''); const formik = useFormik({ enableReinitialize: true, @@ -48,15 +54,15 @@ const DeliveryOrderProductForm = ({ total_price: initialValues?.total_price || undefined, marketing_product: initialValues?.marketing_product || undefined, }, + isInitialValid: false, validationSchema: DeliveryOrderProductSchema, validateOnBlur: true, - validateOnChange: false, onSubmit: async (values) => { setFormErrorMessage(''); if (initialValues?.id) { await onUpdateForm?.(initialValues.id, values); } else { - await onSubmitForm?.(values); + await onUpdateForm?.(values.marketing_product_id as number, values); } handleResetForm(); }, @@ -81,6 +87,7 @@ const DeliveryOrderProductForm = ({ }; const handleBlurField = (field: string) => { + setCurrentInput(field); const { qty, unit_price, total_price, avg_weight, total_weight } = formik.values; @@ -101,47 +108,37 @@ const DeliveryOrderProductForm = ({ } }; - const MarketingProductToFieldValues = ( - product: BaseSalesOrder - ): SalesOrderProductFormValues => { - return { - id: product.id, - vehicle_number: product.vehicle_number, - kandang_id: product.product_warehouse.warehouse.id, - kandang: { - value: product.product_warehouse.warehouse.id, - label: product.product_warehouse.warehouse.name, - }, - product_warehouse: { - value: product.product_warehouse.id, - label: product.product_warehouse.product.name, - }, - product_warehouse_id: product.product_warehouse.id, - unit_price: product.unit_price, - total_weight: product.total_weight, - qty: product.qty, - avg_weight: product.avg_weight, - total_price: product.total_price, - }; - }; - - const options = salesOrders.map((item) => ({ - value: item.id, - label: `${item.product_warehouse.product.name} - ${item.product_warehouse.warehouse.name}`, - })); + const options = exisitingValues + ?.map((item) => { + if (!Boolean(item.qty)) { + return { + value: item.id, + label: `${item.marketing_product?.product_warehouse?.label} - ${item.marketing_product?.kandang?.label}`, + } as OptionType; + } else { + return null; + } + }) + ?.filter((item) => item != null) as OptionType[]; const { setValues: setFormikValues } = formik; useEffect(() => { if (initialValues) { - setFormikValues(initialValues); - const value = salesOrders.find( - (item) => item.id === initialValues.marketing_product_id - ); - setSelectedProduct({ - value: value?.id, - label: `${value?.product_warehouse.product.name} - ${value?.product_warehouse.warehouse.name}`, - } as OptionType); + if (!Boolean(initialValues.qty)) { + handleResetForm(); + } else { + setFormikValues(initialValues); + // const value = exisitingValues?.find( + // (item) => item.id === initialValues?.id + // ); + if (initialValues?.marketing_product_id) { + setSelectedProduct({ + value: initialValues?.id, + label: `${initialValues?.marketing_product?.product_warehouse?.label} - ${initialValues?.marketing_product?.kandang?.label}`, + } as OptionType); + } + } } }, [initialValues]); @@ -149,17 +146,21 @@ const DeliveryOrderProductForm = ({ <>
{ + e.preventDefault(); + handleBlurField(currentInput); + formik.handleSubmit(e); + }} onReset={handleResetForm} > {/* - {JSON.stringify(initialValues)} - - - {JSON.stringify(formik.errors)} + {JSON.stringify(exisitingValues)} {JSON.stringify(formik.values)} + */} + {/* + {JSON.stringify(formik.errors)}
{JSON.stringify(formik.values.marketing_product)} @@ -176,14 +177,14 @@ const DeliveryOrderProductForm = ({ options={options} label='Produk' placeholder='Pilih Produk' - isDisabled + isDisabled={formState == 'edit'} value={ selectedProduct ? ({ value: selectedProduct?.value, - label: salesOrders.find( + label: exisitingValues?.find( (item) => item.id === selectedProduct?.value - )?.product_warehouse.product.name, + )?.marketing_product?.product_warehouse?.label, } as OptionType) : null } @@ -191,7 +192,7 @@ const DeliveryOrderProductForm = ({ const selected = value as OptionType; setSelectedProduct(selected); - const so = salesOrders.find( + const so = salesOrders?.find( (item) => item.id === selected?.value ); if (!so) { @@ -212,7 +213,7 @@ const DeliveryOrderProductForm = ({ formik.setValues({ ...formik.values, marketing_product_id: selected.value as number, - marketing_product: MarketingProductToFieldValues(so), + marketing_product: SalesProductToFieldValues(so), qty: formik.values.qty || so.qty, unit_price: so.unit_price, total_price: so.total_price, @@ -230,9 +231,9 @@ const DeliveryOrderProductForm = ({ className={{ badge: 'whitespace-nowrap font-semibold' }} > { - salesOrders.find( + exisitingValues?.find( (item) => item.id === selectedProduct?.value - )?.product_warehouse?.warehouse?.name + )?.marketing_product?.kandang?.label } ) @@ -254,6 +255,9 @@ const DeliveryOrderProductForm = ({ } errorMessage={formik.errors.delivery_date} placeholder='Pilih Tanggal' + className={{ + inputWrapper: 'bg-white', + }} required /> @@ -278,7 +282,10 @@ const DeliveryOrderProductForm = ({ label='Kuantitas' name='qty' value={formik.values.qty} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('qty')} isError={Boolean(formik.errors.qty)} errorMessage={formik.errors.qty} @@ -290,7 +297,10 @@ const DeliveryOrderProductForm = ({ label='Avg. Bobot (Kg)' name='avg_weight' value={formik.values.avg_weight} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('avg_weight')} isError={Boolean(formik.errors.avg_weight)} errorMessage={formik.errors.avg_weight} @@ -302,7 +312,10 @@ const DeliveryOrderProductForm = ({ label='Harga Satuan (Rp)' name='unit_price' value={formik.values.unit_price} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('unit_price')} isError={Boolean(formik.errors.unit_price)} errorMessage={formik.errors.unit_price} @@ -314,7 +327,10 @@ const DeliveryOrderProductForm = ({ label='Total Bobot (Kg)' name='total_weight' value={formik.values.total_weight} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('total_weight')} isError={Boolean(formik.errors.total_weight)} errorMessage={formik.errors.total_weight} @@ -326,7 +342,10 @@ const DeliveryOrderProductForm = ({ label='Total Penjualan (Rp)' name='total_price' value={formik.values.total_price} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('total_price')} isError={Boolean(formik.errors.total_price)} errorMessage={formik.errors.total_price} diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx index 12675c3f..f1324a90 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx @@ -5,7 +5,7 @@ import { SalesOrderProductFormValues, SalesOrderProductSchema, } from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema'; -import { RefObject, useState } from 'react'; +import { RefObject, useMemo, useState } from 'react'; import SelectInput, { OptionType, useSelect, @@ -20,16 +20,20 @@ import { isResponseSuccess } from '@/lib/api-helper'; import { formatVechicleNumber } from '@/lib/helper'; import PatternInput from '@/components/input/PatternInput'; import Alert from '@/components/Alert'; +import { ProductCalculationFields, recalculate } from '../../MarketingForm'; const SalesOrderProductForm = ({ initialValues, + exisitingValues, onSubmitForm, }: { initialValues?: SalesOrderProductFormValues; + exisitingValues?: SalesOrderProductFormValues[]; modalRef?: RefObject; onSubmitForm?: (value: SalesOrderProductFormValues) => Promise; }) => { const [formErrorMessage, setFormErrorMessage] = useState(''); + const [currentInput, setCurrentInput] = useState(''); const formik = useFormik({ enableReinitialize: true, @@ -51,6 +55,8 @@ const SalesOrderProductForm = ({ onSubmitForm?.(values); handleResetForm(); }, + validateOnBlur: true, + isInitialValid: false, }); const { @@ -72,6 +78,15 @@ const SalesOrderProductForm = ({ } ); + const productOptionsFiltered = useMemo(() => { + return warehouseSourceOptions.filter( + (product) => + !exisitingValues + ?.map((item) => item.product_warehouse_id) + .includes(product.value) + ); + }, [warehouseSourceOptions, exisitingValues]); + const kandangChangeHandler = (val: OptionType | OptionType[] | null) => { formik.setFieldValue('kandang', val as OptionType); formik.setFieldValue('kandang_id', (val as OptionType)?.value); @@ -115,6 +130,7 @@ const SalesOrderProductForm = ({ }; const handleBlurField = (field: string) => { + setCurrentInput(field); const { qty, unit_price, total_price, avg_weight, total_weight } = formik.values; @@ -151,7 +167,11 @@ const SalesOrderProductForm = ({ <> { + e.preventDefault(); + handleBlurField(currentInput); + formik.handleSubmit(e); + }} onReset={handleResetForm} > {formErrorMessage && ( @@ -200,12 +220,18 @@ const SalesOrderProductForm = ({ { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('qty')} isError={formik.touched.qty && Boolean(formik.errors.qty)} errorMessage={formik.errors.qty} @@ -229,7 +258,10 @@ const SalesOrderProductForm = ({ label='Avg. Bobot (Kg)' name='avg_weight' value={formik.values.avg_weight} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('avg_weight')} isError={ formik.touched.avg_weight && Boolean(formik.errors.avg_weight) @@ -242,7 +274,10 @@ const SalesOrderProductForm = ({ label='Harga Satuan (Rp)' name='unit_price' value={formik.values.unit_price} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('unit_price')} isError={ formik.touched.unit_price && Boolean(formik.errors.unit_price) @@ -255,7 +290,10 @@ const SalesOrderProductForm = ({ label='Total Bobot (Kg)' name='total_weight' value={formik.values.total_weight} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('total_weight')} isError={ formik.touched.total_weight && Boolean(formik.errors.total_weight) @@ -268,7 +306,10 @@ const SalesOrderProductForm = ({ label='Total Penjualan (Rp)' name='total_price' value={formik.values.total_price} - onChange={formik.handleChange} + onChange={(e) => { + formik.handleChange(e); + setCurrentInput(e.target.name); + }} onBlur={() => handleBlurField('total_price')} isError={ formik.touched.total_price && Boolean(formik.errors.total_price) diff --git a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx index 5d0fb693..1fd14b7b 100644 --- a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx @@ -4,7 +4,6 @@ import Button from '@/components/Button'; import { Icon } from '@iconify/react'; import * as TanStack from '@tanstack/react-table'; import { useMemo, useRef } from 'react'; -import CheckboxInput from '@/components/input/CheckboxInput'; import { cn, formatCurrency, @@ -12,49 +11,24 @@ import { formatNumber, formatVechicleNumber, } from '@/lib/helper'; -import { SalesOrderProductFormValues } from '../repeater/sales-order/SalesOrderProduct.schema'; -import DateInput from '@/components/input/DateInput'; type DeliveryOrderProductTableProps = { data: DeliveryOrderProductFormValues[]; - salesOrder: SalesOrderProductFormValues[]; formType?: 'add' | 'edit' | 'add_deliver' | 'edit_deliver'; - rowSelection: Record; - setRowSelection: React.Dispatch< - React.SetStateAction> - >; - selectedRowIds: number[]; - onDelete: (id: number) => void; onEdit: (id: number) => void; - onBulkDelete: () => void; onAddProductClick: () => void; - onInputDate: (data: DeliveryOrderProductFormValues) => void; }; const DeliveryOrderProductTable = ({ data, - salesOrder, formType, - rowSelection, - setRowSelection, - selectedRowIds, - onDelete, onEdit, - onBulkDelete, onAddProductClick, - onInputDate, }: DeliveryOrderProductTableProps) => { - const onDeleteRef = useRef(onDelete); - const onEditRef = useRef(onDelete); - onDeleteRef.current = onDelete; + const onEditRef = useRef(onEdit); onEditRef.current = onEdit; - const canAddData = salesOrder.reduce((acc, curr) => { - const deliveredQty = data.filter( - (deliveryItem) => deliveryItem.marketing_product_id == curr.id - ); - return acc && deliveredQty.length != salesOrder.length; - }, true); + const canAddData = data.filter((item) => !Boolean(item.qty)); const columns = useMemo(() => { const cols = [ @@ -93,54 +67,23 @@ const DeliveryOrderProductTable = ({ { accessorFn: (row: DeliveryOrderProductFormValues) => row.do_number, header: 'No. Pengiriman', - cell: ( - props: TanStack.CellContext - ) =>
{props.row.original.do_number}
, - }, - { - accessorFn: (row: DeliveryOrderProductFormValues) => - row.delivery_date - ? formatDate(row.delivery_date as string, 'DD MMM YYYY') - : '-', - header: 'Tanggal Delivery', cell: ( props: TanStack.CellContext ) => ( <> - {formType == 'add_deliver' && ( - { - onInputDate({ - ...props.row.original, - delivery_date: val.target.value, - }); - }} - /> - )} - - {formType == 'edit_deliver' && - formatDate( - props.row.original.delivery_date as string, - 'DD MMM YYYY' - )} + {props.row.original.do_number ? props.row.original.do_number : '-'} ), }, { - accessorFn: (row: DeliveryOrderProductFormValues) => - formatVechicleNumber(row.vehicle_number as string), + accessorFn: (row: DeliveryOrderProductFormValues) => row.vehicle_number, header: 'No. Polisi', + cell: ( + props: TanStack.CellContext + ) => + props.row.original.vehicle_number + ? formatVechicleNumber(props.row.original.vehicle_number as string) + : '-', }, { accessorFn: (row: DeliveryOrderProductFormValues) => @@ -154,29 +97,77 @@ const DeliveryOrderProductTable = ({ }, { accessorFn: (row: DeliveryOrderProductFormValues) => - formatCurrency(parseFloat(row.unit_price as string)), + row.delivery_date + ? formatDate(row.delivery_date as string, 'DD MMM YYYY') + : '-', + header: 'Tanggal Delivery', + cell: ( + props: TanStack.CellContext + ) => + props.row.original.delivery_date + ? formatDate( + props.row.original.delivery_date as string, + 'DD MMM YYYY' + ) + : '-', + }, + { + accessorFn: (row: DeliveryOrderProductFormValues) => row.unit_price, header: 'Harga Satuan (Rp)', + cell: ( + props: TanStack.CellContext + ) => + props.row.original.unit_price + ? formatCurrency( + parseFloat(props.row.original.unit_price as string) + ) + : '-', }, { - accessorFn: (row: DeliveryOrderProductFormValues) => - formatNumber(parseFloat(row.total_weight as string)), + accessorFn: (row: DeliveryOrderProductFormValues) => row.total_weight, header: 'Total Bobot (Kg)', + cell: ( + props: TanStack.CellContext + ) => + props.row.original.total_weight + ? formatNumber( + parseFloat(props.row.original.total_weight as string) + ) + : '-', }, { - accessorFn: (row: DeliveryOrderProductFormValues) => - formatNumber(parseFloat(row.qty as string)), + accessorFn: (row: DeliveryOrderProductFormValues) => row.qty, header: 'Kuantitas', + cell: ( + props: TanStack.CellContext + ) => + props.row.original.qty + ? formatNumber(parseFloat(props.row.original.qty as string)) + : '-', }, { - accessorFn: (row: DeliveryOrderProductFormValues) => - formatNumber(parseFloat(row.avg_weight as string)), + accessorFn: (row: DeliveryOrderProductFormValues) => row.avg_weight, header: 'Avg. Bobot (Kg)', + cell: ( + props: TanStack.CellContext + ) => + props.row.original.avg_weight + ? formatNumber(parseFloat(props.row.original.avg_weight as string)) + : '-', }, { - accessorFn: (row: DeliveryOrderProductFormValues) => - formatCurrency(parseFloat(row.total_price as string)), + accessorFn: (row: DeliveryOrderProductFormValues) => row.total_price, header: 'Total Penjualan (Rp)', + cell: ( + props: TanStack.CellContext + ) => + props.row.original.total_price + ? formatCurrency( + parseFloat(props.row.original.total_price as string) + ) + : '-', }, + { header: 'Aksi', cell: ( @@ -184,44 +175,45 @@ const DeliveryOrderProductTable = ({ ) => (
<> - - {/* */} + {props.row.original.qty && ( + + )} + {!props.row.original.qty && '-'} + {/* {formType == 'add_deliver' && ( + + )} */}
), }, ]; if (formType == 'add_deliver') { - return cols.filter( - (col) => col.header != 'Aksi' && col.header != 'No. Pengiriman' - ); + return cols.filter((col) => col.header != 'No. Pengiriman'); } return cols; - }, [formType, onInputDate, onEditRef]); + }, [formType, onEditRef]); return ( <> - rowSelection={rowSelection} - setRowSelection={setRowSelection} data={data} columns={columns} className={{ @@ -246,17 +238,17 @@ const DeliveryOrderProductTable = ({ } />
- {/* */} - {selectedRowIds.length > 0 && ( + + {/* {selectedRowIds.length > 0 && (
); diff --git a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx index be86dd6c..c37bbfb1 100644 --- a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx @@ -16,7 +16,7 @@ import CheckboxInput from '@/components/input/CheckboxInput'; type SalesOrderProductTableProps = { data: SalesOrderProductFormValues[]; - formType?: 'add' | 'edit' | 'deliver'; + formType: 'add' | 'edit' | 'add_deliver' | 'edit_deliver'; rowSelection: Record; setRowSelection: React.Dispatch< React.SetStateAction> @@ -140,7 +140,7 @@ const SalesOrderProductTable = ({ setRowSelection={setRowSelection} data={data} columns={ - formType == 'deliver' + formType == 'add_deliver' || formType == 'edit_deliver' ? columns.filter( (col) => col.header != 'Aksi' && col.id != 'select' ) @@ -167,7 +167,7 @@ const SalesOrderProductTable = ({
} /> - {formType != 'deliver' && ( + {formType != 'add_deliver' && formType != 'edit_deliver' && (