Update login and book-now pages to enhance user experience by changing images for better representation, refactoring appointment scheduling to use preferred days and times, and improving error handling for user input.

This commit is contained in:
iamkiddy 2025-11-22 20:18:52 +00:00
parent 911ae7433f
commit 487132ee9b
8 changed files with 117 additions and 95 deletions

View File

@ -21,7 +21,7 @@ export default function Login() {
{/* Background Image */} {/* Background Image */}
<div className="absolute inset-0 z-0"> <div className="absolute inset-0 z-0">
<Image <Image
src="/section-image.png" src="/woman.jpg"
alt="Therapy and counseling session with African American clients" alt="Therapy and counseling session with African American clients"
fill fill
className="object-cover object-center" className="object-cover object-center"

View File

@ -78,9 +78,8 @@ export default function BookNowPage() {
lastName: "", lastName: "",
email: "", email: "",
phone: "", phone: "",
appointmentType: "", preferredDays: [] as string[],
preferredDate: "", preferredTimes: [] as string[],
preferredTime: "",
message: "", message: "",
}); });
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -105,17 +104,41 @@ export default function BookNowPage() {
setError(null); setError(null);
try { try {
// Convert time to 24-hour format for ISO string if (formData.preferredDays.length === 0) {
const time24 = formData.preferredTime.includes("PM") setError("Please select at least one available day.");
? formData.preferredTime.replace("PM", "").trim().split(":").map((v, i) => setLoading(false);
i === 0 ? (parseInt(v) === 12 ? 12 : parseInt(v) + 12) : v return;
).join(":") }
: formData.preferredTime.replace("AM", "").trim().split(":").map((v, i) =>
i === 0 ? (parseInt(v) === 12 ? "00" : v.padStart(2, "0")) : v if (formData.preferredTimes.length === 0) {
).join(":"); setError("Please select at least one preferred time.");
setLoading(false);
return;
}
// For now, we'll use the first selected day and first selected time
// This can be adjusted based on your backend requirements
const firstDay = formData.preferredDays[0];
const firstTime = formData.preferredTimes[0];
const timeMap: { [key: string]: string } = {
morning: "09:00",
lunchtime: "12:00",
afternoon: "14:00",
};
const time24 = timeMap[firstTime] || "09:00";
// Get next occurrence of the first selected day
const today = new Date();
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const targetDayIndex = days.indexOf(firstDay);
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];
// Combine date and time into scheduled_at (ISO format) // Combine date and time into scheduled_at (ISO format)
const dateTimeString = `${formData.preferredDate}T${time24}:00Z`; const dateTimeString = `${dateString}T${time24}:00Z`;
// Prepare request payload // Prepare request payload
const payload = { const payload = {
@ -123,9 +146,10 @@ export default function BookNowPage() {
last_name: formData.lastName, last_name: formData.lastName,
email: formData.email, email: formData.email,
phone: formData.phone, phone: formData.phone,
appointment_type: formData.appointmentType,
scheduled_at: dateTimeString, scheduled_at: dateTimeString,
duration: 60, // Default to 60 minutes duration: 60, // Default to 60 minutes
preferred_days: formData.preferredDays,
preferred_times: formData.preferredTimes,
notes: formData.message || "", notes: formData.message || "",
}; };
@ -199,6 +223,24 @@ export default function BookNowPage() {
setFormData((prev) => ({ ...prev, [field]: value })); 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 formatDateTime = (dateString: string) => {
const date = new Date(dateString); const date = new Date(dateString);
return date.toLocaleString("en-US", { return date.toLocaleString("en-US", {
@ -219,7 +261,7 @@ export default function BookNowPage() {
<div className={`hidden lg:block fixed top-0 left-0 h-screen w-1/2 overflow-hidden z-10 bg-gradient-to-br ${isDark ? 'from-gray-900 via-gray-800 to-gray-900' : 'from-rose-100 via-pink-50 to-orange-50'}`}> <div className={`hidden lg:block fixed top-0 left-0 h-screen w-1/2 overflow-hidden z-10 bg-gradient-to-br ${isDark ? 'from-gray-900 via-gray-800 to-gray-900' : 'from-rose-100 via-pink-50 to-orange-50'}`}>
<div className="absolute inset-0"> <div className="absolute inset-0">
<Image <Image
src="/section-image.png" src="/session.jpg"
alt="Therapy session with diverse clients" alt="Therapy session with diverse clients"
fill fill
className="object-cover" className="object-cover"
@ -367,9 +409,8 @@ export default function BookNowPage() {
lastName: "", lastName: "",
email: "", email: "",
phone: "", phone: "",
appointmentType: "", preferredDays: [],
preferredDate: "", preferredTimes: [],
preferredTime: "",
message: "", message: "",
}); });
}} }}
@ -490,92 +531,75 @@ export default function BookNowPage() {
Appointment Details Appointment Details
</h2> </h2>
<div className="space-y-2"> <div className="space-y-4">
<label
htmlFor="appointmentType"
className={`text-sm font-medium ${isDark ? 'text-gray-300' : 'text-gray-700'}`}
>
Appointment Type *
</label>
<Select
value={formData.appointmentType}
onValueChange={(value) =>
handleChange("appointmentType", value)
}
required
>
<SelectTrigger id="appointmentType" className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white' : 'bg-white border-gray-300 text-gray-900'}`}>
<SelectValue placeholder="Select appointment type" />
</SelectTrigger>
<SelectContent className={isDark ? 'bg-gray-700 border-gray-600' : 'bg-white border-gray-300'}>
<SelectItem value="initial-consultation">
Initial Consultation
</SelectItem>
<SelectItem value="individual-therapy">
Individual Therapy
</SelectItem>
<SelectItem value="family-therapy">Family Therapy</SelectItem>
<SelectItem value="couples-therapy">
Couples Therapy
</SelectItem>
<SelectItem value="group-therapy">Group Therapy</SelectItem>
<SelectItem value="follow-up">Follow-up Session</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<label <label
htmlFor="preferredDate"
className={`text-sm font-medium flex items-center gap-2 ${isDark ? 'text-gray-300' : 'text-gray-700'}`} className={`text-sm font-medium flex items-center gap-2 ${isDark ? 'text-gray-300' : 'text-gray-700'}`}
> >
<Calendar className={`w-4 h-4 ${isDark ? 'text-gray-400' : 'text-gray-500'}`} /> <Calendar className={`w-4 h-4 ${isDark ? 'text-gray-400' : 'text-gray-500'}`} />
Preferred Date * Available Days *
</label> </label>
<Input <div className="flex flex-wrap gap-3">
id="preferredDate" {['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'].map((day) => (
type="date" <label
value={formData.preferredDate} key={day}
onChange={(e) => className={`flex items-center gap-2 cursor-pointer px-4 py-2 rounded-lg border transition-all ${
handleChange("preferredDate", e.target.value) formData.preferredDays.includes(day)
} ? isDark
required ? 'bg-rose-600 border-rose-500 text-white'
min={new Date().toISOString().split("T")[0]} : 'bg-rose-500 border-rose-500 text-white'
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white' : 'bg-white border-gray-300 text-gray-900'}`} : isDark
/> ? 'bg-gray-700 border-gray-600 text-gray-300 hover:border-rose-500'
: 'bg-white border-gray-300 text-gray-700 hover:border-rose-500'
}`}
>
<input
type="checkbox"
checked={formData.preferredDays.includes(day)}
onChange={() => handleDayToggle(day)}
className="sr-only"
/>
<span className="text-sm font-medium">{day}</span>
</label>
))}
</div>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<label <label
htmlFor="preferredTime"
className={`text-sm font-medium flex items-center gap-2 ${isDark ? 'text-gray-300' : 'text-gray-700'}`} className={`text-sm font-medium flex items-center gap-2 ${isDark ? 'text-gray-300' : 'text-gray-700'}`}
> >
<Clock className={`w-4 h-4 ${isDark ? 'text-gray-400' : 'text-gray-500'}`} /> <Clock className={`w-4 h-4 ${isDark ? 'text-gray-400' : 'text-gray-500'}`} />
Preferred Time * Preferred Time *
</label> </label>
<Select <div className="flex flex-wrap gap-3">
value={formData.preferredTime} {[
onValueChange={(value) => { value: 'morning', label: 'Morning' },
handleChange("preferredTime", value) { value: 'lunchtime', label: 'Lunchtime' },
} { value: 'afternoon', label: 'Afternoon' }
required ].map((time) => (
> <label
<SelectTrigger id="preferredTime" className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white' : 'bg-white border-gray-300 text-gray-900'}`}> key={time.value}
<SelectValue placeholder="Select time" /> className={`flex items-center gap-2 cursor-pointer px-4 py-2 rounded-lg border transition-all ${
</SelectTrigger> formData.preferredTimes.includes(time.value)
<SelectContent className={isDark ? 'bg-gray-700 border-gray-600' : 'bg-white border-gray-300'}> ? isDark
<SelectItem value="9:00 AM">9:00 AM</SelectItem> ? 'bg-rose-600 border-rose-500 text-white'
<SelectItem value="10:00 AM">10:00 AM</SelectItem> : 'bg-rose-500 border-rose-500 text-white'
<SelectItem value="11:00 AM">11:00 AM</SelectItem> : isDark
<SelectItem value="12:00 PM">12:00 PM</SelectItem> ? 'bg-gray-700 border-gray-600 text-gray-300 hover:border-rose-500'
<SelectItem value="1:00 PM">1:00 PM</SelectItem> : 'bg-white border-gray-300 text-gray-700 hover:border-rose-500'
<SelectItem value="2:00 PM">2:00 PM</SelectItem> }`}
<SelectItem value="3:00 PM">3:00 PM</SelectItem> >
<SelectItem value="4:00 PM">4:00 PM</SelectItem> <input
<SelectItem value="5:00 PM">5:00 PM</SelectItem> type="checkbox"
</SelectContent> checked={formData.preferredTimes.includes(time.value)}
</Select> onChange={() => handleTimeToggle(time.value)}
className="sr-only"
/>
<span className="text-sm font-medium">{time.label}</span>
</label>
))}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -152,10 +152,8 @@ export function ClientFocus() {
className="bg-card/50 backdrop-blur-sm rounded-2xl p-6 border border-border/50 hover:border-rose-500/50 hover:shadow-lg hover:shadow-rose-500/10 hover:scale-105 transition-all duration-300" className="bg-card/50 backdrop-blur-sm rounded-2xl p-6 border border-border/50 hover:border-rose-500/50 hover:shadow-lg hover:shadow-rose-500/10 hover:scale-105 transition-all duration-300"
> >
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="bg-gradient-to-br from-rose-500/20 via-pink-500/20 to-orange-500/20 dark:from-rose-500/30 dark:via-pink-500/30 dark:to-orange-500/30 p-3 rounded-xl">
<Globe className="h-6 w-6 text-rose-600 dark:text-rose-400" /> <h3 className="text-xl font-semibold text-foreground text-center justify-center">Providing Support to all of South Florida's Diverse Communities</h3>
</div>
<h3 className="text-xl font-semibold text-foreground">Communities</h3>
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
<div className="flex justify-center items-center"> <div className="flex justify-center items-center">
@ -166,7 +164,7 @@ export function ClientFocus() {
className="relative w-full max-w-md h-auto" className="relative w-full max-w-md h-auto"
> >
<Image <Image
src="/flags.png" src="/flagss.png"
alt="Organization of American States Flags" alt="Organization of American States Flags"
width={400} width={400}
height={267} height={267}

View File

@ -18,7 +18,7 @@ export function HeroSection() {
<div <div
className="absolute inset-0 z-0" className="absolute inset-0 z-0"
style={{ style={{
backgroundImage: `url('https://images.unsplash.com/photo-1506126613408-eca07ce68773?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80')`, backgroundImage: `url('/large.jpeg')`,
backgroundSize: 'cover', backgroundSize: 'cover',
backgroundPosition: 'center', backgroundPosition: 'center',
backgroundRepeat: 'no-repeat', backgroundRepeat: 'no-repeat',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

BIN
public/flagss.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
public/session.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

BIN
public/woman.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB