Files
lti-web-client/src/components/pages/marketing/detail/MarketingDetail.tsx
T

496 lines
17 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';
import RequirePermission from '@/components/helper/RequirePermission';
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 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 && (
<>
<RequirePermission permissions='lti.marketing.sales_order.approve'>
<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>
</RequirePermission>
<RequirePermission permissions='lti.marketing.sales_order.approve'>
<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>
</RequirePermission>
</>
)}
{initialValues?.latest_approval?.step_number != 1 && (
<>
<RequirePermission
permissions={
initialValues?.latest_approval?.step_number == 3
? 'lti.marketing.delivery_order.update'
: 'lti.marketing.delivery_order.create'
}
>
<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>
</RequirePermission>
</>
)}
</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 && (
<>
<RequirePermission permissions='lti.marketing.sales_order.update'>
<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>
</RequirePermission>
</>
)}
<RequirePermission permissions='lti.marketing.sales_order.delete'>
<Button color='error' onClick={deleteClickHandler}>
<Icon icon='mdi:delete' width={24} height={24} />
Hapus
</Button>
</RequirePermission>
</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;