| | import { createPortal } from 'react-dom' |
| | import PropTypes from 'prop-types' |
| | import { useState, useEffect } from 'react' |
| | import { useDispatch } from 'react-redux' |
| | import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction } from 'store/actions' |
| |
|
| | import { |
| | Box, |
| | Typography, |
| | Button, |
| | Dialog, |
| | DialogActions, |
| | DialogContent, |
| | DialogTitle, |
| | Stack, |
| | IconButton, |
| | OutlinedInput, |
| | Popover |
| | } from '@mui/material' |
| | import { useTheme } from '@mui/material/styles' |
| | import { StyledButton } from 'ui-component/button/StyledButton' |
| |
|
| | |
| | import { IconX, IconCopy } from '@tabler/icons' |
| |
|
| | |
| | import apikeyApi from 'api/apikey' |
| |
|
| | |
| | import useNotifier from 'utils/useNotifier' |
| |
|
| | const APIKeyDialog = ({ show, dialogProps, onCancel, onConfirm }) => { |
| | const portalElement = document.getElementById('portal') |
| |
|
| | const theme = useTheme() |
| | const dispatch = useDispatch() |
| |
|
| | |
| |
|
| | useNotifier() |
| |
|
| | const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) |
| | const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) |
| |
|
| | const [keyName, setKeyName] = useState('') |
| | const [anchorEl, setAnchorEl] = useState(null) |
| | const openPopOver = Boolean(anchorEl) |
| |
|
| | useEffect(() => { |
| | if (dialogProps.type === 'EDIT' && dialogProps.key) { |
| | setKeyName(dialogProps.key.keyName) |
| | } else if (dialogProps.type === 'ADD') { |
| | setKeyName('') |
| | } |
| | }, [dialogProps]) |
| |
|
| | const handleClosePopOver = () => { |
| | setAnchorEl(null) |
| | } |
| |
|
| | const addNewKey = async () => { |
| | try { |
| | const createResp = await apikeyApi.createNewAPI({ keyName }) |
| | if (createResp.data) { |
| | enqueueSnackbar({ |
| | message: 'New API key added', |
| | options: { |
| | key: new Date().getTime() + Math.random(), |
| | variant: 'success', |
| | action: (key) => ( |
| | <Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}> |
| | <IconX /> |
| | </Button> |
| | ) |
| | } |
| | }) |
| | onConfirm() |
| | } |
| | } catch (error) { |
| | const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` |
| | enqueueSnackbar({ |
| | message: `Failed to add new API key: ${errorData}`, |
| | options: { |
| | key: new Date().getTime() + Math.random(), |
| | variant: 'error', |
| | persist: true, |
| | action: (key) => ( |
| | <Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}> |
| | <IconX /> |
| | </Button> |
| | ) |
| | } |
| | }) |
| | onCancel() |
| | } |
| | } |
| |
|
| | const saveKey = async () => { |
| | try { |
| | const saveResp = await apikeyApi.updateAPI(dialogProps.key.id, { keyName }) |
| | if (saveResp.data) { |
| | enqueueSnackbar({ |
| | message: 'API Key saved', |
| | options: { |
| | key: new Date().getTime() + Math.random(), |
| | variant: 'success', |
| | action: (key) => ( |
| | <Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}> |
| | <IconX /> |
| | </Button> |
| | ) |
| | } |
| | }) |
| | onConfirm() |
| | } |
| | } catch (error) { |
| | const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` |
| | enqueueSnackbar({ |
| | message: `Failed to save API key: ${errorData}`, |
| | options: { |
| | key: new Date().getTime() + Math.random(), |
| | variant: 'error', |
| | persist: true, |
| | action: (key) => ( |
| | <Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}> |
| | <IconX /> |
| | </Button> |
| | ) |
| | } |
| | }) |
| | onCancel() |
| | } |
| | } |
| |
|
| | const component = show ? ( |
| | <Dialog |
| | fullWidth |
| | maxWidth='sm' |
| | open={show} |
| | onClose={onCancel} |
| | aria-labelledby='alert-dialog-title' |
| | aria-describedby='alert-dialog-description' |
| | > |
| | <DialogTitle sx={{ fontSize: '1rem' }} id='alert-dialog-title'> |
| | {dialogProps.title} |
| | </DialogTitle> |
| | <DialogContent> |
| | {dialogProps.type === 'EDIT' && ( |
| | <Box sx={{ p: 2 }}> |
| | <Typography variant='overline'>API Key</Typography> |
| | <Stack direction='row' sx={{ mb: 1 }}> |
| | <Typography |
| | sx={{ |
| | p: 1, |
| | borderRadius: 10, |
| | backgroundColor: theme.palette.primary.light, |
| | width: 'max-content', |
| | height: 'max-content' |
| | }} |
| | variant='h5' |
| | > |
| | {dialogProps.key.apiKey} |
| | </Typography> |
| | <IconButton |
| | title='Copy API Key' |
| | color='success' |
| | onClick={(event) => { |
| | navigator.clipboard.writeText(dialogProps.key.apiKey) |
| | setAnchorEl(event.currentTarget) |
| | setTimeout(() => { |
| | handleClosePopOver() |
| | }, 1500) |
| | }} |
| | > |
| | <IconCopy /> |
| | </IconButton> |
| | <Popover |
| | open={openPopOver} |
| | anchorEl={anchorEl} |
| | onClose={handleClosePopOver} |
| | anchorOrigin={{ |
| | vertical: 'top', |
| | horizontal: 'right' |
| | }} |
| | transformOrigin={{ |
| | vertical: 'top', |
| | horizontal: 'left' |
| | }} |
| | > |
| | <Typography variant='h6' sx={{ pl: 1, pr: 1, color: 'white', background: theme.palette.success.dark }}> |
| | Copied! |
| | </Typography> |
| | </Popover> |
| | </Stack> |
| | </Box> |
| | )} |
| | |
| | <Box sx={{ p: 2 }}> |
| | <Stack sx={{ position: 'relative' }} direction='row'> |
| | <Typography variant='overline'>Key Name</Typography> |
| | </Stack> |
| | <OutlinedInput |
| | id='keyName' |
| | type='string' |
| | fullWidth |
| | placeholder='My New Key' |
| | value={keyName} |
| | name='keyName' |
| | onChange={(e) => setKeyName(e.target.value)} |
| | /> |
| | </Box> |
| | </DialogContent> |
| | <DialogActions> |
| | <StyledButton variant='contained' onClick={() => (dialogProps.type === 'ADD' ? addNewKey() : saveKey())}> |
| | {dialogProps.confirmButtonName} |
| | </StyledButton> |
| | </DialogActions> |
| | </Dialog> |
| | ) : null |
| |
|
| | return createPortal(component, portalElement) |
| | } |
| |
|
| | APIKeyDialog.propTypes = { |
| | show: PropTypes.bool, |
| | dialogProps: PropTypes.object, |
| | onCancel: PropTypes.func, |
| | onConfirm: PropTypes.func |
| | } |
| |
|
| | export default APIKeyDialog |
| |
|