fix(FE-179-220): Adjust form add and edit delivery, add validation to prevent duplicate product

This commit is contained in:
randy-ar
2025-11-22 12:04:46 +07:00
parent b198f24b75
commit eaaed9521b
10 changed files with 431 additions and 271 deletions
@@ -2,7 +2,7 @@
import Button from '@/components/Button'; import Button from '@/components/Button';
import CheckboxInput from '@/components/input/CheckboxInput'; 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 Modal, { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal'; import ConfirmationModal from '@/components/modal/ConfirmationModal';
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes'; import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
@@ -280,11 +280,6 @@ const MarketingTable = () => {
placeholder: 'Cari Sales Order', placeholder: 'Cari Sales Order',
}} }}
/> />
<TableRowSizeSelector
value={pageSize}
onChange={pageSizeChangeHandler}
options={ROWS_OPTIONS}
/>
<div className='flex flex-row gap-2'> <div className='flex flex-row gap-2'>
<Button <Button
color='success' color='success'
@@ -306,6 +301,34 @@ const MarketingTable = () => {
Reject Reject
</Button> </Button>
</div> </div>
<TableRowSizeSelector
value={pageSize}
onChange={pageSizeChangeHandler}
options={ROWS_OPTIONS}
>
{/* select multiple product */}
<SelectInput
label='Product'
isClearable
placeholder='Pilih product'
options={[]}
isMulti
/>
{/* select status */}
<SelectInput
label='Status'
isClearable
placeholder='Pilih status'
options={[]}
/>
{/* select customer */}
<SelectInput
label='Customer'
isClearable
placeholder='Pilih customer'
options={[]}
/>
</TableRowSizeSelector>
</div> </div>
<Table <Table
rowSelection={rowSelection} rowSelection={rowSelection}
@@ -158,12 +158,19 @@ const MarketingDetail = ({
</Button> </Button>
</> </>
)} )}
{initialValues?.latest_approval?.step_number == 2 && ( {initialValues?.latest_approval?.step_number != 1 && (
<Button <Button
color='success' color='success'
href={`/marketing/add/delivery-orders?marketingId=${initialValues?.id}`} href={
initialValues?.latest_approval?.step_number == 3
? `/marketing/detail/delivery-orders/edit?marketingId=${initialValues?.id}`
: `/marketing/add/delivery-orders?marketingId=${initialValues?.id}`
}
> >
<Icon icon='mdi:truck' width={24} height={24} /> <Icon icon='mdi:truck' width={24} height={24} />
{initialValues?.latest_approval?.step_number == 3
? 'Edit '
: 'Tambah '}
Delivery Order Delivery Order
</Button> </Button>
)} )}
@@ -405,14 +412,16 @@ const MarketingDetail = ({
</Card> </Card>
)} )}
<div className='flex flex-row gap-3'> <div className='flex flex-row gap-3'>
<Button {initialValues?.latest_approval?.step_number != 3 && (
color='warning' <Button
type='button' color='warning'
href={`/marketing/detail/${initialValues?.latest_approval.step_number == 3 ? 'delivery-orders' : 'sales-orders'}/edit?marketingId=${initialValues?.id}`} type='button'
> href={`/marketing/detail/${initialValues?.latest_approval.step_number == 3 ? 'delivery-orders' : 'sales-orders'}/edit?marketingId=${initialValues?.id}`}
<Icon icon='mdi:pencil' width={24} height={24} /> >
Edit <Icon icon='mdi:pencil' width={24} height={24} />
</Button> Edit
</Button>
)}
<Button color='error' onClick={deleteClickHandler}> <Button color='error' onClick={deleteClickHandler}>
<Icon icon='mdi:delete' width={24} height={24} /> <Icon icon='mdi:delete' width={24} height={24} />
Hapus Hapus
@@ -436,7 +445,7 @@ const MarketingDetail = ({
<ConfirmationModalWithNotes <ConfirmationModalWithNotes
ref={confirmationModal.ref} ref={confirmationModal.ref}
type={approvalAction === 'APPROVED' ? 'success' : 'error'} type={approvalAction === 'APPROVED' ? 'success' : 'error'}
text={`Apakah anda yakin ingin ${approvalAction} data penjualan ini?`} text={`Apakah anda yakin ingin ${approvalAction == 'APPROVED' ? 'approve' : 'reject'} data penjualan ini?`}
secondaryButton={{ secondaryButton={{
text: 'Tidak', text: 'Tidak',
}} }}
@@ -49,22 +49,23 @@ export const SalesOrderSchema: Yup.ObjectSchema<SalesOrderSchemaType> =
export const DeliveryOrderSchema: Yup.ObjectSchema<DeliveryOrderSchemaType> = export const DeliveryOrderSchema: Yup.ObjectSchema<DeliveryOrderSchemaType> =
Yup.object({ Yup.object({
delivery_order: Yup.array() delivery_order: Yup.array()
.of(DeliveryOrderProductSchema)
.min(1, 'Pengiriman wajib diisi!') .min(1, 'Pengiriman wajib diisi!')
.required() .required('Pengiriman wajib diisi!')
.test( .test(
'at-least-one-delivery-date', 'at-least-one-valid-row',
'Minimal ada satu tanggal pengiriman yang harus diisi!', 'Minimal ada satu baris pengiriman yang valid!',
(value) => { function (items) {
if (!value || value.length == 0) { if (!items || items.length === 0) return false;
return false;
} // VALIDASI: minimal 1 item valid full
return value.some( const itemSchema = DeliveryOrderProductSchema;
(item) =>
item.delivery_date !== null && const hasValidItem = items.some((item) => {
item.delivery_date !== undefined && if (!item) return false;
item.delivery_date !== '' return itemSchema.isValidSync(item, { abortEarly: true });
); });
return hasValidItem;
} }
), ),
}); });
@@ -53,7 +53,16 @@ const MemoizedSalesOrderProductForm = memo(SalesOrderProductForm);
const MemoizedDeliveryOrderProductTable = memo(DeliveryOrderProductTable); const MemoizedDeliveryOrderProductTable = memo(DeliveryOrderProductTable);
const MemoizedDeliveryOrderProductForm = memo(DeliveryOrderProductForm); const MemoizedDeliveryOrderProductForm = memo(DeliveryOrderProductForm);
const MarketingProductToFieldValues = ( // ================== EXTERNAL HELPER FUNCTION ==================
export interface ProductCalculationFields {
qty: string | number | undefined;
unit_price: string | number | undefined;
total_price: string | number | undefined;
avg_weight: string | number | undefined;
total_weight: string | number | undefined;
}
export const SalesProductToFieldValues = (
product: BaseSalesOrder product: BaseSalesOrder
): SalesOrderProductFormValues => { ): SalesOrderProductFormValues => {
return { return {
@@ -76,8 +85,7 @@ const MarketingProductToFieldValues = (
total_price: product.total_price, total_price: product.total_price,
}; };
}; };
export const DeliveryProductToFieldValues = (
const DeliveryProductToFieldValues = (
salesOrders: BaseSalesOrder[], salesOrders: BaseSalesOrder[],
delivery: BaseDeliveryOrder delivery: BaseDeliveryOrder
): DeliveryOrderProductFormValues[] => { ): DeliveryOrderProductFormValues[] => {
@@ -119,8 +127,7 @@ const DeliveryProductToFieldValues = (
}); });
return data; return data;
}; };
export const mergeSOwithDO = (
const mergeSOwithDO = (
salesOrders: SalesOrderProductFormValues[], salesOrders: SalesOrderProductFormValues[],
deliveryOrders: DeliveryOrderProductFormValues[] deliveryOrders: DeliveryOrderProductFormValues[]
): DeliveryOrderProductFormValues[] => { ): DeliveryOrderProductFormValues[] => {
@@ -135,15 +142,63 @@ const mergeSOwithDO = (
delivery_date: delivery?.delivery_date || undefined, delivery_date: delivery?.delivery_date || undefined,
do_number: delivery?.do_number || undefined, do_number: delivery?.do_number || undefined,
vehicle_number: delivery?.vehicle_number || so.vehicle_number, vehicle_number: delivery?.vehicle_number || so.vehicle_number,
unit_price: delivery?.unit_price ?? so.unit_price, unit_price: delivery?.unit_price,
total_weight: delivery?.total_weight ?? so.total_weight, total_weight: delivery?.total_weight,
qty: delivery?.qty ?? so.qty, qty: delivery?.qty,
avg_weight: delivery?.avg_weight ?? so.avg_weight, avg_weight: delivery?.avg_weight,
total_price: delivery?.total_price ?? so.total_price, total_price: delivery?.total_price,
marketing_product: so, // jika ada, override marketing_product: so, // jika ada, override
} as DeliveryOrderProductFormValues; } as DeliveryOrderProductFormValues;
}); });
}; };
export const recalculate = (
field: string,
values: ProductCalculationFields
) => {
console.log('Values');
console.log(values);
const { qty, unit_price, total_price, avg_weight, total_weight } = values;
const result: Partial<ProductCalculationFields> = {};
if (field == 'unit_price' || field == 'total_price' || field == 'qty') {
if (qty && unit_price && (field == 'unit_price' || field == 'qty')) {
result.total_price = Number(qty) * Number(unit_price);
} else if (qty && total_price && field == 'total_price') {
result.unit_price = Number(total_price) / Number(qty);
}
}
if (field == 'avg_weight' || field == 'total_weight' || field == 'qty') {
if (qty && avg_weight && (field == 'avg_weight' || field == 'qty')) {
result.total_weight = Number(qty) * Number(avg_weight);
} else if (qty && total_weight && field == 'total_weight') {
result.avg_weight = Number(total_weight) / Number(qty);
}
}
console.log('Result');
console.log(result);
return result;
};
export const getSubmitField = (values: ProductCalculationFields) => {
const { qty, unit_price, total_price, avg_weight, total_weight } = values;
// Harga logic
if (qty && unit_price && !total_price) {
return 'unit_price';
}
if (qty && total_price && !unit_price) {
return 'total_price';
}
// Bobot logic
if (qty && avg_weight && !total_weight) {
return 'avg_weight';
}
if (qty && total_weight && !avg_weight) {
return 'total_weight';
}
// Tidak ada yang perlu dihitung
return '';
};
const MarketingForm = ({ const MarketingForm = ({
formType = 'add', formType = 'add',
@@ -162,11 +217,14 @@ const MarketingForm = ({
useState<SalesOrderProductFormValues | null>(null); useState<SalesOrderProductFormValues | null>(null);
const [selectedDeliveryProduct, setSelectedDeliveryProduct] = const [selectedDeliveryProduct, setSelectedDeliveryProduct] =
useState<DeliveryOrderProductFormValues | null>(null); useState<DeliveryOrderProductFormValues | null>(null);
const [deliveryFormState, setDeliveryFormState] = useState<'add' | 'edit'>(
'add'
);
const [deliveryOrderValues, setDeliveryOrderValues] = useState< const [deliveryOrderValues, setDeliveryOrderValues] = useState<
DeliveryOrderProductFormValues[] DeliveryOrderProductFormValues[]
>( >(
mergeSOwithDO( mergeSOwithDO(
initialValues?.sales_order?.map(MarketingProductToFieldValues) ?? [], initialValues?.sales_order?.map(SalesProductToFieldValues) ?? [],
initialValues?.delivery_order?.flatMap((delivery) => initialValues?.delivery_order?.flatMap((delivery) =>
DeliveryProductToFieldValues(initialValues.sales_order, delivery) DeliveryProductToFieldValues(initialValues.sales_order, delivery)
) ?? [] ) ?? []
@@ -212,10 +270,10 @@ const MarketingForm = ({
: null, : null,
sales_order: sales_order:
initialValues?.sales_order?.map((product) => initialValues?.sales_order?.map((product) =>
MarketingProductToFieldValues(product) SalesProductToFieldValues(product)
) ?? [], ) ?? [],
delivery_order: mergeSOwithDO( delivery_order: mergeSOwithDO(
initialValues?.sales_order?.map(MarketingProductToFieldValues) ?? [], initialValues?.sales_order?.map(SalesProductToFieldValues) ?? [],
initialValues?.delivery_order?.flatMap((delivery) => initialValues?.delivery_order?.flatMap((delivery) =>
DeliveryProductToFieldValues(initialValues.sales_order, delivery) DeliveryProductToFieldValues(initialValues.sales_order, delivery)
) ?? [] ) ?? []
@@ -366,15 +424,18 @@ const MarketingForm = ({
if (isResponseSuccess(updateDeliveryRes)) { if (isResponseSuccess(updateDeliveryRes)) {
console.log(updateDeliveryRes); console.log(updateDeliveryRes);
toast.success(updateDeliveryRes?.message as string); toast.success(updateDeliveryRes?.message as string);
// router.push(`/marketing/detail?marketingId=${initialValues?.id}`);
setDeliveryOrderValues( setDeliveryOrderValues(
updateDeliveryRes.data?.delivery_order?.flatMap((delivery) => mergeSOwithDO(
DeliveryProductToFieldValues( formik.values.sales_order,
updateDeliveryRes.data?.sales_order, updateDeliveryRes.data?.delivery_order?.flatMap((delivery) =>
delivery DeliveryProductToFieldValues(
) updateDeliveryRes.data?.sales_order,
) ?? [] delivery
)
) ?? []
)
); );
router.push(`/marketing/detail?marketingId=${initialValues?.id}`);
} }
if (isResponseError(updateDeliveryRes)) { if (isResponseError(updateDeliveryRes)) {
console.log(updateDeliveryRes); console.log(updateDeliveryRes);
@@ -441,12 +502,31 @@ const MarketingForm = ({
const handleAddSubmitSO = useCallback( const handleAddSubmitSO = useCallback(
async (values: SalesOrderProductFormValues) => { async (values: SalesOrderProductFormValues) => {
const currentProducts = formik.values.sales_order; const currentProducts = formik.values.sales_order;
const newValues = { const newValues = {
...values, ...values,
id: values.id ?? Date.now(), id: values.id ?? Date.now(),
}; };
formik.setFieldValue('sales_order', [...currentProducts, newValues]); const existingIndex = currentProducts.findIndex(
(item) =>
item.kandang_id === newValues.kandang_id &&
item.product_warehouse_id === newValues.product_warehouse_id
);
let updatedProducts = [];
if (existingIndex !== -1) {
// Overwrite
updatedProducts = currentProducts.map((item, index) =>
index === existingIndex ? newValues : item
);
} else {
// Add new item
updatedProducts = [...currentProducts, newValues];
}
formik.setFieldValue('sales_order', updatedProducts);
addSOModal.closeModal(); addSOModal.closeModal();
}, },
@@ -462,14 +542,15 @@ const MarketingForm = ({
[formik] [formik]
); );
const handleEditDO = useCallback( const handleEditDO = useCallback(
(id: number) => { (id: number, values?: DeliveryOrderProductFormValues) => {
setDeliveryFormState('edit');
const currentProducts = formik.values.delivery_order.find( const currentProducts = formik.values.delivery_order.find(
(product) => product.id == id (product) => product.id == id
); );
setSelectedDeliveryProduct(currentProducts ?? null); setSelectedDeliveryProduct(values ?? currentProducts ?? null);
addDOModal.openModal(); addDOModal.openModal();
}, },
[formik] [formik, addDOModal]
); );
const handleBulkDeleteDO = useCallback(() => { const handleBulkDeleteDO = useCallback(() => {
setDeliveryOrderValues((prev) => setDeliveryOrderValues((prev) =>
@@ -478,10 +559,13 @@ const MarketingForm = ({
setRowDOSelection({}); setRowDOSelection({});
}, [formik, selectedRowDOIds]); }, [formik, selectedRowDOIds]);
const handleAddDOClick = useCallback(() => { const handleAddDOClick = useCallback(() => {
setDeliveryFormState('add');
setSelectedDeliveryProduct(null); setSelectedDeliveryProduct(null);
addDOModal.openModal(); addDOModal.openModal();
}, [addDOModal]); }, [addDOModal]);
const handleAddSubmitDO = useCallback( const handleAddSubmitDO = useCallback(
async (values: DeliveryOrderProductFormValues) => { async (values: DeliveryOrderProductFormValues) => {
const newValues = { const newValues = {
@@ -490,8 +574,8 @@ const MarketingForm = ({
}; };
setDeliveryOrderValues((prev) => [...prev, newValues]); setDeliveryOrderValues((prev) => [...prev, newValues]);
addDOModal.closeModal(); addDOModal.closeModal();
setSelectedDeliveryProduct(null);
}, },
[formik, addDOModal] [formik, addDOModal]
); );
@@ -515,8 +599,8 @@ const MarketingForm = ({
product.id === id ? { ...product, ...values } : product product.id === id ? { ...product, ...values } : product
) )
); );
setSelectedDeliveryProduct(null);
addDOModal.closeModal(); addDOModal.closeModal();
setSelectedDeliveryProduct(null);
}, },
[formik, addDOModal] [formik, addDOModal]
); );
@@ -576,25 +660,23 @@ const MarketingForm = ({
</Card> </Card>
{/* Input Table Repeater Sales Order */} {/* Input Table Repeater Sales Order */}
{(formType == 'add' || formType == 'edit') && ( <Card
<Card title='Informasi Produk'
title='Informasi Produk' className={{
className={{ wrapper: 'bg-white w-full',
wrapper: 'bg-white w-full', }}
}} >
> <MemoizedSalesOrderProductTable
<MemoizedSalesOrderProductTable formType={formType}
formType={formType} data={memoSalesOrder}
data={memoSalesOrder} rowSelection={rowSOSelection}
rowSelection={rowSOSelection} setRowSelection={setRowSOSelection}
setRowSelection={setRowSOSelection} selectedRowIds={selectedRowSOIds}
selectedRowIds={selectedRowSOIds} onDelete={handleDeleteSO}
onDelete={handleDeleteSO} onBulkDelete={handleBulkDeleteSO}
onBulkDelete={handleBulkDeleteSO} onAddProductClick={handleAddSOClick}
onAddProductClick={handleAddSOClick} />
/> </Card>
</Card>
)}
{/* Input Table Repeater Delivery Order */} {/* Input Table Repeater Delivery Order */}
{(formType == 'add_deliver' || formType == 'edit_deliver') && {(formType == 'add_deliver' || formType == 'edit_deliver') &&
@@ -606,18 +688,17 @@ const MarketingForm = ({
wrapper: 'bg-white w-full', wrapper: 'bg-white w-full',
}} }}
> >
{/* <div className='text-blue-500'>
{JSON.stringify(formik.values)}
</div>
<div className='text-red-500'>
{JSON.stringify(formik.errors)}
</div> */}
<MemoizedDeliveryOrderProductTable <MemoizedDeliveryOrderProductTable
formType={formType} formType={formType}
data={deliveryOrderValues} data={deliveryOrderValues}
salesOrder={memoSalesOrder}
rowSelection={rowDOSelection}
setRowSelection={setRowDOSelection}
selectedRowIds={selectedRowDOIds}
onDelete={handleDeleteDO}
onEdit={handleEditDO} onEdit={handleEditDO}
onBulkDelete={handleBulkDeleteDO}
onAddProductClick={handleAddDOClick} onAddProductClick={handleAddDOClick}
onInputDate={handleInputDate}
/> />
</Card> </Card>
)} )}
@@ -698,6 +779,7 @@ const MarketingForm = ({
<MemoizedSalesOrderProductForm <MemoizedSalesOrderProductForm
onSubmitForm={handleAddSubmitSO} onSubmitForm={handleAddSubmitSO}
initialValues={selectedMarketingProduct ?? undefined} initialValues={selectedMarketingProduct ?? undefined}
exisitingValues={memoSalesOrder}
/> />
</div> </div>
</div> </div>
@@ -725,7 +807,9 @@ const MarketingForm = ({
</div> </div>
<div> <div>
<MemoizedDeliveryOrderProductForm <MemoizedDeliveryOrderProductForm
formState={deliveryFormState}
salesOrders={initialValues?.sales_order ?? []} salesOrders={initialValues?.sales_order ?? []}
exisitingValues={deliveryOrderValues}
onSubmitForm={handleAddSubmitDO} onSubmitForm={handleAddSubmitDO}
initialValues={selectedDeliveryProduct ?? undefined} initialValues={selectedDeliveryProduct ?? undefined}
onUpdateForm={handleUpdateDO} onUpdateForm={handleUpdateDO}
@@ -42,22 +42,10 @@ export const DeliveryOrderProductSchema: Yup.ObjectSchema<DeliveryOrderProductSc
.min(1, 'Total Penjualan wajib diisi!') .min(1, 'Total Penjualan wajib diisi!')
.required('Total Penjualan wajib diisi!'), .required('Total Penjualan wajib diisi!'),
vehicle_number: Yup.string().required('Nomor Kendaraan wajib diisi!'), vehicle_number: Yup.string().required('Nomor Kendaraan wajib diisi!'),
delivery_date: Yup.string() delivery_date: Yup.string().required('Tanggal Pengiriman wajib diisi!'),
.required('Tanggal Pengiriman wajib diisi!')
.nullable()
.optional(),
do_number: Yup.string().nullable().optional(), do_number: Yup.string().nullable().optional(),
}); });
export type DeliveryOrderProductFormValues = Yup.InferType< export type DeliveryOrderProductFormValues = Yup.InferType<
typeof DeliveryOrderProductSchema typeof DeliveryOrderProductSchema
>; >;
// "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"
@@ -15,15 +15,20 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput';
import { SalesOrderProductFormValues } from '../sales-order/SalesOrderProduct.schema'; import { SalesOrderProductFormValues } from '../sales-order/SalesOrderProduct.schema';
import { BaseSalesOrder } from '@/types/api/marketing/marketing'; import { BaseSalesOrder } from '@/types/api/marketing/marketing';
import Badge from '@/components/Badge'; import Badge from '@/components/Badge';
import { SalesProductToFieldValues } from '../../MarketingForm';
const DeliveryOrderProductForm = ({ const DeliveryOrderProductForm = ({
formState,
salesOrders, salesOrders,
initialValues, initialValues,
exisitingValues,
onSubmitForm, onSubmitForm,
onUpdateForm, onUpdateForm,
}: { }: {
formState: 'add' | 'edit';
salesOrders: BaseSalesOrder[]; salesOrders: BaseSalesOrder[];
initialValues?: DeliveryOrderProductFormValues; initialValues?: DeliveryOrderProductFormValues;
exisitingValues?: DeliveryOrderProductFormValues[];
onSubmitForm?: (value: DeliveryOrderProductFormValues) => Promise<void>; onSubmitForm?: (value: DeliveryOrderProductFormValues) => Promise<void>;
onUpdateForm?: ( onUpdateForm?: (
id: number, id: number,
@@ -34,6 +39,7 @@ const DeliveryOrderProductForm = ({
const [selectedProduct, setSelectedProduct] = useState<OptionType | null>( const [selectedProduct, setSelectedProduct] = useState<OptionType | null>(
null null
); );
const [currentInput, setCurrentInput] = useState<string>('');
const formik = useFormik<DeliveryOrderProductFormValues>({ const formik = useFormik<DeliveryOrderProductFormValues>({
enableReinitialize: true, enableReinitialize: true,
@@ -48,15 +54,15 @@ const DeliveryOrderProductForm = ({
total_price: initialValues?.total_price || undefined, total_price: initialValues?.total_price || undefined,
marketing_product: initialValues?.marketing_product || undefined, marketing_product: initialValues?.marketing_product || undefined,
}, },
isInitialValid: false,
validationSchema: DeliveryOrderProductSchema, validationSchema: DeliveryOrderProductSchema,
validateOnBlur: true, validateOnBlur: true,
validateOnChange: false,
onSubmit: async (values) => { onSubmit: async (values) => {
setFormErrorMessage(''); setFormErrorMessage('');
if (initialValues?.id) { if (initialValues?.id) {
await onUpdateForm?.(initialValues.id, values); await onUpdateForm?.(initialValues.id, values);
} else { } else {
await onSubmitForm?.(values); await onUpdateForm?.(values.marketing_product_id as number, values);
} }
handleResetForm(); handleResetForm();
}, },
@@ -81,6 +87,7 @@ const DeliveryOrderProductForm = ({
}; };
const handleBlurField = (field: string) => { const handleBlurField = (field: string) => {
setCurrentInput(field);
const { qty, unit_price, total_price, avg_weight, total_weight } = const { qty, unit_price, total_price, avg_weight, total_weight } =
formik.values; formik.values;
@@ -101,47 +108,37 @@ const DeliveryOrderProductForm = ({
} }
}; };
const MarketingProductToFieldValues = ( const options = exisitingValues
product: BaseSalesOrder ?.map((item) => {
): SalesOrderProductFormValues => { if (!Boolean(item.qty)) {
return { return {
id: product.id, value: item.id,
vehicle_number: product.vehicle_number, label: `${item.marketing_product?.product_warehouse?.label} - ${item.marketing_product?.kandang?.label}`,
kandang_id: product.product_warehouse.warehouse.id, } as OptionType;
kandang: { } else {
value: product.product_warehouse.warehouse.id, return null;
label: product.product_warehouse.warehouse.name, }
}, })
product_warehouse: { ?.filter((item) => item != null) as OptionType[];
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 { setValues: setFormikValues } = formik; const { setValues: setFormikValues } = formik;
useEffect(() => { useEffect(() => {
if (initialValues) { if (initialValues) {
setFormikValues(initialValues); if (!Boolean(initialValues.qty)) {
const value = salesOrders.find( handleResetForm();
(item) => item.id === initialValues.marketing_product_id } else {
); setFormikValues(initialValues);
setSelectedProduct({ // const value = exisitingValues?.find(
value: value?.id, // (item) => item.id === initialValues?.id
label: `${value?.product_warehouse.product.name} - ${value?.product_warehouse.warehouse.name}`, // );
} as OptionType); if (initialValues?.marketing_product_id) {
setSelectedProduct({
value: initialValues?.id,
label: `${initialValues?.marketing_product?.product_warehouse?.label} - ${initialValues?.marketing_product?.kandang?.label}`,
} as OptionType);
}
}
} }
}, [initialValues]); }, [initialValues]);
@@ -149,17 +146,21 @@ const DeliveryOrderProductForm = ({
<> <>
<form <form
className='size-full' className='size-full'
onSubmit={formik.handleSubmit} onSubmit={(e) => {
e.preventDefault();
handleBlurField(currentInput);
formik.handleSubmit(e);
}}
onReset={handleResetForm} onReset={handleResetForm}
> >
{/* <small className='block text-blue-500'> {/* <small className='block text-blue-500'>
{JSON.stringify(initialValues)} {JSON.stringify(exisitingValues)}
</small>
<small className='block text-red-500'>
{JSON.stringify(formik.errors)}
</small> </small>
<small className='block text-emerald-500'> <small className='block text-emerald-500'>
{JSON.stringify(formik.values)} {JSON.stringify(formik.values)}
</small> */}
{/* <small className='block text-red-500'>
{JSON.stringify(formik.errors)}
</small> </small>
<div className='hidden'> <div className='hidden'>
{JSON.stringify(formik.values.marketing_product)} {JSON.stringify(formik.values.marketing_product)}
@@ -176,14 +177,14 @@ const DeliveryOrderProductForm = ({
options={options} options={options}
label='Produk' label='Produk'
placeholder='Pilih Produk' placeholder='Pilih Produk'
isDisabled isDisabled={formState == 'edit'}
value={ value={
selectedProduct selectedProduct
? ({ ? ({
value: selectedProduct?.value, value: selectedProduct?.value,
label: salesOrders.find( label: exisitingValues?.find(
(item) => item.id === selectedProduct?.value (item) => item.id === selectedProduct?.value
)?.product_warehouse.product.name, )?.marketing_product?.product_warehouse?.label,
} as OptionType) } as OptionType)
: null : null
} }
@@ -191,7 +192,7 @@ const DeliveryOrderProductForm = ({
const selected = value as OptionType; const selected = value as OptionType;
setSelectedProduct(selected); setSelectedProduct(selected);
const so = salesOrders.find( const so = salesOrders?.find(
(item) => item.id === selected?.value (item) => item.id === selected?.value
); );
if (!so) { if (!so) {
@@ -212,7 +213,7 @@ const DeliveryOrderProductForm = ({
formik.setValues({ formik.setValues({
...formik.values, ...formik.values,
marketing_product_id: selected.value as number, marketing_product_id: selected.value as number,
marketing_product: MarketingProductToFieldValues(so), marketing_product: SalesProductToFieldValues(so),
qty: formik.values.qty || so.qty, qty: formik.values.qty || so.qty,
unit_price: so.unit_price, unit_price: so.unit_price,
total_price: so.total_price, total_price: so.total_price,
@@ -230,9 +231,9 @@ const DeliveryOrderProductForm = ({
className={{ badge: 'whitespace-nowrap font-semibold' }} className={{ badge: 'whitespace-nowrap font-semibold' }}
> >
{ {
salesOrders.find( exisitingValues?.find(
(item) => item.id === selectedProduct?.value (item) => item.id === selectedProduct?.value
)?.product_warehouse?.warehouse?.name )?.marketing_product?.kandang?.label
} }
</Badge> </Badge>
) )
@@ -254,6 +255,9 @@ const DeliveryOrderProductForm = ({
} }
errorMessage={formik.errors.delivery_date} errorMessage={formik.errors.delivery_date}
placeholder='Pilih Tanggal' placeholder='Pilih Tanggal'
className={{
inputWrapper: 'bg-white',
}}
required required
/> />
@@ -278,7 +282,10 @@ const DeliveryOrderProductForm = ({
label='Kuantitas' label='Kuantitas'
name='qty' name='qty'
value={formik.values.qty} value={formik.values.qty}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('qty')} onBlur={() => handleBlurField('qty')}
isError={Boolean(formik.errors.qty)} isError={Boolean(formik.errors.qty)}
errorMessage={formik.errors.qty} errorMessage={formik.errors.qty}
@@ -290,7 +297,10 @@ const DeliveryOrderProductForm = ({
label='Avg. Bobot (Kg)' label='Avg. Bobot (Kg)'
name='avg_weight' name='avg_weight'
value={formik.values.avg_weight} value={formik.values.avg_weight}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('avg_weight')} onBlur={() => handleBlurField('avg_weight')}
isError={Boolean(formik.errors.avg_weight)} isError={Boolean(formik.errors.avg_weight)}
errorMessage={formik.errors.avg_weight} errorMessage={formik.errors.avg_weight}
@@ -302,7 +312,10 @@ const DeliveryOrderProductForm = ({
label='Harga Satuan (Rp)' label='Harga Satuan (Rp)'
name='unit_price' name='unit_price'
value={formik.values.unit_price} value={formik.values.unit_price}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('unit_price')} onBlur={() => handleBlurField('unit_price')}
isError={Boolean(formik.errors.unit_price)} isError={Boolean(formik.errors.unit_price)}
errorMessage={formik.errors.unit_price} errorMessage={formik.errors.unit_price}
@@ -314,7 +327,10 @@ const DeliveryOrderProductForm = ({
label='Total Bobot (Kg)' label='Total Bobot (Kg)'
name='total_weight' name='total_weight'
value={formik.values.total_weight} value={formik.values.total_weight}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('total_weight')} onBlur={() => handleBlurField('total_weight')}
isError={Boolean(formik.errors.total_weight)} isError={Boolean(formik.errors.total_weight)}
errorMessage={formik.errors.total_weight} errorMessage={formik.errors.total_weight}
@@ -326,7 +342,10 @@ const DeliveryOrderProductForm = ({
label='Total Penjualan (Rp)' label='Total Penjualan (Rp)'
name='total_price' name='total_price'
value={formik.values.total_price} value={formik.values.total_price}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('total_price')} onBlur={() => handleBlurField('total_price')}
isError={Boolean(formik.errors.total_price)} isError={Boolean(formik.errors.total_price)}
errorMessage={formik.errors.total_price} errorMessage={formik.errors.total_price}
@@ -5,7 +5,7 @@ import {
SalesOrderProductFormValues, SalesOrderProductFormValues,
SalesOrderProductSchema, SalesOrderProductSchema,
} from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema'; } from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema';
import { RefObject, useState } from 'react'; import { RefObject, useMemo, useState } from 'react';
import SelectInput, { import SelectInput, {
OptionType, OptionType,
useSelect, useSelect,
@@ -20,16 +20,20 @@ import { isResponseSuccess } from '@/lib/api-helper';
import { formatVechicleNumber } from '@/lib/helper'; import { formatVechicleNumber } from '@/lib/helper';
import PatternInput from '@/components/input/PatternInput'; import PatternInput from '@/components/input/PatternInput';
import Alert from '@/components/Alert'; import Alert from '@/components/Alert';
import { ProductCalculationFields, recalculate } from '../../MarketingForm';
const SalesOrderProductForm = ({ const SalesOrderProductForm = ({
initialValues, initialValues,
exisitingValues,
onSubmitForm, onSubmitForm,
}: { }: {
initialValues?: SalesOrderProductFormValues; initialValues?: SalesOrderProductFormValues;
exisitingValues?: SalesOrderProductFormValues[];
modalRef?: RefObject<HTMLDialogElement | null>; modalRef?: RefObject<HTMLDialogElement | null>;
onSubmitForm?: (value: SalesOrderProductFormValues) => Promise<void>; onSubmitForm?: (value: SalesOrderProductFormValues) => Promise<void>;
}) => { }) => {
const [formErrorMessage, setFormErrorMessage] = useState(''); const [formErrorMessage, setFormErrorMessage] = useState('');
const [currentInput, setCurrentInput] = useState<string>('');
const formik = useFormik<SalesOrderProductFormValues>({ const formik = useFormik<SalesOrderProductFormValues>({
enableReinitialize: true, enableReinitialize: true,
@@ -51,6 +55,8 @@ const SalesOrderProductForm = ({
onSubmitForm?.(values); onSubmitForm?.(values);
handleResetForm(); handleResetForm();
}, },
validateOnBlur: true,
isInitialValid: false,
}); });
const { 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) => { const kandangChangeHandler = (val: OptionType | OptionType[] | null) => {
formik.setFieldValue('kandang', val as OptionType); formik.setFieldValue('kandang', val as OptionType);
formik.setFieldValue('kandang_id', (val as OptionType)?.value); formik.setFieldValue('kandang_id', (val as OptionType)?.value);
@@ -115,6 +130,7 @@ const SalesOrderProductForm = ({
}; };
const handleBlurField = (field: string) => { const handleBlurField = (field: string) => {
setCurrentInput(field);
const { qty, unit_price, total_price, avg_weight, total_weight } = const { qty, unit_price, total_price, avg_weight, total_weight } =
formik.values; formik.values;
@@ -151,7 +167,11 @@ const SalesOrderProductForm = ({
<> <>
<form <form
className='size-full' className='size-full'
onSubmit={formik.handleSubmit} onSubmit={(e) => {
e.preventDefault();
handleBlurField(currentInput);
formik.handleSubmit(e);
}}
onReset={handleResetForm} onReset={handleResetForm}
> >
{formErrorMessage && ( {formErrorMessage && (
@@ -200,12 +220,18 @@ const SalesOrderProductForm = ({
<SelectInput <SelectInput
required required
label='Produk' label='Produk'
options={warehouseSourceOptions} options={productOptionsFiltered}
isLoading={isLoadingWarehouseSourceOptions} isLoading={isLoadingWarehouseSourceOptions}
value={formik.values.product_warehouse} value={formik.values.product_warehouse}
onChange={warehouseChangeHandler} onChange={warehouseChangeHandler}
isClearable isClearable
placeholder='Pilih Kandang Terlebih Dahulu' placeholder={
formik.values.kandang_id
? productOptionsFiltered.length == 0
? 'Tidak ada produk yang tersedia'
: 'Pilih produk'
: 'Pilih Kandang Terlebih Dahulu'
}
isDisabled={!formik.values.kandang_id} isDisabled={!formik.values.kandang_id}
isError={ isError={
formik.touched.product_warehouse_id && formik.touched.product_warehouse_id &&
@@ -218,7 +244,10 @@ const SalesOrderProductForm = ({
label='Kuantitas' label='Kuantitas'
name='qty' name='qty'
value={formik.values.qty} value={formik.values.qty}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('qty')} onBlur={() => handleBlurField('qty')}
isError={formik.touched.qty && Boolean(formik.errors.qty)} isError={formik.touched.qty && Boolean(formik.errors.qty)}
errorMessage={formik.errors.qty} errorMessage={formik.errors.qty}
@@ -229,7 +258,10 @@ const SalesOrderProductForm = ({
label='Avg. Bobot (Kg)' label='Avg. Bobot (Kg)'
name='avg_weight' name='avg_weight'
value={formik.values.avg_weight} value={formik.values.avg_weight}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('avg_weight')} onBlur={() => handleBlurField('avg_weight')}
isError={ isError={
formik.touched.avg_weight && Boolean(formik.errors.avg_weight) formik.touched.avg_weight && Boolean(formik.errors.avg_weight)
@@ -242,7 +274,10 @@ const SalesOrderProductForm = ({
label='Harga Satuan (Rp)' label='Harga Satuan (Rp)'
name='unit_price' name='unit_price'
value={formik.values.unit_price} value={formik.values.unit_price}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('unit_price')} onBlur={() => handleBlurField('unit_price')}
isError={ isError={
formik.touched.unit_price && Boolean(formik.errors.unit_price) formik.touched.unit_price && Boolean(formik.errors.unit_price)
@@ -255,7 +290,10 @@ const SalesOrderProductForm = ({
label='Total Bobot (Kg)' label='Total Bobot (Kg)'
name='total_weight' name='total_weight'
value={formik.values.total_weight} value={formik.values.total_weight}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('total_weight')} onBlur={() => handleBlurField('total_weight')}
isError={ isError={
formik.touched.total_weight && Boolean(formik.errors.total_weight) formik.touched.total_weight && Boolean(formik.errors.total_weight)
@@ -268,7 +306,10 @@ const SalesOrderProductForm = ({
label='Total Penjualan (Rp)' label='Total Penjualan (Rp)'
name='total_price' name='total_price'
value={formik.values.total_price} value={formik.values.total_price}
onChange={formik.handleChange} onChange={(e) => {
formik.handleChange(e);
setCurrentInput(e.target.name);
}}
onBlur={() => handleBlurField('total_price')} onBlur={() => handleBlurField('total_price')}
isError={ isError={
formik.touched.total_price && Boolean(formik.errors.total_price) formik.touched.total_price && Boolean(formik.errors.total_price)
@@ -4,7 +4,6 @@ import Button from '@/components/Button';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import * as TanStack from '@tanstack/react-table'; import * as TanStack from '@tanstack/react-table';
import { useMemo, useRef } from 'react'; import { useMemo, useRef } from 'react';
import CheckboxInput from '@/components/input/CheckboxInput';
import { import {
cn, cn,
formatCurrency, formatCurrency,
@@ -12,49 +11,24 @@ import {
formatNumber, formatNumber,
formatVechicleNumber, formatVechicleNumber,
} from '@/lib/helper'; } from '@/lib/helper';
import { SalesOrderProductFormValues } from '../repeater/sales-order/SalesOrderProduct.schema';
import DateInput from '@/components/input/DateInput';
type DeliveryOrderProductTableProps = { type DeliveryOrderProductTableProps = {
data: DeliveryOrderProductFormValues[]; data: DeliveryOrderProductFormValues[];
salesOrder: SalesOrderProductFormValues[];
formType?: 'add' | 'edit' | 'add_deliver' | 'edit_deliver'; formType?: 'add' | 'edit' | 'add_deliver' | 'edit_deliver';
rowSelection: Record<string, boolean>;
setRowSelection: React.Dispatch<
React.SetStateAction<Record<string, boolean>>
>;
selectedRowIds: number[];
onDelete: (id: number) => void;
onEdit: (id: number) => void; onEdit: (id: number) => void;
onBulkDelete: () => void;
onAddProductClick: () => void; onAddProductClick: () => void;
onInputDate: (data: DeliveryOrderProductFormValues) => void;
}; };
const DeliveryOrderProductTable = ({ const DeliveryOrderProductTable = ({
data, data,
salesOrder,
formType, formType,
rowSelection,
setRowSelection,
selectedRowIds,
onDelete,
onEdit, onEdit,
onBulkDelete,
onAddProductClick, onAddProductClick,
onInputDate,
}: DeliveryOrderProductTableProps) => { }: DeliveryOrderProductTableProps) => {
const onDeleteRef = useRef(onDelete); const onEditRef = useRef(onEdit);
const onEditRef = useRef(onDelete);
onDeleteRef.current = onDelete;
onEditRef.current = onEdit; onEditRef.current = onEdit;
const canAddData = salesOrder.reduce((acc, curr) => { const canAddData = data.filter((item) => !Boolean(item.qty));
const deliveredQty = data.filter(
(deliveryItem) => deliveryItem.marketing_product_id == curr.id
);
return acc && deliveredQty.length != salesOrder.length;
}, true);
const columns = useMemo(() => { const columns = useMemo(() => {
const cols = [ const cols = [
@@ -93,54 +67,23 @@ const DeliveryOrderProductTable = ({
{ {
accessorFn: (row: DeliveryOrderProductFormValues) => row.do_number, accessorFn: (row: DeliveryOrderProductFormValues) => row.do_number,
header: 'No. Pengiriman', header: 'No. Pengiriman',
cell: (
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
) => <div>{props.row.original.do_number}</div>,
},
{
accessorFn: (row: DeliveryOrderProductFormValues) =>
row.delivery_date
? formatDate(row.delivery_date as string, 'DD MMM YYYY')
: '-',
header: 'Tanggal Delivery',
cell: ( cell: (
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown> props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
) => ( ) => (
<> <>
{formType == 'add_deliver' && ( {props.row.original.do_number ? props.row.original.do_number : '-'}
<DateInput
name={`delivery_date_${props.row.original.marketing_product_id}`}
className={{
input: 'p-0',
inputWrapper: 'py-1 px-3 h-fit w-fit bg-white',
wrapper: 'p-0',
}}
value={
props.row.original.delivery_date
? formatDate(props.row.original.delivery_date, 'yyyy-MM-DD')
: undefined
}
onChange={(val) => {
onInputDate({
...props.row.original,
delivery_date: val.target.value,
});
}}
/>
)}
{formType == 'edit_deliver' &&
formatDate(
props.row.original.delivery_date as string,
'DD MMM YYYY'
)}
</> </>
), ),
}, },
{ {
accessorFn: (row: DeliveryOrderProductFormValues) => accessorFn: (row: DeliveryOrderProductFormValues) => row.vehicle_number,
formatVechicleNumber(row.vehicle_number as string),
header: 'No. Polisi', header: 'No. Polisi',
cell: (
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
) =>
props.row.original.vehicle_number
? formatVechicleNumber(props.row.original.vehicle_number as string)
: '-',
}, },
{ {
accessorFn: (row: DeliveryOrderProductFormValues) => accessorFn: (row: DeliveryOrderProductFormValues) =>
@@ -154,29 +97,77 @@ const DeliveryOrderProductTable = ({
}, },
{ {
accessorFn: (row: DeliveryOrderProductFormValues) => 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<DeliveryOrderProductFormValues, unknown>
) =>
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)', header: 'Harga Satuan (Rp)',
cell: (
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
) =>
props.row.original.unit_price
? formatCurrency(
parseFloat(props.row.original.unit_price as string)
)
: '-',
}, },
{ {
accessorFn: (row: DeliveryOrderProductFormValues) => accessorFn: (row: DeliveryOrderProductFormValues) => row.total_weight,
formatNumber(parseFloat(row.total_weight as string)),
header: 'Total Bobot (Kg)', header: 'Total Bobot (Kg)',
cell: (
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
) =>
props.row.original.total_weight
? formatNumber(
parseFloat(props.row.original.total_weight as string)
)
: '-',
}, },
{ {
accessorFn: (row: DeliveryOrderProductFormValues) => accessorFn: (row: DeliveryOrderProductFormValues) => row.qty,
formatNumber(parseFloat(row.qty as string)),
header: 'Kuantitas', header: 'Kuantitas',
cell: (
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
) =>
props.row.original.qty
? formatNumber(parseFloat(props.row.original.qty as string))
: '-',
}, },
{ {
accessorFn: (row: DeliveryOrderProductFormValues) => accessorFn: (row: DeliveryOrderProductFormValues) => row.avg_weight,
formatNumber(parseFloat(row.avg_weight as string)),
header: 'Avg. Bobot (Kg)', header: 'Avg. Bobot (Kg)',
cell: (
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
) =>
props.row.original.avg_weight
? formatNumber(parseFloat(props.row.original.avg_weight as string))
: '-',
}, },
{ {
accessorFn: (row: DeliveryOrderProductFormValues) => accessorFn: (row: DeliveryOrderProductFormValues) => row.total_price,
formatCurrency(parseFloat(row.total_price as string)),
header: 'Total Penjualan (Rp)', header: 'Total Penjualan (Rp)',
cell: (
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
) =>
props.row.original.total_price
? formatCurrency(
parseFloat(props.row.original.total_price as string)
)
: '-',
}, },
{ {
header: 'Aksi', header: 'Aksi',
cell: ( cell: (
@@ -184,44 +175,45 @@ const DeliveryOrderProductTable = ({
) => ( ) => (
<div className='flex flex-row gap-1 items-center justify-end h-full mt-2'> <div className='flex flex-row gap-1 items-center justify-end h-full mt-2'>
<> <>
<Button {props.row.original.qty && (
color='warning' <Button
className='px-2 py-1 text-sm' color='warning'
onClick={() => className='px-2 py-1 text-sm'
onEditRef.current(props.row.original.id as number) onClick={() =>
} onEditRef.current(props.row.original.id as number)
type='button' }
> type='button'
<Icon icon='mdi:edit' width={16} height={16} /> Edit >
</Button> <Icon icon='mdi:edit' width={16} height={16} /> Edit
{/* <Button </Button>
color='error' )}
className='p-1' {!props.row.original.qty && '-'}
onClick={() => {/* {formType == 'add_deliver' && (
onDeleteRef.current(props.row.original.id as number) <Button
} color='error'
type='button' className='p-1'
> onClick={() =>
<Icon icon='mdi:trash' width={16} height={16} /> onDeleteRef.current(props.row.original.id as number)
</Button> */} }
type='button'
>
<Icon icon='mdi:trash' width={16} height={16} />
</Button>
)} */}
</> </>
</div> </div>
), ),
}, },
]; ];
if (formType == 'add_deliver') { if (formType == 'add_deliver') {
return cols.filter( return cols.filter((col) => col.header != 'No. Pengiriman');
(col) => col.header != 'Aksi' && col.header != 'No. Pengiriman'
);
} }
return cols; return cols;
}, [formType, onInputDate, onEditRef]); }, [formType, onEditRef]);
return ( return (
<> <>
<Table<DeliveryOrderProductFormValues> <Table<DeliveryOrderProductFormValues>
rowSelection={rowSelection}
setRowSelection={setRowSelection}
data={data} data={data}
columns={columns} columns={columns}
className={{ className={{
@@ -246,17 +238,17 @@ const DeliveryOrderProductTable = ({
} }
/> />
<div className='flex flex-row gap-3 mt-3'> <div className='flex flex-row gap-3 mt-3'>
{/* <Button <Button
type='button' type='button'
variant='outline' variant='outline'
className='justify-start w-fit py-1 text-sm' className='justify-start w-fit py-1 text-sm'
onClick={onAddProductClick} onClick={onAddProductClick}
// disabled={!canAddData} disabled={!canAddData}
> >
<Icon icon='mdi:plus' width={16} height={16} /> <Icon icon='mdi:plus' width={16} height={16} />
Tambah Pengiriman Tambah Pengiriman
</Button> */} </Button>
{selectedRowIds.length > 0 && ( {/* {selectedRowIds.length > 0 && (
<Button <Button
type='button' type='button'
variant='outline' variant='outline'
@@ -271,7 +263,7 @@ const DeliveryOrderProductTable = ({
: ''}{' '} : ''}{' '}
Pengiriman Pengiriman
</Button> </Button>
)} )} */}
</div> </div>
</> </>
); );
@@ -16,7 +16,7 @@ import CheckboxInput from '@/components/input/CheckboxInput';
type SalesOrderProductTableProps = { type SalesOrderProductTableProps = {
data: SalesOrderProductFormValues[]; data: SalesOrderProductFormValues[];
formType?: 'add' | 'edit' | 'deliver'; formType: 'add' | 'edit' | 'add_deliver' | 'edit_deliver';
rowSelection: Record<string, boolean>; rowSelection: Record<string, boolean>;
setRowSelection: React.Dispatch< setRowSelection: React.Dispatch<
React.SetStateAction<Record<string, boolean>> React.SetStateAction<Record<string, boolean>>
@@ -140,7 +140,7 @@ const SalesOrderProductTable = ({
setRowSelection={setRowSelection} setRowSelection={setRowSelection}
data={data} data={data}
columns={ columns={
formType == 'deliver' formType == 'add_deliver' || formType == 'edit_deliver'
? columns.filter( ? columns.filter(
(col) => col.header != 'Aksi' && col.id != 'select' (col) => col.header != 'Aksi' && col.id != 'select'
) )
@@ -167,7 +167,7 @@ const SalesOrderProductTable = ({
</div> </div>
} }
/> />
{formType != 'deliver' && ( {formType != 'add_deliver' && formType != 'edit_deliver' && (
<div className='flex flex-row gap-3 mt-3'> <div className='flex flex-row gap-3 mt-3'>
<Button <Button
type='button' type='button'
@@ -9,15 +9,18 @@ interface TableRowSizeSelectorProps {
value: number; value: number;
onChange: (val: OptionType | OptionType[] | null) => void; onChange: (val: OptionType | OptionType[] | null) => void;
options: OptionType[]; options: OptionType[];
children?: React.ReactNode;
} }
export const TableRowSizeSelector = ({ export const TableRowSizeSelector = ({
value, value,
onChange, onChange,
options, options,
children,
}: TableRowSizeSelectorProps) => { }: TableRowSizeSelectorProps) => {
return ( return (
<div className='flex flex-row justify-end'> <div className='flex flex-row gap-3 items-end justify-end'>
{children}
<SelectInput <SelectInput
label='Baris' label='Baris'
options={options} options={options}