diff --git a/src/App.jsx b/src/App.jsx index 12d68bb..97e9778 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,6 +1,7 @@ -import React, { useState } from "react"; +import React, { useState, useEffect, useLayoutEffect } from "react"; import { Outlet, useNavigate } from "react-router-dom"; import { FormsData, UserData, TypeAnswerData } from "./context"; +import { globalRender } from "./router/protectedRouting.js"; import classes from "./assets/styles/app.module.scss" import NavBar from "./components/NavBar.jsx"; import 'bootstrap/dist/css/bootstrap.min.css'; @@ -28,6 +29,8 @@ const App = () => { {id: 8, text: 'Дата', typeTag: InputDate} ]); + // useEffect(() => globalRender(window.location.pathname, user, navigate)); + return ( diff --git a/src/assets/styles/forms.module.scss b/src/assets/styles/forms.module.scss index 208859e..f9dc24c 100644 --- a/src/assets/styles/forms.module.scss +++ b/src/assets/styles/forms.module.scss @@ -26,8 +26,9 @@ width: 100%; &__columns { display: flex; - justify-content: space-around; + justify-content: start; align-items: center; + padding: 0 2%; height: 15%; width: 100%; border-bottom: 1px solid rgb(220, 220, 220); @@ -48,8 +49,9 @@ } &__item { display: flex; - justify-content: space-around; + justify-content: start; align-items: center; + padding: 0 2%; height: 25%; width: 100%; font-family: "Montserrat", sans-serif; @@ -58,7 +60,7 @@ background-color: rgba(240, 240, 240, 0.8); } &__title { - width: 33.3%; + // width: 33.3%; text-align: center; cursor: pointer; &:hover { @@ -80,6 +82,11 @@ top: calc(50% - 7px); cursor: pointer; } + ul { + li { + cursor: pointer; + } + } } } } \ No newline at end of file diff --git a/src/components/MyInput.jsx b/src/components/MyInput.jsx index 7135cfa..60012c9 100644 --- a/src/components/MyInput.jsx +++ b/src/components/MyInput.jsx @@ -4,7 +4,13 @@ import classes from "../assets/styles/components/myInput.module.scss" const MyInput = (props) => { return (
- props.change(e.target.value)} value={props.value}/> + props.change(e.target.value)} + value={props.value} + />
) } diff --git a/src/components/NavBar.jsx b/src/components/NavBar.jsx index 1f67d59..0d0fb5e 100644 --- a/src/components/NavBar.jsx +++ b/src/components/NavBar.jsx @@ -6,12 +6,12 @@ const NavBar = ({navigate, auth, setAuth}) => {
- {auth ?
navigate("/")}>Главная - navigate("/forms")}>Мои формы -
: -
} + {auth ? + navigate("/forms")}>Мои формы : + } +
{auth ? diff --git a/src/hooks/api/enterAccountApi.js b/src/hooks/api/enterAccountApi.js new file mode 100644 index 0000000..438b06d --- /dev/null +++ b/src/hooks/api/enterAccountApi.js @@ -0,0 +1,43 @@ +import { totalRegisterValidate } from "../validation/enterAccountValidate.js"; + +async function logIn(email, password) { + return new Promise((resolve, reject) => { + setTimeout(() => { + if (true) { + resolve({ + email: "senya.bogachev@mail.ru", + phone: "89110128244", + name: "Арсений", + surname: "Богачев", + patronymic: "Валерьевич" + }) + } + else { + reject("Error") + } + }, 1000) + }).catch((error) => { + console.log(error) + }) +}; + +async function completeRegistration(data) { + const validate = totalRegisterValidate(data) + + return new Promise((resolve, reject) => { + setTimeout(() => { + if (validate.status) { + console.log("Отправляем данные на бэк ->", data) + resolve({ + status: 201, + data: data + }) + } + else { + reject(validate.message) + } + }, 1000) + }) +}; + +export { logIn, completeRegistration }; \ No newline at end of file diff --git a/src/hooks/api/formApi.js b/src/hooks/api/formApi.js new file mode 100644 index 0000000..4b98749 --- /dev/null +++ b/src/hooks/api/formApi.js @@ -0,0 +1,65 @@ +function saveAnswersApi(id, answers) { + return new Promise((resolve, reject) => { + setTimeout(() => { + if (true) { + resolve({ + id: id, + answers: answers + }) + } + else { + reject("Error") + } + }, 1000) + }) +} + +function removeFormApi(id) { + return new Promise((resolve, reject) => { + setTimeout(() => { + if (true) { + resolve({ + id: id + }) + } + else { + reject("Error") + } + }, 200) + }) +} + +function updateFormByFormsApi(id, name, questions) { + return new Promise((resolve, reject) => { + setTimeout(() => { + if (true) { + resolve({ + id: id, + name: name, + questions: questions + }) + } + else { + reject("Error") + } + }, 1000) + }) +} + +function saveFormApi(name, questions) { + return new Promise((resolve, reject) => { + setTimeout(() => { + if (true) { + resolve({ + name: name, + questions: questions + }) + } + else { + reject("Error") + } + }, 1000) + }) +} + +export { saveAnswersApi, saveFormApi, updateFormByFormsApi, removeFormApi } \ No newline at end of file diff --git a/src/hooks/validation/enterAccountValidate.js b/src/hooks/validation/enterAccountValidate.js new file mode 100644 index 0000000..c09a0ca --- /dev/null +++ b/src/hooks/validation/enterAccountValidate.js @@ -0,0 +1,31 @@ +const constructorAnswerValidate = (state, messageReject = "Ошибка", messageResolve = undefined) => { + return state ? + { + status: true, + message: messageResolve + } : + { + status: false, + message: messageReject + } +} + +const totalRegisterValidate = (data) => { + const listValidation = [ + constructorAnswerValidate(data.name.length, "Обязательное поле."), + constructorAnswerValidate(data.surname.length, "Обязательное поле."), + constructorAnswerValidate(data.email.length, "Обязательное поле."), + constructorAnswerValidate(data.phone.length, "Обязательное поле."), + constructorAnswerValidate(data.password === data.repiedPassword, "Введенные пароли не совпадают."), + constructorAnswerValidate(data.password < 8, "Пароль должен иметь более 8 символов.") + ] + + for (let value of listValidation) { + if (!value.status) { + return value + } + } + return { status: true } +} + +export { totalRegisterValidate, constructorAnswerValidate } \ No newline at end of file diff --git a/src/pages/EnterAccount.jsx b/src/pages/EnterAccount.jsx index 2d939f8..b8189ae 100644 --- a/src/pages/EnterAccount.jsx +++ b/src/pages/EnterAccount.jsx @@ -4,6 +4,7 @@ import classes from "../assets/styles/enterAccount.module.scss"; import MyInput from "../components/MyInput.jsx"; import MyButton from "../components/MyButton.jsx"; import { UserData } from "../context"; +import { logIn, completeRegistration } from "../hooks/api/enterAccountApi.js"; const EnterAccount = () => { const [enter, setEnter] = useState("login"); @@ -20,31 +21,38 @@ const EnterAccount = () => { const {user, setUser} = useContext(UserData); function cleanState() { - setEmail(); - setPhone(); - setName(); - setSurname(); - setPatronymic(); - setPassword(); - setRepiedPassword(); - } + setEmail(""); + setPhone(""); + setName(""); + setSurname(""); + setPatronymic(""); + setPassword(""); + setRepiedPassword(""); + }; + + function selectTag(tag) { + setEnter(tag); + cleanState(); + }; function createUser() { - if (password === repiedPassword) { - setUser({ - email: email, - phone: phone, - name: name, - surname: surname, - patronymic: patronymic, - password: password - }) - cleanState(); - navigate("/"); - } - else { - console.log('Error') - } + completeRegistration({ + email: email, + phone: phone, + name: name, + surname: surname, + patronymic: patronymic, + password: password, + repiedPassword: repiedPassword + }).then((resolve, reject) => { + if (resolve.status === 201) { + setUser(resolve.data) + cleanState(); + navigate("/"); + } + }).catch((error) => { + console.log(error) + }) }; return ( @@ -52,10 +60,10 @@ const EnterAccount = () => {
@@ -67,11 +75,15 @@ const EnterAccount = () => {

Войти в аккаунт

- - + +
- + logIn(email, password).then((resolve, reject) => setUser(resolve))} + />
:
diff --git a/src/pages/Forms.jsx b/src/pages/Forms.jsx index 135f182..280dd43 100644 --- a/src/pages/Forms.jsx +++ b/src/pages/Forms.jsx @@ -1,22 +1,23 @@ -import React, { useState, useContext } from "react"; +import React, { useState, useContext, useEffect } from "react"; import { useNavigate } from 'react-router-dom'; import classes from "../assets/styles/forms.module.scss" import MyButton from "../components/MyButton.jsx"; import MyInput from "../components/MyInput.jsx"; -import { FormsData } from "../context"; +import { FormsData, UserData } from "../context"; +import { removeFormApi } from "../hooks/api/formApi.js"; const Forms = () => { - const navigate = useNavigate() + const navigate = useNavigate(); const {forms, setForms} = useContext(FormsData); + const {user, setUser} = useContext(UserData); const [stateLoading, setStateLoading] = useState(false); const response = ms => { return new Promise(r => setTimeout(() => r('response end'), ms)) - } + }; function createForm() { setStateLoading(true); - // Эмуляция пост запроса response(1000) .then((r) => { console.log(r); @@ -24,16 +25,27 @@ const Forms = () => { navigate("/forms/edit"); } ) - } + }; function editForm(item) { navigate("/forms/edit", { state: { id: item.id, - data: item.listAnswer + data: item.questions } }); - } + }; + + function removeForm(id) { + removeFormApi(id) + .then((resolve, _) => { + console.log(resolve); + setForms([...forms.filter(item => { + item.id !== id + })]); + }) + .catch(error => console.log(error)); + }; return (
@@ -49,19 +61,20 @@ const Forms = () => {
Название
-
Ответы
-
Изменения
+ {/*
Ответы
+
Изменения
*/}
{forms.map((item, i) => )} diff --git a/src/pages/NewForm.jsx b/src/pages/NewForm.jsx index 5f134b7..65f87f5 100644 --- a/src/pages/NewForm.jsx +++ b/src/pages/NewForm.jsx @@ -5,6 +5,7 @@ import MyButton from "../components/MyButton.jsx"; import AnswerModal from "../components/AnswerModal.jsx"; import PreviewModal from "../components/PreviewModal.jsx" import { FormsData, TypeAnswerData } from "../context"; +import { saveFormApi, updateFormByFormsApi } from "../hooks/api/formApi.js"; const NewForm = () => { const navigate = useNavigate(); @@ -29,11 +30,11 @@ const NewForm = () => { const [newForm, setNewForm] = useState(location.state ? location.state.data : []); - const [stateModal, setStateModal] = useState(false) + const [stateModal, setStateModal] = useState(false); function removeAnswerByForm(id) { setNewForm([...newForm.filter(item => item.id !== id)]); - } + }; function cleanStates() { setStateModal(false) @@ -45,7 +46,7 @@ const NewForm = () => { setCurrentTypeAnswer(""); setCurrentOptionAnswer("") setMandatory(false); - } + }; function addOptionAnswer(text) { setOptionAnswer([...optionAnswer, { @@ -53,7 +54,7 @@ const NewForm = () => { text: currentOptionAnswer }]); setCurrentOptionAnswer(""); - } + }; function editAnswerByForm(id) { const obj = newForm.find(item => item.id === id); @@ -65,7 +66,7 @@ const NewForm = () => { setOptionAnswer(obj.optionAnswer); setMandatory(obj.mandatory); setStateModal(id); - } + }; function updateAnswerByForm() { setNewForm(newForm.map(item => { @@ -81,7 +82,7 @@ const NewForm = () => { return item })) cleanStates() - } + }; function saveStates() { setNewForm([...newForm, { @@ -95,38 +96,43 @@ const NewForm = () => { file: file }]); cleanStates(); - } + }; function updateFormByForms() { - setForms( - forms.map(item => { - if (item.id === location.state.id) { - item.title = 'Новая форма', - item.datetime = 'Без изменений', - item.update = '01/01/24', - item.listAnswer = newForm - } - return item + updateFormByFormsApi(location.state.id, "Новая форма", newForm) + .then((resolve, _) => { + console.log(resolve); + setForms( + forms.map(item => { + if (item.id === location.state.id) { + item.title = "Новая форма", + item.questions = newForm + } + return item + }) + ); + cleanStates(); + navigate("/forms"); }) - ) - cleanStates(); - navigate("/forms"); - } + }; function saveForm() { - setForms( - [...forms, { - id: nextID(forms), - title: 'Новая форма', - datetime: 'Без изменений', - update: '01/01/24', - listAnswer: newForm, - answers: [] - }] - ); - cleanStates(); - navigate("/forms"); - } + saveFormApi("Новая форма", newForm) + .then((resolve, reject) => { + console.log(resolve); + setForms( + [...forms, { + id: nextID(forms), + title: "Новая форма", + questions: newForm, + answers: [] + }] + ); + cleanStates(); + navigate("/forms"); + }) + .catch(error => console.log(error)); + }; return (
diff --git a/src/pages/ViewForm.jsx b/src/pages/ViewForm.jsx index 678bc86..abb5dfd 100644 --- a/src/pages/ViewForm.jsx +++ b/src/pages/ViewForm.jsx @@ -4,6 +4,7 @@ import classes from "../assets/styles/viewForm.module.scss"; import { FormsData, TypeAnswerData } from "../context"; import GeneratingFormFields from "../components/GeneratingFormFields.jsx"; import MyButton from "../components/MyButton.jsx"; +import { saveAnswersApi } from "../hooks/api/formApi.js"; const ViewForm = () => { const navigate = useNavigate(); @@ -16,9 +17,9 @@ const ViewForm = () => { }; const [answers, setAnswers] = useState( - newForm() ? newForm().listAnswer.map(item => ( + newForm() ? newForm().questions.map(item => ( {id: item.id, answer: []} - )) : "" + )) : [] ); function updateAnswersForm(value, id) { @@ -32,6 +33,16 @@ const ViewForm = () => { ) }; + function saveAnswers() { + saveAnswersApi(formId, answers) + .then((resolve, _) => { + console.log(resolve) + setAnswers([]); + navigate("/"); + }) + .catch((error) => console.log(error)); + } + return (
{newForm() ? @@ -46,12 +57,15 @@ const ViewForm = () => {
- +
- - {}}/> + + { + setAnswers([]); + navigate("/"); + }}/>
:
diff --git a/src/router/protectedRouting.js b/src/router/protectedRouting.js new file mode 100644 index 0000000..51b34bc --- /dev/null +++ b/src/router/protectedRouting.js @@ -0,0 +1,18 @@ +const protectedUrl = { + notAuthorized: [ + "/forms", + "/forms/edit", + "/profile" + ], + notRights: [ + + ] +} + +function globalRender(url, user, navigate) { + if (!user && protectedUrl.notAuthorized.some(item => item === url)) { + navigate("/enter") + } +} + +export { globalRender } \ No newline at end of file diff --git a/src/router/router.js b/src/router/router.js index eaa76a8..e1e1b05 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -21,19 +21,19 @@ const router = createBrowserRouter([ element: , }, { - path: '/forms/edit/', + path: "/forms/edit", element: }, { - path: '/enter', + path: "/enter", element: }, { - path: '/profile', + path: "/profile", element: }, { - path: '/forms/:formId', + path: "/forms/:formId", element: } ]