create ViewForm page

This commit is contained in:
kuwsh1n 2024-03-12 01:11:28 +03:00
parent 16a82736a4
commit 90aec8fad0
12 changed files with 204 additions and 55 deletions

View File

@ -1,28 +1,48 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Outlet, useNavigate } from "react-router-dom"; import { Outlet, useNavigate } from "react-router-dom";
import { FormsData, UserData } from "./context"; import { FormsData, UserData, TypeAnswerData } from "./context";
import classes from "./assets/styles/app.module.scss" import classes from "./assets/styles/app.module.scss"
import NavBar from "./components/NavBar.jsx"; import NavBar from "./components/NavBar.jsx";
import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/css/bootstrap.min.css';
import InputText from "./components/typeAnswer/InputText.jsx";
import TextArea from "./components/typeAnswer/TextArea.jsx";
import YesNo from "./components/typeAnswer/YesNo.jsx"
import InputDate from "./components/typeAnswer/InputDate.jsx";
import InputMultipleRadio from "./components/typeAnswer/InputMultipleRadio.jsx";
import InputRadio from "./components/typeAnswer/InputRadio.jsx";
import DropDownList from "./components/typeAnswer/DropDownList.jsx";
import InputFile from "./components/typeAnswer/InputFile.jsx";
const App = () => { const App = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const [forms, setForms] = useState([]); const [forms, setForms] = useState([]);
const [user, setUser] = useState(false); const [user, setUser] = useState(false);
const [listTypeAnswer, setListTypeAnswer] = useState([
{id: 1, text: 'Краткий ответ', typeTag: InputText},
{id: 2, text: 'Расширенный ответ', typeTag: TextArea},
{id: 3, text: 'Выбор из вариантов', typeTag: InputRadio},
{id: 4, text: 'Множественный выбор', typeTag: InputMultipleRadio},
{id: 5, text: 'Выпадающий список', typeTag: DropDownList},
{id: 6, text: 'Да/Нет', typeTag: YesNo},
{id: 7, text: 'Файл', typeTag: InputFile},
{id: 8, text: 'Дата', typeTag: InputDate}
]);
return ( return (
<UserData.Provider value={{ user, setUser }}> <UserData.Provider value={{ user, setUser }}>
<FormsData.Provider value={{ forms, setForms }}> <FormsData.Provider value={{ forms, setForms }}>
<div className={classes.main}> <TypeAnswerData.Provider value={{ listTypeAnswer, setListTypeAnswer }}>
<div className={classes.container}> <div className={classes.main}>
<div className={classes.header}> <div className={classes.container}>
<NavBar navigate={navigate} auth={user} setAuth={setUser}/> <div className={classes.header}>
</div> <NavBar navigate={navigate} auth={user} setAuth={setUser}/>
<div className={classes.content}> </div>
<Outlet/> <div className={classes.content}>
<Outlet/>
</div>
</div> </div>
</div> </div>
</div> </TypeAnswerData.Provider>
</FormsData.Provider> </FormsData.Provider>
</UserData.Provider> </UserData.Provider>
) )

View File

@ -53,6 +53,7 @@
height: 25%; height: 25%;
width: 100%; width: 100%;
font-family: "Montserrat", sans-serif; font-family: "Montserrat", sans-serif;
position: relative;
&:hover { &:hover {
background-color: rgba(240, 240, 240, 0.8); background-color: rgba(240, 240, 240, 0.8);
} }
@ -72,6 +73,13 @@
width: 33.3%; width: 33.3%;
text-align: center; text-align: center;
} }
i {
position: absolute;
font-size: 15px;
right: 30px;
top: calc(50% - 7px);
cursor: pointer;
}
} }
} }
} }

View File

@ -0,0 +1,19 @@
.item {
padding: 10px 20px;
border-top: 1px solid rgb(200, 200, 200);
&__question {
&__text {
font-size: 15px;
font-family: "Montserrat", sans-serif;
}
&__comment {
font-size: 11px;
font-family: "Montserrat", sans-serif;
font-style: italic;
color: rgb(200, 200, 200);
}
}
&__answer {
}
}

View File

@ -0,0 +1,27 @@
.main {
width: 100%;
height: 100%;
}
.wrapper {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.form {
width: 70%;
min-height: 80%;
box-shadow: 0 0 5px 1px rgb(200, 200, 200);
&__header {
}
&__content {
}
&__footer {
}
}

View File

@ -0,0 +1,22 @@
import React, { useState } from "react";
import classes from "../assets/styles/generatingFormFields.module.scss";
const GeneratingFormFields = ({newForm, listTypeAnswer}) => {
return (
newForm.map((item, i) =>
<div className={classes.item} key={i}>
<div className={classes.item__question}>
<p className={classes.item__question__text}>{i + 1}) {item.question}</p>
<p className={classes.item__question__comment}>{item.comment}</p>
</div>
<div className={classes.item__answer}>
{
listTypeAnswer.find(type => type.id === item.typeAnswer).typeTag({postfix: i, answers: item.optionAnswer})
}
</div>
</div>
)
)
}
export default GeneratingFormFields;

View File

@ -1,10 +1,8 @@
import React from "react"; import React from "react";
import classes from "../assets/styles/components/previewModal.module.scss"; import classes from "../assets/styles/components/previewModal.module.scss";
import GeneratingFormFields from "./GeneratingFormFields.jsx";
const PreviewModal = ({newForm, listTypeAnswer}) => { const PreviewModal = ({newForm, listTypeAnswer}) => {
// const [file, setFile] = useState('');
// const [value, setValue] = useState('');
return ( return (
<div class="modal fade modal-lg" className={classes.myModal} id="previewModal" tabIndex="-1" aria-labelledby="exampleModalLabel" data-bs-backdrop="static" aria-hidden="true"> <div class="modal fade modal-lg" className={classes.myModal} id="previewModal" tabIndex="-1" aria-labelledby="exampleModalLabel" data-bs-backdrop="static" aria-hidden="true">
<div class="modal-dialog" className={classes.myModal__dialog}> <div class="modal-dialog" className={classes.myModal__dialog}>
@ -14,19 +12,7 @@ const PreviewModal = ({newForm, listTypeAnswer}) => {
<i class="fa-solid fa-xmark" data-bs-dismiss="modal" aria-label="Close"></i> <i class="fa-solid fa-xmark" data-bs-dismiss="modal" aria-label="Close"></i>
</div> </div>
<div class="modal-body" className={classes.myModal__dialog__content__body}> <div class="modal-body" className={classes.myModal__dialog__content__body}>
{newForm.map((item, i) => <GeneratingFormFields newForm={newForm} listTypeAnswer={listTypeAnswer}/>
<div className={classes.myModal__dialog__content__body__item} key={i}>
<div className={classes.myModal__dialog__content__body__item__question}>
<p className={classes.myModal__dialog__content__body__item__question__text}>{i + 1}) {item.question}</p>
<p className={classes.myModal__dialog__content__body__item__question__comment}>{item.comment}</p>
</div>
<div className={classes.myModal__dialog__content__body__item__answer}>
{
listTypeAnswer.find(type => type.id === item.typeAnswer).typeTag({postfix: i, answers: item.optionAnswer})
}
</div>
</div>
)}
</div> </div>
<div class="modal-footer" className={classes.myModal__dialog__content__footer}> <div class="modal-footer" className={classes.myModal__dialog__content__footer}>

View File

@ -3,3 +3,5 @@ import { createContext } from "react";
export const FormsData = createContext([]); export const FormsData = createContext([]);
export const UserData = createContext(false); export const UserData = createContext(false);
export const TypeAnswerData = createContext();

View File

@ -8,7 +8,7 @@ import { FormsData } from "../context";
const Forms = () => { const Forms = () => {
const navigate = useNavigate() const navigate = useNavigate()
const {forms, setForms} = useContext(FormsData); const {forms, setForms} = useContext(FormsData);
const [stateLoading, setStateLoading] = useState(false) const [stateLoading, setStateLoading] = useState(false);
const response = ms => { const response = ms => {
return new Promise(r => setTimeout(() => r('response end'), ms)) return new Promise(r => setTimeout(() => r('response end'), ms))
@ -27,7 +27,7 @@ const Forms = () => {
} }
function editForm(item) { function editForm(item) {
navigate("/new", { navigate("/forms/edit", {
state: { state: {
id: item.id, id: item.id,
data: item.listAnswer data: item.listAnswer
@ -58,6 +58,11 @@ const Forms = () => {
<div className={classes.listForms__forms__item__title} onClick={() => editForm(item)}>{item.title}</div> <div className={classes.listForms__forms__item__title} onClick={() => editForm(item)}>{item.title}</div>
<div className={classes.listForms__forms__item__answers}>{item.answers}</div> <div className={classes.listForms__forms__item__answers}>{item.answers}</div>
<div className={classes.listForms__forms__item__update}>{item.update}</div> <div className={classes.listForms__forms__item__update}>{item.update}</div>
<i class="fa-solid fa-ellipsis-vertical" id="action" data-bs-toggle="dropdown"></i>
<ul class="dropdown-menu" aria-labelledby="action">
<li><a class="dropdown-item" onClick={() => navigate(`/forms/${item.id}/`)}>Открыть</a></li>
<li><a class="dropdown-item" onClick={() => navigator.clipboard.writeText(`http://localhost:3000/forms/${item.id}/`)}>Скопировать ссылку</a></li>
</ul>
</div> </div>
)} )}
</div> </div>

View File

@ -4,15 +4,7 @@ import classes from "../assets/styles/newForm.module.scss";
import MyButton from "../components/MyButton.jsx"; import MyButton from "../components/MyButton.jsx";
import AnswerModal from "../components/AnswerModal.jsx"; import AnswerModal from "../components/AnswerModal.jsx";
import PreviewModal from "../components/PreviewModal.jsx" import PreviewModal from "../components/PreviewModal.jsx"
import { FormsData } from "../context"; import { FormsData, TypeAnswerData } from "../context";
import InputText from "../components/typeAnswer/InputText.jsx"
import TextArea from "../components/typeAnswer/TextArea.jsx";
import YesNo from "../components/typeAnswer/YesNo.jsx"
import InputDate from "../components/typeAnswer/InputDate.jsx";
import InputMultipleRadio from "../components/typeAnswer/InputMultipleRadio.jsx";
import InputRadio from "../components/typeAnswer/InputRadio.jsx";
import DropDownList from "../components/typeAnswer/DropDownList.jsx";
import InputFile from "../components/typeAnswer/InputFile.jsx";
const NewForm = () => { const NewForm = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@ -21,6 +13,7 @@ const NewForm = () => {
const [dropElem, setDropElem] = useState(null); const [dropElem, setDropElem] = useState(null);
const {forms, setForms} = useContext(FormsData); const {forms, setForms} = useContext(FormsData);
const {listTypeAnswer, setListTypeAnswer} = useContext(TypeAnswerData);
const nextID = (list) => { const nextID = (list) => {
return list.length ? list.at(-1).id + 1 : 1 return list.length ? list.at(-1).id + 1 : 1
@ -38,17 +31,6 @@ const NewForm = () => {
const [stateModal, setStateModal] = useState(false) const [stateModal, setStateModal] = useState(false)
const [listTypeAnswer, setListTypeAnswer] = useState([
{id: 1, text: 'Краткий ответ', typeTag: InputText},
{id: 2, text: 'Расширенный ответ', typeTag: TextArea},
{id: 3, text: 'Выбор из вариантов', typeTag: InputRadio},
{id: 4, text: 'Множественный выбор', typeTag: InputMultipleRadio},
{id: 5, text: 'Выпадающий список', typeTag: DropDownList},
{id: 6, text: 'Да/Нет', typeTag: YesNo},
{id: 7, text: 'Файл', typeTag: InputFile},
{id: 8, text: 'Дата', typeTag: InputDate}
]);
function removeAnswerByForm(id) { function removeAnswerByForm(id) {
setNewForm([...newForm.filter(item => item.id !== id)]); setNewForm([...newForm.filter(item => item.id !== id)]);
} }

View File

@ -7,11 +7,42 @@ const Profile = () => {
const [edit, setEdit] = useState(true); const [edit, setEdit] = useState(true);
const {user, setUser} = useContext(UserData); const {user, setUser} = useContext(UserData);
const [email, setEmail] = useState(""); const [email, setEmail] = useState(user.email);
const [phone, setPhone] = useState(""); const [phone, setPhone] = useState(user.phone);
const [name, setName] = useState(""); const [name, setName] = useState(user.name);
const [surname, setSurname] = useState(""); const [surname, setSurname] = useState(user.surname);
const [patronymic, setPatronymic] = useState(""); const [patronymic, setPatronymic] = useState(user.patronymic);
function choiceInput(key) {
switch (key) {
case "email":
return {get: email, set: setEmail}
case "phone":
return {get: phone, set: setPhone}
case "name":
return {get: name, set: setName}
case "surname":
return {get: surname, set: setSurname}
case "patronymic":
return {get: patronymic, set: setPatronymic}
}
}
function editUser() {
if (edit) {
setEdit(!edit)
}
else {
setUser({
email: email,
phone: phone,
name: name,
surname: surname,
patronymic: patronymic
})
setEdit(!edit)
}
}
return ( return (
<div className={classes.main}> <div className={classes.main}>
@ -27,7 +58,7 @@ const Profile = () => {
<span>Сохранить <i class="fa-solid fa-floppy-disk"></i></span> <span>Сохранить <i class="fa-solid fa-floppy-disk"></i></span>
} }
backgroundColor={edit ? "rgb(200, 200, 200)" : ""} backgroundColor={edit ? "rgb(200, 200, 200)" : ""}
click={() => setEdit(!edit)}/> click={() => editUser()}/>
</div> </div>
<div className={classes.profile__wrapper__body}> <div className={classes.profile__wrapper__body}>
{Object.keys(user).map(key => key !== "password" ? <div className={classes.profile__wrapper__body__item}> {Object.keys(user).map(key => key !== "password" ? <div className={classes.profile__wrapper__body__item}>
@ -36,9 +67,10 @@ const Profile = () => {
<input <input
type="text" type="text"
class="form-control shadow-none" class="form-control shadow-none"
value={user[key]} value={choiceInput(key).get}
pattern={key === "email" ? "+[7-8]{1}[0-9]{3} [0-9]{3}-[0-9]{2}-[0-9]{2}" : ""} pattern={key === "email" ? "+[7-8]{1}[0-9]{3} [0-9]{3}-[0-9]{2}-[0-9]{2}" : ""}
disabled={edit} disabled={edit}
onChange={(e) => choiceInput(key).set(e.target.value)}
required={key !== "patronymic" ? true : false}/> required={key !== "patronymic" ? true : false}/>
</div> </div>
</div> : <div></div>)} </div> : <div></div>)}

41
src/pages/ViewForm.jsx Normal file
View File

@ -0,0 +1,41 @@
import React, { useState, useContext } from "react";
import { useNavigate, useParams } from "react-router-dom";
import classes from "../assets/styles/viewForm.module.scss";
import { FormsData, TypeAnswerData } from "../context";
import GeneratingFormFields from "../components/GeneratingFormFields.jsx";
const ViewForm = () => {
const navigate = useNavigate();
const { formId } = useParams();
const {forms, setForms} = useContext(FormsData);
const {listTypeAnswer, setListTypeAnswer} = useContext(TypeAnswerData);
function newForm() {
const searchForm = forms.find(item => item.id === Number(formId))
if (searchForm) {
return searchForm.listAnswer
}
return []
}
return (
<div className={classes.main}>
<div className={classes.wrapper}>
<div className={classes.form}>
<div className={classes.form__header}>
</div>
<div className={classes.form__content}>
<GeneratingFormFields newForm={newForm()} listTypeAnswer={listTypeAnswer}/>
</div>
<div className={classes.form__footer}>
</div>
</div>
</div>
</div>
)
}
export default ViewForm;

View File

@ -6,6 +6,7 @@ import NewForm from '../pages/NewForm.jsx';
import Home from "../pages/Home.jsx"; import Home from "../pages/Home.jsx";
import App from "../App.jsx"; import App from "../App.jsx";
import Profile from "../pages/Profile.jsx"; import Profile from "../pages/Profile.jsx";
import ViewForm from "../pages/ViewForm.jsx";
const router = createBrowserRouter([ const router = createBrowserRouter([
{ {
@ -30,6 +31,10 @@ const router = createBrowserRouter([
{ {
path: '/profile', path: '/profile',
element: <Profile/> element: <Profile/>
},
{
path: '/forms/:formId',
element: <ViewForm/>
} }
] ]
} }