fix: schedule status labels, Open Day halls, unsaved data guards
Schedule: - Status badges use admin config labels (not hardcoded text) everywhere - DayCard: level badge moved next to status badge - Single location: hide "Все студии" tab, auto-select the only hall - Group view: hide per-card address when all share same location - Filter tooltip z-index fixed (above dropdowns) - Trainer bio: status labels from config, not raw keys Open Day: - Hall name + address shown in schedule grid headers - Only one class card editable at a time (edit/create mutually exclusive) - Bigger action buttons (cancel/delete) on class cards - Create as empty draft (not pre-filled with published status) - Fix discount threshold input (allow delete to empty) - Skip auto-save during partial date input Admin: - SectionEditor: unsaved data guard (force-save before navigation) - Open Day + Team: same navigation guards - Contact: removed working hours field - TimeRangeField: allow end time hour changes - Schedule cards: visible borders, 90min default duration - Trainer bio: RichTextarea for description - Open Day: RichTextarea for description
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Clock, User, MapPin } from "lucide-react";
|
||||
import { shortAddress } from "./constants";
|
||||
import { shortAddress, findStatusConfig } from "./constants";
|
||||
import { ScheduleBadge } from "@/components/ui/ScheduleBadge";
|
||||
import type { ScheduleDayMerged, ScheduleClassWithLocation } from "./constants";
|
||||
|
||||
@@ -11,6 +11,7 @@ interface DayCardProps {
|
||||
toggleFilterTrainer: (trainer: string | null) => void;
|
||||
filterTypes: Set<string>;
|
||||
toggleFilterType: (type: string) => void;
|
||||
statuses?: { key: string; label: string; description: string }[];
|
||||
}
|
||||
|
||||
function ClassRow({
|
||||
@@ -20,6 +21,7 @@ function ClassRow({
|
||||
toggleFilterTrainer,
|
||||
filterTypes,
|
||||
toggleFilterType,
|
||||
statuses,
|
||||
}: {
|
||||
cls: ScheduleClassWithLocation;
|
||||
typeDots: Record<string, string>;
|
||||
@@ -27,19 +29,22 @@ function ClassRow({
|
||||
toggleFilterTrainer: (trainer: string | null) => void;
|
||||
filterTypes: Set<string>;
|
||||
toggleFilterType: (type: string) => void;
|
||||
statuses?: { key: string; label: string; description: string }[];
|
||||
}) {
|
||||
return (
|
||||
<div className={`px-5 py-3.5 ${cls.hasSlots ? "bg-emerald-500/5" : cls.recruiting ? "bg-sky-500/5" : ""}`}>
|
||||
<div className="px-5 py-3.5">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-2 text-sm text-neutral-500 dark:text-white/40">
|
||||
<Clock size={13} />
|
||||
<span className="font-semibold">{cls.time}</span>
|
||||
</div>
|
||||
{cls.hasSlots && <ScheduleBadge>есть места</ScheduleBadge>}
|
||||
{cls.recruiting && <ScheduleBadge>набор</ScheduleBadge>}
|
||||
{cls.status && cls.status !== "hasSlots" && cls.status !== "recruiting" && (
|
||||
<ScheduleBadge>{cls.status}</ScheduleBadge>
|
||||
)}
|
||||
<div className="flex items-center gap-1.5">
|
||||
{cls.status && (() => {
|
||||
const cfg = findStatusConfig(statuses, cls.status);
|
||||
return <ScheduleBadge>{cfg?.label || cls.status}</ScheduleBadge>;
|
||||
})()}
|
||||
{cls.level && <ScheduleBadge>{cls.level}</ScheduleBadge>}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => window.dispatchEvent(new CustomEvent("openTrainerProfile", { detail: cls.trainer }))}
|
||||
@@ -56,13 +61,12 @@ function ClassRow({
|
||||
<span className={`h-2 w-2 shrink-0 rounded-full ${typeDots[cls.type] ?? "bg-white/30"}`} />
|
||||
<span className="text-xs text-neutral-500 dark:text-white/40">{cls.type}</span>
|
||||
</button>
|
||||
{cls.level && <ScheduleBadge>{cls.level}</ScheduleBadge>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function DayCard({ day, typeDots, showLocation, filterTrainerSet, toggleFilterTrainer, filterTypes, toggleFilterType }: DayCardProps) {
|
||||
export function DayCard({ day, typeDots, showLocation, filterTrainerSet, toggleFilterTrainer, filterTypes, toggleFilterType, statuses }: DayCardProps) {
|
||||
// Group classes by location when showLocation is true
|
||||
const locationGroups = showLocation
|
||||
? Array.from(
|
||||
@@ -109,7 +113,7 @@ export function DayCard({ day, typeDots, showLocation, filterTrainerSet, toggleF
|
||||
</div>
|
||||
<div className="divide-y divide-neutral-100 dark:divide-white/[0.04]">
|
||||
{classes.map((cls, i) => (
|
||||
<ClassRow key={i} cls={cls} typeDots={typeDots} filterTrainerSet={filterTrainerSet} toggleFilterTrainer={toggleFilterTrainer} filterTypes={filterTypes} toggleFilterType={toggleFilterType} />
|
||||
<ClassRow key={i} cls={cls} typeDots={typeDots} filterTrainerSet={filterTrainerSet} toggleFilterTrainer={toggleFilterTrainer} filterTypes={filterTypes} toggleFilterType={toggleFilterType} statuses={statuses} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -119,7 +123,7 @@ export function DayCard({ day, typeDots, showLocation, filterTrainerSet, toggleF
|
||||
// Single location — no sub-headers
|
||||
<div className="divide-y divide-neutral-100 dark:divide-white/[0.04]">
|
||||
{day.classes.map((cls, i) => (
|
||||
<ClassRow key={i} cls={cls} typeDots={typeDots} filterTrainerSet={filterTrainerSet} toggleFilterTrainer={toggleFilterTrainer} filterTypes={filterTypes} toggleFilterType={toggleFilterType} />
|
||||
<ClassRow key={i} cls={cls} typeDots={typeDots} filterTrainerSet={filterTrainerSet} toggleFilterTrainer={toggleFilterTrainer} filterTypes={filterTypes} toggleFilterType={toggleFilterType} statuses={statuses} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user