Merge branch 'fix/landing-page-issues'

This commit is contained in:
iamkiddy 2025-11-22 20:24:08 +00:00
commit 1e829de544
10 changed files with 155 additions and 160 deletions

View File

@ -21,21 +21,27 @@ export default function Login() {
{/* Background Image */}
<div className="absolute inset-0 z-0">
<Image
src="/doctors.png"
alt="Medical professionals"
src="/woman.jpg"
alt="Therapy and counseling session with African American clients"
fill
className="object-cover object-center"
priority
sizes="100vw"
/>
{/* Overlay for better readability */}
<div className="absolute inset-0 bg-black/20"></div>
<div className="absolute inset-0 bg-black/50"></div>
</div>
{/* Branding - Top Left */}
<div className="absolute top-8 left-8 flex items-center gap-3 z-30">
<Heart className="w-6 h-6 text-white" fill="white" />
<span className="text-white text-xl font-semibold">Attune Heart Therapy</span>
<div className="absolute top-8 left-8 flex items-center gap-2 z-30">
<Link href="/" className="flex items-center gap-2">
<div className="bg-gradient-to-r from-rose-500 to-pink-600 p-2 rounded-xl">
<Heart className="h-5 w-5 text-white fill-white" />
</div>
<span className={`font-bold text-lg drop-shadow-lg ${isDark ? 'text-rose-400' : 'text-rose-500'}`}>
Attune Heart Therapy
</span>
</Link>
</div>

View File

@ -78,9 +78,8 @@ export default function BookNowPage() {
lastName: "",
email: "",
phone: "",
appointmentType: "",
preferredDate: "",
preferredTime: "",
preferredDays: [] as string[],
preferredTimes: [] as string[],
message: "",
});
const [loading, setLoading] = useState(false);
@ -105,17 +104,41 @@ export default function BookNowPage() {
setError(null);
try {
// Convert time to 24-hour format for ISO string
const time24 = formData.preferredTime.includes("PM")
? formData.preferredTime.replace("PM", "").trim().split(":").map((v, i) =>
i === 0 ? (parseInt(v) === 12 ? 12 : parseInt(v) + 12) : v
).join(":")
: formData.preferredTime.replace("AM", "").trim().split(":").map((v, i) =>
i === 0 ? (parseInt(v) === 12 ? "00" : v.padStart(2, "0")) : v
).join(":");
if (formData.preferredDays.length === 0) {
setError("Please select at least one available day.");
setLoading(false);
return;
}
if (formData.preferredTimes.length === 0) {
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)
const dateTimeString = `${formData.preferredDate}T${time24}:00Z`;
const dateTimeString = `${dateString}T${time24}:00Z`;
// Prepare request payload
const payload = {
@ -123,9 +146,10 @@ export default function BookNowPage() {
last_name: formData.lastName,
email: formData.email,
phone: formData.phone,
appointment_type: formData.appointmentType,
scheduled_at: dateTimeString,
duration: 60, // Default to 60 minutes
preferred_days: formData.preferredDays,
preferred_times: formData.preferredTimes,
notes: formData.message || "",
};
@ -199,6 +223,24 @@ export default function BookNowPage() {
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", {
@ -219,8 +261,8 @@ 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="absolute inset-0">
<Image
src="/doctors.png"
alt="Therapy session"
src="/session.jpg"
alt="Therapy session with diverse clients"
fill
className="object-cover"
priority
@ -367,9 +409,8 @@ export default function BookNowPage() {
lastName: "",
email: "",
phone: "",
appointmentType: "",
preferredDate: "",
preferredTime: "",
preferredDays: [],
preferredTimes: [],
message: "",
});
}}
@ -490,92 +531,75 @@ export default function BookNowPage() {
Appointment Details
</h2>
<div className="space-y-2">
<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-4">
<div className="space-y-2">
<label
htmlFor="preferredDate"
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'}`} />
Preferred Date *
Available Days *
</label>
<Input
id="preferredDate"
type="date"
value={formData.preferredDate}
onChange={(e) =>
handleChange("preferredDate", e.target.value)
}
required
min={new Date().toISOString().split("T")[0]}
className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white' : 'bg-white border-gray-300 text-gray-900'}`}
/>
<div className="flex flex-wrap gap-3">
{['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'].map((day) => (
<label
key={day}
className={`flex items-center gap-2 cursor-pointer px-4 py-2 rounded-lg border transition-all ${
formData.preferredDays.includes(day)
? isDark
? 'bg-rose-600 border-rose-500 text-white'
: 'bg-rose-500 border-rose-500 text-white'
: 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 className="space-y-2">
<label
htmlFor="preferredTime"
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'}`} />
Preferred Time *
</label>
<Select
value={formData.preferredTime}
onValueChange={(value) =>
handleChange("preferredTime", value)
}
required
>
<SelectTrigger id="preferredTime" className={`h-11 ${isDark ? 'bg-gray-700 border-gray-600 text-white' : 'bg-white border-gray-300 text-gray-900'}`}>
<SelectValue placeholder="Select time" />
</SelectTrigger>
<SelectContent className={isDark ? 'bg-gray-700 border-gray-600' : 'bg-white border-gray-300'}>
<SelectItem value="9:00 AM">9:00 AM</SelectItem>
<SelectItem value="10:00 AM">10:00 AM</SelectItem>
<SelectItem value="11:00 AM">11:00 AM</SelectItem>
<SelectItem value="12:00 PM">12:00 PM</SelectItem>
<SelectItem value="1:00 PM">1:00 PM</SelectItem>
<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>
<SelectItem value="5:00 PM">5:00 PM</SelectItem>
</SelectContent>
</Select>
<div className="flex flex-wrap gap-3">
{[
{ value: 'morning', label: 'Morning' },
{ value: 'lunchtime', label: 'Lunchtime' },
{ value: 'afternoon', label: 'Afternoon' }
].map((time) => (
<label
key={time.value}
className={`flex items-center gap-2 cursor-pointer px-4 py-2 rounded-lg border transition-all ${
formData.preferredTimes.includes(time.value)
? isDark
? 'bg-rose-600 border-rose-500 text-white'
: 'bg-rose-500 border-rose-500 text-white'
: 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.preferredTimes.includes(time.value)}
onChange={() => handleTimeToggle(time.value)}
className="sr-only"
/>
<span className="text-sm font-medium">{time.label}</span>
</label>
))}
</div>
</div>
</div>
</div>

View File

@ -5,6 +5,7 @@ import { useInView } from "framer-motion";
import { useRef } from "react";
import { Users, UserCheck, Globe } from "lucide-react";
import { useAppTheme } from "@/components/ThemeProvider";
import Image from "next/image";
export function ClientFocus() {
const ref = useRef(null);
@ -94,7 +95,7 @@ export function ClientFocus() {
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.8, delay: 0.2 }}
>
Client Focus
Who We Serve
</motion.h2>
</motion.div>
@ -143,7 +144,7 @@ export function ClientFocus() {
<p className="text-muted-foreground">Individuals</p>
</motion.div>
{/* Ethnicity */}
{/* Communities */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
@ -151,12 +152,28 @@ 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"
>
<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" />
</div>
<h3 className="text-xl font-semibold text-foreground">Ethnicity</h3>
<h3 className="text-xl font-semibold text-foreground text-center justify-center">Providing Support to all of South Florida's Diverse Communities</h3>
</div>
<div className="space-y-3">
<div className="flex justify-center items-center">
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={isInView ? { opacity: 1, scale: 1 } : {}}
transition={{ duration: 0.5, delay: 0.5 }}
className="relative w-full max-w-md h-auto"
>
<Image
src="/flagss.png"
alt="Organization of American States Flags"
width={400}
height={267}
className="w-full h-auto object-contain rounded-lg"
priority
/>
</motion.div>
</div>
</div>
<p className="text-muted-foreground">Black and African American</p>
</motion.div>
</div>
</div>

View File

@ -3,7 +3,7 @@
import { motion } from "framer-motion";
import { useInView } from "framer-motion";
import { useRef } from "react";
import { CreditCard, DollarSign, Shield } from "lucide-react";
import { CreditCard, DollarSign } from "lucide-react";
import { useAppTheme } from "@/components/ThemeProvider";
export function Finances() {
@ -19,31 +19,6 @@ export function Finances() {
"Visa"
];
const insuranceProviders = [
"Aetna",
"Aetna - Medicare",
"Aetna - WebTPA",
"All Savers",
"Ambetter",
"AvMed",
"Cigna and Evernorth",
"EAP:Cigna",
"EAP:UnitedHealthcare/Optum",
"Golden Rule",
"Harvard Pilgrim/United",
"Humana",
"Humana - Medicare",
"Humana Dual- Medicaid/Medicare",
"Medicaid",
"Optum",
"Oscar Health",
"Oxford",
"Surest (formerly Bind)",
"Tufts Health/Cigna",
"UHC/Optum - Medicare",
"United Medical Resources (UMR)",
"UnitedHealthcare UHC | UBH"
];
return (
<section
@ -132,7 +107,7 @@ export function Finances() {
</motion.p>
</motion.div>
<div className="grid md:grid-cols-3 gap-6 mb-8">
<div className="grid md:grid-cols-2 gap-6 mb-8">
{/* Fees */}
<motion.div
initial={{ opacity: 0, y: 20 }}
@ -178,33 +153,6 @@ export function Finances() {
</div>
</motion.div>
{/* Insurance */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, delay: 0.4 }}
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="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">
<Shield className="h-6 w-6 text-rose-600 dark:text-rose-400" />
</div>
<h3 className="text-xl font-semibold text-foreground">Insurance</h3>
</div>
<div className="max-h-64 overflow-y-auto space-y-2 pr-2">
{insuranceProviders.map((provider, index) => (
<motion.p
key={provider}
className="text-sm text-muted-foreground"
initial={{ opacity: 0, x: -10 }}
animate={isInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.3, delay: 0.5 + index * 0.02 }}
>
{provider}
</motion.p>
))}
</div>
</motion.div>
</div>
</div>
</section>

View File

@ -18,7 +18,7 @@ export function HeroSection() {
<div
className="absolute inset-0 z-0"
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',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
@ -29,7 +29,7 @@ export function HeroSection() {
<div
className="absolute inset-0 z-[1]"
style={{
backgroundColor: isDark ? 'rgba(0, 0, 0, 0.35)' : 'rgba(0, 0, 0, 0.25)'
backgroundColor: isDark ? 'rgba(0, 0, 0, 0.65)' : 'rgba(0, 0, 0, 0.55)'
}}
/>

View File

@ -220,8 +220,8 @@ export function Services() {
animate={isInView ? { opacity: 1 } : {}}
transition={{ duration: 0.8, delay: 0.9 }}
>
Therapy is tailored for children (age 610), teens, adults, and older adults, with services offered to individuals and a
special focus on supporting Black and African American families in Miami and Hollywood, Florida.
Therapy is tailored for children (age 610), teens, adults, and older adults, with services offered to individuals.
I welcome clients from diverse backgrounds and communities throughout Miami and Hollywood, Florida.
</motion.p>
</div>
</motion.div>

BIN
public/flagss.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
public/section-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

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