Merge pull request 'fix : call button' (#26) from feature/email into main
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Reviewed-on: #26
This commit is contained in:
commit
a59f82018d
File diff suppressed because one or more lines are too long
|
|
@ -170,12 +170,12 @@ export function BookingConfirmation({
|
||||||
{bookingData.dropoff.includes("Airport Taxi") ? "Airport Taxi Fee" : "Customize Price"}
|
{bookingData.dropoff.includes("Airport Taxi") ? "Airport Taxi Fee" : "Customize Price"}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xl font-semibold text-green-600">
|
<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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-muted-foreground text-center">
|
<div className="text-sm text-muted-foreground text-center">
|
||||||
{bookingData.dropoff.includes("Airport Taxi")
|
{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.`}
|
: `Driver will contact you at ${bookingData.contactNumber} for final pricing and trip details.`}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export function BookingForm({ onSubmit }: BookingFormProps) {
|
||||||
|
|
||||||
const currentDate = new Date().toISOString().split('T')[0];
|
const currentDate = new Date().toISOString().split('T')[0];
|
||||||
const currentTime = new Date().toTimeString().slice(0, 5);
|
const currentTime = new Date().toTimeString().slice(0, 5);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -48,248 +48,248 @@ export function BookingForm({ onSubmit }: BookingFormProps) {
|
||||||
className="w-full max-w-2xl mx-auto"
|
className="w-full max-w-2xl mx-auto"
|
||||||
>
|
>
|
||||||
<Card className="w-full bg-white border-0 shadow-none">
|
<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]">
|
<CardHeader className="text-center pb-4 sm:pb-6 lg:pb-8 bg-transparent px-4 sm:px-6 rounded-[0px]">
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: -20 }}
|
initial={{ opacity: 0, y: -20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.6 }}
|
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">
|
<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">
|
<div className="mb-1 sm:mb-0">
|
||||||
<MapPin className="h-5 w-5 sm:h-6 sm:w-6 text-primary" />
|
<MapPin className="h-5 w-5 sm:h-6 sm:w-6 text-primary" />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-bold leading-tight text-[32px]">Book Your Airport Taxi Now</span>
|
<span className="font-bold leading-tight text-[32px]">Book Your Airport Taxi Now</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
<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"
|
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 }}
|
initial={{ scaleX: 0 }}
|
||||||
animate={{ scaleX: 1 }}
|
animate={{ scaleX: 1 }}
|
||||||
transition={{ delay: 0.3, duration: 0.8 }}
|
transition={{ delay: 0.3, duration: 0.8 }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="bg-transparent px-4 sm:px-6 pt-[0px] pr-[21px] pb-[21px] pl-[21px]">
|
<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">
|
<form onSubmit={handleSubmit} className="space-y-4 sm:space-y-6">
|
||||||
{/* Location Inputs */}
|
{/* Location Inputs */}
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
|
<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">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="pickup" className="text-sm sm:text-base">Pickup Location</Label>
|
<Label htmlFor="customerEmail" className="flex items-center gap-2 text-sm sm:text-base">
|
||||||
<Select value={formData.pickup} onValueChange={(value) => handleInputChange("pickup", value)} required>
|
<Mail className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||||
<SelectTrigger className="h-10 sm:h-11">
|
Email Address <span className="text-xs text-muted-foreground">(For booking confirmation)</span>
|
||||||
<SelectValue placeholder="Select pickup city" />
|
</Label>
|
||||||
</SelectTrigger>
|
<Input
|
||||||
<SelectContent className="max-h-48">
|
id="customerEmail"
|
||||||
{indiaLocations.map((location) => (
|
type="email"
|
||||||
<SelectItem key={location} value={location}>
|
placeholder="Enter your email address"
|
||||||
{location}
|
// 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>
|
||||||
))}
|
<SelectItem value="7-seater">
|
||||||
</SelectContent>
|
<span className="text-xs sm:text-sm">7 Seater (Ertiga) - Airport Taxi </span>
|
||||||
</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>
|
</SelectItem>
|
||||||
))}
|
<SelectItem value="innova">
|
||||||
<div className="px-2 py-1 text-xs text-muted-foreground border-b">All India Locations</div>
|
<span className="text-xs sm:text-sm">Innova - Airport Taxi </span>
|
||||||
{indiaLocations.map((location) => (
|
|
||||||
<SelectItem key={location} value={location}>
|
|
||||||
{location}
|
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
</SelectContent>
|
||||||
</SelectContent>
|
</Select>
|
||||||
</Select>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Date and Time */}
|
<div className="space-y-3 sm:space-y-4">
|
||||||
<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"
|
|
||||||
>
|
|
||||||
<motion.div
|
<motion.div
|
||||||
className="absolute inset-0 bg-gradient-to-r from-green-400 to-green-600 rounded-lg"
|
whileHover={{ scale: 1.02 }}
|
||||||
animate={{
|
whileTap={{ scale: 0.98 }}
|
||||||
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" />
|
<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]">
|
||||||
<div className="text-center">
|
<span className="font-semibold">
|
||||||
<div className="font-semibold text-sm sm:text-base">Call to Book Taxi</div>
|
Book Your Airport Taxi
|
||||||
<div className="text-xs opacity-90">7477247488</div>
|
</span>
|
||||||
</div>
|
</Button>
|
||||||
</Button>
|
</motion.div>
|
||||||
</motion.div>
|
|
||||||
</div>
|
<div className="flex items-center gap-2">
|
||||||
</form>
|
<div className="h-px bg-border flex-1"></div>
|
||||||
</CardContent>
|
<span className="text-xs text-muted-foreground px-2">OR</span>
|
||||||
</Card>
|
<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>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -8,11 +8,11 @@ export function FloatingCallButton() {
|
||||||
className="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-50"
|
className="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-50"
|
||||||
initial={{ scale: 0, opacity: 0 }}
|
initial={{ scale: 0, opacity: 0 }}
|
||||||
animate={{ scale: 1, opacity: 1 }}
|
animate={{ scale: 1, opacity: 1 }}
|
||||||
transition={{
|
transition={{
|
||||||
delay: 1,
|
delay: 1,
|
||||||
type: "spring",
|
type: "spring",
|
||||||
stiffness: 200,
|
stiffness: 200,
|
||||||
damping: 20
|
damping: 20,
|
||||||
}}
|
}}
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
|
|
@ -21,31 +21,34 @@ export function FloatingCallButton() {
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
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"
|
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">
|
<div className="mr-1 sm:mr-2">
|
||||||
<Phone className="h-4 w-4 sm:h-5 sm:w-5 text-white" />
|
<Phone className="h-4 w-4 sm:h-5 sm:w-5 text-white" />
|
||||||
</div>
|
</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 sm:text-sm font-bold">Call to Book</div>
|
||||||
<div className="text-xs opacity-90">7477247488</div>
|
<div className="text-xs opacity-90">7477247488</div>
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{/* Simple pulse effect */}
|
{/* Simple pulse animation */}
|
||||||
<motion.div
|
<motion.div
|
||||||
className="absolute inset-0 rounded-full bg-green-400/50"
|
className="absolute inset-0 rounded-full bg-green-400/50"
|
||||||
animate={{
|
animate={{
|
||||||
scale: [1, 1.5, 1],
|
scale: [1, 1.5, 1],
|
||||||
opacity: [0.7, 0, 0.7]
|
opacity: [0.7, 0, 0.7],
|
||||||
}}
|
}}
|
||||||
transition={{
|
transition={{
|
||||||
duration: 2,
|
duration: 2,
|
||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
ease: "easeInOut"
|
ease: "easeInOut",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ export function HeroSection({ children }: HeroSectionProps) {
|
||||||
transition={{ duration: 0.8, delay: 0.4 }}
|
transition={{ duration: 0.8, delay: 0.4 }}
|
||||||
className="block text-white"
|
className="block text-white"
|
||||||
>
|
>
|
||||||
Durg/Bhilai-Raipur Airport Drop(Oneway)
|
Durg/Bhilai-Raipur Airport Drop(Oneway)
|
||||||
</motion.span>
|
</motion.span>
|
||||||
<motion.span
|
<motion.span
|
||||||
className="block text-yellow-400 text-xl sm:text-3xl md:text-4xl lg:text-5xl"
|
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 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.8, delay: 0.6 }}
|
transition={{ duration: 0.8, delay: 0.6 }}
|
||||||
>
|
>
|
||||||
₹1099
|
₹999
|
||||||
</motion.span>
|
</motion.span>
|
||||||
</motion.h1>
|
</motion.h1>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ const services = [
|
||||||
icon: Plane,
|
icon: Plane,
|
||||||
title: "Airport Taxi",
|
title: "Airport Taxi",
|
||||||
description: "Comfortable and punctual airport taxi services. Never miss a flight with our dedicated airport service.",
|
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"],
|
features: ["Flight monitoring", "Meet & greet service", "Fixed rate ₹999"],
|
||||||
price: "₹1099",
|
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",
|
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"
|
imageAlt: "Premium car at airport terminal"
|
||||||
},
|
},
|
||||||
|
|
@ -91,7 +91,7 @@ export function ServicesSection() {
|
||||||
return (
|
return (
|
||||||
<div className="py-8 sm:py-12 lg:py-16">
|
<div className="py-8 sm:py-12 lg:py-16">
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4">
|
||||||
<motion.div
|
<motion.div
|
||||||
className="text-center mb-8 sm:mb-10 lg:mb-12"
|
className="text-center mb-8 sm:mb-10 lg:mb-12"
|
||||||
initial={{ opacity: 0, y: 30 }}
|
initial={{ opacity: 0, y: 30 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
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>
|
<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">
|
<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.
|
tailored to your needs with professional drivers and well-maintained vehicles.
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Main Services */}
|
{/* 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"
|
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}
|
variants={containerVariants}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
|
|
@ -117,7 +117,7 @@ export function ServicesSection() {
|
||||||
<motion.div
|
<motion.div
|
||||||
key={index}
|
key={index}
|
||||||
variants={cardVariants}
|
variants={cardVariants}
|
||||||
whileHover={{
|
whileHover={{
|
||||||
y: -8,
|
y: -8,
|
||||||
transition: { duration: 0.3 }
|
transition: { duration: 0.3 }
|
||||||
}}
|
}}
|
||||||
|
|
@ -137,9 +137,9 @@ export function ServicesSection() {
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
|
||||||
|
|
||||||
{/* Icon overlay */}
|
{/* Icon overlay */}
|
||||||
<motion.div
|
<motion.div
|
||||||
className="absolute bottom-4 left-4"
|
className="absolute bottom-4 left-4"
|
||||||
initial={{ scale: 0, opacity: 0 }}
|
initial={{ scale: 0, opacity: 0 }}
|
||||||
whileInView={{ scale: 1, opacity: 1 }}
|
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">
|
<div className="w-12 h-12 bg-white/90 backdrop-blur-sm rounded-lg flex items-center justify-center">
|
||||||
<motion.div
|
<motion.div
|
||||||
animate={{
|
animate={{
|
||||||
rotate: [0, 10, -10, 0],
|
rotate: [0, 10, -10, 0],
|
||||||
scale: [1, 1.1, 1]
|
scale: [1, 1.1, 1]
|
||||||
}}
|
}}
|
||||||
transition={{
|
transition={{
|
||||||
duration: 4,
|
duration: 4,
|
||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
ease: "easeInOut"
|
ease: "easeInOut"
|
||||||
|
|
@ -162,9 +162,9 @@ export function ServicesSection() {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Price badge */}
|
{/* Price badge */}
|
||||||
<motion.div
|
<motion.div
|
||||||
className="absolute top-4 right-4"
|
className="absolute top-4 right-4"
|
||||||
initial={{ x: 50, opacity: 0 }}
|
initial={{ x: 50, opacity: 0 }}
|
||||||
whileInView={{ x: 0, opacity: 1 }}
|
whileInView={{ x: 0, opacity: 1 }}
|
||||||
|
|
@ -189,9 +189,9 @@ export function ServicesSection() {
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<CardContent className="pt-0 px-4 sm:px-6">
|
<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"
|
className="text-muted-foreground mb-3 sm:mb-4 text-sm sm:text-base"
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
whileInView={{ opacity: 1 }}
|
whileInView={{ opacity: 1 }}
|
||||||
|
|
@ -200,8 +200,8 @@ export function ServicesSection() {
|
||||||
>
|
>
|
||||||
{service.description}
|
{service.description}
|
||||||
</motion.p>
|
</motion.p>
|
||||||
|
|
||||||
<motion.div
|
<motion.div
|
||||||
className="space-y-2"
|
className="space-y-2"
|
||||||
initial={{ opacity: 0, y: 10 }}
|
initial={{ opacity: 0, y: 10 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
|
@ -211,21 +211,21 @@ export function ServicesSection() {
|
||||||
<h4>Features:</h4>
|
<h4>Features:</h4>
|
||||||
<ul className="space-y-1">
|
<ul className="space-y-1">
|
||||||
{service.features.map((feature, featureIndex) => (
|
{service.features.map((feature, featureIndex) => (
|
||||||
<motion.li
|
<motion.li
|
||||||
key={featureIndex}
|
key={featureIndex}
|
||||||
className="flex items-center gap-2 text-sm text-muted-foreground"
|
className="flex items-center gap-2 text-sm text-muted-foreground"
|
||||||
initial={{ opacity: 0, x: -10 }}
|
initial={{ opacity: 0, x: -10 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
transition={{ delay: index * 0.2 + 0.7 + featureIndex * 0.1 }}
|
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"
|
className="w-1.5 h-1.5 bg-primary rounded-full"
|
||||||
animate={{
|
animate={{
|
||||||
scale: [1, 1.5, 1],
|
scale: [1, 1.5, 1],
|
||||||
opacity: [0.7, 1, 0.7]
|
opacity: [0.7, 1, 0.7]
|
||||||
}}
|
}}
|
||||||
transition={{
|
transition={{
|
||||||
duration: 2,
|
duration: 2,
|
||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
delay: featureIndex * 0.3
|
delay: featureIndex * 0.3
|
||||||
|
|
@ -243,14 +243,14 @@ export function ServicesSection() {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Additional Services */}
|
{/* Additional Services */}
|
||||||
<motion.div
|
<motion.div
|
||||||
className="bg-muted/50 rounded-lg p-8"
|
className="bg-muted/50 rounded-lg p-8"
|
||||||
initial={{ opacity: 0, y: 30 }}
|
initial={{ opacity: 0, y: 30 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
transition={{ duration: 0.6, delay: 0.2 }}
|
transition={{ duration: 0.6, delay: 0.2 }}
|
||||||
>
|
>
|
||||||
<motion.h2
|
<motion.h2
|
||||||
className="mb-6 text-center"
|
className="mb-6 text-center"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
|
@ -261,8 +261,8 @@ export function ServicesSection() {
|
||||||
</motion.h2>
|
</motion.h2>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
{additionalServices.map((service, index) => (
|
{additionalServices.map((service, index) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex items-center gap-4 p-4 rounded-lg hover:bg-background/50 transition-colors group"
|
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 }}
|
initial={{ opacity: 0, x: index % 2 === 0 ? -20 : 20 }}
|
||||||
whileInView={{ opacity: 1, x: 0 }}
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
|
@ -270,12 +270,12 @@ export function ServicesSection() {
|
||||||
transition={{ delay: 0.4 + index * 0.1 }}
|
transition={{ delay: 0.4 + index * 0.1 }}
|
||||||
whileHover={{ x: 5 }}
|
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"
|
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],
|
rotate: [0, 360],
|
||||||
}}
|
}}
|
||||||
transition={{
|
transition={{
|
||||||
duration: 20,
|
duration: 20,
|
||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
ease: "linear"
|
ease: "linear"
|
||||||
|
|
@ -293,14 +293,14 @@ export function ServicesSection() {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Service Areas */}
|
{/* Service Areas */}
|
||||||
<motion.div
|
<motion.div
|
||||||
className="mt-12 text-center"
|
className="mt-12 text-center"
|
||||||
initial={{ opacity: 0, y: 30 }}
|
initial={{ opacity: 0, y: 30 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
transition={{ duration: 0.6, delay: 0.4 }}
|
transition={{ duration: 0.6, delay: 0.4 }}
|
||||||
>
|
>
|
||||||
<motion.h2
|
<motion.h2
|
||||||
className="mb-6"
|
className="mb-6"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
|
@ -317,7 +317,7 @@ export function ServicesSection() {
|
||||||
whileInView={{ opacity: 1, scale: 1 }}
|
whileInView={{ opacity: 1, scale: 1 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
transition={{ delay: 0.6 + index * 0.05 }}
|
transition={{ delay: 0.6 + index * 0.05 }}
|
||||||
whileHover={{
|
whileHover={{
|
||||||
scale: 1.05,
|
scale: 1.05,
|
||||||
transition: { duration: 0.2 }
|
transition: { duration: 0.2 }
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -6,27 +6,27 @@ export const indiaLocations = [
|
||||||
"Jaipur", "Jodhpur", "Udaipur", "Ajmer", "Kota", "Bikaner", "Alwar",
|
"Jaipur", "Jodhpur", "Udaipur", "Ajmer", "Kota", "Bikaner", "Alwar",
|
||||||
"Lucknow", "Kanpur", "Agra", "Varanasi", "Allahabad", "Meerut", "Bareilly", "Aligarh",
|
"Lucknow", "Kanpur", "Agra", "Varanasi", "Allahabad", "Meerut", "Bareilly", "Aligarh",
|
||||||
"Dehradun", "Haridwar", "Rishikesh", "Mussoorie", "Nainital", "Shimla", "Manali", "Dharamshala",
|
"Dehradun", "Haridwar", "Rishikesh", "Mussoorie", "Nainital", "Shimla", "Manali", "Dharamshala",
|
||||||
|
|
||||||
// East India
|
// East India
|
||||||
"Kolkata", "Howrah", "Durgapur", "Asansol", "Siliguri", "Darjeeling",
|
"Kolkata", "Howrah", "Durgapur", "Asansol", "Siliguri", "Darjeeling",
|
||||||
"Bhubaneswar", "Cuttack", "Rourkela", "Puri",
|
"Bhubaneswar", "Cuttack", "Rourkela", "Puri",
|
||||||
"Patna", "Gaya", "Muzaffarpur", "Bhagalpur", "Darbhanga",
|
"Patna", "Gaya", "Muzaffarpur", "Bhagalpur", "Darbhanga",
|
||||||
"Guwahati", "Silchar", "Dibrugarh", "Jorhat", "Tezpur",
|
"Guwahati", "Silchar", "Dibrugarh", "Jorhat", "Tezpur",
|
||||||
|
|
||||||
// West India
|
// West India
|
||||||
"Ahmedabad", "Surat", "Vadodara", "Rajkot", "Bhavnagar", "Jamnagar", "Gandhinagar",
|
"Ahmedabad", "Surat", "Vadodara", "Rajkot", "Bhavnagar", "Jamnagar", "Gandhinagar",
|
||||||
"Thane", "Navi Mumbai", "Kalyan", "Vasai-Virar", "Solapur", "Nagpur", "Kolhapur",
|
"Thane", "Navi Mumbai", "Kalyan", "Vasai-Virar", "Solapur", "Nagpur", "Kolhapur",
|
||||||
|
|
||||||
// South India
|
// South India
|
||||||
"Bangalore", "Mysore", "Mangalore", "Hubli", "Belgaum", "Gulbarga", "Davangere",
|
"Bangalore", "Mysore", "Mangalore", "Hubli", "Belgaum", "Gulbarga", "Davangere",
|
||||||
"Chennai", "Coimbatore", "Madurai", "Tiruchirappalli", "Salem", "Tirunelveli", "Erode", "Tiruppur", "Vellore",
|
"Chennai", "Coimbatore", "Madurai", "Tiruchirappalli", "Salem", "Tirunelveli", "Erode", "Tiruppur", "Vellore",
|
||||||
"Hyderabad", "Secunderabad", "Warangal", "Nizamabad", "Karimnagar", "Khammam", "Ramagundam",
|
"Hyderabad", "Secunderabad", "Warangal", "Nizamabad", "Karimnagar", "Khammam", "Ramagundam",
|
||||||
"Kochi", "Thiruvananthapuram", "Kozhikode", "Kollam", "Thrissur", "Alappuzha", "Palakkad", "Kannur",
|
"Kochi", "Thiruvananthapuram", "Kozhikode", "Kollam", "Thrissur", "Alappuzha", "Palakkad", "Kannur",
|
||||||
|
|
||||||
// Central India
|
// Central India
|
||||||
"Indore", "Bhopal", "Jabalpur", "Gwalior", "Ujjain", "Sagar", "Dewas", "Satna",
|
"Indore", "Bhopal", "Jabalpur", "Gwalior", "Ujjain", "Sagar", "Dewas", "Satna",
|
||||||
"Raipur", "Bhilai", "Bilaspur", "Korba", "Durg", "Rajnandgaon",
|
"Raipur", "Bhilai", "Bilaspur", "Korba", "Durg", "Rajnandgaon",
|
||||||
|
|
||||||
// Union Territories
|
// Union Territories
|
||||||
"Pondicherry", "Port Blair", "Panaji", "Margao", "Vasco da Gama", "Daman", "Silvassa"
|
"Pondicherry", "Port Blair", "Panaji", "Margao", "Vasco da Gama", "Daman", "Silvassa"
|
||||||
];
|
];
|
||||||
|
|
@ -34,7 +34,7 @@ export const indiaLocations = [
|
||||||
// Service types for drop-off options
|
// Service types for drop-off options
|
||||||
export const serviceTypes = [
|
export const serviceTypes = [
|
||||||
"City Ride - Customize Price",
|
"City Ride - Customize Price",
|
||||||
"Airport Taxi - ₹1099",
|
"Airport Taxi - ₹999",
|
||||||
"Outstation - Customize Price",
|
"Outstation - Customize Price",
|
||||||
"Mover and Packer - Customize Price",
|
"Mover and Packer - Customize Price",
|
||||||
"Corporate Services - Customize Price"
|
"Corporate Services - Customize Price"
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ export const mockVehicles: Vehicle[] = [
|
||||||
id: "1",
|
id: "1",
|
||||||
type: "5-seater",
|
type: "5-seater",
|
||||||
name: "5 Seater",
|
name: "5 Seater",
|
||||||
price: 1099,
|
price: 999,
|
||||||
capacity: 5,
|
capacity: 5,
|
||||||
rating: 4.5,
|
rating: 4.5,
|
||||||
estimatedTime: "Rider will contact you soon",
|
estimatedTime: "Rider will contact you soon",
|
||||||
features: ["AC", "Music System", "Comfortable", "Airport Taxi ₹1099"],
|
features: ["AC", "Music System", "Comfortable", "Airport Taxi ₹999"],
|
||||||
image: ""
|
image: ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ app.get("/make-server-10d555e8/health", (c) => {
|
||||||
// Test email configuration endpoint
|
// Test email configuration endpoint
|
||||||
app.get("/make-server-10d555e8/test-email-config", (c) => {
|
app.get("/make-server-10d555e8/test-email-config", (c) => {
|
||||||
const resendApiKey = Deno.env.get('RESEND_API_KEY');
|
const resendApiKey = Deno.env.get('RESEND_API_KEY');
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
emailConfigured: !!resendApiKey,
|
emailConfigured: !!resendApiKey,
|
||||||
apiKeyFormat: resendApiKey ? (resendApiKey.startsWith('re_') ? 'valid' : 'invalid') : 'missing',
|
apiKeyFormat: resendApiKey ? (resendApiKey.startsWith('re_') ? 'valid' : 'invalid') : 'missing',
|
||||||
apiKeyLength: resendApiKey?.length || 0
|
apiKeyLength: resendApiKey?.length || 0
|
||||||
|
|
@ -40,7 +40,7 @@ app.post("/make-server-10d555e8/send-booking-email", async (c) => {
|
||||||
try {
|
try {
|
||||||
const bookingData = await c.req.json();
|
const bookingData = await c.req.json();
|
||||||
console.log('Received booking data:', JSON.stringify(bookingData, null, 2));
|
console.log('Received booking data:', JSON.stringify(bookingData, null, 2));
|
||||||
|
|
||||||
// Store booking in KV store
|
// Store booking in KV store
|
||||||
const bookingId = `booking_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
const bookingId = `booking_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
await kv.set(bookingId, {
|
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 exists:', !!resendApiKey);
|
||||||
console.log('API Key length:', resendApiKey?.length || 0);
|
console.log('API Key length:', resendApiKey?.length || 0);
|
||||||
console.log('API Key prefix:', resendApiKey?.substring(0, 7) || 'none');
|
console.log('API Key prefix:', resendApiKey?.substring(0, 7) || 'none');
|
||||||
|
|
||||||
if (!resendApiKey) {
|
if (!resendApiKey) {
|
||||||
console.error('RESEND_API_KEY environment variable not found');
|
console.error('RESEND_API_KEY environment variable not found');
|
||||||
throw new Error('RESEND_API_KEY not configured - please set up your Resend API key');
|
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
|
// Get vehicle pricing
|
||||||
const getVehiclePrice = (vehicleType) => {
|
const getVehiclePrice = (vehicleType) => {
|
||||||
switch(vehicleType) {
|
switch (vehicleType) {
|
||||||
case '5-seater': return '₹1099';
|
case '5-seater': return '₹999';
|
||||||
case '7-seater': return '₹1600';
|
case '7-seater': return '₹1600';
|
||||||
case 'innova': return '₹2000';
|
case 'innova': return '₹2000';
|
||||||
default: return 'Contact for pricing';
|
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);
|
console.log('Booking email sent successfully:', bookingId);
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Booking confirmed and emails sent successfully',
|
message: 'Booking confirmed and emails sent successfully',
|
||||||
bookingId: bookingId,
|
bookingId: bookingId,
|
||||||
emailsSent: {
|
emailsSent: {
|
||||||
|
|
@ -205,19 +205,19 @@ app.post("/make-server-10d555e8/send-booking-email", async (c) => {
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error processing booking:', error);
|
console.error('Error processing booking:', error);
|
||||||
|
|
||||||
// If it's an API key issue, provide specific guidance
|
// If it's an API key issue, provide specific guidance
|
||||||
if (error.message.includes('API key') || error.message.includes('validation_error')) {
|
if (error.message.includes('API key') || error.message.includes('validation_error')) {
|
||||||
return c.json({
|
return c.json({
|
||||||
success: false,
|
success: false,
|
||||||
message: `Email service configuration error: ${error.message}. Please check your Resend API key setup.`,
|
message: `Email service configuration error: ${error.message}. Please check your Resend API key setup.`,
|
||||||
error: 'EMAIL_CONFIG_ERROR'
|
error: 'EMAIL_CONFIG_ERROR'
|
||||||
}, 400);
|
}, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For other errors, still save the booking but indicate email failure
|
// For other errors, still save the booking but indicate email failure
|
||||||
return c.json({
|
return c.json({
|
||||||
success: false,
|
success: false,
|
||||||
message: `Booking saved but email notification failed: ${error.message}`,
|
message: `Booking saved but email notification failed: ${error.message}`,
|
||||||
error: 'EMAIL_SEND_FAILED'
|
error: 'EMAIL_SEND_FAILED'
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue