рабочий вход и выход

This commit is contained in:
goblinrf 2023-12-15 17:31:52 +03:00
parent 5ce820f4e9
commit a4056aaf25
11 changed files with 323 additions and 87 deletions

View File

@ -5,6 +5,26 @@
"name": "Новость"
}
],
"users": [
{
"id": 1,
"login": "user1",
"password": "password1",
"status": "user"
},
{
"id": 2,
"login": "user2",
"password": "password2",
"status": "admin"
},
{
"id": 3,
"login": "user3",
"password": "password3",
"status": "user"
}
],
"lines": [
{
"typeId": "1",
@ -29,14 +49,6 @@
"sum": "14.12.2023",
"image": "",
"id": 12
},
{
"typeId": "1",
"price": "jhkh",
"count": "kjh",
"sum": "14.12.2023",
"image": "",
"id": 13
}
]
}

103
Lab5/package-lock.json generated
View File

@ -8,15 +8,19 @@
"name": "lec4",
"version": "0.0.0",
"dependencies": {
"axios": "^1.6.1",
"axios": "^1.6.2",
"bootstrap": "^5.3.2",
"fs": "^0.0.1-security",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-bootstrap": "^2.9.1",
"react-bootstrap-icons": "^1.10.3",
"react-dom": "^18.2.0",
"react-hook-form": "^7.49.2",
"react-hot-toast": "^2.4.1",
"react-router-dom": "^6.18.0"
"react-redux": "^9.0.4",
"react-router-dom": "^6.21.0",
"redux": "^5.0.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
@ -956,9 +960,9 @@
}
},
"node_modules/@remix-run/router": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.11.0.tgz",
"integrity": "sha512-BHdhcWgeiudl91HvVa2wxqZjSHbheSgIiDvxrF1VjFzBzpTtuDPkOdOi3Iqvc08kXtFkLjhbS+ML9aM8mJS+wQ==",
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.0.tgz",
"integrity": "sha512-WOHih+ClN7N8oHk9N4JUiMxQJmRVaOxcg8w7F/oHUXzJt920ekASLI/7cYX8XkntDWRhLZtsk6LbGrkgOAvi5A==",
"engines": {
"node": ">=14.0.0"
}
@ -1094,6 +1098,11 @@
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.6.tgz",
"integrity": "sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA=="
},
"node_modules/@types/use-sync-external-store": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
},
"node_modules/@types/warning": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
@ -1355,9 +1364,9 @@
}
},
"node_modules/axios": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz",
"integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==",
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
@ -2849,6 +2858,11 @@
"node": ">= 0.6"
}
},
"node_modules/fs": {
"version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w=="
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -4750,6 +4764,22 @@
"react": "^18.2.0"
}
},
"node_modules/react-hook-form": {
"version": "7.49.2",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.49.2.tgz",
"integrity": "sha512-TZcnSc17+LPPVpMRIDNVITY6w20deMdNi6iehTFLV1x8SqThXGwu93HjlUVU09pzFgZH7qZOvLMM7UYf2ShAHA==",
"engines": {
"node": ">=18",
"pnpm": "8"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/react-hook-form"
},
"peerDependencies": {
"react": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-hot-toast": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz",
@ -4775,6 +4805,32 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"node_modules/react-redux": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.0.4.tgz",
"integrity": "sha512-9J1xh8sWO0vYq2sCxK2My/QO7MzUMRi3rpiILP/+tDr8krBHixC6JMM17fMK88+Oh3e4Ae6/sHIhNBgkUivwFA==",
"dependencies": {
"@types/use-sync-external-store": "^0.0.3",
"use-sync-external-store": "^1.0.0"
},
"peerDependencies": {
"@types/react": "^18.2.25",
"react": "^18.0",
"react-native": ">=0.69",
"redux": "^5.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"react-native": {
"optional": true
},
"redux": {
"optional": true
}
}
},
"node_modules/react-refresh": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@ -4785,11 +4841,11 @@
}
},
"node_modules/react-router": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.18.0.tgz",
"integrity": "sha512-vk2y7Dsy8wI02eRRaRmOs9g2o+aE72YCx5q9VasT1N9v+lrdB79tIqrjMfByHiY5+6aYkH2rUa5X839nwWGPDg==",
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.0.tgz",
"integrity": "sha512-hGZ0HXbwz3zw52pLZV3j3+ec+m/PQ9cTpBvqjFQmy2XVUWGn5MD+31oXHb6dVTxYzmAeaiUBYjkoNz66n3RGCg==",
"dependencies": {
"@remix-run/router": "1.11.0"
"@remix-run/router": "1.14.0"
},
"engines": {
"node": ">=14.0.0"
@ -4799,12 +4855,12 @@
}
},
"node_modules/react-router-dom": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.18.0.tgz",
"integrity": "sha512-Ubrue4+Ercc/BoDkFQfc6og5zRQ4A8YxSO3Knsne+eRbZ+IepAsK249XBH/XaFuOYOYr3L3r13CXTLvYt5JDjw==",
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.0.tgz",
"integrity": "sha512-1dUdVj3cwc1npzJaf23gulB562ESNvxf7E4x8upNJycqyUm5BRRZ6dd3LrlzhtLaMrwOCO8R0zoiYxdaJx4LlQ==",
"dependencies": {
"@remix-run/router": "1.11.0",
"react-router": "6.18.0"
"@remix-run/router": "1.14.0",
"react-router": "6.21.0"
},
"engines": {
"node": ">=14.0.0"
@ -4843,6 +4899,11 @@
"node": ">=4"
}
},
"node_modules/redux": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.0.tgz",
"integrity": "sha512-blLIYmYetpZMET6Q6uCY7Jtl/Im5OBldy+vNPauA8vvsdqyt66oep4EUpAMWNHauTC6xa9JuRPhRB72rY82QGA=="
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz",
@ -5640,6 +5701,14 @@
"punycode": "^2.1.0"
}
},
"node_modules/use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",

