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.id}/ - - - - {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.id}/ - - {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,