Skip to content

Commit

Permalink
refact: refact modal component (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
elysee15 authored Sep 6, 2021
1 parent ea7676c commit 1bab410
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 99 deletions.
4 changes: 2 additions & 2 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Modal from "components/Modal";
import CreateSecretModal from "components/CreateSecretModal";
import { ModalProvider } from "contexts/modalContext";
import { ServerStatusProvider } from "contexts/serverStatusContext";
import { BrowserRouter as Router } from "react-router-dom";
Expand All @@ -12,7 +12,7 @@ const App: React.FC = () => {
<ServerStatusProvider>
<ModalProvider>
<AppRouter />
<Modal />
<CreateSecretModal />
</ModalProvider>
</ServerStatusProvider>
</div>
Expand Down
118 changes: 118 additions & 0 deletions web/src/components/CreateSecretModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Box, IconButton, makeStyles, Snackbar, Typography } from "@material-ui/core";
import { AxiosError } from "axios";
import { useModal } from "contexts";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import React, { useState } from "react";
import CopyToClipboard from "react-copy-to-clipboard";
import deleteSecret from "services/deleteSecret";
import LinkIcon from "@material-ui/icons/Link";
import { ModalType } from "utils/enums/modal";
import Button from "./Button";
import Alert, { Color } from "@material-ui/lab/Alert";
import { generateSecretLink } from "utils/utils";
import Modal from "./Modal";
dayjs.extend(relativeTime);

const useStyles = makeStyles(() => ({
ellipsis: {
whiteSpace: "nowrap",
textOverflow: "ellipsis",
display: "block",
overflow: "scroll",
scrollbarWidth: "none",
msOverflowStyle: "none",
"&::-webkit-scrollbar": {
display: "none"
}
}
}));

const CreateSecretModal: React.FC = () => {
const classes = useStyles();
const { state, dispatch } = useModal();
const [alert, setAlert] = useState<{ open: boolean; severity?: Color; message?: string }>({
open: false,
severity: "success",
message: ""
});
const [isLoading, setIsLoading] = useState(false);
const secretLink = typeof state.modalProps?.token === "string" ? generateSecretLink(state.modalProps?.token) : "";
const handleCopy = () => setAlert({ open: true, message: "Secret link copied" });
const handleAlertClose = () => setAlert({ open: false });

const handleDeleteSecret = async () => {
if (window.confirm("Do you really want to remove the secret message ?")) {
if (state.modalProps?.token) {
setIsLoading(true);
deleteSecret(state.modalProps?.token).then(
() => {
setIsLoading(false);
setAlert({ open: true, message: "Secret message destroyed" });
dispatch({ type: ModalType.HIDE_MODAL });
},
(error: AxiosError) => {
setIsLoading(false);
setAlert({ open: true, message: error.message, severity: "error" });
}
);
}
}
};

return (
<Modal>
<Box>
<Typography variant="h5" align="center" gutterBottom>
Secret created successfully
</Typography>
<Typography align="center" gutterBottom>
You can find your secret on this link below
</Typography>
<Typography align="center" gutterBottom>
It expires{" "}
<span style={{ color: "red", fontWeight: "bold" }}>{dayjs(state.modalProps?.expires).fromNow()}</span>
</Typography>
</Box>

<Box
display="flex"
alignItems="center"
paddingLeft="15px"
justifyContent="space-between"
bgcolor="#f1f3f4"
borderRadius=".2rem"
>
<div className={classes.ellipsis}>
<Typography>{secretLink}</Typography>
</div>
<div>
<CopyToClipboard text={secretLink} onCopy={handleCopy}>
<IconButton aria-label="copy" size="medium" title="Copy this link">
<LinkIcon />
</IconButton>
</CopyToClipboard>
</div>
</Box>

<Box display="flex" gridGap="2rem" justifyContent="space-around">
<Button
isLoading={isLoading}
label="Destroy this secret"
onClick={handleDeleteSecret}
color="secondary"
variant="contained"
disabled={isLoading}
style={{ minWidth: "200px" }}
/>
</Box>
<Snackbar open={alert.open} autoHideDuration={5000} onClose={handleAlertClose}>
<Alert onClose={handleAlertClose} severity={alert.severity}>
{alert.message}
</Alert>
</Snackbar>
</Modal>
);
};

export default CreateSecretModal;
1 change: 0 additions & 1 deletion web/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const useStyles = makeStyles((theme: Theme) => ({
display: "none"
},
[`${theme.breakpoints.down("md")} and (orientation: landscape)`]: {
border: "2px solid purple !important",
height: "initial"
}
}
Expand Down
111 changes: 16 additions & 95 deletions web/src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,117 +1,38 @@
import React, { useState } from "react";
import { Box, Button, CircularProgress, IconButton, Modal as MuiModal, Snackbar, Typography } from "@material-ui/core";
import React from "react";
import { IconButton, Modal as MuiModal } from "@material-ui/core";
import { useModal } from "contexts";
import LinkIcon from "@material-ui/icons/Link";
import CloseIcon from "@material-ui/icons/Close";
import { CopyToClipboard } from "react-copy-to-clipboard";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { Alert, Color } from "@material-ui/lab";
import deleteSecret from "services/deleteSecret";
import { AxiosError } from "axios";
import { useStyles } from "styles/modalStyles";
import { ModalType } from "utils/enums/modal";
import { generateSecretLink } from "utils/utils";
dayjs.extend(relativeTime);

const Modal: React.FC = () => {
interface CustomModalProps {
children: React.ReactNode;
}

const Modal: React.FC<CustomModalProps> = ({ children }) => {
const classes = useStyles();
const { state, dispatch } = useModal();
const [alert, setAlert] = useState<{ open: boolean; severity?: Color; message?: string }>({
open: false,
severity: "success",
message: ""
});
const [isLoading, setIsLoading] = useState(false);
const secretLink = typeof state.modalProps?.token === "string" ? generateSecretLink(state.modalProps?.token) : "";

const handleCopy = () => setAlert({ open: true, message: "Secret link copied" });
const handleAlertClose = () => setAlert({ open: false });

const handleClose = () => {
if (window.confirm("Be sure to copy the link before closing the window")) {
dispatch({ type: ModalType.HIDE_MODAL });
}
};

const handleDeleteSecret = async () => {
if (window.confirm("Do you really want to remove the secret message ?")) {
if (state.modalProps?.token) {
setIsLoading(true);
deleteSecret(state.modalProps?.token).then(
() => {
setIsLoading(false);
setAlert({ open: true, message: "Secret message destroyed" });
dispatch({ type: ModalType.HIDE_MODAL });
},
(error: AxiosError) => {
setIsLoading(false);
setAlert({ open: true, message: error.message, severity: "error" });
}
);
}
}
};

return (
<div>
<MuiModal open={state.modalType === "SHOW_MODAL"} onClose={handleClose} aria-labelledby="token-modal">
<div className={classes.paper}>
<div>
<IconButton className={classes.close} onClick={handleClose} title="Close">
<CloseIcon />
</IconButton>
</div>
<Box>
<Typography variant="h5" align="center" gutterBottom>
Secret created successfully
</Typography>
<Typography align="center" gutterBottom>
You can find your secret on this link below
</Typography>
<Typography align="center" gutterBottom>
It expires{" "}
<span style={{ color: "red", fontWeight: "bold" }}>{dayjs(state.modalProps?.expires).fromNow()}</span>
</Typography>
</Box>
<Box
display="flex"
alignItems="center"
paddingLeft="15px"
justifyContent="space-between"
bgcolor="#f1f3f4"
borderRadius=".2rem"
>
<div className={classes.ellipsis}>
<Typography>{secretLink}</Typography>
</div>
<div>
<CopyToClipboard text={secretLink} onCopy={handleCopy}>
<IconButton aria-label="copy" size="medium" title="Copy this link">
<LinkIcon />
</IconButton>
</CopyToClipboard>
</div>
</Box>
<Box display="flex" gridGap="2rem" justifyContent="space-around">
<Button
onClick={handleDeleteSecret}
color="secondary"
variant="contained"
disabled={isLoading}
style={{ minWidth: "200px" }}
>
{isLoading ? <CircularProgress size={24} /> : "Destroy this secret"}
</Button>
</Box>
<MuiModal open={state.modalType === "SHOW_MODAL"} onClose={handleClose} aria-labelledby="token-modal">
<div className={classes.paper}>
<div>
<IconButton className={classes.close} onClick={handleClose} title="Close">
<CloseIcon />
</IconButton>
</div>
</MuiModal>
<Snackbar open={alert.open} autoHideDuration={5000} onClose={handleAlertClose}>
<Alert onClose={handleAlertClose} severity={alert.severity}>
{alert.message}
</Alert>
</Snackbar>
</div>
{children}
</div>
</MuiModal>
);
};

Expand Down
2 changes: 1 addition & 1 deletion web/src/styles/modalStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const useStyles = makeStyles((theme: Theme) =>
createStyles({
paper: {
position: "absolute",
width: 500,
minWidth: 500,
backgroundColor: theme.palette.background.paper,
top: "50%",
left: "50%",
Expand Down

0 comments on commit 1bab410

Please sign in to comment.