diff --git a/README.md b/README.md new file mode 100644 index 0000000..15bfb91 --- /dev/null +++ b/README.md @@ -0,0 +1,116 @@ +# GIS Portal & Sinergi Umat Dashboard + +Proyek ini adalah portal Sistem Informasi Geografis (GIS) terintegrasi yang menggabungkan visualisasi peta spasial Pontianak dengan sistem dasbor manajemen kesejahteraan masyarakat (Sinergi Umat). + +--- + +## 🏛️ Komponen Proyek + +1. **Portal Utama GIS (PHP + Apache)**: + - Visualisasi Lokasi SPBU (`spbu-map`) + - Visualisasi Parsil Tanah (`parsil-tanah`) + - Peta Kloroplet (`chloropleth`) +2. **Dasbor Sinergi Umat (`sistem-km-next`)**: + - Aplikasi berbasis Next.js untuk pemetaan rumah ibadah (Mosque, Church, Vihara, Temple) dan survei kesejahteraan Keluarga Penerima Manfaat (KPM). +3. **Database MySQL**: + - Penyimpanan data SPBU, parsil, dan kloroplet. +4. **Supabase**: + - Backend auth dan database real-time untuk data rumah ibadah, data keluarga (households), transaksi donasi, dan approval queue di Sinergi Umat. + +--- + +## 🐳 Opsi 1: Menjalankan Menggunakan Docker (Direkomendasikan) + +Dengan Docker Compose, seluruh aplikasi portal PHP, dasbor Next.js, MySQL database, dan phpMyAdmin akan dijalankan otomatis dalam kontainer yang saling terhubung. + +### Prasyarat +- Sudah menginstal **Docker Desktop** di komputer Anda. + +### Langkah-langkah +1. Buka terminal/command prompt pada **direktori root** proyek (`gis-portal` / folder tempat `docker-compose.yaml` berada). +2. Jalankan perintah berikut untuk mengunduh, membuat build image, dan menjalankan kontainer secara background: + ```bash + docker compose up -d --build + ``` +3. Setelah proses build selesai dan container berjalan (`healthy`), Anda dapat mengakses layanan berikut di browser Anda: + - **Portal Utama GIS (PHP, SPBU, Parsil, Kloroplet)**: [http://localhost:8080](http://localhost:8080) + - **Dasbor Sinergi Umat (Next.js)**: [http://localhost:3000](http://localhost:3000) + - **phpMyAdmin (Manajemen Database MySQL)**: [http://localhost:8085](http://localhost:8085) + - **MySQL Database**: Berjalan di port `3306` (host: `localhost`, user: `root`, password: `rootpassword`, database: `spbu_db`). + +### Catatan Penting Docker: +- Data MySQL disimpan secara persisten di volume docker `db-data`. +- Skema awal database otomatis di-import saat database pertama kali di-boot dari berkas `./docker/db/init.sql`. + +--- + +## 🔧 Opsi 2: Menjalankan Tanpa Docker (Manual) + +Jika ingin menjalankan aplikasi secara langsung di sistem lokal Anda tanpa menggunakan kontainer Docker. + +### Prasyarat +- **Web Server Lokal** (seperti Laragon atau XAMPP) yang mendukung PHP (min v8.1) dan MySQL. +- **Node.js** (min v18 atau v20) terinstal pada komputer Anda. + +### Langkah-langkah Setup Manual: + +#### 1. Setup Database MySQL Lokal +1. Pastikan server MySQL lokal Anda (Laragon/XAMPP) sudah menyala. +2. Buat database baru bernama `spbu_db` melalui phpMyAdmin lokal Anda. +3. Import berkas SQL skema awal yang terletak di `docker/db/init.sql` ke dalam database `spbu_db` tersebut. + +#### 2. Jalankan Portal GIS Utama (PHP App) +1. Pindahkan atau hubungkan (symlink) seluruh folder proyek `gis-portal` ke direktori root web server Anda: + - Untuk **Laragon**: taruh di `C:\laragon\www\gis-portal` + - Untuk **XAMPP**: taruh di `C:\xampp\htdocs\gis-portal` +2. Konfigurasi koneksi database PHP berada di berkas: + - `spbu-map/db.php` + - `parsil-tanah/db.php` + *(Secara default, skrip PHP akan otomatis terhubung ke localhost dengan database `spbu_db`, user `root`, dan password kosong `""`)*. +3. Akses portal utama melalui browser Anda di: + - Laragon: [http://gis-portal.test](http://gis-portal.test) + - XAMPP: [http://localhost/gis-portal](http://localhost/gis-portal) + +#### 3. Jalankan Dasbor Sinergi Umat (Next.js App) +1. Buka terminal Anda dan masuk ke direktori Next.js: + ```bash + cd sistem-km-next + ``` +2. Instal pustaka ketergantungan (dependencies) dengan perintah: + ```bash + npm install + ``` +3. Pastikan berkas `.env.local` sudah ada di dalam folder `sistem-km-next` dan berisi kredensial Supabase berikut (sudah otomatis disertakan dalam berkas zip): + ```env + NEXT_PUBLIC_SUPABASE_URL=https://gzpvygrsfdtzykyqbnes.supabase.co + NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... + SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... + ``` +4. Jalankan server pengembangan Next.js lokal: + ```bash + npm run dev + ``` +5. Buka browser Anda dan akses dasbor Sinergi Umat di [http://localhost:3000](http://localhost:3000). + +--- + +## 💾 Struktur Folder Proyek + +```text +gis-portal/ +├── README.md # Dokumentasi utama (berkas ini) +├── chloropleth/ # Fitur peta kloroplet Pontianak (PHP/HTML/JS) +├── docker/ # Konfigurasi Dockerfile untuk php, nextjs, & db +│ ├── db/ +│ │ └── init.sql # Database schema SQL init +│ ├── nextjs/ +│ └── php/ +├── parsil-tanah/ # Fitur peta parsil tanah (PHP/HTML/JS) +├── sistem-km-next/ # Dasbor Sinergi Umat (Next.js App) +│ ├── src/ +│ └── README.md # Dokumentasi subsistem Next.js +├── spbu-map/ # Fitur peta sebaran SPBU (PHP/HTML/JS) +├── docker-compose.yaml # Main configuration file Docker +├── docker-compose.override.yaml # Local override config (Port mapping & bind mounts) +└── index.html # Halaman Beranda / Gateway Portal GIS +``` diff --git a/sistem-km-next/README.md b/sistem-km-next/README.md index 09a8a4d..bf0dd27 100644 --- a/sistem-km-next/README.md +++ b/sistem-km-next/README.md @@ -1,36 +1,116 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# GIS Portal & Sinergi Umat Dashboard -## Getting Started +Proyek ini adalah portal Sistem Informasi Geografis (GIS) terintegrasi yang menggabungkan visualisasi peta spasial Pontianak dengan sistem dasbor manajemen kesejahteraan masyarakat (Sinergi Umat). -First, run the development server: +--- -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +## 🏛️ Komponen Proyek + +1. **Portal Utama GIS (PHP + Apache)**: + - Visualisasi Lokasi SPBU (`spbu-map`) + - Visualisasi Parsil Tanah (`parsil-tanah`) + - Peta Kloroplet (`chloropleth`) +2. **Dasbor Sinergi Umat (`sistem-km-next`)**: + - Aplikasi berbasis Next.js untuk pemetaan rumah ibadah (Mosque, Church, Vihara, Temple) dan survei kesejahteraan Keluarga Penerima Manfaat (KPM). +3. **Database MySQL**: + - Penyimpanan data SPBU, parsil, dan kloroplet. +4. **Supabase**: + - Backend auth dan database real-time untuk data rumah ibadah, data keluarga (households), transaksi donasi, dan approval queue di Sinergi Umat. + +--- + +## 🐳 Opsi 1: Menjalankan Menggunakan Docker (Direkomendasikan) + +Dengan Docker Compose, seluruh aplikasi portal PHP, dasbor Next.js, MySQL database, dan phpMyAdmin akan dijalankan otomatis dalam kontainer yang saling terhubung. + +### Prasyarat +- Sudah menginstal **Docker Desktop** di komputer Anda. + +### Langkah-langkah +1. Buka terminal/command prompt pada **direktori root** proyek (`gis-portal` / folder tempat `docker-compose.yaml` berada). +2. Jalankan perintah berikut untuk mengunduh, membuat build image, dan menjalankan kontainer secara background: + ```bash + docker compose up -d --build + ``` +3. Setelah proses build selesai dan container berjalan (`healthy`), Anda dapat mengakses layanan berikut di browser Anda: + - **Portal Utama GIS (PHP, SPBU, Parsil, Kloroplet)**: [http://localhost:8080](http://localhost:8080) + - **Dasbor Sinergi Umat (Next.js)**: [http://localhost:3000](http://localhost:3000) + - **phpMyAdmin (Manajemen Database MySQL)**: [http://localhost:8085](http://localhost:8085) + - **MySQL Database**: Berjalan di port `3306` (host: `localhost`, user: `root`, password: `rootpassword`, database: `spbu_db`). + +### Catatan Penting Docker: +- Data MySQL disimpan secara persisten di volume docker `db-data`. +- Skema awal database otomatis di-import saat database pertama kali di-boot dari berkas `./docker/db/init.sql`. + +--- + +## 🔧 Opsi 2: Menjalankan Tanpa Docker (Manual) + +Jika ingin menjalankan aplikasi secara langsung di sistem lokal Anda tanpa menggunakan kontainer Docker. + +### Prasyarat +- **Web Server Lokal** (seperti Laragon atau XAMPP) yang mendukung PHP (min v8.1) dan MySQL. +- **Node.js** (min v18 atau v20) terinstal pada komputer Anda. + +### Langkah-langkah Setup Manual: + +#### 1. Setup Database MySQL Lokal +1. Pastikan server MySQL lokal Anda (Laragon/XAMPP) sudah menyala. +2. Buat database baru bernama `spbu_db` melalui phpMyAdmin lokal Anda. +3. Import berkas SQL skema awal yang terletak di `docker/db/init.sql` ke dalam database `spbu_db` tersebut. + +#### 2. Jalankan Portal GIS Utama (PHP App) +1. Pindahkan atau hubungkan (symlink) seluruh folder proyek `gis-portal` ke direktori root web server Anda: + - Untuk **Laragon**: taruh di `C:\laragon\www\gis-portal` + - Untuk **XAMPP**: taruh di `C:\xampp\htdocs\gis-portal` +2. Konfigurasi koneksi database PHP berada di berkas: + - `spbu-map/db.php` + - `parsil-tanah/db.php` + *(Secara default, skrip PHP akan otomatis terhubung ke localhost dengan database `spbu_db`, user `root`, dan password kosong `""`)*. +3. Akses portal utama melalui browser Anda di: + - Laragon: [http://gis-portal.test](http://gis-portal.test) + - XAMPP: [http://localhost/gis-portal](http://localhost/gis-portal) + +#### 3. Jalankan Dasbor Sinergi Umat (Next.js App) +1. Buka terminal Anda dan masuk ke direktori Next.js: + ```bash + cd sistem-km-next + ``` +2. Instal pustaka ketergantungan (dependencies) dengan perintah: + ```bash + npm install + ``` +3. Pastikan berkas `.env.local` sudah ada di dalam folder `sistem-km-next` dan berisi kredensial Supabase berikut (sudah otomatis disertakan dalam berkas zip): + ```env + NEXT_PUBLIC_SUPABASE_URL=https://gzpvygrsfdtzykyqbnes.supabase.co + NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... + SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... + ``` +4. Jalankan server pengembangan Next.js lokal: + ```bash + npm run dev + ``` +5. Buka browser Anda dan akses dasbor Sinergi Umat di [http://localhost:3000](http://localhost:3000). + +--- + +## 💾 Struktur Folder Proyek + +```text +gis-portal/ +├── chloropleth/ # Fitur peta kloroplet Pontianak (PHP/HTML/JS) +├── docker/ # Konfigurasi Dockerfile untuk php, nextjs, & db +│ ├── db/ +│ │ └── init.sql # Database schema SQL init +│ ├── nextjs/ +│ └── php/ +├── parsil-tanah/ # Fitur peta parsil tanah (PHP/HTML/JS) +├── sistem-km-next/ # Dasbor Sinergi Umat (Next.js App) +│ ├── src/ +│ └── README.md # Dokumentasi ini +├── spbu-map/ # Fitur peta sebaran SPBU (PHP/HTML/JS) +├── docker-compose.yaml # Main configuration file Docker +├── docker-compose.override.yaml # Local override config (Port mapping & bind mounts) +├── index.html # Halaman Beranda / Gateway Portal GIS +└── README.md -> sistem-km-next/README.md ``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/sistem-km-next/src/app/change-password/page.js b/sistem-km-next/src/app/change-password/page.js index 0c6b3ef..a21b965 100644 --- a/sistem-km-next/src/app/change-password/page.js +++ b/sistem-km-next/src/app/change-password/page.js @@ -1,29 +1,105 @@ 'use client'; -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { supabase } from '@/lib/supabase'; import { useRouter } from 'next/navigation'; +import 'leaflet/dist/leaflet.css'; export default function ChangePassword() { const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [user, setUser] = useState(null); + const [profile, setProfile] = useState(null); const [showPassword, setShowPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = useState(false); const router = useRouter(); + const mapRef = useRef(null); + const mapInstanceRef = useRef(null); useEffect(() => { supabase.auth.getUser().then(({ data }) => { - if (!data?.user) router.push('/login'); - else setUser(data.user); + if (!data?.user) { + router.push('/login'); + } else { + setUser(data.user); + supabase + .from('profiles') + .select('*') + .eq('id', data.user.id) + .single() + .then(({ data: profileData }) => { + setProfile(profileData); + }); + } }); }, [router]); + useEffect(() => { + let active = true; + + // Dynamically load Leaflet for the background map + import('leaflet').then((L) => { + if (!active) return; + + if (!mapInstanceRef.current && mapRef.current) { + // Initialize map centered on Pontianak + const map = L.map(mapRef.current, { + center: [-0.0227, 109.3340], + zoom: 13, + zoomControl: false, + dragging: false, + scrollWheelZoom: false, + doubleClickZoom: false, + boxZoom: false, + keyboard: false, + attributionControl: false + }); + + // Use CartoDB Positron for a clean, light background + L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { + maxZoom: 19, + subdomains: 'abcd' + }).addTo(map); + + mapInstanceRef.current = map; + + // Force resize recalculation to ensure tiles render immediately + setTimeout(() => { + if (active && mapInstanceRef.current) { + mapInstanceRef.current.invalidateSize(); + } + }, 150); + } + }); + + return () => { + active = false; + if (mapInstanceRef.current) { + mapInstanceRef.current.remove(); + mapInstanceRef.current = null; + } + }; + }, []); + const handleUpdate = async (e) => { e.preventDefault(); setLoading(true); setError(null); + if (password !== confirmPassword) { + setError('Konfirmasi kata sandi baru tidak cocok.'); + setLoading(false); + return; + } + + if (password.length < 6) { + setError('Kata sandi baru minimal harus 6 karakter.'); + setLoading(false); + return; + } + const { error: authError } = await supabase.auth.updateUser({ password }); if (authError) { @@ -48,50 +124,131 @@ export default function ChangePassword() { return (
+ {/* Return to Dashboard Button */} + + + {/* Dynamic Leaflet Background */} +
+ + {/* Glassmorphism Dark/Blur Overlay */}
+ + {/* Change Password Card */} +
-

