Initial commit
This commit is contained in:
7
front/src/app/pages/cocktails/AllCocktailsPage.js
Normal file
7
front/src/app/pages/cocktails/AllCocktailsPage.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import CocktailsPageContent from "./CocktailsPageContent";
|
||||
|
||||
export function AllCocktailsPage() {
|
||||
return (
|
||||
<CocktailsPageContent all={true}/>
|
||||
)
|
||||
}
|
||||
127
front/src/app/pages/cocktails/CocktailMenuBarPage.js
Normal file
127
front/src/app/pages/cocktails/CocktailMenuBarPage.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import Toolbar from "@mui/material/Toolbar";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import {Fab, FormControl, FormControlLabel, InputAdornment, InputLabel, OutlinedInput} from "@mui/material";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import {blue} from "@mui/material/colors";
|
||||
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
|
||||
import {Loading} from "../../../components/core/Loading";
|
||||
import * as React from "react";
|
||||
import {useEffect, useMemo, useState} from "react";
|
||||
import {CocktailsList} from "../../../components/cocktails/CocktailsList";
|
||||
import {requests} from "../../../requests";
|
||||
import {api} from "../../../lib/clients/api";
|
||||
import {useAlert} from "../../../hooks/useAlert";
|
||||
import {CocktailInfoModal} from "../../../components/cocktails/CocktailInfoModal";
|
||||
|
||||
export function CocktailMenuBarPage() {
|
||||
const {createError} = useAlert();
|
||||
const [grouping, setGrouping] = useState(true);
|
||||
const [findString, setFindString] = useState("");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [cocktails, setCocktails] = useState([]);
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
const [selected, setSelected] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
api().get(`${requests.cocktails.menu}?all=true`)
|
||||
.then((r) => {
|
||||
setCocktails(r.data);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => createError("Ошибка получения данных"))
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
|
||||
const handleOpenModal = (row) => {
|
||||
setSelected(row)
|
||||
setOpenModal(true);
|
||||
}
|
||||
const changeHandler = (row, value) => {
|
||||
const newState = cocktails.map((r) => {
|
||||
if(r.id !== row.id) {
|
||||
return r;
|
||||
}
|
||||
return {
|
||||
...r,
|
||||
inMenu: value
|
||||
}
|
||||
});
|
||||
api().post(`${requests.cocktails.menu}?id=${row.id}&value=${value}`)
|
||||
.then(() => {
|
||||
setCocktails(newState);
|
||||
}).catch(() => createError("Ошибка сохранения данных"))
|
||||
}
|
||||
|
||||
const visibleRows = useMemo(() => {
|
||||
if (findString === "") {
|
||||
return cocktails;
|
||||
}
|
||||
let regExp = new RegExp("(.*?)" + findString + "(.*?)", "i");
|
||||
return cocktails
|
||||
.filter((row) => row.name.split(" ").map((n) => n.match(regExp) !== null).includes(true))
|
||||
// eslint-disable-next-line
|
||||
}, [cocktails, findString])
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/*Заголовок*/}
|
||||
<Toolbar>
|
||||
<Typography variant="h6" component="div" sx={{flexGrow: 1}}>Меню бара</Typography>
|
||||
</Toolbar>
|
||||
{/*Поиск*/}
|
||||
<Paper elevation={6} sx={{my: 2}}>
|
||||
<FormControl sx={{m: 1, width: 'calc(100% - 20px'}}>
|
||||
<InputLabel htmlFor="outlined-adornment-amount">Поиск</InputLabel>
|
||||
<OutlinedInput
|
||||
onChange={(e) => setFindString(e.target.value)}
|
||||
label="With normal TextField"
|
||||
startAdornment={
|
||||
<InputAdornment position="start">
|
||||
<IconButton edge="end">
|
||||
<SearchIcon/>
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControlLabel sx={{ml: '2px'}}
|
||||
control={<Switch defaultChecked/>}
|
||||
onClick={() => setGrouping(!grouping)}
|
||||
label="Группировать"
|
||||
labelPlacement="end"/>
|
||||
</Paper>
|
||||
{/*Рабочее поле коктейлей*/}
|
||||
<CocktailsList rows={visibleRows} changeHandler={changeHandler}
|
||||
infoHandler={handleOpenModal} grouping={grouping}/>
|
||||
{/*Иконка возврата наверх*/}
|
||||
<Fab sx={{
|
||||
alpha: '30%',
|
||||
position: 'sticky',
|
||||
bottom: '16px',
|
||||
color: 'common.white',
|
||||
bgcolor: blue[600],
|
||||
'&:hover': {
|
||||
bgcolor: blue[600],
|
||||
},
|
||||
}}
|
||||
onClick={() => window.window.scrollTo(0, 0)}
|
||||
aria-label='Expand'
|
||||
color='inherit'>
|
||||
<UpIcon/>
|
||||
</Fab>
|
||||
{/*Загрузчик*/}
|
||||
<Loading loading={loading}/>
|
||||
{/*Модальное окно информации об ингредиенте*/}
|
||||
<CocktailInfoModal open={openModal} row={selected}
|
||||
closeHandler={() => {
|
||||
setSelected(null);
|
||||
setOpenModal(false);
|
||||
}}/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
333
front/src/app/pages/cocktails/CocktailsPageContent.js
Normal file
333
front/src/app/pages/cocktails/CocktailsPageContent.js
Normal file
@@ -0,0 +1,333 @@
|
||||
import Grid from "@mui/material/Grid";
|
||||
import {useAlert} from "../../../hooks/useAlert";
|
||||
import * as React from "react";
|
||||
import {useCallback, useEffect, useState} from "react";
|
||||
import {Cocktail} from "../../../components/cocktails/Cocktail";
|
||||
import {Fab, Skeleton} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import {requests} from "../../../requests";
|
||||
import {NoResult} from "../../../components/cocktails/NoResult";
|
||||
import {FilterBlock} from "../../../components/cocktails/FilterBlock";
|
||||
import {api} from "../../../lib/clients/api";
|
||||
import {CocktailInfoModal} from "../../../components/cocktails/CocktailInfoModal";
|
||||
import {useUser} from "../../../hooks/useUser";
|
||||
import {blue} from "@mui/material/colors";
|
||||
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
|
||||
import {sortList} from "../../../components/cocktails/sortingList";
|
||||
import {getComparator} from "../../../components/core/getComparator";
|
||||
import Button from "@mui/material/Button";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import CheckMarks from "../../../components/cocktails/CheckMarks";
|
||||
|
||||
const filterList = (rows, filter, allowIngredients) => {
|
||||
let regExp = new RegExp("(.*?)" + filter.search + "(.*?)", "i");
|
||||
const sortingObj = sortList.find((s) => s.name === filter.sorting);
|
||||
const sortingValues = sortingObj.id.split("|");
|
||||
return rows
|
||||
.filter((row) => {
|
||||
const nameReg = row.name.split(" ").map((n) => n.match(regExp) !== null).includes(true);
|
||||
const ingredientReg = row.components
|
||||
.split(", ")
|
||||
.map((r) => r.match(regExp) !== null)
|
||||
.includes(true);
|
||||
return nameReg || ingredientReg;
|
||||
})
|
||||
.filter((row) => filter.onlyFavourite ? row.rating.favourite : true)
|
||||
.filter((row) => filter.glass.length === 0 || filter.glass.includes(row.glass))
|
||||
.filter((row) => filter.category.length === 0 || filter.category.includes(row.category))
|
||||
.filter((row) => filter.alcohol.length === 0 || filter.alcohol.includes(row.alcoholic))
|
||||
.filter((row) => {
|
||||
if (filter.tags.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (row.tags.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return row.tags.split(",").find((tag) => filter.tags.includes(tag))
|
||||
})
|
||||
.filter((row) => {
|
||||
if (filter.iCount.length === 0) {
|
||||
return true;
|
||||
}
|
||||
const arr = row.components.split(", ");
|
||||
const count = arr.filter((n) => !allowIngredients.includes(n)).length;
|
||||
const filt = filter.ingredient.length === 0 || arr.filter((n) => filter.ingredient.includes(n)).length > 0;
|
||||
|
||||
return filter.iCount === count && filt;
|
||||
})
|
||||
.filter((row) => {
|
||||
if (filter.inMenu === "") {
|
||||
return row;
|
||||
}
|
||||
const filterValue = filter.inMenu === "Есть в меню";
|
||||
return filterValue === row.inMenu;
|
||||
})
|
||||
.sort(getComparator(sortingValues[1], sortingValues[0], "name"))
|
||||
}
|
||||
|
||||
const emptyFilter = {
|
||||
search: "",
|
||||
hidden: true,
|
||||
onlyFavourite: false,
|
||||
glass: [],
|
||||
category: [],
|
||||
alcohol: [],
|
||||
tags: [],
|
||||
iCount: [],
|
||||
ingredient: [],
|
||||
inMenu: "",
|
||||
sorting: "Название по возрастанию"
|
||||
}
|
||||
|
||||
const CocktailsPageContent = ({all}) => {
|
||||
const {user} = useUser();
|
||||
const {createError, createSuccess} = useAlert();
|
||||
const [allowIngredients, setAllowIngredients] = useState([])
|
||||
const [rows, setRows] = useState([]);
|
||||
const [filter, setFilter] = useState(emptyFilter)
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedCocktail, setSelectedCocktail] = useState(null)
|
||||
const [chips, setChips] = useState([])
|
||||
const [page, setPage] = useState(-1);
|
||||
const [load, setLoad] = useState(false);
|
||||
const [isEnd, setIsEnd] = useState(false);
|
||||
const [isNew, setIsNew] = useState(true);
|
||||
|
||||
const loading = useCallback(() => {
|
||||
const size = Math.floor((window.innerWidth) / 350) * 5;
|
||||
if (load || (!isNew && isEnd)) {
|
||||
return false;
|
||||
}
|
||||
setLoad(true);
|
||||
const request = {
|
||||
...filter,
|
||||
all: all,
|
||||
sort: sortList.find((s) => s.name === filter.sorting).id,
|
||||
page: page + 1,
|
||||
size: size,
|
||||
iCount: 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.status)
|
||||
})
|
||||
// eslint-disable-next-line
|
||||
}, [load, isEnd, page]);
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
const {scrollTop, scrollHeight, clientHeight} = document.documentElement;
|
||||
if (scrollTop + clientHeight >= scrollHeight - 100) {
|
||||
loading();
|
||||
}
|
||||
}
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, [loading]);
|
||||
useEffect(() => {
|
||||
api().get(requests.bar.ingredientSimple)
|
||||
.then((r) => {
|
||||
const arr = r.data.filter((i) => i.isHave)
|
||||
.map((i) => i.name)
|
||||
setAllowIngredients(arr)
|
||||
})
|
||||
.catch(() => createError("Ошибка получения ингредиентов"))
|
||||
// eslint-disable-next-line
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
loading();
|
||||
}, [filter])
|
||||
useEffect(() => {
|
||||
if (!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()));
|
||||
}, [rows, allowIngredients])
|
||||
|
||||
const renderSkeleton = () => {
|
||||
return Array.from({length: 3}, () => null)
|
||||
.map((v, index) => <Skeleton sx={{m: 2}}
|
||||
key={index}
|
||||
variant="rounded"
|
||||
width={350}
|
||||
height={690}/>);
|
||||
}
|
||||
const handleChangeRating = (row, value) => {
|
||||
const newState = rows.map((r) => {
|
||||
if (row.id === r.id) {
|
||||
let newRating = r.rating;
|
||||
newRating.rating = value
|
||||
return {
|
||||
...r,
|
||||
rating: newRating
|
||||
}
|
||||
}
|
||||
return r;
|
||||
})
|
||||
api().post(`${requests.cocktails.rating}${row.id}&rating=${value}`)
|
||||
.then(() => {
|
||||
setRows(newState);
|
||||
createSuccess("Спасибо за оценку!")
|
||||
}).catch(() => createError("Ошибка сохранения"))
|
||||
|
||||
}
|
||||
const handleFilterChange = (filterName, value) => {
|
||||
const newState = {
|
||||
...filter,
|
||||
[filterName]: value
|
||||
}
|
||||
setFilter(newState)
|
||||
setIsNew(true);
|
||||
setIsEnd(false);
|
||||
setPage(-1);
|
||||
}
|
||||
const handleFavourite = (row) => {
|
||||
const value = !row.rating.favourite;
|
||||
const newState = rows.map((r) => {
|
||||
if (r.id === row.id) {
|
||||
let newRating = r.rating;
|
||||
newRating.favourite = value;
|
||||
return {
|
||||
...r,
|
||||
rating: newRating
|
||||
}
|
||||
}
|
||||
return r;
|
||||
});
|
||||
let url = `${requests.cocktails.favourite}${row.id}`;
|
||||
let request = value ? api().put(url) : api().delete(url);
|
||||
|
||||
request
|
||||
.then(() => {
|
||||
setRows(newState);
|
||||
createSuccess("Спасибо за оценку!")
|
||||
}).catch(() => createError("Ошибка сохранения"))
|
||||
}
|
||||
const handleFilterClear = () => {
|
||||
setFilter(emptyFilter);
|
||||
}
|
||||
const handleSelectCocktail = (row) => {
|
||||
setSelectedCocktail(row.id)
|
||||
setOpen(true)
|
||||
}
|
||||
const handleCloseCocktailModal = () => {
|
||||
setOpen(false);
|
||||
setSelectedCocktail(null);
|
||||
}
|
||||
const handleEditMenu = (row, value) => {
|
||||
const newState = rows.map((r) => {
|
||||
if (r.id !== row.id) {
|
||||
return r;
|
||||
}
|
||||
if (all) {
|
||||
return {
|
||||
...r,
|
||||
inMenu: value
|
||||
}
|
||||
}
|
||||
return null
|
||||
}).filter((r) => r !== null);
|
||||
|
||||
api().post(`${requests.cocktails.menu}?id=${row.id}&value=${value}`)
|
||||
.then(() => setRows(newState))
|
||||
.catch(() => createError("Ошибка сохранения данных"))
|
||||
}
|
||||
const editMenuBlock = (row) => {
|
||||
if (user.role === "USER" || user.role === "ADMIN_NOT_BARMEN") {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Button color={row.inMenu ? 'error' : 'success'} variant='contained'
|
||||
onClick={() => handleEditMenu(row, !row.inMenu)}>
|
||||
{(row.inMenu ? 'Удалить из' : 'Добавить в') + ' меню'}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/*<Loading loading={load}/>*/}
|
||||
{/*Модальное окно информации о коктейле*/}
|
||||
<CocktailInfoModal row={selectedCocktail} open={open}
|
||||
closeHandler={handleCloseCocktailModal}/>
|
||||
{/*Блок фильтров*/}
|
||||
<FilterBlock
|
||||
filter={filter}
|
||||
handleFilterChange={handleFilterChange}
|
||||
handleClearFilter={handleFilterClear}
|
||||
barmen={user.role !== 'USER'}
|
||||
all={all}
|
||||
/>
|
||||
|
||||
{/*todo: доделать фильтр по количеству недостающих ингредиентов*/}
|
||||
{/*{*/}
|
||||
{/* (all && filter.iCount === 1) && (*/}
|
||||
{/* <Paper sx={{mt: 1}}>*/}
|
||||
{/* <CheckMarks rows={chips} name={"Выбор ингредиента"} filterName={"ingredient"}*/}
|
||||
{/* filterValue={filter.ingredient}*/}
|
||||
{/* handleChange={handleFilterChange}*/}
|
||||
{/* identity*/}
|
||||
{/* />*/}
|
||||
{/* </Paper>*/}
|
||||
{/* )*/}
|
||||
{/*}*/}
|
||||
<Box>
|
||||
{/*Основное содержимое*/}
|
||||
<Grid container rowSpacing={2} columnSpacing={{xs: 1, sm: 1, md: 2}} sx={{m: 1}}>
|
||||
{rows.length > 0 && rows.map((row) => {
|
||||
return (
|
||||
<Cocktail key={row.id} row={row} handleFavourite={handleFavourite}
|
||||
handleChangeRating={handleChangeRating}
|
||||
handleSelect={handleSelectCocktail}
|
||||
editMenuBlock={editMenuBlock}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{load && renderSkeleton()}
|
||||
{rows.length === 0 && (<NoResult/>)}
|
||||
</Grid>
|
||||
</Box>
|
||||
<Fab sx={{
|
||||
alpha: '30%',
|
||||
position: 'sticky',
|
||||
left: 'calc(100% - 16px)',
|
||||
bottom: '16px',
|
||||
color: 'common.white',
|
||||
bgcolor: blue[600],
|
||||
'&:hover': {
|
||||
bgcolor: blue[600],
|
||||
},
|
||||
}}
|
||||
onClick={() => window.window.scrollTo(0, 0)}
|
||||
aria-label='Expand'
|
||||
color='inherit'>
|
||||
<UpIcon/>
|
||||
</Fab>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default CocktailsPageContent;
|
||||
258
front/src/app/pages/cocktails/EditCocktailPage.js
Normal file
258
front/src/app/pages/cocktails/EditCocktailPage.js
Normal file
@@ -0,0 +1,258 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import Toolbar from "@mui/material/Toolbar";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import * as React from "react";
|
||||
import {useEffect, useState} from "react";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import {Autocomplete} from "@mui/material";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {api} from "../../../lib/clients/api";
|
||||
import {requests} from "../../../requests";
|
||||
import {useAlert} from "../../../hooks/useAlert";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Button from "@mui/material/Button";
|
||||
import CheckMarks from "../../../components/cocktails/CheckMarks";
|
||||
import {EditCocktailReceipt} from "../../../components/cocktails/EditCocktailReceipt";
|
||||
import {SelectEdit} from "../../../components/cocktails/SelectEdit";
|
||||
import {getComparator} from "../../../components/core/getComparator";
|
||||
import {useSearchParams} from "react-router-dom";
|
||||
import {Loading} from "../../../components/core/Loading";
|
||||
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
|
||||
import {styled} from "@mui/material/styles";
|
||||
|
||||
const emptyCocktail = {
|
||||
id: null,
|
||||
name: "",
|
||||
alcoholic: "",
|
||||
category: "",
|
||||
components: "",
|
||||
glass: "",
|
||||
image: "",
|
||||
instructions: "",
|
||||
isAllowed: false,
|
||||
rating: {
|
||||
rating: 0,
|
||||
favourite: false
|
||||
},
|
||||
receipt: [],
|
||||
tags: "",
|
||||
video: ""
|
||||
};
|
||||
const alcohol = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Алкогольный"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Безалкогольный",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Опционально"
|
||||
}
|
||||
]
|
||||
const VisuallyHiddenInput = styled('input')({
|
||||
clip: 'rect(0 0 0 0)',
|
||||
clipPath: 'inset(50%)',
|
||||
height: 1,
|
||||
overflow: 'hidden',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
whiteSpace: 'nowrap',
|
||||
width: 1,
|
||||
});
|
||||
|
||||
export function EditCocktailPage() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const {createError, createSuccess, getError} = useAlert();
|
||||
const [cocktails, setCocktails] = useState([]);
|
||||
const [selected, setSelected] = useState(null);
|
||||
const [cocktail, setCocktail] = useState(emptyCocktail);
|
||||
|
||||
const [glass, setGlass] = useState([]);
|
||||
const [category, setCategory] = useState([]);
|
||||
const [tags, setTags] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
api().get(requests.cocktails.simple)
|
||||
.then((r) => {
|
||||
const arr = r.data.sort(getComparator("asc", "name"));
|
||||
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("asc", "name"))))
|
||||
.catch(() => createError("Ошибка получения категорий"))
|
||||
|
||||
api().get(requests.bar.glass)
|
||||
.then((r) => setGlass(r.data.sort(getComparator("asc", "name"))))
|
||||
.catch(() => createError("Ошибка получения посуды"))
|
||||
|
||||
api().get(requests.bar.tags)
|
||||
.then((r) => setTags(r.data.sort(getComparator("asc", "name"))))
|
||||
.catch(() => createError("Ошибка получения тегов"))
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (!selected) {
|
||||
setCocktail(emptyCocktail);
|
||||
return;
|
||||
}
|
||||
api().get(requests.cocktails.cocktail + selected)
|
||||
.then((r) => {
|
||||
setCocktail(r.data)
|
||||
})
|
||||
.catch(() => getError());
|
||||
// eslint-disable-next-line
|
||||
}, [selected])
|
||||
|
||||
const changeCocktailValue = (name, value) => {
|
||||
if (name === "tags") {
|
||||
value = value.join(",");
|
||||
}
|
||||
setCocktail((prev) => ({
|
||||
...prev,
|
||||
[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 (
|
||||
<Box>
|
||||
{/*Загрузка*/}
|
||||
<Loading loading={loading}/>
|
||||
{/*Заголовок*/}
|
||||
<Toolbar>
|
||||
<Typography variant="h6" component="div" sx={{flexGrow: 1}}>Коктейли</Typography>
|
||||
</Toolbar>
|
||||
{/*Поиск*/}
|
||||
<Paper elevation={6} sx={{my: 2, display: 'grid', p: 2}}>
|
||||
<Autocomplete
|
||||
disablePortal
|
||||
options={cocktails}
|
||||
onChange={(e, v) => {
|
||||
if (!v) {
|
||||
setCocktail(emptyCocktail);
|
||||
setSelected(null)
|
||||
} else {
|
||||
setSelected(v.id)
|
||||
}
|
||||
}}
|
||||
isOptionEqualToValue={(selected, value) => selected.id === value.id}
|
||||
getOptionKey={(selected) => selected.id}
|
||||
getOptionLabel={(selected) => selected.name + (selected.hasError ? " (есть ошибка)" : "")}
|
||||
renderInput={(params) => <TextField {...params} label="Поиск"/>}
|
||||
/>
|
||||
</Paper>
|
||||
{/*Рабочая область*/}
|
||||
<Paper elevation={6} sx={{my: 2, display: 'grid', p: 1, pb: 2}}>
|
||||
<Stack>
|
||||
<Box hidden={cocktail.id === null} ml={1} mb={1}>
|
||||
<Button color='error' onClick={() => deleteHandle()}>Удалить коктейль</Button>
|
||||
</Box>
|
||||
{/*Фото*/}
|
||||
<Box ml={1}>
|
||||
<img src={cocktail.image} alt={""} width={300} height={300} loading={'eager'}/>
|
||||
</Box>
|
||||
{/*Редактирование ссылки на фото*/}
|
||||
<Stack direction='row' pr={2} m={1} display='relative'>
|
||||
<TextField sx={{width: '75%'}}
|
||||
label={"Ссылка на фото"} variant='outlined' multiline
|
||||
value={!cocktail.image ? "" : cocktail.image}
|
||||
onChange={(e) => changeCocktailValue("image", e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
component="label"
|
||||
role={undefined}
|
||||
variant="contained"
|
||||
tabIndex={-1}
|
||||
startIcon={<CloudUploadIcon/>}
|
||||
sx={{width: '10%', fontSize: 40, ml: 1, pr: 1}}
|
||||
>
|
||||
<VisuallyHiddenInput
|
||||
type="file"
|
||||
accept=".jpg,.jpeg,.png"
|
||||
onChange={(event) => {
|
||||
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>
|
||||
|
||||
</Stack>
|
||||
{/*Название*/}
|
||||
<Box m={1}>
|
||||
<TextField sx={{mr: 1, mb: 2, minWidth: 300}}
|
||||
variant="outlined" label={"Название"}
|
||||
value={cocktail.name}
|
||||
onChange={(e) => changeCocktailValue("name", e.target.value)}/>
|
||||
</Box>
|
||||
{/*Категория, посуда, алкогольность, теги*/}
|
||||
<Box mb={2}>
|
||||
<SelectEdit value={cocktail.category} label={"Категория"} width={300} margin={1}
|
||||
array={category}
|
||||
attributeName={"category"} handler={changeCocktailValue}/>
|
||||
<SelectEdit value={cocktail.glass} label={"Посуда"} width={300} margin={1} array={glass}
|
||||
attributeName={"glass"} handler={changeCocktailValue}/>
|
||||
<SelectEdit value={cocktail.alcoholic} label={"Алкогольность"} width={300} margin={1}
|
||||
array={alcohol}
|
||||
attributeName={"alcoholic"} handler={changeCocktailValue}/>
|
||||
<CheckMarks rows={tags} width={300} name={"Теги"} handleChange={changeCocktailValue}
|
||||
filterValue={cocktail.tags.split(",")} filterName={"tags"}/>
|
||||
</Box>
|
||||
{/*Рецепт*/}
|
||||
<EditCocktailReceipt receipt={cocktail.receipt} handler={changeCocktailValue}/>
|
||||
|
||||
<Box pr={2} ml={1}>
|
||||
<TextField sx={{width: '100%'}}
|
||||
label={"Инструкция"} variant='outlined' multiline
|
||||
value={!cocktail.instructions ? "" : cocktail.instructions}
|
||||
onChange={(e) => changeCocktailValue("instructions", e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Box display={'flex'} justifyContent={'flex-end'}>
|
||||
<Button variant='contained' onClick={() => saveHandler()}>Сохранить</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
7
front/src/app/pages/cocktails/MenuPage.js
Normal file
7
front/src/app/pages/cocktails/MenuPage.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import CocktailsPageContent from "./CocktailsPageContent";
|
||||
|
||||
export function MenuPage() {
|
||||
return (
|
||||
<CocktailsPageContent all={false}/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user