696 lines
30 KiB
TypeScript
696 lines
30 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import Link from 'next/link';
|
|
import AdminLogo from '../../../components/AdminLogo';
|
|
import Notification from '../../../components/Notification';
|
|
|
|
interface Customer {
|
|
id: number;
|
|
name: string;
|
|
address: string;
|
|
tier: number;
|
|
}
|
|
|
|
interface Vehicle {
|
|
id: string;
|
|
make: string;
|
|
model: string;
|
|
capacity: number;
|
|
yom: number;
|
|
owner: number | null;
|
|
}
|
|
|
|
export default function AddJobPage() {
|
|
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
const router = useRouter();
|
|
|
|
// Form state
|
|
const [selectedCustomerId, setSelectedCustomerId] = useState<string>('');
|
|
const [selectedVehicleId, setSelectedVehicleId] = useState<string>('');
|
|
const [metadata, setMetadata] = useState('');
|
|
const [mileage, setMileage] = useState('');
|
|
|
|
// Search state
|
|
const [customerSearch, setCustomerSearch] = useState('');
|
|
const [vehicleSearch, setVehicleSearch] = useState('');
|
|
const [showCustomerResults, setShowCustomerResults] = useState(false);
|
|
const [showVehicleResults, setShowVehicleResults] = useState(false);
|
|
|
|
// Inline creation state
|
|
const [showAddCustomer, setShowAddCustomer] = useState(false);
|
|
const [showAddVehicle, setShowAddVehicle] = useState(false);
|
|
const [newCustomerName, setNewCustomerName] = useState('');
|
|
const [newCustomerAddress, setNewCustomerAddress] = useState('');
|
|
const [newVehicleId, setNewVehicleId] = useState('');
|
|
const [newVehicleMake, setNewVehicleMake] = useState('');
|
|
const [newVehicleModel, setNewVehicleModel] = useState('');
|
|
const [newVehicleCapacity, setNewVehicleCapacity] = useState('');
|
|
const [newVehicleYom, setNewVehicleYom] = useState('');
|
|
|
|
// Mock data - replace with API calls
|
|
const [customers, setCustomers] = useState<Customer[]>([]);
|
|
const [vehicles, setVehicles] = useState<Vehicle[]>([]);
|
|
|
|
// Notification state
|
|
const [notification, setNotification] = useState<{ message: string; type: 'success' | 'error' | 'info' } | null>(null);
|
|
|
|
useEffect(() => {
|
|
const adminLoggedIn = sessionStorage.getItem('adminLoggedIn');
|
|
if (adminLoggedIn !== 'true') {
|
|
router.push('/admin');
|
|
return;
|
|
}
|
|
setIsAuthenticated(true);
|
|
loadCustomers();
|
|
loadVehicles();
|
|
}, [router]);
|
|
|
|
const loadCustomers = async () => {
|
|
try {
|
|
const response = await fetch('/api/admin/customers');
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setCustomers(data);
|
|
} else {
|
|
console.error('Failed to load customers');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading customers:', error);
|
|
}
|
|
};
|
|
|
|
const loadVehicles = async () => {
|
|
try {
|
|
const response = await fetch('/api/admin/vehicles');
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setVehicles(data);
|
|
} else {
|
|
console.error('Failed to load vehicles');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading vehicles:', error);
|
|
}
|
|
};
|
|
|
|
const handleAddCustomer = async () => {
|
|
if (!newCustomerName.trim()) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/admin/customers', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
name: newCustomerName,
|
|
address: newCustomerAddress,
|
|
tier: 0,
|
|
}),
|
|
});
|
|
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
const newCustomer = result.customer;
|
|
setCustomers([...customers, newCustomer]);
|
|
setSelectedCustomerId(newCustomer.id.toString());
|
|
setNewCustomerName('');
|
|
setNewCustomerAddress('');
|
|
setShowAddCustomer(false);
|
|
setCustomerSearch('');
|
|
setShowCustomerResults(false);
|
|
setNotification({ message: 'Customer created successfully!', type: 'success' });
|
|
} else {
|
|
const error = await response.json();
|
|
setNotification({ message: `Failed to create customer: ${error.error || error.details}`, type: 'error' });
|
|
}
|
|
} catch (error) {
|
|
console.error('Error creating customer:', error);
|
|
setNotification({ message: 'Failed to create customer', type: 'error' });
|
|
}
|
|
};
|
|
|
|
const handleAddVehicle = async () => {
|
|
if (!newVehicleId.trim() || !newVehicleMake.trim() || !newVehicleModel.trim()) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/admin/vehicles', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
id: newVehicleId.toUpperCase(),
|
|
make: newVehicleMake,
|
|
model: newVehicleModel,
|
|
capacity: parseInt(newVehicleCapacity) || 200,
|
|
yom: parseInt(newVehicleYom) || new Date().getFullYear(),
|
|
owner: selectedCustomerId ? parseInt(selectedCustomerId) : null,
|
|
}),
|
|
});
|
|
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
const newVehicle = result.vehicle;
|
|
setVehicles([...vehicles, newVehicle]);
|
|
setSelectedVehicleId(newVehicle.id);
|
|
setNewVehicleId('');
|
|
setNewVehicleMake('');
|
|
setNewVehicleModel('');
|
|
setNewVehicleCapacity('');
|
|
setNewVehicleYom('');
|
|
setShowAddVehicle(false);
|
|
setVehicleSearch('');
|
|
setShowVehicleResults(false);
|
|
setNotification({ message: 'Vehicle created successfully!', type: 'success' });
|
|
} else {
|
|
const error = await response.json();
|
|
setNotification({ message: `Failed to create vehicle: ${error.error || error.details}`, type: 'error' });
|
|
}
|
|
} catch (error) {
|
|
console.error('Error creating vehicle:', error);
|
|
setNotification({ message: 'Failed to create vehicle', type: 'error' });
|
|
}
|
|
};
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
if (!selectedCustomerId) {
|
|
setNotification({ message: 'Please select a customer', type: 'error' });
|
|
return;
|
|
}
|
|
|
|
if (!selectedVehicleId) {
|
|
setNotification({ message: 'Please select a vehicle', type: 'error' });
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/api/admin/jobs', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
vehicleId: selectedVehicleId,
|
|
metadata: metadata || null,
|
|
mileage: mileage ? parseInt(mileage) : null,
|
|
}),
|
|
});
|
|
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
setNotification({ message: 'Job created successfully!', type: 'success' });
|
|
setTimeout(() => {
|
|
router.push('/admin/dashboard');
|
|
}, 1500);
|
|
} else {
|
|
const error = await response.json();
|
|
setNotification({ message: `Failed to create job: ${error.error || error.details}`, type: 'error' });
|
|
}
|
|
} catch (error) {
|
|
console.error('Error creating job:', error);
|
|
setNotification({ message: 'Failed to create job', type: 'error' });
|
|
}
|
|
};
|
|
|
|
const selectedCustomer = customers.find(c => c.id.toString() === selectedCustomerId);
|
|
const selectedVehicle = vehicles.find(v => v.id === selectedVehicleId);
|
|
|
|
const filteredCustomers = customers.filter(customer =>
|
|
customer.name.toLowerCase().includes(customerSearch.toLowerCase()) ||
|
|
(customer.address && customer.address.toLowerCase().includes(customerSearch.toLowerCase()))
|
|
);
|
|
|
|
const filteredVehicles = vehicles
|
|
.filter(v => !selectedCustomerId || v.owner === parseInt(selectedCustomerId))
|
|
.filter(vehicle =>
|
|
vehicle.id.toLowerCase().includes(vehicleSearch.toLowerCase()) ||
|
|
vehicle.make.toLowerCase().includes(vehicleSearch.toLowerCase()) ||
|
|
vehicle.model.toLowerCase().includes(vehicleSearch.toLowerCase())
|
|
);
|
|
|
|
// Close dropdowns when clicking outside
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
const target = event.target as HTMLElement;
|
|
if (!target.closest('.customer-search-container') && !target.closest('.vehicle-search-container')) {
|
|
setShowCustomerResults(false);
|
|
setShowVehicleResults(false);
|
|
}
|
|
};
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
}, []);
|
|
|
|
if (!isAuthenticated) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<AdminLogo />
|
|
<div className="relative min-h-screen bg-black tech-grid scanlines">
|
|
{/* Animated background elements */}
|
|
<div className="absolute inset-0 overflow-hidden">
|
|
<div className="absolute top-1/4 left-1/4 h-96 w-96 rounded-full bg-white/5 blur-3xl animate-pulse"></div>
|
|
<div className="absolute bottom-1/4 right-1/4 h-96 w-96 rounded-full bg-white/5 blur-3xl animate-pulse delay-1000"></div>
|
|
</div>
|
|
|
|
<div className="relative mx-auto max-w-4xl px-4 py-12">
|
|
<div className="relative rounded-lg border-2 border-white/30 bg-black/80 backdrop-blur-sm p-8 neon-border-glow">
|
|
<div className="absolute inset-0 rounded-lg bg-gradient-to-br from-white/5 to-transparent"></div>
|
|
<div className="relative">
|
|
<div className="mb-6 flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<div className="h-2 w-2 rounded-full bg-white animate-pulse"></div>
|
|
<h1 className="text-3xl font-bold text-white uppercase tracking-wider neon-glow">
|
|
Add New Job
|
|
</h1>
|
|
</div>
|
|
<Link
|
|
href="/admin/dashboard"
|
|
className="text-sm font-medium text-white/60 hover:text-white transition-colors font-mono uppercase tracking-wider border border-white/20 px-3 py-1 rounded hover:border-white/40 hover:bg-white/10"
|
|
>
|
|
← Back to Dashboard
|
|
</Link>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
{/* Customer Selection */}
|
|
<div className="relative customer-search-container">
|
|
<div className="mb-2 flex items-center justify-between">
|
|
<label className="block text-sm font-medium text-white uppercase tracking-wider">
|
|
Customer <span className="text-red-500">*</span>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setNewCustomerName(customerSearch);
|
|
setShowAddCustomer(true);
|
|
}}
|
|
className="text-xs font-mono uppercase tracking-wider border border-cyan-500/50 bg-cyan-500/10 px-2 py-1 rounded text-cyan-400 transition-all hover:border-cyan-500 hover:bg-cyan-500/20 hover:text-cyan-300 hover:shadow-[0_0_10px_rgba(0,191,255,0.4)]"
|
|
>
|
|
+ Add New
|
|
</button>
|
|
</div>
|
|
{selectedCustomer ? (
|
|
<div className="mb-2 flex items-center justify-between rounded-lg border-2 border-white/30 bg-black/50 px-4 py-2">
|
|
<span className="text-white font-mono">
|
|
{selectedCustomer.name} {selectedCustomer.address ? `- ${selectedCustomer.address}` : ''}
|
|
</span>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setSelectedCustomerId('');
|
|
setSelectedVehicleId('');
|
|
setCustomerSearch('');
|
|
}}
|
|
className="text-white/60 hover:text-white"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<>
|
|
<input
|
|
type="text"
|
|
value={customerSearch}
|
|
onChange={(e) => {
|
|
setCustomerSearch(e.target.value);
|
|
setShowCustomerResults(true);
|
|
}}
|
|
onFocus={() => setShowCustomerResults(true)}
|
|
placeholder="Search customer by name or address..."
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white placeholder-white/40 focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
/>
|
|
{showCustomerResults && customerSearch && filteredCustomers.length > 0 && (
|
|
<div className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-lg border-2 border-white/20 bg-black/95 backdrop-blur-sm">
|
|
{filteredCustomers.map((customer) => (
|
|
<button
|
|
key={customer.id}
|
|
type="button"
|
|
onClick={() => {
|
|
setSelectedCustomerId(customer.id.toString());
|
|
setSelectedVehicleId('');
|
|
setCustomerSearch('');
|
|
setShowCustomerResults(false);
|
|
}}
|
|
className="w-full px-4 py-3 text-left text-white hover:bg-white/10 font-mono transition-colors border-b border-white/10 last:border-b-0"
|
|
>
|
|
<div className="font-semibold">{customer.name}</div>
|
|
{customer.address && (
|
|
<div className="text-sm text-white/60">{customer.address}</div>
|
|
)}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
{showCustomerResults && customerSearch && filteredCustomers.length === 0 && (
|
|
<div className="absolute z-10 mt-1 w-full rounded-lg border-2 border-white/20 bg-black/95 backdrop-blur-sm px-4 py-3 text-white/60 font-mono text-sm">
|
|
No customers found
|
|
</div>
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* Vehicle Selection */}
|
|
<div className="relative vehicle-search-container">
|
|
<div className="mb-2 flex items-center justify-between">
|
|
<label className="block text-sm font-medium text-white uppercase tracking-wider">
|
|
Vehicle <span className="text-red-500">*</span>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setNewVehicleId(vehicleSearch);
|
|
setShowAddVehicle(true);
|
|
}}
|
|
className="text-xs font-mono uppercase tracking-wider border border-cyan-500/50 bg-cyan-500/10 px-2 py-1 rounded text-cyan-400 transition-all hover:border-cyan-500 hover:bg-cyan-500/20 hover:text-cyan-300 hover:shadow-[0_0_10px_rgba(0,191,255,0.4)]"
|
|
>
|
|
+ Add New
|
|
</button>
|
|
</div>
|
|
{selectedVehicle ? (
|
|
<div className="mb-2 flex items-center justify-between rounded-lg border-2 border-white/30 bg-black/50 px-4 py-2">
|
|
<span className="text-white font-mono">
|
|
{selectedVehicle.id} - {selectedVehicle.make} {selectedVehicle.model}
|
|
</span>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setSelectedVehicleId('');
|
|
setVehicleSearch('');
|
|
}}
|
|
className="text-white/60 hover:text-white"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<>
|
|
<input
|
|
type="text"
|
|
value={vehicleSearch}
|
|
onChange={(e) => {
|
|
setVehicleSearch(e.target.value);
|
|
setShowVehicleResults(true);
|
|
}}
|
|
onFocus={() => setShowVehicleResults(true)}
|
|
placeholder={selectedCustomerId ? "Search vehicles for selected customer..." : "Search vehicle by number, make, or model..."}
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white placeholder-white/40 focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
disabled={!selectedCustomerId}
|
|
/>
|
|
{!selectedCustomerId && (
|
|
<p className="mt-1 text-xs text-white/60 font-mono">
|
|
Please select a customer first
|
|
</p>
|
|
)}
|
|
{showVehicleResults && vehicleSearch && filteredVehicles.length > 0 && (
|
|
<div className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-lg border-2 border-white/20 bg-black/95 backdrop-blur-sm">
|
|
{filteredVehicles.map((vehicle) => (
|
|
<button
|
|
key={vehicle.id}
|
|
type="button"
|
|
onClick={() => {
|
|
setSelectedVehicleId(vehicle.id);
|
|
setVehicleSearch('');
|
|
setShowVehicleResults(false);
|
|
}}
|
|
className="w-full px-4 py-3 text-left text-white hover:bg-white/10 font-mono transition-colors border-b border-white/10 last:border-b-0"
|
|
>
|
|
<div className="font-semibold">{vehicle.id}</div>
|
|
<div className="text-sm text-white/60">
|
|
{vehicle.make} {vehicle.model} {vehicle.capacity ? `(${vehicle.capacity}cc)` : ''}
|
|
</div>
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
{showVehicleResults && vehicleSearch && filteredVehicles.length === 0 && (
|
|
<div className="absolute z-10 mt-1 w-full rounded-lg border-2 border-white/20 bg-black/95 backdrop-blur-sm px-4 py-3 text-white/60 font-mono text-sm">
|
|
No vehicles found
|
|
</div>
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* Mileage */}
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Mileage (km)
|
|
</label>
|
|
<input
|
|
type="number"
|
|
value={mileage}
|
|
onChange={(e) => setMileage(e.target.value)}
|
|
placeholder="Enter vehicle mileage..."
|
|
min="0"
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white placeholder-white/40 focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
/>
|
|
</div>
|
|
|
|
{/* Metadata */}
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Metadata / Notes
|
|
</label>
|
|
<textarea
|
|
value={metadata}
|
|
onChange={(e) => setMetadata(e.target.value)}
|
|
rows={4}
|
|
placeholder="Additional notes or metadata..."
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white placeholder-white/40 focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex gap-4 pt-4">
|
|
<Link
|
|
href="/admin/dashboard"
|
|
className="flex-1 rounded-lg border-2 border-white/30 bg-black/50 px-6 py-3 text-center font-medium uppercase tracking-wider text-white transition-all hover:bg-white/10 hover:border-white/50 hover:shadow-[0_0_15px_rgba(255,255,255,0.3)]"
|
|
>
|
|
Cancel
|
|
</Link>
|
|
<button
|
|
type="submit"
|
|
className="flex-1 rounded-lg border-2 border-white/30 bg-white/5 px-6 py-3 font-bold uppercase tracking-wider text-white transition-all hover:bg-white/10 hover:border-white/50 hover:text-gray-200 hover:shadow-[0_0_20px_rgba(255,255,255,0.3)] focus:outline-none focus:ring-2 focus:ring-white/30"
|
|
>
|
|
Create Job
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Add Customer Modal */}
|
|
{showAddCustomer && (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 p-4">
|
|
<div className="relative w-full max-w-md rounded-lg border-2 border-white/30 bg-black/95 p-6 neon-border-glow">
|
|
<div className="mb-4 flex items-center justify-between">
|
|
<h2 className="text-xl font-bold text-white uppercase tracking-wider">
|
|
Add New Customer
|
|
</h2>
|
|
<button
|
|
onClick={() => {
|
|
setShowAddCustomer(false);
|
|
setNewCustomerName('');
|
|
setNewCustomerAddress('');
|
|
}}
|
|
className="text-white/60 hover:text-white"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
<div className="space-y-4">
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Name <span className="text-red-500">*</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={newCustomerName}
|
|
onChange={(e) => setNewCustomerName(e.target.value)}
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Address
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={newCustomerAddress}
|
|
onChange={(e) => setNewCustomerAddress(e.target.value)}
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
/>
|
|
</div>
|
|
<div className="flex gap-4">
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setShowAddCustomer(false);
|
|
setNewCustomerName('');
|
|
setNewCustomerAddress('');
|
|
}}
|
|
className="flex-1 rounded-lg border-2 border-white/30 bg-black/50 px-4 py-2 text-white transition-all hover:bg-white/10"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={handleAddCustomer}
|
|
className="flex-1 rounded-lg border-2 border-white/30 bg-white/5 px-4 py-2 font-bold text-white transition-all hover:bg-white/10"
|
|
>
|
|
Add Customer
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Add Vehicle Modal */}
|
|
{showAddVehicle && (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 p-4">
|
|
<div className="relative w-full max-w-md rounded-lg border-2 border-white/30 bg-black/95 p-6 neon-border-glow">
|
|
<div className="mb-4 flex items-center justify-between">
|
|
<h2 className="text-xl font-bold text-white uppercase tracking-wider">
|
|
Add New Vehicle
|
|
</h2>
|
|
<button
|
|
onClick={() => {
|
|
setShowAddVehicle(false);
|
|
setNewVehicleId('');
|
|
setNewVehicleMake('');
|
|
setNewVehicleModel('');
|
|
setNewVehicleCapacity('');
|
|
setNewVehicleYom('');
|
|
}}
|
|
className="text-white/60 hover:text-white"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
<div className="space-y-4">
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Vehicle Number <span className="text-red-500">*</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={newVehicleId}
|
|
onChange={(e) => setNewVehicleId(e.target.value.toUpperCase())}
|
|
placeholder="ABC-1234"
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Make <span className="text-red-500">*</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={newVehicleMake}
|
|
onChange={(e) => setNewVehicleMake(e.target.value)}
|
|
placeholder="Honda"
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
required
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Model <span className="text-red-500">*</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={newVehicleModel}
|
|
onChange={(e) => setNewVehicleModel(e.target.value)}
|
|
placeholder="Civic"
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Capacity (cc)
|
|
</label>
|
|
<input
|
|
type="number"
|
|
value={newVehicleCapacity}
|
|
onChange={(e) => setNewVehicleCapacity(e.target.value)}
|
|
placeholder="200"
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="mb-2 block text-sm font-medium text-white uppercase tracking-wider">
|
|
Year of Manufacture
|
|
</label>
|
|
<input
|
|
type="number"
|
|
value={newVehicleYom}
|
|
onChange={(e) => setNewVehicleYom(e.target.value)}
|
|
placeholder={new Date().getFullYear().toString()}
|
|
className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all"
|
|
/>
|
|
</div>
|
|
</div>
|
|
{selectedCustomerId && (
|
|
<div className="rounded-lg border border-white/20 bg-white/5 p-3">
|
|
<p className="text-xs text-white/60 font-mono">
|
|
Vehicle will be linked to selected customer
|
|
</p>
|
|
</div>
|
|
)}
|
|
<div className="flex gap-4">
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setShowAddVehicle(false);
|
|
setNewVehicleId('');
|
|
setNewVehicleMake('');
|
|
setNewVehicleModel('');
|
|
setNewVehicleCapacity('');
|
|
setNewVehicleYom('');
|
|
}}
|
|
className="flex-1 rounded-lg border-2 border-white/30 bg-black/50 px-4 py-2 text-white transition-all hover:bg-white/10"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={handleAddVehicle}
|
|
className="flex-1 rounded-lg border-2 border-white/30 bg-white/5 px-4 py-2 font-bold text-white transition-all hover:bg-white/10"
|
|
>
|
|
Add Vehicle
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{notification && (
|
|
<Notification
|
|
message={notification.message}
|
|
type={notification.type}
|
|
onClose={() => setNotification(null)}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|