const PlanEditor = () => { const {plans, setPlans, go, route, toast} = useApp(); const editing = route.params?.id; const existing = editing ? plans.find(p => p.id == editing) : null; // Campos con nombres EXACTOS que usa el backend / Icaro const blank = { id: 'pl_' + Math.random().toString(36).slice(2, 8), name: 'Nuevo plan', favorite: false, // Identificacion (3/7/8) message_type: 'FPL', arcid: '', flight_rules: 'Z', flight_type: 'X', // Aeronave (9) aircraft_count: 1, aircraft_type: 'C172', wake: 'L', // Equipo y Capacidades (10) com_equipment: 'SGY', ssr: 'C', ads: '', // Salida (13) adep: 'LEMU', eobt: '08:00', flight_date: new Date().toISOString().slice(0, 10), aro_office: 'OFICINA ARO CENTRAL', // Destino (16) ades: '', eet_total: '01:00', altn: 'LEVC', altn2: '', // Ruta (15) speed: 'N0149', level: 'F0100', route: '', // Otros datos (18) reg: 'EC-OBE', opr: '', sts: '', pbn: '', nav: '', com: '', dat: '', rmk: '', extra_data: '', // Suplementaria (19) emergency_radio: 'E', survival_equipment: '', life_jacket_type: 'F', dinghies_number: '', dinghies_capacity: '', dinghies_covered: false, dinghies_color: '', persons_on_board: '002', endurance: '05:00', pic_name: '', colors: '', observations: '', }; const [p, setP] = useState(existing ? {...blank, ...existing} : blank); const [tab, setTab] = useState('identification'); const [ifrOpen, setIfrOpen] = useState(false); const [saving, setSaving] = useState(false); // Sync if plan arrives late (e.g. from IFR table create) useEffect(() => { if (!editing) return; const found = plans.find(x => x.id == editing); if (found && p.name === blank.name && found.name !== blank.name) { setP({...blank, ...found}); } }, [plans, editing]); const u = (k, v) => setP(x => ({...x, [k]: v})); const validate = () => { const errs = []; if (!p.arcid || !p.arcid.trim()) errs.push('ARCID (indicativo) es obligatorio'); if (!p.flight_rules) errs.push('Reglas de vuelo es obligatorio'); if (!p.adep || p.adep.length !== 4) errs.push('ADEP debe ser un codigo ICAO de 4 letras'); if (!p.ades || p.ades.length !== 4) errs.push('ADES debe ser un codigo ICAO de 4 letras'); if (!p.aircraft_type) errs.push('Tipo de aeronave es obligatorio'); if (!p.eobt || !/^\d{2}:\d{2}$/.test(p.eobt)) errs.push('EOBT debe tener formato hh:mm'); if (!p.speed) errs.push('Velocidad es obligatoria'); if (!p.level) errs.push('Nivel de vuelo es obligatorio'); if (!p.eet_total || !/^\d{2}:\d{2}$/.test(p.eet_total)) errs.push('EET debe tener formato hh:mm'); if (!p.flight_date) errs.push('Fecha de vuelo es obligatoria'); if (p.flight_date) { const today = new Date().toISOString().slice(0, 10); if (p.flight_date < today) errs.push('Fecha de vuelo no puede ser anterior a hoy (' + today + ')'); } if (!p.persons_on_board || parseInt(p.persons_on_board) < 1) errs.push('Personas a bordo debe ser al menos 1'); if (!p.pic_name || !p.pic_name.trim()) errs.push('Piloto al mando (PIC) es obligatorio'); return errs; }; const save = async () => { const errs = validate(); if (errs.length) { toast(errs[0]); return; } setSaving(true); try { let saved = {...p}; if (editing) { await api.updatePlan(saved); } else { const res = await api.createPlan(saved); if (res && res.id) saved.id = res.id; } // Update local state if (editing) setPlans(pl => pl.map(x => x.id === saved.id ? saved : x)); else setPlans(pl => [saved, ...pl]); toast(editing ? 'Plan actualizado' : 'Plan creado'); go('dashboard'); } catch (e) { if (e.error === 'validation' && e.errors) { toast('Error: ' + e.errors.map(x => x.message).join(', ')); } else { toast('Error: ' + (e.error || 'desconocido')); } } setSaving(false); }; const pickIfr = (r) => { setP(x => ({ ...x, adep: r.from, ades: r.to, flight_rules: r.rules, route: r.route, level: r.fl || x.level, eet_total: r.dur || x.eet_total, name: `${r.from} -> ${r.to}${r.notes ? ' — ' + r.notes : ''}` })); setIfrOpen(false); toast('Ruta cargada'); }; const TABS = [ {id: 'identification', label: 'Identificacion'}, {id: 'aircraft', label: 'Aeronave'}, {id: 'flight', label: 'Datos de Vuelo'}, {id: 'route', label: 'Ruta'}, {id: 'other', label: 'Otros Datos'}, {id: 'supplementary', label: 'Info. Suplementaria'}, ]; const sectionLabel = (text) =>
{text}
; return

{editing ? 'Editar plan' : 'Nuevo plan'}

{p.adep} -> {p.ades || '????'}
{TABS.map(t => )}
{/* ===== IDENTIFICACION DEL MENSAJE (3/7/8) ===== */} {tab === 'identification' &&
u('name', e.target.value)}/>
{sectionLabel('IDENTIFICACION DEL MENSAJE')}
u('arcid', e.target.value.toUpperCase().slice(0, 7))} maxLength={7} placeholder="FYS23KN"/>
u('flight_type', v)} options={[{value: 'S', label: 'S — Regular'}, {value: 'N', label: 'N — No regular'}, {value: 'G', label: 'G — Aviacion general'}, {value: 'M', label: 'M — Militar'}, {value: 'X', label: 'X — Otros'}]}/>
{sectionLabel('DIA DE VUELO')}
u('flight_date', v)}/>
} {/* ===== DATOS AERONAVE (9/10) ===== */} {tab === 'aircraft' &&
{sectionLabel('AERONAVE — FLOTA EF')}
u('aircraft_count', parseInt(e.target.value) || 1)}/>
u('aircraft_type', e.target.value.toUpperCase())} placeholder="C172"/>
u('com_equipment', e.target.value.toUpperCase())} placeholder="SGY"/>
u('ssr', e.target.value.toUpperCase())} placeholder="C"/>
u('ads', e.target.value.toUpperCase())} placeholder=""/>
} {/* ===== DATOS DE VUELO (13/16) ===== */} {tab === 'flight' &&
{sectionLabel('SALIDA (13)')}
u('adep', e.target.value.toUpperCase().slice(0, 4))} maxLength={4} placeholder="LEMU"/>
u('eobt', e.target.value)} placeholder="08:00"/>
u('aro_office', e.target.value)}/>
{sectionLabel('DESTINO Y AERODROMOS ALTERNATIVOS (16)')}
u('ades', e.target.value.toUpperCase().slice(0, 4))} maxLength={4} placeholder="LEIB"/>
u('eet_total', e.target.value)} placeholder="01:00"/>
u('altn', e.target.value.toUpperCase().slice(0, 4))} maxLength={4} placeholder="LEVC"/>
u('altn2', e.target.value.toUpperCase().slice(0, 4))} maxLength={4}/>
} {/* ===== RUTA (15) ===== */} {tab === 'route' &&
{sectionLabel('RUTA (15)')}
u('speed', e.target.value.toUpperCase())} placeholder="N0149"/>
u('level', e.target.value.toUpperCase())} placeholder="F0100"/>