fix: schedule status system — auto-key, config order, label lookup
- Auto-generate status key from label (admin doesn't need to set keys) - Remove visible key field from status config editor - Order statuses/levels in filters by config order (matches admin panel) - Shared findStatusConfig() for robust label lookup (by key, label, or derived key) - Custom status badges in DayCard, GroupCard, MobileSchedule - Simplified filter logic with clsStatus helper - Removed dead code: TIME_PRESETS, StatusFilter type - SelectField: blur input after selection to prevent re-open
This commit is contained in:
@@ -192,19 +192,37 @@ export function Schedule({ data: schedule, scheduleConfig, classItems, teamMembe
|
||||
for (const cls of day.classes) {
|
||||
typeSet.add(cls.type);
|
||||
trainerSet.add(cls.trainer);
|
||||
if (cls.status) statusSet.add(cls.status);
|
||||
if (cls.hasSlots) statusSet.add("hasSlots");
|
||||
if (cls.recruiting) statusSet.add("recruiting");
|
||||
const clsStatus = cls.status || (cls.recruiting ? "recruiting" : cls.hasSlots ? "hasSlots" : "");
|
||||
if (clsStatus) statusSet.add(clsStatus);
|
||||
if (cls.level) levelSet.add(cls.level);
|
||||
}
|
||||
}
|
||||
// Also include all configured statuses/levels so they appear in filters
|
||||
if (scheduleConfig?.statuses) {
|
||||
for (const s of scheduleConfig.statuses) if (s.key) statusSet.add(s.key);
|
||||
}
|
||||
if (scheduleConfig?.levels) {
|
||||
for (const l of scheduleConfig.levels) if (l.value) levelSet.add(l.value);
|
||||
}
|
||||
// Order statuses by config order, then any extras from data
|
||||
const configStatusOrder = (scheduleConfig?.statuses ?? []).map((s) => s.key).filter(Boolean);
|
||||
const orderedStatuses = [
|
||||
...configStatusOrder.filter((k) => statusSet.has(k)),
|
||||
...Array.from(statusSet).filter((k) => !configStatusOrder.includes(k)),
|
||||
];
|
||||
// Order levels by config order
|
||||
const configLevelOrder = (scheduleConfig?.levels ?? []).map((l) => l.value).filter(Boolean);
|
||||
const orderedLevels = [
|
||||
...configLevelOrder.filter((v) => levelSet.has(v)),
|
||||
...Array.from(levelSet).filter((v) => !configLevelOrder.includes(v)),
|
||||
];
|
||||
return {
|
||||
types: Array.from(typeSet).sort(),
|
||||
availableStatuses: Array.from(statusSet),
|
||||
levels: Array.from(levelSet).sort(),
|
||||
availableStatuses: orderedStatuses,
|
||||
levels: orderedLevels,
|
||||
trainerNames: Array.from(trainerSet).sort(),
|
||||
};
|
||||
}, [activeDays]);
|
||||
}, [activeDays, scheduleConfig]);
|
||||
|
||||
// Parse time range for filtering
|
||||
const activeTimeRange = isTimeFilterActive(filterTime)
|
||||
@@ -227,19 +245,17 @@ export function Schedule({ data: schedule, scheduleConfig, classItems, teamMembe
|
||||
.map((day) => ({
|
||||
...day,
|
||||
classes: day.classes.filter(
|
||||
(cls) =>
|
||||
(filterTrainerSet.size === 0 || filterTrainerSet.has(cls.trainer)) &&
|
||||
(cls) => {
|
||||
const clsStatus = cls.status || (cls.recruiting ? "recruiting" : cls.hasSlots ? "hasSlots" : "");
|
||||
return (filterTrainerSet.size === 0 || filterTrainerSet.has(cls.trainer)) &&
|
||||
(filterTypes.size === 0 || filterTypes.has(cls.type)) &&
|
||||
(filterStatusSet.size === 0 ||
|
||||
(cls.status && filterStatusSet.has(cls.status as StatusTag)) ||
|
||||
(filterStatusSet.has("hasSlots" as StatusTag) && cls.hasSlots) ||
|
||||
(filterStatusSet.has("recruiting" as StatusTag) && cls.recruiting)) &&
|
||||
(filterStatusSet.size === 0 || (clsStatus && filterStatusSet.has(clsStatus))) &&
|
||||
(!filterLevel || cls.level === filterLevel) &&
|
||||
(!activeTimeRange || (() => {
|
||||
const m = startTimeMinutes(cls.time);
|
||||
return m >= activeTimeRange[0] && m < activeTimeRange[1];
|
||||
})())
|
||||
),
|
||||
})());
|
||||
}),
|
||||
}))
|
||||
.filter((day) => day.classes.length > 0);
|
||||
}, [activeDays, filterTrainerSet, filterTypes, filterStatusSet, filterLevel, filterTime, activeTimeRange, filterDaySet]);
|
||||
@@ -443,6 +459,7 @@ export function Schedule({ data: schedule, scheduleConfig, classItems, teamMembe
|
||||
showLocation={isAllMode}
|
||||
onBook={(v) => dispatch({ type: "SET_BOOKING", value: v })}
|
||||
trainerPhotos={trainerPhotos}
|
||||
scheduleConfig={scheduleConfig}
|
||||
/>
|
||||
</Reveal>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user