import { formatSessionDurationRange } from './trainingDurationUtils' export function frameworkSessionDurationLabel(row) { return formatSessionDurationRange(row?.session_duration_min, row?.session_duration_max, { empty: 'Dauer nicht angegeben', }) } function parseIdList(raw) { if (Array.isArray(raw)) { return raw.map((x) => String(x)).filter(Boolean) } if (typeof raw === 'string' && raw.trim().startsWith('[')) { try { const arr = JSON.parse(raw) if (Array.isArray(arr)) return arr.map((x) => String(x)) } catch { /* ignore */ } } return [] } function rowMatchesDuration(row, targetMin, toleranceMin = 10) { if (targetMin == null || targetMin === '' || Number.isNaN(Number(targetMin))) return true const t = Number(targetMin) const lo = row.session_duration_min != null ? Number(row.session_duration_min) : null const hi = row.session_duration_max != null ? Number(row.session_duration_max) : null if (lo == null && hi == null) return true if (lo != null && hi != null) { return t >= lo - toleranceMin && t <= hi + toleranceMin } const single = lo ?? hi return single != null && Math.abs(single - t) <= toleranceMin } /** * Client-Filter für Rahmenprogramm-Auswahl (Liste / Import-Dialog). */ export function filterFrameworkPrograms(rows, filters = {}) { const q = (filters.query || '').trim().toLowerCase() const focusIds = new Set((filters.focusAreaIds || []).map(String)) const typeIds = new Set((filters.trainingTypeIds || []).map(String)) const tgIds = new Set((filters.targetGroupIds || []).map(String)) const durationTarget = filters.durationTargetMin return (rows || []).filter((r) => { if (q) { const blob = [ r.title, r.description, r.goal_titles_agg, r.focus_area_names_agg, r.style_direction_names_agg, r.training_type_names_agg, r.target_group_names_agg, ] .filter(Boolean) .join(' ') .toLowerCase() if (!blob.includes(q)) return false } if (focusIds.size) { const fa = parseIdList(r.focus_area_ids) if (!fa.some((id) => focusIds.has(id))) return false } if (typeIds.size) { const tt = parseIdList(r.training_type_ids) if (!tt.some((id) => typeIds.has(id))) return false } if (tgIds.size) { const tg = parseIdList(r.target_group_ids) if (!tg.some((id) => tgIds.has(id))) return false } if (!rowMatchesDuration(r, durationTarget)) return false return true }) } export function frameworkProgramOptionLabel(row) { const title = (row?.title || '').trim() || `Rahmen #${row?.id}` const dur = frameworkSessionDurationLabel(row) const slots = row?.slots_count != null ? `${row.slots_count} Slot(s)` : '' const bits = [dur !== 'Dauer nicht angegeben' ? dur : null, slots].filter(Boolean) return bits.length ? `${title} · ${bits.join(' · ')}` : title }