266 lines
10 KiB
JavaScript
266 lines
10 KiB
JavaScript
/**
|
|
* 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('<option value="">-- Sila Pilih Kawasan --</option>');
|
|
data.forEach(k => {
|
|
$kawasan.append($('<option>', {
|
|
value: k.id,
|
|
text: k.nama,
|
|
selected: k.id == cfg.defaultKawasanId
|
|
}));
|
|
});
|
|
if (cfg.defaultKawasanId && cfg.defaultTamanId) {
|
|
loadTaman(cfg.defaultKawasanId, cfg.defaultTamanId);
|
|
}
|
|
}).fail(function () {
|
|
toast('Gagal load kawasan.', 'error');
|
|
});
|
|
}
|
|
|
|
function loadPenempatan() {
|
|
return $.getJSON('/get_penempatan').done(function (data) {
|
|
const $penempatan = $('#penempatan').empty().append('<option value="">-- Sila Pilih Penempatan --</option>');
|
|
data.forEach(p => {
|
|
$penempatan.append($('<option>', {
|
|
value: p.id,
|
|
text: p.nama,
|
|
selected: p.id == cfg.defaultPenempatanId
|
|
}));
|
|
});
|
|
}).fail(function () {
|
|
toast('Gagal load penempatan.', 'error');
|
|
});
|
|
}
|
|
|
|
function loadTaman(kawasanId, selectedId) {
|
|
if (!kawasanId) return;
|
|
return $.getJSON('/get_taman', { kawasan_id: kawasanId }).done(function (data) {
|
|
const $taman = $('#taman').empty().append('<option value="">-- Sila Pilih Taman --</option>');
|
|
data.forEach(t => {
|
|
$taman.append($('<option>', {
|
|
value: t.id,
|
|
text: t.nama,
|
|
selected: t.id == selectedId
|
|
}));
|
|
});
|
|
$taman.prop('disabled', false);
|
|
|
|
if (selectedId && cfg.defaultJalanId) {
|
|
loadJalan(selectedId, cfg.defaultJalanId);
|
|
}
|
|
}).fail(function () {
|
|
toast('Gagal load taman.', 'error');
|
|
});
|
|
}
|
|
|
|
function loadJalan(tamanId, selectedId) {
|
|
if (!tamanId) return;
|
|
return $.getJSON('/get_jalan', { taman_id: tamanId }).done(function (data) {
|
|
const $jalan = $('#jalan').empty().append('<option value="">-- Sila Pilih Jalan --</option>');
|
|
data.forEach(j => {
|
|
$jalan.append($('<option>', {
|
|
value: j.id,
|
|
text: j.nama,
|
|
selected: j.id == selectedId
|
|
}));
|
|
});
|
|
$jalan.prop('disabled', false);
|
|
}).fail(function () {
|
|
toast('Gagal load jalan.', 'error');
|
|
});
|
|
}
|
|
|
|
// Event listeners
|
|
$('#kawasan').on('change', function () {
|
|
const kawasanId = $(this).val();
|
|
$('#taman').empty().append('<option value="">-- Sila Pilih Taman --</option>');
|
|
$('#jalan').empty().append('<option value="">-- Sila Pilih Jalan --</option>').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('<option value="">-- Sila Pilih Jalan --</option>');
|
|
|
|
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);
|