PageSourceSearch

https://pizzeria-planeta.pl/js/ingredients.js

js pizzeria-planeta.pl collected 2026-10-08 07:35:11 UTC 4,660 bytes, 145 lines download raw bytes

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.