265 lines
No EOL
9.2 KiB
JavaScript
265 lines
No EOL
9.2 KiB
JavaScript
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" });
|
|
}
|
|
});
|
|
|
|
// --- DYNAMIC PRICING ENGINE (DB DRIVEN) ---
|
|
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;
|
|
|
|
// Fetch ACTIVE vehicles from DB
|
|
const [rows] = await pool.execute("SELECT * FROM Vehicles WHERE isAvailable = TRUE");
|
|
|
|
const results = rows.map(vehicle => {
|
|
const features = typeof vehicle.features === 'string' ? JSON.parse(vehicle.features) : vehicle.features;
|
|
|
|
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
|
|
if (tripType === 'airport') {
|
|
if (vehicle.type === 'SEDAN') totalBaseFare = 1200;
|
|
else if (vehicle.type === 'SUV') totalBaseFare = 2200;
|
|
else totalBaseFare = 1800;
|
|
totalDriverAllowance = 0;
|
|
}
|
|
|
|
const grandTotal = totalBaseFare + totalDriverAllowance;
|
|
const advancePayment = Math.round(grandTotal * 0.20);
|
|
|
|
return {
|
|
...vehicle,
|
|
features,
|
|
calc: {
|
|
days: durationDays,
|
|
baseFare: totalBaseFare,
|
|
driverAllowance: totalDriverAllowance,
|
|
totalKmIncluded: vehicle.includedKmPerDay * (tripType === 'airport' ? 0.2 : durationDays),
|
|
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 * (tripType === 'airport' ? 1 : 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" });
|
|
}
|
|
});
|
|
|
|
// --- ADMIN API ENDPOINTS ---
|
|
|
|
// Secure Admin Login
|
|
app.post("/api/admin/login", async (req, res) => {
|
|
const { adminId, password } = req.body;
|
|
|
|
// Environment-based credentials for security
|
|
const VALID_ADMIN_ID = process.env.ADMIN_ID || "admin";
|
|
const VALID_ADMIN_PASS = process.env.ADMIN_PASSWORD || "admin123";
|
|
|
|
if (adminId === VALID_ADMIN_ID && password === VALID_ADMIN_PASS) {
|
|
res.json({ success: true, token: "secure_session_token_xyz_987" });
|
|
} else {
|
|
res.status(401).json({ detail: "Invalid Admin ID or Password" });
|
|
}
|
|
});
|
|
|
|
// Get Full Fleet for Management
|
|
app.get("/api/admin/vehicles", async (req, res) => {
|
|
try {
|
|
const [rows] = await pool.execute("SELECT * FROM Vehicles ORDER BY id DESC");
|
|
const cars = rows.map(v => ({
|
|
...v,
|
|
features: typeof v.features === 'string' ? JSON.parse(v.features) : v.features
|
|
}));
|
|
res.json(cars);
|
|
} catch (err) {
|
|
res.status(500).json({ detail: "Fail to fetch fleet" });
|
|
}
|
|
});
|
|
|
|
// Update Availability or Pricing
|
|
app.patch("/api/admin/vehicles/:id", async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { baseFarePerDay, isAvailable } = req.body;
|
|
|
|
if (baseFarePerDay !== undefined) {
|
|
await pool.execute("UPDATE Vehicles SET baseFarePerDay = ? WHERE id = ?", [baseFarePerDay, id]);
|
|
}
|
|
if (isAvailable !== undefined) {
|
|
await pool.execute("UPDATE Vehicles SET isAvailable = ? WHERE id = ?", [isAvailable, id]);
|
|
}
|
|
|
|
res.json({ success: true, message: "Vehicle updated successfully" });
|
|
} catch (err) {
|
|
res.status(500).json({ detail: "Failed to update vehicle" });
|
|
}
|
|
});
|
|
|
|
// Add New Cab
|
|
app.post("/api/admin/vehicles", async (req, res) => {
|
|
try {
|
|
const v = req.body;
|
|
const features = JSON.stringify(v.features || []);
|
|
|
|
await pool.execute(
|
|
`INSERT INTO Vehicles (name, type, seats, luggage, image, baseFarePerDay, driverAllowancePerDay, extraKmRate, includedKmPerDay, badge, features)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
[v.name, v.type, v.seats, v.luggage, v.image, v.baseFarePerDay, v.driverAllowancePerDay, v.extraKmRate, v.includedKmPerDay, v.badge, features]
|
|
);
|
|
|
|
res.status(201).json({ success: true, message: "New vehicle added" });
|
|
} catch (err) {
|
|
res.status(500).json({ detail: "Failed to add new vehicle" });
|
|
}
|
|
});
|
|
|
|
// Delete Cab
|
|
app.delete("/api/admin/vehicles/:id", async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
await pool.execute("DELETE FROM Vehicles WHERE id = ?", [id]);
|
|
res.json({ success: true, message: "Vehicle removed" });
|
|
} catch (err) {
|
|
res.status(500).json({ detail: "Failed to delete vehicle" });
|
|
}
|
|
});
|
|
|
|
|
|
const PORT = 8000;
|
|
|
|
app.listen(PORT, () => {
|
|
console.log(`Server running on http://localhost:${PORT}`);
|
|
}); |