Homepage Redesign
This commit is contained in:
@@ -32,40 +32,40 @@ export const vehiclesApi = {
|
||||
await apiClient.delete(`/vehicles/${id}`);
|
||||
},
|
||||
|
||||
// Dropdown API methods (authenticated)
|
||||
// Dropdown API methods (authenticated) - using unified platform endpoints
|
||||
getYears: async (): Promise<number[]> => {
|
||||
const response = await apiClient.get('/vehicles/dropdown/years');
|
||||
const response = await apiClient.get('/platform/years');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getMakes: async (year: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/makes?year=${year}`);
|
||||
const response = await apiClient.get(`/platform/makes?year=${year}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getModels: async (year: number, makeId: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/models?year=${year}&make_id=${makeId}`);
|
||||
const response = await apiClient.get(`/platform/models?year=${year}&make_id=${makeId}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getTransmissions: async (year: number, makeId: number, modelId: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/transmissions?year=${year}&make_id=${makeId}&model_id=${modelId}`);
|
||||
const response = await apiClient.get(`/platform/transmissions?year=${year}&make_id=${makeId}&model_id=${modelId}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getEngines: async (year: number, makeId: number, modelId: number, trimId: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/engines?year=${year}&make_id=${makeId}&model_id=${modelId}&trim_id=${trimId}`);
|
||||
const response = await apiClient.get(`/platform/engines?year=${year}&make_id=${makeId}&model_id=${modelId}&trim_id=${trimId}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getTrims: async (year: number, makeId: number, modelId: number): Promise<DropdownOption[]> => {
|
||||
const response = await apiClient.get(`/vehicles/dropdown/trims?year=${year}&make_id=${makeId}&model_id=${modelId}`);
|
||||
const response = await apiClient.get(`/platform/trims?year=${year}&make_id=${makeId}&model_id=${modelId}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// VIN decode method
|
||||
// VIN decode method - using unified platform endpoint
|
||||
decodeVIN: async (vin: string): Promise<VINDecodeResponse> => {
|
||||
const response = await apiClient.post('/vehicles/decode-vin', { vin });
|
||||
const response = await apiClient.get(`/platform/vehicle?vin=${vin}`);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -268,11 +268,15 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
VIN or License Plate <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<p className="text-xs text-gray-600 mb-2">
|
||||
Enter VIN to auto-fill vehicle details OR manually select from dropdowns below
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<input
|
||||
{...register('vin')}
|
||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 text-base"
|
||||
placeholder="Enter 17-character VIN (optional if License Plate provided)"
|
||||
style={{ fontSize: '16px' }}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
@@ -280,8 +284,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
loading={decodingVIN}
|
||||
disabled={!watchedVIN || watchedVIN.length !== 17}
|
||||
variant="secondary"
|
||||
className="w-full sm:w-auto min-h-[44px]"
|
||||
>
|
||||
Decode
|
||||
Decode VIN
|
||||
</Button>
|
||||
</div>
|
||||
{decodeSuccess && (
|
||||
@@ -293,14 +298,15 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</div>
|
||||
|
||||
{/* Vehicle Specification Dropdowns */}
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Year
|
||||
</label>
|
||||
<select
|
||||
{...register('year', { valueAsNumber: true })}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Year</option>
|
||||
{years.map((year) => (
|
||||
@@ -317,8 +323,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('make')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || !watchedYear}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Make</option>
|
||||
{makes.map((make) => (
|
||||
@@ -335,8 +342,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('model')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || !watchedMake || models.length === 0}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Model</option>
|
||||
{models.map((model) => (
|
||||
@@ -348,7 +356,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
||||
{/* Trim (left) */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
@@ -356,8 +364,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('trimLevel')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || !watchedModel || trims.length === 0}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Trim</option>
|
||||
{trims.map((trim) => (
|
||||
@@ -375,8 +384,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('engine')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
disabled={loadingDropdowns || !watchedModel || !selectedTrim || engines.length === 0}
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Engine</option>
|
||||
{engines.map((engine) => (
|
||||
@@ -394,7 +404,8 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<select
|
||||
{...register('transmission')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
<option value="">Select Transmission</option>
|
||||
<option value="Automatic">Automatic</option>
|
||||
@@ -409,20 +420,22 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<input
|
||||
{...register('nickname')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
placeholder="e.g., Family Car"
|
||||
style={{ fontSize: '16px' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Color
|
||||
</label>
|
||||
<input
|
||||
{...register('color')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
placeholder="e.g., Blue"
|
||||
style={{ fontSize: '16px' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -432,8 +445,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
</label>
|
||||
<input
|
||||
{...register('licensePlate')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
placeholder="e.g., ABC-123 (required if VIN omitted)"
|
||||
style={{ fontSize: '16px' }}
|
||||
/>
|
||||
{errors.licensePlate && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.licensePlate.message}</p>
|
||||
@@ -448,8 +462,10 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
||||
<input
|
||||
{...register('odometerReading', { valueAsNumber: true })}
|
||||
type="number"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
inputMode="numeric"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
||||
placeholder="e.g., 50000"
|
||||
style={{ fontSize: '16px' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user