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