fix: use groupId for trainer bio schedule groups
Group extraction now uses groupId (from admin panel) instead of type+time heuristic, with mergeSlotsByDay for proper day/time display. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,24 +37,65 @@ export function TeamProfile({ member, onBack, schedule }: TeamProfileProps) {
|
|||||||
const hasExperience = member.experience && member.experience.length > 0;
|
const hasExperience = member.experience && member.experience.length > 0;
|
||||||
const hasEducation = member.education && member.education.length > 0;
|
const hasEducation = member.education && member.education.length > 0;
|
||||||
|
|
||||||
// Extract trainer's groups from schedule, grouped by type + time + location
|
// Extract trainer's groups from schedule using groupId
|
||||||
const groupMap = new Map<string, { type: string; time: string; location: string; address: string; days: string[]; level?: string; recruiting?: boolean }>();
|
const groupMap = new Map<string, { type: string; location: string; address: string; slots: { day: string; dayShort: string; time: string }[]; level?: string; recruiting?: boolean }>();
|
||||||
schedule?.forEach(location => {
|
schedule?.forEach(location => {
|
||||||
location.days.forEach(day => {
|
location.days.forEach(day => {
|
||||||
day.classes
|
day.classes
|
||||||
.filter(c => c.trainer === member.name)
|
.filter(c => c.trainer === member.name)
|
||||||
.forEach(c => {
|
.forEach(c => {
|
||||||
const key = `${c.type}|${c.time}|${location.name}`;
|
const key = c.groupId
|
||||||
|
? `${c.groupId}||${location.name}`
|
||||||
|
: `${c.trainer}||${c.type}||${location.name}`;
|
||||||
const existing = groupMap.get(key);
|
const existing = groupMap.get(key);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
if (!existing.days.includes(day.dayShort)) existing.days.push(day.dayShort);
|
existing.slots.push({ day: day.day, dayShort: day.dayShort, time: c.time });
|
||||||
|
if (c.level && !existing.level) existing.level = c.level;
|
||||||
|
if (c.recruiting) existing.recruiting = true;
|
||||||
} else {
|
} else {
|
||||||
groupMap.set(key, { type: c.type, time: c.time, location: location.name, address: location.address, days: [day.dayShort], level: c.level, recruiting: c.recruiting });
|
groupMap.set(key, {
|
||||||
|
type: c.type,
|
||||||
|
location: location.name,
|
||||||
|
address: location.address,
|
||||||
|
slots: [{ day: day.day, dayShort: day.dayShort, time: c.time }],
|
||||||
|
level: c.level,
|
||||||
|
recruiting: c.recruiting,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const uniqueGroups = Array.from(groupMap.values());
|
const uniqueGroups = Array.from(groupMap.values()).map(g => {
|
||||||
|
// Merge slots by day, then merge days with identical time sets
|
||||||
|
const dayMap = new Map<string, { dayShort: string; times: string[] }>();
|
||||||
|
const dayOrder: string[] = [];
|
||||||
|
for (const s of g.slots) {
|
||||||
|
const existing = dayMap.get(s.day);
|
||||||
|
if (existing) {
|
||||||
|
if (!existing.times.includes(s.time)) existing.times.push(s.time);
|
||||||
|
} else {
|
||||||
|
dayMap.set(s.day, { dayShort: s.dayShort, times: [s.time] });
|
||||||
|
dayOrder.push(s.day);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const entry of dayMap.values()) entry.times.sort();
|
||||||
|
const merged: { days: string[]; times: string[] }[] = [];
|
||||||
|
const used = new Set<string>();
|
||||||
|
for (const day of dayOrder) {
|
||||||
|
if (used.has(day)) continue;
|
||||||
|
const entry = dayMap.get(day)!;
|
||||||
|
const timeKey = entry.times.join("|");
|
||||||
|
const days = [entry.dayShort];
|
||||||
|
used.add(day);
|
||||||
|
for (const other of dayOrder) {
|
||||||
|
if (used.has(other)) continue;
|
||||||
|
const o = dayMap.get(other)!;
|
||||||
|
if (o.times.join("|") === timeKey) { days.push(o.dayShort); used.add(other); }
|
||||||
|
}
|
||||||
|
merged.push({ days, times: entry.times });
|
||||||
|
}
|
||||||
|
return { ...g, merged };
|
||||||
|
});
|
||||||
const hasGroups = uniqueGroups.length > 0;
|
const hasGroups = uniqueGroups.length > 0;
|
||||||
|
|
||||||
const hasBio = hasVictories || hasExperience || hasEducation || hasGroups;
|
const hasBio = hasVictories || hasExperience || hasEducation || hasGroups;
|
||||||
@@ -181,9 +222,14 @@ export function TeamProfile({ member, onBack, schedule }: TeamProfileProps) {
|
|||||||
{uniqueGroups.map((g, i) => (
|
{uniqueGroups.map((g, i) => (
|
||||||
<div key={i} className="w-48 shrink-0 rounded-xl border border-white/[0.08] bg-white/[0.03] p-3 space-y-1.5">
|
<div key={i} className="w-48 shrink-0 rounded-xl border border-white/[0.08] bg-white/[0.03] p-3 space-y-1.5">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-white/80">{g.type}</p>
|
<p className="text-xs font-semibold uppercase tracking-wider text-white/80">{g.type}</p>
|
||||||
<div className="flex items-center gap-1.5 text-xs text-white/50">
|
<div className="space-y-0.5">
|
||||||
<Clock size={11} />
|
{g.merged.map((m, mi) => (
|
||||||
{g.days.join(", ")} · {g.time}
|
<div key={mi} className="flex items-center gap-1.5 text-xs text-white/50">
|
||||||
|
<Clock size={11} className="shrink-0" />
|
||||||
|
<span className="font-medium text-white/70">{m.days.join(", ")}</span>
|
||||||
|
<span>{m.times.join(", ")}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-start gap-1.5 text-xs text-white/40">
|
<div className="flex items-start gap-1.5 text-xs text-white/40">
|
||||||
<MapPin size={11} className="mt-0.5 shrink-0" />
|
<MapPin size={11} className="mt-0.5 shrink-0" />
|
||||||
@@ -198,7 +244,7 @@ export function TeamProfile({ member, onBack, schedule }: TeamProfileProps) {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={() => setBookingGroup(`${g.type}, ${g.days.join("/")} ${g.time}`)}
|
onClick={() => setBookingGroup(`${g.type}, ${g.merged.map(m => m.days.join("/")).join(", ")} ${g.merged[0]?.times[0] ?? ""}`)}
|
||||||
className="w-full mt-1 rounded-lg bg-gold/15 border border-gold/25 py-1.5 text-[11px] font-semibold text-gold hover:bg-gold/25 transition-colors cursor-pointer"
|
className="w-full mt-1 rounded-lg bg-gold/15 border border-gold/25 py-1.5 text-[11px] font-semibold text-gold hover:bg-gold/25 transition-colors cursor-pointer"
|
||||||
>
|
>
|
||||||
Записаться
|
Записаться
|
||||||
|
|||||||
Reference in New Issue
Block a user