Beautiful loading state
This commit is contained in:
parent
ba30079d03
commit
3149928484
2 changed files with 76 additions and 7 deletions
|
|
@ -136,6 +136,10 @@ tabloRouter.post("/create-and-invite", async (c) => {
|
|||
email: string;
|
||||
};
|
||||
|
||||
if (ownerId === user.id) {
|
||||
return c.json({ error: "You cannot create a tablo with yourself" }, 400);
|
||||
}
|
||||
|
||||
// TODO: Verify that the event start and end correspond to a slot
|
||||
|
||||
// Check if there's already a tablo between the owner and the invited user
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import {
|
|||
TypographyMuted,
|
||||
} from "@xtablo/ui/components/typography";
|
||||
import {
|
||||
CalendarCheck2,
|
||||
CalendarIcon,
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
|
|
@ -28,7 +29,7 @@ import {
|
|||
SunIcon,
|
||||
UserIcon,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { api } from "../lib/api";
|
||||
|
|
@ -53,12 +54,13 @@ export function PublicBookingPage() {
|
|||
event_type_standard_name || ""
|
||||
);
|
||||
|
||||
const { mutateAsync: createTabloWithOwner } = useCreateTabloWithOwner(api, (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["tablos"] });
|
||||
invalidatePublicSlots();
|
||||
navigate(`/chat/${data.id}`, { replace: true });
|
||||
navigate(0);
|
||||
});
|
||||
const { mutateAsync: createTabloWithOwner, isPending: isCreatingTabloWithOwner } =
|
||||
useCreateTabloWithOwner(api, (data) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["tablos"] });
|
||||
invalidatePublicSlots();
|
||||
navigate(`/chat/${data.id}`, { replace: true });
|
||||
navigate(0);
|
||||
});
|
||||
|
||||
const userProfile = publicSlots?.user;
|
||||
const eventType = publicSlots?.eventType;
|
||||
|
|
@ -83,6 +85,26 @@ export function PublicBookingPage() {
|
|||
name: "",
|
||||
});
|
||||
|
||||
// Loading messages rotation
|
||||
const loadingMessages = [
|
||||
"Nous créons votre rendez-vous, veuillez patienter",
|
||||
"Préparation de votre réservation...",
|
||||
"Configuration de votre appel...",
|
||||
"Finalisation de votre créneau...",
|
||||
];
|
||||
const [currentMessageIndex, setCurrentMessageIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentMessageIndex(0);
|
||||
if (isCreatingTabloWithOwner) {
|
||||
const interval = setInterval(() => {
|
||||
setCurrentMessageIndex((prev) => (prev + 1) % loadingMessages.length);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [isCreatingTabloWithOwner]);
|
||||
|
||||
// Theme
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
|
|
@ -566,6 +588,49 @@ export function PublicBookingPage() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Loading Overlay */}
|
||||
{isCreatingTabloWithOwner && (
|
||||
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[100] flex items-center justify-center">
|
||||
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-2xl p-8 w-md mx-4 border border-gray-200 dark:border-gray-700">
|
||||
<div className="flex flex-col items-center gap-6">
|
||||
{/* Animated Icon */}
|
||||
<div className="relative">
|
||||
<div className="w-20 h-20 rounded-full bg-gradient-to-br from-purple-500 to-blue-500 flex items-center justify-center animate-pulse">
|
||||
<CalendarCheck2 className="w-10 h-10 text-white" />
|
||||
</div>
|
||||
<div className="absolute inset-0 rounded-full border-4 border-purple-500/30 animate-ping"></div>
|
||||
</div>
|
||||
|
||||
{/* Text */}
|
||||
<div className="text-center space-y-2">
|
||||
<TypographyH3 className="text-gray-900 dark:text-white">
|
||||
Réservation en cours...
|
||||
</TypographyH3>
|
||||
<TypographyMuted className="text-gray-600 dark:text-gray-400">
|
||||
{loadingMessages[currentMessageIndex]}
|
||||
</TypographyMuted>
|
||||
</div>
|
||||
|
||||
{/* Loading Spinner */}
|
||||
<div className="flex gap-2">
|
||||
<div
|
||||
className="w-3 h-3 rounded-full bg-purple-500 animate-bounce"
|
||||
style={{ animationDelay: "0ms" }}
|
||||
></div>
|
||||
<div
|
||||
className="w-3 h-3 rounded-full bg-purple-500 animate-bounce"
|
||||
style={{ animationDelay: "150ms" }}
|
||||
></div>
|
||||
<div
|
||||
className="w-3 h-3 rounded-full bg-purple-500 animate-bounce"
|
||||
style={{ animationDelay: "300ms" }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Booking Modal */}
|
||||
<CustomModal
|
||||
isOpen={isModalOpen}
|
||||
|
|
|
|||
Loading…
Reference in a new issue