diff --git a/front/package-lock.json b/front/package-lock.json
index f4ec148..9fb04d8 100644
--- a/front/package-lock.json
+++ b/front/package-lock.json
@@ -28,12 +28,14 @@
"apexcharts": "3.49.2",
"axios": "^1.7.3",
"cors": "^2.8.5",
+ "date-fns": "^2.29.3",
"dayjs": "1.11.11",
"moment": "^2.30.1",
"notistack": "^3.0.1",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-apexcharts": "1.4.1",
+ "react-calendar": "^6.0.0",
"react-dom": "^18.3.1",
"react-hook-form": "7.52.0",
"react-jwt": "^1.2.2",
@@ -5528,6 +5530,15 @@
"@xtuc/long": "4.2.2"
}
},
+ "node_modules/@wojtekmaj/date-utils": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-2.0.2.tgz",
+ "integrity": "sha512-Do66mSlSNifFFuo3l9gNKfRMSFi26CRuQMsDJuuKO/ekrDWuTTtE4ZQxoFCUOG+NgxnpSeBq/k5TY8ZseEzLpA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/wojtekmaj/date-utils?sponsor=1"
+ }
+ },
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@@ -7498,6 +7509,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/date-fns": {
+ "version": "2.30.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
+ "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.21.0"
+ },
+ "engines": {
+ "node": ">=0.11"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/date-fns"
+ }
+ },
"node_modules/dayjs": {
"version": "1.11.11",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
@@ -9625,6 +9652,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-user-locale": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-3.0.0.tgz",
+ "integrity": "sha512-iJfHSmdYV39UUBw7Jq6GJzeJxUr4U+S03qdhVuDsR9gCEnfbqLy9gYDJFBJQL1riqolFUKQvx36mEkp2iGgJ3g==",
+ "license": "MIT",
+ "dependencies": {
+ "memoize": "^10.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1"
+ }
+ },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -13265,6 +13304,21 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/memoize": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/memoize/-/memoize-10.2.0.tgz",
+ "integrity": "sha512-DeC6b7QBrZsRs3Y02A6A7lQyzFbsQbqgjI6UW0GigGWV+u1s25TycMr0XHZE4cJce7rY/vyw2ctMQqfDkIhUEA==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-function": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/memoize?sponsor=1"
+ }
+ },
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -13341,6 +13395,18 @@
"node": ">=6"
}
},
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -15584,6 +15650,31 @@
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
+ "node_modules/react-calendar": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-6.0.0.tgz",
+ "integrity": "sha512-6wqaki3Us0DNDjZDr0DYIzhSFprNoy4FdPT9Pjy5aD2hJJVjtJwmdMT9VmrTUo949nlk35BOxehThxX62RkuRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@wojtekmaj/date-utils": "^2.0.2",
+ "clsx": "^2.0.0",
+ "get-user-locale": "^3.0.0",
+ "warning": "^4.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/wojtekmaj/react-calendar?sponsor=1"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-dev-utils": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -18421,6 +18512,15 @@
"makeerror": "1.0.12"
}
},
+ "node_modules/warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"node_modules/watchpack": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
diff --git a/front/package.json b/front/package.json
index 1034a42..e9f1aff 100644
--- a/front/package.json
+++ b/front/package.json
@@ -23,12 +23,14 @@
"apexcharts": "3.49.2",
"axios": "^1.7.3",
"cors": "^2.8.5",
+ "date-fns": "^2.29.3",
"dayjs": "1.11.11",
"moment": "^2.30.1",
"notistack": "^3.0.1",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-apexcharts": "1.4.1",
+ "react-calendar": "^6.0.0",
"react-dom": "^18.3.1",
"react-hook-form": "7.52.0",
"react-jwt": "^1.2.2",
diff --git a/front/public/assets/background.png b/front/public/assets/background.png
new file mode 100644
index 0000000..62454f2
Binary files /dev/null and b/front/public/assets/background.png differ
diff --git a/front/public/assets/logo_ulyanka-1.svg b/front/public/assets/logo_ulyanka-1.svg
new file mode 100644
index 0000000..25acf61
--- /dev/null
+++ b/front/public/assets/logo_ulyanka-1.svg
@@ -0,0 +1,457 @@
+
+
+
diff --git a/front/src/app/App.js b/front/src/app/App.js
index d741347..03af354 100644
--- a/front/src/app/App.js
+++ b/front/src/app/App.js
@@ -4,7 +4,7 @@ import {AuthProvider} from "../context/AuthContext";
import {createTTheme} from "../styles/theme/create-theme";
import {Experimental_CssVarsProvider as CssVarsProvider} from '@mui/material/styles';
import {BrowserRouter as Router} from "react-router-dom";
-import {NavigationRoutes} from "./NavigationRoutes";
+import {NavigationRoutes} from "../components/navigation/NavigationRoutes";
import {SnackbarProvider} from 'notistack';
import {UserProvider} from "../context/UserContext";
import {SelectProvider} from "../context/SelectContext";
diff --git a/front/src/app/HomeRedirect.js b/front/src/app/HomeRedirect.js
deleted file mode 100644
index 4c5e970..0000000
--- a/front/src/app/HomeRedirect.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import {paths} from "../path";
-import {Loading} from "../components/core/Loading";
-
-export function HomeRedirect({auth}) {
- const redirectPath = auth ? paths.dashboard.overview : paths.auth.signIn;
- window.location.replace(redirectPath);
- return (
-
- )
-}
\ No newline at end of file
diff --git a/front/src/app/layout/UserLayout.js b/front/src/app/layout/UserLayout.js
index d98ee16..e847bb6 100644
--- a/front/src/app/layout/UserLayout.js
+++ b/front/src/app/layout/UserLayout.js
@@ -1,4 +1,3 @@
-import {SideNav} from "../../components/navigation/SideNav";
import Box from "@mui/material/Box";
import {MainNav} from "../../components/navigation/MainNav";
import Container from "@mui/material/Container";
@@ -14,12 +13,10 @@ export function UserLayout({children}) {
minHeight: '100%',
}}
>
-
diff --git a/front/src/app/pages/BarChangePage.js b/front/src/app/pages/BarChangePage.js
deleted file mode 100644
index 601d840..0000000
--- a/front/src/app/pages/BarChangePage.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import Paper from "@mui/material/Paper";
-import React, {useEffect, useState} from "react";
-import {useAlert} from "../../hooks/useAlert";
-import {Card} from "@mui/material";
-import Stack from "@mui/material/Stack";
-import Typography from "@mui/material/Typography";
-import IconButton from "@mui/material/IconButton";
-import Box from "@mui/material/Box";
-import DeleteIcon from '@mui/icons-material/Delete';
-import ElectricalServicesIcon from '@mui/icons-material/ElectricalServices';
-import Toolbar from "@mui/material/Toolbar";
-import AddCircleIcon from '@mui/icons-material/AddCircle';
-import {BarCreateModal} from "../../components/BarCreateModal";
-import PowerIcon from '@mui/icons-material/Power';
-import ContentCopyIcon from '@mui/icons-material/ContentCopy';
-import {barClient} from "../../lib/clients/BarClient";
-
-export function BarChangePage() {
- const [bars, setBars] = useState([])
- const [open, setOpen] = useState(false)
- const [oldId, setOldId] = useState(null);
- const {createError, createSuccess, createWarning} = useAlert();
-
- const createHandler = (id, name) => {
- if (id) {
- barClient.copyBar(id, name, setBars, bars, createError, createSuccess, setOpen)
- } else {
- barClient.createBar(name, bars, createSuccess, createError, setBars, setOpen)
- }
- }
-
- // eslint-disable-next-line
- useEffect(() => barClient.getBarList(setBars, createError), []);
-
- return (<>
-
-
-
- Списки ингредиентов (бары)
- {
- setOldId(null);
- setOpen(true);
- }}>
-
-
-
- {bars.map((b) => {
- return
-
- {b.name}
-
- {
- setOldId(b.id)
- setOpen(true);
- }}>
-
-
- {b.active &&
-
- }
- {!b.active && <>
- barClient.deleteBar(b, bars, createError, createSuccess, setBars)}>
-
-
- barClient.changeBar(b.id, bars, createWarning, createSuccess, createError, setBars)}>
-
-
- >}
-
-
-
- })}
-
- >
-
- )
-}
\ No newline at end of file
diff --git a/front/src/app/pages/calc/CalcPage.js b/front/src/app/pages/calc/CalcPage.js
deleted file mode 100644
index e87d8fa..0000000
--- a/front/src/app/pages/calc/CalcPage.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import Typography from "@mui/material/Typography";
-import * as React from "react";
-import {useEffect, useMemo} from "react";
-import {useAlert} from "../../../hooks/useAlert";
-import Stack from "@mui/material/Stack";
-import Box from "@mui/material/Box";
-import {CocktailItemCalc} from "./CocktailItemCalc";
-import {IngredientCalcCard} from "./IngredientCalcCard";
-import {cocktailClient} from "../../../lib/clients/CocktailClient";
-
-export function CalcPage() {
- const {createError} = useAlert();
- const [cocktails, setCocktails] = React.useState([]);
- const [load, setLoad] = React.useState(false);
- const [cocktailMap, setCocktailMap] = React.useState({});
-
- const changeHandler = (id, value) => {
- setCocktailMap((prev) => ({
- ...prev,
- [id]: value
- }));
- }
-
- useEffect(() => {
- cocktailClient.getCocktailsForCalcPage(load, setLoad, setCocktails, setCocktailMap, createError)
- // eslint-disable-next-line
- }, [load]);
-
- const ingredients = useMemo(() => {
- let map = {}
- if (!cocktails) {
- return [];
- }
- cocktails.forEach((c) => {
- const receipts = c.receipt;
- const countMeter = cocktailMap[c.id];
-
- if (!receipts) {
- return
- }
- receipts.forEach((r) => {
- const ingredient = r.ingredient;
- const id = ingredient.id;
- const ingredientCount = r.count;
-
- const resultCount = ingredientCount * countMeter;
-
- if (map[id]) {
- map[id] = {
- ...map[id],
- count: map[id].count + resultCount
- }
- } else {
- map[id] = {
- ingredient: ingredient,
- count: resultCount
- }
- }
- })
- })
- return Object.values(map);
- },
- [cocktails, cocktailMap])
-
- const deleteHandler = (id) => {
- const state = cocktails.filter((c) => c.id !== id);
- setCocktails(state);
- }
-
- console.log(cocktailMap)
-
- return (
-
- Коктейли
-
- {cocktails.map((item, i) => (
-
- ))}
-
-
- Ингредиенты
-
- {ingredients.map((item, i) => (
-
- ))}
-
-
- )
-}
\ No newline at end of file
diff --git a/front/src/app/pages/calc/CocktailItemCalc.js b/front/src/app/pages/calc/CocktailItemCalc.js
deleted file mode 100644
index c864d93..0000000
--- a/front/src/app/pages/calc/CocktailItemCalc.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import {Card} from "@mui/material";
-import Stack from "@mui/material/Stack";
-import Box from "@mui/material/Box";
-import IconButton from "@mui/material/IconButton";
-import DeleteIcon from "@mui/icons-material/Delete";
-import React from "react";
-import Typography from "@mui/material/Typography";
-import {Counter} from "./Counter";
-
-export function CocktailItemCalc({cocktail, deleteHandler, changeHandler}) {
- return (
-
-
-
-
-
-
-
-
- {cocktail.name}
- {cocktail.volume}
- {cocktail.category}
- {cocktail.alcoholic}
- {cocktail.components}
-
-
-
-
-
- deleteHandler(cocktail.id)}>
-
-
-
-
-
-
-
-
- )
-}
\ No newline at end of file
diff --git a/front/src/app/pages/calc/Counter.js b/front/src/app/pages/calc/Counter.js
deleted file mode 100644
index e7b00af..0000000
--- a/front/src/app/pages/calc/Counter.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React, {useState} from 'react';
-import {Box, TextField, Button} from '@mui/material';
-import {styled} from '@mui/material/styles';
-
-// Стилизуем контейнер счетчика
-styled(Box)`
- display: flex;
- align-items: center;
- justify-content: center;
- width: 150px;
- height: 50px;
- border-radius: 8px;
- //box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
- //background-color: #ffffff;
-`;
-
-export function Counter({id, changeHandler}) {
- const [value, setValue] = useState(1);
-
- const handleChange = (newValue) => {
- setValue(newValue);
- changeHandler(id, newValue);
- }
-
- return (
-
-
- {
- const newValue = parseInt(e.target.value, 10);
- if (!isNaN(newValue)) {
- handleChange(newValue);
- }
- }}
- inputProps={{inputMode: 'numeric'}}
- sx={{
- width: '40px',
- height: '15px',
- fontSize: '10px',
- textAlign: 'center'
- }}
- />
-
-
- );
-}
\ No newline at end of file
diff --git a/front/src/app/pages/calc/IngredientCalcCard.js b/front/src/app/pages/calc/IngredientCalcCard.js
deleted file mode 100644
index 16907d9..0000000
--- a/front/src/app/pages/calc/IngredientCalcCard.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import {Card} from "@mui/material";
-import Stack from "@mui/material/Stack";
-import Box from "@mui/material/Box";
-import React from "react";
-
-export function IngredientCalcCard({ingredient, count}) {
- return (
-
-
-
-
-
- {ingredient.name}
-
- {count}
-
-
-
- )
-
-}
\ No newline at end of file
diff --git a/front/src/app/pages/cocktails/CocktailsPageContent.js b/front/src/app/pages/cocktails/CocktailsPageContent.js
deleted file mode 100644
index c7c54d6..0000000
--- a/front/src/app/pages/cocktails/CocktailsPageContent.js
+++ /dev/null
@@ -1,196 +0,0 @@
-import Grid from "@mui/material/Grid";
-import {useAlert} from "../../../hooks/useAlert";
-import * as React from "react";
-import {useCallback, useEffect, useState} from "react";
-import {Cocktail} from "../../../components/cocktails/Cocktail";
-import {Fab, Skeleton} from "@mui/material";
-import Box from "@mui/material/Box";
-import {NoResult} from "../../../components/cocktails/NoResult";
-import {FilterBlock} from "../../../components/cocktails/FilterBlock";
-import {CocktailInfoModal} from "../../../components/cocktails/CocktailInfoModal";
-import {useUser} from "../../../hooks/useUser";
-import {blue} from "@mui/material/colors";
-import UpIcon from "@mui/icons-material/KeyboardArrowUp";
-import {useSelect} from "../../../hooks/useSelect";
-import Paper from "@mui/material/Paper";
-import CheckMarks from "../../../components/cocktails/CheckMarks";
-import {cocktailClient} from "../../../lib/clients/CocktailClient";
-
-const emptyFilter = {
- search: "",
- all: false,
- hidden: true,
- onlyFavourite: false,
- glass: [],
- category: [],
- alcohol: [],
- iCount: [],
- ingredient: [],
- inMenu: "",
- sorting: "Название по возрастанию"
-}
-
-const CocktailsPageContent = () => {
- const {user} = useUser();
- const {createError, createSuccess} = useAlert();
- const [rows, setRows] = useState([]);
- const [filter, setFilter] = useState(emptyFilter)
- // const [chips, setChips] = useState([])
- const chips = [];
- const [page, setPage] = useState(-1);
- const [load, setLoad] = useState(false);
- const [isEnd, setIsEnd] = useState(false);
- const [isNew, setIsNew] = useState(true);
-
- const {selectCocktail, getCocktail, getOpenCocktail} = useSelect();
-
- const loading = useCallback(() => {
- const size = Math.floor((window.innerWidth) / 350) * 5;
- if (load || (!isNew && isEnd)) {
- return false;
- }
- cocktailClient.getMenu(setRows, setIsNew, setPage, setLoad, setIsEnd, isNew, rows, page, size, filter, createError);
- // eslint-disable-next-line
- }, [load, isEnd, page]);
-
- useEffect(() => {
- const handleScroll = () => {
- const {scrollTop, scrollHeight, clientHeight} = document.documentElement;
- if (scrollTop + clientHeight >= scrollHeight - 100) {
- loading();
- }
- }
- window.addEventListener('scroll', handleScroll);
- return () => window.removeEventListener('scroll', handleScroll);
- // eslint-disable-next-line
- }, [loading]);
- // eslint-disable-next-line
- useEffect(() => loading(), [filter])
-
- const renderSkeleton = () => {
- return Array.from({length: 3}, () => null)
- .map((v, index) => );
- }
- const handleChangeRating = (row, value) => {
- const newState = rows.map((r) => {
- if (row.id === r.id) {
- let newRating = r.rating;
- newRating.rating = value
- return {
- ...r,
- rating: newRating
- }
- }
- return r;
- })
- cocktailClient.changeRating(row.id, newState, value, setRows, createSuccess, createError)
-
- }
- const handleFilterChange = (filterName, value) => {
- const newState = {
- ...filter,
- [filterName]: value
- }
- setFilter(newState)
- setIsNew(true);
- setIsEnd(false);
- setPage(-1);
- }
- const handleFavourite = (row) => {
- const value = !row.rating.favourite;
- const newState = rows.map((r) => {
- if (r.id === row.id) {
- let newRating = r.rating;
- newRating.favourite = value;
- return {
- ...r,
- rating: newRating
- }
- }
- return r;
- });
- cocktailClient.changeFavourite(value, row.id, newState, setRows, createSuccess, createError)
- }
- const handleFilterClear = () => {
- setFilter(emptyFilter);
- setIsNew(true);
- setIsEnd(false);
- setPage(-1);
- }
-
- const handleSelectCocktail = (row) => selectCocktail(row.id)
- const deleteHandle = (row) => cocktailClient.deleteCocktail(row.id, rows, setRows, createSuccess, createError)
- const hideHandler = (id) => {
- cocktailClient.hiddenCocktail(id)
- .then(() => {
- createSuccess("Коктейль скрыт успешно");
- setRows(rows.filter((r) => r.id !== id))
- }).catch(() => createError("Ошибка при попытке скрыть коктейль"))
- }
-
- return (
-
- {/**/}
- {/*Модальное окно информации о коктейле*/}
-
- {/*Блок фильтров*/}
-
-
- {
- (filter.all && filter.iCount === 1) && (
-
-
-
- )
- }
-
- {/*Основное содержимое*/}
-
- {rows.length > 0 && rows.map((row) => {
- return (
-
- )
- })}
- {load && renderSkeleton()}
- {rows.length === 0 && ()}
-
-
- window.window.scrollTo(0, 0)}
- aria-label='Expand'
- color='inherit'>
-
-
-
- );
-}
-
-export default CocktailsPageContent;
\ No newline at end of file
diff --git a/front/src/app/pages/ingredients/EditIngredientPage.js b/front/src/app/pages/ingredients/EditIngredientPage.js
deleted file mode 100644
index 70d5787..0000000
--- a/front/src/app/pages/ingredients/EditIngredientPage.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import Box from "@mui/material/Box";
-import Toolbar from "@mui/material/Toolbar";
-import Typography from "@mui/material/Typography";
-import * as React from "react";
-import {useEffect, useState} from "react";
-import Paper from "@mui/material/Paper";
-import {Autocomplete, FormControl, FormControlLabel, InputLabel} from "@mui/material";
-import {useAlert} from "../../../hooks/useAlert";
-import {useSearchParams} from "react-router-dom";
-import TextField from "@mui/material/TextField";
-import Switch from "@mui/material/Switch";
-import Stack from "@mui/material/Stack";
-import Button from "@mui/material/Button";
-import Select from "@mui/material/Select";
-import MenuItem from "@mui/material/MenuItem";
-import {ingredientClient} from "../../../lib/clients/IngredientClient";
-
-const emptyIngredient = {
- id: null,
- name: "",
- enName: "",
- have: false,
- image: null,
- type: "",
- alcohol: false,
- abv: null,
- description: null
-}
-
-export function EditIngredientPage() {
- const [searchParams] = useSearchParams();
- const [ingredients, setIngredients] = useState([]);
- const [types, setTypes] = useState([]);
- const [ingredient, setIngredient] = useState(emptyIngredient)
- const {createError, createSuccess} = useAlert();
- useEffect(() => {
- ingredientClient.allList(searchParams.get("id"), setIngredients, setIngredient, createError)
- ingredientClient.getType(setTypes)
- // eslint-disable-next-line
- }, []);
-
- const changeIngredientValue = (name, value) => {
- setIngredient((prev) => ({
- ...prev,
- [name]: value
- }))
- }
-
- return (
-
- {/*Заголовок*/}
-
- Ингредиенты
-
- {/*Поиск*/}
-
- {
- return !v ? setIngredient(emptyIngredient) : setIngredient(v)
- }}
- isOptionEqualToValue={(selected, value) => selected.id === value.id}
- getOptionKey={(selected) => selected.id}
- getOptionLabel={(selected) => selected.name}
- renderInput={(params) => }
- />
-
- {/*Форма ингредиента*/}
-
-
-
- changeIngredientValue("have", !ingredient.have)}
- />}
- label={"Наличие"} labelPlacement={'start'}/>
-
-
-
-
-
- changeIngredientValue("name", e.target.value)}/>
-
-
-
- changeIngredientValue("alcohol", !ingredient.alcohol)}
- />}
- label="Алкогольный"/>
- {ingredient.alcohol && (
- changeIngredientValue("abv", e.target.value)}/>
- )}
-
-
-
-
- Категория
-
-
-
-
-
- changeIngredientValue("description", e.target.value)}
- value={!ingredient.description ? "" : ingredient.description}/>
-
-
-
-
-
-
-
- )
-}
\ No newline at end of file
diff --git a/front/src/app/pages/ingredients/IngredientsPage.js b/front/src/app/pages/ingredients/IngredientsPage.js
deleted file mode 100644
index ea0f23c..0000000
--- a/front/src/app/pages/ingredients/IngredientsPage.js
+++ /dev/null
@@ -1,126 +0,0 @@
-import Box from "@mui/material/Box";
-import Typography from "@mui/material/Typography";
-import Toolbar from "@mui/material/Toolbar";
-import Paper from "@mui/material/Paper";
-import {Fab, FormControl, InputAdornment, InputLabel, OutlinedInput, Tabs} from "@mui/material";
-import IconButton from "@mui/material/IconButton";
-import SearchIcon from "@mui/icons-material/Search";
-import * as React from "react";
-import {useEffect, useMemo, useState} from "react";
-import {Loading} from "../../../components/core/Loading";
-import {useAlert} from "../../../hooks/useAlert";
-import {IngredientInfoModal} from "../../../components/Ingredients/IngredientInfoModal";
-import Tab from "@mui/material/Tab";
-import {a11yProps} from "../../../components/core/tabProps";
-import {CustomTabPanel} from "../../../components/core/TabPanel";
-import {IngredientList} from "../../../components/Ingredients/IngredientList";
-import {blue} from "@mui/material/colors";
-import UpIcon from "@mui/icons-material/KeyboardArrowUp";
-import {useSelect} from "../../../hooks/useSelect";
-import {ingredientClient} from "../../../lib/clients/IngredientClient";
-
-export function IngredientsPage() {
- const [value, setValue] = React.useState(0);
- const handleChange = (event, newValue) => setValue(newValue);
- const [loading, setLoading] = useState(true);
- const [findString, setFindString] = useState("");
- const [ingredients, setIngredients] = useState([]);
- const {getIngredient, selectIngredient} = useSelect();
- const {createError, createSuccess} = useAlert();
-
- useEffect(() => {
- ingredientClient.getAllIngredients(setIngredients, setLoading, createError)
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
- const visibleIngredients = useMemo(() => {
- if (findString.length === 0) {
- return ingredients;
- }
- const reg = new RegExp("(.*?)" + findString + "(.*?)", "i");
- return ingredients.filter((ingredient) => ingredient.name.match(reg) !== null);
- }, [findString, ingredients]);
- const ingredientsToAdd = visibleIngredients.filter((ingredient) => !ingredient.have);
- const ingredientsInBar = visibleIngredients.filter((ingredient) => ingredient.have);
-
- const changeHandler = (row, value) => {
- const newState = ingredients.map((ingredient) => {
- if (ingredient.id === row.id) {
- return {
- ...ingredient,
- have: value
- }
- } else {
- return ingredient;
- }
- })
- ingredientClient.changeIngredientIsHave(row.id, value, newState, setIngredients, createError)
- }
- const handleDelete = (id) => {
- const newState = ingredients.filter((ingredient) => ingredient.id !== id);
- setIngredients(newState)
- ingredientClient.deleteIngredientIsHave(id, createSuccess, createError)
- }
-
- return (
-
- {/*Заголовок*/}
-
- Ингредиенты бара
-
- {/*Поиск*/}
-
-
- Поиск
- setFindString(e.target.value)}
- label="With normal TextField"
- startAdornment={
-
-
-
-
-
- }
- />
-
-
- {/*Рабочее поле ингредиентов*/}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- window.window.scrollTo(0, 0)}
- aria-label='Expand'
- color='inherit'>
-
-
- {/*Загрузчик*/}
-
- {/*Модальное окно информации об ингредиенте*/}
-
-
- )
-}
\ No newline at end of file
diff --git a/front/src/components/navigation/SideNav.js b/front/src/components/navigation/SideNav.js
deleted file mode 100644
index a90632a..0000000
--- a/front/src/components/navigation/SideNav.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import * as React from 'react';
-import Box from '@mui/material/Box';
-import {NavigationMenu} from "./NavigationMenu";
-
-export function SideNav() {
- return (
-
-
-
- );
-}
\ No newline at end of file
diff --git a/front/src/context/UserContext.js b/front/src/context/UserContext.js
index 16c0256..2f75719 100644
--- a/front/src/context/UserContext.js
+++ b/front/src/context/UserContext.js
@@ -27,6 +27,12 @@ export function UserProvider({children}) {
return;
}
if (Object.keys(state.user).length === 0) {
+ const userMock = {
+ name: 'Sergey',
+ lastName: 'Kayashov'
+ }
+ setState((prev) => ({...prev, error: "", isLoading: false, user: userMock}))
+ return;
const {data, errorData} = await userClient.getMe();
if (errorData) {
setState((prev) => ({...prev, error: errorData, isLoading: false, user: {}}));
diff --git a/front/src/data/constants.js b/front/src/data/constants.js
new file mode 100644
index 0000000..4607bb0
--- /dev/null
+++ b/front/src/data/constants.js
@@ -0,0 +1,126 @@
+// src/data/constants.js
+
+/**
+ * Константы для приложения «КартХолл»
+ */
+
+// Классы участников
+export const CLASSES = [
+ 'Юниоры',
+ 'Взрослые',
+ 'Pro',
+ 'Amateur',
+ 'Симулятор A',
+ 'Симулятор B'
+];
+
+// Статусы этапов
+export const STAGE_STATUSES = {
+ GOING: 'Идёт',
+ REGISTRATION_OPEN: 'Регистрация открыта',
+ PRE_REGISTRATION: 'Предрегистрация',
+ COMPLETED: 'Завершено'
+};
+
+// Моковые данные этапов соревнований
+export const MOCK_STAGES = [
+ {
+ id: 1,
+ title: 'SWC Зимний чемпионат',
+ stage: '2‑й этап',
+ date: '2026-02-08',
+ class: 'Юниоры',
+ status: STAGE_STATUSES.GOING,
+ description: 'Главный зимний турнир года. Призовой фонд — 500 000 ₽.',
+ location: 'Москва, стадион "Лужники"',
+ registrationLink: 'https://example.com/register/1'
+ },
+ {
+ id: 2,
+ title: 'Honda Winter Cup',
+ stage: '1‑й этап',
+ date: '2026-01-31',
+ class: 'Pro',
+ status: STAGE_STATUSES.REGISTRATION_OPEN,
+ description: 'Отборочный этап серии Honda. Участие — по заявке.',
+ location: 'Санкт-Петербург, трасса "Ижора"',
+ registrationLink: 'https://example.com/register/2'
+ },
+ {
+ id: 3,
+ title: 'Кубок Покровска (онлайн)',
+ stage: '1‑й этап',
+ date: '2026-02-01',
+ class: 'Симулятор A',
+ status: STAGE_STATUSES.PRE_REGISTRATION,
+ description: 'Онлайн‑соревнование для пилотов симулятора.',
+ location: 'Онлайн-платформа',
+ registrationLink: 'https://example.com/register/3'
+ },
+ {
+ id: 4,
+ title: 'Гран-при Урала',
+ stage: 'Финальный этап',
+ date: '2026-03-15',
+ class: 'Взрослые',
+ status: STAGE_STATUSES.PRE_REGISTRATION,
+ description: 'Заключительный этап сезона. Борьба за чемпионский титул.',
+ location: 'Екатеринбург, автодром "Урал"',
+ registrationLink: 'https://example.com/register/4'
+ },
+ {
+ id: 5,
+ title: 'Открытый кубок Москвы',
+ stage: 'Квалификационный раунд',
+ date: '2026-01-20',
+ class: 'Amateur',
+ status: STAGE_STATUSES.COMPLETED,
+ description: 'Первый этап для начинающих пилотов.',
+ location: 'Москва, картодром "Сокольники"',
+ registrationLink: null
+ },
+ {
+ id: 6,
+ title: 'Этап 6',
+ stage: 'Тест',
+ date: '2026-04-01',
+ class: 'Pro',
+ status: STAGE_STATUSES.REGISTRATION_OPEN,
+ description: 'Тестовый этап для проверки системы.',
+ location: 'Казань, трасса "Казань‑Ринг"',
+ registrationLink: 'https://example.com/register/6'
+ },
+ {
+ id: 7,
+ title: 'Этап 7',
+ stage: 'Тест',
+ date: '2026-05-01',
+ class: 'Юниоры',
+ status: STAGE_STATUSES.GOING,
+ description: 'Пробный заезд для юниоров.',
+ location: 'Нижний Новгород, картодром "Нижегородский"',
+ registrationLink: null
+ },
+ {
+ id: 8,
+ title: 'Этап 8',
+ stage: 'Тест',
+ date: '2026-06-01',
+ class: 'Взрослые',
+ status: STAGE_STATUSES.PRE_REGISTRATION,
+ description: 'Экспериментальный формат гонки.',
+ location: 'Сочи, автодром "Сочи Автоспорт"',
+ registrationLink: 'https://example.com/register/8'
+ }
+];
+
+// Дополнительные константы (если понадобятся позже)
+export const DEFAULT_PAGINATION = {
+ page: 1,
+ limit: 5
+};
+
+export const SORT_ORDERS = {
+ ASC: 'asc',
+ DESC: 'desc'
+};
diff --git a/front/src/lib/clients/TokenUtil.js b/front/src/lib/clients/TokenUtil.js
index 437efb7..b75774b 100644
--- a/front/src/lib/clients/TokenUtil.js
+++ b/front/src/lib/clients/TokenUtil.js
@@ -5,6 +5,7 @@ import axios from "axios";
class TokenUtil {
checkToken(token) {
+ return true;
if (token == null || isExpired(token)) {
return false;
}
diff --git a/front/src/navItems.js b/front/src/navItems.js
index 0e39376..0fce7b2 100644
--- a/front/src/navItems.js
+++ b/front/src/navItems.js
@@ -1,10 +1,8 @@
import {paths} from "./path";
export const navItems = [
- {key: 'menu', title: 'Меню', href: paths.dashboard.overview, icon: 'menu'},
- {key: 'barList', title: 'Список баров', href: paths.bar.list, icon: 'basket', forBarmen: true},
- {key: 'ingredients', title: 'Список ингредиентов', href: paths.bar.ingredients, icon: 'basket', forBarmen: true},
- {key: 'ingredientEdit', title: 'Ингредиенты', href: paths.bar.ingredientEdit, icon: 'ingredients', forAdmin: true},
- {key: 'cocktailEdit', title: 'Коктейли', href: paths.bar.cocktailEdit, icon: 'cocktail', forAdmin: true},
- {key: 'calc', title: 'Калькулятор', href: paths.bar.calc, icon: 'calc', forAdmin: true},
+ {key: 'home', title: 'Домашняя страница', href: paths.home, icon: 'menu'},
+ {key: 'championships', title: 'Чемпионаты', href: paths.chp.championships, icon: 'basket'},
+ {key: 'calendar', title: 'Календарь', href: paths.calendar, icon: 'basket'},
+ {key: 'stages', title: 'Этапы', href: paths.stg.stages, icon: 'ingredients'},
];
diff --git a/front/src/path.js b/front/src/path.js
index e6b91b6..b8a8440 100644
--- a/front/src/path.js
+++ b/front/src/path.js
@@ -1,25 +1,17 @@
export const paths = {
home: '/',
+ chp:
+ {
+ championships: '/championships',
+ championship: '/championships/:id',
+ },
+ stg:
+ {
+ stages: '/stages',
+ stage: '/stages/:id',
+ },
+ calendar: '/calendar',
auth: {signIn: '/auth/sign-in', bot: 'https://t.me/kayashovBarClientBot', tg: '/tg'},
- dashboard: {
- overview: '/menu'
- },
- visitor: {
- inBar: "/visitors"
- },
- orders: {
- my: '/orders'
- },
- bar: {
- list: "/barList",
- ordersQueue: '/queue',
- ingredients: '/ingredients',
- cocktails: "/cocktails",
- ingredientEdit: '/ingredients/edit',
- cocktailEdit: '/cocktail/edit',
- menu: '/menuList',
- calc: '/calc',
- },
errors: {notFound: '/errors/not-found'},
notFound: '*',
};
\ No newline at end of file
diff --git a/front/src/styles/theme/create-theme.js b/front/src/styles/theme/create-theme.js
index 535bbd9..7d21f33 100644
--- a/front/src/styles/theme/create-theme.js
+++ b/front/src/styles/theme/create-theme.js
@@ -6,7 +6,7 @@ import {colorSchemes} from "./color-schemes";
export function createTTheme() {
return extendTheme({
- breakpoints: {values: {xs: 0, sm: 450, md: 600, lg: 900, xl: 1440}},
+ breakpoints: {values: {xs: 0, sm: 550, md: 900, lg: 1200, xl: 1500}},
colorSchemes: colorSchemes,
components: components,
shadows: shadows,