caterium-app/ops/demo/trial-banquet-data.mjs
pavlov346346-source 40b5c146c2 feat: add photos for the 34 training-catalog items that had none
The banquet menu (18 dishes) and extras/supplies/delivery items (16)
in the training catalog were seeded with photo:'', which the catalog
tiles render as a plain red placeholder square. Sourced a real photo
for each item (mostly Pexels, free license, picked and visually
reviewed one by one to avoid mismatches -- several first search hits
were wrong: a live chicken for "chicken caesar salad", a person in
frame, branded bottles/cups) and two AI-generated (banquet-caprese,
banquet-roastbeef). Converted to square 1024x1024 WebP with sharp.

Wires the paths through the actual source of truth: ops/demo/trial-
banquet-data.mjs and trial-extras-data.mjs now set photo to the real
path, then ops/demo/build-trial-*.mjs regenerated public/demo/*.json
and the matching Supabase seed-function migrations, so the client's
static JSON fetch and the server-side company-provisioning function
stay in sync.

Bumped the demo-catalog fetch's own cache-busting query string in
training-catalog.js (and its script-tag/precache version), since it's
fetched by the client with a separate version from the outer script
tags -- the same stale-cache class of bug fixed earlier this session.

Verified: all 34 referenced files resolve (200) and decode as real
1024x1024 images; confirmed via the actual rendered catalog tiles
(#tiles img[src]) that the extras category -- where the user's
red-square screenshot was taken -- now serves the real photo paths.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 17:00:45 +03:00

78 lines
9.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Fictional one-portion recipes. Reuse the original demo stock without resetting it.
import {stock as boxStock} from './trial-demo-data.mjs';
const extra=[
['potato','Картофель',80,'fresh'],['butter','Масло сливочное',1100,'fresh'],
['milk','Молоко',110,'fresh'],['egg','Яйцо куриное без скорлупы',260,'fresh'],
['peas','Горошек зелёный консервированный',300,'grocery'],
['chicken-raw','Филе куриное сырое',480,'protein'],['whitefish','Филе трески',950,'protein'],
['lemon','Лимон',300,'fresh'],['rice','Рис сухой',180,'grocery']
].map(([key,name,cost,supplier])=>({id:`demo-banquet-v1-stock-${key}`,name,cost,unit:'кг',qty:0,min:0.1,supplierId:`demo-v1-supplier-${supplier}`,lastPurchaseDate:'',lastPurchasePrice:0}));
const products=new Map([...boxStock.map(p=>[p.id.replace('demo-v1-stock-',''),p]),...extra.map(p=>[p.id.replace('demo-banquet-v1-stock-',''),p])]);
// Gross / prepared net grams per guest; water absorbed by rice is described separately.
const recipes=[
['caprese','Капрезе с моцареллой и базиликом','Холодные закуски',290,
[['mozzarella',50,50],['tomato',70,60],['basil',6,5],['oil',5,5]],['Молоко'],
['Нарезать томаты и моцареллу.','Выложить слоями, добавить базилик и масло.']],
['roastbeef','Ростбиф с корнишонами и горчичным соусом','Холодные закуски',390,
[['beef',65,65],['pickle',22,20],['mustard',5,5],['cooking-cream',10,10]],['Молоко','Горчица'],
['Нарезать готовый ростбиф тонкими ломтиками.','Смешать сливки с горчицей, подать с корнишонами.']],
['salmon-roll','Рулетики из лосося со сливочным сыром','Холодные закуски',350,
[['salmon',45,45],['cream',25,25],['cucumber',22,18],['dill',3,2]],['Рыба','Молоко'],
['Нарезать лосось и огурец тонкими ломтиками.','Распределить сыр, свернуть рулетики, украсить укропом.']],
['hummus','Овощные палочки с хумусом','Холодные закуски',230,
[['carrot',48,40],['cucumber',44,40],['pepper',40,30],['hummus',50,50]],['Кунжут в составе хумуса'],
['Очистить овощи и нарезать палочками.','Подать с порцией готового хумуса.']],
['caesar','Салат с курицей, сухариками и сыром','Салаты',340,
[['chicken',60,60],['lettuce',42,35],['cherry',35,30],['toast',23,20],['gouda',15,15],['cooking-cream',15,15],['mustard',5,5]],['Глютен','Молоко','Горчица'],
['Подсушить кубики хлеба, подготовить салат и томаты.','Нарезать готовую курицу, соединить с овощами и сыром.','Заправить сливками с горчицей, сверху добавить сухарики.']],
['olivier','Оливье с индейкой','Салаты',280,
[['potato',65,50],['carrot',26,20],['turkey',35,35],['egg',22,20],['peas',20,20],['pickle',22,20],['cooking-cream',12,12],['mustard',3,3]],['Яйцо','Молоко','Горчица'],
['Отварить картофель, морковь и яйцо; остудить.','Нарезать овощи, яйцо, ветчину и корнишоны кубиком.','Добавить горошек и заправить сливками с горчицей.']],
['greek','Овощной салат с моцареллой и маслинами','Салаты',290,
[['tomato',55,50],['cucumber',44,40],['pepper',32,25],['mozzarella',40,40],['olive',17,15],['oil',10,10]],['Молоко'],
['Подготовить и крупно нарезать овощи.','Добавить моцареллу и маслины, заправить маслом.']],
['julienne','Жюльен с курицей и грибами','Горячие закуски',310,
[['chicken',40,40],['mushroom',60,40],['onion',15,10],['cooking-cream',25,20],['gouda',15,15],['oil',5,5]],['Молоко'],
['Обжарить нарезанные грибы и лук на масле.','Добавить готовую курицу и сливки, распределить по формам.','Посыпать сыром и запечь до расплавления.']],
['stuffed-mushrooms','Шампиньоны, запечённые с сыром','Горячие закуски',270,
[['mushroom',125,85],['cream',20,20],['gouda',10,10],['dill',3,2],['oil',3,3]],['Молоко'],
['Подготовить шляпки грибов, ножки мелко нарезать.','Смешать ножки со сливочным сыром и укропом, наполнить шляпки.','Добавить гауду и запечь.']],
['chicken','Куриное филе с овощами и сливочным соусом','Горячие блюда',490,
[['chicken-raw',180,135],['pepper',45,30],['carrot',32,25],['cooking-cream',30,25],['oil',5,5]],['Молоко'],
['Обжарить куриное филе и довести до готовности.','Отдельно приготовить перец и морковь.','Добавить сливочный соус, подать с овощами; учесть потери при приготовлении.']],
['cod','Треска с лимоном и овощами','Горячие блюда',590,
[['whitefish',170,130],['tomato',45,35],['pepper',30,20],['lemon',15,10],['oil',5,5]],['Рыба'],
['Подготовить филе и нарезать овощи.','Запечь рыбу с овощами, лимоном и маслом до готовности.']],
['beef-hot','Ростбиф с грибами в сливочном соусе','Горячие блюда',690,
[['beef',125,120],['mushroom',80,55],['onion',24,15],['cooking-cream',30,25],['oil',5,5]],['Молоко'],
['Обжарить грибы и лук, добавить сливки.','Прогреть готовый ростбиф и подать с грибным соусом.']],
['mash','Картофельное пюре','Гарниры',160,
[['potato',170,120],['milk',25,20],['butter',10,10]],['Молоко'],
['Очистить и отварить картофель, слить воду.','Размять с тёплым молоком и сливочным маслом.']],
['rice','Рис с овощами','Гарниры',170,
[['rice',40,40],['carrot',25,20],['pepper',25,20],['peas',15,15],['oil',5,5]],[],
['Отварить рис; учебный расчёт учитывает 50 г поглощённой воды на порцию.','Приготовить овощи, добавить горошек и смешать с рисом.'],50],
['berry-cream','Ягодный десерт со сливочным кремом','Десерты',240,
[['cream',35,35],['cooking-cream',20,20],['biscuit',15,15],['strawberry',28,25],['blueberry',11,10],['sugar',5,5]],['Молоко','Глютен','Яйцо в составе бисквита'],
['Смешать сыр, сливки и сахарную пудру.','Выложить в креманку бисквит, крем и подготовленные ягоды.']],
['cheese-honey','Бри с виноградом, мёдом и орехами','Десерты',310,
[['brie',45,45],['grape',39,35],['walnut',10,10],['honey',10,10]],['Молоко','Орехи'],
['Нарезать бри и подготовить виноград.','Подать с грецким орехом и мёдом.']],
['fruit','Фруктово-ягодное ассорти','Фрукты и ягоды',290,
[['grape',88,80],['strawberry',77,70],['blueberry',32,30]],[],
['Подготовить ягоды и виноград, удалить плодоножки.','Выложить порционное ассорти.']],
['bread','Хлебная корзинка с зелёным маслом','Хлеб и масло',120,
[['baguette',30,30],['rye',20,20],['butter',8,8],['dill',3,2]],['Глютен','Молоко'],
['Нарезать хлеб, при желании подсушить.','Смешать масло с укропом, подать отдельно.']]
];
export const banquet=recipes.map(([key,name,catalogSection,price,quantities,allergens,steps,waterGrams=0],index)=>{
const rows=quantities.map(([key,gross,net])=>{const p=products.get(key);return {productId:p.id,name:p.name,unit:p.unit,gross:gross/1000,net:net/1000,unitCost:p.cost}});
const outputGrams=Math.round(rows.reduce((sum,r)=>sum+r.net*1000,waterGrams));
return {id:`demo-banquet-v1-${key}`,name,category:6,catalogSection,price,weight:`${outputGrams} г`,pieces:1,photo:`demo/images/banquet-${key}.webp`,demo:true,
composition:[rows.map(r=>r.name).join(', ')],ingredients:rows.map(r=>[r.name,r.gross,r.unit]),
ttk:{number:`ДЕМО-Б${String(index+1).padStart(2,'0')}`,basis:'На 1 порцию / 1 гостя',outputGrams,waterGrams,pieces:1,rows,steps,allergens,
ingredientCost:Math.round(rows.reduce((sum,r)=>sum+r.gross*r.unitCost,0)*100)/100,
note:'Учебная рецептура и примерные цены. Выход указан после приготовления. Перед использованием в работе уточните нормы, стоимость и аллергены.'}};
});
export const banquetDemo={version:1,banquet,stock:extra};