Merge pull request 'fix : call button' (#26) from feature/email into main
continuous-integration/drone/push Build is passing Details

Reviewed-on: #26
This commit is contained in:
hardik 2025-10-16 10:24:14 +05:30
commit a59f82018d
9 changed files with 405 additions and 374 deletions

File diff suppressed because one or more lines are too long

View File

@ -170,12 +170,12 @@ export function BookingConfirmation({
{bookingData.dropoff.includes("Airport Taxi") ? "Airport Taxi Fee" : "Customize Price"}
</span>
<span className="text-xl font-semibold text-green-600">
{bookingData.dropoff.includes("Airport Taxi") ? "₹1099" : "Call for Quote"}
{bookingData.dropoff.includes("Airport Taxi") ? "₹999" : "Call for Quote"}
</span>
</div>
<div className="text-sm text-muted-foreground text-center">
{bookingData.dropoff.includes("Airport Taxi")
? `1099 fixed rate for airport taxi. Driver will contact you at ${bookingData.contactNumber} for pickup details.`
? `999 fixed rate for airport taxi. Driver will contact you at ${bookingData.contactNumber} for pickup details.`
: `Driver will contact you at ${bookingData.contactNumber} for final pricing and trip details.`}
</div>
</div>

View File

@ -37,7 +37,7 @@ export function BookingForm({ onSubmit }: BookingFormProps) {
const currentDate = new Date().toISOString().split('T')[0];
const currentTime = new Date().toTimeString().slice(0, 5);
return (
@ -48,248 +48,248 @@ export function BookingForm({ onSubmit }: BookingFormProps) {
className="w-full max-w-2xl mx-auto"
>
<Card className="w-full bg-white border-0 shadow-none">
<CardHeader className="text-center pb-4 sm:pb-6 lg:pb-8 bg-transparent px-4 sm:px-6 rounded-[0px]">
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
<CardTitle className="flex flex-col sm:flex-row items-center justify-center gap-2 text-center text-lg sm:text-xl lg:text-2xl bg-gradient-to-r from-primary to-primary/80 bg-clip-text text-transparent">
<div className="mb-1 sm:mb-0">
<MapPin className="h-5 w-5 sm:h-6 sm:w-6 text-primary" />
</div>
<span className="font-bold leading-tight text-[32px]">Book Your Airport Taxi Now</span>
</CardTitle>
</motion.div>
<motion.div
className="w-16 sm:w-20 lg:w-24 h-1 bg-gradient-to-r from-primary/30 via-primary to-primary/30 mx-auto mt-2 sm:mt-3 lg:mt-4 rounded-full"
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
transition={{ delay: 0.3, duration: 0.8 }}
/>
<CardHeader className="text-center pb-4 sm:pb-6 lg:pb-8 bg-transparent px-4 sm:px-6 rounded-[0px]">
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
<CardTitle className="flex flex-col sm:flex-row items-center justify-center gap-2 text-center text-lg sm:text-xl lg:text-2xl bg-gradient-to-r from-primary to-primary/80 bg-clip-text text-transparent">
<div className="mb-1 sm:mb-0">
<MapPin className="h-5 w-5 sm:h-6 sm:w-6 text-primary" />
</div>
<span className="font-bold leading-tight text-[32px]">Book Your Airport Taxi Now</span>
</CardTitle>
</motion.div>
<motion.div
className="w-16 sm:w-20 lg:w-24 h-1 bg-gradient-to-r from-primary/30 via-primary to-primary/30 mx-auto mt-2 sm:mt-3 lg:mt-4 rounded-full"
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
transition={{ delay: 0.3, duration: 0.8 }}
/>
</CardHeader>
<CardContent className="bg-transparent px-4 sm:px-6 pt-[0px] pr-[21px] pb-[21px] pl-[21px]">
<form onSubmit={handleSubmit} className="space-y-4 sm:space-y-6">
{/* Location Inputs */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
</CardHeader>
<CardContent className="bg-transparent px-4 sm:px-6 pt-[0px] pr-[21px] pb-[21px] pl-[21px]">
<form onSubmit={handleSubmit} className="space-y-4 sm:space-y-6">
{/* Location Inputs */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<div className="space-y-2">
<Label htmlFor="pickup" className="text-sm sm:text-base">Pickup Location</Label>
<Select value={formData.pickup} onValueChange={(value) => handleInputChange("pickup", value)} required>
<SelectTrigger className="h-10 sm:h-11">
<SelectValue placeholder="Select pickup city" />
</SelectTrigger>
<SelectContent className="max-h-48">
{indiaLocations.map((location) => (
<SelectItem key={location} value={location}>
{location}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="dropoff" className="text-sm sm:text-base">Drop-off Location / Service</Label>
<Select value={formData.dropoff} onValueChange={(value) => handleInputChange("dropoff", value)} required>
<SelectTrigger className="h-10 sm:h-11">
<SelectValue placeholder="Select destination or service" />
</SelectTrigger>
<SelectContent className="max-h-48">
<div className="px-2 py-1 text-xs text-muted-foreground border-b">Services</div>
{serviceTypes.map((service) => (
<SelectItem key={service} value={service}>
{service}
</SelectItem>
))}
<div className="px-2 py-1 text-xs text-muted-foreground border-b">All India Locations</div>
{indiaLocations.map((location) => (
<SelectItem key={location} value={location}>
{location}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
{/* Date and Time */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<div className="space-y-2">
<Label htmlFor="date" className="flex items-center gap-2 text-sm sm:text-base">
<Calendar className="h-3 w-3 sm:h-4 sm:w-4" />
Date
</Label>
<Input
id="date"
type="date"
min={currentDate}
value={formData.date}
onChange={(e) => handleInputChange("date", e.target.value)}
className="h-10 sm:h-11"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="time" className="flex items-center gap-2 text-sm sm:text-base">
<Clock className="h-3 w-3 sm:h-4 sm:w-4" />
Time
</Label>
<Input
id="time"
type="time"
value={formData.time}
onChange={(e) => handleInputChange("time", e.target.value)}
className="h-10 sm:h-11"
required
/>
</div>
</div>
{/* Contact Information */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<div className="space-y-2">
<Label htmlFor="contactName" className="flex items-center gap-2 text-sm sm:text-base">
<User className="h-3 w-3 sm:h-4 sm:w-4" />
Contact Name
</Label>
<Input
id="contactName"
type="text"
placeholder="Enter your name"
value={formData.contactName}
onChange={(e) => handleInputChange("contactName", e.target.value)}
className="h-10 sm:h-11"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="contactNumber" className="flex items-center gap-2 text-sm sm:text-base">
<Phone className="h-3 w-3 sm:h-4 sm:w-4" />
Contact Number
</Label>
<Input
id="contactNumber"
type="tel"
placeholder="Enter your contact number"
value={formData.contactNumber}
onChange={(e) => handleInputChange("contactNumber", e.target.value)}
className="h-10 sm:h-11"
required
/>
</div>
</div>
{/* Email (Optional) */}
<div className="space-y-2">
<Label htmlFor="pickup" className="text-sm sm:text-base">Pickup Location</Label>
<Select value={formData.pickup} onValueChange={(value) => handleInputChange("pickup", value)} required>
<SelectTrigger className="h-10 sm:h-11">
<SelectValue placeholder="Select pickup city" />
</SelectTrigger>
<SelectContent className="max-h-48">
{indiaLocations.map((location) => (
<SelectItem key={location} value={location}>
{location}
<Label htmlFor="customerEmail" className="flex items-center gap-2 text-sm sm:text-base">
<Mail className="h-3 w-3 sm:h-4 sm:w-4" />
Email Address <span className="text-xs text-muted-foreground">(For booking confirmation)</span>
</Label>
<Input
id="customerEmail"
type="email"
placeholder="Enter your email address"
// value={formData.customerEmail}
onChange={(e) => handleInputChange("customerEmail", e.target.value)}
className="h-10 sm:h-11"
/>
</div>
{/* Passengers and Vehicle Type */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<div className="space-y-2">
<Label className="flex items-center gap-2 text-sm sm:text-base">
<Users className="h-3 w-3 sm:h-4 sm:w-4" />
Passengers
</Label>
<Select value={formData.passengers} onValueChange={(value) => handleInputChange("passengers", value)}>
<SelectTrigger className="h-10 sm:h-11">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">1 Passenger</SelectItem>
<SelectItem value="2">2 Passengers</SelectItem>
<SelectItem value="3">3 Passengers</SelectItem>
<SelectItem value="4">4 Passengers</SelectItem>
<SelectItem value="5">5 Passengers</SelectItem>
<SelectItem value="6">6 Passengers</SelectItem>
<SelectItem value="7">7 Passengers</SelectItem>
<SelectItem value="8">8+ Passengers</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="text-sm sm:text-base">Vehicle Type</Label>
<Select value={formData.vehicleType} onValueChange={(value) => handleInputChange("vehicleType", value)} required>
<SelectTrigger className="h-10 sm:h-11">
<SelectValue placeholder="Select vehicle" />
</SelectTrigger>
<SelectContent>
<SelectItem value="5-seater">
<span className="text-xs sm:text-sm">5 Seater - Airport Taxi </span>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="dropoff" className="text-sm sm:text-base">Drop-off Location / Service</Label>
<Select value={formData.dropoff} onValueChange={(value) => handleInputChange("dropoff", value)} required>
<SelectTrigger className="h-10 sm:h-11">
<SelectValue placeholder="Select destination or service" />
</SelectTrigger>
<SelectContent className="max-h-48">
<div className="px-2 py-1 text-xs text-muted-foreground border-b">Services</div>
{serviceTypes.map((service) => (
<SelectItem key={service} value={service}>
{service}
<SelectItem value="7-seater">
<span className="text-xs sm:text-sm">7 Seater (Ertiga) - Airport Taxi </span>
</SelectItem>
))}
<div className="px-2 py-1 text-xs text-muted-foreground border-b">All India Locations</div>
{indiaLocations.map((location) => (
<SelectItem key={location} value={location}>
{location}
<SelectItem value="innova">
<span className="text-xs sm:text-sm">Innova - Airport Taxi </span>
</SelectItem>
))}
</SelectContent>
</Select>
</SelectContent>
</Select>
</div>
</div>
</div>
{/* Date and Time */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<div className="space-y-2">
<Label htmlFor="date" className="flex items-center gap-2 text-sm sm:text-base">
<Calendar className="h-3 w-3 sm:h-4 sm:w-4" />
Date
</Label>
<Input
id="date"
type="date"
min={currentDate}
value={formData.date}
onChange={(e) => handleInputChange("date", e.target.value)}
className="h-10 sm:h-11"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="time" className="flex items-center gap-2 text-sm sm:text-base">
<Clock className="h-3 w-3 sm:h-4 sm:w-4" />
Time
</Label>
<Input
id="time"
type="time"
value={formData.time}
onChange={(e) => handleInputChange("time", e.target.value)}
className="h-10 sm:h-11"
required
/>
</div>
</div>
{/* Contact Information */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<div className="space-y-2">
<Label htmlFor="contactName" className="flex items-center gap-2 text-sm sm:text-base">
<User className="h-3 w-3 sm:h-4 sm:w-4" />
Contact Name
</Label>
<Input
id="contactName"
type="text"
placeholder="Enter your name"
value={formData.contactName}
onChange={(e) => handleInputChange("contactName", e.target.value)}
className="h-10 sm:h-11"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="contactNumber" className="flex items-center gap-2 text-sm sm:text-base">
<Phone className="h-3 w-3 sm:h-4 sm:w-4" />
Contact Number
</Label>
<Input
id="contactNumber"
type="tel"
placeholder="Enter your contact number"
value={formData.contactNumber}
onChange={(e) => handleInputChange("contactNumber", e.target.value)}
className="h-10 sm:h-11"
required
/>
</div>
</div>
{/* Email (Optional) */}
<div className="space-y-2">
<Label htmlFor="customerEmail" className="flex items-center gap-2 text-sm sm:text-base">
<Mail className="h-3 w-3 sm:h-4 sm:w-4" />
Email Address <span className="text-xs text-muted-foreground">(For booking confirmation)</span>
</Label>
<Input
id="customerEmail"
type="email"
placeholder="Enter your email address"
value={formData.customerEmail}
onChange={(e) => handleInputChange("customerEmail", e.target.value)}
className="h-10 sm:h-11"
/>
</div>
{/* Passengers and Vehicle Type */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
<div className="space-y-2">
<Label className="flex items-center gap-2 text-sm sm:text-base">
<Users className="h-3 w-3 sm:h-4 sm:w-4" />
Passengers
</Label>
<Select value={formData.passengers} onValueChange={(value) => handleInputChange("passengers", value)}>
<SelectTrigger className="h-10 sm:h-11">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">1 Passenger</SelectItem>
<SelectItem value="2">2 Passengers</SelectItem>
<SelectItem value="3">3 Passengers</SelectItem>
<SelectItem value="4">4 Passengers</SelectItem>
<SelectItem value="5">5 Passengers</SelectItem>
<SelectItem value="6">6 Passengers</SelectItem>
<SelectItem value="7">7 Passengers</SelectItem>
<SelectItem value="8">8+ Passengers</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="text-sm sm:text-base">Vehicle Type</Label>
<Select value={formData.vehicleType} onValueChange={(value) => handleInputChange("vehicleType", value)} required>
<SelectTrigger className="h-10 sm:h-11">
<SelectValue placeholder="Select vehicle" />
</SelectTrigger>
<SelectContent>
<SelectItem value="5-seater">
<span className="text-xs sm:text-sm">5 Seater - Airport Taxi </span>
</SelectItem>
<SelectItem value="7-seater">
<span className="text-xs sm:text-sm">7 Seater (Ertiga) - Airport Taxi </span>
</SelectItem>
<SelectItem value="innova">
<span className="text-xs sm:text-sm">Innova - Airport Taxi </span>
</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-3 sm:space-y-4">
<motion.div
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<Button type="submit" className="w-full h-11 sm:h-12 text-sm sm:text-base shadow-lg hover:shadow-xl transition-all duration-300 rounded-[8px]">
<span className="font-semibold">
Book Your Airport Taxi
</span>
</Button>
</motion.div>
<div className="flex items-center gap-2">
<div className="h-px bg-border flex-1"></div>
<span className="text-xs text-muted-foreground px-2">OR</span>
<div className="h-px bg-border flex-1"></div>
</div>
<motion.div
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
className="relative"
>
<div className="space-y-3 sm:space-y-4">
<motion.div
className="absolute inset-0 bg-gradient-to-r from-green-400 to-green-600 rounded-lg"
animate={{
opacity: [0.8, 1, 0.8],
scale: [1, 1.02, 1]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<Button
type="button"
className="w-full h-11 sm:h-12 relative z-10 bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 text-white border-0 shadow-lg"
onClick={() => window.open('tel:+91-7477247488', '_self')}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<Phone className="h-3 w-3 sm:h-4 sm:w-4 mr-2" />
<div className="text-center">
<div className="font-semibold text-sm sm:text-base">Call to Book Taxi</div>
<div className="text-xs opacity-90">7477247488</div>
</div>
</Button>
</motion.div>
</div>
</form>
</CardContent>
</Card>
<Button type="submit" className="w-full h-11 sm:h-12 text-sm sm:text-base shadow-lg hover:shadow-xl transition-all duration-300 rounded-[8px]">
<span className="font-semibold">
Book Your Airport Taxi
</span>
</Button>
</motion.div>
<div className="flex items-center gap-2">
<div className="h-px bg-border flex-1"></div>
<span className="text-xs text-muted-foreground px-2">OR</span>
<div className="h-px bg-border flex-1"></div>
</div>
<motion.div
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
className="relative"
>
<motion.div
className="absolute inset-0 bg-gradient-to-r from-green-400 to-green-600 rounded-lg"
animate={{
opacity: [0.8, 1, 0.8],
scale: [1, 1.02, 1]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<Button
type="button"
className="w-full h-11 sm:h-12 relative z-10 bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 text-white border-0 shadow-lg"
onClick={() => window.open('tel:+91-7477247488', '_self')}
>
<Phone className="h-3 w-3 sm:h-4 sm:w-4 mr-2" />
<div className="text-center">
<div className="font-semibold text-sm sm:text-base">Call to Book Taxi</div>
<div className="text-xs opacity-90">7477247488</div>
</div>
</Button>
</motion.div>
</div>
</form>
</CardContent>
</Card>
</motion.div>
);
}

View File

@ -8,11 +8,11 @@ export function FloatingCallButton() {
className="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-50"
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{
transition={{
delay: 1,
type: "spring",
stiffness: 200,
damping: 20
damping: 20,
}}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
@ -21,31 +21,34 @@ export function FloatingCallButton() {
<Button
size="lg"
className="bg-transparent hover:bg-white/10 border-0 px-3 py-2 sm:px-4 sm:py-2 h-auto rounded-full"
onClick={() => window.open('tel:+91-7477247488', '_self')}
onClick={() => {
// Opens dialpad directly on mobile
window.location.href = "tel:+917477247488";
}}
>
<div className="mr-1 sm:mr-2">
<Phone className="h-4 w-4 sm:h-5 sm:w-5 text-white" />
</div>
<div className="text-white">
<div className="text-white text-left">
<div className="text-xs sm:text-sm font-bold">Call to Book</div>
<div className="text-xs opacity-90">7477247488</div>
</div>
</Button>
{/* Simple pulse effect */}
{/* Simple pulse animation */}
<motion.div
className="absolute inset-0 rounded-full bg-green-400/50"
animate={{
scale: [1, 1.5, 1],
opacity: [0.7, 0, 0.7]
opacity: [0.7, 0, 0.7],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
ease: "easeInOut",
}}
/>
</div>
</motion.div>
);
}
}

View File

@ -104,7 +104,7 @@ export function HeroSection({ children }: HeroSectionProps) {
transition={{ duration: 0.8, delay: 0.4 }}
className="block text-white"
>
Durg/Bhilai-Raipur Airport Drop(Oneway)
Durg/Bhilai-Raipur Airport Drop(Oneway)
</motion.span>
<motion.span
className="block text-yellow-400 text-xl sm:text-3xl md:text-4xl lg:text-5xl"
@ -112,7 +112,7 @@ export function HeroSection({ children }: HeroSectionProps) {
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.6 }}
>
1099
999
</motion.span>
</motion.h1>

View File

@ -18,8 +18,8 @@ const services = [
icon: Plane,
title: "Airport Taxi",
description: "Comfortable and punctual airport taxi services. Never miss a flight with our dedicated airport service.",
features: ["Flight monitoring", "Meet & greet service", "Fixed rate ₹1099"],
price: "₹1099",
features: ["Flight monitoring", "Meet & greet service", "Fixed rate ₹999"],
price: "₹999",
image: "https://images.unsplash.com/photo-1733222012917-e9e74636080c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhaXJwb3J0JTIwdHJhbnNmZXIlMjBjYXIlMjBzZXJ2aWNlfGVufDF8fHx8MTc1NTYwMDgwM3ww&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral",
imageAlt: "Premium car at airport terminal"
},
@ -91,7 +91,7 @@ export function ServicesSection() {
return (
<div className="py-8 sm:py-12 lg:py-16">
<div className="container mx-auto px-4">
<motion.div
<motion.div
className="text-center mb-8 sm:mb-10 lg:mb-12"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
@ -100,13 +100,13 @@ export function ServicesSection() {
>
<h1 className="mb-3 sm:mb-4 text-2xl sm:text-3xl lg:text-4xl font-normal font-bold">Our Services</h1>
<p className="text-base sm:text-lg lg:text-xl text-muted-foreground max-w-3xl mx-auto px-4">
From daily commutes to special occasions, we provide reliable transportation solutions
From daily commutes to special occasions, we provide reliable transportation solutions
tailored to your needs with professional drivers and well-maintained vehicles.
</p>
</motion.div>
{/* Main Services */}
<motion.div
<motion.div
className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 sm:gap-6 lg:gap-8 mb-8 sm:mb-10 lg:mb-12"
variants={containerVariants}
initial="hidden"
@ -117,7 +117,7 @@ export function ServicesSection() {
<motion.div
key={index}
variants={cardVariants}
whileHover={{
whileHover={{
y: -8,
transition: { duration: 0.3 }
}}
@ -137,9 +137,9 @@ export function ServicesSection() {
/>
</motion.div>
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
{/* Icon overlay */}
<motion.div
<motion.div
className="absolute bottom-4 left-4"
initial={{ scale: 0, opacity: 0 }}
whileInView={{ scale: 1, opacity: 1 }}
@ -148,11 +148,11 @@ export function ServicesSection() {
>
<div className="w-12 h-12 bg-white/90 backdrop-blur-sm rounded-lg flex items-center justify-center">
<motion.div
animate={{
animate={{
rotate: [0, 10, -10, 0],
scale: [1, 1.1, 1]
}}
transition={{
transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut"
@ -162,9 +162,9 @@ export function ServicesSection() {
</motion.div>
</div>
</motion.div>
{/* Price badge */}
<motion.div
<motion.div
className="absolute top-4 right-4"
initial={{ x: 50, opacity: 0 }}
whileInView={{ x: 0, opacity: 1 }}
@ -189,9 +189,9 @@ export function ServicesSection() {
</CardTitle>
</motion.div>
</CardHeader>
<CardContent className="pt-0 px-4 sm:px-6">
<motion.p
<motion.p
className="text-muted-foreground mb-3 sm:mb-4 text-sm sm:text-base"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
@ -200,8 +200,8 @@ export function ServicesSection() {
>
{service.description}
</motion.p>
<motion.div
<motion.div
className="space-y-2"
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
@ -211,21 +211,21 @@ export function ServicesSection() {
<h4>Features:</h4>
<ul className="space-y-1">
{service.features.map((feature, featureIndex) => (
<motion.li
key={featureIndex}
<motion.li
key={featureIndex}
className="flex items-center gap-2 text-sm text-muted-foreground"
initial={{ opacity: 0, x: -10 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ delay: index * 0.2 + 0.7 + featureIndex * 0.1 }}
>
<motion.div
<motion.div
className="w-1.5 h-1.5 bg-primary rounded-full"
animate={{
animate={{
scale: [1, 1.5, 1],
opacity: [0.7, 1, 0.7]
}}
transition={{
transition={{
duration: 2,
repeat: Infinity,
delay: featureIndex * 0.3
@ -243,14 +243,14 @@ export function ServicesSection() {
</motion.div>
{/* Additional Services */}
<motion.div
<motion.div
className="bg-muted/50 rounded-lg p-8"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.2 }}
>
<motion.h2
<motion.h2
className="mb-6 text-center"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
@ -261,8 +261,8 @@ export function ServicesSection() {
</motion.h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{additionalServices.map((service, index) => (
<motion.div
key={index}
<motion.div
key={index}
className="flex items-center gap-4 p-4 rounded-lg hover:bg-background/50 transition-colors group"
initial={{ opacity: 0, x: index % 2 === 0 ? -20 : 20 }}
whileInView={{ opacity: 1, x: 0 }}
@ -270,12 +270,12 @@ export function ServicesSection() {
transition={{ delay: 0.4 + index * 0.1 }}
whileHover={{ x: 5 }}
>
<motion.div
<motion.div
className="w-10 h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0 group-hover:bg-primary/20 transition-colors"
animate={{
animate={{
rotate: [0, 360],
}}
transition={{
transition={{
duration: 20,
repeat: Infinity,
ease: "linear"
@ -293,14 +293,14 @@ export function ServicesSection() {
</motion.div>
{/* Service Areas */}
<motion.div
<motion.div
className="mt-12 text-center"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.4 }}
>
<motion.h2
<motion.h2
className="mb-6"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
@ -317,7 +317,7 @@ export function ServicesSection() {
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.6 + index * 0.05 }}
whileHover={{
whileHover={{
scale: 1.05,
transition: { duration: 0.2 }
}}

View File

@ -6,27 +6,27 @@ export const indiaLocations = [
"Jaipur", "Jodhpur", "Udaipur", "Ajmer", "Kota", "Bikaner", "Alwar",
"Lucknow", "Kanpur", "Agra", "Varanasi", "Allahabad", "Meerut", "Bareilly", "Aligarh",
"Dehradun", "Haridwar", "Rishikesh", "Mussoorie", "Nainital", "Shimla", "Manali", "Dharamshala",
// East India
"Kolkata", "Howrah", "Durgapur", "Asansol", "Siliguri", "Darjeeling",
"Bhubaneswar", "Cuttack", "Rourkela", "Puri",
"Patna", "Gaya", "Muzaffarpur", "Bhagalpur", "Darbhanga",
"Guwahati", "Silchar", "Dibrugarh", "Jorhat", "Tezpur",
// West India
"Ahmedabad", "Surat", "Vadodara", "Rajkot", "Bhavnagar", "Jamnagar", "Gandhinagar",
"Thane", "Navi Mumbai", "Kalyan", "Vasai-Virar", "Solapur", "Nagpur", "Kolhapur",
// South India
"Bangalore", "Mysore", "Mangalore", "Hubli", "Belgaum", "Gulbarga", "Davangere",
"Chennai", "Coimbatore", "Madurai", "Tiruchirappalli", "Salem", "Tirunelveli", "Erode", "Tiruppur", "Vellore",
"Hyderabad", "Secunderabad", "Warangal", "Nizamabad", "Karimnagar", "Khammam", "Ramagundam",
"Kochi", "Thiruvananthapuram", "Kozhikode", "Kollam", "Thrissur", "Alappuzha", "Palakkad", "Kannur",
// Central India
"Indore", "Bhopal", "Jabalpur", "Gwalior", "Ujjain", "Sagar", "Dewas", "Satna",
"Raipur", "Bhilai", "Bilaspur", "Korba", "Durg", "Rajnandgaon",
// Union Territories
"Pondicherry", "Port Blair", "Panaji", "Margao", "Vasco da Gama", "Daman", "Silvassa"
];
@ -34,7 +34,7 @@ export const indiaLocations = [
// Service types for drop-off options
export const serviceTypes = [
"City Ride - Customize Price",
"Airport Taxi - ₹1099",
"Airport Taxi - ₹999",
"Outstation - Customize Price",
"Mover and Packer - Customize Price",
"Corporate Services - Customize Price"

View File

@ -5,11 +5,11 @@ export const mockVehicles: Vehicle[] = [
id: "1",
type: "5-seater",
name: "5 Seater",
price: 1099,
price: 999,
capacity: 5,
rating: 4.5,
estimatedTime: "Rider will contact you soon",
features: ["AC", "Music System", "Comfortable", "Airport Taxi ₹1099"],
features: ["AC", "Music System", "Comfortable", "Airport Taxi ₹999"],
image: ""
},
{

View File

@ -27,8 +27,8 @@ app.get("/make-server-10d555e8/health", (c) => {
// Test email configuration endpoint
app.get("/make-server-10d555e8/test-email-config", (c) => {
const resendApiKey = Deno.env.get('RESEND_API_KEY');
return c.json({
return c.json({
emailConfigured: !!resendApiKey,
apiKeyFormat: resendApiKey ? (resendApiKey.startsWith('re_') ? 'valid' : 'invalid') : 'missing',
apiKeyLength: resendApiKey?.length || 0
@ -40,7 +40,7 @@ app.post("/make-server-10d555e8/send-booking-email", async (c) => {
try {
const bookingData = await c.req.json();
console.log('Received booking data:', JSON.stringify(bookingData, null, 2));
// Store booking in KV store
const bookingId = `booking_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
await kv.set(bookingId, {
@ -55,7 +55,7 @@ app.post("/make-server-10d555e8/send-booking-email", async (c) => {
console.log('API Key exists:', !!resendApiKey);
console.log('API Key length:', resendApiKey?.length || 0);
console.log('API Key prefix:', resendApiKey?.substring(0, 7) || 'none');
if (!resendApiKey) {
console.error('RESEND_API_KEY environment variable not found');
throw new Error('RESEND_API_KEY not configured - please set up your Resend API key');
@ -69,9 +69,9 @@ app.post("/make-server-10d555e8/send-booking-email", async (c) => {
// Get vehicle pricing
const getVehiclePrice = (vehicleType) => {
switch(vehicleType) {
case '5-seater': return '₹1099';
case '7-seater': return '₹1600';
switch (vehicleType) {
case '5-seater': return '₹999';
case '7-seater': return '₹1600';
case 'innova': return '₹2000';
default: return 'Contact for pricing';
}
@ -193,8 +193,8 @@ app.post("/make-server-10d555e8/send-booking-email", async (c) => {
console.log('Booking email sent successfully:', bookingId);
return c.json({
success: true,
return c.json({
success: true,
message: 'Booking confirmed and emails sent successfully',
bookingId: bookingId,
emailsSent: {
@ -205,19 +205,19 @@ app.post("/make-server-10d555e8/send-booking-email", async (c) => {
} catch (error) {
console.error('Error processing booking:', error);
// If it's an API key issue, provide specific guidance
if (error.message.includes('API key') || error.message.includes('validation_error')) {
return c.json({
success: false,
return c.json({
success: false,
message: `Email service configuration error: ${error.message}. Please check your Resend API key setup.`,
error: 'EMAIL_CONFIG_ERROR'
}, 400);
}
// For other errors, still save the booking but indicate email failure
return c.json({
success: false,
return c.json({
success: false,
message: `Booking saved but email notification failed: ${error.message}`,
error: 'EMAIL_SEND_FAILED'
}, 500);