Add src/app/quote-calculator/page.tsx
This commit is contained in:
227
src/app/quote-calculator/page.tsx
Normal file
227
src/app/quote-calculator/page.tsx
Normal file
@@ -0,0 +1,227 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
import ReactLenis from "lenis/react";
|
||||
import NavbarLayoutFloatingInline from "@/components/navbar/NavbarLayoutFloatingInline";
|
||||
import FooterCard from "@/components/sections/footer/FooterCard";
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import { Instagram, Facebook, Linkedin } from "lucide-react";
|
||||
|
||||
export default function QuoteCalculatorPage() {
|
||||
const [departurePort, setDeparturePort] = useState("");
|
||||
const [arrivalPort, setArrivalPort] = useState("");
|
||||
const [cargoType, setCargoType] = useState("");
|
||||
const [weight, setWeight] = useState(0);
|
||||
const [volume, setVolume] = useState(0);
|
||||
const [isCharter, setIsCharter] = useState(false);
|
||||
const [estimatedCost, setEstimatedCost] = useState(0);
|
||||
|
||||
const calculateCost = useCallback(() => {
|
||||
let baseCost = 1000; // Base cost
|
||||
let factor = 1;
|
||||
|
||||
if (departurePort && arrivalPort) {
|
||||
// Simple logic for demonstration
|
||||
if (departurePort !== arrivalPort) {
|
||||
factor *= 1.5;
|
||||
}
|
||||
if (departurePort === "Shanghai" && arrivalPort === "New York") factor *= 2.5;
|
||||
if (departurePort === "Rotterdam" && arrivalPort === "Dubai") factor *= 2.0;
|
||||
}
|
||||
|
||||
if (cargoType === "Perishable") factor *= 1.8;
|
||||
if (cargoType === "Hazardous") factor *= 2.5;
|
||||
|
||||
factor += (weight / 1000) * 0.5; // Weight in tons
|
||||
factor += (volume / 10) * 0.3; // Volume in CBM
|
||||
|
||||
if (isCharter) {
|
||||
factor *= 3; // Charter is more expensive
|
||||
}
|
||||
|
||||
setEstimatedCost(baseCost * factor);
|
||||
}, [departurePort, arrivalPort, cargoType, weight, volume, isCharter]);
|
||||
|
||||
useEffect(() => {
|
||||
calculateCost();
|
||||
}, [calculateCost]);
|
||||
|
||||
const handleRequestDetailedOffer = () => {
|
||||
alert("Your detailed offer request has been submitted! We will contact you soon.");
|
||||
// In a real app, this would submit data to a backend or redirect to a contact form with pre-filled details.
|
||||
};
|
||||
|
||||
const navbarNavItems = [
|
||||
{ name: "About", id: "about" },
|
||||
{ name: "Services", id: "services" },
|
||||
{ name: "Destinations", id: "destinations" },
|
||||
{ name: "Reviews", id: "reviews" },
|
||||
{ name: "Get Quote", id: "/quote-calculator" }, // New link
|
||||
{ name: "Contact", id: "contact" },
|
||||
];
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="icon-arrow"
|
||||
defaultTextAnimation="entrance-slide"
|
||||
borderRadius="rounded"
|
||||
contentWidth="medium"
|
||||
sizing="medium"
|
||||
background="none"
|
||||
cardStyle="solid"
|
||||
primaryButtonStyle="shadow"
|
||||
secondaryButtonStyle="solid"
|
||||
headingFontWeight="medium"
|
||||
>
|
||||
<ReactLenis root>
|
||||
<NavbarLayoutFloatingInline
|
||||
navItems={navbarNavItems}
|
||||
brandName="Luxuria"
|
||||
button={{ text: "Plan Your Trip", href: "#contact" }}
|
||||
/>
|
||||
|
||||
<div id="quote-calculator" data-section="quote-calculator" className="py-20 md:py-32 lg:py-40 bg-background text-foreground">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold mb-6">
|
||||
Intelligent Quote Calculator
|
||||
</h1>
|
||||
<p className="text-lg sm:text-xl text-muted-foreground mb-12">
|
||||
Get an instant estimation for your cargo shipment.
|
||||
</p>
|
||||
|
||||
<div className="bg-card p-8 rounded-lg shadow-xl space-y-6 text-left">
|
||||
{/* Input Fields */}
|
||||
<div>
|
||||
<label htmlFor="departurePort" className="block text-sm font-medium text-foreground mb-2">
|
||||
Departure Port
|
||||
</label>
|
||||
<select
|
||||
id="departurePort"
|
||||
className="block w-full p-3 border border-border rounded-md bg-input focus:outline-none focus:ring-2 focus:ring-primary-cta"
|
||||
value={departurePort}
|
||||
onChange={(e) => setDeparturePort(e.target.value)}
|
||||
>
|
||||
<option value="">Select Departure Port</option>
|
||||
<option value="Shanghai">Shanghai</option>
|
||||
<option value="Rotterdam">Rotterdam</option>
|
||||
<option value="New York">New York</option>
|
||||
<option value="Dubai">Dubai</option>
|
||||
<option value="Singapore">Singapore</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="arrivalPort" className="block text-sm font-medium text-foreground mb-2">
|
||||
Arrival Port
|
||||
</label>
|
||||
<select
|
||||
id="arrivalPort"
|
||||
className="block w-full p-3 border border-border rounded-md bg-input focus:outline-none focus:ring-2 focus:ring-primary-cta"
|
||||
value={arrivalPort}
|
||||
onChange={(e) => setArrivalPort(e.target.value)}
|
||||
>
|
||||
<option value="">Select Arrival Port</option>
|
||||
<option value="Shanghai">Shanghai</option>
|
||||
<option value="Rotterdam">Rotterdam</option>
|
||||
<option value="New York">New York</option>
|
||||
<option value="Dubai">Dubai</option>
|
||||
<option value="Singapore">Singapore</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="cargoType" className="block text-sm font-medium text-foreground mb-2">
|
||||
Cargo Type
|
||||
</label>
|
||||
<select
|
||||
id="cargoType"
|
||||
className="block w-full p-3 border border-border rounded-md bg-input focus:outline-none focus:ring-2 focus:ring-primary-cta"
|
||||
value={cargoType}
|
||||
onChange={(e) => setCargoType(e.target.value)}
|
||||
>
|
||||
<option value="">Select Cargo Type</option>
|
||||
<option value="General">General Cargo</option>
|
||||
<option value="Perishable">Perishable Goods</option>
|
||||
<option value="Hazardous">Hazardous Materials</option>
|
||||
<option value="Fragile">Fragile Items</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label htmlFor="weight" className="block text-sm font-medium text-foreground mb-2">
|
||||
Weight (kg)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="weight"
|
||||
className="block w-full p-3 border border-border rounded-md bg-input focus:outline-none focus:ring-2 focus:ring-primary-cta"
|
||||
value={weight}
|
||||
onChange={(e) => setWeight(parseFloat(e.target.value))}
|
||||
min="0"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="volume" className="block text-sm font-medium text-foreground mb-2">
|
||||
Volume (CBM)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="volume"
|
||||
className="block w-full p-3 border border-border rounded-md bg-input focus:outline-none focus:ring-2 focus:ring-primary-cta"
|
||||
value={volume}
|
||||
onChange={(e) => setVolume(parseFloat(e.target.value))}
|
||||
min="0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="isCharter"
|
||||
className="h-5 w-5 text-primary-cta rounded border-border focus:ring-primary-cta"
|
||||
checked={isCharter}
|
||||
onChange={(e) => setIsCharter(e.target.checked)}
|
||||
/>
|
||||
<label htmlFor="isCharter" className="text-sm font-medium text-foreground">
|
||||
Charter Option (Full Vessel)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Instant Cost Estimation */}
|
||||
<div className="mt-8 pt-6 border-t border-border">
|
||||
<h3 className="text-2xl font-bold text-foreground mb-4">
|
||||
Estimated Cost:
|
||||
</h3>
|
||||
<p className="text-4xl font-extrabold text-primary-cta">
|
||||
${estimatedCost.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Request Detailed Offer Button */}
|
||||
<div className="mt-8 text-center">
|
||||
<button
|
||||
onClick={handleRequestDetailedOffer}
|
||||
className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 h-10 px-4 py-2 bg-primary-cta text-primary-cta-foreground hover:bg-primary-cta/90"
|
||||
>
|
||||
Request Detailed Offer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FooterCard
|
||||
logoText="Luxuria"
|
||||
copyrightText="© 2025 Luxuria Travel | Luxury Journeys Worldwide"
|
||||
socialLinks={[
|
||||
{ icon: Instagram, href: "#", ariaLabel: "Instagram" },
|
||||
{ icon: Facebook, href: "#", ariaLabel: "Facebook" },
|
||||
{ icon: Linkedin, href: "#", ariaLabel: "LinkedIn" },
|
||||
]}
|
||||
/>
|
||||
</ReactLenis>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user