feat/booking-panel #57
@ -104,6 +104,14 @@ export default function BookNowPage() {
|
|||||||
const [showSignupDialog, setShowSignupDialog] = useState(false);
|
const [showSignupDialog, setShowSignupDialog] = useState(false);
|
||||||
const [loginPrefillEmail, setLoginPrefillEmail] = useState<string | undefined>(undefined);
|
const [loginPrefillEmail, setLoginPrefillEmail] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
|
// Require authentication before accessing booking page
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
// Show login dialog immediately if not authenticated
|
||||||
|
setShowLoginDialog(true);
|
||||||
|
}
|
||||||
|
}, [isAuthenticated]);
|
||||||
|
|
||||||
// Helper function to convert day name to day number (0-6)
|
// Helper function to convert day name to day number (0-6)
|
||||||
const getDayNumber = (dayName: string): number => {
|
const getDayNumber = (dayName: string): number => {
|
||||||
const dayMap: Record<string, number> = {
|
const dayMap: Record<string, number> = {
|
||||||
@ -241,15 +249,21 @@ export default function BookNowPage() {
|
|||||||
const handleLoginSuccess = async () => {
|
const handleLoginSuccess = async () => {
|
||||||
// Close login dialog
|
// Close login dialog
|
||||||
setShowLoginDialog(false);
|
setShowLoginDialog(false);
|
||||||
// After successful login, proceed with booking submission
|
// If there's a pending booking submission, proceed with it
|
||||||
|
// Otherwise, just close the dialog and allow user to fill the form
|
||||||
|
if (formData.selectedSlots.length > 0 && formData.firstName && formData.lastName && formData.email) {
|
||||||
await submitBooking();
|
await submitBooking();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSignupSuccess = async () => {
|
const handleSignupSuccess = async () => {
|
||||||
// Close signup dialog
|
// Close signup dialog
|
||||||
setShowSignupDialog(false);
|
setShowSignupDialog(false);
|
||||||
// After successful signup, proceed with booking submission
|
// If there's a pending booking submission, proceed with it
|
||||||
|
// Otherwise, just close the dialog and allow user to fill the form
|
||||||
|
if (formData.selectedSlots.length > 0 && formData.firstName && formData.lastName && formData.email) {
|
||||||
await submitBooking();
|
await submitBooking();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSwitchToSignup = () => {
|
const handleSwitchToSignup = () => {
|
||||||
@ -652,6 +666,13 @@ export default function BookNowPage() {
|
|||||||
<p className={`text-sm ${isDark ? 'text-red-200' : 'text-red-800'}`}>{error}</p>
|
<p className={`text-sm ${isDark ? 'text-red-200' : 'text-red-800'}`}>{error}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!isAuthenticated && (
|
||||||
|
<div className={`mb-6 p-4 rounded-lg border ${isDark ? 'bg-yellow-900/20 border-yellow-800' : 'bg-yellow-50 border-yellow-200'}`}>
|
||||||
|
<p className={`text-sm ${isDark ? 'text-yellow-200' : 'text-yellow-800'}`}>
|
||||||
|
Please log in to book an appointment. The login dialog should appear automatically.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
{/* Personal Information Section */}
|
{/* Personal Information Section */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
@ -678,6 +699,7 @@ export default function BookNowPage() {
|
|||||||
}
|
}
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
required
|
required
|
||||||
|
disabled={!isAuthenticated}
|
||||||
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900 placeholder:text-gray-500'}`}
|
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900 placeholder:text-gray-500'}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -699,6 +721,7 @@ export default function BookNowPage() {
|
|||||||
}
|
}
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
required
|
required
|
||||||
|
disabled={!isAuthenticated}
|
||||||
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900 placeholder:text-gray-500'}`}
|
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900 placeholder:text-gray-500'}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -720,6 +743,7 @@ export default function BookNowPage() {
|
|||||||
onChange={(e) => handleChange("email", e.target.value)}
|
onChange={(e) => handleChange("email", e.target.value)}
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
required
|
required
|
||||||
|
disabled={!isAuthenticated}
|
||||||
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900 placeholder:text-gray-500'}`}
|
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900 placeholder:text-gray-500'}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -740,6 +764,7 @@ export default function BookNowPage() {
|
|||||||
onChange={(e) => handleChange("phone", e.target.value)}
|
onChange={(e) => handleChange("phone", e.target.value)}
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
required
|
required
|
||||||
|
disabled={!isAuthenticated}
|
||||||
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900 placeholder:text-gray-500'}`}
|
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900 placeholder:text-gray-500'}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -814,9 +839,14 @@ export default function BookNowPage() {
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
setShowLoginDialog(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Pass the specific day and time slot for this button
|
// Pass the specific day and time slot for this button
|
||||||
handleSlotToggle(currentDay, normalizedTimeSlot);
|
handleSlotToggle(currentDay, normalizedTimeSlot);
|
||||||
}}
|
}}
|
||||||
|
disabled={!isAuthenticated}
|
||||||
aria-pressed={isSelected}
|
aria-pressed={isSelected}
|
||||||
className={`flex items-center gap-2 cursor-pointer px-4 py-2 rounded-lg border-2 transition-all focus:outline-none focus:ring-2 focus:ring-rose-500 ${
|
className={`flex items-center gap-2 cursor-pointer px-4 py-2 rounded-lg border-2 transition-all focus:outline-none focus:ring-2 focus:ring-rose-500 ${
|
||||||
isSelected
|
isSelected
|
||||||
@ -861,6 +891,7 @@ export default function BookNowPage() {
|
|||||||
value={formData.message}
|
value={formData.message}
|
||||||
onChange={(e) => handleChange("message", e.target.value)}
|
onChange={(e) => handleChange("message", e.target.value)}
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
|
disabled={!isAuthenticated}
|
||||||
className={`w-full rounded-md border px-3 py-2 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-rose-500 focus-visible:border-rose-500 disabled:cursor-not-allowed disabled:opacity-50 ${isDark ? 'border-gray-600 bg-gray-700 text-white placeholder:text-gray-400 focus-visible:ring-rose-400 focus-visible:border-rose-400' : 'border-gray-300 bg-white text-gray-900 placeholder:text-gray-500'}`}
|
className={`w-full rounded-md border px-3 py-2 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-rose-500 focus-visible:border-rose-500 disabled:cursor-not-allowed disabled:opacity-50 ${isDark ? 'border-gray-600 bg-gray-700 text-white placeholder:text-gray-400 focus-visible:ring-rose-400 focus-visible:border-rose-400' : 'border-gray-300 bg-white text-gray-900 placeholder:text-gray-500'}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -870,7 +901,7 @@ export default function BookNowPage() {
|
|||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
size="lg"
|
size="lg"
|
||||||
disabled={isCreating || availableDaysOfWeek.length === 0 || formData.selectedSlots.length === 0}
|
disabled={!isAuthenticated || isCreating || availableDaysOfWeek.length === 0 || formData.selectedSlots.length === 0}
|
||||||
className="w-full bg-gradient-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white shadow-lg hover:shadow-xl transition-all h-12 text-base font-semibold disabled:opacity-50 disabled:cursor-not-allowed"
|
className="w-full bg-gradient-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white shadow-lg hover:shadow-xl transition-all h-12 text-base font-semibold disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{isCreating ? (
|
{isCreating ? (
|
||||||
@ -915,6 +946,12 @@ export default function BookNowPage() {
|
|||||||
<LoginDialog
|
<LoginDialog
|
||||||
open={showLoginDialog}
|
open={showLoginDialog}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
|
// Prevent closing if user is not authenticated (force login)
|
||||||
|
if (!open && !isAuthenticated) {
|
||||||
|
// Redirect to home if they try to close without logging in
|
||||||
|
router.push("/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
setShowLoginDialog(open);
|
setShowLoginDialog(open);
|
||||||
if (!open) {
|
if (!open) {
|
||||||
setLoginPrefillEmail(undefined);
|
setLoginPrefillEmail(undefined);
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export function Navbar() {
|
|||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={isAuthenticated && !isAdmin ? "/user/dashboard" : "/"}
|
href="/"
|
||||||
className="flex items-center gap-1.5 sm:gap-2"
|
className="flex items-center gap-1.5 sm:gap-2"
|
||||||
>
|
>
|
||||||
<div className="bg-gradient-to-r from-rose-500 to-pink-600 p-1.5 sm:p-2 rounded-lg sm:rounded-xl">
|
<div className="bg-gradient-to-r from-rose-500 to-pink-600 p-1.5 sm:p-2 rounded-lg sm:rounded-xl">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user