feat: implement hero section with multi-trip booking widget and backend infrastructure

This commit is contained in:
AnuragJangid18 2026-04-04 22:04:48 +05:30
parent 44995cb5db
commit e7365b06ac
21 changed files with 4104 additions and 113 deletions

386
backend/index.js Normal file
View file

@ -0,0 +1,386 @@
import "dotenv/config";
import express from "express";
import mysql from "mysql2/promise";
// Create a connection pool to MySQL
const pool = mysql.createPool({
host: process.env.DB_HOST || "localhost",
user: process.env.DB_USER || "root",
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME || "roadrentals",
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
const app = express();
app.use(express.json());
const checkToken = (req, res, next) => {
console.log("Welcome");
next();
};
app.use(checkToken);
app.get("/", (req, res) => {
res.json({ status: 1, message: "Home Page API" });
});
app.get("/api/news", (req, res) => {
res.json({ status: 1, message: "News API" });
});
// Database Connected Endpoint
app.post("/api/auth/register", async (req, res) => {
try {
const { name, email, mobile_number, password } = req.body;
if (!name || !email || !mobile_number || !password) {
return res.status(400).json({ detail: "Missing required fields" });
}
// Search the MySQL Database
const [users] = await pool.execute("SELECT * FROM User WHERE email = ?", [email]);
const existingUser = users[0];
if (existingUser) {
return res.status(409).json({ detail: "Email already registered" });
}
// Insert new user row into MySQL table
const [result] = await pool.execute(
"INSERT INTO User (name, email, mobile_number, password) VALUES (?, ?, ?, ?)",
[name, email, mobile_number, password]
);
const newUser = {
id: result.insertId,
name,
email,
mobile_number
};
return res.status(201).json({ status: 1, message: "User registered successfully", user: newUser });
} catch (error) {
console.error("Database Error:", error);
return res.status(500).json({ detail: "Internal Server Error" });
}
});
// Create a New Booking
app.post("/api/bookings", async (req, res) => {
try {
const {
tripType,
pickupLocation,
dropLocation,
pickupDateTime,
returnDateTime,
packageType,
carName,
totalAmount
} = req.body;
if (!tripType || !pickupLocation || !pickupDateTime) {
return res.status(400).json({ detail: "Missing required booking details" });
}
const [result] = await pool.execute(
`INSERT INTO Bookings (trip_type, pickup_location, drop_location, pickup_datetime, return_datetime, package_type, car_name, total_amount)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[
tripType,
pickupLocation,
dropLocation || null,
new Date(pickupDateTime),
returnDateTime ? new Date(returnDateTime) : null,
packageType || null,
carName || null,
totalAmount || null
]
);
return res.status(201).json({
status: 1,
message: "Booking requested successfully!",
bookingId: result.insertId
});
} catch (error) {
console.error("Booking Error:", error);
return res.status(500).json({ detail: "Failed to create booking" });
}
});
// Pricing Engine & Car Data
const VEHICLES = [
// LUXURY TIER
{
id: 1,
name: "Audi A6 Premium",
type: "LUXURY",
seats: "4+1",
luggage: "2 Bags",
image: "audi_a6",
baseFarePerDay: 12000,
driverAllowancePerDay: 600,
extraKmRate: 45,
includedKmPerDay: 250,
badge: "Executive",
features: ["Leather Interior", "Dual Climate", "Premium Audio", "Sunroof"]
},
{
id: 2,
name: "BMW 7 Series",
type: "LUXURY",
seats: "4+1",
luggage: "3 Bags",
image: "bmw_7_series",
baseFarePerDay: 25000,
driverAllowancePerDay: 800,
extraKmRate: 85,
includedKmPerDay: 200,
badge: "VVIP Choice",
features: ["Rear-seat Entertainment", "Massage Seats", "Quiet Cabin", "Chauffeur Driven"]
},
{
id: 3,
name: "Mercedes S-Class",
type: "LUXURY",
seats: "4+1",
luggage: "2 Bags",
image: "mercedes_s_class",
baseFarePerDay: 28000,
driverAllowancePerDay: 800,
extraKmRate: 90,
includedKmPerDay: 200,
badge: "Ultimate Luxury",
features: ["Ambient Lighting", "Burmester Sound", "Premium Chauffeur"]
},
// SUV/MUV TIER
{
id: 4,
name: "Toyota Fortuner 4x4",
type: "SUV",
seats: "6+1",
luggage: "4 Bags",
image: "fortuner",
baseFarePerDay: 6500,
driverAllowancePerDay: 500,
extraKmRate: 25,
includedKmPerDay: 300,
badge: "Advanture King",
features: ["Off-road capable", "Powerful AC", "Spacious", "Rugged Built"]
},
{
id: 5,
name: "Innova Crysta",
type: "MUV",
seats: "7+1",
luggage: "3 Bags",
image: "innova_crysta",
baseFarePerDay: 4500,
driverAllowancePerDay: 400,
extraKmRate: 18,
includedKmPerDay: 300,
badge: "Best Seller",
features: ["Clean Interiors", "Captain Seats", "Smooth Ride", "Carrier Available"]
},
{
id: 6,
name: "Toyota Innova",
type: "MUV",
seats: "7+1",
luggage: "2 Bags",
image: "innova",
baseFarePerDay: 3800,
driverAllowancePerDay: 400,
extraKmRate: 16,
includedKmPerDay: 300,
badge: "Value MUV",
features: ["Comfortable", "Spacious", "Economical for Family"]
},
// SEDAN TIER
{
id: 7,
name: "Toyota Camry",
type: "SEDAN",
seats: "4+1",
luggage: "2 Bags",
image: "camry",
baseFarePerDay: 4200,
driverAllowancePerDay: 400,
extraKmRate: 18,
includedKmPerDay: 300,
badge: "Corporate Elite",
features: ["Hybrid Tech", "Quiet Ride", "Executive Space"]
},
{
id: 8,
name: "Toyota Etios",
type: "SEDAN",
seats: "4+1",
luggage: "2 Bags",
image: "etios",
baseFarePerDay: 2800,
driverAllowancePerDay: 400,
extraKmRate: 13,
includedKmPerDay: 300,
badge: "Economic",
features: ["Spacious Boot", "Good Legroom", "Standard AC"]
},
{
id: 9,
name: "Swift Dzire",
type: "SEDAN",
seats: "4+1",
luggage: "2 Bags",
image: "dzire",
baseFarePerDay: 2600,
driverAllowancePerDay: 400,
extraKmRate: 13,
includedKmPerDay: 300,
badge: "Economic Choice",
features: ["Popular", "Quick Maneuver", "Efficient AC"]
},
// GROUP TRAVEL
{
id: 11,
name: "Audi Q7 Luxury SUV",
type: "SUV",
seats: "6+1",
luggage: "4 Bags",
image: "audi_q7",
baseFarePerDay: 15000,
driverAllowancePerDay: 700,
extraKmRate: 55,
includedKmPerDay: 250,
badge: "Luxury SUV",
features: ["Quattro 4x4", "Panoramic Sunroof", "Premium Audio", "Heated Seats"]
},
{
id: 12,
name: "BMW 5 Series",
type: "LUXURY",
seats: "4+1",
luggage: "2 Bags",
image: "bmw_5_series",
baseFarePerDay: 14000,
driverAllowancePerDay: 600,
extraKmRate: 50,
includedKmPerDay: 250,
badge: "Business Class",
features: ["Dynamic Drive", "Luxury Interiors", "Silent Hybrid", "Touchscreen Control"]
},
{
id: 13,
name: "Mercedes E-Class",
type: "LUXURY",
seats: "4+1",
luggage: "2 Bags",
image: "mercedes_e_class",
baseFarePerDay: 14500,
driverAllowancePerDay: 600,
extraKmRate: 52,
includedKmPerDay: 250,
badge: "Timeless Elegance",
features: ["Soft Close Doors", "Ambient Light", "Professional Driver", "WIFI Enabled"]
},
{
id: 14,
name: "Toyota Corolla Altis",
type: "SEDAN",
seats: "4+1",
luggage: "2 Bags",
image: "corolla_altis",
baseFarePerDay: 3800,
driverAllowancePerDay: 400,
extraKmRate: 16,
includedKmPerDay: 300,
badge: "Executive Sedan",
features: ["Durable", "Comfortable Suspension", "Clean Air Filter"]
}
];
// Lead Capture
app.post("/api/leads", async (req, res) => {
try {
const { name, mobile_number, tripType, pickupLocation, dropLocation } = req.body;
if (!name || !mobile_number) return res.status(400).json({ detail: "Name and Mobile are required" });
await pool.execute(
`INSERT INTO Leads (name, mobile_number, trip_type, pickup_location, drop_location) VALUES (?, ?, ?, ?, ?)`,
[name, mobile_number, tripType || null, pickupLocation || null, dropLocation || null]
);
res.status(201).json({ status: 1, message: "Lead captured" });
} catch (error) {
console.error("Lead Error:", error);
res.status(500).json({ detail: "Failed to capture lead" });
}
});
// Centralized Pricing Calculator
app.post("/api/pricing/calculate", async (req, res) => {
try {
const { tripType, pickupDate, returnDate, packageType } = req.body;
const start = new Date(pickupDate);
const end = returnDate ? new Date(returnDate) : start;
const diffTime = Math.abs(end - start);
const durationDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) || 1;
const results = VEHICLES.map(vehicle => {
let totalBaseFare = vehicle.baseFarePerDay * durationDays;
let totalDriverAllowance = vehicle.driverAllowancePerDay * durationDays;
// Special Case: Local Packages
if (tripType === 'local' && packageType) {
if (packageType.includes("4Hr")) totalBaseFare = 1500;
else if (packageType.includes("8Hr")) totalBaseFare = 2500;
else if (packageType.includes("12Hr")) totalBaseFare = 3500;
totalDriverAllowance = 0;
}
// Special Case: Airport Transfers (Flat Rates)
if (tripType === 'airport') {
if (vehicle.type === 'SEDAN') totalBaseFare = 1200;
else if (vehicle.type === 'SUV') totalBaseFare = 2200;
else totalBaseFare = 1800; // MUV/Other
totalDriverAllowance = 0;
}
const grandTotal = totalBaseFare + totalDriverAllowance;
const advancePayment = Math.round(grandTotal * 0.20);
return {
...vehicle,
calc: {
days: durationDays,
baseFare: totalBaseFare,
driverAllowance: totalDriverAllowance,
totalKmIncluded: vehicle.includedKmPerDay * (tripType === 'airport' ? 0.2 : durationDays), // Approx for airport
grandTotal,
advancePayment,
math: tripType === 'airport' || tripType === 'local'
? `Fixed ${tripType.charAt(0).toUpperCase() + tripType.slice(1)} Rate`
: `(₹${vehicle.baseFarePerDay} x ${durationDays} Days) + ₹${totalDriverAllowance} Driver`
},
inclusions: ["AC", "Professional Driver", tripType === 'airport' ? "Airport Toll Included" : "First " + (vehicle.includedKmPerDay * durationDays) + " Kms"],
exclusions: ["Parking Charges", "Extra Waiting Time", "Inter-state Permits"]
};
});
res.json({ status: 1, data: results });
} catch (error) {
console.error("Pricing Error:", error);
res.status(500).json({ detail: "Failed to calculate pricing" });
}
});
const PORT = 8000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});