review whole logic for displaying messages

Get rid of buildMessageList and MessageBubblesGroup.
Better handling of styles and informations (time) conditional to previous and next messages.
Should help to implement "compact" view.

Change-Id: I78fca656e7ad769f2efb3ee21ef1ba719f7919ec
diff --git a/client/src/components/MessageList.tsx b/client/src/components/MessageList.tsx
index 6c3c8bf..6e5e233 100644
--- a/client/src/components/MessageList.tsx
+++ b/client/src/components/MessageList.tsx
@@ -16,24 +16,9 @@
  * <https://www.gnu.org/licenses/>.
  */
 import { Stack } from '@mui/system';
-import dayjs, { Dayjs } from 'dayjs';
-import dayOfYear from 'dayjs/plugin/dayOfYear';
-import isBetween from 'dayjs/plugin/isBetween';
 import { Account, ConversationMember, Message } from 'jami-web-common';
-import { ReactNode, useMemo } from 'react';
 
-import {
-  MessageBubblesGroup,
-  MessageCall,
-  MessageDate,
-  MessageInitial,
-  MessageMember,
-  MessageMerge,
-  MessageTime,
-} from './Message';
-
-dayjs.extend(dayOfYear);
-dayjs.extend(isBetween);
+import { MessageRow } from './Message';
 
 interface MessageListProps {
   account: Account;
@@ -42,113 +27,31 @@
 }
 
 export default function MessageList({ account, members, messages }: MessageListProps) {
-  const messageComponents = useMemo(() => buildMessagesList(account, members, messages), [account, members, messages]);
-  return <Stack direction="column-reverse">{messageComponents}</Stack>;
-}
-
-const buildMessagesList = (account: Account, members: ConversationMember[], messages: Message[]) => {
-  if (messages.length === 0) {
-    return [];
-  }
-
-  const messageComponents: ReactNode[] = [];
-  let lastTime = dayjs.unix(Number(messages[0].timestamp));
-  let lastAuthor = messages[0].author;
-  let messagesGroup: Message[] = [];
-
-  const pushMessageBubblesGroup = () => {
-    if (messagesGroup.length === 0) {
-      return;
-    }
-    const props = { account, members, messages: messagesGroup };
-    messageComponents.push(<MessageBubblesGroup key={`group-${messagesGroup[0].id}`} {...props} />);
-    messagesGroup = [];
-  };
-
-  const pushMessageCall = (message: Message) => {
-    const props = { message };
-    messageComponents.push(<MessageCall key={`call-${message.id}`} {...props} />);
-  };
-
-  const pushMessageMember = (message: Message) => {
-    const props = { message };
-    messageComponents.push(<MessageMember key={`member-${message.id}`} {...props} />);
-  };
-
-  const pushMessageMerge = (message: Message) => {
-    const props = { message };
-    messageComponents.push(<MessageMerge key={`merge-${message.id}`} {...props} />);
-  };
-
-  const pushMessageTime = (message: Message, time: Dayjs, hasDateOnTop = false) => {
-    const props = { time, hasDateOnTop };
-    messageComponents.push(<MessageTime key={`time-${message.id}`} {...props} />);
-  };
-
-  const pushMessageDate = (message: Message, time: Dayjs) => {
-    const props = { time };
-    messageComponents.push(<MessageDate key={`date-${message.id}`} {...props} />);
-  };
-
-  const pushMessageInitial = (message: Message) => {
-    const props = { message };
-    messageComponents.push(<MessageInitial key={`initial-${message.id}`} {...props} />);
-  };
-
-  messages.forEach((message) => {
-    // most recent messages first
-    switch (message.type) {
-      case 'text/plain':
-      case 'application/data-transfer+json':
-        if (lastAuthor !== message.author) {
-          pushMessageBubblesGroup();
-        }
-        messagesGroup.push(message);
-        break;
-      case 'application/call-history+json':
-        pushMessageBubblesGroup();
-        pushMessageCall(message);
-        break;
-      case 'member':
-        pushMessageBubblesGroup();
-        pushMessageMember(message);
-        break;
-      case 'merge':
-        pushMessageBubblesGroup();
-        pushMessageMerge(message);
-        break;
-      case 'initial':
-      default:
-        break;
-    }
-
-    const time = dayjs.unix(Number(message.timestamp));
-    if (message.type === 'initial') {
-      pushMessageBubblesGroup();
-      pushMessageTime(message, time, true);
-      pushMessageDate(message, time);
-      pushMessageInitial(message);
-    } else {
-      if (
-        // If the date is different
-        lastTime?.year() !== time.year() ||
-        lastTime?.dayOfYear() !== time.dayOfYear()
-      ) {
-        pushMessageBubblesGroup();
-        pushMessageTime(message, time, true);
-        pushMessageDate(message, time);
-      } else if (
-        // If more than 5 minutes have passed since the last message
-        !lastTime.isBetween(time, time?.add(5, 'minute'))
-      ) {
-        pushMessageBubblesGroup();
-        pushMessageTime(message, time);
+  return (
+    <Stack direction="column-reverse">
+      {
+        // most recent messages first
+        messages.map((message, index) => {
+          const isAccountMessage = message.author === account.getUri();
+          let author;
+          if (isAccountMessage) {
+            author = account;
+          } else {
+            const member = members.find((member) => message.author === member.contact.getUri());
+            author = member?.contact;
+          }
+          if (!author) {
+            return null;
+          }
+          const props = {
+            messageIndex: index,
+            messages,
+            isAccountMessage,
+            author,
+          };
+          return <MessageRow key={message.id} {...props} />;
+        })
       }
-
-      lastTime = time;
-      lastAuthor = message.author;
-    }
-  });
-
-  return messageComponents;
-};
+    </Stack>
+  );
+}