Compare commits

..

2 Commits

172 changed files with 1421 additions and 5840 deletions

5
.gitignore vendored
View File

@@ -13,7 +13,10 @@ Thumbs.db
# Dependencies (if any in future)
node_modules/
vendor/
!plugins/vendor/
# Uploads
foto/
# Debug files
debug_ai.txt
debug_log.txt

View File

@@ -19,7 +19,7 @@ $mimeType = mime_content_type($imagePath);
// Construct Prompt based on Type
if ($type === 'kk') {
$promptText = "Extract strictly from this Indonesian Family Card (Kartu Keluarga). Return ONLY a raw JSON object with these keys: 'no_kk' (16 digits), 'kepala_keluarga' (Name), 'alamat', 'rt', 'rw', 'desa', 'kecamatan', 'kabupaten', 'provinsi', 'kode_pos', 'anggota': [ { 'nik': '...', 'nama': '...', 'hubungan': '...' } ] (Array of all family members found in the table. 'hubungan' examples: KEPALA KELUARGA, ISTRI, ANAK, FAMILI LAIN). Value must be string. If not found, use empty string.";
$promptText = "Extract strictly from this Indonesian Family Card (Kartu Keluarga). Return ONLY a raw JSON object with these keys: 'no_kk' (16 digits), 'kepala_keluarga' (Name), 'alamat', 'rt', 'rw', 'desa', 'kecamatan', 'kabupaten', 'provinsi', 'kode_pos', 'anggota': [ { 'nik': '...', 'nama': '...', 'hubungan': '...', 'tempat_lh': '...', 'tgl_lh': 'YYYY-MM-DD', 'jekel': 'LK/PR', 'agama': '...', 'kawin': '...', 'pekerjaan': '...', 'kewarganegaraan': 'WNI/WNA' } ] (Array of all family members found in the table. 'hubungan' examples: KEPALA KELUARGA, ISTRI, ANAK, FAMILI LAIN). Value must be string. If not found, use empty string.";
} else {
// Default to KTP
$promptText = "Extract data from this Indonesian KTP. Return ONLY a raw JSON object with keys: 'nik' (16 digits), 'nama' (Name), 'tempat_lh' (Place of Birth), 'tgl_lh' (YYYY-MM-DD), 'je_kel' (LK/PR), 'alamat' (Street only), 'rt', 'rw', 'desa' (Kel/Desa), 'kecamatan', 'kabupaten' (or Kota), 'provinsi', 'agama', 'status' (Sudah/Belum/Cerai Hidup/Cerai Mati), 'pekerjaan', 'kewarganegaraan' (WNI/WNA). Clean up text. If field is unclear, return empty string.";
@@ -74,6 +74,7 @@ if (!isset($result['candidates'][0]['content']['parts'][0]['text'])) {
// Parse AI Response
$rawText = $result['candidates'][0]['content']['parts'][0]['text'];
file_put_contents('../../debug_ai.txt', "AI Response:\n" . $rawText . "\n-------------------\n", FILE_APPEND);
// Remove Markdown Code Blocks if any (```json ... ```)
$cleanJson = preg_replace('/^```json\s*|\s*```$/', '', trim($rawText));

View File

@@ -1,6 +1,3 @@
<?php
$selected_id = isset($_GET['selected_id']) ? (int)$_GET['selected_id'] : 0;
?>
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">
@@ -9,40 +6,37 @@ $selected_id = isset($_GET['selected_id']) ? (int)$_GET['selected_id'] : 0;
<form action="" method="post" enctype="multipart/form-data">
<div class="card-body">
<div class="form-group row">
<label class="col-sm-2 col-form-label">Pendatang</label>
<div class="col-sm-6">
<select name="id_pend" id="id_pend" class="form-control select2bs4" required>
<option value="" <?php echo ($selected_id == 0) ? 'selected="selected"' : ''; ?>>- Pilih Penduduk -</option>
<?php
// ambil data dari database
$query = "select * from tb_pdd where status='Ada'";
$hasil = mysqli_query($koneksi, $query);
while ($row = mysqli_fetch_array($hasil)) {
?>
<option value="<?php echo $row['id_pend'] ?>" <?php echo ($row['id_pend'] == $selected_id) ? 'selected="selected"' : ''; ?>>
<?php echo $row['nik'] ?>
-
<?php echo $row['nama'] ?>
</option>
<?php
}
?>
</select>
</div>
<div class="col-sm-2">
<a href="?page=add-pend&return_to=add-datang" class="btn btn-outline-primary btn-sm">
<i class="fa fa-plus"></i> Tambah Penduduk Baru
</a>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Tgl Datang</label>
<div class="col-sm-3">
<input type="date" class="form-control" id="tgl_datang" name="tgl_datang" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">NIK</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="nik" name="nik" placeholder="NIK" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Nama</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="nama_datang" name="nama_datang" placeholder="Nama Pendatang" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Jenis Kelain</label>
<div class="col-sm-3">
<select name="jekel" id="jekel" class="form-control">
<option>- Pilih -</option>
<option>LK</option>
<option>PR</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Tgl Datang</label>
<div class="col-sm-3">
<input type="date" class="form-control" id="tgl_datang" name="tgl_datang" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Pelapor</label>
@@ -56,9 +50,9 @@ $selected_id = isset($_GET['selected_id']) ? (int)$_GET['selected_id'] : 0;
while ($row = mysqli_fetch_array($hasil)) {
?>
<option value="<?php echo $row['id_pend'] ?>">
<?php echo htmlspecialchars($row['nik'], ENT_QUOTES); ?>
<?php echo $row['nik'] ?>
-
<?php echo htmlspecialchars($row['nama'], ENT_QUOTES); ?>
<?php echo $row['nama'] ?>
</option>
<?php
}
@@ -77,51 +71,51 @@ $selected_id = isset($_GET['selected_id']) ? (int)$_GET['selected_id'] : 0;
<?php
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
// Sanitize Input to prevent SQL Injection & Syntax Errors
$id_pend = (int)$_POST['id_pend']; // Cast to integer for safety
$tgl_datang = mysqli_real_escape_string($koneksi, trim($_POST['tgl_datang']));
$pelapor = (int)$_POST['pelapor']; // Cast to integer for safety
// Ambil data penduduk yang dipilih
$sql_pend = "SELECT nik, nama, jekel FROM tb_pdd WHERE id_pend='$id_pend'";
$q_pend = mysqli_query($koneksi, $sql_pend);
$d_pend = mysqli_fetch_array($q_pend);
if (!$d_pend) {
die("Data penduduk tidak ditemukan. Silakan pilih penduduk yang valid.");
}
$nik = mysqli_real_escape_string($koneksi, trim($d_pend['nik']));
$nama_datang = mysqli_real_escape_string($koneksi, trim($d_pend['nama']));
$jekel = mysqli_real_escape_string($koneksi, trim($d_pend['jekel']));
$sql_simpan = "INSERT INTO tb_datang (id_pend, nik, nama_datang, jekel, tgl_datang, pelapor) VALUES (
'$id_pend',
'$nik',
'$nama_datang',
'$jekel',
'$tgl_datang',
'$pelapor')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
mysqli_close($koneksi);
if ($query_simpan) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-datang';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-datang';
}
})</script>";
}}
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
$sql_simpan = "INSERT INTO tb_datang (nik, nama_datang, jekel, tgl_datang, pelapor) VALUES (
'".$_POST['nik']."',
'".$_POST['nama_datang']."',
'".$_POST['jekel']."',
'".$_POST['tgl_datang']."',
'".$_POST['pelapor']."')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
// Otomatis tambah ke Data Penduduk
// Ambil data alamat dari pelapor
$id_pelapor = $_POST['pelapor'];
$sql_pelapor = "SELECT desa, rt, rw FROM tb_pdd WHERE id_pend='$id_pelapor'";
$q_pelapor = mysqli_query($koneksi, $sql_pelapor);
$d_pelapor = mysqli_fetch_array($q_pelapor);
$desa = $d_pelapor['desa'];
$rt = $d_pelapor['rt'];
$rw = $d_pelapor['rw'];
$sql_pdd = "INSERT INTO tb_pdd (nik, nama, tempat_lh, tgl_lh, jekel, desa, rt, rw, agama, kawin, pekerjaan, status) VALUES (
'".$_POST['nik']."',
'".$_POST['nama_datang']."',
'-',
'0000-00-00',
'".$_POST['jekel']."',
'$desa', '$rt', '$rw',
'-', '-', '-', 'Ada')";
$query_pdd = mysqli_query($koneksi, $sql_pdd);
mysqli_close($koneksi);
if ($query_simpan && $query_pdd) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-datang';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-datang';
}
})</script>";
}}
//selesai proses simpan data

View File

@@ -17,7 +17,7 @@
<th>No</th>
<th>NIK</th>
<th>Nama</th>
<th>Jenis Kelamin</th>
<th>Jekel</th>
<th>Tanggal</th>
<th>Pelapor</th>
<th>Aksi</th>
@@ -43,15 +43,7 @@
<?php echo $data['nama_datang']; ?>
</td>
<td>
<?php
if ($data['jekel'] == 'LK') {
echo 'LAKI-LAKI';
} elseif ($data['jekel'] == 'PR') {
echo 'PEREMPUAN';
} else {
echo $data['jekel'];
}
?>
<?php echo $data['jekel']; ?>
</td>
<td>
<?php echo $data['tgl_datang']; ?>
@@ -64,10 +56,10 @@
class="btn btn-success btn-sm">
<i class="fa fa-edit"></i>
</a>
<a href="?page=del-datang&kode=<?php echo $data['id_datang']; ?>" onclick="confirmDelete(event)"
<a href="?page=del-datang&kode=<?php echo $data['id_datang']; ?>" onclick="return confirm('Apakah anda yakin hapus data ini ?')"
title="Hapus" class="btn btn-danger btn-sm">
<i class="fa fa-trash"></i>
</a>
</>
</td>
</tr>
@@ -76,26 +68,7 @@
?>
</tbody>
</tfoot>
</table>
</div>
</div>
<!-- /.card-body -->
<script>
function confirmDelete(event) {
event.preventDefault();
Swal.fire({
title: 'Konfirmasi Hapus',
text: 'Apakah Anda yakin ingin menghapus data ini?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = event.currentTarget.href;
}
});
}
</script>
</table>
</div>
</div>
<!-- /.card-body -->

View File

