Compare commits
32 Commits
34295bc045
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
060188e9e0 | ||
|
|
1fa351357b | ||
|
|
a84a37c1aa | ||
|
|
74f8a0b864 | ||
|
|
b585214f58 | ||
|
|
e282681679 | ||
|
|
de96c83ddf | ||
|
|
21e44246b9 | ||
|
|
ed72511ed4 | ||
|
|
1f26015bad | ||
|
|
f573660325 | ||
|
|
9fb5cdf87c | ||
|
|
0cb15aae70 | ||
|
|
da188a65a4 | ||
|
|
1fdf084a25 | ||
|
|
d9f5a32486 | ||
|
|
8bc3501998 | ||
|
|
5abfc4d6c3 | ||
|
|
ba1c0e747c | ||
|
|
60b792ebc3 | ||
|
|
13fd6b176a | ||
|
|
fc6c60ad0c | ||
|
|
015416c43b | ||
|
|
6fe2ca6c57 | ||
|
|
56f81ea54b | ||
|
|
92f2523396 | ||
|
|
91770b99b7 | ||
|
|
10634242e4 | ||
|
|
198be069b4 | ||
|
|
488638885c | ||
|
|
d98686de12 | ||
|
|
9da769beb5 |
@@ -5,7 +5,7 @@ COPY . /build/source
|
|||||||
WORKDIR /build/source
|
WORKDIR /build/source
|
||||||
RUN mvn -am clean package
|
RUN mvn -am clean package
|
||||||
# Создание образа my-bar
|
# Создание образа my-bar
|
||||||
FROM openjdk:17-jdk-slim as my-bar
|
FROM openjdk:17-ea-jdk-slim as my-bar
|
||||||
COPY --from=build /build/source/target/*.jar /data/app/my-bar.jar
|
COPY --from=build /build/source/target/*.jar /data/app/my-bar.jar
|
||||||
WORKDIR /data/app
|
WORKDIR /data/app
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {EditIngredientPage} from "./pages/ingredients/EditIngredientPage";
|
|||||||
import {EditCocktailPage} from "./pages/cocktails/EditCocktailPage";
|
import {EditCocktailPage} from "./pages/cocktails/EditCocktailPage";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {BarChangePage} from "./pages/BarChangePage";
|
import {BarChangePage} from "./pages/BarChangePage";
|
||||||
|
import {CalcPage} from "./pages/calc/CalcPage";
|
||||||
|
|
||||||
export function NavigationRoutes() {
|
export function NavigationRoutes() {
|
||||||
const {auth} = useAuth();
|
const {auth} = useAuth();
|
||||||
@@ -59,6 +60,11 @@ const authPages = [
|
|||||||
children: (<LoginPage/>),
|
children: (<LoginPage/>),
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: paths.bar.calc,
|
||||||
|
children: (<CalcPage/>),
|
||||||
|
isPrivate: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: paths.dashboard.overview,
|
path: paths.dashboard.overview,
|
||||||
isPrivate: true,
|
isPrivate: true,
|
||||||
@@ -96,11 +102,16 @@ const authPages = [
|
|||||||
|
|
||||||
const guestPages = [
|
const guestPages = [
|
||||||
{
|
{
|
||||||
path: paths.home,
|
path: paths.dashboard.overview,
|
||||||
isPrivate: false,
|
isPrivate: true,
|
||||||
children: (<HomeRedirect auth={false}/>),
|
children: (<MenuPage/>),
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
children: (<HomeRedirect auth={true}/>),
|
||||||
|
isPrivate: false,
|
||||||
|
path: paths.home,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: paths.auth.tg,
|
path: paths.auth.tg,
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import Paper from "@mui/material/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {api} from "../../lib/clients/api";
|
|
||||||
import {requests} from "../../requests";
|
|
||||||
import {useAlert} from "../../hooks/useAlert";
|
import {useAlert} from "../../hooks/useAlert";
|
||||||
import {Card} from "@mui/material";
|
import {Card} from "@mui/material";
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
@@ -10,79 +8,39 @@ import IconButton from "@mui/material/IconButton";
|
|||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
import ElectricalServicesIcon from '@mui/icons-material/ElectricalServices';
|
import ElectricalServicesIcon from '@mui/icons-material/ElectricalServices';
|
||||||
import {getComparator} from "../../components/core/getComparator";
|
|
||||||
import Toolbar from "@mui/material/Toolbar";
|
import Toolbar from "@mui/material/Toolbar";
|
||||||
import AddCircleIcon from '@mui/icons-material/AddCircle';
|
import AddCircleIcon from '@mui/icons-material/AddCircle';
|
||||||
import {BarCreateModal} from "../../components/BarCreateModal";
|
import {BarCreateModal} from "../../components/BarCreateModal";
|
||||||
import PowerIcon from '@mui/icons-material/Power';
|
import PowerIcon from '@mui/icons-material/Power';
|
||||||
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||||
|
import {barClient} from "../../lib/clients/BarClient";
|
||||||
|
|
||||||
export function BarChangePage() {
|
export function BarChangePage() {
|
||||||
const [bars, setBars] = useState([])
|
const [bars, setBars] = useState([])
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
const [oldId, setOldId] = useState(null);
|
||||||
const {createError, createSuccess, createWarning} = useAlert();
|
const {createError, createSuccess, createWarning} = useAlert();
|
||||||
|
|
||||||
useEffect(() => {
|
const createHandler = (id, name) => {
|
||||||
api().get(requests.bar.list)
|
if (id) {
|
||||||
.then((r) => {
|
barClient.copyBar(id, name, setBars, bars, createError, createSuccess, setOpen)
|
||||||
setBars(r.data.sort(getComparator("name")))
|
} else {
|
||||||
})
|
barClient.createBar(name, bars, createSuccess, createError, setBars, setOpen)
|
||||||
.catch(() => {
|
|
||||||
createError("Ошибка получения списков")
|
|
||||||
})
|
|
||||||
}, []);
|
|
||||||
const changeHandler = (bar) => {
|
|
||||||
createWarning("Дождитесь окончания операции")
|
|
||||||
api().post(`${requests.bar.change}/${bar.id}`)
|
|
||||||
.then(() => createSuccess("Список изменен"))
|
|
||||||
.catch(() => createError("Ошибка изменения активного списка"))
|
|
||||||
|
|
||||||
const newState = bars.map((b) => {
|
|
||||||
if (b.active) {
|
|
||||||
return {
|
|
||||||
...b, active: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (b.id === bar.id) {
|
|
||||||
return {
|
|
||||||
...b, active: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b;
|
|
||||||
})
|
|
||||||
setBars(newState);
|
|
||||||
}
|
|
||||||
const deleteHandler = (bar) => {
|
|
||||||
if (bar.active) {
|
|
||||||
createError("Нельзя удалить активный бар!")
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
api().delete(requests.bar.crud + bar.id)
|
|
||||||
.then(() => createSuccess("Список удален"))
|
|
||||||
.catch(() => createError("Ошибка удаления. Обновите страницу"))
|
|
||||||
|
|
||||||
setBars(bars.filter((b) => b.id !== bar.id));
|
|
||||||
}
|
|
||||||
const createHandler = (name) => {
|
|
||||||
api().post(requests.bar.crud + name)
|
|
||||||
.then((r) => {
|
|
||||||
createSuccess("Cписок создан");
|
|
||||||
let state = bars;
|
|
||||||
state.push(r.data);
|
|
||||||
setBars(state)
|
|
||||||
setOpen(false)
|
|
||||||
}).catch(() => createError("Ошибка создания списка"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeHandler() {
|
// eslint-disable-next-line
|
||||||
setOpen(false)
|
useEffect(() => barClient.getBarList(setBars, createError), []);
|
||||||
}
|
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<BarCreateModal open={open} close={closeHandler} create={createHandler}/>
|
<BarCreateModal open={open} setOpen={setOpen} create={createHandler} id={oldId}/>
|
||||||
<Paper sx={{p: 1}}>
|
<Paper sx={{p: 1}}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Typography variant='h6'>Списки ингредиентов (бары)</Typography>
|
<Typography variant='h6'>Списки ингредиентов (бары)</Typography>
|
||||||
<IconButton edge="end" onClick={() => setOpen(true)}>
|
<IconButton edge="end" onClick={() => {
|
||||||
|
setOldId(null);
|
||||||
|
setOpen(true);
|
||||||
|
}}>
|
||||||
<AddCircleIcon/>
|
<AddCircleIcon/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
@@ -90,17 +48,27 @@ export function BarChangePage() {
|
|||||||
return <Card key={b.id} sx={{m: 2, p: 2}}>
|
return <Card key={b.id} sx={{m: 2, p: 2}}>
|
||||||
<Stack direction='row' justifyContent={'space-between'}>
|
<Stack direction='row' justifyContent={'space-between'}>
|
||||||
<Typography>{b.name}</Typography>
|
<Typography>{b.name}</Typography>
|
||||||
{b.active && <IconButton disabled>
|
<Box>
|
||||||
<PowerIcon/>
|
<IconButton onClick={() => {
|
||||||
</IconButton>}
|
setOldId(b.id)
|
||||||
{!b.active && <Box>
|
setOpen(true);
|
||||||
<IconButton onClick={() => deleteHandler(b)}>
|
}}>
|
||||||
<DeleteIcon/>
|
<ContentCopyIcon/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton onClick={() => changeHandler(b)}>
|
{b.active && <IconButton disabled>
|
||||||
<ElectricalServicesIcon/>
|
<PowerIcon/>
|
||||||
</IconButton>
|
</IconButton>}
|
||||||
</Box>}
|
{!b.active && <>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => barClient.deleteBar(b, bars, createError, createSuccess, setBars)}>
|
||||||
|
<DeleteIcon/>
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => barClient.changeBar(b.id, bars, createWarning, createSuccess, createError, setBars)}>
|
||||||
|
<ElectricalServicesIcon/>
|
||||||
|
</IconButton>
|
||||||
|
</>}
|
||||||
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,28 +1,14 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {useSearchParams} from "react-router-dom";
|
import {useSearchParams} from "react-router-dom";
|
||||||
import {Loading} from "../../../../components/core/Loading";
|
import {Loading} from "../../../../components/core/Loading";
|
||||||
import {api} from "../../../../lib/clients/api";
|
|
||||||
import {requests} from "../../../../requests";
|
|
||||||
import {useAuth} from "../../../../hooks/useAuth";
|
import {useAuth} from "../../../../hooks/useAuth";
|
||||||
|
import {authClient} from "../../../../lib/clients/AuthClient";
|
||||||
|
|
||||||
export function TelegramCode() {
|
export function TelegramCode() {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const {checkSession} = useAuth();
|
const {checkSession} = useAuth();
|
||||||
|
|
||||||
let code = searchParams.get("code");
|
authClient.loginByCode(searchParams.get("code"), checkSession)
|
||||||
const request = {
|
|
||||||
byLogin: false,
|
|
||||||
code: code
|
|
||||||
}
|
|
||||||
api().post(requests.auth.login, request)
|
|
||||||
.then(async (response) => {
|
|
||||||
if (response.data.error) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
localStorage.setItem("token", response.data.token);
|
|
||||||
await checkSession?.();
|
|
||||||
window.location.reload();
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Loading loading={true}/>
|
<Loading loading={true}/>
|
||||||
|
|||||||
90
front/src/app/pages/calc/CalcPage.js
Normal file
90
front/src/app/pages/calc/CalcPage.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
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 (
|
||||||
|
<Box padding={2}>
|
||||||
|
<Typography variant="h4" align="center">Коктейли</Typography>
|
||||||
|
<Stack mt={2}>
|
||||||
|
{cocktails.map((item, i) => (
|
||||||
|
<CocktailItemCalc key={i} cocktail={item} deleteHandler={deleteHandler}
|
||||||
|
changeHandler={changeHandler}/>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Typography variant="h4" mt={2} align="center">Ингредиенты</Typography>
|
||||||
|
<Stack mt={2}>
|
||||||
|
{ingredients.map((item, i) => (
|
||||||
|
<IngredientCalcCard key={i} count={item.count} ingredient={item.ingredient}/>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
40
front/src/app/pages/calc/CocktailItemCalc.js
Normal file
40
front/src/app/pages/calc/CocktailItemCalc.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
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 (
|
||||||
|
<Card sx={{mb: 1, display: 'relative', p: 2}}>
|
||||||
|
<Stack justifyContent={'start'} spacing={2}>
|
||||||
|
<Stack direction='row' justifyContent='start' alignItems='center'>
|
||||||
|
<Box sx={{width: '100px', height: '100px'}}>
|
||||||
|
<img src={cocktail.image} loading='lazy' height={'100px'} width={'100px'} alt={cocktail.id}/>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{width: 'calc(90% - 100px)', pr: 2, ml: 2}}>
|
||||||
|
<Stack>
|
||||||
|
<Typography>{cocktail.name}</Typography>
|
||||||
|
<Typography>{cocktail.volume}</Typography>
|
||||||
|
<Typography>{cocktail.category}</Typography>
|
||||||
|
<Typography>{cocktail.alcoholic}</Typography>
|
||||||
|
<Typography color={'textSecondary'}>{cocktail.components}</Typography>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Stack direction='row'>
|
||||||
|
<Stack sx={{width: '5%'}} spacing={1} justifyContent='flex-start'>
|
||||||
|
<IconButton size='small' onClick={() => deleteHandler(cocktail.id)}>
|
||||||
|
<DeleteIcon/>
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
<Counter id={cocktail.id} changeHandler={changeHandler}/>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
65
front/src/app/pages/calc/Counter.js
Normal file
65
front/src/app/pages/calc/Counter.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
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 (
|
||||||
|
<Box>
|
||||||
|
<Button onClick={() => {
|
||||||
|
if (value > 0) {
|
||||||
|
setValue(value - 1);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
width: '20px',
|
||||||
|
height: '55px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
margin: '0 8px',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
}}>−</Button>
|
||||||
|
<TextField
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newValue = parseInt(e.target.value, 10);
|
||||||
|
if (!isNaN(newValue)) {
|
||||||
|
handleChange(newValue);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
inputProps={{inputMode: 'numeric'}}
|
||||||
|
sx={{
|
||||||
|
width: '40px',
|
||||||
|
height: '15px',
|
||||||
|
fontSize: '10px',
|
||||||
|
textAlign: 'center'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button onClick={() => handleChange(value + 1)}
|
||||||
|
sx={{
|
||||||
|
width: '20px',
|
||||||
|
height: '55px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
margin: '0 8px',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
}}>+</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
21
front/src/app/pages/calc/IngredientCalcCard.js
Normal file
21
front/src/app/pages/calc/IngredientCalcCard.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
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 (
|
||||||
|
<Card sx={{mb: 1, height: '130px', display: 'relative', pt: 1}}>
|
||||||
|
<Stack direction='row' justifyContent='start' alignItems='center'>
|
||||||
|
<Box sx={{width: '100px', height: '100px'}}>
|
||||||
|
<img src={ingredient.image} loading='lazy' height={'100px'} width={'100px'} alt={ingredient.id}/>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{width: 'calc(90% - 100px)', pr: 2}}>{ingredient.name}</Box>
|
||||||
|
<Stack direction='row'>
|
||||||
|
<Box mr={1} pt={'3px'}>{count}</Box>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,20 +5,16 @@ import {useCallback, useEffect, useState} from "react";
|
|||||||
import {Cocktail} from "../../../components/cocktails/Cocktail";
|
import {Cocktail} from "../../../components/cocktails/Cocktail";
|
||||||
import {Fab, Skeleton} from "@mui/material";
|
import {Fab, Skeleton} from "@mui/material";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import {requests} from "../../../requests";
|
|
||||||
import {NoResult} from "../../../components/cocktails/NoResult";
|
import {NoResult} from "../../../components/cocktails/NoResult";
|
||||||
import {FilterBlock} from "../../../components/cocktails/FilterBlock";
|
import {FilterBlock} from "../../../components/cocktails/FilterBlock";
|
||||||
import {api} from "../../../lib/clients/api";
|
|
||||||
import {CocktailInfoModal} from "../../../components/cocktails/CocktailInfoModal";
|
import {CocktailInfoModal} from "../../../components/cocktails/CocktailInfoModal";
|
||||||
import {useUser} from "../../../hooks/useUser";
|
import {useUser} from "../../../hooks/useUser";
|
||||||
import {blue} from "@mui/material/colors";
|
import {blue} from "@mui/material/colors";
|
||||||
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
|
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
|
||||||
import {sortList} from "../../../components/cocktails/sortingList";
|
|
||||||
import Button from "@mui/material/Button";
|
|
||||||
import {useSelect} from "../../../hooks/useSelect";
|
import {useSelect} from "../../../hooks/useSelect";
|
||||||
import Paper from "@mui/material/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
import CheckMarks from "../../../components/cocktails/CheckMarks";
|
import CheckMarks from "../../../components/cocktails/CheckMarks";
|
||||||
import {getComparator} from "../../../components/core/getComparator";
|
import {cocktailClient} from "../../../lib/clients/CocktailClient";
|
||||||
|
|
||||||
const emptyFilter = {
|
const emptyFilter = {
|
||||||
search: "",
|
search: "",
|
||||||
@@ -37,10 +33,10 @@ const emptyFilter = {
|
|||||||
const CocktailsPageContent = () => {
|
const CocktailsPageContent = () => {
|
||||||
const {user} = useUser();
|
const {user} = useUser();
|
||||||
const {createError, createSuccess} = useAlert();
|
const {createError, createSuccess} = useAlert();
|
||||||
const [allowIngredients, setAllowIngredients] = useState([])
|
|
||||||
const [rows, setRows] = useState([]);
|
const [rows, setRows] = useState([]);
|
||||||
const [filter, setFilter] = useState(emptyFilter)
|
const [filter, setFilter] = useState(emptyFilter)
|
||||||
const [chips, setChips] = useState([])
|
// const [chips, setChips] = useState([])
|
||||||
|
const chips = [];
|
||||||
const [page, setPage] = useState(-1);
|
const [page, setPage] = useState(-1);
|
||||||
const [load, setLoad] = useState(false);
|
const [load, setLoad] = useState(false);
|
||||||
const [isEnd, setIsEnd] = useState(false);
|
const [isEnd, setIsEnd] = useState(false);
|
||||||
@@ -53,36 +49,10 @@ const CocktailsPageContent = () => {
|
|||||||
if (load || (!isNew && isEnd)) {
|
if (load || (!isNew && isEnd)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
setLoad(true);
|
cocktailClient.getMenu(setRows, setIsNew, setPage, setLoad, setIsEnd, isNew, rows, page, size, filter, createError);
|
||||||
const request = {
|
|
||||||
...filter,
|
|
||||||
sort: sortList.find((s) => s.name === filter.sorting).id,
|
|
||||||
page: page + 1,
|
|
||||||
size: size,
|
|
||||||
notHaveCount: Array.isArray(filter.iCount) ? null : filter.iCount
|
|
||||||
}
|
|
||||||
api().post(requests.cocktails.menu, request)
|
|
||||||
.then((r) => {
|
|
||||||
if (r.data.length === 0) {
|
|
||||||
if (isNew) {
|
|
||||||
setRows([]);
|
|
||||||
}
|
|
||||||
setIsEnd(true);
|
|
||||||
setLoad(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const cocktails = isNew ? r.data : rows.concat(r.data);
|
|
||||||
setRows(cocktails);
|
|
||||||
setIsNew(false);
|
|
||||||
setPage(page + 1);
|
|
||||||
setLoad(false);
|
|
||||||
})
|
|
||||||
.catch((r) => {
|
|
||||||
setLoad(false);
|
|
||||||
createError("Ошибка загрузки данных от сервера Status:" + r.code)
|
|
||||||
})
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [load, isEnd, page]);
|
}, [load, isEnd, page]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
const {scrollTop, scrollHeight, clientHeight} = document.documentElement;
|
const {scrollTop, scrollHeight, clientHeight} = document.documentElement;
|
||||||
@@ -94,34 +64,8 @@ const CocktailsPageContent = () => {
|
|||||||
return () => window.removeEventListener('scroll', handleScroll);
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [loading]);
|
}, [loading]);
|
||||||
useEffect(() => {
|
// eslint-disable-next-line
|
||||||
api().get(requests.bar.ingredientSimple)
|
useEffect(() => loading(), [filter])
|
||||||
.then((r) => {
|
|
||||||
const arr = r.data.filter((i) => i.isHave)
|
|
||||||
.map((i) => i.name)
|
|
||||||
setAllowIngredients(arr)
|
|
||||||
})
|
|
||||||
.catch(() => createError("Ошибка получения ингредиентов"))
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [])
|
|
||||||
useEffect(() => {
|
|
||||||
loading();
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [filter])
|
|
||||||
useEffect(() => {
|
|
||||||
if (!filter.all) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const ingredients = new Set();
|
|
||||||
rows.map((c) => c.components)
|
|
||||||
.map((c) => c.split(", "))
|
|
||||||
.map((c) => c.filter((i) => !allowIngredients.includes(i)))
|
|
||||||
.filter((nhc) => nhc.length === 1)
|
|
||||||
.map((fc) => fc[0])
|
|
||||||
.forEach((i) => ingredients.add(i))
|
|
||||||
setChips(Array.from(ingredients).sort(getComparator()));
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [rows, allowIngredients])
|
|
||||||
|
|
||||||
const renderSkeleton = () => {
|
const renderSkeleton = () => {
|
||||||
return Array.from({length: 3}, () => null)
|
return Array.from({length: 3}, () => null)
|
||||||
@@ -143,11 +87,7 @@ const CocktailsPageContent = () => {
|
|||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
})
|
})
|
||||||
api().post(`${requests.cocktails.rating}${row.id}&rating=${value}`)
|
cocktailClient.changeRating(row.id, newState, value, setRows, createSuccess, createError)
|
||||||
.then(() => {
|
|
||||||
setRows(newState);
|
|
||||||
createSuccess("Спасибо за оценку!")
|
|
||||||
}).catch(() => createError("Ошибка сохранения"))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
const handleFilterChange = (filterName, value) => {
|
const handleFilterChange = (filterName, value) => {
|
||||||
@@ -173,14 +113,7 @@ const CocktailsPageContent = () => {
|
|||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
let url = `${requests.cocktails.favourite}${row.id}`;
|
cocktailClient.changeFavourite(value, row.id, newState, setRows, createSuccess, createError)
|
||||||
let request = value ? api().put(url) : api().delete(url);
|
|
||||||
|
|
||||||
request
|
|
||||||
.then(() => {
|
|
||||||
setRows(newState);
|
|
||||||
createSuccess("Спасибо за оценку!")
|
|
||||||
}).catch(() => createError("Ошибка сохранения"))
|
|
||||||
}
|
}
|
||||||
const handleFilterClear = () => {
|
const handleFilterClear = () => {
|
||||||
setFilter(emptyFilter);
|
setFilter(emptyFilter);
|
||||||
@@ -188,16 +121,15 @@ const CocktailsPageContent = () => {
|
|||||||
setIsEnd(false);
|
setIsEnd(false);
|
||||||
setPage(-1);
|
setPage(-1);
|
||||||
}
|
}
|
||||||
const handleSelectCocktail = (row) => {
|
|
||||||
selectCocktail(row.id)
|
const handleSelectCocktail = (row) => selectCocktail(row.id)
|
||||||
}
|
const deleteHandle = (row) => cocktailClient.deleteCocktail(row.id, rows, setRows, createSuccess, createError)
|
||||||
const deleteHandle = (row) => {
|
const hideHandler = (id) => {
|
||||||
api().delete(requests.cocktails.cocktail + row.id)
|
cocktailClient.hiddenCocktail(id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setRows(rows.filter((r) => r.id !== row.id))
|
createSuccess("Коктейль скрыт успешно");
|
||||||
createSuccess("Коктейль удален")
|
setRows(rows.filter((r) => r.id !== id))
|
||||||
})
|
}).catch(() => createError("Ошибка при попытке скрыть коктейль"))
|
||||||
.catch(() => createError("Ошибка удаления коктейля"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -233,6 +165,7 @@ const CocktailsPageContent = () => {
|
|||||||
handleChangeRating={handleChangeRating}
|
handleChangeRating={handleChangeRating}
|
||||||
handleSelect={handleSelectCocktail}
|
handleSelect={handleSelectCocktail}
|
||||||
deleteHandler={deleteHandle}
|
deleteHandler={deleteHandle}
|
||||||
|
hideHandler={hideHandler}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -6,19 +6,18 @@ import {useEffect, useState} from "react";
|
|||||||
import Paper from "@mui/material/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
import {Autocomplete} from "@mui/material";
|
import {Autocomplete} from "@mui/material";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import {api} from "../../../lib/clients/api";
|
|
||||||
import {requests} from "../../../requests";
|
|
||||||
import {useAlert} from "../../../hooks/useAlert";
|
import {useAlert} from "../../../hooks/useAlert";
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import CheckMarks from "../../../components/cocktails/CheckMarks";
|
|
||||||
import {EditCocktailReceipt} from "../../../components/cocktails/EditCocktailReceipt";
|
import {EditCocktailReceipt} from "../../../components/cocktails/EditCocktailReceipt";
|
||||||
import {SelectEdit} from "../../../components/cocktails/SelectEdit";
|
import {SelectEdit} from "../../../components/cocktails/SelectEdit";
|
||||||
import {getComparator} from "../../../components/core/getComparator";
|
|
||||||
import {useSearchParams} from "react-router-dom";
|
import {useSearchParams} from "react-router-dom";
|
||||||
import {Loading} from "../../../components/core/Loading";
|
import {Loading} from "../../../components/core/Loading";
|
||||||
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
|
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
|
||||||
import {styled} from "@mui/material/styles";
|
import {styled} from "@mui/material/styles";
|
||||||
|
import {cocktailClient} from "../../../lib/clients/CocktailClient";
|
||||||
|
import {categoryClient} from "../../../lib/clients/CategoryClient";
|
||||||
|
import {glassClient} from "../../../lib/clients/GlassClient";
|
||||||
|
|
||||||
const emptyCocktail = {
|
const emptyCocktail = {
|
||||||
id: null,
|
id: null,
|
||||||
@@ -76,47 +75,16 @@ export function EditCocktailPage() {
|
|||||||
const [category, setCategory] = useState([]);
|
const [category, setCategory] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api().get(requests.cocktails.simple)
|
cocktailClient.getSimpleList(setCocktails, setSelected, setLoading, createError, searchParams.get("id"))
|
||||||
.then((r) => {
|
categoryClient.getCategoryList(setCategory, createError);
|
||||||
const arr = r.data.sort(getComparator("asc", "name"));
|
glassClient.getGlassList(setGlass, createError)
|
||||||
setCocktails(arr)
|
|
||||||
|
|
||||||
const currentId = searchParams.get("id");
|
|
||||||
if (!currentId) {
|
|
||||||
setLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const currentCocktail = arr.find((r) => r.id === (currentId * 1));
|
|
||||||
if (!currentCocktail) {
|
|
||||||
setLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setSelected(currentCocktail.id);
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch(() => createError("Ошибка получения данных"))
|
|
||||||
|
|
||||||
api().get(requests.bar.category)
|
|
||||||
.then((r) => setCategory(r.data.sort(getComparator())))
|
|
||||||
.catch(() => createError("Ошибка получения категорий"))
|
|
||||||
|
|
||||||
api().get(requests.bar.glass)
|
|
||||||
.then((r) => setGlass(r.data.sort(getComparator())))
|
|
||||||
.catch(() => createError("Ошибка получения посуды"))
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
|
||||||
if (!selected) {
|
// eslint-disable-next-line
|
||||||
setCocktail(emptyCocktail);
|
useEffect(() => cocktailClient.getOneCocktail(selected, setCocktail, getError, emptyCocktail), [selected])
|
||||||
return;
|
const saveHandler = () => cocktailClient.saveChangeCocktail(cocktail, createError, createSuccess)
|
||||||
}
|
const deleteHandle = () => cocktailClient.deleteCocktailFromEdit(setCocktails, setCocktail, createError, cocktails, cocktail, emptyCocktail)
|
||||||
api().get(requests.cocktails.cocktail + selected)
|
|
||||||
.then((r) => {
|
|
||||||
setCocktail(r.data)
|
|
||||||
})
|
|
||||||
.catch(() => getError());
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [selected])
|
|
||||||
|
|
||||||
const changeCocktailValue = (name, value) => {
|
const changeCocktailValue = (name, value) => {
|
||||||
if (name === "tags") {
|
if (name === "tags") {
|
||||||
@@ -127,25 +95,7 @@ export function EditCocktailPage() {
|
|||||||
[name]: value
|
[name]: value
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
const saveHandler = () => {
|
|
||||||
api().patch(requests.cocktails.edit, cocktail)
|
|
||||||
.then((r) => {
|
|
||||||
if (!r.data.error) {
|
|
||||||
createSuccess("Сохранено")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
createError("Ошибка на сервере: " + r.data.error)
|
|
||||||
})
|
|
||||||
.catch(() => createError("Неизвестная ошибка"))
|
|
||||||
}
|
|
||||||
const deleteHandle = () => {
|
|
||||||
api().delete(requests.cocktails.cocktail + cocktail.id)
|
|
||||||
.then(() => {
|
|
||||||
setCocktails(cocktails.filter((r) => r.id !== cocktail.id))
|
|
||||||
setCocktail(emptyCocktail);
|
|
||||||
})
|
|
||||||
.catch(() => createError("Ошибка удаления коктейля"))
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
{/*Загрузка*/}
|
{/*Загрузка*/}
|
||||||
@@ -201,14 +151,7 @@ export function EditCocktailPage() {
|
|||||||
<VisuallyHiddenInput
|
<VisuallyHiddenInput
|
||||||
type="file"
|
type="file"
|
||||||
accept=".jpg,.jpeg,.png"
|
accept=".jpg,.jpeg,.png"
|
||||||
onChange={(event) => {
|
onChange={(event) => cocktailClient.savePhoto(event, changeCocktailValue, getError)}
|
||||||
const file = event.target.files[0];
|
|
||||||
let formData = new FormData();
|
|
||||||
formData.append('file', file);
|
|
||||||
api().post(requests.cocktails.savePhoto, formData)
|
|
||||||
.then((r) => changeCocktailValue("image", r.data))
|
|
||||||
.catch(() => getError())
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import * as React from "react";
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import Paper from "@mui/material/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
import {Autocomplete, FormControl, FormControlLabel, InputLabel} from "@mui/material";
|
import {Autocomplete, FormControl, FormControlLabel, InputLabel} from "@mui/material";
|
||||||
import {api} from "../../../lib/clients/api";
|
|
||||||
import {requests} from "../../../requests";
|
|
||||||
import {useAlert} from "../../../hooks/useAlert";
|
import {useAlert} from "../../../hooks/useAlert";
|
||||||
import {useSearchParams} from "react-router-dom";
|
import {useSearchParams} from "react-router-dom";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
@@ -15,7 +13,7 @@ import Stack from "@mui/material/Stack";
|
|||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Select from "@mui/material/Select";
|
import Select from "@mui/material/Select";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import {getComparator} from "../../../components/core/getComparator";
|
import {ingredientClient} from "../../../lib/clients/IngredientClient";
|
||||||
|
|
||||||
const emptyIngredient = {
|
const emptyIngredient = {
|
||||||
id: null,
|
id: null,
|
||||||
@@ -36,25 +34,8 @@ export function EditIngredientPage() {
|
|||||||
const [ingredient, setIngredient] = useState(emptyIngredient)
|
const [ingredient, setIngredient] = useState(emptyIngredient)
|
||||||
const {createError, createSuccess} = useAlert();
|
const {createError, createSuccess} = useAlert();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api().get(requests.bar.ingredientList)
|
ingredientClient.allList(searchParams.get("id"), setIngredients, setIngredient, createError)
|
||||||
.then((r) => {
|
ingredientClient.getType(setTypes)
|
||||||
const arr = r.data.sort(getComparator("asc", "name"));
|
|
||||||
setIngredients(arr)
|
|
||||||
|
|
||||||
const currentId = searchParams.get("id");
|
|
||||||
if (!currentId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const currentIngredient = arr.find((r) => r.id === (currentId * 1));
|
|
||||||
if (!currentIngredient) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIngredient(currentIngredient);
|
|
||||||
})
|
|
||||||
.catch(() => createError("Ошибка получения данных"))
|
|
||||||
|
|
||||||
api().get(requests.bar.type)
|
|
||||||
.then((r) => setTypes(r.data.sort(getComparator("asc", "name"))))
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -64,11 +45,6 @@ export function EditIngredientPage() {
|
|||||||
[name]: value
|
[name]: value
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
const saveIngredientHandler = () => {
|
|
||||||
api().patch(requests.bar.ingredient, ingredient)
|
|
||||||
.then(() => createSuccess("Ингредиент сохранен"))
|
|
||||||
.catch(() => createError("Ошибка сохранения"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
@@ -111,10 +87,6 @@ export function EditIngredientPage() {
|
|||||||
variant="outlined" label={"Название"}
|
variant="outlined" label={"Название"}
|
||||||
value={ingredient.name}
|
value={ingredient.name}
|
||||||
onChange={(e) => changeIngredientValue("name", e.target.value)}/>
|
onChange={(e) => changeIngredientValue("name", e.target.value)}/>
|
||||||
<TextField sx={{mr: 1, mb: 2, minWidth: 330}}
|
|
||||||
label="Английское название" variant="outlined"
|
|
||||||
value={ingredient.enName}
|
|
||||||
onChange={(e) => changeIngredientValue("enName", e.target.value)}/>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box height={70} mt={1} ml={1}>
|
<Box height={70} mt={1} ml={1}>
|
||||||
@@ -162,7 +134,8 @@ export function EditIngredientPage() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Box display={'flex'} justifyContent={'flex-end'}>
|
<Box display={'flex'} justifyContent={'flex-end'}>
|
||||||
<Button variant='contained' onClick={() => saveIngredientHandler()}>Сохранить</Button>
|
<Button variant='contained'
|
||||||
|
onClick={() => ingredientClient.saveIngredient(ingredient, createSuccess, createError)}>Сохранить</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ import SearchIcon from "@mui/icons-material/Search";
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {useEffect, useMemo, useState} from "react";
|
import {useEffect, useMemo, useState} from "react";
|
||||||
import {Loading} from "../../../components/core/Loading";
|
import {Loading} from "../../../components/core/Loading";
|
||||||
import {requests} from "../../../requests";
|
|
||||||
import {useAlert} from "../../../hooks/useAlert";
|
import {useAlert} from "../../../hooks/useAlert";
|
||||||
import {IngredientInfoModal} from "../../../components/Ingredients/IngredientInfoModal";
|
import {IngredientInfoModal} from "../../../components/Ingredients/IngredientInfoModal";
|
||||||
import {api} from "../../../lib/clients/api";
|
|
||||||
import Tab from "@mui/material/Tab";
|
import Tab from "@mui/material/Tab";
|
||||||
import {a11yProps} from "../../../components/core/tabProps";
|
import {a11yProps} from "../../../components/core/tabProps";
|
||||||
import {CustomTabPanel} from "../../../components/core/TabPanel";
|
import {CustomTabPanel} from "../../../components/core/TabPanel";
|
||||||
@@ -19,6 +17,7 @@ import {IngredientList} from "../../../components/Ingredients/IngredientList";
|
|||||||
import {blue} from "@mui/material/colors";
|
import {blue} from "@mui/material/colors";
|
||||||
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
|
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
|
||||||
import {useSelect} from "../../../hooks/useSelect";
|
import {useSelect} from "../../../hooks/useSelect";
|
||||||
|
import {ingredientClient} from "../../../lib/clients/IngredientClient";
|
||||||
|
|
||||||
export function IngredientsPage() {
|
export function IngredientsPage() {
|
||||||
const [value, setValue] = React.useState(0);
|
const [value, setValue] = React.useState(0);
|
||||||
@@ -30,15 +29,7 @@ export function IngredientsPage() {
|
|||||||
const {createError, createSuccess} = useAlert();
|
const {createError, createSuccess} = useAlert();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api().get(requests.bar.ingredientList)
|
ingredientClient.getAllIngredients(setIngredients, setLoading, createError)
|
||||||
.then((r) => {
|
|
||||||
setIngredients(r.data)
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
createError("Ошибка получения списка ингредиентов");
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -63,26 +54,12 @@ export function IngredientsPage() {
|
|||||||
return ingredient;
|
return ingredient;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const url = `${requests.bar.ingredient}?id=${row.id}`;
|
ingredientClient.changeIngredientIsHave(row.id, value, newState, setIngredients, createError)
|
||||||
const request = value ? api().put(url) : api().delete(url);
|
|
||||||
request
|
|
||||||
.then(() => {
|
|
||||||
setIngredients(newState);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
createError("Ошибка изменения ингредиента");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const handleOpenModal = (i) => {
|
|
||||||
selectIngredient(i)
|
|
||||||
}
|
}
|
||||||
const handleDelete = (id) => {
|
const handleDelete = (id) => {
|
||||||
const newState = ingredients.filter((ingredient) => ingredient.id !== id);
|
const newState = ingredients.filter((ingredient) => ingredient.id !== id);
|
||||||
setIngredients(newState)
|
setIngredients(newState)
|
||||||
|
ingredientClient.deleteIngredientIsHave(id, createSuccess, createError)
|
||||||
api().delete(`${requests.bar.ingredient}/${id}`)
|
|
||||||
.then((r) => createSuccess("Ингредиент удален"))
|
|
||||||
.catch(() => createError("Ошибка удаления ингредиента. Перезагрузите страницу"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -118,11 +95,11 @@ export function IngredientsPage() {
|
|||||||
<Box>
|
<Box>
|
||||||
<CustomTabPanel value={value} index={0}>
|
<CustomTabPanel value={value} index={0}>
|
||||||
<IngredientList rows={ingredientsInBar} value={false} changeHandler={changeHandler}
|
<IngredientList rows={ingredientsInBar} value={false} changeHandler={changeHandler}
|
||||||
infoHandler={handleOpenModal}/>
|
infoHandler={selectIngredient}/>
|
||||||
</CustomTabPanel>
|
</CustomTabPanel>
|
||||||
<CustomTabPanel value={value} index={1}>
|
<CustomTabPanel value={value} index={1}>
|
||||||
<IngredientList rows={ingredientsToAdd} value={true} changeHandler={changeHandler}
|
<IngredientList rows={ingredientsToAdd} value={true} changeHandler={changeHandler}
|
||||||
infoHandler={handleOpenModal}/>
|
infoHandler={selectIngredient}/>
|
||||||
</CustomTabPanel>
|
</CustomTabPanel>
|
||||||
</Box>
|
</Box>
|
||||||
<Fab sx={{
|
<Fab sx={{
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import Dialog from "@mui/material/Dialog";
|
import Dialog from "@mui/material/Dialog";
|
||||||
import DialogTitle from "@mui/material/DialogTitle";
|
import DialogTitle from "@mui/material/DialogTitle";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import {useState} from "react";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import DialogContent from "@mui/material/DialogContent";
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
import DialogActions from "@mui/material/DialogActions";
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import {useState} from "react";
|
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
|
|
||||||
export function BarCreateModal({open, close, create}) {
|
export function BarCreateModal({open, setOpen, create, id}) {
|
||||||
const [value, setValue] = useState("");
|
const [value, setValue] = useState("");
|
||||||
return (
|
return (
|
||||||
<Dialog fullWidth={true}
|
<Dialog fullWidth={true}
|
||||||
open={open} onClose={close}
|
open={open} onClose={() => setOpen(false)}
|
||||||
sx={{
|
sx={{
|
||||||
'& .MuiDialog-paper': {
|
'& .MuiDialog-paper': {
|
||||||
margin: '8px',
|
margin: '8px',
|
||||||
@@ -26,13 +26,17 @@ export function BarCreateModal({open, close, create}) {
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<TextField sx={{width: '75%'}}
|
<TextField sx={{width: '75%'}}
|
||||||
label={"Название списка"} variant='outlined'
|
label={<Typography pt={'4px'}>
|
||||||
|
Название списка</Typography>} variant='outlined'
|
||||||
value={!value ? "" : value}
|
value={!value ? "" : value}
|
||||||
onChange={(e) => setValue(e.target.value)}
|
onChange={(e) => setValue(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => create(value)}>Создать</Button>
|
<Button onClick={() => {
|
||||||
|
create(id, value);
|
||||||
|
setValue("");
|
||||||
|
}}>Создать</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,17 +4,16 @@ import DialogContent from "@mui/material/DialogContent";
|
|||||||
import DialogActions from "@mui/material/DialogActions";
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import List from "@mui/material/List";
|
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 {useAlert} from "../../hooks/useAlert";
|
||||||
import ListItem from "@mui/material/ListItem";
|
import ListItem from "@mui/material/ListItem";
|
||||||
import {useSelect} from "../../hooks/useSelect";
|
import {useSelect} from "../../hooks/useSelect";
|
||||||
import {IngredientAlert} from "./IngredientAlert";
|
import {IngredientAlert} from "./IngredientAlert";
|
||||||
import {useUser} from "../../hooks/useUser";
|
import {useUser} from "../../hooks/useUser";
|
||||||
|
import {cocktailClient} from "../../lib/clients/CocktailClient";
|
||||||
|
|
||||||
export function IngredientInfoModal({ingredient, handleDelete}) {
|
export function IngredientInfoModal({ingredient, handleDelete}) {
|
||||||
const {user} = useUser();
|
const {user} = useUser();
|
||||||
@@ -28,11 +27,7 @@ export function IngredientInfoModal({ingredient, handleDelete}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(!ingredient) {
|
cocktailClient.getCocktailByIngredient(ingredient, setCocktails)
|
||||||
return
|
|
||||||
}
|
|
||||||
api().get(requests.cocktails.byIngredient + ingredient.id)
|
|
||||||
.then((r) => setCocktails(r.data))
|
|
||||||
.catch(() => createError())
|
.catch(() => createError())
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [ingredient]);
|
}, [ingredient]);
|
||||||
@@ -59,7 +54,7 @@ export function IngredientInfoModal({ingredient, handleDelete}) {
|
|||||||
</Stack>
|
</Stack>
|
||||||
{cocktails.length > 0 && (
|
{cocktails.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Typography sx={{ mt:2}}>Коктейли:</Typography>
|
<Typography sx={{mt: 2}}>Коктейли:</Typography>
|
||||||
<List>
|
<List>
|
||||||
{cocktails.map((c) => {
|
{cocktails.map((c) => {
|
||||||
return (
|
return (
|
||||||
@@ -69,7 +64,7 @@ export function IngredientInfoModal({ingredient, handleDelete}) {
|
|||||||
}}>
|
}}>
|
||||||
<Stack direction={'row'}>
|
<Stack direction={'row'}>
|
||||||
<img src={c.image} alt={c.name} loading={"eager"} width={"50"}/>
|
<img src={c.image} alt={c.name} loading={"eager"} width={"50"}/>
|
||||||
<Typography sx={{mx:1}}>{c.name}</Typography>
|
<Typography sx={{mx: 1}}>{c.name}</Typography>
|
||||||
{c.rating.rating > 0 && <Typography> {`${c.rating.rating}/5`}</Typography>}
|
{c.rating.rating > 0 && <Typography> {`${c.rating.rating}/5`}</Typography>}
|
||||||
</Stack>
|
</Stack>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@@ -83,7 +78,8 @@ export function IngredientInfoModal({ingredient, handleDelete}) {
|
|||||||
{user.role !== 'USER' && <Button onClick={() => setOpen(true)}>Удалить</Button>}
|
{user.role !== 'USER' && <Button onClick={() => setOpen(true)}>Удалить</Button>}
|
||||||
<Button onClick={closeIngredient}>Закрыть</Button>
|
<Button onClick={closeIngredient}>Закрыть</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
<IngredientAlert handleDelete={handleDelete} handleClose={handleClose} open={open} id={ingredient.id} handleCloseParent={closeIngredient}/>
|
<IngredientAlert handleDelete={handleDelete} handleClose={handleClose} open={open} id={ingredient.id}
|
||||||
|
handleCloseParent={closeIngredient}/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -10,12 +10,11 @@ import Button from "@mui/material/Button";
|
|||||||
import CircularProgress from "@mui/material/CircularProgress";
|
import CircularProgress from "@mui/material/CircularProgress";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import {red} from "@mui/material/colors";
|
import {red} from "@mui/material/colors";
|
||||||
import {requests} from "../../requests";
|
|
||||||
import {useAuth} from "../../hooks/useAuth";
|
import {useAuth} from "../../hooks/useAuth";
|
||||||
import {api} from "../../lib/clients/api";
|
import {authClient} from "../../lib/clients/AuthClient";
|
||||||
|
|
||||||
const emptyRequest = {
|
const emptyRequest = {
|
||||||
byLogin: false,
|
byLogin: true,
|
||||||
code: "",
|
code: "",
|
||||||
login: "",
|
login: "",
|
||||||
password: ""
|
password: ""
|
||||||
@@ -25,7 +24,7 @@ export function SignInForm() {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
const [request, setRequest] = useState(emptyRequest);
|
const [request, setRequest] = useState(emptyRequest);
|
||||||
const [pass, setPass] = useState(false)
|
const [pass, setPass] = useState(true)
|
||||||
const {checkSession} = useAuth();
|
const {checkSession} = useAuth();
|
||||||
|
|
||||||
const buttonSx = {
|
const buttonSx = {
|
||||||
@@ -38,21 +37,9 @@ export function SignInForm() {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
const handleButtonClick = async () => {
|
const handleButtonClick = async () => {
|
||||||
setLoading(true);
|
await authClient.login(request, setLoading, setError, checkSession)
|
||||||
const response = await api().post(requests.auth.login, request);
|
|
||||||
|
|
||||||
if (response.data.error) {
|
|
||||||
setError(response.data.error);
|
|
||||||
setLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem("token", response.data.token);
|
|
||||||
|
|
||||||
await checkSession?.();
|
|
||||||
|
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderByCode = () => {
|
const renderByCode = () => {
|
||||||
return (
|
return (
|
||||||
<Stack direction='row' mt={1}>
|
<Stack direction='row' mt={1}>
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
import {Card} from "@mui/material";
|
|
||||||
import Stack from "@mui/material/Stack";
|
|
||||||
import Box from "@mui/material/Box";
|
|
||||||
import React from "react";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import Button from "@mui/material/Button";
|
|
||||||
|
|
||||||
const role = (myRole) => {
|
|
||||||
switch (myRole) {
|
|
||||||
case "ADMIN":
|
|
||||||
return "Администратор";
|
|
||||||
case "ADMIN_NOT_BARMEN":
|
|
||||||
return "Управляющий";
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function BarItem({row, changeHandler, all, enterExist}) {
|
|
||||||
return (
|
|
||||||
<Card sx={{mb: 1, height: '100px', display: 'relative', p: 1}}>
|
|
||||||
<Stack direction='row' justifyContent='start' alignItems='start'>
|
|
||||||
<Box sx={{width: '75%', pr: 2}}>
|
|
||||||
<Typography variant='h6'>{row.name}</Typography>
|
|
||||||
<Typography>{role(row.myRole)}</Typography>
|
|
||||||
</Box>
|
|
||||||
<Stack sx={{width: '25%'}} spacing={1} justifyContent='flex-end' display='flex'>
|
|
||||||
<Typography color={row.open ? 'green' : 'red'}>{row.open ? "Бар открыт" : "Бар закрыт"}</Typography>
|
|
||||||
<Button variant='contained'
|
|
||||||
color={row.enter ? 'error' : 'success'}
|
|
||||||
onClick={() => changeHandler(row, !row.enter)}
|
|
||||||
disabled={!row.enter && enterExist}
|
|
||||||
>
|
|
||||||
{all ? "Добавить" : row.enter ? "Выйти" : "Войти"}
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import Box from "@mui/material/Box";
|
|
||||||
import {useEffect, useMemo, useState} from "react";
|
|
||||||
import {api} from "../../lib/clients/api";
|
|
||||||
import {requests} from "../../requests";
|
|
||||||
import {useAlert} from "../../hooks/useAlert";
|
|
||||||
import {BarItem} from "./BarItem";
|
|
||||||
import {Loading} from "../core/Loading";
|
|
||||||
import * as React from "react";
|
|
||||||
import {useUser} from "../../hooks/useUser";
|
|
||||||
|
|
||||||
export function BarList({all}) {
|
|
||||||
const {getError, createError} = useAlert();
|
|
||||||
const {refresh} = useUser();
|
|
||||||
const [bars, setBars] = useState([]);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setLoading(true);
|
|
||||||
api().get(`${requests.bar.list}?my=${!all}`)
|
|
||||||
.then((r) => {
|
|
||||||
setBars(r.data)
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch(() => getError())
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, []);
|
|
||||||
const enterExist = useMemo(() => bars.find((b) => b.enter), [bars])
|
|
||||||
const changeHandler = (row, value) => {
|
|
||||||
let request;
|
|
||||||
let newState;
|
|
||||||
if (!all) {
|
|
||||||
if (value && enterExist) {
|
|
||||||
//todo: добавить переключение
|
|
||||||
createError("Нельзя войти более чем в один бар одновременно")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
request = api().patch(`${requests.bar.enter}${row.id}&value=${value}`);
|
|
||||||
newState = bars.map((b) => {
|
|
||||||
if (b.id !== row.id) {
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...b,
|
|
||||||
enter: value
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
request = api().post(requests.bar.addToMyList, row);
|
|
||||||
newState = bars.filter((b) => b.id !== row.id);
|
|
||||||
}
|
|
||||||
request.then(() => {
|
|
||||||
setBars(newState)
|
|
||||||
refresh();
|
|
||||||
}).catch(() => getError())
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Box mt={2}>
|
|
||||||
{
|
|
||||||
bars.map((row) => {
|
|
||||||
return (
|
|
||||||
<BarItem key={row.id} row={row} changeHandler={changeHandler}
|
|
||||||
all={all} enterExist={enterExist}/>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
{/*Загрузчик*/}
|
|
||||||
<Loading loading={loading}/>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -10,9 +10,11 @@ import {CocktailDescription} from "./CocktailDescription";
|
|||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
import LocalBarIcon from '@mui/icons-material/LocalBar';
|
import LocalBarIcon from '@mui/icons-material/LocalBar';
|
||||||
|
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
|
||||||
import {paths} from "../../path";
|
import {paths} from "../../path";
|
||||||
import {useAlert} from "../../hooks/useAlert";
|
import {useAlert} from "../../hooks/useAlert";
|
||||||
import {useUser} from "../../hooks/useUser";
|
import {useUser} from "../../hooks/useUser";
|
||||||
|
import {cocktailClient} from "../../lib/clients/CocktailClient";
|
||||||
|
|
||||||
function renderFavouriteBadge(handleFavourite, row) {
|
function renderFavouriteBadge(handleFavourite, row) {
|
||||||
const childIcon = row.rating.favourite ? <FavoriteIcon/> : <FavoriteBorderIcon/>;
|
const childIcon = row.rating.favourite ? <FavoriteIcon/> : <FavoriteBorderIcon/>;
|
||||||
@@ -34,8 +36,8 @@ function renderRating(handleChangeRating, row) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect, deleteHandler}) {
|
export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect, deleteHandler, hideHandler}) {
|
||||||
const {notImplement} = useAlert();
|
const {createError, createSuccess} = useAlert();
|
||||||
const {user} = useUser();
|
const {user} = useUser();
|
||||||
return (
|
return (
|
||||||
<Grid item sx={{pr: 2}}>
|
<Grid item sx={{pr: 2}}>
|
||||||
@@ -59,17 +61,22 @@ export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect
|
|||||||
image={row.image.includes("thecocktaildb") ? (row.image + "/preview") : row.image}
|
image={row.image.includes("thecocktaildb") ? (row.image + "/preview") : row.image}
|
||||||
/>
|
/>
|
||||||
<CardActions>
|
<CardActions>
|
||||||
<IconButton sx={{m: 0}} size='small' onClick={() => notImplement()}>
|
<IconButton sx={{m: 0}} size='small'
|
||||||
|
onClick={() => cocktailClient.drinkCocktail(row.id, createSuccess, createError)}>
|
||||||
<LocalBarIcon fontSize='small'/>
|
<LocalBarIcon fontSize='small'/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{renderFavouriteBadge(handleFavourite, row)}
|
{renderFavouriteBadge(handleFavourite, row)}
|
||||||
{renderRating(handleChangeRating, row)}
|
{renderRating(handleChangeRating, row)}
|
||||||
|
|
||||||
{user.role !== 'USER' &&
|
{
|
||||||
|
(user.role && user.role !== 'USER') &&
|
||||||
<>
|
<>
|
||||||
<IconButton size='small' href={`${paths.bar.cocktailEdit}?id=${row.id}`}>
|
<IconButton size='small' href={`${paths.bar.cocktailEdit}?id=${row.id}`}>
|
||||||
<EditIcon fontSize='small'/>
|
<EditIcon fontSize='small'/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
<IconButton size='small' onClick={() => hideHandler(row.id)}>
|
||||||
|
<VisibilityOffIcon fontSize='small'/>
|
||||||
|
</IconButton>
|
||||||
<IconButton size='small' onClick={() => deleteHandler(row)}>
|
<IconButton size='small' onClick={() => deleteHandler(row)}>
|
||||||
<DeleteIcon fontSize='small'/>
|
<DeleteIcon fontSize='small'/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ import IconButton from "@mui/material/IconButton";
|
|||||||
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
|
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
import {IngredientInfoModal} from "../Ingredients/IngredientInfoModal";
|
import {IngredientInfoModal} from "../Ingredients/IngredientInfoModal";
|
||||||
import {api} from "../../lib/clients/api";
|
|
||||||
import {requests} from "../../requests";
|
|
||||||
import {useAlert} from "../../hooks/useAlert";
|
import {useAlert} from "../../hooks/useAlert";
|
||||||
import {paths} from "../../path";
|
import {paths} from "../../path";
|
||||||
import {Loading} from "../core/Loading";
|
import {Loading} from "../core/Loading";
|
||||||
import {useUser} from "../../hooks/useUser";
|
import {useUser} from "../../hooks/useUser";
|
||||||
import {useSelect} from "../../hooks/useSelect";
|
import {useSelect} from "../../hooks/useSelect";
|
||||||
|
import {cocktailClient} from "../../lib/clients/CocktailClient";
|
||||||
|
import {ingredientClient} from "../../lib/clients/IngredientClient";
|
||||||
|
|
||||||
export function CocktailInfoModal({row}) {
|
export function CocktailInfoModal({row}) {
|
||||||
const {user} = useUser();
|
const {user} = useUser();
|
||||||
@@ -29,56 +29,9 @@ export function CocktailInfoModal({row}) {
|
|||||||
const [cocktail, setCocktail] = useState(null)
|
const [cocktail, setCocktail] = useState(null)
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const {closeCocktail, selectIngredient, getIngredient, getOpenCocktail} = useSelect();
|
const {closeCocktail, selectIngredient, getIngredient, getOpenCocktail} = useSelect();
|
||||||
const openIngredientModalHandler = (id) => {
|
|
||||||
api().get(`${requests.bar.ingredient}?id=${id}`)
|
|
||||||
.then((r) => {
|
|
||||||
selectIngredient(r.data)
|
|
||||||
})
|
|
||||||
.catch(() => createError("Ошибка получения информации об ингредиенте"))
|
|
||||||
}
|
|
||||||
const selectIngredientHandler = (ingredient) => {
|
|
||||||
const url = `${requests.bar.ingredient}?id=${ingredient.id}`;
|
|
||||||
const request = ingredient.isHave ? api().delete(url) : api().put(url);
|
|
||||||
const value = !ingredient.isHave;
|
|
||||||
request.then(() => {
|
|
||||||
const newReceipts = cocktail.receipt.map((r) => {
|
|
||||||
if (r.ingredient.id !== ingredient.id) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...r,
|
|
||||||
ingredient: {
|
|
||||||
...ingredient,
|
|
||||||
isHave: value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
setCocktail({
|
|
||||||
...cocktail,
|
|
||||||
receipt: newReceipts
|
|
||||||
})
|
|
||||||
createSuccess("Сохранено")
|
|
||||||
}).catch(() => createError("Ошибка сохранения"))
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
// eslint-disable-next-line
|
||||||
setLoading(true)
|
useEffect(() => cocktailClient.getCocktailForModal(row, setLoading, setCocktail, closeCocktail, getError), [row]);
|
||||||
if (!row) {
|
|
||||||
setLoading(false)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
api().get(requests.cocktails.modal + row)
|
|
||||||
.then((r) => {
|
|
||||||
setCocktail(r.data)
|
|
||||||
setLoading(false)
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
getError();
|
|
||||||
setLoading(false)
|
|
||||||
closeCocktail();
|
|
||||||
})
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [row]);
|
|
||||||
|
|
||||||
if (!row || !cocktail) {
|
if (!row || !cocktail) {
|
||||||
return null;
|
return null;
|
||||||
@@ -132,9 +85,9 @@ export function CocktailInfoModal({row}) {
|
|||||||
<Stack key={r.ingredient.id} direction='row' justifyContent={'space-between'}
|
<Stack key={r.ingredient.id} direction='row' justifyContent={'space-between'}
|
||||||
mt={1}>
|
mt={1}>
|
||||||
<Stack direction='row'>
|
<Stack direction='row'>
|
||||||
{user.role !== "USER" && (
|
{(user.role && user.role !== "USER") && (
|
||||||
<IconButton size="small" sx={{pb: "2px"}}
|
<IconButton size="small" sx={{pb: "2px"}}
|
||||||
onClick={() => selectIngredientHandler(r.ingredient)}>
|
onClick={() => ingredientClient.changeIngredientInBar(r.ingredient, cocktail, setCocktail, createSuccess, createError)}>
|
||||||
{r.ingredient.isHave
|
{r.ingredient.isHave
|
||||||
? (<DeleteIcon fontSize="small"/>)
|
? (<DeleteIcon fontSize="small"/>)
|
||||||
: (<ShoppingCartIcon fontSize="small"/>)
|
: (<ShoppingCartIcon fontSize="small"/>)
|
||||||
@@ -142,7 +95,7 @@ export function CocktailInfoModal({row}) {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
<Typography
|
<Typography
|
||||||
onClick={() => openIngredientModalHandler(r.ingredient.id)}>{r.ingredient.name}</Typography>
|
onClick={() => ingredientClient.findOne(r.ingredient.id, selectIngredient, createError)}>{r.ingredient.name}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Typography color={hasError && 'red'}>{measure}</Typography>
|
<Typography color={hasError && 'red'}>{measure}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -161,7 +114,7 @@ export function CocktailInfoModal({row}) {
|
|||||||
</Box>
|
</Box>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
{user.role.includes("ADMIN") && (
|
{(user.role && user.role.includes("ADMIN")) && (
|
||||||
<Button href={`${paths.bar.cocktailEdit}?id=${cocktail.id}`}>Редактировать</Button>
|
<Button href={`${paths.bar.cocktailEdit}?id=${cocktail.id}`}>Редактировать</Button>
|
||||||
)}
|
)}
|
||||||
<Button onClick={closeCocktail}>Закрыть</Button>
|
<Button onClick={closeCocktail}>Закрыть</Button>
|
||||||
|
|||||||
@@ -6,13 +6,11 @@ import AddIcon from "@mui/icons-material/Add";
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {useAlert} from "../../hooks/useAlert";
|
import {useAlert} from "../../hooks/useAlert";
|
||||||
import {api} from "../../lib/clients/api";
|
|
||||||
import {requests} from "../../requests";
|
|
||||||
import {getComparator} from "../core/getComparator";
|
|
||||||
import {Card} from "@mui/material";
|
import {Card} from "@mui/material";
|
||||||
import {SelectEdit} from "./SelectEdit";
|
import {SelectEdit} from "./SelectEdit";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
|
import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
|
||||||
|
import {ingredientClient} from "../../lib/clients/IngredientClient";
|
||||||
|
|
||||||
export function EditCocktailReceipt({receipt, handler}) {
|
export function EditCocktailReceipt({receipt, handler}) {
|
||||||
const {createError} = useAlert()
|
const {createError} = useAlert()
|
||||||
@@ -20,13 +18,9 @@ export function EditCocktailReceipt({receipt, handler}) {
|
|||||||
const [units, setUnits] = useState([])
|
const [units, setUnits] = useState([])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api().get(requests.bar.ingredientList)
|
ingredientClient.findAll(setIngredients, createError)
|
||||||
.then((r) => setIngredients(r.data.sort(getComparator("asc", "name"))))
|
ingredientClient.findUnit(setUnits, createError)
|
||||||
.catch(() => createError("Ошибка получения списка ингредиентов"))
|
// eslint-disable-next-line
|
||||||
|
|
||||||
api().get(requests.bar.unit)
|
|
||||||
.then((r) => setUnits(r.data.sort(getComparator("asc", "name"))))
|
|
||||||
.catch(() => createError("Ошибка получения единиц измерения"))
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const selectHandler = (name, value) => {
|
const selectHandler = (name, value) => {
|
||||||
@@ -152,7 +146,8 @@ export function EditCocktailReceipt({receipt, handler}) {
|
|||||||
value={r.count}
|
value={r.count}
|
||||||
onChange={(e) => countHandler(i, e.target.value)}
|
onChange={(e) => countHandler(i, e.target.value)}
|
||||||
/>
|
/>
|
||||||
<SelectEdit width={'calc(65% - 28px)'} array={units} value={!r.unit ? null : r.unit.name}
|
<SelectEdit width={'calc(65% - 28px)'} array={units}
|
||||||
|
value={!r.unit ? null : r.unit.name}
|
||||||
handler={unitHandler} label={"Ед."}
|
handler={unitHandler} label={"Ед."}
|
||||||
margin={1} attributeName={i}
|
margin={1} attributeName={i}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -10,27 +10,21 @@ import CheckMarks from "./CheckMarks";
|
|||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {requests} from "../../requests";
|
|
||||||
import {useAlert} from "../../hooks/useAlert";
|
import {useAlert} from "../../hooks/useAlert";
|
||||||
import {api} from "../../lib/clients/api";
|
import {categoryClient} from "../../lib/clients/CategoryClient";
|
||||||
import {sortList} from "./sortingList";
|
import {glassClient} from "../../lib/clients/GlassClient";
|
||||||
|
|
||||||
export function FilterBlock({filter, handleFilterChange, handleClearFilter, barmen}) {
|
export function FilterBlock({filter, handleFilterChange, handleClearFilter, barmen}) {
|
||||||
const {createError} = useAlert();
|
const {createError} = useAlert();
|
||||||
const [glass, setGlass] = useState([]);
|
const [glass, setGlass] = useState([]);
|
||||||
const [category, setCategory] = useState([]);
|
const [category, setCategory] = useState([]);
|
||||||
const alcohol = ['Алкогольный', 'Безалкогольный'];
|
const alcohol = ['Алкогольный', 'Безалкогольный'];
|
||||||
const ingredientCount = [1,2,3,4,5];
|
const ingredientCount = [1, 2, 3, 4, 5];
|
||||||
const sort = ['Название по возрастанию', 'Название по убыванию'];
|
const sort = ['Название по возрастанию', 'Название по убыванию'];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api().get(requests.bar.category)
|
categoryClient.getCategoryList(setCategory, createError)
|
||||||
.then((r) => setCategory(r.data))
|
glassClient.getGlassList(setGlass, createError)
|
||||||
.catch(() => createError("Ошибка получения категорий"))
|
|
||||||
|
|
||||||
api().get(requests.bar.glass)
|
|
||||||
.then((r) => setGlass(r.data))
|
|
||||||
.catch(() => createError("Ошибка получения посуды"))
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -94,15 +88,15 @@ export function FilterBlock({filter, handleFilterChange, handleClearFilter, barm
|
|||||||
{/*Фильтр по категории*/}
|
{/*Фильтр по категории*/}
|
||||||
{category.length > 0 && (
|
{category.length > 0 && (
|
||||||
<CheckMarks rows={category} name={"Категории"} filterValue={filter.category}
|
<CheckMarks rows={category} name={"Категории"} filterValue={filter.category}
|
||||||
filterName={"category"} handleChange={handleFilterChange} identity/>)}
|
filterName={"category"} handleChange={handleFilterChange}/>)}
|
||||||
{/*Фильтр по посуде*/}
|
{/*Фильтр по посуде*/}
|
||||||
{glass.length > 0 && (<CheckMarks rows={glass} name={"Подача"} handleChange={handleFilterChange}
|
{glass.length > 0 && (<CheckMarks rows={glass} name={"Подача"} handleChange={handleFilterChange}
|
||||||
filterValue={filter.glass} filterName={"glass"} identity/>)}
|
filterValue={filter.glass} filterName={"glass"}/>)}
|
||||||
{/*Фильтр по нехватке ингредиентов*/}
|
{/*Фильтр по нехватке ингредиентов*/}
|
||||||
{(barmen && filter.all) && (<CheckMarks rows={ingredientCount} name={"Не хватает ингредиентов"}
|
{(barmen && filter.all) && (<CheckMarks rows={ingredientCount} name={"Не хватает ингредиентов"}
|
||||||
handleChange={handleFilterChange}
|
handleChange={handleFilterChange}
|
||||||
nonMulti nullValue identity
|
nonMulti nullValue identity
|
||||||
filterValue={filter.iCount} filterName={"iCount"}/>)}
|
filterValue={filter.iCount} filterName={"iCount"}/>)}
|
||||||
<Button onClick={() => handleClearFilter()}>Сбросить</Button>
|
<Button onClick={() => handleClearFilter()}>Сбросить</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import MenuItem from "@mui/material/MenuItem";
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
export function SelectEdit({label, value, array, handler, attributeName, width, margin}) {
|
export function SelectEdit({label, value, array, handler, attributeName, width, margin}) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl sx={{width: width, m: margin}}>
|
<FormControl sx={{width: width, m: margin}}>
|
||||||
<InputLabel>{label}</InputLabel>
|
<InputLabel>{label}</InputLabel>
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ import MenuList from '@mui/material/MenuList';
|
|||||||
import Popover from '@mui/material/Popover';
|
import Popover from '@mui/material/Popover';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import {SignOut as SignOutIcon} from '@phosphor-icons/react/dist/ssr/SignOut';
|
import {SignOut as SignOutIcon} from '@phosphor-icons/react/dist/ssr/SignOut';
|
||||||
|
import {SignIn as SignInIcon} from '@phosphor-icons/react/dist/ssr/SignIn';
|
||||||
import {logger} from "../../lib/DefaultLogger";
|
import {logger} from "../../lib/DefaultLogger";
|
||||||
import {useAuth} from "../../hooks/useAuth";
|
import {useAuth} from "../../hooks/useAuth";
|
||||||
import {authClient} from "../../lib/clients/AuthClient";
|
import {authClient} from "../../lib/clients/AuthClient";
|
||||||
import {useLocation} from "react-router-dom";
|
import {useLocation} from "react-router-dom";
|
||||||
import {useUser} from "../../hooks/useUser";
|
import {useUser} from "../../hooks/useUser";
|
||||||
|
import {paths} from "../../path";
|
||||||
|
|
||||||
export function UserPopover({anchorEl, onClose, open}) {
|
export function UserPopover({anchorEl, onClose, open}) {
|
||||||
const {checkSession} = useAuth();
|
const {checkSession} = useAuth();
|
||||||
@@ -37,6 +39,7 @@ export function UserPopover({anchorEl, onClose, open}) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Sign out error', err);
|
logger.error('Sign out error', err);
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
}, [checkSession, location]);
|
}, [checkSession, location]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -64,24 +67,31 @@ export function UserPopover({anchorEl, onClose, open}) {
|
|||||||
{/* </ListItemIcon>*/}
|
{/* </ListItemIcon>*/}
|
||||||
{/* Профиль*/}
|
{/* Профиль*/}
|
||||||
{/*</MenuItem>*/}
|
{/*</MenuItem>*/}
|
||||||
<MenuItem onClick={handleSignOut}>
|
{!user.name ? <MenuItem onClick={() => window.location.replace(paths.auth.signIn)}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<SignOutIcon fontSize="var(--icon-fontSize-md)"/>
|
<SignInIcon fontSize="var(--icon-fontSize-md)"/>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
Выход
|
Вход
|
||||||
</MenuItem>
|
</MenuItem> :
|
||||||
|
<MenuItem onClick={handleSignOut}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<SignOutIcon fontSize="var(--icon-fontSize-md)"/>
|
||||||
|
</ListItemIcon>
|
||||||
|
Выход
|
||||||
|
</MenuItem>
|
||||||
|
}
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function userDescriptor(user, session) {
|
function userDescriptor(user) {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return (<Typography variant="subtitle1">Ошибка загрузки данных</Typography>);
|
return null;
|
||||||
|
}
|
||||||
|
if (!user.name) {
|
||||||
|
return (<Typography variant="subtitle1">Гость</Typography>);
|
||||||
}
|
}
|
||||||
|
|
||||||
const open = (session.isActive && user.invited) ? "открыт" : "закрыт";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typography variant="subtitle1">{user.name + " " + user.lastName}</Typography>
|
<Typography variant="subtitle1">{user.name + " " + user.lastName}</Typography>
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import {
|
|||||||
Martini,
|
Martini,
|
||||||
Storefront,
|
Storefront,
|
||||||
Users,
|
Users,
|
||||||
Wallet
|
Wallet,
|
||||||
|
Calculator
|
||||||
} from "@phosphor-icons/react";
|
} from "@phosphor-icons/react";
|
||||||
|
|
||||||
export const navIcons = {
|
export const navIcons = {
|
||||||
@@ -31,6 +32,7 @@ export const navIcons = {
|
|||||||
'chart-pie': ChartPieIcon,
|
'chart-pie': ChartPieIcon,
|
||||||
'gear-six': GearSixIcon,
|
'gear-six': GearSixIcon,
|
||||||
'plugs-connected': PlugsConnectedIcon,
|
'plugs-connected': PlugsConnectedIcon,
|
||||||
|
'calc': Calculator,
|
||||||
'x-square': XSquare,
|
'x-square': XSquare,
|
||||||
user: UserIcon,
|
user: UserIcon,
|
||||||
users: UsersIcon,
|
users: UsersIcon,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
import {isNavItemActive} from "../../lib/isNavItemActive";
|
import {isNavItemActive} from "./isNavItemActive";
|
||||||
import {navIcons} from "../core/navIcons";
|
import {navIcons} from "../core/navIcons";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {useCallback, useEffect} from 'react';
|
import {useCallback, useEffect} from 'react';
|
||||||
import {logger} from "../lib/DefaultLogger";
|
import {logger} from "../lib/DefaultLogger";
|
||||||
import {tokenUtil} from "../lib/TokenUtil";
|
import {tokenUtil} from "../lib/clients/TokenUtil";
|
||||||
|
|
||||||
export const AuthContext = React.createContext(undefined);
|
export const AuthContext = React.createContext(undefined);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import {createContext, useCallback, useEffect, useState} from "react";
|
||||||
import {logger} from "../lib/DefaultLogger";
|
import {logger} from "../lib/DefaultLogger";
|
||||||
import {userClient} from "../lib/clients/UserClient";
|
import {userClient} from "../lib/clients/UserClient";
|
||||||
import {tokenUtil} from "../lib/TokenUtil";
|
import {tokenUtil} from "../lib/clients/TokenUtil";
|
||||||
import {createContext, useCallback, useEffect, useState} from "react";
|
|
||||||
import {api} from "../lib/clients/api";
|
|
||||||
import {requests} from "../requests";
|
|
||||||
|
|
||||||
export const UserContext = createContext(undefined);
|
export const UserContext = createContext(undefined);
|
||||||
|
|
||||||
@@ -24,19 +22,10 @@ export function UserProvider({children}) {
|
|||||||
const checkSession = useCallback(async () => {
|
const checkSession = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setState((prev) => ({...prev, isLoading: true}));
|
setState((prev) => ({...prev, isLoading: true}));
|
||||||
if (!await tokenUtil.checkToken(tokenUtil.getToken())) {
|
if (!tokenUtil.checkToken(tokenUtil.getToken())) {
|
||||||
setState((prev) => ({...prev, error: '', isLoading: false, user: {}}));
|
setState((prev) => ({...prev, error: '', isLoading: false, user: {}}));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
api().get(requests.bar.session.status)
|
|
||||||
.then((r) => setState((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
session: r.data
|
|
||||||
})))
|
|
||||||
.catch(() => setState((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
session: {}
|
|
||||||
})))
|
|
||||||
if (Object.keys(state.user).length === 0) {
|
if (Object.keys(state.user).length === 0) {
|
||||||
const {data, errorData} = await userClient.getMe();
|
const {data, errorData} = await userClient.getMe();
|
||||||
if (errorData) {
|
if (errorData) {
|
||||||
|
|||||||
@@ -1,9 +1,45 @@
|
|||||||
|
import {api} from "./api";
|
||||||
|
import {requests} from "../../requests";
|
||||||
|
|
||||||
class AuthClient {
|
class AuthClient {
|
||||||
|
|
||||||
async signOut() {
|
async signOut() {
|
||||||
localStorage.removeItem("token");
|
localStorage.removeItem("token");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async login(request, setLoading, setError, checkSession) {
|
||||||
|
setLoading(true);
|
||||||
|
const response = await api().post(requests.auth.login, request);
|
||||||
|
|
||||||
|
if (response.data.error) {
|
||||||
|
setError(response.data.error);
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem("token", response.data.token);
|
||||||
|
|
||||||
|
await checkSession?.();
|
||||||
|
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
loginByCode(code, checkSession) {
|
||||||
|
const request = {
|
||||||
|
byLogin: false,
|
||||||
|
code: code
|
||||||
|
}
|
||||||
|
api().post(requests.auth.login, request)
|
||||||
|
.then(async (response) => {
|
||||||
|
if (response.data.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localStorage.setItem("token", response.data.token);
|
||||||
|
await checkSession?.();
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const authClient = new AuthClient();
|
export const authClient = new AuthClient();
|
||||||
|
|||||||
74
front/src/lib/clients/BarClient.js
Normal file
74
front/src/lib/clients/BarClient.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import {api} from "./api";
|
||||||
|
import {requests} from "../../requests";
|
||||||
|
import {getComparator} from "../../components/core/getComparator";
|
||||||
|
|
||||||
|
class BarClient {
|
||||||
|
|
||||||
|
getBarList(setBars, createError) {
|
||||||
|
api().get(requests.bar.all)
|
||||||
|
.then((r) => {
|
||||||
|
setBars(r.data.sort(getComparator("name")))
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
createError("Ошибка получения списков")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
changeBar(id, bars, createWarning, createSuccess, createError, setBars) {
|
||||||
|
createWarning("Дождитесь окончания операции")
|
||||||
|
api().post(`${requests.bar.change}/${id}`)
|
||||||
|
.then(() => createSuccess("Список изменен"))
|
||||||
|
.catch(() => createError("Ошибка изменения активного списка"))
|
||||||
|
|
||||||
|
const newState = bars.map((b) => {
|
||||||
|
if (b.active) {
|
||||||
|
return {
|
||||||
|
...b, active: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (b.id === id) {
|
||||||
|
return {
|
||||||
|
...b, active: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
})
|
||||||
|
setBars(newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteBar(bar, bars, createError, createSuccess, setBars) {
|
||||||
|
if (bar.active) {
|
||||||
|
createError("Нельзя удалить активный бар!")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
api().delete(requests.bar.crud + bar.id)
|
||||||
|
.then(() => createSuccess("Список удален"))
|
||||||
|
.catch(() => createError("Ошибка удаления. Обновите страницу"))
|
||||||
|
|
||||||
|
setBars(bars.filter((b) => b.id !== bar.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
createBar(name, bars, createSuccess, createError, setBars, setOpen) {
|
||||||
|
api().post(requests.bar.crud + name)
|
||||||
|
.then((r) => {
|
||||||
|
createSuccess("Cписок создан");
|
||||||
|
let state = bars;
|
||||||
|
state.push(r.data);
|
||||||
|
setBars(state)
|
||||||
|
setOpen(false)
|
||||||
|
}).catch(() => createError("Ошибка создания списка"))
|
||||||
|
}
|
||||||
|
|
||||||
|
copyBar(oldId, newName, setBars, bars, createError, createSuccess, setOpen) {
|
||||||
|
api().post(requests.bar.crud + "copy/" + oldId + "/" + newName)
|
||||||
|
.then((r) => {
|
||||||
|
const state = bars;
|
||||||
|
state.push(r.data)
|
||||||
|
setBars(state);
|
||||||
|
createSuccess("Бар скопирован")
|
||||||
|
setOpen(false)
|
||||||
|
}).catch(() => createError("Ошибка при копировании бара"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const barClient = new BarClient();
|
||||||
19
front/src/lib/clients/CategoryClient.js
Normal file
19
front/src/lib/clients/CategoryClient.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import {api} from "./api";
|
||||||
|
import {requests} from "../../requests";
|
||||||
|
import {getComparator} from "../../components/core/getComparator";
|
||||||
|
|
||||||
|
class CategoryClient {
|
||||||
|
|
||||||
|
getCategoryList(setCategory, createError) {
|
||||||
|
api().get(requests.category.basic)
|
||||||
|
.then((r) => {
|
||||||
|
setCategory(r.data.sort(getComparator())
|
||||||
|
.map((item, i) => {
|
||||||
|
return {id: i, name: item}
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
.catch(() => createError("Ошибка получения категорий"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const categoryClient = new CategoryClient();
|
||||||
216
front/src/lib/clients/CocktailClient.js
Normal file
216
front/src/lib/clients/CocktailClient.js
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
import {api} from "./api";
|
||||||
|
import {requests} from "../../requests";
|
||||||
|
import {sortList} from "../../components/cocktails/sortingList";
|
||||||
|
import {getComparator} from "../../components/core/getComparator";
|
||||||
|
|
||||||
|
class CocktailClient {
|
||||||
|
emptyCocktailForEditPage = {
|
||||||
|
id: null,
|
||||||
|
name: "",
|
||||||
|
alcoholic: "",
|
||||||
|
category: "",
|
||||||
|
components: "",
|
||||||
|
glass: "",
|
||||||
|
image: "",
|
||||||
|
instructions: "",
|
||||||
|
isAllowed: false,
|
||||||
|
rating: {
|
||||||
|
rating: 0,
|
||||||
|
favourite: false
|
||||||
|
},
|
||||||
|
receipt: [],
|
||||||
|
tags: "",
|
||||||
|
video: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
getMenu(setRows, setIsNew, setPage, setLoad, setIsEnd, isNew, rows, page, size, filter, createError) {
|
||||||
|
setLoad(true);
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
...filter,
|
||||||
|
sort: sortList.find((s) => s.name === filter.sorting).id,
|
||||||
|
page: page + 1,
|
||||||
|
size: size,
|
||||||
|
notHaveCount: Array.isArray(filter.iCount) ? null : filter.iCount
|
||||||
|
}
|
||||||
|
|
||||||
|
api().post(requests.cocktails.menu, request)
|
||||||
|
.then((r) => {
|
||||||
|
if (r.data.length === 0) {
|
||||||
|
if (isNew) {
|
||||||
|
setRows([]);
|
||||||
|
}
|
||||||
|
setIsEnd(true);
|
||||||
|
setLoad(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cocktails = isNew ? r.data : rows.concat(r.data);
|
||||||
|
setRows(cocktails);
|
||||||
|
setIsNew(false);
|
||||||
|
setPage(page + 1);
|
||||||
|
setLoad(false);
|
||||||
|
})
|
||||||
|
.catch((r) => {
|
||||||
|
setLoad(false);
|
||||||
|
createError("Ошибка загрузки данных от сервера Status:" + r.code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCocktailByIngredient(ingredient, setCocktails) {
|
||||||
|
if(!ingredient) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
api().get(requests.cocktails.byIngredient + ingredient.id)
|
||||||
|
.then((r) => setCocktails(r.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
getCocktailsForCalcPage(load,setLoad, setCocktails, setCocktailMap, createError) {
|
||||||
|
if (load) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
api().get(requests.cocktails.calc)
|
||||||
|
.then((r) => {
|
||||||
|
const data = r.data;
|
||||||
|
if (data.length === 0) {
|
||||||
|
setLoad(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCocktails(data);
|
||||||
|
let map = {};
|
||||||
|
data.forEach((d) => {
|
||||||
|
map = {
|
||||||
|
...map,
|
||||||
|
[d.id]: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setCocktailMap(map);
|
||||||
|
setLoad(true);
|
||||||
|
})
|
||||||
|
.catch((r) => {
|
||||||
|
setLoad(true);
|
||||||
|
createError("Ошибка загрузки данных от сервера Status:" + r.code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
savePhoto(event, changeCocktailValue, getError) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
api().post(requests.cocktails.photo, formData)
|
||||||
|
.then((r) => changeCocktailValue("image", r.data))
|
||||||
|
.catch(() => getError())
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteCocktailFromEdit(setCocktails, setCocktail, createError, cocktails, cocktail, emptyCocktail) {
|
||||||
|
api().delete(requests.cocktails.cocktail + cocktail.id)
|
||||||
|
.then(() => {
|
||||||
|
setCocktails(cocktails.filter((r) => r.id !== cocktail.id))
|
||||||
|
setCocktail(emptyCocktail);
|
||||||
|
})
|
||||||
|
.catch(() => createError("Ошибка удаления коктейля"))
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteCocktail(id, rows, setRows, createSuccess, createError) {
|
||||||
|
api().delete(requests.cocktails.cocktail + id)
|
||||||
|
.then(() => {
|
||||||
|
setRows(rows.filter((r) => r.id !== id))
|
||||||
|
createSuccess("Коктейль удален")
|
||||||
|
})
|
||||||
|
.catch(() => createError("Ошибка удаления коктейля"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async hiddenCocktail(id) {
|
||||||
|
return api().post(requests.cocktails.hide + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveChangeCocktail (cocktail, createError, createSuccess) {
|
||||||
|
api().patch(requests.cocktails.basic, cocktail)
|
||||||
|
.then((r) => {
|
||||||
|
if (!r.data.error) {
|
||||||
|
createSuccess("Сохранено")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
createError("Ошибка на сервере: " + r.data.error)
|
||||||
|
})
|
||||||
|
.catch(() => createError("Неизвестная ошибка"))
|
||||||
|
}
|
||||||
|
|
||||||
|
getOneCocktail (selected, setCocktail, getError, emptyCocktail) {
|
||||||
|
if (!selected) {
|
||||||
|
setCocktail(emptyCocktail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
api().get(requests.cocktails.cocktail + selected)
|
||||||
|
.then((r) => {
|
||||||
|
setCocktail(r.data)
|
||||||
|
})
|
||||||
|
.catch(() => getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
getSimpleList(setCocktails, setSelected, setLoading, createError, currentId) {
|
||||||
|
api().get(requests.cocktails.simple)
|
||||||
|
.then((r) => {
|
||||||
|
const arr = r.data.sort(getComparator("asc", "name"));
|
||||||
|
setCocktails(arr)
|
||||||
|
|
||||||
|
if (!currentId) {
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentCocktail = arr.find((r) => r.id === (currentId * 1));
|
||||||
|
if (!currentCocktail) {
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSelected(currentCocktail.id);
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(() => createError("Ошибка получения данных"))
|
||||||
|
}
|
||||||
|
|
||||||
|
getCocktailForModal (row, setLoading, setCocktail, closeCocktail, getError) {
|
||||||
|
setLoading(true)
|
||||||
|
if (!row) {
|
||||||
|
setLoading(false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
api().get(requests.cocktails.modal + row)
|
||||||
|
.then((r) => {
|
||||||
|
setCocktail(r.data)
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
getError();
|
||||||
|
setLoading(false)
|
||||||
|
closeCocktail();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
changeFavourite(value, id, newState, setRows, createSuccess, createError) {
|
||||||
|
const url = `${requests.cocktails.favourite}${id}`;
|
||||||
|
const request = value ? api().put(url) : api().delete(url);
|
||||||
|
|
||||||
|
request
|
||||||
|
.then(() => {
|
||||||
|
setRows(newState);
|
||||||
|
createSuccess("Спасибо за оценку!")
|
||||||
|
}).catch(() => createError("Ошибка сохранения"))
|
||||||
|
}
|
||||||
|
|
||||||
|
changeRating(id, newState, value, setRows, createSuccess, createError) {
|
||||||
|
api().post(`${requests.cocktails.rating}${id}&rating=${value}`)
|
||||||
|
.then(() => {
|
||||||
|
setRows(newState);
|
||||||
|
createSuccess("Спасибо за оценку!")
|
||||||
|
}).catch(() => createError("Ошибка сохранения"))
|
||||||
|
}
|
||||||
|
|
||||||
|
drinkCocktail(id, createSuccess, createError) {
|
||||||
|
api().post(`${requests.cocktails.drink}/${id}`)
|
||||||
|
.then(() => createSuccess("Бон аппетит"))
|
||||||
|
.catch(() => createError("Ошибка отметки коктейля"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cocktailClient = new CocktailClient();
|
||||||
17
front/src/lib/clients/GlassClient.js
Normal file
17
front/src/lib/clients/GlassClient.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import {api} from "./api";
|
||||||
|
import {requests} from "../../requests";
|
||||||
|
import {getComparator} from "../../components/core/getComparator";
|
||||||
|
|
||||||
|
class GlassClient {
|
||||||
|
|
||||||
|
getGlassList(setGlass, createError) {
|
||||||
|
api().get(requests.glass.list)
|
||||||
|
.then((r) => setGlass(r.data.sort(getComparator())
|
||||||
|
.map((item, i) => {
|
||||||
|
return {id: i, name: item}
|
||||||
|
})))
|
||||||
|
.catch(() => createError("Ошибка получения посуды"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const glassClient = new GlassClient();
|
||||||
112
front/src/lib/clients/IngredientClient.js
Normal file
112
front/src/lib/clients/IngredientClient.js
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import {api} from "./api";
|
||||||
|
import {requests} from "../../requests";
|
||||||
|
import {getComparator} from "../../components/core/getComparator";
|
||||||
|
|
||||||
|
class IngredientClient {
|
||||||
|
|
||||||
|
allList(currentId, setIngredients, setIngredient, createError) {
|
||||||
|
api().get(requests.ingredient.all)
|
||||||
|
.then((r) => {
|
||||||
|
const arr = r.data.sort(getComparator("asc", "name"));
|
||||||
|
setIngredients(arr)
|
||||||
|
|
||||||
|
if (!currentId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentIngredient = arr.find((r) => r.id === (currentId * 1));
|
||||||
|
if (!currentIngredient) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIngredient(currentIngredient);
|
||||||
|
})
|
||||||
|
.catch(() => createError("Ошибка получения данных"))
|
||||||
|
}
|
||||||
|
|
||||||
|
getType(setTypes) {
|
||||||
|
api().get(requests.ingredient.type)
|
||||||
|
.then((r) => setTypes(r.data.sort(getComparator("asc", "name"))))
|
||||||
|
}
|
||||||
|
|
||||||
|
findAll(setIngredients, createError) {
|
||||||
|
api().get(requests.ingredient.all)
|
||||||
|
.then((r) => setIngredients(r.data.sort(getComparator("asc", "name"))))
|
||||||
|
.catch(() => createError("Ошибка получения списка ингредиентов"))
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllIngredients(setIngredients, setLoading, createError) {
|
||||||
|
api().get(requests.ingredient.all)
|
||||||
|
.then((r) => {
|
||||||
|
setIngredients(r.data)
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
createError("Ошибка получения списка ингредиентов");
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
changeIngredientIsHave(id, value, state, setIngredients, createError) {
|
||||||
|
const url = `${requests.ingredient.crud}?id=${id}`;
|
||||||
|
const request = value ? api().put(url) : api().delete(url);
|
||||||
|
request
|
||||||
|
.then(() => {
|
||||||
|
setIngredients(state);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
createError("Ошибка изменения ингредиента");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteIngredientIsHave(id, createSuccess, createError) {
|
||||||
|
api().delete(`${requests.ingredient.crud}/${id}`)
|
||||||
|
.then(() => createSuccess("Ингредиент удален"))
|
||||||
|
.catch(() => createError("Ошибка удаления ингредиента. Перезагрузите страницу"))
|
||||||
|
}
|
||||||
|
|
||||||
|
saveIngredient(ingredient, createSuccess, createError) {
|
||||||
|
api().patch(requests.ingredient.crud, ingredient)
|
||||||
|
.then(() => createSuccess("Ингредиент сохранен"))
|
||||||
|
.catch(() => createError("Ошибка сохранения"))
|
||||||
|
}
|
||||||
|
|
||||||
|
findOne(id, selectIngredient, createError) {
|
||||||
|
api().get(`${requests.ingredient.crud}?id=${id}`)
|
||||||
|
.then((r) => {
|
||||||
|
selectIngredient(r.data)
|
||||||
|
})
|
||||||
|
.catch(() => createError("Ошибка получения информации об ингредиенте"))
|
||||||
|
}
|
||||||
|
|
||||||
|
changeIngredientInBar(ingredient, cocktail, setCocktail, createSuccess, createError) {
|
||||||
|
const url = `${requests.ingredient.crud}?id=${ingredient.id}`;
|
||||||
|
const request = ingredient.isHave ? api().delete(url) : api().put(url);
|
||||||
|
const value = !ingredient.isHave;
|
||||||
|
request.then(() => {
|
||||||
|
const newReceipts = cocktail.receipt.map((r) => {
|
||||||
|
if (r.ingredient.id !== ingredient.id) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...r,
|
||||||
|
ingredient: {
|
||||||
|
...ingredient,
|
||||||
|
isHave: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setCocktail({
|
||||||
|
...cocktail,
|
||||||
|
receipt: newReceipts
|
||||||
|
})
|
||||||
|
createSuccess("Сохранено")
|
||||||
|
}).catch(() => createError("Ошибка сохранения"))
|
||||||
|
}
|
||||||
|
|
||||||
|
findUnit(setUnits, createError) {
|
||||||
|
api().get(requests.unit)
|
||||||
|
.then((r) => setUnits(r.data.sort(getComparator("asc", "name"))))
|
||||||
|
.catch(() => createError("Ошибка получения единиц измерения"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ingredientClient = new IngredientClient()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import {decodeToken, isExpired} from "react-jwt";
|
import {decodeToken, isExpired} from "react-jwt";
|
||||||
import {requests} from "../requests";
|
import {requests} from "../../requests";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
class TokenUtil {
|
class TokenUtil {
|
||||||
@@ -5,7 +5,7 @@ class UserClient {
|
|||||||
|
|
||||||
async getMe() {
|
async getMe() {
|
||||||
try{
|
try{
|
||||||
let url = requests.users.getMe
|
let url = requests.auth.getMe
|
||||||
const response = await api().get(url);
|
const response = await api().get(url);
|
||||||
return {data: response.data}
|
return {data: response.data}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {tokenUtil} from "../TokenUtil";
|
import {tokenUtil} from "./TokenUtil";
|
||||||
|
|
||||||
const host = "localhost:8080"; //дебаг вместе с беком
|
// const host = "localhost:8080"; //дебаг вместе с беком
|
||||||
// const host = "192.168.1.100:8091"; //дебаг фронта
|
// const host = "192.168.1.100:8091"; //дебаг фронта
|
||||||
// const host = "bar.kayashov.keenetic.pro"; //прод
|
const host = "bar.kayashov.keenetic.pro"; //прод
|
||||||
export const api = () => {
|
export const api = () => {
|
||||||
const result = axios;
|
const result = axios;
|
||||||
result.defaults.baseURL = `${window.location.protocol}//${host}/`;
|
result.defaults.baseURL = `${window.location.protocol}//${host}/`;
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
export const sliceData = (rows, page, elementOnPage) => {
|
|
||||||
if (!rows || rows.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxPage = Math.ceil(rows.length / elementOnPage);
|
|
||||||
// const start = (page - 1) * elementOnPage;
|
|
||||||
const start = 0;
|
|
||||||
console.log(maxPage, start)
|
|
||||||
let end;
|
|
||||||
if (page === maxPage) {
|
|
||||||
end = rows.length;
|
|
||||||
} else {
|
|
||||||
end = start + elementOnPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rows.slice(start, end);
|
|
||||||
}
|
|
||||||
@@ -5,5 +5,6 @@ export const navItems = [
|
|||||||
{key: 'barList', title: 'Список баров', href: paths.bar.list, icon: 'basket', forBarmen: true},
|
{key: 'barList', title: 'Список баров', href: paths.bar.list, icon: 'basket', forBarmen: true},
|
||||||
{key: 'ingredients', title: 'Список ингредиентов', href: paths.bar.ingredients, 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: 'ingredientEdit', title: 'Ингредиенты', href: paths.bar.ingredientEdit, icon: 'ingredients', forAdmin: true},
|
||||||
{key: 'cocktailEdit', title: 'Коктейли', href: paths.bar.cocktailEdit, icon: 'cocktail', forAdmin: true}
|
{key: 'cocktailEdit', title: 'Коктейли', href: paths.bar.cocktailEdit, icon: 'cocktail', forAdmin: true},
|
||||||
|
{key: 'calc', title: 'Калькулятор', href: paths.bar.calc, icon: 'calc', forAdmin: true},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ export const paths = {
|
|||||||
cocktails: "/cocktails",
|
cocktails: "/cocktails",
|
||||||
ingredientEdit: '/ingredients/edit',
|
ingredientEdit: '/ingredients/edit',
|
||||||
cocktailEdit: '/cocktail/edit',
|
cocktailEdit: '/cocktail/edit',
|
||||||
menu: '/menuList'
|
menu: '/menuList',
|
||||||
|
calc: '/calc',
|
||||||
},
|
},
|
||||||
errors: {notFound: '/errors/not-found'},
|
errors: {notFound: '/errors/not-found'},
|
||||||
notFound: '*',
|
notFound: '*',
|
||||||
|
|||||||
@@ -2,70 +2,52 @@ const host = "api/";
|
|||||||
|
|
||||||
const routes = {
|
const routes = {
|
||||||
auth: host + "auth/",
|
auth: host + "auth/",
|
||||||
users: host + "users/",
|
|
||||||
operations: host + "operations/",
|
|
||||||
bar: host + "bar/",
|
bar: host + "bar/",
|
||||||
session: host + "bar/session",
|
category: host + "category",
|
||||||
|
cocktail: host + "cocktail",
|
||||||
|
glass: host + "glass",
|
||||||
ingredient: host + "ingredient",
|
ingredient: host + "ingredient",
|
||||||
order: host + "order",
|
receipt: host + "receipt",
|
||||||
cocktails: host + "cocktail",
|
unit: host + "unit",
|
||||||
visitor: host + "visitors"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const requests = {
|
export const requests = {
|
||||||
auth: {
|
auth: {
|
||||||
login: routes.auth + "login",
|
login: routes.auth + "login",
|
||||||
refresh: routes.auth + "refresh",
|
refresh: routes.auth + "refresh",
|
||||||
singOut: "signOut"
|
singOut: "signOut",
|
||||||
},
|
getMe: routes.auth + "getMe",
|
||||||
cocktails: {
|
|
||||||
menu: routes.cocktails + "/menu",
|
|
||||||
simple: routes.cocktails + "/simple",
|
|
||||||
cocktail: routes.cocktails + "?id=",
|
|
||||||
modal: routes.cocktails + "/modal?id=",
|
|
||||||
edit: routes.cocktails,
|
|
||||||
savePhoto: routes.cocktails + "/photo",
|
|
||||||
favourite: routes.cocktails + "/favourite?id=",
|
|
||||||
rating: routes.cocktails + "/rating?id=",
|
|
||||||
receipts: routes.cocktails + "/receipts?id=",
|
|
||||||
byIngredient: routes.cocktails + "/byIngredient?id=",
|
|
||||||
instructions: routes.cocktails + "/instructions?id="
|
|
||||||
},
|
|
||||||
visitors: {
|
|
||||||
all: routes.visitor,
|
|
||||||
invite: routes.visitor + "/invite?"
|
|
||||||
},
|
},
|
||||||
bar: {
|
bar: {
|
||||||
list: routes.bar + "all",
|
|
||||||
change: routes.bar + "change",
|
|
||||||
crud: routes.bar,
|
crud: routes.bar,
|
||||||
addToMyList: routes.bar + "addToMyList",
|
all: routes.bar + "all",
|
||||||
enter: routes.bar + "enter?id=",
|
change: routes.bar + "change",
|
||||||
pay: routes.order + "?",
|
},
|
||||||
order: routes.order,
|
category: {
|
||||||
myOrders: routes.order + "/my",
|
basic: routes.category,
|
||||||
purchases: routes.bar + "purchases",
|
},
|
||||||
menu: routes.bar + "menu",
|
cocktails: {
|
||||||
ingredients: routes.ingredient,
|
menu: routes.cocktail + "/menu",
|
||||||
ingredientSimple: routes.ingredient + "/simple",
|
calc: routes.cocktail + "/calc",
|
||||||
ingredient: routes.ingredient,
|
byIngredient: routes.cocktail + "/byIngredient?id=",
|
||||||
ingredientList: routes.ingredient + "/all",
|
photo: routes.cocktail + "/photo",
|
||||||
glass: routes.bar + "glass",
|
cocktail: routes.cocktail + "?id=",
|
||||||
category: routes.bar + "category",
|
basic: routes.cocktail,
|
||||||
receipts: routes.bar + "receipt?id=",
|
simple: routes.cocktail + "/simple",
|
||||||
tags: routes.bar + "tags",
|
modal: routes.cocktail + "/modal?id=",
|
||||||
|
favourite: routes.cocktail + "/favourite?id=",
|
||||||
|
rating: routes.cocktail + "/rating?id=",
|
||||||
|
drink: routes.cocktail + "/drink",
|
||||||
|
hide: routes.cocktail + "/hidden/",
|
||||||
|
},
|
||||||
|
glass: {
|
||||||
|
list: routes.glass,
|
||||||
|
},
|
||||||
|
ingredient: {
|
||||||
|
all: routes.ingredient + "/all",
|
||||||
|
simple: routes.ingredient + "/simple",
|
||||||
type: routes.ingredient + "/type",
|
type: routes.ingredient + "/type",
|
||||||
session: {
|
crud: routes.ingredient,
|
||||||
status: routes.session + "/info",
|
|
||||||
change: routes.session
|
|
||||||
},
|
|
||||||
unit: routes.bar + "units"
|
|
||||||
},
|
},
|
||||||
users: {
|
unit: routes.unit + "/units"
|
||||||
getMe: routes.bar + "getMe",
|
|
||||||
},
|
|
||||||
operations: {
|
|
||||||
getAll: routes.operations,
|
|
||||||
create: routes.operations,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import io.jsonwebtoken.Claims;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestHeader;
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
@@ -11,11 +12,18 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import ru.kayashov.bar.controller.dto.AuthRequestDto;
|
import ru.kayashov.bar.controller.dto.AuthRequestDto;
|
||||||
import ru.kayashov.bar.controller.dto.AuthResponseDto;
|
import ru.kayashov.bar.controller.dto.AuthResponseDto;
|
||||||
|
import ru.kayashov.bar.controller.dto.VisitorResponseDto;
|
||||||
|
import ru.kayashov.bar.model.entity.Event;
|
||||||
|
import ru.kayashov.bar.model.entity.EventType;
|
||||||
import ru.kayashov.bar.model.entity.Visitor;
|
import ru.kayashov.bar.model.entity.Visitor;
|
||||||
import ru.kayashov.bar.repository.VisitorsRepository;
|
import ru.kayashov.bar.repository.VisitorsRepository;
|
||||||
import ru.kayashov.bar.security.JwtTokenProvider;
|
import ru.kayashov.bar.security.JwtTokenProvider;
|
||||||
|
import ru.kayashov.bar.service.EventService;
|
||||||
|
import ru.kayashov.bar.service.VisitorService;
|
||||||
|
|
||||||
|
import javax.annotation.security.PermitAll;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -28,53 +36,47 @@ public class AuthController {
|
|||||||
private final JwtTokenProvider jwtTokenProvider;
|
private final JwtTokenProvider jwtTokenProvider;
|
||||||
private final VisitorsRepository visitorsRepository;
|
private final VisitorsRepository visitorsRepository;
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final VisitorService visitorService;
|
||||||
|
private final EventService eventService;
|
||||||
|
|
||||||
|
@PermitAll
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public AuthResponseDto checkTelegramChat(@RequestBody AuthRequestDto dto) {
|
public AuthResponseDto checkTelegramChat(@RequestBody AuthRequestDto dto) {
|
||||||
|
AuthResponseDto responseDto;
|
||||||
|
Visitor visitor = null;
|
||||||
if (dto.getByLogin()) {
|
if (dto.getByLogin()) {
|
||||||
return checkLogin(dto.getLogin(), dto.getPassword());
|
String login = dto.getLogin();
|
||||||
|
String password = dto.getPassword();
|
||||||
|
if (login == null || login.isEmpty() || password == null || password.isEmpty()) {
|
||||||
|
return new AuthResponseDto(null, "Поля не могут быть пустые");
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Visitor> visitorOpt = visitorsRepository.findByLogin(login);
|
||||||
|
if (visitorOpt.isEmpty()) {
|
||||||
|
responseDto = new AuthResponseDto(null, "Не найдет пользователь " + login);
|
||||||
|
} else {
|
||||||
|
visitor = visitorOpt.get();
|
||||||
|
responseDto = checkLogin(visitor, dto.getPassword());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return parseCode(dto.getCode());
|
String decode = new String(Base64.getDecoder().decode(dto.getCode()), StandardCharsets.UTF_8);
|
||||||
}
|
String[] decodeArr = decode.split(":");
|
||||||
}
|
visitor = visitorsRepository.findById(Long.valueOf(decodeArr[0]))
|
||||||
|
.orElseThrow();
|
||||||
private AuthResponseDto parseCode(String code) {
|
responseDto = parseCode(Integer.valueOf(decodeArr[1]), visitor);
|
||||||
String decode = new String(Base64.getDecoder().decode(code), StandardCharsets.UTF_8);
|
|
||||||
String[] decodeArr = decode.split(":");
|
|
||||||
Visitor visitor = visitorsRepository.findById(Long.valueOf(decodeArr[0]))
|
|
||||||
.orElseThrow();
|
|
||||||
|
|
||||||
log.info("Попытка авторизации пользователя {}", visitor.getId());
|
|
||||||
Integer visitorCode = visitor.getCode();
|
|
||||||
if (visitorCode == null) {
|
|
||||||
return new AuthResponseDto(null, "Повторите запрос кода из бота");
|
|
||||||
}
|
|
||||||
if (Integer.valueOf(decodeArr[1]).equals(visitor.getCode())) {
|
|
||||||
visitor.setCode(null);
|
|
||||||
visitor = visitorsRepository.save(visitor);
|
|
||||||
return new AuthResponseDto(jwtTokenProvider.generateToken(visitor), null);
|
|
||||||
}
|
|
||||||
return new AuthResponseDto(null, "Неверный код подтверждения");
|
|
||||||
}
|
|
||||||
|
|
||||||
private AuthResponseDto checkLogin(String login, String password) {
|
|
||||||
if (login == null || login.isEmpty() || password == null || password.isEmpty()) {
|
|
||||||
return new AuthResponseDto(null, "Поля не могут быть пустые");
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<Visitor> visitorOpt = visitorsRepository.findByLogin(login);
|
|
||||||
if (visitorOpt.isEmpty()) {
|
|
||||||
return new AuthResponseDto(null, "Не найдет пользователь " + login);
|
|
||||||
}
|
|
||||||
Visitor visitor = visitorOpt.get();
|
|
||||||
log.info("Попытка авторизации пользователя {}", visitor.getId());
|
|
||||||
if (passwordEncoder.matches(password, visitor.getPassword())) {
|
|
||||||
return new AuthResponseDto(jwtTokenProvider.generateToken(visitor), null);
|
|
||||||
} else {
|
|
||||||
return new AuthResponseDto(null, "Неверный логин или пароль");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eventService.createEvent(Event.builder()
|
||||||
|
.date(LocalDateTime.now())
|
||||||
|
.type(EventType.LOGIN)
|
||||||
|
.newState(visitor != null ? visitor.getName() : null)
|
||||||
|
.oldState(responseDto.getError() != null ? responseDto.getError() : "Выполнен вход")
|
||||||
|
.build());
|
||||||
|
|
||||||
|
return responseDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PermitAll
|
||||||
@PostMapping("refresh")
|
@PostMapping("refresh")
|
||||||
public AuthResponseDto refreshToken(@RequestHeader("Authorization") String token) {
|
public AuthResponseDto refreshToken(@RequestHeader("Authorization") String token) {
|
||||||
Claims claims = jwtTokenProvider.extractAllClaims(token);
|
Claims claims = jwtTokenProvider.extractAllClaims(token);
|
||||||
@@ -84,4 +86,38 @@ public class AuthController {
|
|||||||
return new AuthResponseDto(jwtTokenProvider.generateToken(visitor), null);
|
return new AuthResponseDto(jwtTokenProvider.generateToken(visitor), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/getMe")
|
||||||
|
public VisitorResponseDto getMe() {
|
||||||
|
Visitor visitor = visitorService.getCurrentVisitor();
|
||||||
|
VisitorResponseDto dto = VisitorResponseDto.mapToDto(visitor, true, visitor.getRole().toString(), true);
|
||||||
|
log.info("Запрос информации о пользователе: {}-{} {}, вошел в бар",
|
||||||
|
dto.getId(),
|
||||||
|
dto.getName().strip(),
|
||||||
|
dto.getLastName() != null ? dto.getLastName().strip() : "");
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthResponseDto checkLogin(Visitor visitor, String password) {
|
||||||
|
log.info("Попытка авторизации пользователя {}", visitor.getId());
|
||||||
|
if (passwordEncoder.matches(password, visitor.getPassword())) {
|
||||||
|
return new AuthResponseDto(jwtTokenProvider.generateToken(visitor), null);
|
||||||
|
} else {
|
||||||
|
return new AuthResponseDto(null, "Неверный логин или пароль");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthResponseDto parseCode(Integer code, Visitor visitor) {
|
||||||
|
log.info("Попытка авторизации пользователя {}", visitor.getId());
|
||||||
|
Integer visitorCode = visitor.getCode();
|
||||||
|
if (visitorCode == null) {
|
||||||
|
return new AuthResponseDto(null, "Повторите запрос кода из бота");
|
||||||
|
}
|
||||||
|
if (code.equals(visitor.getCode())) {
|
||||||
|
visitor.setCode(null);
|
||||||
|
visitor = visitorsRepository.save(visitor);
|
||||||
|
return new AuthResponseDto(jwtTokenProvider.generateToken(visitor), null);
|
||||||
|
}
|
||||||
|
return new AuthResponseDto(null, "Неверный код подтверждения");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,82 +8,43 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import ru.kayashov.bar.controller.dto.VisitorResponseDto;
|
|
||||||
import ru.kayashov.bar.controller.dto.bar.BarResponseDto;
|
import ru.kayashov.bar.controller.dto.bar.BarResponseDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
|
import ru.kayashov.bar.service.BarService;
|
||||||
import ru.kayashov.bar.model.entity.Category;
|
|
||||||
import ru.kayashov.bar.model.entity.Glass;
|
|
||||||
import ru.kayashov.bar.model.entity.Unit;
|
|
||||||
import ru.kayashov.bar.model.entity.UserRole;
|
|
||||||
import ru.kayashov.bar.model.entity.Visitor;
|
|
||||||
import ru.kayashov.bar.repository.UnitRepository;
|
|
||||||
import ru.kayashov.bar.service.SessionService;
|
|
||||||
import ru.kayashov.bar.service.VisitorService;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@CrossOrigin(origins = {"*"})
|
@CrossOrigin(origins = {"*"})
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/bar/")
|
@RequestMapping("/api/bar")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class BarController {
|
public class BarController {
|
||||||
|
|
||||||
private final SessionService sessionService;
|
private final BarService barService;
|
||||||
private final VisitorService visitorService;
|
|
||||||
private final UnitRepository unitRepository;
|
|
||||||
|
|
||||||
@GetMapping("/units")
|
|
||||||
public List<Unit> getUnitList() {
|
|
||||||
return unitRepository.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/glass")
|
|
||||||
public List<String> getGlass() {
|
|
||||||
return Arrays.stream(Glass.values()).map(Glass::getName).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/category")
|
|
||||||
public List<String> getCategory() {
|
|
||||||
return Arrays.stream(Category.values()).map(Category::getName).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/receipt")
|
|
||||||
public List<ReceiptResponseDto> getReceipt(@RequestParam("id") Long id) {
|
|
||||||
return sessionService.getReceiptList(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/change/{id}")
|
@PostMapping("/change/{id}")
|
||||||
public void changeActiveBar(@PathVariable Long id) {
|
public void changeActiveBar(@PathVariable Long id) {
|
||||||
sessionService.changeActiveBar(id);
|
barService.changeActiveBar(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/copy/{id}/{name}")
|
||||||
|
public BarResponseDto copyActiveBar(@PathVariable Long id, @PathVariable String name) {
|
||||||
|
return barService.copyBar(id, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void deleteBar(@PathVariable Long id) {
|
public void deleteBar(@PathVariable Long id) {
|
||||||
sessionService.deleteBar(id);
|
barService.deleteBar(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{name}")
|
@PostMapping("/{name}")
|
||||||
public BarResponseDto createBar(@PathVariable String name) {
|
public BarResponseDto createBar(@PathVariable String name) {
|
||||||
return sessionService.createBar(name);
|
return barService.createBar(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/all")
|
@GetMapping("/all")
|
||||||
public List<BarResponseDto> getAll() {
|
public List<BarResponseDto> getAll() {
|
||||||
return sessionService.findAllBar();
|
return barService.findAllBar();
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/getMe")
|
|
||||||
public VisitorResponseDto getMe() {
|
|
||||||
Visitor visitor = visitorService.getCurrentVisitor();
|
|
||||||
VisitorResponseDto dto = VisitorResponseDto.mapToDto(visitor, true, visitor.getRole().toString(), true);
|
|
||||||
log.info("Запрос информации о пользователе: {}-{} {}, вошел в бар",
|
|
||||||
dto.getId(),
|
|
||||||
dto.getName().strip(),
|
|
||||||
dto.getLastName() != null ? dto.getLastName().strip() : "");
|
|
||||||
return dto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package ru.kayashov.bar.controller;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.kayashov.bar.model.entity.Category;
|
||||||
|
|
||||||
|
import javax.annotation.security.PermitAll;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@CrossOrigin(origins = {"*"})
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/category")
|
||||||
|
public class CategoryController {
|
||||||
|
|
||||||
|
@PermitAll
|
||||||
|
@GetMapping
|
||||||
|
public List<String> getCategory() {
|
||||||
|
return Arrays.stream(Category.values()).map(Category::getName).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,11 +3,11 @@ package ru.kayashov.bar.controller;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PatchMapping;
|
import org.springframework.web.bind.annotation.PatchMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
@@ -15,16 +15,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import ru.kayashov.bar.controller.dto.ErrorDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.CocktailFilterRequestDto;
|
import ru.kayashov.bar.controller.dto.cocktail.CocktailFilterRequestDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.CocktailForIngredientModalDto;
|
import ru.kayashov.bar.controller.dto.cocktail.CocktailForIngredientModalDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.CocktailForListResponseDto;
|
import ru.kayashov.bar.controller.dto.cocktail.CocktailForListResponseDto;
|
||||||
import ru.kayashov.bar.controller.dto.ErrorDto;
|
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.CocktailModalDto;
|
import ru.kayashov.bar.controller.dto.cocktail.CocktailModalDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.CocktailSimpleResponseDto;
|
import ru.kayashov.bar.controller.dto.cocktail.CocktailSimpleResponseDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
|
|
||||||
import ru.kayashov.bar.model.entity.Visitor;
|
|
||||||
import ru.kayashov.bar.service.CocktailService;
|
import ru.kayashov.bar.service.CocktailService;
|
||||||
|
|
||||||
|
import javax.annotation.security.PermitAll;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -39,14 +38,15 @@ public class CocktailController {
|
|||||||
private final CocktailService cocktailService;
|
private final CocktailService cocktailService;
|
||||||
|
|
||||||
//получить все
|
//получить все
|
||||||
|
@PermitAll
|
||||||
@PostMapping("menu")
|
@PostMapping("menu")
|
||||||
public List<CocktailForListResponseDto> menu(@RequestBody CocktailFilterRequestDto dto) {
|
public List<CocktailForListResponseDto> menu(@RequestBody CocktailFilterRequestDto dto) {
|
||||||
return cocktailService.getMenu(dto);
|
return cocktailService.getMenu(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/instructions")
|
@GetMapping("calc")
|
||||||
public String getInstructions(@RequestParam("id") Long id) {
|
public List<CocktailForListResponseDto> calc() {
|
||||||
return cocktailService.findInstructions(id);
|
return cocktailService.calc();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/byIngredient")
|
@GetMapping("/byIngredient")
|
||||||
@@ -56,12 +56,17 @@ public class CocktailController {
|
|||||||
|
|
||||||
@PostMapping("/photo")
|
@PostMapping("/photo")
|
||||||
public String savePhoto(@RequestBody MultipartFile file) throws IOException {
|
public String savePhoto(@RequestBody MultipartFile file) throws IOException {
|
||||||
if(file == null) {
|
if (file == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return cocktailService.savePhoto(file);
|
return cocktailService.savePhoto(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/hidden/{id}")
|
||||||
|
public void hiddenCocktail(@PathVariable Long id) {
|
||||||
|
cocktailService.hiddenCocktail(id);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public CocktailForListResponseDto getOne(@RequestParam Long id) {
|
public CocktailForListResponseDto getOne(@RequestParam Long id) {
|
||||||
return cocktailService.findById(id);
|
return cocktailService.findById(id);
|
||||||
@@ -72,11 +77,6 @@ public class CocktailController {
|
|||||||
return cocktailService.getSimple();
|
return cocktailService.getSimple();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/receipts")
|
|
||||||
public List<ReceiptResponseDto> getReceipts(@RequestParam Long id) {
|
|
||||||
return cocktailService.getReceipts(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/modal")
|
@GetMapping("/modal")
|
||||||
public CocktailModalDto getForModal(@RequestParam Long id) {
|
public CocktailModalDto getForModal(@RequestParam Long id) {
|
||||||
return cocktailService.getForModal(id);
|
return cocktailService.getForModal(id);
|
||||||
@@ -112,4 +112,9 @@ public class CocktailController {
|
|||||||
public void addRating(@RequestParam("id") Long id, @RequestParam("rating") Integer rating) {
|
public void addRating(@RequestParam("id") Long id, @RequestParam("rating") Integer rating) {
|
||||||
cocktailService.setRating(id, rating);
|
cocktailService.setRating(id, rating);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/drink/{id}")
|
||||||
|
public void drinkCocktail(@PathVariable Long id) {
|
||||||
|
cocktailService.drink(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package ru.kayashov.bar.controller;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.kayashov.bar.model.entity.Glass;
|
||||||
|
|
||||||
|
import javax.annotation.security.PermitAll;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@CrossOrigin(origins = {"*"})
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/glass")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class GlassController {
|
||||||
|
|
||||||
|
@PermitAll
|
||||||
|
@GetMapping
|
||||||
|
public List<String> getGlass() {
|
||||||
|
return Arrays.stream(Glass.values()).map(Glass::getName).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,8 @@ public class IngredientController {
|
|||||||
return ingredientService.getAllSimple();
|
return ingredientService.getAllSimple();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo: перевести на enum
|
||||||
|
@Deprecated
|
||||||
@GetMapping("/type")
|
@GetMapping("/type")
|
||||||
public List<TypeResponseDto> getTypes() {
|
public List<TypeResponseDto> getTypes() {
|
||||||
return typeRepository.findAll().stream()
|
return typeRepository.findAll().stream()
|
||||||
|
|||||||
29
src/main/java/ru/kayashov/bar/controller/UnitController.java
Normal file
29
src/main/java/ru/kayashov/bar/controller/UnitController.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package ru.kayashov.bar.controller;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.kayashov.bar.model.entity.Unit;
|
||||||
|
import ru.kayashov.bar.repository.UnitRepository;
|
||||||
|
|
||||||
|
import javax.annotation.security.PermitAll;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@CrossOrigin(origins = {"*"})
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/unit")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UnitController {
|
||||||
|
|
||||||
|
private final UnitRepository unitRepository;
|
||||||
|
|
||||||
|
@PermitAll
|
||||||
|
@GetMapping("/units")
|
||||||
|
public List<Unit> getUnitList() {
|
||||||
|
return unitRepository.findAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ public class VisitorResponseDto {
|
|||||||
private String lastName;
|
private String lastName;
|
||||||
private Boolean invited;
|
private Boolean invited;
|
||||||
private Boolean isActive;
|
private Boolean isActive;
|
||||||
|
private String image;
|
||||||
private String role;
|
private String role;
|
||||||
|
|
||||||
public static VisitorResponseDto mapToDto(Visitor e) {
|
public static VisitorResponseDto mapToDto(Visitor e) {
|
||||||
@@ -21,8 +22,8 @@ public class VisitorResponseDto {
|
|||||||
d.setId(e.getId());
|
d.setId(e.getId());
|
||||||
d.setName(e.getName());
|
d.setName(e.getName());
|
||||||
d.setLastName(e.getLastName());
|
d.setLastName(e.getLastName());
|
||||||
// d.setInvited(e.getInvited());
|
d.setRole(e.getRole().toString());
|
||||||
// d.setRole(e.getRole().toString());
|
d.setImage(e.getImage());
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import java.util.List;
|
|||||||
@Setter
|
@Setter
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class CocktailFilterRequestDto {
|
public class CocktailFilterRequestDto {
|
||||||
private String search;
|
private String search = "";
|
||||||
private Boolean onlyFavourite;
|
private Boolean onlyFavourite;
|
||||||
private List<String> glass;
|
private List<String> glass;
|
||||||
private List<String> category;
|
private List<String> category;
|
||||||
|
|||||||
@@ -37,27 +37,4 @@ public class CocktailForListResponseDto {
|
|||||||
private List<ReceiptResponseDto> receipt;
|
private List<ReceiptResponseDto> receipt;
|
||||||
|
|
||||||
private RatingResponseDto rating;
|
private RatingResponseDto rating;
|
||||||
|
|
||||||
public static CocktailForListResponseDto mapToDto(CocktailEntity e, Long visitorId) {
|
|
||||||
CocktailForListResponseDto d = new CocktailForListResponseDto();
|
|
||||||
d.setId(e.getId());
|
|
||||||
d.setName(e.getName());
|
|
||||||
d.setImage(e.getImage());
|
|
||||||
d.setVideo(e.getVideo());
|
|
||||||
d.setInstructions(e.getInstructions());
|
|
||||||
|
|
||||||
d.setCategory(e.getCategory().getName());
|
|
||||||
d.setAlcoholic(e.getAlcoholic().getValue());
|
|
||||||
d.setGlass(e.getGlass().getName());
|
|
||||||
|
|
||||||
String components = e.getReceipt().stream().map(r -> r.getIngredient().getName()).collect(Collectors.joining(", "));
|
|
||||||
d.setComponents(components);
|
|
||||||
d.setReceipt(e.getReceipt().stream().map(ReceiptResponseDto::mapToDto).toList());
|
|
||||||
|
|
||||||
RatingResponseDto rating = new RatingResponseDto();
|
|
||||||
rating.setFavourite(e.getIsFavorite());
|
|
||||||
rating.setRating(e.getRating());
|
|
||||||
d.setRating(rating);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import ru.kayashov.bar.model.entity.IngredientEntity;
|
|||||||
public class IngredientResponseDto {
|
public class IngredientResponseDto {
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
// private String enName;
|
|
||||||
private Boolean alcohol;
|
private Boolean alcohol;
|
||||||
private Integer abv;
|
private Integer abv;
|
||||||
private boolean isHave;
|
private boolean isHave;
|
||||||
@@ -29,12 +28,11 @@ public class IngredientResponseDto {
|
|||||||
.builder()
|
.builder()
|
||||||
.id(i.getId())
|
.id(i.getId())
|
||||||
.name(i.getName())
|
.name(i.getName())
|
||||||
// .enName(i.getEnName())
|
|
||||||
.alcohol(i.getAlcohol())
|
.alcohol(i.getAlcohol())
|
||||||
.type(i.getType() != null ? i.getType().getName() : null)
|
.type(i.getType() != null ? i.getType().getName() : null)
|
||||||
.abv(i.getAbv())
|
.abv(i.getAbv())
|
||||||
// .isHave(i.getIsHave())
|
.isHave(i.getIsHave())
|
||||||
.image("https://thecocktaildb.com/images/ingredients/" + i.getEnName() + "-Medium.png")
|
.image(i.getImage())
|
||||||
.description(i.getDescription())
|
.description(i.getDescription())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,12 @@ import ru.kayashov.bar.model.entity.IngredientEntity;
|
|||||||
public class IngredientSimpleResponseDto {
|
public class IngredientSimpleResponseDto {
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
|
private String image;
|
||||||
private Boolean isHave;
|
private Boolean isHave;
|
||||||
|
|
||||||
public static IngredientSimpleResponseDto mapToDto(IngredientEntity ingredient) {
|
public static IngredientSimpleResponseDto mapToDto(IngredientEntity ingredient) {
|
||||||
return new IngredientSimpleResponseDto(ingredient.getId(), ingredient.getName(), false/*ingredient.getIsHave()*/);
|
return new IngredientSimpleResponseDto(ingredient.getId(), ingredient.getName(),
|
||||||
|
ingredient.getImage(),
|
||||||
|
ingredient.getIsHave());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package ru.kayashov.bar.mapper;
|
package ru.kayashov.bar.mapper;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -10,15 +12,12 @@ import ru.kayashov.bar.controller.dto.cocktail.CocktailModalDto;
|
|||||||
import ru.kayashov.bar.controller.dto.cocktail.RatingResponseDto;
|
import ru.kayashov.bar.controller.dto.cocktail.RatingResponseDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
|
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
|
||||||
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
||||||
import ru.kayashov.bar.model.entity.BarEntity;
|
|
||||||
import ru.kayashov.bar.model.entity.CocktailEntity;
|
import ru.kayashov.bar.model.entity.CocktailEntity;
|
||||||
import ru.kayashov.bar.model.entity.IngredientEntity;
|
import ru.kayashov.bar.model.entity.IngredientEntity;
|
||||||
import ru.kayashov.bar.model.entity.ReceiptEntity;
|
import ru.kayashov.bar.model.entity.ReceiptEntity;
|
||||||
import ru.kayashov.bar.model.entity.Visitor;
|
import ru.kayashov.bar.model.entity.Visitor;
|
||||||
import ru.kayashov.bar.repository.BarEntityRepository;
|
|
||||||
import ru.kayashov.bar.repository.VisitorsRepository;
|
import ru.kayashov.bar.repository.VisitorsRepository;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -27,25 +26,15 @@ import java.util.stream.Collectors;
|
|||||||
public class CocktailMapper {
|
public class CocktailMapper {
|
||||||
|
|
||||||
private final VisitorsRepository visitorsRepository;
|
private final VisitorsRepository visitorsRepository;
|
||||||
private final BarEntityRepository barRepository;
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public List<CocktailForListResponseDto> cocktailsToDtoList(List<CocktailEntity> cocktails, Boolean all) {
|
public List<CocktailForListResponseDto> cocktailsToDtoList(List<CocktailEntity> cocktails, Boolean all, boolean withReceipts) {
|
||||||
Visitor visitor = getCurrentVisitor();
|
|
||||||
// if(checkUserNotInBar(visitor)) {
|
|
||||||
// return new ArrayList<>();
|
|
||||||
// }
|
|
||||||
List<Long> barStopList = new ArrayList<>();
|
|
||||||
List<Long> allowedIngredients = getAllowedIngredients();
|
|
||||||
return cocktails.stream()
|
return cocktails.stream()
|
||||||
.map(c -> cocktailToDto(c, visitor, allowedIngredients, barStopList))
|
.map(c -> cocktailToDto(c, withReceipts))
|
||||||
// .filter(c -> all || c.getIsAllowed())
|
|
||||||
// .filter(c -> all || c.getInMenu())
|
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CocktailForListResponseDto cocktailToFullDto(CocktailEntity e) {
|
public CocktailForListResponseDto cocktailToFullDto(CocktailEntity e) {
|
||||||
List<Long> allowed = getAllowedIngredients();
|
|
||||||
return CocktailForListResponseDto.builder()
|
return CocktailForListResponseDto.builder()
|
||||||
.id(e.getId())
|
.id(e.getId())
|
||||||
.name(e.getName())
|
.name(e.getName())
|
||||||
@@ -55,11 +44,11 @@ public class CocktailMapper {
|
|||||||
.glass(e.getGlass().getName())
|
.glass(e.getGlass().getName())
|
||||||
.instructions(e.getInstructions())
|
.instructions(e.getInstructions())
|
||||||
.video(e.getVideo())
|
.video(e.getVideo())
|
||||||
.receipt(createReceiptDtoList(e.getReceipt(), allowed))
|
.receipt(createReceiptDtoList(e.getReceipt()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CocktailForListResponseDto cocktailToDto(CocktailEntity e, Visitor visitor, List<Long> allowedIngredients, List<Long> barStopList) {
|
private CocktailForListResponseDto cocktailToDto(CocktailEntity e, boolean withReceipts) {
|
||||||
boolean hasError = false;
|
boolean hasError = false;
|
||||||
int volume = 0;
|
int volume = 0;
|
||||||
Float abv = 0f;
|
Float abv = 0f;
|
||||||
@@ -104,33 +93,9 @@ public class CocktailMapper {
|
|||||||
.glass(e.getGlass().getName())
|
.glass(e.getGlass().getName())
|
||||||
.components(containCocktailComponents(e.getReceipt()))
|
.components(containCocktailComponents(e.getReceipt()))
|
||||||
.rating(createRatingDto(e))
|
.rating(createRatingDto(e))
|
||||||
.isAllowed(calculateAllowed(e.getReceipt(), allowedIngredients))
|
.isAllowed(e.getAllowed())
|
||||||
.inMenu(!barStopList.contains(e.getId()))
|
.receipt(!withReceipts ? null : e.getReceipt().stream().map(ReceiptResponseDto::mapToDto).toList())
|
||||||
.build();
|
.build();
|
||||||
// d.setReceipt(e.getReceipt().stream().map(ReceiptResponseDto::mapToDto).toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Long> getAllowedIngredients() {
|
|
||||||
return barRepository.findByActiveTrue()
|
|
||||||
.map(BarEntity::getIngredients)
|
|
||||||
.orElseThrow()
|
|
||||||
.stream()
|
|
||||||
.map(IngredientEntity::getId)
|
|
||||||
.toList();
|
|
||||||
// return visitor.getResidents().stream()
|
|
||||||
// .filter(BarResident::getActive)
|
|
||||||
// .map(BarResident::getBar)
|
|
||||||
// .map(BarEntity::getIngredients)
|
|
||||||
// .flatMap(List::stream)
|
|
||||||
// .map(BarIngredientStorage::getIngredient)
|
|
||||||
// .map(IngredientEntity::getId)
|
|
||||||
// .toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Boolean calculateAllowed(List<ReceiptEntity> e, List<Long> allowedIngredients) {
|
|
||||||
return e.stream()
|
|
||||||
.map(ReceiptEntity::getIngredient)
|
|
||||||
.allMatch(i -> allowedIngredients.contains(i.getId()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private RatingResponseDto createRatingDto(CocktailEntity entity) {
|
private RatingResponseDto createRatingDto(CocktailEntity entity) {
|
||||||
@@ -148,40 +113,49 @@ public class CocktailMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Visitor getCurrentVisitor() {
|
private Visitor getCurrentVisitor() {
|
||||||
Long visitorId = ((Visitor) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId();
|
SecurityContext context = SecurityContextHolder.getContext();
|
||||||
|
Authentication authentication = context.getAuthentication();
|
||||||
|
Long visitorId;
|
||||||
|
if (authentication.getPrincipal() instanceof Visitor) {
|
||||||
|
visitorId = ((Visitor) authentication.getPrincipal()).getId();
|
||||||
|
} else {
|
||||||
|
visitorId = 1L;
|
||||||
|
}
|
||||||
return visitorsRepository.findById(visitorId).orElseThrow(RuntimeException::new);
|
return visitorsRepository.findById(visitorId).orElseThrow(RuntimeException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CocktailModalDto cocktailToModalDto(CocktailEntity e) {
|
public CocktailModalDto cocktailToModalDto(CocktailEntity e) {
|
||||||
List<Long> allowedIngredients = getAllowedIngredients();
|
|
||||||
return CocktailModalDto.builder()
|
return CocktailModalDto.builder()
|
||||||
.id(e.getId())
|
.id(e.getId())
|
||||||
.name(e.getName())
|
.name(e.getName())
|
||||||
.image(e.getImage())
|
.image(e.getImage())
|
||||||
.instructions(e.getInstructions())
|
.instructions(e.getInstructions())
|
||||||
.rating(createRatingDto(e))
|
.rating(createRatingDto(e))
|
||||||
.receipt(createReceiptDtoList(e.getReceipt(), allowedIngredients))
|
.receipt(createReceiptDtoList(e.getReceipt()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ReceiptResponseDto> createReceiptDtoList(List<ReceiptEntity> receipts, List<Long> allowedIngredients) {
|
private List<ReceiptResponseDto> createReceiptDtoList(List<ReceiptEntity> receipts) {
|
||||||
return receipts.stream()
|
return receipts.stream()
|
||||||
.map(r -> createReceiptDto(r, allowedIngredients))
|
.map(this::createReceiptDto)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReceiptResponseDto createReceiptDto(ReceiptEntity e, List<Long> allowedIngredients) {
|
private ReceiptResponseDto createReceiptDto(ReceiptEntity e) {
|
||||||
return ReceiptResponseDto.builder()
|
return ReceiptResponseDto.builder()
|
||||||
.id(e.getId())
|
.id(e.getId())
|
||||||
.ingredient(createIngredientResponseDto(e.getIngredient(), allowedIngredients))
|
.ingredient(createIngredientResponseDto(e.getIngredient()))
|
||||||
.count(e.getCount())
|
.count(e.getCount())
|
||||||
.unit(e.getUnit())
|
.unit(e.getUnit())
|
||||||
.measure(e.getMeasure())
|
.measure(e.getMeasure())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IngredientSimpleResponseDto createIngredientResponseDto(IngredientEntity i, List<Long> allowedIngredients) {
|
private IngredientSimpleResponseDto createIngredientResponseDto(IngredientEntity i) {
|
||||||
return new IngredientSimpleResponseDto(i.getId(), i.getName(), allowedIngredients.contains(i.getId()));
|
return new IngredientSimpleResponseDto(i.getId(),
|
||||||
|
i.getName(),
|
||||||
|
i.getImage(),
|
||||||
|
i.getIsHave());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import ru.kayashov.bar.controller.dto.ingredient.IngredientResponseDto;
|
import ru.kayashov.bar.controller.dto.ingredient.IngredientResponseDto;
|
||||||
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
||||||
import ru.kayashov.bar.model.entity.BarEntity;
|
|
||||||
import ru.kayashov.bar.model.entity.IngredientEntity;
|
import ru.kayashov.bar.model.entity.IngredientEntity;
|
||||||
import ru.kayashov.bar.repository.BarEntityRepository;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -14,25 +12,13 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class IngredientMapper {
|
public class IngredientMapper {
|
||||||
|
|
||||||
private final BarEntityRepository barRepository;
|
|
||||||
|
|
||||||
public List<IngredientResponseDto> mapIngredientsToDtoList(List<IngredientEntity> ingredients) {
|
public List<IngredientResponseDto> mapIngredientsToDtoList(List<IngredientEntity> ingredients) {
|
||||||
List<Long> allowedIngredients = getAllowedIngredients();
|
|
||||||
return ingredients.stream()
|
return ingredients.stream()
|
||||||
.map(i -> mapIngredientToDto(i, allowedIngredients))
|
.map(this::mapIngredientToDto)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> getAllowedIngredients() {
|
private IngredientResponseDto mapIngredientToDto(IngredientEntity i) {
|
||||||
return barRepository.findByActiveTrue()
|
|
||||||
.map(BarEntity::getIngredients)
|
|
||||||
.orElseThrow()
|
|
||||||
.stream()
|
|
||||||
.map(IngredientEntity::getId)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IngredientResponseDto mapIngredientToDto(IngredientEntity i, List<Long> allowedIngredients) {
|
|
||||||
return IngredientResponseDto
|
return IngredientResponseDto
|
||||||
.builder()
|
.builder()
|
||||||
.id(i.getId())
|
.id(i.getId())
|
||||||
@@ -40,20 +26,21 @@ public class IngredientMapper {
|
|||||||
.alcohol(i.getAlcohol())
|
.alcohol(i.getAlcohol())
|
||||||
.type(i.getType() != null ? i.getType().getName() : null)
|
.type(i.getType() != null ? i.getType().getName() : null)
|
||||||
.abv(i.getAbv())
|
.abv(i.getAbv())
|
||||||
.isHave(allowedIngredients.contains(i.getId()))
|
.isHave(i.getIsHave())
|
||||||
.image("https://thecocktaildb.com/images/ingredients/" + i.getEnName() + "-Medium.png")
|
.image(i.getImage())
|
||||||
.description(i.getDescription())
|
.description(i.getDescription())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IngredientSimpleResponseDto> mapIngredientsToSimpleDtoList(List<IngredientEntity> ingredients) {
|
public List<IngredientSimpleResponseDto> mapIngredientsToSimpleDtoList(List<IngredientEntity> ingredients) {
|
||||||
List<Long> allowedIngredients = getAllowedIngredients();
|
|
||||||
return ingredients.stream()
|
return ingredients.stream()
|
||||||
.map(i -> mapIngredientToSimpleDto(i, allowedIngredients))
|
.map(this::mapIngredientToSimpleDto)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IngredientSimpleResponseDto mapIngredientToSimpleDto(IngredientEntity i, List<Long> allowedIngredients) {
|
private IngredientSimpleResponseDto mapIngredientToSimpleDto(IngredientEntity i) {
|
||||||
return new IngredientSimpleResponseDto(i.getId(), i.getName(), allowedIngredients.contains(i.getId()));
|
return new IngredientSimpleResponseDto(i.getId(), i.getName(),
|
||||||
|
i.getImage(),
|
||||||
|
i.getIsHave());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,4 +32,12 @@ public class BarEntity {
|
|||||||
inverseJoinColumns = @JoinColumn(name = "ingredient")
|
inverseJoinColumns = @JoinColumn(name = "ingredient")
|
||||||
)
|
)
|
||||||
private List<IngredientEntity> ingredients;
|
private List<IngredientEntity> ingredients;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "hidden_cocktails",
|
||||||
|
joinColumns = @JoinColumn(name = "bar"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "cocktail")
|
||||||
|
)
|
||||||
|
private List<CocktailEntity> hiddenCocktails;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,16 +7,10 @@ import lombok.RequiredArgsConstructor;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public enum Category {
|
public enum Category {
|
||||||
COCKTAIL("Коктейль"),
|
COCKTAIL("Коктейль"),
|
||||||
PUNCH("Пунш"),
|
|
||||||
SHAKE("Шейк"),
|
|
||||||
OTHER("Другие"),
|
|
||||||
BEER("Пиво"),
|
BEER("Пиво"),
|
||||||
HOMEMADE_LIQUEUR("Домашний ликер"),
|
|
||||||
SHOT("Шот"),
|
SHOT("Шот"),
|
||||||
COCOA("Какао"),
|
|
||||||
COFFEE_TEA("Кофе-Чай"),
|
COFFEE_TEA("Кофе-Чай"),
|
||||||
SOFT("Безалкогольный напиток"),
|
SOFT("Безалкогольный напиток");
|
||||||
ORDINARY("Обычный напиток");
|
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.util.List;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class CocktailEntity {
|
public class CocktailEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
@@ -46,10 +47,14 @@ public class CocktailEntity {
|
|||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private Glass glass;
|
private Glass glass;
|
||||||
|
|
||||||
private Integer rating;
|
private Boolean allowed;
|
||||||
|
|
||||||
|
private Integer rating = 0;
|
||||||
|
|
||||||
@Column(name = "favourite")
|
@Column(name = "favourite")
|
||||||
private Boolean isFavorite;
|
private Boolean isFavorite = false;
|
||||||
|
|
||||||
|
private Integer countDrink = 0;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "cocktail", cascade = CascadeType.REMOVE)
|
@OneToMany(mappedBy = "cocktail", cascade = CascadeType.REMOVE)
|
||||||
private List<ReceiptEntity> receipt;
|
private List<ReceiptEntity> receipt;
|
||||||
|
|||||||
32
src/main/java/ru/kayashov/bar/model/entity/Event.java
Normal file
32
src/main/java/ru/kayashov/bar/model/entity/Event.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package ru.kayashov.bar.model.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.EnumType;
|
||||||
|
import javax.persistence.Enumerated;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Event {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private int id;
|
||||||
|
private LocalDateTime date;
|
||||||
|
private String oldState;
|
||||||
|
private String newState;
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private EventType type;
|
||||||
|
}
|
||||||
23
src/main/java/ru/kayashov/bar/model/entity/EventType.java
Normal file
23
src/main/java/ru/kayashov/bar/model/entity/EventType.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package ru.kayashov.bar.model.entity;
|
||||||
|
|
||||||
|
public enum EventType {
|
||||||
|
LOGIN,
|
||||||
|
DRINK,
|
||||||
|
COCKTAIL_CREATE,
|
||||||
|
COCKTAIL_EDIT,
|
||||||
|
COCKTAIL_DELETE,
|
||||||
|
COCKTAIL_UPLOAD_PHOTO,
|
||||||
|
INGREDIENT_CREATE,
|
||||||
|
INGREDIENT_EDIT,
|
||||||
|
INGREDIENT_DELETE,
|
||||||
|
INGREDIENT_ADD,
|
||||||
|
INGREDIENT_REMOVE,
|
||||||
|
INGREDIENT_UPLOAD_PHOTO,
|
||||||
|
BAR_CREATE,
|
||||||
|
BAR_DELETE,
|
||||||
|
BAR_CHANGE,
|
||||||
|
USER_CREATE,
|
||||||
|
USER_EDIT,
|
||||||
|
USER_UPLOAD_PHOTO
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,23 +6,20 @@ import lombok.RequiredArgsConstructor;
|
|||||||
@Getter
|
@Getter
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public enum Glass {
|
public enum Glass {
|
||||||
HIGHBALL("Хайболл"),
|
HIGHBALL("Хайболл",250),
|
||||||
COCKTAIL("Коктейльный бокал"),
|
COCKTAIL("Коктейльный бокал",120),
|
||||||
COLLINS("Стакан"),
|
COLLINS("Стакан", 200),
|
||||||
POUSSE("Рюмка на ножке"),
|
CHAMPAGNE("Бокал флюте", 200),
|
||||||
CHAMPAGNE("Бокал флюте"),
|
HURRICANE("Ураган", 350),
|
||||||
BRANDY("Коньячный бокал"),
|
COFFEE("Кофейная кружка", 250),
|
||||||
HURRICANE("Ураган"),
|
SHOT("Рюмка",50),
|
||||||
COFFEE("Кофейная кружка"),
|
CORDIAL("Ликерная рюмка",150),
|
||||||
SHOT("Рюмка"),
|
BEER("Пивной бокал", 500),
|
||||||
JAR("Банка"),
|
WINE("Бокал для вина", 350),
|
||||||
PITCHER("Кувшин"),
|
MARGARITA("Бокал Маргарита", 260);
|
||||||
CORDIAL("Ликерная рюмка"),
|
|
||||||
BEER("Пивной бокал"),
|
|
||||||
WINE("Бокал для вина"),
|
|
||||||
MARGARITA("Бокал Маргарита");
|
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final Integer capacity;
|
||||||
|
|
||||||
public static Glass findValue(String name) {
|
public static Glass findValue(String name) {
|
||||||
for (Glass glass : Glass.values()) {
|
for (Glass glass : Glass.values()) {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import lombok.Setter;
|
|||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.JoinTable;
|
import javax.persistence.JoinTable;
|
||||||
@@ -26,13 +28,15 @@ import java.util.List;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class IngredientEntity {
|
public class IngredientEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
private String enName;
|
|
||||||
private Boolean alcohol;
|
private Boolean alcohol;
|
||||||
private Integer abv;
|
private Integer abv;
|
||||||
private Boolean isHave;
|
private Boolean isHave;
|
||||||
|
private String image;
|
||||||
|
|
||||||
@Column(columnDefinition = "text")
|
@Column(columnDefinition = "text")
|
||||||
private String description;
|
private String description;
|
||||||
@@ -44,7 +48,7 @@ public class IngredientEntity {
|
|||||||
@JoinColumn(name = "type")
|
@JoinColumn(name = "type")
|
||||||
private TypeEntity type;
|
private TypeEntity type;
|
||||||
|
|
||||||
@ManyToMany(cascade = CascadeType.REMOVE)
|
@ManyToMany
|
||||||
@JoinTable(
|
@JoinTable(
|
||||||
name = "bar_ingredient",
|
name = "bar_ingredient",
|
||||||
joinColumns = @JoinColumn(name = "ingredient"),
|
joinColumns = @JoinColumn(name = "ingredient"),
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
package ru.kayashov.bar.model.entity;
|
package ru.kayashov.bar.model.entity;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.GeneratedValue;
|
import javax.persistence.GeneratedValue;
|
||||||
import javax.persistence.GenerationType;
|
import javax.persistence.GenerationType;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@@ -19,17 +18,12 @@ import java.util.List;
|
|||||||
@Table(name = "ingredient_type")
|
@Table(name = "ingredient_type")
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class TypeEntity {
|
public class TypeEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
@Column(name = "en_name")
|
|
||||||
private String enName;
|
|
||||||
|
|
||||||
@OneToMany(mappedBy = "type")
|
@OneToMany(mappedBy = "type")
|
||||||
private List<IngredientEntity> ingredients;
|
private List<IngredientEntity> ingredients;
|
||||||
|
|
||||||
public TypeEntity(String enName) {
|
|
||||||
this.enName = enName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class Visitor implements UserDetails {
|
|||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private UserRole role;
|
private UserRole role;
|
||||||
private Integer code;
|
private Integer code;
|
||||||
|
private String image;
|
||||||
private String login;
|
private String login;
|
||||||
private String password;
|
private String password;
|
||||||
private LocalDateTime expired;
|
private LocalDateTime expired;
|
||||||
@@ -33,13 +34,6 @@ public class Visitor implements UserDetails {
|
|||||||
@Override
|
@Override
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
return role.getAuthorities();
|
return role.getAuthorities();
|
||||||
// return UserRole.ADMIN.getAuthorities();
|
|
||||||
// return residents.stream()
|
|
||||||
// .filter(BarResident::getActive)
|
|
||||||
// .map(BarResident::getRole)
|
|
||||||
// .map(UserRole::getAuthorities)
|
|
||||||
// .flatMap(Collection::stream)
|
|
||||||
// .collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -8,11 +8,17 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import ru.kayashov.bar.model.entity.CocktailEntity;
|
import ru.kayashov.bar.model.entity.CocktailEntity;
|
||||||
|
|
||||||
public interface CocktailRepository extends JpaRepository<CocktailEntity, Long> {
|
public interface CocktailRepository extends JpaRepository<CocktailEntity, Long> {
|
||||||
|
|
||||||
@Modifying
|
@Modifying
|
||||||
@Transactional
|
@Transactional
|
||||||
@Query("UPDATE CocktailEntity c SET c.isFavorite = :favorite WHERE c.id = :id")
|
@Query("UPDATE CocktailEntity c SET c.isFavorite = :favorite WHERE c.id = :id")
|
||||||
void updateFavouriteById(@Param("id") Long id, @Param("favorite") Boolean favorite);
|
void updateFavouriteById(@Param("id") Long id, @Param("favorite") Boolean favorite);
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Transactional
|
||||||
|
@Query("UPDATE CocktailEntity c SET c.allowed = false WHERE c.allowed = true")
|
||||||
|
void markAllAsNotAllowed();
|
||||||
|
|
||||||
@Modifying
|
@Modifying
|
||||||
@Transactional
|
@Transactional
|
||||||
@Query("UPDATE CocktailEntity c SET c.rating = :rating WHERE c.id = :id")
|
@Query("UPDATE CocktailEntity c SET c.rating = :rating WHERE c.id = :id")
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package ru.kayashov.bar.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import ru.kayashov.bar.model.entity.Event;
|
||||||
|
|
||||||
|
public interface EventRepository extends JpaRepository<Event, Integer> {
|
||||||
|
}
|
||||||
@@ -6,6 +6,4 @@ import ru.kayashov.bar.model.entity.IngredientEntity;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface IngredientRepository extends JpaRepository<IngredientEntity, Long> {
|
public interface IngredientRepository extends JpaRepository<IngredientEntity, Long> {
|
||||||
|
|
||||||
Optional<IngredientEntity> findByEnNameIgnoreCase(String name);
|
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,11 @@
|
|||||||
package ru.kayashov.bar.repository;
|
package ru.kayashov.bar.repository;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
|
||||||
import ru.kayashov.bar.model.entity.TypeEntity;
|
import ru.kayashov.bar.model.entity.TypeEntity;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface TypeRepository extends JpaRepository<TypeEntity, Long> {
|
public interface TypeRepository extends JpaRepository<TypeEntity, Long> {
|
||||||
|
|
||||||
Optional<TypeEntity> findByEnNameIgnoreCase(String name);
|
|
||||||
|
|
||||||
Optional<TypeEntity> findByName(String name);
|
Optional<TypeEntity> findByName(String name);
|
||||||
|
|
||||||
@Query("select i from TypeEntity i where upper(i.name) like upper(?1) or upper(i.enName) like upper(?1)")
|
|
||||||
List<TypeEntity> findByWord(String word);
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import org.springframework.security.authentication.AuthenticationManager;
|
|||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
@@ -26,6 +27,7 @@ import static org.springframework.security.config.http.SessionCreationPolicy.STA
|
|||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@EnableMethodSecurity
|
@EnableMethodSecurity
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
|
||||||
@@ -51,8 +53,13 @@ public class SecurityConfig {
|
|||||||
private void authorizeConfiguration(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry request) {
|
private void authorizeConfiguration(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry request) {
|
||||||
request
|
request
|
||||||
// Можно указать конкретный путь, * - 1 уровень вложенности, ** - любое количество уровней вложенности
|
// Можно указать конкретный путь, * - 1 уровень вложенности, ** - любое количество уровней вложенности
|
||||||
.antMatchers("/api/auth/**")
|
.antMatchers("/api/auth/**").permitAll()
|
||||||
.permitAll()
|
.antMatchers("/api/cocktail/menu").permitAll()
|
||||||
|
.antMatchers("/api/cocktail/drink/**").permitAll()
|
||||||
|
.antMatchers("/api/cocktail/modal").permitAll()
|
||||||
|
.antMatchers("/api/category").permitAll()
|
||||||
|
.antMatchers("/api/glass").permitAll()
|
||||||
|
.antMatchers("/api/ingredient/simple").permitAll()
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.authenticated();
|
.authenticated();
|
||||||
}
|
}
|
||||||
|
|||||||
133
src/main/java/ru/kayashov/bar/service/BarService.java
Normal file
133
src/main/java/ru/kayashov/bar/service/BarService.java
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
package ru.kayashov.bar.service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.kayashov.bar.controller.dto.bar.BarResponseDto;
|
||||||
|
import ru.kayashov.bar.model.entity.BarEntity;
|
||||||
|
import ru.kayashov.bar.model.entity.CocktailEntity;
|
||||||
|
import ru.kayashov.bar.model.entity.Event;
|
||||||
|
import ru.kayashov.bar.model.entity.EventType;
|
||||||
|
import ru.kayashov.bar.model.entity.IngredientEntity;
|
||||||
|
import ru.kayashov.bar.model.entity.ReceiptEntity;
|
||||||
|
import ru.kayashov.bar.repository.BarEntityRepository;
|
||||||
|
import ru.kayashov.bar.repository.CocktailRepository;
|
||||||
|
import ru.kayashov.bar.repository.IngredientRepository;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BarService {
|
||||||
|
|
||||||
|
private final BarEntityRepository barEntityRepository;
|
||||||
|
private final IngredientRepository ingredientRepository;
|
||||||
|
private final CocktailRepository cocktailRepository;
|
||||||
|
private final EventService eventService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void changeActiveBar(Long id) {
|
||||||
|
Optional<BarEntity> lastBarOpt = barEntityRepository.findByActiveTrue();
|
||||||
|
if (lastBarOpt.isPresent()) {
|
||||||
|
BarEntity lastBar = lastBarOpt.get();
|
||||||
|
|
||||||
|
lastBar.setActive(false);
|
||||||
|
barEntityRepository.save(lastBar);
|
||||||
|
|
||||||
|
lastBar.getIngredients().stream()
|
||||||
|
.peek(i -> i.setIsHave(false))
|
||||||
|
.forEach(ingredientRepository::save);
|
||||||
|
|
||||||
|
cocktailRepository.markAllAsNotAllowed();
|
||||||
|
|
||||||
|
log.info("Бар {} отключен", lastBar.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
BarEntity barEntity = barEntityRepository.findById(id).orElseThrow();
|
||||||
|
barEntity.setActive(true);
|
||||||
|
|
||||||
|
List<IngredientEntity> ingredients = barEntity.getIngredients().stream()
|
||||||
|
.peek(i -> i.setIsHave(true))
|
||||||
|
.map(ingredientRepository::save)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
cocktailRepository.saveAll(findAllowedCocktails(ingredients, barEntity.getHiddenCocktails().stream().map(CocktailEntity::getId).toList()));
|
||||||
|
|
||||||
|
barEntityRepository.save(barEntity);
|
||||||
|
|
||||||
|
eventService.createEvent(Event.builder()
|
||||||
|
.date(LocalDateTime.now())
|
||||||
|
.type(EventType.BAR_CHANGE)
|
||||||
|
.newState(barEntity.getName())
|
||||||
|
.oldState(lastBarOpt.map(BarEntity::getName).orElse(null))
|
||||||
|
.build());
|
||||||
|
log.info("Бар {} подключен", barEntity.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BarResponseDto> findAllBar() {
|
||||||
|
List<BarEntity> barEntities = barEntityRepository.findAll();
|
||||||
|
log.info("По запросу найдено {} баров", barEntities.size());
|
||||||
|
return barEntities.stream()
|
||||||
|
.map(BarResponseDto::mapToDto)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteBar(Long id) {
|
||||||
|
barEntityRepository.deleteById(id);
|
||||||
|
log.info("Бар с id {} удален", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BarResponseDto createBar(String name) {
|
||||||
|
BarEntity bar = new BarEntity();
|
||||||
|
bar.setName(name);
|
||||||
|
bar.setActive(false);
|
||||||
|
bar = barEntityRepository.save(bar);
|
||||||
|
|
||||||
|
log.info("Создан бар {}", name);
|
||||||
|
|
||||||
|
return BarResponseDto.mapToDto(bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public BarResponseDto copyBar(Long id, String name) {
|
||||||
|
BarEntity barEntity = barEntityRepository.findById(id).orElseThrow();
|
||||||
|
|
||||||
|
BarEntity entity = new BarEntity();
|
||||||
|
entity.setName(name);
|
||||||
|
entity.setActive(false);
|
||||||
|
entity.setIngredients(new ArrayList<>());
|
||||||
|
barEntityRepository.save(entity);
|
||||||
|
List<IngredientEntity> ingredients = barEntity.getIngredients()
|
||||||
|
.stream()
|
||||||
|
.peek(i -> i.getBars().add(entity))
|
||||||
|
.toList();
|
||||||
|
entity.setIngredients(ingredients);
|
||||||
|
ingredientRepository.saveAll(ingredients);
|
||||||
|
log.info("Бар {} - {}, скопирован как {} - {}", barEntity.getId(), barEntity.getName(), entity.getId(), name);
|
||||||
|
|
||||||
|
return BarResponseDto.mapToDto(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CocktailEntity> findAllowedCocktails(List<IngredientEntity> ingredients, List<Long> hiddenCocktails) {
|
||||||
|
List<CocktailEntity> result = new ArrayList<>();
|
||||||
|
for (IngredientEntity ingredient : ingredients) {
|
||||||
|
List<CocktailEntity> cocktails = ingredient.getReceipts().stream()
|
||||||
|
.map(ReceiptEntity::getCocktail)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
for (CocktailEntity cocktail : cocktails) {
|
||||||
|
if (cocktail.getReceipt().stream().allMatch(r -> r.getIngredient().getIsHave())
|
||||||
|
&& !hiddenCocktails.contains(cocktail.getId())) {
|
||||||
|
cocktail.setAllowed(true);
|
||||||
|
result.add(cocktail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@ package ru.kayashov.bar.service;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.query.Query;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -14,35 +12,36 @@ import ru.kayashov.bar.controller.dto.cocktail.CocktailForListResponseDto;
|
|||||||
import ru.kayashov.bar.controller.dto.cocktail.CocktailModalDto;
|
import ru.kayashov.bar.controller.dto.cocktail.CocktailModalDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.CocktailSimpleResponseDto;
|
import ru.kayashov.bar.controller.dto.cocktail.CocktailSimpleResponseDto;
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
|
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
|
||||||
|
import ru.kayashov.bar.controller.dto.cocktail.SortingEnum;
|
||||||
|
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
||||||
import ru.kayashov.bar.mapper.CocktailMapper;
|
import ru.kayashov.bar.mapper.CocktailMapper;
|
||||||
import ru.kayashov.bar.model.entity.Alcoholic;
|
import ru.kayashov.bar.model.entity.Alcoholic;
|
||||||
|
import ru.kayashov.bar.model.entity.BarEntity;
|
||||||
import ru.kayashov.bar.model.entity.Category;
|
import ru.kayashov.bar.model.entity.Category;
|
||||||
import ru.kayashov.bar.model.entity.CocktailEntity;
|
import ru.kayashov.bar.model.entity.CocktailEntity;
|
||||||
|
import ru.kayashov.bar.model.entity.Event;
|
||||||
|
import ru.kayashov.bar.model.entity.EventType;
|
||||||
import ru.kayashov.bar.model.entity.Glass;
|
import ru.kayashov.bar.model.entity.Glass;
|
||||||
import ru.kayashov.bar.model.entity.IngredientEntity;
|
import ru.kayashov.bar.model.entity.IngredientEntity;
|
||||||
import ru.kayashov.bar.model.entity.ReceiptEntity;
|
import ru.kayashov.bar.model.entity.ReceiptEntity;
|
||||||
|
import ru.kayashov.bar.repository.BarEntityRepository;
|
||||||
import ru.kayashov.bar.repository.CocktailRepository;
|
import ru.kayashov.bar.repository.CocktailRepository;
|
||||||
import ru.kayashov.bar.repository.IngredientRepository;
|
import ru.kayashov.bar.repository.IngredientRepository;
|
||||||
import ru.kayashov.bar.repository.ReceiptRepository;
|
import ru.kayashov.bar.repository.ReceiptRepository;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
|
||||||
import javax.persistence.criteria.CriteriaQuery;
|
|
||||||
import javax.persistence.criteria.Expression;
|
|
||||||
import javax.persistence.criteria.Join;
|
|
||||||
import javax.persistence.criteria.JoinType;
|
|
||||||
import javax.persistence.criteria.Order;
|
|
||||||
import javax.persistence.criteria.Predicate;
|
|
||||||
import javax.persistence.criteria.Root;
|
|
||||||
import javax.persistence.criteria.Subquery;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -50,6 +49,8 @@ import java.util.stream.Stream;
|
|||||||
public class CocktailService {
|
public class CocktailService {
|
||||||
|
|
||||||
private final CocktailRepository cocktailRepository;
|
private final CocktailRepository cocktailRepository;
|
||||||
|
private final EventService eventService;
|
||||||
|
private final BarEntityRepository barRepository;
|
||||||
@Value("${cocktail.photo.path}")
|
@Value("${cocktail.photo.path}")
|
||||||
private String photoFolder;
|
private String photoFolder;
|
||||||
|
|
||||||
@@ -67,174 +68,19 @@ public class CocktailService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public List<CocktailForListResponseDto> getMenu(CocktailFilterRequestDto dto) {
|
public List<CocktailForListResponseDto> getMenu(CocktailFilterRequestDto dto) {
|
||||||
return mapper.cocktailsToDtoList(criteria(dto), dto.getAll());
|
return mapper.cocktailsToDtoList(criteria(dto), dto.getAll(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CocktailEntity> criteria(CocktailFilterRequestDto dto) {
|
@Transactional
|
||||||
Session session = entityManager.unwrap(Session.class);
|
public List<CocktailForListResponseDto> calc() {
|
||||||
CriteriaBuilder cb = session.getCriteriaBuilder();
|
CocktailFilterRequestDto dto = new CocktailFilterRequestDto();
|
||||||
CriteriaQuery<CocktailEntity> criteriaQuery = cb.createQuery(CocktailEntity.class);
|
dto.setPage(0);
|
||||||
Root<CocktailEntity> root = criteriaQuery.from(CocktailEntity.class);
|
dto.setSize(1000);
|
||||||
List<Predicate> predicates = new ArrayList<>();
|
dto.setAll(false);
|
||||||
|
dto.setOnlyFavourite(false);
|
||||||
|
dto.setSort(SortingEnum.NAME_ASC);
|
||||||
|
|
||||||
criteriaQuery.distinct(true);
|
return mapper.cocktailsToDtoList(criteria(dto), false, true);
|
||||||
if (!dto.getAll()) {
|
|
||||||
// List<Long> cocktailIds = findICountCocktailIds(0, new ArrayList<>());
|
|
||||||
List<Long> cocktailIds = findCocktailByCountNotHaveIngredient();
|
|
||||||
Predicate pr = root.get("id").in(cocktailIds);
|
|
||||||
predicates.add(pr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dto.getSearch().isEmpty()) {
|
|
||||||
String[] search = dto.getSearch().split(" ");
|
|
||||||
List<Predicate> in = new ArrayList<>();
|
|
||||||
Join<CocktailEntity, ReceiptEntity> receiptJoin = root.join("receipt", JoinType.LEFT);
|
|
||||||
for (String s : search) {
|
|
||||||
in.add(cb.like(cb.lower(root.get("name")), "%" + s.toLowerCase() + "%"));
|
|
||||||
in.add(cb.like(cb.lower(receiptJoin.get("ingredient").get("name")), "%" + s.toLowerCase() + "%"));
|
|
||||||
}
|
|
||||||
predicates.add(cb.or(in.toArray(new Predicate[0])));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.getOnlyFavourite()) {
|
|
||||||
predicates.add(cb.isTrue(root.get("favourite")));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.getGlass() != null && !dto.getGlass().isEmpty()) {
|
|
||||||
predicates.add(root.get("glass").in(dto.getGlass().stream().map(Glass::findValue).toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.getCategory() != null && !dto.getCategory().isEmpty()) {
|
|
||||||
predicates.add(root.get("category").in(dto.getCategory().stream().map(Category::findValue).toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.getAlcohol() != null && !dto.getAlcohol().isEmpty()) {
|
|
||||||
predicates.add(root.get("alcoholic").in(dto.getAlcohol().stream().map(Alcoholic::findValue).toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.getNotHaveCount() != null) {
|
|
||||||
List<Long> approveCocktail = findICountCocktailIds(dto.getNotHaveCount(), dto.getIngredient());
|
|
||||||
predicates.add(root.get("id").in(approveCocktail));
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// if (!dto.getSortField().equals("name") || !dto.getSortOrder().equals("asc")) {
|
|
||||||
// cb.asc(root.get("name"));
|
|
||||||
//// query.orderBy(cb.asc(root.get("name").get(dto.getSortField())));
|
|
||||||
// } else {
|
|
||||||
// criteriaQuery.orderBy(cb.asc(root.get("name")));
|
|
||||||
// }
|
|
||||||
|
|
||||||
//todo: доделать другие виды сортировки
|
|
||||||
Order order;
|
|
||||||
switch (dto.getSort()) {
|
|
||||||
case NAME_ASC -> order = cb.asc(root.get("name"));
|
|
||||||
case NAME_DESC -> order = cb.desc(root.get("name"));
|
|
||||||
default -> order = cb.asc(root.get("name"));
|
|
||||||
}
|
|
||||||
|
|
||||||
criteriaQuery.where(predicates.toArray(new Predicate[0]))
|
|
||||||
.orderBy(order);
|
|
||||||
Query<CocktailEntity> query = session.createQuery(criteriaQuery);
|
|
||||||
query.setFirstResult(dto.getPage() * dto.getSize());
|
|
||||||
query.setMaxResults(dto.getSize());
|
|
||||||
List<CocktailEntity> cocktailEntities = query.getResultList();
|
|
||||||
|
|
||||||
log.info("Найдено {} коктейлей", cocktailEntities.size());
|
|
||||||
return cocktailEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Long> findICountCocktailIds(Integer iCount, List<String> ingredientFilter) {
|
|
||||||
List<Long> allowedIngredient = visitorService.getAllowedIngredients();
|
|
||||||
|
|
||||||
Stream<List<ReceiptEntity>> receiptStream = receiptRepository.findAll()
|
|
||||||
.stream()
|
|
||||||
.collect(Collectors.groupingBy(k -> k.getCocktail().getId()))
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.filter(l -> getCountNotHaveIngredient(allowedIngredient, l).equals(iCount));
|
|
||||||
|
|
||||||
if (!ingredientFilter.isEmpty()) {
|
|
||||||
receiptStream = receiptStream.filter(l -> findIngredientInReceipts(ingredientFilter, l));
|
|
||||||
}
|
|
||||||
return receiptStream
|
|
||||||
.map(l -> l.get(0))
|
|
||||||
.map(ReceiptEntity::getCocktail)
|
|
||||||
.map(CocktailEntity::getId)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean findIngredientInReceipts(List<String> ingredientFilter, List<ReceiptEntity> receipts) {
|
|
||||||
return receipts.stream().anyMatch(r -> ingredientFilter.contains(r.getIngredient().getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Integer getCountNotHaveIngredient(List<Long> allowedIngredientIds, List<ReceiptEntity> receipts) {
|
|
||||||
return Math.toIntExact(receipts.size() - receipts.stream()
|
|
||||||
.filter(r -> allowedIngredientIds.contains(r.getIngredient().getId()))
|
|
||||||
.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
// private List<Long> getAllowedCocktailIds(Long barId) {
|
|
||||||
// CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
|
||||||
// CriteriaQuery<Long> query = cb.createQuery(Long.class);
|
|
||||||
//
|
|
||||||
// Root<ReceiptEntity> receiptRoot = query.from(ReceiptEntity.class);
|
|
||||||
// Join<ReceiptEntity, IngredientEntity> ingredientJoin = receiptRoot.join("ingredient", JoinType.LEFT);
|
|
||||||
// Join<IngredientEntity, BarEntity> barIngredientStorageJoin = ingredientJoin.join("bars", JoinType.LEFT);
|
|
||||||
//
|
|
||||||
// // Внешний подзапрос с NOT EXISTS
|
|
||||||
// Subquery<Long> subquery = query.subquery(Long.class);
|
|
||||||
// Root<ReceiptEntity> receiptSubRoot = subquery.from(ReceiptEntity.class);
|
|
||||||
// Join<ReceiptEntity, IngredientEntity> ingredientSubJoin = receiptSubRoot.join("ingredient", JoinType.LEFT);
|
|
||||||
//
|
|
||||||
// // Внутренний подзапрос с NOT EXISTS
|
|
||||||
// Subquery<Long> innerSubquery = subquery.subquery(Long.class);
|
|
||||||
// Root<BarIngredientStorage> barIngredientStorageInnerRoot = innerSubquery.from(BarIngredientStorage.class);
|
|
||||||
//
|
|
||||||
// // Условия внутреннего подзапроса
|
|
||||||
// innerSubquery.select(barIngredientStorageInnerRoot.get("id"))
|
|
||||||
// .where(
|
|
||||||
// cb.equal(barIngredientStorageInnerRoot.get("ingredient"), ingredientSubJoin.get("id")),
|
|
||||||
// cb.equal(barIngredientStorageInnerRoot.get("bar").get("id"), barId)
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// // Условия внешнего подзапроса
|
|
||||||
// subquery.select(receiptSubRoot.get("id"))
|
|
||||||
// .where(
|
|
||||||
// cb.equal(receiptSubRoot.get("cocktail").get("id"), receiptRoot.get("cocktail").get("id")),
|
|
||||||
// cb.not(cb.exists(innerSubquery))
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// // Основной запрос
|
|
||||||
// query.select(receiptRoot.get("cocktail").get("id"))
|
|
||||||
// .distinct(true)
|
|
||||||
// .where(
|
|
||||||
// cb.equal(barIngredientStorageJoin.get("bar").get("id"), barId),
|
|
||||||
// cb.not(cb.exists(subquery))
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// return entityManager.createQuery(query).getResultList();
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*
|
|
||||||
select cifc.cocktail_id
|
|
||||||
from (select r.cocktail_id, COUNT(CASE WHEN i.is_have THEN 0 END) as false_count
|
|
||||||
from receipt r
|
|
||||||
left join public.ingredient i on i.id = r.ingredient_id
|
|
||||||
group by r.cocktail_id) as cifc
|
|
||||||
where false_count = 0
|
|
||||||
*/
|
|
||||||
//todo: так и не придумал я нормальный запрос
|
|
||||||
private List<Long> findCocktailByCountNotHaveIngredient() {
|
|
||||||
String sql = "SELECT cifc.cocktail_id" +
|
|
||||||
" FROM (SELECT r.cocktail_id," +
|
|
||||||
" COUNT(CASE WHEN i.is_have = false THEN 1 END) AS false_count" +
|
|
||||||
" FROM receipt r" +
|
|
||||||
" LEFT JOIN public.ingredient i ON i.id = r.ingredient_id" +
|
|
||||||
" GROUP BY r.cocktail_id) AS cifc" +
|
|
||||||
" WHERE false_count = 0";
|
|
||||||
|
|
||||||
javax.persistence.Query query = entityManager.createNativeQuery(sql);
|
|
||||||
return query.getResultList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CocktailForListResponseDto findById(Long id) {
|
public CocktailForListResponseDto findById(Long id) {
|
||||||
@@ -256,6 +102,11 @@ public class CocktailService {
|
|||||||
.orElseThrow(() -> new RuntimeException("Не удалось найти коктейль с id " + dto.getId()));
|
.orElseThrow(() -> new RuntimeException("Не удалось найти коктейль с id " + dto.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean allowed = dto.getReceipt().stream()
|
||||||
|
.map(ReceiptResponseDto::getIngredient)
|
||||||
|
.allMatch(IngredientSimpleResponseDto::getIsHave);
|
||||||
|
|
||||||
|
cocktail.setAllowed(allowed);
|
||||||
cocktail.setName(dto.getName());
|
cocktail.setName(dto.getName());
|
||||||
cocktail.setInstructions(dto.getInstructions());
|
cocktail.setInstructions(dto.getInstructions());
|
||||||
cocktail.setImage(dto.getImage());
|
cocktail.setImage(dto.getImage());
|
||||||
@@ -264,19 +115,127 @@ public class CocktailService {
|
|||||||
cocktail.setGlass(Glass.findValue(dto.getGlass()));
|
cocktail.setGlass(Glass.findValue(dto.getGlass()));
|
||||||
cocktail.setAlcoholic(Alcoholic.findValue(dto.getAlcoholic()));
|
cocktail.setAlcoholic(Alcoholic.findValue(dto.getAlcoholic()));
|
||||||
cocktail.setRating(cocktail.getRating());
|
cocktail.setRating(cocktail.getRating());
|
||||||
repository.save(cocktail);
|
cocktail = repository.save(cocktail);
|
||||||
|
|
||||||
|
log.info("{} коктейль {}", dto.getId() == null ? "Создан" : "Изменен", cocktail.getName());
|
||||||
|
|
||||||
editCocktailReceipts(cocktail.getReceipt(), dto.getReceipt(), cocktail);
|
editCocktailReceipts(cocktail.getReceipt(), dto.getReceipt(), cocktail);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void editFavourite(Long cocktailId, boolean put) {
|
public void editFavourite(Long cocktailId, boolean put) {
|
||||||
|
log.info("Коктейль с id {} {}", cocktailId, put ? "добавлен в избранное" : "удален из избранного");
|
||||||
cocktailRepository.updateFavouriteById(cocktailId, put);
|
cocktailRepository.updateFavouriteById(cocktailId, put);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRating(Long cocktailId, Integer rating) {
|
public void setRating(Long cocktailId, Integer rating) {
|
||||||
|
log.info("Коктейлю с id {} выставлена новая оценка {}", cocktailId, rating);
|
||||||
cocktailRepository.updateRatingById(cocktailId, rating);
|
cocktailRepository.updateRatingById(cocktailId, rating);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CocktailModalDto getForModal(Long id) {
|
||||||
|
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
|
||||||
|
return mapper.cocktailToModalDto(cocktail);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CocktailSimpleResponseDto> getSimple() {
|
||||||
|
return repository.findAll().stream()
|
||||||
|
.map(CocktailSimpleResponseDto::mapToDto)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String savePhoto(MultipartFile file) throws IOException {
|
||||||
|
File folder = new File(photoFolder);
|
||||||
|
List<File> files = Arrays.asList(Objects.requireNonNull(folder.listFiles()));
|
||||||
|
String fileName = getPhotoPath(files, file.getOriginalFilename());
|
||||||
|
String fullName = photoFolder + "/" + fileName;
|
||||||
|
file.transferTo(new File(fullName));
|
||||||
|
log.info("сохранено фото {}", fileName);
|
||||||
|
return "/assets/cocktails/" + fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(Long id) {
|
||||||
|
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
|
||||||
|
log.info("Удален коктейль {}", cocktail);
|
||||||
|
repository.delete(cocktail);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CocktailForIngredientModalDto> findByIngredient(Long id) {
|
||||||
|
return ingredientRepository.findById(id).orElseThrow(RuntimeException::new)
|
||||||
|
.getReceipts()
|
||||||
|
.stream()
|
||||||
|
.map(ReceiptEntity::getCocktail)
|
||||||
|
.distinct()
|
||||||
|
.map(mapper::cocktailToIngredientDtoList)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hiddenCocktail(Long id) {
|
||||||
|
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
|
||||||
|
|
||||||
|
BarEntity bar = barRepository.findByActiveTrue().orElseThrow();
|
||||||
|
bar.getHiddenCocktails().add(cocktail);
|
||||||
|
barRepository.save(bar);
|
||||||
|
|
||||||
|
cocktail.setAllowed(false);
|
||||||
|
repository.save(cocktail);
|
||||||
|
log.info("Коктейль {} - {} был скрыт для бара {} - {}", cocktail.getId(), cocktail.getName(), bar.getId(), bar.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drink(Long id) {
|
||||||
|
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
|
||||||
|
int count = cocktail.getCountDrink() + 1;
|
||||||
|
cocktail.setCountDrink(count);
|
||||||
|
repository.save(cocktail);
|
||||||
|
|
||||||
|
eventService.createEvent(Event.builder()
|
||||||
|
.type(EventType.DRINK)
|
||||||
|
.date(LocalDateTime.now())
|
||||||
|
.oldState(cocktail.getName())
|
||||||
|
.newState(String.valueOf(count))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: написать функцию в БД, чтобы ускорить работу и сохранить читаемый код
|
||||||
|
private List<CocktailEntity> criteria(CocktailFilterRequestDto dto) {
|
||||||
|
Instant now = Instant.now();
|
||||||
|
List<CocktailEntity> cocktails = repository.findAll()
|
||||||
|
.stream()
|
||||||
|
//todo: доделать другие виды сортировки
|
||||||
|
.sorted(Comparator.comparing(CocktailEntity::getName))
|
||||||
|
.filter(c -> c.getAllowed() || dto.getAll())
|
||||||
|
.filter(c -> c.getIsFavorite() || !dto.getOnlyFavourite())
|
||||||
|
.filter(c -> isEmpty(dto.getGlass()) || dto.getGlass().contains(c.getGlass().getName()))
|
||||||
|
.filter(c -> isEmpty(dto.getCategory()) || dto.getCategory().contains(c.getCategory().getName()))
|
||||||
|
.filter(c -> isEmpty(dto.getAlcohol()) || dto.getAlcohol().contains(c.getAlcoholic().getValue()))
|
||||||
|
.filter(c -> dto.getSearch().isEmpty() || textSearchFilter(c, dto.getSearch()))
|
||||||
|
.skip((long) dto.getPage() * dto.getSize())
|
||||||
|
.limit(dto.getSize())
|
||||||
|
.toList();
|
||||||
|
log.info("Найдено {} коктейлей за {} ms", cocktails.size(), Duration.between(now, Instant.now()).toMillis());
|
||||||
|
return cocktails;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean textSearchFilter(CocktailEntity cocktail, String founding) {
|
||||||
|
String[] search = founding.split(" ");
|
||||||
|
|
||||||
|
if (Arrays.stream(search).anyMatch(s -> cocktail.getName().toLowerCase().contains(s.toLowerCase()))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> ingredientsNames = cocktail.getReceipt().stream()
|
||||||
|
.map(ReceiptEntity::getIngredient)
|
||||||
|
.map(IngredientEntity::getName)
|
||||||
|
.map(String::toLowerCase)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
return Arrays.stream(search).anyMatch(s -> ingredientsNames.contains(s.toLowerCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEmpty(List<?> value) {
|
||||||
|
return value == null || value.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: попробовать отыграть эту связку каскадами
|
||||||
private void editCocktailReceipts(List<ReceiptEntity> old, List<ReceiptResponseDto> actual, CocktailEntity cocktail) {
|
private void editCocktailReceipts(List<ReceiptEntity> old, List<ReceiptResponseDto> actual, CocktailEntity cocktail) {
|
||||||
for (ReceiptResponseDto receipt : actual) {
|
for (ReceiptResponseDto receipt : actual) {
|
||||||
if (receipt.getId() == null) {
|
if (receipt.getId() == null) {
|
||||||
@@ -324,33 +283,6 @@ public class CocktailService {
|
|||||||
receiptRepository.save(receiptEntity);
|
receiptRepository.save(receiptEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CocktailModalDto getForModal(Long id) {
|
|
||||||
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
|
|
||||||
return mapper.cocktailToModalDto(cocktail);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ReceiptResponseDto> getReceipts(Long id) {
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<CocktailSimpleResponseDto> getSimple() {
|
|
||||||
return repository.findAll().stream()
|
|
||||||
.map(CocktailSimpleResponseDto::mapToDto)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String savePhoto(MultipartFile file) throws IOException {
|
|
||||||
File folder = new File(photoFolder);
|
|
||||||
List<File> files = Arrays.asList(Objects.requireNonNull(folder.listFiles()));
|
|
||||||
String fileName = getPhotoPath(files, file.getOriginalFilename());
|
|
||||||
String fullName = photoFolder + "/" + fileName;
|
|
||||||
file.transferTo(new File(fullName));
|
|
||||||
log.info("сохранено фото {}", fileName);
|
|
||||||
return "/assets/cocktails/" + fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getPhotoPath(List<File> files, String originalName) {
|
private String getPhotoPath(List<File> files, String originalName) {
|
||||||
if (files.stream().map(File::getName).anyMatch(name -> name.equals(originalName))) {
|
if (files.stream().map(File::getName).anyMatch(name -> name.equals(originalName))) {
|
||||||
String[] split = originalName.split("\\.");
|
String[] split = originalName.split("\\.");
|
||||||
@@ -368,24 +300,65 @@ public class CocktailService {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(Long id) {
|
|
||||||
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
|
|
||||||
log.info("Удален коктейль {}", cocktail);
|
|
||||||
repository.delete(cocktail);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String findInstructions(Long id) {
|
//todo: оставить до написания функции в БД
|
||||||
CocktailEntity cocktail = repository.findById(id).orElseThrow(RuntimeException::new);
|
// private List<CocktailEntity> criteria(CocktailFilterRequestDto dto) {
|
||||||
return cocktail.getInstructions();
|
// Instant now = Instant.now();
|
||||||
}
|
// Session session = entityManager.unwrap(Session.class);
|
||||||
|
// CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||||
|
// CriteriaQuery<CocktailEntity> criteriaQuery = cb.createQuery(CocktailEntity.class);
|
||||||
|
// Root<CocktailEntity> root = criteriaQuery.from(CocktailEntity.class);
|
||||||
|
// List<Predicate> predicates = new ArrayList<>();
|
||||||
|
//
|
||||||
|
// criteriaQuery.distinct(true);
|
||||||
|
// if (!dto.getAll()) {
|
||||||
|
// Predicate pr = cb.isTrue(root.get("allowed"));
|
||||||
|
// predicates.add(pr);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!dto.getSearch().isEmpty()) {
|
||||||
|
// String[] search = dto.getSearch().split(" ");
|
||||||
|
// List<Predicate> in = new ArrayList<>();
|
||||||
|
// Join<CocktailEntity, ReceiptEntity> receiptJoin = root.join("receipt", JoinType.LEFT);
|
||||||
|
// for (String s : search) {
|
||||||
|
// in.add(cb.like(cb.lower(root.get("name")), "%" + s.toLowerCase() + "%"));
|
||||||
|
// in.add(cb.like(cb.lower(receiptJoin.get("ingredient").get("name")), "%" + s.toLowerCase() + "%"));
|
||||||
|
// }
|
||||||
|
// predicates.add(cb.or(in.toArray(new Predicate[0])));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (dto.getOnlyFavourite()) {
|
||||||
|
// predicates.add(cb.isTrue(root.get("isFavorite")));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (dto.getGlass() != null && !dto.getGlass().isEmpty()) {
|
||||||
|
// predicates.add(root.get("glass").in(dto.getGlass().stream().map(Glass::findValue).toList()));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (dto.getCategory() != null && !dto.getCategory().isEmpty()) {
|
||||||
|
// predicates.add(root.get("category").in(dto.getCategory().stream().map(Category::findValue).toList()));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (dto.getAlcohol() != null && !dto.getAlcohol().isEmpty()) {
|
||||||
|
// predicates.add(root.get("alcoholic").in(dto.getAlcohol().stream().map(Alcoholic::findValue).toList()));
|
||||||
|
// }
|
||||||
|
|
||||||
public List<CocktailForIngredientModalDto> findByIngredient(Long id) {
|
// //todo: доделать другие виды сортировки
|
||||||
return ingredientRepository.findById(id).orElseThrow(RuntimeException::new)
|
// Order order;
|
||||||
.getReceipts()
|
// switch (dto.getSort()) {
|
||||||
.stream()
|
// case NAME_ASC -> order = cb.asc(root.get("name"));
|
||||||
.map(ReceiptEntity::getCocktail)
|
// case NAME_DESC -> order = cb.desc(root.get("name"));
|
||||||
.distinct()
|
// default -> order = cb.asc(root.get("name"));
|
||||||
.map(mapper::cocktailToIngredientDtoList)
|
// }
|
||||||
.toList();
|
//
|
||||||
}
|
// criteriaQuery.where(predicates.toArray(new Predicate[0]))
|
||||||
|
// .orderBy(order);
|
||||||
|
// Query<CocktailEntity> query = session.createQuery(criteriaQuery);
|
||||||
|
// query.setFirstResult(dto.getPage() * dto.getSize());
|
||||||
|
// query.setMaxResults(dto.getSize());
|
||||||
|
// List<CocktailEntity> cocktailEntities = query.getResultList();
|
||||||
|
//
|
||||||
|
// log.info("Найдено {} коктейлей за {} ms", cocktailEntities.size(), Duration.between(now, Instant.now()).toMillis());
|
||||||
|
// return cocktailEntities;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/main/java/ru/kayashov/bar/service/EventService.java
Normal file
23
src/main/java/ru/kayashov/bar/service/EventService.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package ru.kayashov.bar.service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.kayashov.bar.model.entity.Event;
|
||||||
|
import ru.kayashov.bar.repository.EventRepository;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class EventService {
|
||||||
|
|
||||||
|
private final EventRepository eventRepository;
|
||||||
|
private final ExecutorService executorService;
|
||||||
|
|
||||||
|
public void createEvent(Event event) {
|
||||||
|
executorService.submit(() -> {eventRepository.save(event);});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -45,11 +45,13 @@ public class IngredientService {
|
|||||||
*/
|
*/
|
||||||
public List<IngredientResponseDto> getAll() {
|
public List<IngredientResponseDto> getAll() {
|
||||||
List<IngredientEntity> ingredients = repository.findAll();
|
List<IngredientEntity> ingredients = repository.findAll();
|
||||||
|
log.info("По запросу найдено {} ингредиентов", ingredients.size());
|
||||||
return mapper.mapIngredientsToDtoList(ingredients);
|
return mapper.mapIngredientsToDtoList(ingredients);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IngredientSimpleResponseDto> getAllSimple() {
|
public List<IngredientSimpleResponseDto> getAllSimple() {
|
||||||
List<IngredientEntity> ingredients = repository.findAll();
|
List<IngredientEntity> ingredients = repository.findAll();
|
||||||
|
log.info("По запросу найдено {} ингредиентов", ingredients.size());
|
||||||
return mapper.mapIngredientsToSimpleDtoList(ingredients);
|
return mapper.mapIngredientsToSimpleDtoList(ingredients);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,25 +62,44 @@ public class IngredientService {
|
|||||||
public void changeBarIngredient(Long id, boolean isHave) {
|
public void changeBarIngredient(Long id, boolean isHave) {
|
||||||
BarEntity bar = barEntityRepository.findByActiveTrue().orElseThrow();
|
BarEntity bar = barEntityRepository.findByActiveTrue().orElseThrow();
|
||||||
IngredientEntity ingredientEntity = getIngredientById(id);
|
IngredientEntity ingredientEntity = getIngredientById(id);
|
||||||
|
|
||||||
if (isHave) {
|
|
||||||
bar.getIngredients().add(ingredientEntity);
|
|
||||||
} else {
|
|
||||||
bar.getIngredients().remove(ingredientEntity);
|
|
||||||
}
|
|
||||||
ingredientEntity.setIsHave(isHave);
|
ingredientEntity.setIsHave(isHave);
|
||||||
ingredientRepository.save(ingredientEntity);
|
ingredientRepository.save(ingredientEntity);
|
||||||
|
|
||||||
|
List<CocktailEntity> cocktails = ingredientEntity.getReceipts().stream().map(ReceiptEntity::getCocktail).toList();
|
||||||
|
List<CocktailEntity> listForSave;
|
||||||
|
if (isHave) {
|
||||||
|
bar.getIngredients().add(ingredientEntity);
|
||||||
|
listForSave = new ArrayList<>();
|
||||||
|
for (CocktailEntity cocktail : cocktails) {
|
||||||
|
if (cocktail.getReceipt().stream().map(ReceiptEntity::getIngredient).allMatch(IngredientEntity::getIsHave)) {
|
||||||
|
cocktail.setAllowed(true);
|
||||||
|
listForSave.add(cocktail);
|
||||||
|
log.info("Коктейль {} стал доступен", cocktail.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bar.getIngredients().remove(ingredientEntity);
|
||||||
|
listForSave = cocktails.stream().peek(c -> c.setAllowed(false)).toList();
|
||||||
|
log.info("Коктейли {} пропали из доступа", listForSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
cocktailRepository.saveAll(listForSave);
|
||||||
barEntityRepository.save(bar);
|
barEntityRepository.save(bar);
|
||||||
|
|
||||||
|
log.info("Ингредиент {} {}", ingredientEntity.getName(), isHave ? "добавлен в бар" : "удален из бара");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean saveChange(IngredientResponseDto dto) {
|
public boolean saveChange(IngredientResponseDto dto) {
|
||||||
|
IngredientEntity entity;
|
||||||
if (dto.getId() == null) {
|
if (dto.getId() == null) {
|
||||||
return false;
|
entity = new IngredientEntity();
|
||||||
}
|
entity.setIsHave(false);
|
||||||
IngredientEntity entity = repository.findById(dto.getId())
|
} else {
|
||||||
.orElse(null);
|
entity = repository.findById(dto.getId())
|
||||||
if (entity == null) {
|
.orElse(null);
|
||||||
return false;
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entity.setName(dto.getName());
|
entity.setName(dto.getName());
|
||||||
@@ -87,11 +108,12 @@ public class IngredientService {
|
|||||||
entity.setAlcohol(dto.getAlcohol());
|
entity.setAlcohol(dto.getAlcohol());
|
||||||
|
|
||||||
TypeEntity type = findTypeByName(dto.getType());
|
TypeEntity type = findTypeByName(dto.getType());
|
||||||
if (type == null) {
|
// if (type == null) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
entity.setType(type);
|
entity.setType(type);
|
||||||
repository.save(entity);
|
repository.save(entity);
|
||||||
|
log.info("Ингредиент {} {}", entity.getName(), dto.getId() == null ? "создан" : "изменен");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
src/main/java/ru/kayashov/bar/service/ReceiptService.java
Normal file
30
src/main/java/ru/kayashov/bar/service/ReceiptService.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package ru.kayashov.bar.service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
|
||||||
|
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
||||||
|
import ru.kayashov.bar.model.entity.CocktailEntity;
|
||||||
|
import ru.kayashov.bar.repository.CocktailRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ReceiptService {
|
||||||
|
|
||||||
|
private final CocktailRepository cocktailRepository;
|
||||||
|
|
||||||
|
public List<ReceiptResponseDto> getReceiptList(Long cocktailId) {
|
||||||
|
CocktailEntity cocktail = cocktailRepository.findById(cocktailId).orElseThrow();
|
||||||
|
return cocktail.getReceipt().stream()
|
||||||
|
.map(e -> ReceiptResponseDto.builder()
|
||||||
|
.id(e.getId())
|
||||||
|
.ingredient(IngredientSimpleResponseDto.mapToDto(e.getIngredient()))
|
||||||
|
.measure(e.getMeasure())
|
||||||
|
.build())
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package ru.kayashov.bar.service;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ru.kayashov.bar.controller.dto.bar.BarResponseDto;
|
|
||||||
import ru.kayashov.bar.controller.dto.cocktail.ReceiptResponseDto;
|
|
||||||
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
|
||||||
import ru.kayashov.bar.model.entity.BarEntity;
|
|
||||||
import ru.kayashov.bar.model.entity.CocktailEntity;
|
|
||||||
import ru.kayashov.bar.model.entity.IngredientEntity;
|
|
||||||
import ru.kayashov.bar.model.entity.Visitor;
|
|
||||||
import ru.kayashov.bar.repository.BarEntityRepository;
|
|
||||||
import ru.kayashov.bar.repository.CocktailRepository;
|
|
||||||
import ru.kayashov.bar.repository.IngredientRepository;
|
|
||||||
import ru.kayashov.bar.repository.VisitorsRepository;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SessionService {
|
|
||||||
|
|
||||||
private final VisitorsRepository visitorsRepository;
|
|
||||||
private final CocktailRepository cocktailRepository;
|
|
||||||
private final BarEntityRepository barEntityRepository;
|
|
||||||
private final IngredientRepository ingredientRepository;
|
|
||||||
|
|
||||||
public Visitor getVisitor() {
|
|
||||||
Long id = ((Visitor) SecurityContextHolder.getContext()
|
|
||||||
.getAuthentication()
|
|
||||||
.getPrincipal())
|
|
||||||
.getId();
|
|
||||||
return visitorsRepository.findById(id)
|
|
||||||
.orElseThrow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ReceiptResponseDto> getReceiptList(Long cocktailId) {
|
|
||||||
CocktailEntity cocktail = cocktailRepository.findById(cocktailId).orElseThrow();
|
|
||||||
return cocktail.getReceipt().stream()
|
|
||||||
.map(e -> ReceiptResponseDto.builder()
|
|
||||||
.id(e.getId())
|
|
||||||
.ingredient(IngredientSimpleResponseDto.mapToDto(e.getIngredient()))
|
|
||||||
.measure(e.getMeasure())
|
|
||||||
.build())
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void changeActiveBar(Long id) {
|
|
||||||
BarEntity lastBar = barEntityRepository.findByActiveTrue().orElseThrow();
|
|
||||||
lastBar.setActive(false);
|
|
||||||
barEntityRepository.save(lastBar);
|
|
||||||
|
|
||||||
lastBar.getIngredients().stream()
|
|
||||||
.peek(i -> i.setIsHave(false))
|
|
||||||
.forEach(ingredientRepository::save);
|
|
||||||
|
|
||||||
BarEntity barEntity = barEntityRepository.findById(id).orElseThrow();
|
|
||||||
barEntity.setActive(true);
|
|
||||||
|
|
||||||
barEntity.getIngredients().stream()
|
|
||||||
.peek(i -> i.setIsHave(true))
|
|
||||||
.forEach(ingredientRepository::save);
|
|
||||||
|
|
||||||
barEntityRepository.save(barEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<BarResponseDto> findAllBar() {
|
|
||||||
return barEntityRepository.findAll().stream()
|
|
||||||
.map(BarResponseDto::mapToDto)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteBar(Long id) {
|
|
||||||
barEntityRepository.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BarResponseDto createBar(String name) {
|
|
||||||
BarEntity bar = new BarEntity();
|
|
||||||
bar.setName(name);
|
|
||||||
bar.setActive(false);
|
|
||||||
bar = barEntityRepository.save(bar);
|
|
||||||
|
|
||||||
return BarResponseDto.mapToDto(bar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,20 +3,14 @@ package ru.kayashov.bar.service;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.kayashov.bar.model.entity.IngredientEntity;
|
|
||||||
import ru.kayashov.bar.model.entity.Visitor;
|
import ru.kayashov.bar.model.entity.Visitor;
|
||||||
import ru.kayashov.bar.repository.BarEntityRepository;
|
|
||||||
import ru.kayashov.bar.repository.VisitorsRepository;
|
import ru.kayashov.bar.repository.VisitorsRepository;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class VisitorService {
|
public class VisitorService {
|
||||||
|
|
||||||
private final VisitorsRepository visitorsRepository;
|
private final VisitorsRepository visitorsRepository;
|
||||||
private final BarEntityRepository barRepository;
|
|
||||||
|
|
||||||
public Visitor getCurrentVisitor() {
|
public Visitor getCurrentVisitor() {
|
||||||
Long id = ((Visitor) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId();
|
Long id = ((Visitor) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId();
|
||||||
@@ -26,12 +20,4 @@ public class VisitorService {
|
|||||||
public Visitor findById(Long id) {
|
public Visitor findById(Long id) {
|
||||||
return visitorsRepository.findById(id).orElseThrow(() -> new RuntimeException("Visitor not found. id: " + id));
|
return visitorsRepository.findById(id).orElseThrow(() -> new RuntimeException("Visitor not found. id: " + id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getAllowedIngredients() {
|
|
||||||
return barRepository.findByActiveTrue().orElseThrow()
|
|
||||||
.getIngredients()
|
|
||||||
.stream()
|
|
||||||
.map(IngredientEntity::getId)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
package ru.kayashov.bar.service.integration.translate;
|
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.RequestEntity;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import ru.kayashov.bar.model.api.translate.Request;
|
|
||||||
import ru.kayashov.bar.model.api.translate.Response;
|
|
||||||
import ru.kayashov.bar.model.api.translate.Translate;
|
|
||||||
import ru.kayashov.bar.service.RestUtil;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@UtilityClass
|
|
||||||
public class TranslateService {
|
|
||||||
|
|
||||||
private static final String TOKEN = "t1.9euelZrJyoyTmZGQyc2TiZCWlYyLiu3rnpWazsubi8vOzcycms6Znc2dkI7l8_dgXlNC-e9UAyJ4_t3z9yANUUL571QDInj-zef1656Vms2Uio2JmJ6OxpucmoqNjZ6J7_zF656Vms2Uio2JmJ6OxpucmoqNjZ6J.uXSVsrpZcSgQ9qz0-wx6WR79rvq14QCtlC6tnWvah33YRrNqSEBFXBwqMoEq18nG3wHElKE4NsHXK3lxV9SSBQ";
|
|
||||||
|
|
||||||
public static String translate(String text) {
|
|
||||||
return sendTranslate(text)
|
|
||||||
.map(TranslateService::getTranslateText)
|
|
||||||
.orElseThrow(RuntimeException::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String softTranslate(String text) {
|
|
||||||
Optional<ResponseEntity<Response>> opt = sendTranslate(text);
|
|
||||||
if(opt.isPresent()) {
|
|
||||||
return TranslateService.getTranslateText(opt.get());
|
|
||||||
} else {
|
|
||||||
log.warn("Не удалось перевести текст {}", text);
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<ResponseEntity<Response>> sendTranslate(String text) {
|
|
||||||
return RestUtil.sendRequest(Response.class,
|
|
||||||
RequestEntity.post("https://translate.api.cloud.yandex.net/translate/v2/translate")
|
|
||||||
.header("Authorization", "Bearer " + TOKEN)
|
|
||||||
.body(new Request(List.of(text))));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getTranslateText(ResponseEntity<Response> response) {
|
|
||||||
Response resp = response.getBody();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
List<Translate> translates = resp.getTranslations();
|
|
||||||
for(Translate translate : translates) {
|
|
||||||
sb.append(translate.getText());
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,9 +3,9 @@ spring.application.name=myBar
|
|||||||
cocktail.photo.path=${COCKTAIL_PHOTO_PATH:/mnt/sdb1/my-bar-front/build/assets/cocktails}
|
cocktail.photo.path=${COCKTAIL_PHOTO_PATH:/mnt/sdb1/my-bar-front/build/assets/cocktails}
|
||||||
|
|
||||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||||
spring.datasource.url=${DB_URL:jdbc:postgresql://192.168.1.100:5432/drinks}
|
spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:5433/drink}
|
||||||
spring.datasource.username=${DB_NAME:nextcloud}
|
spring.datasource.username=${DB_NAME:postgres}
|
||||||
spring.datasource.password=${DB_PASSWORD:kayash73}
|
spring.datasource.password=${DB_PASSWORD:pgpass}
|
||||||
spring.datasource.hikari.minimum-idle=15
|
spring.datasource.hikari.minimum-idle=15
|
||||||
spring.datasource.hikari.maximum-pool-size=50
|
spring.datasource.hikari.maximum-pool-size=50
|
||||||
spring.datasource.hikari.idle-timeout=30000
|
spring.datasource.hikari.idle-timeout=30000
|
||||||
@@ -15,4 +15,6 @@ spring.jpa.generate-ddl=true
|
|||||||
|
|
||||||
token.signing.key=${SIGNING_KEY:ThisIsKayashovBarSecretKey-1.0.0Version}
|
token.signing.key=${SIGNING_KEY:ThisIsKayashovBarSecretKey-1.0.0Version}
|
||||||
|
|
||||||
spring.jpa.show-sql=false
|
spring.jpa.show-sql=false
|
||||||
|
|
||||||
|
#server.port=8081
|
||||||
Reference in New Issue
Block a user