fix: update facility detail types to match current API response shape
continuous-integration/drone/push Build is passing Details

The API now returns 'facility' with expanded address/settings fields instead of 'club', and slot types have been restructured to use flat properties instead of nested booking/meta objects.
master
Guillermo Pages 1 month ago
parent 4d9aeb9045
commit 94a1979201

@ -160,11 +160,11 @@ export default function AdminClubDetailComponent({ clubId }: AdminClubDetailProp
</div> </div>
<div className="flex-1"> <div className="flex-1">
<h1 className="text-4xl font-bold text-slate-900 mb-3 tracking-tight"> <h1 className="text-4xl font-bold text-slate-900 mb-3 tracking-tight">
{clubDetail.club.name} {clubDetail.facility.name}
</h1> </h1>
<div className="flex items-center text-slate-600 space-x-2"> <div className="flex items-center text-slate-600 space-x-2">
<MapPin className="w-5 h-5" /> <MapPin className="w-5 h-5" />
<span className="text-lg font-medium">{clubDetail.club.timezone}</span> <span className="text-lg font-medium">{clubDetail.facility.timezone}</span>
</div> </div>
</div> </div>
</div> </div>

@ -160,10 +160,10 @@ export default function ClubDetailTabs({ clubId }: ClubDetailTabsProps) {
{/* Club Header */} {/* Club Header */}
<div className="mb-8"> <div className="mb-8">
<h1 className="text-4xl font-bold text-slate-900 mb-2 tracking-tight"> <h1 className="text-4xl font-bold text-slate-900 mb-2 tracking-tight">
{clubDetail.club.name} {clubDetail.facility.name}
</h1> </h1>
<p className="text-lg text-slate-600 font-light"> <p className="text-lg text-slate-600 font-light">
{clubDetail.club.timezone} {clubDetail.facility.timezone}
</p> </p>
</div> </div>

@ -185,10 +185,25 @@ export const MOCK_CLUBS: AdminClubsResponse = [
]; ];
export const MOCK_CLUB_DETAIL: AdminClubDetail = { export const MOCK_CLUB_DETAIL: AdminClubDetail = {
club: { facility: {
facility_id: 1, facility_id: 1,
name: 'Central Padel Geneva', name: 'Central Padel Geneva',
timezone: 'Europe/Zurich', timezone: 'Europe/Zurich',
address: {
address_line_1: '123 Main Street',
address_line_2: null,
city: 'Geneva',
zip: '1200',
canton: 'GE',
country: 'Switzerland',
},
settings: {
contact: {
email: 'info@centralpadel.ch',
phone: '+41 22 123 45 67',
website: 'https://centralpadel.ch',
},
},
}, },
courts: [ courts: [
{ {

@ -37,9 +37,9 @@ export async function getClubProfile(clubId: number): Promise<ApiResult<ClubProf
} }
const responseData = await response.json(); const responseData = await response.json();
// Backend returns { club: {...}, courts: [], provider: {...}, ... } // Backend returns { facility: {...}, courts: [], provider: {...}, ... }
// Extract the club object // Extract the facility object
const data: ClubProfile = responseData.club; const data: ClubProfile = responseData.facility;
return { success: true, data }; return { success: true, data };
} catch (error) { } catch (error) {
return { return {

@ -27,12 +27,28 @@ export type AdminClubsResponse = AdminClub[];
/** /**
* GET /admin/facilities/{club_id} - Detailed facility view * GET /admin/facilities/{club_id} - Detailed facility view
* Based on VENUE_ADMIN_DESIGN.md and Access Avery correction 2025-11-05 12:14 UTC * Based on VENUE_ADMIN_DESIGN.md and Access Avery correction 2025-11-05 12:14 UTC
* Updated: 2025-11-13 to match new API shape
*/ */
export interface AdminClubDetail { export interface AdminClubDetail {
club: { facility: {
facility_id: number; facility_id: number;
name: string; name: string;
timezone: string; timezone: string;
address: {
address_line_1: string | null;
address_line_2: string | null;
city: string | null;
zip: string | null;
canton: string | null;
country: string | null;
};
settings: {
contact: {
email: string | null;
phone: string | null;
website: string | null;
};
};
}; };
courts: import('./courts').Court[]; courts: import('./courts').Court[];
slot_definitions: AdminSlotDefinition[]; slot_definitions: AdminSlotDefinition[];
@ -55,39 +71,23 @@ export interface AdminSlotDefinition {
capacity: number; capacity: number;
valid_from: string; // Date string "YYYY-MM-DD" valid_from: string; // Date string "YYYY-MM-DD"
valid_to: string | null; // Date string or null valid_to: string | null; // Date string or null
rule: Record<string, any>; // Slot generation rules (JSONB)
created_at: string; // ISO 8601 timestamp
updated_at: string; // ISO 8601 timestamp
} }
export interface AdminSlot { export interface AdminSlot {
slot_id: number; // slot_instance_id slot_instance_id: number;
court_id: number; court_id: number;
court_name: string; court_name: string;
facility_id: number;
starts_at: string; // ISO 8601 timestamp starts_at: string; // ISO 8601 timestamp
ends_at: string; // ISO 8601 timestamp ends_at: string; // ISO 8601 timestamp
booking: AdminSlotBooking;
meta: AdminSlotMeta;
updated_at: string; // ISO 8601 timestamp
etag: string;
}
export interface AdminSlotBooking {
available: boolean; // Mapped from status
status: 'available' | 'pending' | 'booked' | 'cancelled';
capacity: number; capacity: number;
booked_count: number; booked_count: number;
players: AdminPlayer[]; status: string; // e.g., "cancelled", "available", "booked"
} display_status: string; // e.g., "cancelled"
reason?: string | null; // e.g., "materialiser_retired"
export interface AdminPlayer { source: string; // e.g., "internal"
display_name: string;
app_user_id?: number; // Optional for guests
position: number;
is_guest: boolean;
}
export interface AdminSlotMeta {
tags?: string[]; // Optional annotations like ["maintenance"]
provider: 'local' | 'fairplay';
} }
export interface AdminProviderInfo { export interface AdminProviderInfo {

Loading…
Cancel
Save