mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
fix(FE-179-220): Adjust form add and edit delivery, add validation to prevent duplicate product
This commit is contained in:
@@ -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',
|
||||
}}
|
||||
/>
|
||||
<TableRowSizeSelector
|
||||
value={pageSize}
|
||||
onChange={pageSizeChangeHandler}
|
||||
options={ROWS_OPTIONS}
|
||||
/>
|
||||
<div className='flex flex-row gap-2'>
|
||||
<Button
|
||||
color='success'
|
||||
@@ -306,6 +301,34 @@ const MarketingTable = () => {
|
||||
Reject
|
||||
</Button>
|
||||
</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>
|
||||
<Table
|
||||
rowSelection={rowSelection}
|
||||
|
||||
@@ -158,12 +158,19 @@ const MarketingDetail = ({
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{initialValues?.latest_approval?.step_number == 2 && (
|
||||
{initialValues?.latest_approval?.step_number != 1 && (
|
||||
<Button
|
||||
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} />
|
||||
{initialValues?.latest_approval?.step_number == 3
|
||||
? 'Edit '
|
||||
: 'Tambah '}
|
||||
Delivery Order
|
||||
</Button>
|
||||
)}
|
||||
@@ -405,14 +412,16 @@ const MarketingDetail = ({
|
||||
</Card>
|
||||
)}
|
||||
<div className='flex flex-row gap-3'>
|
||||
<Button
|
||||
color='warning'
|
||||
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
|
||||
</Button>
|
||||
{initialValues?.latest_approval?.step_number != 3 && (
|
||||
<Button
|
||||
color='warning'
|
||||
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
|
||||
</Button>
|
||||
)}
|
||||
<Button color='error' onClick={deleteClickHandler}>
|
||||
<Icon icon='mdi:delete' width={24} height={24} />
|
||||
Hapus
|
||||
@@ -436,7 +445,7 @@ const MarketingDetail = ({
|
||||
<ConfirmationModalWithNotes
|
||||
ref={confirmationModal.ref}
|
||||
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={{
|
||||
text: 'Tidak',
|
||||
}}
|
||||
|
||||
@@ -49,22 +49,23 @@ export const SalesOrderSchema: Yup.ObjectSchema<SalesOrderSchemaType> =
|
||||
export const DeliveryOrderSchema: Yup.ObjectSchema<DeliveryOrderSchemaType> =
|
||||
Yup.object({
|
||||
delivery_order: Yup.array()
|
||||
.of(DeliveryOrderProductSchema)
|
||||
.min(1, 'Pengiriman wajib diisi!')
|
||||
.required()
|
||||
.required('Pengiriman wajib diisi!')
|
||||
.test(
|
||||
'at-least-one-delivery-date',
|
||||
'Minimal ada satu tanggal pengiriman yang harus diisi!',
|
||||
(value) => {
|
||||
if (!value || value.length == 0) {
|
||||
return false;
|
||||
}
|
||||
return value.some(
|
||||
(item) =>
|
||||
item.delivery_date !== null &&
|
||||
item.delivery_date !== undefined &&
|
||||
item.delivery_date !== ''
|
||||
);
|
||||
'at-least-one-valid-row',
|
||||
'Minimal ada satu baris pengiriman yang valid!',
|
||||
function (items) {
|
||||
if (!items || items.length === 0) return false;
|
||||
|
||||
// VALIDASI: minimal 1 item valid full
|
||||
const itemSchema = DeliveryOrderProductSchema;
|
||||
|
||||
const hasValidItem = items.some((item) => {
|
||||
if (!item) return false;
|
||||
return itemSchema.isValidSync(item, { abortEarly: true });
|
||||
});
|
||||
|
||||
return hasValidItem;
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
@@ -53,7 +53,16 @@ const MemoizedSalesOrderProductForm = memo(SalesOrderProductForm);
|
||||
const MemoizedDeliveryOrderProductTable = memo(DeliveryOrderProductTable);
|
||||
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
|
||||
): SalesOrderProductFormValues => {
|
||||
return {
|
||||
@@ -76,8 +85,7 @@ const MarketingProductToFieldValues = (
|
||||
total_price: product.total_price,
|
||||
};
|
||||
};
|
||||
|
||||
const DeliveryProductToFieldValues = (
|
||||
export const DeliveryProductToFieldValues = (
|
||||
salesOrders: BaseSalesOrder[],
|
||||
delivery: BaseDeliveryOrder
|
||||
): DeliveryOrderProductFormValues[] => {
|
||||
@@ -119,8 +127,7 @@ const DeliveryProductToFieldValues = (
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
const mergeSOwithDO = (
|
||||
export const mergeSOwithDO = (
|
||||
salesOrders: SalesOrderProductFormValues[],
|
||||
deliveryOrders: DeliveryOrderProductFormValues[]
|
||||
): DeliveryOrderProductFormValues[] => {
|
||||
@@ -135,15 +142,63 @@ const mergeSOwithDO = (
|
||||
delivery_date: delivery?.delivery_date || undefined,
|
||||
do_number: delivery?.do_number || undefined,
|
||||
vehicle_number: delivery?.vehicle_number || so.vehicle_number,
|
||||
unit_price: delivery?.unit_price ?? so.unit_price,
|
||||
total_weight: delivery?.total_weight ?? so.total_weight,
|
||||
qty: delivery?.qty ?? so.qty,
|
||||
avg_weight: delivery?.avg_weight ?? so.avg_weight,
|
||||
total_price: delivery?.total_price ?? so.total_price,
|
||||
unit_price: delivery?.unit_price,
|
||||
total_weight: delivery?.total_weight,
|
||||
qty: delivery?.qty,
|
||||
avg_weight: delivery?.avg_weight,
|
||||
total_price: delivery?.total_price,
|
||||
marketing_product: so, // jika ada, override
|
||||
} 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 = ({
|
||||
formType = 'add',
|
||||
@@ -162,11 +217,14 @@ const MarketingForm = ({
|
||||
useState<SalesOrderProductFormValues | null>(null);
|
||||
const [selectedDeliveryProduct, setSelectedDeliveryProduct] =
|
||||
useState<DeliveryOrderProductFormValues | null>(null);
|
||||
const [deliveryFormState, setDeliveryFormState] = useState<'add' | 'edit'>(
|
||||
'add'
|
||||
);
|
||||
const [deliveryOrderValues, setDeliveryOrderValues] = useState<
|
||||
DeliveryOrderProductFormValues[]
|
||||
>(
|
||||
mergeSOwithDO(
|
||||
initialValues?.sales_order?.map(MarketingProductToFieldValues) ?? [],
|
||||
initialValues?.sales_order?.map(SalesProductToFieldValues) ?? [],
|
||||
initialValues?.delivery_order?.flatMap((delivery) =>
|
||||
DeliveryProductToFieldValues(initialValues.sales_order, delivery)
|
||||
) ?? []
|
||||
@@ -212,10 +270,10 @@ const MarketingForm = ({
|
||||
: null,
|
||||
sales_order:
|
||||
initialValues?.sales_order?.map((product) =>
|
||||
MarketingProductToFieldValues(product)
|
||||
SalesProductToFieldValues(product)
|
||||
) ?? [],
|
||||
delivery_order: mergeSOwithDO(
|
||||
initialValues?.sales_order?.map(MarketingProductToFieldValues) ?? [],
|
||||
initialValues?.sales_order?.map(SalesProductToFieldValues) ?? [],
|
||||
initialValues?.delivery_order?.flatMap((delivery) =>
|
||||
DeliveryProductToFieldValues(initialValues.sales_order, delivery)
|
||||
) ?? []
|
||||
@@ -366,15 +424,18 @@ const MarketingForm = ({
|
||||
if (isResponseSuccess(updateDeliveryRes)) {
|
||||
console.log(updateDeliveryRes);
|
||||
toast.success(updateDeliveryRes?.message as string);
|
||||
// router.push(`/marketing/detail?marketingId=${initialValues?.id}`);
|
||||
setDeliveryOrderValues(
|
||||
updateDeliveryRes.data?.delivery_order?.flatMap((delivery) =>
|
||||
DeliveryProductToFieldValues(
|
||||
updateDeliveryRes.data?.sales_order,
|
||||
delivery
|
||||
)
|
||||
) ?? []
|
||||
mergeSOwithDO(
|
||||
formik.values.sales_order,
|
||||
updateDeliveryRes.data?.delivery_order?.flatMap((delivery) =>
|
||||
DeliveryProductToFieldValues(
|
||||
updateDeliveryRes.data?.sales_order,
|
||||
delivery
|
||||
)
|
||||
) ?? []
|
||||
)
|
||||
);
|
||||
router.push(`/marketing/detail?marketingId=${initialValues?.id}`);
|
||||
}
|
||||
if (isResponseError(updateDeliveryRes)) {
|
||||
console.log(updateDeliveryRes);
|
||||
@@ -441,12 +502,31 @@ const MarketingForm = ({
|
||||
const handleAddSubmitSO = useCallback(
|
||||
async (values: SalesOrderProductFormValues) => {
|
||||
const currentProducts = formik.values.sales_order;
|
||||
|
||||
const newValues = {
|
||||
...values,
|
||||
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();
|
||||
},
|
||||
@@ -462,14 +542,15 @@ const MarketingForm = ({
|
||||
[formik]
|
||||
);
|
||||
const handleEditDO = useCallback(
|
||||
(id: number) => {
|
||||
(id: number, values?: DeliveryOrderProductFormValues) => {
|
||||
setDeliveryFormState('edit');
|
||||
const currentProducts = formik.values.delivery_order.find(
|
||||
(product) => product.id == id
|
||||
);
|
||||
setSelectedDeliveryProduct(currentProducts ?? null);
|
||||
setSelectedDeliveryProduct(values ?? currentProducts ?? null);
|
||||
addDOModal.openModal();
|
||||
},
|
||||
[formik]
|
||||
[formik, addDOModal]
|
||||
);
|
||||
const handleBulkDeleteDO = useCallback(() => {
|
||||
setDeliveryOrderValues((prev) =>
|
||||
@@ -478,10 +559,13 @@ const MarketingForm = ({
|
||||
|
||||
setRowDOSelection({});
|
||||
}, [formik, selectedRowDOIds]);
|
||||
|
||||
const handleAddDOClick = useCallback(() => {
|
||||
setDeliveryFormState('add');
|
||||
setSelectedDeliveryProduct(null);
|
||||
addDOModal.openModal();
|
||||
}, [addDOModal]);
|
||||
|
||||
const handleAddSubmitDO = useCallback(
|
||||
async (values: DeliveryOrderProductFormValues) => {
|
||||
const newValues = {
|
||||
@@ -490,8 +574,8 @@ const MarketingForm = ({
|
||||
};
|
||||
|
||||
setDeliveryOrderValues((prev) => [...prev, newValues]);
|
||||
|
||||
addDOModal.closeModal();
|
||||
setSelectedDeliveryProduct(null);
|
||||
},
|
||||
[formik, addDOModal]
|
||||
);
|
||||
@@ -515,8 +599,8 @@ const MarketingForm = ({
|
||||
product.id === id ? { ...product, ...values } : product
|
||||
)
|
||||
);
|
||||
setSelectedDeliveryProduct(null);
|
||||
addDOModal.closeModal();
|
||||
setSelectedDeliveryProduct(null);
|
||||
},
|
||||
[formik, addDOModal]
|
||||
);
|
||||
@@ -576,25 +660,23 @@ const MarketingForm = ({
|
||||
</Card>
|
||||
|
||||
{/* Input Table Repeater Sales Order */}
|
||||
{(formType == 'add' || formType == 'edit') && (
|
||||
<Card
|
||||
title='Informasi Produk'
|
||||
className={{
|
||||
wrapper: 'bg-white w-full',
|
||||
}}
|
||||
>
|
||||
<MemoizedSalesOrderProductTable
|
||||
formType={formType}
|
||||
data={memoSalesOrder}
|
||||
rowSelection={rowSOSelection}
|
||||
setRowSelection={setRowSOSelection}
|
||||
selectedRowIds={selectedRowSOIds}
|
||||
onDelete={handleDeleteSO}
|
||||
onBulkDelete={handleBulkDeleteSO}
|
||||
onAddProductClick={handleAddSOClick}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
<Card
|
||||
title='Informasi Produk'
|
||||
className={{
|
||||
wrapper: 'bg-white w-full',
|
||||
}}
|
||||
>
|
||||
<MemoizedSalesOrderProductTable
|
||||
formType={formType}
|
||||
data={memoSalesOrder}
|
||||
rowSelection={rowSOSelection}
|
||||
setRowSelection={setRowSOSelection}
|
||||
selectedRowIds={selectedRowSOIds}
|
||||
onDelete={handleDeleteSO}
|
||||
onBulkDelete={handleBulkDeleteSO}
|
||||
onAddProductClick={handleAddSOClick}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
{/* Input Table Repeater Delivery Order */}
|
||||
{(formType == 'add_deliver' || formType == 'edit_deliver') &&
|
||||
@@ -606,18 +688,17 @@ const MarketingForm = ({
|
||||
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
|
||||
formType={formType}
|
||||
data={deliveryOrderValues}
|
||||
salesOrder={memoSalesOrder}
|
||||
rowSelection={rowDOSelection}
|
||||
setRowSelection={setRowDOSelection}
|
||||
selectedRowIds={selectedRowDOIds}
|
||||
onDelete={handleDeleteDO}
|
||||
onEdit={handleEditDO}
|
||||
onBulkDelete={handleBulkDeleteDO}
|
||||
onAddProductClick={handleAddDOClick}
|
||||
onInputDate={handleInputDate}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
@@ -698,6 +779,7 @@ const MarketingForm = ({
|
||||
<MemoizedSalesOrderProductForm
|
||||
onSubmitForm={handleAddSubmitSO}
|
||||
initialValues={selectedMarketingProduct ?? undefined}
|
||||
exisitingValues={memoSalesOrder}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -725,7 +807,9 @@ const MarketingForm = ({
|
||||
</div>
|
||||
<div>
|
||||
<MemoizedDeliveryOrderProductForm
|
||||
formState={deliveryFormState}
|
||||
salesOrders={initialValues?.sales_order ?? []}
|
||||
exisitingValues={deliveryOrderValues}
|
||||
onSubmitForm={handleAddSubmitDO}
|
||||
initialValues={selectedDeliveryProduct ?? undefined}
|
||||
onUpdateForm={handleUpdateDO}
|
||||
|
||||
+1
-13
@@ -42,22 +42,10 @@ export const DeliveryOrderProductSchema: Yup.ObjectSchema<DeliveryOrderProductSc
|
||||
.min(1, 'Total Penjualan wajib diisi!')
|
||||
.required('Total Penjualan wajib diisi!'),
|
||||
vehicle_number: Yup.string().required('Nomor Kendaraan wajib diisi!'),
|
||||
delivery_date: Yup.string()
|
||||
.required('Tanggal Pengiriman wajib diisi!')
|
||||
.nullable()
|
||||
.optional(),
|
||||
delivery_date: Yup.string().required('Tanggal Pengiriman wajib diisi!'),
|
||||
do_number: Yup.string().nullable().optional(),
|
||||
});
|
||||
|
||||
export type DeliveryOrderProductFormValues = Yup.InferType<
|
||||
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"
|
||||
|
||||
+74
-55
@@ -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<void>;
|
||||
onUpdateForm?: (
|
||||
id: number,
|
||||
@@ -34,6 +39,7 @@ const DeliveryOrderProductForm = ({
|
||||
const [selectedProduct, setSelectedProduct] = useState<OptionType | null>(
|
||||
null
|
||||
);
|
||||
const [currentInput, setCurrentInput] = useState<string>('');
|
||||
|
||||
const formik = useFormik<DeliveryOrderProductFormValues>({
|
||||
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 = ({
|
||||
<>
|
||||
<form
|
||||
className='size-full'
|
||||
onSubmit={formik.handleSubmit}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
handleBlurField(currentInput);
|
||||
formik.handleSubmit(e);
|
||||
}}
|
||||
onReset={handleResetForm}
|
||||
>
|
||||
{/* <small className='block text-blue-500'>
|
||||
{JSON.stringify(initialValues)}
|
||||
</small>
|
||||
<small className='block text-red-500'>
|
||||
{JSON.stringify(formik.errors)}
|
||||
{JSON.stringify(exisitingValues)}
|
||||
</small>
|
||||
<small className='block text-emerald-500'>
|
||||
{JSON.stringify(formik.values)}
|
||||
</small> */}
|
||||
{/* <small className='block text-red-500'>
|
||||
{JSON.stringify(formik.errors)}
|
||||
</small>
|
||||
<div className='hidden'>
|
||||
{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
|
||||
}
|
||||
</Badge>
|
||||
)
|
||||
@@ -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}
|
||||
|
||||
@@ -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<HTMLDialogElement | null>;
|
||||
onSubmitForm?: (value: SalesOrderProductFormValues) => Promise<void>;
|
||||
}) => {
|
||||
const [formErrorMessage, setFormErrorMessage] = useState('');
|
||||
const [currentInput, setCurrentInput] = useState<string>('');
|
||||
|
||||
const formik = useFormik<SalesOrderProductFormValues>({
|
||||
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 = ({
|
||||
<>
|
||||
<form
|
||||
className='size-full'
|
||||
onSubmit={formik.handleSubmit}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
handleBlurField(currentInput);
|
||||
formik.handleSubmit(e);
|
||||
}}
|
||||
onReset={handleResetForm}
|
||||
>
|
||||
{formErrorMessage && (
|
||||
@@ -200,12 +220,18 @@ const SalesOrderProductForm = ({
|
||||
<SelectInput
|
||||
required
|
||||
label='Produk'
|
||||
options={warehouseSourceOptions}
|
||||
options={productOptionsFiltered}
|
||||
isLoading={isLoadingWarehouseSourceOptions}
|
||||
value={formik.values.product_warehouse}
|
||||
onChange={warehouseChangeHandler}
|
||||
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}
|
||||
isError={
|
||||
formik.touched.product_warehouse_id &&
|
||||
@@ -218,7 +244,10 @@ const SalesOrderProductForm = ({
|
||||
label='Kuantitas'
|
||||
name='qty'
|
||||
value={formik.values.qty}
|
||||
onChange={formik.handleChange}
|
||||
onChange={(e) => {
|
||||
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)
|
||||
|
||||
@@ -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<string, boolean>;
|
||||
setRowSelection: React.Dispatch<
|
||||
React.SetStateAction<Record<string, boolean>>
|
||||
>;
|
||||
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<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: (
|
||||
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
|
||||
) => (
|
||||
<>
|
||||
{formType == 'add_deliver' && (
|
||||
<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'
|
||||
)}
|
||||
{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<DeliveryOrderProductFormValues, unknown>
|
||||
) =>
|
||||
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<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)',
|
||||
cell: (
|
||||
props: TanStack.CellContext<DeliveryOrderProductFormValues, unknown>
|
||||
) =>
|
||||
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<DeliveryOrderProductFormValues, unknown>
|
||||
) =>
|
||||
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<DeliveryOrderProductFormValues, unknown>
|
||||
) =>
|
||||
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<DeliveryOrderProductFormValues, unknown>
|
||||
) =>
|
||||
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<DeliveryOrderProductFormValues, unknown>
|
||||
) =>
|
||||
props.row.original.total_price
|
||||
? formatCurrency(
|
||||
parseFloat(props.row.original.total_price as string)
|
||||
)
|
||||
: '-',
|
||||
},
|
||||
|
||||
{
|
||||
header: 'Aksi',
|
||||
cell: (
|
||||
@@ -184,44 +175,45 @@ const DeliveryOrderProductTable = ({
|
||||
) => (
|
||||
<div className='flex flex-row gap-1 items-center justify-end h-full mt-2'>
|
||||
<>
|
||||
<Button
|
||||
color='warning'
|
||||
className='px-2 py-1 text-sm'
|
||||
onClick={() =>
|
||||
onEditRef.current(props.row.original.id as number)
|
||||
}
|
||||
type='button'
|
||||
>
|
||||
<Icon icon='mdi:edit' width={16} height={16} /> Edit
|
||||
</Button>
|
||||
{/* <Button
|
||||
color='error'
|
||||
className='p-1'
|
||||
onClick={() =>
|
||||
onDeleteRef.current(props.row.original.id as number)
|
||||
}
|
||||
type='button'
|
||||
>
|
||||
<Icon icon='mdi:trash' width={16} height={16} />
|
||||
</Button> */}
|
||||
{props.row.original.qty && (
|
||||
<Button
|
||||
color='warning'
|
||||
className='px-2 py-1 text-sm'
|
||||
onClick={() =>
|
||||
onEditRef.current(props.row.original.id as number)
|
||||
}
|
||||
type='button'
|
||||
>
|
||||
<Icon icon='mdi:edit' width={16} height={16} /> Edit
|
||||
</Button>
|
||||
)}
|
||||
{!props.row.original.qty && '-'}
|
||||
{/* {formType == 'add_deliver' && (
|
||||
<Button
|
||||
color='error'
|
||||
className='p-1'
|
||||
onClick={() =>
|
||||
onDeleteRef.current(props.row.original.id as number)
|
||||
}
|
||||
type='button'
|
||||
>
|
||||
<Icon icon='mdi:trash' width={16} height={16} />
|
||||
</Button>
|
||||
)} */}
|
||||
</>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
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 (
|
||||
<>
|
||||
<Table<DeliveryOrderProductFormValues>
|
||||
rowSelection={rowSelection}
|
||||
setRowSelection={setRowSelection}
|
||||
data={data}
|
||||
columns={columns}
|
||||
className={{
|
||||
@@ -246,17 +238,17 @@ const DeliveryOrderProductTable = ({
|
||||
}
|
||||
/>
|
||||
<div className='flex flex-row gap-3 mt-3'>
|
||||
{/* <Button
|
||||
<Button
|
||||
type='button'
|
||||
variant='outline'
|
||||
className='justify-start w-fit py-1 text-sm'
|
||||
onClick={onAddProductClick}
|
||||
// disabled={!canAddData}
|
||||
disabled={!canAddData}
|
||||
>
|
||||
<Icon icon='mdi:plus' width={16} height={16} />
|
||||
Tambah Pengiriman
|
||||
</Button> */}
|
||||
{selectedRowIds.length > 0 && (
|
||||
</Button>
|
||||
{/* {selectedRowIds.length > 0 && (
|
||||
<Button
|
||||
type='button'
|
||||
variant='outline'
|
||||
@@ -271,7 +263,7 @@ const DeliveryOrderProductTable = ({
|
||||
: ''}{' '}
|
||||
Pengiriman
|
||||
</Button>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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<string, boolean>;
|
||||
setRowSelection: React.Dispatch<
|
||||
React.SetStateAction<Record<string, boolean>>
|
||||
@@ -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 = ({
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
{formType != 'deliver' && (
|
||||
{formType != 'add_deliver' && formType != 'edit_deliver' && (
|
||||
<div className='flex flex-row gap-3 mt-3'>
|
||||
<Button
|
||||
type='button'
|
||||
|
||||
@@ -9,15 +9,18 @@ interface TableRowSizeSelectorProps {
|
||||
value: number;
|
||||
onChange: (val: OptionType | OptionType[] | null) => void;
|
||||
options: OptionType[];
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const TableRowSizeSelector = ({
|
||||
value,
|
||||
onChange,
|
||||
options,
|
||||
children,
|
||||
}: TableRowSizeSelectorProps) => {
|
||||
return (
|
||||
<div className='flex flex-row justify-end'>
|
||||
<div className='flex flex-row gap-3 items-end justify-end'>
|
||||
{children}
|
||||
<SelectInput
|
||||
label='Baris'
|
||||
options={options}
|
||||
|
||||
Reference in New Issue
Block a user