Perbaiki pengisian alamat laundry dari peta

This commit is contained in:
micko samawa 2026-05-17 14:16:55 +07:00
parent c0fe039e91
commit cf41a8b582
3 changed files with 166 additions and 0 deletions

View File

@ -671,6 +671,7 @@ public function update(Request $request, Laundry $laundry)
} }
} }
/** /**
* Remove the specified laundry from storage * Remove the specified laundry from storage
*/ */

View File

@ -149,6 +149,12 @@ class="form-control border-start-0 @error('alamat') is-invalid @enderror"
@error('alamat') @error('alamat')
<div class="invalid-feedback">{{ $message }}</div> <div class="invalid-feedback">{{ $message }}</div>
@enderror @enderror
<div class="d-flex flex-wrap gap-2 align-items-center mt-2">
<button type="button" class="btn btn-sm btn-outline-secondary" id="alamatAutoBtn">
<i class="bi bi-geo-alt me-1"></i>Gunakan alamat dari peta
</button>
<small class="text-muted">Alamat otomatis dari peta, silakan lengkapi RT/RW/No rumah.</small>
</div>
</div> </div>
</div> </div>
@ -795,6 +801,142 @@ function updateJarakKampus(lat, lng) {
} }
} }
// ========== AUTO UPDATE ALAMAT DARI MAP ==========
const alamatInput = document.getElementById('alamat');
const alamatAutoBtn = document.getElementById('alamatAutoBtn');
let reverseGeocodeTimeout;
let lastGeocodeKey = '';
let lastLatLng = null;
let isManualAddress = false;
let isSettingAlamat = false;
function setAlamatValue(value) {
if (!alamatInput) {
return;
}
isSettingAlamat = true;
alamatInput.value = value;
isSettingAlamat = false;
isManualAddress = false;
}
if (alamatInput) {
alamatInput.addEventListener('input', function () {
if (isSettingAlamat) {
return;
}
isManualAddress = alamatInput.value.trim() !== '';
});
}
function scheduleReverseGeocode(lat, lng, force = false) {
if (!alamatInput) {
return;
}
lastLatLng = { lat, lng };
if (!force && isManualAddress && alamatInput.value.trim() !== '') {
return;
}
const key = `${lat.toFixed(6)},${lng.toFixed(6)}`;
if (!force && key === lastGeocodeKey) {
return;
}
lastGeocodeKey = key;
clearTimeout(reverseGeocodeTimeout);
reverseGeocodeTimeout = setTimeout(() => {
reverseGeocode(lat, lng, force);
}, 450);
}
async function reverseGeocode(lat, lng, force = false) {
if (!alamatInput) {
return;
}
if (!force && isManualAddress && alamatInput.value.trim() !== '') {
return;
}
const url = `https://nominatim.openstreetmap.org/reverse?format=jsonv2&addressdetails=1&zoom=18&lat=${encodeURIComponent(lat)}&lon=${encodeURIComponent(lng)}&accept-language=id`;
try {
const response = await fetch(url, {
headers: {
'Accept': 'application/json'
}
});
if (!response.ok) {
return;
}
const data = await response.json();
const detailedAddress = buildDetailedAddress(data?.address);
if (detailedAddress) {
setAlamatValue(detailedAddress);
return;
}
if (data && data.display_name) {
setAlamatValue(data.display_name);
}
} catch (error) {
console.warn('Gagal mengambil alamat otomatis.', error);
}
}
function buildDetailedAddress(address) {
if (!address) {
return '';
}
const parts = [];
const seen = new Set();
const addPart = (value) => {
if (!value) {
return;
}
const text = String(value).trim();
if (!text) {
return;
}
const key = text.toLowerCase();
if (seen.has(key)) {
return;
}
seen.add(key);
parts.push(text);
};
const road = address.road || address.pedestrian || address.cycleway || address.footway || address.path || address.residential;
const houseNumber = address.house_number || address.house_name || address.building;
if (road && houseNumber) {
addPart(`${road} No ${houseNumber}`);
} else {
addPart(road);
addPart(houseNumber);
}
addPart(address.neighbourhood);
addPart(address.suburb);
addPart(address.hamlet);
addPart(address.village);
addPart(address.town);
addPart(address.city_district);
addPart(address.city);
addPart(address.county);
addPart(address.state);
addPart(address.postcode);
addPart(address.country);
return parts.join(', ');
}
// ========== LAYANAN MANAGEMENT ========== // ========== LAYANAN MANAGEMENT ==========
let layananCount = {{ $laundry->layanan ? $laundry->layanan->count() : 1 }}; let layananCount = {{ $laundry->layanan ? $laundry->layanan->count() : 1 }};
const container = document.getElementById('layananContainer'); const container = document.getElementById('layananContainer');
@ -1122,6 +1264,7 @@ function restoreDraft() {
document.getElementById('latitude').value = position.lat.toFixed(6); document.getElementById('latitude').value = position.lat.toFixed(6);
document.getElementById('longitude').value = position.lng.toFixed(6); document.getElementById('longitude').value = position.lng.toFixed(6);
updateJarakKampus(position.lat, position.lng); updateJarakKampus(position.lat, position.lng);
scheduleReverseGeocode(position.lat, position.lng);
}); });
// Update marker saat klik di peta // Update marker saat klik di peta
@ -1134,6 +1277,7 @@ function restoreDraft() {
document.getElementById('latitude').value = lat.toFixed(6); document.getElementById('latitude').value = lat.toFixed(6);
document.getElementById('longitude').value = lng.toFixed(6); document.getElementById('longitude').value = lng.toFixed(6);
updateJarakKampus(lat, lng); updateJarakKampus(lat, lng);
scheduleReverseGeocode(lat, lng);
map.setView([lat, lng], map.getZoom()); map.setView([lat, lng], map.getZoom());
}); });
@ -1158,6 +1302,7 @@ function(position) {
marker.setLatLng([lat, lng]); marker.setLatLng([lat, lng]);
map.setView([lat, lng], 15); map.setView([lat, lng], 15);
updateJarakKampus(lat, lng); updateJarakKampus(lat, lng);
scheduleReverseGeocode(lat, lng);
btn.disabled = false; btn.disabled = false;
btn.innerHTML = originalHTML; btn.innerHTML = originalHTML;
@ -1211,6 +1356,25 @@ function handleManualCoordinateInput() {
marker.setLatLng([lat, lng]); marker.setLatLng([lat, lng]);
map.setView([lat, lng], map.getZoom()); map.setView([lat, lng], map.getZoom());
updateJarakKampus(lat, lng); updateJarakKampus(lat, lng);
scheduleReverseGeocode(lat, lng);
}
if (alamatAutoBtn) {
alamatAutoBtn.addEventListener('click', function () {
let lat = lastLatLng?.lat;
let lng = lastLatLng?.lng;
if ((!lat || !lng) && marker) {
const position = marker.getLatLng();
lat = position.lat;
lng = position.lng;
}
if (lat && lng) {
isManualAddress = false;
scheduleReverseGeocode(lat, lng, true);
}
});
} }
latInput.addEventListener('change', handleManualCoordinateInput); latInput.addEventListener('change', handleManualCoordinateInput);

View File

@ -129,6 +129,7 @@
// ========== 🗺️ MAP VIEW LAUNDRY (BARU - HARUS SEBELUM RESOURCE!) ========== // ========== 🗺️ MAP VIEW LAUNDRY (BARU - HARUS SEBELUM RESOURCE!) ==========
Route::get('/laundry/map', [LaundryController::class, 'map'])->name('laundry.map'); Route::get('/laundry/map', [LaundryController::class, 'map'])->name('laundry.map');
// ========== BULK DELETE LAUNDRY (HARUS SEBELUM RESOURCE!) ========== // ========== BULK DELETE LAUNDRY (HARUS SEBELUM RESOURCE!) ==========
Route::post('/laundry/bulk-destroy', [LaundryController::class, 'bulkDestroy'])->name('laundry.bulk-destroy'); Route::post('/laundry/bulk-destroy', [LaundryController::class, 'bulkDestroy'])->name('laundry.bulk-destroy');