mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-25 02:11:12 -05:00
Fix: Type safety and unit validation
This commit is contained in:
@@ -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<Record<number, string>>({});
|
||||
|
||||
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' : ''}
|
||||
/>
|
||||
<datalist id={`units-${index}`}>
|
||||
{COMMON_UNITS.map(u => <option key={u} value={u} />)}
|
||||
{METRIC_UNITS.map(u => <option key={u} value={u} />)}
|
||||
</datalist>
|
||||
{unitErrors[index] && (
|
||||
<p className="text-xs text-destructive mt-1">{unitErrors[index]}</p>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
⚠️ Metric units only
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
@@ -242,3 +260,28 @@ export function TechnicalSpecsEditor({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates technical specs before submission
|
||||
*/
|
||||
export function validateTechnicalSpecs(specs: TechnicalSpec[]): { valid: boolean; errors: string[] } {
|
||||
const errors: string[] = [];
|
||||
|
||||
specs.forEach((spec, index) => {
|
||||
if (!spec.spec_name?.trim()) {
|
||||
errors.push(`Spec ${index + 1}: Name is required`);
|
||||
}
|
||||
if (!spec.spec_value?.trim()) {
|
||||
errors.push(`Spec ${index + 1} (${spec.spec_name}): Value is required`);
|
||||
}
|
||||
if (spec.unit) {
|
||||
try {
|
||||
validateMetricUnit(spec.unit, `Spec ${index + 1} (${spec.spec_name})`);
|
||||
} catch (error: unknown) {
|
||||
errors.push(getErrorMessage(error));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { valid: errors.length === 0, errors };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user