diff --git a/src/components/fieldsAnswerForm/FormFieldCheckbox.js b/src/components/fieldsAnswerForm/FormFieldCheckbox.js index 462b63f1bd60af6128e7340f95ea291d5c43c3c5..f658a90cf6865332b94ed4e4e47bd0da39cecd0f 100644 --- a/src/components/fieldsAnswerForm/FormFieldCheckbox.js +++ b/src/components/fieldsAnswerForm/FormFieldCheckbox.js @@ -1,51 +1,126 @@ -import React from "react"; +import React, { useEffect } from "react"; 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 DeleteOutlinedIcon from "@material-ui/icons/DeleteOutlined"; -import IconButton from "@material-ui/core/IconButton"; -import Select from "@material-ui/core/Select"; -import MenuItem from "@material-ui/core/MenuItem"; -import AddCircleIcon from "@material-ui/icons/AddCircle"; -import CloseIcon from "@material-ui/icons/Close"; -import Switch from "@material-ui/core/Switch"; -import FormControlLabel from "@material-ui/core/FormControlLabel"; import Typography from "@material-ui/core/Typography"; import Checkbox from "@material-ui/core/Checkbox"; import FieldFooterOptions from "./FieldFooterOptions"; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles(theme => ({ paper: { padding: theme.spacing(3), width: theme.spacing(100), - minheight: theme.spacing(16), + minheight: theme.spacing(18), margin: theme.spacing(2), + ["@media (max-width:827px)"]: { + width: theme.spacing(70) + }, + ["@media (max-width:590px)"]: { + width: theme.spacing(40) + } }, questionsGrid: { - marginBottom: "20px", + marginBottom: "20px" }, + text: { + color: "black" + }, + validation: { + fontSize: "14px", + color: "red" + } })); function FormFieldCheckbox(props) { const classes = useStyles(); - const options = props.options.map(function (x) { + /** Temporary array to be used as a type. */ + function vetorTmp() { + let tmp = []; + props.options.map(x => { + tmp.push(false); + }); + return tmp; + } + + /** Variable that displays the validation message. */ + const [valid, setValid] = React.useState(); + + /** Array of boolean to specify what is selected as true */ + const [checkedArray, setcheckedArray] = React.useState(vetorTmp()); + + /** Function to send answer to the father component. */ + function sendArray() { + if (validate(checkedArray)) { + props.createAnswer(props.id, checkedArray, false); + } else { + props.createAnswer(props.id, checkedArray, true); + } + } + + /** + * Function that changes the array based on selected index. + * @param index - Selected value from input. + */ + function handleArray(index) { + checkedArray[index] = !checkedArray[index]; + sendArray(); + } + + /** + * Function to validate an input based on input validation. + * @param answer - Input to be validated. + */ + function validate(answer) { + let isValid = true; + + setValid(""); + props.validation.map(val => { + switch (val.type) { + case 6: + if ( + !answer.some(value => { + return value === true; + }) + ) { + setValid("Preencha pelo menos uma caixa."); + isValid = false; + } + break; + default: + isValid = true; + } + }); + + return isValid; + } + + /** HTML to be displayed. */ + const options = props.options.map((x, index) => { return ( <span> - {x.value} <Checkbox /> + <Typography className={classes.text} variant="h7"> + {x.value} + </Typography> + <Checkbox onChange={() => handleArray(index)} /> </span> ); }); + /** First validates an empty array. */ + useEffect(() => { + validate([]); + }, []); + return ( <Paper className={classes.paper}> <Grid container> <Grid item xs={12} className={classes.questionsGrid}> - <Typography variant="h6" gutterBottom> + <Typography className={classes.text} variant="h6"> {props.question} </Typography> + <Typography variant="h8">{props.description}</Typography> </Grid> <Grid item @@ -57,6 +132,9 @@ function FormFieldCheckbox(props) { className={classes.questionsGrid} > {options} + <div> + <Typography className={classes.validation}>{valid}</Typography> + </div> </Grid> </Grid> </Paper> diff --git a/src/components/fieldsAnswerForm/FormFieldRadio.js b/src/components/fieldsAnswerForm/FormFieldRadio.js index 68a79e4755a18af240c46f9ff0592027b9d27fcd..3b2724e3dea2242366f18658059480b07481c48b 100644 --- a/src/components/fieldsAnswerForm/FormFieldRadio.js +++ b/src/components/fieldsAnswerForm/FormFieldRadio.js @@ -1,16 +1,7 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; 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 DeleteOutlinedIcon from "@material-ui/icons/DeleteOutlined"; -import IconButton from "@material-ui/core/IconButton"; -import Select from "@material-ui/core/Select"; -import MenuItem from "@material-ui/core/MenuItem"; -import AddCircleIcon from "@material-ui/icons/AddCircle"; -import CloseIcon from "@material-ui/icons/Close"; -import Switch from "@material-ui/core/Switch"; -import FormControlLabel from "@material-ui/core/FormControlLabel"; import Typography from "@material-ui/core/Typography"; import Radio from "@material-ui/core/Radio"; import RadioGroup from "@material-ui/core/RadioGroup"; @@ -21,43 +12,131 @@ const useStyles = makeStyles(theme => ({ paper: { padding: theme.spacing(3), width: theme.spacing(100), - minheight: theme.spacing(16), - margin: theme.spacing(2) + minheight: theme.spacing(18), + margin: theme.spacing(2), + ["@media (max-width:827px)"]: { + width: theme.spacing(70) + }, + ["@media (max-width:590px)"]: { + width: theme.spacing(40) + } }, questionsGrid: { marginBottom: "20px" + }, + text: { + color: "black" + }, + validation: { + fontSize: "14px", + color: "red" } })); function FormFieldRadio(props) { const classes = useStyles(); + /** Temporary array to be used as a type. */ + function vetorTmp() { + let tmp = []; + props.options.map(x => { + tmp.push(false); + }); + return tmp; + } + + /** Input number that was just selected. */ const [selectedValue, setSelectedValue] = React.useState(); + /** Variable that displays the validation message. */ + const [valid, setValid] = React.useState(); + + /** Array of boolean to specify what is selected as true */ + const [checkedArray, setCheckedArray] = React.useState(vetorTmp()); + + /** + * Function to validate an input based on input validation. + * @param answer - Input to be validated. + */ + function validate(answer) { + let isValid = true; + + setValid(""); + props.validation.map(val => { + switch (val.type) { + case 2: + if ( + !answer.some(value => { + return value === true; + }) + ) { + setValid("Campo obrigatório."); + isValid = false; + } + break; + default: + isValid = true; + } + }); + + return isValid; + } + + /** + * Function to send answer to the father component. + * @param index - Number of the selected value. + */ + function handleArray(index) { + for (let i = 0; i < checkedArray.length; ++i) { + checkedArray[i] = false; + } + + checkedArray[index] = !checkedArray[index]; + if (validate(checkedArray)) { + props.createAnswer(props.id, checkedArray, false); + } else { + props.createAnswer(props.id, checkedArray, true); + } + } + + /** + * Function to set the selectedValue as the event. + * @param event - React event to get what is selected. + */ const handleChange = event => { setSelectedValue(event.target.value); }; - const options = props.options.map(function(x) { + /** HTML object to be displayed on component return. */ + const options = props.options.map(function(x, index) { return ( <span> - {x.value} + <Typography className={classes.text} variant="h7"> + {x.value} + </Typography> <Radio + onClick={handleChange} checked={selectedValue === x.value} - onChange={handleChange} + onChange={() => handleArray(index)} value={x.value} /> </span> ); }); + /** First validates an empty array. */ + useEffect(() => { + validate([]); + }, []); + return ( <Paper className={classes.paper}> <Grid container> <Grid item xs={12} className={classes.questionsGrid}> - <Typography variant="h6" gutterBottom> + <Typography className={classes.text} variant="h6"> {props.question} </Typography> + <Typography variant="h8">{props.description}</Typography> </Grid> <Grid item @@ -68,7 +147,10 @@ function FormFieldRadio(props) { xs={5} className={classes.questionsGrid} > - <RadioGroup>{options}</RadioGroup> + <RadioGroup> + {options} + <Typography className={classes.validation}>{valid}</Typography> + </RadioGroup> </Grid> </Grid> </Paper> diff --git a/src/components/fieldsAnswerForm/FormFieldSelect.js b/src/components/fieldsAnswerForm/FormFieldSelect.js index 46ee77babe54fa416c76aaac1f39e05cd0eb805a..d00a1ba8390609ec6bb4d0c41c46961a272bfbe1 100644 --- a/src/components/fieldsAnswerForm/FormFieldSelect.js +++ b/src/components/fieldsAnswerForm/FormFieldSelect.js @@ -1,67 +1,155 @@ -import React from 'react'; -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 DeleteOutlinedIcon from '@material-ui/icons/DeleteOutlined'; -import IconButton from '@material-ui/core/IconButton'; -import Select from '@material-ui/core/Select'; -import MenuItem from '@material-ui/core/MenuItem'; -import AddCircleIcon from '@material-ui/icons/AddCircle'; -import CloseIcon from '@material-ui/icons/Close'; -import Switch from '@material-ui/core/Switch'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import Typography from '@material-ui/core/Typography'; - -import FieldFooterOptions from './FieldFooterOptions'; +import React, { useState, useEffect } from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import Paper from "@material-ui/core/Paper"; +import Select from "@material-ui/core/Select"; +import MenuItem from "@material-ui/core/MenuItem"; +import Typography from "@material-ui/core/Typography"; +import FieldFooterOptions from "./FieldFooterOptions"; const useStyles = makeStyles(theme => ({ paper: { padding: theme.spacing(3), width: theme.spacing(100), - minheight: theme.spacing(16), - margin: theme.spacing(2) + minheight: theme.spacing(18), + margin: theme.spacing(2), + ["@media (max-width:827px)"]: { + width: theme.spacing(70) + }, + ["@media (max-width:590px)"]: { + width: theme.spacing(40) + } }, questionsGrid: { - marginBottom: '20px' + marginBottom: "20px" }, + text: { + color: "black" + }, + validation: { + fontSize: "14px", + color: "red" + } })); - - function FormFieldSelect(props) { const classes = useStyles(); + /** Temporary array to be used as a type. */ + function vetorTmp() { + let tmp = []; + props.options.map(x => { + tmp.push(false); + }); + return tmp; + } + + /** Variable that displays the validation message. */ + const [valid, setValid] = React.useState(); + + /** Input number that was just selected. */ + const [selectedValue, setselectedValue] = React.useState(); + + /** + * Function to validate an input based on input validation. + * @param answer - Input to be validated. + */ + function validate(answer) { + let isValid = true; + + setValid(""); + props.validation.map(val => { + switch (val.type) { + case 2: + if ( + !answer.some(value => { + return value === true; + }) + ) { + setValid("Campo obrigatório."); + isValid = false; + } + break; + default: + isValid = true; + } + }); + + return isValid; + } + + /** + * Function to set the selectedValue as the event. + * @param event - React event to get what is selected. + */ + const handleChange = event => { + validate([]); + setselectedValue(event.target.value); + }; + + /** Array of boolean to specify what is selected as true */ + const [checkedArray, setcheckedArray] = React.useState(vetorTmp()); + + /** + * Function to send answer to the father component. + * @param index - Number of the selected value. + */ + function handleArray(index) { + for (let i = 0; i < checkedArray.length; ++i) { + checkedArray[i] = false; + } + + checkedArray[index] = !checkedArray[index]; + if (validate(checkedArray)) { + props.createAnswer(props.id, checkedArray, false); + } else { + props.createAnswer(props.id, checkedArray, true); + } + } + + /** HTML object to be displayed on component return. */ const options = props.options.map(function(x) { - return <MenuItem value={x.value}>{x.value}</MenuItem>; + return <MenuItem value={x.placement}>{x.value}</MenuItem>; }); + /** Everytime selectedValue is changed it's sent to the father component. */ + useEffect(() => { + handleArray(selectedValue); + }, [selectedValue]); + return ( <Paper className={classes.paper}> <Grid container> <Grid item xs={12} className={classes.questionsGrid}> - <Typography variant="h6" gutterBottom> + <Typography className={classes.text} variant="h6"> {props.question} </Typography> + <Typography variant="h8" gutterBottom> + {props.description} + </Typography> </Grid> - <Grid item container + <Grid + item + container direction="column" justify="flex-start" - alignItems="flex-start" xs={5} className={classes.questionsGrid} + alignItems="flex-start" + xs={5} + className={classes.questionsGrid} > <Select labelId="demo-simple-select-label" id="demo-simple-select" - // onChange={handleChange} + onChange={handleChange} > {options} </Select> + <Typography className={classes.validation}>{valid}</Typography> </Grid> </Grid> </Paper> ); - } -export default FormFieldSelect; \ No newline at end of file +export default FormFieldSelect; diff --git a/src/components/fieldsAnswerForm/FormFieldSubform.js b/src/components/fieldsAnswerForm/FormFieldSubform.js new file mode 100644 index 0000000000000000000000000000000000000000..7a14fb8bb75a55c185a1a3f60fc00bafde33c460 --- /dev/null +++ b/src/components/fieldsAnswerForm/FormFieldSubform.js @@ -0,0 +1,116 @@ +import React, { useState, useEffect } from "react"; +import { useParams } from "react-router-dom"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import Button from "@material-ui/core/Button"; +import api from "../../api"; + +import FormFieldText from "./FormFieldText"; +import FormFieldSelect from "./FormFieldSelect"; +import FormFieldRadio from "./FormFieldRadio"; +import FormFieldCheckbox from "./FormFieldCheckbox"; + +const useStyles = makeStyles(theme => ({ + menu: { + width: theme.spacing(6), + minheight: theme.spacing(15), + position: "fixed", + top: theme.spacing(10), + left: "90%", + padding: theme.spacing(1) + } +})); + +function FormFieldSubform(props) { + const classes = useStyles(); + + /** Subform id */ + const id = props.id; + + /** Maped subform */ + const [formData, setFormData] = useState(0); + + /** Get subform */ + async function getForm(id) { + const res = await api.get(`/form/${id}`).then(function(res) { + setFormData(res.data); + props.mapInputs(res.data); + }); + } + + /** First gets info from the backend */ + useEffect(() => { + getForm(id); + }, []); + + return ( + <div> + <Grid container direction="column" alignItems="center" justify="center"> + {formData ? ( + <div> + {formData.inputs.map((input, index) => { + if (input.type === 0) + return ( + <FormFieldText + question={input.question} + validation={input.validation} + description={input.description} + id={input.id} + createAnswer={props.createAnswer} + /> + ); + else if (input.type === 3) + return ( + <FormFieldSelect + question={input.question} + validation={input.validation} + id={input.id} + description={input.description} + options={input.sugestions} + createAnswer={props.createAnswer} + /> + ); + else if (input.type === 2) + return ( + <FormFieldRadio + question={input.question} + description={input.description} + id={input.id} + validation={input.validation} + options={input.sugestions} + createAnswer={props.createAnswer} + /> + ); + else if (input.type === 1) + return ( + <FormFieldCheckbox + question={input.question} + description={input.description} + validation={input.validation} + options={input.sugestions} + id={input.id} + createAnswer={props.createAnswer} + /> + ); + else if (input.type === 4) + return ( + <FormFieldSubform + question={input.question} + description={input.description} + options={input.sugestions} + id={input.subForm.contentFormId} + createAnswer={props.createAnswer} + mapInputs={props.mapInputs} + /> + ); + })} + </div> + ) : ( + <p>Loading...</p> + )} + </Grid> + </div> + ); +} + +export default FormFieldSubform; diff --git a/src/components/fieldsAnswerForm/FormFieldText.js b/src/components/fieldsAnswerForm/FormFieldText.js index 91e2f594edaa680195880ac1df7abf57daa69513..1ad6d0cbcd2fdf117840ca9653d9bac7ee1ecec8 100644 --- a/src/components/fieldsAnswerForm/FormFieldText.js +++ b/src/components/fieldsAnswerForm/FormFieldText.js @@ -1,10 +1,8 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; 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 DeleteOutlinedIcon from "@material-ui/icons/DeleteOutlined"; -import IconButton from "@material-ui/core/IconButton"; import Typography from "@material-ui/core/Typography"; import FieldFooterOptions from "./FieldFooterOptions"; @@ -13,31 +11,108 @@ const useStyles = makeStyles(theme => ({ paper: { padding: theme.spacing(3), width: theme.spacing(100), - height: theme.spacing(16), - margin: theme.spacing(2) + height: "15%", + margin: theme.spacing(2), + ["@media (max-width:827px)"]: { + width: theme.spacing(70) + }, + ["@media (max-width:590px)"]: { + width: theme.spacing(40) + } }, questionsGrid: { marginBottom: "20px" + }, + text: { + color: "black" + }, + validation: { + fontSize: "14px", + color: "red" } })); function FormFieldText(props) { const classes = useStyles(); + /** Variable that displays the validation message. */ + const [valid, setValid] = React.useState(); + + /** + * Function to validate an input based on input validation. + * @param answer - Input to be validated. + */ + function validate(answer) { + let isValid = true; + + setValid(""); + props.validation.map(val => { + switch (val.type) { + case 2: + if (answer === "") { + setValid("Campo obrigatório."); + isValid = false; + } + break; + case 3: + if (answer.length > Number(val.arguments[0])) { + setValid( + "Este campo requer o máximo de " + val.arguments[0] + " digitos." + ); + isValid = false; + } + break; + case 4: + if (answer.length < Number(val.arguments[0])) { + setValid( + "Este campo requer o mínimo de " + val.arguments[0] + " digitos." + ); + isValid = false; + } + break; + default: + isValid = true; + } + }); + + return isValid; + } + + /** + * Function to send answer to the father component. + * @param event - React event to get what is typed in. + */ + const handleChange = event => { + if (validate(event.target.value)) { + props.createAnswer(props.id, event.target.value, false); + } else { + props.createAnswer(props.id, event.target.value, true); + } + }; + + /** First validates an empty string. */ + useEffect(() => { + validate(""); + }, []); + return ( <Paper className={classes.paper}> <Grid container> <Grid item xs={12} className={classes.questionsGrid}> - <Typography variant="h6" gutterBottom> + <Typography className={classes.text} variant="h6"> {props.question} </Typography> + <Typography variant="h8">{props.description}</Typography> </Grid> <Grid item xs={9} className={classes.questionsGrid}> <TextField + multiline id="outlined-disabled" label="" - placeholder="Resposta curta" + placeholder="Resposta" + onChange={handleChange} /> + <Typography className={classes.validation}>{valid}</Typography> </Grid> <Grid item diff --git a/src/components/fieldsAnswerForm/FormFieldTitle.js b/src/components/fieldsAnswerForm/FormFieldTitle.js index 52c907b48c241a0715c967379024f82e2d75446b..34a2d79a7eaf5255acba28b33055ffd6cad1a421 100644 --- a/src/components/fieldsAnswerForm/FormFieldTitle.js +++ b/src/components/fieldsAnswerForm/FormFieldTitle.js @@ -2,9 +2,6 @@ import React from 'react'; 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 DeleteOutlinedIcon from '@material-ui/icons/DeleteOutlined'; -import IconButton from '@material-ui/core/IconButton'; import Typography from '@material-ui/core/Typography'; import FieldFooterOptions from './FieldFooterOptions'; @@ -13,45 +10,72 @@ const useStyles = makeStyles(theme => ({ paper: { padding: theme.spacing(3), width: theme.spacing(100), - height: theme.spacing(16), - margin: theme.spacing(2) + height: theme.spacing(22), + margin: theme.spacing(2), + color: '#000000', + ["@media (max-width:827px)"]: { + width: theme.spacing(70) + }, + ["@media (max-width:590px)"]: { + width: theme.spacing(40) + } }, questionsGrid: { - marginBottom: '20px' - }, - title: { - fontSize: 'xx-large' - }, - description: { - fontSize: 'x-large' - }, + marginBottom: '20px', + color: '#000000', + ["@media (max-width:827px)"]: { + width: theme.spacing(70) + } + }, + title: { + fontSize: '45px', + color: '#000000', + ["@media (max-width:827px)"]: { + fontSize: '35px' + }, + ["@media (max-width:590px)"]: { + fontSize: '25px' + } + }, + description: { + fontSize: '30px', + color: '#000000', + ["@media (max-width:827px)"]: { + fontSize: '25px' + }, + ["@media (max-width:590px)"]: { + fontSize: '15px' + } + }, })); function FormFieldText(props) { const classes = useStyles(); return ( - <Paper className={classes.paper}> - <Grid container> - <Grid item xs={12} className={classes.questionsGrid}> - <Typography variant="h3" gutterBottom> - {props.title} - </Typography> - </Grid> - <Grid item xs={9} className={classes.questionsGrid}> - <Typography variant="h4" gutterBottom> - {props.description} - </Typography> - </Grid> - <Grid item container - direction="row" - justify="flex-end" - alignItems="flex-end" - xs={3} - > + <Grid> + <Paper className={classes.paper}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Typography className={classes.title} variant="h3" gutterBottom> + {props.title} + </Typography> + </Grid> + <Grid item xs={9} className={classes.questionsGrid}> + <Typography className={classes.description} variant="h4" gutterBottom> + {props.description} + </Typography> + </Grid> + <Grid item container + direction="row" + justify="flex-end" + alignItems="flex-end" + xs={3} + > + </Grid> </Grid> - </Grid> - </Paper> + </Paper> + </Grid> ); } diff --git a/src/pages/AnswerForm.js b/src/pages/AnswerForm.js index f123fd561bb6d80f8b7127b20a30462a1e3591b5..f09d9e0408172c1165939dd0c713e9eda44f5556 100644 --- a/src/pages/AnswerForm.js +++ b/src/pages/AnswerForm.js @@ -1,97 +1,299 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; -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 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'; -import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; -import Button from '@material-ui/core/Button'; -import axios from 'axios'; - -import FormFieldText from '../components/fieldsAnswerForm/FormFieldText'; -import FormFieldSelect from '../components/fieldsAnswerForm/FormFieldSelect'; -import FormFieldRadio from '../components/fieldsAnswerForm/FormFieldRadio'; -import FormFieldCheckbox from '../components/fieldsAnswerForm/FormFieldCheckbox'; -import FormFieldTitle from '../components/fieldsAnswerForm/FormFieldTitle'; - -import config from '../config'; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import api from "../api"; +import Button from "@material-ui/core/Button"; +import { createMuiTheme, MuiThemeProvider } from "@material-ui/core"; +import FormFieldText from "../components/fieldsAnswerForm/FormFieldText"; +import FormFieldSelect from "../components/fieldsAnswerForm/FormFieldSelect"; +import FormFieldRadio from "../components/fieldsAnswerForm/FormFieldRadio"; +import FormFieldCheckbox from "../components/fieldsAnswerForm/FormFieldCheckbox"; +import FormFieldTitle from "../components/fieldsAnswerForm/FormFieldTitle"; +import FormFieldSubform from "../components/fieldsAnswerForm/FormFieldSubform"; +import { validate } from "json-schema"; const useStyles = makeStyles(theme => ({ menu: { width: theme.spacing(6), minheight: theme.spacing(15), - position: 'fixed', + position: "fixed", top: theme.spacing(10), - left: '90%', + left: "90%", padding: theme.spacing(1) }, + button: { + type: "submit", + width: "100%", + background: "#6ec46c", + borderRadius: "2px", + padding: "10px 20px", + fontSize: "18px", + "&:hover": { + backgroundColor: "rgb(25, 109, 23)" + } + }, + pageBody: { + minHeight: "calc(100vh - 92.4px - 78px)", + paddingBottom: "78px" + } })); +const theme = createMuiTheme({ + overrides: { + MuiInput: { + underline: { + "&:before": { + borderBottom: "1px solid #35c7fc" + }, + "&:after": { + borderBottom: "1px solid #3f51b5" + } + } + }, + MuiButton: { + label: { + color: "black" + } + } + } +}); + function AnwserForm() { const classes = useStyles(); + /** Array of answers created when form is maped from the api */ + const [answerArray, setanswerArray] = React.useState([]); + + /** + * Function to update the array of answers. + * @param id - Input's id that was just answered. + * @param inputAnswer - Input's answer that was just answered. + * @param error - Boolean variable that indicates if answer is valid or not. + */ + function createAnswer(id, inputAnswer, error) { + for (const answer of answerArray) { + if (id === answer.idInput) { + answer.answerInput = inputAnswer; + answer.error = error; + } + } + } + + /** Function to check if answers are valid */ + function isError() { + return answerArray.some(value => { + return value.error; + }); + } + + /** + * Function to check if some question was answered. + * It wouldn't make sense to have a form answered without any answers on it. + */ + function isAnswer() { + return answerArray.some(value => { + return value.answerInput.length !== 0; + }); + } + + /** Function to check if the answers of a form can generate a JSON */ + function isValid() { + if (!isAnswer()) { + alert("Não há respostas no form"); + return false; + } + + if (isError()) { + alert( + "Erro. Verifique se suas respostas estão de acordo com as validações." + ); + return false; + } + + return true; + } + + /** + * Funtion to generate the JSON object that is sent to the API + */ + function backendTranslation() { + let id; + let retVal = {}; + + if (!isValid()) { + return; + } + + for (const answerObj of answerArray) { + if (answerObj.typeInput === 0 && answerObj.answerInput.length !== 0) { + id = answerObj.idInput; + var answer = answerObj.answerInput; + retVal[id] = [answer]; + } else if ( + (answerObj.typeInput === 1 || + answerObj.typeInput === 2 || + answerObj.typeInput === 3) && + answerObj.answerInput.length !== 0 + ) { + let tmpArray = []; + id = answerObj.idInput; + for (const value of answerObj.answerInput) { + tmpArray.push(String(value)); + } + retVal[id] = tmpArray; + } + } + + return retVal; + } + + /** Form id got from the browser's URL */ const { id } = useParams(); + /** Maped form from backend */ const [formData, setFormData] = useState(0); - function getForm(id) { - axios.get(`${config.genformsapi.url}/form/${id}`) - .then(res => { - console.log(res); - console.log(res.data); - setFormData(res.data); + /** + * Function to send some form answers to the API + * @param id - Form id got from the broswer's URL + */ + async function answerForm(id) { + const res = await api + .post(`/answer/${id}`, backendTranslation()) + .then(function(res) { + alert("Formulário respondido!"); }); - } + } - function answerForm() { - axios.post(`${config.genformsapi.url}/form`) - .then(res => { - console.log(res); - console.log(res.data); - }); + /** + * Function to map form inputs from the backend. + * @param form - Form object that just came from the API. + */ + function mapInputs(form) { + form.inputs.map(input => { + if ( + input.validation.some(value => { + return value.type === 2 || value.type === 6; + }) + ) { + answerArray.push({ + idInput: input.id, + typeInput: input.type, + answerInput: [], + error: true + }); + } else { + answerArray.push({ + idInput: input.id, + typeInput: input.type, + answerInput: [], + error: false + }); + } + }); } + /** + * Function to get form object from the API. + * @param id - Form id got from the broswer's URL + */ + async function getForm(id) { + const res = await api.get(`/form/${id}`).then(function(res) { + setFormData(res.data); + mapInputs(res.data); + }); + } + + /** First thing the page does is getting the form from the API. */ useEffect(() => { getForm(id); }, []); return ( - <div> - <Grid - container - direction="column" - alignItems="center" - justify="center" - > - - { - formData ? - <div> - <FormFieldTitle title={formData.title} description={formData.description}/> - { - formData.inputs.map((x, index) => { - if(x.type === 0) - return <FormFieldText question={x.question}/> - else if(x.type === 4) - return <FormFieldSelect question={x.question} options={x.sugestions}/> - else if(x.type === 2) - return <FormFieldRadio question={x.question} options={x.sugestions}/> - else if(x.type === 1) - return <FormFieldCheckbox question={x.question} options={x.sugestions}/> - }) - } - </div> : <p>Loading...</p> - } - <Button variant="contained" color="primary" onClick={answerForm}> - Responder - </Button> - </Grid> - </div> + <MuiThemeProvider theme={theme}> + <div className={classes.pageBody}> + <Grid container direction="column" alignItems="center" justify="center"> + {formData ? ( + <div> + <FormFieldTitle + title={formData.title} + description={formData.description} + /> + {formData.inputs.map((input, index) => { + if (input.type === 0) + return ( + <FormFieldText + question={input.question} + validation={input.validation} + description={input.description} + id={input.id} + createAnswer={createAnswer} + /> + ); + else if (input.type === 3) + return ( + <FormFieldSelect + question={input.question} + validation={input.validation} + id={input.id} + description={input.description} + options={input.sugestions} + createAnswer={createAnswer} + /> + ); + else if (input.type === 2) + return ( + <FormFieldRadio + question={input.question} + description={input.description} + id={input.id} + validation={input.validation} + options={input.sugestions} + createAnswer={createAnswer} + /> + ); + else if (input.type === 1) + return ( + <FormFieldCheckbox + question={input.question} + description={input.description} + validation={input.validation} + options={input.sugestions} + id={input.id} + createAnswer={createAnswer} + /> + ); + else if (input.type === 4) + return ( + <FormFieldSubform + question={input.question} + description={input.description} + options={input.sugestions} + id={input.subForm.contentFormId} + createAnswer={createAnswer} + mapInputs={mapInputs} + /> + ); + })} + </div> + ) : ( + <p>Loading...</p> + )} + <Grid> + <Button + type="submit" + variant="contained" + className={classes.button} + onClick={() => answerForm(id)} + > + Responder + </Button> + </Grid> + </Grid> + </div> + </MuiThemeProvider> ); }