From 302554c9d9413abcd9fb4438abd6263eec6f1223 Mon Sep 17 00:00:00 2001 From: Richard Fernando Heise Ferreira <rfhf19@inf.ufpr.br> Date: Fri, 17 Jul 2020 12:31:57 -0300 Subject: [PATCH] Issue #13: Add visualize form page Signed-off-by: Richard Heise <rfhf19@inf.ufpr.br> --- src/App.js | 2 + .../JornalFolder/FieldFooterOptions.js | 40 +++ .../JornalFolder/FormFieldCheckbox.js | 88 +++++++ .../JornalFolder/FormFieldRadio.js | 89 +++++++ .../JornalFolder/FormFieldSelect.js | 95 ++++++++ .../JornalFolder/FormFieldSubform.js | 123 ++++++++++ .../JornalFolder/FormFieldText.js | 93 +++++++ .../JornalFolder/FormFieldTitle.js | 87 +++++++ .../fieldsGetForm/JornalFolder/FormJornal.js | 181 ++++++++++++++ .../JornalFolder/FormPagination.js | 164 +++++++++++++ .../fieldsGetForm/JornalFolder/JornalTab.js | 43 ++++ .../SummaryFolder/FieldFooterOptions.js | 33 +++ .../SummaryFolder/FormFieldCheckbox.js | 93 +++++++ .../SummaryFolder/FormFieldRadio.js | 96 ++++++++ .../SummaryFolder/FormFieldSelect.js | 95 ++++++++ .../SummaryFolder/FormFieldSubform.js | 126 ++++++++++ .../SummaryFolder/FormFieldText.js | 144 +++++++++++ .../SummaryFolder/FormFieldTitle.js | 93 +++++++ .../SummaryFolder/FormSummary.js | 161 ++++++++++++ src/pages/GetForm.js | 229 ++++++++++++++++++ 20 files changed, 2075 insertions(+) create mode 100644 src/components/fieldsGetForm/JornalFolder/FieldFooterOptions.js create mode 100644 src/components/fieldsGetForm/JornalFolder/FormFieldCheckbox.js create mode 100644 src/components/fieldsGetForm/JornalFolder/FormFieldRadio.js create mode 100644 src/components/fieldsGetForm/JornalFolder/FormFieldSelect.js create mode 100644 src/components/fieldsGetForm/JornalFolder/FormFieldSubform.js create mode 100644 src/components/fieldsGetForm/JornalFolder/FormFieldText.js create mode 100644 src/components/fieldsGetForm/JornalFolder/FormFieldTitle.js create mode 100644 src/components/fieldsGetForm/JornalFolder/FormJornal.js create mode 100644 src/components/fieldsGetForm/JornalFolder/FormPagination.js create mode 100644 src/components/fieldsGetForm/JornalFolder/JornalTab.js create mode 100644 src/components/fieldsGetForm/SummaryFolder/FieldFooterOptions.js create mode 100644 src/components/fieldsGetForm/SummaryFolder/FormFieldCheckbox.js create mode 100644 src/components/fieldsGetForm/SummaryFolder/FormFieldRadio.js create mode 100644 src/components/fieldsGetForm/SummaryFolder/FormFieldSelect.js create mode 100644 src/components/fieldsGetForm/SummaryFolder/FormFieldSubform.js create mode 100644 src/components/fieldsGetForm/SummaryFolder/FormFieldText.js create mode 100644 src/components/fieldsGetForm/SummaryFolder/FormFieldTitle.js create mode 100644 src/components/fieldsGetForm/SummaryFolder/FormSummary.js create mode 100644 src/pages/GetForm.js diff --git a/src/App.js b/src/App.js index f909603..64dc8a2 100644 --- a/src/App.js +++ b/src/App.js @@ -9,6 +9,7 @@ import SignUp from "./pages/SignUp"; import SignIn from "./pages/SignIn"; import ListForms from "./pages/ListForms"; import EditForm from "./pages/EditForm"; +import GetForm from "./pages/GetForm"; function App() { return ( <HashRouter> @@ -19,6 +20,7 @@ function App() { <Route path="/SignUp" component={SignUp} /> <Route path="/SignIn" component={SignIn} /> <Route path="/list/:id" component={ListForms} /> + <Route path="/form/:id" component={GetForm} /> <Footer /> </HashRouter> ); diff --git a/src/components/fieldsGetForm/JornalFolder/FieldFooterOptions.js b/src/components/fieldsGetForm/JornalFolder/FieldFooterOptions.js new file mode 100644 index 0000000..f6446f0 --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FieldFooterOptions.js @@ -0,0 +1,40 @@ +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'; + +function FieldFooterOptions(props) { + + return ( + <> + <FormControlLabel + control={ + <Switch + onChange={e => props.setRequiredField(props.idq) } + value="required" + color="primary" + checked={props.required} + /> + } + label="Obrigatória" + /> + <IconButton aria-label="delete" onClick={() => { props.deleteFromForm(props.idq) } }> + <DeleteOutlinedIcon /> + </IconButton> + </> + ); + + +} + + +export default FieldFooterOptions; \ No newline at end of file diff --git a/src/components/fieldsGetForm/JornalFolder/FormFieldCheckbox.js b/src/components/fieldsGetForm/JornalFolder/FormFieldCheckbox.js new file mode 100644 index 0000000..119e9a9 --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FormFieldCheckbox.js @@ -0,0 +1,88 @@ +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 Typography from "@material-ui/core/Typography"; +import Checkbox from "@material-ui/core/Checkbox"; + +import FieldFooterOptions from "./FieldFooterOptions"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + marginBottom: "2%", + ["@media (max-width: 896px)"]: { + width: "300px" + } + }, + questionsGrid: { + marginBottom: "20px" + }, + text: { + color: "black" + } +})); + +function FormFieldCheckbox(props) { + const classes = useStyles(); + + /** + * Function to check if an index has a true value. + * @param index - Index of a given value. + */ + function handleProps(index) { + if (props.answer) { + if (props.answer[index].value === "false") { + return false; + } + return true; + } + return false; + } + + /** HTML to be displayed. */ + const options = props.options.map((x, index) => { + return ( + <span> + <Typography className={classes.text} variant="h7"> + {x.value} + </Typography> + <Checkbox checked={handleProps(index)} disabled /> + </span> + ); + }); + + return ( + <Paper className={classes.paper}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Typography>id: {Number(props.place)}</Typography> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.text} + variant="h6" + > + {props.question} + </Typography> + <Typography style={{ wordWrap: "break-word" }} variant="h8"> + {props.description} + </Typography> + </Grid> + <Grid + item + container + direction="column" + justify="flex-start" + alignItems="flex-start" + xs={5} + className={classes.questionsGrid} + > + {options} + </Grid> + </Grid> + </Paper> + ); +} + +export default FormFieldCheckbox; diff --git a/src/components/fieldsGetForm/JornalFolder/FormFieldRadio.js b/src/components/fieldsGetForm/JornalFolder/FormFieldRadio.js new file mode 100644 index 0000000..441eb79 --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FormFieldRadio.js @@ -0,0 +1,89 @@ +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 Typography from "@material-ui/core/Typography"; +import Radio from "@material-ui/core/Radio"; +import RadioGroup from "@material-ui/core/RadioGroup"; + +import FieldFooterOptions from "./FieldFooterOptions"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + marginBottom: "2%", + ["@media (max-width: 896px)"]: { + width: "300px" + } + }, + questionsGrid: { + marginBottom: "20px" + }, + text: { + color: "black" + } +})); + +function FormFieldRadio(props) { + const classes = useStyles(); + + /** + * Function to check if an index has a true value. + * @param index - Index of a given value. + */ + function handleProps(index) { + if (props.answer) { + if (props.answer[index].value === "false") { + return false; + } + return true; + } + return false; + } + + /** HTML object to be displayed on component return. */ + const options = props.options.map(function(x, index) { + return ( + <span> + <Typography className={classes.text} variant="h7"> + {x.value} + </Typography> + <Radio disabled checked={handleProps(index)} value={x.value} /> + </span> + ); + }); + + return ( + <Paper className={classes.paper}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Typography>id: {Number(props.place)}</Typography> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.text} + variant="h6" + > + {props.question} + </Typography> + <Typography style={{ wordWrap: "break-word" }} variant="h8"> + {props.description} + </Typography> + </Grid> + <Grid + item + container + direction="column" + justify="flex-start" + alignItems="flex-start" + xs={5} + className={classes.questionsGrid} + > + <RadioGroup>{options}</RadioGroup> + </Grid> + </Grid> + </Paper> + ); +} + +export default FormFieldRadio; diff --git a/src/components/fieldsGetForm/JornalFolder/FormFieldSelect.js b/src/components/fieldsGetForm/JornalFolder/FormFieldSelect.js new file mode 100644 index 0000000..5c175d1 --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FormFieldSelect.js @@ -0,0 +1,95 @@ +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), + marginBottom: "2%", + ["@media (max-width: 896px)"]: { + width: "300px" + } + }, + questionsGrid: { + marginBottom: "20px" + }, + text: { + color: "black" + } +})); + +function FormFieldSelect(props) { + const classes = useStyles(); + + /** Variable to track if there's an answer. */ + const [hasAnswer, setHasAnswer] = useState(false); + + /** + * Function to handle the selected answer. + */ + function handleProps() { + if (props.answer) { + setHasAnswer(true); + return props.answer.filter(each => { + return each.value === "true"; + })[0].placement; + } else { + setHasAnswer(false); + } + } + + /** + * Function to prevent page from broking if there's no answer. + */ + function answer() { + if (hasAnswer) { + return props.options[handleProps()].value; + } + } + + return ( + <Paper className={classes.paper}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Typography>id: {Number(props.place)}</Typography> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.text} + variant="h6" + > + {props.question} + </Typography> + <Typography + style={{ wordWrap: "break-word" }} + variant="h8" + gutterBottom + > + {props.description} + </Typography> + </Grid> + <Grid + item + container + direction="column" + justify="flex-start" + alignItems="flex-start" + xs={5} + className={classes.questionsGrid} + > + <Select disabled value={""} displayEmpty> + <MenuItem value="">{answer()}</MenuItem> + </Select> + </Grid> + </Grid> + </Paper> + ); +} + +export default FormFieldSelect; diff --git a/src/components/fieldsGetForm/JornalFolder/FormFieldSubform.js b/src/components/fieldsGetForm/JornalFolder/FormFieldSubform.js new file mode 100644 index 0000000..980d51d --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FormFieldSubform.js @@ -0,0 +1,123 @@ +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); + }) + .catch(error => { + alert( + "Um erro inesperado ocorreu ao tentar obter o subform na tela de Jornal." + ); + }); + } + + /** 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} + description={input.description} + id={input.id} + answer={props.findAnswer(input.id)} + place={input.placement + props.place} + /> + ); + else if (input.type === 3) + return ( + <FormFieldSelect + question={input.question} + id={input.id} + description={input.description} + options={input.sugestions} + answer={props.findAnswer(input.id)} + place={input.placement + props.place} + /> + ); + else if (input.type === 2) + return ( + <FormFieldRadio + question={input.question} + description={input.description} + id={input.id} + options={input.sugestions} + answer={props.findAnswer(input.id)} + place={input.placement + props.place} + /> + ); + else if (input.type === 1) + return ( + <FormFieldCheckbox + question={input.question} + description={input.description} + options={input.sugestions} + id={input.id} + answer={props.findAnswer(input.id)} + place={input.placement + props.place} + /> + ); + else if (input.type === 4) + return ( + <FormFieldSubform + question={input.question} + description={input.description} + options={input.sugestions} + id={input.subForm.contentFormId} + findAnswer={props.findAnswer} + answer={props.findAnswer(input.id)} + place={input.placement} + /> + ); + })} + </div> + ) : ( + <p>Loading...</p> + )} + </Grid> + </div> + ); +} + +export default FormFieldSubform; diff --git a/src/components/fieldsGetForm/JornalFolder/FormFieldText.js b/src/components/fieldsGetForm/JornalFolder/FormFieldText.js new file mode 100644 index 0000000..f0969f4 --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FormFieldText.js @@ -0,0 +1,93 @@ +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 Typography from "@material-ui/core/Typography"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + marginBottom: "2%", + ["@media (max-width: 896px)"]: { + width: "300px" + } + }, + answersGrid: { + flexDirection: "column", + color: "black" + }, + description: { + marginBottom: "10px" + }, + questionsGrid: { + marginBottom: "10px" + }, + answer: { + color: "black", + marginBottom: "5px" + } +})); + +function FormFieldText(props) { + const classes = useStyles(); + + /** + * Function to display an answer or an messange if there's no answer. + */ + function answer() { + if (props.answer) { + return props.answer[0].value; + } + + return "Nenhuma resposta"; + } + + return ( + <Paper className={classes.paper}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Typography>id: {Number(props.place)}</Typography> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.text} + variant="h6" + gutterBottom + > + {"Pergunta: " + props.question} + </Typography> + <Grid className={classes.description} container> + <Typography + style={{ wordWrap: "break-word" }} + container + item + variant="h8" + > + {"Descrição: " + props.description} + </Typography> + </Grid> + <Typography + style={{ wordWrap: "break-word" }} + gutterBottom + variant="h6" + > + Resposta: + </Typography> + </Grid> + <Grid container wrap="wrap" container className={classes.answersGrid}> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.answer} + container + wrap="wrap" + variant="body1" + > + {answer()} + </Typography> + </Grid> + </Grid> + </Paper> + ); +} + +export default FormFieldText; diff --git a/src/components/fieldsGetForm/JornalFolder/FormFieldTitle.js b/src/components/fieldsGetForm/JornalFolder/FormFieldTitle.js new file mode 100644 index 0000000..d334754 --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FormFieldTitle.js @@ -0,0 +1,87 @@ +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 Typography from "@material-ui/core/Typography"; + +import FieldFooterOptions from "./FieldFooterOptions"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + height: theme.spacing(22), + margin: theme.spacing(2), + color: "#000000" + }, + questionsGrid: { + 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 ( + <Grid> + <Paper className={classes.paper}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.title} + variant="h3" + gutterBottom + > + {props.title} + </Typography> + </Grid> + <Grid item xs={9} className={classes.questionsGrid}> + <Typography + style={{ wordWrap: "break-word" }} + 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> + </Paper> + </Grid> + ); +} + +export default FormFieldText; diff --git a/src/components/fieldsGetForm/JornalFolder/FormJornal.js b/src/components/fieldsGetForm/JornalFolder/FormJornal.js new file mode 100644 index 0000000..d7826dc --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FormJornal.js @@ -0,0 +1,181 @@ +import React, { useState, useEffect } from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import { createMuiTheme, MuiThemeProvider } from "@material-ui/core"; +import Typography from "@material-ui/core/Typography"; + +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 JornalTab from "./JornalTab"; +import { validate } from "json-schema"; + +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) + }, + formControl: { + margin: theme.spacing(1), + minWidth: 120, + ["@media (max-width: 446px)"]: { + marginRight: "100px", + marginBottom: "20px" + } + }, + container: { + flexDirection: "column", + justifyContent: "space-between", + backgroundColor: "white", + marginBottom: "20px", + marginLeft: "2%", + minHeight: "calc(100vh - 92.4px - 78px)", + paddingBottom: "78px", + justifyContent: "center" + }, + gridMenu: { + display: "flex", + alignItems: "center", + marginLeft: "20px" + }, + formTitle: { + marginTop: "10px" + }, + + date: { + marginLeft: "30%", + ["@media (max-width: 494px)"]: { + marginLeft: "3%" + } + } +})); + +function Jornal(props) { + const classes = useStyles(); + + /** Variable of the selected form number in an array of forms. */ + const [selectedForm, setSelectedForm] = useState(0); + + /** + * Date parser and validator. + * @param date - Date string to be parsed. + */ + function manageDate(date) { + if (date === "") { + return ""; + } + + let newDate = new Date(date); + let options = { year: "numeric", month: "2-digit", day: "2-digit" }; + return newDate.toLocaleDateString("pt-BR", options); + } + + /** + * Function to find the array of answers of a given question. + * @param questionId - Question's ID. + */ + function findAnswer(questionId) { + if (props.formArray[selectedForm].inputAnswers[questionId]) { + return Object.values( + props.formArray[selectedForm].inputAnswers[questionId] + ); + } + } + + /** + * Function to change the current page to a new one. + * @param page - Selected page. + */ + function changePage(page) { + setSelectedForm(page - 1); + } + + return ( + <> + <JornalTab + answerNumber={props.answerNumber} + pagesNum={props.formArray.length} + changePage={changePage} + /> + <Grid + container + direction="column" + className={classes.container} + alignItems="center" + justify="center" + > + <div> + <Grid container item className={classes.date}> + <Typography> + Data da resposta: {manageDate(props.timestamp[selectedForm])} + </Typography> + </Grid> + {props.formArray[selectedForm].form.inputs.map((input, index) => { + if (input.type === 0) + return ( + <FormFieldText + question={input.question} + description={input.description} + id={input.id} + answer={findAnswer(input.id)} + place={input.placement} + /> + ); + else if (input.type === 3) + return ( + <FormFieldSelect + question={input.question} + id={input.id} + description={input.description} + options={input.sugestions} + answer={findAnswer(input.id)} + place={input.placement} + /> + ); + else if (input.type === 2) + return ( + <FormFieldRadio + question={input.question} + description={input.description} + id={input.id} + options={input.sugestions} + answer={findAnswer(input.id)} + place={input.placement} + /> + ); + else if (input.type === 1) + return ( + <FormFieldCheckbox + question={input.question} + description={input.description} + options={input.sugestions} + id={input.id} + answer={findAnswer(input.id)} + place={input.placement} + /> + ); + else if (input.type === 4) + return ( + <FormFieldSubform + question={input.question} + description={input.description} + options={input.sugestions} + id={input.subForm.contentFormId} + findAnswer={findAnswer} + place={input.placement - 1} + /> + ); + })} + </div> + </Grid> + </> + ); +} +export default Jornal; diff --git a/src/components/fieldsGetForm/JornalFolder/FormPagination.js b/src/components/fieldsGetForm/JornalFolder/FormPagination.js new file mode 100644 index 0000000..e64429c --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/FormPagination.js @@ -0,0 +1,164 @@ +import React, { useState, useEffect } from "react"; +import Grid from "@material-ui/core/Grid"; +import TextField from "@material-ui/core/TextField"; +import Button from "@material-ui/core/Button"; +import NavigateBeforeIcon from "@material-ui/icons/NavigateBefore"; +import NavigateNextIcon from "@material-ui/icons/NavigateNext"; + +import { makeStyles } from "@material-ui/core/styles"; +import { Typography } from "@material-ui/core"; +const useStyles = makeStyles(theme => ({ + container: { + flexDirection: "row", + backgroundColor: "white", + marginBottom: "20px" + }, + + text: { + width: "50px", + marginRight: "1px", + marginLeft: "1px" + }, + + button: { + fontSize: "30px", + height: "30px" + }, + + buttonDisabled: { + fontSize: "30px", + height: "30px", + color: "grey" + }, + + valid: { + color: "red" + } +})); + +function FormPagination(props) { + const classes = useStyles(); + + /** Variables declarition */ + const [selectedPage, setSelectedPage] = React.useState(1); + const [isFirst, setIsFirst] = React.useState(true); + const [isLast, setIsLast] = React.useState(false); + const [valid, setValid] = React.useState(""); + + /** + * Function that checks if a value is beetwen 0 and the last page number. + * @param value - Value to be checked. + */ + function checksValid(value) { + if (value <= 0 || value > props.pagesNum) { + return false; + } + + return true; + } + + /** + * Handler of pagination's text field. + * @param event - React event. + */ + const handlePage = event => { + checkPage(event.target.value); + setSelectedPage(event.target.value); + if (/^[0-9\b]+$/.test(event.target.value)) { + if (checksValid(event.target.value)) { + setValid(""); + props.changePage(event.target.value); + } else { + setSelectedPage(setSelectedPage); + setValid("Página não encontrada"); + } + } + }; + + /** + * Function to handle if user cicked on minus button. + */ + function handleMinus() { + checkPage(Number(selectedPage) - 1); + setSelectedPage(Number(selectedPage) - 1); + if (Number(selectedPage) - 1 <= props.pagesNum) { + setValid(""); + } + if (checksValid(selectedPage - 1)) { + props.changePage(selectedPage - 1); + } + } + + /** + * Function to handle if user cicked on plus button. + */ + function handlePlus() { + checkPage(Number(selectedPage) + 1); + setSelectedPage(Number(selectedPage) + 1); + if (Number(selectedPage) + 1 <= props.pagesNum) { + setValid(""); + } + if (checksValid(Number(selectedPage) + 1)) { + props.changePage(Number(selectedPage) + 1); + } + } + + /** + * Function to set the states of isFirs and isLast, uses a value as reference. + * @param value - Value to be used as reference. + */ + function checkPage(value) { + if (value === 1 || value === "") { + setIsFirst(true); + setIsLast(false); + } else { + setIsFirst(false); + if (value >= props.pagesNum) { + setIsLast(true); + } else { + setIsLast(false); + } + } + } + + /** Prevents a bug if there's only one page. */ + useEffect(() => { + if (props.pagesNum === 1) { + setIsLast(true); + } + }, []); + + return ( + <> + <Grid container className={classes.container}> + {isFirst ? ( + <Button disabled onClick={handleMinus}> + <NavigateBeforeIcon + color="grey" + className={classes.buttonDisabled} + /> + </Button> + ) : ( + <Button onClick={handleMinus}> + <NavigateBeforeIcon className={classes.button} /> + </Button> + )} + <Grid className={classes.text} item> + <TextField value={selectedPage} onChange={handlePage} /> + </Grid> + {isLast ? ( + <Button disabled onClick={handlePlus}> + <NavigateNextIcon className={classes.buttonDisabled} /> + </Button> + ) : ( + <Button onClick={handlePlus}> + <NavigateNextIcon className={classes.button} /> + </Button> + )} + </Grid> + <Typography className={classes.valid}>{valid}</Typography> + </> + ); +} + +export default FormPagination; diff --git a/src/components/fieldsGetForm/JornalFolder/JornalTab.js b/src/components/fieldsGetForm/JornalFolder/JornalTab.js new file mode 100644 index 0000000..417fea8 --- /dev/null +++ b/src/components/fieldsGetForm/JornalFolder/JornalTab.js @@ -0,0 +1,43 @@ +import React, { useState, useEffect } from "react"; +import FormControl from "@material-ui/core/FormControl"; +import Grid from "@material-ui/core/Grid"; +import FormPagination from "./FormPagination"; + +import { makeStyles } from "@material-ui/core/styles"; +const useStyles = makeStyles(theme => ({ + container: { + flexDirection: "row", + justifyContent: "space-between", + backgroundColor: "white", + marginBottom: "20px" + }, + + formControl: { + margin: theme.spacing(1), + minWidth: 120 + }, + + gridMenu: { + display: "flex", + alignItems: "center" + } +})); + +function JornalTab(props) { + const classes = useStyles(); + + return ( + <Grid container className={classes.container}> + <Grid item className={classes.gridMenu}> + <FormControl className={classes.formControl}> + <FormPagination + changePage={props.changePage} + pagesNum={props.pagesNum} + /> + </FormControl> + </Grid> + </Grid> + ); +} + +export default JornalTab; diff --git a/src/components/fieldsGetForm/SummaryFolder/FieldFooterOptions.js b/src/components/fieldsGetForm/SummaryFolder/FieldFooterOptions.js new file mode 100644 index 0000000..ebc8504 --- /dev/null +++ b/src/components/fieldsGetForm/SummaryFolder/FieldFooterOptions.js @@ -0,0 +1,33 @@ +import React from "react"; +import DeleteOutlinedIcon from "@material-ui/icons/DeleteOutlined"; +import IconButton from "@material-ui/core/IconButton"; +import Switch from "@material-ui/core/Switch"; +import FormControlLabel from "@material-ui/core/FormControlLabel"; + +function FieldFooterOptions(props) { + return ( + <> + <FormControlLabel + control={ + <Switch + onChange={e => props.setRequiredField(props.idq)} + value="required" + color="primary" + checked={props.required} + /> + } + label="Obrigatória" + /> + <IconButton + aria-label="delete" + onClick={() => { + props.deleteFromForm(props.idq); + }} + > + <DeleteOutlinedIcon /> + </IconButton> + </> + ); +} + +export default FieldFooterOptions; diff --git a/src/components/fieldsGetForm/SummaryFolder/FormFieldCheckbox.js b/src/components/fieldsGetForm/SummaryFolder/FormFieldCheckbox.js new file mode 100644 index 0000000..8c71c26 --- /dev/null +++ b/src/components/fieldsGetForm/SummaryFolder/FormFieldCheckbox.js @@ -0,0 +1,93 @@ +import React, { useEffect } from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import Typography from "@material-ui/core/Typography"; +import ExpansionPanel from "@material-ui/core/ExpansionPanel"; +import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary"; +import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails"; +import ArrowDownwardOutlinedIcon from "@material-ui/icons/ArrowDownwardOutlined"; +import Checkbox from "@material-ui/core/Checkbox"; +import Tooltip from "@material-ui/core/Tooltip"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + marginBottom: "2%", + ["@media (max-width: 896px)"]: { + width: "300px" + } + }, + questionsGrid: { + marginBottom: "20px" + }, + text: { + color: "black" + }, + expPainelD: { + display: "block" + }, + type: { + width: "50px" + } +})); + +function FormFieldCheckbox(props) { + const classes = useStyles(); + + /** HTML object to be displayed on component return. */ + const options = props.options.map((x, index) => { + return props.answer[x.placement] ? ( + <Typography + style={{ wordWrap: "break-word" }} + gutterBottom + className={classes.text} + > + Opção {x.value} foi marcada por {props.answer[x.placement]} pessoa(s). + </Typography> + ) : ( + <Typography style={{ wordWrap: "break-word" }} gutterBottom> + Opção {x.value} não foi marcada. + </Typography> + ); + }); + + return ( + <ExpansionPanel className={classes.paper}> + <ExpansionPanelSummary expandIcon={<ArrowDownwardOutlinedIcon />}> + <Grid item xs={12} className={classes.questionsGrid}> + <Tooltip placement="left" title="Múltipla escolha" arrow> + <Grid container className={classes.type}> + <Checkbox disabled /> + </Grid> + </Tooltip> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.text} + variant="h6" + > + {props.question} + </Typography> + <Typography style={{ wordWrap: "break-word" }} variant="h8"> + {props.description} + </Typography> + </Grid> + </ExpansionPanelSummary> + <ExpansionPanelDetails className={classes.expPainelD}> + <Grid + item + container + direction="column" + justify="flex-start" + alignItems="flex-start" + xs={5} + className={classes.questionsGrid} + > + {options} + </Grid> + </ExpansionPanelDetails> + </ExpansionPanel> + ); +} + +export default FormFieldCheckbox; diff --git a/src/components/fieldsGetForm/SummaryFolder/FormFieldRadio.js b/src/components/fieldsGetForm/SummaryFolder/FormFieldRadio.js new file mode 100644 index 0000000..65f1086 --- /dev/null +++ b/src/components/fieldsGetForm/SummaryFolder/FormFieldRadio.js @@ -0,0 +1,96 @@ +import React, { useState, useEffect } from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import ExpansionPanel from "@material-ui/core/ExpansionPanel"; +import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary"; +import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails"; +import ArrowDownwardOutlinedIcon from "@material-ui/icons/ArrowDownwardOutlined"; +import Typography from "@material-ui/core/Typography"; +import Radio from "@material-ui/core/Radio"; +import Tooltip from "@material-ui/core/Tooltip"; +import RadioGroup from "@material-ui/core/RadioGroup"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + marginBottom: "2%", + ["@media (max-width: 896px)"]: { + width: "300px" + } + }, + questionsGrid: { + marginBottom: "20px" + }, + text: { + color: "black" + }, + expPainelD: { + display: "block" + }, + type: { + width: "50px" + } +})); + +function FormFieldRadio(props) { + const classes = useStyles(); + + /** HTML object to be displayed on component return. */ + const options = props.options.map(function(x, index) { + return props.answer[x.placement] ? ( + <Typography + style={{ wordWrap: "break-word" }} + className={classes.text} + gutterBottom + > + Opção {x.value} foi marcada por {props.answer[x.placement]} pessoa(s). + </Typography> + ) : ( + <Typography style={{ wordWrap: "break-word" }} gutterBottom> + Opção {x.value} não foi marcada. + </Typography> + ); + }); + + return ( + <ExpansionPanel className={classes.paper}> + <ExpansionPanelSummary expandIcon={<ArrowDownwardOutlinedIcon />}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Tooltip placement="left" title="Seleção única" arrow> + <Grid container className={classes.type}> + <Radio disabled /> + </Grid> + </Tooltip> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.text} + variant="h6" + > + {props.question} + </Typography> + <Typography style={{ wordWrap: "break-word" }} variant="h8"> + {props.description} + </Typography> + </Grid> + </Grid> + </ExpansionPanelSummary> + <ExpansionPanelDetails className={classes.expPainelD}> + <Grid + item + container + direction="column" + justify="flex-start" + alignItems="flex-start" + xs={5} + className={classes.questionsGrid} + > + <RadioGroup>{options}</RadioGroup> + </Grid> + </ExpansionPanelDetails> + </ExpansionPanel> + ); +} + +export default FormFieldRadio; diff --git a/src/components/fieldsGetForm/SummaryFolder/FormFieldSelect.js b/src/components/fieldsGetForm/SummaryFolder/FormFieldSelect.js new file mode 100644 index 0000000..17e5398 --- /dev/null +++ b/src/components/fieldsGetForm/SummaryFolder/FormFieldSelect.js @@ -0,0 +1,95 @@ +import React, { useState, useEffect } from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import ExpansionPanel from "@material-ui/core/ExpansionPanel"; +import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary"; +import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails"; +import ArrowDownwardOutlinedIcon from "@material-ui/icons/ArrowDownwardOutlined"; +import Typography from "@material-ui/core/Typography"; +import Select from "@material-ui/core/Select"; +import Tooltip from "@material-ui/core/Tooltip"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + marginBottom: "2%", + ["@media (max-width: 896px)"]: { + width: "300px" + } + }, + questionsGrid: { + marginBottom: "20px" + }, + text: { + color: "black" + }, + expPainelD: { + display: "block" + }, + type: { + width: "50px" + } +})); + +function FormFieldSelect(props) { + const classes = useStyles(); + + /** HTML object to be displayed on component return. */ + const options = props.options.map(function(x) { + return props.answer[x.placement] ? ( + <Typography style={{ wordWrap: "break-word" }} gutterBottom> + Opção {x.value} foi marcada por {props.answer[x.placement]} pessoa(s). + </Typography> + ) : ( + <Typography style={{ wordWrap: "break-word" }} gutterBottom> + Opção {x.value} não foi marcada. + </Typography> + ); + }); + + return ( + <ExpansionPanel className={classes.paper}> + <ExpansionPanelSummary expandIcon={<ArrowDownwardOutlinedIcon />}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Tooltip placement="left" title="Lista Suspensa" arrow> + <Grid container className={classes.type}> + <Select disabled /> + </Grid> + </Tooltip> + <Typography + style={{ wordWrap: "break-word" }} + lassName={classes.text} + variant="h6" + > + {props.question} + </Typography> + <Typography + style={{ wordWrap: "break-word" }} + variant="h8" + gutterBottom + > + {props.description} + </Typography> + </Grid> + </Grid> + </ExpansionPanelSummary> + <ExpansionPanelDetails className={classes.expPainelD}> + <Grid + item + container + direction="column" + justify="flex-start" + alignItems="flex-start" + xs={5} + className={classes.questionsGrid} + > + {options} + </Grid> + </ExpansionPanelDetails> + </ExpansionPanel> + ); +} + +export default FormFieldSelect; diff --git a/src/components/fieldsGetForm/SummaryFolder/FormFieldSubform.js b/src/components/fieldsGetForm/SummaryFolder/FormFieldSubform.js new file mode 100644 index 0000000..50d40f9 --- /dev/null +++ b/src/components/fieldsGetForm/SummaryFolder/FormFieldSubform.js @@ -0,0 +1,126 @@ +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 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); + }) + .catch(error => { + alert( + "Um erro inesperado ocorreu ao tentar obter o subform na tela de resumo." + ); + }); + } + + /** First gets info from the backend */ + useEffect(() => { + getForm(id); + }, []); + + return ( + <> + <Grid + container + direction="column" + className={classes.container} + alignItems="center" + justify="center" + > + {formData ? ( + <div> + {formData.inputs.map((input, index) => { + if (input.type === 0) + return ( + <FormFieldText + question={input.question} + description={input.description} + id={input.id} + answers={props.findAnswer(input.id)} + /> + ); + else if (input.type === 3) + return ( + <FormFieldSelect + question={input.question} + id={input.id} + description={input.description} + options={input.sugestions} + answer={props.result(input.id)} + place={input.placement} + /> + ); + else if (input.type === 2) + return ( + <FormFieldRadio + question={input.question} + description={input.description} + id={input.id} + options={input.sugestions} + answer={props.result(input.id)} + place={input.placement} + /> + ); + else if (input.type === 1) + return ( + <FormFieldCheckbox + question={input.question} + description={input.description} + options={input.sugestions} + id={input.id} + answer={props.result(input.id)} + place={input.placement} + /> + ); + else if (input.type === 4) + return ( + <FormFieldSubform + question={input.question} + description={input.description} + options={input.sugestions} + id={input.subForm.contentFormId} + result={props.result} + findAnswer={props.findAnswer} + /> + ); + })} + </div> + ) : ( + <p>Loading...</p> + )} + </Grid> + </> + ); +} + +export default FormFieldSubform; diff --git a/src/components/fieldsGetForm/SummaryFolder/FormFieldText.js b/src/components/fieldsGetForm/SummaryFolder/FormFieldText.js new file mode 100644 index 0000000..6b94208 --- /dev/null +++ b/src/components/fieldsGetForm/SummaryFolder/FormFieldText.js @@ -0,0 +1,144 @@ +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 ExpansionPanel from "@material-ui/core/ExpansionPanel"; +import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary"; +import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails"; +import ArrowDownwardOutlinedIcon from "@material-ui/icons/ArrowDownwardOutlined"; +import Typography from "@material-ui/core/Typography"; +import TextFieldsIcon from "@material-ui/icons/TextFields"; +import Tooltip from "@material-ui/core/Tooltip"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + marginBottom: "2%", + ["@media (max-width: 896px)"]: { + width: "300px" + } + }, + answersGrid: { + flexDirection: "column", + color: "black" + }, + description: { + marginBottom: "10px" + }, + questionsGrid: { + marginBottom: "10px" + }, + expPainelD: { + display: "block" + }, + answer: { + color: "black", + marginBottom: "5px", + background: "#80d4ff" + }, + noAnswer: { + color: "black", + marginBottom: "5px" + }, + type: { + width: "50px" + } +})); + +function FormFieldText(props) { + const classes = useStyles(); + + /** Counter to text answers. */ + let counter = 0; + + /** HTML object to be displayed on component return. */ + const answer = props.answers.map(function(value) { + counter += 1; + if (!value) { + return ( + <> + <Typography>{counter}:</Typography> + <Paper className={classes.noAnswer}> + <Typography + container + wrap="wrap" + style={{ wordWrap: "break-word" }} + variant="body1" + > + Não respondido. + </Typography> + </Paper> + </> + ); + } + return ( + <> + <Typography>{counter}:</Typography> + <Paper className={classes.answer}> + <Typography + container + wrap="wrap" + style={{ wordWrap: "break-word" }} + variant="body1" + > + {value} + </Typography> + </Paper> + </> + ); + }); + + /** + * Function to check if there's an answer to be display. + * @param ans - Answer array. + */ + function checkAnswer(ans) { + if (ans.length) { + return ans; + } + + return "Não há respostas."; + } + + return ( + <ExpansionPanel className={classes.paper}> + <ExpansionPanelSummary expandIcon={<ArrowDownwardOutlinedIcon />}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Tooltip placement="left" title="Texto" arrow> + <Grid container className={classes.type}> + <TextFieldsIcon /> + </Grid> + </Tooltip> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.text} + variant="h6" + gutterBottom + > + {"Pergunta: " + props.question} + </Typography> + <Grid className={classes.description} container> + <Typography + style={{ wordWrap: "break-word" }} + container + item + variant="h8" + > + {"Descrição: " + props.description} + </Typography> + </Grid> + </Grid> + </Grid> + </ExpansionPanelSummary> + <ExpansionPanelDetails className={classes.expPainelD}> + <Grid container wrap="wrap" container className={classes.answersGrid}> + {checkAnswer(answer)} + </Grid> + </ExpansionPanelDetails> + </ExpansionPanel> + ); +} + +export default FormFieldText; diff --git a/src/components/fieldsGetForm/SummaryFolder/FormFieldTitle.js b/src/components/fieldsGetForm/SummaryFolder/FormFieldTitle.js new file mode 100644 index 0000000..cf2c22e --- /dev/null +++ b/src/components/fieldsGetForm/SummaryFolder/FormFieldTitle.js @@ -0,0 +1,93 @@ +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 Typography from "@material-ui/core/Typography"; + +import FieldFooterOptions from "./FieldFooterOptions"; + +const useStyles = makeStyles(theme => ({ + paper: { + padding: theme.spacing(3), + width: theme.spacing(100), + 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", + 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 ( + <Grid> + <Paper className={classes.paper}> + <Grid container> + <Grid item xs={12} className={classes.questionsGrid}> + <Typography + style={{ wordWrap: "break-word" }} + className={classes.title} + variant="h3" + gutterBottom + > + {props.title} + </Typography> + </Grid> + <Grid item xs={9} className={classes.questionsGrid}> + <Typography + style={{ wordWrap: "break-word" }} + 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> + </Paper> + </Grid> + ); +} + +export default FormFieldText; diff --git a/src/components/fieldsGetForm/SummaryFolder/FormSummary.js b/src/components/fieldsGetForm/SummaryFolder/FormSummary.js new file mode 100644 index 0000000..660eb19 --- /dev/null +++ b/src/components/fieldsGetForm/SummaryFolder/FormSummary.js @@ -0,0 +1,161 @@ +import React from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; + +import FormFieldText from "./FormFieldText"; +import FormFieldSelect from "./FormFieldSelect"; +import FormFieldRadio from "./FormFieldRadio"; +import FormFieldCheckbox from "./FormFieldCheckbox"; +import FormFieldSubform from "./FormFieldSubform"; + +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) + }, + + formControl: { + margin: theme.spacing(1), + minWidth: 120, + ["@media (max-width: 446px)"]: { + marginRight: "100px", + marginBottom: "20px" + } + }, + container: { + flexDirection: "column", + justifyContent: "space-between", + backgroundColor: "white", + marginBottom: "20px", + marginTop: "25px", + marginLeft: "2%", + minHeight: "calc(100vh - 92.4px - 78px)", + paddingBottom: "78px", + justifyContent: "center" + }, + gridMenu: { + display: "flex", + alignItems: "center", + marginLeft: "20px" + }, + formTitle: { + marginTop: "10px" + } +})); +function Summary(props) { + const classes = useStyles(); + + /** + * Finds all the answers from a question. + * @param questionId - Qustion's ID to have answers associated with. + * @returns - All the question's answer in an array + */ + function findAnswer(questionId) { + let tmp = []; + props.answers.filter(value => { + if (value[questionId]) { + tmp.push(value[questionId][0].value); + } else { + tmp.push(""); + } + }); + return tmp; + } + + /** + * Function to count how many answers a checkbox/radio/select has + * @param questionId - Question's ID. + */ + function result(questionId) { + let result = []; + props.formArray.map(form => { + if (form.inputAnswers[questionId]) { + form.inputAnswers[questionId].map((answer, index) => { + if (answer.value === "true") { + if (result[index]) { + result[index] += 1; + } else { + result[index] = 1; + } + } + }); + } + }); + return result; + } + + return ( + <> + <Grid + container + direction="column" + className={classes.container} + alignItems="center" + justify="center" + > + <div> + {props.formArray[0].form.inputs.map((input, index) => { + if (input.type === 0) + return ( + <FormFieldText + question={input.question} + description={input.description} + id={input.id} + answers={findAnswer(input.id)} + /> + ); + else if (input.type === 3) + return ( + <FormFieldSelect + question={input.question} + id={input.id} + description={input.description} + options={input.sugestions} + answer={result(input.id)} + place={input.placement} + /> + ); + else if (input.type === 2) + return ( + <FormFieldRadio + question={input.question} + description={input.description} + id={input.id} + options={input.sugestions} + answer={result(input.id)} + place={input.placement} + /> + ); + else if (input.type === 1) + return ( + <FormFieldCheckbox + question={input.question} + description={input.description} + options={input.sugestions} + id={input.id} + answer={result(input.id)} + place={input.placement} + /> + ); + else if (input.type === 4) + return ( + <FormFieldSubform + question={input.question} + description={input.description} + options={input.sugestions} + id={input.subForm.contentFormId} + result={result} + findAnswer={findAnswer} + /> + ); + })} + </div> + </Grid> + </> + ); +} +export default Summary; diff --git a/src/pages/GetForm.js b/src/pages/GetForm.js new file mode 100644 index 0000000..fb24c5f --- /dev/null +++ b/src/pages/GetForm.js @@ -0,0 +1,229 @@ +import React, { useState, useEffect } from "react"; +import { useParams, Route, Redirect } from "react-router-dom"; +import { makeStyles } from "@material-ui/core/styles"; +import Grid from "@material-ui/core/Grid"; +import api from "../api"; +import { createMuiTheme, MuiThemeProvider } from "@material-ui/core"; +import FormControl from "@material-ui/core/FormControl"; +import MenuItem from "@material-ui/core/MenuItem"; +import Select from "@material-ui/core/Select"; +import FormHelperText from "@material-ui/core/FormHelperText"; +import Typography from "@material-ui/core/Typography"; + +import Jornal from "../components/fieldsGetForm/JornalFolder/FormJornal"; +import Summary from "../components/fieldsGetForm/SummaryFolder/FormSummary"; +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) + }, + selector: { + width: "100%", + borderRadius: "2px", + padding: "10px 20px" + }, + formControl: { + margin: theme.spacing(1), + minWidth: 120, + ["@media (max-width: 738px)"]: { + marginBottom: "20px", + marginLeft: "225px" + }, + ["@media (max-width: 460px)"]: { + marginLeft: "20px" + } + }, + container: { + flexDirection: "row", + justifyContent: "space-between", + backgroundColor: "white", + marginBottom: "20px" + }, + answerNum: { + display: "flex", + alignItems: "center", + marginLeft: "20px", + ["@media (max-width: 654px)"]: { + marginBottom: "10px", + marginLeft: "225px" + }, + ["@media (max-width: 460px)"]: { + marginLeft: "20px" + } + }, + formTitle: { + textAlign: "center", + marginTop: "10px", + width: "450px", + ["@media (max-width: 738px)"]: { + marginBottom: "20px", + marginRight: "50px" + }, + ["@media (max-width: 654px)"]: { + marginBottom: "10px", + marginLeft: "100px" + }, + ["@media (max-width: 460px)"]: { + marginLeft: "20px" + } + } +})); + +const theme = createMuiTheme({ + overrides: { + MuiInput: { + underline: { + "&:before": { + borderBottom: "1px solid #35c7fc" + }, + "&:after": { + borderBottom: "1px solid #3f51b5" + } + } + }, + MuiButton: { + label: { + color: "black" + } + } + } +}); + +function GetForm() { + const classes = useStyles(); + + /** Form id got from the browser's URL */ + const { id } = useParams(); + + /** Maped form from backend */ + const [formArray, setFormArray] = useState([]); + const [answers, setAnswers] = useState([]); + const [answerNum, setAnswerNum] = useState(0); + const [isReady, setIsReady] = useState(false); + const [selectedValue, setSelectedValue] = useState(""); + const [times, setTimes] = useState([]); + const [toLogin, setToLogin] = useState(false); + + /** + * Set selectedValue variable to the right value. + */ + const handleChange = event => { + setSelectedValue(event.target.value); + }; + + /** + * 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(`/answer/${id}`, { + headers: { + authorization: `bearer ${window.sessionStorage.getItem("token")}` + } + }) + .then(function(res) { + if (!res.data.length) { + alert("Não há respostas!"); + return; + } + setFormArray(res.data); + res.data.map(value => { + answers.push(value.inputAnswers); + times.push(value.timestamp); + }); + getAnswerNumber(id); + }) + .catch(error => { + if (error.response.status === 401) { + setToLogin(true); + return; + } + + if (error.response.status === 500) { + if (error.response.data.error === "User dont own this form.") { + alert("Você não é o dono deste formulário."); + } else { + alert("Ocorreu um erro inesperado. Tente novamente mais tarde."); + } + } + return; + }); + } + + /** + * Gets the number of answers from a form. + * @param id - Form's id. + */ + async function getAnswerNumber(id) { + const res = await api + .get(`/answerNumber/${id}`) + .then(function(res) { + setAnswerNum(res.data.answerNumber); + }) + .catch(error => { + alert( + "Um erro inesperado ocorreu. Contate os desenvolvedores (código 500-2)" + ); + }); + setIsReady(true); + } + + /** First thing the page does is getting the form from the API. */ + useEffect(() => { + getForm(id); + }, []); + + return toLogin ? ( + <Redirect to="/signin" /> + ) : isReady ? ( + <Grid container className={classes.container}> + <Grid item className={classes.answerNum}> + <Typography style={{ wordWrap: "break-word" }} variant="h5"> + {answerNum + " Respostas"} + </Typography> + </Grid> + <Grid item className={classes.formTitle}> + <Typography style={{ wordWrap: "break-word" }} variant="h4"> + {formArray[0].form.title} + </Typography> + </Grid> + <Grid item> + <FormControl className={classes.formControl}> + <Select + value={selectedValue} + onChange={handleChange} + displayEmpty + className={classes.selector} + inputProps={{ "aria-label": "Without label" }} + > + <MenuItem value=""> + <em>Jornal</em> + </MenuItem> + <MenuItem value={1}>Resumo</MenuItem> + </Select> + <FormHelperText>Visualização</FormHelperText> + </FormControl> + </Grid> + <Grid container item> + {selectedValue ? ( + <Summary formArray={formArray} answers={answers} /> + ) : ( + <Jornal + formArray={formArray} + timestamp={times} + answerNumber={answerNum} + /> + )} + </Grid> + </Grid> + ) : ( + <p>loading...</p> + ); +} + +export default GetForm; -- GitLab