
Sobre Azul Virtual
Portal da tripulação para escalas, manuais e integração ACARS. Voos realistas com gerenciamento de escalas simplificado.
Serviços Azul Virtual

Escalas diárias, manuais detalhados e integração ACARS para voos imersivos. Acesso a documentação, guias de operação e suporte dedicado.

Ferramentas de planejamento, simuladores integrados e comunicação em tempo real com a equipe.
Últimas notícias




Vozes da Azul
Esperança D.
Voar com precisão, segurança e atendimento excepcional sempre me surpreende.
Esperança D.
Imersão total em cada escala.
Esperança D.
Experiência incrível, realismo autêntico.
Esperança D.
Recomendo a Azul Virtual!
Nossa equipe

Aarav Sharma

Mateo García

Zuri Ndlovu

import jsPDF from "jspdf";import autoTable from "jspdf-autotable";// =========================// TYPES// =========================export interface OFPData { flightNumber: string; aircraft: string; origin: string; destination: string; alternate: string; etd: string; eta: string; status: string; route?: string; fuel: { trip: string | number; cont: string | number; alt: string | number; final: string | number; taxi: string | number; block: string | number; }; mel?: Array<{ code: string; description: string; category: string; impact: string; }>; weather: { origin: { visibility: string; severity: string }; destination: { visibility: string; severity: string; phenomena?: string }; alternate: { visibility: string; severity: string }; }; metarOrigin?: string; metarDest?: string; metarAlt?: string; notams?: Array<{ message: string }>; remarks?: string;}// =========================// GENERATOR FUNCTION// =========================export const generateOFP = (f: OFPData) => { const doc = new jsPDF(); // HEADER doc.setFont("courier", "normal"); doc.setFontSize(12); doc.text("AZUL LINHAS AÉREAS - OPERATIONAL FLIGHT PLAN", 14, 12); doc.setFontSize(9); doc.text( `FLT: ${f.flightNumber} ACFT: ${f.aircraft} DATE: ${new Date().toUTCString()}`, 14, 18 ); doc.text( `ROUTE: ${f.origin} - ${f.destination} ALT: ${f.alternate}`, 14, 23 ); doc.text( `ETD: ${f.etd}Z ETA: ${f.eta}Z STATUS: ${f.status}`, 14, 28 ); // ROUTE STRING autoTable(doc, { startY: 32, head: [["ROUTE"]], body: [[f.route || "DCT"]], styles: { font: "courier", fontSize: 8 }, }); // FUEL / WEIGHT // Using type assertion because jsPDF-autotable types can be tricky with finalY autoTable(doc, { startY: (doc as any).lastAutoTable.finalY + 3, head: [["TYPE", "VALUE"]], body: [ ["TRIP FUEL", f.fuel?.trip || "-"], ["CONTINGENCY", f.fuel?.cont || "-"], ["ALTERNATE", f.fuel?.alt || "-"], ["FINAL RESERVE", f.fuel?.final || "-"], ["TAXI", f.fuel?.taxi || "-"], ["BLOCK FUEL", f.fuel?.block || "-"], ], styles: { fontSize: 8 }, }); // MEL / CDL const melData = f.mel && f.mel.length > 0 ? f.mel.map((m) => [m.code, m.description, m.category, m.impact]) : [["NIL", "NO DEFERRED ITEMS", "-", "-"]]; autoTable(doc, { startY: (doc as any).lastAutoTable.finalY + 3, head: [["MEL", "DESCRIPTION", "CAT", "STATUS"]], body: melData, styles: { font: "courier", fontSize: 8 }, }); // WX SUMMARY autoTable(doc, { startY: (doc as any).lastAutoTable.finalY + 3, head: [["LOC", "VIS", "WX", "SEV"]], body: [ ["DEP", f.weather?.origin?.visibility || "-", "-", f.weather?.origin?.severity || "-"], ["DEST", f.weather?.destination?.visibility || "-", f.weather?.destination?.phenomena || "-", f.weather?.destination?.severity || "-"], ["ALT", f.weather?.alternate?.visibility || "-", "-", f.weather?.alternate?.severity || "-"], ], styles: { fontSize: 8 }, }); // ========================= // PAGE 2 // ========================= doc.addPage(); doc.setFontSize(10); doc.text("METAR / TAF", 14, 15); autoTable(doc, { startY: 20, head: [["STATION", "DATA"]], body: [ ["DEP", f.metarOrigin || "NIL"], ["DEST", f.metarDest || "NIL"], ["ALT", f.metarAlt || "NIL"], ], styles: { font: "courier", fontSize: 8 }, }); // NOTAM const notamData = f.notams && f.notams.length > 0 ? f.notams.map((n) => [n.message]) : [["NIL"]]; autoTable(doc, { startY: (doc as any).lastAutoTable.finalY + 5, head: [["NOTAM"]], body: notamData, styles: { fontSize: 8 }, }); // REMARKS autoTable(doc, { startY: (doc as any).lastAutoTable.finalY + 5, head: [["DISPATCH REMARKS"]], body: [[f.remarks || "NIL"]], styles: { fontSize: 8 }, }); // ========================= // SIGNATURE (Dynamic Y positioning) // ========================= let finalY = (doc as any).lastAutoTable.finalY + 20; // A4 page height is approx 297mm. If signatures don't fit, add a new page. if (finalY > 260) { doc.addPage(); finalY = 20; } doc.setFontSize(10); doc.text("DISPATCH RELEASE: ______________________________", 14, finalY); doc.text("CAPTAIN ACCEPTANCE: ____________________________", 14, finalY + 10); doc.save(`OFP_${f.flightNumber}.pdf`);};
