{
    "component": {
        "id": 31,
        "name": "Calender NRES",
        "code": "calender_nres",
        "content": "{{--\n  CALENDER NRES — Kalendar aktiviti (module content-calendar)\n  ---------------------------------------------------------------------------\n  Data SEBENAR:\n    /widget/calendar  → module content-calendar\n                        (ContentCalendar + ContentCalendarTranslation)\n                        ?month=YYYY-MM\n  Admin module: /portal-k7m4x9/content-calendar\n--}}\n<div class=\"container-xl\">\n    {{-- ── KALENDAR NRES ─────────────────────────────────────────────── --}}\n    <section class=\"calendar-section mb-5\" id=\"kalendar\" data-calendar=\"{{ url('/widget/calendar') }}\">\n        <div class=\"section-heading\">\n            <div>\n                <div class=\"section-kicker\">PROGRAM &amp; AKTIVITI</div>\n                <h2>Kalendar NRES</h2>\n            </div>\n\n            <div class=\"calendar-controls\">\n                <button id=\"previousMonth\" type=\"button\" aria-label=\"Bulan sebelumnya\">‹</button>\n                <strong id=\"calendarMonth\">—</strong>\n                <button id=\"nextMonth\" type=\"button\" aria-label=\"Bulan seterusnya\">›</button>\n            </div>\n        </div>\n\n        <div class=\"calendar-layout\">\n            <div class=\"calendar-box\">\n                <div class=\"calendar-week\" aria-hidden=\"true\">\n                    <span>Isn</span><span>Sel</span><span>Rab</span><span>Kha</span><span>Jum</span><span>Sab</span><span>Ahd</span>\n                </div>\n\n                <div id=\"calendarDays\" class=\"calendar-days\"></div>\n\n                <p class=\"small text-body-secondary mt-3 mb-0\">\n                    ● Tarikh beraktiviti &nbsp; · &nbsp; Pilih tarikh untuk butiran\n                </p>\n            </div>\n\n            <div class=\"calendar-agenda\">\n                <h3 id=\"selectedDate\">—</h3>\n                <div id=\"dayEvents\" aria-live=\"polite\">\n                    <p class=\"small text-body-secondary\">Tiada aktiviti disenaraikan pada tarikh ini.</p>\n                </div>\n\n                <hr>\n\n                <h3>Senarai aktiviti bulan ini</h3>\n                <div id=\"monthEvents\">\n                    <p class=\"small text-body-secondary\">Tiada aktiviti disenaraikan untuk bulan ini.</p>\n                </div>\n            </div>\n        </div>\n    </section>\n</div>\n\n<style>\n    /* ── tajuk seksyen ─────────────────────────────────────────────── */\n    .section-heading {\n        display: flex;\n        flex-wrap: wrap;\n        align-items: flex-end;\n        justify-content: space-between;\n        gap: 12px;\n        margin-bottom: 16px;\n    }\n\n    .section-kicker {\n        color: #11808f;\n        font-size: .74rem;\n        font-weight: 800;\n        letter-spacing: .08em;\n    }\n\n    .section-heading h2 {\n        margin: 4px 0 0;\n        color: #14413a;\n        font-size: 1.35rem;\n        font-weight: 800;\n    }\n\n    /* ── kad seksyen ───────────────────────────────────────────────── */\n    .calendar-section {\n        padding: 22px 24px;\n        border: 1px solid #dbe7e9;\n        border-radius: 16px;\n        background: #fff;\n        box-shadow: 0 10px 26px rgba(16, 62, 56, .06);\n    }\n\n    /* ── kawalan bulan ─────────────────────────────────────────────── */\n    .calendar-controls {\n        display: inline-flex;\n        align-items: center;\n        gap: 10px;\n    }\n\n    .calendar-controls button {\n        width: 34px;\n        height: 34px;\n        border: 1px solid #d9e6e7;\n        border-radius: 10px;\n        background: #f8fbfb;\n        color: #14413a;\n        font-size: 1.1rem;\n        font-weight: 800;\n        line-height: 1;\n        cursor: pointer;\n        transition: .18s;\n    }\n\n    .calendar-controls button:hover {\n        border-color: #11808f;\n        background: #eef7f8;\n    }\n\n    .calendar-controls strong {\n        min-width: 150px;\n        color: #14413a;\n        font-size: .95rem;\n        text-align: center;\n    }\n\n    .calendar-layout {\n        display: grid;\n        grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);\n        gap: 22px;\n    }\n\n    @media (max-width: 768px) {\n        .calendar-layout {\n            grid-template-columns: 1fr;\n        }\n    }\n\n    /* ── grid hari ─────────────────────────────────────────────────── */\n    .calendar-week,\n    .calendar-days {\n        display: grid;\n        grid-template-columns: repeat(7, 1fr);\n        gap: 6px;\n    }\n\n    .calendar-week span {\n        padding: 6px 0;\n        color: #8aa0a0;\n        font-size: .72rem;\n        font-weight: 800;\n        text-align: center;\n        text-transform: uppercase;\n    }\n\n    .calendar-days button {\n        position: relative;\n        aspect-ratio: 1 / 1;\n        border: 1px solid #eef4f5;\n        border-radius: 10px;\n        background: #fff;\n        color: #24443f;\n        font-size: .84rem;\n        font-weight: 600;\n        cursor: pointer;\n        transition: .18s;\n    }\n\n    .calendar-days button:hover {\n        border-color: #11808f;\n        background: #eef7f8;\n    }\n\n    .calendar-days button.has-event {\n        border-color: #11808f;\n        background: #f2fbfb;\n        font-weight: 800;\n    }\n\n    .calendar-days button.has-event::after {\n        content: '';\n        position: absolute;\n        bottom: 6px;\n        left: 50%;\n        width: 6px;\n        height: 6px;\n        border-radius: 50%;\n        background: #11808f;\n        transform: translateX(-50%);\n    }\n\n    .calendar-days button.selected {\n        border-color: #14413a;\n        background: #14413a;\n        color: #fff;\n    }\n\n    .calendar-days button.selected::after {\n        background: #fff;\n    }\n\n    .calendar-days span {\n        aspect-ratio: 1 / 1;\n    }\n\n    /* ── agenda ────────────────────────────────────────────────────── */\n    .calendar-agenda h3 {\n        margin: 0 0 10px;\n        color: #14413a;\n        font-size: .98rem;\n        font-weight: 800;\n    }\n\n    .calendar-agenda hr {\n        margin: 18px 0;\n        border: 0;\n        border-top: 1px solid #eef4f5;\n    }\n\n    .cal-item {\n        margin-bottom: 10px;\n        padding: 11px 13px;\n        border-left: 3px solid #11808f;\n        border-radius: 0 10px 10px 0;\n        background: #f8fbfb;\n    }\n\n    .cal-item b {\n        display: block;\n        color: #14413a;\n        font-size: .86rem;\n        font-weight: 800;\n    }\n\n    .cal-item span {\n        display: block;\n        margin-top: 3px;\n        color: #7b8f8c;\n        font-size: .76rem;\n    }\n\n    .cal-tag {\n        display: inline-block;\n        margin-top: 6px;\n        padding: 2px 8px;\n        border-radius: 999px;\n        background: #e2f1f3;\n        color: #0c6a77;\n        font-size: .66rem;\n        font-weight: 800;\n        letter-spacing: .04em;\n    }\n\n</style>\n\n<script>\n    (function () {\n        'use strict';\n\n        var $ = function (id) { return document.getElementById(id); };\n\n        function fmt(n) {\n            return (n === null || n === undefined || isNaN(n)) ? '–' : Number(n).toLocaleString('en-MY');\n        }\n\n        /* ── 1. KALENDAR ──────────────────────────────────────────── */\n        var calSec = document.getElementById('kalendar');\n        var calUrl = calSec ? calSec.dataset.calendar : null;\n        var calState = { y: null, m: null, items: [] };\n\n        var BULAN = ['Januari', 'Februari', 'Mac', 'April', 'Mei', 'Jun',\n            'Julai', 'Ogos', 'September', 'Oktober', 'November', 'Disember'];\n\n        function pad(n) { return (n < 10 ? '0' : '') + n; }\n\n        function iso(y, m, d) { return y + '-' + pad(m) + '-' + pad(d); }\n\n        function eventsOn(dateStr) {\n            return calState.items.filter(function (it) {\n                return dateStr >= it.date && dateStr <= (it.date_end || it.date);\n            });\n        }\n\n        function calItemHtml(it) {\n            return '<div class=\"cal-item\"><b>' + (it.title || '(tanpa tajuk)') + '</b>' +\n                '<span>' + (it.time || '') + (it.location ? ' · ' + it.location : '') + '</span>' +\n                (it.category ? '<span class=\"cal-tag\">' + it.category + '</span>' : '') +\n                '</div>';\n        }\n\n        function renderCalendar() {\n            var box = $('calendarDays');\n\n            if (!box) return;\n\n            var first = new Date(calState.y, calState.m - 1, 1);\n            var days = new Date(calState.y, calState.m, 0).getDate();\n            var offset = (first.getDay() + 6) % 7;   // Isnin = 0\n            var html = '';\n            var i;\n\n            for (i = 0; i < offset; i++) {\n                html += '<span></span>';\n            }\n\n            for (i = 1; i <= days; i++) {\n                var ds = iso(calState.y, calState.m, i);\n                var n = eventsOn(ds).length;\n\n                html += '<button type=\"button\" data-date=\"' + ds + '\" aria-label=\"' + i + ' ' +\n                    BULAN[calState.m - 1] + ' ' + calState.y + '; ' + n + ' aktiviti\"' +\n                    (n ? ' class=\"has-event\"' : '') + ' aria-pressed=\"false\">' + i + '</button>';\n            }\n\n            box.innerHTML = html;\n        }\n\n        function selectDay(ds) {\n            var btns = document.querySelectorAll('#calendarDays button');\n            var i;\n\n            for (i = 0; i < btns.length; i++) {\n                var on = btns[i].dataset.date === ds;\n\n                btns[i].classList.toggle('selected', on);\n                btns[i].setAttribute('aria-pressed', on ? 'true' : 'false');\n            }\n\n            var p = ds.split('-');\n\n            $('selectedDate').textContent = parseInt(p[2], 10) + ' ' +\n                BULAN[parseInt(p[1], 10) - 1] + ' ' + p[0];\n\n            var ev = eventsOn(ds);\n\n            $('dayEvents').innerHTML = ev.length\n                ? ev.map(calItemHtml).join('')\n                : '<p class=\"small text-body-secondary\">Tiada aktiviti disenaraikan pada tarikh ini.</p>';\n        }\n\n        function renderMonthList() {\n            $('monthEvents').innerHTML = calState.items.length\n                ? calState.items.map(calItemHtml).join('')\n                : '<p class=\"small text-body-secondary\">Tiada aktiviti disenaraikan untuk bulan ini.</p>';\n        }\n\n        function loadCalendar(y, m, firstLoad) {\n            if (!calUrl) return;\n\n            calState.y = y;\n            calState.m = m;\n            $('calendarMonth').textContent = BULAN[m - 1] + ' ' + y;\n\n            fetch(calUrl + '?month=' + y + '-' + pad(m))\n                .then(function (r) { return r.json(); })\n                .then(function (d) {\n                    calState.items = (d && d.items) ? d.items : [];\n                    renderCalendar();\n                    renderMonthList();\n\n                    // Bulan semasa kosong → lompat ke bulan terdekat yang ada aktiviti\n                    if (firstLoad && !calState.items.length && d && d.nearest) {\n                        var p = String(d.nearest).split('-');\n                        var ny = parseInt(p[0], 10);\n                        var nm = parseInt(p[1], 10);\n\n                        if (ny && nm && (ny !== y || nm !== m)) {\n                            loadCalendar(ny, nm, false);\n                        }\n                    }\n                })\n                .catch(function () {\n                    calState.items = [];\n                    renderCalendar();\n                    renderMonthList();\n                });\n        }\n\n        if (calSec && calUrl) {\n            var now = new Date();\n\n            loadCalendar(now.getFullYear(), now.getMonth() + 1, true);\n\n            $('previousMonth').addEventListener('click', function () {\n                var m = calState.m - 1;\n                var y = calState.y;\n\n                if (m < 1) { m = 12; y--; }\n\n                loadCalendar(y, m);\n            });\n\n            $('nextMonth').addEventListener('click', function () {\n                var m = calState.m + 1;\n                var y = calState.y;\n\n                if (m > 12) { m = 1; y++; }\n\n                loadCalendar(y, m);\n            });\n\n            $('calendarDays').addEventListener('click', function (e) {\n                var b = e.target.closest('button[data-date]');\n\n                if (b) selectDay(b.dataset.date);\n            });\n        }\n\n    })();\n</script>\n",
        "type": "PHP",
        "category": "Section",
        "status": 1,
        "created_at": "2026-11-01 16:46:10",
        "updated_at": "2026-11-01 17:06:12"
    },
    "pages": [
        {
            "id": 97,
            "page_fk": 22,
            "component_fk": 31,
            "sort": 6,
            "params": null,
            "created_at": "2026-11-01 16:52:25",
            "updated_at": "2026-11-01 16:52:25"
        }
    ]
}