From 98be17522ef0474a40b134a3ca4e0d2e8096d469 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 3 Jan 2024 18:36:53 -0500 Subject: feat: stuff changed --- src/App.js | 10 ++ src/components/FormBuilder/FinalForm.js | 12 ++ src/components/FormBuilder/index.js | 201 +++++++++++++++++++------------- src/hooks/useForm.js | 20 ++++ src/hooks/useLocalStorage.js | 17 +++ src/pages/NewSurvey/index.js | 5 +- src/pages/Survey/index.js | 7 ++ src/pages/SurveyAnswer/index.js | 27 +++++ src/pages/SurveyResults/index.js | 58 ++++++++- src/pages/Surveys/SurveysList.js | 36 +++--- 10 files changed, 299 insertions(+), 94 deletions(-) create mode 100644 src/components/FormBuilder/FinalForm.js create mode 100644 src/hooks/useForm.js create mode 100644 src/hooks/useLocalStorage.js create mode 100644 src/pages/Survey/index.js create mode 100644 src/pages/SurveyAnswer/index.js diff --git a/src/App.js b/src/App.js index 28e3a52..bb574c5 100644 --- a/src/App.js +++ b/src/App.js @@ -7,7 +7,9 @@ import { import Login from "./pages/Login"; import Surveys from "./pages/Surveys"; import NewSurvey from "./pages/NewSurvey"; +import Survey from "./pages/Survey"; import SurveyResults from "./pages/SurveyResults"; +import SurveyAnswer from "./pages/SurveyAnswer"; import SurveyAssignees from "./pages/SurveyAssignees"; import Users from "./pages/Users"; import NavBar from "./components/NavBar"; @@ -52,10 +54,18 @@ function routes({ login, logout, isLoggedIn }) { path: "/surveys/new", element: withNavBar(), }, + { + path: "/surveys/:formId", + element: withNavBar(), + }, { path: "/surveys/:surveyId/results", element: withNavBar(), }, + { + path: "/surveys/:surveyId/results/:runId/answer", + element: withNavBar(), + }, { path: "/surveys/:surveyId/assignees", element: withNavBar(), diff --git a/src/components/FormBuilder/FinalForm.js b/src/components/FormBuilder/FinalForm.js new file mode 100644 index 0000000..070a0fe --- /dev/null +++ b/src/components/FormBuilder/FinalForm.js @@ -0,0 +1,12 @@ +import { Form } from "./index"; + +export default function FinalForm({ formId, setResults, results }) { + return ( +
+ ); +} diff --git a/src/components/FormBuilder/index.js b/src/components/FormBuilder/index.js index 5636b32..5c77c25 100644 --- a/src/components/FormBuilder/index.js +++ b/src/components/FormBuilder/index.js @@ -8,7 +8,9 @@ import { TextField, } from "@mui/material"; import React, { useRef, useState } from "react"; -export default function FormBuilder() { +import useForm from "../../hooks/useForm"; + +export default function FormBuilder({ formId }) { return (

FormBuilder

@@ -18,7 +20,7 @@ export default function FormBuilder() { alignItems={"flex-start"} spacing={2} > - +
@@ -28,43 +30,57 @@ export default function FormBuilder() { const availableWidgets = { label: { name: "Label", - element: ({ id, name, setName }) => ( - setName(e.target.value)} - fullWidth - /> - ), - finalElement: ({ id }) =>
{id}
, + element: ({ id, name, setName, finalField }) => + finalField ? ( +
{name}
+ ) : ( + setName(e.target.value)} + fullWidth + /> + ), }, number: { name: "Number", - element: ({ id }) => ( + element: ({ id, value, setValue }) => ( { + if (setValue) { + setValue(e.target.value); + } + }} fullWidth /> ), }, text: { name: "Text", - element: ({ id }) => ( + element: ({ id, setValue, value }) => ( { + if (setValue) { + setValue(e.target.value); + } + }} /> ), }, multiline: { name: "Multiline", - element: ({ id }) => ( + element: ({ id, setValue, value }) => ( { + if (setValue) { + setValue(e.target.value); + } + }} /> ), }, @@ -134,7 +156,14 @@ function WidgetCard({ name, element, type, finalElement }) { } } -function FormField({ formField, setFormField, deleteFormField }) { +function FormField({ + formField, + setFormField, + deleteFormField, + editable, + setResult, + result, +}) { const { id, type, name } = formField; function setName(name) { @@ -147,33 +176,47 @@ function FormField({ formField, setFormField, deleteFormField }) { const { element: Element } = availableWidgets[type]; const dragHandleRef = useRef(); const [target, setTarget] = useState(); - return ( - { - setTarget(e.target); - }} - onDragStart={(e) => { - if (dragHandleRef.current.contains(target)) { - e.dataTransfer.setData("application/formwidgetid", id); - } else { - e.preventDefault(); - } - }} - > - - - - - - - - - ); + if (!editable) { + return ( + + ); + } else { + return ( + { + setTarget(e.target); + }} + onDragStart={(e) => { + if (dragHandleRef.current.contains(target)) { + e.dataTransfer.setData("application/formwidgetid", id); + } else { + e.preventDefault(); + } + }} + > + + + + + + + + + ); + } } function capture(e) { @@ -214,8 +257,9 @@ function DropZone({ insertField, index, moveField }) { ); } -function Form({ initialForm, editable }) { - const [form, setForm] = useState({ fields: [], ...initialForm }); +export function Form({ editable, formId, setResults, results }) { + // const [form, setForm] = useState({ fields: [], ...initialForm }); + const [form, setForm] = useForm(formId); function updateFormField(newField) { setForm({ @@ -254,41 +298,42 @@ function Form({ initialForm, editable }) { setForm({ ...form }); } - if (!editable && !initialForm) { - return; - // else if (!initialForm) { - // return ; - // } - } else { - return ( - - - {editable && ( - id === fieldId)?.name, + }; + setResults({ ...results, [fieldId]: fieldResult }); + } + + return ( + + + {editable && ( + + )} + {form?.fields?.map((formField, i) => ( + + updateFormField(field)} + deleteFormField={() => deleteFormField(formField.id)} + formField={formField} + editable={editable} + setResult={results && ((result) => setResult(formField.id, result))} + result={results && results[formField.id]} /> - )} - {form?.fields?.map((formField, i) => ( - - updateFormField(field)} - deleteFormField={() => deleteFormField(formField.id)} - formField={formField} + {editable && ( + - {editable && ( - - )} - - ))} - - ); - } + )} + + ))} + + ); } function FormHeader() { diff --git a/src/hooks/useForm.js b/src/hooks/useForm.js new file mode 100644 index 0000000..6270c1e --- /dev/null +++ b/src/hooks/useForm.js @@ -0,0 +1,20 @@ +import useLocalStorage from "./useLocalStorage"; + +export default function useForm(formId) { + const [forms, setForms] = useLocalStorage(`forms`, {}); + + const form = forms[formId] || { fields: [], id: formId }; + + function setForm(newForm) { + console.log( + "setForm", + newForm, + { ...forms, [newForm.id]: newForm }, + { form: forms[formId], formId, forms }, + ); + setForms({ ...forms, [newForm.id]: newForm }); + } + + console.log("useForm", formId, form); + return [form, setForm]; +} diff --git a/src/hooks/useLocalStorage.js b/src/hooks/useLocalStorage.js new file mode 100644 index 0000000..6dbed36 --- /dev/null +++ b/src/hooks/useLocalStorage.js @@ -0,0 +1,17 @@ +import { useState } from "react"; + +const useLocalStorage = (key, initialValue) => { + const storedVal = localStorage[key] + ? JSON.parse(localStorage[key]) || initialValue + : initialValue; + const [value, setValue] = useState(storedVal); + + function update(newValue) { + localStorage[key] = JSON.stringify(newValue); + setValue(newValue); + } + + return [value, update]; +}; + +export default useLocalStorage; diff --git a/src/pages/NewSurvey/index.js b/src/pages/NewSurvey/index.js index f1d4b89..335eb93 100644 --- a/src/pages/NewSurvey/index.js +++ b/src/pages/NewSurvey/index.js @@ -1,4 +1,5 @@ -import FormBuilder from "../../components/FormBuilder"; +import { Navigate } from "react-router-dom"; export default function NewSurvey() { - return ; + const id = crypto.randomUUID(); + return ; } diff --git a/src/pages/Survey/index.js b/src/pages/Survey/index.js new file mode 100644 index 0000000..41bac5e --- /dev/null +++ b/src/pages/Survey/index.js @@ -0,0 +1,7 @@ +import FormBuilder from "../../components/FormBuilder"; +import { useParams } from "react-router-dom"; + +export default function Survey() { + const { formId } = useParams(); + return ; +} diff --git a/src/pages/SurveyAnswer/index.js b/src/pages/SurveyAnswer/index.js new file mode 100644 index 0000000..d1676c1 --- /dev/null +++ b/src/pages/SurveyAnswer/index.js @@ -0,0 +1,27 @@ +import { useState } from "react"; +import { useParams } from "react-router-dom"; +import Form from "../../components/FormBuilder/FinalForm"; +import useLocalStorage from "../../hooks/useLocalStorage"; + +export default function SurveyAnswers() { + const { runId, surveyId } = useParams(); + const [resultsSet, setResultsSet] = useLocalStorage( + `results-${surveyId}-${runId}`, + {}, + ); + const [answerSetId] = useState(crypto.randomUUID()); + const results = (resultsSet && resultsSet[answerSetId]) || { + datetime: new Date().toISOString(), + }; + + function setResults(newResults) { + setResultsSet({ ...resultsSet, [answerSetId]: newResults }); + } + + return ( +
+ {runId} + +
+ ); +} diff --git a/src/pages/SurveyResults/index.js b/src/pages/SurveyResults/index.js index 82d41c6..dec182e 100644 --- a/src/pages/SurveyResults/index.js +++ b/src/pages/SurveyResults/index.js @@ -1,3 +1,59 @@ +import { Button } from "@mui/material"; +import { DataGrid } from "@mui/x-data-grid"; +import { Link, useParams } from "react-router-dom"; +import useLocalStorage from "../../hooks/useLocalStorage"; +import useForm from "../../hooks/useForm"; + export default function SurveyResults() { - return <>SurveyResults; + const { surveyId } = useParams(); + const [runs, setRuns] = useLocalStorage(`runs-${surveyId}`, []); + const [form] = useForm(surveyId); + + const columns = form?.fields?.map(({ id, name }) => ({ + field: id, + headerName: name, + })); + + return ( + <> +

SurveyRuns

+ {surveyId} + + + {runs && + runs.map((r) => { + const runRs = runResults(surveyId, r.id); + + console.log(runRs); + + return ( +
+ Add Answer {JSON.stringify(r)} + Total Results: {Object.keys(runRs).length} + +
+ ); + })} + + ); +} + +function runResults(surveyId, runId) { + const str = localStorage[`results-${surveyId}-${runId}`]; + return !str ? {} : JSON.parse(str); } diff --git a/src/pages/Surveys/SurveysList.js b/src/pages/Surveys/SurveysList.js index c9c5b90..a320716 100644 --- a/src/pages/Surveys/SurveysList.js +++ b/src/pages/Surveys/SurveysList.js @@ -1,9 +1,10 @@ import React from "react"; import Box from "@mui/material/Box"; import { DataGrid } from "@mui/x-data-grid"; +import useLocalStorage from "../../hooks/useLocalStorage"; +import { Link } from "react-router-dom"; const columns = [ - { field: "id", headerName: "ID", width: 90 }, { field: "name", headerName: "Name", @@ -14,21 +15,30 @@ const columns = [ headerName: "Next Run", width: 150, }, -]; - -const rows = [ - { id: 1, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, - { id: 2, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, - { id: 3, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, - { id: 4, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, - { id: 5, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, - { id: 6, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, - { id: 7, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, - { id: 8, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, - { id: 9, name: "survey", next_run_at: "Mon 28 Aug 16:35:36 EDT 2023" }, + { + field: "edit_survey_link", + headerName: "", + renderCell: ({ row }) => Edit, + width: 150, + }, + { + field: "results_survey_link", + headerName: "", + renderCell: ({ row }) => Results, + width: 150, + }, ]; export default function SurveysList() { + const [forms] = useLocalStorage(`forms`, {}); + + const rows = Object.keys(forms).map((id, i) => ({ + id, + name: `Survey ${i}`, + next_run_at: "Mon 28 Aug 16:35:36 EDT 2023", + path: `/surveys/${id}`, + })); + return (