fix: display purchase info and fix validation on vehicle detail (#41) #42
@@ -13,10 +13,13 @@ import { VehicleImageUpload } from './VehicleImageUpload';
|
|||||||
import { useTierAccess } from '../../../core/hooks/useTierAccess';
|
import { useTierAccess } from '../../../core/hooks/useTierAccess';
|
||||||
import { UpgradeRequiredDialog } from '../../../shared-minimal/components/UpgradeRequiredDialog';
|
import { UpgradeRequiredDialog } from '../../../shared-minimal/components/UpgradeRequiredDialog';
|
||||||
|
|
||||||
|
// Helper to convert NaN (from empty number inputs) to null
|
||||||
|
const nanToNull = (val: unknown) => (typeof val === 'number' && isNaN(val) ? null : val);
|
||||||
|
|
||||||
const vehicleSchema = z
|
const vehicleSchema = z
|
||||||
.object({
|
.object({
|
||||||
vin: z.string().max(17).nullable().optional().transform(val => val ?? undefined),
|
vin: z.string().max(17).nullable().optional().transform(val => val ?? undefined),
|
||||||
year: z.number().min(1950).max(new Date().getFullYear() + 1).nullable().optional(),
|
year: z.preprocess(nanToNull, z.number().min(1950).max(new Date().getFullYear() + 1).nullable().optional()),
|
||||||
make: z.string().nullable().optional(),
|
make: z.string().nullable().optional(),
|
||||||
model: z.string().nullable().optional(),
|
model: z.string().nullable().optional(),
|
||||||
engine: z.string().nullable().optional(),
|
engine: z.string().nullable().optional(),
|
||||||
@@ -27,8 +30,8 @@ const vehicleSchema = z
|
|||||||
nickname: z.string().nullable().optional(),
|
nickname: z.string().nullable().optional(),
|
||||||
color: z.string().nullable().optional(),
|
color: z.string().nullable().optional(),
|
||||||
licensePlate: z.string().nullable().optional(),
|
licensePlate: z.string().nullable().optional(),
|
||||||
odometerReading: z.number().min(0).nullable().optional(),
|
odometerReading: z.preprocess(nanToNull, z.number().min(0).nullable().optional()),
|
||||||
purchasePrice: z.number().min(0).nullable().optional(),
|
purchasePrice: z.preprocess(nanToNull, z.number().min(0).nullable().optional()),
|
||||||
purchaseDate: z.string().nullable().optional(),
|
purchaseDate: z.string().nullable().optional(),
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
|
|||||||
@@ -414,6 +414,23 @@ export const VehicleDetailPage: React.FC = () => {
|
|||||||
label="Current Odometer Reading"
|
label="Current Odometer Reading"
|
||||||
value={vehicle.odometerReading ? `${vehicle.odometerReading.toLocaleString()} mi` : undefined}
|
value={vehicle.odometerReading ? `${vehicle.odometerReading.toLocaleString()} mi` : undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Purchase Information Section */}
|
||||||
|
<div className="border-t border-gray-200 dark:border-silverstone pt-4 mt-4">
|
||||||
|
<h3 className="text-lg font-medium text-gray-900 dark:text-avus mb-4">
|
||||||
|
Purchase Information
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
<DetailField
|
||||||
|
label="Purchase Price"
|
||||||
|
value={vehicle.purchasePrice ? `$${vehicle.purchasePrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : undefined}
|
||||||
|
/>
|
||||||
|
<DetailField
|
||||||
|
label="Purchase Date"
|
||||||
|
value={vehicle.purchaseDate ? new Date(vehicle.purchaseDate).toLocaleDateString() : undefined}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<Divider sx={{ my: 4 }} />
|
<Divider sx={{ my: 4 }} />
|
||||||
|
|||||||
Reference in New Issue
Block a user