fix: display purchase info and fix validation on vehicle detail (refs #41)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 2m47s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 38s
Deploy to Staging / Verify Staging (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped

- 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 <noreply@anthropic.com>
This commit is contained in:
Eric Gullickson
2026-01-15 20:53:23 -06:00
parent f325ff49d0
commit a1d3dd965a
2 changed files with 23 additions and 3 deletions

View File

@@ -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(

View File

@@ -414,6 +414,23 @@ export const VehicleDetailPage: React.FC = () => {
label="Current Odometer Reading"
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-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>
<Divider sx={{ my: 4 }} />