-
+
+
+
+
+
diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx
index 767cd9b3..3161054c 100644
--- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx
+++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx
@@ -6,27 +6,20 @@ import {
SalesOrderProductSchema,
} from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema';
import { RefObject, useMemo, useState } from 'react';
-import SelectInput, {
- OptionType,
- useSelect,
-} from '@/components/input/SelectInput';
+import { OptionType, useSelect } from '@/components/input/SelectInput';
import { Kandang } from '@/types/api/master-data/kandang';
-import { ProductApi, UomApi, WarehouseApi } from '@/services/api/master-data';
+import { WarehouseApi } from '@/services/api/master-data';
import { ProductWarehouse } from '@/types/api/inventory/product-warehouse';
import { ProductWarehouseApi } from '@/services/api/inventory';
import NumberInput from '@/components/input/NumberInput';
import Button from '@/components/Button';
import { isResponseSuccess } from '@/lib/api-helper';
-import {
- formatCurrency,
- formatNumber,
- formatVechicleNumber,
-} from '@/lib/helper';
+import { formatNumber, formatVechicleNumber } from '@/lib/helper';
import PatternInput from '@/components/input/PatternInput';
import Alert from '@/components/Alert';
import AlertErrorList from '@/components/helper/form/FormErrors';
import { useFormikErrorList } from '@/services/hooks/useFormikErrorList';
-import useSWR from 'swr';
+import SelectInputRadio from '@/components/input/SelectInputRadio';
const roundWeight = (value: number) => Number(value.toFixed(2));
const roundPrice = (value: number) => Math.round(value);
@@ -282,7 +275,7 @@ const SalesOrderProductForm = ({
return (
<>
)}
-
-
-
-
{
- formik.handleChange(e);
- setCurrentInput(e.target.name);
- }}
- onBlur={() => handleBlurField('qty')}
- isError={formik.touched.qty && Boolean(formik.errors.qty)}
- errorMessage={formik.errors.qty}
- placeholder='Masukan Kuantitas'
- endAdornment={
-
-
- {selectedProductWarehouse?.product?.uom?.name}
-
-
- }
- bottomLabel={
- isResponseSuccess(warehouseSourceRawData) &&
- formik.values.product_warehouse_id
- ? `Stok tersedia: ${formatNumber(
- warehouseSourceRawData?.data?.find(
- (item) => item.id === formik.values.product_warehouse_id
- )?.quantity ?? 0
- )} ${selectedProductWarehouse?.product?.uom?.name}`
- : ''
- }
- />
- {
- formik.handleChange(e);
- setCurrentInput(e.target.name);
- }}
- onBlur={() => handleBlurField('unit_price')}
- isError={
- formik.touched.unit_price && Boolean(formik.errors.unit_price)
- }
- errorMessage={formik.errors.unit_price}
- placeholder='Masukan Harga Satuan'
- />
- {
- formik.handleChange(e);
- setCurrentInput(e.target.name);
- }}
- onBlur={() => handleBlurField('avg_weight')}
- isError={
- formik.touched.avg_weight && Boolean(formik.errors.avg_weight)
- }
- errorMessage={formik.errors.avg_weight}
- placeholder='Masukan Bobot Rata-rata'
- />
- {
- formik.handleChange(e);
- setCurrentInput(e.target.name);
- }}
- onBlur={() => handleBlurField('total_weight')}
- isError={
- formik.touched.total_weight && Boolean(formik.errors.total_weight)
- }
- errorMessage={formik.errors.total_weight}
- placeholder='Masukan Total Bobot'
- />
- {
- formik.handleChange(e);
- setCurrentInput(e.target.name);
- }}
- onBlur={() => handleBlurField('total_price')}
- isError={
- formik.touched.total_price && Boolean(formik.errors.total_price)
- }
- errorMessage={formik.errors.total_price}
- placeholder='Masukan Total Penjualan'
- />
-
+
+
+
+
{
+ formik.handleChange(e);
+ setCurrentInput(e.target.name);
+ }}
+ onBlur={() => handleBlurField('qty')}
+ isError={formik.touched.qty && Boolean(formik.errors.qty)}
+ errorMessage={formik.errors.qty}
+ placeholder='Masukan Kuantitas'
+ endAdornment={
+
+
+ {selectedProductWarehouse?.product?.uom?.name}
+
+
+ }
+ bottomLabel={
+ isResponseSuccess(warehouseSourceRawData) &&
+ formik.values.product_warehouse_id
+ ? `Stok tersedia: ${formatNumber(
+ warehouseSourceRawData?.data?.find(
+ (item) => item.id === formik.values.product_warehouse_id
+ )?.quantity ?? 0
+ )} ${selectedProductWarehouse?.product?.uom?.name}`
+ : ''
+ }
+ />
+ {
+ formik.handleChange(e);
+ setCurrentInput(e.target.name);
+ }}
+ onBlur={() => handleBlurField('unit_price')}
+ isError={
+ formik.touched.unit_price && Boolean(formik.errors.unit_price)
+ }
+ errorMessage={formik.errors.unit_price}
+ placeholder='Masukan Harga Satuan'
+ />
+ {
+ formik.handleChange(e);
+ setCurrentInput(e.target.name);
+ }}
+ onBlur={() => handleBlurField('avg_weight')}
+ isError={
+ formik.touched.avg_weight && Boolean(formik.errors.avg_weight)
+ }
+ errorMessage={formik.errors.avg_weight}
+ placeholder='Masukan Bobot Rata-rata'
+ />
+ {
+ formik.handleChange(e);
+ setCurrentInput(e.target.name);
+ }}
+ onBlur={() => handleBlurField('total_weight')}
+ isError={
+ formik.touched.total_weight && Boolean(formik.errors.total_weight)
+ }
+ errorMessage={formik.errors.total_weight}
+ placeholder='Masukan Total Bobot'
+ />
+ {
+ formik.handleChange(e);
+ setCurrentInput(e.target.name);
+ }}
+ onBlur={() => handleBlurField('total_price')}
+ isError={
+ formik.touched.total_price && Boolean(formik.errors.total_price)
+ }
+ errorMessage={formik.errors.total_price}
+ placeholder='Masukan Total Penjualan'
+ />
-
-
+
+
+
diff --git a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx
index 6b6f6a81..885cd8fc 100644
--- a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx
+++ b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx
@@ -1,21 +1,27 @@
-import Table from '@/components/Table';
import { DeliveryOrderProductFormValues } from '@/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.schema';
import Button from '@/components/Button';
import { Icon } from '@iconify/react';
-import * as TanStack from '@tanstack/react-table';
-import { useMemo, useRef } from 'react';
-import {
- cn,
- formatCurrency,
- formatDate,
- formatNumber,
- formatVechicleNumber,
-} from '@/lib/helper';
+import { useRef } from 'react';
+import { formatCurrency, formatDate, formatNumber } from '@/lib/helper';
+import DeliveryOrderExport from '@/components/pages/marketing/pdf/DeliveryOrderExport';
+import { Marketing } from '@/types/api/marketing/marketing';
type DeliveryOrderProductTableProps = {
data: DeliveryOrderProductFormValues[];
- formType?: 'add' | 'edit' | 'add_deliver' | 'edit_deliver';
- onEdit: (id: number) => void;
+ formType?:
+ | 'add'
+ | 'edit'
+ | 'add_deliver'
+ | 'edit_deliver'
+ | 'add_delivery'
+ | 'edit_delivery'
+ | 'detail'
+ | 'rejected'
+ | 'pending'
+ | string
+ | null;
+ marketing?: Marketing;
+ onEdit: (id: number, values: DeliveryOrderProductFormValues) => void;
onDelete: (id: number) => void;
onAddProductClick: () => void;
};
@@ -26,201 +32,168 @@ const DeliveryOrderProductTable = ({
onEdit,
onDelete,
onAddProductClick,
+ marketing,
}: DeliveryOrderProductTableProps) => {
const onEditRef = useRef(onEdit);
onEditRef.current = onEdit;
const onDeleteRef = useRef(onDelete);
onDeleteRef.current = onDelete;
- const canAddData = data.filter((item) => !Boolean(item.qty));
-
- const columns = useMemo(() => {
- const cols = [
- {
- accessorFn: (row: DeliveryOrderProductFormValues) => row.do_number,
- header: 'No. Pengiriman',
- cell: (
- props: TanStack.CellContext
- ) => (
- <>
- {props.row.original.do_number ? props.row.original.do_number : '-'}
- >
- ),
- },
- {
- accessorFn: (row: DeliveryOrderProductFormValues) => row.vehicle_number,
- header: 'No. Polisi',
- cell: (
- props: TanStack.CellContext
- ) =>
- props.row.original.vehicle_number
- ? formatVechicleNumber(props.row.original.vehicle_number as string)
- : '-',
- },
- {
- accessorFn: (row: DeliveryOrderProductFormValues) =>
- row.marketing_product?.kandang?.label,
- header: 'Kandang',
- },
- {
- accessorFn: (row: DeliveryOrderProductFormValues) =>
- row.marketing_product?.product_warehouse?.label,
- header: 'Produk',
- },
- {
- accessorFn: (row: DeliveryOrderProductFormValues) =>
- row.delivery_date
- ? formatDate(row.delivery_date as string, 'DD MMM YYYY')
- : '-',
- header: 'Tanggal Delivery',
- cell: (
- props: TanStack.CellContext
- ) =>
- 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
- ) =>
- props.row.original.unit_price
- ? formatCurrency(
- parseFloat(props.row.original.unit_price as string)
- )
- : '-',
- },
- {
- accessorFn: (row: DeliveryOrderProductFormValues) => row.total_weight,
- header: 'Total Bobot (Kg)',
- cell: (
- props: TanStack.CellContext
- ) =>
- props.row.original.total_weight
- ? formatNumber(
- parseFloat(props.row.original.total_weight as string)
- )
- : '-',
- },
- {
- accessorFn: (row: DeliveryOrderProductFormValues) => row.qty,
- header: 'Kuantitas',
- cell: (
- props: TanStack.CellContext
- ) =>
- props.row.original.qty
- ? formatNumber(parseFloat(props.row.original.qty as string))
- : '-',
- },
- {
- accessorFn: (row: DeliveryOrderProductFormValues) => row.avg_weight,
- header: 'Avg. Bobot (Kg)',
- cell: (
- props: TanStack.CellContext
- ) =>
- props.row.original.avg_weight
- ? formatNumber(parseFloat(props.row.original.avg_weight as string))
- : '-',
- },
- {
- accessorFn: (row: DeliveryOrderProductFormValues) => row.total_price,
- header: 'Total Penjualan (Rp)',
- cell: (
- props: TanStack.CellContext
- ) =>
- props.row.original.total_price
- ? formatCurrency(
- parseFloat(props.row.original.total_price as string)
- )
- : '-',
- },
-
- {
- header: 'Aksi',
- cell: (
- props: TanStack.CellContext
- ) => (
-
- <>
- {props.row.original.qty && (
- <>
-
-
- >
- )}
- {!props.row.original.qty && '-'}
- >
-
- ),
- },
- ];
- if (formType == 'add_deliver') {
- return cols.filter((col) => col.header != 'No. Pengiriman');
- }
- return cols;
- }, [formType, onEditRef]);
-
return (
<>
-
- data={data}
- columns={columns}
- className={{
- 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-2 py-2 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end first:flex first:flex-row first:justify-start',
- bodyRowClassName: 'border-b border-b-gray-200',
- bodyColumnClassName:
- 'px-2 py-2 last:flex last:flex-row last:justify-end',
- paginationClassName: 'hidden',
- }}
- emptyContent={
-
- Belum ada data pengiriman
-
- }
- />
-
-
+
+ {data.map((item) => {
+ const doItem = marketing?.delivery_order?.find(
+ (doItem) => doItem.do_number === item.do_number
+ );
+ return (
+
+
+
+
+ |
+ Label
+ |
+
+
+ Value
+ {(formType === 'add_delivery' ||
+ formType === 'edit_delivery' ||
+ formType === 'detail') && (
+
+
+
+
+ )}
+
+ |
+
+ <>
+
+ | Tanggal Pengiriman |
+
+ {item.delivery_date ? (
+ formatDate(item.delivery_date, 'DD MMM YYYY')
+ ) : (
+ Belum diisi
+ )}
+ |
+
+ {item.do_number && (
+
+ | No. Pengiriman |
+ {item.do_number} |
+
+ )}
+
+ | No. Polisi |
+
+ {item.vehicle_number}
+ |
+
+
+ | Gudang |
+
+ {item.marketing_product?.product_warehouse?.label}
+ |
+
+
+ | Produk |
+
+ {item.marketing_product?.product_warehouse?.label}
+ |
+
+
+ | Qty |
+
+ {item.qty
+ ? `${formatNumber(parseFloat(item.qty as string))} ${item.marketing_product?.uom ?? ''}`
+ : '-'}
+ |
+
+
+ | Avg Bobot |
+
+ {item.avg_weight
+ ? formatNumber(
+ parseFloat(item.avg_weight as string)
+ ) + ' Kg'
+ : '-'}
+ |
+
+
+ | Total Bobot |
+
+ {formatNumber(parseFloat(item.total_weight as string))}
+ |
+
+
+ | Total Harga Satuan |
+
+ {formatCurrency(parseFloat(item.unit_price as string))}
+ |
+
+
+ | Total Penjualan |
+
+ {formatCurrency(parseFloat(item.total_price as string))}
+ |
+
+ {doItem && (
+
+ |
+ Dokumen Pengiriman
+ |
+
+
+ |
+
+ )}
+ >
+
+
+
+ );
+ })}
>
);
diff --git a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx
index 02d33587..5ac9eede 100644
--- a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx
+++ b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx
@@ -1,42 +1,30 @@
'use client';
import Button from '@/components/Button';
-import Table from '@/components/Table';
import { SalesOrderProductFormValues } from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema';
import {
- cn,
formatCurrency,
formatNumber,
formatVechicleNumber,
} from '@/lib/helper';
import { Icon } from '@iconify/react';
-import { useMemo, useRef, useState } from 'react';
+import { useMemo, useRef } from 'react';
import * as TanStack from '@tanstack/react-table';
import CheckboxInput from '@/components/input/CheckboxInput';
type SalesOrderProductTableProps = {
data: SalesOrderProductFormValues[];
- formType: 'add' | 'edit' | 'add_deliver' | 'edit_deliver';
- rowSelection: Record
;
- setRowSelection: React.Dispatch<
- React.SetStateAction>
- >;
- selectedRowIds: number[];
+ formType: 'add' | 'edit' | 'add_deliver' | 'edit_deliver' | 'success';
onDelete: (id: number) => void;
onEdit: (id: number) => void;
- onBulkDelete: () => void;
onAddProductClick: () => void;
};
const SalesOrderProductTable = ({
data,
formType,
- rowSelection,
- setRowSelection,
- selectedRowIds,
onDelete,
onEdit,
- onBulkDelete,
onAddProductClick,
}: SalesOrderProductTableProps) => {
const onDeleteRef = useRef(onDelete);
@@ -156,67 +144,135 @@ const SalesOrderProductTable = ({
return (
<>
-
- rowSelection={rowSelection}
- setRowSelection={setRowSelection}
- data={data}
- columns={
- formType == 'add_deliver' || formType == 'edit_deliver'
- ? columns.filter(
- (col) => col.header != 'Aksi' && col.id != 'select'
- )
- : columns
- }
- className={{
- 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-2 py-2 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end first:flex first:flex-row first:justify-start',
- bodyRowClassName: 'border-b border-b-gray-200',
- bodyColumnClassName:
- 'px-2 py-2 last:flex last:flex-row last:justify-end first:flex first:flex-row first:justify-start',
- paginationClassName: 'hidden',
- }}
- emptyContent={
+
+ {data.map((item) => (
-
Belum ada data penjualan
+
+
+
+ |
+ Label
+ |
+
+
+ Value
+ {formType !== 'success' && (
+
+
+
+
+ )}
+
+ |
+
+ <>
+
+ | No. Polisi |
+ {item.vehicle_number} |
+
+
+ | Gudang |
+
+ {item.product_warehouse?.label}
+ |
+
+
+ | Produk |
+
+ {item.product_warehouse?.label}
+ |
+
+
+ | Total Bobot |
+
+ {item.total_weight
+ ? formatNumber(
+ parseFloat(item.total_weight as string)
+ ) + ' Kg'
+ : '-'}
+ |
+
+
+ | Avg Bobot |
+
+ {item.avg_weight
+ ? formatNumber(parseFloat(item.avg_weight as string)) +
+ ' Kg'
+ : '-'}
+ |
+
+
+ | Qty |
+
+ {`${formatNumber(parseFloat(item.qty as string))} ${item.uom || ''}`}
+ |
+
+
+ | Total Harga Satuan |
+
+ {formatCurrency(parseFloat(item.unit_price as string))}
+ |
+
+
+ | Total Penjualan |
+
+ {formatCurrency(parseFloat(item.total_price as string))}
+ |
+
+ >
+
+
- }
- />
- {formType != 'add_deliver' && formType != 'edit_deliver' && (
-
-
- {selectedRowIds.length > 0 && (
+ ))}
+ {formType != 'add_deliver' &&
+ formType != 'edit_deliver' &&
+ formType != 'success' && (
)}
-
- )}
+
>
);
};
diff --git a/src/components/pages/marketing/pdf/DeliveryOrderExport.tsx b/src/components/pages/marketing/pdf/DeliveryOrderExport.tsx
index 4659c650..61ce7913 100644
--- a/src/components/pages/marketing/pdf/DeliveryOrderExport.tsx
+++ b/src/components/pages/marketing/pdf/DeliveryOrderExport.tsx
@@ -4,10 +4,9 @@ import { Icon } from '@iconify/react';
import { Document, Image, Page, pdf, Text, View } from '@react-pdf/renderer';
import { useMemo, useState } from 'react';
import { formatDate, formatNumber, formatVechicleNumber } from '@/lib/helper';
-import { format } from 'path';
-import { date } from 'yup';
import pdfStyles from '@/components/pages/marketing/pdf/styles/MarketingPDFStyles';
import toast from 'react-hot-toast';
+import { useSearchParams } from 'next/navigation';
interface DeliveryOrderExportProps {
data?: Marketing;
@@ -21,6 +20,9 @@ const DeliveryOrderExport = ({
}: DeliveryOrderExportProps) => {
const [isGeneratingPDF, setIsGeneratingPDF] = useState(false);
const salesData = data;
+ const searchParams = useSearchParams();
+ const action = searchParams.get('action');
+ const id = searchParams.get('id');
const handleDownloadPDF = async () => {
if (!salesData) {
@@ -32,37 +34,47 @@ const DeliveryOrderExport = ({
const blob = await pdf(
).toBlob();
- const url = URL.createObjectURL(blob);
+ const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
+ link.style.display = 'none';
link.href = url;
link.download = `${deliveryOrder?.do_number || 'delivery-order'}.pdf`;
+ link.setAttribute('target', '_blank');
+ link.setAttribute('rel', 'noopener noreferrer');
document.body.appendChild(link);
link.click();
- document.body.removeChild(link);
- URL.revokeObjectURL(url);
+
+ // Delay cleanup to ensure download starts
+ setTimeout(() => {
+ document.body.removeChild(link);
+ window.URL.revokeObjectURL(url);
+ }, 150);
} catch (error) {
toast.error('Failed to generate PDF. Please try again.');
} finally {
setIsGeneratingPDF(false);
+ window.location.href = `/marketing?action=${action}&id=${id}`;
}
};
if (!salesData) {
return (
-
+
No sales order data available
);
}
- return salesData?.so_number && salesData.so_number !== 'Belum dibuat' ? (
+ return deliveryOrder?.do_number ? (
) : null;
@@ -87,11 +99,6 @@ const PDFDocument = ({
{/* Header Section */}
-
PT LUMBUNG TELUR INDONESIA
SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel.
diff --git a/src/components/pages/marketing/pdf/SalesOrderExport.tsx b/src/components/pages/marketing/pdf/SalesOrderExport.tsx
index 5d892853..5767c049 100644
--- a/src/components/pages/marketing/pdf/SalesOrderExport.tsx
+++ b/src/components/pages/marketing/pdf/SalesOrderExport.tsx
@@ -6,6 +6,7 @@ import { useMemo, useState } from 'react';
import { formatDate, formatNumber } from '@/lib/helper';
import pdfStyles from '@/components/pages/marketing/pdf/styles/MarketingPDFStyles';
import toast from 'react-hot-toast';
+import { useSearchParams } from 'next/navigation';
interface SalesOrderExportProps {
data?: Marketing;
@@ -15,6 +16,9 @@ interface SalesOrderExportProps {
const SalesOrderExport = ({ data }: SalesOrderExportProps) => {
const [isGeneratingPDF, setIsGeneratingPDF] = useState(false);
const salesData = data;
+ const searchParams = useSearchParams();
+ const action = searchParams.get('action');
+ const id = searchParams.get('id');
const handleDownloadPDF = async () => {
if (!salesData) {
@@ -24,24 +28,32 @@ const SalesOrderExport = ({ data }: SalesOrderExportProps) => {
setIsGeneratingPDF(true);
try {
const blob = await pdf().toBlob();
- const url = URL.createObjectURL(blob);
+ const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
+ link.style.display = 'none';
link.href = url;
link.download = `${salesData?.so_number || 'sales-order'}.pdf`;
+ link.setAttribute('target', '_blank');
+ link.setAttribute('rel', 'noopener noreferrer');
document.body.appendChild(link);
link.click();
- document.body.removeChild(link);
- URL.revokeObjectURL(url);
+
+ // Delay cleanup to ensure download starts
+ setTimeout(() => {
+ document.body.removeChild(link);
+ window.URL.revokeObjectURL(url);
+ }, 150);
} catch (error) {
toast.error('Failed to generate PDF. Please try again.');
} finally {
setIsGeneratingPDF(false);
+ window.location.href = `/marketing?action=${action}&id=${id}`;
}
};
if (!salesData) {
return (
-
+
No sales order data available
);
@@ -49,12 +61,14 @@ const SalesOrderExport = ({ data }: SalesOrderExportProps) => {
return salesData?.so_number && salesData.so_number !== 'Belum dibuat' ? (
) : null;
@@ -71,11 +85,6 @@ const PDFDocument = ({ data }: { data: Marketing }) => {
{/* Header Section */}
-
PT LUMBUNG TELUR INDONESIA
SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel.
diff --git a/src/components/pages/report/DailyMarketingsTable.tsx b/src/components/pages/report/DailyMarketingsTable.tsx
index 2ed5a9cb..4904ef16 100644
--- a/src/components/pages/report/DailyMarketingsTable.tsx
+++ b/src/components/pages/report/DailyMarketingsTable.tsx
@@ -190,8 +190,6 @@ const DailyMarketingsTable = ({
];
useEffect(() => {
- // console.log({ sorting });
-
if (sorting.length === 1) {
onFilterByChange(sorting[0].id);
onSortByChange(sorting[0].desc ? 'desc' : 'asc');
diff --git a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx
index 266b8740..8cef1da7 100644
--- a/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx
+++ b/src/figma-make/components/pages/daily-checklist/DailyChecklistContent.tsx
@@ -658,16 +658,6 @@ export function DailyChecklistContent() {
) => {
const taskId = taskIdsByPhaseActivityId[activityId];
- // console.log('[CHECKBOX] Click detected:', {
- // activityId,
- // employeeId,
- // checked,
- // taskId,
- // hasTaskId: !!taskId,
- // checklistStatus,
- // isChecklistStatusDraft,
- // });
-
if (!taskId) {
console.error('[CHECKBOX] No taskId found for activityId:', activityId);
console.error('[CHECKBOX] Available taskIds:', taskIdsByPhaseActivityId);
@@ -695,10 +685,7 @@ export function DailyChecklistContent() {
},
},
};
- // console.log(
- // '[CHECKBOX] State updated optimistically:',
- // updated[taskId]?.[employeeId]
- // );
+
return updated;
});
@@ -710,8 +697,6 @@ export function DailyChecklistContent() {
note: assignments[taskId]?.[employeeId]?.note || null,
};
- // console.log('[CHECKBOX] Saving to database:', payload);
-
const checkOrUncheckAssignmentRes =
await DailyChecklistApi.checkOrUncheckAssignment(payload);
@@ -735,8 +720,6 @@ export function DailyChecklistContent() {
}));
return;
}
-
- // console.log('[CHECKBOX] Saved successfully');
};
const handleNoteChange = async (
@@ -1247,8 +1230,6 @@ export function DailyChecklistContent() {
})
);
- console.log(activities);
-
activities.forEach((activity, index) => {
const taskId =
taskIdsByPhaseActivityId[activity.id];
diff --git a/src/figma-make/components/pages/list-daily-checklist/detail/DetailDailyChecklistContent.tsx b/src/figma-make/components/pages/list-daily-checklist/detail/DetailDailyChecklistContent.tsx
index bc9653d4..846a2670 100644
--- a/src/figma-make/components/pages/list-daily-checklist/detail/DetailDailyChecklistContent.tsx
+++ b/src/figma-make/components/pages/list-daily-checklist/detail/DetailDailyChecklistContent.tsx
@@ -17,7 +17,7 @@ import {
DialogFooter,
} from '@/figma-make/components/base/dialog';
import { toast } from 'sonner';
-import { useRouter, useSearchParams } from 'next/navigation';
+import { notFound, useRouter, useSearchParams } from 'next/navigation';
import { DailyChecklistApi } from '@/services/api/daily-checklist/daily-checklist';
import { isResponseError } from '@/lib/api-helper';
import Link from 'next/link';
@@ -140,6 +140,8 @@ export function DetailDailyChecklistContent() {
useEffect(() => {
if (checklistId) {
fetchChecklistDetail();
+ } else {
+ router.push('/404');
}
}, [checklistId]);
@@ -802,10 +804,6 @@ export function DetailDailyChecklistContent() {
? 'pl-12'
: 'pl-8';
- console.log({
- activity,
- });
-
rows.push(
{
+ constructor(basePath: string = '/marketing') {
+ super(basePath);
+ }
+
+ /**
+ * Export to Excel
+ */
+ async exportToExcel(initialQueryString: string) {
+ const params = new URLSearchParams(initialQueryString);
+ const queryString = `?${params.toString()}`;
+
+ try {
+ const marketingData = await httpClientFetcher<
+ BaseApiResponse
+ >(`${this.basePath}${queryString}`);
+
+ if (isResponseError(marketingData)) {
+ toast.error('Gagal melakukan export marketing! Coba lagi.');
+ return;
+ }
+
+ const rows = marketingData.data;
+
+ const formattedRows = [];
+
+ for (let i = 0; i < rows.length; i++) {
+ const row = rows[i];
+ const approval = row.latest_approval;
+ const isRejected = approval?.action === 'REJECTED';
+
+ // Calculate grand total from sales_order products
+ const grandTotal =
+ row.sales_order
+ ?.map((product) => product.total_price)
+ .reduce((a, b) => a + b, 0) ?? 0;
+
+ // Get product names
+ const products =
+ row.sales_order
+ ?.map((product) => product.product_warehouse?.product?.name)
+ .filter(Boolean)
+ .join(', ') ?? '';
+
+ formattedRows.push({
+ 'No. Order': row.so_number,
+ Tanggal: formatDate(row.so_date, 'DD-MM-YYYY'),
+ Status: isRejected
+ ? 'Ditolak'
+ : formatTitleCase(approval?.step_name || ''),
+ Customer: row.customer?.name || '',
+ 'Grand Total': formatCurrency(grandTotal),
+ Products: products,
+ Notes: row.notes || '',
+ });
+ }
+
+ const ws = XLSX.utils.json_to_sheet(formattedRows);
+ const wb = XLSX.utils.book_new();
+ XLSX.utils.book_append_sheet(wb, ws, 'marketing');
+
+ // triggers download in browser
+ XLSX.writeFile(wb, 'marketing.xlsx');
+ } catch (error) {
+ toast.error('Gagal melakukan export marketing! Coba lagi.');
+ }
+ }
+}
export const SalesOrderApi = new SalesOrderService('/marketing/sales-orders');
export const DeliveryOrderApi = new BaseApiService<
@@ -104,6 +180,4 @@ export const DeliveryOrderApi = new BaseApiService<
CreateDeliveryOrderPayload,
UpdateDeliveryOrderPayload
>('/marketing/delivery-orders');
-export const MarketingApi = new BaseApiService(
- '/marketing'
-);
+export const MarketingApi = new MarketingExportService('/marketing');
diff --git a/src/services/hooks/useFormikErrorList.ts b/src/services/hooks/useFormikErrorList.ts
index 94aa78bd..0d26acca 100644
--- a/src/services/hooks/useFormikErrorList.ts
+++ b/src/services/hooks/useFormikErrorList.ts
@@ -5,6 +5,7 @@ import { useState } from 'react';
interface UseFormikErrorListOptions {
onBeforeSubmit?: (e: React.FormEvent) => boolean | void;
onAfterValidation?: () => void | Promise;
+ onAfterSubmit?: () => void | Promise;
}
export const useFormikErrorList = (
@@ -49,6 +50,11 @@ export const useFormikErrorList = (
// Submit form
formik.handleSubmit();
+
+ // Call onAfterSubmit callback if validation passed
+ if (options?.onAfterSubmit) {
+ await options.onAfterSubmit();
+ }
};
const close = () => {
diff --git a/src/types/api/marketing/marketing.d.ts b/src/types/api/marketing/marketing.d.ts
index 931184f9..7d0e390c 100644
--- a/src/types/api/marketing/marketing.d.ts
+++ b/src/types/api/marketing/marketing.d.ts
@@ -82,6 +82,15 @@ export type MarketingDeliveryProducts = {
export type Marketing = BaseMetadata & BaseMarketing;
+/**
+ * Filter Data Types
+ */
+export type MarketingFilter = {
+ product_ids: number[];
+ status: string;
+ customer_id: number;
+};
+
/**
* Base Data Payload
*/