{"id":1207,"date":"2025-12-15T01:58:03","date_gmt":"2025-12-15T01:58:03","guid":{"rendered":"https:\/\/dhalionairva.com\/?page_id=1207"},"modified":"2025-12-15T02:06:10","modified_gmt":"2025-12-15T02:06:10","slug":"operations","status":"publish","type":"page","link":"https:\/\/dhalionairva.com\/index.php\/operations\/","title":{"rendered":"Operations"},"content":{"rendered":"    <style>\r\n        .live-map-container {\r\n            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\r\n            padding: 20px;\r\n            width: 100%;\r\n        }\r\n        \r\n        .live-map-wrapper {\r\n            width: 100%;\r\n            margin: 0 auto;\r\n            background: linear-gradient(135deg, #5fbfbc 0%, #4a9c99 100%);\r\n            border-radius: 15px;\r\n            box-shadow: 0 8px 30px rgba(95, 191, 188, 0.3);\r\n            overflow: hidden;\r\n        }\r\n        \r\n        .live-map-wrapper h1 {\r\n            color: white;\r\n            padding: 40px;\r\n            text-align: center;\r\n            font-size: 36px;\r\n            margin: 0;\r\n            text-shadow: 0 2px 4px rgba(0,0,0,0.2);\r\n        }\r\n        \r\n        .map-controls {\r\n            background: white;\r\n            padding: 20px 30px;\r\n            display: flex;\r\n            gap: 15px;\r\n            align-items: center;\r\n            flex-wrap: wrap;\r\n            border-bottom: 3px solid #5fbfbc;\r\n        }\r\n        \r\n        .map-controls label {\r\n            font-weight: 600;\r\n            color: #2c5f5d;\r\n            font-size: 14px;\r\n        }\r\n        \r\n        .map-controls button {\r\n            background: #5fbfbc;\r\n            color: white;\r\n            border: none;\r\n            padding: 10px 20px;\r\n            border-radius: 6px;\r\n            cursor: pointer;\r\n            font-weight: 600;\r\n            font-size: 14px;\r\n            transition: all 0.3s;\r\n        }\r\n        \r\n        .map-controls button:hover {\r\n            background: #4a9c99;\r\n            transform: translateY(-2px);\r\n        }\r\n        \r\n        .map-controls button.active {\r\n            background: #2c5f5d;\r\n        }\r\n        \r\n        .network-badge {\r\n            display: inline-flex;\r\n            align-items: center;\r\n            gap: 5px;\r\n            padding: 5px 12px;\r\n            border-radius: 20px;\r\n            font-size: 11px;\r\n            font-weight: 700;\r\n            text-transform: uppercase;\r\n        }\r\n        \r\n        .network-badge.ivao {\r\n            background: #0066cc;\r\n            color: white;\r\n        }\r\n        \r\n        .network-badge.vatsim {\r\n            background: #00a651;\r\n            color: white;\r\n        }\r\n        \r\n        .map-content {\r\n            background: #f5f5f5;\r\n            padding: 30px;\r\n        }\r\n        \r\n        .map-container-inner {\r\n            background: white;\r\n            border-radius: 12px;\r\n            overflow: hidden;\r\n            box-shadow: 0 2px 8px rgba(0,0,0,0.08);\r\n        }\r\n        \r\n        #liveMap {\r\n            width: 100%;\r\n            height: 600px;\r\n            background: #e0e0e0;\r\n        }\r\n        \r\n        .flights-list {\r\n            padding: 20px;\r\n        }\r\n        \r\n        .flight-row {\r\n            background: white;\r\n            border-radius: 12px;\r\n            margin-bottom: 15px;\r\n            box-shadow: 0 2px 8px rgba(0,0,0,0.08);\r\n            transition: all 0.3s ease;\r\n            cursor: pointer;\r\n            overflow: hidden;\r\n        }\r\n        \r\n        .flight-row:hover {\r\n            box-shadow: 0 8px 20px rgba(95, 191, 188, 0.3);\r\n            transform: translateY(-2px);\r\n        }\r\n        \r\n        .flight-compact {\r\n            display: flex;\r\n            align-items: center;\r\n            padding: 20px;\r\n            gap: 20px;\r\n        }\r\n        \r\n        .flight-icon {\r\n            width: 60px;\r\n            height: 60px;\r\n            border-radius: 10px;\r\n            background: linear-gradient(135deg, #5fbfbc 0%, #4a9c99 100%);\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: center;\r\n            font-size: 30px;\r\n            flex-shrink: 0;\r\n        }\r\n        \r\n        .flight-main-info {\r\n            flex: 1;\r\n            min-width: 0;\r\n        }\r\n        \r\n        .flight-header {\r\n            display: flex;\r\n            align-items: center;\r\n            gap: 10px;\r\n            margin-bottom: 5px;\r\n        }\r\n        \r\n        .flight-callsign {\r\n            font-size: 20px;\r\n            font-weight: 700;\r\n            color: #333;\r\n        }\r\n        \r\n        .flight-route {\r\n            font-size: 14px;\r\n            color: #666;\r\n            font-weight: 500;\r\n        }\r\n        \r\n        .flight-stats {\r\n            display: flex;\r\n            gap: 20px;\r\n            flex-shrink: 0;\r\n        }\r\n        \r\n        .flight-stat {\r\n            text-align: center;\r\n        }\r\n        \r\n        .flight-stat-label {\r\n            font-size: 10px;\r\n            color: #888;\r\n            text-transform: uppercase;\r\n            font-weight: 600;\r\n            margin-bottom: 3px;\r\n        }\r\n        \r\n        .flight-stat-value {\r\n            font-size: 16px;\r\n            font-weight: 700;\r\n            color: #333;\r\n        }\r\n        \r\n        .flight-expanded {\r\n            max-height: 0;\r\n            opacity: 0;\r\n            overflow: hidden;\r\n            transition: all 0.4s ease;\r\n            padding: 0 20px;\r\n        }\r\n        \r\n        .flight-row:hover .flight-expanded {\r\n            max-height: 200px;\r\n            opacity: 1;\r\n            padding: 0 20px 20px 20px;\r\n        }\r\n        \r\n        .flight-details {\r\n            display: grid;\r\n            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\r\n            gap: 15px;\r\n            padding-top: 15px;\r\n            border-top: 2px solid #f0f0f0;\r\n        }\r\n        \r\n        .flight-detail-item {\r\n            background: #f8f9fa;\r\n            padding: 10px;\r\n            border-radius: 8px;\r\n            text-align: center;\r\n        }\r\n        \r\n        .flight-detail-label {\r\n            font-size: 10px;\r\n            color: #888;\r\n            text-transform: uppercase;\r\n            font-weight: 600;\r\n            margin-bottom: 5px;\r\n        }\r\n        \r\n        .flight-detail-value {\r\n            font-size: 14px;\r\n            font-weight: 700;\r\n            color: #333;\r\n        }\r\n        \r\n        .no-flights-message {\r\n            text-align: center;\r\n            padding: 60px 20px;\r\n            background: white;\r\n            border-radius: 12px;\r\n        }\r\n        \r\n        .no-flights-icon {\r\n            font-size: 80px;\r\n            margin-bottom: 20px;\r\n        }\r\n        \r\n        .no-flights-text {\r\n            font-size: 20px;\r\n            color: #888;\r\n            font-weight: 600;\r\n        }\r\n        \r\n        .loading-spinner {\r\n            text-align: center;\r\n            padding: 60px;\r\n        }\r\n        \r\n        .spinner {\r\n            border: 4px solid #f3f3f3;\r\n            border-top: 4px solid #5fbfbc;\r\n            border-radius: 50%;\r\n            width: 50px;\r\n            height: 50px;\r\n            animation: spin 1s linear infinite;\r\n            margin: 0 auto 20px;\r\n        }\r\n        \r\n        @keyframes spin {\r\n            0% { transform: rotate(0deg); }\r\n            100% { transform: rotate(360deg); }\r\n        }\r\n        \r\n        .stats-bar {\r\n            display: flex;\r\n            justify-content: space-around;\r\n            padding: 20px;\r\n            background: white;\r\n            border-radius: 12px;\r\n            margin-bottom: 20px;\r\n        }\r\n        \r\n        .stat-box {\r\n            text-align: center;\r\n        }\r\n        \r\n        .stat-box-value {\r\n            font-size: 32px;\r\n            font-weight: 700;\r\n            color: #5fbfbc;\r\n        }\r\n        \r\n        .stat-box-label {\r\n            font-size: 12px;\r\n            color: #888;\r\n            text-transform: uppercase;\r\n            font-weight: 600;\r\n            margin-top: 5px;\r\n        }\r\n        \r\n        @media (max-width: 768px) {\r\n            .live-map-wrapper h1 {\r\n                font-size: 24px;\r\n                padding: 25px;\r\n            }\r\n            \r\n            .map-content {\r\n                padding: 15px;\r\n            }\r\n            \r\n            #liveMap {\r\n                height: 400px;\r\n            }\r\n            \r\n            .flight-compact {\r\n                flex-wrap: wrap;\r\n            }\r\n            \r\n            .flight-stats {\r\n                width: 100%;\r\n                justify-content: space-between;\r\n            }\r\n        }\r\n    <\/style>\r\n    \r\n    <div class=\"live-map-container\">\r\n        <div class=\"live-map-wrapper\">\r\n            <h1>Live Flight Map - Dhalion AirVA<\/h1>\r\n            \r\n            <div class=\"map-controls\">\r\n                <label>Network:<\/label>\r\n                <button onclick=\"filterNetwork('all')\" data-network=\"all\" class=\"active\">All Networks<\/button>\r\n                <button onclick=\"filterNetwork('ivao')\" data-network=\"ivao\">IVAO<\/button>\r\n                <button onclick=\"filterNetwork('vatsim')\" data-network=\"vatsim\">VATSIM<\/button>\r\n                <button onclick=\"refreshFlights()\" style=\"margin-left: auto;\">\ud83d\udd04 Refresh<\/button>\r\n            <\/div>\r\n            \r\n            <div class=\"map-content\">\r\n                <div class=\"stats-bar\" id=\"statsBar\">\r\n                    <div class=\"stat-box\">\r\n                        <div class=\"stat-box-value\" id=\"totalFlights\">-<\/div>\r\n                        <div class=\"stat-box-label\">Active Flights<\/div>\r\n                    <\/div>\r\n                    <div class=\"stat-box\">\r\n                        <div class=\"stat-box-value\" id=\"ivaoCount\">-<\/div>\r\n                        <div class=\"stat-box-label\">IVAO<\/div>\r\n                    <\/div>\r\n                    <div class=\"stat-box\">\r\n                        <div class=\"stat-box-value\" id=\"vatsimCount\">-<\/div>\r\n                        <div class=\"stat-box-label\">VATSIM<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n                \r\n                <div class=\"map-container-inner\">\r\n                    <div id=\"liveMap\"><\/div>\r\n                <\/div>\r\n                \r\n                <div class=\"flights-list\" id=\"flightsList\">\r\n                    <div class=\"loading-spinner\">\r\n                        <div class=\"spinner\"><\/div>\r\n                        <div style=\"color: #888; font-size: 16px;\">Loading live flights...<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n    \r\n    <link rel=\"stylesheet\" href=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.css\" \/>\r\n    <script src=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.js\"><\/script>\r\n    \r\n    <script>\r\n    const PROXY_URL = 'https:\/\/dhalionairva.com\/ivao-vatsim-proxy.php';\r\n    \r\n    let map;\r\n    let flightMarkers = [];\r\n    let allFlights = [];\r\n    let currentFilter = 'all';\r\n    \r\n    \/\/ Inicializar mapa\r\n    function initMap() {\r\n        map = L.map('liveMap').setView([10, -84], 6); \/\/ Centrado en Costa Rica\/Centroam\u00e9rica\r\n        \r\n        L.tileLayer('https:\/\/{s}.tile.openstreetmap.org\/{z}\/{x}\/{y}.png', {\r\n            attribution: '\u00a9 OpenStreetMap contributors',\r\n            maxZoom: 18\r\n        }).addTo(map);\r\n    }\r\n    \r\n    \/\/ Obtener vuelos de IVAO\r\n    async function getIVAOFlights() {\r\n        try {\r\n            const response = await fetch(PROXY_URL + '?network=ivao&airline=DIO');\r\n            if (!response.ok) throw new Error('IVAO API error');\r\n            const data = await response.json();\r\n            return data.error ? [] : data;\r\n        } catch (error) {\r\n            console.error('Error fetching IVAO flights:', error);\r\n            return [];\r\n        }\r\n    }\r\n    \r\n    \/\/ Obtener vuelos de VATSIM\r\n    async function getVATSIMFlights() {\r\n        try {\r\n            const response = await fetch(PROXY_URL + '?network=vatsim&airline=DIO');\r\n            if (!response.ok) throw new Error('VATSIM API error');\r\n            const data = await response.json();\r\n            return data.error ? [] : data;\r\n        } catch (error) {\r\n            console.error('Error fetching VATSIM flights:', error);\r\n            return [];\r\n        }\r\n    }\r\n    \r\n    \/\/ Actualizar estad\u00edsticas\r\n    function updateStats(flights) {\r\n        const ivaoFlights = flights.filter(f => f.network === 'ivao');\r\n        const vatsimFlights = flights.filter(f => f.network === 'vatsim');\r\n        \r\n        document.getElementById('totalFlights').textContent = flights.length;\r\n        document.getElementById('ivaoCount').textContent = ivaoFlights.length;\r\n        document.getElementById('vatsimCount').textContent = vatsimFlights.length;\r\n    }\r\n    \r\n    \/\/ Mostrar vuelos en el mapa\r\n    function displayFlightsOnMap(flights) {\r\n        \/\/ Limpiar marcadores anteriores\r\n        flightMarkers.forEach(marker => map.removeLayer(marker));\r\n        flightMarkers = [];\r\n        \r\n        flights.forEach(flight => {\r\n            const planeIcon = L.divIcon({\r\n                className: 'custom-plane-icon',\r\n                html: `<div style=\"\r\n                    width: 30px; \r\n                    height: 30px; \r\n                    display: flex; \r\n                    align-items: center; \r\n                    justify-content: center;\r\n                    transform: rotate(${flight.heading}deg);\r\n                    filter: drop-shadow(0 2px 4px rgba(0,0,0,0.3));\">\r\n                    <span style=\"font-size: 24px;\">${flight.network === 'ivao' ? '\ud83d\udd35' : '\ud83d\udfe2'}\u2708\ufe0f<\/span>\r\n                <\/div>`,\r\n                iconSize: [30, 30],\r\n                iconAnchor: [15, 15]\r\n            });\r\n            \r\n            const marker = L.marker([flight.latitude, flight.longitude], { icon: planeIcon })\r\n                .bindPopup(`\r\n                    <div style=\"min-width: 200px;\">\r\n                        <strong style=\"font-size: 16px; color: ${flight.network === 'ivao' ? '#0066cc' : '#00a651'};\">\r\n                            ${flight.callsign}\r\n                        <\/strong><br>\r\n                        <strong>Pilot:<\/strong> ${flight.pilot}<br>\r\n                        <strong>Route:<\/strong> ${flight.departure} \u2192 ${flight.arrival}<br>\r\n                        <strong>Altitude:<\/strong> ${flight.altitude} ft<br>\r\n                        <strong>Speed:<\/strong> ${flight.groundSpeed} kts<br>\r\n                        <strong>Aircraft:<\/strong> ${flight.aircraft}<br>\r\n                        <strong>Network:<\/strong> <span style=\"\r\n                            background: ${flight.network === 'ivao' ? '#0066cc' : '#00a651'}; \r\n                            color: white; \r\n                            padding: 2px 8px; \r\n                            border-radius: 10px;\r\n                            font-size: 11px;\r\n                            font-weight: bold;\">\r\n                            ${flight.network.toUpperCase()}\r\n                        <\/span>\r\n                    <\/div>\r\n                `)\r\n                .addTo(map);\r\n            \r\n            flightMarkers.push(marker);\r\n        });\r\n        \r\n        \/\/ Ajustar vista si hay vuelos\r\n        if (flights.length > 0) {\r\n            const bounds = L.latLngBounds(flights.map(f => [f.latitude, f.longitude]));\r\n            map.fitBounds(bounds, { padding: [50, 50], maxZoom: 8 });\r\n        }\r\n    }\r\n    \r\n    \/\/ Mostrar lista de vuelos\r\n    function displayFlightsList(flights) {\r\n        const listContainer = document.getElementById('flightsList');\r\n        \r\n        if (flights.length === 0) {\r\n            listContainer.innerHTML = `\r\n                <div class=\"no-flights-message\">\r\n                    <div class=\"no-flights-icon\">\u2708\ufe0f<\/div>\r\n                    <div class=\"no-flights-text\">No active flights at the moment<\/div>\r\n                    <p style=\"color: #aaa; margin-top: 10px;\">Check back later or start your flight!<\/p>\r\n                <\/div>\r\n            `;\r\n            return;\r\n        }\r\n        \r\n        let html = '';\r\n        flights.forEach(flight => {\r\n            html += `\r\n                <div class=\"flight-row\" data-network=\"${flight.network}\">\r\n                    <div class=\"flight-compact\">\r\n                        <div class=\"flight-icon\">\u2708\ufe0f<\/div>\r\n                        <div class=\"flight-main-info\">\r\n                            <div class=\"flight-header\">\r\n                                <span class=\"flight-callsign\">${flight.callsign}<\/span>\r\n                                <span class=\"network-badge ${flight.network}\">${flight.network.toUpperCase()}<\/span>\r\n                            <\/div>\r\n                            <div class=\"flight-route\">${flight.departure} \u2192 ${flight.arrival}<\/div>\r\n                        <\/div>\r\n                        <div class=\"flight-stats\">\r\n                            <div class=\"flight-stat\">\r\n                                <div class=\"flight-stat-label\">Altitude<\/div>\r\n                                <div class=\"flight-stat-value\">${flight.altitude} ft<\/div>\r\n                            <\/div>\r\n                            <div class=\"flight-stat\">\r\n                                <div class=\"flight-stat-label\">Speed<\/div>\r\n                                <div class=\"flight-stat-value\">${flight.groundSpeed} kts<\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n                    <div class=\"flight-expanded\">\r\n                        <div class=\"flight-details\">\r\n                            <div class=\"flight-detail-item\">\r\n                                <div class=\"flight-detail-label\">Pilot<\/div>\r\n                                <div class=\"flight-detail-value\">${flight.pilot}<\/div>\r\n                            <\/div>\r\n                            <div class=\"flight-detail-item\">\r\n                                <div class=\"flight-detail-label\">Aircraft<\/div>\r\n                                <div class=\"flight-detail-value\">${flight.aircraft}<\/div>\r\n                            <\/div>\r\n                            <div class=\"flight-detail-item\">\r\n                                <div class=\"flight-detail-label\">Heading<\/div>\r\n                                <div class=\"flight-detail-value\">${flight.heading}\u00b0<\/div>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        });\r\n        \r\n        listContainer.innerHTML = html;\r\n    }\r\n    \r\n    \/\/ Cargar todos los vuelos\r\n    async function loadFlights() {\r\n        try {\r\n            const [ivaoFlights, vatsimFlights] = await Promise.all([\r\n                getIVAOFlights(),\r\n                getVATSIMFlights()\r\n            ]);\r\n            \r\n            allFlights = [...ivaoFlights, ...vatsimFlights];\r\n            \r\n            updateStats(allFlights);\r\n            \r\n            const filtered = currentFilter === 'all' \r\n                ? allFlights \r\n                : allFlights.filter(f => f.network === currentFilter);\r\n            \r\n            displayFlightsOnMap(filtered);\r\n            displayFlightsList(filtered);\r\n        } catch (error) {\r\n            console.error('Error loading flights:', error);\r\n            document.getElementById('flightsList').innerHTML = `\r\n                <div class=\"no-flights-message\">\r\n                    <div class=\"no-flights-icon\">\u26a0\ufe0f<\/div>\r\n                    <div class=\"no-flights-text\">Error loading flight data<\/div>\r\n                    <p style=\"color: #aaa; margin-top: 10px;\">Please try refreshing the page<\/p>\r\n                <\/div>\r\n            `;\r\n        }\r\n    }\r\n    \r\n    \/\/ Filtrar por red\r\n    function filterNetwork(network) {\r\n        currentFilter = network;\r\n        \r\n        document.querySelectorAll('.map-controls button[data-network]').forEach(btn => {\r\n            btn.classList.remove('active');\r\n        });\r\n        document.querySelector(`button[data-network=\"${network}\"]`).classList.add('active');\r\n        \r\n        const filtered = network === 'all' \r\n            ? allFlights \r\n            : allFlights.filter(f => f.network === network);\r\n        \r\n        displayFlightsOnMap(filtered);\r\n        displayFlightsList(filtered);\r\n    }\r\n    \r\n    \/\/ Refrescar vuelos\r\n    function refreshFlights() {\r\n        document.getElementById('flightsList').innerHTML = `\r\n            <div class=\"loading-spinner\">\r\n                <div class=\"spinner\"><\/div>\r\n                <div style=\"color: #888; font-size: 16px;\">Refreshing flights...<\/div>\r\n            <\/div>\r\n        `;\r\n        loadFlights();\r\n    }\r\n    \r\n    \/\/ Inicializar\r\n    document.addEventListener('DOMContentLoaded', function() {\r\n        initMap();\r\n        loadFlights();\r\n        \r\n        \/\/ Auto-refresh cada 2 minutos\r\n        setInterval(loadFlights, 120000);\r\n    });\r\n    <\/script>\r\n    \n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"class_list":["post-1207","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/dhalionairva.com\/index.php\/wp-json\/wp\/v2\/pages\/1207","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dhalionairva.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/dhalionairva.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/dhalionairva.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dhalionairva.com\/index.php\/wp-json\/wp\/v2\/comments?post=1207"}],"version-history":[{"count":2,"href":"https:\/\/dhalionairva.com\/index.php\/wp-json\/wp\/v2\/pages\/1207\/revisions"}],"predecessor-version":[{"id":1211,"href":"https:\/\/dhalionairva.com\/index.php\/wp-json\/wp\/v2\/pages\/1207\/revisions\/1211"}],"wp:attachment":[{"href":"https:\/\/dhalionairva.com\/index.php\/wp-json\/wp\/v2\/media?parent=1207"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}