89 lines
2.9 KiB
JavaScript
89 lines
2.9 KiB
JavaScript
|
|
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
|
||
|
|
}
|