Authorization and registration coding

Coding of registration and authorization is finished. Also other fixes
This commit is contained in:
RailTH
2024-05-16 00:11:43 +11:00
parent 5e521ab5db
commit 239e6c0420
19 changed files with 104 additions and 44 deletions

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.1 on 2024-05-04 09:04 # Generated by Django 4.1 on 2024-05-14 07:21
import django.core.validators import django.core.validators
from django.db import migrations, models from django.db import migrations, models
@@ -61,7 +61,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(db_index=True, primary_key=True, serialize=False, unique=True, verbose_name='ID Отзыва')), ('id', models.AutoField(db_index=True, primary_key=True, serialize=False, unique=True, verbose_name='ID Отзыва')),
('commentary', models.TextField(max_length=300, verbose_name='Комментарий отзыва')), ('commentary', models.TextField(max_length=300, verbose_name='Комментарий отзыва')),
('rate', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)], verbose_name='Оценка')), ('rate', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)], verbose_name='Оценка')),
('icons', models.TextField(verbose_name='Изображение отзыва в BASE64')), ('icons', models.TextField(null=True, verbose_name='Изображение отзыва в BASE64')),
('date', models.DateTimeField(auto_now=True, verbose_name='Дата создания отзыва')), ('date', models.DateTimeField(auto_now=True, verbose_name='Дата создания отзыва')),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='SusMarketBackend.product')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='SusMarketBackend.product')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='SusMarketBackend.user')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='SusMarketBackend.user')),

View File

@@ -1,7 +1,7 @@
{ {
"files": { "files": {
"main.css": "/static/css/main.b9cb408a.css", "main.css": "/static/css/main.f8545ce2.css",
"main.js": "/static/js/main.d5c997c3.js", "main.js": "/static/js/main.142d0adb.js",
"static/media/scam-image.png": "/static/media/scam-image.c6c14289dc251ba2d2b1.png", "static/media/scam-image.png": "/static/media/scam-image.c6c14289dc251ba2d2b1.png",
"static/media/info-page__railth-avatar.png": "/static/media/info-page__railth-avatar.cbf11c43b5ef243b38c0.png", "static/media/info-page__railth-avatar.png": "/static/media/info-page__railth-avatar.cbf11c43b5ef243b38c0.png",
"static/media/add.webp": "/static/media/add.cd69f1e2a8c91109db0f.webp", "static/media/add.webp": "/static/media/add.cd69f1e2a8c91109db0f.webp",
@@ -13,11 +13,11 @@
"static/media/rating__star-icon.svg": "/static/media/rating__star-icon.73718a24d04eb67f5873.svg", "static/media/rating__star-icon.svg": "/static/media/rating__star-icon.73718a24d04eb67f5873.svg",
"static/media/rating__filled-star-icon.svg": "/static/media/rating__filled-star-icon.dc7d908d4d943b7f3b56.svg", "static/media/rating__filled-star-icon.svg": "/static/media/rating__filled-star-icon.dc7d908d4d943b7f3b56.svg",
"index.html": "/index.html", "index.html": "/index.html",
"main.b9cb408a.css.map": "/static/css/main.b9cb408a.css.map", "main.f8545ce2.css.map": "/static/css/main.f8545ce2.css.map",
"main.d5c997c3.js.map": "/static/js/main.d5c997c3.js.map" "main.142d0adb.js.map": "/static/js/main.142d0adb.js.map"
}, },
"entrypoints": [ "entrypoints": [
"static/css/main.b9cb408a.css", "static/css/main.f8545ce2.css",
"static/js/main.d5c997c3.js" "static/js/main.142d0adb.js"
] ]
} }

View File

