I wrote a hook to calculate sales based on month to set data for chart.
its work fine, but I’m not satisfied.
is there a different or easy way to avoid repeating and make code clean and extendable!
note: I’m not working with companies or team – ( self learning )
i want to calculate the total per day in the month and return new array of objects
Function:
const month = (date) => new Date(date).toLocaleString('default', { month: 'long' });
export const useGetChartData = (orders) => {
const orderTotal = orders.length
const orderTotalsArray = orders.map(order => (+order.total) + (+order.total_tax));
const sumOrders = orderTotalsArray?.reduce((inc, a) => inc + a, 0);
const getMonthFromDateAndTotals = orders?.map(order => (
{
date: (order.date_paid ? month(order.date_paid) : month(order.date_modified)),
total: +order.total + +order.total_tax
}));
const sendToChart = getMonthFromDateAndTotals.filter(o => o.total > 0);
//filter!
const January = sendToChart.filter((d) => d.date == 'January')
const February = sendToChart.filter((d) => d.date == 'February')
const March = sendToChart.filter((d) => d.date == 'March')
const April = sendToChart.filter((d) => d.date == 'April')
const May = sendToChart.filter((d) => d.date == 'May')
const June = sendToChart.filter((d) => d.date == 'June')
const July = sendToChart.filter((d) => d.date == 'July')
const August = sendToChart.filter((d) => d.date == 'August')
const September = sendToChart.filter((d) => d.date == 'September')
const October = sendToChart.filter((d) => d.date == 'October')
const November = sendToChart.filter((d) => d.date == 'November')
const December = sendToChart.filter((d) => d.date == 'December')
//
const totalsPerMonths = [
//reduce!
{ month: 'January', total: January?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'February', total: February?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'March', total: March?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'April', total: April?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'May', total: May?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'June', total: June?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'July', total: July?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'August', total: August?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'September', total: September?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'October', total: October?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'November', total: November?.reduce((inc, a) => inc + a.total, 0) },
{ month: 'December', total: December?.reduce((inc, a) => inc + a.total, 0) },
//
];
const dataVisualizationToChart = totalsPerMonths.filter(vd => vd.total > 0);
return {
dataVisualizationToChart,
orderTotal,
sumOrders
};
};
usage:
const { data: orders, isLoading: ordersLoading, errors: orderErrors} = useGetShopData("orders");
const { dataVisualizationToChart, sumOrders } = useGetChartData(orders)
Return :
{
"dataVisualizationToChart": [
{"month": "February","total": 1875.96},
{ "month": "March", "total": 1362.46},
{ "month": "April","total": 66.05000000000004},
],
"orderTotal": 70,
"sumOrders": 13064
}```
2
Answers
I would suggest something like this:
Create the monthNames object: Mapping numerical values of months to string names.
Instead of creating individual arrays for each month and then calculating the totals, I used reduce to group totals by month in a single pass.
The result of totalsPerMonths will be an object where the keys are unique dates (months) and the values are the total sums for each month.
Here, I extracted the numeric value of the month into a string name using the monthNames mapping.
After reducing, I constructed the dataVisualizationToChart by iterating over the keys of the grouped and reduced object.
I hope my solution helps you!
I’d suggest you work on problems related to arrays and result aggregation on LeetCode. It really helps with solving similar tasks in the future!
Use
Map.groupBy()
to group by the date, then sum each total when mapping to an array usingArray.from()
. You also don’t need a final.filter()
here as months that don’t exist won’t exist in the resulting array, so no need to filter them out of the result like you’re currently doing:See working example below: