|
|
|
|
@@ -5,11 +5,11 @@ import NavbarLayoutFloatingInline from "@/components/navbar/NavbarLayoutFloating
|
|
|
|
|
import HeroSplitKpi from "@/components/sections/hero/HeroSplitKpi";
|
|
|
|
|
import ProductCardTwo from "@/components/sections/product/ProductCardTwo";
|
|
|
|
|
import InlineImageSplitTextAbout from "@/components/sections/about/InlineImageSplitTextAbout";
|
|
|
|
|
import FeatureCardOne from "@/components/sections/feature/FeatureCardOne";
|
|
|
|
|
import FeatureCardNine from "@/components/sections/feature/FeatureCardNine";
|
|
|
|
|
import TestimonialCardSix from "@/components/sections/testimonial/TestimonialCardSix";
|
|
|
|
|
import ContactSplit from "@/components/sections/contact/ContactSplit";
|
|
|
|
|
import FooterBase from "@/components/sections/footer/FooterBase";
|
|
|
|
|
import { Star, Sparkles, Award, Heart, Mail, CheckCircle } from "lucide-react";
|
|
|
|
|
import { Star, Sparkles, Award, Heart, Mail, Calendar, X, Clock, Users, CheckCircle } from "lucide-react";
|
|
|
|
|
import { useState } from "react";
|
|
|
|
|
import React from "react";
|
|
|
|
|
|
|
|
|
|
@@ -50,54 +50,6 @@ const TIME_SLOTS: TimeSlot[] = [
|
|
|
|
|
{ time: '04:00 PM', available: true },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Pre-generate random values outside of render to avoid impure function violations
|
|
|
|
|
const generateRandomValues = () => {
|
|
|
|
|
return Array.from({ length: 30 }).map(() => ({
|
|
|
|
|
delay: Math.random() * 2,
|
|
|
|
|
duration: 3 + Math.random() * 2,
|
|
|
|
|
x: Math.random() * 100,
|
|
|
|
|
y: Math.random() * 100,
|
|
|
|
|
size: 2 + Math.random() * 4,
|
|
|
|
|
offsetX: Math.random() * 100 - 50,
|
|
|
|
|
offsetY: Math.random() * 100 - 50,
|
|
|
|
|
}));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const RANDOM_VALUES = generateRandomValues();
|
|
|
|
|
|
|
|
|
|
function FloatingDotsAnimation() {
|
|
|
|
|
return (
|
|
|
|
|
<div className="fixed inset-0 pointer-events-none overflow-hidden">
|
|
|
|
|
{RANDOM_VALUES.map((values, i) => (
|
|
|
|
|
<div
|
|
|
|
|
key={i}
|
|
|
|
|
className="absolute rounded-full bg-magenta-500 opacity-60"
|
|
|
|
|
style={{
|
|
|
|
|
width: `${values.size}px`,
|
|
|
|
|
height: `${values.size}px`,
|
|
|
|
|
left: `${values.x}%`,
|
|
|
|
|
top: `${values.y}%`,
|
|
|
|
|
animation: `float-dots ${values.duration}s ease-in-out ${values.delay}s infinite`,
|
|
|
|
|
backgroundColor: '#ff00ff',
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
<style>{`
|
|
|
|
|
@keyframes float-dots {
|
|
|
|
|
0%, 100% {
|
|
|
|
|
transform: translate(0, 0) scale(1);
|
|
|
|
|
opacity: 0.3;
|
|
|
|
|
}
|
|
|
|
|
50% {
|
|
|
|
|
transform: translate(var(--tx), var(--ty)) scale(1.2);
|
|
|
|
|
opacity: 0.8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
`}</style>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function BookingModal({ isOpen, onClose, onSubmit }: { isOpen: boolean; onClose: () => void; onSubmit: (data: any) => void }) {
|
|
|
|
|
const [state, setState] = React.useState<BookingState>({
|
|
|
|
|
isOpen,
|
|
|
|
|
@@ -158,6 +110,12 @@ function BookingModal({ isOpen, onClose, onSubmit }: { isOpen: boolean; onClose:
|
|
|
|
|
onClose();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getNextAvailableDate = () => {
|
|
|
|
|
const tomorrow = new Date();
|
|
|
|
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
|
|
|
return tomorrow.toISOString().split('T')[0];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getDateRangeOptions = () => {
|
|
|
|
|
const dates = [];
|
|
|
|
|
for (let i = 1; i <= 30; i++) {
|
|
|
|
|
@@ -184,7 +142,7 @@ function BookingModal({ isOpen, onClose, onSubmit }: { isOpen: boolean; onClose:
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
className="p-2 hover:bg-blue-200 rounded-lg transition"
|
|
|
|
|
>
|
|
|
|
|
<svg className="w-6 h-6 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>
|
|
|
|
|
<X size={24} className="text-gray-600" />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
@@ -242,7 +200,7 @@ function BookingModal({ isOpen, onClose, onSubmit }: { isOpen: boolean; onClose:
|
|
|
|
|
>
|
|
|
|
|
<div className="font-semibold text-gray-900">{service.name}</div>
|
|
|
|
|
<div className="text-sm text-gray-500 flex items-center gap-1 mt-1">
|
|
|
|
|
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" /></svg> {service.duration}
|
|
|
|
|
<Clock size={14} /> {service.duration}
|
|
|
|
|
</div>
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
@@ -400,6 +358,7 @@ export default function LandingPage() {
|
|
|
|
|
|
|
|
|
|
const handleBookingSubmit = (data: any) => {
|
|
|
|
|
console.log('Booking submitted:', data);
|
|
|
|
|
// Here you would typically send this to your backend
|
|
|
|
|
alert(`Booking confirmed for ${data.name} on ${data.date} at ${data.time}`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -416,7 +375,6 @@ export default function LandingPage() {
|
|
|
|
|
secondaryButtonStyle="solid"
|
|
|
|
|
headingFontWeight="light"
|
|
|
|
|
>
|
|
|
|
|
<FloatingDotsAnimation />
|
|
|
|
|
<BookingModal
|
|
|
|
|
isOpen={bookingOpen}
|
|
|
|
|
onClose={() => setBookingOpen(false)}
|
|
|
|
|
@@ -514,7 +472,7 @@ export default function LandingPage() {
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div id="features" data-section="features">
|
|
|
|
|
<FeatureCardOne
|
|
|
|
|
<FeatureCardNine
|
|
|
|
|
title="Why Choose Us"
|
|
|
|
|
description="We combine luxury amenities with cutting-edge dental technology to create an unparalleled patient experience."
|
|
|
|
|
tag="Our Advantages"
|
|
|
|
|
@@ -524,16 +482,22 @@ export default function LandingPage() {
|
|
|
|
|
useInvertedBackground={false}
|
|
|
|
|
features={[
|
|
|
|
|
{
|
|
|
|
|
title: "Patient Comfort", description: "Relax in our luxurious treatment rooms with premium seating, ambient lighting, and calming environments designed for maximum comfort.", imageSrc: "http://img.b2bpic.net/free-photo/portrait-young-female-patient_23-2148396133.jpg", imageAlt: "Comfortable patient treatment area"
|
|
|
|
|
id: 1,
|
|
|
|
|
title: "Patient Comfort", description: "Relax in our luxurious treatment rooms with premium seating, ambient lighting, and calming environments designed for maximum comfort.", phoneOne: { imageSrc: "http://img.b2bpic.net/free-photo/portrait-young-female-patient_23-2148396133.jpg?_wi=1", imageAlt: "Comfortable patient treatment area" },
|
|
|
|
|
phoneTwo: { imageSrc: "http://img.b2bpic.net/free-photo/portrait-young-female-patient_23-2148396133.jpg?_wi=2", imageAlt: "Comfortable patient treatment area" }
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "Advanced Technology", description: "We invest in the latest dental technology including digital imaging, laser treatments, and computer-guided implant placement.", imageSrc: "http://img.b2bpic.net/free-photo/dentist-doctor-patient-looking-digital-teeh-x-ray-dental-office-person-pov-stomatology-wearing-protective-face-mask-gloves-pointing-teeth-radiography-stomatological-clinic_482257-13097.jpg", imageAlt: "Advanced dental technology"
|
|
|
|
|
id: 2,
|
|
|
|
|
title: "Advanced Technology", description: "We invest in the latest dental technology including digital imaging, laser treatments, and computer-guided implant placement.", phoneOne: { imageSrc: "http://img.b2bpic.net/free-photo/dentist-doctor-patient-looking-digital-teeh-x-ray-dental-office-person-pov-stomatology-wearing-protective-face-mask-gloves-pointing-teeth-radiography-stomatological-clinic_482257-13097.jpg?_wi=1", imageAlt: "Advanced dental technology" },
|
|
|
|
|
phoneTwo: { imageSrc: "http://img.b2bpic.net/free-photo/dentist-doctor-patient-looking-digital-teeh-x-ray-dental-office-person-pov-stomatology-wearing-protective-face-mask-gloves-pointing-teeth-radiography-stomatological-clinic_482257-13097.jpg?_wi=2", imageAlt: "Advanced dental technology" }
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "Expert Team", description: "Our board-certified dentists and specialists have over 25 years combined experience delivering exceptional results.", imageSrc: "http://img.b2bpic.net/free-photo/smiley-doctor-talking-with-nurse_23-2148757329.jpg", imageAlt: "Professional dental team"
|
|
|
|
|
id: 3,
|
|
|
|
|
title: "Expert Team", description: "Our board-certified dentists and specialists have over 25 years combined experience delivering exceptional results.", phoneOne: { imageSrc: "http://img.b2bpic.net/free-photo/smiley-doctor-talking-with-nurse_23-2148757329.jpg?_wi=1", imageAlt: "Professional dental team" },
|
|
|
|
|
phoneTwo: { imageSrc: "http://img.b2bpic.net/free-photo/smiley-doctor-talking-with-nurse_23-2148757329.jpg?_wi=2", imageAlt: "Professional dental team" }
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
gridVariant="three-columns-all-equal-width"
|
|
|
|
|
showStepNumbers={true}
|
|
|
|
|
animationType="slide-up"
|
|
|
|
|
buttons={[{ text: "Schedule Appointment", onClick: () => setBookingOpen(true) }]}
|
|
|
|
|
buttonAnimation="slide-up"
|
|
|
|
|
@@ -627,4 +591,4 @@ export default function LandingPage() {
|
|
|
|
|
</div>
|
|
|
|
|
</ThemeProvider>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|