@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>SusMarket</title><link rel="manifest" href="/manifest.json"/><script defer="defer" src="/static/js/main.d5c997c3.js"></script><link href="/static/css/main.b9cb408a.css" rel="stylesheet"></head><body><div id="root"></div></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>SusMarket</title><link rel="manifest" href="/manifest.json"/><script defer="defer" src="/static/js/main.142d0adb.js"></script><link href="/static/css/main.f8545ce2.css" rel="stylesheet"></head><body><div id="root"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,5 @@
/*! js-cookie v3.0.5 | MIT */
/** /**
* @license React * @license React
* react-dom.production.min.js * react-dom.production.min.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -16,6 +16,7 @@
"@types/react": "^18.2.51", "@types/react": "^18.2.51",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.18",
"framer-motion": "^11.0.3", "framer-motion": "^11.0.3",
"js-cookie": "^3.0.5",
"node-sass": "^9.0.0", "node-sass": "^9.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@@ -26,7 +27,8 @@
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11" "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@types/js-cookie": "^3.0.6"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@@ -4487,6 +4489,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/@types/js-cookie": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz",
"integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==",
"dev": true
},
"node_modules/@types/json-schema": { "node_modules/@types/json-schema": {
"version": "7.0.15", "version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -12575,6 +12583,14 @@
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
"integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ=="
}, },
"node_modules/js-cookie": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
"engines": {
"node": ">=14"
}
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",

View File

@@ -11,6 +11,7 @@
"@types/react": "^18.2.51", "@types/react": "^18.2.51",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.18",
"framer-motion": "^11.0.3", "framer-motion": "^11.0.3",
"js-cookie": "^3.0.5",
"node-sass": "^9.0.0", "node-sass": "^9.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@@ -45,6 +46,7 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11" "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@types/js-cookie": "^3.0.6"
} }
} }

View File

@@ -5,6 +5,8 @@ import Logotype from "../assets/img/amongasik.png";
import CatalogMenu from "./CatalogMenu"; import CatalogMenu from "./CatalogMenu";
import LoginMenu from "./LoginMenu"; import LoginMenu from "./LoginMenu";
import { Category } from "../utils/types"; import { Category } from "../utils/types";
import Cookies from "js-cookie";
import { useNavigate } from "react-router-dom";
interface HeaderProps { interface HeaderProps {
togglePopupMap: () => void; togglePopupMap: () => void;
@@ -22,26 +24,25 @@ interface HeaderLoginMenuState {
export default function Header({ togglePopupMap, onSelectCategory, onSearchChange }: HeaderProps): JSX.Element { export default function Header({ togglePopupMap, onSelectCategory, onSearchChange }: HeaderProps): JSX.Element {
const [stateCatalog, setStateCatalog] = useState<HeaderCatalogMenuState>({ const [isCatalogMenuVisible, setIsCatalogMenuVisible] = useState(false);
isCatalogMenuVisible: false, const [isLoginMenuVisible, setIsLoginMenuVisible] = useState(false);
}); const navigate = useNavigate();
const [stateLogin, setStateLogin] = useState<HeaderLoginMenuState>({
isLoginMenuVisible: false,
});
const toggleCatalogMenu = () => { const toggleCatalogMenu = () => {
setStateCatalog((prevState) => ({ setIsCatalogMenuVisible(!isCatalogMenuVisible);
...prevState,
isCatalogMenuVisible: !prevState.isCatalogMenuVisible,
}));
}; };
const toggleLoginMenu = () => { const toggleLoginMenu = () => {
setStateLogin((prevState) => ({ setIsLoginMenuVisible(!isLoginMenuVisible);
...prevState, };
isLoginMenuVisible: !prevState.isLoginMenuVisible,
})); const handleProfileClick = () => {
const userCookie = Cookies.get('user');
if (userCookie) {
navigate('/profile');
} else {
toggleLoginMenu();
}
}; };
const resetCategoryFilter = () => { const resetCategoryFilter = () => {
@@ -102,7 +103,7 @@ export default function Header({ togglePopupMap, onSelectCategory, onSearchChang
className="header__profile-a" className="header__profile-a"
whileTap={{scale: 0.9}} whileTap={{scale: 0.9}}
transition={{duration: 0.2, type: "spring"}} transition={{duration: 0.2, type: "spring"}}
onClick={toggleLoginMenu} onClick={handleProfileClick}
> >
{/* Код для svg */} {/* Код для svg */}
<motion.svg width="48.000000" height="48.000000" viewBox="0 0 48 48" fill="none" <motion.svg width="48.000000" height="48.000000" viewBox="0 0 48 48" fill="none"
@@ -162,8 +163,8 @@ export default function Header({ togglePopupMap, onSelectCategory, onSearchChang
{/* Код для svg */} {/* Код для svg */}
</motion.a> </motion.a>
</nav> </nav>
{stateCatalog.isCatalogMenuVisible && <CatalogMenu toggleCatalogMenu={toggleCatalogMenu} onSelectCategory={onSelectCategory}/>} {isCatalogMenuVisible && <CatalogMenu toggleCatalogMenu={toggleCatalogMenu} onSelectCategory={onSelectCategory}/>}
{stateLogin.isLoginMenuVisible && <LoginMenu toggleLoginMenu={toggleLoginMenu}/>} {isLoginMenuVisible && <LoginMenu toggleLoginMenu={toggleLoginMenu}/>}
</header> </header>
) )
} }

View File

