From a1d3dd965acd1a10db163e2d7430599e8c51b4eb Mon Sep 17 00:00:00 2001 From: Eric Gullickson <16152721+ericgullickson@users.noreply.github.com> Date: Thu, 15 Jan 2026 20:53:23 -0600 Subject: [PATCH 1/2] fix: display purchase info and fix validation on vehicle detail (refs #41) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add purchase price and purchase date display to vehicle detail page - Fix form validation to handle NaN from empty number inputs using z.preprocess 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../vehicles/components/VehicleForm.tsx | 9 ++++++--- .../vehicles/pages/VehicleDetailPage.tsx | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/frontend/src/features/vehicles/components/VehicleForm.tsx b/frontend/src/features/vehicles/components/VehicleForm.tsx index 0b61c6f..2aa0717 100644 --- a/frontend/src/features/vehicles/components/VehicleForm.tsx +++ b/frontend/src/features/vehicles/components/VehicleForm.tsx @@ -13,10 +13,13 @@ import { VehicleImageUpload } from './VehicleImageUpload'; import { useTierAccess } from '../../../core/hooks/useTierAccess'; 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 .object({ 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(), model: z.string().nullable().optional(), engine: z.string().nullable().optional(), @@ -27,8 +30,8 @@ const vehicleSchema = z nickname: z.string().nullable().optional(), color: z.string().nullable().optional(), licensePlate: z.string().nullable().optional(), - odometerReading: z.number().min(0).nullable().optional(), - purchasePrice: z.number().min(0).nullable().optional(), + odometerReading: z.preprocess(nanToNull, z.number().min(0).nullable().optional()), + purchasePrice: z.preprocess(nanToNull, z.number().min(0).nullable().optional()), purchaseDate: z.string().nullable().optional(), }) .refine( diff --git a/frontend/src/features/vehicles/pages/VehicleDetailPage.tsx b/frontend/src/features/vehicles/pages/VehicleDetailPage.tsx index 97d8feb..1fb8fdc 100644 --- a/frontend/src/features/vehicles/pages/VehicleDetailPage.tsx +++ b/frontend/src/features/vehicles/pages/VehicleDetailPage.tsx @@ -414,6 +414,23 @@ export const VehicleDetailPage: React.FC = () => { label="Current Odometer Reading" value={vehicle.odometerReading ? `${vehicle.odometerReading.toLocaleString()} mi` : undefined} /> + + {/* Purchase Information Section */} +
+

+ Purchase Information +

+
+ + +
+
From 731d67f324d6be3595a78a4ca9a1a7952b8f8df0 Mon Sep 17 00:00:00 2001 From: Eric Gullickson <16152721+ericgullickson@users.noreply.github.com> Date: Thu, 15 Jan 2026 20:56:03 -0600 Subject: [PATCH 2/2] fix: add mobile responsive breakpoint to purchase info grid (refs #41) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- frontend/src/features/vehicles/pages/VehicleDetailPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/features/vehicles/pages/VehicleDetailPage.tsx b/frontend/src/features/vehicles/pages/VehicleDetailPage.tsx index 1fb8fdc..5e8fa0d 100644 --- a/frontend/src/features/vehicles/pages/VehicleDetailPage.tsx +++ b/frontend/src/features/vehicles/pages/VehicleDetailPage.tsx @@ -420,7 +420,7 @@ export const VehicleDetailPage: React.FC = () => {

Purchase Information

-
+