View File

@ -11,15 +11,19 @@
"prod": "npm-run-all lint 'vite build' --parallel rest 'vite preview'"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.18.0",
"react-hot-toast": "^2.4.1",
"axios": "^1.6.1",
"axios": "^1.6.2",
"bootstrap": "^5.3.2",
"fs": "^0.0.1-security",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-bootstrap": "^2.9.1",
"react-bootstrap-icons": "^1.10.3",
"prop-types": "^15.8.1"
"react-dom": "^18.2.0",
"react-hook-form": "^7.49.2",
"react-hot-toast": "^2.4.1",
"react-redux": "^9.0.4",
"react-router-dom": "^6.21.0",
"redux": "^5.0.0"
},
"devDependencies": {
"@types/react": "^18.2.15",

View File

@ -2,18 +2,31 @@ import PropTypes from 'prop-types';
import { Container } from 'react-bootstrap';
import { Toaster } from 'react-hot-toast';
import { Outlet } from 'react-router-dom';
import { Provider } from 'react-redux';
import React, { useEffect } from 'react';
import Footer from './components/footer/Footer.jsx';
import Navigation from './components/navigation/Navigation.jsx';
import { BrowserRouter as Router } from 'react-router-dom';
import store from './Reducer/store'; // Путь к вашему store
const App = ({ routes }) => {
useEffect(() => {
const storedUser = localStorage.getItem('user');
if (storedUser) {
store.dispatch({ type: 'SET_USER', payload: JSON.parse(storedUser) });
}
}, []);
return (
<>
<Provider store={store}>
<Navigation routes={routes}></Navigation>
<Container className='p-2' as='main' fluid>
<Outlet />
</Container>
<Footer />
<Toaster position='top-center' reverseOrder={true} />
</Provider>
</>
);
};

View File

@ -0,0 +1,7 @@
// store.js
import { createStore } from 'redux';
import userReducer from './userReducer';
const store = createStore(userReducer);
export default store;

View File

@ -0,0 +1,23 @@
// userReducer.js
const initialState = {
user: null,
};
const userReducer = (state = initialState, action) => {
switch (action.type) {
case 'SET_USER':
return {
...state,
user: action.payload,
};
case 'LOGOUT':
return {
...state,
user: null,
};
default:
return state;
}
};
export default userReducer;

View File

@ -0,0 +1,21 @@
const axios = require('axios');
const fs = require('fs');
// Чтение содержимого файла db.json
const dbContent = fs.readFileSync('./db.json', 'utf8');
// Адрес вашего JSON Server
const baseURL = 'http://localhost:8081/';
// Отправка данных на сервер
axios({
method: 'post',
url: `${baseURL}db`,
data: JSON.parse(dbContent),
})
.then((response) => {
console.log('Данные успешно загружены на сервер JSON Server.');
})
.catch((error) => {
console.error('Ошибка загрузки данных:', error);
});

View File

@ -1,7 +1,9 @@
import PropTypes from 'prop-types';
import { Container, Nav, Navbar } from 'react-bootstrap';
import { Cart2 } from 'react-bootstrap-icons';
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Link, useLocation } from 'react-router-dom';
import { Container, Nav, Navbar } from 'react-bootstrap';
import { logoutUser } from './js/userActions';
import PropTypes from 'prop-types';
import logo from '../../assets/logo.png';
import './Navigation.css';
@ -9,6 +11,12 @@ const Navigation = ({ routes }) => {
const location = useLocation();
const indexPageLink = routes.filter((route) => route.index === false).shift();
const pages = routes.filter((route) => Object.prototype.hasOwnProperty.call(route, 'title'));
const user = useSelector((state) => state.user); // Получение пользователя из хранилища Redux
const dispatch = useDispatch();
const handleLogout = () => {
dispatch(logoutUser()); // Действие для выхода пользователя
};
return (
<header>
@ -20,13 +28,25 @@ const Navigation = ({ routes }) => {
<Navbar.Toggle aria-controls='main-navbar' />
<Navbar.Collapse id='main-navbar'>
<Nav className='me-auto link' activeKey={location.pathname}>
{
pages.map((page) =>
<Nav.Link as={Link} key={page.path} eventKey={page.path} to={page.path ?? '/'}>
{pages.map((page) => (
<Nav.Link
as={Link}
key={page.path}
eventKey={page.path}
to={page.path ?? '/'}
>
{page.title}
</Nav.Link>)
}
</Nav.Link>
))}
</Nav>
<div className='user-info'>
{user ? (
<div className='user-welcome'>
<span>Добро пожаловать, {user.username}</span>
<button onClick={handleLogout}>Выход</button>
</div>
) : null}
</div>
</Navbar.Collapse>
</Container>
</Navbar>

View File

@ -0,0 +1,7 @@
// userActions.js
export const logoutUser = () => {
return {
type: 'LOGOUT',
};
};

View File

@ -60,7 +60,7 @@ const Page1 = () => {
</div>
<div className="col-md-4">
<div className="p-2">
<img src="./src/assets/image_from_main_1.jpg" alt="Картинка" className="w-100" />
<img src="src/assets/image_from_main_1.jpg" alt="Картинка" className="w-100" />
<img src="../src/assets/image_from_main_2.jpg" alt="Картинка" className=" d-block mt-2 w-100" />
<img src="../src/assets/image_from_main_3.jpg" alt="Картинка" className="d-block mt-2 w-100" />
</div>

View File

@ -1,5 +1,42 @@
/* eslint-disable linebreak-style */
import { useForm } from 'react-hook-form';
import { useState } from 'react';
import axios from 'axios';
import { useDispatch } from 'react-redux';
const Page5 = () => {
const { register, handleSubmit } = useForm();
const [errorMessage, setErrorMessage] = useState('');
const baseURL = 'http://localhost:8081/';
const dispatch = useDispatch();
const onSubmit = async (data) => {
try {
const response = await axios.get(`${baseURL}users`, {
params: {
login: data.login,
password: data.password,
},
});
if (response.data.length > 0) {
console.log('Успешный вход');
const userData = { username: data.login }; // Замените на данные пользователя
dispatch({ type: 'SET_USER', payload: userData });
localStorage.setItem('user', JSON.stringify(userData));
redirectToHomePage(); // Замените на вашу функцию перехода
} else {
console.error('Неверный логин или пароль');
setErrorMessage('Неверный логин или пароль');
}
} catch (error) {
console.error('Произошла ошибка:', error);
setErrorMessage('Произошла ошибка. Пожалуйста, попробуйте снова.');
}
};
const redirectToHomePage = () => {
window.location.href = 'http://localhost:5173/';
};
return (
<>
<div className="container-fluid">
@ -8,23 +45,46 @@ const Page5 = () => {
<div className="d-flex align-items-center min-vh-100">
<div className="container">
<a className="navbar-brand" href="/">
<img src="./src/assets/logo_cabinet.jpg" alt="Логотип" width="280" height="170" className="text-center mb-4" />
<img
src="./src/assets/logo_cabinet.jpg"
alt="Логотип"
width="280"
height="170"
className="text-center mb-4"
/>
</a>
<h2 className="text-center"> Вход</h2>
<h3 className="text-center">Личный кабинет</h3>
<form>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="mb-3">
<input type="text" className="form-control" id="login" name="login" placeholder="Логин" required />
<input
type="text"
className="form-control"
placeholder="Логин"
{...register('login', { required: true })}
/>
</div>
<div className="mb-3">
<input type="password" className="form-control" id="password" name="password" placeholder="Пароль" required />
<input
type="password"
className="form-control"
placeholder="Пароль"
{...register('password', { required: true })}
/>
</div>
<button className="btn btn-purple btn-block" type="submit">Вход</button>
{errorMessage && <p>{errorMessage}</p>}
</form>
</div>
</div>
</div>
<div id="ams-auth-image" className="col-xl-8 col-lg-7 col-md-6 d-none d-md-flex" style={ { backgroundImage: 'url(./src/assets/cabinet_autch.jpg)' }}></div>
<div className="col-xl-8 col-lg-7 col-md-6 d-none d-md-flex">
<img
src="./src/assets/cabinet_autch.jpg"
alt="Изображение"
style={{ width: '100%', height: 'auto' }}
/>
</div>
</div>
</div>
</>