346 lines
8.5 KiB
JavaScript
346 lines
8.5 KiB
JavaScript
import React from "react";
|
||
import Chart from "react-apexcharts";
|
||
import { useGetCollectionOverview } from "../../hooks/useDashboard_Data";
|
||
import { formatFigure } from "../../utils/appUtils";
|
||
|
||
const CollectionOverview = ({ data, isLoading }) => {
|
||
const borderColor = "#ddd";
|
||
const labelColor = "#6c757d";
|
||
|
||
// Extract bucket values
|
||
const labels = ["0–30 Days", "30–60 Days", "60–90 Days", "90+ Days"];
|
||
|
||
const amounts = [
|
||
data.bucket0To30Amount,
|
||
data.bucket30To60Amount,
|
||
data.bucket60To90Amount,
|
||
data.bucket90PlusAmount,
|
||
];
|
||
|
||
// Colors (Zoho-style distributed)
|
||
const colors = ["#7367F0", "#00cfe8", "#28c76f", "#ea5455"];
|
||
|
||
const options = {
|
||
chart: {
|
||
type: "bar",
|
||
height: 260,
|
||
toolbar: { show: false },
|
||
},
|
||
|
||
plotOptions: {
|
||
bar: {
|
||
horizontal: true,
|
||
barHeight: "65%",
|
||
distributed: true,
|
||
borderRadius: 8,
|
||
startingShape: "rounded",
|
||
},
|
||
},
|
||
|
||
colors: colors,
|
||
|
||
grid: {
|
||
borderColor: borderColor,
|
||
strokeDashArray: 6,
|
||
padding: { top: -10, bottom: -10 },
|
||
xaxis: { lines: { show: true } },
|
||
},
|
||
|
||
dataLabels: {
|
||
enabled: true,
|
||
formatter: (_, opts) => labels[opts.dataPointIndex],
|
||
style: {
|
||
colors: ["#fff"],
|
||
fontSize: "13px",
|
||
fontWeight: 500,
|
||
},
|
||
offsetX: 0,
|
||
},
|
||
|
||
xaxis: {
|
||
categories: amounts.map((a) => a),
|
||
labels: {
|
||
style: { colors: labelColor, fontSize: "12px" },
|
||
formatter: (val) => `₹${val.toLocaleString()}`,
|
||
},
|
||
},
|
||
|
||
yaxis: {
|
||
labels: {
|
||
style: {
|
||
colors: labelColor,
|
||
fontSize: "13px",
|
||
},
|
||
formatter: () => "", // hide duplicate labels
|
||
},
|
||
},
|
||
|
||
tooltip: {
|
||
custom: ({ series, seriesIndex, dataPointIndex }) => {
|
||
return `
|
||
<div class="px-2 py-1">
|
||
<strong>${labels[dataPointIndex]}</strong><br>
|
||
₹${series[seriesIndex][dataPointIndex].toLocaleString()}
|
||
</div>
|
||
`;
|
||
},
|
||
},
|
||
|
||
legend: { show: false },
|
||
};
|
||
|
||
const series = [
|
||
{
|
||
name: "Amount",
|
||
data: amounts,
|
||
},
|
||
];
|
||
|
||
return (
|
||
<div>
|
||
<Chart options={options} series={series} type="bar" height={260} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default CollectionOverview;
|
||
export const TopicBarChart = ({ data,isLoading }) => {
|
||
const data1 = {
|
||
totalDueAmount: 213590,
|
||
totalCollectedAmount: 5000,
|
||
totalValue: 218590,
|
||
pendingPercentage: 97.71,
|
||
collectedPercentage: 2.29,
|
||
|
||
bucket0To30Invoices: 10,
|
||
bucket30To60Invoices: 4,
|
||
bucket60To90Invoices: 2,
|
||
bucket90PlusInvoices: 1,
|
||
|
||
bucket0To30Amount: 2130,
|
||
bucket30To60Amount: 2003,
|
||
bucket60To90Amount: 4500,
|
||
bucket90PlusAmount: 8800,
|
||
|
||
topClientBalance: 55300,
|
||
topClient: {
|
||
id: "4e3a6d31-c640-40f7-8d67-6c109fcdb9ea",
|
||
name: "Marco Secure Solutions Ltd.",
|
||
email: "admin@marcoaiot.com",
|
||
contactPerson: "Admin",
|
||
address:
|
||
"2nd Floor, Fullora Building, Tejas CHS, behind Kothrud Stand, Tejas Society, Dahanukar Colony, Kothrud, Pune, Maharashtra 411038",
|
||
gstNumber: null,
|
||
contactNumber: "123456789",
|
||
sprid: 5400,
|
||
},
|
||
};
|
||
|
||
const borderColor = "#ddd";
|
||
const labelColor = "#6c757d";
|
||
|
||
// COLORS
|
||
const config = {
|
||
colors: {
|
||
b0: "#7367F0",
|
||
b30: "#00cfe8",
|
||
b60: "#28c76f",
|
||
b90: "#ea5455",
|
||
},
|
||
};
|
||
|
||
// NEW LABELS (BUCKETS)
|
||
const chartLabels = ["0–30 Days", "30–60 Days", "60–90 Days", "90+ Days"];
|
||
|
||
// NEW VALUES (BUCKET AMOUNT)
|
||
const chartValues = [
|
||
data.bucket0To30Amount,
|
||
data.bucket30To60Amount,
|
||
data.bucket60To90Amount,
|
||
data.bucket90PlusAmount,
|
||
];
|
||
|
||
const options = {
|
||
chart: {
|
||
height: 300,
|
||
type: "bar",
|
||
toolbar: { show: false },
|
||
},
|
||
|
||
plotOptions: {
|
||
bar: {
|
||
horizontal: true,
|
||
barHeight: "40%",
|
||
distributed: true,
|
||
startingShape: "rounded",
|
||
borderRadius: 7,
|
||
},
|
||
},
|
||
|
||
grid: {
|
||
strokeDashArray: 10,
|
||
borderColor,
|
||
xaxis: { lines: { show: true } },
|
||
yaxis: { lines: { show: false } },
|
||
padding: { top: -35, bottom: -12 },
|
||
},
|
||
|
||
colors: [
|
||
config.colors.b0,
|
||
config.colors.b30,
|
||
config.colors.b60,
|
||
config.colors.b90,
|
||
],
|
||
|
||
labels: chartLabels,
|
||
|
||
fill: { opacity: 1 },
|
||
|
||
dataLabels: {
|
||
enabled: true,
|
||
style: {
|
||
colors: ["#fff"],
|
||
fontWeight: 400,
|
||
fontSize: "13px",
|
||
fontFamily: "Public Sans",
|
||
},
|
||
formatter: (_, opts) => chartLabels[opts.dataPointIndex],
|
||
},
|
||
|
||
xaxis: {
|
||
categories: chartValues.map((x) => formatFigure(x, { type: "currency" })),
|
||
axisBorder: { show: false },
|
||
axisTicks: { show: false },
|
||
labels: {
|
||
style: {
|
||
colors: labelColor,
|
||
fontFamily: "Public Sans",
|
||
fontSize: "13px",
|
||
},
|
||
formatter: (val) => `₹${Number(val).toLocaleString()}`,
|
||
},
|
||
},
|
||
|
||
yaxis: {
|
||
labels: {
|
||
style: {
|
||
colors: labelColor,
|
||
fontFamily: "Public Sans",
|
||
fontSize: "13px",
|
||
},
|
||
},
|
||
},
|
||
|
||
tooltip: {
|
||
enabled: true,
|
||
custom: ({ series, seriesIndex, dataPointIndex }) => {
|
||
return `
|
||
<div class="px-3 py-2">
|
||
<span>₹${series[seriesIndex][
|
||
dataPointIndex
|
||
].toLocaleString()}</span>
|
||
</div>
|
||
`;
|
||
},
|
||
},
|
||
|
||
legend: { show: false },
|
||
};
|
||
|
||
const series = [
|
||
{
|
||
data: chartValues,
|
||
},
|
||
];
|
||
|
||
return (
|
||
<div className="row p-2">
|
||
<div className="col-md-8">
|
||
<div class="card-header d-flex align-items-center justify-content-between">
|
||
<h5 class="card-title m-0 me-2">Collection Overview</h5>
|
||
</div>
|
||
<div className="w-100 d-flex align-items-center text-start px-6">
|
||
<p className="text-secondary fs-6 m-0">Due Amount</p>
|
||
<span className="ms-2 fs-5">
|
||
{formatFigure(data.totalDueAmount, { type: "currency" })}
|
||
</span>
|
||
<p className="text-secondary fs-6 m-0 ms-1">Collected Amount</p>
|
||
<span className="ms-2 fs-5">
|
||
{formatFigure(data.totalCollectedAmount, { type: "currency" })}
|
||
</span>
|
||
</div>
|
||
|
||
<Chart options={options} series={series} type="bar" height={300} />
|
||
</div>
|
||
|
||
<div className="col-md-4 d-flex flex-column gap-2">
|
||
<div class="card-header d-flex align-items-end justify-content-between"></div>
|
||
<div className="p-1 m-1 text-start">
|
||
{/* <p className="fs-5 fs-5">Top Client</p>
|
||
<small> {data.topClient.name}</small> */}
|
||
</div>
|
||
|
||
{/* 0–30 Days */}
|
||
<div
|
||
className="p-1 rounded-3 text-start mx-1"
|
||
style={{
|
||
background: "var(--bs-primary-bg-subtle)",
|
||
borderLeft: "4px solid var(--bs-primary)",
|
||
minWidth: "170px",
|
||
}}
|
||
>
|
||
<h5 className="fw-bold mb-0">
|
||
{formatFigure(data.bucket0To30Amount, { type: "currency" })}
|
||
</h5>
|
||
<p className="text-secondary mb-0 small">0–30 Days</p>
|
||
</div>
|
||
|
||
{/* 30–60 Days */}
|
||
<div
|
||
className="p-1 rounded-3 text-start mx-1"
|
||
style={{
|
||
background: "var(--bs-info-bg-subtle)",
|
||
borderLeft: "4px solid var(--bs-info)",
|
||
minWidth: "170px",
|
||
}}
|
||
>
|
||
<h5 className="fw-bold mb-0">
|
||
{formatFigure(data.bucket30To60Amount, { type: "currency" })}
|
||
</h5>
|
||
<p className="text-secondary mb-0 small">30–60 Days</p>
|
||
</div>
|
||
|
||
{/* 60–90 Days */}
|
||
<div
|
||
className="p-1 rounded-3 text-start mx-1"
|
||
style={{
|
||
background: "var(--bs-warning-bg-subtle)",
|
||
borderLeft: "4px solid var(--bs-warning)",
|
||
minWidth: "170px",
|
||
}}
|
||
>
|
||
<h5 className="fw-bold mb-0">
|
||
{formatFigure(data.bucket60To90Amount, { type: "currency" })}
|
||
</h5>
|
||
<p className="text-secondary mb-0 small">60–90 Days</p>
|
||
</div>
|
||
|
||
{/* 90+ Days */}
|
||
<div
|
||
className="p-1 rounded-3 text-start mx-1"
|
||
style={{
|
||
background: "var(--bs-danger-bg-subtle)",
|
||
borderLeft: "4px solid var(--bs-danger)",
|
||
minWidth: "170px",
|
||
}}
|
||
>
|
||
<h5 className="fw-bold mb-0">
|
||
{formatFigure(data.bucket90PlusAmount, { type: "currency" })}
|
||
</h5>
|
||
<p className="text-secondary mb-0 small">90+ Days</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|