/** * JsonEditor - Better UX for JSONB fields * * Provides syntax highlighting, validation, and error messages * instead of raw textarea for JSON editing. * * Used by: QualityTemplateWizard, CustomerOrderWizard */ import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { AlertCircle, CheckCircle } from 'lucide-react'; interface JsonEditorProps { value: any; onChange: (value: any) => void; label?: string; placeholder?: string; required?: boolean; rows?: number; } export const JsonEditor: React.FC = ({ value, onChange, label, placeholder, required = false, rows = 6, }) => { const { t } = useTranslation('wizards'); const [jsonString, setJsonString] = useState(''); const [error, setError] = useState(null); const [isValid, setIsValid] = useState(true); // Initialize from value useEffect(() => { try { if (value === null || value === undefined || value === '') { setJsonString(''); } else if (typeof value === 'string') { // Try to parse to validate JSON.parse(value); setJsonString(value); } else { setJsonString(JSON.stringify(value, null, 2)); } setIsValid(true); setError(null); } catch (e) { setJsonString(typeof value === 'string' ? value : ''); setIsValid(false); } }, []); const handleChange = (newValue: string) => { setJsonString(newValue); // Validate JSON if (newValue.trim() === '') { setError(null); setIsValid(true); onChange(null); return; } try { const parsed = JSON.parse(newValue); setError(null); setIsValid(true); onChange(parsed); } catch (e) { setError(e instanceof Error ? e.message : 'Invalid JSON'); setIsValid(false); // Don't update parent with invalid JSON } }; const formatJson = () => { try { const parsed = JSON.parse(jsonString); const formatted = JSON.stringify(parsed, null, 2); setJsonString(formatted); setError(null); setIsValid(true); onChange(parsed); } catch (e) { setError(e instanceof Error ? e.message : 'Invalid JSON'); setIsValid(false); } }; return (
{label && ( )}