Partition messages by date, last read in angular

Viewed 40

I want to partition my messages by date for my chat application(Similar to the Microsoft teams app) The message data will be like

[
    {
        "id": 577,
        "source": {
            "userID": 56469,
            "profilePictureUrl": "",
            "name": "John J"
        },
        "body": "test test",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T07:59:28.873+00:00"
    },
    {
        "id": 578,
        "source": {
            "userID": 56469,
            "profilePictureUrl": "",
            "name": "Don V"
        },
        "body": "ok",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T08:02:26.262+00:00"
    },
    {
        "id": 628,
        "source": {
            "userID": 56470,
            "profilePictureUrl": "",
            "name": "Sam GP"
        },
        "body": "Hola",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T17:27:48.038+00:00"
    },
    {
        "id": 629,
        "source": {
            "userID": 56470,
            "profilePictureUrl": "",
            "name": "Rawn OP"
        },
        "body": "ek",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T17:29:36.705+00:00"
    },
    {
        "id": 630,
        "source": {
            "userID": 56470,
            "profilePictureUrl": "",
            "name": "Paul John"
        },
        "body": "hi",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T17:30:36.695+00:00"
    },
    {
        "id": 631,
        "source": {
            "userID": 56470,
            "profilePictureUrl": "",
            "name": "Dennise V"
        },
        "body": "knock knock",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T17:32:38.035+00:00"
    },
    {
        "id": 632,
        "source": {
            "userID": 56469,
            "profilePictureUrl": "",
            "name": "Shawn"
        },
        "body": "who's this",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T17:37:25.985+00:00"
    },
    {
        "id": 633,
        "source": {
            "userID": 56469,
            "profilePictureUrl": "",
            "name": "Pater B"
        },
        "body": "I see",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T17:37:30.783+00:00"
    },
    {
        "id": 634,
        "source": {
            "userID": 56469,
            "profilePictureUrl": "",
            "name": "Cera LO"
        },
        "body": "Will call you later",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-20T17:37:38.268+00:00"
    },
    {
        "id": 642,
        "source": {
            "userID": 56469,
            "profilePictureUrl": "",
            "name": "Rose BH"
        },
        "body": "hello???????",
        "readStatus": true,
        "attachments": null,
        "createdDateTime": "2022-09-21T05:25:56.642+00:00"
    }
]

I need to arrange these data to show the messages by date like

------------------------------Sep 30-----------------------------
Messages sent/received on sep 30

------------------------------Yesterday--------------------------
Messages sent/received on yesterday

------------------------------Last read-------------------------
------------------------------Oct30-----------------------------
------------------------------Yesterday-------------------------
------------------------------Today-----------------------------

For displaying "Sep 30", "yesterday", and "Today" I've created a pipe that converts the timestamp into the month and "yesterday", "today" etc.

I already got the solution to arrange the message by date. But I have to arrange it under the "Last read" block too. Same as by dates. the flag "readStatus" is sed to check whether the message has been read or not" If it is false is should come under "Last read".

Any ideas? Any help will be appreciated.

1 Answers

I imagine you can has something like (if your data is in a variable "data"

  dataOrder = {
    readed: this.group(this.data.filter((x) => x.readStatus)),
    notReaded: this.group(this.data.filter((x) => !x.readStatus)),
  };

  group(data: any[]) {
    return data.reduce((a, b) => {
      const dateTime=new Date(b.createdDateTime.substr(0,10)+"T00:00:00.00+00:00")
                                            .getTime()
      const element = a.find((x) => x.dateTime == dateTime);
      if (!element) a.push({ dateTime:dateTime,data: [b] });
      else element.data.push(b);
      return a;
    }, []);
  }

See that "dataOrder" has two properties "readed" and "notReaded", each one are arrays of objects in the way

   {
    dateTime:a dateTime,
    data:an array with the messages
   }

This makes easy indicate the date using Angular date pipe, and loop over the messages

So, an .html like

<h1>Readed</h1>
<ng-container
  *ngTemplateOutlet="messagedata; context: { $implicit: dataOrder.readed }"
></ng-container>
<h1>Not Readed</h1>
<ng-container
  *ngTemplateOutlet="messagedata; context: { $implicit: dataOrder.notReaded }"
></ng-container>

<ng-template #messagedata let-data>
  <div *ngFor="let readed of data">
    {{ readed.dateTime | date }}
    <div *ngFor="let message of readed.data">
      {{ message.createdDateTime }} - {{ message.body }}
    </div>
  </div>
</ng-template>

I use the same template for both type of messages

A stackblitz

Update As the dataOrder it's only change at fisrt is better use a function

getDataOrdered(data:any[])
{
     return {
        readed: this.group(data.filter((x) => x.readStatus)),
        notReaded: this.group(data.filter((x) => !x.readStatus)),
      };
}

Then, we can, each time some message change its "readStatus" we can do

this.dataOrder=this.getDataOrdered(this.data)
Related