feat: limity skupinových objednávek nastavitelné přes env
CI / Generate TypeScript types (push) Successful in 12s
CI / Server unit tests (push) Successful in 25s
CI / Build server (push) Successful in 30s
CI / Build client (push) Successful in 39s
CI / Playwright E2E tests (push) Successful in 3m55s
CI / Build and push Docker image (push) Successful in 49s
CI / Notify (push) Successful in 2s
CI / Generate TypeScript types (push) Successful in 12s
CI / Server unit tests (push) Successful in 25s
CI / Build server (push) Successful in 30s
CI / Build client (push) Successful in 39s
CI / Playwright E2E tests (push) Successful in 3m55s
CI / Build and push Docker image (push) Successful in 49s
CI / Notify (push) Successful in 2s
This commit is contained in:
15 files changed
+386
-28
No files matched your search
@@ -0,0 +1,34 @@
|
||||
import type { GroupLimits } from "../../../types";
|
||||
|
||||
/**
|
||||
* Runtime konfigurace ze serveru (GET /api/config). Do načtení (nebo když endpoint
|
||||
* neodpoví) platí výchozí hodnoty — stejné jako výchozí hodnoty na serveru (server/src/limits.ts).
|
||||
*/
|
||||
export const DEFAULT_GROUP_LIMITS: GroupLimits = {
|
||||
maxNoteLength: 300,
|
||||
maxSurchargeTextLength: 100,
|
||||
maxNameLength: 100,
|
||||
maxUrlLength: 500,
|
||||
maxAmountKc: 10_000,
|
||||
maxItemQuantity: 10,
|
||||
maxItems: 20,
|
||||
};
|
||||
|
||||
let groupLimits: GroupLimits = DEFAULT_GROUP_LIMITS;
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
export function getGroupLimits(): GroupLimits {
|
||||
return groupLimits;
|
||||
}
|
||||
|
||||
/** Nastaví limity ze serveru (chybějící hodnoty doplní výchozími) a upozorní odběratele. */
|
||||
export function setGroupLimits(limits: Partial<GroupLimits> | undefined): void {
|
||||
if (!limits) return;
|
||||
groupLimits = { ...DEFAULT_GROUP_LIMITS, ...limits };
|
||||
listeners.forEach(l => l());
|
||||
}
|
||||
|
||||
export function subscribeGroupLimits(listener: () => void): () => void {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { StoreMenuDish } from "../../../types";
|
||||
import type { GroupLimits, StoreMenuDish } from "../../../types";
|
||||
import { getGroupLimits } from "./appConfig";
|
||||
|
||||
/** Normalizace pro porovnání: malá písmena, bez diakritiky, emoji, čísel položek („28." / „13A.") a interpunkce. */
|
||||
export function normalizeDishName(text: string): string {
|
||||
@@ -121,3 +122,26 @@ export function addNoteItem(note: string | undefined, dishName: string, menu: St
|
||||
parts[index] = `${existing.quantity + 1}x ${existing.rest.trim()}`;
|
||||
return parts.join(' + ');
|
||||
}
|
||||
|
||||
|
||||
/** Kolik kusů daného jídla už poznámka obsahuje (0 = není tam). */
|
||||
export function noteItemQuantity(note: string | undefined, dishName: string, menu: StoreMenuDish[] = []): number {
|
||||
const target = normalizeDishName(dishName);
|
||||
const part = splitNoteItems(note, menu).find(p => normalizeDishName(p) === target || normalizeDishName(parseQuantity(p).rest) === target);
|
||||
if (!part) return 0;
|
||||
return normalizeDishName(part) === target ? 1 : parseQuantity(part).quantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrátí důvod, proč jídlo nejde přidat (limit kusů/položek — pojistky proti překlepům,
|
||||
* hodnoty z konfigurace serveru), jinak undefined.
|
||||
*/
|
||||
export function addItemLimitError(note: string | undefined, dishName: string, menu: StoreMenuDish[] = [], limits: GroupLimits = getGroupLimits()): string | undefined {
|
||||
if (noteItemQuantity(note, dishName, menu) >= limits.maxItemQuantity) {
|
||||
return `Jedné položky lze přidat nejvýše ${limits.maxItemQuantity} kusů`;
|
||||
}
|
||||
if (countNoteItems(note, menu) >= limits.maxItems) {
|
||||
return `Objednávka může mít nejvýše ${limits.maxItems} položek`;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
Reference in new issue
Block a user