@@ -1,14 +1,11 @@
<?php
if(isset($_GET['kode'])){
$sql_cek = "SELECT d.id_datang, d.id_pend, d.nik, d.nama_datang, d.jekel, d.tgl_datang, p.id_pend as id_pelapor, p.nama as nama_pelapor, pd.tgl_lh
FROM tb_datang d
INNER JOIN tb_pdd p ON d.pelapor=p.id_pend
LEFT JOIN tb_pdd pd ON d.id_pend=pd.id_pend
WHERE d.id_datang='".$_GET['kode']."'";
$query_cek = mysqli_query($koneksi, $sql_cek);
$data_cek = mysqli_fetch_array($query_cek,MYSQLI_BOTH);
}
if(isset($_GET['kode'])){
$sql_cek = "SELECT d.id_datang, d.nik, d.nama_datang, d.jekel, d.tgl_datang, p.id_pend, p.nama from
tb_datang d inner join tb_pdd p on d.pelapor=p.id_pend WHERE id_datang='".$_GET['kode']."'";
$query_cek = mysqli_query($koneksi, $sql_cek);
$data_cek = mysqli_fetch_array($query_cek,MYSQLI_BOTH);
}
?>
<div class="card card-success">
@@ -27,51 +24,43 @@
</div>
</div>
<input type="hidden" id="id_pend" name="id_pend" value="<?php echo isset($data_cek['id_pend']) ? $data_cek['id_pend'] : ''; ?>">
<div class="form-group row">
<label class="col-sm-2 col-form-label">NIK</label>
<div class="col-sm-6">
<input type="text" class="form-control" value="<?php echo htmlspecialchars($data_cek['nik'], ENT_QUOTES); ?>" readonly>
<input type="hidden" name="nik" value="<?php echo htmlspecialchars($data_cek['nik'], ENT_QUOTES); ?>">
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Nama</label>
<div class="col-sm-6">
<input type="text" class="form-control" value="<?php echo htmlspecialchars($data_cek['nama_datang'], ENT_QUOTES); ?>" readonly>
<input type="hidden" name="nama_datang" value="<?php echo htmlspecialchars($data_cek['nama_datang'], ENT_QUOTES); ?>">
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Jenis Kelamin</label>
<div class="col-sm-3">
<input type="text" class="form-control" value="<?php
$display_jekel = $data_cek['jekel'];
if ($display_jekel == 'LK') {
$display_jekel = 'LAKI-LAKI';
} elseif ($display_jekel == 'PR') {
$display_jekel = 'PEREMPUAN';
}
echo htmlspecialchars($display_jekel, ENT_QUOTES);
?>" readonly>
<input type="hidden" name="jekel" value="<?php echo htmlspecialchars($data_cek['jekel'], ENT_QUOTES); ?>">
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Tgl Lahir</label>
<div class="col-sm-3">
<input type="text" class="form-control" value="<?php echo htmlspecialchars(isset($data_cek['tgl_lh']) ? $data_cek['tgl_lh'] : '-', ENT_QUOTES); ?>" readonly>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Tgl Datang</label>
<div class="form-group row">
<label class="col-sm-2 col-form-label">NIK</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="nik" name="nik" value="<?php echo $data_cek['nik']; ?>"
required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Nama</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="nama_datang" name="nama_datang" value="<?php echo $data_cek['nama_datang']; ?>"
required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Jenis Kelamin</label>
<div class="col-sm-3">
<input type="date" class="form-control" id="tgl_datang" name="tgl_datang" value="<?php echo htmlspecialchars($data_cek['tgl_datang'], ENT_QUOTES); ?>"
<select name="jekel" id="jekel" class="form-control">
<option value="">-- Pilih jekel --</option>
<?php
//menhecek data yg dipilih sebelumnya
if ($data_cek['jekel'] == "LK") echo "<option value='LK' selected>LK</option>";
else echo "<option value='LK'>LK</option>";
if ($data_cek['jekel'] == "PR") echo "<option value='PR' selected>PR</option>";
else echo "<option value='PR'>PR</option>";
?>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Tgl Datang</label>
<div class="col-sm-3">
<input type="date" class="form-control" id="tgl_datang" name="tgl_datang" value="<?php echo $data_cek['tgl_datang']; ?>"
required>
</div>
</div>
@@ -83,14 +72,15 @@
<option selected="">- Pilih -</option>
<?php
// ambil data dari database
$query = "select * from tb_pdd where status='Ada'";
$query = "select * from tb_pdd";
$hasil = mysqli_query($koneksi, $query);
while ($row = mysqli_fetch_array($hasil)) {
?>
<option value="<?php echo $row['id_pend'] ?>" <?=$data_cek['id_pelapor']==$row['id_pend'] ? "selected" : null ?>>
<?php echo htmlspecialchars($row['nik'], ENT_QUOTES); ?>
<option value="<?php echo $row['id_pend'] ?>" <?=$data_cek[
'id_pend']==$row[ 'id_pend'] ? "selected" : null ?>>
<?php echo $row['nik'] ?>
-
<?php echo htmlspecialchars($row['nama'], ENT_QUOTES); ?>
<?php echo $row['nama'] ?>
</option>
<?php
}
@@ -108,44 +98,31 @@
</form>
</div>
<?php
if (isset ($_POST['Ubah'])){
// Sanitize Input to prevent SQL Injection & Syntax Errors
$id_datang = (int)$_POST['id_datang'];
$nik = mysqli_real_escape_string($koneksi, trim($_POST['nik']));
$nama_datang = mysqli_real_escape_string($koneksi, trim($_POST['nama_datang']));
$jekel = mysqli_real_escape_string($koneksi, trim($_POST['jekel']));
$tgl_datang = mysqli_real_escape_string($koneksi, trim($_POST['tgl_datang']));
$pelapor = (int)$_POST['pelapor'];
// Update tb_datang table
$sql_ubah = "UPDATE tb_datang SET
nik='$nik',
nama_datang='$nama_datang',
jekel='$jekel',
tgl_datang='$tgl_datang',
pelapor='$pelapor'
WHERE id_datang='$id_datang'";
$query_ubah = mysqli_query($koneksi, $sql_ubah);
mysqli_close($koneksi);
if ($query_ubah) {
echo "<script>
Swal.fire({title: 'Ubah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value)
{window.location = 'index.php?page=data-datang';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Ubah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value)
{window.location = 'index.php?page=data-datang';
}
})</script>";
}}
<?php
if (isset ($_POST['Ubah'])){
$sql_ubah = "UPDATE tb_datang SET
nik='".$_POST['nik']."',
nama_datang='".$_POST['nama_datang']."',
jekel='".$_POST['jekel']."',
tgl_datang='".$_POST['tgl_datang']."',
pelapor='".$_POST['pelapor']."'
WHERE id_datang='".$_POST['id_datang']."'";
$query_ubah = mysqli_query($koneksi, $sql_ubah);
mysqli_close($koneksi);
if ($query_ubah) {
echo "<script>
Swal.fire({title: 'Ubah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value)
{window.location = 'index.php?page=data-datang';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Ubah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value)
{window.location = 'index.php?page=data-datang';
}
})</script>";
}}

View File

