blob: 7b9bf2d3964671cda9f32124aefe66e127c555a9 [file] [log] [blame]
idillon-sfl9d956ab2022-10-20 16:33:24 -04001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
idillon02f579d2022-11-06 21:26:55 -050018import { Typography } from '@mui/material';
19import { Box, Stack } from '@mui/system';
idillon-sfl9d956ab2022-10-20 16:33:24 -040020import { Account, ConversationMember, Message } from 'jami-web-common';
idillon02f579d2022-11-06 21:26:55 -050021import { MutableRefObject, useRef, useState } from 'react';
22import { useTranslation } from 'react-i18next';
23import { Waypoint } from 'react-waypoint';
idillon-sfl9d956ab2022-10-20 16:33:24 -040024
idillon-sfl118ae442022-10-25 10:42:54 -040025import { MessageRow } from './Message';
idillon02f579d2022-11-06 21:26:55 -050026import { ArrowDownIcon } from './SvgIcon';
idillon-sfl9d956ab2022-10-20 16:33:24 -040027
28interface MessageListProps {
29 account: Account;
30 members: ConversationMember[];
31 messages: Message[];
32}
33
34export default function MessageList({ account, members, messages }: MessageListProps) {
idillon02f579d2022-11-06 21:26:55 -050035 const [showScrollButton, setShowScrollButton] = useState(false);
36 const listBottomRef = useRef<HTMLElement>();
37
idillon-sfl118ae442022-10-25 10:42:54 -040038 return (
idillon02f579d2022-11-06 21:26:55 -050039 <>
40 <Stack flex={1} overflow="auto" padding="0px 16px" direction="column-reverse">
41 {/* Here is the bottom of the list of messages because of 'column-reverse' */}
42 <Box ref={listBottomRef} />
43 <Waypoint
44 onEnter={() => setShowScrollButton(false)}
45 onLeave={() => setShowScrollButton(true)}
46 bottomOffset="-100px"
47 />
48 <Stack direction="column-reverse">
49 {
50 // most recent messages first
51 messages.map((message, index) => {
52 const isAccountMessage = message.author === account.getUri();
53 let author;
54 if (isAccountMessage) {
55 author = account;
56 } else {
57 const member = members.find((member) => message.author === member.contact.getUri());
58 author = member?.contact;
59 }
60 if (!author) {
61 return null;
62 }
63 const props = {
64 messageIndex: index,
65 messages,
66 isAccountMessage,
67 author,
68 };
69 return <MessageRow key={message.id} {...props} />;
70 })
idillon-sfl118ae442022-10-25 10:42:54 -040071 }
idillon02f579d2022-11-06 21:26:55 -050072 </Stack>
73 <Waypoint onEnter={() => console.log('should load more messages')} topOffset="-200px" />
74 </Stack>
75 {showScrollButton && (
76 <Box position="relative">
77 <Box position="absolute" bottom="10px" left="50%" sx={{ transform: 'translate(-50%)' }}>
78 <ScrollToEndButton listBottomRef={listBottomRef} />
79 </Box>
80 </Box>
81 )}
82 </>
idillon-sfl118ae442022-10-25 10:42:54 -040083 );
84}
idillon02f579d2022-11-06 21:26:55 -050085
86interface ScrollToEndButtonProps {
87 listBottomRef: MutableRefObject<HTMLElement | undefined>;
88}
89
90const ScrollToEndButton = ({ listBottomRef }: ScrollToEndButtonProps) => {
91 const { t } = useTranslation();
92 const textColor = 'white';
93 return (
94 <Stack
95 direction="row"
96 borderRadius="5px"
97 height="30px"
98 alignItems="center"
99 padding="0 16px"
100 spacing="12px"
101 sx={{
102 backgroundColor: '#005699', // Should be same color as message bubble
103 cursor: 'pointer',
104 }}
105 onClick={() => listBottomRef.current?.scrollIntoView({ behavior: 'smooth' })}
106 >
107 <ArrowDownIcon sx={{ fontSize: '12px', color: textColor }} />
108 <Typography variant="caption" fontWeight="bold" color={textColor}>
109 {t('messages_scroll_to_end')}
110 </Typography>
111 </Stack>
112 );
113};