mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 15:55:48 +00:00
478 lines
16 KiB
TypeScript
478 lines
16 KiB
TypeScript
'use client';
|
|
|
|
import Button from '@/components/Button';
|
|
import Card from '@/components/Card';
|
|
import { FormHeader } from '@/components/helper/form/FormHeader';
|
|
import { useModal } from '@/components/Modal';
|
|
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
|
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
|
|
import ApprovalSteps, {
|
|
useApprovalSteps,
|
|
} from '@/components/pages/ApprovalSteps';
|
|
import Table from '@/components/Table';
|
|
import { MARKETING_APPROVAL_LINE } from '@/config/approval-line';
|
|
import {
|
|
cn,
|
|
formatCurrency,
|
|
formatDate,
|
|
formatNumber,
|
|
formatVechicleNumber,
|
|
} from '@/lib/helper';
|
|
import {
|
|
MarketingApi,
|
|
SalesOrderApi,
|
|
} from '@/services/api/marketing/marketing';
|
|
import {
|
|
BaseDelivery,
|
|
BaseSalesOrder,
|
|
Marketing,
|
|
} from '@/types/api/marketing/marketing';
|
|
import { Icon } from '@iconify/react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { useState } from 'react';
|
|
import toast from 'react-hot-toast';
|
|
import SalesOrderExport from '@/components/pages/marketing/pdf/SalesOrderExport';
|
|
import DeliveryOrderExport from '@/components/pages/marketing/pdf/DeliveryOrderExport';
|
|
|
|
const MarketingDetail = ({
|
|
initialValues,
|
|
refresh,
|
|
}: {
|
|
initialValues?: Marketing;
|
|
refresh?: () => void;
|
|
}) => {
|
|
const router = useRouter();
|
|
const [approvalAction, setApprovalAction] = useState<'APPROVED' | 'REJECTED'>(
|
|
'APPROVED'
|
|
);
|
|
const [grandTotal, setGrandTotal] = useState(
|
|
initialValues?.sales_order
|
|
?.map((item) => item.total_price)
|
|
.reduce((a, b) => a + b, 0)
|
|
);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const deleteModal = useModal();
|
|
const confirmationModal = useModal();
|
|
const deliveryModal = useModal();
|
|
const {
|
|
approvals,
|
|
isLoading: isLoadingApproval,
|
|
refresh: refreshApproval,
|
|
} = useApprovalSteps({
|
|
latestApproval: initialValues?.latest_approval,
|
|
approvalLines: MARKETING_APPROVAL_LINE,
|
|
moduleName: 'MARKETINGS',
|
|
moduleId: initialValues?.id as number as unknown as string,
|
|
});
|
|
|
|
const approveClickHandler = () => {
|
|
setApprovalAction('APPROVED');
|
|
confirmationModal.openModal();
|
|
};
|
|
|
|
const rejectClickHandler = () => {
|
|
setApprovalAction('REJECTED');
|
|
confirmationModal.openModal();
|
|
};
|
|
|
|
const deliveryClickHandler = () => {
|
|
deliveryModal.openModal();
|
|
};
|
|
|
|
const deleteClickHandler = () => {
|
|
deleteModal.openModal();
|
|
};
|
|
|
|
const confirmationModalDeleteClickHandler = async () => {
|
|
setIsLoading(true);
|
|
const res = await MarketingApi.delete(initialValues?.id as number);
|
|
deleteModal.closeModal();
|
|
router.push('/marketing');
|
|
toast.success(res?.message as string);
|
|
refresh?.();
|
|
setIsLoading(false);
|
|
};
|
|
|
|
const confirmationModalApproveClickHandler = async (notes: string) => {
|
|
setIsLoading(true);
|
|
const res = await SalesOrderApi.singleApproval(
|
|
initialValues?.id as number,
|
|
approvalAction,
|
|
notes
|
|
);
|
|
setIsLoading(false);
|
|
confirmationModal.closeModal();
|
|
toast.success(res?.message as string);
|
|
refresh?.();
|
|
refreshApproval?.();
|
|
};
|
|
|
|
const confirmationModalDeliveryClickHandler = async (notes: string) => {
|
|
setIsLoading(true);
|
|
const res = await SalesOrderApi.delivery(
|
|
initialValues?.id as number,
|
|
notes
|
|
);
|
|
setIsLoading(false);
|
|
deliveryModal.closeModal();
|
|
toast.success(res?.message as string);
|
|
refresh?.();
|
|
refreshApproval?.();
|
|
router.push(
|
|
`/marketing/detail/delivery-orders/edit?marketingId=${initialValues?.id}`
|
|
);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className='flex flex-col w-full gap-4'>
|
|
<FormHeader title='Detail Sales Order' backUrl='/marketing' />
|
|
{!isLoadingApproval && approvals && (
|
|
<ApprovalSteps approvals={approvals} />
|
|
)}
|
|
<div className='flex-row flex gap-3'>
|
|
{initialValues?.latest_approval?.step_number == 1 && (
|
|
<>
|
|
<Button
|
|
color='success'
|
|
onClick={approveClickHandler}
|
|
disabled={
|
|
initialValues?.latest_approval?.step_number == 1 &&
|
|
initialValues?.latest_approval?.action == 'REJECTED'
|
|
}
|
|
>
|
|
<Icon icon='mdi:check' width={24} height={24} />
|
|
Approve
|
|
</Button>
|
|
<Button
|
|
color='error'
|
|
onClick={rejectClickHandler}
|
|
disabled={
|
|
initialValues?.latest_approval?.step_number == 1 &&
|
|
initialValues?.latest_approval?.action == 'REJECTED'
|
|
}
|
|
>
|
|
<Icon icon='mdi:close' width={24} height={24} />
|
|
Reject
|
|
</Button>
|
|
</>
|
|
)}
|
|
{initialValues?.latest_approval?.step_number != 1 && (
|
|
<Button
|
|
color='success'
|
|
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>
|
|
)}
|
|
</div>
|
|
|
|
<Card
|
|
title='Informasi Penjualan'
|
|
className={{
|
|
wrapper: 'w-full bg-white',
|
|
}}
|
|
>
|
|
<div className='overflow-x-auto rounded-box border border-base-content/5 bg-base-100 mt-3'>
|
|
<table className='table'>
|
|
<tbody>
|
|
<tr>
|
|
<td width='45%' className='font-semibold'>
|
|
No. Sales Order
|
|
</td>
|
|
<td>:</td>
|
|
<td width='50%'>{initialValues?.so_number}</td>
|
|
</tr>
|
|
<tr>
|
|
<td className='font-semibold'>Nama Pelanggan</td>
|
|
<td>:</td>
|
|
<td>{initialValues?.customer?.name}</td>
|
|
</tr>
|
|
<tr>
|
|
<td className='font-semibold'>Status</td>
|
|
<td>:</td>
|
|
<td>{initialValues?.latest_approval?.step_name}</td>
|
|
</tr>
|
|
<tr>
|
|
<td className='font-semibold'>Tanggal Penjualan</td>
|
|
<td>:</td>
|
|
<td>{formatDate(initialValues?.so_date, 'DD MMM yyyy')}</td>
|
|
</tr>
|
|
<tr>
|
|
<td className='font-semibold'>Total Penjualan</td>
|
|
<td>:</td>
|
|
<td>{formatCurrency(grandTotal as number)}</td>
|
|
</tr>
|
|
<tr>
|
|
<td className='font-semibold'>Catatan</td>
|
|
<td>:</td>
|
|
<td>{initialValues?.notes ?? '-'}</td>
|
|
</tr>
|
|
<tr>
|
|
<td className='font-semibold'>Dokumen</td>
|
|
<td>:</td>
|
|
<td>
|
|
<SalesOrderExport data={initialValues} />
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</Card>
|
|
{initialValues?.sales_order && (
|
|
<Card
|
|
title='Informasi Produk'
|
|
className={{
|
|
wrapper: 'w-full bg-white',
|
|
}}
|
|
>
|
|
<Table<BaseSalesOrder>
|
|
data={initialValues?.sales_order}
|
|
columns={[
|
|
{
|
|
header: 'Kandang',
|
|
accessorFn(row) {
|
|
return row.product_warehouse.warehouse.name;
|
|
},
|
|
},
|
|
{
|
|
header: 'Produk',
|
|
accessorFn(row) {
|
|
return row.product_warehouse.product.name;
|
|
},
|
|
},
|
|
{
|
|
header: 'Harga Satuan (Rp)',
|
|
accessorFn(row) {
|
|
return formatCurrency(row.unit_price);
|
|
},
|
|
},
|
|
{
|
|
header: 'Total Bobot (Kg)',
|
|
accessorFn(row) {
|
|
return formatNumber(row.total_weight);
|
|
},
|
|
},
|
|
{
|
|
header: 'Kuantitas',
|
|
accessorFn(row) {
|
|
return formatNumber(row.qty);
|
|
},
|
|
},
|
|
{
|
|
header: 'Avg. Bobot (Kg)',
|
|
accessorFn(row) {
|
|
return formatNumber(row.avg_weight);
|
|
},
|
|
},
|
|
{
|
|
header: 'Total Penjualan (Rp)',
|
|
accessorFn(row) {
|
|
return formatCurrency(row.total_price);
|
|
},
|
|
},
|
|
]}
|
|
className={{
|
|
containerClassName: cn({
|
|
'mb-20':
|
|
initialValues?.sales_order &&
|
|
initialValues?.sales_order?.length === 0,
|
|
}),
|
|
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
|
tableClassName: 'font-inter w-full table-auto min-h-full!',
|
|
headerRowClassName: 'border-b border-b-gray-200',
|
|
headerColumnClassName:
|
|
'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end',
|
|
bodyRowClassName: 'border-b border-b-gray-200',
|
|
bodyColumnClassName:
|
|
'px-6 py-3 last:flex last:flex-row last:justify-end',
|
|
paginationClassName: 'hidden',
|
|
}}
|
|
/>
|
|
</Card>
|
|
)}
|
|
{initialValues?.delivery_order && (
|
|
<Card
|
|
title='Informasi Pengiriman'
|
|
className={{
|
|
wrapper: 'w-full bg-white',
|
|
}}
|
|
>
|
|
{initialValues?.delivery_order.map((delivery, index) => {
|
|
return (
|
|
<div key={index}>
|
|
<Card
|
|
className={{
|
|
wrapper: 'w-full',
|
|
}}
|
|
>
|
|
<div className='flex flex-row gap-3'>
|
|
<div className='font-semibold'>
|
|
Nomor DO : {delivery.do_number}
|
|
</div>
|
|
</div>
|
|
<Table<BaseDelivery>
|
|
data={delivery.deliveries}
|
|
columns={[
|
|
{
|
|
header: 'Tanggal Pengiriman',
|
|
accessorFn() {
|
|
return formatDate(
|
|
delivery.delivery_date,
|
|
'DD MMM yyyy'
|
|
);
|
|
},
|
|
},
|
|
{
|
|
header: 'No. Polisi',
|
|
accessorFn(row) {
|
|
return formatVechicleNumber(row.vehicle_number);
|
|
},
|
|
},
|
|
{
|
|
header: 'Kandang',
|
|
accessorFn(row) {
|
|
return row.product_warehouse.warehouse.name;
|
|
},
|
|
},
|
|
{
|
|
header: 'Produk',
|
|
accessorFn(row) {
|
|
return row.product_warehouse.product.name;
|
|
},
|
|
},
|
|
{
|
|
header: 'Harga Satuan (Rp)',
|
|
accessorFn(row) {
|
|
return formatCurrency(row.unit_price);
|
|
},
|
|
},
|
|
{
|
|
header: 'Total Bobot (Kg)',
|
|
accessorFn(row) {
|
|
return formatNumber(row.total_weight);
|
|
},
|
|
},
|
|
{
|
|
header: 'Kuantitas',
|
|
accessorFn(row) {
|
|
return formatNumber(row.qty);
|
|
},
|
|
},
|
|
{
|
|
header: 'Avg. Bobot (Kg)',
|
|
accessorFn(row) {
|
|
return formatNumber(row.avg_weight);
|
|
},
|
|
},
|
|
{
|
|
header: 'Total Penjualan (Rp)',
|
|
accessorFn(row) {
|
|
return formatCurrency(row.total_price);
|
|
},
|
|
},
|
|
]}
|
|
className={{
|
|
containerClassName: cn({
|
|
'mb-20':
|
|
initialValues?.sales_order &&
|
|
initialValues?.sales_order?.length === 0,
|
|
}),
|
|
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
|
tableClassName:
|
|
'font-inter w-full table-auto min-h-full!',
|
|
headerRowClassName: 'border-b border-b-gray-200',
|
|
headerColumnClassName:
|
|
'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end',
|
|
bodyRowClassName: 'border-b border-b-gray-200',
|
|
bodyColumnClassName:
|
|
'px-6 py-3 last:flex last:flex-row last:justify-end',
|
|
paginationClassName: 'hidden',
|
|
}}
|
|
/>
|
|
</Card>
|
|
<div className='flex flex-row gap-3 my-3'>
|
|
<DeliveryOrderExport
|
|
data={initialValues}
|
|
deliveryOrder={delivery}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</Card>
|
|
)}
|
|
<div className='flex flex-row gap-3'>
|
|
{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
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<ConfirmationModal
|
|
ref={deleteModal.ref}
|
|
type='error'
|
|
text={`Apakah anda yakin ingin menghapus data penjualan ini?`}
|
|
secondaryButton={{
|
|
text: 'Tidak',
|
|
}}
|
|
primaryButton={{
|
|
text: 'Ya',
|
|
color: 'error',
|
|
isLoading: isLoading,
|
|
onClick: confirmationModalDeleteClickHandler,
|
|
}}
|
|
/>
|
|
<ConfirmationModalWithNotes
|
|
ref={confirmationModal.ref}
|
|
type={approvalAction === 'APPROVED' ? 'success' : 'error'}
|
|
text={`Apakah anda yakin ingin ${approvalAction == 'APPROVED' ? 'approve' : 'reject'} data penjualan ini?`}
|
|
secondaryButton={{
|
|
text: 'Tidak',
|
|
}}
|
|
primaryButton={{
|
|
text: 'Ya',
|
|
color: approvalAction === 'APPROVED' ? 'success' : 'error',
|
|
isLoading: isLoading,
|
|
onClick: confirmationModalApproveClickHandler,
|
|
}}
|
|
/>
|
|
<ConfirmationModalWithNotes
|
|
ref={deliveryModal.ref}
|
|
type={'success'}
|
|
text={`Apakah anda yakin ingin deliver penjualan ini?`}
|
|
secondaryButton={{
|
|
text: 'Tidak',
|
|
}}
|
|
primaryButton={{
|
|
text: 'Ya',
|
|
color: 'success',
|
|
isLoading: isLoading,
|
|
onClick: confirmationModalDeliveryClickHandler,
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default MarketingDetail;
|