Arrange Chat Messages By Date - javascript

I am working with Vue, but this is a general javascript question.
I make a call to an api to get cat messages for a chat UI. The initial call returns an array of objects where each object is a chat message object as below.
data: [
0: {id: 1, created_at: "2022-05-20T15:12:40.000000Z", updated_at: "2022-05-20T17:18:03.000000Z",…}
1: {id: 2, created_at: "2022-05-20T15:12:41.000000Z", updated_at: "2022-05-20T17:18:04.000000Z",…}
2: {id: 3, created_at: "2022-05-20T15:12:41.000000Z", updated_at: "2022-05-20T17:18:04.000000Z",…}
3: {id: 4, created_at: "2022-05-20T15:12:41.000000Z", updated_at: "2022-05-20T17:18:04.000000Z",…}
]
I initial wanted to format the message so they can be grouped by their dates in the chat window. This is the code I used to group them
This is a computed property in vue
const formattedChats = computed(() => {
let dateFormattedMessages = messages.value.map(message => {
return {...message, updated_at: new Date(message.updated_at).toDateString(), created_at: new Date(message.created_at).toDateString()}
})
return dateFormattedMessages.reduce((total, currentValue) => {
total[currentValue.updated_at] = total[currentValue.updated_at] || [];
total[currentValue.updated_at].push(currentValue);
return total;
}, Object.create(null));
})
The above will first take the each chat object an convert their updated_at and created_at to a date string and then group the array using the updated_at.
The result was as follows:
formattedChats = {
Fri Jun 24 2022: [
{...}, {...
]
Fri May 20 2022:[
{...}, {...
]
Mon Jun 27 2022:Array[
{...}, {...
]
Sat May 21 2022:Array[
{...}, {...
]
Tue Jun 28 2022:Array[
{...}, {...
]
}
If you notice, the problem I am facing is that the dates are not arranged in any order. it doesnt make sense to render it to the UI like this because the resulting chats with not be arranged by date.
This is how the UI should look

You need to use arrays (or a map) to keep the order sorted. I would use an array of arrays. First you need to sort the data on date (I used updated_at, which I made of type Date in the data array). Then iterate over the sorted array. See snippet below.
const data = [{
id: 1,
updated_at: new Date("2022-05-21T15:12:40.000000Z"),
created_at: "2022-05-20T17:18:03.000000Z"
},
{
id: 2,
updated_at: new Date("2022-05-20T15:12:41.000000Z"),
created_at: "2022-05-20T17:18:04.000000Z"
},
{
id: 3,
updated_at: new Date("2022-05-23T15:12:41.000000Z"),
created_at: "2022-05-20T17:18:04.000000Z"
},
{
id: 4,
updated_at: new Date("2022-05-21T15:12:41.000000Z"),
created_at: "2022-05-20T17:18:04.000000Z"
},
]
const sortedData = data.sort(
(a, b) => Number(a.updated_at) - Number(b.updated_at),
);
let currentDay = sortedData[0].updated_at;
const stillCurrentDay = (dayOfMessage) => {
return dayOfMessage.getFullYear() === currentDay.getFullYear() &&
dayOfMessage.getMonth() === currentDay.getMonth() &&
dayOfMessage.getDate() === currentDay.getDate()
}
let dayMessageArray = [];
const fullMessageArray = [];
const createMessagesArray = (messages) => {
const newDay = {};
newDay[currentDay.toISOString().split('T')[0]] = messages;
fullMessageArray.push(newDay);
}
sortedData.forEach(message => {
if (!stillCurrentDay(message.updated_at)) {
createMessagesArray(dayMessageArray);
currentDay = message.updated_at;
dayMessageArray = [];
}
dayMessageArray.push(message);
});
createMessagesArray(dayMessageArray);
console.log(fullMessageArray);
Hope this helps. Perhaps there are easier ways, please let me know.

Related

Lodash custom orderBy then by

I need to use lodash to implement a custom sort based on classification, then by creation time, with more recently created items with the same classification having a lower index in the array. I'm pretty sure I need to use orderBy, but I don't know how to add the date sorting part. This is what I have:
let sorted = _.orderBy(this.followed_requests, function(element){
const rank = { "INCOMPLETE.NEW": 1,
"INCOMPLETE.IN_PROGRESS":2,
"INCOMPLETE.LATER":3}
return rank[element["status"]]})
I'd like my output to have something like:
sorted = [{status:"INCOMPLETE.NEW", created_at: "2021-05-14T14:48:00.000Z"},
{status:"INCOMPLETE.NEW", created_at: "2021-05-13T14:48:00.000Z"},
{status:"INCOMPLETE.IN_PROGRESS", created_at: "2021-05-14T14:48:00.000Z"},
{status:"INCOMPLETE.IN_PROGRESS", created_at: "2021-05-13T14:48:00.000Z"},
{status:"INCOMPLETE.LATER", created_at: "2021-05-14T14:48:00.000Z"},
{status:"INCOMPLETE.NEW", created_at: "2021-05-13T14:48:00.000Z"} ]
orderBy accepts an array of functions and sort directions. There's multiple ways this could be implemented, but since both sort values require transformation this seems like a good option.
const reqs = [
{ status: "INCOMPLETE.LATER", created_at: "2021-05-14T14:48:00.000Z" },
{ status: "INCOMPLETE.NEW", created_at: "2021-05-13T15:48:00.000Z" },
{ status: "INCOMPLETE.IN_PROGRESS", created_at: "2021-05-14T14:48:00.000Z" },
{ status: "INCOMPLETE.IN_PROGRESS", created_at: "2021-05-13T15:48:00.000Z" },
{ status: "INCOMPLETE.NEW", created_at: "2021-05-14T16:48:00.000Z" },
{ status: "INCOMPLETE.NEW", created_at: "2021-05-13T14:48:00.000Z" },
]
const rank = {
"INCOMPLETE.NEW": 1,
"INCOMPLETE.IN_PROGRESS": 2,
"INCOMPLETE.LATER": 3,
}
let sorted = _.orderBy(reqs, [
i => rank[i.status],
i => new Date(i.created_at)
], ["asc", "asc"])
console.log(sorted)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

How to filter data of object according to keys and make new array in react?

I am working with the object like this:-
{
0:
buyAmount: 16.664328043964396
buyAmountInUsd: 16.685266204095775
date: {date: '2021-12-07'}
sellAmount: {USD: 500, INR: 35000}
1:
buyAmount: 1004.7015442959262
buyAmountInUsd: 1005.9639175379324
date: {date: '2021-12-07'}
sellAmount: {USD: 1000, INR: 79000}
......
and I am trying to make a new array using useState hook with this data but the problem I am facing is how to filter data and make an almost similar array with the same data.
e.g.:-
0: [amount: 500, date: '2021-12-07'],
1: [amount: 1000, date: '2021-12-07']
The problem I am facing is I don't know the approach how to get the data like amount = sellAmount.USD and date = date.date
I thought of trying the for...of But I don't think it will be a good hit.
You can do this with Array.map
const arr = [{
buyAmount: 16.664328043964396,
buyAmountInUsd: 16.685266204095775,
date: {date: '2021-12-07'},
sellAmount: {USD: 500, INR: 35000}
},{
buyAmount: 1004.7015442959262,
buyAmountInUsd: 1005.9639175379324,
date: {date: '2021-12-07'},
sellAmount: {USD: 1000, INR: 79000}
}]
console.log(
arr.map(initialValue => {
return {
amount: initialValue.sellAmount.USD,
date: initialValue.date.date
}
})
)
The better idea would be the having an array of objects rather than array of array elements
let result = yourArray.map(each => ({ amount: each.sellAmount.USD, date: each.date.date }))
This is not related to ReactJS - just native Javascript object handling.
If your original data has the shape of an Object you can convert it into an Array like so:
const objData = { 0: {...}, 1: {...} };
const arrData = Object.entries(objData); // [[0, {...}], [1, {...}]];
From there, you can filter/map/sort your array with native array methods:
const reshapedArray = arrData.map(([key, value]) => {
return {
amount: value.sellAmount.USD,
date: value.date.date,
};
});
Then sort:
const sortedArray = reshapedArray.sort((prev, next) => {
return prev.amount - next.amount; // sort by amount ascending
});
You can of could chain these array functions and shorten the syntax a bit:
Object.entries(objData)
.map(([_, { sellAmount, date: { date } }]) => ({ amount: sellAmount.USD, date }))
.sort((a, b) => a.amount - b.amount);

create sectionList with a title that compares the today's date and the date from the array?

So I have an array with a data of
var today = "2020-08-31"
var array = [
{
name: "Joshua",
id: 1,
date: "2020-08-31"
},
{
name: "Michael",
id: 2,
date: "2020-09-1"
}]
I want to create a sectionList that the sectionHeader title will be depending on the date today and will compare it to the date value from the array. so for example the date from the array is "2020-08-31" and today's date is same as "2020-08-31" the title should be "Today" and tomorrow is "2020-09-01" and the date from the array is still "2020-08-31" the title should be "Yesterday" is it possible?? please help me. im stuck with this. Thank you!!!!
Use the parse function from the JS Date library to parse the date hence convert it into long and then return the string (yesterday, today, tomorrow).
Add the displayDate into you array in order to loop through and display the field's value.
const today = "2020-08-31"
let array = [{
name: "Joshua",
id: 1,
date: "2020-08-31"
},
{
name: "Michael",
id: 2,
date: "2020-09-1"
}
]
array = array.map(x => ({
...x,
displayDate: (() => {
if (Date.parse(today) < Date.parse(x.date)) {
return 'yesterday';
} else if (Date.parse(today) > Date.parse(x.date)) {
return 'tomorrow';
}
return 'today';
})()
}));
console.log(array)

Create a table from added data sorted by month

I have a problem sorting data and getting an array with the right data. Here is the situation :
I get a table of data representing invoices (creation date and price) in this format :
invoices: [
0: {
amount: 200,
created_at: 1590572830425
},
1: {
amount: 799,
created_at: 1590572847553
}
...
]
I would like to loop on this table of invoices, and extract the total sum of the amount of invoices according to the month of the year (thanks to the fields created_at representing a timestamp.
At the end, I would like to obtain a table with 12 values maximum, representing the total amount of invoices classified by month
Expected result : [300, 450, 799, 650, 288, 400, 643, 809, 1073, 499, 640, 600]
Thank you in advance.
As you would not want amounts to get mingled up across different years, it would be better to have a result that lists the relevant years, and then for each year, have the 12 sums:
function monthTotals(invoices) {
let totals = {};
for (let {created_at, amount} of invoices) {
let date = new Date(created_at);
let year = date.getFullYear();
(totals[year] = (totals[year] || Array(12).fill(0)))[date.getMonth()] += amount;
}
return totals;
}
let invoices = [{
amount: 200,
created_at: 1590572830425
},{
amount: 799,
created_at: 1590572847553
}];
console.log(monthTotals(invoices));
If you can, try to always give a real input and output combination - i.e. ones that match (input maps to expected output), so that we can run it and test our output against your expected output. Also, often known as a minimal reproducible example (https://stackoverflow.com/help/minimal-reproducible-example):
const invoices = [
{
amount: 200,
created_at: 1590572830425
},
{
amount: 799,
created_at: 1590572847553
}
]
const outputArr = [0,0,0,0,0,0,0,0,0,0,0,0];
invoices.forEach(item => {
const myDate = new Date(item.created_at);
console.log(myDate.toDateString())
const month = parseInt(myDate.getMonth());
outputArr[month] += item.amount
});
console.log(outputArr);
Output:
[0,0,0,0,999,0,0,0,0,0,0,0]
Like this. I first did a reduce but that was overkill
This solution will not work across years
const invoices = [{
amount: 200,
created_at: 1590572830425
},
{
amount: 799,
created_at: 1590572847553
}
];
const monthVal = new Array(12).fill(0);
invoices.forEach(item => {
const month = new Date(item.created_at).getMonth();
monthVal[month] += item.amount;
});
console.log(monthVal)
Also you can sum up the entire process in reduce method.
var invoices = [ {amount: 200,created_at: 1590572830425},{amount: 799,created_at:1590572847553}];
var result = invoices.reduce((acc, elem)=>{
month = new Date(elem.created_at).getMonth();
acc[month] += elem.amount;
return acc;
},Array.from({length:12}, ()=>0));
console.log(result);

Remove duplicate elements based on date field in javascript

I want a function that takes an array and filters out old duplicates.
Specifically, if duplicate ids exist in myList, keep only the object with the newest date. Given the following array
let myList = [{
id: "e9519e95-5a10-4274-ac24-de72ad60ffd7",
date: "2018-02-21 21:04:13"
},
{
id: "026e7ecf-d236-4aff-b26d-7546ac85b7d5",
date: "2018-02-22 21:04:13"
},
{
id: "e9519e95-5a10-4274-ac24-de72ad60ffd7",
date: "2018-02-23 21:04:13"
}]
the function should return:
[{
id: "026e7ecf-d236-4aff-b26d-7546ac85b7d5",
date: "2018-02-22 21:04:13"
},
{
id: "e9519e95-5a10-4274-ac24-de72ad60ffd7",
date: "2018-02-23 21:04:13"
}]
You can use the function reduce to build the desired output.
let myList = [{ id: "e9519e95-5a10-4274-ac24-de72ad60ffd7", date: "2018-02-21 21:04:13"},{ id: "026e7ecf-d236-4aff-b26d-7546ac85b7d5", date: "2018-02-22 21:04:13"},{ id: "e9519e95-5a10-4274-ac24-de72ad60ffd7", date: "2018-02-23 21:04:13"}];
let result = Object.values(myList.reduce((a, {id, date}) => {
if (a[id]) {
if (a[id].date < date) a[id] = {id, date};
} else a[id] = {id, date};
return a;
}, {}));
console.log(result);
Put the entries into a hash table keyed by id. Each time you add an entry, look up the id and either keep the existing entry or replace it with the new one, based on whichever has a more recent date.
Map and Array.prototype.map() can be combined to functionally filter key based duplicates from arrays.
Array.prototype.sort() can be leveraged to guarantee order.
See below for a practical example.
// Input.
const input = [
{id: "e9519e95-5a10-4274-ac24-de72ad60ffd7", date: "2018-02-21 21:04:13"},
{id: "026e7ecf-d236-4aff-b26d-7546ac85b7d5", date: "2018-02-22 21:04:13"},
{id: "e9519e95-5a10-4274-ac24-de72ad60ffd7", date: "2018-02-23 21:04:13"}
]
// Sort By Date.
const sortDate = array => array.sort((A, B) => new Date(A.date)*1 - new Date(B.date)*1)
// Filter Duplicates.
const filter = array => [...new Map(array.map(x => [x.id, x])).values()]
// Output.
const outputRaw = filter(input) // No guaranteed order.
const outputSorted = sortDate(filter(sortDate(input))) // Guaranteed latest.
// Proof.
console.log('Raw', outputRaw)
console.log('Sorted', outputSorted)
This isn't the best answer, just another take on #Ele's solution offered for completeness. Instead of plucking the values after the unique set is found, it works on the returned array for each iteration. The find during each iteration should be less efficient than a key lookup, which is one of the reasons it's not the best answer.
let myList = [{
id: "e9519e95-5a10-4274-ac24-de72ad60ffd7",
date: "2018-02-21 21:04:13"
}, {
id: "026e7ecf-d236-4aff-b26d-7546ac85b7d5",
date: "2018-02-22 21:04:13"
}, {
id: "e9519e95-5a10-4274-ac24-de72ad60ffd7",
date: "2018-02-23 21:04:13"
}]
let result = myList.reduce((arr, { id, date }) => {
let found = arr.find(v=>v.id==id)
if (found) {
if (found.date < date)
found.date = date
}
else
arr.push({ id, date });
return arr;
}, []);
console.log(result);

Categories