/** * papar_permohonan.js * Modular JS untuk papar_permohonan.blade.php * Requires: jQuery, Leaflet, Bootstrap (for toasts/modals if used) * * Usage: ensure window.PermohonanConfig object exists before loading this file. */ (function ($, window, document, undefined) { 'use strict'; // read config (set by blade) const cfg = window.PermohonanConfig || {}; $(function () { /* =========================== * Helper / Utilities * =========================== */ function isEmpty(v) { return v === null || v === undefined || v === ''; } function toast(msg, level = 'info') { // simple bootstrap toast fallback (console if not present) if (typeof bootstrap !== 'undefined' && $('#globalToast').length) { $('#globalToast .toast-body').text(msg); let toastEl = new bootstrap.Toast($('#globalToast')[0]); toastEl.show(); } else { console[level === 'error' ? 'error' : 'log'](msg); } } /* ============================================================ * 1. FIELD TOGGLE HANDLERS * ============================================================ */ function handleJenisPenjaja() { const selected = $("#jenis_penjaja").val(); $("#jenis_penjaja_lain").prop("disabled", selected !== "lain-lain"); if (selected !== "lain-lain") $("#jenis_penjaja_lain").val(""); } function handleJenisKenderaan() { const jenis = $("#jenis_kenderaan").val(); const disable = ["kereta sorong", "basikal", ""].includes(jenis); $("#no_pendaftaran").prop("disabled", disable); if (disable) $("#no_pendaftaran").val(""); } $("#jenis_penjaja").on("change", handleJenisPenjaja); $("#jenis_kenderaan").on("change", handleJenisKenderaan); // run initial toggles handleJenisPenjaja(); handleJenisKenderaan(); /* ============================================================ * 2. LEAFLET MAP + NOMINATIM SEARCH (with debounce) * ============================================================ */ const defaultLat = parseFloat(cfg.latitude) || 1.48348; const defaultLng = parseFloat(cfg.longitude) || 103.58197; const defaultZoom = cfg.latitude ? 16 : 12; const map = L.map('viewDiv', { preferCanvas: true }).setView([defaultLat, defaultLng], defaultZoom); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map); let marker = null; if (!isEmpty(cfg.latitude) && !isEmpty(cfg.longitude)) { marker = L.marker([cfg.latitude, cfg.longitude], { draggable: true }).addTo(map); marker.on('dragend', updateInputByMarker); } map.on('click', function (e) { placeMarker(e.latlng); updateInputFromLatLng(e.latlng); }); function placeMarker(latlng) { if (!marker) { marker = L.marker(latlng, { draggable: true }).addTo(map); marker.on('dragend', updateInputByMarker); } else { marker.setLatLng(latlng); } } function updateInputByMarker(e) { updateInputFromLatLng(e.target.getLatLng()); } function updateInputFromLatLng(latlng) { $('#latitude').val(latlng.lat); $('#longitude').val(latlng.lng); } // Debounce util function debounce(fn, wait) { let t; return function () { const args = arguments; clearTimeout(t); t = setTimeout(function () { fn.apply(null, args); }, wait); }; } // Nominatim search (uses fetch) function _cariKoordinat(rawQuery) { const query = rawQuery || $('#searchBox').val(); if (typeof query !== 'string' || query.trim().length < 3) { toast('Masukkan nama tempat yang lebih spesifik.', 'info'); return; } const url = 'https://nominatim.openstreetmap.org/search?format=json&q=' + encodeURIComponent(query); fetch(url, { headers: { 'Accept': 'application/json' } }) .then(res => res.json()) .then(data => { if (!Array.isArray(data) || data.length === 0) { toast('Lokasi tak dijumpai.', 'info'); return; } const place = data[0]; const lat = parseFloat(place.lat); const lon = parseFloat(place.lon); map.setView([lat, lon], 17); placeMarker({ lat: lat, lng: lon }); updateInputFromLatLng({ lat: lat, lng: lon }); }) .catch(err => { console.error('Nominatim error', err); toast('Ralat semasa mencari lokasi.', 'error'); }); } const cariKoordinat = debounce(_cariKoordinat, 450); $('#searchBtn').on('click', function (e) { e.preventDefault(); cariKoordinat($('#searchBox').val()); }); // optional: live suggestions trigger (not heavy) // $('#searchBox').on('input', debounce(function(){ cariKoordinat($(this).val()); }, 800)); /* ============================================================ * 3. CASCADING DROPDOWN: KAWASAN → TAMAN → JALAN * ============================================================ */ function loadKawasan() { return $.getJSON('/get_kawasan').done(function (data) { const $kawasan = $('#kawasan').empty().append(''); data.forEach(k => { $kawasan.append($(''); data.forEach(p => { $penempatan.append($(''); data.forEach(t => { $taman.append($(''); data.forEach(j => { $jalan.append($(''); $('#jalan').empty().append('').prop('disabled', true); if (kawasanId) loadTaman(kawasanId); else $('#taman').prop('disabled', true); }); $('#taman').on('change', function () { const tid = $(this).val(); const textTaman = $(this).find('option:selected').text(); $('#jalan').empty().append(''); if (tid) { loadJalan(tid); $('#searchBox').val(textTaman); cariKoordinat(textTaman); } else { $('#jalan').prop('disabled', true); } }); $('#jalan').on('change', function () { const jalanText = $(this).find('option:selected').text(); const tamanText = $('#taman').find('option:selected').text(); if (jalanText) { $('#searchBox').val(jalanText + ', ' + tamanText); cariKoordinat(jalanText + ', ' + tamanText); } }); // Init loadKawasan(); loadPenempatan(); }); // end jQuery ready })(jQuery, window, document);