Skip to content

Commit

Permalink
fix(create secret): create secret using backend endpoint (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
elysee15 authored Aug 5, 2021
1 parent 78f4063 commit a7343e3
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 75 deletions.
68 changes: 9 additions & 59 deletions src/components/CreateSecretForm.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,13 @@
import { Button, makeStyles, Theme, Typography } from "@material-ui/core";
import { Button, Typography } from "@material-ui/core";
import { TextField, Switch } from "formik-material-ui";
import { Field, Form, Formik } from "formik";
import { Autocomplete, AutocompleteRenderInputParams } from "formik-material-ui-lab";
import { TextField as MuiTextField } from "@material-ui/core";
import * as Yup from "yup";
import { Lifetime } from "utils/interfaces";
import { useEffect } from "react";

const useStyles = makeStyles((theme: Theme) => ({
form: {
display: "flex",
flexDirection: "column",
gap: theme.spacing(2),
maxWidth: 400,
margin: "auto",
"& .MuiTextField-root": {
width: "100%"
}
},
height__full: {
height: "100%"
},
hide: {
display: "none"
}
}));
import { CreateSecretFormProps } from "types/CreateSecretFormProps";
import { preventNonNumericalInput } from "utils/utils";
import { useStyles } from "styles/createSecretFormStyles";

const options: Lifetime[] = [
{ value: "5m", label: "5 min" },
Expand All @@ -39,50 +22,17 @@ const options: Lifetime[] = [
{ value: "168h", label: "7 days" }
];

const initialValues = {
secret: "",
password: "",
accessType: true,
accessNumber: 1,
lifetime: { value: "7d", label: "7 days" }
};

const CreateSecretSchema = Yup.object().shape({
secret: Yup.string().required("You must add a secret"),
password: Yup.string(),
lifetime: Yup.object().shape({ value: Yup.string(), label: Yup.string() }).nullable(),
accessType: Yup.boolean(),
accessNumber: Yup.number().max(108, "The max number is 108")
});

const CreateSecretForm: React.FC = () => {
const CreateSecretForm: React.FC<CreateSecretFormProps> = props => {
const classes = useStyles();

function preventNonNumericalInput(e: any) {
e = e || window.event;
const charCode = typeof e.which == "undefined" ? e.keyCode : e.which;
const charStr = String.fromCharCode(charCode);

if (!charStr.match(/^[0-9]+$/)) e.preventDefault();
}

return (
<Formik
initialValues={initialValues}
validationSchema={CreateSecretSchema}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
setSubmitting(false);
alert(JSON.stringify(values, null, 2));
}, 200);
}}
>
<Formik initialValues={props.initialValues} validationSchema={props.validationSchema} onSubmit={props.onSubmit}>
{({ isSubmitting, errors, values, setFieldValue }) => {
useEffect(() => {
if (values.accessType) {
setFieldValue("accessNumber", -1);
setFieldValue("accesses", -1);
} else {
setFieldValue("accessNumber", 1);
setFieldValue("accesses", 1);
}
}, [values.accessType]);

Expand Down Expand Up @@ -122,7 +72,7 @@ const CreateSecretForm: React.FC = () => {
component={TextField}
type="number"
label="Number of access"
name="accessNumber"
name="accesses"
size="small"
variant="outlined"
pattern="[0-9]*"
Expand Down
94 changes: 79 additions & 15 deletions src/pages/CreateSecret.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,92 @@
import React from "react";
import { Grid, makeStyles, Theme } from "@material-ui/core";
import React, { useState } from "react";
import { Grid } from "@material-ui/core";
import CreateSecretForm from "components/CreateSecretForm";
import createSecret from "services/createSecret";
import { Secret } from "utils/interfaces/Secret";
import { FormikHelpers, FormikValues } from "formik";
import { AxiosError, AxiosResponse } from "axios";
import * as Yup from "yup";
import { useStyles } from "styles/createSecretStyles";
import { Alert, Color } from "@material-ui/lab";
import { Lifetime } from "utils/interfaces";

const useStyles = makeStyles((theme: Theme) => ({
root: {
flexGrow: 1,
padding: theme.spacing(2)
},
h__full: {
height: "100%"
},
w__full: {
width: "100%"
}
}));
const CreateSecretSchema = Yup.object().shape({
secret: Yup.string().required("You must add a secret"),
password: Yup.string(),
lifetime: Yup.object().shape({ value: Yup.string(), label: Yup.string() }).nullable(),
accessType: Yup.boolean(),
accesses: Yup.number().max(108, "The max number is 108")
});

interface Values {
secret: string;
password: string;
accessType: boolean;
accesses: number;
lifetime: Lifetime;
}

const initialValues: Values = {
secret: "",
password: "",
accessType: true,
accesses: 1,
lifetime: { value: "168h", label: "7 days" }
};

const CreateSecret: React.FC = () => {
const [, setToken] = useState<{ token: string; expires: Date }>();
const [message, setMessage] = useState<{ status?: Color; message?: string }>({
status: undefined,
message: undefined
});
const classes = useStyles();

function handleSubmit(values: FormikValues, helpers: FormikHelpers<Values>) {
const data: Secret = {
lifetime: values.lifetime.value,
secret: values.secret,
password: values.password,
accesses: values.accesses,
filename: values.filename || "",
is_base64: false
};

createSecret(data).then(
(response: AxiosResponse) => {
setToken(response.data);

helpers.setSubmitting(false);
},
(error: AxiosError) => {
console.error("[error when creating secret]", error.message);
setMessage({ status: "error", message: error.message });

setTimeout(() => {
setMessage({ status: undefined, message: undefined });
}, 5000);

helpers.setSubmitting(false);
}
);
}

return (
<div className={classes.root}>
<Grid container alignItems="center" className={classes.h__full}>
<Grid item sm={12} md={12} className={classes.w__full}>
<CreateSecretForm />
<Alert
severity={message.status}
className={classes.alert}
style={{ visibility: message.message ? "visible" : "hidden" }}
>
{message.message}
</Alert>
<CreateSecretForm
onSubmit={handleSubmit}
initialValues={initialValues}
validationSchema={CreateSecretSchema}
/>
</Grid>
</Grid>
</div>
Expand Down
7 changes: 7 additions & 0 deletions src/services/createSecret.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AxiosPromise, AxiosRequestConfig } from "axios";
import client from "config";
import { Secret } from "utils/interfaces/Secret";

export default function createSecret(data: Secret, config: AxiosRequestConfig = {}): AxiosPromise {
return client.post("/secrets", data, config);
}
20 changes: 20 additions & 0 deletions src/styles/createSecretFormStyles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { makeStyles, Theme } from "@material-ui/core";

export const useStyles = makeStyles((theme: Theme) => ({
form: {
display: "flex",
flexDirection: "column",
gap: theme.spacing(2),
maxWidth: 400,
margin: "auto",
"& .MuiTextField-root": {
width: "100%"
}
},
height__full: {
height: "100%"
},
hide: {
display: "none"
}
}));
24 changes: 24 additions & 0 deletions src/styles/createSecretStyles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { makeStyles, Theme } from "@material-ui/core";

export const useStyles = makeStyles((theme: Theme) => ({
root: {
flexGrow: 1,
padding: theme.spacing(2)
},
h__full: {
height: "100%"
},
w__full: {
width: "100%",
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)"
},
alert: {
maxWidth: 400,
margin: "0 auto",
boxSizing: "border-box",
marginBottom: "1rem"
}
}));
3 changes: 3 additions & 0 deletions src/styles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * as createSecretStyles from "./createSecretStyles";
export * as footerStyles from "./footerStyles";
export * as createSecretFormStyles from "./createSecretFormStyles";
8 changes: 8 additions & 0 deletions src/types/CreateSecretFormProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { FormikHelpers, FormikValues } from "formik";
import { ObjectSchema } from "yup";

export type CreateSecretFormProps = {
onSubmit: (values: FormikValues, helpers: FormikHelpers<any>) => void;
validationSchema: ObjectSchema<any>;
initialValues: FormikValues;
};
4 changes: 3 additions & 1 deletion src/utils/interfaces/Lifetime.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export type LifetimeValue = "5m" | "15m" | "30m" | "1h" | "2h" | "3h" | "24h" | "48h" | "72h" | "168h";

export interface Lifetime {
label: string;
value: string;
value: LifetimeValue;
}
8 changes: 8 additions & 0 deletions src/utils/interfaces/Secret.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface Secret {
secret: string;
password: string;
accesses: number;
lifetime: string;
filename?: string;
is_base64: false;
}
10 changes: 10 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Form } from "formik";

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function preventNonNumericalInput(e: React.KeyboardEvent<typeof Form>) {
e = e || window.event;
const charCode = typeof e.which == "undefined" ? e.keyCode : e.which;
const charStr = String.fromCharCode(charCode);

if (!charStr.match(/^[0-9]+$/)) e.preventDefault();
}

0 comments on commit a7343e3

Please sign in to comment.