diff --git a/src/app/App.tsx b/src/app/App.tsx index 9a70839..149b611 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -3,6 +3,7 @@ import { HeaderUi } from "../widgets/loyaout/ui/HeaderUi"; import { FooterUi } from "../widgets/loyaout/ui/FooterUi"; import { AuctionPage } from "../pages/AuctionPage"; import { AuthPage } from "../pages/AuthPage"; +import { PrivateRoute } from "./PrivateRoute"; import { BrowserRouter as Router, @@ -20,7 +21,9 @@ function App() {
- } /> + }> + }/> + } /> } /> diff --git a/src/app/PrivateRoute.tsx b/src/app/PrivateRoute.tsx new file mode 100644 index 0000000..3d15294 --- /dev/null +++ b/src/app/PrivateRoute.tsx @@ -0,0 +1,7 @@ +import React from 'react'; +import { Navigate, Outlet } from 'react-router-dom'; +import { getCookie } from "typescript-cookie"; + +export const PrivateRoute = () => { + return getCookie('authToken') ? : ; +} diff --git a/src/entities/Ui/SearchUi/SearchUi.tsx b/src/entities/Ui/SearchUi/SearchUi.tsx new file mode 100644 index 0000000..786e3db --- /dev/null +++ b/src/entities/Ui/SearchUi/SearchUi.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import Form from "react-bootstrap/Form"; + +import loupe from "../../../shared/images/loupe.png"; + +import styles from "./searchUi.module.scss"; + +export const SearchUi = () => { + return ( +
+ + loupe +
+ ) +} diff --git a/src/entities/Ui/SearchUi/index.ts b/src/entities/Ui/SearchUi/index.ts new file mode 100644 index 0000000..df86c54 --- /dev/null +++ b/src/entities/Ui/SearchUi/index.ts @@ -0,0 +1 @@ +export { SearchUi } from "./SearchUi" diff --git a/src/entities/Ui/SearchUi/searchUi.module.scss b/src/entities/Ui/SearchUi/searchUi.module.scss new file mode 100644 index 0000000..1994a36 --- /dev/null +++ b/src/entities/Ui/SearchUi/searchUi.module.scss @@ -0,0 +1,25 @@ +.container { + display: flex; + padding: 5px 10px; + border-radius: 8px; + border: 2px solid gray; + max-width: 300px; + width: 100%; + align-items: center; + + input { + border: none; + width: 100%; + outline: none; + box-shadow: none; + + &:focus { + box-shadow: none; + } + } + + img { + width: 18px; + height: 18px; + } +} diff --git a/src/features/auth/ui/AuthLoginFormUi/AuthLoginFormUi.tsx b/src/features/auth/ui/AuthLoginFormUi/AuthLoginFormUi.tsx new file mode 100644 index 0000000..0b95763 --- /dev/null +++ b/src/features/auth/ui/AuthLoginFormUi/AuthLoginFormUi.tsx @@ -0,0 +1,95 @@ +import React from "react"; +import { useNavigate } from "react-router-dom"; + +import { ButtonUi, ButtonUiType } from "../../../../shared/UI/ButtonUi"; + +import Form from 'react-bootstrap/Form'; + +import { useFormik } from 'formik'; +import * as yup from 'yup'; + +import { AuthResponsePayload } from '../../../../types'; +import { api } from "../../../../query/query"; +import { setCookie } from "typescript-cookie"; +import styles from "./authLoginForm.module.scss"; + +export const AuthLoginFormUi = () => { + + const navigate = useNavigate(); + + const schema = yup.object().shape({ + username: yup.string() + .min(3, 'Минимум 3 символа!') + .max(16, 'Максимум 16 символов!') + .required('Это поле обязательное.'), + + password: yup.string().required('Это обязательное поле.').min(6, 'Минимум 6 символов!'), + }); + + const { + handleSubmit, + handleChange, + handleBlur, + errors, + values, + setFieldError + } = useFormik({ + initialValues: { + username: '', + password: '', + }, + validationSchema: schema, + onSubmit: async (values): Promise => { + return await api.post('/authorization', { + username: values.username, + password: values.password + }).then((res) => { + if (res.data[0]) { + setFieldError('username', res.data[0]) + setFieldError('password', res.data[0]) + } else { + setCookie('authToken', res.data!.authToken) + setCookie('refreshToken', res.data!.refreshToken) + navigate("/auction") + } + return res.data as AuthResponsePayload + }) + }, + }) + + return ( +
+ + + + {errors.username} + + + + + + {errors.password} + + + + + ) +} diff --git a/src/features/auth/ui/AuthLoginFormUi/authLoginForm.module.scss b/src/features/auth/ui/AuthLoginFormUi/authLoginForm.module.scss new file mode 100644 index 0000000..1c6fad9 --- /dev/null +++ b/src/features/auth/ui/AuthLoginFormUi/authLoginForm.module.scss @@ -0,0 +1,8 @@ +.container { + padding: 20px 0; + display: flex; + flex-direction: column; + row-gap: 15px; + width: 100%; + max-width: 400px; +} diff --git a/src/features/auth/ui/AuthLoginFormUi/index.ts b/src/features/auth/ui/AuthLoginFormUi/index.ts new file mode 100644 index 0000000..1b1a588 --- /dev/null +++ b/src/features/auth/ui/AuthLoginFormUi/index.ts @@ -0,0 +1 @@ +export { AuthLoginFormUi } from "./AuthLoginFormUi"; diff --git a/src/pages/AuctionPage/AuctionPage.tsx b/src/pages/AuctionPage/AuctionPage.tsx index 930e40e..2d3e4bb 100644 --- a/src/pages/AuctionPage/AuctionPage.tsx +++ b/src/pages/AuctionPage/AuctionPage.tsx @@ -3,19 +3,19 @@ import React, { useState, useEffect } from "react"; import { BreadCrumbsUi } from "../../shared/UI/BreadCrumbsUi"; import {ButtonUi, ButtonUiType} from "../../shared/UI/ButtonUi"; import { LoaderUi } from "../../shared/UI/LoaderUi/LoaderUi"; -import { DefaultDropDown } from "../../entities/DefaultDropDown"; +import { AuctionFilters } from "../../widgets/AuctionFilters"; import { DefaultPagination } from "../../entities/DefaultPagination"; import { AddAuctionModal } from "../../widgets/AddAuctionModal"; import { EditAuctionModal } from "../../widgets/EditAuctionModal"; -import Form from 'react-bootstrap/Form'; +import { SearchUi } from "../../entities/Ui/SearchUi"; + +import Table from 'react-bootstrap/Table'; + import { AuctionItem } from "../../types"; -import { filterItems } from "../../constants/data"; import { api } from "../../query/query"; +import { getCookie } from "typescript-cookie"; -import loupe from "../../shared/images/loupe.png" -import filterImg from "../../shared/images/filter.png" -import close from "../../shared/images/close.png" import edit from "../../shared/images/edit.png" import styles from "./auctionPage.module.scss" @@ -24,13 +24,7 @@ export const AuctionPage = () => { const [auctionItems, setAuctionItems] = useState([]) - const [openAddModal, setOpenAddModal] = useState(false) - - const [loader, setLoader] = useState(false) - - const [openEditModal, setOpenEditModal] = useState(false) - - const [currentEditAuction, setCurrentEditAuction] = useState({ + const [currentEditAuction, setCurrentEditAuction] = useState({ uuid: '018c448e-c7d7-7092-b151-08f8d8bc410e', dateCreate: "2023-12-07 16:54:17", name: '', @@ -41,6 +35,12 @@ export const AuctionPage = () => { status: 'Сбор заявок' }) + const [openAddModal, setOpenAddModal] = useState(false) + + const [loader, setLoader] = useState(false) + + const [openEditModal, setOpenEditModal] = useState(false) + const addNewAuction = (newAction: string) => { setAuctionItems((prevValue) => [...prevValue, { uuid: '018c448e-c7d7-7092-b151-08f8d8bc480e', @@ -91,7 +91,7 @@ export const AuctionPage = () => { setAuctionItems(res.data) setLoader(false) }) - }, []) + }, [getCookie('authToken')]) return (
@@ -102,60 +102,42 @@ export const AuctionPage = () => {
setOpenAddModal(true)} title={'+ Добавить аукцион'} variant={ButtonUiType.PRIMARY} /> -
- - loupe -
-
-
- filter -
- {filterItems.map((item) => { - return - })} -
- } /> - +
+
{loader ? : <> - +
- - - - - - - + + + + + + + - {auctionItems.map((item) => { - return - - - - - - - - })} + {auctionItems.map((item) => { + return + + + + + + + + })} -
Название аукционаПрием заявокПроведениеСтатус
Название аукционаПрием заявокПроведениеСтатус
{item.uuid}{item.name}{getCorrectDate((item.requestsStartDate))}{item.dateCreate}{item.status} - edit { - setCurrentEditAuction(item) - setOpenEditModal(true) - }}/> -
{item.uuid}{item.name}{getCorrectDate((item.requestsStartDate))}{item.dateCreate}{item.status} + edit { + setCurrentEditAuction(item) + setOpenEditModal(true) + }}/> +
+ } diff --git a/src/pages/AuctionPage/auctionPage.module.scss b/src/pages/AuctionPage/auctionPage.module.scss index 01da11e..8d5ac1c 100644 --- a/src/pages/AuctionPage/auctionPage.module.scss +++ b/src/pages/AuctionPage/auctionPage.module.scss @@ -10,7 +10,7 @@ &__info { width: 100%; margin: 35px 0; - min-height: 168px; + min-height: 281px; display: flex; flex-direction: column; row-gap: 15px; @@ -23,8 +23,8 @@ &::-webkit-scrollbar { border-radius: 8px; - width: 5px; - height: 10px; + width: 3px; + height: 5px; background: gray; } @@ -36,79 +36,8 @@ max-height: 40px; } - &__search { - display: flex; - padding: 5px 10px; - border-radius: 8px; - border: 2px solid gray; - max-width: 300px; - width: 100%; - align-items: center; - - input { - border: none; - width: 100%; - outline: none; - box-shadow: none; - } - - img { - width: 18px; - height: 18px; - } - } - - &__filters { - display: flex; - padding: 10px 15px; - background-color: #2f95f2; - align-items: center; - justify-content: space-between; - min-width: 1213px; - - &Img { - width: 20px; - height: 20px; - } - - &__items { - display: flex; - column-gap: 10px; - } - - button { - display: flex; - align-items: center; - font-size: 17px; - max-width: 200px; - border: none; - color: white; - width: 100%; - cursor: pointer; - column-gap: 8px; - justify-content: center; - - img { - width: 17px; - height: 17px; - } - } - - .filter { - &__reset { - background-color: #0668c2; - } - - &__confirm { - background-color: #00529d; - } - } - } &__tableWrapper { - min-width: 1243px; - display: flex; - flex-direction: column; - align-items: center; + min-width: 1213px; .tableItem { padding: 10px; @@ -123,6 +52,8 @@ cursor: pointer; align-items: center; justify-content: center; + border: none; + img { width: 15px; height: 15px; @@ -133,34 +64,6 @@ text-align: center; } } - table { - width: 100%; - font-size: 15px; - font-weight: 500; - display: flex; - flex-direction: column; - row-gap: 10px; - margin-bottom: 15px; - - thead { - display: grid; - - tr { - display: grid; - grid-template-columns: 30% 20% 16% 12% 14% 8%; - } - } - - tbody { - display: grid; - row-gap: 10px; - - tr { - display: grid; - grid-template-columns: 30% 20% 16% 12% 14% 8%; - } - } - } } } } diff --git a/src/pages/AuthPage/AuthPage.tsx b/src/pages/AuthPage/AuthPage.tsx index d73f538..61e91a9 100644 --- a/src/pages/AuthPage/AuthPage.tsx +++ b/src/pages/AuthPage/AuthPage.tsx @@ -1,99 +1,15 @@ import React from "react"; -import { useNavigate } from "react-router-dom"; -import { ButtonUi, ButtonUiType } from "../../shared/UI/ButtonUi"; - -import Form from 'react-bootstrap/Form'; - -import { useFormik } from 'formik'; -import * as yup from 'yup'; - -import { api } from "../../query/query"; -import { setCookie } from "typescript-cookie"; -import { AuthResponsePayload } from "../../types"; +import { AuthLoginFormUi } from "../../features/auth/ui/AuthLoginFormUi"; import styles from "./authPage.module.scss" export const AuthPage = () => { - const navigate = useNavigate(); - - const schema = yup.object().shape({ - username: yup.string() - .min(3, 'Минимум 3 символа!') - .max(16, 'Максимум 16 символов!') - .required('Это поле обязательное.'), - - password: yup.string().required('Это обязательное поле.').min(6, 'Минимум 6 символов!'), - }); - - const { - handleSubmit, - handleChange, - handleBlur, - errors, - values, - setFieldError - } = useFormik({ - initialValues: { - username: '', - password: '', - }, - validationSchema: schema, - onSubmit: async (values): Promise => { - return await api.post('/authorization', { - username: values.username, - password: values.password - }).then((res) => { - if (res.data[0]) { - setFieldError('username', res.data[0]) - setFieldError('password', res.data[0]) - } else { - setCookie('authToken', res.data!.authToken) - setCookie('refreshToken', res.data!.refreshToken) - navigate("/auction") - } - return res.data as AuthResponsePayload - }) - }, - }) - return (

Аукционная площадка для проведения закупок ГК Проф-Пресс

-
- - - - {errors.username} - - - - - - {errors.password} - - - - +
) } diff --git a/src/pages/AuthPage/authPage.module.scss b/src/pages/AuthPage/authPage.module.scss index 3a1f6c2..6920659 100644 --- a/src/pages/AuthPage/authPage.module.scss +++ b/src/pages/AuthPage/authPage.module.scss @@ -10,13 +10,4 @@ max-width: 700px; text-align: center; } - - &__form { - padding: 20px 0; - display: flex; - flex-direction: column; - row-gap: 15px; - width: 100%; - max-width: 400px; - } } diff --git a/src/query/query.ts b/src/query/query.ts index d2e4c2b..3aec9ec 100644 --- a/src/query/query.ts +++ b/src/query/query.ts @@ -14,6 +14,7 @@ api.interceptors.response.use(undefined, async function (error) { if (error?.response?.status === 401) { removeCookie('authToken') removeCookie('refreshToken') + window.location.replace("/auth") } return Promise.reject(error) }) diff --git a/src/widgets/AuctionFilters/AuctionFilters.tsx b/src/widgets/AuctionFilters/AuctionFilters.tsx new file mode 100644 index 0000000..1831420 --- /dev/null +++ b/src/widgets/AuctionFilters/AuctionFilters.tsx @@ -0,0 +1,28 @@ +import React from "react"; + +import { DefaultDropDown } from "../../entities/DefaultDropDown"; +import { ButtonUi, ButtonUiType } from "../../shared/UI/ButtonUi"; + +import { filterItems } from "../../constants/data"; + +import filterImg from "../../shared/images/filter.png"; +import close from "../../shared/images/close.png"; +import styles from "./auctionFilters.module.scss"; + +export const AuctionFilters = () => { + return ( +
+ filter +
+ {filterItems.map((item) => { + return + })} +
+ } /> + +
+ ) +} diff --git a/src/widgets/AuctionFilters/auctionFilters.module.scss b/src/widgets/AuctionFilters/auctionFilters.module.scss new file mode 100644 index 0000000..01da22f --- /dev/null +++ b/src/widgets/AuctionFilters/auctionFilters.module.scss @@ -0,0 +1,36 @@ +.filter { + display: flex; + padding: 10px 15px; + background-color: #2f95f2; + align-items: center; + justify-content: space-between; + min-width: 1213px; + + &__img { + width: 20px; + height: 20px; + } + + &__items { + display: flex; + column-gap: 10px; + } + + button { + display: flex; + align-items: center; + font-size: 17px; + max-width: 200px; + border: none; + color: white; + width: 100%; + cursor: pointer; + column-gap: 8px; + justify-content: center; + + img { + width: 17px; + height: 17px; + } + } +} diff --git a/src/widgets/AuctionFilters/index.ts b/src/widgets/AuctionFilters/index.ts new file mode 100644 index 0000000..90fe18d --- /dev/null +++ b/src/widgets/AuctionFilters/index.ts @@ -0,0 +1 @@ +export { AuctionFilters } from "./AuctionFilters"