From 7ef7620d2a72ded413f86f007a58e2b73148d51d Mon Sep 17 00:00:00 2001 From: tistopandita Date: Thu, 11 Jun 2026 13:04:28 +0700 Subject: [PATCH] tambah fitur add tempat ibadah --- backend/routes/poverty.js | 131 ++++++++++++++++++++++ frontend/admin-poverty.html | 211 ++++++++++++++++++++++++++++++++++-- frontend/poverty-map.html | 92 +++++++++++++++- 3 files changed, 426 insertions(+), 8 deletions(-) diff --git a/backend/routes/poverty.js b/backend/routes/poverty.js index 5f2a214..a3d6a65 100644 --- a/backend/routes/poverty.js +++ b/backend/routes/poverty.js @@ -1,6 +1,59 @@ const express = require("express"); const db = require("../db"); +const TEMPAT_IBADAH_TYPES = ["Gereja Katolik", "GPIB", "GKI", "HKBP", "Pentakosta"]; + +const createTempatIbadah = ` + CREATE TABLE IF NOT EXISTS tempat_ibadah ( + id INT AUTO_INCREMENT PRIMARY KEY, + nama VARCHAR(150) NOT NULL, + jenis ENUM('Gereja Katolik','GPIB','GKI','HKBP','Pentakosta') NOT NULL, + alamat TEXT NOT NULL, + kelurahan VARCHAR(100) NOT NULL, + lat DOUBLE NOT NULL, + lng DOUBLE NOT NULL, + aktif TINYINT(1) NOT NULL DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +`; + +async function initTempatIbadahTable() { + await db.execute(createTempatIbadah); + const columns = await tableColumns("tempat_ibadah"); + if (!columns.includes("aktif")) { + await db.execute("ALTER TABLE tempat_ibadah ADD COLUMN aktif TINYINT(1) NOT NULL DEFAULT 1"); + } + if (!columns.includes("created_at")) { + await db.execute("ALTER TABLE tempat_ibadah ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP"); + } + await db.execute(` + UPDATE tempat_ibadah + SET jenis = 'Gereja Katolik' + WHERE jenis IS NULL + OR jenis = '' + OR jenis NOT IN ('Gereja Katolik','GPIB','GKI','HKBP','Pentakosta') + `); + await db.execute(` + ALTER TABLE tempat_ibadah + MODIFY jenis ENUM('Gereja Katolik','GPIB','GKI','HKBP','Pentakosta') NOT NULL + `); + await db.execute(` + UPDATE tempat_ibadah + SET jenis = 'Gereja Katolik' + WHERE jenis IS NULL + OR jenis = '' + OR jenis NOT IN ('Gereja Katolik','GPIB','GKI','HKBP','Pentakosta') + `); +} + +(async () => { + try { + await initTempatIbadahTable(); + } catch (e) { + console.error(e); + } +})(); + const router = express.Router(); let tablesReady = false; @@ -128,6 +181,8 @@ function buildFeature(item) { async function ensureTables() { if (tablesReady) return; + await initTempatIbadahTable(); + await db.execute(` CREATE TABLE IF NOT EXISTS users ( id_user INT AUTO_INCREMENT PRIMARY KEY, @@ -492,6 +547,22 @@ function validateFamily(body) { return null; } +function validateIbadah(body) { + const required = ["nama", "jenis", "alamat", "kelurahan", "lat", "lng"]; + for (const key of required) { + if (body[key] === undefined || body[key] === null || body[key] === "") { + return `${key} wajib diisi.`; + } + } + if (!TEMPAT_IBADAH_TYPES.includes(body.jenis)) { + return "Jenis tempat ibadah wajib valid."; + } + if (!Number.isFinite(Number(body.lat)) || !Number.isFinite(Number(body.lng))) { + return "Latitude dan longitude wajib valid."; + } + return null; +} + router.use(async (req, res, next) => { try { await ensureTables(); @@ -904,4 +975,64 @@ router.delete("/riwayat-bantuan/:id", async (req, res) => { res.json({ success: true, message: "Riwayat bantuan berhasil dihapus." }); }); +router.get("/ibadah", async (req, res) => { + try { + const [rows] = await db.execute("SELECT * FROM tempat_ibadah WHERE aktif = 1 ORDER BY nama ASC"); + res.json({ success: true, data: rows }); + } catch (error) { + res.status(500).json({ success: false, message: error.message }); + } +}); + +router.get("/ibadah/:id", async (req, res) => { + try { + const [rows] = await db.execute("SELECT * FROM tempat_ibadah WHERE id = ? AND aktif = 1", [req.params.id]); + if (!rows.length) return res.status(404).json({ success: false, message: "Tempat ibadah tidak ditemukan." }); + res.json({ success: true, data: rows[0] }); + } catch (error) { + res.status(500).json({ success: false, message: error.message }); + } +}); + +router.post("/ibadah", async (req, res) => { + const error = validateIbadah(req.body); + if (error) return res.status(400).json({ success: false, message: error }); + const body = req.body; + try { + const [result] = await db.execute( + "INSERT INTO tempat_ibadah (nama, jenis, alamat, kelurahan, lat, lng) VALUES (?, ?, ?, ?, ?, ?)", + [body.nama, body.jenis, body.alamat, body.kelurahan, Number(body.lat), Number(body.lng)], + ); + res.status(201).json({ success: true, id: result.insertId, message: "Tempat ibadah berhasil ditambahkan." }); + } catch (err) { + res.status(500).json({ success: false, message: err.message }); + } +}); + +router.put("/ibadah/:id", async (req, res) => { + const error = validateIbadah(req.body); + if (error) return res.status(400).json({ success: false, message: error }); + const body = req.body; + try { + const [result] = await db.execute( + "UPDATE tempat_ibadah SET nama=?, jenis=?, alamat=?, kelurahan=?, lat=?, lng=? WHERE id=? AND aktif = 1", + [body.nama, body.jenis, body.alamat, body.kelurahan, Number(body.lat), Number(body.lng), req.params.id], + ); + if (!result.affectedRows) return res.status(404).json({ success: false, message: "Tempat ibadah tidak ditemukan." }); + res.json({ success: true, message: "Tempat ibadah berhasil diperbarui." }); + } catch (err) { + res.status(500).json({ success: false, message: err.message }); + } +}); + +router.delete("/ibadah/:id", async (req, res) => { + try { + const [result] = await db.execute("UPDATE tempat_ibadah SET aktif = 0 WHERE id = ?", [req.params.id]); + if (!result.affectedRows) return res.status(404).json({ success: false, message: "Tempat ibadah tidak ditemukan." }); + res.json({ success: true, message: "Tempat ibadah berhasil dihapus." }); + } catch (error) { + res.status(500).json({ success: false, message: error.message }); + } +}); + module.exports = router; diff --git a/frontend/admin-poverty.html b/frontend/admin-poverty.html index 835cb34..aa6e85d 100644 --- a/frontend/admin-poverty.html +++ b/frontend/admin-poverty.html @@ -157,6 +157,25 @@ z-index: 2000; } .toast.show { opacity: 1; transform: translateY(0); } + .ibadah-map { height: 300px; position: relative; border-radius: var(--radius); overflow: hidden; border: 1px solid #dbe2ea; background: #eef2f7; } + .coord-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; } + .ibadah-badge-gereja-katolik { background: #ede9fe; color: #4c1d95; } + .ibadah-badge-gpib { background: #dbeafe; color: #1e3a8a; } + .ibadah-badge-gki { background: #cffafe; color: #164e63; } + .ibadah-badge-hkbp { background: #dcfce7; color: #14532d; } + .ibadah-badge-pentakosta { background: #ffedd5; color: #7c2d12; } + .ibadah-pin { + display: grid; + place-items: center; + width: 32px; + height: 32px; + border-radius: 999px; + background: #7c3aed; + color: #fff; + border: 3px solid #fff; + box-shadow: 0 10px 22px rgba(15, 23, 42, .25); + font-size: 16px; + } @media (max-width: 980px) { .shell { grid-template-columns: 1fr; } .sidebar { position: relative; height: auto; } @@ -183,6 +202,7 @@ + Buka Peta Poverty Admin SPBU @@ -312,6 +332,46 @@ +
+
+

Form Tempat Ibadah

+
+
+ +
+ + + + +
+ +
+
+ + +
+ + +
+
+
+ + +
+
+
+
+
+

Daftar Tempat Ibadah

0 data
+
+ + + +
#NamaJenisAlamatKelurahanKoordinatAksi
+
+
+
+

Preview Peta Keluarga Prioritas

Klik peta untuk mengisi koordinat form keluarga.
@@ -324,8 +384,11 @@ diff --git a/frontend/poverty-map.html b/frontend/poverty-map.html index 44a47a6..664fd03 100644 --- a/frontend/poverty-map.html +++ b/frontend/poverty-map.html @@ -170,6 +170,19 @@ z-index: 2000; } .toast.show { opacity: 1; transform: translateY(0); } + .ibadah-legend { display: none; } + .ibadah-legend.active { display: block; } + .ibadah-map-marker { + display: grid; + place-items: center; + width: 30px; + height: 30px; + border-radius: 999px; + color: white; + border: 3px solid white; + box-shadow: 0 10px 24px rgba(15, 23, 42, .28); + font-size: 15px; + } @media (max-width: 880px) { body { overflow: hidden; } .app { grid-template-columns: 1fr; } @@ -222,6 +235,7 @@ +
@@ -234,6 +248,17 @@
+
+

Legenda Tempat Ibadah

+
+ Gereja Katolik + GPIB + GKI + HKBP + Pentakosta +
+
+

Statistik Wilayah

@@ -262,11 +287,12 @@