Skip to content

Commit

Permalink
Feat: add about us modal (#22)
Browse files Browse the repository at this point in the history
elysee15 authored Sep 10, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 55b4159 commit c7cff61
Showing 12 changed files with 180 additions and 93 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ on:
branches:
- main
tags:
- 'v*'
- "v*"
pull_request:

jobs:
@@ -70,7 +70,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: 16.x
node-version: 16.8.0
cache: "npm"
cache-dependency-path: ./web/package-lock.json

@@ -112,4 +112,4 @@ jobs:

- name: Build React Bundle
working-directory: ./web
run: npm run build
run: npm run build
2 changes: 2 additions & 0 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AboutUs from "components/AboutUs";
import CreateSecretModal from "components/CreateSecretModal";
import { ModalProvider } from "contexts/modalContext";
import { ServerStatusProvider } from "contexts/serverStatusContext";
@@ -13,6 +14,7 @@ const App: React.FC = () => {
<ModalProvider>
<AppRouter />
<CreateSecretModal />
<AboutUs />
</ModalProvider>
</ServerStatusProvider>
</div>
2 changes: 1 addition & 1 deletion web/src/__tests__/CreateSecretForm.spec.tsx
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ describe("CreateSecretForm", () => {
it("render the message validation error", async () => {
const onSubmitMock = jest.fn();
const { getByPlaceholderText, container } = render(
<CreateSecretForm onSubmit={onSubmitMock} initialValues={{}} />
<CreateSecretForm loading={false} type="message" onSubmit={onSubmitMock} initialValues={{}} />
);
const messageInput = getByPlaceholderText(/type your secret here/i);

81 changes: 81 additions & 0 deletions web/src/components/AboutUs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Box, Typography } from "@material-ui/core";
import { useModal } from "contexts";
import { useServerStatus } from "contexts/serverStatusContext";
import React from "react";
import { ModalType } from "utils/enums/modal";
import Badge from "./Badge";
import Modal from "./Modal";

const AboutUs: React.FC = () => {
const { state, dispatch } = useModal();
const [status] = useServerStatus();

const StatusColor = {
ok: "green",
maintainance: "yellow",
unhealthy: "red"
};

const handleClose = () => dispatch({ type: ModalType.HIDE_MODAL });

return (
<Modal open={state.modalType === ModalType.SHOW_ABOUT_US_MODAL} onClose={handleClose}>
<>
<div>
<h3>About Whisper</h3>
<p>
The Whisper service is an internal helper tool used at <a href="https://rotational.io">Rotational Labs</a>{" "}
to quickly share secrets, configurations, environment files, credentials, certificates, and more. Whisper is
designed to accelerate our own internal software engineering practice and is comprised of an API service
that is accessed by both a web UI and a command line application. There are many tools like Whisper, but
this one is ours!
</p>
<p>
To download the CLI application, report bugs or issues, or learn more about Whisper, please see the
README.md file in the Whisper GitHub repository:{" "}
<a href="https://github.com/rotationalio/whisper">rotationalio/whisper</a>.
</p>
<p>
Although Whisper is an internal tool at Rotational, We&apos;ve made the code open source and are happy to
have general contributions that enhance the project (particularly if you&apos;re a member of the Rotational
Engineering Team!) We&apos;ve made our releases and the code freely available under the{" "}
<a href="https://github.com/rotationalio/whisper/blob/main/LICENSE">Apache License 2.0</a> and we&apos;d
feel privileged if you used Whisper in your own organization. Please note, however, that Rotational Labs
makes no guarantees about the security of this software project and provides all code and binaries as is for
general use. Use with common sense and at your own risk!
</p>
<p>
If you&apos;re a Rotational customer and are interested in Whisper, please let us know, we&apos;d be happy
to deploy it for you as a single-tenant service. If you&apos;re not a Rotational customer but are
interested, please get in touch with us at <a href="mailto:info@rotational.io">info@rotational.io</a>.
</p>
</div>
<footer>
<Box display="flex" flexDirection="column" alignItems="center">
<Box display="flex" alignItems="center" gridGap=".5rem" marginBottom=".3rem">
{status.status && status.version && (
<>
<Typography variant="caption">
{status.status && (
<span>
<Badge content={`${status?.host || "server"} status`} color={StatusColor[status?.status]} />
</span>
)}
</Typography>
<Typography variant="caption">
version: <span style={{ fontWeight: "bold" }}>{status?.version}</span>
</Typography>
</>
)}
</Box>
<Typography>
Made with &spades; by <a href="https://rotational.io/">Rotational Labs</a>
</Typography>
</Box>
</footer>
</>
</Modal>
);
};

export default AboutUs;
104 changes: 56 additions & 48 deletions web/src/components/CreateSecretModal.tsx
Original file line number Diff line number Diff line change
@@ -62,57 +62,65 @@ const CreateSecretModal: React.FC = () => {
}
};

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

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>
<Modal open={state.modalType === "SHOW_MODAL"} onClose={handleClose}>
<>
<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"
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>
<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>
);
};
22 changes: 7 additions & 15 deletions web/src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,24 @@
import React from "react";
import { IconButton, Modal as MuiModal } from "@material-ui/core";
import { useModal } from "contexts";
import { IconButton, Modal as MuiModal, ModalProps } from "@material-ui/core";
import CloseIcon from "@material-ui/icons/Close";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { useStyles } from "styles/modalStyles";
import { ModalType } from "utils/enums/modal";
dayjs.extend(relativeTime);

interface CustomModalProps {
children: React.ReactNode;
interface CustomModalProps extends ModalProps {
children: React.ReactElement;
onClose: () => void;
}

const Modal: React.FC<CustomModalProps> = ({ children }) => {
const Modal: React.FC<CustomModalProps> = ({ children, onClose, ...props }) => {
const classes = useStyles();
const { state, dispatch } = useModal();

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

return (
<MuiModal open={state.modalType === "SHOW_MODAL"} onClose={handleClose} aria-labelledby="token-modal">
<MuiModal aria-labelledby="token-modal" {...props}>
<div className={classes.paper}>
<div>
<IconButton className={classes.close} onClick={handleClose} title="Close">
<IconButton className={classes.close} onClick={onClose} title="Close">
<CloseIcon />
</IconButton>
</div>
9 changes: 8 additions & 1 deletion web/src/contexts/modalContext.tsx
Original file line number Diff line number Diff line change
@@ -9,7 +9,8 @@ type State = {

type Action =
| { type: ModalType.SHOW_MODAL; payload?: Record<string, never> }
| { type: ModalType.HIDE_MODAL; payload?: Record<string, never> };
| { type: ModalType.HIDE_MODAL; payload?: Record<string, never> }
| { type: ModalType.SHOW_ABOUT_US_MODAL; payload?: Record<string, never> };

type ModalProviderProps = {
children: React.ReactNode;
@@ -30,6 +31,12 @@ const modalReducer = (state = initialState, action: Action) => {
modalType: ModalType.SHOW_MODAL,
modalProps: action.payload
};
case ModalType.SHOW_ABOUT_US_MODAL:
return {
...state,
modalType: ModalType.SHOW_ABOUT_US_MODAL,
modalProps: action.payload
};
case ModalType.HIDE_MODAL:
return initialState;
default:
13 changes: 12 additions & 1 deletion web/src/layouts/ContentLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import React from "react";
import { makeStyles, Theme } from "@material-ui/core";
import { Chip, makeStyles, Theme } from "@material-ui/core";
import HelpOutlineIcon from "@material-ui/icons/HelpOutline";
import { useModal } from "contexts";
import { ModalType } from "utils/enums/modal";

const useStyles = makeStyles((theme: Theme) => ({
root: {
@@ -23,9 +26,17 @@ type ContentLayoutProps = {

const ContentLayout: React.FC<ContentLayoutProps> = ({ children }) => {
const classes = useStyles();
const { dispatch } = useModal();

const handleClick = () => {
dispatch({ type: ModalType.SHOW_ABOUT_US_MODAL });
};

return (
<div className={classes.root}>
<div className={classes.chpisContainer}>
<Chip variant="outlined" size="small" avatar={<HelpOutlineIcon />} label="Learn More" onClick={handleClick} />
</div>
<div className={classes.container}>{children}</div>
</div>
);
18 changes: 0 additions & 18 deletions web/src/pages/AboutUs.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions web/src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@ import NotFound from "pages/NotFound";
import { Redirect, Route, Switch } from "react-router-dom";
import getStatus from "services/status";
import { Status } from "utils/enums/status";
import AboutUs from "pages/AboutUs";
import Help from "pages/Help";

const ShowSecret = React.lazy(() => import("pages/FetchSecret"));
@@ -31,7 +30,6 @@ const AppRouter: React.FC = () => {
<Suspense fallback="loading...">
<Switch>
<Route path="/" exact component={CreateSecret} />
<Route path="/about" exact component={AboutUs} />
<Route path="/help" exact component={Help} />
<Route path="/maintainance" exact component={MaintainancePage} />
{status.status === Status.maintainance ? <Redirect to="/maintainance" /> : null}
1 change: 1 addition & 0 deletions web/src/utils/enums/modal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum ModalType {
SHOW_MODAL = "SHOW_MODAL",
SHOW_ABOUT_US_MODAL = "SHOW_ABOUT_US_MODAL",
HIDE_MODAL = "HIDE_MODAL"
}
13 changes: 9 additions & 4 deletions web/src/utils/test-utils.tsx
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import { createMemoryHistory, MemoryHistory } from "history";
import { ServerStatusProvider } from "contexts/serverStatusContext";
import { ThemeProvider } from "@material-ui/core";
import theme from "theme";
import { ModalProvider } from "contexts";

export function render(
ui: React.ReactNode,
@@ -13,7 +14,9 @@ export function render(
return {
...rtlRender(
<ThemeProvider theme={theme}>
<Router history={history}>{ui}</Router>
<ModalProvider>
<Router history={history}>{ui}</Router>
</ModalProvider>
</ThemeProvider>
),
history
@@ -34,9 +37,11 @@ export function renderWithRouterMatch(
return {
...rtlRender(
<ServerStatusProvider>
<Router history={history}>
<Route path={path}>{ui}</Route>
</Router>
<ModalProvider>
<Router history={history}>
<Route path={path}>{ui}</Route>
</Router>
</ModalProvider>
</ServerStatusProvider>
)
};

0 comments on commit c7cff61

Please sign in to comment.