diff --git a/src/components/admin/ParkForm.tsx b/src/components/admin/ParkForm.tsx index 6c613388..dc2c1de6 100644 --- a/src/components/admin/ParkForm.tsx +++ b/src/components/admin/ParkForm.tsx @@ -293,7 +293,7 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
setValue('status', value as any)} + onValueChange={(value) => setValue('status', value as "operating" | "closed_permanently" | "closed_temporarily" | "under_construction" | "relocated" | "stored" | "demolished")} defaultValue={initialData?.status || 'operating'} > diff --git a/src/components/admin/editors/CoasterStatsEditor.tsx b/src/components/admin/editors/CoasterStatsEditor.tsx index 7a22834b..79d818fc 100644 --- a/src/components/admin/editors/CoasterStatsEditor.tsx +++ b/src/components/admin/editors/CoasterStatsEditor.tsx @@ -1,4 +1,5 @@ import { Plus, Trash2 } from "lucide-react"; +import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -15,6 +16,7 @@ import { getDisplayUnit } from "@/lib/units"; import { validateMetricUnit } from "@/lib/unitValidation"; +import { getErrorMessage } from "@/lib/errorHandler"; interface CoasterStat { stat_name: string; @@ -49,6 +51,7 @@ export function CoasterStatsEditor({ categories = DEFAULT_CATEGORIES }: CoasterStatsEditorProps) { const { preferences } = useUnitPreferences(); + const [unitErrors, setUnitErrors] = useState>({}); const addStat = () => { onChange([ @@ -91,8 +94,17 @@ export function CoasterStatsEditor({ try { validateMetricUnit(value, 'Unit'); newStats[index] = { ...newStats[index], [field]: value }; - } catch (error) { - toast.error(`Invalid unit: ${value}. Please use metric units only (km/h, m, cm, kg, G, etc.)`); + // Clear error for this index + setUnitErrors(prev => { + const updated = { ...prev }; + delete updated[index]; + return updated; + }); + } catch (error: unknown) { + const message = getErrorMessage(error); + toast.error(message); + // Store error for visual feedback + setUnitErrors(prev => ({ ...prev, [index]: message })); return; } } else { @@ -202,7 +214,14 @@ export function CoasterStatsEditor({ value={stat.unit || ''} onChange={(e) => updateStat(index, 'unit', e.target.value)} placeholder="km/h, m, G..." + className={unitErrors[index] ? 'border-destructive' : ''} /> + {unitErrors[index] && ( +

{unitErrors[index]}

+ )} +

+ ⚠️ Use metric units only: km/h, m, cm, kg, G, celsius +

@@ -253,3 +272,28 @@ export function CoasterStatsEditor({ ); } + +/** + * Validates coaster stats before submission + */ +export function validateCoasterStats(stats: CoasterStat[]): { valid: boolean; errors: string[] } { + const errors: string[] = []; + + stats.forEach((stat, index) => { + if (!stat.stat_name?.trim()) { + errors.push(`Stat ${index + 1}: Name is required`); + } + if (stat.stat_value === null || stat.stat_value === undefined) { + errors.push(`Stat ${index + 1} (${stat.stat_name}): Value is required`); + } + if (stat.unit) { + try { + validateMetricUnit(stat.unit, `Stat ${index + 1} (${stat.stat_name})`); + } catch (error: unknown) { + errors.push(getErrorMessage(error)); + } + } + }); + + return { valid: errors.length === 0, errors }; +} diff --git a/src/components/admin/editors/TechnicalSpecsEditor.tsx b/src/components/admin/editors/TechnicalSpecsEditor.tsx index ed051d0e..ba60a223 100644 --- a/src/components/admin/editors/TechnicalSpecsEditor.tsx +++ b/src/components/admin/editors/TechnicalSpecsEditor.tsx @@ -1,4 +1,5 @@ import { Plus, Trash2 } from "lucide-react"; +import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -13,7 +14,8 @@ import { getMetricUnit, getDisplayUnit } from "@/lib/units"; -import { validateMetricUnit } from "@/lib/unitValidation"; +import { validateMetricUnit, METRIC_UNITS } from "@/lib/unitValidation"; +import { getErrorMessage } from "@/lib/errorHandler"; interface TechnicalSpec { spec_name: string; @@ -32,7 +34,6 @@ interface TechnicalSpecsEditorProps { } const DEFAULT_CATEGORIES = ['Performance', 'Safety', 'Design', 'Capacity', 'Technical', 'Other']; -const COMMON_UNITS = ['m', 'km/h', 'mph', 'ft', 'seconds', 'minutes', 'kg', 'lbs', 'passengers', '%']; export function TechnicalSpecsEditor({ specs, @@ -41,6 +42,7 @@ export function TechnicalSpecsEditor({ commonSpecs = [] }: TechnicalSpecsEditorProps) { const { preferences } = useUnitPreferences(); + const [unitErrors, setUnitErrors] = useState>({}); const addSpec = () => { onChange([ @@ -70,8 +72,17 @@ export function TechnicalSpecsEditor({ try { validateMetricUnit(value, 'Unit'); newSpecs[index] = { ...newSpecs[index], [field]: value }; - } catch (error) { - toast.error(`Invalid unit: ${value}. Please use metric units only (m, km/h, cm, kg, celsius, etc.)`); + // Clear error for this index + setUnitErrors(prev => { + const updated = { ...prev }; + delete updated[index]; + return updated; + }); + } catch (error: unknown) { + const message = getErrorMessage(error); + toast.error(message); + // Store error for visual feedback + setUnitErrors(prev => ({ ...prev, [index]: message })); return; } } else { @@ -220,10 +231,17 @@ export function TechnicalSpecsEditor({ onChange={(e) => updateSpec(index, 'unit', e.target.value)} placeholder="Unit" list={`units-${index}`} + className={unitErrors[index] ? 'border-destructive' : ''} /> - {COMMON_UNITS.map(u => + {unitErrors[index] && ( +

{unitErrors[index]}

+ )} +

+ ⚠️ Metric units only +