добавлена страница калькулятора
This commit is contained in:
@@ -13,6 +13,7 @@ import {EditIngredientPage} from "./pages/ingredients/EditIngredientPage";
|
||||
import {EditCocktailPage} from "./pages/cocktails/EditCocktailPage";
|
||||
import {useEffect, useState} from "react";
|
||||
import {BarChangePage} from "./pages/BarChangePage";
|
||||
import {CalcPage} from "./pages/calc/CalcPage";
|
||||
|
||||
export function NavigationRoutes() {
|
||||
const {auth} = useAuth();
|
||||
@@ -59,6 +60,11 @@ const authPages = [
|
||||
children: (<LoginPage/>),
|
||||
isPrivate: false,
|
||||
},
|
||||
{
|
||||
path: paths.bar.calc,
|
||||
children: (<CalcPage/>),
|
||||
isPrivate: true,
|
||||
},
|
||||
{
|
||||
path: paths.dashboard.overview,
|
||||
isPrivate: true,
|
||||
@@ -96,11 +102,16 @@ const authPages = [
|
||||
|
||||
const guestPages = [
|
||||
{
|
||||
path: paths.home,
|
||||
isPrivate: false,
|
||||
children: (<HomeRedirect auth={false}/>),
|
||||
path: paths.dashboard.overview,
|
||||
isPrivate: true,
|
||||
children: (<MenuPage/>),
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
children: (<HomeRedirect auth={true}/>),
|
||||
isPrivate: false,
|
||||
path: paths.home,
|
||||
},
|
||||
{
|
||||
path: paths.auth.tg,
|
||||
isPrivate: false,
|
||||
|
||||
110
front/src/app/pages/calc/CalcPage.js
Normal file
110
front/src/app/pages/calc/CalcPage.js
Normal file
@@ -0,0 +1,110 @@
|
||||
import Typography from "@mui/material/Typography";
|
||||
import * as React from "react";
|
||||
import {useEffect, useMemo} from "react";
|
||||
import {api} from "../../../lib/clients/api";
|
||||
import {requests} from "../../../requests";
|
||||
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";
|
||||
|
||||
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(() => {
|
||||
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.map((d) => {
|
||||
map[d.id] = 1
|
||||
})
|
||||
setCocktailMap(map);
|
||||
setLoad(true);
|
||||
})
|
||||
.catch((r) => {
|
||||
setLoad(true);
|
||||
createError("Ошибка загрузки данных от сервера Status:" + r.code)
|
||||
})
|
||||
// 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);
|
||||
}
|
||||
|
||||
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, height: '250px', 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';
|
||||
|
||||
// Стилизуем контейнер счетчика
|
||||
const CounterContainer = 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>
|
||||
)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user