initial commit

This commit is contained in:
Kayashov.SM
2026-01-30 20:09:37 +04:00
parent f34a7eced5
commit 1c08be1d07
132 changed files with 24439 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
import {createLogger} from "./Logger";
import {config} from "../Config";
export const logger = createLogger({ level: config.logLevel });

65
front/src/lib/Logger.js Normal file
View File

@@ -0,0 +1,65 @@
/* eslint-disable no-console -- Allow */
// NOTE: A tracking system such as Sentry should replace the console
export const LogLevel = {NONE: 'NONE', ERROR: 'ERROR', WARN: 'WARN', DEBUG: 'DEBUG', ALL: 'ALL'};
const LogLevelNumber = {NONE: 0, ERROR: 1, WARN: 2, DEBUG: 3, ALL: 4};
export class Logger {
prefix;
level;
showLevel;
levelNumber;
constructor({prefix = '', level = LogLevel.ALL, showLevel = true}) {
this.prefix = prefix;
this.level = level;
this.levelNumber = LogLevelNumber[this.level];
this.showLevel = showLevel;
}
debug = (...args) => {
if (this.canWrite(LogLevel.DEBUG)) {
this.write(LogLevel.DEBUG, ...args);
}
};
warn = (...args) => {
if (this.canWrite(LogLevel.WARN)) {
this.write(LogLevel.WARN, ...args);
}
};
error = (...args) => {
if (this.canWrite(LogLevel.ERROR)) {
this.write(LogLevel.ERROR, ...args);
}
};
canWrite(level) {
return this.levelNumber >= LogLevelNumber[level];
}
write(level, ...args) {
let prefix = this.prefix;
if (this.showLevel) {
prefix = `- ${level} ${prefix}`;
}
if (level === LogLevel.ERROR) {
console.error(prefix, ...args);
} else {
console.log(prefix, ...args);
}
}
}
// This can be extended to create context specific logger (Server Action, Router Handler, etc.)
// to add context information (IP, User-Agent, timestamp, etc.)
export function createLogger({prefix, level} = {}) {
return new Logger({prefix, level});
}

View File

@@ -0,0 +1,45 @@
import {api} from "./api";
import {requests} from "../../requests";
class AuthClient {
async signOut() {
localStorage.removeItem("token");
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();

View 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();

View 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();

View 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();

View 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();

View 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.bar.ingredient}?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()

View File

@@ -0,0 +1,34 @@
import {decodeToken, isExpired} from "react-jwt";
import {requests} from "../../requests";
import axios from "axios";
class TokenUtil {
checkToken(token) {
if (token == null || isExpired(token)) {
return false;
}
this.refreshToken();
return true;
}
getToken() {
return localStorage.getItem("token");
}
refreshToken() {
const decoded = decodeToken(this.getToken());
const currentTime = Date.now() / 1000;
if (decoded.exp - currentTime > 43200) {
return
}
axios.post(requests.auth.refresh, {}, {headers: {'Authorization': this.getToken()}})
.then((r) => {
localStorage.setItem("token", r.data.token)
})
}
}
export const tokenUtil = new TokenUtil();

View File

@@ -0,0 +1,17 @@
import {requests} from "../../requests";
import {api} from "./api";
class UserClient {
async getMe() {
try{
let url = requests.auth.getMe
const response = await api().get(url);
return {data: response.data}
} catch (e) {
return {errorData: e.data}
}
}
}
export const userClient = new UserClient();

View File

@@ -0,0 +1,16 @@
import axios from "axios";
import {tokenUtil} from "./TokenUtil";
const host = "localhost:8080"; //дебаг вместе с беком
// const host = "192.168.1.100:8091"; //дебаг фронта
// const host = "bar.kayashov.keenetic.pro"; //прод
export const api = () => {
const result = axios;
result.defaults.baseURL = `${window.location.protocol}//${host}/`;
if (tokenUtil.checkToken(tokenUtil.getToken())) {
result.defaults.headers.common["Authorization"] = "Bearer " + tokenUtil.getToken();
} else {
delete result.defaults.headers.common
}
return result;
}

View File

@@ -0,0 +1,11 @@
export function getSiteURL() {
let url =
process.env.NEXT_PUBLIC_SITE_URL ?? // Set this to your site URL in production env.
process.env.NEXT_PUBLIC_VERCEL_URL ?? // Automatically set by Vercel.
'http://localhost:3000/';
// Make sure to include `https://` when not localhost.
url = url.includes('http') ? url : `https://${url}`;
// Make sure to include a trailing `/`.
url = url.endsWith('/') ? url : `${url}/`;
return url;
}