From b8314b8ed66b044b1b057feac1f4dab0e216d2c8 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 11 Dec 2025 19:24:21 +0000 Subject: [PATCH] Mysqli 008 --- api_members.php | 102 +++++++++++++ assets/css/custom.css | 24 +++ assets/js/main.js | 198 +++++++++++++++++++++++++ db_setup.php | 30 ++++ index.php | 331 ++++++++++++++++++++++++------------------ 5 files changed, 543 insertions(+), 142 deletions(-) create mode 100644 api_members.php create mode 100644 assets/css/custom.css create mode 100644 assets/js/main.js create mode 100644 db_setup.php diff --git a/api_members.php b/api_members.php new file mode 100644 index 0000000..38973ef --- /dev/null +++ b/api_members.php @@ -0,0 +1,102 @@ + false, 'error' => '', 'members' => []]; + +// Get action from request, default to 'list' +$action = $_REQUEST['action'] ?? 'list'; + + +try { + $pdo = db(); + + switch ($action) { + case 'list': + $stmt = $pdo->query("SELECT id, name, nik, address, phone FROM members ORDER BY created_at DESC"); + $response['members'] = $stmt->fetchAll(PDO::FETCH_ASSOC); + $response['success'] = true; + break; + + case 'add': + // Simple validation + if (empty($_POST['name']) || empty($_POST['nik'])) { + throw new Exception('Nama dan NIK tidak boleh kosong.'); + } + + $sql = "INSERT INTO members (name, nik, address, phone) VALUES (:name, :nik, :address, :phone)"; + $stmt = $pdo->prepare($sql); + + $stmt->execute([ + ':name' => $_POST['name'], + ':nik' => $_POST['nik'], + ':address' => $_POST['address'] ?? '', + ':phone' => $_POST['phone'] ?? '' + ]); + + $response['success'] = true; + break; + + case 'get': + if (empty($_GET['id'])) { + throw new Exception('ID anggota tidak valid.'); + } + $stmt = $pdo->prepare("SELECT id, name, nik, address, phone FROM members WHERE id = :id"); + $stmt->execute([':id' => $_GET['id']]); + $member = $stmt->fetch(PDO::FETCH_ASSOC); + if (!$member) { + throw new Exception('Anggota tidak ditemukan.'); + } + $response['member'] = $member; + $response['success'] = true; + break; + + case 'update': + if (empty($_POST['id']) || empty($_POST['name']) || empty($_POST['nik'])) { + throw new Exception('ID, Nama, dan NIK tidak boleh kosong.'); + } + + $sql = "UPDATE members SET name = :name, nik = :nik, address = :address, phone = :phone WHERE id = :id"; + $stmt = $pdo->prepare($sql); + + $stmt->execute([ + ':id' => $_POST['id'], + ':name' => $_POST['name'], + ':nik' => $_POST['nik'], + ':address' => $_POST['address'] ?? '', + ':phone' => $_POST['phone'] ?? '' + ]); + + $response['success'] = true; + break; + + case 'delete': + if (empty($_POST['id'])) { + throw new Exception('ID anggota tidak valid.'); + } + + $sql = "DELETE FROM members WHERE id = :id"; + $stmt = $pdo->prepare($sql); + $stmt->execute([':id' => $_POST['id']]); + + $response['success'] = true; + break; + + default: + throw new Exception('Aksi tidak valid.'); + } + +} catch (PDOException $e) { + $response['error'] = 'Database error: ' . $e->getMessage(); + // Check for duplicate entry + if ($e->getCode() == 23000) { + $response['error'] = 'NIK sudah terdaftar.'; + } +} catch (Exception $e) { + $response['error'] = $e->getMessage(); +} + +echo json_encode($response); diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..5511f00 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,24 @@ + +body { + background-color: #f8f9fa; +} + +.card { + border: none; + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); +} + +.modal-header { + border-bottom: none; +} + +.modal-footer { + border-top: none; +} + +.toast { + position: fixed; + top: 20px; + right: 20px; + z-index: 1055; +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..733df19 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,198 @@ +document.addEventListener('DOMContentLoaded', function () { + const addMemberModal = new bootstrap.Modal(document.getElementById('addMemberModal')); + const editMemberModal = new bootstrap.Modal(document.getElementById('editMemberModal')); + const addMemberForm = document.getElementById('addMemberForm'); + const editMemberForm = document.getElementById('editMemberForm'); + const memberTableBody = document.getElementById('memberTableBody'); + + // Function to show a toast notification + function showToast(message, success = true) { + const toastContainer = document.getElementById('toastContainer'); + const toast = document.createElement('div'); + toast.className = `toast align-items-center text-white ${success ? 'bg-success' : 'bg-danger'} border-0 show`; + toast.role = 'alert'; + toast.ariaLive = 'assertive'; + toast.ariaAtomic = 'true'; + + toast.innerHTML = ` +
+
${message}
+ +
+ `; + toastContainer.appendChild(toast); + + const bsToast = new bootstrap.Toast(toast); + bsToast.show(); + + setTimeout(() => { + bsToast.hide(); + setTimeout(() => { + toast.remove(); + }, 500); + }, 3000); + } + + function loadMembers() { + fetch('api_members.php?action=list') + .then(response => response.json()) + .then(data => { + memberTableBody.innerHTML = ''; + if (data.success) { + if (data.members.length === 0) { + memberTableBody.innerHTML = 'Belum ada anggota.'; + } else { + data.members.forEach(member => { + const row = ` + ${member.id} + ${escapeHTML(member.name)} + ${escapeHTML(member.nik)} + ${escapeHTML(member.address)} + ${escapeHTML(member.phone)} + + + + + `; + memberTableBody.innerHTML += row; + }); + } + // Update total members card + document.getElementById('totalMembers').innerText = data.members.length; + } else { + memberTableBody.innerHTML = `Gagal memuat data: ${data.error}`; + } + }) + .catch(error => { + memberTableBody.innerHTML = `Error: ${error}`; + }); + } + + // Helper to prevent XSS + function escapeHTML(str) { + return str.toString().replace(/[&<>"']/g, function (tag) { + var chars = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + return chars[tag] || tag; + }); + } + + // Handle Add Member form submission + addMemberForm.addEventListener('submit', function (event) { + event.preventDefault(); + + const formData = new FormData(addMemberForm); + formData.append('action', 'add'); + + fetch('api_members.php', { + method: 'POST', + body: formData + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showToast('Anggota berhasil ditambahkan!'); + addMemberModal.hide(); + addMemberForm.reset(); + loadMembers(); + } else { + showToast('Gagal menambahkan anggota: ' + data.error, false); + } + }) + .catch(error => { + showToast('Terjadi kesalahan. Silakan coba lagi.', false); + }); + }); + +''' // Delegated event listener for edit and delete buttons + memberTableBody.addEventListener('click', function (event) { + const editButton = event.target.closest('.btn-edit'); + const deleteButton = event.target.closest('.btn-delete'); + + if (editButton) { + const memberId = editButton.dataset.id; + openEditModal(memberId); + } else if (deleteButton) { + const memberId = deleteButton.dataset.id; + deleteMember(memberId); + } + }); + + // Function to open and populate the edit modal + function openEditModal(memberId) { + fetch(`api_members.php?action=get&id=${memberId}`) + .then(response => response.json()) + .then(data => { + if (data.success) { + const member = data.member; + document.getElementById('editMemberId').value = member.id; + document.getElementById('editName').value = member.name; + document.getElementById('editNik').value = member.nik; + document.getElementById('editAddress').value = member.address; + document.getElementById('editPhone').value = member.phone; + editMemberModal.show(); + } else { + showToast('Gagal mengambil data anggota: ' + data.error, false); + } + }) + .catch(() => showToast('Terjadi kesalahan jaringan.', false)); + } + + // Handle Edit Member form submission + editMemberForm.addEventListener('submit', function (event) { + event.preventDefault(); + + const formData = new FormData(editMemberForm); + formData.append('action', 'update'); + + fetch('api_members.php', { + method: 'POST', + body: new URLSearchParams(formData) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showToast('Data anggota berhasil diperbarui!'); + editMemberModal.hide(); + loadMembers(); + } else { + showToast('Gagal memperbarui data: ' + data.error, false); + } + }) + .catch(() => { + showToast('Terjadi kesalahan. Silakan coba lagi.', false); + }); + }); + + // Function to delete a member + function deleteMember(memberId) { + if (confirm('Apakah Anda yakin ingin menghapus anggota ini?')) { + const formData = new FormData(); + formData.append('action', 'delete'); + formData.append('id', memberId); + + fetch('api_members.php', { + method: 'POST', + body: new URLSearchParams(formData) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showToast('Anggota berhasil dihapus.'); + loadMembers(); + } else { + showToast('Gagal menghapus anggota: ' + data.error, false); + } + }) + .catch(() => showToast('Terjadi kesalahan jaringan.', false)); + } + } + + // Initial load + loadMembers(); +});'' diff --git a/db_setup.php b/db_setup.php new file mode 100644 index 0000000..c0b4d9c --- /dev/null +++ b/db_setup.php @@ -0,0 +1,30 @@ +exec($sql); + + // You can add more table creations here in the future + + } catch (PDOException $e) { + // In a real app, you'd want to log this error + // For this example, we'll just output it. + die("DB setup failed: " . $e->getMessage()); + } +} + +// Run the setup +setup_database(); diff --git a/index.php b/index.php index 7205f3d..b454588 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,197 @@ - - + + - - - New Style - - - - - - - - - - - - - - - - - - - + + + <?php echo $projectName; ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ + + +
+

Dashboard

+ + +
+
+
+
+
Total Anggota
+

0

+
+
+
+
+
+
+
Total Simpanan
+

Rp 0

+
+
+
+
+
+
+
Total Pinjaman
+

Rp 0

+
+
+
+
+ + +
+
+

Daftar Anggota

+ +
+
+
+ + + + + + + + + + + + + + + +
IDNamaNIKAlamatTeleponAksi
Memuat data...
+
+
+
+
+ + +
+ + + -
- + + + + + + + + + - + \ No newline at end of file