blob: 9a6790d53541ea94521ce98ca21c259add8f1169 [file] [log] [blame]
idillonef9ab812022-11-18 13:46:24 -05001/*
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 */
18import { Box, Button, List, ListItem, ListItemIcon, Stack, SvgIconProps, Typography } from '@mui/material';
19import Dialog from '@mui/material/Dialog';
20import DialogActions from '@mui/material/DialogActions';
21import DialogContent from '@mui/material/DialogContent';
22import DialogTitle from '@mui/material/DialogTitle';
23import { ComponentType, ReactNode, useCallback, useMemo, useState } from 'react';
24import { useTranslation } from 'react-i18next';
25
26interface DialogHandler {
27 props: {
28 open: boolean;
29 onClose: () => void;
30 };
31 openDialog: () => void;
32}
33
34export const useDialogHandler = (): DialogHandler => {
35 const [open, setOpen] = useState(false);
36
37 const onClose = useCallback(() => {
38 setOpen(false);
39 }, []);
40
41 const openDialog = useCallback(() => {
42 setOpen(true);
43 }, []);
44
45 return useMemo(
46 () => ({
47 props: { open, onClose },
48 openDialog,
49 }),
50 [open, onClose, openDialog]
51 );
52};
53
54interface BaseDialogProps {
55 open: boolean;
56 onClose: () => void;
57 icon?: ReactNode;
58 title: string;
59 content: ReactNode;
60 actions: ReactNode;
61}
62
63export const BaseDialog = ({ open, onClose, icon, title, content, actions }: BaseDialogProps) => {
64 return (
65 <Dialog open={open} onClose={onClose}>
66 <DialogTitle>
67 <Stack direction="row" alignItems="center" spacing="16px">
68 {icon && (
69 <Box height="80px" width="80px">
70 {icon}
71 </Box>
72 )}
73 <Box>
74 <Typography variant="h2">{title}</Typography>
75 </Box>
76 </Stack>
77 </DialogTitle>
78 <DialogContent>{content}</DialogContent>
79 <DialogActions>{actions}</DialogActions>
80 </Dialog>
81 );
82};
83
84type InfosDialogProps = Omit<BaseDialogProps, 'actions'>;
85
86export const InfosDialog = (props: InfosDialogProps) => {
87 const { t } = useTranslation();
88 return (
89 <BaseDialog
90 {...props}
91 actions={
92 <Button onClick={props.onClose} autoFocus>
93 {t('dialog_close')}
94 </Button>
95 }
96 />
97 );
98};
99
100interface ConfirmationDialogProps extends Omit<BaseDialogProps, 'actions'> {
101 onConfirm: () => void;
102 confirmButtonText: string;
103}
104
105export const ConfirmationDialog = ({ onConfirm, confirmButtonText, ...props }: ConfirmationDialogProps) => {
106 const { t } = useTranslation();
107 props.title = props.title || t('dialog_confirm_title_default');
108
109 return (
110 <BaseDialog
111 {...props}
112 actions={
113 <>
114 <Button onClick={onConfirm}>{confirmButtonText}</Button>
115 <Button onClick={props.onClose}>{t('dialog_cancel')}</Button>
116 </>
117 }
118 />
119 );
120};
121
122interface DialogContentListItem {
123 Icon?: ComponentType<SvgIconProps>;
124 label?: string;
125 value: ReactNode;
126}
127
128interface DialogContentListProps {
129 title?: string;
130 items: DialogContentListItem[];
131}
132
133export const DialogContentList = ({ title, items }: DialogContentListProps) => {
134 return (
135 <List subheader={<Typography variant="h3">{title}</Typography>}>
136 {items.map(({ Icon, label, value }, index) => (
137 <ListItem key={index}>
138 {Icon && (
139 <ListItemIcon>
140 <Icon />
141 </ListItemIcon>
142 )}
143 <Stack direction="row" alignItems="center" spacing="24px">
144 {label && (
145 <Stack direction="row" width="100px" justifyContent="end">
146 <Typography variant="body2" color="#a0a0a0">
147 {label}
148 </Typography>
149 </Stack>
150 )}
151 <Box>
152 <Typography variant="body2" sx={{ fontWeight: 'bold' }}>
153 {value}
154 </Typography>
155 </Box>
156 </Stack>
157 </ListItem>
158 ))}
159 </List>
160 );
161};