fix(FE-169-177): Allow Drafted Marketing to be rejected

This commit is contained in:
randy-ar
2025-11-21 13:33:40 +07:00
parent 70521330e4
commit b7c3b9313c
4 changed files with 57 additions and 55 deletions
+1 -1
View File
@@ -213,7 +213,7 @@ const DateInput = ({
<div <div
className={cn( className={cn(
'input h-12 px-4 py-2 text-base font-normal leading-6 w-full rounded transition-all duration-200 flex items-center border', 'input h-12 bg-inherit px-4 py-2 text-base font-normal leading-6 w-full rounded transition-all duration-200 flex items-center border',
{ {
'border-error': finalIsError, 'border-error': finalIsError,
'border-success': externalValid && !finalIsError, 'border-success': externalValid && !finalIsError,
@@ -183,14 +183,18 @@ const MarketingTable = () => {
); );
const hasApprovable = selectedRowsData.some( const hasApprovable = selectedRowsData.some(
(row) => row.latest_approval.step_number === 1 (row) =>
row.latest_approval.step_number === 1 &&
row.latest_approval.action !== 'REJECTED'
); );
const hasRejectable = selectedRowsData.some( const hasRejectable = selectedRowsData.some(
(row) => row.latest_approval.step_number === 2 (row) =>
row.latest_approval.step_number === 1 &&
row.latest_approval.action !== 'REJECTED'
); );
const disableApprove = !hasApprovable || hasRejectable; const disableApprove = !hasApprovable;
// const disableReject = !hasRejectable || hasApprovable; const disableReject = !hasRejectable;
const idsToProcess = const idsToProcess =
approveAction === 'APPROVED' approveAction === 'APPROVED'
@@ -204,15 +208,9 @@ const MarketingTable = () => {
const approveMarketingHandler = async (notes: string) => { const approveMarketingHandler = async (notes: string) => {
let idsToProcess: number[] = []; let idsToProcess: number[] = [];
if (approveAction === 'APPROVED') {
idsToProcess = selectedRowsData idsToProcess = selectedRowsData
.filter((row) => row.latest_approval.step_number === 1) .filter((row) => row.latest_approval.step_number === 1)
.map((row) => row.id); .map((row) => row.id);
} else if (approveAction === 'REJECTED') {
idsToProcess = selectedRowsData
.filter((row) => row.latest_approval.step_number === 2)
.map((row) => row.id);
}
if (idsToProcess.length === 0) { if (idsToProcess.length === 0) {
toast.error(`Tidak ada data yang valid untuk di ${approveAction}.`); toast.error(`Tidak ada data yang valid untuk di ${approveAction}.`);
@@ -263,8 +261,8 @@ const MarketingTable = () => {
}); });
const getRowCanSelect = (row: Row<Marketing>): boolean => { const getRowCanSelect = (row: Row<Marketing>): boolean => {
const step = row.original.latest_approval?.step_number; const approval = row.original.latest_approval;
return step === 1; return approval?.step_number === 1 && approval?.action !== 'REJECTED';
}; };
return ( return (
@@ -298,7 +296,7 @@ const MarketingTable = () => {
Approve Approve
</Button> </Button>
{/* <Button <Button
color='error' color='error'
onClick={rejectClickHandler} onClick={rejectClickHandler}
className='justify-start text-sm' className='justify-start text-sm'
@@ -306,7 +304,7 @@ const MarketingTable = () => {
> >
<Icon icon='material-symbols:close' width={24} height={24} /> <Icon icon='material-symbols:close' width={24} height={24} />
Reject Reject
</Button> */} </Button>
</div> </div>
</div> </div>
<Table <Table
@@ -71,10 +71,10 @@ const MarketingDetail = ({
confirmationModal.openModal(); confirmationModal.openModal();
}; };
// const rejectClickHandler = () => { const rejectClickHandler = () => {
// setApprovalAction('REJECTED'); setApprovalAction('REJECTED');
// confirmationModal.openModal(); confirmationModal.openModal();
// }; };
const deliveryClickHandler = () => { const deliveryClickHandler = () => {
deliveryModal.openModal(); deliveryModal.openModal();
@@ -87,10 +87,11 @@ const MarketingDetail = ({
const confirmationModalDeleteClickHandler = async () => { const confirmationModalDeleteClickHandler = async () => {
setIsLoading(true); setIsLoading(true);
const res = await MarketingApi.delete(initialValues?.id as number); const res = await MarketingApi.delete(initialValues?.id as number);
setIsLoading(false);
deleteModal.closeModal(); deleteModal.closeModal();
router.push('/marketing');
toast.success(res?.message as string); toast.success(res?.message as string);
refresh?.(); refresh?.();
setIsLoading(false);
}; };
const confirmationModalApproveClickHandler = async (notes: string) => { const confirmationModalApproveClickHandler = async (notes: string) => {
@@ -131,24 +132,30 @@ const MarketingDetail = ({
<ApprovalSteps approvals={approvals} /> <ApprovalSteps approvals={approvals} />
)} )}
<div className='flex-row flex gap-3'> <div className='flex-row flex gap-3'>
{initialValues?.latest_approval?.step_number != 3 && ( {initialValues?.latest_approval?.step_number == 1 && (
<> <>
<Button <Button
color='success' color='success'
onClick={approveClickHandler} onClick={approveClickHandler}
disabled={initialValues?.latest_approval?.step_number != 1} disabled={
initialValues?.latest_approval?.step_number == 1 &&
initialValues?.latest_approval?.action == 'REJECTED'
}
> >
<Icon icon='mdi:check' width={24} height={24} /> <Icon icon='mdi:check' width={24} height={24} />
Approve Approve
</Button> </Button>
{/* <Button <Button
color='error' color='error'
onClick={rejectClickHandler} onClick={rejectClickHandler}
disabled={initialValues?.latest_approval?.step_number != 2} disabled={
initialValues?.latest_approval?.step_number == 1 &&
initialValues?.latest_approval?.action == 'REJECTED'
}
> >
<Icon icon='mdi:close' width={24} height={24} /> <Icon icon='mdi:close' width={24} height={24} />
Reject Reject
</Button> */} </Button>
</> </>
)} )}
{initialValues?.latest_approval?.step_number == 2 && ( {initialValues?.latest_approval?.step_number == 2 && (
@@ -162,7 +162,6 @@ 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 [deliveryOrderValues, setDeliveryOrderValues] = useState< const [deliveryOrderValues, setDeliveryOrderValues] = useState<
DeliveryOrderProductFormValues[] DeliveryOrderProductFormValues[]
>( >(
@@ -174,7 +173,7 @@ const MarketingForm = ({
) )
); );
// Repeater Props // ================== REPEATER ==================
const addSOModal = useModal(); const addSOModal = useModal();
const addDOModal = useModal(); const addDOModal = useModal();
const [rowSOSelection, setRowSOSelection] = useState<Record<string, boolean>>( const [rowSOSelection, setRowSOSelection] = useState<Record<string, boolean>>(
@@ -190,12 +189,13 @@ const MarketingForm = ({
parseInt(item) parseInt(item)
); );
// End Repeater Props // ================== FETCH OPTIONS ==================
const { const {
options: customerOptions, options: customerOptions,
isLoadingOptions: isLoadingCustomerOptions, isLoadingOptions: isLoadingCustomerOptions,
} = useSelect<Customer>(CustomerApi.basePath, 'id', 'name'); } = useSelect<Customer>(CustomerApi.basePath, 'id', 'name');
// ================== SETUP FORMIK ==================
const formikInitialValues = useMemo< const formikInitialValues = useMemo<
SalesOrderFormValues & DeliveryOrderFormValues SalesOrderFormValues & DeliveryOrderFormValues
>(() => { >(() => {
@@ -222,7 +222,6 @@ const MarketingForm = ({
), ),
}; };
}, [initialValues]); }, [initialValues]);
const formik = useFormik<SalesOrderFormValues & DeliveryOrderFormValues>({ const formik = useFormik<SalesOrderFormValues & DeliveryOrderFormValues>({
enableReinitialize: true, enableReinitialize: true,
initialValues: formikInitialValues, initialValues: formikInitialValues,
@@ -296,7 +295,6 @@ const MarketingForm = ({
afterSubmit?.(); afterSubmit?.();
}, },
}); });
const grandTotal = useMemo(() => { const grandTotal = useMemo(() => {
return formik.values.sales_order.reduce( return formik.values.sales_order.reduce(
(total, product) => (total, product) =>
@@ -305,6 +303,7 @@ const MarketingForm = ({
); );
}, [formik.values.sales_order]); }, [formik.values.sales_order]);
// ================== FORM REPEATER HANDLER ==================
const createMarketingHandler = async (values: CreateSalesOrderPayload) => { const createMarketingHandler = async (values: CreateSalesOrderPayload) => {
setIsLoading(true); setIsLoading(true);
console.log(values); console.log(values);
@@ -334,7 +333,6 @@ const MarketingForm = ({
} }
setIsLoading(false); setIsLoading(false);
}; };
const createDeliveryHandler = async (values: CreateDeliveryOrderPayload) => { const createDeliveryHandler = async (values: CreateDeliveryOrderPayload) => {
setIsLoading(true); setIsLoading(true);
console.log(initialValues?.id); console.log(initialValues?.id);
@@ -350,9 +348,7 @@ const MarketingForm = ({
) )
) ?? [] ) ?? []
); );
router.push( router.push(`/marketing/detail?marketingId=${initialValues?.id}`);
`/marketing/detail/delivery-orders/edit?marketingId=${initialValues?.id}`
);
} }
if (isResponseError(createDeliveryRes)) { if (isResponseError(createDeliveryRes)) {
console.log(createDeliveryRes); console.log(createDeliveryRes);
@@ -360,7 +356,6 @@ const MarketingForm = ({
} }
setIsLoading(false); setIsLoading(false);
}; };
const updateDeliveryHandler = async (values: UpdateDeliveryOrderPayload) => { const updateDeliveryHandler = async (values: UpdateDeliveryOrderPayload) => {
setIsLoading(true); setIsLoading(true);
console.log(initialValues?.id); console.log(initialValues?.id);
@@ -388,6 +383,7 @@ const MarketingForm = ({
setIsLoading(false); setIsLoading(false);
}; };
// ================== MARKETING HANDLER ==================
const deleteMarketingHandler = async () => { const deleteMarketingHandler = async () => {
setIsLoading(true); setIsLoading(true);
console.log(initialValues?.id); console.log(initialValues?.id);
@@ -404,9 +400,8 @@ const MarketingForm = ({
} }
setIsLoading(false); setIsLoading(false);
deleteModal.closeModal(); deleteModal.closeModal();
router.push('/marketing/sales-orders'); router.push('/marketing');
}; };
const handleChangeCustomer = useCallback( const handleChangeCustomer = useCallback(
(val: OptionType | OptionType[] | null) => { (val: OptionType | OptionType[] | null) => {
formik.setFieldValue('customer_id', (val as OptionType)?.value); formik.setFieldValue('customer_id', (val as OptionType)?.value);
@@ -414,8 +409,11 @@ const MarketingForm = ({
}, },
[formik] [formik]
); );
const handleDelete = useCallback(() => {
deleteModal.openModal();
}, [deleteModal]);
// Repeater Handle // ================== SALES ORDER HANDLER ==================
const handleDeleteSO = useCallback( const handleDeleteSO = useCallback(
(id: number) => { (id: number) => {
const currentProducts = formik.values.sales_order; const currentProducts = formik.values.sales_order;
@@ -436,9 +434,6 @@ const MarketingForm = ({
); );
setRowSOSelection({}); setRowSOSelection({});
}, [formik, selectedRowSOIds]); }, [formik, selectedRowSOIds]);
const handleDelete = useCallback(() => {
deleteModal.openModal();
}, [deleteModal]);
const handleAddSOClick = useCallback(() => { const handleAddSOClick = useCallback(() => {
setSelectedMarketingProduct(null); setSelectedMarketingProduct(null);
addSOModal.openModal(); addSOModal.openModal();
@@ -458,6 +453,7 @@ const MarketingForm = ({
[formik, addSOModal] [formik, addSOModal]
); );
// ================== DELIVERY ORDER HANDLER ==================
const handleDeleteDO = useCallback( const handleDeleteDO = useCallback(
(id: number) => { (id: number) => {
const currentProducts = formik.values.delivery_order; const currentProducts = formik.values.delivery_order;
@@ -482,12 +478,10 @@ const MarketingForm = ({
setRowDOSelection({}); setRowDOSelection({});
}, [formik, selectedRowDOIds]); }, [formik, selectedRowDOIds]);
const handleAddDOClick = useCallback(() => { const handleAddDOClick = useCallback(() => {
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 = {
@@ -526,7 +520,6 @@ const MarketingForm = ({
}, },
[formik, addDOModal] [formik, addDOModal]
); );
// End Repeater Handle
const memoSalesOrder = formik.values.sales_order; const memoSalesOrder = formik.values.sales_order;
@@ -545,6 +538,7 @@ const MarketingForm = ({
title={`${formType == 'add' || formType == 'add_deliver' ? 'Tambah' : 'Edit'} ${formType === 'add_deliver' || formType === 'edit_deliver' ? 'Delivery' : 'Sales'} Order`} title={`${formType == 'add' || formType == 'add_deliver' ? 'Tambah' : 'Edit'} ${formType === 'add_deliver' || formType === 'edit_deliver' ? 'Delivery' : 'Sales'} Order`}
backUrl='/marketing' backUrl='/marketing'
/> />
{/* Input Cutomer And Date */}
<Card <Card
title='Informasi Order' title='Informasi Order'
className={{ className={{
@@ -580,6 +574,8 @@ const MarketingForm = ({
/> />
</div> </div>
</Card> </Card>
{/* Input Table Repeater Sales Order */}
{(formType == 'add' || formType == 'edit') && ( {(formType == 'add' || formType == 'edit') && (
<Card <Card
title='Informasi Produk' title='Informasi Produk'
@@ -587,9 +583,6 @@ const MarketingForm = ({
wrapper: 'bg-white w-full', wrapper: 'bg-white w-full',
}} }}
> >
{/* <div className='text-blue-500'>{JSON.stringify(initialValues)}</div>
<div className='text-green-500'>{JSON.stringify(formik.values)}</div>
<div className='text-red-500'>{JSON.stringify(formik.errors)}</div> */}
<MemoizedSalesOrderProductTable <MemoizedSalesOrderProductTable
formType={formType} formType={formType}
data={memoSalesOrder} data={memoSalesOrder}
@@ -602,6 +595,8 @@ const MarketingForm = ({
/> />
</Card> </Card>
)} )}
{/* Input Table Repeater Delivery Order */}
{(formType == 'add_deliver' || formType == 'edit_deliver') && {(formType == 'add_deliver' || formType == 'edit_deliver') &&
initialValues?.sales_order && initialValues?.sales_order &&
initialValues?.sales_order.length > 0 && ( initialValues?.sales_order.length > 0 && (
@@ -611,11 +606,6 @@ const MarketingForm = ({
wrapper: 'bg-white w-full', wrapper: 'bg-white w-full',
}} }}
> >
{/* {JSON.stringify(memoSalesOrder)} */}
{/* <small>{JSON.stringify(memoDeliveryOrder)}</small> */}
{/* <small className='block text-error'>
{JSON.stringify(formik.errors)}
</small> */}
<MemoizedDeliveryOrderProductTable <MemoizedDeliveryOrderProductTable
formType={formType} formType={formType}
data={deliveryOrderValues} data={deliveryOrderValues}
@@ -632,6 +622,7 @@ const MarketingForm = ({
</Card> </Card>
)} )}
{/* Input Notes */}
<div className='grid grid-cols-2 gap-3'> <div className='grid grid-cols-2 gap-3'>
<TextArea <TextArea
required required
@@ -652,6 +643,8 @@ const MarketingForm = ({
</span> </span>
</div> </div>
</div> </div>
{/* Form Actions */}
<div className='flex flex-row items-start justify-center gap-2 mt-4'> <div className='flex flex-row items-start justify-center gap-2 mt-4'>
<Button type='reset' color='warning' disabled={formik.isSubmitting}> <Button type='reset' color='warning' disabled={formik.isSubmitting}>
Reset Reset
@@ -665,6 +658,8 @@ const MarketingForm = ({
</Button> </Button>
</div> </div>
</form> </form>
{/* Actions button */}
{formType == 'edit' && ( {formType == 'edit' && (
<div className='flex flex-row justify-start'> <div className='flex flex-row justify-start'>
<Button <Button
@@ -678,6 +673,8 @@ const MarketingForm = ({
</Button> </Button>
</div> </div>
)} )}
{/* Modals */}
<Modal <Modal
ref={addSOModal.ref} ref={addSOModal.ref}
closeOnBackdrop closeOnBackdrop