@@ -30,9 +30,9 @@
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Kepala Keluarga</label>
<label class="col-sm-2 col-form-label">Kpl Keluarga</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="kepala" name="kepala" placeholder="Kepala Keluarga" required>
<input type="text" class="form-control" id="kepala" name="kepala" placeholder="Kpl Keluarga" required>
</div>
</div>
@@ -46,10 +46,10 @@
<div class="form-group row">
<label class="col-sm-2 col-form-label">RT/RW</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="rt" name="rt" placeholder="RT" value="000" required>
<input type="text" class="form-control" id="rt" name="rt" placeholder="RT" required>
</div>
<div class="col-sm-3">
<input type="text" class="form-control" id="rw" name="rw" placeholder="RW" value="000" required>
<input type="text" class="form-control" id="rw" name="rw" placeholder="RW" required>
</div>
</div>
@@ -166,18 +166,7 @@ window.addEventListener('load', function() {
<tr><td>Kabupaten</td><td>${d.kabupaten || '-'}</td></tr>
<tr><td>Provinsi</td><td>${d.provinsi || '-'}</td></tr>
</table>
<hr>
<strong>Ditemukan ${d.anggota ? d.anggota.length : 0} Anggota:</strong>
<div style="max-height: 150px; overflow-y: auto; background: #f8f9fa; border: 1px solid #ddd; padding: 5px;">
${d.anggota && d.anggota.length > 0 ?
'<ul style="padding-left: 20px; margin-bottom: 0;">' +
d.anggota.map(m => `<li><b>${m.nama}</b><br><small>${m.nik} (${m.hubungan})</small></li>`).join('') +
'</ul>'
: '<i class="text-muted">Tidak ada anggota terdeteksi</i>'}
</div>
<p class="mb-0 text-muted mt-2">Gunakan data ini?</p>
<p class="mb-0 text-muted">Gunakan data ini?</p>
</div>
`,
icon: 'question',
@@ -190,8 +179,8 @@ window.addEventListener('load', function() {
if(d.anggota) document.getElementById('anggota_json').value = JSON.stringify(d.anggota);
if(d.kepala_keluarga) document.getElementsByName('kepala')[0].value = d.kepala_keluarga;
if(d.desa) document.getElementsByName('desa')[0].value = d.desa;
if(d.rt) document.getElementsByName('rt')[0].value = d.rt;
if(d.rw) document.getElementsByName('rw')[0].value = d.rw;
document.getElementsByName('rt')[0].value = d.rt || '000';
document.getElementsByName('rw')[0].value = d.rw || '000';
if(d.kecamatan) document.getElementsByName('kec')[0].value = d.kecamatan;
if(d.kabupaten) document.getElementsByName('kab')[0].value = d.kabupaten;
if(d.provinsi) document.getElementsByName('prov')[0].value = d.provinsi;
@@ -238,28 +227,27 @@ window.addEventListener('load', function() {
}
//mulai proses simpan data
$no_kk_raw = trim($_POST['no_kk']);
$no_kk_clean = mysqli_real_escape_string($koneksi, $no_kk_raw);
$cek_kk = mysqli_query($koneksi, "SELECT * FROM tb_kk WHERE no_kk='$no_kk_clean'");
if(mysqli_num_rows($cek_kk) > 0){
echo "<script>
Swal.fire({title: 'Gagal',text: 'No KK sudah terdaftar dalam sistem!',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-kartu';
}
})</script>";
return;
}
// Sanitize Inputs
$no_kk = $no_kk_clean;
$kepala = mysqli_real_escape_string($koneksi, trim($_POST['kepala']));
$desa = mysqli_real_escape_string($koneksi, trim($_POST['desa']));
$rt = mysqli_real_escape_string($koneksi, trim($_POST['rt']));
$rw = mysqli_real_escape_string($koneksi, trim($_POST['rw']));
$kec = mysqli_real_escape_string($koneksi, trim($_POST['kec']));
$kab = mysqli_real_escape_string($koneksi, trim($_POST['kab']));
$prov = mysqli_real_escape_string($koneksi, trim($_POST['prov']));
$no_kk = $_POST['no_kk'];
$cek_kk = mysqli_query($koneksi, "SELECT * FROM tb_kk WHERE no_kk='$no_kk'");
if(mysqli_num_rows($cek_kk) > 0){
echo "<script>
Swal.fire({title: 'Gagal',text: 'No KK sudah terdaftar dalam sistem!',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-kartu';
}
})</script>";
return;
}
// Sanitize Inputs
$no_kk = mysqli_real_escape_string($koneksi, $_POST['no_kk']);
$kepala = mysqli_real_escape_string($koneksi, $_POST['kepala']);
$desa = mysqli_real_escape_string($koneksi, $_POST['desa']);
$rt = mysqli_real_escape_string($koneksi, $_POST['rt']);
$rw = mysqli_real_escape_string($koneksi, $_POST['rw']);
$kec = mysqli_real_escape_string($koneksi, $_POST['kec']);
$kab = mysqli_real_escape_string($koneksi, $_POST['kab']);
$prov = mysqli_real_escape_string($koneksi, $_POST['prov']);
$sql_simpan = "INSERT INTO tb_kk (no_kk, kepala, desa, rt, rw, kec, kab, prov, foto_kk) VALUES (
'$no_kk',
@@ -273,70 +261,80 @@ window.addEventListener('load', function() {
'$nama_file')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
// Process Auto-Linking Members
$linked_count = 0;
$failed_count = 0;
$failed_members = []; // Store failed members for detailed feedback
if ($query_simpan && !empty($_POST['anggota_json'])) {
$id_kk_baru = mysqli_insert_id($koneksi);
$anggota_list = json_decode($_POST['anggota_json'], true);
if (is_array($anggota_list)) {
foreach ($anggota_list as $mem) {
$nik_mem = mysqli_real_escape_string($koneksi, $mem['nik']);
$nama_mem = isset($mem['nama']) ? mysqli_real_escape_string($koneksi, $mem['nama']) : '';
$hub_mem = mysqli_real_escape_string($koneksi, $mem['hubungan']);
// Search Resident by NIK
$sql_cek_pend = "SELECT id_pend FROM tb_pdd WHERE nik='$nik_mem'";
$q_cek_pend = mysqli_query($koneksi, $sql_cek_pend);
if ($row_pend = mysqli_fetch_assoc($q_cek_pend)) {
$id_pend_found = $row_pend['id_pend'];
// Insert into tb_anggota
$sql_add_ang = "INSERT INTO tb_anggota (id_kk, id_pend, hubungan) VALUES ('$id_kk_baru', '$id_pend_found', '$hub_mem')";
mysqli_query($koneksi, $sql_add_ang);
$linked_count++;
} else {
$failed_count++;
$failed_members[] = ['nik' => $nik_mem, 'nama' => $nama_mem, 'hubungan' => $hub_mem];
}
}
}
}
// Process Auto-Linking Members
if ($query_simpan && !empty($_POST['anggota_json'])) {
file_put_contents('debug_log.txt', "----------------------------------------\n", FILE_APPEND);
file_put_contents('debug_log.txt', "Saving KK ID: " . mysqli_insert_id($koneksi) . "\n", FILE_APPEND);
file_put_contents('debug_log.txt', "Raw JSON: " . $_POST['anggota_json'] . "\n", FILE_APPEND);
$id_kk_baru = mysqli_insert_id($koneksi);
$anggota_list = json_decode($_POST['anggota_json'], true);
if (is_array($anggota_list)) {
foreach ($anggota_list as $mem) {
$nik_mem = mysqli_real_escape_string($koneksi, $mem['nik']);
$hub_mem = mysqli_real_escape_string($koneksi, $mem['hubungan']);
file_put_contents('debug_log.txt', "Processing NIK: $nik_mem\n", FILE_APPEND);
// Search Resident by NIK
$sql_cek_pend = "SELECT id_pend FROM tb_pdd WHERE nik='$nik_mem'";
$q_cek_pend = mysqli_query($koneksi, $sql_cek_pend);
if ($row_pend = mysqli_fetch_assoc($q_cek_pend)) {
$id_pend_found = $row_pend['id_pend'];
file_put_contents('debug_log.txt', "Found Existing ID: $id_pend_found. Linking...\n", FILE_APPEND);
// Insert into tb_anggota
$sql_add_ang = "INSERT INTO tb_anggota (id_kk, id_pend, hubungan) VALUES ('$id_kk_baru', '$id_pend_found', '$hub_mem')";
if (!mysqli_query($koneksi, $sql_add_ang)) {
file_put_contents('debug_log.txt', "Link Error: " . mysqli_error($koneksi) . "\n", FILE_APPEND);
} else {
file_put_contents('debug_log.txt', "Success Link ID $id_pend_found\n", FILE_APPEND);
}
} else {
// Create New Resident if not found
file_put_contents('debug_log.txt', "NIK Not Found. Creating New.\n", FILE_APPEND);
$nama_mem = mysqli_real_escape_string($koneksi, $mem['nama']);
$tempat_lh = mysqli_real_escape_string($koneksi, $mem['tempat_lh'] ?? '-');
$tgl_lh = mysqli_real_escape_string($koneksi, $mem['tgl_lh'] ?? '0000-00-00');
$jekel = mysqli_real_escape_string($koneksi, $mem['jekel'] ?? 'LK');
$agama = mysqli_real_escape_string($koneksi, $mem['agama'] ?? 'Islam');
$kawin = mysqli_real_escape_string($koneksi, $mem['kawin'] ?? 'Belum Kawin');
$pekerjaan = mysqli_real_escape_string($koneksi, $mem['pekerjaan'] ?? 'Pelajar/Mahasiswa');
$kewarganegaraan = mysqli_real_escape_string($koneksi, $mem['kewarganegaraan'] ?? 'WNI');
$sql_new_pend = "INSERT INTO tb_pdd (
nik, nama, tempat_lh, tgl_lh, jekel,
desa, rt, rw, agama, kawin, pekerjaan, status, kwn
) VALUES (
'$nik_mem', '$nama_mem', '$tempat_lh', '$tgl_lh', '$jekel',
'$desa', '$rt', '$rw', '$agama', '$kawin', '$pekerjaan', 'Ada', '$kewarganegaraan'
)";
if (mysqli_query($koneksi, $sql_new_pend)) {
$id_pend_new = mysqli_insert_id($koneksi);
file_put_contents('debug_log.txt', "Created New ID: $id_pend_new. Linking...\n", FILE_APPEND);
// Link to KK
$sql_add_ang = "INSERT INTO tb_anggota (id_kk, id_pend, hubungan) VALUES ('$id_kk_baru', '$id_pend_new', '$hub_mem')";
mysqli_query($koneksi, $sql_add_ang);
} else {
file_put_contents('debug_log.txt', "Error Creating Resident: " . mysqli_error($koneksi) . "\n", FILE_APPEND);
}
}
}
} else {
file_put_contents('debug_log.txt', "JSON Decode Failed or Not Array\n", FILE_APPEND);
}
}
mysqli_close($koneksi);
if ($query_simpan) {
$msg_add = "";
if($linked_count > 0 || $failed_count > 0) {
$msg_add = "<br>Anggota Terhubung: <b>$linked_count</b><br>Tidak Ditemukan: <b>$failed_count</b>";
// Add detailed failed members list if any
if (!empty($failed_members)) {
$msg_add .= "<br><br><b>Detail Anggota Tidak Ditemukan:</b><br>";
$msg_add .= "<div style='max-height: 150px; overflow-y: auto; background: #f8f9fa; border: 1px solid #ddd; padding: 5px; font-size: 0.9rem;'>";
foreach ($failed_members as $fm) {
$url_params = http_build_query([
'nik' => $fm['nik'],
'nama' => $fm['nama'],
'desa' => $desa,
'rt' => $rt,
'rw' => $rw,
'kecamatan' => $kec,
'kabupaten' => $kab,
'provinsi' => $prov
]);
$add_link = "<a href='index.php?page=add-pend&$url_params' class='btn btn-xs btn-outline-primary ml-2'>Tambah</a>";
$msg_add .= "• <b>" . htmlspecialchars($fm['nik']) . "</b> - " . htmlspecialchars($fm['nama']) . " (" . htmlspecialchars($fm['hubungan']) . ") $add_link<br>";
}
$msg_add .= "</div>";
$msg_add .= "<small class='text-muted'>Tambahkan data penduduk yang belum terdaftar melalui menu <a href='index.php?page=add-pend'>Tambah Penduduk</a>.</small>";
}
}
if ($query_simpan) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',html: 'Data KK disimpan.$msg_add',icon: 'success',confirmButtonText: 'OK'
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-kartu';
}

View File

@@ -97,7 +97,7 @@
<tr>
<th>NIK</th>
<th>Nama</th>
<th>Jenis Kelamin</th>
<th>Jekel</th>
<th>Hub Keluarga</th>
<th>Aksi</th>
</tr>
@@ -119,21 +119,13 @@
<?php echo $data['nama']; ?>
</td>
<td>
<?php
if ($data['jekel'] == 'LK') {
echo 'LAKI-LAKI';
} elseif ($data['jekel'] == 'PR') {
echo 'PEREMPUAN';
} else {
echo $data['jekel'];
}
?>
<?php echo $data['jekel']; ?>
</td>
<td>
<?php echo $data['hubungan']; ?>
</td>
<td>
<a href="?page=del-anggota&kode=<?php echo $data['id_anggota']; ?>" onclick="confirmDelete(event)"
<a href="?page=del-anggota&kode=<?php echo $data['id_anggota']; ?>" onclick="return confirm('Apakah anda yakin hapus data ini ?')"
title="Hapus" class="btn btn-danger btn-sm">
<i class="fa fa-trash"></i>
</a>
@@ -143,30 +135,11 @@
<?php
}
?>
</tbody>
</tfoot>
</table>
</div>
</div>
<script>
function confirmDelete(event) {
event.preventDefault();
Swal.fire({
title: 'Konfirmasi Hapus',
text: 'Apakah Anda yakin ingin menghapus data ini?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = event.currentTarget.href;
}
});
}
</script>
</tbody>
</tfoot>
</table>
</div>
</div>
</div>
<div class="card-footer">
<a href="?page=data-kartu" title="Kembali" class="btn btn-warning">Kembali</a>

View File

@@ -59,7 +59,7 @@
<th>No</th>
<th>NIK</th>
<th>Nama</th>
<th>Jenis Kelamin</th>
<th>Jekel</th>
<th>Hub Keluarga</th>
<th>Status</th>
</tr>
@@ -85,15 +85,7 @@
<?php echo $data['nama']; ?>
</td>
<td>
<?php
if ($data['jekel'] == 'LK') {
echo 'LAKI-LAKI';
} elseif ($data['jekel'] == 'PR') {
echo 'PEREMPUAN';
} else {
echo $data['jekel'];
}
?>
<?php echo $data['jekel']; ?>
</td>
<td>
<?php echo $data['hubungan']; ?>

View File

@@ -52,7 +52,7 @@
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Kepala Keluarga</label>
<label class="col-sm-2 col-form-label">Kpl Keluarga</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="kepala" name="kepala" value="<?php echo $data_cek['kepala']; ?>"
required>
@@ -208,8 +208,8 @@ window.addEventListener('load', function() {
if(d.no_kk) document.getElementsByName('no_kk')[0].value = d.no_kk;
if(d.kepala_keluarga) document.getElementsByName('kepala')[0].value = d.kepala_keluarga;
if(d.desa) document.getElementsByName('desa')[0].value = d.desa;
if(d.rt) document.getElementsByName('rt')[0].value = d.rt;
if(d.rw) document.getElementsByName('rw')[0].value = d.rw;
document.getElementsByName('rt')[0].value = d.rt || '000';
document.getElementsByName('rw')[0].value = d.rw || '000';
if(d.kecamatan) document.getElementsByName('kec')[0].value = d.kecamatan;
if(d.kabupaten) document.getElementsByName('kab')[0].value = d.kabupaten;
if(d.provinsi) document.getElementsByName('prov')[0].value = d.provinsi;

View File

@@ -27,16 +27,16 @@
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Jenis Kelamin</label>
<div class="col-sm-3">
<select name="jekel" id="jekel" class="form-control">
<option>- Pilih -</option>
<option>LK</option>
<option>PR</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Jenis Kelain</label>
<div class="col-sm-3">
<select name="jekel" id="jekel" class="form-control">
<option>- Pilih -</option>
<option>LK</option>
<option>PR</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-form-label">Keluarga</label>
@@ -69,69 +69,62 @@
</form>
</div>
<?php
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
// Sanitize Input to prevent SQL Injection & Syntax Errors
$nik = mysqli_real_escape_string($koneksi, trim($_POST['nik']));
$nama = mysqli_real_escape_string($koneksi, trim($_POST['nama']));
$tgl_lh = mysqli_real_escape_string($koneksi, trim($_POST['tgl_lh']));
$jekel = mysqli_real_escape_string($koneksi, trim($_POST['jekel']));
$id_kk = (int)$_POST['id_kk']; // Cast to integer for safety
$sql_simpan = "INSERT INTO tb_lahir (nama, tgl_lh, jekel, id_kk) VALUES (
'$nama',
'$tgl_lh',
'$jekel',
'$id_kk')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
// Otomatis tambah ke Data Penduduk
// Ambil data alamat dari KK
$sql_kk = "SELECT desa, rt, rw FROM tb_kk WHERE id_kk='$id_kk'";
$q_kk = mysqli_query($koneksi, $sql_kk);
$d_kk = mysqli_fetch_array($q_kk);
$desa = $d_kk['desa'];
$rt = $d_kk['rt'];
$rw = $d_kk['rw'];
$sql_pdd = "INSERT INTO tb_pdd (nik, nama, tempat_lh, tgl_lh, jekel, desa, rt, rw, agama, kawin, pekerjaan, status) VALUES (
'$nik',
'$nama',
'-',
'$tgl_lh',
'$jekel',
'$desa', '$rt', '$rw',
'-', 'Belum', 'Belum/Tidak Bekerja', 'Ada')";
$query_pdd = mysqli_query($koneksi, $sql_pdd);
// Ambil ID Penduduk yang baru dibuat
$id_pend_baru = mysqli_insert_id($koneksi);
// Masukkan ke Anggota KK
$sql_anggota = "INSERT INTO tb_anggota (id_kk, id_pend, hubungan) VALUES (
'$id_kk',
'$id_pend_baru',
'Anak')";
$query_anggota = mysqli_query($koneksi, $sql_anggota);
mysqli_close($koneksi);
if ($query_simpan && $query_pdd && $query_anggota) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-lahir';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-lahir';
}
})</script>";
}}
//selesai proses simpan data
<?php
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
$sql_simpan = "INSERT INTO tb_lahir (nama, tgl_lh, jekel, id_kk) VALUES (
'".$_POST['nama']."',
'".$_POST['tgl_lh']."',
'".$_POST['jekel']."',
'".$_POST['id_kk']."')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
// Otomatis tambah ke Data Penduduk
// Ambil data alamat dari KK
$id_kk = $_POST['id_kk'];
$sql_kk = "SELECT desa, rt, rw FROM tb_kk WHERE id_kk='$id_kk'";
$q_kk = mysqli_query($koneksi, $sql_kk);
$d_kk = mysqli_fetch_array($q_kk);
$desa = $d_kk['desa'];
$rt = $d_kk['rt'];
$rw = $d_kk['rw'];
$sql_pdd = "INSERT INTO tb_pdd (nik, nama, tempat_lh, tgl_lh, jekel, desa, rt, rw, agama, kawin, pekerjaan, status) VALUES (
'".$_POST['nik']."',
'".$_POST['nama']."',
'-',
'".$_POST['tgl_lh']."',
'".$_POST['jekel']."',
'$desa', '$rt', '$rw',
'-', 'Belum', 'Belum/Tidak Bekerja', 'Ada')";
$query_pdd = mysqli_query($koneksi, $sql_pdd);
// Ambil ID Penduduk yang baru dibuat
$id_pend_baru = mysqli_insert_id($koneksi);
// Masukkan ke Anggota KK
$sql_anggota = "INSERT INTO tb_anggota (id_kk, id_pend, hubungan) VALUES (
'$id_kk',
'$id_pend_baru',
'Anak')";
$query_anggota = mysqli_query($koneksi, $sql_anggota);
mysqli_close($koneksi);
if ($query_simpan && $query_pdd && $query_anggota) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-lahir';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-lahir';
}
})</script>";
}}
//selesai proses simpan data

View File

@@ -17,7 +17,7 @@
<th>No</th>
<th>Nama</th>
<th>Tgl Lahir</th>
<th>Jenis Kelamin</th>
<th>Jekel</th>
<th>Keluarga</th>
<th>Aksi</th>
</tr>
@@ -42,15 +42,7 @@
<?php echo $data['tgl_lh']; ?>
</td>
<td>
<?php
if ($data['jekel'] == 'LK') {
echo 'LAKI-LAKI';
} elseif ($data['jekel'] == 'PR') {
echo 'PEREMPUAN';
} else {
echo $data['jekel'];
}
?>
<?php echo $data['jekel']; ?>
</td>
<td>
<?php echo $data['no_kk']; ?>-
@@ -61,10 +53,10 @@
class="btn btn-success btn-sm">
<i class="fa fa-edit"></i>
</a>
<a href="?page=del-lahir&kode=<?php echo $data['id_lahir']; ?>" onclick="confirmDelete(event)"
<a href="?page=del-lahir&kode=<?php echo $data['id_lahir']; ?>" onclick="return confirm('Apakah anda yakin hapus data ini ?')"
title="Hapus" class="btn btn-danger btn-sm">
<i class="fa fa-trash"></i>
</a>
</>
</td>
</tr>
@@ -73,26 +65,7 @@
?>
</tbody>
</tfoot>
</table>
</div>
</div>
<!-- /.card-body -->
<script>
function confirmDelete(event) {
event.preventDefault();
Swal.fire({
title: 'Konfirmasi Hapus',
text: 'Apakah Anda yakin ingin menghapus data ini?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = event.currentTarget.href;
}
});
}
</script>
</table>
</div>
</div>
<!-- /.card-body -->

View File

@@ -52,41 +52,35 @@
</form>
</div>
<?php
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
// Sanitize Input to prevent SQL Injection & Syntax Errors
$id_pdd = (int)$_POST['id_pdd']; // Cast to integer for safety
$tgl_mendu = mysqli_real_escape_string($koneksi, trim($_POST['tgl_mendu']));
$sebab = mysqli_real_escape_string($koneksi, trim($_POST['sebab']));
$sql_simpan = "INSERT INTO tb_mendu (id_pdd, tgl_mendu, sebab) VALUES (
'$id_pdd',
'$tgl_mendu',
'$sebab')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
$sql_ubah = "UPDATE tb_pdd SET
status='Meninggal'
WHERE id_pend='$id_pdd'";
$query_ubah = mysqli_query($koneksi, $sql_ubah);
mysqli_close($koneksi);
if ($query_simpan && $query_ubah) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-mendu';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-mendu';
}
})</script>";
}}
//selesai proses simpan data
<?php
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
$sql_simpan = "INSERT INTO tb_mendu (id_pdd, tgl_mendu, sebab) VALUES (
'".$_POST['id_pdd']."',
'".$_POST['tgl_mendu']."',
'".$_POST['sebab']."')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
$sql_ubah = "UPDATE tb_pdd SET
status='Meninggal'
WHERE id_pend='".$_POST['id_pdd']."'";
$query_ubah = mysqli_query($koneksi, $sql_ubah);
mysqli_close($koneksi);
if ($query_simpan && $query_ubah) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-mendu';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-mendu';
}
})</script>";
}}
//selesai proses simpan data

View File

@@ -13,21 +13,20 @@
<br>
<table id="example1" class="table table-bordered table-striped">
<thead>
<tr>
<th>No</th>
<th>NIK</th>
<th>Nama</th>
<th>Jenis Kelamin</th>
<th>Tanggal</th>
<th>Sebab</th>
<th>Aksi</th>
</tr>
<tr>
<th>No</th>
<th>NIK</th>
<th>Nama</th>
<th>Tanggal</th>
<th>Sebab</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php
$no = 1;
$sql = $koneksi->query("SELECT p.id_pend, p.nik, p.nama, p.jekel, m.tgl_mendu, m.sebab, m.id_mendu from
$sql = $koneksi->query("SELECT p.id_pend, p.nik, p.nama, m.tgl_mendu, m.sebab, m.id_mendu from
tb_mendu m inner join tb_pdd p on p.id_pend=m.id_pdd");
while ($data= $sql->fetch_assoc()) {
?>
@@ -42,12 +41,9 @@
<td>
<?php echo $data['nama']; ?>
</td>
<td>
<?php echo $data['jekel'] == 'LK' ? 'LAKI-LAKI' : 'PEREMPUAN'; ?>
</td>
<td>
<?php echo $data['tgl_mendu']; ?>
</td>
<td>
<?php echo $data['tgl_mendu']; ?>
</td>
<td>
<?php echo $data['sebab']; ?>
</td>
@@ -60,10 +56,10 @@
class="btn btn-success btn-sm">
<i class="fa fa-edit"></i>
</a>
<a href="?page=del-mendu&kode=<?php echo $data['id_pend']; ?>" onclick="confirmDelete(event)"
<a href="?page=del-mendu&kode=<?php echo $data['id_pend']; ?>" onclick="return confirm('Apakah anda yakin hapus data ini ?')"
title="Hapus" class="btn btn-danger btn-sm">
<i class="fa fa-trash"></i>
</a>
</>
</td>
</tr>
@@ -72,26 +68,7 @@
?>
</tbody>
</tfoot>
</table>
</div>
</div>
<!-- /.card-body -->
<script>
function confirmDelete(event) {
event.preventDefault();
Swal.fire({
title: 'Konfirmasi Hapus',
text: 'Apakah Anda yakin ingin menghapus data ini?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = event.currentTarget.href;
}
});
}
</script>
</table>
</div>
</div>
<!-- /.card-body -->

View File

@@ -90,15 +90,7 @@
<b>Jenis Kelamin</b>
</td>
<td>:
<?php
if ($data_cek['jekel'] == 'LK') {
echo 'LAKI-LAKI';
} elseif ($data_cek['jekel'] == 'PR') {
echo 'PEREMPUAN';
} else {
echo $data_cek['jekel'];
}
?>
<?php echo $data_cek['jekel']; ?>
</td>
</tr>
<tr>

View File

@@ -1,6 +1,3 @@
<?php
$return_to = isset($_GET['return_to']) ? mysqli_real_escape_string($koneksi, trim($_GET['return_to'])) : '';
?>
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">
@@ -91,10 +88,10 @@ $return_to = isset($_GET['return_to']) ? mysqli_real_escape_string($koneksi, tri
<div class="form-group row">
<label class="col-sm-2 col-form-label">RT/RW</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="rt" name="rt" placeholder="RT" value="000" required>
<input type="text" class="form-control" id="rt" name="rt" placeholder="RT" required>
</div>
<div class="col-sm-3">
<input type="text" class="form-control" id="rw" name="rw" placeholder="RW" value="000" required>
<input type="text" class="form-control" id="rw" name="rw" placeholder="RW" required>
</div>
</div>
@@ -143,62 +140,11 @@ $return_to = isset($_GET['return_to']) ? mysqli_real_escape_string($koneksi, tri
</div>
<script>
window.addEventListener('load', function() {
// Pre-fill form from URL parameters
var urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('nik')) document.getElementsByName('nik')[0].value = urlParams.get('nik');
if (urlParams.has('nama')) document.getElementsByName('nama')[0].value = urlParams.get('nama');
if (urlParams.has('desa')) document.getElementsByName('desa')[0].value = urlParams.get('desa');
if (urlParams.has('rt')) document.getElementsByName('rt')[0].value = urlParams.get('rt');
if (urlParams.has('rw')) document.getElementsByName('rw')[0].value = urlParams.get('rw');
if (urlParams.has('kecamatan')) document.getElementsByName('kecamatan')[0].value = urlParams.get('kecamatan');
if (urlParams.has('kabupaten')) document.getElementsByName('kabupaten')[0].value = urlParams.get('kabupaten');
if (urlParams.has('provinsi')) document.getElementsByName('provinsi')[0].value = urlParams.get('provinsi');
// NIK Validation (16 digits, numeric)
var nikInput = document.getElementsByName('nik')[0];
function validateNIK(nik) {
nik = nik.trim();
if (nik.length !== 16) return false;
return /^\d+$/.test(nik); // Only digits
}
function showNIKError(message) {
Swal.fire({
icon: 'warning',
title: 'Format NIK Salah',
text: message,
confirmButtonText: 'OK'
});
}
// Validate on blur
if (nikInput) {
nikInput.addEventListener('blur', function() {
var nik = this.value.trim();
if (nik === '') return;
if (!validateNIK(nik)) {
showNIKError('NIK harus terdiri dari 16 digit angka.');
this.focus();
}
});
}
// Validate on form submit
var form = document.querySelector('form');
if (form) {
form.addEventListener('submit', function(e) {
var nik = nikInput.value.trim();
if (nik !== '' && !validateNIK(nik)) {
e.preventDefault();
showNIKError('NIK harus terdiri dari 16 digit angka.');
nikInput.focus();
return false;
}
});
}
// Scanner Logic
var inputImage = document.getElementById('foto_ktp');
var preview = document.getElementById('preview_ktp');
var hiddenInput = document.getElementById('foto_cropped');
window.addEventListener('load', function() {
// Scanner Logic
var inputImage = document.getElementById('foto_ktp');
var preview = document.getElementById('preview_ktp');
var hiddenInput = document.getElementById('foto_cropped');
// Defines callback for scanner modal
window.handleScannerResult = function(base64) {
@@ -385,144 +331,102 @@ window.addEventListener('load', function() {
}
//mulai proses simpan data
$nik = mysqli_real_escape_string($koneksi, trim($_POST['nik']));
$cek_nik = mysqli_query($koneksi, "SELECT * FROM tb_pdd WHERE nik='$nik'");
if(mysqli_num_rows($cek_nik) > 0){
echo "<script>
Swal.fire({title: 'Gagal',text: 'NIK sudah terdaftar dalam sistem!',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-pend" . (!empty($return_to) ? '&return_to=' . $return_to : '') . "';
}
})</script>";
return;
}
// Sanitize Input to prevent SQL Injection & Syntax Errors
$nama = mysqli_real_escape_string($koneksi, trim($_POST['nama']));
$tempat_lh = mysqli_real_escape_string($koneksi, trim($_POST['tempat_lh']));
$tgl_lh = mysqli_real_escape_string($koneksi, trim($_POST['tgl_lh']));
$jekel = mysqli_real_escape_string($koneksi, trim($_POST['jekel']));
$desa = mysqli_real_escape_string($koneksi, trim($_POST['desa']));
$rt = mysqli_real_escape_string($koneksi, trim($_POST['rt']));
$rw = mysqli_real_escape_string($koneksi, trim($_POST['rw']));
$agama = mysqli_real_escape_string($koneksi, trim($_POST['agama']));
$kawin = mysqli_real_escape_string($koneksi, trim($_POST['kawin']));
$pekerjaan = mysqli_real_escape_string($koneksi, trim($_POST['pekerjaan']));
$kecamatan = mysqli_real_escape_string($koneksi, trim($_POST['kecamatan']));
$kabupaten = mysqli_real_escape_string($koneksi, trim($_POST['kabupaten']));
$provinsi = mysqli_real_escape_string($koneksi, trim($_POST['provinsi']));
$kewarganegaraan = mysqli_real_escape_string($koneksi, trim($_POST['kewarganegaraan']));
$nik = $_POST['nik'];
$cek_nik = mysqli_query($koneksi, "SELECT * FROM tb_pdd WHERE nik='$nik'");
if(mysqli_num_rows($cek_nik) > 0){
// AUTO-LINKING: Instead of blocking, we UPDATE the existing record with Scan Data
// Sanitize input first before UPDATE
$nama = mysqli_real_escape_string($koneksi, $_POST['nama']);
$tempat_lh = mysqli_real_escape_string($koneksi, $_POST['tempat_lh']);
$tgl_lh = mysqli_real_escape_string($koneksi, $_POST['tgl_lh']);
$jekel = mysqli_real_escape_string($koneksi, $_POST['jekel']);
$desa = mysqli_real_escape_string($koneksi, $_POST['desa']);
$rt = mysqli_real_escape_string($koneksi, $_POST['rt']);
$rw = mysqli_real_escape_string($koneksi, $_POST['rw']);
$agama = mysqli_real_escape_string($koneksi, $_POST['agama']);
$kawin = mysqli_real_escape_string($koneksi, $_POST['kawin']);
$pekerjaan = mysqli_real_escape_string($koneksi, $_POST['pekerjaan']);
$kewarganegaraan = mysqli_real_escape_string($koneksi, $_POST['kewarganegaraan']);
$sql_simpan = "INSERT INTO tb_pdd (nik, nama, tempat_lh, tgl_lh, jekel, desa, rt, rw, agama, kawin, pekerjaan, foto_ktp, status, kecamatan, kabupaten, provinsi, kewarganegaraan) VALUES (
'$nik',
'$nama',
'$tempat_lh',
'$tgl_lh',
'$jekel',
'$desa',
'$rt',
'$rw',
'$agama',
'$kawin',
'$pekerjaan',
'$nama_file',
'Ada',
'$kecamatan',
'$kabupaten',
'$provinsi',
'$kewarganegaraan')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
if ($query_simpan) {
$id_pend_baru = mysqli_insert_id($koneksi);
$redirect_url = !empty($return_to) ? "index.php?page=" . $return_to . "&selected_id=" . $id_pend_baru : "index.php?page=data-pend";
// KTP → KK: Cari KK yang cocok berdasarkan alamat
$sql_cari_kk = "SELECT k.id_kk, k.no_kk, k.kepala, k.desa, k.rt, k.rw
FROM tb_kk k
WHERE k.desa='$desa' AND k.rt='$rt' AND k.rw='$rw'
AND k.kec='$kecamatan' AND k.kab='$kabupaten' AND k.prov='$provinsi'";
$q_cari_kk = mysqli_query($koneksi, $sql_cari_kk);
$kk_cocok = mysqli_fetch_assoc($q_cari_kk);
if ($kk_cocok) {
// Tawarkan untuk menghubungkan dengan KK
$no_kk = $kk_cocok['no_kk'];
$kepala_kk = $kk_cocok['kepala'];
$id_kk = $kk_cocok['id_kk'];
// Cek apakah sudah terhubung
$sql_cek_hubungan = "SELECT * FROM tb_anggota WHERE id_kk='$id_kk' AND id_pend='$id_pend_baru'";
$q_cek_hubungan = mysqli_query($koneksi, $sql_cek_hubungan);
if (mysqli_num_rows($q_cek_hubungan) == 0) {
// Simpan sementara data untuk konfirmasi JavaScript
$_SESSION['kk_link_data'] = [
'id_pend' => $id_pend_baru,
'id_kk' => $id_kk,
'no_kk' => $no_kk,
'kepala_kk' => $kepala_kk,
'nama_pend' => $nama
];
echo "<script>
Swal.fire({
title: 'Data Penduduk Disimpan!',
html: '<b>Data berhasil disimpan.</b><br><br>Ditemukan KK dengan alamat yang sama:<br><b>No KK: $no_kk</b><br>Kepala Keluarga: $kepala_kk<br><br>Hubungkan ke KK ini sebagai anggota?',
icon: 'success',
showCancelButton: true,
confirmButtonText: 'Ya, Hubungkan',
cancelButtonText: 'Tidak, Simpan Saja'
}).then((result) => {
if (result.value) {
// Kirim permintaan untuk menghubungkan
fetch('admin/pend/link_to_kk.php', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'id_pend=$id_pend_baru&id_kk=$id_kk&hubungan=ANGGOTA'
}).then(resp => resp.json()).then(data => {
if(data.success) {
Swal.fire('Berhasil!', 'Data telah dihubungkan dengan KK.', 'success').then(() => {
window.location = '$redirect_url';
});
} else {
Swal.fire('Gagal', 'Gagal menghubungkan: ' + data.message, 'error').then(() => {
window.location = '$redirect_url';
});
}
});
} else {
window.location = '$redirect_url';
}
});
</script>";
} else {
// Sudah terhubung
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: 'Data telah terhubung dengan KK $no_kk',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = '$redirect_url';
}
})</script>";
}
} else {
// Tidak ada KK yang cocok
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = '$redirect_url';
}
})</script>";
}
} else {
$error_redirect = 'index.php?page=add-pend' . (!empty($return_to) ? '&return_to=' . $return_to : '');
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '" . mysqli_error($koneksi) . "',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = '$error_redirect';
}
})</script>";
}
mysqli_close($koneksi);
}
$sql_update = "UPDATE tb_pdd SET
nama='$nama',
tempat_lh='$tempat_lh',
tgl_lh='$tgl_lh',
jekel='$jekel',
desa='$desa',
rt='$rt',
rw='$rw',
agama='$agama',
kawin='$kawin',
pekerjaan='$pekerjaan',
kewarganegaraan='$kewarganegaraan',
foto_ktp='$nama_file'
WHERE nik='$nik'";
$query_update = mysqli_query($koneksi, $sql_update);
if ($query_update) {
echo "<script>
Swal.fire({title: 'Data Diperbarui',text: 'NIK sudah ada, data penduduk telah diperbarui dengan hasil scan KTP.',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-pend';
}
})</script>";
return;
}
}
// Sanitize Input to prevent SQL Injection & Syntax Errors
$nik = mysqli_real_escape_string($koneksi, $_POST['nik']);
$nama = mysqli_real_escape_string($koneksi, $_POST['nama']);
$tempat_lh = mysqli_real_escape_string($koneksi, $_POST['tempat_lh']);
$tgl_lh = mysqli_real_escape_string($koneksi, $_POST['tgl_lh']);
$jekel = mysqli_real_escape_string($koneksi, $_POST['jekel']);
$desa = mysqli_real_escape_string($koneksi, $_POST['desa']);
$rt = mysqli_real_escape_string($koneksi, $_POST['rt']);
$rw = mysqli_real_escape_string($koneksi, $_POST['rw']);
$agama = mysqli_real_escape_string($koneksi, $_POST['agama']);
$kawin = mysqli_real_escape_string($koneksi, $_POST['kawin']);
$pekerjaan = mysqli_real_escape_string($koneksi, $_POST['pekerjaan']);
$kecamatan = mysqli_real_escape_string($koneksi, $_POST['kecamatan']);
$kabupaten = mysqli_real_escape_string($koneksi, $_POST['kabupaten']);
$provinsi = mysqli_real_escape_string($koneksi, $_POST['provinsi']);
$kewarganegaraan = mysqli_real_escape_string($koneksi, $_POST['kewarganegaraan']);
$sql_simpan = "INSERT INTO tb_pdd (nik, nama, tempat_lh, tgl_lh, jekel, desa, rt, rw, agama, kawin, pekerjaan, foto_ktp, status, kecamatan, kabupaten, provinsi, kewarganegaraan) VALUES (
'$nik',
'$nama',
'$tempat_lh',
'$tgl_lh',
'$jekel',
'$desa',
'$rt',
'$rw',
'$agama',
'$kawin',
'$pekerjaan',
'$nama_file',
'Ada',
'$kecamatan',
'$kabupaten',
'$provinsi',
'$kewarganegaraan')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
mysqli_close($koneksi);
if ($query_simpan) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-pend';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '<?php echo mysqli_error($koneksi); ?>',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-pend';
}
})</script>";
}}
//selesai proses simpan data

View File

@@ -17,7 +17,7 @@
<th>No</th>
<th>NIK</th>
<th>Nama</th>
<th>Jenis Kelamin</th>
<th>JK</th>
<th>Alamat</th>
<th>No KK</th>
<th>Aksi</th>
@@ -59,15 +59,7 @@
<?php echo $data['nama']; ?>
</td>
<td>
<?php
if ($data['jekel'] == 'LK') {
echo 'LAKI-LAKI';
} elseif ($data['jekel'] == 'PR') {
echo 'PEREMPUAN';
} else {
echo $data['jekel'];
}
?>
<?php echo $data['jekel']; ?>
</td>
<td>
<?php echo $data['desa']; ?>

View File

@@ -1,62 +0,0 @@
<?php
session_start();
include "../inc/koneksi.php";
header('Content-Type: application/json');
if (!isset($_SESSION["ses_username"])) {
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'message' => 'Invalid request method']);
exit;
}
$id_pend = isset($_POST['id_pend']) ? intval($_POST['id_pend']) : 0;
$id_kk = isset($_POST['id_kk']) ? intval($_POST['id_kk']) : 0;
$hubungan = isset($_POST['hubungan']) ? mysqli_real_escape_string($koneksi, $_POST['hubungan']) : 'ANGGOTA';
if ($id_pend <= 0 || $id_kk <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
// Cek apakah sudah terhubung
$sql_cek = "SELECT * FROM tb_anggota WHERE id_kk='$id_kk' AND id_pend='$id_pend'";
$q_cek = mysqli_query($koneksi, $sql_cek);
if (mysqli_num_rows($q_cek) > 0) {
echo json_encode(['success' => false, 'message' => 'Sudah terhubung']);
exit;
}
// Cek apakah penduduk ada
$sql_cek_pend = "SELECT * FROM tb_pdd WHERE id_pend='$id_pend'";
$q_cek_pend = mysqli_query($koneksi, $sql_cek_pend);
if (mysqli_num_rows($q_cek_pend) == 0) {
echo json_encode(['success' => false, 'message' => 'Data penduduk tidak ditemukan']);
exit;
}
// Cek apakah KK ada
$sql_cek_kk = "SELECT * FROM tb_kk WHERE id_kk='$id_kk'";
$q_cek_kk = mysqli_query($koneksi, $sql_cek_kk);
if (mysqli_num_rows($q_cek_kk) == 0) {
echo json_encode(['success' => false, 'message' => 'Data KK tidak ditemukan']);
exit;
}
// Hubungkan
$sql_link = "INSERT INTO tb_anggota (id_kk, id_pend, hubungan) VALUES ('$id_kk', '$id_pend', '$hubungan')";
$q_link = mysqli_query($koneksi, $sql_link);
if ($q_link) {
echo json_encode(['success' => true, 'message' => 'Berhasil dihubungkan']);
} else {
echo json_encode(['success' => false, 'message' => 'Database error: ' . mysqli_error($koneksi)]);
}
mysqli_close($koneksi);
?>

View File

@@ -30,11 +30,11 @@
<div class="form-group row">
<label class="col-sm-2 col-form-label">Level</label>
<div class="col-sm-4">
<select name="level" id="level" class="form-control">
<option value="">- Pilih -</option>
<option value="Administrator">Administrator</option>
<option value="Kaur Pemerintah">Kaur Pemerintah</option>
</select>
<select name="level" id="level" class="form-control">
<option>- Pilih -</option>
<option>Administrator</option>
<option>Kaur Pemerintah</option>
</select>
</div>
</div>
@@ -46,45 +46,31 @@
</form>
</div>
<?php
if (isset ($_POST['Simpan'])){
// Map level untuk database (enum: 'admin', 'kaur')
$level_map = [
'Administrator' => 'admin',
'Kaur Pemerintah' => 'kaur'
];
$level_db = isset($level_map[$_POST['level']]) ? $level_map[$_POST['level']] : $_POST['level'];
// Sanitize Input to prevent SQL Injection & Syntax Errors
$nama_pengguna = mysqli_real_escape_string($koneksi, trim($_POST['nama_pengguna']));
$username = mysqli_real_escape_string($koneksi, trim($_POST['username']));
$password_raw = trim($_POST['password']);
$password_hash = MD5($password_raw);
$level_db = mysqli_real_escape_string($koneksi, $level_db);
//mulai proses simpan data
$sql_simpan = "INSERT INTO tb_pengguna (nama_pengguna,username,password,level) VALUES (
'$nama_pengguna',
'$username',
'$password_hash',
'$level_db')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
mysqli_close($koneksi);
if ($query_simpan) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-pengguna';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-pengguna';
}
})</script>";
}}
//selesai proses simpan data
<?php
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
$sql_simpan = "INSERT INTO tb_pengguna (nama_pengguna,username,password,level) VALUES (
'".$_POST['nama_pengguna']."',
'".$_POST['username']."',
'".$_POST['password']."',
'".$_POST['level']."')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
mysqli_close($koneksi);
if ($query_simpan) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-pengguna';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-pengguna';
}
})</script>";
}}
//selesai proses simpan data

View File

@@ -23,16 +23,11 @@
</thead>
<tbody>
<?php
$no = 1;
$level_map = [
'admin' => 'Administrator',
'kaur' => 'Kaur Pemerintah'
];
$sql = $koneksi->query("select * from tb_pengguna");
while ($data= $sql->fetch_assoc()) {
$level_display = isset($level_map[$data['level']]) ? $level_map[$data['level']] : $data['level'];
?>
<?php
$no = 1;
$sql = $koneksi->query("select * from tb_pengguna");
while ($data= $sql->fetch_assoc()) {
?>
<tr>
<td>
@@ -45,17 +40,17 @@
<?php echo $data['username']; ?>
</td>
<td>
<?php echo $level_display; ?>
<?php echo $data['level']; ?>
</td>
<td>
<a href="?page=edit-pengguna&kode=<?php echo $data['id_pengguna']; ?>" title="Ubah"
class="btn btn-success btn-sm">
<i class="fa fa-edit"></i>
</a>
<a href="?page=del-pengguna&kode=<?php echo $data['id_pengguna']; ?>" onclick="confirmDelete(event)"
<a href="?page=del-pengguna&kode=<?php echo $data['id_pengguna']; ?>" onclick="return confirm('Apakah anda yakin hapus data ini ?')"
title="Hapus" class="btn btn-danger btn-sm">
<i class="fa fa-trash"></i>
</a>
</>
</td>
</tr>
@@ -64,26 +59,7 @@
?>
</tbody>
</tfoot>
</table>
</div>
</div>
<!-- /.card-body -->
<script>
function confirmDelete(event) {
event.preventDefault();
Swal.fire({
title: 'Konfirmasi Hapus',
text: 'Apakah Anda yakin ingin menghapus data ini?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = event.currentTarget.href;
}
});
}
</script>
</table>
</div>
</div>
<!-- /.card-body -->

View File

@@ -46,29 +46,17 @@
<div class="form-group row">
<label class="col-sm-2 col-form-label">Level</label>
<div class="col-sm-4">
<select name="level" id="level" class="form-control">
<option value="">-- Pilih Level --</option>
<?php
// Mapping level dari database ke tampilan
$level_display_map = [
'admin' => 'Administrator',
'kaur' => 'Kaur Pemerintah',
'Administrator' => 'Administrator', // backward compatibility
'Kaur Pemerintah' => 'Kaur Pemerintah'
];
$current_level = $data_cek['level'];
$current_display = isset($level_display_map[$current_level]) ? $level_display_map[$current_level] : $current_level;
// Opsi Administrator
if ($current_display == "Administrator") {
echo "<option value='Administrator' selected>Administrator</option>";
echo "<option value='Kaur Pemerintah'>Kaur Pemerintah</option>";
} else {
echo "<option value='Administrator'>Administrator</option>";
echo "<option value='Kaur Pemerintah' selected>Kaur Pemerintah</option>";
}
?>
</select>
<select name="level" id="level" class="form-control">
<option value="">-- Pilih Level --</option>
<?php
//menhecek data yg dipilih sebelumnya
if ($data_cek['level'] == "Administrator") echo "<option value='Administrator' selected>Administrator</option>";
else echo "<option value='Administrator'>Administrator</option>";
if ($data_cek['level'] == "Kaur Pemerintah") echo "<option value='Kaur Pemerintah' selected>Kaur Pemerintah</option>";
else echo "<option value='Kaur Pemerintah'>Kaur Pemerintah</option>";
?>
</select>
</div>
</div>
@@ -84,21 +72,14 @@
<?php
if (isset ($_POST['Ubah'])){
// Map level untuk database (enum: 'admin', 'kaur')
$level_map = [
'Administrator' => 'admin',
'Kaur Pemerintah' => 'kaur'
];
$level_db = isset($level_map[$_POST['level']]) ? $level_map[$_POST['level']] : $_POST['level'];
$sql_ubah = "UPDATE tb_pengguna SET
nama_pengguna='".$_POST['nama_pengguna']."',
username='".$_POST['username']."',
password='".$_POST['password']."',
level='".$level_db."'
WHERE id_pengguna='".$_POST['id_pengguna']."'";
$query_ubah = mysqli_query($koneksi, $sql_ubah);
if (isset ($_POST['Ubah'])){
$sql_ubah = "UPDATE tb_pengguna SET
nama_pengguna='".$_POST['nama_pengguna']."',
username='".$_POST['username']."',
password='".$_POST['password']."',
level='".$_POST['level']."'
WHERE id_pengguna='".$_POST['id_pengguna']."'";
$query_ubah = mysqli_query($koneksi, $sql_ubah);
mysqli_close($koneksi);
if ($query_ubah) {

View File

@@ -52,41 +52,35 @@
</form>
</div>
<?php
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
// Sanitize Input to prevent SQL Injection & Syntax Errors
$id_pdd = (int)$_POST['id_pdd']; // Cast to integer for safety
$tgl_pindah = mysqli_real_escape_string($koneksi, trim($_POST['tgl_pindah']));
$alasan = mysqli_real_escape_string($koneksi, trim($_POST['alasan']));
$sql_simpan = "INSERT INTO tb_pindah (id_pdd, tgl_pindah, alasan) VALUES (
'$id_pdd',
'$tgl_pindah',
'$alasan')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
$sql_ubah = "UPDATE tb_pdd SET
status='Pindah'
WHERE id_pend='$id_pdd'";
$query_ubah = mysqli_query($koneksi, $sql_ubah);
mysqli_close($koneksi);
if ($query_simpan && $query_ubah) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-pindah';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-pindah';
}
})</script>";
}}
//selesai proses simpan data
<?php
if (isset ($_POST['Simpan'])){
//mulai proses simpan data
$sql_simpan = "INSERT INTO tb_pindah (id_pdd, tgl_pindah, alasan) VALUES (
'".$_POST['id_pdd']."',
'".$_POST['tgl_pindah']."',
'".$_POST['alasan']."')";
$query_simpan = mysqli_query($koneksi, $sql_simpan);
$sql_ubah = "UPDATE tb_pdd SET
status='Pindah'
WHERE id_pend='".$_POST['id_pdd']."'";
$query_ubah = mysqli_query($koneksi, $sql_ubah);
mysqli_close($koneksi);
if ($query_simpan && $query_ubah) {
echo "<script>
Swal.fire({title: 'Tambah Data Berhasil',text: '',icon: 'success',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=data-pindah';
}
})</script>";
}else{
echo "<script>
Swal.fire({title: 'Tambah Data Gagal',text: '',icon: 'error',confirmButtonText: 'OK'
}).then((result) => {if (result.value){
window.location = 'index.php?page=add-pindah';
}
})</script>";
}}
//selesai proses simpan data

View File

@@ -13,21 +13,20 @@
<br>
<table id="example1" class="table table-bordered table-striped">
<thead>
<tr>
<th>No</th>
<th>NIK</th>
<th>Nama</th>
<th>Jenis Kelamin</th>
<th>Tanggal</th>
<th>Alasan</th>
<th>Aksi</th>
</tr>
<tr>
<th>No</th>
<th>NIK</th>
<th>Nama</th>
<th>Tanggal</th>
<th>Alasan</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php
$no = 1;
$sql = $koneksi->query("SELECT p.id_pend, p.nik, p.nama, p.jekel, d.tgl_pindah, d.alasan, d.id_pindah from
$sql = $koneksi->query("SELECT p.id_pend, p.nik, p.nama, d.tgl_pindah, d.alasan, d.id_pindah from
tb_pindah d inner join tb_pdd p on p.id_pend=d.id_pdd");
while ($data= $sql->fetch_assoc()) {
?>
@@ -42,12 +41,9 @@
<td>
<?php echo $data['nama']; ?>
</td>
<td>
<?php echo $data['jekel'] == 'LK' ? 'LAKI-LAKI' : 'PEREMPUAN'; ?>
</td>
<td>
<?php echo $data['tgl_pindah']; ?>
</td>
<td>
<?php echo $data['tgl_pindah']; ?>
</td>
<td>
<?php echo $data['alasan']; ?>
</td>
@@ -60,10 +56,10 @@
class="btn btn-success btn-sm">
<i class="fa fa-edit"></i>
</a>
<a href="?page=del-pindah&kode=<?php echo $data['id_pend']; ?>" onclick="confirmDelete(event)"
<a href="?page=del-pindah&kode=<?php echo $data['id_pend']; ?>" onclick="return confirm('Apakah anda yakin hapus data ini ?')"
title="Hapus" class="btn btn-danger btn-sm">
<i class="fa fa-trash"></i>
</a>
</>
</td>
</tr>
@@ -72,26 +68,7 @@
?>
</tbody>
</tfoot>
</table>
</div>
</div>
<!-- /.card-body -->
<script>
function confirmDelete(event) {
event.preventDefault();
Swal.fire({
title: 'Konfirmasi Hapus',
text: 'Apakah Anda yakin ingin menghapus data ini?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = event.currentTarget.href;
}
});
}
</script>
</table>
</div>
</div>
<!-- /.card-body -->

View File

@@ -90,15 +90,7 @@
<b>Jenis Kelamin</b>
</td>
<td>:
<?php
if ($data_cek['jekel'] == 'LK') {
echo 'LAKI-LAKI';
} elseif ($data_cek['jekel'] == 'PR') {
echo 'PEREMPUAN';
} else {
echo $data_cek['jekel'];
}
?>
<?php echo $data_cek['jekel']; ?>
</td>
</tr>
<tr>

View File

@@ -3,51 +3,29 @@
<div class="modal fade" id="modalScanner" tabindex="-1" role="dialog" aria-labelledby="modalScannerLabel" aria-hidden="true" data-backdrop="static">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<div class="modal-header">
<h5 class="modal-title" id="modalScannerLabel"><i class="fas fa-expand"></i> Smart Scanner</h5>
<div class="ml-auto mr-3">
<div class="btn-group btn-group-sm" role="group" id="scannerModeToggle">
<button type="button" class="btn btn-outline-primary active" data-mode="smart">
<i class="fas fa-magic"></i> Smart Scan
</button>
<button type="button" class="btn btn-outline-secondary" data-mode="manual">
<i class="fas fa-crop-alt"></i> Manual Crop
</button>
</div>
</div>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body text-center bg-dark p-0" style="position: relative; overflow: hidden; height: 80vh;">
<!-- Smart Scan Mode (Default) -->
<div id="scanner-container" class="scanner-mode" data-mode="smart" style="display: block; position: relative; margin: auto; display: inline-block;">
<canvas id="canvas-image" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
<canvas id="canvas-overlay" style="position: absolute; left: 0; top: 0; z-index: 2; cursor: crosshair;"></canvas>
<div class="modal-body text-center bg-dark p-0" style="position: relative; overflow: hidden; height: 80vh;">
<!-- Container for Canvases -->
<!-- Container for Canvases -->
<div id="scanner-container" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); box-shadow: 0 0 10px rgba(0,0,0,0.5);">
<canvas id="canvas-image" style="position: absolute; left: 0; top: 0; z-index: 10;"></canvas>
<canvas id="canvas-overlay" style="position: absolute; left: 0; top: 0; z-index: 20; cursor: crosshair;"></canvas>
</div>
<!-- Manual Crop Mode (Cropper.js) -->
<div id="crop-container" class="scanner-mode" data-mode="manual" style="display: none; width: 100%; height: 100%;">
<img id="crop-image" style="max-width: 100%; max-height: 100%;">
</div>
<div id="scanner-loading" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); color: white; display: none;">
<i class="fas fa-spinner fa-spin fa-3x"></i><br>Detecting Document...
</div>
<!-- Mobile Help Tips -->
<div id="mobile-help" class="d-none d-md-none d-lg-none" style="position: absolute; bottom: 10px; left: 0; right: 0; text-align: center; color: white; background: rgba(0,0,0,0.7); padding: 5px; font-size: 12px;">
<span id="help-text-smart">📍 Sentuh & geser titik biru untuk atur sudut (untuk mobile, gunakan Manual Crop)</span>
<span id="help-text-manual" style="display: none;">📍 Pinch untuk zoom, geser untuk pindah area crop</span>
<div id="scanner-loading" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); color: white; display: none; z-index: 50; text-align: center;">
<i class="fas fa-spinner fa-spin fa-3x"></i><br><span style="margin-top: 10px; display: block;">Sedang menganalisa...</span>
</div>
</div>
<div class="modal-footer justify-content-between">
<div>
<button type="button" class="btn btn-secondary" id="btnScanRotateLeft" title="Putar Kiri (-90°)"><i class="fas fa-undo"></i></button>
<button type="button" class="btn btn-secondary" id="btnScanRotateRight" title="Putar Kanan (+90°)"><i class="fas fa-redo"></i></button>
<button type="button" class="btn btn-warning" id="btnScanReset"><i class="fas fa-sync"></i> Reset Sudut</button>
<button type="button" class="btn btn-info d-none" id="btnCropReset"><i class="fas fa-crop"></i> Reset Crop</button>
</div>
<div>
<button type="button" class="btn btn-secondary" id="btnScanRotateLeft" title="Putar Kiri (-90°)"><i class="fas fa-undo"></i></button>
<button type="button" class="btn btn-secondary" id="btnScanRotateRight" title="Putar Kanan (+90°)"><i class="fas fa-redo"></i></button>
<button type="button" class="btn btn-warning" id="btnScanReset"><i class="fas fa-sync"></i> Reset Sudut</button>
</div>
<div>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button type="button" class="btn btn-primary" id="btnScanSave"><i class="fas fa-check"></i> Simpan Hasil Scan</button>
@@ -57,158 +35,6 @@
</div>
</div>
<style>
/* Disable all transitions and hover effects for scanner modal */
#modalScanner .card,
#modalScanner .modal-content,
#modalScanner .modal-body,
#modalScanner .modal-header,
#modalScanner .modal-footer,
#modalScanner .modal-dialog,
#modalScanner #scanner-container,
#modalScanner #scanner-container * {
transition: none !important;
}
#modalScanner .card:hover,
#modalScanner .modal-content:hover,
#modalScanner .modal-body:hover,
#modalScanner .modal-header:hover,
#modalScanner .modal-footer:hover,
#modalScanner .modal-dialog:hover,
#modalScanner #scanner-container:hover,
#modalScanner #scanner-container *:hover {
transform: none !important;
}
/* Ensure canvas is fully visible */
#canvas-image {
opacity: 1 !important;
filter: none !important;
background-color: white !important;
}
#canvas-overlay {
opacity: 1 !important;
filter: none !important;
}
/* Prevent canvas from moving on hover */
#canvas-image:hover,
#canvas-overlay:hover {
transform: none !important;
}
/* Prevent modal dragging and improve touch handling on mobile */
#modalScanner .modal-dialog,
#modalScanner .modal-content,
#modalScanner .modal-header,
#modalScanner .modal-footer {
touch-action: none !important; /* Prevent browser touch gestures (pan, zoom, swipe) */
user-select: none !important; /* Prevent text selection during drag */
-webkit-user-select: none !important;
-webkit-touch-callout: none !important;
}
/* Allow touch interaction only on canvas and buttons */
#modalScanner .modal-body,
#canvas-image,
#canvas-overlay {
touch-action: manipulation !important; /* Allow pinch-zoom and pan on canvas only */
}
/* Prevent modal backdrop from responding to touch */
.modal-backdrop {
touch-action: none !important;
}
/* Lock modal position on mobile */
@media (max-width: 768px) {
#modalScanner {
padding-right: 0 !important; /* Prevent shift from scrollbar */
}
#modalScanner .modal-dialog {
margin: 0 !important;
max-height: 100vh !important;
height: 100vh !important;
width: 100vw !important;
max-width: 100vw !important;
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
transform: none !important;
transition: none !important;
}
#modalScanner .modal-content {
border-radius: 0 !important;
height: 100vh !important;
max-height: 100vh !important;
width: 100vw !important;
max-width: 100vw !important;
overflow: hidden !important;
position: fixed !important;
top: 0 !important;
left: 0 !important;
transform: none !important;
transition: none !important;
}
#modalScanner .modal-body {
height: calc(100vh - 120px) !important; /* Account for header and footer */
overflow: hidden !important;
}
/* Prevent any modal movement */
.modal-open #modalScanner {
overflow: hidden !important;
}
/* Larger touch target for close button on mobile */
#modalScanner .modal-header .close {
padding: 20px !important;
font-size: 2rem !important;
line-height: 1 !important;
margin: -10px -10px -10px auto !important;
}
/* Larger touch targets for all buttons */
#modalScanner .modal-footer .btn {
min-height: 44px !important;
min-width: 44px !important;
padding: 10px 15px !important;
font-size: 16px !important; /* Prevent zoom on iOS */
}
/* Larger corner points for touch */
#canvas-overlay {
touch-action: manipulation;
}
/* Mode toggle buttons */
#scannerModeToggle .btn {
min-height: 36px !important;
min-width: 90px !important;
font-size: 14px !important;
}
/* Help text */
#mobile-help {
font-size: 14px !important;
padding: 10px !important;
}
}
/* Cropper.js customizations for mobile */
.cropper-point {
width: 30px !important;
height: 30px !important;
}
.cropper-line {
background-color: rgba(0, 123, 255, 0.5) !important;
}
/* Larger hit area for corner points in smart scan */
.scanner-mode[data-mode="smart"] canvas {
touch-action: pinch-zoom;
}
</style>
<script>
window.addEventListener('load', function() {
// Scanner Variables
@@ -218,72 +44,22 @@ window.addEventListener('load', function() {
var ctxImg = canvasImage.getContext('2d');
var ctxOver = canvasOverlay.getContext('2d');
var scanner = null;
try {
scanner = new jscanify();
} catch (e) {
console.error('Failed to initialize jscanify:', e);
// scanner remains null
}
var originalImg = new Image();
// Cropper.js instance
var cropper = null;
var currentMode = IS_TOUCH_DEVICE ? 'manual' : 'smart'; // Default to manual for touch devices
var scanner = new jscanify();
var originalImg = new Image();
// Corner Points (tl, tr, bl, br)
var corners = [];
var activePoint = null;
var isDragging = false;
var touchStartPos = null;
var isTouchInteraction = false;
var touchOffset = null;
// Corner Points (tl, tr, bl, br)
var corners = [];
var activePoint = null;
var isDragging = false;
// Config
const POINT_RADIUS = IS_TOUCH_DEVICE ? 25 : 15; // Larger for touch devices
const POINT_COLOR = '#007bff';
const LINE_COLOR = '#00ff00';
const LINE_WIDTH = IS_TOUCH_DEVICE ? 5 : 3;
const TOUCH_RADIUS_MULTIPLIER = 2.5; // Larger hit area for touch devices
const TOUCH_SLOP = 5; // pixels threshold before dragging starts
const IS_TOUCH_DEVICE = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
// Config
const POINT_RADIUS = 15;
const POINT_COLOR = '#007bff';
const LINE_COLOR = '#00ff00';
const LINE_WIDTH = 3;
// --- Mode Toggle Handler ---
$('#scannerModeToggle button').on('click', function() {
var mode = $(this).data('mode');
if (mode === currentMode) return;
// Update UI
$('#scannerModeToggle button').removeClass('active btn-primary').addClass('btn-outline-secondary');
$(this).removeClass('btn-outline-secondary').addClass('active btn-primary');
// Switch modes
$('.scanner-mode').hide();
$('.scanner-mode[data-mode="' + mode + '"]').show();
// Update help text
$('#help-text-smart, #help-text-manual').hide();
$('#help-text-' + mode).show();
// Show/hide appropriate buttons
if (mode === 'smart') {
$('#btnScanReset').removeClass('d-none');
$('#btnCropReset').addClass('d-none');
} else {
$('#btnScanReset').addClass('d-none');
$('#btnCropReset').removeClass('d-none');
// Initialize cropper if not already
if (typeof Cropper !== 'undefined' && !cropper && originalImg.src) {
initCropper();
}
}
currentMode = mode;
});
// --- Public Function to Open Scanner ---
window.openScanner = function(file) {
// --- Public Function to Open Scanner ---
window.openScanner = function(file) {
if (!file) return;
// Reset State
@@ -300,7 +76,10 @@ window.addEventListener('load', function() {
function checkReady() {
if (imgLoaded && modalShown) {
initScanner();
// Defer execution to allow UI (spinner) to render first
setTimeout(function() {
initScanner();
}, 100);
}
}
@@ -315,224 +94,77 @@ window.addEventListener('load', function() {
};
reader.readAsDataURL(file);
// 2. Show Modal & Listen
scannerModal.off('shown.bs.modal'); // Remove old listeners
scannerModal.on('shown.bs.modal', function() {
modalShown = true;
checkReady();
// Prevent body scrolling on mobile
document.body.style.overflow = 'hidden';
document.body.style.position = 'fixed';
document.body.style.width = '100%';
// Prevent modal dragging on mobile
var modalDialog = document.querySelector('#modalScanner .modal-dialog');
var modalContent = document.querySelector('#modalScanner .modal-content');
var modalHeader = document.querySelector('#modalScanner .modal-header');
var modalFooter = document.querySelector('#modalScanner .modal-footer');
var preventTouch = function(e) {
// Allow touch on canvas elements and buttons
var target = e.target;
var isCanvas = target.id === 'canvas-overlay' || target.id === 'canvas-image' ||
target.id === 'crop-image' || target.closest('#crop-container') ||
target.closest('#scanner-container');
var isButton = target.tagName === 'BUTTON' || target.closest('button');
if (!isCanvas && !isButton) {
e.preventDefault();
e.stopPropagation();
}
};
if (modalDialog) {
modalDialog.addEventListener('touchstart', preventTouch, { passive: false });
modalDialog.addEventListener('touchmove', preventTouch, { passive: false });
}
if (modalContent) {
modalContent.addEventListener('touchstart', preventTouch, { passive: false });
modalContent.addEventListener('touchmove', preventTouch, { passive: false });
}
if (modalHeader) {
modalHeader.addEventListener('touchstart', preventTouch, { passive: false });
modalHeader.addEventListener('touchmove', preventTouch, { passive: false });
}
if (modalFooter) {
modalFooter.addEventListener('touchstart', preventTouch, { passive: false });
modalFooter.addEventListener('touchmove', preventTouch, { passive: false });
}
});
// Restore scrolling when modal is hidden
scannerModal.on('hidden.bs.modal', function() {
document.body.style.overflow = '';
document.body.style.position = '';
document.body.style.width = '';
// Cleanup cropper
destroyCropper();
});
// 2. Show Modal & Listen
scannerModal.off('shown.bs.modal'); // Remove old listeners
scannerModal.on('shown.bs.modal', function() {
modalShown = true;
checkReady();
});
scannerModal.modal('show');
};
function detectDocument(scale, w, h, showAlert = false) {
// Detect Contour using jscanify
try {
// jscanify expects an image element, we can pass originalImg but we need to map coordinates
// Wait, jscanify uses OpenCV which might not be ready.
if (typeof cv !== 'undefined' && cv.Mat) {
// We need to work on the original image for detection, then scale points
var contour = scanner ? scanner.findPaper(originalImg) : null;
// contour returns { topLeftCorner, topRightCorner, bottomLeftCorner, bottomRightCorner } each {x, y}
if (contour) {
// Order: TL, TR, BR, BL (clockwise)
corners = [
{ x: contour.topLeftCorner.x * scale, y: contour.topLeftCorner.y * scale },
{ x: contour.topRightCorner.x * scale, y: contour.topRightCorner.y * scale },
{ x: contour.bottomRightCorner.x * scale, y: contour.bottomRightCorner.y * scale },
{ x: contour.bottomLeftCorner.x * scale, y: contour.bottomLeftCorner.y * scale }
];
function initScanner() {
// Resize Canvas to fit screen but keep aspect ratio
var maxWidth = $('#modalScanner .modal-body').width() - 20;
var maxHeight = $('#modalScanner .modal-body').height() - 20;
var scale = Math.min(maxWidth / originalImg.width, maxHeight / originalImg.height);
var w = originalImg.width * scale;
var h = originalImg.height * scale;
canvasImage.width = w;
canvasImage.height = h;
canvasOverlay.width = w;
canvasOverlay.height = h;
// Resize container
$('#scanner-container').css({ width: w, height: h });
// Draw Image
ctxImg.drawImage(originalImg, 0, 0, w, h);
// Detect Contour using jscanify
try {
// jscanify expects an image element, we can pass originalImg but we need to map coordinates
// Wait, jscanify uses OpenCV which might not be ready.
if (typeof cv !== 'undefined' && cv.Mat) {
// We need to work on the original image for detection, then scale points
var contour = scanner.findPaper(originalImg);
// contour returns { topLeftCorner, topRightCorner, bottomLeftCorner, bottomRightCorner } each {x, y}
if (contour) {
corners = [
{ x: contour.topLeftCorner.x * scale, y: contour.topLeftCorner.y * scale },
{ x: contour.topRightCorner.x * scale, y: contour.topRightCorner.y * scale },
{ x: contour.bottomRightCorner.x * scale, y: contour.bottomRightCorner.y * scale }, // Order: tr -> br -> bl ?? No, usually tl, tr, br, bl order for polygon drawing
{ x: contour.bottomLeftCorner.x * scale, y: contour.bottomLeftCorner.y * scale }
];
// Reorder primarily for logic: TL, TR, BR, BL
corners = [
{ x: contour.topLeftCorner.x * scale, y: contour.topLeftCorner.y * scale },
{ x: contour.topRightCorner.x * scale, y: contour.topRightCorner.y * scale },
{ x: contour.bottomRightCorner.x * scale, y: contour.bottomRightCorner.y * scale },
{ x: contour.bottomLeftCorner.x * scale, y: contour.bottomLeftCorner.y * scale }
];
} else {
defaultCorners(w, h);
if (showAlert) {
Swal.fire({
icon: 'warning',
title: 'Deteksi Gagal',
text: 'Dokumen tidak terdeteksi. Silakan atur sudut secara manual.',
confirmButtonText: 'OK'
});
}
}
} else {
console.warn("OpenCV not ready yet");
defaultCorners(w, h);
if (showAlert) {
Swal.fire({
icon: 'warning',
title: 'Scanner Tidak Siap',
text: 'OpenCV belum siap. Silakan atur sudut secara manual.',
confirmButtonText: 'OK'
});
}
}
} catch(e) {
console.error("Scanner Error:", e);
defaultCorners(w, h); // Fallback
if (showAlert) {
Swal.fire({
icon: 'error',
title: 'Error Scanner',
text: 'Terjadi kesalahan saat mendeteksi dokumen: ' + e.message,
confirmButtonText: 'OK'
});
}
}
drawOverlay();
}
} else {
defaultCorners(w, h);
}
} else {
console.warn("OpenCV not ready yet");
defaultCorners(w, h);
}
} catch(e) {
console.error("Scanner Error:", e);
defaultCorners(w, h); // Fallback
}
$('#scanner-loading').hide();
drawOverlay();
}
function initScanner() {
// Resize Canvas to fit screen but keep aspect ratio
var maxWidth = $('#modalScanner .modal-body').width() - 20;
var maxHeight = $('#modalScanner .modal-body').height() - 20;
var scale = Math.min(maxWidth / originalImg.width, maxHeight / originalImg.height);
var w = originalImg.width * scale;
var h = originalImg.height * scale;
canvasImage.width = w;
canvasImage.height = h;
canvasOverlay.width = w;
canvasOverlay.height = h;
// Resize container
$('#scanner-container').css({ width: w, height: h, marginTop: '10px' });
// Draw Image
ctxImg.drawImage(originalImg, 0, 0, w, h);
detectDocument(scale, w, h, false);
$('#scanner-loading').hide();
// Prepare image for cropper
var cropImage = document.getElementById('crop-image');
cropImage.src = originalImg.src;
// Initialize cropper if in manual mode
if (currentMode === 'manual' && typeof Cropper !== 'undefined') {
initCropper();
}
}
function initCropper() {
if (typeof Cropper === 'undefined') {
console.error('Cropper.js not loaded');
alert('Cropper library not loaded. Please refresh the page.');
return;
}
var cropImage = document.getElementById('crop-image');
if (!cropImage.src) {
console.warn('Crop image not loaded yet');
return;
}
// Destroy existing cropper
if (cropper) {
cropper.destroy();
cropper = null;
}
// Initialize new cropper with mobile-friendly options
cropper = new Cropper(cropImage, {
viewMode: 1,
dragMode: 'crop',
initialAspectRatio: 16 / 9,
aspectRatio: NaN, // Free aspect ratio
autoCrop: true,
autoCropArea: 0.8,
responsive: true,
restore: true,
checkCrossOrigin: false,
highlight: false,
cropBoxMovable: true,
cropBoxResizable: true,
toggleDragModeOnDblclick: false,
minCanvasWidth: 100,
minCanvasHeight: 100,
minContainerWidth: 100,
minContainerHeight: 100,
minCropBoxWidth: 50,
minCropBoxHeight: 50,
// Mobile touch settings
touchDragZoom: true,
wheelZoomRatio: 0.1,
ready: function() {
// Adjust for mobile
if (IS_TOUCH_DEVICE) {
// Make handles larger for touch
var points = this.cropper.cropBox.querySelectorAll('.cropper-point');
points.forEach(function(point) {
point.style.width = '30px';
point.style.height = '30px';
});
}
}
});
}
function destroyCropper() {
if (cropper) {
cropper.destroy();
cropper = null;
}
}
function defaultCorners(w, h) {
function defaultCorners(w, h) {
// Default 20% margin
var mX = w * 0.1;
var mY = h * 0.1;
@@ -582,225 +214,106 @@ window.addEventListener('load', function() {
};
}
function isInside(pos, point) {
var dx = pos.x - point.x;
var dy = pos.y - point.y;
return dx * dx + dy * dy <= POINT_RADIUS * POINT_RADIUS * 2; // Bigger hit area
}
function getClosestCorner(pos, isTouch) {
var closestIdx = -1;
var closestDist = Infinity;
var radius = POINT_RADIUS * (isTouch ? TOUCH_RADIUS_MULTIPLIER : 1.5); // Larger radius for touch
var radiusSq = radius * radius;
corners.forEach((p, i) => {
var dx = pos.x - p.x;
var dy = pos.y - p.y;
var distSq = dx * dx + dy * dy;
if (distSq < radiusSq && distSq < closestDist) {
closestDist = distSq;
closestIdx = i;
}
});
return closestIdx;
}
function isInside(pos, point) {
var dx = pos.x - point.x;
var dy = pos.y - point.y;
return dx * dx + dy * dy <= POINT_RADIUS * POINT_RADIUS * 2; // Bigger hit area
}
canvasOverlay.addEventListener('mousedown', function(e) {
handleStart(getMousePos(e), false);
e.stopPropagation();
});
canvasOverlay.addEventListener('touchstart', function(e) {
var pos = getMousePos(e);
handleStart(pos, true);
e.preventDefault();
e.stopPropagation();
}, {passive: false});
canvasOverlay.addEventListener('mousedown', function(e) { handleStart(getMousePos(e)); });
canvasOverlay.addEventListener('touchstart', function(e) { handleStart(getMousePos(e)); e.preventDefault(); }, {passive: false});
window.addEventListener('mousemove', function(e) { if(isDragging) handleMove(getMousePos(e)); }); // Window to catch drag out
canvasOverlay.addEventListener('touchmove', function(e) {
if(isDragging) {
handleMove(getMousePos(e));
e.preventDefault();
e.stopPropagation();
}
}, {passive: false});
window.addEventListener('mousemove', function(e) { if(isDragging) handleMove(getMousePos(e)); }); // Window to catch drag out
canvasOverlay.addEventListener('touchmove', function(e) { if(isDragging) handleMove(getMousePos(e)); e.preventDefault(); }, {passive: false});
window.addEventListener('mouseup', function() { handleEnd(); });
window.addEventListener('touchend', function() { handleEnd(); });
function handleStart(pos, isTouch = false) {
activePoint = getClosestCorner(pos, isTouch);
if (activePoint !== -1) {
isTouchInteraction = isTouch;
touchOffset = { x: pos.x - corners[activePoint].x, y: pos.y - corners[activePoint].y };
if (isTouch) {
touchStartPos = pos;
// Start dragging immediately but handle slop in handleMove
isDragging = true;
} else {
isDragging = true;
touchStartPos = null;
}
} else {
activePoint = null;
isDragging = false;
isTouchInteraction = false;
touchStartPos = null;
touchOffset = null;
}
}
function handleStart(pos) {
activePoint = null;
corners.forEach((p, i) => {
if (isInside(pos, p)) {
activePoint = i;
isDragging = true;
}
});
}
function handleMove(pos) {
if (activePoint !== null) {
// Touch slop detection
if (isTouchInteraction && touchStartPos) {
var dx = pos.x - touchStartPos.x;
var dy = pos.y - touchStartPos.y;
var distSq = dx * dx + dy * dy;
if (distSq < TOUCH_SLOP * TOUCH_SLOP) {
return; // Ignore small movements until slop exceeded
}
// Slop exceeded, clear touchStartPos so we don't check again
touchStartPos = null;
}
function handleMove(pos) {
if (activePoint !== null) {
// Constrain to canvas?? Optional but good
corners[activePoint].x = pos.x;
corners[activePoint].y = pos.y;
drawOverlay();
}
}
function handleEnd() {
isDragging = false;
activePoint = null;
}
// --- Rotate Functions ---
function rotateImage(degree) {
var offCanvas = document.createElement('canvas');
var offCtx = offCanvas.getContext('2d');
// Swap Width/Height for 90 degree rotation
offCanvas.width = originalImg.height;
offCanvas.height = originalImg.width;
offCtx.translate(offCanvas.width / 2, offCanvas.height / 2);
offCtx.rotate(degree * Math.PI / 180);
offCtx.drawImage(originalImg, -originalImg.width / 2, -originalImg.height / 2);
// Update originalImg
var rotatedUrl = offCanvas.toDataURL();
originalImg.onload = function() {
initScanner(); // Re-init with new image
}
originalImg.src = rotatedUrl;
}
$('#btnScanRotateLeft').click(function() { rotateImage(-90); });
$('#btnScanRotateRight').click(function() { rotateImage(90); });
// --- Reset Button ---
$('#btnScanReset').click(function() {
initScanner();
});
// --- Save / Extract Button ---
$('#btnScanSave').click(function() {
// Warp Image
try {
// 1. Get raw points relative to Original Image
var scaleX = originalImg.width / canvasImage.width;
var scaleY = originalImg.height / canvasImage.height;
// Apply offset to maintain relative position
if (touchOffset) {
corners[activePoint].x = pos.x - touchOffset.x;
corners[activePoint].y = pos.y - touchOffset.y;
} else {
corners[activePoint].x = pos.x;
corners[activePoint].y = pos.y;
}
var tl = { x: corners[0].x * scaleX, y: corners[0].y * scaleY };
var tr = { x: corners[1].x * scaleX, y: corners[1].y * scaleY };
var br = { x: corners[2].x * scaleX, y: corners[2].y * scaleY };
var bl = { x: corners[3].x * scaleX, y: corners[3].y * scaleY };
// Optional: constrain to canvas bounds
var w = canvasOverlay.width;
var h = canvasOverlay.height;
corners[activePoint].x = Math.max(0, Math.min(w, corners[activePoint].x));
corners[activePoint].y = Math.max(0, Math.min(h, corners[activePoint].y));
// 2. Calculate dimensions of the crop area
var widthTop = Math.hypot(tr.x - tl.x, tr.y - tl.y);
var widthBottom = Math.hypot(br.x - bl.x, br.y - bl.y);
var outputWidth = Math.max(widthTop, widthBottom);
drawOverlay();
}
}
var heightLeft = Math.hypot(bl.x - tl.x, bl.y - tl.y);
var heightRight = Math.hypot(br.x - tr.x, br.y - tr.y);
var outputHeight = Math.max(heightLeft, heightRight);
function handleEnd() {
isDragging = false;
activePoint = null;
isTouchInteraction = false;
touchStartPos = null;
touchOffset = null;
}
// --- Rotate Functions ---
function rotateImage(degree) {
var offCanvas = document.createElement('canvas');
var offCtx = offCanvas.getContext('2d');
// Swap Width/Height for 90 degree rotation
offCanvas.width = originalImg.height;
offCanvas.height = originalImg.width;
offCtx.translate(offCanvas.width / 2, offCanvas.height / 2);
offCtx.rotate(degree * Math.PI / 180);
offCtx.drawImage(originalImg, -originalImg.width / 2, -originalImg.height / 2);
// Update originalImg
var rotatedUrl = offCanvas.toDataURL();
originalImg.onload = function() {
// Re-init scanner for both modes
if (currentMode === 'smart') {
initScanner();
} else {
// Update cropper image
var cropImage = document.getElementById('crop-image');
cropImage.src = rotatedUrl;
// Reinitialize cropper
if (cropper) {
cropper.destroy();
}
initCropper();
}
}
originalImg.src = rotatedUrl;
}
$('#btnScanRotateLeft').click(function() { rotateImage(-90); });
$('#btnScanRotateRight').click(function() { rotateImage(90); });
// --- Reset Button ---
$('#btnScanReset').click(function() {
initScanner();
});
// --- Crop Reset Button ---
$('#btnCropReset').click(function() {
if (cropper) {
cropper.reset();
}
});
// --- Save / Extract Button ---
$('#btnScanSave').click(function() {
try {
var base64;
var extractPoints = {
topLeftCorner: tl,
topRightCorner: tr,
bottomRightCorner: br,
bottomLeftCorner: bl
};
if (currentMode === 'smart') {
// Smart Scan Mode - Use jscanify
// 1. Get raw points relative to Original Image
var scaleX = originalImg.width / canvasImage.width;
var scaleY = originalImg.height / canvasImage.height;
var tl = { x: corners[0].x * scaleX, y: corners[0].y * scaleY };
var tr = { x: corners[1].x * scaleX, y: corners[1].y * scaleY };
var br = { x: corners[2].x * scaleX, y: corners[2].y * scaleY };
var bl = { x: corners[3].x * scaleX, y: corners[3].y * scaleY };
// 2. Calculate dimensions of the crop area
var widthTop = Math.hypot(tr.x - tl.x, tr.y - tl.y);
var widthBottom = Math.hypot(br.x - bl.x, br.y - bl.y);
var outputWidth = Math.max(widthTop, widthBottom);
var heightLeft = Math.hypot(bl.x - tl.x, bl.y - tl.y);
var heightRight = Math.hypot(br.x - tr.x, br.y - tr.y);
var outputHeight = Math.max(heightLeft, heightRight);
var extractPoints = {
topLeftCorner: tl,
topRightCorner: tr,
bottomRightCorner: br,
bottomLeftCorner: bl
};
// 3. Extract with dynamic dimensions
var resultCanvas = null;
if (scanner && scanner.extractPaper) {
resultCanvas = scanner.extractPaper(originalImg, outputWidth, outputHeight, extractPoints);
} else {
alert("Scanner library not loaded. Please refresh the page.");
return;
}
base64 = resultCanvas.toDataURL('image/jpeg');
} else {
// Manual Crop Mode - Use cropper.js
if (!cropper) {
alert("Cropper not initialized. Please try again.");
return;
}
// Get cropped canvas
var canvas = cropper.getCroppedCanvas({
width: originalImg.width,
height: originalImg.height,
fillColor: '#fff',
imageSmoothingEnabled: true,
imageSmoothingQuality: 'high'
});
base64 = canvas.toDataURL('image/jpeg');
}
// 3. Extract with dynamic dimensions
var resultCanvas = scanner.extractPaper(originalImg, outputWidth, outputHeight, extractPoints);
var base64 = resultCanvas.toDataURL('image/jpeg');
if (window.handleScannerResult) {
window.handleScannerResult(base64);
@@ -808,25 +321,10 @@ window.addEventListener('load', function() {
scannerModal.modal('hide');
} catch (e) {
alert("Gagal memproses gambar: " + e.message);
console.error(e);
}
});
// Show mobile help if touch device
if (IS_TOUCH_DEVICE) {
$('#mobile-help').removeClass('d-none');
}
// Set initial mode based on device
setTimeout(function() {
var initialMode = IS_TOUCH_DEVICE ? 'manual' : 'smart';
var button = $('#scannerModeToggle button[data-mode="' + initialMode + '"]');
if (button.length) {
button.click();
}
}, 100);
});
} catch (e) {
alert("Gagal memproses gambar: " + e.message);
}
});
</script>
});
</script>

Some files were not shown because too many files have changed in this diff Show More