| /* |
| * Copyright (C) 2022 Savoir-faire Linux Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU Affero General Public License as |
| * published by the Free Software Foundation; either version 3 of the |
| * License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Affero General Public License for more details. |
| * |
| * You should have received a copy of the GNU Affero General Public |
| * License along with this program. If not, see |
| * <https://www.gnu.org/licenses/>. |
| */ |
| import { Stack } from '@mui/system'; |
| import dayjs from 'dayjs'; |
| import dayOfYear from 'dayjs/plugin/dayOfYear'; |
| import isBetween from 'dayjs/plugin/isBetween'; |
| import { useMemo } from 'react'; |
| |
| import { |
| MessageBubblesGroup, |
| MessageCall, |
| MessageDate, |
| MessageInitial, |
| MessageMember, |
| MessageMerge, |
| MessageTime, |
| } from './Message'; |
| |
| dayjs.extend(dayOfYear); |
| dayjs.extend(isBetween); |
| |
| export default function MessageList(props) { |
| const messagesComponents = useMemo(() => buildMessagesList(props.messages), [props.messages]); |
| |
| return ( |
| <Stack marginLeft="16px" marginRight="16px" direction="column-reverse"> |
| {messagesComponents?.map(({ Component, id, props }) => ( |
| <Component key={id} {...props} /> |
| ))} |
| </Stack> |
| ); |
| } |
| |
| const buildMessagesList = (messages) => { |
| if (messages.length == 0) { |
| return null; |
| } |
| |
| const components = []; |
| let lastTime = dayjs.unix(messages[0].timestamp); |
| let lastAuthor = messages[0].author; |
| let messageBubblesGroup = []; |
| |
| const pushMessageBubblesGroup = () => { |
| if (messageBubblesGroup.length == 0) { |
| return; |
| } |
| components.push({ |
| id: `group-${messageBubblesGroup[0].id}`, |
| Component: MessageBubblesGroup, |
| props: { messages: messageBubblesGroup }, |
| }); |
| messageBubblesGroup = []; |
| }; |
| |
| const pushMessageCall = (message) => { |
| components.push({ |
| id: `call-${message.id}`, |
| Component: MessageCall, |
| props: { message }, |
| }); |
| }; |
| |
| const pushMessageMember = (message) => { |
| components.push({ |
| id: `member-${message.id}`, |
| Component: MessageMember, |
| props: { message }, |
| }); |
| }; |
| |
| const pushMessageMerge = (message) => { |
| components.push({ |
| id: `merge-${message.id}`, |
| Component: MessageMerge, |
| props: { message }, |
| }); |
| }; |
| |
| const pushMessageTime = (message, time, hasDateOnTop = false) => { |
| components.push({ |
| id: `time-${message.id}`, |
| Component: MessageTime, |
| props: { time, hasDateOnTop }, |
| }); |
| }; |
| |
| const pushMessageDate = (message, time) => { |
| components.push({ |
| id: `date-${message.id}`, |
| Component: MessageDate, |
| props: { time }, |
| }); |
| }; |
| |
| const pushMessageInitial = (message) => { |
| components.push({ |
| id: `initial-${message.id}`, |
| Component: MessageInitial, |
| props: { message }, |
| }); |
| }; |
| |
| messages.forEach((message) => { |
| // most recent messages first |
| switch (message.type) { |
| case 'text/plain': |
| case 'application/data-transfer+json': |
| if (lastAuthor != message.author) { |
| pushMessageBubblesGroup(); |
| } |
| messageBubblesGroup.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(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); |
| } |
| |
| lastTime = time; |
| lastAuthor = message.author; |
| } |
| }); |
| |
| return components; |
| }; |