Merge pull request 'fix: display purchase info and fix validation on vehicle detail (#41)' (#42) from issue-41-fix-purchase-info into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 27s
Deploy to Staging / Deploy to Staging (push) Successful in 29s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Mirror Base Images / Mirror Base Images (push) Successful in 43s

Reviewed-on: #42
This commit was merged in pull request #42.
This commit is contained in:
2026-01-16 03:04:16 +00:00
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 { 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(

View File

@@ -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 }} />