Rotasi Keamanan

-

- Untuk alasan keamanan, Anda wajib mengubah kata sandi default sebelum melanjutkan. +

+ +
+

Ubah Kata Sandi

+

+ {profile?.password_changed === false + ? 'Anda wajib mengubah kata sandi bawaan demi keamanan akun.' + : 'Ubah kata sandi Anda untuk meningkatkan keamanan akun.'}

{error && ( -
- {error} +
+ {error}
)}
- +
setPassword(e.target.value)} - minLength={6} style={{ width: '100%', padding: '12px 44px 12px 16px', borderRadius: '12px', border: '1px solid #cbd5e1', background: 'white', - outline: 'none', transition: 'border-color 0.2s', color: 'black', + outline: 'none', transition: 'all 0.2s', color: '#1e293b', boxShadow: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.05)' }} + onFocus={(e) => e.target.style.borderColor = 'var(--primary, #3b82f6)'} + onBlur={(e) => e.target.style.borderColor = '#cbd5e1'} required + minLength={6} />
+ +
+ +
+ setConfirmPassword(e.target.value)} + style={{ + width: '100%', padding: '12px 44px 12px 16px', borderRadius: '12px', + border: '1px solid #cbd5e1', background: 'white', + outline: 'none', transition: 'all 0.2s', color: '#1e293b', + boxShadow: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.05)' + }} + onFocus={(e) => e.target.style.borderColor = 'var(--primary, #3b82f6)'} + onBlur={(e) => e.target.style.borderColor = '#cbd5e1'} + required + minLength={6} + /> + +
+
+
diff --git a/sistem-km-next/src/components/dashboard/modals/ProfileModal.js b/sistem-km-next/src/components/dashboard/modals/ProfileModal.js index 3856e0f..676eef7 100644 --- a/sistem-km-next/src/components/dashboard/modals/ProfileModal.js +++ b/sistem-km-next/src/components/dashboard/modals/ProfileModal.js @@ -1,4 +1,5 @@ import React from 'react'; +import { useRouter } from 'next/navigation'; export default function ProfileModal({ showProfileModal, @@ -8,6 +9,7 @@ export default function ProfileModal({ handleLogout, isLoggingOut }) { + const router = useRouter(); if (!showProfileModal) return null; const getRoleBadge = (role) => { @@ -138,6 +140,33 @@ export default function ProfileModal({ > {isLoggingOut ? 'Keluar...' : 'Keluar dari Akun (Logout)'} +