"use client"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import { useAppTheme } from "@/components/ThemeProvider"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Calendar, Clock, User, Mail, Phone, MessageSquare, ArrowLeft, Heart, CheckCircle2, CheckCircle, Loader2, LogOut, } from "lucide-react"; import Link from "next/link"; import Image from "next/image"; import { useRouter } from "next/navigation"; import { LoginDialog } from "@/components/LoginDialog"; import { SignupDialog } from "@/components/SignupDialog"; import { useAuth } from "@/hooks/useAuth"; import { useAppointments } from "@/hooks/useAppointments"; import { toast } from "sonner"; import type { Appointment } from "@/lib/models/appointments"; interface User { ID: number; CreatedAt?: string; UpdatedAt?: string; DeletedAt?: string | null; first_name: string; last_name: string; email: string; phone: string; location: string; date_of_birth?: string; is_admin?: boolean; bookings?: null; } interface Booking { ID: number; CreatedAt: string; UpdatedAt: string; DeletedAt: string | null; user_id: number; user: User; scheduled_at: string; duration: number; status: string; jitsi_room_id: string; jitsi_room_url: string; payment_id: string; payment_status: string; amount: number; notes: string; } interface BookingsResponse { bookings: Booking[]; limit: number; offset: number; total: number; } export default function BookNowPage() { const router = useRouter(); const { theme } = useAppTheme(); const isDark = theme === "dark"; const { isAuthenticated, logout } = useAuth(); const { create, isCreating } = useAppointments(); const [formData, setFormData] = useState({ firstName: "", lastName: "", email: "", phone: "", preferredDays: [] as string[], preferredTimes: [] as string[], message: "", }); const [booking, setBooking] = useState(null); const [error, setError] = useState(null); const [showLoginDialog, setShowLoginDialog] = useState(false); const [showSignupDialog, setShowSignupDialog] = useState(false); const [loginPrefillEmail, setLoginPrefillEmail] = useState(undefined); const handleLogout = () => { logout(); toast.success("Logged out successfully"); router.push("/"); }; // Handle submit button click const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); // Check if user is authenticated if (!isAuthenticated) { // Open login dialog if not authenticated setShowLoginDialog(true); return; } // If authenticated, proceed with booking await submitBooking(); }; const handleLoginSuccess = async () => { // Close login dialog setShowLoginDialog(false); // After successful login, proceed with booking submission await submitBooking(); }; const handleSignupSuccess = async () => { // Close signup dialog setShowSignupDialog(false); // After successful signup, proceed with booking submission await submitBooking(); }; const handleSwitchToSignup = () => { // Close login dialog and open signup dialog setShowLoginDialog(false); setTimeout(() => { setShowSignupDialog(true); }, 100); }; const handleSwitchToLogin = (email?: string) => { // Close signup dialog and open login dialog with email prefilled setShowSignupDialog(false); setLoginPrefillEmail(email); setTimeout(() => { setShowLoginDialog(true); }, 100); }; const submitBooking = async () => { setError(null); try { if (formData.preferredDays.length === 0) { setError("Please select at least one available day."); return; } if (formData.preferredTimes.length === 0) { setError("Please select at least one preferred time."); return; } // Convert day names to dates (YYYY-MM-DD format) // Get next occurrence of each selected day const today = new Date(); const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; const preferredDates: string[] = []; formData.preferredDays.forEach((dayName) => { const targetDayIndex = days.indexOf(dayName); if (targetDayIndex === -1) return; let daysUntilTarget = (targetDayIndex - today.getDay() + 7) % 7; if (daysUntilTarget === 0) daysUntilTarget = 7; // Next week if today const targetDate = new Date(today); targetDate.setDate(today.getDate() + daysUntilTarget); const dateString = targetDate.toISOString().split("T")[0]; preferredDates.push(dateString); }); // Map time slots - API expects "morning", "afternoon", "evening" // Form has "morning", "lunchtime", "afternoon" const timeSlotMap: { [key: string]: "morning" | "afternoon" | "evening" } = { morning: "morning", lunchtime: "afternoon", // Map lunchtime to afternoon afternoon: "afternoon", }; const preferredTimeSlots = formData.preferredTimes .map((time) => timeSlotMap[time] || "morning") .filter((time, index, self) => self.indexOf(time) === index) as ("morning" | "afternoon" | "evening")[]; // Remove duplicates // Prepare request payload according to API spec const payload = { first_name: formData.firstName, last_name: formData.lastName, email: formData.email, preferred_dates: preferredDates, preferred_time_slots: preferredTimeSlots, ...(formData.phone && { phone: formData.phone }), ...(formData.message && { reason: formData.message }), }; // Call the actual API using the hook const appointmentData = await create(payload); // Convert API response to Booking format for display // Use a stable ID - if appointmentData.id exists, use it, otherwise use 0 const appointmentId = appointmentData.id ? parseInt(appointmentData.id, 10) : 0; const now = new Date().toISOString(); const bookingData: Booking = { ID: appointmentId || 0, CreatedAt: appointmentData.created_at || now, UpdatedAt: appointmentData.updated_at || now, DeletedAt: null, user_id: 0, // API doesn't return user_id in this response user: { ID: 0, first_name: appointmentData.first_name, last_name: appointmentData.last_name, email: appointmentData.email, phone: appointmentData.phone || "", location: "", is_admin: false, bookings: null, }, scheduled_at: appointmentData.scheduled_datetime || "", duration: appointmentData.scheduled_duration || 60, status: appointmentData.status || "pending_review", jitsi_room_id: appointmentData.jitsi_room_id || "", jitsi_room_url: appointmentData.jitsi_meet_url || "", payment_id: "", payment_status: "pending", amount: 0, notes: appointmentData.reason || "", }; setBooking(bookingData); toast.success("Appointment request submitted successfully! We'll review and get back to you soon."); // Redirect to user dashboard after 3 seconds setTimeout(() => { router.push("/user/dashboard"); }, 3000); } catch (err) { const errorMessage = err instanceof Error ? err.message : "Failed to submit booking. Please try again."; setError(errorMessage); toast.error(errorMessage); console.error("Booking error:", err); } }; const handleChange = (field: string, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })); }; const handleDayToggle = (day: string) => { setFormData((prev) => { const days = prev.preferredDays.includes(day) ? prev.preferredDays.filter((d) => d !== day) : [...prev.preferredDays, day]; return { ...prev, preferredDays: days }; }); }; const handleTimeToggle = (time: string) => { setFormData((prev) => { const times = prev.preferredTimes.includes(time) ? prev.preferredTimes.filter((t) => t !== time) : [...prev.preferredTimes, time]; return { ...prev, preferredTimes: times }; }); }; const formatDateTime = (dateString: string) => { const date = new Date(dateString); return date.toLocaleString("en-US", { month: "short", day: "numeric", year: "numeric", hour: "numeric", minute: "2-digit", hour12: true, }); }; return (
{/* Main Content */}
{/* Left Side - Image (Fixed) */}
Therapy session with diverse clients
{/* Logo at Top */}
Attune Heart Therapy
{/* Overlay Content - Lower Position */}

Begin Your Journey to Wellness

Take the first step towards healing and growth. Our compassionate team is here to support you every step of the way.

{/* Features List */}
Safe and confidential environment
Experienced licensed therapists
Personalized treatment plans
Flexible scheduling options
{/* Right Side - Form (Scrollable) */}
{/* Page Header */}

Book Your Appointment

Fill out the form below and we'll get back to you to confirm your appointment

{/* Booking Form or Success Message */}
{booking ? (

Booking Confirmed!

Your appointment has been successfully booked.

Booking ID

#{booking.ID}

Patient

{booking.user.first_name} {booking.user.last_name}

Scheduled Time

{formatDateTime(booking.scheduled_at)}

Duration

{booking.duration} minutes

Status

{booking.status}

Amount

${booking.amount}

{booking.notes && (

Notes

{booking.notes}

)}
) : ( <>
{error && (

{error}

)}
{/* Personal Information Section */}

Personal Information

handleChange("firstName", e.target.value) } required 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'}`} />
handleChange("lastName", e.target.value) } required 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'}`} />
handleChange("email", e.target.value)} required 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'}`} />
handleChange("phone", e.target.value)} required 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'}`} />
{/* Appointment Details Section */}

Appointment Details

{['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'].map((day) => ( ))}
{[ { value: 'morning', label: 'Morning' }, { value: 'lunchtime', label: 'Lunchtime' }, { value: 'afternoon', label: 'Afternoon' } ].map((time) => ( ))}
{/* Additional Message Section */}