blob: c33def225743964be6500616615d538db3fe54aa [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 */
simon1170c322022-10-31 14:51:31 -040018import { QuestionMark, RadioButtonChecked, RadioButtonUnchecked } 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,
simond47ef9e2022-09-28 22:24:28 -040029 CameraIcon,
30 CameraInBubbleIcon,
31 CancelIcon,
32 CrossedEyeIcon,
33 CrossIcon,
34 EmojiIcon,
35 EyeIcon,
36 FolderIcon,
37 InfoIcon,
idillonae655dd2022-10-14 18:11:02 -040038 ListIcon,
simond47ef9e2022-09-28 22:24:28 -040039 MicroInBubbleIcon,
40 PaperClipIcon,
41 PenIcon,
idillonae655dd2022-10-14 18:11:02 -040042 PeopleWithPlusSignIcon,
simond47ef9e2022-09-28 22:24:28 -040043 SaltireIcon,
idillonae655dd2022-10-14 18:11:02 -040044 VideoCallIcon,
simon35378692022-10-02 23:25:57 -040045} from './SvgIcon';
Michelle Sepkap Simef5ebc2e2022-10-27 18:30:53 -040046import CustomTooltip from './Tooltip';
idillon-sfl44b05342022-08-24 15:46:42 -040047
simon35378692022-10-02 23:25:57 -040048type ShapedButtonProps = IconButtonProps & {
49 Icon: ComponentType<SvgIconProps>;
50};
51
52const RoundButton = styled(({ Icon, ...props }: ShapedButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -040053 <IconButton {...props} disableRipple={true}>
54 <Icon fontSize="inherit" />
55 </IconButton>
56))(({ theme }) => ({
57 border: `1px solid ${theme.palette.primary.dark}`,
58 color: theme.palette.primary.dark,
59 fontSize: '15px',
60 '&:hover': {
61 background: theme.palette.primary.light,
62 },
63 '&:active': {
64 color: '#FFF',
65 background: theme.palette.primary.dark,
66 },
67 '&.MuiIconButton-sizeSmall': {
68 height: '15px',
69 width: '15px',
70 },
71 '&.MuiIconButton-sizeMedium': {
72 height: '30px',
73 width: '30px',
74 },
75 '&.MuiIconButton-sizeLarge': {
76 height: '53px',
77 width: '53px',
78 },
idillon-sfld5cc7862022-08-25 11:11:34 -040079}));
idillon-sfl44b05342022-08-24 15:46:42 -040080
simon35378692022-10-02 23:25:57 -040081export const CancelPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040082 return <RoundButton {...props} aria-label="remove picture" Icon={CancelIcon} size="large" />;
83};
idillon-sfl44b05342022-08-24 15:46:42 -040084
simon35378692022-10-02 23:25:57 -040085export const EditPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040086 return <RoundButton {...props} aria-label="edit picture" Icon={PenIcon} size="large" />;
87};
idillon-sfl44b05342022-08-24 15:46:42 -040088
simon35378692022-10-02 23:25:57 -040089export const UploadPictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040090 return <RoundButton {...props} aria-label="upload picture" Icon={FolderIcon} size="large" />;
91};
idillon-sfl44b05342022-08-24 15:46:42 -040092
simon35378692022-10-02 23:25:57 -040093export const TakePictureButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -040094 return <RoundButton {...props} aria-label="take picture" Icon={CameraIcon} size="large" />;
95};
idillon-sfl37c18df2022-08-26 18:44:27 -040096
Michelle Sepkap Simef5ebc2e2022-10-27 18:30:53 -040097type InfoButtonProps = IconButtonProps & {
98 tooltipTitle: string;
99};
100export const InfoButton = ({ tooltipTitle, ...props }: InfoButtonProps) => {
101 return (
102 <CustomTooltip className="tooltip" title={tooltipTitle}>
103 <RoundButton {...props} aria-label="informations" Icon={InfoIcon} size="small" />
104 </CustomTooltip>
105 );
simond47ef9e2022-09-28 22:24:28 -0400106};
idillon-sfl37c18df2022-08-26 18:44:27 -0400107
simon35378692022-10-02 23:25:57 -0400108export const TipButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400109 return <RoundButton {...props} aria-label="tip" Icon={QuestionMark} size="medium" />;
110};
idillon-sfl37c18df2022-08-26 18:44:27 -0400111
simon35378692022-10-02 23:25:57 -0400112export const MoreButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400113 return (
114 <IconButton {...props} disableRipple={true} aria-label="more">
115 <CrossIcon fontSize="inherit" />
116 </IconButton>
117 );
118})(({ theme }) => ({
119 border: `1px solid ${theme.palette.primary.dark}`,
120 color: theme.palette.primary.dark,
121 fontSize: '10px',
122 height: '20px',
123 width: '20px',
124 '&:hover': {
125 background: theme.palette.primary.light,
126 },
127 '&:active': {
128 color: '#FFF',
129 background: theme.palette.primary.dark,
130 },
131}));
idillon927b7592022-09-15 12:56:45 -0400132
simon35378692022-10-02 23:25:57 -0400133export const BackButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400134 return (
135 <IconButton {...props} disableRipple={true} aria-label="back">
136 <ArrowIcon fontSize="inherit" />
137 </IconButton>
138 );
139})(({ theme }) => ({
140 color: theme.palette.primary.dark,
141 fontSize: '15px',
142 height: '30px',
143 width: '51px',
144 borderRadius: '5px',
145 '&:hover': {
146 background: theme.palette.primary.light,
147 },
148}));
idillonb3788bf2022-08-29 15:57:57 -0400149
simon1170c322022-10-31 14:51:31 -0400150export type ToggleIconButtonProps = IconButtonProps & {
151 selected: boolean;
152 toggle: () => void;
153 IconOn?: ComponentType<SvgIconProps>;
154 IconOff?: ComponentType<SvgIconProps>;
Gabriel Rochone3ec0d22022-10-08 14:27:03 -0400155};
simon1170c322022-10-31 14:51:31 -0400156export const ToggleIconButton = ({
157 IconOn = RadioButtonChecked,
158 IconOff = RadioButtonUnchecked,
159 selected,
160 toggle,
161 ...props
162}: ToggleIconButtonProps) => {
Gabriel Rochone3ec0d22022-10-08 14:27:03 -0400163 return (
simon1170c322022-10-31 14:51:31 -0400164 <IconButton
165 {...props}
166 onClick={() => {
167 toggle();
168 }}
169 >
170 {selected ? <IconOn /> : <IconOff />}
Gabriel Rochone3ec0d22022-10-08 14:27:03 -0400171 </IconButton>
172 );
173};
174
simon35378692022-10-02 23:25:57 -0400175export const CloseButton = styled((props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400176 return (
177 <IconButton {...props} disableRipple={true} aria-label="close">
178 <SaltireIcon fontSize="inherit" />
179 </IconButton>
180 );
181})(({ theme }) => ({
182 color: theme.palette.primary.dark,
183 fontSize: '15px',
184 height: '30px',
185 width: '30px',
186 borderRadius: '5px',
187 '&:hover': {
188 background: theme.palette.primary.light,
189 },
190}));
idillonb3788bf2022-08-29 15:57:57 -0400191
simon35378692022-10-02 23:25:57 -0400192type ToggleVisibilityButtonProps = IconButtonProps & {
193 visible: boolean;
194};
195export const ToggleVisibilityButton = styled(({ visible, ...props }: ToggleVisibilityButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400196 const Icon = visible ? CrossedEyeIcon : EyeIcon;
197 return (
198 <IconButton {...props} disableRipple={true}>
199 <Icon fontSize="inherit" />
200 </IconButton>
201 );
202})(({ theme }) => ({
203 color: theme.palette.primary.dark,
204 fontSize: '15px',
205 height: '15px',
206 width: '15px',
207 '&:hover': {
208 background: theme.palette.primary.light,
209 },
210}));
idillonaedab942022-09-01 14:29:43 -0400211
simon35378692022-10-02 23:25:57 -0400212const SquareButton = styled(({ Icon, ...props }: ShapedButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400213 <IconButton {...props} disableRipple={true}>
214 <Icon fontSize="inherit" />
215 </IconButton>
simon416d0792022-11-03 02:46:18 -0400216))(() => ({
simond47ef9e2022-09-28 22:24:28 -0400217 color: '#7E7E7E',
218 fontSize: '25px',
219 height: '36px',
220 width: '36px',
221 borderRadius: '5px',
222 '&:hover': {
223 background: '#E5E5E5',
224 },
idillonaedab942022-09-01 14:29:43 -0400225}));
226
idillonae655dd2022-10-14 18:11:02 -0400227export const AddParticipantButton = (props: IconButtonProps) => {
228 return <SquareButton {...props} aria-label="add participant" Icon={PeopleWithPlusSignIcon} />;
229};
230
simon35378692022-10-02 23:25:57 -0400231export const RecordVideoMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400232 return <SquareButton {...props} aria-label="record video message" Icon={CameraInBubbleIcon} />;
233};
idillonaedab942022-09-01 14:29:43 -0400234
simon35378692022-10-02 23:25:57 -0400235export const RecordVoiceMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400236 return <SquareButton {...props} aria-label="record voice message" Icon={MicroInBubbleIcon} />;
237};
idillonaedab942022-09-01 14:29:43 -0400238
idillonae655dd2022-10-14 18:11:02 -0400239export const ShowOptionsMenuButton = (props: IconButtonProps) => {
240 return <SquareButton {...props} aria-label="show options menu" Icon={ListIcon} />;
241};
242
243export const StartVideoCallButton = (props: IconButtonProps) => {
244 return <SquareButton {...props} aria-label="start audio call" Icon={AudioCallIcon} />;
245};
246
247export const StartAudioCallButton = (props: IconButtonProps) => {
248 return <SquareButton {...props} aria-label="start video call" Icon={VideoCallIcon} />;
249};
250
simon35378692022-10-02 23:25:57 -0400251export const UploadFileButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400252 return <SquareButton {...props} aria-label="upload file" Icon={PaperClipIcon} />;
253};
idillonaedab942022-09-01 14:29:43 -0400254
simon35378692022-10-02 23:25:57 -0400255export const SendMessageButton = (props: IconButtonProps) => {
simond47ef9e2022-09-28 22:24:28 -0400256 return <SquareButton {...props} aria-label="send message" Icon={Arrow2Icon} />;
257};
idillonaedab942022-09-01 14:29:43 -0400258
simon35378692022-10-02 23:25:57 -0400259export const ReplyMessageButton = styled((props: IconButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400260 <IconButton {...props} disableRipple={true} aria-label="send message">
261 <Arrow3Icon fontSize="inherit" />
262 </IconButton>
263))(({ theme }) => ({
264 color: theme.palette.primary.dark,
265 fontSize: '20px',
266 height: '20px',
267 width: '20px',
268 borderRadius: '5px',
269 '&:hover': {
270 background: '#E5E5E5',
271 },
idillon927b7592022-09-15 12:56:45 -0400272}));
273
simon35378692022-10-02 23:25:57 -0400274type EmojiButtonProps = IconButtonProps & {
275 emoji: string;
276};
277export const EmojiButton = styled(({ emoji, ...props }: EmojiButtonProps) => (
simond47ef9e2022-09-28 22:24:28 -0400278 <IconButton {...props} disableRipple={true}>
279 {emoji}
280 </IconButton>
simon416d0792022-11-03 02:46:18 -0400281))(() => ({
simond47ef9e2022-09-28 22:24:28 -0400282 color: 'white',
283 fontSize: '20px',
284 height: '20px',
285 width: '20px',
idillon927b7592022-09-15 12:56:45 -0400286}));
287
simon35378692022-10-02 23:25:57 -0400288type SelectEmojiButtonProps = {
289 onEmojiSelected: (emoji: string) => void;
290};
simon416d0792022-11-03 02:46:18 -0400291export const SelectEmojiButton = ({ onEmojiSelected }: SelectEmojiButtonProps) => {
simon35378692022-10-02 23:25:57 -0400292 const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
idillon1664bb22022-09-14 17:18:15 -0400293
simon35378692022-10-02 23:25:57 -0400294 const handleOpenEmojiPicker = useCallback(
295 (e: MouseEvent<HTMLButtonElement>) => setAnchorEl(anchorEl ? null : e.currentTarget),
296 [anchorEl]
297 );
simond47ef9e2022-09-28 22:24:28 -0400298
299 const handleClose = useCallback(() => setAnchorEl(null), [setAnchorEl]);
300
301 const onEmojiClick = useCallback(
simon35378692022-10-02 23:25:57 -0400302 (e: MouseEvent, emojiObject: IEmojiData) => {
simon80b7b3b2022-09-28 17:50:10 -0400303 onEmojiSelected(emojiObject.emoji);
simond47ef9e2022-09-28 22:24:28 -0400304 handleClose();
305 },
simon80b7b3b2022-09-28 17:50:10 -0400306 [handleClose, onEmojiSelected]
simond47ef9e2022-09-28 22:24:28 -0400307 );
308
309 const open = Boolean(anchorEl);
310 const id = open ? 'simple-popover' : undefined;
311
312 return (
313 <ClickAwayListener onClickAway={handleClose}>
314 <Box>
idillonae655dd2022-10-14 18:11:02 -0400315 <SquareButton
316 aria-describedby={id}
317 aria-label="select emoji"
318 Icon={EmojiIcon}
319 onClick={handleOpenEmojiPicker}
320 />
simon35378692022-10-02 23:25:57 -0400321 <Popper id={id} open={open} anchorEl={anchorEl}>
322 <EmojiPicker onEmojiClick={onEmojiClick} disableAutoFocus={true} disableSkinTonePicker={true} native />
simond47ef9e2022-09-28 22:24:28 -0400323 </Popper>
324 </Box>
325 </ClickAwayListener>
326 );
327};