| /* |
| * Copyright (C) 2022 Savoir-faire Linux Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU Affero General Public License as |
| * published by the Free Software Foundation; either version 3 of the |
| * License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU Affero General Public License for more details. |
| * |
| * You should have received a copy of the GNU Affero General Public |
| * License along with this program. If not, see |
| * <https://www.gnu.org/licenses/>. |
| */ |
| import { Box, Button, List, ListItem, ListItemIcon, Stack, SvgIconProps, Typography } from '@mui/material'; |
| import Dialog from '@mui/material/Dialog'; |
| import DialogActions from '@mui/material/DialogActions'; |
| import DialogContent from '@mui/material/DialogContent'; |
| import DialogTitle from '@mui/material/DialogTitle'; |
| import { ComponentType, ReactNode, useCallback, useMemo, useState } from 'react'; |
| import { useTranslation } from 'react-i18next'; |
| |
| interface DialogHandler { |
| props: { |
| open: boolean; |
| onClose: () => void; |
| }; |
| openDialog: () => void; |
| } |
| |
| export const useDialogHandler = (): DialogHandler => { |
| const [open, setOpen] = useState(false); |
| |
| const onClose = useCallback(() => { |
| setOpen(false); |
| }, []); |
| |
| const openDialog = useCallback(() => { |
| setOpen(true); |
| }, []); |
| |
| return useMemo( |
| () => ({ |
| props: { open, onClose }, |
| openDialog, |
| }), |
| [open, onClose, openDialog] |
| ); |
| }; |
| |
| interface BaseDialogProps { |
| open: boolean; |
| onClose: () => void; |
| icon?: ReactNode; |
| title: string; |
| content: ReactNode; |
| actions: ReactNode; |
| } |
| |
| export const BaseDialog = ({ open, onClose, icon, title, content, actions }: BaseDialogProps) => { |
| return ( |
| <Dialog open={open} onClose={onClose}> |
| <DialogTitle> |
| <Stack direction="row" alignItems="center" spacing="16px"> |
| {icon && ( |
| <Box height="80px" width="80px"> |
| {icon} |
| </Box> |
| )} |
| <Box> |
| <Typography variant="h2">{title}</Typography> |
| </Box> |
| </Stack> |
| </DialogTitle> |
| <DialogContent>{content}</DialogContent> |
| <DialogActions>{actions}</DialogActions> |
| </Dialog> |
| ); |
| }; |
| |
| type InfosDialogProps = Omit<BaseDialogProps, 'actions'>; |
| |
| export const InfosDialog = (props: InfosDialogProps) => { |
| const { t } = useTranslation(); |
| return ( |
| <BaseDialog |
| {...props} |
| actions={ |
| <Button onClick={props.onClose} autoFocus> |
| {t('dialog_close')} |
| </Button> |
| } |
| /> |
| ); |
| }; |
| |
| interface ConfirmationDialogProps extends Omit<BaseDialogProps, 'actions'> { |
| onConfirm: () => void; |
| confirmButtonText: string; |
| content: string; |
| } |
| |
| export const ConfirmationDialog = ({ onConfirm, confirmButtonText, ...props }: ConfirmationDialogProps) => { |
| const { t } = useTranslation(); |
| props.title = props.title || t('dialog_confirm_title_default'); |
| |
| return ( |
| <BaseDialog |
| {...props} |
| content={<Typography variant="body1">{props.content}</Typography>} |
| actions={ |
| <> |
| <Button onClick={onConfirm}>{confirmButtonText}</Button> |
| <Button onClick={props.onClose}>{t('dialog_cancel')}</Button> |
| </> |
| } |
| /> |
| ); |
| }; |
| |
| interface DialogContentListItem { |
| Icon?: ComponentType<SvgIconProps>; |
| label?: string; |
| value: ReactNode; |
| } |
| |
| interface DialogContentListProps { |
| title?: string; |
| items: DialogContentListItem[]; |
| } |
| |
| export const DialogContentList = ({ title, items }: DialogContentListProps) => { |
| return ( |
| <List subheader={<Typography variant="h3">{title}</Typography>}> |
| {items.map(({ Icon, label, value }, index) => ( |
| <ListItem key={index}> |
| {Icon && ( |
| <ListItemIcon> |
| <Icon /> |
| </ListItemIcon> |
| )} |
| <Stack direction="row" alignItems="center" spacing="24px"> |
| {label && ( |
| <Stack direction="row" width="100px" justifyContent="end"> |
| <Typography variant="body2" color="#a0a0a0"> |
| {label} |
| </Typography> |
| </Stack> |
| )} |
| <Box> |
| <Typography variant="body2" sx={{ fontWeight: 'bold' }}> |
| {value} |
| </Typography> |
| </Box> |
| </Stack> |
| </ListItem> |
| ))} |
| </List> |
| ); |
| }; |