Регистрация и вход работают
This commit is contained in:
parent
5be5bb06bb
commit
0abb511375
126
cucumber-frontend/package-lock.json
generated
126
cucumber-frontend/package-lock.json
generated
@ -15,9 +15,11 @@
|
|||||||
"@types/node": "^16.18.115",
|
"@types/node": "^16.18.115",
|
||||||
"@types/react": "^18.3.12",
|
"@types/react": "^18.3.12",
|
||||||
"antd": "^5.21.6",
|
"antd": "^5.21.6",
|
||||||
|
"axios": "^1.7.7",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.2.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-router-dom": "^6.27.0",
|
||||||
|
"react-scripts": "^5.0.1",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
@ -3392,6 +3394,15 @@
|
|||||||
"react-dom": ">=16.9.0"
|
"react-dom": ">=16.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@remix-run/router": {
|
||||||
|
"version": "1.20.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz",
|
||||||
|
"integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/plugin-babel": {
|
"node_modules/@rollup/plugin-babel": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||||
@ -3760,16 +3771,6 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@testing-library/dom/node_modules/aria-query": {
|
|
||||||
"version": "5.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
|
||||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"dequal": "^2.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@testing-library/jest-dom": {
|
"node_modules/@testing-library/jest-dom": {
|
||||||
"version": "5.17.0",
|
"version": "5.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz",
|
||||||
@ -4105,9 +4106,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "16.18.115",
|
"version": "16.18.116",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.115.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.116.tgz",
|
||||||
"integrity": "sha512-NF5ajYn+dq0tRfswdyp8Df75h7D9z+L8TCIwrXoh46ZLK6KZVXkRhf/luXaZytvm/keUo9vU4m1Bg39St91a5w==",
|
"integrity": "sha512-mLigUvhoaADRewggiby+XfAAFOUOMCm/SwL5DAJ+CMUGjSLIGMsJVN7BOKftuQSHGjUmS/W7hVht8fcNbi/MRA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node-forge": {
|
"node_modules/@types/node-forge": {
|
||||||
@ -5014,12 +5015,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/aria-query": {
|
"node_modules/aria-query": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
||||||
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
|
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"dependencies": {
|
||||||
"node": ">= 0.4"
|
"dequal": "^2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/array-buffer-byte-length": {
|
"node_modules/array-buffer-byte-length": {
|
||||||
@ -5308,6 +5309,17 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.7.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
||||||
|
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/axobject-query": {
|
"node_modules/axobject-query": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||||
@ -5850,9 +5862,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001673",
|
"version": "1.0.30001675",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001673.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001675.tgz",
|
||||||
"integrity": "sha512-WTrjUCSMp3LYX0nE12ECkV0a+e6LC85E0Auz75555/qr78Oc8YWhEPNfDd6SHdtlCMSzqtuXY0uyEMNRcsKpKw==",
|
"integrity": "sha512-/wV1bQwPrkLiQMjaJF5yUMVM/VdRPOCU8QZ+PmG6uW6DvYSrNY1bpwHI/3mOcUosLaJCzYDi5o91IQB51ft6cg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -7001,7 +7013,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@ -7864,6 +7875,15 @@
|
|||||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
|
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eslint-plugin-react": {
|
"node_modules/eslint-plugin-react": {
|
||||||
"version": "7.37.2",
|
"version": "7.37.2",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz",
|
||||||
@ -8775,9 +8795,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "3.0.2",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
|
||||||
"integrity": "sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==",
|
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
@ -11301,6 +11321,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsdom/node_modules/form-data": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsesc": {
|
"node_modules/jsesc": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
|
||||||
@ -13994,6 +14028,12 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/psl": {
|
"node_modules/psl": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
||||||
@ -14910,6 +14950,38 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-router": {
|
||||||
|
"version": "6.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz",
|
||||||
|
"integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@remix-run/router": "1.20.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-router-dom": {
|
||||||
|
"version": "6.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz",
|
||||||
|
"integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@remix-run/router": "1.20.0",
|
||||||
|
"react-router": "6.27.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8",
|
||||||
|
"react-dom": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-scripts": {
|
"node_modules/react-scripts": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
"@types/node": "^16.18.115",
|
"@types/node": "^16.18.115",
|
||||||
"@types/react": "^18.3.12",
|
"@types/react": "^18.3.12",
|
||||||
"antd": "^5.21.6",
|
"antd": "^5.21.6",
|
||||||
|
"axios": "^1.7.7",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.2.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-router-dom": "^6.27.0",
|
||||||
|
"react-scripts": "^5.0.1",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
|
62
cucumber-frontend/src/API/api.ts
Normal file
62
cucumber-frontend/src/API/api.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import axios, { AxiosError, AxiosRequestHeaders } from 'axios';
|
||||||
|
import IUser from '../models/IUser';
|
||||||
|
import IFarm from '../models/IFarm';
|
||||||
|
import LoginRequest from '../Requests/LoginRequest';
|
||||||
|
import IRegisterRequest from '../Requests/RegisterRequest';
|
||||||
|
|
||||||
|
const API_BASE_URL = 'https://localhost:7113/api';
|
||||||
|
|
||||||
|
const getHeaders = (): { [key: string]: string } => {
|
||||||
|
return {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export const getFarms = async (): Promise<IFarm[]> => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${API_BASE_URL}/farms`, { headers: getHeaders() });
|
||||||
|
return response.data;
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const axiosError = error as AxiosError;
|
||||||
|
console.error('Error fetching farms:', axiosError.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getUser = async (userId: number): Promise<IUser> => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${API_BASE_URL}/Auth/user/${userId}`, { headers: getHeaders() });
|
||||||
|
return response.data;
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const axiosError = error as AxiosError;
|
||||||
|
console.error('Error fetching user:', axiosError.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createUser = async (userData: IRegisterRequest): Promise<IUser> => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`${API_BASE_URL}/Auth/register`, userData, { headers: getHeaders() });
|
||||||
|
return response.data;
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const axiosError = error as AxiosError;
|
||||||
|
console.error('Error creating user:', axiosError.message);
|
||||||
|
if (axiosError.response) {
|
||||||
|
// Логируем дополнительные данные об ошибке
|
||||||
|
console.error('Response data:', axiosError.response.data);
|
||||||
|
console.error('Response status:', axiosError.response.status);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const loginUser = async (userData: LoginRequest): Promise<string> => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`${API_BASE_URL}/Auth/login`, userData, { headers: getHeaders() });
|
||||||
|
return response.data; // JWT токен
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const axiosError = error as AxiosError;
|
||||||
|
console.error('Error logging in:', axiosError.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
@ -1,11 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import { Routes } from 'react-router-dom';
|
import { Navigate, Route, Routes } from 'react-router-dom';
|
||||||
|
import {LoginPage} from './pages/Login';
|
||||||
|
import {RegisterPage} from './pages/Register';
|
||||||
|
import {AppLayout} from './components/Layout';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<Routes>
|
<Routes>
|
||||||
|
<Route path="/" element={<AppLayout />}>
|
||||||
|
<Route index element={<Navigate to="/login" />} />
|
||||||
|
<Route path="/login" element={<LoginPage />} />
|
||||||
|
<Route path="/register" element={<RegisterPage />} />
|
||||||
|
</Route>
|
||||||
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
6
cucumber-frontend/src/Requests/LoginRequest.ts
Normal file
6
cucumber-frontend/src/Requests/LoginRequest.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
interface ILoginRequest {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ILoginRequest;
|
7
cucumber-frontend/src/Requests/RegisterRequest.ts
Normal file
7
cucumber-frontend/src/Requests/RegisterRequest.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
interface IRegisterRequest {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IRegisterRequest;
|
8
cucumber-frontend/src/components/Footer.tsx
Normal file
8
cucumber-frontend/src/components/Footer.tsx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export function Footer () {
|
||||||
|
return (
|
||||||
|
<footer className="footer">
|
||||||
|
<p>© {new Date().getFullYear()} Cucumber</p>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
22
cucumber-frontend/src/components/Header.tsx
Normal file
22
cucumber-frontend/src/components/Header.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
export function Header () {
|
||||||
|
return (
|
||||||
|
<header className="header">
|
||||||
|
<div className="logo">
|
||||||
|
<Link to="/">Cucumber App</Link>
|
||||||
|
</div>
|
||||||
|
<nav className="nav">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<Link to="/login">Login</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/register">Register</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
};
|
19
cucumber-frontend/src/components/Layout.tsx
Normal file
19
cucumber-frontend/src/components/Layout.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Layout } from 'antd';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
import {Header} from './Header';
|
||||||
|
import {Footer} from './Footer';
|
||||||
|
|
||||||
|
export function AppLayout () {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<Header />
|
||||||
|
<Layout.Content>
|
||||||
|
<Outlet />
|
||||||
|
</Layout.Content>
|
||||||
|
<Footer />
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppLayout;
|
@ -11,3 +11,27 @@ code {
|
|||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
text-align: center;
|
||||||
|
background-color: #282c34;
|
||||||
|
min-height: 10vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: calc(10px + 2vmin);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
background-color: #282c34;
|
||||||
|
min-height: 10vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: calc(10px + 2vmin);
|
||||||
|
color: white;
|
||||||
|
}
|
11
cucumber-frontend/src/models/IFarm.tsx
Normal file
11
cucumber-frontend/src/models/IFarm.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import type IUser from "./IUser";
|
||||||
|
|
||||||
|
interface IFarm {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
userId: number;
|
||||||
|
user: IUser | null;
|
||||||
|
rasberryMacAddr: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IFarm;
|
11
cucumber-frontend/src/models/IUser.tsx
Normal file
11
cucumber-frontend/src/models/IUser.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import type IFarm from "./IFarm";
|
||||||
|
|
||||||
|
interface IUser {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
farms: IFarm[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IUser
|
66
cucumber-frontend/src/pages/Login.tsx
Normal file
66
cucumber-frontend/src/pages/Login.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
import { Button, Form, Input } from 'antd';
|
||||||
|
import { loginUser } from '../API/api';
|
||||||
|
import ILoginRequest from '../Requests/LoginRequest';
|
||||||
|
|
||||||
|
export function LoginPage () {
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const onFinish = async () => {
|
||||||
|
// Создаём объект с данными для отправки на сервер
|
||||||
|
const userData: ILoginRequest = {
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const token = await loginUser(userData);
|
||||||
|
// Сохраняем токен
|
||||||
|
localStorage.setItem('token', token);
|
||||||
|
alert('Вы успешно вошли в систему!');
|
||||||
|
navigate('/'); // Перенаправляем на главную страницу
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error logging in:', error);
|
||||||
|
alert('Ошибка при входе в систему. Проверьте введенные данные.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="login-page">
|
||||||
|
<h1>Login</h1>
|
||||||
|
<Form onFinish={onFinish}>
|
||||||
|
<Form.Item
|
||||||
|
label="Email"
|
||||||
|
name="email"
|
||||||
|
rules={[{ required: true, type: 'email', message: 'Пожалуйста, введите корректный email!' }]}
|
||||||
|
>
|
||||||
|
<Input value={email} onChange={e => setEmail(e.target.value)} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label="Password"
|
||||||
|
name="password"
|
||||||
|
rules={[{ required: true, min: 8, message: 'Пароль должен содержать не менее 8 символов!' }]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onChange={e => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" htmlType="submit">
|
||||||
|
Войти
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
<p>
|
||||||
|
Нет аккаунта? <Link to="/register">Зарегистрируйтесь</Link>
|
||||||
|
</p>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoginPage;
|
70
cucumber-frontend/src/pages/Register.tsx
Normal file
70
cucumber-frontend/src/pages/Register.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
import { Button, Form, Input } from 'antd';
|
||||||
|
import { createUser } from '../API/api';
|
||||||
|
import IRegisterRequest from '../Requests/RegisterRequest';
|
||||||
|
|
||||||
|
export function RegisterPage () {
|
||||||
|
const [name, setName] = useState('');
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleFinish = async () => {
|
||||||
|
// Create the user data object to send to the API
|
||||||
|
const userData: IRegisterRequest = {
|
||||||
|
name,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!navigator.onLine) {
|
||||||
|
alert('No internet connection');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await createUser(userData); // Pass the userData object
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
navigate('/login'); // Redirect to the login page after successful registration
|
||||||
|
alert('Пользователь успешно зарегестрирован!');
|
||||||
|
} else {
|
||||||
|
console.error('Error registering:');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error registering:', error);
|
||||||
|
alert('Error registering');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="register-page">
|
||||||
|
<h1>Register</h1>
|
||||||
|
<Form onFinish={handleFinish}>
|
||||||
|
<Form.Item label="Name" name="name" rules={[{ required: true, message: 'Пожалуйста, введите имя!' }]}>
|
||||||
|
<Input value={name} onChange={e => setName(e.target.value)} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="Email" name="email" rules={[{ required: true, type: 'email', message: 'Пожалуйста, введите корректный адрес почты!' }]}>
|
||||||
|
<Input value={email} onChange={e => setEmail(e.target.value)} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="Password" name="password" rules={[{ required: true, min: 8, message: 'Пароль должен содержать не менее 8 символов!' }]}>
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onChange={e => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" htmlType="submit">
|
||||||
|
Регистрация
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
<p>
|
||||||
|
Уже есть аккаунт? <Link to="/login">Войдите</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RegisterPage;
|
1184
package-lock.json
generated
1184
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"antd": "^5.21.6",
|
|
||||||
"react-router-dom": "^6.27.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/react": "^18.3.12"
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user