mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-23 14:55:44 +00:00
Merge branch 'development' of https://gitlab.com/mbugroup/lti-web-client into fix/debt-supplier
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { ChangeEventHandler, useState } from 'react';
|
||||
import { ChangeEventHandler, useEffect, useState } from 'react';
|
||||
import { pdf } from '@react-pdf/renderer';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
@@ -28,7 +28,10 @@ import {
|
||||
import { Warehouse } from '@/types/api/master-data/warehouse';
|
||||
import { Customer } from '@/types/api/master-data/customer';
|
||||
import { MarketingReportApi } from '@/services/api/report/marketing-report';
|
||||
import { MARKETING_TYPE_OPTIONS } from '@/config/constant';
|
||||
import {
|
||||
MARKETING_DATE_FILTER_TYPE_OPTIONS,
|
||||
MARKETING_TYPE_OPTIONS,
|
||||
} from '@/config/constant';
|
||||
import { httpClient } from '@/services/http/client';
|
||||
import { BaseApiResponse } from '@/types/api/api-general';
|
||||
import {
|
||||
@@ -150,6 +153,15 @@ const DailyMarketingReportContent = () => {
|
||||
updateFilter('end_date', e.target.value ? e.target.value : '');
|
||||
};
|
||||
|
||||
const [selectedMarketingDateFilterType, setSelectedMarketingDateFilterType] =
|
||||
useState<OptionType | null>(null);
|
||||
const marketingDateFilterTypeChangeHandler = (
|
||||
val: OptionType | OptionType[] | null
|
||||
) => {
|
||||
setSelectedMarketingDateFilterType(val as OptionType);
|
||||
updateFilter('filter_by', val ? ((val as OptionType).value as string) : '');
|
||||
};
|
||||
|
||||
const [selectedMarketingType, setSelectedMarketingType] =
|
||||
useState<OptionType | null>(null);
|
||||
const marketingTypeChangeHandler = (
|
||||
@@ -252,6 +264,23 @@ const DailyMarketingReportContent = () => {
|
||||
resetFilter();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
tableFilterState.filter_by === 'realization_date' ||
|
||||
tableFilterState.filter_by === 'so_date'
|
||||
) {
|
||||
setSelectedMarketingDateFilterType({
|
||||
label:
|
||||
tableFilterState.filter_by === 'realization_date'
|
||||
? 'Tanggal Realisasi'
|
||||
: 'Tanggal SO',
|
||||
value: tableFilterState.filter_by,
|
||||
});
|
||||
} else {
|
||||
setSelectedMarketingDateFilterType(null);
|
||||
}
|
||||
}, [tableFilterState.filter_by]);
|
||||
|
||||
return (
|
||||
<div className='w-full border border-gray-200 p-4'>
|
||||
<div>
|
||||
@@ -341,6 +370,18 @@ const DailyMarketingReportContent = () => {
|
||||
</div>
|
||||
|
||||
<div className='grid grid-cols-12 gap-4'>
|
||||
<SelectInput
|
||||
label='Filter Tanggal'
|
||||
placeholder='Pilih Filter Tanggal'
|
||||
options={MARKETING_DATE_FILTER_TYPE_OPTIONS}
|
||||
value={selectedMarketingDateFilterType}
|
||||
onChange={marketingDateFilterTypeChangeHandler}
|
||||
isClearable
|
||||
className={{
|
||||
wrapper: 'col-span-12 sm:col-span-6 lg:col-span-4',
|
||||
}}
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
label='Tipe Marketing'
|
||||
placeholder='Pilih Tipe Marketing'
|
||||
|
||||
@@ -71,19 +71,22 @@ const DailyMarketingsTable = ({
|
||||
cell: (props) => `${props.row.original.aging_days} hari`,
|
||||
},
|
||||
{
|
||||
accessorKey: 'warehouse.name',
|
||||
accessorKey: 'warehouse',
|
||||
header: 'Gudang',
|
||||
cell: ({ row }) => row.original.warehouse.name,
|
||||
},
|
||||
{
|
||||
accessorKey: 'customer.name',
|
||||
accessorKey: 'customer',
|
||||
header: 'Pelanggan',
|
||||
cell: ({ row }) => row.original.customer.name,
|
||||
},
|
||||
{
|
||||
accessorKey: 'do_number',
|
||||
header: 'No. DO',
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
accessorKey: 'sales',
|
||||
accessorKey: 'sales_person',
|
||||
header: 'Sales/Marketing',
|
||||
cell: (props) => props.row.original.sales.name,
|
||||
},
|
||||
@@ -97,10 +100,12 @@ const DailyMarketingsTable = ({
|
||||
{
|
||||
accessorKey: 'marketing_type',
|
||||
header: 'Marketing Type',
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
accessorKey: 'product.name',
|
||||
accessorKey: 'product',
|
||||
header: 'Produk',
|
||||
cell: ({ row }) => row.original.product.name,
|
||||
},
|
||||
{
|
||||
accessorKey: 'qty',
|
||||
@@ -115,12 +120,12 @@ const DailyMarketingsTable = ({
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'average_weight_kg',
|
||||
accessorKey: 'average_weight',
|
||||
header: 'Bobot Rata-Rata (Kg)',
|
||||
cell: (props) => formatNumber(props.row.original.average_weight_kg),
|
||||
},
|
||||
{
|
||||
accessorKey: 'total_weight_kg',
|
||||
accessorKey: 'total_weight',
|
||||
header: 'Bobot Total (Kg)',
|
||||
cell: (props) => formatNumber(props.row.original.total_weight_kg),
|
||||
footer: () => {
|
||||
@@ -132,12 +137,12 @@ const DailyMarketingsTable = ({
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'sales_price_per_kg',
|
||||
accessorKey: 'sales_price',
|
||||
header: 'Harga Jual (Rp)',
|
||||
cell: (props) => formatCurrency(props.row.original.sales_price_per_kg),
|
||||
},
|
||||
{
|
||||
accessorKey: 'hpp_price_per_kg',
|
||||
accessorKey: 'hpp_price',
|
||||
header: 'HPP (Rp)',
|
||||
cell: (props) => formatCurrency(props.row.original.hpp_price_per_kg),
|
||||
footer: () => {
|
||||
@@ -163,6 +168,8 @@ const DailyMarketingsTable = ({
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
console.log({ sorting });
|
||||
|
||||
if (sorting.length === 1) {
|
||||
onFilterByChange(sorting[0].id);
|
||||
onSortByChange(sorting[0].desc ? 'desc' : 'asc');
|
||||
|
||||
@@ -33,7 +33,7 @@ const MarketingReportContent = () => {
|
||||
const [activeTab, setActiveTab] = useState<string>('daily');
|
||||
|
||||
return (
|
||||
<section className='w-full max-w-7xl pb-16'>
|
||||
<section className='w-full max-w-full pb-16'>
|
||||
<Tabs
|
||||
activeTabId={activeTab}
|
||||
onTabChange={setActiveTab}
|
||||
|
||||
@@ -136,41 +136,132 @@ const pdfStyles = StyleSheet.create({
|
||||
backgroundColor: '#F0F0F0',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
badge: {
|
||||
backgroundColor: '#1f74bf',
|
||||
color: '#FFFFFF',
|
||||
padding: 2,
|
||||
borderRadius: 2,
|
||||
fontSize: 7,
|
||||
fontWeight: 'bold',
|
||||
alignSelf: 'center',
|
||||
marginRight: 4,
|
||||
},
|
||||
badgeLunas: {
|
||||
backgroundColor: '#1f74bf',
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
badgeBelumLunas: {
|
||||
backgroundColor: '#F97316',
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
textError: {
|
||||
color: '#DC2626',
|
||||
},
|
||||
parameterBadge: {
|
||||
backgroundColor: '#F5F5F5',
|
||||
color: '#333333',
|
||||
padding: 4,
|
||||
borderRadius: 4,
|
||||
fontSize: 8,
|
||||
marginRight: 8,
|
||||
marginBottom: 4,
|
||||
},
|
||||
parameterContainer: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
marginBottom: 8,
|
||||
},
|
||||
});
|
||||
|
||||
interface CustomerPaymentExportPDFParams {
|
||||
data: CustomerPaymentReport[];
|
||||
params?: {
|
||||
customer_name?: string;
|
||||
sales?: string;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
filter_by?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const getParameterText = (
|
||||
params?: CustomerPaymentExportPDFParams['params']
|
||||
) => {
|
||||
const paramsText = [];
|
||||
|
||||
if (params?.customer_name) {
|
||||
paramsText.push(`Customer: ${params.customer_name}`);
|
||||
} else {
|
||||
paramsText.push('Semua Customer');
|
||||
}
|
||||
|
||||
if (params?.sales) {
|
||||
paramsText.push(`Sales: ${params.sales}`);
|
||||
}
|
||||
|
||||
if (params?.start_date && params?.end_date) {
|
||||
const startDate = formatDate(params.start_date, 'DD MMM YYYY');
|
||||
const endDate = formatDate(params.end_date, 'DD MMM YYYY');
|
||||
paramsText.push(`Periode: ${startDate} - ${endDate}`);
|
||||
} else if (params?.start_date) {
|
||||
const startDate = formatDate(params.start_date, 'DD MMM YYYY');
|
||||
paramsText.push(`Tanggal: ${startDate}`);
|
||||
}
|
||||
|
||||
const currentDate = formatDate(new Date(), 'DD MMM YYYY HH:mm');
|
||||
paramsText.push(`Dicetak: ${currentDate}`);
|
||||
|
||||
return paramsText;
|
||||
};
|
||||
|
||||
const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
||||
return (
|
||||
<Document>
|
||||
{params.data.map((customerReport, customerIndex) => (
|
||||
<Page
|
||||
key={customerIndex}
|
||||
size='A4'
|
||||
size='A3'
|
||||
orientation='landscape'
|
||||
style={pdfStyles.page}
|
||||
>
|
||||
{/* Title and Customer Info */}
|
||||
{/* Title and Parameters */}
|
||||
<View style={pdfStyles.titleSection}>
|
||||
<Text style={pdfStyles.mainTitle}>
|
||||
Laporan > Kontrol Pembayaran Customer
|
||||
</Text>
|
||||
<View style={pdfStyles.parameterContainer}>
|
||||
<View style={pdfStyles.parameterBadge}>
|
||||
<Text>
|
||||
Periode:{' '}
|
||||
{params.params?.start_date
|
||||
? formatDate(params.params.start_date, 'DD MMM YYYY')
|
||||
: '-'}{' '}
|
||||
s.d{' '}
|
||||
{params.params?.end_date
|
||||
? formatDate(params.params.end_date, 'DD MMM YYYY')
|
||||
: '-'}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={pdfStyles.parameterBadge}>
|
||||
<Text>Filter Tanggal: Tanggal DO</Text>
|
||||
</View>
|
||||
<View style={pdfStyles.parameterBadge}>
|
||||
<Text>
|
||||
Customer: {params.params?.customer_name || 'Semua Customer'}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={pdfStyles.parameterBadge}>
|
||||
<Text>
|
||||
Dicetak: {formatDate(new Date(), 'DD MMM YYYY HH:mm')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Text style={pdfStyles.supplierTitle}>
|
||||
{customerReport.customer.name}
|
||||
</Text>
|
||||
<Text style={pdfStyles.supplierInfo}>
|
||||
{customerReport.customer.address || ''}
|
||||
Alamat: {customerReport.customer.address || '-'}
|
||||
</Text>
|
||||
{customerReport.summary && (
|
||||
<Text style={pdfStyles.supplierInfo}>
|
||||
Total Saldo Piutang:{' '}
|
||||
{formatCurrency(
|
||||
customerReport.summary.total_accounts_receivable
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Table */}
|
||||
@@ -181,10 +272,10 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
||||
<Text>No</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
||||
<Text>Tgl DO/Bayar</Text>
|
||||
<Text>Tanggal DO</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
||||
<Text>Tgl Realisasi</Text>
|
||||
<Text>Tanggal Realisasi</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeader, { flex: 0.8 }]}>
|
||||
<Text>Aging</Text>
|
||||
@@ -193,16 +284,16 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
||||
<Text>Referensi</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
||||
<Text>No. Polisi</Text>
|
||||
<Text>No Polisi</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
||||
<Text>Qty</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1 }]}>
|
||||
<Text>Berat (Kg)</Text>
|
||||
<Text>Berat</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
||||
<Text>AVG</Text>
|
||||
<Text>Rata-Rata</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
||||
<Text>Harga Awal</Text>
|
||||
@@ -214,7 +305,7 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
||||
<Text>Harga Akhir</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
||||
<Text>PPN (%)</Text>
|
||||
<Text>Pajak</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
||||
<Text>Total</Text>
|
||||
@@ -223,10 +314,10 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
||||
<Text>Pembayaran</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
||||
<Text>Saldo Piutang</Text>
|
||||
<Text>Saldo</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeader, { flex: 1.5 }]}>
|
||||
<Text>Ket</Text>
|
||||
<Text>Keterangan</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
||||
<Text>Pengambilan</Text>
|
||||
@@ -301,10 +392,29 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
||||
<Text>{formatCurrency(item.payment)}</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||
<Text>{formatCurrency(item.accounts_receivable)}</Text>
|
||||
<Text style={pdfStyles.textError}>
|
||||
{formatCurrency(item.accounts_receivable)}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
||||
<Text>{item.notes || '-'}</Text>
|
||||
{item.notes ? (
|
||||
<Text>{item.notes}</Text>
|
||||
) : (
|
||||
<View
|
||||
style={[
|
||||
pdfStyles.badge,
|
||||
item.accounts_receivable === 0
|
||||
? pdfStyles.badgeLunas
|
||||
: pdfStyles.badgeBelumLunas,
|
||||
]}
|
||||
>
|
||||
<Text>
|
||||
{item.accounts_receivable === 0
|
||||
? 'Lunas'
|
||||
: 'Belum Lunas'}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||
<Text>{item.pickup_info || '-'}</Text>
|
||||
@@ -378,7 +488,7 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||
<Text>
|
||||
<Text style={pdfStyles.textError}>
|
||||
{formatCurrency(
|
||||
customerReport.summary.total_accounts_receivable
|
||||
)}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState, useMemo, useCallback } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import { Icon } from '@iconify/react';
|
||||
import Card from '@/components/Card';
|
||||
import Badge from '@/components/Badge';
|
||||
import SelectInput, {
|
||||
useSelect,
|
||||
OptionType,
|
||||
@@ -46,7 +47,6 @@ const CustomerPaymentTab = () => {
|
||||
const [filterSales, setFilterSales] = useState<OptionType[]>([]);
|
||||
const [filterStartDate, setFilterStartDate] = useState('');
|
||||
const [filterEndDate, setFilterEndDate] = useState('');
|
||||
const [filterErrors, setFilterErrors] = useState<Record<string, string>>({});
|
||||
|
||||
const filterModal = useModal();
|
||||
|
||||
@@ -68,6 +68,38 @@ const CustomerPaymentTab = () => {
|
||||
[]
|
||||
);
|
||||
|
||||
const getPaymentStatusColor = (notes: string) => {
|
||||
const normalizedValue = notes.toLowerCase();
|
||||
|
||||
if (normalizedValue === 'lunas') {
|
||||
return 'bg-info/10 text-info border-info';
|
||||
}
|
||||
|
||||
if (normalizedValue.includes('belum')) {
|
||||
return 'bg-warning/10 text-warning border-warning';
|
||||
}
|
||||
|
||||
return 'bg-gray-100 text-gray-600 border-gray-300';
|
||||
};
|
||||
|
||||
const getPaymentStatusIndicatorColor = (notes: string) => {
|
||||
const normalizedValue = notes.toLowerCase();
|
||||
|
||||
if (normalizedValue === 'lunas') {
|
||||
return 'bg-info';
|
||||
}
|
||||
|
||||
if (normalizedValue.includes('belum')) {
|
||||
return 'bg-warning';
|
||||
}
|
||||
|
||||
return 'bg-gray-400';
|
||||
};
|
||||
|
||||
const getPaymentStatusText = (notes: string) => {
|
||||
return notes;
|
||||
};
|
||||
|
||||
// ===== FILTER HANDLERS =====
|
||||
const handleResetFilters = useCallback(() => {
|
||||
setIsSubmitted(false);
|
||||
@@ -75,27 +107,13 @@ const CustomerPaymentTab = () => {
|
||||
setFilterSales([]);
|
||||
setFilterStartDate('');
|
||||
setFilterEndDate('');
|
||||
setFilterErrors({});
|
||||
}, []);
|
||||
|
||||
const handleApplyFilters = useCallback(() => {
|
||||
const errors: Record<string, string> = {};
|
||||
|
||||
if (!filterStartDate) {
|
||||
errors.start_date = 'Tanggal mulai wajib diisi';
|
||||
}
|
||||
if (!filterEndDate) {
|
||||
errors.end_date = 'Tanggal akhir wajib diisi';
|
||||
}
|
||||
|
||||
setFilterErrors(errors);
|
||||
|
||||
if (Object.keys(errors).length === 0) {
|
||||
setIsSubmitted(true);
|
||||
setCurrentPage(1);
|
||||
filterModal.closeModal();
|
||||
}
|
||||
}, [filterModal, filterStartDate, filterEndDate]);
|
||||
setIsSubmitted(true);
|
||||
setCurrentPage(1);
|
||||
filterModal.closeModal();
|
||||
}, [filterModal]);
|
||||
|
||||
// ===== DATA FETCHING =====
|
||||
const { data: customerPayment, isLoading } = useSWR(
|
||||
@@ -218,7 +236,22 @@ const CustomerPaymentTab = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
await generateCustomerPaymentPDF({ data: allDataForExport });
|
||||
await generateCustomerPaymentPDF({
|
||||
data: allDataForExport,
|
||||
params: {
|
||||
customer_name:
|
||||
filterCustomer.length > 0
|
||||
? filterCustomer.map((c) => c.label).join(', ')
|
||||
: undefined,
|
||||
sales:
|
||||
filterSales.length > 0
|
||||
? filterSales.map((s) => s.label).join(', ')
|
||||
: undefined,
|
||||
start_date: filterStartDate || undefined,
|
||||
end_date: filterEndDate || undefined,
|
||||
filter_by: 'do_date',
|
||||
},
|
||||
});
|
||||
toast.success('PDF berhasil dibuat dan diunduh.');
|
||||
} catch {
|
||||
toast.error('Gagal membuat PDF. Silakan coba lagi.');
|
||||
@@ -435,7 +468,9 @@ const CustomerPaymentTab = () => {
|
||||
accessorKey: 'accounts_receivable',
|
||||
cell: (props) => {
|
||||
const value = props.row.original.accounts_receivable;
|
||||
return <div className='text-right'>{formatCurrency(value)}</div>;
|
||||
return (
|
||||
<div className='text-right text-error'>{formatCurrency(value)}</div>
|
||||
);
|
||||
},
|
||||
footer: () => (
|
||||
<div className='text-right font-semibold text-gray-900'>
|
||||
@@ -449,7 +484,23 @@ const CustomerPaymentTab = () => {
|
||||
accessorKey: 'notes',
|
||||
cell: (props) => {
|
||||
const value = props.row.original.notes;
|
||||
return value || '-';
|
||||
|
||||
if (!value) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
return (
|
||||
<Badge
|
||||
statusIndicator={true}
|
||||
variant='soft'
|
||||
className={{
|
||||
badge: `rounded-xl justify-start border border-gray-200 ${getPaymentStatusColor(value)}`,
|
||||
status: getPaymentStatusIndicatorColor(value),
|
||||
}}
|
||||
>
|
||||
{getPaymentStatusText(value)}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -538,15 +589,9 @@ const CustomerPaymentTab = () => {
|
||||
value={filterStartDate}
|
||||
onChange={(e) => {
|
||||
setFilterStartDate(e.target.value);
|
||||
setFilterErrors((prev) => ({ ...prev, start_date: '' }));
|
||||
}}
|
||||
className={{ wrapper: 'w-full' }}
|
||||
/>
|
||||
{filterErrors.start_date && (
|
||||
<p className='text-red-500 text-sm mt-1'>
|
||||
{filterErrors.start_date}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -556,15 +601,9 @@ const CustomerPaymentTab = () => {
|
||||
value={filterEndDate}
|
||||
onChange={(e) => {
|
||||
setFilterEndDate(e.target.value);
|
||||
setFilterErrors((prev) => ({ ...prev, end_date: '' }));
|
||||
}}
|
||||
className={{ wrapper: 'w-full' }}
|
||||
/>
|
||||
{filterErrors.end_date && (
|
||||
<p className='text-red-500 text-sm mt-1'>
|
||||
{filterErrors.end_date}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -659,14 +698,13 @@ const CustomerPaymentTab = () => {
|
||||
total_accounts_receivable: 0,
|
||||
};
|
||||
|
||||
const totalAccountsReceivable = summary.total_accounts_receivable;
|
||||
const tableColumns = getTableColumns(summary);
|
||||
|
||||
return (
|
||||
<Card
|
||||
key={customerReport.customer.id}
|
||||
title={customerReport.customer.name}
|
||||
subtitle={`${customerReport.customer.address || ''}\nSaldo Piutang: ${formatCurrency(totalAccountsReceivable)}`}
|
||||
subtitle={`${customerReport.customer.address || ''}`}
|
||||
className={{ wrapper: 'w-full' }}
|
||||
variant='bordered'
|
||||
collapsible={true}
|
||||
|
||||
Reference in New Issue
Block a user