From 1b7497b6d2af8c9f3ab21ca14eefbf69d0a95901 Mon Sep 17 00:00:00 2001 From: Guillermo Pages Date: Fri, 7 Nov 2025 22:29:16 +0100 Subject: [PATCH] fix(admin): duration validation + sport variation display Fixed two issues reported by user: 1. Slot definition duration validation error: - Changed step from "15" to "1" on duration input - HTML5 validation was failing because with min="1" and step="15", valid values were 1, 16, 31, 46, 61, 76, 91... (not 90!) - Now accepts any integer duration >= 1 minute - Error "nearest 76 or 91" resolved 2. Sport variation not showing in court edit form: - Updated Court type to include nested sport_variation structure - Backend now returns full sport_variation object with sport details - Updated CourtFormModal to extract sport_variation_id from nested structure: court.sport_variation.sport_variation_id - Added sport variation display in court list (e.g., "Padel - Indoor") - Maintains backward compatibility with deprecated flat field Changes: - SlotDefinitionForm: step="1" instead of step="15" - Court interface: added optional sport_variation nested object - ClubCourtsTab: reads sport_variation_id from nested structure - ClubCourtsTab: displays "Sport - Variation" in court list Related: Backend Brooke nested sport_variation response structure --- .../slot-definitions/SlotDefinitionForm.tsx | 2 +- .../clubs/[club_id]/tabs/ClubCourtsTab.tsx | 18 ++++++++++++++---- src/types/courts.ts | 12 +++++++++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/app/[locale]/admin/clubs/[club_id]/slot-definitions/SlotDefinitionForm.tsx b/src/app/[locale]/admin/clubs/[club_id]/slot-definitions/SlotDefinitionForm.tsx index 74de7bc..68ffdcb 100644 --- a/src/app/[locale]/admin/clubs/[club_id]/slot-definitions/SlotDefinitionForm.tsx +++ b/src/app/[locale]/admin/clubs/[club_id]/slot-definitions/SlotDefinitionForm.tsx @@ -240,7 +240,7 @@ export default function SlotDefinitionForm({ value={durationMinutes} onChange={(e) => setDurationMinutes(parseInt(e.target.value) || 0)} min="1" - step="15" + step="1" className={`w-full px-4 py-3 border-2 rounded-lg font-medium transition-colors ${ errors.duration_minutes ? 'border-red-300 focus:border-red-500' diff --git a/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubCourtsTab.tsx b/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubCourtsTab.tsx index 4c4ce91..23198c4 100644 --- a/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubCourtsTab.tsx +++ b/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubCourtsTab.tsx @@ -164,9 +164,16 @@ export default function ClubCourtsTab({ clubId }: ClubCourtsTabProps) {

{court.name}

-

- ID: {court.court_id} · Created {formatTimestamp(court.created_at)} -

+
+ {court.sport_variation && ( +

+ {court.sport_variation.sport.name} - {court.sport_variation.name} +

+ )} +

+ ID: {court.court_id} · Created {formatTimestamp(court.created_at)} +

+
@@ -245,7 +252,10 @@ interface CourtFormModalProps { function CourtFormModal({ clubId, court, onClose, onSuccess }: CourtFormModalProps) { const isEditing = !!court; const [name, setName] = useState(court?.name || ''); - const [sportVariationId, setSportVariationId] = useState(court?.sport_variation_id || 0); + // Get sport_variation_id from nested structure or fall back to deprecated flat field + const [sportVariationId, setSportVariationId] = useState( + court?.sport_variation?.sport_variation_id || court?.sport_variation_id || 0 + ); const [sports, setSports] = useState([]); const [loadingSports, setLoadingSports] = useState(true); const [saving, setSaving] = useState(false); diff --git a/src/types/courts.ts b/src/types/courts.ts index 70dda64..ae7c9e9 100644 --- a/src/types/courts.ts +++ b/src/types/courts.ts @@ -7,7 +7,17 @@ export interface Court { court_id: number; name: string; - sport_variation_id: number; + sport_variation_id?: number; // For backward compatibility (deprecated) + sport_variation?: { + sport_variation_id: number; + name: string; + slug: string; + sport: { + sport_id: number; + name: string; + slug: string; + }; + }; created_at: string; // ISO 8601 timestamp updated_at: string; // ISO 8601 timestamp }