feat: add saldo balance tracking and item notes support for orders and reports

This commit is contained in:
Firman Ramdhani
2026-09-16 13:13:40 +07:00
parent 44466f1566
commit d5791e759e
16 changed files with 6793 additions and 2538 deletions
+31 -20
View File
@@ -16,12 +16,19 @@ export default function ReportCharts({ type, data }: { type: 'SUBMITTOR' | 'CREA
chartData = [...data]
.filter(sub => sub.order.status === 'CLOSE')
.sort((a, b) => new Date(a.order.date).getTime() - new Date(b.order.date).getTime()) // oldest → newest
.map(sub => ({
name: sub.order.title.length > 15 ? sub.order.title.substring(0, 15) + '...' : sub.order.title,
fullTitle: sub.order.title,
Total: sub.bill || 0,
status: sub.payment_status
}))
.map(sub => {
const bill = sub.bill || 0
const paid = (sub.paid_amount ?? (sub.payment_status === 'LUNAS' ? bill : 0)) + (sub.saldo_used || 0)
const unpaid = Math.max(0, bill - paid)
return {
name: sub.order.title.length > 15 ? sub.order.title.substring(0, 15) + '...' : sub.order.title,
fullTitle: sub.order.title,
Total: bill,
Paid: paid,
Unpaid: unpaid,
status: unpaid > 0 ? (paid > 0 ? 'SEBAGIAN' : 'BELUM BAYAR') : 'LUNAS'
}
})
} else {
chartData = [...data]
.filter(order => order.status === 'CLOSE')
@@ -50,14 +57,21 @@ export default function ReportCharts({ type, data }: { type: 'SUBMITTOR' | 'CREA
const CustomTooltip = ({ active, payload, label }: any) => {
if (active && payload && payload.length) {
const data = payload[0].payload
return (
<div className="bg-white dark:bg-slate-900 p-3 border border-slate-200 dark:border-slate-800 rounded-xl shadow-lg">
<p className="font-bold text-xs text-slate-800 dark:text-slate-200 mb-1">{payload[0].payload.fullTitle}</p>
<p className="font-bold text-xs text-slate-800 dark:text-slate-200 mb-1">{data.fullTitle}</p>
<p className="text-sm font-black text-[#1B2CC1]">
{formatRupiah(payload[0].value)}
Total: {formatRupiah(data.Total)}
</p>
{type === 'SUBMITTOR' && (
<>
<p className="text-[11px] text-emerald-600 font-bold mt-1">Dibayar: {formatRupiah(data.Paid)}</p>
{data.Unpaid > 0 && <p className="text-[11px] text-rose-600 font-bold">Kurang: {formatRupiah(data.Unpaid)}</p>}
</>
)}
<p className="text-[10px] text-slate-500 mt-1 uppercase font-bold tracking-wider">
Status: {payload[0].payload.status}
Status: {data.status}
</p>
</div>
)
@@ -90,17 +104,14 @@ export default function ReportCharts({ type, data }: { type: 'SUBMITTOR' | 'CREA
tickFormatter={(value) => `Rp${value / 1000}k`}
/>
<Tooltip cursor={{ fill: 'rgba(27, 44, 193, 0.05)' }} content={<CustomTooltip />} />
<Bar dataKey="Total" radius={[4, 4, 0, 0]}>
{chartData.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={type === 'SUBMITTOR'
? (entry.status === 'LUNAS' ? '#10b981' : '#f43f5e') // Emerald or Rose
: '#1B2CC1' // Primary for creator
}
/>
))}
</Bar>
{type === 'SUBMITTOR' ? (
<>
<Bar dataKey="Paid" stackId="a" fill="#10b981" />
<Bar dataKey="Unpaid" stackId="a" fill="#f43f5e" radius={[4, 4, 0, 0]} />
</>
) : (
<Bar dataKey="Total" radius={[4, 4, 0, 0]} fill="#1B2CC1" />
)}
</BarChart>
</ResponsiveContainer>
</CardContent>