blob: 2325ecbd29bae36de2d277273b68fe58bca1af84 [file] [log] [blame]
simon26e79f72022-10-05 22:16:08 -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 */
simond47ef9e2022-09-28 22:24:28 -040018import { QuestionMark } from '@mui/icons-material';
simon35378692022-10-02 23:25:57 -040019import { Box, ClickAwayListener, IconButton, IconButtonProps, Popper, SvgIconProps } from '@mui/material';
simond47ef9e2022-09-28 22:24:28 -040020import { styled } from '@mui/material/styles';
simon35378692022-10-02 23:25:57 -040021import EmojiPicker, { IEmojiData } from 'emoji-picker-react';
idillonae655dd2022-10-14 18:11:02 -040022import { ComponentType, MouseEvent, useCallback, useState } from 'react';
simon07b4eb02022-09-29 17:50:26 -040023
simond47ef9e2022-09-28 22:24:28 -040024import {
25 Arrow2Icon,
26 Arrow3Icon,
27 ArrowIcon,
idillonae655dd2022-10-14 18:11:02 -040028 AudioCallIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040029 CallEndIcon,
simond47ef9e2022-09-28 22:24:28 -040030 CameraIcon,
31 CameraInBubbleIcon,
32 CancelIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040033 ChatBubbleIcon,
simond47ef9e2022-09-28 22:24:28 -040034 CrossedEyeIcon,
35 CrossIcon,
36 EmojiIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040037 ExtensionIcon,
simond47ef9e2022-09-28 22:24:28 -040038 EyeIcon,
39 FolderIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040040 FullscreenIcon,
41 GroupAddIcon,
simond47ef9e2022-09-28 22:24:28 -040042 InfoIcon,
idillonae655dd2022-10-14 18:11:02 -040043 ListIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040044 MicroIcon,
simond47ef9e2022-09-28 22:24:28 -040045 MicroInBubbleIcon,
46 PaperClipIcon,
47 PenIcon,
idillonae655dd2022-10-14 18:11:02 -040048 PeopleWithPlusSignIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040049 RecordingIcon,
simond47ef9e2022-09-28 22:24:28 -040050 SaltireIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040051 ScreenShareIcon,
idillonae655dd2022-10-14 18:11:02 -040052 VideoCallIcon,
Gabriel Rochone3ec0d22022-10-08 14:27:03 -040053 VideoCameraIcon,
54 VolumeIcon,
simon35378692022-10-02 23:25:57 -040055} from './SvgIcon';
Michelle Sepkap Simef5ebc2e2022-10-27 18:30:53 -040056import CustomTooltip from './Tooltip';
idillon-sfl44b05342022-08-24 15:46:42 -040057
simon35378692022-10-02 23:25:57 -040058type ShapedButtonProps = IconButtonProps & {
59 Icon: ComponentType<SvgIconProps>;
60};
61
62const RoundButton = styled(({ Icon, ...props }: ShapedButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -040063 <IconButton {...props} disableRipple={true}>
64 <Icon fontSize="inherit" />
65 </IconButton>
66))(({ theme }) => ({
67 border: `1px solid ${theme.palette.primary.dark}`,
68 color: theme.palette.primary.dark,
69 fontSize: '15px',
70 '&:hover': {
71 background: theme.palette.primary.light,
72 },
73 '&:active': {
74 color: '#FFF',
75 background: theme.palette.primary.dark,
76 },
77 '&.MuiIconButton-sizeSmall': {
78 height: '15px',
79 width: '15px',
80 },
81 '&.MuiIconButton-sizeMedium': {
82 height: '30px',
83 width: '30px',
84 },
85 '&.MuiIconButton-sizeLarge': {
86 height: '53px',
87 width: '53px',
88 },
idillon-sfld5cc7862022-08-25 11:11:34 -040089}));
idillon-sfl44b05342022-08-24 15:46:42 -040090
simon35378692022-10-02 23:25:57 -040091export const CancelPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040092 return <RoundButton {...props} aria-label="remove picture" Icon={CancelIcon} size="large" />;
93};
idillon-sfl44b05342022-08-24 15:46:42 -040094
simon35378692022-10-02 23:25:57 -040095export const EditPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040096 return <RoundButton {...props} aria-label="edit picture" Icon={PenIcon} size="large" />;
97};
idillon-sfl44b05342022-08-24 15:46:42 -040098
simon35378692022-10-02 23:25:57 -040099export const UploadPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400100 return <RoundButton {...props} aria-label="upload picture" Icon={FolderIcon} size="large" />;
101};
idillon-sfl44b05342022-08-24 15:46:42 -0400102
simon35378692022-10-02 23:25:57 -0400103export const TakePictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400104 return <RoundButton {...props} aria-label="take picture" Icon={CameraIcon} size="large" />;
105};
idillon-sfl37c18df2022-08-26 18:44:27 -0400106
Michelle Sepkap Simef5ebc2e2022-10-27 18:30:53 -0400107type InfoButtonProps = IconButtonProps & {
108 tooltipTitle: string;
109};
110export const InfoButton = ({ tooltipTitle, ...props }: InfoButtonProps) => {
111 return (
112 <CustomTooltip className="tooltip" title={tooltipTitle}>
113 <RoundButton {...props} aria-label="informations" Icon={InfoIcon} size="small" />
114 </CustomTooltip>
115 );
simond47ef9e2022-09-28 22:24:28 -0400116};
idillon-sfl37c18df2022-08-26 18:44:27 -0400117
simon35378692022-10-02 23:25:57 -0400118export const TipButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400119 return <RoundButton {...props} aria-label="tip" Icon={QuestionMark} size="medium" />;
120};
idillon-sfl37c18df2022-08-26 18:44:27 -0400121
simon35378692022-10-02 23:25:57 -0400122export const MoreButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400123 return (
124 <IconButton {...props} disableRipple={true} aria-label="more">
125 <CrossIcon fontSize="inherit" />
126 </IconButton>
127 );
128})(({ theme }) => ({
129 border: `1px solid ${theme.palette.primary.dark}`,
130 color: theme.palette.primary.dark,
131 fontSize: '10px',
132 height: '20px',
133 width: '20px',
134 '&:hover': {
135 background: theme.palette.primary.light,
136 },
137 '&:active': {
138 color: '#FFF',
139 background: theme.palette.primary.dark,
140 },
141}));
idillon927b7592022-09-15 12:56:45 -0400142
simon35378692022-10-02 23:25:57 -0400143export const BackButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400144 return (
145 <IconButton {...props} disableRipple={true} aria-label="back">
146 <ArrowIcon fontSize="inherit" />
147 </IconButton>
148 );
149})(({ theme }) => ({
150 color: theme.palette.primary.dark,
151 fontSize: '15px',
152 height: '30px',
153 width: '51px',
154 borderRadius: '5px',
155 '&:hover': {
156 background: theme.palette.primary.light,
157 },
158}));
idillonb3788bf2022-08-29 15:57:57 -0400159
Gabriel Rochone3ec0d22022-10-08 14:27:03 -0400160export const CallingChatButton = (props: IconButtonProps) => {
161 return (
162 <IconButton {...props} aria-label="chat" sx={{ color: 'white' }}>
163 <ChatBubbleIcon />
164 </IconButton>
165 );
166};
167
168export const CallingEndButton = (props: IconButtonProps) => {
169 return (
170 <IconButton {...props} aria-label="end call" sx={{ color: 'white', backgroundColor: 'red' }}>
171 <CallEndIcon />
172 </IconButton>
173 );
174};
175
176export const CallingExtensionButton = (props: IconButtonProps) => {
177 return (
178 <IconButton {...props} aria-label="extensions" sx={{ color: 'white' }}>
179 <ExtensionIcon />
180 </IconButton>
181 );
182};
183
184export const CallingFullscreenButton = (props: IconButtonProps) => {
185 return (
186 <IconButton {...props} aria-label="fullscreen" sx={{ color: 'white' }}>
187 <FullscreenIcon />
188 </IconButton>
189 );
190};
191
192export const CallingGroupButton = (props: IconButtonProps) => {
193 return (
194 <IconButton {...props} aria-label="group options" sx={{ color: 'white' }}>
195 <GroupAddIcon />
196 </IconButton>
197 );
198};
199
200export const CallingMicButton = (props: IconButtonProps) => {
201 return (
202 <IconButton {...props} aria-label="microphone options" sx={{ color: 'white' }}>
203 <MicroIcon />
204 </IconButton>
205 );
206};
207
208export const CallingRecordButton = (props: IconButtonProps) => {
209 return (
210 <IconButton {...props} aria-label="recording options" sx={{ color: 'white' }}>
211 <RecordingIcon />
212 </IconButton>
213 );
214};
215
216export const CallingScreenShareButton = (props: IconButtonProps) => {
217 return (
218 <IconButton {...props} aria-label="screen share" sx={{ color: 'white' }}>
219 <ScreenShareIcon />
220 </IconButton>
221 );
222};
223
224export const CallingVideoCameraButton = (props: IconButtonProps) => {
225 return (
226 <IconButton {...props} aria-label="camera options" sx={{ color: 'white' }}>
227 <VideoCameraIcon />
228 </IconButton>
229 );
230};
231export const CallingVolumeButton = (props: IconButtonProps) => {
232 return (
233 <IconButton {...props} aria-label="volume options" sx={{ color: 'white' }}>
234 <VolumeIcon />
235 </IconButton>
236 );
237};
238
simon35378692022-10-02 23:25:57 -0400239export const CloseButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400240 return (
241 <IconButton {...props} disableRipple={true} aria-label="close">
242 <SaltireIcon fontSize="inherit" />
243 </IconButton>
244 );
245})(({ theme }) => ({
246 color: theme.palette.primary.dark,
247 fontSize: '15px',
248 height: '30px',
249 width: '30px',
250 borderRadius: '5px',
251 '&:hover': {
252 background: theme.palette.primary.light,
253 },
254}));
idillonb3788bf2022-08-29 15:57:57 -0400255
simon35378692022-10-02 23:25:57 -0400256type ToggleVisibilityButtonProps = IconButtonProps & {
257 visible: boolean;
258};
259export const ToggleVisibilityButton = styled(({ visible, ...props }: ToggleVisibilityButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400260 const Icon = visible ? CrossedEyeIcon : EyeIcon;
261 return (
262 <IconButton {...props} disableRipple={true}>
263 <Icon fontSize="inherit" />
264 </IconButton>
265 );
266})(({ theme }) => ({
267 color: theme.palette.primary.dark,
268 fontSize: '15px',
269 height: '15px',
270 width: '15px',
271 '&:hover': {
272 background: theme.palette.primary.light,
273 },
274}));
idillonaedab942022-09-01 14:29:43 -0400275
simon35378692022-10-02 23:25:57 -0400276const SquareButton = styled(({ Icon, ...props }: ShapedButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400277 <IconButton {...props} disableRipple={true}>
278 <Icon fontSize="inherit" />
279 </IconButton>
280))(({ theme }) => ({
281 color: '#7E7E7E',
282 fontSize: '25px',
283 height: '36px',
284 width: '36px',
285 borderRadius: '5px',
286 '&:hover': {
287 background: '#E5E5E5',
288 },
idillonaedab942022-09-01 14:29:43 -0400289}));
290
idillonae655dd2022-10-14 18:11:02 -0400291export const AddParticipantButton = (props: IconButtonProps) => {
292 return <SquareButton {...props} aria-label="add participant" Icon={PeopleWithPlusSignIcon} />;
293};
294
simon35378692022-10-02 23:25:57 -0400295export const RecordVideoMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400296 return <SquareButton {...props} aria-label="record video message" Icon={CameraInBubbleIcon} />;
297};
idillonaedab942022-09-01 14:29:43 -0400298
simon35378692022-10-02 23:25:57 -0400299export const RecordVoiceMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400300 return <SquareButton {...props} aria-label="record voice message" Icon={MicroInBubbleIcon} />;
301};
idillonaedab942022-09-01 14:29:43 -0400302
idillonae655dd2022-10-14 18:11:02 -0400303export const ShowOptionsMenuButton = (props: IconButtonProps) => {
304 return <SquareButton {...props} aria-label="show options menu" Icon={ListIcon} />;
305};
306
307export const StartVideoCallButton = (props: IconButtonProps) => {
308 return <SquareButton {...props} aria-label="start audio call" Icon={AudioCallIcon} />;
309};
310
311export const StartAudioCallButton = (props: IconButtonProps) => {
312 return <SquareButton {...props} aria-label="start video call" Icon={VideoCallIcon} />;
313};
314
simon35378692022-10-02 23:25:57 -0400315export const UploadFileButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400316 return <SquareButton {...props} aria-label="upload file" Icon={PaperClipIcon} />;
317};
idillonaedab942022-09-01 14:29:43 -0400318
simon35378692022-10-02 23:25:57 -0400319export const SendMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400320 return <SquareButton {...props} aria-label="send message" Icon={Arrow2Icon} />;
321};
idillonaedab942022-09-01 14:29:43 -0400322
simon35378692022-10-02 23:25:57 -0400323export const ReplyMessageButton = styled((props: IconButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400324 <IconButton {...props} disableRipple={true} aria-label="send message">
325 <Arrow3Icon fontSize="inherit" />
326 </IconButton>
327))(({ theme }) => ({
328 color: theme.palette.primary.dark,
329 fontSize: '20px',
330 height: '20px',
331 width: '20px',
332 borderRadius: '5px',
333 '&:hover': {
334 background: '#E5E5E5',
335 },
idillon927b7592022-09-15 12:56:45 -0400336}));
337
simon35378692022-10-02 23:25:57 -0400338type EmojiButtonProps = IconButtonProps & {
339 emoji: string;
340};
341export const EmojiButton = styled(({ emoji, ...props }: EmojiButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400342 <IconButton {...props} disableRipple={true}>
343 {emoji}
344 </IconButton>
345))(({ theme }) => ({
346 color: 'white',
347 fontSize: '20px',
348 height: '20px',
349 width: '20px',
idillon927b7592022-09-15 12:56:45 -0400350}));
351
simon35378692022-10-02 23:25:57 -0400352type SelectEmojiButtonProps = {
353 onEmojiSelected: (emoji: string) => void;
354};
355export const SelectEmojiButton = ({ onEmojiSelected, ...props }: SelectEmojiButtonProps) => {
356 const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
idillon1664bb22022-09-14 17:18:15 -0400357
simon35378692022-10-02 23:25:57 -0400358 const handleOpenEmojiPicker = useCallback(
359 (e: MouseEvent<HTMLButtonElement>) => setAnchorEl(anchorEl ? null : e.currentTarget),
360 [anchorEl]
361 );
simond47ef9e2022-09-28 22:24:28 -0400362
363 const handleClose = useCallback(() => setAnchorEl(null), [setAnchorEl]);
364
365 const onEmojiClick = useCallback(
simon35378692022-10-02 23:25:57 -0400366 (e: MouseEvent, emojiObject: IEmojiData) => {
simon80b7b3b2022-09-28 17:50:10 -0400367 onEmojiSelected(emojiObject.emoji);
simond47ef9e2022-09-28 22:24:28 -0400368 handleClose();
369 },
simon80b7b3b2022-09-28 17:50:10 -0400370 [handleClose, onEmojiSelected]
simond47ef9e2022-09-28 22:24:28 -0400371 );
372
373 const open = Boolean(anchorEl);
374 const id = open ? 'simple-popover' : undefined;
375
376 return (
377 <ClickAwayListener onClickAway={handleClose}>
378 <Box>
idillonae655dd2022-10-14 18:11:02 -0400379 <SquareButton
380 aria-describedby={id}
381 aria-label="select emoji"
382 Icon={EmojiIcon}
383 onClick={handleOpenEmojiPicker}
384 />
simon35378692022-10-02 23:25:57 -0400385 <Popper id={id} open={open} anchorEl={anchorEl}>
386 <EmojiPicker onEmojiClick={onEmojiClick} disableAutoFocus={true} disableSkinTonePicker={true} native />
simond47ef9e2022-09-28 22:24:28 -0400387 </Popper>
388 </Box>
389 </ClickAwayListener>
390 );
391};