diff --git a/apps/main/src/pages/PublicBookingPage.tsx b/apps/main/src/pages/PublicBookingPage.tsx index 6e86861..6d6db6e 100644 --- a/apps/main/src/pages/PublicBookingPage.tsx +++ b/apps/main/src/pages/PublicBookingPage.tsx @@ -11,7 +11,12 @@ import { Button } from "@xtablo/ui/components/button"; import { FieldError } from "@xtablo/ui/components/field"; import { Input } from "@xtablo/ui/components/input"; import { Label } from "@xtablo/ui/components/label"; -import { Strong, Text } from "@xtablo/ui/components/typography"; +import { + Text, + TypographyH3, + TypographyH4, + TypographyMuted, +} from "@xtablo/ui/components/typography"; import { CalendarIcon, ChevronLeftIcon, @@ -25,6 +30,7 @@ import { } from "lucide-react"; import { useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; +import { twMerge } from "tailwind-merge"; import { api } from "../lib/api"; import { supabase } from "../lib/supabase"; import { useMaybeUser } from "../providers/UserStoreProvider"; @@ -81,13 +87,7 @@ export function PublicBookingPage() { const { theme, setTheme } = useTheme(); const toggleTheme = () => { - if (theme === "light") { - setTheme("dark"); - } else if (theme === "dark") { - setTheme("system"); - } else { - setTheme("light"); - } + setTheme(theme === "light" ? "dark" : "light"); }; const getThemeIcon = () => { @@ -321,244 +321,246 @@ export function PublicBookingPage() { }; return ( -
- {/* Header */} -
-
-
- {/* Xtablo Logo */} -
- Xtablo -
- - {/* Avatar */} - {/*
- {userProfile.avatar_url ? ( - {userProfile.name - ) : ( -
- -
- )} -
*/} - - {/* User Info */} -
-

- {userProfile?.name || "Professionnel"} -

-
- - {/* Theme Toggle */} -
- -
-
+
+
+ {/* Theme Toggle - Floating */} +
+
-
- {/* Main Content */} -
-
- {/* Left Sidebar - Event Type Info */} -
-
-

- {eventType?.name || "Type d'appel"} -

+ {/* Main Card */} +
+
+ {/* Left Panel - User Profile & Event Details */} +
+ {/* Subtle accent overlay */} +
- {eventType?.description && ( - - {eventType.description} - - )} - -
- {eventType?.duration && ( -
- -
- - Durée: {formatDuration(eventType.duration)} - +
+ {/* User Profile */} +
+ {userProfile?.avatar_url ? ( + {userProfile.name + ) : ( +
+
-
- )} - - {eventType?.price && ( -
- - € - -
- - {eventType.price}€ - -
-
- )} - {eventType?.location && ( -
- -
- - {eventType.location} - -
-
- )} - {eventType?.requiresApproval && ( -
- -
- - Approbation requise - -
-
- )} -
-
-
- - {/* Center - Calendar */} -
-
- {/* Calendar Header */} -
-

- {formatMonthYear(currentDate)} -

-
- - + )} +

+ {userProfile?.name || "Professionnel"} +

-
- {/* Calendar Grid */} -
- {["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"].map((day) => ( -
- {day} -
- ))} -
+ {/* Event Type Info */} +
+

+ {eventType?.name || "Type d'appel"} +

-
- {getDaysInMonth(currentDate).map((date, index) => ( -
- {date ? ( - - ) : ( -
+ {eventType?.description && ( + + {eventType.description} + + )} + +
+ {eventType?.duration && ( +
+
+ +
+
+

Durée

+

+ {formatDuration(eventType.duration)} +

+
+
+ )} + + {eventType?.price && ( +
+
+ +
+
+

Prix

+

{eventType.price}€

+
+
+ )} + + {eventType?.location && ( +
+
+ +
+
+

Lieu

+

{eventType.location}

+
+
)}
- ))} +
+ + {/* Footer */} +
+
+ Xtablo +
+ + Propulsé par{" "} + + XTablo + + +
-
- {/* Right Sidebar - Available Slots */} -
-
-

- {selectedDate ? ( - <> - Créneaux disponibles -
- - {selectedDate.toLocaleDateString("fr-FR", { - weekday: "long", - day: "numeric", - month: "long", - })} - - - ) : ( - "Sélectionnez une date" - )} -

+ {/* Right Panel - Calendar & Time Slots */} +
+
+ {/* Calendar */} +
+
+ + {formatMonthYear(currentDate)} + +
+ + +
+
- {selectedDate ? ( -
- {getAvailableSlots(selectedDate).map((slot, index) => ( - - ))} + {/* Calendar Grid */} +
+ {["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"].map((day) => ( +
+ {day} +
+ ))} +
- {getAvailableSlots(selectedDate).length === 0 && ( +
+ {getDaysInMonth(currentDate).map((date, index) => ( +
+ {date ? ( + + ) : ( +
+ )} +
+ ))} +
+
+ + {/* Time Slots */} +
+ + {selectedDate ? ( + <> + Créneaux disponibles +
+ + {selectedDate.toLocaleDateString("fr-FR", { + weekday: "long", + day: "numeric", + month: "long", + })} + + + ) : ( + "Sélectionnez une date" + )} +
+ + {selectedDate ? ( +
+ {getAvailableSlots(selectedDate).map((slot, index) => ( + + ))} + + {getAvailableSlots(selectedDate).length === 0 && ( +
+ + Aucun créneau disponible ce jour + +
+ )} +
+ ) : (
- - Aucun créneau disponible ce jour + + + Choisissez une date dans le calendrier
)}
- ) : ( -
- - - Choisissez une date dans le calendrier pour voir les créneaux disponibles - -
- )} +
@@ -572,9 +574,9 @@ export function PublicBookingPage() { width="md" > {selectedSlot && ( -
-
- +
+
+ {selectedSlot.date.toLocaleDateString("fr-FR", { weekday: "long", @@ -583,8 +585,8 @@ export function PublicBookingPage() { })}
-
- +
+ {selectedSlot.slot.time}
diff --git a/packages/shared/src/hooks/public.ts b/packages/shared/src/hooks/public.ts index 43c5b64..5e17b48 100644 --- a/packages/shared/src/hooks/public.ts +++ b/packages/shared/src/hooks/public.ts @@ -25,7 +25,7 @@ export type TimeSlot = { export function usePublicSlots(api: AxiosInstance, shortUserId: string, standardName: string) { return useQuery<{ - user: { name: string }; + user: { name: string; avatar_url?: string }; eventType: EventTypeConfig; slots: { [date: string]: TimeSlot[] }; availableSlots: TimeSlot[];