Merge remote-tracking branch 'origin/main' into main
This commit is contained in:
		@@ -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() {
 | 
			
		||||
        <div>
 | 
			
		||||
            <Router>
 | 
			
		||||
                <Routes>
 | 
			
		||||
                    <Route path="/auction" element={<AuctionPage />} />
 | 
			
		||||
                    <Route path='/auction' element={<PrivateRoute/>}>
 | 
			
		||||
                        <Route path='/auction' element={<AuctionPage/>}/>
 | 
			
		||||
                    </Route>
 | 
			
		||||
                    <Route path="/auth" element={<AuthPage />} />
 | 
			
		||||
                    <Route path="*" element={<Navigate to="/auth" replace />} />
 | 
			
		||||
                </Routes>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								src/app/PrivateRoute.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/app/PrivateRoute.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -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') ? <Outlet /> : <Navigate to="/auth" />;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								src/entities/Ui/SearchUi/SearchUi.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/entities/Ui/SearchUi/SearchUi.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -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 (
 | 
			
		||||
        <div className={styles.container}>
 | 
			
		||||
            <Form.Control
 | 
			
		||||
                type="text"
 | 
			
		||||
                placeholder="Найти аукцион"
 | 
			
		||||
            />
 | 
			
		||||
            <img src={loupe} alt='loupe' />
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/entities/Ui/SearchUi/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/entities/Ui/SearchUi/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export { SearchUi } from "./SearchUi"
 | 
			
		||||
							
								
								
									
										25
									
								
								src/entities/Ui/SearchUi/searchUi.module.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/entities/Ui/SearchUi/searchUi.module.scss
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								src/features/auth/ui/AuthLoginFormUi/AuthLoginFormUi.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/features/auth/ui/AuthLoginFormUi/AuthLoginFormUi.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -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<AuthResponsePayload> => {
 | 
			
		||||
            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 (
 | 
			
		||||
        <Form noValidate className={styles.container} onSubmit={handleSubmit}>
 | 
			
		||||
            <Form.Group>
 | 
			
		||||
                <Form.Control
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    id="username"
 | 
			
		||||
                    placeholder="username"
 | 
			
		||||
                    onChange={handleChange}
 | 
			
		||||
                    name="username"
 | 
			
		||||
                    onBlur={handleBlur}
 | 
			
		||||
                    value={values.username}
 | 
			
		||||
                    isInvalid={!!errors.username}
 | 
			
		||||
                />
 | 
			
		||||
                <Form.Control.Feedback type="invalid">
 | 
			
		||||
                    {errors.username}
 | 
			
		||||
                </Form.Control.Feedback>
 | 
			
		||||
            </Form.Group>
 | 
			
		||||
            <Form.Group>
 | 
			
		||||
                <Form.Control
 | 
			
		||||
                    type="password"
 | 
			
		||||
                    id="password"
 | 
			
		||||
                    placeholder="password"
 | 
			
		||||
                    onChange={handleChange}
 | 
			
		||||
                    value={values.password}
 | 
			
		||||
                    name="password"
 | 
			
		||||
                    onBlur={handleBlur}
 | 
			
		||||
                    isInvalid={!!errors.password}
 | 
			
		||||
                />
 | 
			
		||||
                <Form.Control.Feedback type="invalid">
 | 
			
		||||
                    {errors.password}
 | 
			
		||||
                </Form.Control.Feedback>
 | 
			
		||||
            </Form.Group>
 | 
			
		||||
            <ButtonUi title={'Войти'} variant={ButtonUiType.PRIMARY} type={'submit'}/>
 | 
			
		||||
        </Form >
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
.container {
 | 
			
		||||
  padding: 20px 0;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  row-gap: 15px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  max-width: 400px;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/features/auth/ui/AuthLoginFormUi/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/features/auth/ui/AuthLoginFormUi/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export { AuthLoginFormUi } from "./AuthLoginFormUi";
 | 
			
		||||
@@ -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<AuctionItem[]>([])
 | 
			
		||||
 | 
			
		||||
    const [openAddModal, setOpenAddModal] = useState(false)
 | 
			
		||||
 | 
			
		||||
    const [loader, setLoader] = useState(false)
 | 
			
		||||
 | 
			
		||||
    const [openEditModal, setOpenEditModal] = useState(false)
 | 
			
		||||
 | 
			
		||||
    const [currentEditAuction, setCurrentEditAuction] = useState({
 | 
			
		||||
    const [currentEditAuction, setCurrentEditAuction] = useState<AuctionItem>({
 | 
			
		||||
        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 (
 | 
			
		||||
        <div className={styles.home}>
 | 
			
		||||
@@ -102,33 +102,15 @@ export const AuctionPage = () => {
 | 
			
		||||
            <div className={styles.home__info}>
 | 
			
		||||
                <div className={styles.info__top}>
 | 
			
		||||
                    <ButtonUi event={() => setOpenAddModal(true)} title={'+ Добавить аукцион'} variant={ButtonUiType.PRIMARY} />
 | 
			
		||||
                    <div className={styles.info__search}>
 | 
			
		||||
                        <Form.Control
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            placeholder="Найти аукцион"
 | 
			
		||||
                        />
 | 
			
		||||
                        <img src={loupe} alt='loupe' />
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div className={styles.info__filters}>
 | 
			
		||||
                    <img className={styles.info__filtersImg} src={filterImg} alt="filter" />
 | 
			
		||||
                    <div className={styles.info__filters__items}>
 | 
			
		||||
                        {filterItems.map((item) => {
 | 
			
		||||
                            return <DefaultDropDown key={item.title} title={item.title} options={item.options} />
 | 
			
		||||
                        })}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <ButtonUi
 | 
			
		||||
                        title={'Сбросить фильтры'}
 | 
			
		||||
                        variant={ButtonUiType.PRIMARY}
 | 
			
		||||
                        img={<img src={close} alt="cross" />} />
 | 
			
		||||
                    <ButtonUi title={'Применить'} variant={ButtonUiType.INFO} />
 | 
			
		||||
                    <SearchUi />
 | 
			
		||||
                </div>
 | 
			
		||||
                <AuctionFilters />
 | 
			
		||||
                <div className={styles.info__tableWrapper}>
 | 
			
		||||
                    {loader ?
 | 
			
		||||
                        <LoaderUi animation={'border'} variant={'primary'} />
 | 
			
		||||
                        :
 | 
			
		||||
                        <>
 | 
			
		||||
                            <table>
 | 
			
		||||
                            <Table>
 | 
			
		||||
                                <thead>
 | 
			
		||||
                                    <tr className={styles.tableItem}>
 | 
			
		||||
                                        <td>№</td>
 | 
			
		||||
@@ -155,7 +137,7 @@ export const AuctionPage = () => {
 | 
			
		||||
                                        </tr>
 | 
			
		||||
                                    })}
 | 
			
		||||
                                </tbody>
 | 
			
		||||
                            </table>
 | 
			
		||||
                            </Table>
 | 
			
		||||
                            <DefaultPagination pageCount={10} currentPage={2} />
 | 
			
		||||
                        </>
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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%;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -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<AuthResponsePayload> => {
 | 
			
		||||
            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 (
 | 
			
		||||
        <div className={styles.auth}>
 | 
			
		||||
            <h1 className={styles.auth__title}>Аукционная площадка для проведения закупок ГК Проф-Пресс</h1>
 | 
			
		||||
            <Form noValidate className={styles.auth__form} onSubmit={handleSubmit}>
 | 
			
		||||
                <Form.Group>
 | 
			
		||||
                    <Form.Control
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        id="username"
 | 
			
		||||
                        placeholder="username"
 | 
			
		||||
                        onChange={handleChange}
 | 
			
		||||
                        name="username"
 | 
			
		||||
                        onBlur={handleBlur}
 | 
			
		||||
                        value={values.username}
 | 
			
		||||
                        isInvalid={!!errors.username}
 | 
			
		||||
                    />
 | 
			
		||||
                    <Form.Control.Feedback type="invalid">
 | 
			
		||||
                        {errors.username}
 | 
			
		||||
                    </Form.Control.Feedback>
 | 
			
		||||
                </Form.Group>
 | 
			
		||||
                <Form.Group>
 | 
			
		||||
                    <Form.Control
 | 
			
		||||
                        type="password"
 | 
			
		||||
                        id="password"
 | 
			
		||||
                        placeholder="password"
 | 
			
		||||
                        onChange={handleChange}
 | 
			
		||||
                        value={values.password}
 | 
			
		||||
                        name="password"
 | 
			
		||||
                        onBlur={handleBlur}
 | 
			
		||||
                        isInvalid={!!errors.password}
 | 
			
		||||
                    />
 | 
			
		||||
                    <Form.Control.Feedback type="invalid">
 | 
			
		||||
                        {errors.password}
 | 
			
		||||
                    </Form.Control.Feedback>
 | 
			
		||||
                </Form.Group>
 | 
			
		||||
                <ButtonUi title={'Войти'} variant={ButtonUiType.PRIMARY} type={'submit'}/>
 | 
			
		||||
            </Form >
 | 
			
		||||
            <AuthLoginFormUi />
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								src/widgets/AuctionFilters/AuctionFilters.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/widgets/AuctionFilters/AuctionFilters.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -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 (
 | 
			
		||||
        <div className={styles.filter}>
 | 
			
		||||
            <img className={styles.filter__img} src={filterImg} alt="filter" />
 | 
			
		||||
            <div className={styles.filter__items}>
 | 
			
		||||
                {filterItems.map((item) => {
 | 
			
		||||
                    return <DefaultDropDown key={item.title} title={item.title} options={item.options} />
 | 
			
		||||
                })}
 | 
			
		||||
            </div>
 | 
			
		||||
            <ButtonUi
 | 
			
		||||
                title={'Сбросить фильтры'}
 | 
			
		||||
                variant={ButtonUiType.PRIMARY}
 | 
			
		||||
                img={<img src={close} alt="cross" />} />
 | 
			
		||||
            <ButtonUi title={'Применить'} variant={ButtonUiType.INFO} />
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								src/widgets/AuctionFilters/auctionFilters.module.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/widgets/AuctionFilters/auctionFilters.module.scss
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/widgets/AuctionFilters/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/widgets/AuctionFilters/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export { AuctionFilters } from "./AuctionFilters"
 | 
			
		||||
		Reference in New Issue
	
	Block a user