blob: 513af54b8bf19152b2ad37df34cfe2fb8b94a0e0 [file] [log] [blame]
/*
* 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.account, props.members, props.messages),
[props.account, props.members, props.messages]
);
return (
<Stack direction="column-reverse">
{messagesComponents?.map(({ Component, id, props }) => (
<Component key={id} {...props} />
))}
</Stack>
);
}
const buildMessagesList = (account, members, 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: { account, members, 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;
};