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:
@@ -2,12 +2,13 @@
|
||||
|
||||
import { useState, useMemo } from "react";
|
||||
import Image from "next/image";
|
||||
import { Calendar, Sparkles, User } from "lucide-react";
|
||||
import { Calendar, Sparkles, User, MapPin } from "lucide-react";
|
||||
import { SectionHeading } from "@/components/ui/SectionHeading";
|
||||
import { Reveal } from "@/components/ui/Reveal";
|
||||
import { SignupModal } from "@/components/ui/SignupModal";
|
||||
import type { OpenDayEvent, OpenDayClass } from "@/lib/openDay";
|
||||
import type { SiteContent } from "@/types";
|
||||
import type { SiteContent, ScheduleLocation } from "@/types";
|
||||
import { formatMarkup } from "@/lib/markup";
|
||||
|
||||
interface OpenDayProps {
|
||||
data: {
|
||||
@@ -16,6 +17,7 @@ interface OpenDayProps {
|
||||
};
|
||||
popups?: SiteContent["popups"];
|
||||
teamMembers?: { name: string; image: string }[];
|
||||
locations?: ScheduleLocation[];
|
||||
}
|
||||
|
||||
function formatDateRu(dateStr: string): string {
|
||||
@@ -27,7 +29,7 @@ function formatDateRu(dateStr: string): string {
|
||||
});
|
||||
}
|
||||
|
||||
export function OpenDay({ data, popups, teamMembers }: OpenDayProps) {
|
||||
export function OpenDay({ data, popups, teamMembers, locations }: OpenDayProps) {
|
||||
const { event, classes } = data;
|
||||
const [signup, setSignup] = useState<{ classId: number; label: string } | null>(null);
|
||||
|
||||
@@ -57,6 +59,17 @@ export function OpenDay({ data, popups, teamMembers }: OpenDayProps) {
|
||||
|
||||
const halls = Object.keys(hallGroups);
|
||||
|
||||
// Map hall name → address from schedule locations
|
||||
const hallAddress = useMemo(() => {
|
||||
const map: Record<string, string> = {};
|
||||
if (locations) {
|
||||
for (const loc of locations) {
|
||||
if (loc.name && loc.address) map[loc.name] = loc.address;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}, [locations]);
|
||||
|
||||
if (classes.length === 0) return null;
|
||||
|
||||
return (
|
||||
@@ -93,9 +106,9 @@ export function OpenDay({ data, popups, teamMembers }: OpenDayProps) {
|
||||
|
||||
{event.description && (
|
||||
<Reveal>
|
||||
<p className="mt-4 text-center text-sm text-neutral-400 max-w-2xl mx-auto">
|
||||
{event.description}
|
||||
</p>
|
||||
<div className="mt-4 text-center text-sm text-neutral-400 max-w-2xl mx-auto">
|
||||
{formatMarkup(event.description)}
|
||||
</div>
|
||||
</Reveal>
|
||||
)}
|
||||
|
||||
@@ -105,7 +118,15 @@ export function OpenDay({ data, popups, teamMembers }: OpenDayProps) {
|
||||
// Single hall — simple list
|
||||
<Reveal>
|
||||
<div className="max-w-lg mx-auto space-y-3">
|
||||
<h3 className="text-sm font-medium text-neutral-400 text-center">{halls[0]}</h3>
|
||||
<div className="text-center mb-4">
|
||||
<h3 className="text-base font-semibold text-white">{halls[0]}</h3>
|
||||
{hallAddress[halls[0]] && (
|
||||
<p className="text-sm text-gold/70 mt-0.5 flex items-center justify-center gap-1.5">
|
||||
<MapPin size={13} />
|
||||
{hallAddress[halls[0]]}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{hallGroups[halls[0]].map((cls) => (
|
||||
<ClassCard
|
||||
key={cls.id}
|
||||
@@ -123,7 +144,15 @@ export function OpenDay({ data, popups, teamMembers }: OpenDayProps) {
|
||||
{halls.map((hall) => (
|
||||
<Reveal key={hall}>
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-neutral-400 mb-3 text-center">{hall}</h3>
|
||||
<div className="text-center mb-4 rounded-lg bg-white/[0.03] border border-white/[0.06] py-3 px-4">
|
||||
<h3 className="text-base font-semibold text-white">{hall}</h3>
|
||||
{hallAddress[hall] && (
|
||||
<p className="text-sm text-gold/70 mt-0.5 flex items-center justify-center gap-1.5">
|
||||
<MapPin size={13} />
|
||||
{hallAddress[hall]}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{hallGroups[hall].map((cls) => (
|
||||
<ClassCard
|
||||
|
||||
Reference in New Issue
Block a user