@@ -1,5 +1,8 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import Cookies from "js-cookie";
interface LoginMenuProps { interface LoginMenuProps {
toggleLoginMenu: () => void; toggleLoginMenu: () => void;
@@ -7,15 +10,49 @@ interface LoginMenuProps {
export default function LoginMenu({ toggleLoginMenu }: LoginMenuProps): JSX.Element { export default function LoginMenu({ toggleLoginMenu }: LoginMenuProps): JSX.Element {
const [isLoginMode, setIsLoginMode] = useState(true); const [isLoginMode, setIsLoginMode] = useState(true);
const [login, setLogin] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const toggleMode = () => { const toggleMode = () => {
setIsLoginMode(!isLoginMode); setIsLoginMode(!isLoginMode);
} }
const handleAuth = async (isRegistering: boolean) => {
try {
let response;
if (isRegistering) {
// Регистрация пользователя
const params = new URLSearchParams({
login: login,
password: password
});
response = await axios.get(`http://127.0.0.1:8000/api/post/user?${params.toString()}`);
} else {
// Вход в систему
response = await axios.get(`http://127.0.0.1:8000/api/get/user?login=${encodeURIComponent(login)}&password=${encodeURIComponent(password)}`);
}
if (response.status === 200) {
// Создание cookie файла
Cookies.set('user', login, { expires: 1 }); // Cookie на 1 день
// Перенаправление на страницу профиля
navigate('/profile');
toggleLoginMenu(); // Закрытие меню входа
}
} catch (error) {
console.error('Ошибка при авторизации:', error);
}
}
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
await handleAuth(!isLoginMode);
}
return( return(
<> <>
<div className="background-blackout" onClick={toggleLoginMenu}></div> <div className="background-blackout" onClick={toggleLoginMenu}></div>
<form className="popup-login"> <form className="popup-login" onSubmit={handleSubmit}>
<div className="popup-login__top-container"> <div className="popup-login__top-container">
<div className="top-container__headings-text"> <div className="top-container__headings-text">
<h5 className="popup-menu__heading"> <h5 className="popup-menu__heading">
@@ -27,8 +64,8 @@ export default function LoginMenu({ toggleLoginMenu }: LoginMenuProps): JSX.Elem
</div> </div>
</div> </div>
<div className="popup-login__inputs-container"> <div className="popup-login__inputs-container">
<input type="text" name="userName" id="userName" className="popup-login__name-input" placeholder="Логин"/> <input type="text" name="userName" id="userName" className="popup-login__name-input" placeholder="Логин" value={login} onChange={(e) => setLogin(e.target.value)}/>
<input type="password" name="userPassword" id="userPassword" className="popup-login__password-input" placeholder="Пароль"/> <input type="password" name="userPassword" id="userPassword" className="popup-login__password-input" placeholder="Пароль" value={password} onChange={(e) => setPassword(e.target.value)}/>
</div> </div>
<div className="popup-login__bottom-container"> <div className="popup-login__bottom-container">
<p className="popup-login__prompt-url" onClick={toggleMode}> <p className="popup-login__prompt-url" onClick={toggleMode}>
@@ -36,6 +73,7 @@ export default function LoginMenu({ toggleLoginMenu }: LoginMenuProps): JSX.Elem
<u>{isLoginMode ? 'Зарегистрироваться' : 'Войти'}</u> <u>{isLoginMode ? 'Зарегистрироваться' : 'Войти'}</u>
</p> </p>
<motion.button <motion.button
type="submit"
className="popup-login__login-button" className="popup-login__login-button"
whileTap={{scale: 0.98}} whileTap={{scale: 0.98}}
transition={{duration: 0.2, type: "spring"}} transition={{duration: 0.2, type: "spring"}}

View File

@@ -1,12 +1,15 @@
import React from "react"; import React from "react";
import ProfileAvatar from '../assets/icons/profile-avatar.svg'; import ProfileAvatar from '../assets/icons/profile-avatar.svg';
import '../ProfileStyle.scss'; import '../ProfileStyle.scss';
import Cookies from "js-cookie";
export default function ProfileInfo() { export default function ProfileInfo() {
const userLogin = Cookies.get('user');
return( return(
<div className="profile-page__info-div"> <div className="profile-page__info-div">
<img src={ProfileAvatar} alt="" className="info-div__img"/> <img src={ProfileAvatar} alt="" className="info-div__img"/>
<span>Роман Константинов</span> <span>{userLogin || 'Гость'}</span>
</div> </div>
) )
} }

View File

@@ -2,7 +2,7 @@ import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import '../ProfileStyle.scss'; import '../ProfileStyle.scss';
import ProfileInfo from "./ProfileInfo"; import ProfileInfo from "./ProfileInfo";
import ProductCard from "./ProductCard"; // import ProductCard from "./ProductCard";
export default function ProfilePurchases() { export default function ProfilePurchases() {
return( return(

View File

@@ -157,13 +157,11 @@ body {
position: fixed; position: fixed;
z-index: 999; z-index: 999;
width: 340px; width: 340px;
height: 495px;
left: 218px; left: 218px;
top: 108px; top: 108px;
display: flex; display: flex;
gap: 30px;
flex-direction: column; flex-direction: column;
justify-content: space-between;
align-items: flex-start;
box-sizing: border-box; box-sizing: border-box;
border-radius: 20px; border-radius: 20px;
background-color: $background-color; background-color: $background-color;