1import { getDataPaths, getDataBasePath, isEnglish } from './locale.js'; 2import { fetchJsonWithTimeout, withRetries } from './data-load.js'; 3 4let ingredientsData = null; 5 6export const PIZZA_INGREDIENT_SIZE_KEYS = ['30', '40', '50']; 7 8export function normalizeIngredientSizeKey(sizeName = '') { 9 const match = String(sizeName).match(/(\d+)\s*cm/i); 10 if (match) return match[1]; 11 const plain = String(sizeName).trim(); 12 return PIZZA_INGREDIENT_SIZE_KEYS.includes(plain) ? plain : null; 13} 14 15export function getIngredientPrice(ingredient, sizeName = null) { 16 if (!ingredient) return 0; 17 const key = normalizeIngredientSizeKey(sizeName); 18 const prices = ingredient.prices && typeof ingredient.prices === 'object' 19 ? ingredient.prices 20 : null; 21 22 if (key && prices && prices[key] != null && prices[key] !== '') { 23 return Math.max(0, Number(prices[key]) || 0); 24 } 25 26 if (prices?.['40'] != null && prices['40'] !== '') { 27 return Math.max(0, Number(prices['40']) || 0); 28 } 29 30 return Math.max(0, Number(ingredient.price) || 0); 31} 32 33export function normalizeIngredientItem(item = {}) { 34 const basePrice = Math.max(0, Number(item.price) || 0); 35 const prices = { 36 '30': item.prices?.['30'] != null ? Math.max(0, Number(item.prices['30']) || 0) : basePrice, 37 '40': item.prices?.['40'] != null ? Math.max(0, Number(item.prices['40']) || 0) : basePrice, 38 '50': item.prices?.['50'] != null ? Math.max(0, Number(item.prices['50']) || 0) : basePrice 39 }; 40 41 return { 42 ...item, 43 price: prices['40'], 44 prices, 45 enabled: item.enabled !== false 46 }; 47} 48 49function indexIngredientCategories(overlay) { 50 const byId = new Map(); 51 (overlay?.categories || []).forEach(category => { 52 if (!category?.id) return; 53 const items = new Map(); 54 (category.items || []).forEach(item => { 55 if (item?.id) items.set(String(item.id), item); 56 }); 57 byId.set(String(category.id), { category, items }); 58 }); 59 return byId; 60} 61 62/** EN: dane/ceny z PL + angielskie nazwy z nameEn lub ingredients.en.json */ 63export function mergeEnglishIngredients(plData, enOverlay = null) { 64 if (!plData || !Array.isArray(plData.categories)) { 65 throw new Error('ingredients.json jest niekompletne â brak categories'); 66 } 67 68 const overlay = indexIngredientCategories(enOverlay); 69 70 return { 71 categories: plData.categories.map(category => { 72 const enCat = overlay.get(String(category.id)); 73 const nameEn = category.nameEn?.trim() || enCat?.category?.name || ''; 74 return { 75 ...category, 76 name: nameEn || category.name, 77 nameEn: category.nameEn || enCat?.category?.name || '', 78 items: (category.items || []).map(item => { 79 const enItem = enCat?.items.get(String(item.id)); 80 const itemNameEn = item.nameEn?.trim() || enItem?.name || ''; 81 return normalizeIngredientItem({ 82 ...item, 83 name: itemNameEn || item.name, 84 nameEn: item.nameEn || enItem?.name || '' 85 }); 86 }) 87 }; 88 }) 89 }; 90} 91 92export async function fetchDefaultIngredients() { 93 const paths = getDataPaths(); 94 return fetchJsonWithTimeout(paths.ingredients); 95} 96 97export async function loadIngredients() { 98 return withRetries(async () => { 99 const paths = getDataPaths(); 100 101 if (isEnglish() && !window.ADMIN_PANEL) { 102 const base = getDataBasePath(); 103 const [plData, enOverlay] = await Promise.all([ 104 fetchJsonWithTimeout(`${base}/ingredients.json`), 105 fetchJsonWithTimeout(`${base}/ingredients.en.json`).catch(() => null) 106 ]); 107 ingredientsData = mergeEnglishIngredients(plData, enOverlay); 108 } else { 109 const data = await fetchJsonWithTimeout(paths.ingredients); 110 if (!data || !Array.isArray(data.categories)) { 111 throw new Error('ingredients.json jest niekompletne â brak categories'); 112 } 113 ingredientsData = data; 114 } 115 return ingredientsData; 116 }); 117} 118 119export function getIngredients() { 120 return ingredientsData; 121} 122 123export function setIngredientsOverride(data) { 124 if (!data || !Array.isArray(data.categories)) return false; 125 ingredientsData = data; 126 return true; 127} 128 129export function clearIngredientsOverride() { 130 ingredientsData = null; 131} 132 133export function findIngredientById(id) { 134 for (const category of getIngredients().categories || []) { 135 const found = (category.items || []).find(item => item.id === id); 136 if (found) return { ...found, categoryName: category.name }; 137 } 138 return null; 139} 140 141export function getAllIngredientItems() { 142 return (getIngredients().categories || []).flatMap(cat => 143 (cat.items || []).map(item => ({ ...item, categoryId: cat.id, categoryName: cat.name })) 144 ); 145}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.