675 lines
25 KiB
PHP
675 lines
25 KiB
PHP
@extends('layouts.dashboard')
|
|
|
|
@section('content')
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght=400;500;600;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/css/intlTelInput.css">
|
|
|
|
<style>
|
|
html, body {
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
}
|
|
|
|
.page-wrapper {
|
|
font-family: 'Inter', sans-serif;
|
|
background-color: #f8fafc;
|
|
padding: 40px 20px;
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.main-card {
|
|
width: 100%;
|
|
max-width: 1000px;
|
|
background: #ffffff;
|
|
border-radius: 16px;
|
|
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.05);
|
|
border: 1px solid #e2e8f0;
|
|
overflow: hidden;
|
|
animation: fadeIn 0.6s ease-out;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.card-header-pro {
|
|
padding: 30px 40px;
|
|
background: #ffffff;
|
|
border-bottom: 1px solid #f1f5f9;
|
|
}
|
|
|
|
.card-header-pro h2 {
|
|
font-weight: 800;
|
|
color: #1e293b;
|
|
margin: 0;
|
|
}
|
|
|
|
.form-body { padding: 40px; }
|
|
|
|
.section-title {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
font-size: 0.8rem;
|
|
font-weight: 700;
|
|
color: #6366f1;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.1em;
|
|
margin-bottom: 25px;
|
|
}
|
|
|
|
.section-title::after {
|
|
content: "";
|
|
flex: 1;
|
|
height: 1px;
|
|
background: #e2e8f0;
|
|
}
|
|
|
|
.label-text {
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
color: #475569;
|
|
margin-bottom: 8px;
|
|
display: block;
|
|
}
|
|
|
|
.input-pro {
|
|
width: 100%;
|
|
padding: 12px 16px;
|
|
border-radius: 10px;
|
|
border: 1px solid #cbd5e1;
|
|
transition: all 0.2s ease;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.input-pro:focus {
|
|
outline: none;
|
|
border-color: #6366f1;
|
|
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1);
|
|
}
|
|
|
|
.input-pro.is-invalid {
|
|
border-color: #ef4444 !important;
|
|
box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.1) !important;
|
|
}
|
|
|
|
.input-pro.is-valid {
|
|
border-color: #10b981 !important;
|
|
box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.1) !important;
|
|
}
|
|
|
|
.input-pro[readonly] {
|
|
background-color: #f1f5f9;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.iti { width: 100%; }
|
|
.iti__country-list { z-index: 10; }
|
|
|
|
.phone-feedback {
|
|
font-size: 0.8rem;
|
|
margin-top: 6px;
|
|
display: none;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-weight: 500;
|
|
}
|
|
.phone-feedback.valid-msg { color: #10b981; }
|
|
.phone-feedback.invalid-msg { color: #ef4444; }
|
|
|
|
.photo-upload-wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
background: #f8fafc;
|
|
padding: 15px;
|
|
border-radius: 12px;
|
|
border: 1px dashed #cbd5e1;
|
|
}
|
|
|
|
.photo-upload-main {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20px;
|
|
}
|
|
|
|
.img-preview {
|
|
width: 70px;
|
|
height: 70px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
display: none;
|
|
border: 2px solid #6366f1;
|
|
}
|
|
|
|
.form-footer {
|
|
padding: 25px 40px;
|
|
background: #f8fafc;
|
|
border-top: 1px solid #f1f5f9;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 15px;
|
|
}
|
|
|
|
.btn-save {
|
|
background: #6366f1;
|
|
color: white;
|
|
padding: 12px 30px;
|
|
border-radius: 10px;
|
|
font-weight: 600;
|
|
border: none;
|
|
transition: 0.3s;
|
|
cursor: pointer;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.btn-save:hover:not(:disabled) {
|
|
background: #4f46e5;
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 10px 15px -3px rgba(99, 102, 241, 0.3);
|
|
}
|
|
|
|
.btn-save:disabled {
|
|
background: #94a3b8;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.alert-custom {
|
|
padding: 15px 20px;
|
|
border-radius: 10px;
|
|
margin-bottom: 25px;
|
|
font-size: 0.9rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.alert-danger { background: #fee2e2; color: #b91c1c; border: 1px solid #fecaca; }
|
|
|
|
@media (max-width: 768px) {
|
|
.form-footer { flex-direction: column; }
|
|
.btn-save { width: 100%; justify-content: center; }
|
|
}
|
|
</style>
|
|
|
|
<div class="page-wrapper">
|
|
<div class="main-card">
|
|
<div class="card-header-pro">
|
|
<h2>Pendaftaran Anggota</h2>
|
|
<p class="text-muted mb-0">Lengkapi profil Anda. Satu akun hanya dapat mendaftar satu kali.</p>
|
|
</div>
|
|
|
|
<div class="form-body">
|
|
@if(session('error'))
|
|
<div class="alert-custom alert-danger">
|
|
<i class="fas fa-exclamation-triangle"></i>
|
|
{{ session('error') }}
|
|
</div>
|
|
@endif
|
|
|
|
<div id="clientErrorAlert" class="alert-custom alert-danger" style="display: none;">
|
|
<i class="fas fa-exclamation-triangle"></i>
|
|
<span id="clientErrorMessage"></span>
|
|
</div>
|
|
|
|
@if($errors->any())
|
|
<div class="alert-custom alert-danger">
|
|
<ul class="mb-0">
|
|
@foreach ($errors->all() as $error)
|
|
<li>{{ $error }}</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endif
|
|
|
|
<form id="memberForm" action="{{ route('user.member.store') }}" method="POST" enctype="multipart/form-data" novalidate>
|
|
@csrf
|
|
|
|
<div class="section-title">Informasi Pribadi</div>
|
|
<div class="row g-4 mb-5">
|
|
<div class="col-md-6">
|
|
<label class="label-text">Nama Lengkap</label>
|
|
<input type="text" class="input-pro" value="{{ Auth::user()->name }}" readonly>
|
|
<input type="hidden" name="nama" value="{{ Auth::user()->name }}">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="label-text">Email</label>
|
|
<input type="email" class="input-pro" value="{{ Auth::user()->email }}" readonly>
|
|
<input type="hidden" name="email" value="{{ Auth::user()->email }}">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="label-text">NIK / NIP</label>
|
|
<input type="text" name="nik_nip" id="nik_nip" class="input-pro" placeholder="Masukkan NIK (16 digit) atau NIP (18 digit)..." minlength="16" maxlength="18" required value="{{ old('nik_nip') }}">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="label-text">Jenis Kelamin</label>
|
|
<!-- Mengganti class form-control menjadi input-pro agar seragam & ditambahkan atribut required -->
|
|
<select name="gender" id="gender" class="input-pro form-select" required>
|
|
<option value="">-- Pilih Jenis Kelamin --</option>
|
|
<option value="Laki-laki" {{ old('gender') == 'Laki-laki' ? 'selected' : '' }}>Laki-laki</option>
|
|
<option value="Perempuan" {{ old('gender') == 'Perempuan' ? 'selected' : '' }}>Perempuan</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="label-text">Nomor Telepon / WhatsApp</label>
|
|
<input type="tel" id="no_hp_display" class="input-pro" placeholder="8123456xxx" required autocomplete="off">
|
|
<input type="hidden" name="no_hp" id="no_hp_hidden" value="{{ old('no_hp') }}">
|
|
|
|
<div id="valid-msg" class="phone-feedback valid-msg"><i class="fas fa-check-circle"></i> Nomor sah</div>
|
|
<div id="invalid-msg" class="phone-feedback invalid-msg"><i class="fas fa-times-circle"></i> Nomor tidak valid</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<label class="label-text">Foto Profil</label>
|
|
<div class="photo-upload-wrapper">
|
|
<div class="photo-upload-main">
|
|
<img id="imgPreview" src="#" alt="Preview" class="img-preview">
|
|
<input type="file" name="foto" id="foto" class="form-control border-0 bg-transparent" accept="image/jpeg,image/png,image/jpg" onchange="previewImage(this)" required>
|
|
</div>
|
|
<small style="color: #64748b; font-size: 0.825rem; display: block; margin-top: 4px;">
|
|
<i class="fas fa-info-circle" style="color: #6366f1;"></i> Format berkas yang didukung: JPG, JPEG, PNG. Ukuran berkas maksimal <strong>5 MB</strong>.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section-title">
|
|
Alamat Domisili
|
|
<span id="loader" class="ms-2" style="display:none;"><i class="fas fa-spinner fa-spin"></i> Memuat...</span>
|
|
</div>
|
|
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="label-text">Provinsi</label>
|
|
<select id="provinsi" name="provinsi_id" class="input-pro form-select" required>
|
|
<option value="">Pilih Provinsi</option>
|
|
</select>
|
|
<input type="hidden" name="provinsi" id="provinsi_nama">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="label-text">Kota / Kabupaten</label>
|
|
<select id="kota" name="kota_id" class="input-pro form-select" required disabled>
|
|
<option value="">Pilih Kota</option>
|
|
</select>
|
|
<input type="hidden" name="kota" id="kota_nama">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="label-text">Kecamatan</label>
|
|
<select id="kecamatan" name="kecamatan_id" class="input-pro form-select" required disabled>
|
|
<option value="">Pilih Kecamatan</option>
|
|
</select>
|
|
<input type="hidden" name="kecamatan" id="kecamatan_nama">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="label-text">Desa / Kelurahan</label>
|
|
<select id="desa" name="desa_id" class="input-pro form-select" required disabled>
|
|
<option value="">Pilih Desa</option>
|
|
</select>
|
|
<input type="hidden" name="desa" id="desa_nama">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="label-text">Kode Pos</label>
|
|
<input type="text" name="kode_pos" id="kode_pos" class="input-pro" placeholder="Masukkan 5 digit kode pos..." maxlength="5" required value="{{ old('kode_pos') }}">
|
|
</div>
|
|
<div class="col-md-8">
|
|
<label class="label-text">Alamat Lengkap</label>
|
|
<input type="text" name="alamat" id="alamat" class="input-pro" placeholder="Lengkapi Alamat Lengkap Anda" minlength="10" maxlength="255" required value="{{ old('alamat') }}">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-footer mt-4">
|
|
<button type="button" class="btn-cancel" onclick="window.history.back()" style="background:none; border:none; color:#64748b; cursor:pointer;">Batal</button>
|
|
<button type="submit" id="btnSubmit" class="btn-save">
|
|
<i class="fas fa-check-circle"></i> Simpan Data Anggota
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/intlTelInput.min.js"></script>
|
|
|
|
<script>
|
|
const phoneInput = document.getElementById("no_hp_display");
|
|
const hiddenPhoneInput = document.getElementById("no_hp_hidden");
|
|
const clientAlert = document.getElementById("clientErrorAlert");
|
|
const clientMessage = document.getElementById("clientErrorMessage");
|
|
|
|
const validMsg = document.getElementById("valid-msg");
|
|
const invalidMsg = document.getElementById("invalid-msg");
|
|
|
|
const iti = window.intlTelInput(phoneInput, {
|
|
initialCountry: "id",
|
|
separateDialCode: true,
|
|
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js"
|
|
});
|
|
|
|
function resetPhoneValidation() {
|
|
phoneInput.classList.remove("is-valid", "is-invalid");
|
|
validMsg.style.display = "none";
|
|
invalidMsg.style.display = "none";
|
|
}
|
|
|
|
function checkPhoneNumberRealtime() {
|
|
resetPhoneValidation();
|
|
const value = phoneInput.value.trim();
|
|
|
|
if (value) {
|
|
if (iti.isValidNumber()) {
|
|
phoneInput.classList.add("is-valid");
|
|
validMsg.style.display = "flex";
|
|
hiddenPhoneInput.value = iti.getNumber();
|
|
} else {
|
|
phoneInput.classList.add("is-invalid");
|
|
invalidMsg.style.display = "flex";
|
|
hiddenPhoneInput.value = "";
|
|
}
|
|
} else {
|
|
hiddenPhoneInput.value = "";
|
|
}
|
|
}
|
|
|
|
phoneInput.addEventListener('keyup', checkPhoneNumberRealtime);
|
|
phoneInput.addEventListener('blur', checkPhoneNumberRealtime);
|
|
phoneInput.addEventListener('change', checkPhoneNumberRealtime);
|
|
phoneInput.addEventListener('countrychange', checkPhoneNumberRealtime);
|
|
|
|
phoneInput.addEventListener('input', function() {
|
|
let value = this.value.replace(/[^0-9]/g, '');
|
|
|
|
if (value.startsWith('62')) {
|
|
value = value.substring(2);
|
|
}
|
|
while (value.startsWith('0')) {
|
|
value = value.substring(1);
|
|
}
|
|
this.value = value;
|
|
});
|
|
|
|
document.getElementById('nik_nip').addEventListener('input', function() {
|
|
this.value = this.value.replace(/[^0-9]/g, '');
|
|
});
|
|
|
|
document.getElementById('kode_pos').addEventListener('input', function() {
|
|
this.value = this.value.replace(/[^0-9]/g, '');
|
|
});
|
|
|
|
document.querySelectorAll('.input-pro:not([readonly])').forEach(input => {
|
|
input.addEventListener('blur', function() {
|
|
this.value = this.value.trim();
|
|
});
|
|
});
|
|
|
|
function previewImage(input) {
|
|
const preview = document.getElementById('imgPreview');
|
|
clientAlert.style.display = 'none';
|
|
|
|
if (input.files && input.files[0]) {
|
|
const file = input.files[0];
|
|
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png'];
|
|
|
|
if (!allowedTypes.includes(file.type)) {
|
|
showAlert("Format berkas tidak valid! Hanya diperbolehkan gambar berformat JPG, JPEG, atau PNG.", input);
|
|
input.value = "";
|
|
preview.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
const maxByteSize = 5 * 1024 * 1024;
|
|
if (file.size > maxByteSize) {
|
|
showAlert("Ukuran gambar terlalu besar! Batas maksimal ukuran berkas adalah 5 MB.", input);
|
|
input.value = "";
|
|
preview.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
preview.src = e.target.result;
|
|
preview.style.display = 'block';
|
|
input.classList.remove('is-invalid');
|
|
}
|
|
reader.readAsDataURL(file);
|
|
}
|
|
}
|
|
|
|
function showAlert(message, focusElement = null) {
|
|
clientAlert.style.display = 'flex';
|
|
clientMessage.innerText = message;
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
if (focusElement) {
|
|
focusElement.classList.add('is-invalid');
|
|
focusElement.focus();
|
|
}
|
|
}
|
|
|
|
// Menghapus status error saat user mengetik/memilih ulang
|
|
document.querySelectorAll('.input-pro, select, input[type="file"]').forEach(item => {
|
|
item.addEventListener('input', function() {
|
|
this.classList.remove('is-invalid');
|
|
});
|
|
item.addEventListener('change', function() {
|
|
this.classList.remove('is-invalid');
|
|
});
|
|
});
|
|
|
|
const form = document.getElementById('memberForm');
|
|
const btnSubmit = document.getElementById('btnSubmit');
|
|
|
|
form.addEventListener('submit', function(e) {
|
|
clientAlert.style.display = 'none';
|
|
|
|
const nikNip = document.getElementById('nik_nip');
|
|
const gender = document.getElementById('gender');
|
|
const phoneDisplay = document.getElementById('no_hp_display');
|
|
const foto = document.getElementById('foto');
|
|
const kodePos = document.getElementById('kode_pos');
|
|
const alamat = document.getElementById('alamat');
|
|
const provinsi = document.getElementById('provinsi');
|
|
const kota = document.getElementById('kota');
|
|
const kecamatan = document.getElementById('kecamatan');
|
|
const desa = document.getElementById('desa');
|
|
|
|
// 1. Validasi NIK / NIP wajib diisi & sesuai panjang digit
|
|
if (!nikNip.value.trim()) {
|
|
e.preventDefault();
|
|
showAlert("NIK / NIP wajib diisi!", nikNip);
|
|
return false;
|
|
}
|
|
const valLen = nikNip.value.trim().length;
|
|
if (valLen !== 16 && valLen !== 18) {
|
|
e.preventDefault();
|
|
showAlert("Identitas tidak valid! Panjang data harus tepat 16 digit jika NIK, atau 18 digit jika NIP.", nikNip);
|
|
return false;
|
|
}
|
|
|
|
// 2. Validasi Jenis Kelamin
|
|
if (!gender.value) {
|
|
e.preventDefault();
|
|
showAlert("Harap pilih jenis kelamin Anda.", gender);
|
|
return false;
|
|
}
|
|
|
|
// 3. Validasi Nomor Telepon
|
|
if (!phoneDisplay.value.trim()) {
|
|
e.preventDefault();
|
|
showAlert("Nomor Telepon / WhatsApp wajib diisi!", phoneDisplay);
|
|
return false;
|
|
}
|
|
if (!iti.isValidNumber()) {
|
|
e.preventDefault();
|
|
showAlert("Format nomor Telepon / WhatsApp tidak sah atau jumlah digit salah!", phoneDisplay);
|
|
return false;
|
|
}
|
|
|
|
// 4. Validasi Foto Profil Wajib Diunggah
|
|
if (foto.files.length === 0) {
|
|
e.preventDefault();
|
|
showAlert("Foto profil wajib diunggah!", foto);
|
|
return false;
|
|
}
|
|
|
|
// 5. Validasi Struktur Alamat Dropdown
|
|
if (!provinsi.value) { e.preventDefault(); showAlert("Harap pilih Provinsi Anda.", provinsi); return false; }
|
|
if (!kota.value) { e.preventDefault(); showAlert("Harap pilih Kota / Kabupaten Anda.", kota); return false; }
|
|
if (!kecamatan.value) { e.preventDefault(); showAlert("Harap pilih Kecamatan Anda.", kecamatan); return false; }
|
|
if (!desa.value) { e.preventDefault(); showAlert("Harap pilih Desa / Kelurahan Anda.", desa); return false; }
|
|
|
|
// 6. Validasi Kode Pos
|
|
if (!kodePos.value.trim()) {
|
|
e.preventDefault();
|
|
showAlert("Kode Pos wajib diisi!", kodePos);
|
|
return false;
|
|
}
|
|
if (kodePos.value.trim().length !== 5) {
|
|
e.preventDefault();
|
|
showAlert("Kode Pos Indonesia tidak valid! Harus berisikan tepat 5 digit angka.", kodePos);
|
|
return false;
|
|
}
|
|
|
|
// 7. Validasi Alamat Fisik
|
|
// Menghapus spasi di ujung input dan mengecek teks asli tambahan selain template otomatis wilayah
|
|
const alamatVal = alamat.value.trim();
|
|
if (!alamatVal) {
|
|
e.preventDefault();
|
|
showAlert("Alamat Lengkap wajib diisi!", alamat);
|
|
return false;
|
|
}
|
|
if (alamatVal.length < 15) {
|
|
e.preventDefault();
|
|
showAlert("Tuliskan alamat domisili secara lebih detail dan lengkap (Minimal 15 karakter).", alamat);
|
|
return false;
|
|
}
|
|
|
|
btnSubmit.disabled = true;
|
|
btnSubmit.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
|
|
});
|
|
|
|
// =========================================================================
|
|
// MODUL API WILAYAH INDONESIA - EMSIFA
|
|
// =========================================================================
|
|
const apiBase = 'https://www.emsifa.com/api-wilayah-indonesia/api';
|
|
const sel = {
|
|
prov: document.getElementById('provinsi'),
|
|
kota: document.getElementById('kota'),
|
|
kec: document.getElementById('kecamatan'),
|
|
desa: document.getElementById('desa'),
|
|
load: document.getElementById('loader')
|
|
};
|
|
|
|
const hid = {
|
|
prov: document.getElementById('provinsi_nama'),
|
|
kota: document.getElementById('kota_nama'),
|
|
kec: document.getElementById('kecamatan_nama'),
|
|
desa: document.getElementById('desa_nama')
|
|
};
|
|
|
|
function sortWilayah(array) {
|
|
return array.sort((a, b) => a.name.localeCompare(b.name));
|
|
}
|
|
|
|
async function fetchData(url) {
|
|
sel.load.style.display = 'inline';
|
|
try {
|
|
const response = await fetch(url);
|
|
return await response.json();
|
|
} catch (e) {
|
|
console.error("Gagal memuat data wilayah");
|
|
return [];
|
|
} finally {
|
|
sel.load.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
window.addEventListener('load', async () => {
|
|
let data = await fetchData(`${apiBase}/provinces.json`);
|
|
data = sortWilayah(data);
|
|
data.forEach(p => sel.prov.add(new Option(p.name, p.id)));
|
|
});
|
|
|
|
sel.prov.addEventListener('change', async function() {
|
|
resetSelect(['kota', 'kec', 'desa']);
|
|
if (this.value) {
|
|
hid.prov.value = this.options[this.selectedIndex].text;
|
|
let data = await fetchData(`${apiBase}/regencies/${this.value}.json`);
|
|
data = sortWilayah(data);
|
|
sel.kota.disabled = false;
|
|
data.forEach(r => sel.kota.add(new Option(r.name, r.id)));
|
|
}
|
|
});
|
|
|
|
sel.kota.addEventListener('change', async function() {
|
|
resetSelect(['kec', 'desa']);
|
|
if (this.value) {
|
|
hid.kota.value = this.options[this.selectedIndex].text;
|
|
let data = await fetchData(`${apiBase}/districts/${this.value}.json`);
|
|
data = sortWilayah(data);
|
|
sel.kec.disabled = false;
|
|
data.forEach(d => sel.kec.add(new Option(d.name, d.id)));
|
|
}
|
|
});
|
|
|
|
sel.kec.addEventListener('change', async function() {
|
|
resetSelect(['desa']);
|
|
if (this.value) {
|
|
hid.kec.value = this.options[this.selectedIndex].text;
|
|
let data = await fetchData(`${apiBase}/villages/${this.value}.json`);
|
|
data = sortWilayah(data);
|
|
sel.desa.disabled = false;
|
|
data.forEach(v => sel.desa.add(new Option(v.name, v.id)));
|
|
}
|
|
});
|
|
|
|
sel.desa.addEventListener('change', async function() {
|
|
const alamatInput = document.getElementById('alamat');
|
|
const kodePosInput = document.getElementById('kode_pos');
|
|
|
|
if (this.value) {
|
|
hid.desa.value = this.options[this.selectedIndex].text;
|
|
|
|
const namaProv = hid.prov.value;
|
|
const namaKota = hid.kota.value;
|
|
const namaKec = hid.kec.value;
|
|
const namaDesa = hid.desa.value;
|
|
|
|
alamatInput.value = `Desa/Kel. ${namaDesa}, Kec. ${namaKec}, ${namaKota}, Provinsi ${namaProv}. `;
|
|
alamatInput.focus();
|
|
|
|
try {
|
|
const query = encodeURIComponent(`${namaDesa} ${namaKec}`);
|
|
const response = await fetch(`https://api.allorigins.win/get?url=${encodeURIComponent('https://nominatim.openstreetmap.org/search?format=json&addressdetails=1&countrycodes=id&q=' + query)}`);
|
|
const wrapper = await response.json();
|
|
const geoData = JSON.parse(wrapper.contents);
|
|
|
|
if (geoData && geoData.length > 0 && geoData[0].address && geoData[0].address.postcode) {
|
|
const postal = geoData[0].address.postcode.replace(/[^0-9]/g, '');
|
|
if(postal.length === 5) {
|
|
kodePosInput.value = postal;
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.log("Menunggu input manual kode pos oleh user.");
|
|
}
|
|
} else {
|
|
alamatInput.value = '';
|
|
kodePosInput.value = '';
|
|
}
|
|
});
|
|
|
|
function resetSelect(keys) {
|
|
keys.forEach(k => {
|
|
sel[k].innerHTML = `<option value="">Pilih ${k.charAt(0).toUpperCase() + k.slice(1)}</option>`;
|
|
sel[k].disabled = true;
|
|
});
|
|
document.getElementById('alamat').value = '';
|
|
document.getElementById('kode_pos').value = '';
|
|
}
|
|
</script>
|
|
@endsection |