first commit
This commit is contained in:
265
public/js/papar_permohonan.js
Normal file
265
public/js/papar_permohonan.js
Normal file
@@ -0,0 +1,265 @@
|
||||
/**
|
||||
* 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);
|
||||
Reference in New Issue
Block a user