{
    "component": {
        "id": 29,
        "name": "Widget NRES",
        "code": "widget_nres",
        "content": "{{--\r\n  WIDGET NRES — Cuaca (data.gov.my) + Indeks Pencemaran Udara (APIMS · DOE)\r\n  ---------------------------------------------------------------------------\r\n  · Cuaca     : API terbuka data.gov.my (proksi: /widget/weather)\r\n  · IPU/APIMS : widget rasmi DOE (widgetnres.js) + fallback proksi\r\n                (/widget/air-quality) kerana CORS DOE hanya benarkan\r\n                eqmp.doe.gov.my sahaja.\r\n--}}\r\n<section class=\"nres-widget row g-3 mt-4 mb-5\" aria-label=\"{{ t('Widget NRES') }}\">\r\n\r\n    {{-- Kad 1: Cuaca --}}\r\n    <div class=\"col-lg-6\">\r\n        <div class=\"nres-widget__card\">\r\n            <div class=\"nres-widget__head\">\r\n                <span class=\"nres-widget__icon\" aria-hidden=\"true\">\r\n                    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"\r\n                        stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n                        <path d=\"M17.5 19a4.5 4.5 0 1 0-1.4-8.8A5.5 5.5 0 0 0 6 11.5 3.5 3.5 0 0 0 6.5 19z\" />\r\n                    </svg>\r\n                </span>\r\n                <span class=\"nres-widget__title\">{{ t('Cuaca Semasa') }}</span>\r\n                <span class=\"nres-widget__src\">data.gov.my</span>\r\n            </div>\r\n\r\n            <div class=\"nres-widget__body\" id=\"nres-weather\"\r\n                data-endpoint=\"{{ url('/widget/weather') }}\" data-location=\"Putrajaya\">\r\n                <p class=\"nres-widget__muted\">{{ t('Memuatkan ramalan cuaca…') }}</p>\r\n            </div>\r\n\r\n            <div class=\"nres-widget__foot\">\r\n                <label class=\"nres-widget__label\" for=\"nres-weather-loc\">{{ t('Lokasi') }}</label>\r\n                <select class=\"nres-widget__select\" id=\"nres-weather-loc\">\r\n                    <option value=\"Putrajaya\" selected>Putrajaya</option>\r\n                    <option value=\"Kuala Lumpur\">Kuala Lumpur</option>\r\n                    <option value=\"Ipoh\">Ipoh</option>\r\n                    <option value=\"Kuantan\">Kuantan</option>\r\n                    <option value=\"Kuching\">Kuching</option>\r\n                    <option value=\"Kota Kinabalu\">Kota Kinabalu</option>\r\n                    <option value=\"Johor Bahru\">Johor Bahru</option>\r\n                    <option value=\"Kangar\">Kangar</option>\r\n                </select>\r\n            </div>\r\n        </div>\r\n    </div>\r\n\r\n    {{-- Kad 2: Indeks Pencemaran Udara --}}\r\n    <div class=\"col-lg-6\">\r\n        <div class=\"nres-widget__card\">\r\n            <div class=\"nres-widget__head\">\r\n                <span class=\"nres-widget__icon\" aria-hidden=\"true\">\r\n                    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"\r\n                        stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n                        <path d=\"M3 8h11a3 3 0 1 0-3-3\" />\r\n                        <path d=\"M3 12h15a3 3 0 1 1-3 3\" />\r\n                        <path d=\"M3 16h8\" />\r\n                    </svg>\r\n                </span>\r\n                <span class=\"nres-widget__title\">{{ t('Indeks Pencemaran Udara') }}</span>\r\n                <span class=\"nres-widget__src\">APIMS · DOE</span>\r\n            </div>\r\n\r\n            <div class=\"nres-widget__body\">\r\n                {{-- Widget rasmi DOE (jika CORS DOE benarkan) --}}\r\n                <div id=\"apims-widget-container\" class=\"nres-widget__doe\"></div>\r\n\r\n                {{-- Fallback: data melalui proksi kita --}}\r\n                <div id=\"nres-air\" class=\"nres-widget__air\" hidden\r\n                    data-endpoint=\"{{ url('/widget/air-quality') }}\">\r\n                    <p class=\"nres-widget__muted\">{{ t('Memuatkan IPU…') }}</p>\r\n                </div>\r\n            </div>\r\n\r\n            <div class=\"nres-widget__foot nres-widget__foot--note\">\r\n                <span id=\"nres-air-updated\" class=\"nres-widget__note\"></span>\r\n            </div>\r\n        </div>\r\n    </div>\r\n</section>\r\n\r\n<style>\r\n    .nres-widget__card {\r\n        display: flex;\r\n        flex-direction: column;\r\n        height: 100%;\r\n        border: 1px solid #dbe7e9;\r\n        border-radius: 16px;\r\n        background: #fff;\r\n        box-shadow: 0 10px 26px rgba(16, 62, 56, .06);\r\n        overflow: hidden;\r\n    }\r\n\r\n    .nres-widget__head {\r\n        display: flex;\r\n        align-items: center;\r\n        gap: 10px;\r\n        padding: 14px 18px;\r\n        background: linear-gradient(120deg, #14413a, #11808f);\r\n        color: #fff;\r\n    }\r\n\r\n    .nres-widget__icon {\r\n        display: inline-flex;\r\n        align-items: center;\r\n        justify-content: center;\r\n        width: 34px;\r\n        height: 34px;\r\n        border-radius: 10px;\r\n        background: rgba(255, 255, 255, .18);\r\n        flex-shrink: 0;\r\n    }\r\n\r\n    .nres-widget__icon svg {\r\n        width: 20px;\r\n        height: 20px;\r\n    }\r\n\r\n    .nres-widget__title {\r\n        flex: 1;\r\n        font-size: .98rem;\r\n        font-weight: 800;\r\n        letter-spacing: .01em;\r\n    }\r\n\r\n    .nres-widget__src {\r\n        padding: 3px 10px;\r\n        border-radius: 999px;\r\n        background: rgba(255, 255, 255, .18);\r\n        font-size: .68rem;\r\n        font-weight: 700;\r\n        letter-spacing: .04em;\r\n        text-transform: uppercase;\r\n    }\r\n\r\n    .nres-widget__body {\r\n        flex: 1;\r\n        padding: 18px;\r\n    }\r\n\r\n    .nres-widget__muted {\r\n        margin: 0;\r\n        color: #7b8f8c;\r\n        font-size: .88rem;\r\n    }\r\n\r\n    .nres-widget__foot {\r\n        display: flex;\r\n        align-items: center;\r\n        gap: 10px;\r\n        padding: 12px 18px;\r\n        border-top: 1px solid #eef4f5;\r\n        background: #f8fbfb;\r\n    }\r\n\r\n    .nres-widget__foot--note {\r\n        justify-content: flex-end;\r\n        min-height: 44px;\r\n    }\r\n\r\n    .nres-widget__label {\r\n        color: #4a6b66;\r\n        font-size: .8rem;\r\n        font-weight: 700;\r\n    }\r\n\r\n    .nres-widget__select {\r\n        flex: 1;\r\n        padding: 8px 10px;\r\n        border: 1px solid #d9e6e7;\r\n        border-radius: 10px;\r\n        background: #fff;\r\n        color: #24443f;\r\n        font-size: .85rem;\r\n        font-weight: 600;\r\n    }\r\n\r\n    .nres-widget__note {\r\n        color: #7b8f8c;\r\n        font-size: .74rem;\r\n    }\r\n\r\n    .nres-widget__doe {\r\n        max-width: 220px;\r\n        margin: 0 auto;\r\n    }\r\n</style>\r\n\r\n{{-- Widget rasmi DOE (APIMS) --}}\r\n<script src=\"https://eqms.doe.gov.my/widget/widgetnres.js\" defer></script>\r\n\r\n<script>\r\n    (function () {\r\n        'use strict';\r\n\r\n        /* ─────────────── 1. CUACA (data.gov.my) ─────────────── */\r\n        var wBox = document.getElementById('nres-weather');\r\n        var wSel = document.getElementById('nres-weather-loc');\r\n\r\n        function weatherIcon(text) {\r\n            var t = (text || '').toLowerCase();\r\n\r\n            if (t.indexOf('ribut') > -1 || t.indexOf('petir') > -1) return '⛈️';\r\n            if (t.indexOf('hujan') > -1) return '🌧️';\r\n            if (t.indexOf('mendung') > -1 || t.indexOf('awan') > -1) return '☁️';\r\n            if (t.indexOf('jerebu') > -1) return '🌫️';\r\n\r\n            return '☀️';\r\n        }\r\n\r\n        function loadWeather(loc) {\r\n            if (!wBox) return;\r\n\r\n            wBox.innerHTML = '<p class=\"nres-widget__muted\">Memuatkan ramalan cuaca…</p>';\r\n\r\n            fetch(wBox.dataset.endpoint + '?location=' + encodeURIComponent(loc || 'Putrajaya'))\r\n                .then(function (r) { return r.json(); })\r\n                .then(function (d) {\r\n                    if (!d || !d.ok || !d.items || !d.items.length) {\r\n                        wBox.innerHTML = '<p class=\"nres-widget__muted\">Ramalan cuaca tidak tersedia buat masa ini.</p>';\r\n\r\n                        return;\r\n                    }\r\n\r\n                    var it = d.items[0];\r\n                    var parts = [['Pagi', it.morning], ['Petang', it.afternoon], ['Malam', it.night]];\r\n                    var rows = '';\r\n\r\n                    for (var i = 0; i < parts.length; i++) {\r\n                        rows += '<div class=\"nres-wx__row\"><span class=\"nres-wx__when\">' + parts[i][0] + '</span>' +\r\n                            '<span class=\"nres-wx__val\">' + weatherIcon(parts[i][1]) + ' ' + (parts[i][1] || '-') + '</span></div>';\r\n                    }\r\n\r\n                    wBox.innerHTML =\r\n                        '<div class=\"nres-wx\">' +\r\n                            '<div class=\"nres-wx__top\">' +\r\n                                '<span class=\"nres-wx__icon\">' + weatherIcon(it.summary) + '</span>' +\r\n                                '<div>' +\r\n                                    '<div class=\"nres-wx__loc\">' + (it.location || loc) + '</div>' +\r\n                                    '<div class=\"nres-wx__summary\">' + (it.summary || '-') +\r\n                                        (it.summary_when ? ' · ' + it.summary_when : '') + '</div>' +\r\n                                '</div>' +\r\n                                '<div class=\"nres-wx__temp\">' +\r\n                                    '<span class=\"nres-wx__max\">' + (it.max_temp != null ? it.max_temp + '°' : '-') + '</span>' +\r\n                                    '<span class=\"nres-wx__min\">' + (it.min_temp != null ? it.min_temp + '°' : '') + '</span>' +\r\n                                '</div>' +\r\n                            '</div>' +\r\n                            '<div class=\"nres-wx__rows\">' + rows + '</div>' +\r\n                            '<div class=\"nres-wx__date\">' + (it.date || '') + '</div>' +\r\n                        '</div>';\r\n                })\r\n                .catch(function () {\r\n                    wBox.innerHTML = '<p class=\"nres-widget__muted\">Ramalan cuaca tidak tersedia buat masa ini.</p>';\r\n                });\r\n        }\r\n\r\n        if (wBox && wSel) {\r\n            loadWeather(wBox.dataset.location);\r\n\r\n            wSel.addEventListener('change', function () {\r\n                loadWeather(this.value);\r\n            });\r\n        }\r\n\r\n        /* ─────────────── 2. INDEKS PENCEMARAN UDARA (APIMS · DOE) ─────────────── */\r\n        var aBox = document.getElementById('nres-air');\r\n        var aNote = document.getElementById('nres-air-updated');\r\n\r\n        var AIR_COLORS = {\r\n            'Baik': '#00a651',\r\n            'Sederhana': '#0072bc',\r\n            'Moderate': '#0072bc',\r\n            'Tidak Sihat': '#fff200',\r\n            'Unhealthy': '#fff200',\r\n            'Sangat Tidak Sihat': '#f7941d',\r\n            'Very Unhealthy': '#f7941d',\r\n            'Berbahaya': '#ed1c24',\r\n            'Hazardous': '#ed1c24'\r\n        };\r\n\r\n        function airColor(cat) {\r\n            return AIR_COLORS[cat] || '#0072bc';\r\n        }\r\n\r\n        function airTextColor(cat) {\r\n            return ['Tidak Sihat', 'Unhealthy'].indexOf(cat) > -1 ? '#3a3a00' : '#fff';\r\n        }\r\n\r\n        function loadAir() {\r\n            if (!aBox) return;\r\n\r\n            aBox.innerHTML = '<p class=\"nres-widget__muted\">Memuatkan IPU…</p>';\r\n\r\n            fetch(aBox.dataset.endpoint)\r\n                .then(function (r) { return r.json(); })\r\n                .then(function (d) {\r\n                    if (!d || !d.ok) {\r\n                        aBox.innerHTML = '<p class=\"nres-widget__muted\">Data IPU tidak tersedia buat masa ini.</p>';\r\n\r\n                        return;\r\n                    }\r\n\r\n                    aBox.innerHTML =\r\n                        '<div class=\"nres-air\">' +\r\n                            '<div class=\"nres-air__badge\" style=\"background:' + airColor(d.category) +\r\n                                ';color:' + airTextColor(d.category) + '\">' +\r\n                                '<span class=\"nres-air__lbl\">IPU</span>' +\r\n                                '<span class=\"nres-air__val\">' + (d.api != null ? d.api : '-') + '</span>' +\r\n                                '<span class=\"nres-air__cat\">' + (d.category || '-') + '</span>' +\r\n                            '</div>' +\r\n                            '<div class=\"nres-air__meta\">' +\r\n                                '<div class=\"nres-air__loc\">' + (d.location || '-') + '</div>' +\r\n                                '<div class=\"nres-air__stn\">Stesen ' + (d.station_id || '-') + '</div>' +\r\n                            '</div>' +\r\n                        '</div>';\r\n\r\n                    if (aNote && d.date_time) {\r\n                        aNote.textContent = 'Dikemas kini ' + String(d.date_time).replace('T', ' ');\r\n                    }\r\n                })\r\n                .catch(function () {\r\n                    aBox.innerHTML = '<p class=\"nres-widget__muted\">Data IPU tidak tersedia buat masa ini.</p>';\r\n                });\r\n        }\r\n\r\n        /* Widget rasmi DOE cuba muat data. Jika gagal (CORS DOE hanya benarkan\r\n           eqmp.doe.gov.my), guna proksi kita supaya kad ini tetap berfungsi. */\r\n        function useAirFallback() {\r\n            var doe = document.getElementById('apims-widget-container');\r\n            var reading = document.getElementById('apims-reading');\r\n            var val = reading ? (reading.textContent || '').trim() : '';\r\n            var ok = val !== '' && val !== '-' && val !== 'LOADING...';\r\n\r\n            if (doe) {\r\n                doe.hidden = !ok;\r\n            }\r\n\r\n            if (aBox) {\r\n                aBox.hidden = ok;\r\n            }\r\n\r\n            if (!ok) {\r\n                loadAir();\r\n            }\r\n        }\r\n\r\n        if (document.readyState === 'loading') {\r\n            document.addEventListener('DOMContentLoaded', function () {\r\n                setTimeout(useAirFallback, 4500);\r\n            });\r\n        } else {\r\n            setTimeout(useAirFallback, 4500);\r\n        }\r\n    })();\r\n</script>\r\n\r\n<style>\r\n    .nres-wx__top {\r\n        display: flex;\r\n        align-items: center;\r\n        gap: 14px;\r\n    }\r\n\r\n    .nres-wx__icon {\r\n        font-size: 2rem;\r\n        line-height: 1;\r\n    }\r\n\r\n    .nres-wx__loc {\r\n        color: #14413a;\r\n        font-size: .95rem;\r\n        font-weight: 800;\r\n    }\r\n\r\n    .nres-wx__summary {\r\n        color: #5c6b6b;\r\n        font-size: .82rem;\r\n    }\r\n\r\n    .nres-wx__temp {\r\n        margin-left: auto;\r\n        text-align: right;\r\n    }\r\n\r\n    .nres-wx__max {\r\n        display: block;\r\n        color: #11808f;\r\n        font-size: 1.5rem;\r\n        font-weight: 800;\r\n        line-height: 1.1;\r\n    }\r\n\r\n    .nres-wx__min {\r\n        color: #8aa0a0;\r\n        font-size: .82rem;\r\n        font-weight: 600;\r\n    }\r\n\r\n    .nres-wx__rows {\r\n        display: grid;\r\n        gap: 6px;\r\n        margin-top: 14px;\r\n    }\r\n\r\n    .nres-wx__row {\r\n        display: flex;\r\n        justify-content: space-between;\r\n        gap: 10px;\r\n        padding: 7px 10px;\r\n        border-radius: 9px;\r\n        background: #f6fbfb;\r\n        font-size: .82rem;\r\n    }\r\n\r\n    .nres-wx__when {\r\n        color: #4a6b66;\r\n        font-weight: 700;\r\n    }\r\n\r\n    .nres-wx__val {\r\n        color: #24443f;\r\n        font-weight: 600;\r\n    }\r\n\r\n    .nres-wx__date {\r\n        margin-top: 12px;\r\n        color: #8aa0a0;\r\n        font-size: .74rem;\r\n        text-align: right;\r\n    }\r\n\r\n    .nres-air {\r\n        display: flex;\r\n        align-items: center;\r\n        gap: 16px;\r\n    }\r\n\r\n    .nres-air__badge {\r\n        display: flex;\r\n        flex-direction: column;\r\n        align-items: center;\r\n        justify-content: center;\r\n        width: 96px;\r\n        height: 96px;\r\n        border-radius: 16px;\r\n        flex-shrink: 0;\r\n        text-align: center;\r\n    }\r\n\r\n    .nres-air__lbl {\r\n        font-size: .62rem;\r\n        font-weight: 700;\r\n        letter-spacing: .08em;\r\n    }\r\n\r\n    .nres-air__val {\r\n        font-size: 2rem;\r\n        font-weight: 800;\r\n        line-height: 1.1;\r\n    }\r\n\r\n    .nres-air__cat {\r\n        font-size: .62rem;\r\n        font-weight: 700;\r\n    }\r\n\r\n    .nres-air__loc {\r\n        color: #14413a;\r\n        font-size: .95rem;\r\n        font-weight: 800;\r\n    }\r\n\r\n    .nres-air__stn {\r\n        margin-top: 4px;\r\n        color: #7b8f8c;\r\n        font-size: .8rem;\r\n    }\r\n</style>\r\n",
        "type": "PHP",
        "category": "Section",
        "status": 1,
        "created_at": "2026-11-01 01:01:32",
        "updated_at": "2026-11-01 16:27:55"
    },
    "pages": [
        {
            "id": 96,
            "page_fk": 22,
            "component_fk": 29,
            "sort": 5,
            "params": null,
            "created_at": null,
            "updated_at": null
        }
    ]
}