From 00329478267351fc3cc73b228586ca7135ae12be Mon Sep 17 00:00:00 2001 From: Gabriel Silva Hermida <gash18@inf.ufpr.br> Date: Mon, 22 Jun 2020 13:27:57 -0300 Subject: [PATCH] Issue #7: Criar tela de editar formularios Signed-off-by: Gabriel Silva Hermida <gash18@inf.ufpr.br> --- src/App.js | 3 +- .../utils/BackendTranslation.js | 105 ---- .../DefaultField.js | 10 +- .../fieldsDisplayForm/DisplayForm.js | 201 +++++++ .../FieldFooterOptions.js | 7 +- .../FormFieldCheckbox.js | 20 +- .../FormFieldRadio.js | 19 +- .../FormFieldSelect.js | 20 +- .../FormFieldSubform.js | 19 +- .../FormFieldText.js | 23 +- .../FormFieldTitle.js | 24 +- .../SideMenu.js | 37 +- .../fieldsDisplayForm/SubmitButton.js | 62 +++ .../utils/BackendTranslation.js | 108 ++++ .../utils/FormComposition.js | 205 +++++++ .../utils/FrontEndTranslation.js | 89 +++ .../utils/schemas.js | 16 +- src/components/fieldsListForms/CardForm.jsx | 4 +- src/components/header/header.jsx | 3 - src/contexts/FormContext.js | 48 ++ src/contexts/useForm.js | 338 ++++++++++++ src/pages/CreateForm.js | 514 +----------------- src/pages/EditForm.js | 11 + src/pages/SignUp.js | 56 +- 24 files changed, 1205 insertions(+), 737 deletions(-) delete mode 100644 src/components/fieldsCreateForm/utils/BackendTranslation.js rename src/components/{fieldsCreateForm => fieldsDisplayForm}/DefaultField.js (73%) create mode 100644 src/components/fieldsDisplayForm/DisplayForm.js rename src/components/{fieldsCreateForm => fieldsDisplayForm}/FieldFooterOptions.js (82%) rename src/components/{fieldsCreateForm => fieldsDisplayForm}/FormFieldCheckbox.js (90%) rename src/components/{fieldsCreateForm => fieldsDisplayForm}/FormFieldRadio.js (90%) rename src/components/{fieldsCreateForm => fieldsDisplayForm}/FormFieldSelect.js (88%) rename src/components/{fieldsCreateForm => fieldsDisplayForm}/FormFieldSubform.js (90%) rename src/components/{fieldsCreateForm => fieldsDisplayForm}/FormFieldText.js (91%) rename src/components/{fieldsCreateForm => fieldsDisplayForm}/FormFieldTitle.js (74%) rename src/components/{fieldsCreateForm => fieldsDisplayForm}/SideMenu.js (84%) create mode 100644 src/components/fieldsDisplayForm/SubmitButton.js create mode 100644 src/components/fieldsDisplayForm/utils/BackendTranslation.js create mode 100644 src/components/fieldsDisplayForm/utils/FormComposition.js create mode 100644 src/components/fieldsDisplayForm/utils/FrontEndTranslation.js rename src/components/{fieldsCreateForm => fieldsDisplayForm}/utils/schemas.js (93%) create mode 100644 src/contexts/FormContext.js create mode 100644 src/contexts/useForm.js create mode 100644 src/pages/EditForm.js diff --git a/src/App.js b/src/App.js index a11c029..f909603 100644 --- a/src/App.js +++ b/src/App.js @@ -8,13 +8,14 @@ import Footer from "./components/footer/footer"; import SignUp from "./pages/SignUp"; import SignIn from "./pages/SignIn"; import ListForms from "./pages/ListForms"; - +import EditForm from "./pages/EditForm"; function App() { return ( <HashRouter> <Header /> <Route path="/create" component={CreateForm} /> <Route path="/answer/:id" component={AnswerForm} /> + <Route path="/edit/:id" component={EditForm} /> <Route path="/SignUp" component={SignUp} /> <Route path="/SignIn" component={SignIn} /> <Route path="/list/:id" component={ListForms} /> diff --git a/src/components/fieldsCreateForm/utils/BackendTranslation.js b/src/components/fieldsCreateForm/utils/BackendTranslation.js deleted file mode 100644 index 698eee3..0000000 --- a/src/components/fieldsCreateForm/utils/BackendTranslation.js +++ /dev/null @@ -1,105 +0,0 @@ -/** Functions that create the json object to be sent to the backend. */ - -/** Function that pushes the 'translated' object into the new array, wich will be sent to the backend. */ -function setInput(form, index, json, sugestions, validation, subForm, type) { - //the case when the input has a subform -> backend requires it to be different - if (subForm) { - json.inputs.push({ - placement: index, - description: form.description, - question: form.question, - type: type, - validation: validation, - sugestions: sugestions, - subForm: subForm, - }); - } else { - json.inputs.push({ - placement: index, - description: form.description, - question: form.question, - type: type, - validation: validation, - sugestions: sugestions, - }); - } -} - -/** Returns the type of the question as the backend padronization. */ -function getType(stringified_type) { - switch (stringified_type) { - case "question": - return 0; - case "select": - return 3; - case "radio": - return 2; - case "checkbox": - return 1; - case "subForm": - return 4; - default: - return -1; - } -} -/** Translates the 'options' array to the backend padronization. */ -function setSugestions(sugestions) { - let tmp = []; - if (!sugestions) return tmp; - sugestions.forEach((value, index) => { - tmp.push({ - value: value, - placement: index, - }); - }); - return tmp; -} - -/** Sets the validation field to be sent to the backend. */ -function setValidation(form) { - if (!form.validation[0].value) return []; - let val = []; - if (form.type === "checkbox") - val.push({ - type: 6, - arguments: [], - }); - else if (form.type === "question" && form.validation.length > 1) { - val.push({ - type: form.validation[1].type, - arguments: [form.validation[1].value], - }); - } else - val.push({ - type: 2, - arguments: [], - }); - return val; -} -/** Set the subform as the backend padronization. */ -function setSubform(form, idq) { - if (form.type !== "subForm") return null; - return { - contentFormId: form.subformId, - }; -} -/** The function that triggers the 'translation' */ -export default function createForm(form) { - let json = { - title: form[0].title, - description: form[0].description, - inputs: [], - }; - for (var i = 1; i < form.length; i++) { - setInput( - form[i], - i, - json, - setSugestions(form[i].options), - setValidation(form[i]), - setSubform(form[i], i), - getType(form[i].type) - ); - } - return json; -} diff --git a/src/components/fieldsCreateForm/DefaultField.js b/src/components/fieldsDisplayForm/DefaultField.js similarity index 73% rename from src/components/fieldsCreateForm/DefaultField.js rename to src/components/fieldsDisplayForm/DefaultField.js index 258abf4..5c2c127 100644 --- a/src/components/fieldsCreateForm/DefaultField.js +++ b/src/components/fieldsDisplayForm/DefaultField.js @@ -2,6 +2,7 @@ import React from "react"; import { makeStyles } from "@material-ui/core/styles"; import Grid from "@material-ui/core/Grid"; import TextField from "@material-ui/core/TextField"; +import useForm from "../../contexts/useForm"; const useStyles = makeStyles((theme) => ({ questionsGrid: { marginBottom: "20px", @@ -16,9 +17,12 @@ const useStyles = makeStyles((theme) => ({ width: "80%", }, })); - +/** Function that returns the question and description components. */ export default function DefaultField(props) { + /** Style class. */ const classes = useStyles(); + /** Importing functions to set question and description fields values. */ + const { setQuestionField, setDescriptionField } = useForm(); return ( <> <Grid item xs={12} sm={6} className={classes.questionsGrid}> @@ -26,7 +30,7 @@ export default function DefaultField(props) { value={props.question} label="Pergunta" className={classes.textFieldStyle} - onChange={(e) => props.setQuestionField(e.target.value, props.idq)} + onChange={(e) => setQuestionField(e.target.value, props.idq)} /> <Grid className={classes.errorGrid}> {props.error.errorMsg.question} @@ -37,7 +41,7 @@ export default function DefaultField(props) { value={props.description} label="Descrição" className={classes.textFieldStyle} - onChange={(e) => props.setDescriptionField(e.target.value, props.idq)} + onChange={(e) => setDescriptionField(e.target.value, props.idq)} /> <Grid className={classes.errorGrid}> {props.error.errorMsg.description} diff --git a/src/components/fieldsDisplayForm/DisplayForm.js b/src/components/fieldsDisplayForm/DisplayForm.js new file mode 100644 index 0000000..6591e03 --- /dev/null +++ b/src/components/fieldsDisplayForm/DisplayForm.js @@ -0,0 +1,201 @@ +import React, { useState, useEffect, useContext } from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import { DragDropContext, Droppable } from "react-beautiful-dnd"; +import { createMuiTheme, MuiThemeProvider } from "@material-ui/core"; +import FormFieldText from "./FormFieldText"; +import FormFieldSelect from "./FormFieldSelect"; +import FormFieldRadio from "./FormFieldRadio"; +import FormFieldCheckbox from "./FormFieldCheckbox"; +import FormFieldTitle from "./FormFieldTitle"; +import FormFieldSubForm from "./FormFieldSubform"; +import uuid from "uuid/v4"; +import { verifyError } from "./utils/schemas"; +import SideMenu from "./SideMenu"; + +import { FormEditionContext } from "../../contexts/FormContext"; +import useForm from "../../contexts/useForm"; +import SubmitButton from "./SubmitButton"; +/** CSS styles used on page components */ +const useStyles = makeStyles((theme) => ({ + app: { + margin: "0", + padding: "40px", + display: "flex", + ["@media (max-width: 600px)"]: { + flexDirection: "column-reverse", + justifyContent: "flex-end", + }, + paddingBottom: "78px", + ["@media (min-width: 600px)"]: { + minHeight: "calc(100vh - 92.4px - 78px -60px)", + }, + minHeight: "calc(100vh - 71.6px - 78px -60px)", + marginBottom: "60px", + }, + addButton: { + fontSize: "100%", + }, + sideMenuFormatingGrid: { + ["@media (max-width:600px)"]: { + marginTop: "-90px", + }, + }, +})); +/** CSS style used through Material Ui. */ +const theme = createMuiTheme({ + overrides: { + MuiInput: { + underline: { + "&:before": { + borderBottom: "1px solid #35c7fc", + }, + "&:after": { + borderBottom: "1px solid #3f51b5", + }, + }, + }, + MuiButton: { + label: { + color: "white", + }, + }, + }, +}); +/** Main function that returns the children that composes the form creation or edition page. */ +function DisplayForm() { + /** Importing and using form state from the context */ + const { formState } = useContext(FormEditionContext); + const [form] = formState; + /** Style class. */ + const classes = useStyles(); + /** Importing the function to reorder the questions as consequence of drag'n'drop event */ + const { onDragEnd } = useForm(); + /** An unique string to be used as ID for drag and drop function. */ + const columnId = uuid(); + /** Error state. */ + const [validToSend, setValidToSend] = useState(); + + /** Error handling -> every time the form object is updated, it is verified to evaluate it's error messages, + * so the submit button can be enabled or disabled. + */ + useEffect(() => { + setValidToSend(verifyError(form)); + }, [form]); + return ( + <MuiThemeProvider theme={theme}> + <Grid className={classes.app}> + <Grid xs={12} sm={2} className={classes.sideMenuFormatingGrid}> + <SideMenu /> + </Grid> + <DragDropContext onDragEnd={onDragEnd}> + <Grid + dragOver + container + xs={12} + sm={8} + direction="column" + alignItems="center" + > + <Droppable droppableId={columnId}> + {(provided, snapshot) => { + return ( + <Grid {...provided.droppableProps} ref={provided.innerRef}> + {form ? ( + form.map((x, index) => { + if (x.type === 0) + return ( + <FormFieldText + question={x.question} + idq={index} + description={x.description} + id={x.id} + error={x.error} + validation={x.validation} + validationValue={ + x.validation[1] ? x.validation[1].value : null + } + validationType={ + x.validation[1] ? x.validation[1].type : null + } + /> + ); + else if (x.type === 3) + return ( + <FormFieldSelect + question={x.question} + options={x.options} + idq={index} + description={x.description} + validation={x.validation} + id={x.id} + error={x.error} + /> + ); + else if (x.type === 2) + return ( + <FormFieldRadio + question={x.question} + options={x.options} + idq={index} + description={x.description} + validation={x.validation} + id={x.id} + error={x.error} + /> + ); + else if (x.type === 1) + return ( + <FormFieldCheckbox + question={x.question} + options={x.options} + idq={index} + description={x.description} + validation={x.validation} + id={x.id} + error={x.error} + /> + ); + else if (x.type === 4) + return ( + <FormFieldSubForm + question={x.question} + idq={index} + description={x.description} + validation={x.validation} + id={x.id} + error={x.error} + validToSend={validToSend} + subformId={x.subformId ? x.subformId : null} + /> + ); + else if (x.type === "title") + return ( + <FormFieldTitle + question={x.question} + description={x.description} + idq={index} + error={x.error} + /> + ); + }) + ) : ( + <p> carregando... </p> + )} + {provided.placeholder} + </Grid> + ); + }} + </Droppable> + <SubmitButton + validToSend={validToSend} + formId={form ? (form[0] ? form[0].id : false) : false} + /> + </Grid> + </DragDropContext> + </Grid> + </MuiThemeProvider> + ); +} + +export default DisplayForm; diff --git a/src/components/fieldsCreateForm/FieldFooterOptions.js b/src/components/fieldsDisplayForm/FieldFooterOptions.js similarity index 82% rename from src/components/fieldsCreateForm/FieldFooterOptions.js rename to src/components/fieldsDisplayForm/FieldFooterOptions.js index 8890267..b7a8b91 100644 --- a/src/components/fieldsCreateForm/FieldFooterOptions.js +++ b/src/components/fieldsDisplayForm/FieldFooterOptions.js @@ -6,9 +6,12 @@ import IconButton from "@material-ui/core/IconButton"; import Switch from "@material-ui/core/Switch"; import FormControlLabel from "@material-ui/core/FormControlLabel"; import Tooltip from "@material-ui/core/Tooltip"; +import useForm from "../../contexts/useForm"; /** Main function that return the component's 'footer' options, handling the required validation and deleting the field as necessary. */ function FieldFooterOptions(props) { + /** Importing functions to set a question as required and to delete the question. */ + const { setRequiredField, deleteFromForm } = useForm(); return ( <Grid> <FormControlLabel @@ -18,7 +21,7 @@ function FieldFooterOptions(props) { aria-label="Marcar como obrigatório" > <Switch - onChange={(e) => props.setRequiredField(props.idq)} + onChange={(e) => setRequiredField(props.idq)} value="required" color="primary" checked={props.required} @@ -32,7 +35,7 @@ function FieldFooterOptions(props) { <IconButton aria-label="Remover a pergunta" onClick={() => { - props.deleteFromForm(props.idq); + deleteFromForm(props.idq); }} > <DeleteOutlinedIcon /> diff --git a/src/components/fieldsCreateForm/FormFieldCheckbox.js b/src/components/fieldsDisplayForm/FormFieldCheckbox.js similarity index 90% rename from src/components/fieldsCreateForm/FormFieldCheckbox.js rename to src/components/fieldsDisplayForm/FormFieldCheckbox.js index fc8d1ba..a35fe25 100644 --- a/src/components/fieldsCreateForm/FormFieldCheckbox.js +++ b/src/components/fieldsDisplayForm/FormFieldCheckbox.js @@ -11,6 +11,7 @@ import Tooltip from "@material-ui/core/Tooltip"; import FieldFooterOptions from "./FieldFooterOptions"; import { Draggable } from "react-beautiful-dnd"; import DefaultField from "./DefaultField"; +import useForm from "../../contexts/useForm"; /** CSS styles used on page components. */ const useStyles = makeStyles((theme) => ({ @@ -46,7 +47,10 @@ const useStyles = makeStyles((theme) => ({ })); /** Main function that returns the 'checkbox' field. */ function FormFieldCheckbox(props) { + /** Style class. */ const classes = useStyles(); + /** Importing functions to add, remove and set Options and its value. */ + const { setSelectOption, removeSelectOption, addSelectOption } = useForm(); return ( <Draggable key={props.id} draggableId={props.id} index={props.idq}> @@ -63,8 +67,6 @@ function FormFieldCheckbox(props) { question={props.question} description={props.description} idq={props.idq} - setQuestionField={props.setQuestionField} - setDescriptionField={props.setDescriptionField} error={props.error} /> <Grid @@ -100,11 +102,7 @@ function FormFieldCheckbox(props) { value={x} className={classes.textFieldStyle} onChange={(e) => - props.setSelectOption( - e.target.value, - props.idq, - index - ) + setSelectOption(e.target.value, props.idq, index) } /> <Grid @@ -123,7 +121,7 @@ function FormFieldCheckbox(props) { <IconButton aria-label="remove option" onClick={() => { - props.removeSelectOption(props.idq, index); + removeSelectOption(props.idq, index); }} > <CloseIcon /> @@ -141,7 +139,7 @@ function FormFieldCheckbox(props) { direction="column" justify="flex-start" alignItems="flex-start" - sm={4} //antes era 3 + sm={4} xs={12} > {props.error.errorMsg.optionsNumber} @@ -160,7 +158,7 @@ function FormFieldCheckbox(props) { <IconButton aria-label="add option" onClick={() => { - props.addSelectOption(props.idq); + addSelectOption(props.idq); }} > <AddCircleIcon /> @@ -177,9 +175,7 @@ function FormFieldCheckbox(props) { xs={12} > <FieldFooterOptions - deleteFromForm={props.deleteFromForm} idq={props.idq} - setRequiredField={props.setRequiredField} required={props.validation[0].value} /> </Grid> diff --git a/src/components/fieldsCreateForm/FormFieldRadio.js b/src/components/fieldsDisplayForm/FormFieldRadio.js similarity index 90% rename from src/components/fieldsCreateForm/FormFieldRadio.js rename to src/components/fieldsDisplayForm/FormFieldRadio.js index 9518569..9abb836 100644 --- a/src/components/fieldsCreateForm/FormFieldRadio.js +++ b/src/components/fieldsDisplayForm/FormFieldRadio.js @@ -11,6 +11,7 @@ import Tooltip from "@material-ui/core/Tooltip"; import { Draggable } from "react-beautiful-dnd"; import FieldFooterOptions from "./FieldFooterOptions"; import DefaultField from "./DefaultField"; +import useForm from "../../contexts/useForm"; /** CSS styles used on page components. */ const useStyles = makeStyles((theme) => ({ @@ -46,8 +47,10 @@ const useStyles = makeStyles((theme) => ({ })); /** Main function that returns the 'radio' field. */ function FormFieldRadio(props) { + /** Style clas. */ const classes = useStyles(); - + /** Importing functions to add, remove and set Options and its value. */ + const { setSelectOption, removeSelectOption, addSelectOption } = useForm(); return ( <Draggable key={props.id} draggableId={props.id} index={props.idq}> {(provided, snapshot) => { @@ -63,8 +66,6 @@ function FormFieldRadio(props) { question={props.question} description={props.description} idq={props.idq} - setQuestionField={props.setQuestionField} - setDescriptionField={props.setDescriptionField} error={props.error} /> <Grid @@ -100,11 +101,7 @@ function FormFieldRadio(props) { value={x} className={classes.textFieldStyle} onChange={(e) => - props.setSelectOption( - e.target.value, - props.idq, - index - ) + setSelectOption(e.target.value, props.idq, index) } /> <Grid @@ -122,7 +119,7 @@ function FormFieldRadio(props) { > <IconButton onClick={() => { - props.removeSelectOption(props.idq, index); + removeSelectOption(props.idq, index); }} > <CloseIcon /> @@ -159,7 +156,7 @@ function FormFieldRadio(props) { <IconButton aria-label="adicionar opção" onClick={() => { - props.addSelectOption(props.idq); + addSelectOption(props.idq); }} > <AddCircleIcon /> @@ -176,9 +173,7 @@ function FormFieldRadio(props) { sm={6} > <FieldFooterOptions - deleteFromForm={props.deleteFromForm} idq={props.idq} - setRequiredField={props.setRequiredField} required={props.validation[0].value} /> </Grid> diff --git a/src/components/fieldsCreateForm/FormFieldSelect.js b/src/components/fieldsDisplayForm/FormFieldSelect.js similarity index 88% rename from src/components/fieldsCreateForm/FormFieldSelect.js rename to src/components/fieldsDisplayForm/FormFieldSelect.js index 7555ef5..1ae1057 100644 --- a/src/components/fieldsCreateForm/FormFieldSelect.js +++ b/src/components/fieldsDisplayForm/FormFieldSelect.js @@ -10,6 +10,7 @@ import Tooltip from "@material-ui/core/Tooltip"; import FieldFooterOptions from "./FieldFooterOptions"; import { Draggable } from "react-beautiful-dnd"; import DefaultField from "./DefaultField"; +import useForm from "../../contexts/useForm"; /** CSS styles used on page components. */ const useStyles = makeStyles((theme) => ({ @@ -50,6 +51,8 @@ const useStyles = makeStyles((theme) => ({ function FormFieldSelect(props) { /** Style class. */ const classes = useStyles(); + /** Importing functions to add, remove and set Options and its value. */ + const { setSelectOption, removeSelectOption, addSelectOption } = useForm(); return ( <Draggable key={props.id} draggableId={props.id} index={props.idq}> {(provided, snapshot) => { @@ -65,8 +68,6 @@ function FormFieldSelect(props) { question={props.question} description={props.description} idq={props.idq} - setQuestionField={props.setQuestionField} - setDescriptionField={props.setDescriptionField} error={props.error} /> <Grid @@ -82,25 +83,20 @@ function FormFieldSelect(props) { {props.options.map((x, index) => { return ( <Grid container> - <Grid itemxs={1}></Grid> <Grid item xs={10}> <TextField label={"Opção " + index} value={x} className={classes.textFieldStyle} onChange={(e) => - props.setSelectOption( - e.target.value, - props.idq, - index - ) + setSelectOption(e.target.value, props.idq, index) } /> <Grid item className={classes.errorGridOpts}> {props.error.errorMsg.options[index]} </Grid> </Grid> - <Grid item xs={1}> + <Grid item xs={2}> <Tooltip title="Remover a opção" aria-label="Remover a opção" @@ -108,7 +104,7 @@ function FormFieldSelect(props) { <IconButton aria-label="remove option" onClick={() => { - props.removeSelectOption(props.idq, index); + removeSelectOption(props.idq, index); }} > <CloseIcon /> @@ -145,7 +141,7 @@ function FormFieldSelect(props) { <IconButton aria-label="add option" onClick={() => { - props.addSelectOption(props.idq); + addSelectOption(props.idq); }} > <AddCircleIcon /> @@ -162,9 +158,7 @@ function FormFieldSelect(props) { xs={12} > <FieldFooterOptions - deleteFromForm={props.deleteFromForm} idq={props.idq} - setRequiredField={props.setRequiredField} required={props.validation[0].value} /> </Grid> diff --git a/src/components/fieldsCreateForm/FormFieldSubform.js b/src/components/fieldsDisplayForm/FormFieldSubform.js similarity index 90% rename from src/components/fieldsCreateForm/FormFieldSubform.js rename to src/components/fieldsDisplayForm/FormFieldSubform.js index e04e839..08d4201 100644 --- a/src/components/fieldsCreateForm/FormFieldSubform.js +++ b/src/components/fieldsDisplayForm/FormFieldSubform.js @@ -10,6 +10,7 @@ import FormControl from "@material-ui/core/FormControl"; import InputLabel from "@material-ui/core/InputLabel"; import { Draggable } from "react-beautiful-dnd"; import DefaultField from "./DefaultField"; +import useForm from "../../contexts/useForm"; /** CSS styles used on page components. */ const useStyles = makeStyles((theme) => ({ @@ -65,14 +66,15 @@ const useStyles = makeStyles((theme) => ({ function SubformSelect(props) { /** Style class. */ const classes = useStyles(); + /** Importing function to save the chosen form id as a subform. */ + const { setSubformId } = useForm(); /** Functions that handle the input changes to save it at the father component. */ const handleChange = (event) => { - props.setSubformId(event.target.value, props.idq); + setSubformId(event.target.value, props.idq); }; return ( <FormControl variant="outlined" className={classes.subformSelect}> <InputLabel - // style={{ fontSize: "5px" }} className={classes.subformSelect} id="demo-simple-select-outlined-label" htmlFor="outlined-subform-simple" @@ -95,10 +97,10 @@ function SubformSelect(props) { </MenuItem> )) ) : ( - <MenuItem key={0} value={0} disabled> - {"Você não tem formulários para usar aqui"} - </MenuItem> - )} + <MenuItem key={0} value={0} disabled> + {"Você não tem formulários para usar aqui"} + </MenuItem> + )} </Select> </FormControl> ); @@ -137,8 +139,6 @@ export default function FormFieldSubform(props) { question={props.question} description={props.description} idq={props.idq} - setQuestionField={props.setQuestionField} - setDescriptionField={props.setDescriptionField} error={props.error} /> </Grid> @@ -150,7 +150,6 @@ export default function FormFieldSubform(props) { idq={props.idq} error={props.error} subformId={props.subformId} - subformId={props.subformId} /> </Grid> <Grid item sm={2} xs={12} className={classes.errorGridSubform}> @@ -167,9 +166,7 @@ export default function FormFieldSubform(props) { className={classes.footerOptsAdjustment} > <FieldFooterOptions - deleteFromForm={props.deleteFromForm} idq={props.idq} - setRequiredField={props.setRequiredField} required={props.validation[0].value} /> </Grid> diff --git a/src/components/fieldsCreateForm/FormFieldText.js b/src/components/fieldsDisplayForm/FormFieldText.js similarity index 91% rename from src/components/fieldsCreateForm/FormFieldText.js rename to src/components/fieldsDisplayForm/FormFieldText.js index 18b4750..595841d 100644 --- a/src/components/fieldsCreateForm/FormFieldText.js +++ b/src/components/fieldsDisplayForm/FormFieldText.js @@ -14,6 +14,7 @@ import { Draggable } from "react-beautiful-dnd"; import FieldFooterOptions from "./FieldFooterOptions"; import DefaultField from "./DefaultField"; import CloseIcon from "@material-ui/icons/Close"; +import useForm from "../../contexts/useForm"; /** CSS styles used on page components. */ const useStyles = makeStyles((theme) => ({ @@ -60,7 +61,13 @@ function FormFieldText(props) { { type: 3, name: "Mínimo de caracteres", value: "" }, { type: 4, name: "Máximo de caracteres", value: "" }, ]; - + /** Importing functions to add, remove and set validations and it's properties. */ + const { + setValidationType, + setValidationValue, + removeValidation, + addValidation, + } = useForm(); return ( <Draggable key={props.id} draggableId={props.id} index={props.idq}> {(provided, snapshot) => { @@ -76,8 +83,6 @@ function FormFieldText(props) { question={props.question} description={props.description} idq={props.idq} - setQuestionField={props.setQuestionField} - setDescriptionField={props.setDescriptionField} error={props.error} /> <Grid item xs={12} sm={8} className={classes.questionsGrid}> @@ -98,9 +103,7 @@ function FormFieldText(props) { sm={4} > <FieldFooterOptions - deleteFromForm={props.deleteFromForm} idq={props.idq} - setRequiredField={props.setRequiredField} required={props.validation[0].value} /> </Grid> @@ -119,7 +122,7 @@ function FormFieldText(props) { labelId="demo-simple-select-outlined-label" id="demo-simple-select-outlined" onChange={(event) => - props.setValidationType(event.target.value, props.idq) + setValidationType(event.target.value, props.idq) } value={props.validationType} label="Selecione uma validação" @@ -140,11 +143,11 @@ function FormFieldText(props) { label="Quantidade" value={props.validationValue} onChange={(event) => - props.setValidationValue(event.target.value, props.idq) + setValidationValue(event.target.value, props.idq) } /> <Grid className={classes.errorGrid}> - {props.error.errorMsg.validation.value} + {props.error.errorMsg.validationValue} </Grid> </Grid> ) : null} @@ -156,7 +159,7 @@ function FormFieldText(props) { <IconButton aria-label="remove validation" onClick={() => { - props.removeValidation(props.idq); + removeValidation(props.idq); }} > <CloseIcon /> @@ -179,7 +182,7 @@ function FormFieldText(props) { <IconButton aria-label="adicionar opção" onClick={() => { - props.addValidation(props.idq); + addValidation(props.idq); }} > <AddCircleIcon /> diff --git a/src/components/fieldsCreateForm/FormFieldTitle.js b/src/components/fieldsDisplayForm/FormFieldTitle.js similarity index 74% rename from src/components/fieldsCreateForm/FormFieldTitle.js rename to src/components/fieldsDisplayForm/FormFieldTitle.js index 2042a9c..ca1b0c0 100644 --- a/src/components/fieldsCreateForm/FormFieldTitle.js +++ b/src/components/fieldsDisplayForm/FormFieldTitle.js @@ -3,6 +3,7 @@ import { makeStyles } from "@material-ui/core/styles"; import Grid from "@material-ui/core/Grid"; import Paper from "@material-ui/core/Paper"; import TextField from "@material-ui/core/TextField"; +import useForm from "../../contexts/useForm"; /** CSS styles used on page components. */ const useStyles = makeStyles((theme) => ({ @@ -40,34 +41,43 @@ const useStyles = makeStyles((theme) => ({ function FormFieldText(props) { /** Style class. */ const classes = useStyles(); - + /** Importing functions to change the question and the description values. */ + const { setQuestionField, setDescriptionField } = useForm(); return ( <Paper className={classes.paper}> <TextField value={props.question} label="Título do formulário" fullWidth - onChange={(e) => props.setTitleField(e.target.value, props.idq)} + onChange={(e) => setQuestionField(e.target.value, props.idq)} InputProps={{ classes: { input: classes.title, }, }} /> - <Grid className={classes.errorGrid}>{props.error.errorMsg.question}</Grid> + {props.error ? ( + <Grid className={classes.errorGrid}> + {props.error.errorMsg.question} + </Grid> + ) : null} + <Grid item xs={9} className={classes.questionsGrid}> <TextField + value={props.description} label="Descrição do formulário" - onChange={(e) => props.setDescriptionField(e.target.value, props.idq)} + onChange={(e) => setDescriptionField(e.target.value, props.idq)} InputProps={{ classes: { input: classes.description, }, }} /> - <Grid className={classes.errorGrid}> - {props.error.errorMsg.description} - </Grid> + {props.error ? ( + <Grid className={classes.errorGrid}> + {props.error.errorMsg.description} + </Grid> + ) : null} </Grid> <Grid item diff --git a/src/components/fieldsCreateForm/SideMenu.js b/src/components/fieldsDisplayForm/SideMenu.js similarity index 84% rename from src/components/fieldsCreateForm/SideMenu.js rename to src/components/fieldsDisplayForm/SideMenu.js index fb51492..1c5764c 100644 --- a/src/components/fieldsCreateForm/SideMenu.js +++ b/src/components/fieldsDisplayForm/SideMenu.js @@ -1,7 +1,5 @@ import React, { useState } from "react"; import Paper from "@material-ui/core/Paper"; -import TextField from "@material-ui/core/TextField"; -import AddIcon from "@material-ui/icons/Add"; import IconButton from "@material-ui/core/IconButton"; import ReorderIcon from "@material-ui/icons/Reorder"; import RadioButtonCheckedIcon from "@material-ui/icons/RadioButtonChecked"; @@ -10,14 +8,13 @@ import Grid from "@material-ui/core/Grid"; import { makeStyles } from "@material-ui/core"; import ListAltIcon from "@material-ui/icons/ListAlt"; import TextFieldsIcon from "@material-ui/icons/TextFields"; +import useForm from "../../contexts/useForm"; const useStyles = makeStyles((theme) => ({ addButton: { fontSize: "100%", }, outerGrid: { - // alignItems: "flex-start", - flexDirection: "column", ["@media(max-width: 600px)"]: { flexDirection: "row", @@ -40,7 +37,6 @@ const useStyles = makeStyles((theme) => ({ }, }, justifyContent: "flex-start", - // minWidth: "160.167px", }, newQuestionGrid: { marginTop: "5%", @@ -49,7 +45,6 @@ const useStyles = makeStyles((theme) => ({ display: "flex", flexDirection: "row", maxWidth: "190px", - // minWidth: "160.167px", height: "268.5", }, flex: {}, @@ -59,8 +54,14 @@ const useStyles = makeStyles((theme) => ({ }, }, })); -// fazer com que desca comforme a rolagem da página function SideMenu(props) { + const { + addToFormQuestion, + addToFormSelect, + addToFormRadio, + addToFormCheckbox, + addToFormSubform, + } = useForm(); const classes = useStyles(); return ( <Paper className={classes.paper}> @@ -68,13 +69,14 @@ function SideMenu(props) { <Grid className={classes.newQuestionGrid} container justify="center"> <h4>Adicionar pergunta:</h4> </Grid> - {/* <Grid> */} <IconButton aria-label="add select" type="submit" size="medium" className={classes.addButton} - onClick={props.addToFormQuestion} + onClick={() => { + addToFormQuestion(); + }} > <TextFieldsIcon /> Caixa de texto @@ -84,7 +86,9 @@ function SideMenu(props) { type="submit" size="medium" className={classes.addButton} - onClick={props.addToFormSelect} + onClick={() => { + addToFormSelect(); + }} > <ReorderIcon /> Lista Suspensa @@ -94,7 +98,9 @@ function SideMenu(props) { type="submit" size="medium" className={classes.addButton} - onClick={props.addToFormRadio} + onClick={() => { + addToFormRadio(); + }} > <RadioButtonCheckedIcon /> Múltipla escolha @@ -104,7 +110,9 @@ function SideMenu(props) { type="submit" size="medium" className={classes.addButton} - onClick={props.addToFormCheckbox} + onClick={() => { + addToFormCheckbox(); + }} > <CheckBoxOutlineBlankIcon /> Seleção Única @@ -114,13 +122,14 @@ function SideMenu(props) { type="submit" size="medium" className={classes.addButton} - onClick={props.addToFormSubForm} + onClick={() => { + addToFormSubform(); + }} > <ListAltIcon /> Subformulário </IconButton> </Grid> - {/* </Grid> */} </Paper> ); } diff --git a/src/components/fieldsDisplayForm/SubmitButton.js b/src/components/fieldsDisplayForm/SubmitButton.js new file mode 100644 index 0000000..528737a --- /dev/null +++ b/src/components/fieldsDisplayForm/SubmitButton.js @@ -0,0 +1,62 @@ +import React from "react"; +import Tooltip from "@material-ui/core/Tooltip"; +import Button from "@material-ui/core/Button"; +import useForm from "../../contexts/useForm"; +import { makeStyles } from "@material-ui/core"; + +const useStyles = makeStyles((theme) => ({ + buttonOk: { + minWidth: "92px", + backgroundColor: "#6ec46c", + "&:hover": { + backgroundColor: "rgb(25, 109, 23)", + }, + width: "20%", + ["@media (max-width:600px)"]: { + marginTop: "52px", + }, + }, + button: { + minWidth: "92px", + ["@media (max-width:600px)"]: { + marginTop: "52px", + }, + }, +})); +/** Main function that returns the button to submit the form, it may vary between a form creation and edition. + * @param formId - if an id is passed, then it's the edition operation that's being done. + */ +export default function SubmitButton({ validToSend, formId }) { + /** Importing the submit function. */ + const { submit } = useForm(); + /** Style class. */ + const classes = useStyles(); + /** Handling the variables between the creation and the edition screens */ + let submitMsg, + unabledMsg = + "Verifique se você criou pelo menos uma pergunta e se as perguntas estão propriamente construídas", + buttonLabel; + if (formId) { + submitMsg = "Submeter edição"; + buttonLabel = "Confirmar"; + } else { + submitMsg = "Criar seu formulário"; + buttonLabel = "Criar"; + } + + return ( + <Tooltip + title={validToSend ? submitMsg : unabledMsg} + aria-label={validToSend ? submitMsg : unabledMsg} + > + <Button + className={validToSend ? classes.buttonOk : classes.button} + variant="contained" + type="submit" + onClick={() => submit(validToSend)} + > + {buttonLabel} + </Button> + </Tooltip> + ); +} diff --git a/src/components/fieldsDisplayForm/utils/BackendTranslation.js b/src/components/fieldsDisplayForm/utils/BackendTranslation.js new file mode 100644 index 0000000..06687d9 --- /dev/null +++ b/src/components/fieldsDisplayForm/utils/BackendTranslation.js @@ -0,0 +1,108 @@ +/** Functions that create the json object to be sent to the backend. */ +import api from "../../../api"; +import { createFrontendForm } from "./FrontEndTranslation"; +/** Function that pushes the 'translated' object into the new array, wich will be sent to the backend. + * @param form - the form object; + * @param index - the position of the question inside the array, to be used as the placement. + * @param json - the object that will recieve the 'translation', to be sent to the bakcend; + * @param {sugestions, validation, subForm, type} - translated properties to be used on the backend object. + */ +function setInput( + form, + placement, + json, + sugestions, + validation, + subForm, + type, + id +) { + json.inputs.push({ + placement: placement, + description: form.description, + question: form.question, + type: type, + validation: validation, + sugestions: sugestions, + subForm: subForm ? subForm : null, + id: id, + }); +} + +/** Translates the 'options' array to the backend padronization. + * @param sugestions - the 'options' property from the frontend object; + */ +function setSugestions(sugestions) { + let tmp = []; + if (!sugestions) return tmp; + sugestions.forEach((value, index) => { + tmp.push({ + value: value, + placement: index, + }); + }); + return tmp; +} + +/** Sets the validation field to be sent to the backend. + * @param form - the form[i] position of the array. + */ +function setValidation(form) { + if (!form.validation[0].value && form.validation.length <= 1) return []; + let val = []; + if (form.type === 1) { + val.push({ + type: 6, + arguments: [], + }); + return val; + } + + if (form.validation[0].value) { + val.push({ + type: 2, + arguments: [], + }); + } + if (form.type === 0 && form.validation.length > 1) { + val.push({ + type: form.validation[1].type, + arguments: [form.validation[1].value], + }); + } + return val; +} +/** Set the subform as the backend padronization. + * @param form - the form[i] position of the array. + */ +function setSubform(form) { + if (form.type !== 4) return null; + return { + contentFormId: form.subformId, + }; +} + +/** The function that triggers the 'translation' + * @param form - the form[i] position of the array. + */ +export default async function createBackendForm(form) { + let json = { + id: form[0].id ? form[0].id : "", + title: form[0].question, + description: form[0].description, + inputs: [], + }; + for (var i = 1; i < form.length; i++) { + setInput( + form[i], + i, + json, + setSugestions(form[i].options), + setValidation(form[i]), + setSubform(form[i], i), + form[i].type, + form[i].inputId + ); + } + return json; +} diff --git a/src/components/fieldsDisplayForm/utils/FormComposition.js b/src/components/fieldsDisplayForm/utils/FormComposition.js new file mode 100644 index 0000000..b09b3e7 --- /dev/null +++ b/src/components/fieldsDisplayForm/utils/FormComposition.js @@ -0,0 +1,205 @@ +import uuid from "uuid/v4"; + +/** Function that pushes the title object into the form array. + * @param form - the form where the field will be pushed; + * @param title - the title; + * @param description - the description of the form. + */ +export function pushTitle(form, title, description, id) { + return form.push({ + type: "title", + question: title ? title : "", + description: description ? description : "", + id: id ? id : "", + error: { + errorMsg: { + question: title ? "" : "Este campo é obrigatório!", + description: "", + }, + }, + }); +} +/** Function that pushes a 'question' object into the form array. + * @param form - the form where the field will be pushed; + * @param question - the question; + * @param description - the description of the question; + * @param validation - optional validation the question may have. + */ +export function pushQuestion(form, question, description, validation, id) { + form.push({ + type: 0, + validation: validation ? validation : [{ type: "required", value: false }], + question: question ? question : "", + description: description ? description : "", + id: uuid(), + inputId: id ? id : null, + error: { + errorMsg: { + question: question ? "" : "Este campo é obrigatório!", + description: "", + validationValue: validation + ? validation[1] + ? validation[1].value + ? "" + : "Por favor, digite um número" + : "" + : "", + }, + }, + }); +} + +/** Function that pushes a 'select' object into the form array. + * @param form - the form where the field will be pushed; + * @param question - the question; + * @param description - the description of the question; + * @param options - the options array; + * @param validation - optional validation the question may have. + */ +export function pushSelect( + form, + question, + description, + options, + validation, + id +) { + let value = { + type: 3, + question: question ? question : "", + validation: validation ? validation : [{ type: "required", value: false }], + options: options ? options.map((x) => x.value) : [""], + description: description ? description : "", + id: uuid(), + inputId: id ? id : null, + error: { + errorMsg: { + question: question ? "" : "Este campo é obrigatório!", + description: "", + optionsNumber: options + ? options.length < 2 + ? "O campo precisa ter pelo menos duas opções!" + : "" + : "O campo precisa ter pelo menos duas opções!", + options: options + ? options.map((x) => (x = "")) + : ["Por favor, preencha esta opção"], + }, + }, + }; + return form.push(value); +} + +/** Function that pushes a 'radio' object into the form array. + * @param form - the form where the field will be pushed; + * @param question - the question; + * @param description - the description of the question; + * @param options - the options array; + * @param validation - optional validation the question may have. + */ +export function pushRadio( + form, + question, + description, + options, + validation, + id +) { + let value = { + type: 2, + question: question ? question : "", + validation: validation ? validation : [{ type: "required", value: false }], + options: options ? options.map((x) => x.value) : [""], + description: description ? description : "", + id: uuid(), + inputId: id ? id : null, + error: { + errorMsg: { + question: question ? "" : "Este campo é obrigatório!", + description: "", + optionsNumber: options + ? options.length < 2 + ? "O campo precisa ter pelo menos duas opções!" + : "" + : "O campo precisa ter pelo menos duas opções!", + options: options + ? options.map((x) => (x = "")) + : ["Por favor, preencha esta opção"], + }, + }, + }; + return form.push(value); +} + +/** Function that pushes a 'checkbox' object into the form array. + * @param form - the form where the field will be pushed; + * @param question - the question; + * @param description - the description of the question; + * @param options - the options array; + * @param validation - optional validation the question may have. + */ +export function pushCheckbox( + form, + question, + description, + options, + validation, + id +) { + let value = { + type: 1, + question: question ? question : "", + validation: validation ? validation : [{ type: "required", value: false }], + options: options ? options.map((x) => x.value) : [""], + description: description ? description : "", + id: uuid(), + inputId: id ? id : null, + error: { + errorMsg: { + question: question ? "" : "Este campo é obrigatório!", + description: "", + optionsNumber: options + ? options.length < 2 + ? "O campo precisa ter pelo menos duas opções!" + : "" + : "O campo precisa ter pelo menos duas opções!", + options: options + ? options.map((x) => (x = "")) + : ["Por favor, preencha esta opção"], + }, + }, + }; + return form.push(value); +} +/** Function that pushes a 'select' object into the form array. + * @param form - the form where the field will be pushed; + * @param question - the question; + * @param description - the description of the question; + * @param subformId - id of the form being used as a subform; + * @param validation - optional validation the question may have. + */ +export function pushSubform( + form, + question, + description, + subformId, + validation, + id +) { + return form.push({ + type: 4, + validation: validation ? validation : [{ type: "required", value: false }], + question: question ? question : "", + description: description ? description : "", + subformId: subformId, + id: uuid(), + inputId: id ? id : null, + error: { + errorMsg: { + question: question ? "" : "Este campo é obrigatório!", + description: "", + subformUsage: "", + }, + }, + }); +} diff --git a/src/components/fieldsDisplayForm/utils/FrontEndTranslation.js b/src/components/fieldsDisplayForm/utils/FrontEndTranslation.js new file mode 100644 index 0000000..d0f158e --- /dev/null +++ b/src/components/fieldsDisplayForm/utils/FrontEndTranslation.js @@ -0,0 +1,89 @@ +import { + pushTitle, + pushQuestion, + pushSelect, + pushRadio, + pushCheckbox, + pushSubform, +} from "./FormComposition"; + +/** Function that recieves the validation from the backend to translate it to the frontend. + * @param validaiton - the validation as it comes from the backend. + */ +function validationTranslate(validation) { + let val = [{ type: "required", value: false }]; + if (!validation) return val; + validation.forEach((opt) => { + if (opt.type === 6) { + val[0].value = true; + } else if (opt.type === 2) { + val[0].value = true; + } else { + val.push({ type: opt.type, value: opt.arguments[0] }); + } + }); + return val; +} + +/** Function that converts the backend form to an structure to be used on frontend. + * @param formData - the backend data. + */ +export function createFrontendForm(formData) { + let json = []; + pushTitle(json, formData.title, formData.description, formData.id); + + formData.inputs.forEach((option) => { + switch (option.type) { + case 0: + pushQuestion( + json, + option.question, + option.description, + validationTranslate(option.validation), + option.id + ); + break; + case 1: + pushCheckbox( + json, + option.question, + option.description, + option.sugestions, + validationTranslate(option.validation), + option.id + ); + break; + case 2: + pushRadio( + json, + option.question, + option.description, + option.sugestions, + validationTranslate(option.validation), + option.id + ); + break; + case 3: + pushSelect( + json, + option.question, + option.description, + option.sugestions, + validationTranslate(option.validation), + option.id + ); + break; + case 4: + pushSubform( + json, + option.question, + option.description, + option.subForm.contentFormId, + validationTranslate(option.validation), + option.id + ); + default: + } + }); + return json; +} diff --git a/src/components/fieldsCreateForm/utils/schemas.js b/src/components/fieldsDisplayForm/utils/schemas.js similarity index 93% rename from src/components/fieldsCreateForm/utils/schemas.js rename to src/components/fieldsDisplayForm/utils/schemas.js index 1995384..3ec954c 100644 --- a/src/components/fieldsCreateForm/utils/schemas.js +++ b/src/components/fieldsDisplayForm/utils/schemas.js @@ -116,34 +116,32 @@ export async function testTextValidation(form, index, value) { await textValidationSchema .validate(value) .then((x) => { - form[index].error.errorMsg.validation.value = ""; + form[index].error.errorMsg.validationValue = ""; }) - .catch( - (err) => (form[index].error.errorMsg.validation.value = err.message) - ); + .catch((err) => (form[index].error.errorMsg.validationValue = err.message)); } /** Functions that verify if the form array can be sent to the backend. */ export function verifyError(form) { - if (form.length === 1) return false; + if (!form || form.length < 2) return false; let valid = true; form.map(function (x) { if (x.error.errorMsg.question || x.error.errorMsg.description) { valid = false; return; } - if (x.type === "question") { - if (x.error.errorMsg.validation.value) { + if (x.type === 0) { + if (x.error.errorMsg.validationValue) { valid = false; return; } } - if (x.type === "subForm") { + if (x.type === 4) { if (x.error.errorMsg.subformUsage || !x.subformId) { valid = false; return; } } - if (x.type === "checkbox" || x.type === "radio" || x.type === "select") { + if (x.type === 1 || x.type === 2 || x.type === 3) { if (x.error.errorMsg.optionsNumber) valid = false; x.error.errorMsg.options.forEach((y) => { if (y) { diff --git a/src/components/fieldsListForms/CardForm.jsx b/src/components/fieldsListForms/CardForm.jsx index 9dca0c0..40fc1f8 100644 --- a/src/components/fieldsListForms/CardForm.jsx +++ b/src/components/fieldsListForms/CardForm.jsx @@ -97,7 +97,7 @@ function CardForm(props) { return ( <ExpansionPanel> <ExpansionPanelSummary expandIcon={<MoreVertOutlinedIcon />}> - <Typography noWrap className={classes.title}> + <Typography className={classes.title}> {props.title} <br /> <div className={classes.create} noWrap> @@ -139,4 +139,4 @@ function CardForm(props) { ); } -export default CardForm; +export default CardForm; \ No newline at end of file diff --git a/src/components/header/header.jsx b/src/components/header/header.jsx index 4846204..d714258 100644 --- a/src/components/header/header.jsx +++ b/src/components/header/header.jsx @@ -21,9 +21,6 @@ const useStyles = makeStyles((theme) => ({ ["@media (max-width:1040px)"]: { display: "none", }, - // ["@media (max-height:681px)"]: { - // display: "none" - // } }, form_creator: { color: "#ffffff", diff --git a/src/contexts/FormContext.js b/src/contexts/FormContext.js new file mode 100644 index 0000000..bd70c89 --- /dev/null +++ b/src/contexts/FormContext.js @@ -0,0 +1,48 @@ +import React, { useState, createContext, useEffect } from "react"; +import { useParams } from "react-router-dom"; +import api from "../api"; +import { createFrontendForm } from "../components/fieldsDisplayForm/utils/FrontEndTranslation"; +export const FormEditionContext = createContext(); + +const FormProvider = (props) => { + /** Getting the id from the route information */ + const { id } = useParams(); + /** Form state being started with the title in the case of the creation or 0 when editing (to be overrided by the backend data afterwards) + * it's an array where each position stands for a question selected by the user. */ + const [form, setForm] = useState( + id + ? 0 + : [ + { + type: "title", + question: "", + description: "", + error: { + errorMsg: { + question: "Este campo é obrigatório!", + description: "", + }, + }, + }, + ] + ); + + /** Hook to access the API in the case a edition is being done */ + useEffect(() => { + const fetchData = async () => { + api.get(`/form/${id}`).then(async function (res) { + setForm(await createFrontendForm(res.data)); + }); + }; + if (id) fetchData(); + }, []); + return ( + <FormEditionContext.Provider + value={{ formState: [form, setForm], idValue: id }} + > + {props.children} + </FormEditionContext.Provider> + ); +}; + +export default FormProvider; diff --git a/src/contexts/useForm.js b/src/contexts/useForm.js new file mode 100644 index 0000000..71fc926 --- /dev/null +++ b/src/contexts/useForm.js @@ -0,0 +1,338 @@ +import { useContext, useEffect } from "react"; +import { FormEditionContext } from "./FormContext"; +import uuid from "uuid/v4"; +import { + testQuestionTextSchema, + testDescriptionTextSchema, + selectOptionsTesting, + testSubformSchema, + selectOptionTextTesting, + testTextValidation, +} from "../components/fieldsDisplayForm/utils/schemas"; +import { + pushTitle, + pushQuestion, + pushSelect, + pushRadio, + pushCheckbox, + pushSubform, +} from "../components/fieldsDisplayForm/utils/FormComposition"; + +import api from "../api"; + +import createBackendForm from "../components/fieldsDisplayForm/utils/BackendTranslation"; +import { createFrontendForm } from "../components/fieldsDisplayForm/utils/FrontEndTranslation"; + +const useForm = () => { + const { formState, idValue } = useContext(FormEditionContext); + const [form, setForm] = formState; + + const routeId = idValue; + + /** Function that adds the title object into the form array. + * Its parameters are used on the translation of the backend data. + * @param title - the title; + * @param description - the description of the form; + * @param id - optional parameter, it is used when editing a form. + */ + function addToFormTitle(title, description, id) { + setForm(pushTitle(form, title, description, id)); + } + /** Function that adds a 'question' object into the form array. + * Its parameters are used on the translation of the backend data. + * @param question - the question; + * @param description - the description of the question; + * @param validation - optional validation the question may have. + */ + function addToFormQuestion(question, description, validation) { + pushQuestion(form, question, description, validation); + setForm([...form]); + } + /** Function that adds a 'select' object into the form array. + * Its parameters are used on the translation of the backend data. + * @param question - the question; + * @param description - the description of the question; + * @param options - the options array; + * @param validation - optional validation the question may have. + */ + function addToFormSelect(question, description, options, validation) { + pushSelect(form, question, description, options, validation); + setForm([...form]); + } + /** Function that adds a 'radio' object into the form array. + * Its parameters are used on the translation of the backend data. + * @param question - the question; + * @param description - the description of the question; + * @param options - the options array; + * @param validation - optional validation the question may have. + */ + function addToFormRadio(question, description, options, validation) { + pushRadio(form, question, description, options, validation); + setForm([...form]); + } + /** Function that adds a 'checkbox' object into the form array. + * Its parameters are used on the translation of the backend data. + * @param question - the question; + * @param description - the description of the question; + * @param options - the options array; + * @param validation - optional validation the question may have. + */ + function addToFormCheckbox(question, description, options, validation) { + pushCheckbox(form, question, description, options, validation); + setForm([...form]); + } + /** Function that adds a 'select' object into the form array. + * Its parameters are used on the translation of the backend data. + * @param question - the question; + * @param description - the description of the question; + * @param subformId - id of the form being used as a subform; + * @param validation - optional validation the question may have. + */ + function addToFormSubform(question, description, subformId, validation) { + pushSubform(form, question, description, subformId, validation); + setForm([...form]); + } + + /** Function used on FormFieldRadio, FormFieldCheckbox and FormFieldSelect, it adds a new option field for those types of questions. + * @param index - the position on the array that the operation needs to be done. + */ + async function addSelectOption(index) { + form[index].options.push(""); + form[index].error.errorMsg.options.push("Por favor, preencha esta opção"); + await selectOptionsTesting(form, index); + setForm([...form]); + } + + /** Function used on FormFieldRadio, FormFieldCheckbox and FormFieldSelect, it removes an option field for those types of questions. + * @param index - the position on the array that the operation needs to be done. + */ + async function removeSelectOption(index, idopt) { + form[index].options.splice(idopt, 1); + form[index].error.errorMsg.options.splice(idopt, 1); + await selectOptionsTesting(form, index); + setForm([...form]); + } + + /** Function used on every FormField, it deletes the question from the array. + * @param index - the position on the array that the operation needs to be done. + */ + function deleteFromForm(index) { + form.splice(index, 1); + setForm([...form]); + } + + /** Function used on FormFieldQuestion, it handles the validation the user chooses. + * Currently, only handle max and min number of characters. + * @param index - the position on the array that the operation needs to be done. + */ + function addValidation(index) { + form[index].validation.push({ type: "", value: "" }); + form[index].error.errorMsg.validationValue = "Por favor, digite um número"; + setForm([...form]); + } + + /** Function used on every FormField, it updates the value of the question property on the form array. + * @param value - the value being typed by the user; + * @param index - the position on the array that the operation needs to be done. + */ + async function setQuestionField(value, index) { + form[index].question = value; + await testQuestionTextSchema(form, value, index); + setForm([...form]); + } + + /** Function used on every FormField, it updates the value of the description property on the array. + * @param value - the value being typed by the user; + * @param index - the position on the array that the operation needs to be done. + */ + async function setDescriptionField(value, index) { + form[index].description = value; + await testDescriptionTextSchema(form, value, index); + setForm([...form]); + } + + /** Function used on every FormField, it updates the value of the oprion property of the object on the array. + * @param value - the value being typed by the user; + * @param index - the position on the array that the operation needs to be done; + * @param idopt - the id of the options being changed, inside the form[index]. + */ + async function setSelectOption(value, index, idopt) { + form[index].options[idopt] = value; + await selectOptionTextTesting(form, value, index, idopt); + setForm([...form]); + } + + /** Function used on every FormField, it updates the value of the required property of a question. + * @param index - the position on the array that the operation needs to be done. + */ + function setRequiredField(index) { + form[index].validation[0].value = !form[index].validation[0].value; + setForm([...form]); + } + /** Function to store the selected subform Id on it's corresponding object. + * @param value - the id of the selected form; + * @param index - the position on the array that the operation needs to be done. + */ + async function setSubformId(value, index) { + form[index].subformId = value; + await testSubformSchema(form, index); + setForm([...form]); + } + + /** Function used on FormFieldText to set the chosen validation type, currently min and max char. + * @param value - the type of the chosen validation; + * @param index - the position on the array that the operation needs to be done. + */ + async function setValidationType(value, index) { + form[index].validation[1].type = value; + setForm([...form]); + } + + /** Function used on FormFieldText to set the value of the validation + * @param value - the value for the chosen validation; + * @param index - the position on the array that the operation needs to be done. + */ + async function setValidationValue(value, index) { + form[index].validation[1].value = value; + await testTextValidation(form, index, value); + setForm([...form]); + } + + /** Function used on FormFieldText to remove the validaiton. + * @param index - the position on the array that the operation needs to be done. + */ + function removeValidation(index) { + form[index].validation.splice(-1, 1); + form[index].error.errorMsg.validationValue = ""; + setForm([...form]); + } + /** Reordering the form array based on the place the question is being dragged over. + * @param result - an composed object bringing info about the drag event. + */ + function onDragEnd(result) { + if (!result.destination) return; + const { source, destination } = result; + const copiedForm = [...form]; + const [removed] = copiedForm.splice(source.index, 1); + copiedForm.splice(destination.index, 0, removed); + setForm(copiedForm); + } + /** Verify if the validation was changed on the edition. + * @param backForm - form that came from the backend; + * @param form - form being edited. + */ + function differentValidation(backForm, form) { + for (let i = 0; i < form.validation.length; i++) { + if ( + JSON.stringify(form.validation[i]) !== + JSON.stringify(backForm.validation[i]) + ) { + return true; + } + } + return false; + } + /** Comparing the edited form with the 'original' form that is on the backend. + * If some property of the input was changed in the edition, its id becomes null. + */ + async function setId() { + const fetchData = async () => { + await api.get(`/form/${routeId}`).then(async function (res) { + let backForm = createFrontendForm(res.data); + for (let i = 1; i < backForm.length; i++) { + for (let j = 1; j < form.length; j++) { + if (backForm[i].inputId === form[j].inputId) { + if ( + JSON.stringify(backForm[i], [ + "question", + "description", + "options", + "subformId", + ]) !== + JSON.stringify(form[j], [ + "question", + "description", + "options", + "subformId", + ]) || + differentValidation(backForm[i], form[j]) + ) { + form[j].inputId = null; + } + } + } + } + }); + }; + await fetchData(); + } + /** The submit function. It's triggered when the submit button is pressed on the interface. + * Its api call may be to create or to edit a form. + */ + async function submit(validToSend) { + if (!validToSend) return; + if (form[0].id) { + await setId(); + let data = await createBackendForm(form, routeId); + const post_response = await api + .put(`/form/${routeId}`, data, { + headers: { + authorization: `bearer ${window.sessionStorage.getItem("token")}`, + }, + }) + .then(function (error) { + if (!error.response) + alert("Seu formulário foi atualizado com sucesso."); + }) + .catch(function (error) { + if (error.response.data.error === "User dont own this form.") + alert("Você não tem permissão para alterar este formulário"); + else if (error.response.data.error === "Found a subform loop") + alert( + "Foi encontrada uma recursão de subformulários. Por favor, altere o subformulário selecionado ou o exclua." + ); + else alert("Um erro ocorreu."); + }); + } else { + const post_response = await api + .post(`/form`, await createBackendForm(form), { + headers: { + authorization: `bearer ${window.sessionStorage.getItem("token")}`, + }, + }) + .then(function (error) { + if (!error.response) alert("Seu formulário foi criado com sucesso."); + else console.log("ERROR NO POST_RESPONSE", error); + }) + .catch(function (error) { + console.log("ERROR NO POST RESPONSE", error.response); + alert("Um erro ocorreu."); + }); + } + } + + return { + addToFormTitle, + addToFormQuestion, + addToFormSelect, + addToFormRadio, + addToFormCheckbox, + addToFormSubform, + addSelectOption, + removeSelectOption, + deleteFromForm, + addValidation, + setQuestionField, + setDescriptionField, + setSelectOption, + setRequiredField, + setSubformId, + setValidationType, + setValidationValue, + removeValidation, + onDragEnd, + submit, + }; +}; + +export default useForm; diff --git a/src/pages/CreateForm.js b/src/pages/CreateForm.js index 9a2a477..670a86f 100644 --- a/src/pages/CreateForm.js +++ b/src/pages/CreateForm.js @@ -1,509 +1,11 @@ -import React, { useState, useEffect } from "react"; -import { makeStyles } from "@material-ui/core/styles"; -import Grid from "@material-ui/core/Grid"; -import Button from "@material-ui/core/Button"; -import { DragDropContext, Droppable } from "react-beautiful-dnd"; -import { createMuiTheme, MuiThemeProvider } from "@material-ui/core"; -import FormFieldText from "../components/fieldsCreateForm/FormFieldText"; -import FormFieldSelect from "../components/fieldsCreateForm/FormFieldSelect"; -import FormFieldRadio from "../components/fieldsCreateForm/FormFieldRadio"; -import FormFieldCheckbox from "../components/fieldsCreateForm/FormFieldCheckbox"; -import FormFieldTitle from "../components/fieldsCreateForm/FormFieldTitle"; -import FormFieldSubForm from "../components/fieldsCreateForm/FormFieldSubform"; -import uuid from "uuid/v4"; -import { - testQuestionTextSchema, - testDescriptionTextSchema, - selectOptionsTesting, - testSubformSchema, - selectOptionTextTesting, - testTextValidation, - verifyError, -} from "../components/fieldsCreateForm/utils/schemas"; -import createForm from "../components/fieldsCreateForm/utils/BackendTranslation"; -import SideMenu from "../components/fieldsCreateForm/SideMenu"; -import api from "../api"; - -import Tooltip from "@material-ui/core/Tooltip"; -/** CSS styles used on page components */ -const useStyles = makeStyles((theme) => ({ - app: { - margin: "0", - padding: "40px", - display: "flex", - ["@media (max-width: 600px)"]: { - flexDirection: "column-reverse", - justifyContent: "flex-end", - }, - paddingBottom: "78px", - ["@media (min-width: 600px)"]: { - minHeight: "calc(100vh - 92.4px - 78px)", - }, - minHeight: "calc(100vh - 71.6px - 78px)", - }, - addButton: { - fontSize: "100%", - }, - buttonOk: { - backgroundColor: "#6ec46c", - "&:hover": { - backgroundColor: "rgb(25, 109, 23)", - }, - width: "20%", - ["@media (max-width:600px)"]: { - marginTop: "52px", - }, - }, - button: { - ["@media (max-width:600px)"]: { - marginTop: "52px", - }, - }, - questionsGrid: { - // da pra mexer no deslocamento do titulo por aqui; - ["@media (max-width:600px)"]: { - // marginBottom: "100%", - // padding: 0, - }, - }, - sideMenuFormatingGrid: { - ["@media (max-width:600px)"]: { - marginTop: "-90px", - }, - }, -})); -/** CSS style used through Material Ui. */ -const theme = createMuiTheme({ - overrides: { - MuiInput: { - underline: { - "&:before": { - borderBottom: "1px solid #35c7fc", - }, - "&:after": { - borderBottom: "1px solid #3f51b5", - }, - }, - }, - MuiButton: { - label: { - color: "white", - }, - }, - }, -}); -/** Main function that returns the children that composes the form creation page. */ -function CreateForm() { - /** Style class. */ - const classes = useStyles(); - /** An unique string to be used as ID for drag and drop function. */ - const columnId = uuid(); - /** Error state. */ - const [validToSend, setValidToSend] = useState(); - - /** Form state being started with the title, it's an array where each position stands for a question selected by the user. */ - const [form, setForm] = useState([ - { - type: "title", - title: "", - description: "", - error: { - errorMsg: { question: "Este campo é obrigatório!", description: "" }, - }, - }, - ]); - /** Function used on 'sidemenu' that adds to the form array the object of a question. */ - function addToFormQuestion() { - setForm([ - ...form, - { - type: "question", - validation: [{ type: "required", value: false }], - question: "", - description: "", - id: uuid(), - error: { - errorMsg: { - question: "Este campo é obrigatório!", - description: "", - validation: { - value: "", - }, - }, - }, - }, - ]); - } - /** Function used on 'sidemenu' that adds to the form array the object of a select question. */ - function addToFormSelect() { - setForm([ - ...form, - { - type: "select", - question: "", - validation: [{ type: "required", value: false }], - options: [""], - description: "", - id: uuid(), - error: { - errorMsg: { - question: "Este campo é obrigatório!", - description: "", - optionsNumber: "O campo precisa ter pelo menos duas opções!", - options: ["Por favor, preencha esta opção"], - }, - }, - }, - ]); - } - /** Function used on 'sidemenu' that adds to the form array the object of a radio question. */ - function addToFormRadio() { - setForm([ - ...form, - { - type: "radio", - question: "", - validation: [{ type: "required", value: false }], - options: [""], - description: "", - id: uuid(), - error: { - errorMsg: { - question: "Este campo é obrigatório!", - description: "", - optionsNumber: "O campo precisa ter pelo menos duas opções!", - options: ["Por favor, preencha esta opção"], - }, - }, - }, - ]); - } - /** Function used on 'sidemenu' that adds to the form array the object of a checkbox question. */ - function addToFormCheckbox() { - setForm([ - ...form, - { - type: "checkbox", - question: "", - validation: [{ type: "required", value: false }], - options: [""], - description: "", - id: uuid(), - error: { - errorMsg: { - question: "Este campo é obrigatório!", - description: "", - optionsNumber: "O campo precisa ter pelo menos duas opções!", - options: ["Por favor, preencha esta opção"], - }, - }, - }, - ]); - } - /** Function used on 'sidemenu' that adds to the form array the object of a subform question. */ - function addToFormSubForm() { - setForm([ - ...form, - { - type: "subForm", - validation: [{ type: "required", value: false }], - description: "", - question: "", - subformId: "", - id: uuid(), - error: { - errorMsg: { - question: "Este campo é obrigatório!", - description: "", - subformUsage: "", - }, - }, - }, - ]); - } - /** Function used on FormFieldRadio, FormFieldCheckbox and FormFieldSelect, it adds a new option field for those questions. */ - async function addSelectOption(index) { - form[index].options.push(""); - form[index].error.errorMsg.options.push("Por favor, preencha esta opção"); - await selectOptionsTesting(form, index); - setForm([...form]); - } - /** Function used on FormFieldRadio, FormFieldCheckbox and FormFieldSelect, it removes an option field for those questions. */ - async function removeSelectOption(index, idopt) { - form[index].options.splice(idopt, 1); - form[index].error.errorMsg.options.splice(idopt, 1); - await selectOptionsTesting(form, index); - setForm([...form]); - } - /** Function used on every FormField, it deletes the question from the array. */ - function deleteFromForm(index) { - form.splice(index, 1); - setForm([...form]); - } - /** Function used on FormFieldQuestion, it handles the validation the user chooses. - * Currently, only handle max and min number of characters. - */ - function addValidation(index) { - form[index].validation.push({ type: "", value: "" }); - form[index].error.errorMsg.validation.value = "Por favor, digite um número"; - setForm([...form]); - } - /** Function used on every FormField, it updates the value of the question property on the form array. */ - async function setQuestionField(value, index) { - form[index].question = value; - await testQuestionTextSchema(form, value, index); - setForm([...form]); - } - /** Function used on every FormField, it updates the value of the description property on the array. */ - async function setDescriptionField(value, index) { - form[index].description = value; - await testDescriptionTextSchema(form, value, index); - setForm([...form]); - } - /** Function used on every FormField, it updates the value of the oprion property of the object on the array. */ - async function setSelectOption(value, index, idopt) { - form[index].options[idopt] = value; - await selectOptionTextTesting(form, value, index, idopt); - setForm([...form]); - } - /** Function used on every FormField, it updates the value of the required property of a question. */ - function setRequiredField(index) { - form[index].validation[0].value = !form[index].validation[0].value; - setForm([...form]); - } - /** Function to update the title, used on FormFieldTitle. */ - async function setTitleField(value) { - form[0].title = value; - await testQuestionTextSchema(form, value, 0); - setForm([...form]); - } - /** Function to store the selected subform Id on it's corresponding object. */ - async function setSubformId(value, index) { - form[index].subformId = value; - await testSubformSchema(form, index); - setForm([...form]); - } - /** Function used on FormFieldText to set the chosen validation type, currently min and max char. */ - async function setValidationType(value, index) { - form[index].validation[1].type = value; - - setForm([...form]); - } - /** Function used on FormFieldText to set the value of the validation*/ - async function setValidationValue(value, index) { - form[index].validation[1].value = value; - await testTextValidation(form, index, value); - setForm([...form]); - } - /** Function used on FormFieldText to remove the validaiton. */ - function removeValidation(index) { - form[index].validation.splice(-1, 1); - setForm([...form]); - } - /** The submit function. It's triggered when the submit button is pressed on the interface. */ - async function submit(event) { - if (!validToSend) return; - let data = createForm(form); - const post_response = await api - .post(`/form`, data, { - headers: { - authorization: `bearer ${window.sessionStorage.getItem("token")}`, - }, - }) - .then(function (error) { - if (!error.response) alert("Seu formulário foi criado com sucesso."); - }) - .catch(function (error) { - alert("Um erro ocorreu."); - }); - } - /** Reordering the form array based on the place the question is being dragged over. */ - const onDragEnd = (result) => { - if (!result.destination) return; - const { source, destination } = result; - - const copiedForm = [...form]; - const [removed] = copiedForm.splice(source.index, 1); - copiedForm.splice(destination.index, 0, removed); - setForm(copiedForm); - }; - /** Error handling -> every time the form object is updated, it is verified to evaluate it's error messages, - * so the submit button can be enabled or disabled. - */ - useEffect(() => { - setValidToSend(verifyError(form)); - }, [form]); - +import React from "react"; +import DisplayForm from "../components/fieldsDisplayForm/DisplayForm"; +import FormProvider from "../contexts/FormContext"; +/** External component that wraps the display page into the form context. */ +export default function CreateForm() { return ( - <MuiThemeProvider theme={theme}> - <Grid className={classes.app}> - <Grid xs={12} sm={2} className={classes.sideMenuFormatingGrid}> - <SideMenu - addToFormQuestion={addToFormQuestion} - addToFormSelect={addToFormSelect} - addToFormRadio={addToFormRadio} - addToFormCheckbox={addToFormCheckbox} - addToFormSubForm={addToFormSubForm} - /> - </Grid> - <DragDropContext onDragEnd={onDragEnd}> - <Grid - dragOver - container - xs={12} - sm={8} - direction="column" - alignItems="center" - className={classes.questionsGrid} - > - <Droppable droppableId={columnId}> - {(provided, snapshot) => { - return ( - <Grid {...provided.droppableProps} ref={provided.innerRef}> - {form.map((x, index) => { - if (x.type === "question") - return ( - <FormFieldText - question={x.question} - idq={index} - description={x.description} - deleteFromForm={deleteFromForm} - setQuestionField={setQuestionField} - setRequiredField={setRequiredField} - setDescriptionField={setDescriptionField} - id={x.id} - error={x.error} - validation={x.validation} - addValidation={addValidation} - setValidationType={setValidationType} - setValidationValue={setValidationValue} - removeValidation={removeValidation} - validationValue={ - x.validation[1] ? x.validation[1].value : null - } - validationType={ - x.validation[1] ? x.validation[1].type : null - } - /> - ); - else if (x.type === "select") - return ( - <FormFieldSelect - question={x.question} - options={x.options} - idq={index} - description={x.description} - deleteFromForm={deleteFromForm} - addSelectOption={addSelectOption} - removeSelectOption={removeSelectOption} - setSelectOption={setSelectOption} - setQuestionField={setQuestionField} - setRequiredField={setRequiredField} - setDescriptionField={setDescriptionField} - validation={x.validation} - id={x.id} - error={x.error} - /> - ); - else if (x.type === "radio") - return ( - <FormFieldRadio - question={x.question} - options={x.options} - idq={index} - description={x.description} - deleteFromForm={deleteFromForm} - addSelectOption={addSelectOption} - removeSelectOption={removeSelectOption} - setSelectOption={setSelectOption} - setQuestionField={setQuestionField} - setRequiredField={setRequiredField} - setDescriptionField={setDescriptionField} - validation={x.validation} - id={x.id} - error={x.error} - /> - ); - else if (x.type === "checkbox") - return ( - <FormFieldCheckbox - question={x.question} - options={x.options} - idq={index} - description={x.description} - deleteFromForm={deleteFromForm} - addSelectOption={addSelectOption} - removeSelectOption={removeSelectOption} - setSelectOption={setSelectOption} - setQuestionField={setQuestionField} - setRequiredField={setRequiredField} - setDescriptionField={setDescriptionField} - validation={x.validation} - id={x.id} - error={x.error} - /> - ); - else if (x.type === "subForm") - return ( - <FormFieldSubForm - question={x.question} - idq={index} - description={x.description} - deleteFromForm={deleteFromForm} - setQuestionField={setQuestionField} - setRequiredField={setRequiredField} - setDescriptionField={setDescriptionField} - setSubformId={setSubformId} - validation={x.validation} - id={x.id} - error={x.error} - validToSend={validToSend} - subformId={x.subformId ? x.subformId : null} - /> - ); - else if (x.type === "title") - return ( - <FormFieldTitle - question={x.question} - idq={index} - deleteFromForm={deleteFromForm} - setTitleField={setTitleField} - setDescriptionField={setDescriptionField} - error={x.error} - /> - ); - })} - {provided.placeholder} - </Grid> - ); - }} - </Droppable> - <Tooltip - title={ - validToSend - ? "Criar seu formulário" - : "Verifique se você criou pelo menos uma pergunta e se as perguntas estão propriamente construídas" - } - aria-label={ - validToSend - ? "Criar seu formulário" - : "Verifique se você criou pelo menos uma pergunta e se as perguntas estão propriamente construídas" - } - > - <Button - className={validToSend ? classes.buttonOk : classes.button} - variant="contained" - type="submit" - onClick={submit} - > - Criar - </Button> - </Tooltip> - </Grid> - </DragDropContext> - </Grid> - </MuiThemeProvider> + <FormProvider> + <DisplayForm /> + </FormProvider> ); } - -export default CreateForm; diff --git a/src/pages/EditForm.js b/src/pages/EditForm.js new file mode 100644 index 0000000..cdda379 --- /dev/null +++ b/src/pages/EditForm.js @@ -0,0 +1,11 @@ +import React from "react"; +import DisplayForm from "../components/fieldsDisplayForm/DisplayForm"; +import FormProvider from "../contexts/FormContext"; +/** External component that wraps the display page into the form context. */ +export default function EditForm() { + return ( + <FormProvider> + <DisplayForm /> + </FormProvider> + ); +} diff --git a/src/pages/SignUp.js b/src/pages/SignUp.js index 50e755a..e9a0af5 100644 --- a/src/pages/SignUp.js +++ b/src/pages/SignUp.js @@ -8,7 +8,7 @@ import FormInput from "../components/fieldsSignUp/FormInput"; import Paper from "@material-ui/core/Paper"; import api from "../api"; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ register: { maxWidth: "1000px", background: "#ffffff", @@ -16,22 +16,22 @@ const useStyles = makeStyles(theme => ({ padding: "2% 1%", margin: "0 auto", marginTop: "9%", - width: "95%" + width: "95%", }, custom_strong: { fontSize: "25px", textAlign: "center", display: "block", - color: "#46525d" + color: "#46525d", }, strong_description: { fontSize: "14px", - color: "#c2c6ca" + color: "#c2c6ca", }, form: { marginTop: "3%", alignItems: "center", - textAlign: "center" + textAlign: "center", }, button: { type: "submit", @@ -42,12 +42,12 @@ const useStyles = makeStyles(theme => ({ padding: "10px 20px", fontSize: "18px", "&:hover": { - backgroundColor: "rgb(25, 109, 23)" + backgroundColor: "rgb(25, 109, 23)", }, ["@media (max-width:550px)"]: { - width: "55%" - } - } + width: "55%", + }, + }, })); export default function SignUp() { const classes = useStyles(); @@ -57,13 +57,13 @@ export default function SignUp() { password: "", password_confirm: "", nameError: false, - emailError: false + emailError: false, }); async function update(prop, event) { await setValues({ ...values, [prop]: event.target.value }); } - const handleChange = prop => event => { + const handleChange = (prop) => (event) => { switch (prop) { case "name": if (!checkName()) { @@ -89,7 +89,11 @@ export default function SignUp() { return true; } function checkName() { - if (/^[a-zA-Z ]+$/.test(values.name) && !(/^$|\s+/.test(values.name)) &&values.name.length <= 225) { + if ( + /^[a-zA-Z ]+$/.test(values.name) && + !/^$|\s+/.test(values.name) && + values.name.length <= 225 + ) { return true; } return false; @@ -113,16 +117,15 @@ export default function SignUp() { } // Ficou com essa configuração porque as funções para verificar nome e email são chamadas em 'tempo real' para deixar o campo em vermelho. function verifyValuesContent() { - if (!checkName()){ + if (!checkName()) { alert("Nome inválido"); return false; - }else if (!checkEmail()) { + } else if (!checkEmail()) { alert("Email invalido"); return false; - }else if (!checkPassword()){ + } else if (!checkPassword()) { return false; - } - else{ + } else { return true; } } @@ -131,15 +134,15 @@ export default function SignUp() { .post(`/user/signUp`, { email: values.email, name: values.name, - hash: values.password + hash: values.password, }) - .then(function(error) { + .then(function (error) { if (!error.response) { alert("Usuário criado com sucesso"); // redirecionar para a main page } }) - .catch(function(error) { + .catch(function (error) { if (error.response) { switch (error.response.data.error) { case 'duplicate key value violates unique constraint "form_user_name_key"': @@ -156,7 +159,6 @@ export default function SignUp() { alert("Um erro ocorreu. Tente novamente mais tarde."); } return; - // console.log(error.response.data); } }); } @@ -170,19 +172,19 @@ export default function SignUp() { const theme = createMuiTheme({ overrides: { root: { - color: "white" + color: "white", }, MuiInput: { underline: { "&:before": { - borderBottom: "1px solid #35c7fc" + borderBottom: "1px solid #35c7fc", }, "&:after": { - borderBottom: "1px solid #3f51b5" - } - } + borderBottom: "1px solid #3f51b5", + }, + }, }, - } + }, }); return ( <MuiThemeProvider theme={theme}> -- GitLab