9 Commits

Author SHA1 Message Date
f03bcbda5d Update src/app/layout.tsx 2026-03-09 16:19:29 +00:00
5106b3acfd Update src/app/page.tsx 2026-03-09 16:18:37 +00:00
c30656c5ee Update src/app/layout.tsx 2026-03-09 16:18:36 +00:00
83609c638c Add src/app/appointment/page.tsx 2026-03-09 16:18:36 +00:00
30c527968a Merge version_1 into main
Merge version_1 into main
2026-03-09 16:15:27 +00:00
12894561f5 Merge version_1 into main
Merge version_1 into main
2026-03-09 16:14:32 +00:00
66f4233143 Merge version_1 into main
Merge version_1 into main
2026-03-09 16:10:22 +00:00
7c89acbdef Merge version_1 into main
Merge version_1 into main
2026-03-09 16:09:07 +00:00
89e5458985 Merge version_1 into main
Merge version_1 into main
2026-03-09 16:08:02 +00:00
3 changed files with 513 additions and 1409 deletions

View File

@@ -0,0 +1,292 @@
"use client";
import NavbarStyleApple from "@/components/navbar/NavbarStyleApple/NavbarStyleApple";
import HeroLogoBillboardSplit from "@/components/sections/hero/HeroLogoBillboardSplit";
import ContactForm from "@/components/form/ContactForm";
import FooterLogoEmphasis from "@/components/sections/footer/FooterLogoEmphasis";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import { Calendar, User, Sparkles } from "lucide-react";
import { useState } from "react";
export default function AppointmentPage() {
const [selectedService, setSelectedService] = useState<string>("");
const [selectedDate, setSelectedDate] = useState<string>("");
const [formData, setFormData] = useState({
fullName: "", email: "", phone: "", service: "", date: "", time: ""});
const services = [
{ id: "makeup", name: "Professional Makeup Consultation", duration: "60 min", price: "$75" },
{ id: "skincare", name: "Skincare Analysis & Treatment", duration: "90 min", price: "$120" },
{ id: "makeover", name: "Complete Beauty Makeover", duration: "120 min", price: "$180" },
{ id: "bridal", name: "Bridal Beauty Package", duration: "180 min", price: "$250" },
];
const timeSlots = [
"9:00 AM", "10:00 AM", "11:00 AM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM", "5:00 PM"];
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({
...prev,
[name]: value,
}));
if (name === "service") setSelectedService(value);
if (name === "date") setSelectedDate(value);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Appointment booked:", formData);
alert(`Appointment booked for ${formData.fullName} on ${formData.date} at ${formData.time}`);
setFormData({ fullName: "", email: "", phone: "", service: "", date: "", time: "" });
setSelectedService("");
setSelectedDate("");
};
return (
<ThemeProvider
defaultButtonVariant="expand-hover"
defaultTextAnimation="background-highlight"
borderRadius="soft"
contentWidth="small"
sizing="largeSizeMediumTitles"
background="noiseDiagonalGradient"
cardStyle="solid"
primaryButtonStyle="diagonal-gradient"
secondaryButtonStyle="glass"
headingFontWeight="bold"
>
<div id="nav" data-section="nav">
<NavbarStyleApple
brandName="Radiance Beauty"
navItems={[
{ name: "Shop", id: "products" },
{ name: "About", id: "about" },
{ name: "Testimonials", id: "testimonials" },
{ name: "Booking", id: "/appointment" },
{ name: "Contact", id: "contact" },
]}
/>
</div>
<div id="hero" data-section="hero">
<HeroLogoBillboardSplit
logoText="BOOK YOUR APPOINTMENT"
description="Schedule a personalized beauty consultation with our expert beauty professionals. Choose your preferred service, date, and time."
background={{ variant: "radial-gradient" }}
buttons={[
{ text: "Back to Shop", href: "/" },
]}
layoutOrder="default"
imageSrc="http://img.b2bpic.net/free-photo/happy-woman-holding-mascara-wand_23-2148398589.jpg?_wi=1"
imageAlt="Radiance Beauty professional makeup artist"
frameStyle="card"
mediaAnimation="slide-up"
buttonAnimation="slide-up"
/>
</div>
<div className="py-20 px-6 md:px-10">
<div className="max-w-4xl mx-auto">
<div className="grid md:grid-cols-2 gap-10">
{/* Services Section */}
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-2 flex items-center gap-2">
<Sparkles className="w-6 h-6" />
Our Services
</h2>
<p className="text-foreground/80 mb-4">Select a service to get started</p>
</div>
<div className="space-y-3">
{services.map((service) => (
<div
key={service.id}
onClick={() =>
setFormData((prev) => ({
...prev,
service: service.id,
}))
}
className={`p-4 rounded-lg border-2 cursor-pointer transition-all ${
selectedService === service.id
? "border-primary-cta bg-primary-cta/10"
: "border-background-accent hover:border-primary-cta/50"
}`}
>
<h3 className="font-semibold text-sm">{service.name}</h3>
<p className="text-xs text-foreground/60 mt-1">
{service.duration} {service.price}
</p>
</div>
))}
</div>
</div>
{/* Booking Form Section */}
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-2 flex items-center gap-2">
<Calendar className="w-6 h-6" />
Your Information
</h2>
<p className="text-foreground/80 mb-4">Complete your booking details</p>
</div>
<form onSubmit={handleSubmit} className="space-y-4">
{/* Client Name */}
<div>
<label htmlFor="fullName" className="block text-sm font-medium mb-2 flex items-center gap-2">
<User className="w-4 h-4" />
Full Name *
</label>
<input
type="text"
id="fullName"
name="fullName"
value={formData.fullName}
onChange={handleInputChange}
required
placeholder="Enter your full name"
className="w-full px-4 py-2 border-2 border-background-accent rounded-lg bg-background focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Email */}
<div>
<label htmlFor="email" className="block text-sm font-medium mb-2">
Email Address *
</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleInputChange}
required
placeholder="your.email@example.com"
className="w-full px-4 py-2 border-2 border-background-accent rounded-lg bg-background focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Phone */}
<div>
<label htmlFor="phone" className="block text-sm font-medium mb-2">
Phone Number *
</label>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleInputChange}
required
placeholder="(555) 123-4567"
className="w-full px-4 py-2 border-2 border-background-accent rounded-lg bg-background focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Date Selection */}
<div>
<label htmlFor="date" className="block text-sm font-medium mb-2">
Preferred Date *
</label>
<input
type="date"
id="date"
name="date"
value={formData.date}
onChange={handleInputChange}
required
className="w-full px-4 py-2 border-2 border-background-accent rounded-lg bg-background focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Time Selection */}
<div>
<label htmlFor="time" className="block text-sm font-medium mb-2">
Preferred Time *
</label>
<select
id="time"
name="time"
value={formData.time}
onChange={handleInputChange}
required
className="w-full px-4 py-2 border-2 border-background-accent rounded-lg bg-background focus:outline-none focus:border-primary-cta transition-colors"
>
<option value="">Select a time slot</option>
{timeSlots.map((time) => (
<option key={time} value={time}>
{time}
</option>
))}
</select>
</div>
{/* Service Confirmation */}
{selectedService && (
<div className="p-3 bg-primary-cta/10 border-2 border-primary-cta rounded-lg">
<p className="text-sm font-medium">
Selected Service:{" "}
<span className="text-primary-cta">
{services.find((s) => s.id === selectedService)?.name}
</span>
</p>
</div>
)}
{/* Submit Button */}
<button
type="submit"
className="w-full bg-primary-cta text-background font-semibold py-3 rounded-lg hover:opacity-90 transition-opacity mt-6"
>
Confirm Appointment
</button>
</form>
</div>
</div>
</div>
</div>
<div id="footer" data-section="footer">
<FooterLogoEmphasis
logoText="Radiance Beauty"
columns={[
{
items: [
{ label: "Shop", href: "/" },
{ label: "Book Appointment", href: "/appointment" },
{ label: "New Arrivals", href: "/" },
{ label: "Collections", href: "/" },
],
},
{
items: [
{ label: "About Us", href: "/" },
{ label: "Our Story", href: "/" },
{ label: "Sustainability", href: "#" },
{ label: "Careers", href: "#" },
],
},
{
items: [
{ label: "Help Center", href: "/" },
{ label: "Contact Us", href: "#" },
{ label: "Shipping Info", href: "#" },
{ label: "Track Order", href: "#" },
],
},
{
items: [
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" },
{ label: "Refund Policy", href: "#" },
{ label: "Accessibility", href: "#" },
],
},
]}
/>
</div>
</ThemeProvider>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,75 @@ import SocialProofOne from "@/components/sections/socialProof/SocialProofOne";
import FaqSplitText from "@/components/sections/faq/FaqSplitText"; import FaqSplitText from "@/components/sections/faq/FaqSplitText";
import FooterLogoEmphasis from "@/components/sections/footer/FooterLogoEmphasis"; import FooterLogoEmphasis from "@/components/sections/footer/FooterLogoEmphasis";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import { Award, CheckCircle, Crown, Heart, Shield, Sparkles } from "lucide-react"; import { Award, CheckCircle, Crown, Heart, Shield, Sparkles, Calendar, Clock, Users } from "lucide-react";
import React, { useState, useEffect } from "react";
interface TimeSlot {
time: string;
available: boolean;
}
interface DaySlots {
date: string;
day: string;
slots: TimeSlot[];
}
export default function LandingPage() { export default function LandingPage() {
const [calendarData, setCalendarData] = useState<DaySlots[]>([]);
const [selectedDate, setSelectedDate] = useState<string | null>(null);
const [selectedSlot, setSelectedSlot] = useState<string | null>(null);
useEffect(() => {
// Generate availability calendar for next 7 days
const generateCalendar = () => {
const days: DaySlots[] = [];
const today = new Date();
for (let i = 0; i < 7; i++) {
const date = new Date(today);
date.setDate(date.getDate() + i);
const dateStr = date.toISOString().split('T')[0];
const dayName = date.toLocaleDateString('en-US', { weekday: 'short' });
const slots: TimeSlot[] = [];
const hours = [9, 10, 11, 13, 14, 15, 16, 17];
for (const hour of hours) {
// Simulate availability - 80% slots available
const available = Math.random() > 0.2;
slots.push({
time: `${hour.toString().padStart(2, '0')}:00`,
available,
});
}
days.push({
date: dateStr,
day: dayName,
slots,
});
}
setCalendarData(days);
if (days.length > 0) {
setSelectedDate(days[0].date);
}
};
generateCalendar();
}, []);
const getAvailableCount = (date: string): number => {
const day = calendarData.find(d => d.date === date);
return day ? day.slots.filter(s => s.available).length : 0;
};
const getSelectedDaySlots = (): TimeSlot[] => {
const day = calendarData.find(d => d.date === selectedDate);
return day ? day.slots : [];
};
return ( return (
<ThemeProvider <ThemeProvider
defaultButtonVariant="expand-hover" defaultButtonVariant="expand-hover"
@@ -34,7 +100,7 @@ export default function LandingPage() {
{ name: "Shop", id: "products" }, { name: "Shop", id: "products" },
{ name: "About", id: "about" }, { name: "About", id: "about" },
{ name: "Testimonials", id: "testimonials" }, { name: "Testimonials", id: "testimonials" },
{ name: "Contact", id: "contact" }, { name: "Book Consultation", id: "availability" },
]} ]}
/> />
</div> </div>
@@ -206,6 +272,145 @@ export default function LandingPage() {
/> />
</div> </div>
<div id="availability" data-section="availability" className="py-20">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="mb-12 text-center">
<div className="inline-flex items-center gap-2 mb-4 px-4 py-2 rounded-full bg-opacity-10 backdrop-blur">
<Calendar className="w-4 h-4" />
<span className="text-sm font-medium">Consultation Booking</span>
</div>
<h2 className="text-4xl md:text-5xl font-bold mb-4">Schedule Your Personal Consultation</h2>
<p className="text-lg text-opacity-70 max-w-2xl mx-auto">Book a consultation with our beauty experts to find the perfect products and routine for your skin type.</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Calendar */}
<div className="lg:col-span-2">
<div className="rounded-lg border border-opacity-20 p-8 backdrop-blur">
<h3 className="text-2xl font-bold mb-6 flex items-center gap-2">
<Calendar className="w-6 h-6" />
Available Dates
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
{calendarData.map((day) => (
<button
key={day.date}
onClick={() => setSelectedDate(day.date)}
className={`p-4 rounded-lg border-2 transition-all ${
selectedDate === day.date
? 'border-opacity-100 bg-opacity-20'
: 'border-opacity-20 hover:border-opacity-40'
}`}
>
<div className="flex justify-between items-center">
<div className="text-left">
<p className="font-semibold">{day.day}</p>
<p className="text-sm opacity-70">{new Date(day.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}</p>
</div>
<div className="text-right">
<p className="font-bold text-lg">{getAvailableCount(day.date)}</p>
<p className="text-xs opacity-70">slots</p>
</div>
</div>
</button>
))}
</div>
{/* Time Slots */}
<div>
<h4 className="text-xl font-bold mb-4 flex items-center gap-2">
<Clock className="w-5 h-5" />
Available Times
</h4>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{getSelectedDaySlots().map((slot, idx) => (
<button
key={idx}
onClick={() => slot.available && setSelectedSlot(slot.time)}
disabled={!slot.available}
className={`py-3 px-4 rounded-lg font-semibold transition-all ${
!slot.available
? 'opacity-30 cursor-not-allowed'
: selectedSlot === slot.time
? 'bg-opacity-100 text-white shadow-lg transform scale-105'
: 'hover:bg-opacity-20'
}`}
>
{slot.time}
</button>
))}
</div>
</div>
</div>
</div>
{/* Booking Summary */}
<div className="lg:col-span-1">
<div className="rounded-lg border border-opacity-20 p-8 backdrop-blur sticky top-20">
<h3 className="text-xl font-bold mb-6 flex items-center gap-2">
<Users className="w-5 h-5" />
Booking Summary
</h3>
<div className="space-y-4">
<div>
<p className="text-sm opacity-70 mb-2">Selected Date</p>
<p className="font-bold text-lg">
{selectedDate
? new Date(selectedDate).toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric' })
: 'No date selected'}
</p>
</div>
<div>
<p className="text-sm opacity-70 mb-2">Selected Time</p>
<p className="font-bold text-lg">
{selectedSlot ? selectedSlot : 'No time selected'}
</p>
</div>
<div>
<p className="text-sm opacity-70 mb-2">Consultation Type</p>
<p className="font-bold">30-Minute Personal Consultation</p>
</div>
<div className="border-t border-opacity-20 pt-4 mt-6">
<p className="text-sm opacity-70 mb-3">What to Expect:</p>
<ul className="space-y-2 text-sm">
<li className="flex items-start gap-2">
<CheckCircle className="w-4 h-4 flex-shrink-0 mt-0.5" />
<span>Personalized skin analysis</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle className="w-4 h-4 flex-shrink-0 mt-0.5" />
<span>Product recommendations</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle className="w-4 h-4 flex-shrink-0 mt-0.5" />
<span>Custom routine guidance</span>
</li>
</ul>
</div>
<button
disabled={!selectedDate || !selectedSlot}
className={`w-full py-3 px-4 rounded-lg font-bold transition-all mt-6 ${
selectedDate && selectedSlot
? 'hover:shadow-lg hover:scale-105'
: 'opacity-50 cursor-not-allowed'
}`}
>
Confirm Booking
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="socialproof" data-section="socialproof"> <div id="socialproof" data-section="socialproof">
<SocialProofOne <SocialProofOne
title="Trusted by Beauty Experts" title="Trusted by Beauty Experts"
@@ -276,7 +481,7 @@ export default function LandingPage() {
{ {
items: [ items: [
{ label: "Help Center", href: "#faq" }, { label: "Help Center", href: "#faq" },
{ label: "Contact Us", href: "#" }, { label: "Book Consultation", href: "#availability" },
{ label: "Shipping Info", href: "#" }, { label: "Shipping Info", href: "#" },
{ label: "Track Order", href: "#" }, { label: "Track Order", href: "#" },
], ],
@@ -294,4 +499,4 @@ export default function LandingPage() {
</div> </div>
</ThemeProvider> </ThemeProvider>
); );
} }