diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 809e5ee..238304e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ stages: - deploy front - deploy back -stop-job: +deploy-back-job: stage: deploy back only: - back_release @@ -18,5 +18,17 @@ stop-job: - echo "Сборка образа докер" - docker build -t my-bar . - echo "Запуск докер контейнера" - - docker run --name my-bar --restart=always -p 8091:8080 -d my-bar - - echo "Деплой завершен" \ No newline at end of file + - docker run --name my-bar --restart=always -p 8091:8080 -d -e COCKTAIL_PHOTO_PATH=/front/assets/cocktails -v /mnt/sdb1/my-bar-front/build:/front my-bar + - echo "Деплой завершен" + +deploy-front-job: + stage: deploy front + only: + - release_front + image: node:22.12 + script: + - cd front + - npm install + - npm run build + - cp -r build /app + - echo "Деплой завершен" diff --git a/front/package.json b/front/package.json index 1034a42..27949b9 100644 --- a/front/package.json +++ b/front/package.json @@ -41,7 +41,7 @@ }, "scripts": { "start": "react-scripts start", - "build": "react-scripts build", + "build": "CI=false && react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, diff --git a/front/src/app/App.js b/front/src/app/App.js index 3f99800..d741347 100644 --- a/front/src/app/App.js +++ b/front/src/app/App.js @@ -7,6 +7,7 @@ import {BrowserRouter as Router} from "react-router-dom"; import {NavigationRoutes} from "./NavigationRoutes"; import {SnackbarProvider} from 'notistack'; import {UserProvider} from "../context/UserContext"; +import {SelectProvider} from "../context/SelectContext"; function App() { const theme = createTTheme(); @@ -36,10 +37,13 @@ function App() { }, }} /> - {/*Маршрутизация*/} - - - + {/*Провайдер выбора*/} + + {/*Маршрутизация*/} + + + + diff --git a/front/src/app/pages/cocktails/CocktailMenuBarPage.js b/front/src/app/pages/cocktails/CocktailMenuBarPage.js index bef556f..531bfe8 100644 --- a/front/src/app/pages/cocktails/CocktailMenuBarPage.js +++ b/front/src/app/pages/cocktails/CocktailMenuBarPage.js @@ -16,6 +16,7 @@ import {requests} from "../../../requests"; import {api} from "../../../lib/clients/api"; import {useAlert} from "../../../hooks/useAlert"; import {CocktailInfoModal} from "../../../components/cocktails/CocktailInfoModal"; +import {useSelect} from "../../../hooks/useSelect"; export function CocktailMenuBarPage() { const {createError} = useAlert(); @@ -23,8 +24,7 @@ export function CocktailMenuBarPage() { const [findString, setFindString] = useState(""); const [loading, setLoading] = useState(true); const [cocktails, setCocktails] = useState([]); - const [openModal, setOpenModal] = useState(false); - const [selected, setSelected] = useState(null); + const {setCocktail, state} = useSelect(); useEffect(() => { api().get(`${requests.cocktails.menu}?all=true`) @@ -38,12 +38,11 @@ export function CocktailMenuBarPage() { const handleOpenModal = (row) => { - setSelected(row) - setOpenModal(true); + setCocktail(row); } const changeHandler = (row, value) => { const newState = cocktails.map((r) => { - if(r.id !== row.id) { + if (r.id !== row.id) { return r; } return { @@ -117,11 +116,7 @@ export function CocktailMenuBarPage() { {/*Загрузчик*/} {/*Модальное окно информации об ингредиенте*/} - { - setSelected(null); - setOpenModal(false); - }}/> + ) } \ No newline at end of file diff --git a/front/src/app/pages/cocktails/CocktailsPageContent.js b/front/src/app/pages/cocktails/CocktailsPageContent.js index 428aa5e..176c480 100644 --- a/front/src/app/pages/cocktails/CocktailsPageContent.js +++ b/front/src/app/pages/cocktails/CocktailsPageContent.js @@ -14,57 +14,8 @@ import {useUser} from "../../../hooks/useUser"; import {blue} from "@mui/material/colors"; import UpIcon from "@mui/icons-material/KeyboardArrowUp"; import {sortList} from "../../../components/cocktails/sortingList"; -import {getComparator} from "../../../components/core/getComparator"; import Button from "@mui/material/Button"; -import Paper from "@mui/material/Paper"; -import CheckMarks from "../../../components/cocktails/CheckMarks"; - -const filterList = (rows, filter, allowIngredients) => { - let regExp = new RegExp("(.*?)" + filter.search + "(.*?)", "i"); - const sortingObj = sortList.find((s) => s.name === filter.sorting); - const sortingValues = sortingObj.id.split("|"); - return rows - .filter((row) => { - const nameReg = row.name.split(" ").map((n) => n.match(regExp) !== null).includes(true); - const ingredientReg = row.components - .split(", ") - .map((r) => r.match(regExp) !== null) - .includes(true); - return nameReg || ingredientReg; - }) - .filter((row) => filter.onlyFavourite ? row.rating.favourite : true) - .filter((row) => filter.glass.length === 0 || filter.glass.includes(row.glass)) - .filter((row) => filter.category.length === 0 || filter.category.includes(row.category)) - .filter((row) => filter.alcohol.length === 0 || filter.alcohol.includes(row.alcoholic)) - .filter((row) => { - if (filter.tags.length === 0) { - return true; - } - - if (row.tags.length === 0) { - return false; - } - return row.tags.split(",").find((tag) => filter.tags.includes(tag)) - }) - .filter((row) => { - if (filter.iCount.length === 0) { - return true; - } - const arr = row.components.split(", "); - const count = arr.filter((n) => !allowIngredients.includes(n)).length; - const filt = filter.ingredient.length === 0 || arr.filter((n) => filter.ingredient.includes(n)).length > 0; - - return filter.iCount === count && filt; - }) - .filter((row) => { - if (filter.inMenu === "") { - return row; - } - const filterValue = filter.inMenu === "Есть в меню"; - return filterValue === row.inMenu; - }) - .sort(getComparator(sortingValues[1], sortingValues[0], "name")) -} +import {useSelect} from "../../../hooks/useSelect"; const emptyFilter = { search: "", @@ -86,14 +37,14 @@ const CocktailsPageContent = ({all}) => { const [allowIngredients, setAllowIngredients] = useState([]) const [rows, setRows] = useState([]); const [filter, setFilter] = useState(emptyFilter) - const [open, setOpen] = useState(false); - const [selectedCocktail, setSelectedCocktail] = useState(null) - const [chips, setChips] = useState([]) + // const [chips, setChips] = useState([]) 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)) { @@ -111,7 +62,7 @@ const CocktailsPageContent = ({all}) => { api().post(requests.cocktails.menu, request) .then((r) => { if (r.data.length === 0) { - if(isNew) { + if (isNew) { setRows([]); } setIsEnd(true); @@ -139,6 +90,7 @@ const CocktailsPageContent = ({all}) => { } window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); + // eslint-disable-next-line }, [loading]); useEffect(() => { api().get(requests.bar.ingredientSimple) @@ -152,6 +104,7 @@ const CocktailsPageContent = ({all}) => { }, []) useEffect(() => { loading(); + // eslint-disable-next-line }, [filter]) useEffect(() => { if (!all) { @@ -164,7 +117,8 @@ const CocktailsPageContent = ({all}) => { .filter((nhc) => nhc.length === 1) .map((fc) => fc[0]) .forEach((i) => ingredients.add(i)) - setChips(Array.from(ingredients).sort(getComparator())); + // setChips(Array.from(ingredients).sort(getComparator())); + // eslint-disable-next-line }, [rows, allowIngredients]) const renderSkeleton = () => { @@ -230,12 +184,9 @@ const CocktailsPageContent = ({all}) => { setFilter(emptyFilter); } const handleSelectCocktail = (row) => { - setSelectedCocktail(row.id) - setOpen(true) - } - const handleCloseCocktailModal = () => { - setOpen(false); - setSelectedCocktail(null); + selectCocktail(row.id) + // setSelectedCocktail(row.id) + // setOpen(true) } const handleEditMenu = (row, value) => { const newState = rows.map((r) => { @@ -271,8 +222,7 @@ const CocktailsPageContent = ({all}) => { {/**/} {/*Модальное окно информации о коктейле*/} - + {/*Блок фильтров*/} { @@ -76,12 +76,7 @@ export function IngredientsPage() { }); } const handleOpenModal = (i) => { - setOpenModal(true); - setSelectedInfo(i); - } - const handleCloseModal = () => { - setSelectedInfo(null); - setOpenModal(false); + selectIngredient(i) } return ( @@ -147,7 +142,7 @@ export function IngredientsPage() { {/*Загрузчик*/} {/*Модальное окно информации об ингредиенте*/} - + ) } \ No newline at end of file diff --git a/front/src/components/Ingredients/IngredientInfoModal.js b/front/src/components/Ingredients/IngredientInfoModal.js index 75ce54f..103ab14 100644 --- a/front/src/components/Ingredients/IngredientInfoModal.js +++ b/front/src/components/Ingredients/IngredientInfoModal.js @@ -6,13 +6,34 @@ import Button from "@mui/material/Button"; import * as React from "react"; import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; +import List from "@mui/material/List"; +import {useEffect, useState} from "react"; +import {api} from "../../lib/clients/api"; +import {requests} from "../../requests"; +import {useAlert} from "../../hooks/useAlert"; +import ListItem from "@mui/material/ListItem"; +import {useSelect} from "../../hooks/useSelect"; + +export function IngredientInfoModal({ingredient}) { + const [cocktails, setCocktails] = useState([]); + const {closeIngredient, getOpenIngredient, selectCocktail} = useSelect(); + const {createError} = useAlert(); + + useEffect(() => { + if(!ingredient) { + return + } + api().get(requests.cocktails.byIngredient + ingredient.id) + .then((r) => setCocktails(r.data)) + .catch(() => createError()) + // eslint-disable-next-line + }, [ingredient]); -export function IngredientInfoModal({ingredient, open, closeHandler}) { if (!ingredient) { return null; } return ( - {`Крепость ${ingredient.abv}`})} {ingredient.description} + {cocktails.length > 0 && ( + <> + Коктейли: + + {cocktails.map((c) => { + return ( + { + selectCocktail(c.id) + closeIngredient(); + }}> + + {c.name} + {c.name} + {c.rating.rating > 0 && {`${c.rating.rating}/5`}} + + + ) + })} + + + )} - + ); diff --git a/front/src/components/cocktails/Cocktail.js b/front/src/components/cocktails/Cocktail.js index 272da22..ddfb922 100644 --- a/front/src/components/cocktails/Cocktail.js +++ b/front/src/components/cocktails/Cocktail.js @@ -1,9 +1,6 @@ import {CardActions, CardContent, CardMedia, Rating} from "@mui/material"; import {useAlert} from "../../hooks/useAlert"; import Typography from "@mui/material/Typography"; -import List from "@mui/material/List"; -import ListItem from "@mui/material/ListItem"; -import ListItemText from "@mui/material/ListItemText"; import Button from "@mui/material/Button"; import Grid from "@mui/material/Grid"; import {requests} from "../../requests"; @@ -14,6 +11,7 @@ import FavoriteIcon from '@mui/icons-material/Favorite'; import {api} from "../../lib/clients/api"; import Box from "@mui/material/Box"; import {useUser} from "../../hooks/useUser"; +import {CocktailDescription} from "./CocktailDescription"; function renderFavouriteBadge(handleFavourite, row) { const childIcon = row.rating.favourite ? : ; @@ -65,40 +63,13 @@ export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect alt={row.name} height="300" - image={`${row.image}/preview`} + image={row.image.includes("thecocktaildb") ? (row.image + "/preview") : row.image} /> {renderFavouriteBadge(handleFavourite, row)} {renderRating(handleChangeRating, row)} {row.name} - - {row.hasError && ( - - Имеет ошибку в рецепте или ингредиентах - - )} - - {"Категория: " + row.category} - - - {"Алкоголь: " + row.alcoholic} - - {row.volume !== null && ( - - {"Крепость: ≈" + row.volume} - - )} - - {"Подача: " + row.glass} - - - {"Состав: " + row.components} - - {(row.tags && row.tags.length > 0) && ( - - {"Теги: " + row.tags.replaceAll(',', ', ')} - )} - + {(row.isAllowed && session.isActive && user.invited) && diff --git a/front/src/components/cocktails/CocktailDescription.js b/front/src/components/cocktails/CocktailDescription.js new file mode 100644 index 0000000..db6b9e2 --- /dev/null +++ b/front/src/components/cocktails/CocktailDescription.js @@ -0,0 +1,36 @@ +import ListItem from "@mui/material/ListItem"; +import ListItemText from "@mui/material/ListItemText"; +import List from "@mui/material/List"; + +export function CocktailDescription({row}) { + return ( + + {row.hasError && ( + + Имеет ошибку в рецепте или ингредиентах + + )} + + {"Категория: " + row.category} + + + {"Алкоголь: " + row.alcoholic} + + {row.volume !== null && ( + + {"Крепость: ≈" + row.volume} + + )} + + {"Подача: " + row.glass} + + + {"Состав: " + row.components} + + {(row.tags && row.tags.length > 0) && ( + + {"Теги: " + row.tags.replaceAll(',', ', ')} + )} + + ) +} \ No newline at end of file diff --git a/front/src/components/cocktails/CocktailInfoModal.js b/front/src/components/cocktails/CocktailInfoModal.js index 98a018c..afb6053 100644 --- a/front/src/components/cocktails/CocktailInfoModal.js +++ b/front/src/components/cocktails/CocktailInfoModal.js @@ -21,24 +21,20 @@ import {useAlert} from "../../hooks/useAlert"; import {paths} from "../../path"; import {Loading} from "../core/Loading"; import {useUser} from "../../hooks/useUser"; +import {useSelect} from "../../hooks/useSelect"; -export function CocktailInfoModal({open, row, closeHandler}) { +export function CocktailInfoModal({row}) { const {user} = useUser(); const {getError, createError, createSuccess} = useAlert(); const [cocktail, setCocktail] = useState(null) const [loading, setLoading] = useState(false); - const [selectedIngredient, setSelectedIngredient] = useState(null); - const [openIngredientModal, setOpenIngredientModal] = useState(false) - const closeIngredientHandler = () => { - setOpenIngredientModal(false); - setSelectedIngredient(null); - } + const {closeCocktail, selectIngredient, getIngredient, getOpenCocktail} = useSelect(); const openIngredientModalHandler = (id) => { api().get(`${requests.bar.ingredient}?id=${id}`) .then((r) => { - setSelectedIngredient(r.data) - setOpenIngredientModal(true); - }).catch(() => createError("Ошибка получения информации об ингредиенте")) + selectIngredient(r.data) + }) + .catch(() => createError("Ошибка получения информации об ингредиенте")) } const selectIngredientHandler = (ingredient) => { const url = `${requests.bar.ingredient}?id=${ingredient.id}`; @@ -79,18 +75,17 @@ export function CocktailInfoModal({open, row, closeHandler}) { .catch(() => { getError(); setLoading(false) - closeHandler(); + closeCocktail(); }) + // eslint-disable-next-line }, [row]); if (!row || !cocktail) { return null; } - let alko = 0; - let volume = 0; return ( - + @@ -118,7 +112,7 @@ export function CocktailInfoModal({open, row, closeHandler}) { { const hasError = r.count === null || r.unit === null; const measure = hasError ? r.measure : (r.count + " " + r.unit.name) - if(alko !== null && volume !== null) { - console.log(r) - } return ( @@ -173,7 +164,7 @@ export function CocktailInfoModal({open, row, closeHandler}) { {user.role.includes("ADMIN") && ( )} - + ) diff --git a/front/src/components/orders/OrderModal.js b/front/src/components/orders/OrderModal.js index 53d4928..907842d 100644 --- a/front/src/components/orders/OrderModal.js +++ b/front/src/components/orders/OrderModal.js @@ -37,6 +37,7 @@ function renderButtons(row, my, handleChange) { export default function OrderModal({row, handleClose, open, handleChange, my}) { const [receipt, setReceipt] = useState([]); + const [instructions, setInstructions] = useState(); const {createError} = useAlert(); useEffect(() => { @@ -46,6 +47,10 @@ export default function OrderModal({row, handleClose, open, handleChange, my}) { api().get(requests.bar.receipts + row.cocktail.id) .then((r) => setReceipt(r.data)) .catch(() => createError("Ошибка получения рецепта")) + + api().get(requests.cocktails.instructions + row.cocktail.id) + .then((r) => setInstructions(r.data)) + .catch(() => createError("Ошибка получения инструкции")) // eslint-disable-next-line }, [row]); @@ -62,7 +67,6 @@ export default function OrderModal({row, handleClose, open, handleChange, my}) { {"Заказ №" + row.id} {row.cocktail.name} - {row.cocktail.alcoholic + " " + row.cocktail.category} {"для: " + row.visitor.name + " " + row.visitor.lastName} @@ -74,8 +78,14 @@ export default function OrderModal({row, handleClose, open, handleChange, my}) { return ({`${r.ingredient.name} - ${r.measure}`}) })} - Инструкция: - {row.cocktail.instructions} + {instructions && + ( + <> + Инструкция: + {instructions} + + ) + } {row.cocktail.video && (