'display avatar on the last current message in case of subsequent messages

I am working on a chat box where I need to show the messages of users by grouping the messages on a particular date. The grouping has been working fine so far. However, I could not show the image of the user on his/her latest message if sent consecutive messages. I have my code on sandbox where there is no issue on feb 19 but in case of feb 22 only messages of 'How are you?' on sender and receiver side should be shown profile picture and on the last message of Hello Man.

https://codesandbox.io/s/inspiring-heyrovsky-kksr9?file=/src/Message.js

This is how I have arranges the list of messages

utils.js

import format from "date-fns/format";
import getSeconds from "date-fns/getSeconds";

export function getDateInYearsMonthDay(ts) {
  return format(new Date(ts), "yyyy-MM-dd");
}

export function getTimeinms(ts) {
  return new Date(ts).getTime();
}

function shouldShowAvatar(previous, message) {
  console.log("previous", previous, message);
  const isFirst = !previous;
  console.log("isFirst", isFirst);
  if (isFirst) return true;

  const differentUser = message.clientid !== previous.clientid;
  if (differentUser) return true;

  const hasBeenAwhile = getSeconds(message.createdAt) > 60;
  return hasBeenAwhile;
}

function messageNode(showAvatar, node) {
  let updatedNode = { ...node };
  if (showAvatar) {
    if (node?.direction === "Outgoing") {
      updatedNode = {
        ...updatedNode,
        profilePicture: node?.agentProfilePicture
      };
    } else {
      updatedNode = {
        ...updatedNode,
        profilePicture: node?.clientProfilePicture
      };
    }
  }
  return updatedNode;
}

export function groupedChatDays(messages) {
  // const senderCountInParticularDate = {};
  // const receiverCountInParticularDate = {};
  // const numberOfSenderMessages = 0;
  // const numberOfReceiverMessages = 0;
  return messages?.reduce((acc, el, index) => {
    const messageDay = getDateInYearsMonthDay(el.createdAt);
    const previous = messages[index - 1];
    const showAvatar = shouldShowAvatar(previous, el);
    if (acc[messageDay]) {
      // senderCountInParticularDate[messageDay] =
      //   el?.direction === 'Outgoing' ? numberOfSenderMessages + 1 : 0;
      // receiverCountInParticularDate[messageDay] =
      //   el?.direction === 'Incoming' ? numberOfReceiverMessages + 1 : 0;
      return {
        ...acc,
        [messageDay]: acc[messageDay].concat([messageNode(showAvatar, el)])
      };
    }
    return { ...acc, [messageDay]: [messageNode(showAvatar, el)] };
  }, {});
}

export function generateChatMessages(messages) {
  const days = groupedChatDays(messages);
  const sortedDays = Object.keys(days).sort((x, y) => {
    const a = new Date(x);
    const b = new Date(y);
    return a - b;
  });

  const items = sortedDays.reduce((acc, date) => {
    const sortedMessages = days[date].sort((x, y) => {
      const a = new Date(x.createdAt);
      const b = new Date(y.createdAt);
      return a - b;
    });
    return acc.concat([{ type: "day", date, id: date }, ...sortedMessages]);
  }, []);

  return items;
}

Message.js

import React from "react";
import format from "date-fns/format";

import { generateChatMessages } from "./utils";
import { messages } from "./data";

export function getTimefromIso(ts) {
  if (ts) {
    return format(new Date(ts), "HH:mm");
  }
  return "";
}

export function renderDate(dateStr) {
  const date = new Date(dateStr);
  const today = new Date();
  const yesterday = new Date();
  yesterday.setDate(today.getDate() - 1);
  if (date.toLocaleDateString() === today.toLocaleDateString()) {
    return "Today";
  }
  if (date.toLocaleDateString() === yesterday.toLocaleDateString()) {
    return "Yesterday";
  }
  return date.toLocaleDateString("en-US", {
    day: "numeric",
    month: "long"
  });
}

export const Messages = () => {
  const groupedMessages = generateChatMessages(messages);
  return (
    <>
      {groupedMessages.map((message) => (
        <List key={message?.clientid || message.id} message={message} />
      ))}
    </>
  );
};

const List = ({ message }) => {
  return (
    <>
      <div className="message-in-day">
        {message.date && <div className="date">{renderDate(message.date)}</div>}
        <div className="chat">
          <div
            className={
              message.direction === "Incoming" ? "receiver-chat" : "sender-chat"
            }
          >
            {message?.type !== "day" && (
              <>
                <div className="message-block">
                  {message.direction === "Outgoing" &&
                    message.profilePicture && (
                      <img
                        className="custom-avatar"
                        src={message.profilePicture}
                        alt="avatar"
                      />
                    )}
                  {message.direction === "Incoming" &&
                    message.profilePicture && (
                      <img
                        className="custom-avatar"
                        src={message.profilePicture}
                        alt="avatar"
                      />
                    )}
                  <div className="messages">
                    <p>
                      {message.conversationType === "Message" && (
                        // eslint-disable-next-line react/no-danger
                        <span>{message.content.body}</span>
                      )}
                    </p>
                  </div>
                </div>
              </>
            )}
          </div>
        </div>
      </div>
    </>
  );
};

export default Messages;

This is how it should look

enter image description here

The crossed one that i am highlighting to show there should not be a profile picture.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source