new login screen added

This commit is contained in:
laxman h 2026-04-22 18:27:19 +05:30
parent 6c7640737e
commit 26604fd7d1
6 changed files with 345 additions and 651 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

View File

@ -1,14 +1,10 @@
import { useState, useEffect } from 'react';
import { Button } from '../ui/button';
import { Input } from '../ui/input';
import { Label } from '../ui/label';
import { Textarea } from '../ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
import { RadioGroup, RadioGroupItem } from '../ui/radio-group';
import { Checkbox } from '../ui/checkbox';
import { CheckCircle, Users, Star, LogIn, Award, TrendingUp, Handshake } from 'lucide-react';
import { LogIn, ChevronRight, ChevronDown } from 'lucide-react';
import { toast } from 'sonner';
// import backgroundImage from 'figma:asset/ee01d864b6e23a8197b42f3168c98eedec9d2440.png';
import { onboardingService } from '../../services/onboarding.service';
import { masterService } from '../../services/master.service';
@ -18,7 +14,7 @@ interface ApplicationFormPageProps {
export function ApplicationFormPage({ onAdminLogin }: ApplicationFormPageProps) {
const [formData, setFormData] = useState({
country: 'India', // Default to India
country: 'India',
stateId: '',
districtId: '',
name: '',
@ -38,19 +34,16 @@ export function ApplicationFormPage({ onAdminLogin }: ApplicationFormPageProps)
acceptTerms: false
});
const [otpVerified, setOtpVerified] = useState(false);
const [states, setStates] = useState<any[]>([]);
const [districts, setDistricts] = useState<any[]>([]);
const [fetchingStates, setFetchingStates] = useState(false);
const [fetchingDistricts, setFetchingDistricts] = useState(false);
useEffect(() => {
fetchStates();
}, []);
const fetchStates = async () => {
setFetchingStates(true);
try {
// ZoneID is optional, public API should return all states if no zone override
const response: any = await masterService.getStates();
if (response && response.data) {
setStates(response.data);
@ -59,40 +52,36 @@ export function ApplicationFormPage({ onAdminLogin }: ApplicationFormPageProps)
}
} catch (error) {
console.error('Error fetching states:', error);
toast.error('Failed to load states. Please refresh the page.');
} finally {
setFetchingStates(false);
}
};
const handleStateChange = async (selectedState: any) => {
if (!selectedState) return;
setFormData(prev => ({ ...prev, stateId: selectedState.id, districtId: '' }));
const handleStateChange = async (stateId: string) => {
if (!stateId) return;
setFormData(prev => ({ ...prev, stateId, districtId: '' }));
setDistricts([]);
setFetchingDistricts(true);
try {
const response: any = await masterService.getDistricts(selectedState.id);
if (response && response.data) {
setDistricts(response.data);
} else if (response && response.districts) {
setDistricts(response.districts);
}
const response: any = await masterService.getDistricts(stateId);
if (response && response.data) setDistricts(response.data);
else if (response && response.districts) setDistricts(response.districts);
} catch (error) {
console.error('Error fetching districts:', error);
toast.error('Failed to load districts.');
} finally {
setFetchingDistricts(false);
}
};
const handleVerifyMobile = () => {
if (!formData.mobile || formData.mobile.length < 10) {
toast.error('Please enter a valid mobile number');
return;
}
toast.success('OTP sent to ' + formData.mobile);
setTimeout(() => {
setOtpVerified(true);
toast.success('Mobile number verified');
}, 1500);
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Validate required fields
if (!formData.country || !formData.stateId || !formData.districtId || !formData.name ||
!formData.interestedCity || !formData.email || !formData.pincode || !formData.mobile ||
!formData.ownRoyalEnfield || !formData.age || !formData.education ||
@ -102,10 +91,9 @@ export function ApplicationFormPage({ onAdminLogin }: ApplicationFormPageProps)
return;
}
// Validate Royal Enfield model
if (formData.ownRoyalEnfield === 'yes' && !formData.royalEnfieldModel) {
toast.error('Please select your Royal Enfield model');
return;
if (!otpVerified) {
toast.error('Please verify your mobile number');
return;
}
if (!formData.acceptTerms) {
@ -119,604 +107,337 @@ export function ApplicationFormPage({ onAdminLogin }: ApplicationFormPageProps)
const stateName = selectedState?.name || selectedState?.stateName || '';
const districtName = selectedDistrict?.name || selectedDistrict?.districtName || '';
// Map form data to backend expected format
const payload = {
applicantName: formData.name,
email: formData.email,
phone: formData.mobile,
state: stateName,
city: formData.interestedCity, // Or district?
district: districtName, // Backward compatibility
city: formData.interestedCity,
district: districtName,
preferredLocation: `${formData.interestedCity}, ${stateName}`,
businessType: 'Dealership', // Default or derived
businessType: 'Dealership',
locationType: 'district',
locationId: formData.districtId,
address: formData.address, // Need backend support?
pincode: formData.pincode, // Need backend support?
address: formData.address,
pincode: formData.pincode,
age: formData.age,
education: formData.education,
companyName: formData.companyName,
source: formData.source,
existingDealer: formData.existingDealer,
ownRoyalEnfield: formData.ownRoyalEnfield,
existingDealer: formData.existingDealer === 'yes',
ownRoyalEnfield: formData.ownRoyalEnfield === 'yes',
royalEnfieldModel: formData.royalEnfieldModel,
description: formData.description,
// flexible fields for now
experienceYears: 0, // Not in form
investmentCapacity: 'Unknown' // Not in form
experienceYears: 0,
investmentCapacity: 'Unknown'
};
await onboardingService.submitApplication(payload);
toast.success('Application submitted successfully! We will contact you soon.');
toast.success('Application submitted successfully');
// Reset form
setFormData({
country: 'India', stateId: '', districtId: '', name: '', interestedCity: '',
email: '', pincode: '', mobile: '', ownRoyalEnfield: '', royalEnfieldModel: '',
age: '', education: '', companyName: '', source: '', existingDealer: '',
description: '', address: '', acceptTerms: false
});
setOtpVerified(false);
} catch (error: any) {
toast.error(error.response?.data?.message || 'Failed to submit application.');
}
};
const reModels = [
"Classic 650", "Scram 440", "Goan Classic 350", "Bear 650", "Guerrilla 450",
"Shotgun 650", "Himalayan 450", "Bullet 350", "Super Meteor 650", "Hunter 350",
"Scram 411", "Meteor 350", "Interceptor INT 650", "Continental GT 650",
"Classic 350", "Other Royal Enfield motorcycle"
];
const sourceOptions = [
"Existing RE dealer", "Customer", "RE Employee", "News Paper", "Website", "Friends", "Others"
];
return (
<div className="min-h-screen bg-slate-950">
{/* Header */}
<header className="bg-black/90 backdrop-blur-md border-b border-amber-500/20 sticky top-0 z-50 shadow-xl">
<div className="max-w-7xl mx-auto px-6 py-5 flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-gradient-to-br from-amber-500 to-orange-600 rounded-lg flex items-center justify-center shadow-lg">
<span className="text-white text-xl">RE</span>
</div>
<div>
<h1 className="text-white text-2xl tracking-tight">Royal Enfield</h1>
<p className="text-amber-400/80 text-xs tracking-wide uppercase">Dealer Partnership Portal</p>
</div>
</div>
<Button
variant="outline"
onClick={onAdminLogin}
className="flex items-center gap-2 bg-white/5 border-amber-500/30 text-amber-400 hover:bg-amber-500/10 hover:border-amber-500/50 hover:text-amber-300 transition-all"
>
<LogIn className="w-4 h-4" />
Admin Login
</Button>
</div>
</header>
<div className="min-h-screen relative flex flex-col font-['Montserrat']">
{/* Background Image Wrapper */}
<div className="fixed inset-0 z-0">
<img
src="/assets/images/become_a_dealer.webp"
alt="Royal Enfield Background"
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-black/20" />
</div>
{/* Hero Section */}
<section className="relative py-24 overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950"></div>
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top_right,rgba(251,191,36,0.1),transparent_50%)]"></div>
<div className="absolute inset-0 bg-[radial-gradient(circle_at_bottom_left,rgba(251,146,60,0.1),transparent_50%)]"></div>
{/* Navigation Header */}
<nav className="relative z-10 bg-black px-6 md:px-12 py-4 flex items-center justify-between border-b border-white/10">
<img src="/assets/images/Re_Logo.png" alt="Royal Enfield" className="h-10 md:h-12 w-auto" />
<Button variant="ghost" onClick={onAdminLogin} className="text-[10px] uppercase tracking-widest font-bold text-slate-400 hover:text-white transition-colors">
<LogIn className="w-3.5 h-3.5 mr-2" />
Login
</Button>
</nav>
<div className="max-w-7xl mx-auto px-6 text-center relative z-10">
<div className="inline-block mb-6">
<div className="bg-amber-500/10 border border-amber-500/30 rounded-full px-6 py-2">
<p className="text-amber-400 text-sm tracking-wide">Since 1901 Legacy of Excellence</p>
</div>
</div>
<h1 className="text-5xl md:text-6xl text-white mb-6 tracking-tight">
Join the Royal Enfield
<span className="block text-transparent bg-clip-text bg-gradient-to-r from-amber-400 to-orange-500">
Partnership Network
</span>
</h1>
<p className="text-slate-300 text-lg md:text-xl max-w-3xl mx-auto mb-12 leading-relaxed">
Become part of our legendary heritage and bring the spirit of Pure Motorcycling to riders in your community
</p>
<div className="flex flex-wrap justify-center gap-8">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-amber-500/20 flex items-center justify-center">
<CheckCircle className="w-5 h-5 text-amber-400" />
</div>
<span className="text-slate-200">120+ Year Heritage</span>
</div>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-amber-500/20 flex items-center justify-center">
<CheckCircle className="w-5 h-5 text-amber-400" />
</div>
<span className="text-slate-200">Global Recognition</span>
</div>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-amber-500/20 flex items-center justify-center">
<CheckCircle className="w-5 h-5 text-amber-400" />
</div>
<span className="text-slate-200">Premium Support</span>
</div>
</div>
</div>
</section>
{/* Main Content Area over the background */}
<main className="relative z-10 flex-grow flex flex-col items-center pt-24 pb-24 px-6">
{/* Content Container with white background */}
<div className="w-full max-w-[1240px] bg-white shadow-2xl p-8 md:p-16">
{/* Why Partner Section */}
<section className="py-20 bg-slate-900/50">
<div className="max-w-7xl mx-auto px-6">
<div className="text-center mb-16">
<h2 className="text-4xl text-white mb-4">Why Partner With Royal Enfield?</h2>
<p className="text-slate-400 text-lg">Unmatched benefits for ambitious entrepreneurs</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{/* Premium Brand */}
<div className="group relative bg-gradient-to-br from-slate-800/50 to-slate-900/50 backdrop-blur border border-slate-700/50 rounded-2xl p-8 text-center hover:border-amber-500/50 transition-all duration-300 hover:shadow-2xl hover:shadow-amber-500/10">
<div className="w-16 h-16 bg-gradient-to-br from-amber-500 to-orange-600 rounded-2xl flex items-center justify-center mx-auto mb-6 group-hover:scale-110 transition-transform shadow-lg">
<Star className="w-8 h-8 text-white" />
</div>
<h3 className="text-white text-xl mb-3">Premium Brand</h3>
<p className="text-slate-400 text-sm leading-relaxed">
Represent a legendary brand trusted by millions worldwide since 1901
{/* Introductory Text */}
<section className="text-[#333333] mb-12">
<h1 className="text-[28px] font-bold mb-8 uppercase tracking-wide text-black">Become a Dealer</h1>
<div className="space-y-6 text-[15px] leading-relaxed">
<p>
At Royal Enfield, we endeavour to partner our patrons and customers in their journeys of exploration. Our main objective is to provide an immersive brand and retail experience in addition to ensuring a superior product experience. Our dealers, distributors and network teams are our extended partners in this task.
</p>
<p>
Royal Enfield employs a comprehensive and professional process for Dealership allotment. Dealer selection is done based on a variety of criteria including a personal meeting with the applicant. It is only post completion of the evaluation and selection process, that other formalities are considered.
</p>
<p>
Royal Enfield does not accept or demand money / deposits from prospective partners prior to processing the application or candidature of the Dealership.
</p>
<p>
If you receive any communication offering allotment of Royal Enfield Dealership against payment / transfer of money and / or otherwise, we advise you to seek information / clarifications by writing to us at <b><a href="mailto:support@royalenfield.com" className="text-red-600">support@royalenfield.com</a></b> or by contacting us on our customer care toll-free number <b><a href="tel:18002100008" className="text-red-600">1800 210 0008</a></b>.
</p>
<p className="font-bold py-1 mt-8 text-black text-[15px]">
*This is the ONLY official website and central number for dealership enquiries for Royal Enfield and we do not have any other partner website(s).
</p>
</div>
</section>
{/* Strong Support */}
<div className="group relative bg-gradient-to-br from-slate-800/50 to-slate-900/50 backdrop-blur border border-slate-700/50 rounded-2xl p-8 text-center hover:border-amber-500/50 transition-all duration-300 hover:shadow-2xl hover:shadow-amber-500/10">
<div className="w-16 h-16 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-2xl flex items-center justify-center mx-auto mb-6 group-hover:scale-110 transition-transform shadow-lg">
<Handshake className="w-8 h-8 text-white" />
</div>
<h3 className="text-white text-xl mb-3">Complete Support</h3>
<p className="text-slate-400 text-sm leading-relaxed">
Comprehensive training, marketing, and ongoing operational support
</p>
</div>
{/* Growth Opportunity */}
<div className="group relative bg-gradient-to-br from-slate-800/50 to-slate-900/50 backdrop-blur border border-slate-700/50 rounded-2xl p-8 text-center hover:border-amber-500/50 transition-all duration-300 hover:shadow-2xl hover:shadow-amber-500/10">
<div className="w-16 h-16 bg-gradient-to-br from-emerald-500 to-teal-600 rounded-2xl flex items-center justify-center mx-auto mb-6 group-hover:scale-110 transition-transform shadow-lg">
<TrendingUp className="w-8 h-8 text-white" />
</div>
<h3 className="text-white text-xl mb-3">Growth Potential</h3>
<p className="text-slate-400 text-sm leading-relaxed">
Tap into expanding markets with increasing customer demand
</p>
</div>
{/* Proven Success */}
<div className="group relative bg-gradient-to-br from-slate-800/50 to-slate-900/50 backdrop-blur border border-slate-700/50 rounded-2xl p-8 text-center hover:border-amber-500/50 transition-all duration-300 hover:shadow-2xl hover:shadow-amber-500/10">
<div className="w-16 h-16 bg-gradient-to-br from-purple-500 to-pink-600 rounded-2xl flex items-center justify-center mx-auto mb-6 group-hover:scale-110 transition-transform shadow-lg">
<Award className="w-8 h-8 text-white" />
</div>
<h3 className="text-white text-xl mb-3">Proven Model</h3>
<p className="text-slate-400 text-sm leading-relaxed">
Join thousands of successful dealers in our global network
</p>
</div>
</div>
</div>
</section>
{/* Application Form Section */}
<section className="relative py-24 overflow-hidden">
{/* Background Image with Overlay */}
<div className="absolute inset-0">
<div className="absolute inset-0 bg-gradient-to-br from-slate-950/95 via-slate-900/90 to-slate-950/95 backdrop-blur-sm"></div>
</div>
<div className="max-w-4xl mx-auto px-6 relative z-10">
<div className="text-center mb-12">
<div className="inline-block mb-4">
<div className="bg-amber-500/10 border border-amber-500/30 rounded-full px-5 py-2">
<p className="text-amber-400 text-sm tracking-wide">Start Your Journey</p>
</div>
</div>
<h2 className="text-4xl text-white mb-4">Dealership Application</h2>
<p className="text-slate-300 text-lg">
Complete the form below to begin your partnership with Royal Enfield
</p>
</div>
<form onSubmit={handleSubmit} className="bg-slate-900/60 backdrop-blur-xl rounded-3xl border border-slate-700/50 p-10 shadow-2xl">
<div className="space-y-7">
{/* Name & Email */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<Label htmlFor="name" className="flex items-center gap-2 text-slate-200 mb-3">
<Users className="w-4 h-4 text-amber-400" />
Full Name <span className="text-amber-500">*</span>
</Label>
<Input
id="name"
placeholder="Enter your full name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
required
/>
</div>
<div>
<Label htmlFor="email" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400"></span>
Email Address <span className="text-amber-500">*</span>
</Label>
<Input
id="email"
type="email"
placeholder="your-email@example.com"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
required
/>
</div>
</div>
{/* Mobile & Age */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<Label htmlFor="mobile" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">📱</span>
Mobile Number <span className="text-amber-500">*</span>
</Label>
<Input
id="mobile"
type="tel"
placeholder="+91 98765 43210"
value={formData.mobile}
onChange={(e) => setFormData({ ...formData, mobile: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
required
/>
</div>
<div>
<Label htmlFor="age" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">👤</span>
Age <span className="text-amber-500">*</span>
</Label>
<Input
id="age"
type="number"
placeholder="Enter your age"
value={formData.age}
onChange={(e) => setFormData({ ...formData, age: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
required
/>
</div>
</div>
{/* Country, State, District */}
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-6">
{/* Country Selection */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<Label htmlFor="country" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">🌍</span>
Country <span className="text-amber-500">*</span>
</Label>
<Select value={formData.country} onValueChange={(value) => setFormData({ ...formData, country: value })} disabled>
<SelectTrigger className="bg-slate-800/50 border-slate-600/50 text-white focus:border-amber-500/50 focus:ring-amber-500/20 disabled:opacity-70 disabled:cursor-not-allowed">
<SelectValue placeholder="Select country" />
</SelectTrigger>
<SelectContent className="bg-slate-800 border-slate-700 text-white">
<SelectItem value="India">India</SelectItem>
<SelectItem value="Nepal">Nepal</SelectItem>
<SelectItem value="Bangladesh">Bangladesh</SelectItem>
<SelectItem value="Sri Lanka">Sri Lanka</SelectItem>
</SelectContent>
</Select>
<div className="relative">
<select
className="w-full h-[44px] px-4 border border-[#cccccc] appearance-none bg-white text-[14px] outline-none"
value={formData.country}
onChange={(e) => setFormData({...formData, country: e.target.value})}
>
<option value="India">India</option>
<option value="Other">Others</option>
</select>
<ChevronDown className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500 pointer-events-none" />
</div>
<div>
<Label htmlFor="state" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">🏛</span>
State <span className="text-amber-500">*</span>
</Label>
<Select
<div className="relative">
<select
className="w-full h-[44px] px-4 border border-[#cccccc] appearance-none bg-white text-[14px] outline-none"
value={formData.stateId}
onValueChange={(value) => {
const selectedState = states.find((s: any) => s.id === value);
handleStateChange(selectedState);
}}
disabled={fetchingStates}
onChange={(e) => handleStateChange(e.target.value)}
>
<SelectTrigger className="bg-slate-800/50 border-slate-600/50 text-white focus:border-amber-500/50 focus:ring-amber-500/20">
<SelectValue placeholder={fetchingStates ? "Loading states..." : "Select state"} />
</SelectTrigger>
<SelectContent className="bg-slate-800 border-slate-700 text-white h-64">
{states.map((state: any) => (
<SelectItem key={state.id} value={state.id}>
{state.name || state.stateName}
</SelectItem>
))}
</SelectContent>
</Select>
<option value="">Select State*</option>
{states.map(s => <option key={s.id} value={s.id}>{s.name || s.stateName}</option>)}
</select>
<ChevronDown className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500 pointer-events-none" />
</div>
<div>
<Label htmlFor="district" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">📍</span>
District <span className="text-amber-500">*</span>
</Label>
<Select
<div className="relative">
<select
className="w-full h-[44px] px-4 border border-[#cccccc] appearance-none bg-white text-[14px] outline-none"
value={formData.districtId}
onValueChange={(value) => setFormData({ ...formData, districtId: value })}
disabled={!formData.stateId || fetchingDistricts}
onChange={(e) => setFormData({...formData, districtId: e.target.value})}
>
<SelectTrigger className="bg-slate-800/50 border-slate-600/50 text-white focus:border-amber-500/50 focus:ring-amber-500/20">
<SelectValue placeholder={fetchingDistricts ? "Loading districts..." : "Select district"} />
</SelectTrigger>
<SelectContent className="bg-slate-800 border-slate-700 text-white h-64">
{districts.map((district: any) => (
<SelectItem key={district.id} value={district.id}>
{district.name || district.districtName}
</SelectItem>
))}
</SelectContent>
</Select>
<option value="">Select District*</option>
{districts.map(d => <option key={d.id} value={d.id}>{d.name || d.districtName}</option>)}
</select>
<ChevronDown className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500 pointer-events-none" />
</div>
</div>
{/* Interested City & Pincode */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<Label htmlFor="interestedCity" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">🏙</span>
Interested City for Dealership <span className="text-amber-500">*</span>
</Label>
{/* Personal Details - Two Column */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-10 gap-y-6">
<Input
placeholder="Name*"
className="h-[44px] border-[#cccccc] rounded-none px-4 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999]"
value={formData.name}
onChange={(e) => setFormData({...formData, name: e.target.value})}
/>
<Input
placeholder="Interested city for Dealership*"
className="h-[44px] border-[#cccccc] rounded-none px-4 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999]"
value={formData.interestedCity}
onChange={(e) => setFormData({...formData, interestedCity: e.target.value})}
/>
<Input
placeholder="Email Id*"
className="h-[44px] border-[#cccccc] rounded-none px-4 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999]"
value={formData.email}
onChange={(e) => setFormData({...formData, email: e.target.value})}
/>
<Input
placeholder="Pincode*"
className="h-[44px] border-[#cccccc] rounded-none px-4 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999]"
value={formData.pincode}
onChange={(e) => setFormData({...formData, pincode: e.target.value})}
/>
<div className="relative">
<Input
id="interestedCity"
placeholder="Enter city name"
value={formData.interestedCity}
onChange={(e) => setFormData({ ...formData, interestedCity: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
required
placeholder="Mobile No.*"
className="h-[44px] border-[#cccccc] rounded-none px-4 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999]"
value={formData.mobile}
onChange={(e) => setFormData({...formData, mobile: e.target.value})}
/>
{!otpVerified ? (
<button
type="button"
onClick={handleVerifyMobile}
className="absolute right-4 top-1/2 -translate-y-1/2 text-[12px] font-bold text-red-600 hover:text-black transition-colors"
>
Verify
</button>
) : (
<span className="absolute right-4 top-1/2 -translate-y-1/2 text-[12px] font-bold text-green-600">Verified</span>
)}
</div>
<div>
<Label htmlFor="pincode" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">📮</span>
Pincode <span className="text-amber-500">*</span>
</Label>
<Input
id="pincode"
type="text"
placeholder="Enter pincode"
value={formData.pincode}
onChange={(e) => setFormData({ ...formData, pincode: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
required
/>
</div>
</div>
{/* Education & Company Name */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<Label htmlFor="education" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">🎓</span>
Education Qualification <span className="text-amber-500">*</span>
</Label>
<Select value={formData.education} onValueChange={(value) => setFormData({ ...formData, education: value })}>
<SelectTrigger className="bg-slate-800/50 border-slate-600/50 text-white focus:border-amber-500/50 focus:ring-amber-500/20">
<SelectValue placeholder="Select qualification" />
</SelectTrigger>
<SelectContent className="bg-slate-800 border-slate-700 text-white">
<SelectItem value="high-school">High School</SelectItem>
<SelectItem value="diploma">Diploma</SelectItem>
<SelectItem value="bachelors">Bachelor's Degree</SelectItem>
<SelectItem value="masters">Master's Degree</SelectItem>
<SelectItem value="doctorate">Doctorate</SelectItem>
<SelectItem value="other">Other</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="companyName" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">🏢</span>
Company Name <span className="text-amber-500">*</span>
</Label>
<Input
id="companyName"
placeholder="Enter company name"
value={formData.companyName}
onChange={(e) => setFormData({ ...formData, companyName: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
required
/>
</div>
</div>
{/* Source */}
<div>
<Label htmlFor="source" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">📢</span>
How did you hear about us? <span className="text-amber-500">*</span>
</Label>
<Select value={formData.source} onValueChange={(value) => setFormData({ ...formData, source: value })}>
<SelectTrigger className="bg-slate-800/50 border-slate-600/50 text-white focus:border-amber-500/50 focus:ring-amber-500/20">
<SelectValue placeholder="Select source" />
</SelectTrigger>
<SelectContent className="bg-slate-800 border-slate-700 text-white">
<SelectItem value="existing-dealer">Existing RE Dealer</SelectItem>
<SelectItem value="customer">Customer</SelectItem>
<SelectItem value="re-employee">RE Employee</SelectItem>
<SelectItem value="newspaper">Newspaper</SelectItem>
<SelectItem value="website">Website</SelectItem>
<SelectItem value="friend">Friend</SelectItem>
<SelectItem value="other">Other</SelectItem>
</SelectContent>
</Select>
</div>
{/* Do you own a Royal Enfield? */}
<div>
<Label className="flex items-center gap-2 text-slate-200 mb-4">
<span className="text-amber-400">🏍</span>
Do you own a Royal Enfield? <span className="text-amber-500">*</span>
</Label>
<RadioGroup value={formData.ownRoyalEnfield} onValueChange={(value) => setFormData({ ...formData, ownRoyalEnfield: value, royalEnfieldModel: value === 'no' ? '' : formData.royalEnfieldModel })}>
<div className="flex items-center space-x-8">
<div className="flex items-center space-x-3">
<RadioGroupItem value="yes" id="own-yes" className="border-amber-400/60 hover:border-amber-400 data-[state=checked]:border-amber-500 data-[state=checked]:bg-amber-500/20" />
<Label htmlFor="own-yes" className="cursor-pointer text-slate-200 hover:text-amber-300">Yes</Label>
<div className="flex items-center gap-10 h-[44px]">
<span className="text-[14px] font-medium text-[#333333]">Own a Royal Enfield?</span>
<div className="flex gap-8">
{['yes', 'no'].map(val => (
<label key={val} className="flex items-center gap-2 cursor-pointer">
<div className={`w-5 h-5 rounded-full border flex items-center justify-center ${formData.ownRoyalEnfield === val ? 'border-red-600' : 'border-[#cccccc]'}`}>
{formData.ownRoyalEnfield === val && <div className="w-2.5 h-2.5 rounded-full bg-red-600" />}
</div>
<input
type="radio"
className="hidden"
checked={formData.ownRoyalEnfield === val}
onChange={() => setFormData({...formData, ownRoyalEnfield: val})}
/>
<span className="text-[14px] capitalize">{val}</span>
</label>
))}
</div>
<div className="flex items-center space-x-3">
<RadioGroupItem value="no" id="own-no" className="border-amber-400/60 hover:border-amber-400 data-[state=checked]:border-amber-500 data-[state=checked]:bg-amber-500/20" />
<Label htmlFor="no" className="cursor-pointer text-slate-200 hover:text-amber-300">No</Label>
</div>
</div>
</RadioGroup>
</div>
{/* Royal Enfield Model - Conditional */}
{formData.ownRoyalEnfield === 'yes' && (
<div className="animate-in fade-in slide-in-from-top-2 duration-300">
<Label htmlFor="royalEnfieldModel" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">🏍</span>
Which Royal Enfield model do you own? <span className="text-amber-500">*</span>
</Label>
<Select value={formData.royalEnfieldModel} onValueChange={(value) => setFormData({ ...formData, royalEnfieldModel: value })}>
<SelectTrigger className="bg-slate-800/50 border-slate-600/50 text-white focus:border-amber-500/50 focus:ring-amber-500/20">
<SelectValue placeholder="Select your bike model" />
</SelectTrigger>
<SelectContent className="bg-slate-800 border-slate-700 text-white">
<SelectItem value="classic-350">Classic 350</SelectItem>
<SelectItem value="meteor-350">Meteor 350</SelectItem>
<SelectItem value="hunter-350">Hunter 350</SelectItem>
<SelectItem value="bullet-350">Bullet 350</SelectItem>
<SelectItem value="himalayan">Himalayan</SelectItem>
<SelectItem value="scram-411">Scram 411</SelectItem>
<SelectItem value="interceptor-650">Interceptor 650</SelectItem>
<SelectItem value="continental-gt-650">Continental GT 650</SelectItem>
<SelectItem value="super-meteor-650">Super Meteor 650</SelectItem>
<SelectItem value="shotgun-650">Shotgun 650</SelectItem>
<SelectItem value="himalayan-450">Himalayan 450</SelectItem>
<SelectItem value="other">Other</SelectItem>
</SelectContent>
</Select>
</div>
)}
{/* Existing Dealer/Vendor */}
<div>
<Label className="flex items-center gap-2 text-slate-200 mb-4">
<span className="text-amber-400">🏪</span>
Are you an existing dealer/vendor of Royal Enfield? <span className="text-amber-500">*</span>
</Label>
<RadioGroup value={formData.existingDealer} onValueChange={(value) => setFormData({ ...formData, existingDealer: value })}>
<div className="flex items-center space-x-8">
<div className="flex items-center space-x-3">
<RadioGroupItem value="yes" id="dealer-yes" className="border-amber-400/60 hover:border-amber-400 data-[state=checked]:border-amber-500 data-[state=checked]:bg-amber-500/20" />
<Label htmlFor="dealer-yes" className="cursor-pointer text-slate-200 hover:text-amber-300">Yes</Label>
<Input
placeholder="Age*"
className="h-[44px] border-[#cccccc] rounded-none px-4 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999]"
value={formData.age}
onChange={(e) => setFormData({...formData, age: e.target.value})}
/>
<div className="relative">
<select
className="w-full h-[44px] px-4 border border-[#cccccc] appearance-none bg-white text-[14px] outline-none disabled:bg-slate-50"
value={formData.royalEnfieldModel}
disabled={formData.ownRoyalEnfield !== 'yes'}
onChange={(e) => setFormData({...formData, royalEnfieldModel: e.target.value})}
>
<option value="">Motorcycle Owned</option>
{reModels.map(m => <option key={m} value={m}>{m}</option>)}
</select>
<ChevronDown className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500 pointer-events-none" />
</div>
<Input
placeholder="Education Qualification*"
className="h-[44px] border-[#cccccc] rounded-none px-4 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999]"
value={formData.education}
onChange={(e) => setFormData({...formData, education: e.target.value})}
/>
<Input
placeholder="Company Name*"
className="h-[44px] border-[#cccccc] rounded-none px-4 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999]"
value={formData.companyName}
onChange={(e) => setFormData({...formData, companyName: e.target.value})}
/>
<div className="relative">
<select
className="w-full h-[44px] px-4 border border-[#cccccc] appearance-none bg-white text-[14px] outline-none"
value={formData.source}
onChange={(e) => setFormData({...formData, source: e.target.value})}
>
<option value="">Select Source</option>
{sourceOptions.map(s => <option key={s} value={s}>{s}</option>)}
</select>
<ChevronDown className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500 pointer-events-none" />
</div>
<div className="flex flex-col justify-center h-auto min-h-[44px] space-y-1">
<span className="text-[13px] font-medium text-[#333333]">Are you an existing Dealer / Vendor of Royal Enfield?</span>
<div className="flex gap-8">
{['yes', 'no'].map(val => (
<label key={val} className="flex items-center gap-2 cursor-pointer">
<div className={`w-5 h-5 rounded-full border flex items-center justify-center ${formData.existingDealer === val ? 'border-red-600' : 'border-[#cccccc]'}`}>
{formData.existingDealer === val && <div className="w-2.5 h-2.5 rounded-full bg-red-600" />}
</div>
<input
type="radio"
className="hidden"
checked={formData.existingDealer === val}
onChange={() => setFormData({...formData, existingDealer: val})}
/>
<span className="text-[14px] capitalize">{val}</span>
</label>
))}
</div>
<div className="flex items-center space-x-3">
<RadioGroupItem value="no" id="dealer-no" className="border-amber-400/60 hover:border-amber-400 data-[state=checked]:border-amber-500 data-[state=checked]:bg-amber-500/20" />
<Label htmlFor="dealer-no" className="cursor-pointer text-slate-200 hover:text-amber-300">No</Label>
</div>
</div>
</RadioGroup>
</div>
</div>
{/* Address */}
<div>
<Label htmlFor="address" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">🏠</span>
Address <span className="text-amber-500">*</span>
</Label>
{/* Full Width Text Areas */}
<div className="space-y-6 pt-4">
<Textarea
id="address"
placeholder="Enter your complete address including landmarks"
value={formData.address}
onChange={(e) => setFormData({ ...formData, address: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
rows={3}
required
placeholder="Description*"
className="min-h-[120px] border-[#cccccc] rounded-none px-4 py-3 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999] resize-none"
value={formData.description}
onChange={(e) => setFormData({...formData, description: e.target.value})}
/>
</div>
{/* Description */}
<div>
<Label htmlFor="description" className="flex items-center gap-2 text-slate-200 mb-3">
<span className="text-amber-400">📝</span>
Description <span className="text-amber-500">*</span>
</Label>
<Textarea
id="description"
placeholder="Tell us about your business background, experience, and why you want to become a Royal Enfield dealer..."
value={formData.description}
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
className="bg-slate-800/50 border-slate-600/50 text-white placeholder:text-slate-500 focus:border-amber-500/50 focus:ring-amber-500/20"
rows={5}
required
placeholder="Address*"
className="min-h-[120px] border-[#cccccc] rounded-none px-4 py-3 text-[14px] focus-visible:ring-1 focus-visible:ring-black placeholder:text-[#999999] resize-none"
value={formData.address}
onChange={(e) => setFormData({...formData, address: e.target.value})}
/>
</div>
{/* Terms and Conditions */}
<div className="flex items-start space-x-3 bg-slate-800/30 p-5 rounded-xl border border-slate-700/50">
<Checkbox
id="terms"
checked={formData.acceptTerms}
onCheckedChange={(checked) => setFormData({ ...formData, acceptTerms: checked as boolean })}
className="border-slate-600 data-[state=checked]:bg-amber-500 data-[state=checked]:border-amber-500 mt-0.5"
/>
<div className="flex-1">
<Label htmlFor="terms" className="cursor-pointer text-slate-200">
I accept the terms and conditions <span className="text-amber-500">*</span>
</Label>
<p className="text-slate-400 text-xs mt-2 leading-relaxed">
By submitting this form, you agree to our privacy policy and terms of service.
We will use your information to process your dealership application.
</p>
{/* Terms & Submit */}
<div className="pt-6 space-y-8">
<div className="space-y-6">
<p className="text-[14px] text-[#666666] leading-relaxed">
Disclaimer: By signing this form/checking this box, you acknowledge and agree that we may use the information you share with us, to communicate with you through e-mails, text messages, WhatsApp and calls, in order to provide our product or service related information and/or for promotional and marketing purposes. All information provided will be secured and processed as per our <b>privacy policy</b>.
</p>
<div className="flex items-center gap-3">
<Checkbox
id="terms"
className="w-5 h-5 border-[#cccccc] rounded-none data-[state=checked]:bg-black data-[state=checked]:border-black"
checked={formData.acceptTerms}
onCheckedChange={(checked) => setFormData({...formData, acceptTerms: checked as boolean})}
/>
<label htmlFor="terms" className="text-[14px] font-medium cursor-pointer">
I accept the <b>terms and conditions</b> as well as <b>privacy policy</b>.
</label>
</div>
</div>
</div>
{/* Submit Button */}
<Button
type="submit"
className="w-full bg-gradient-to-r from-amber-500 to-orange-600 hover:from-amber-600 hover:to-orange-700 text-white py-6 text-lg shadow-xl shadow-amber-500/20 hover:shadow-2xl hover:shadow-amber-500/30 transition-all duration-300"
>
Submit Application
</Button>
</div>
</form>
<button
type="submit"
className="h-12 px-10 bg-black text-white flex items-center gap-3 hover:bg-slate-900 transition-colors"
>
<span className="font-bold uppercase tracking-wider text-[14px]">Submit</span>
<ChevronRight className="w-4 h-4" />
</button>
</div>
</form>
</div>
</section>
</main>
{/* Footer */}
<footer className="bg-black/90 backdrop-blur-md border-t border-slate-800 py-16">
<div className="max-w-7xl mx-auto px-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-12">
{/* About Section */}
<div>
<div className="w-12 h-12 bg-gradient-to-br from-amber-500 to-orange-600 rounded-lg flex items-center justify-center shadow-lg mb-6">
<span className="text-white text-xl">RE</span>
</div>
<p className="text-slate-400 text-sm leading-relaxed mb-4">
Since 1901, Royal Enfield has been the world's oldest motorcycle brand in continuous production,
creating timeless motorcycles that define the pure motorcycling experience.
</p>
</div>
{/* Quick Links */}
<div>
<h3 className="text-white mb-6">Quick Links</h3>
<ul className="space-y-3 text-sm">
<li><a href="#" className="text-slate-400 hover:text-amber-400 transition-colors">About Royal Enfield</a></li>
<li><a href="#" className="text-slate-400 hover:text-amber-400 transition-colors">Our Motorcycles</a></li>
<li><a href="#" className="text-slate-400 hover:text-amber-400 transition-colors">Service & Support</a></li>
<li><a href="#" className="text-slate-400 hover:text-amber-400 transition-colors">Contact Us</a></li>
</ul>
</div>
{/* Dealership & Contact */}
<div>
<h3 className="text-white mb-6">Dealership Support</h3>
<ul className="space-y-3 text-sm mb-8">
<li><a href="#" className="text-slate-400 hover:text-amber-400 transition-colors">Application Process</a></li>
<li><a href="#" className="text-slate-400 hover:text-amber-400 transition-colors">Partnership Requirements</a></li>
<li><a href="#" className="text-slate-400 hover:text-amber-400 transition-colors">Training & Support</a></li>
<li><a href="#" className="text-slate-400 hover:text-amber-400 transition-colors">FAQs</a></li>
</ul>
<div className="space-y-2 text-sm">
<p className="text-slate-400">Email: <span className="text-amber-400">dealership@royalenfield.com</span></p>
<p className="text-slate-400">Phone: <span className="text-amber-400">+91 1800-123-7567</span></p>
<p className="text-slate-500">Mon-Fri, 9:00 AM - 6:00 PM IST</p>
</div>
</div>
</div>
<div className="border-t border-slate-800 mt-12 pt-8 text-center">
<p className="text-slate-500 text-sm">
© 2024 Royal Enfield. All rights reserved. | Made like a gun, goes like a bullet.
</p>
<footer className="relative z-10 bg-black py-16">
<div className="max-w-[1240px] mx-auto px-6 grid grid-cols-1 md:grid-cols-3 items-center gap-8">
<img src="/assets/images/Re_Logo.png" alt="Royal Enfield" className="h-10 w-auto opacity-100" />
<div className="flex justify-center gap-12 text-[10px] font-bold uppercase tracking-widest text-slate-500">
<a href="#" className="hover:text-white transition-all">Legal</a>
<a href="#" className="hover:text-white transition-all">Privacy</a>
<a href="#" className="hover:text-white transition-all">Terms</a>
</div>
<p className="text-[10px] text-center md:text-right uppercase tracking-widest text-slate-500 font-bold">
© 2026 Royal Enfield. All Rights Reserved.
</p>
</div>
</footer>
</div>

View File

@ -30,7 +30,7 @@ export const ZMManagement: React.FC<ZMManagementProps> = ({
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle>Zonal Managers (ZM)</CardTitle>
<CardTitle>Zonal Managers (DD-ZM)</CardTitle>
<CardDescription>Manage Zonal Managers and their region assignments</CardDescription>
</div>
<Button onClick={onAddZM} className="bg-amber-600 hover:bg-amber-700">
@ -63,7 +63,7 @@ export const ZMManagement: React.FC<ZMManagementProps> = ({
</TableCell>
<TableCell>{zm.name}</TableCell>
<TableCell>
<div className="flex flex-wrap gap-1">
<div className="flex flex-wrap gap-1">
{(zm.zones || [zm.zoneName]).map((z: string, i: number) => (
<Badge key={i} variant="outline">{z}</Badge>
))}

View File

@ -52,33 +52,7 @@ export function ProspectiveApplicationDetails({ id, onBack }: Props) {
const [isUploading, setIsUploading] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const normalizeStatus = (value?: string) =>
String(value || '')
.toLowerCase()
.trim();
const getTimelineColorClass = (progressStatus?: string) => {
if (progressStatus === 'completed') {
return {
border: 'border-green-500',
dot: 'bg-green-500',
text: 'text-green-700'
};
}
if (progressStatus === 'active') {
return {
border: 'border-sky-500',
dot: 'bg-sky-500',
text: 'text-sky-700'
};
}
// Default and explicit pending
return {
border: 'border-amber-500',
dot: 'bg-amber-500',
text: 'text-amber-700'
};
};
// Statutory & Bank State
const emptyForm = {
@ -328,7 +302,7 @@ export function ProspectiveApplicationDetails({ id, onBack }: Props) {
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-2 space-y-6">
<div className="lg:col-span-3 space-y-6">
{/* Statutory & Bank Details Form */}
<div className="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden" data-testid="onboarding-prospective-details-statutory-card">
<div className="p-4 bg-slate-900 text-white flex justify-between items-center">
@ -551,52 +525,7 @@ export function ProspectiveApplicationDetails({ id, onBack }: Props) {
</div>
</div>
<div className="lg:col-span-1 space-y-6">
<div className="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden" data-testid="onboarding-prospective-details-timeline-card">
<div className="p-4 bg-slate-50 border-b border-slate-200">
<h3 className="text-xs font-bold text-slate-900 flex items-center gap-2 uppercase tracking-widest">
<Clock className="w-4 h-4 text-amber-600" /> Recent Updates
</h3>
</div>
<div className="p-6">
{(details.progressTracking || []).length > 0 ? (
<div className="relative space-y-6">
<div className="absolute left-[11px] top-2 bottom-4 w-0.5 bg-slate-100"></div>
{[...(details.progressTracking || [])]
.sort((a: any, b: any) => Number(a.stageOrder || 0) - Number(b.stageOrder || 0))
.map((item: any, idx: number) => {
const progressStatus = normalizeStatus(item.status);
const colorClass = getTimelineColorClass(progressStatus);
return (
<div key={item.id} className="relative pl-8 animate-in slide-in-from-left duration-300" style={{ animationDelay: `${idx * 100}ms` }} data-testid={`onboarding-prospective-details-timeline-item-${idx}`}>
<div className={`absolute left-0 top-1 w-[24px] h-[24px] rounded-full border-2 bg-white flex items-center justify-center shadow-sm ${colorClass.border}`}>
<div className={`w-1.5 h-1.5 rounded-full ${colorClass.dot}`}></div>
</div>
<div>
<p className={`text-xs font-bold uppercase tracking-tight ${colorClass.text}`} data-testid={`onboarding-prospective-details-timeline-stage-${idx}`}>{item.stageName}</p>
<p className="text-[10px] text-slate-400 font-medium">
{item.stageCompletedAt
? new Date(item.stageCompletedAt).toLocaleString('en-IN')
: item.stageStartedAt
? new Date(item.stageStartedAt).toLocaleString('en-IN')
: new Date(item.createdAt).toLocaleString('en-IN')}
</p>
<p className="text-[10px] text-slate-500 mt-1 italic leading-tight" data-testid={`onboarding-prospective-details-timeline-status-${idx}`}>
Status: {item.status || 'pending'}
</p>
</div>
</div>
);
})}
</div>
) : (
<div className="text-center py-6" data-testid="onboarding-prospective-details-timeline-empty">
<p className="text-xs text-slate-500 italic">No history available yet</p>
</div>
)}
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,3 +1,4 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Public+Sans:ital,wght@0,100..900;1,100..900&display=swap');
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@ -40,6 +41,12 @@
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
/* Royal Enfield Brand Colors */
--re-red: #DA1A32;
--re-black: #000000;
--re-white: #FFFFFF;
--re-gray: #717171;
}
.dark {
@ -127,9 +134,46 @@
body {
@apply bg-background text-foreground;
font-family: 'Montserrat', sans-serif;
}
}
/* RE Branding Utilities */
.re-heading {
font-family: 'Montserrat', sans-serif;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
}
.re-card {
@apply bg-white border border-slate-200 rounded-none shadow-sm;
}
.re-input {
@apply w-full px-4 py-3 border border-slate-300 rounded-none focus:border-red-600 focus:ring-1 focus:ring-red-600/20 outline-none transition-all duration-200 text-sm;
}
.re-label {
@apply block text-sm font-semibold text-slate-800 mb-1.5 uppercase tracking-wide;
}
.re-btn-primary {
@apply bg-black text-white px-8 py-3 font-bold uppercase tracking-widest hover:bg-slate-900 transition-all active:scale-[0.98];
}
.re-btn-outline {
@apply border-2 border-black text-black px-8 py-3 font-bold uppercase tracking-widest hover:bg-black hover:text-white transition-all active:scale-[0.98];
}
.re-intro-text {
@apply text-slate-700 leading-relaxed text-sm;
}
.re-disclaimer {
@apply bg-slate-50 border-l-4 border-red-600 p-4 text-xs italic text-slate-600;
}
/**
* Base typography. This is not applied to elements which have an ancestor with a Tailwind text class.
*/