blob: 0ae04d282645186e50416205f81ff3792cc48623 [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';
simon5da8ca62022-11-09 15:21:25 -050020import { 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
simon5da8ca62022-11-09 15:21:25 -050025import { useAuthContext } from '../contexts/AuthProvider';
idillon-sfl118ae442022-10-25 10:42:54 -040026import { MessageRow } from './Message';
idillon02f579d2022-11-06 21:26:55 -050027import { ArrowDownIcon } from './SvgIcon';
idillon-sfl9d956ab2022-10-20 16:33:24 -040028
29interface MessageListProps {
idillon-sfl9d956ab2022-10-20 16:33:24 -040030 members: ConversationMember[];
31 messages: Message[];
32}
33
simon5da8ca62022-11-09 15:21:25 -050034export default function MessageList({ members, messages }: MessageListProps) {
35 const { account } = useAuthContext();
idillon02f579d2022-11-06 21:26:55 -050036 const [showScrollButton, setShowScrollButton] = useState(false);
37 const listBottomRef = useRef<HTMLElement>();
38
idillon-sfl118ae442022-10-25 10:42:54 -040039 return (
idillon02f579d2022-11-06 21:26:55 -050040 <>
41 <Stack flex={1} overflow="auto" padding="0px 16px" direction="column-reverse">
42 {/* Here is the bottom of the list of messages because of 'column-reverse' */}
43 <Box ref={listBottomRef} />
44 <Waypoint
45 onEnter={() => setShowScrollButton(false)}
46 onLeave={() => setShowScrollButton(true)}
47 bottomOffset="-100px"
48 />
49 <Stack direction="column-reverse">
50 {
51 // most recent messages first
52 messages.map((message, index) => {
53 const isAccountMessage = message.author === account.getUri();
54 let author;
55 if (isAccountMessage) {
56 author = account;
57 } else {
58 const member = members.find((member) => message.author === member.contact.getUri());
59 author = member?.contact;
60 }
61 if (!author) {
62 return null;
63 }
64 const props = {
65 messageIndex: index,
66 messages,
67 isAccountMessage,
68 author,
69 };
70 return <MessageRow key={message.id} {...props} />;
71 })
idillon-sfl118ae442022-10-25 10:42:54 -040072 }
idillon02f579d2022-11-06 21:26:55 -050073 </Stack>
74 <Waypoint onEnter={() => console.log('should load more messages')} topOffset="-200px" />
75 </Stack>
76 {showScrollButton && (
77 <Box position="relative">
78 <Box position="absolute" bottom="10px" left="50%" sx={{ transform: 'translate(-50%)' }}>
79 <ScrollToEndButton listBottomRef={listBottomRef} />
80 </Box>
81 </Box>
82 )}
83 </>
idillon-sfl118ae442022-10-25 10:42:54 -040084 );
85}
idillon02f579d2022-11-06 21:26:55 -050086
87interface ScrollToEndButtonProps {
88 listBottomRef: MutableRefObject<HTMLElement | undefined>;
89}
90
91const ScrollToEndButton = ({ listBottomRef }: ScrollToEndButtonProps) => {
92 const { t } = useTranslation();
93 const textColor = 'white';
94 return (
95 <Stack
96 direction="row"
97 borderRadius="5px"
98 height="30px"
99 alignItems="center"
100 padding="0 16px"
101 spacing="12px"
102 sx={{
103 backgroundColor: '#005699', // Should be same color as message bubble
104 cursor: 'pointer',
105 }}
106 onClick={() => listBottomRef.current?.scrollIntoView({ behavior: 'smooth' })}
107 >
108 <ArrowDownIcon sx={{ fontSize: '12px', color: textColor }} />
109 <Typography variant="caption" fontWeight="bold" color={textColor}>
110 {t('messages_scroll_to_end')}
111 </Typography>
112 </Stack>
113 );
114};