Reputation: 217
I wanted to show the Monthly sale of a shop, the charts show the total sales per date of the month. The below sales amount and dates are from database, I wanted to show all dates of the month (until 1-till current date) like today is 27, so it show (1-27), the date which has no sales or no data need to show 0.
import React from "react";
import { Line } from "react-chartjs-2";
// API Example data {
// "Count": 2,
// "Result": [
// {
// "ID": "62d7b594466f086f718a0c1f",
// "Name": "K",
// "PurchaseID": "62d7b594466f086f718a0c1d",
// "ShopOrderStatus": "Order Shipped Out",
// "TotalOrderCost": 503.25,
// "Courier": null,
// "OrderDate": "2022-06-20T07:58:12.385Z"
// },
// {
// "ID": "62d7b576466f086f718a0c1a",
// "Name": "K",
// "PurchaseID": "62d7b576466f086f718a0c18",
// "ShopOrderStatus": "Order Shipped Out",
// "TotalOrderCost": 824.83,
// "Courier": null,
// "OrderDate": "2022-07-24T07:57:42.527Z"
// },
// ]}
function SalesReport() {
const yesterday = new Date(today - 1);
yesterday.setHours(0, 0, 0, 0);
let CmonthOrder = [];
if (isSuccess) {
// Get data from api
CmonthOrder = data.data.Result.filter(
(OldOrder) =>
new Date(OldOrder.OrderDate).getMonth() === yesterday.getMonth()
);
}
// seperate each date with price eg: 62d7b576466f086f718a0c1a: {24/07: 824.83}
const Cmonth = CmonthOrder.reduce((acc, e) => {
const date = moment(e.OrderDate).format("DD/MM");
if (!acc[e.ID]) {
acc[e.ID] = {
[date]: e.TotalOrderCost,
};
} else {
acc[e.ID][date] = e.TotalOrderCost;
}
return acc;
}, {});
// Get the Order Date data
const CmonthOrderdate = [
...new Set(
Object.keys(Cmonth)
.map((i) => Object.keys(Cmonth[i]))
.flat()
),
];
// Get Sum of Order Per day of the Month
const totalSumPerDateM = {};
CmonthOrderdate.forEach((date) => {
const sumOnDate = Object.values(Cmonth).reduce((acc, curr) => {
acc += curr[date] ? curr[date] : 0;
return acc;
}, 0);
totalSumPerDateM[[date]] = sumOnDate;
});
// Get Sum Currentday Sales Amount
const CmonthOrderdata = Object.values(totalSumPerDateM);
// Chart for this Month SalesReport
const chartExample3 = {
data: (canvas) => {
const ctx = canvas.getContext("2d");
const gradientStroke = ctx.createLinearGradient(500, 0, 100, 0);
gradientStroke.addColorStop(0, "#2CA8FF");
gradientStroke.addColorStop(1, chartColor);
const gradientFill = ctx.createLinearGradient(0, 170, 0, 50);
gradientFill.addColorStop(0, "rgba(128, 182, 244, 0)");
gradientFill.addColorStop(1, hexToRGB("#2CA8FF", 0.4));
return {
labels: CmonthOrderdate,
datasets: [
{
label: "Sales",
backgroundColor: gradientFill,
borderColor: "#fbc658 ",
pointHoverRadius: 2,
pointRadius: 1,
fill: false,
borderWidth: 3,
barPercentage: 1.6,
tension: 0.4,
data: CmonthOrderdata,
},
],
};
},
options: {
plugins: {
legend: {
display: false,
},
tooltips: {
enabled: false,
},
},
scales: {
y: {
ticks: {
color: "#9f9f9f",
beginAtZero: false,
maxTicksLimit: 5,
},
grid: {
drawBorder: false,
display: false,
},
},
x: {
grid: {
drawBorder: false,
display: false,
},
ticks: {
padding: 20,
color: "#9f9f9f",
},
},
},
},
};
return (
<div className="content">
<Card className="card-dark">
<CardHeader>
<Row>
<Col sm="7">
<div className="numbers pull-left">{`RM ${CmonthOtotal.toFixed(
2
)}`}</div>
</Col>
<Col sm="5">
<div className="pull-right">
<Badge color="warning" pill>
~51%
</Badge>
</div>
</Col>
</Row>
</CardHeader>
<CardBody>
<h6 className="big-title">
total Sales for this {moment().format("MMMM")}
</h6>
<Line
data={chartExample3.data}
options={chartExample3.options}
height={380}
width={826}
/>
</CardBody>
<CardFooter>
<hr />
<Row>
<Col sm="7">
<div className="footer-title">View more details</div>
</Col>
<Col sm="5">
<div className="pull-right">
<Button
className="btn-round btn-icon"
color="warning"
size="sm"
>
<i className="nc-icon nc-alert-circle-i" />
</Button>
</div>
</Col>
</Row>
</CardFooter>
</Card>
</div>
)
}
I don't know how to show all the dates of the month even if not in the database, Need help on this.
Upvotes: 0
Views: 628
Reputation: 26
Given that your datasource is totalSumPerDateM
and it seems to be an object of type
{<DAY_OF_MONTH>: <SUM_OF_ORDERS_FOR_DAY>}
and you only have like three dates, you should pre-fill your object with each day of the month as a key with default value zero, then proceed to fill some of the zero-value keys with data from the API (as you already do).
EXAMPLE
const totalSumPerDateM = {};
CmonthOrderdata.forEach((date) => {
const sumOnDate = Object.values(Cmonth).reduce((acc, curr) => {
acc += curr[date] ? curr[date] : 0;
return acc;
}, 0);
totalSumPerDateM[[date]] = sumOnDate;
});
const datesToYesterday = [...Array(yesterday.getDate()).keys()]
.map(k => new Date(
yesterday.getFullYear(),
yesterday.getMonth(),
k+1
));
datesToYesterday.forEach((date) => {
const formattedDate = moment(date).format("DD/MM");
totalSumPerDateM[formattedDate] = totalSumPerDateM[formattedDate] || 0;
});
Upvotes: 0