I have a plain array of objects with a date as an attribute and want to transform that array based on that date with a specific date category.
const orders = [
{
"order_id": "1",
"description": "Description 1",
"date": "2024-02-03T19:00:57.744Z",
},
{
"order_id": "2",
"description": "Description 2",
"date": "2024-02-04T19:00:57.744Z",
},
{
"order_id": "3",
"description": "Description 3",
"date": "2024-02-06T19:00:57.744Z",
},
]
Along with this, I have a date categories as below:
const category = [
'Overdue',
'Today',
'Tomorrow',
'This Week',
'Next Week',
'This Month',
'Next Month',
'Later',
'No Date',
];
I need to transform a new array with specific date categories and categories should be sorted in this manner only (increasing date).
Expected output:
[
{
"category": "Today",
"data": [
{
"order_id": "1",
"description": "Description 1",
"date": "2024-02-03T19:00:57.744Z"
}
]
},
{
"category": "Tomorrow",
"data": [
{
"order_id": "2",
"description": "Description 2",
"date": "2024-02-04T19:00:57.744Z"
}
]
},
{
"category": "This Week",
"data": [
{
"order_id": "3",
"description": "Description 3",
"date": "2024-02-06T19:00:57.744Z"
}
]
}
]
I'm using dayjs for date manipulations, and using the below function to check the date for a specific category
const getCategoryByDate = date => {
if (date === null || date === undefined) {
return 'No Date';
}
const isToday = dayjs(date).isToday();
const isTomorrow = dayjs(date).isTomorrow();
const overdue = dayjs().isAfter(date, 'day');
const isThisYear = dayjs().year() === dayjs(date).year();
const isThisWeek = isThisYear && dayjs().isoWeek() === dayjs(date).isoWeek();
const isNextWeek = isThisYear && dayjs().isoWeek() + 1 === dayjs(date).isoWeek();
const isThisMonth = isThisYear && dayjs().month() === dayjs(date).month();
const isNextMonth = isThisYear && dayjs().month() + 1 === dayjs(date).month();
if (overdue) {
return 'Overdue';
} else if (isToday) {
return 'Today';
} else if (isTomorrow) {
return 'Tomorrow';
} else if (isThisWeek) {
return 'This Week';
} else if (isNextWeek) {
return 'Next Week';
} else if (isThisMonth) {
return 'This Month';
} else if (isNextMonth) {
return 'Next Month';
}
return 'Later';
};
and finally using the array.reduce function to transform new desired array
const output = orders.reduce((acc, curr) => {
const {date} = curr;
const category = getCategoryByDate(date);
const found = acc.find((item) => item.category === category);
if (found) {
found.data.push(curr);
} else {
const obj = {category: category, data: [curr]};
acc = [obj];
}
return acc;
}, []);
With this, I'm not getting the desired result, output array is not sorted in order according to category if the order array is not sorted previously.
Convert your categories to an object with values of dates (generate them as strings with dayjs or vanilla js), then use
Array::findLast()to find a category.This will be more performant than calling date functions on each comparison.
If your dates aren't sorted, sort them afterwards based on index keys of the categories.