/** Effektives Ablaufprofil für Kombination im Coach/in der Planung */ /** * Vereinigt slot_profiles_v1 aus Katalog und Planungs-Overlay (je slot_index). * @param {unknown} catArr * @param {unknown} planArr */ function mergeSlotProfilesV1(catArr, planArr) { const c = Array.isArray(catArr) ? catArr : [] const p = Array.isArray(planArr) ? planArr : [] const byIx = new Map() for (const r of c) { if (!r || typeof r !== 'object') continue const ix = Number(r.slot_index) if (!Number.isFinite(ix)) continue byIx.set(ix, { ...r }) } for (const r of p) { if (!r || typeof r !== 'object') continue const ix = Number(r.slot_index) if (!Number.isFinite(ix)) continue const prev = byIx.get(ix) || {} byIx.set(ix, { ...prev, ...r }) } return [...byIx.entries()].sort((a, b) => a[0] - b[0]).map(([, row]) => row) } /** * Katalog-Basis + optionaler Planungs-Snapshot. * Wichtig: `planning_method_profile` darf nur **Überschreibungen** sein — nie den Katalog komplett ersetzen * (sonst verschwinden Zeiten/Runden bei leerem Objekt oder Teil-Payload). */ export function effectiveComboMethodProfile(catalogDict, planningSnapshot) { const cat = catalogDict && typeof catalogDict === 'object' && !Array.isArray(catalogDict) ? { ...catalogDict } : {} if ( planningSnapshot === null || planningSnapshot === undefined || typeof planningSnapshot !== 'object' || Array.isArray(planningSnapshot) ) { return { ...cat } } const plan = planningSnapshot const merged = { ...cat, ...plan } if (Object.prototype.hasOwnProperty.call(plan, 'slot_profiles_v1')) { merged.slot_profiles_v1 = mergeSlotProfilesV1(cat.slot_profiles_v1, plan.slot_profiles_v1) } return merged } export function comboPlanningProfileJsonForEditor(catalogDict, planningSnapshot) { const o = effectiveComboMethodProfile(catalogDict, planningSnapshot) try { return JSON.stringify(Object.keys(o).length ? o : {}) } catch { return '{}' } }