diff --git a/CLAUDE.md b/CLAUDE.md index 7561ba9b..60c45a43 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,6 +30,7 @@ bun eslint . --fix - Architecture, request flow, domain modules, key files: @.claude/ARCHITECTURE.md - Database conventions, auth flow, file handling: @.claude/DATABASE.md - Env vars, Docker, CI/CD, releasing: @.claude/DEPLOYMENT.md +- UI/UX design system, tokens, komponen, pola halaman: @.claude/DESIGN.md - AI collaboration contract, rules, and guidelines: @AI-CONTRACT.md ### Workflow for Code Changes diff --git a/MIND/SUMMARY/posyandu-banjar-publik-fix-tips-keamanan-summary.md b/MIND/SUMMARY/posyandu-banjar-publik-fix-tips-keamanan-summary.md new file mode 100644 index 00000000..755bc186 --- /dev/null +++ b/MIND/SUMMARY/posyandu-banjar-publik-fix-tips-keamanan-summary.md @@ -0,0 +1,98 @@ +# Summary: Posyandu Banjar + Halaman Publik + Fix Tips Keamanan + +**Tanggal:** 2026-05-28 +**Branch:** tasks/kesehatan/posyandu-banjar-publik-fix-tips-keamanan/20260528 + +--- + +## Apa yang Berubah + +### 1. Fitur Banjar pada Posyandu + +**Problem:** Posyandu tidak memiliki relasi ke wilayah banjar, sehingga tidak bisa dikelompokkan per banjar. + +**Perubahan:** +- `prisma/schema.prisma` — Tambah model `Banjar` baru dan field `banjarId` (optional FK) pada model `Posyandu` +- `prisma/migrations/20260528100000_add_banjar_to_posyandu/migration.sql` — Migration: CREATE TABLE `Banjar`, ALTER TABLE `Posyandu` ADD COLUMN `banjarId` +- `prisma/_seeder_list/kesehatan/seed_banjar.ts` — Seeder baru untuk data banjar +- `prisma/data/kesehatan/banjar/banjar.json` — Data seed 16 banjar Desa Darmasaba +- `prisma/seed.ts` — Tambah `seedBanjar()` sebelum `seedTipsKeamanan()` + +**API changes:** +- `src/app/api/[[...slugs]]/_lib/kesehatan/posyandu/create.ts` — Terima `banjarId` optional saat create +- `src/app/api/[[...slugs]]/_lib/kesehatan/posyandu/updt.ts` — Terima `banjarId` optional saat update +- `src/app/api/[[...slugs]]/_lib/kesehatan/posyandu/find-by-id.ts` — Include relasi `banjar` +- `src/app/api/[[...slugs]]/_lib/kesehatan/posyandu/find-many.ts` — Include relasi `banjar` +- `src/app/api/[[...slugs]]/_lib/kesehatan/posyandu/index.ts` — Tambah endpoint banjar +- `src/app/api/[[...slugs]]/_lib/kesehatan/index.ts` — Daftarkan endpoint banjar baru +- `src/app/api/[[...slugs]]/_lib/kesehatan/banjar/` — Module API baru untuk list banjar +- `src/app/api/[[...slugs]]/_lib/kesehatan/balita/find-many.ts` — Support filter per posyandu +- `src/app/api/[[...slugs]]/_lib/kesehatan/ibu-hamil/find-many.ts` — Support filter per posyandu + +**Admin CMS changes:** +- `src/app/admin/(dashboard)/kesehatan/posyandu/list-posyandu/page.tsx` — Tampilkan info banjar di tabel +- `src/app/admin/(dashboard)/kesehatan/posyandu/list-posyandu/create/page.tsx` — Tambah Select banjar +- `src/app/admin/(dashboard)/kesehatan/posyandu/list-posyandu/[id]/edit/page.tsx` — Tambah Select banjar +- `src/app/admin/(dashboard)/kesehatan/posyandu/list-posyandu/[id]/page.tsx` — Tampilkan nama banjar di detail +- `src/app/admin/(dashboard)/_state/kesehatan/posyandu/posyandu.ts` — Include `banjar` di state + +--- + +### 2. Redesign Halaman Publik Posyandu + +**Problem:** Halaman publik `/darmasaba/kesehatan/posyandu` hanya menampilkan daftar posyandu saja, belum menampilkan data balita, ibu hamil, dan ringkasan statistik. + +**Perubahan:** +- `src/app/darmasaba/(pages)/kesehatan/posyandu/page.tsx` — Redesign total dengan sistem Tab: + - **Tab Ringkasan** — Statistik kesehatan (total posyandu, balita, ibu hamil, angka stunting) + - **Tab Data Posyandu** — List posyandu dengan filter search dan info banjar + - **Tab Data Balita** — Tabel data balita dengan filter search + filter status stunting + - **Tab Ibu Hamil** — Tabel data ibu hamil dengan filter search + filter status +- `src/app/darmasaba/(pages)/kesehatan/posyandu/[id]/page.tsx` — Halaman detail posyandu dengan tampilan tab balita & ibu hamil per posyandu +- `src/app/admin/(dashboard)/_state/kesehatan/balita/balita.ts` — Tambah state `findMany` untuk halaman publik +- `src/app/admin/(dashboard)/_state/kesehatan/ibu-hamil/ibuHamil.ts` — Tambah state `findMany` untuk halaman publik +- `src/app/admin/(dashboard)/_state/kesehatan/ringkasan-kesehatan/ringkasanKesehatan.ts` — Refactor state ringkasan +- `src/app/admin/(dashboard)/kesehatan/posyandu/balita/page.tsx` — Update admin balita page +- `src/app/admin/(dashboard)/kesehatan/posyandu/ibu-hamil/page.tsx` — Update admin ibu hamil page +- `src/app/admin/(dashboard)/kesehatan/posyandu/ringkasan-kesehatan/page.tsx` — Update admin ringkasan +- `src/app/api/[[...slugs]]/_lib/kesehatan/ringkasan-kesehatan/stats.ts` — Perbaiki kalkulasi statistik +- `src/app/api/[[...slugs]]/_lib/kesehatan/ringkasan-kesehatan/index.ts` — Update endpoint + +--- + +### 3. Fix Image Tips Keamanan (Ketuker) + +**Problem:** Gambar pada data Tips Keamanan tertukar antara "Keamanan Rumah" dan "Keamanan Lingkungan Tanggungjawab Bersama". + +**Root cause:** Nilai `imageName` di `tips-keamanan.json` salah assign — nama file gambar di-swap antara 2 record. + +**Perubahan:** +- `prisma/data/keamanan/tips-keamanan/tips-keamanan.json` — Tukar nilai `imageName`: + - "Keamanan Rumah" → `vwZsaxcoFWDlxG1PW7FC0-mobile.webp` (sebelumnya `dSe0xyvNLkP2t2f6iq-Hk-mobile.webp`) + - "Keamanan Lingkungan..." → `dSe0xyvNLkP2t2f6iq-Hk-mobile.webp` (sebelumnya `vwZsaxcoFWDlxG1PW7FC0-mobile.webp`) + +**Catatan:** `imageId` akan null di lokal karena MinIO lokal tidak punya file tersebut. Di STG, MinIO sudah punya kedua file — seed akan resolve dengan benar setelah deploy. + +--- + +### 4. Cleanup Seed Core + +- `prisma/_seeder_list/core/seed_app_menu.ts` — Dihapus (sudah tidak dipakai) +- `prisma/_seeder_list/core/seed_core.ts` — Dihapus (sudah tidak dipakai) +- `prisma/seed.ts` — Hapus import + call ke seed core, tambah `seedBanjar` dan `seedTipsKeamanan` + +--- + +### 5. Update Seed PPID & Data + +- `prisma/data/ppid/struktur-organisasi-ppid/struktur-organisasi-ppid.json` — Update data struktur organisasi PPID +- `prisma/_seeder_list/kesehatan/posyandu/seed_posyandu.ts` — Update seeder posyandu untuk include `banjarId` +- `prisma/data/kesehatan/posyandu/posyandu.json` — Update data seed posyandu dengan `banjarId` + +--- + +## Catatan Penting + +- **Migration wajib dijalankan** saat deploy: `prisma migrate deploy` sudah otomatis via `docker-entrypoint.sh` +- **Seed harus dijalankan ulang** di STG setelah deploy agar data banjar terisi dan imageId tips keamanan terkoreksi +- Gambar tips keamanan akan tetap null di lokal (MinIO lokal tidak punya file), tapi akan resolve di STG diff --git a/prisma/_seeder_list/core/seed_app_menu.ts b/prisma/_seeder_list/core/seed_app_menu.ts deleted file mode 100644 index 98a57e1e..00000000 --- a/prisma/_seeder_list/core/seed_app_menu.ts +++ /dev/null @@ -1,57 +0,0 @@ -import prisma from "@/lib/prisma"; -import { loadJsonData } from "../../load-json"; - -const appMenuJson = loadJsonData("core/app-menu.json"); -const appMenuChildJson = loadJsonData("core/app-menu-child.json"); - -export async function seedAppMenu() { - console.log("🔄 Seeding AppMenu..."); - - for (const item of appMenuJson) { - await prisma.appMenu.upsert({ - where: { id: item.id }, - update: { - name: item.name, - link: item.link, - isActive: item.isActive, - }, - create: { - id: item.id, - name: item.name, - link: item.link, - isActive: item.isActive, - }, - }); - - console.log(`✅ AppMenu seeded: ${item.name}`); - } - - console.log("🎉 AppMenu seed selesai"); -} - -export async function seedAppMenuChild() { - console.log("🔄 Seeding AppMenuChild..."); - - for (const item of appMenuChildJson) { - await prisma.appMenuChild.upsert({ - where: { id: item.id }, - update: { - name: item.name, - link: item.link, - isActive: item.isActive, - appMenuId: item.appMenuId, - }, - create: { - id: item.id, - name: item.name, - link: item.link, - isActive: item.isActive, - appMenuId: item.appMenuId, - }, - }); - - console.log(`✅ AppMenuChild seeded: ${item.name}`); - } - - console.log("🎉 AppMenuChild seed selesai"); -} diff --git a/prisma/_seeder_list/core/seed_core.ts b/prisma/_seeder_list/core/seed_core.ts deleted file mode 100644 index 4838c28b..00000000 --- a/prisma/_seeder_list/core/seed_core.ts +++ /dev/null @@ -1,69 +0,0 @@ -import prisma from "@/lib/prisma"; -import { loadJsonData } from "../../load-json"; - -const layananJson = loadJsonData("core/layanan.json"); -const potensiJson = loadJsonData("core/potensi.json"); -const landingPageLayananJson = loadJsonData("core/landingpage-layanan.json"); - -export async function seedLayananCore() { - console.log("🔄 Seeding Layanan..."); - - for (const item of layananJson) { - await prisma.layanan.upsert({ - where: { id: item.id }, - update: { - name: item.name, - }, - create: { - id: item.id, - name: item.name, - }, - }); - - console.log(`✅ Layanan seeded: ${item.name}`); - } - - console.log("🎉 Layanan seed selesai"); -} - -export async function seedPotensiCore() { - console.log("🔄 Seeding Potensi..."); - - for (const item of potensiJson) { - await prisma.potensi.upsert({ - where: { id: item.id }, - update: { - name: item.name, - }, - create: { - id: item.id, - name: item.name, - }, - }); - - console.log(`✅ Potensi seeded: ${item.name}`); - } - - console.log("🎉 Potensi seed selesai"); -} - -export async function seedLandingPageLayanan() { - console.log("🔄 Seeding LandingPage_Layanan..."); - - for (const item of landingPageLayananJson) { - await prisma.landingPage_Layanan.upsert({ - where: { id: item.id }, - update: { - deksripsi: item.deksripsi, - }, - create: { - id: item.id, - deksripsi: item.deksripsi, - }, - }); - - console.log(`✅ LandingPage_Layanan seeded: ${item.id}`); - } - - console.log("🎉 LandingPage_Layanan seed selesai"); -} diff --git a/prisma/_seeder_list/kesehatan/posyandu/seed_posyandu.ts b/prisma/_seeder_list/kesehatan/posyandu/seed_posyandu.ts index 67130c76..70b25a01 100644 --- a/prisma/_seeder_list/kesehatan/posyandu/seed_posyandu.ts +++ b/prisma/_seeder_list/kesehatan/posyandu/seed_posyandu.ts @@ -32,6 +32,7 @@ export async function seedPosyandu() { deskripsi: p.deskripsi, jadwalPelayanan: p.jadwalPelayanan, imageId, + banjarId: p.banjarId || null, }, create: { id: p.id, @@ -40,6 +41,7 @@ export async function seedPosyandu() { deskripsi: p.deskripsi, jadwalPelayanan: p.jadwalPelayanan, imageId, + banjarId: p.banjarId || null, }, }); diff --git a/prisma/_seeder_list/kesehatan/seed_banjar.ts b/prisma/_seeder_list/kesehatan/seed_banjar.ts new file mode 100644 index 00000000..2a2845a5 --- /dev/null +++ b/prisma/_seeder_list/kesehatan/seed_banjar.ts @@ -0,0 +1,19 @@ +import prisma from "@/lib/prisma"; +import { loadJsonData } from "../../load-json"; + +const banjarJson = loadJsonData("kesehatan/banjar/banjar.json"); + +export async function seedBanjar() { + console.log("🔄 Seeding Banjar..."); + + for (const b of banjarJson) { + await prisma.banjar.upsert({ + where: { id: b.id }, + update: { name: b.name }, + create: { id: b.id, name: b.name }, + }); + console.log(`✅ Banjar seeded: ${b.name}`); + } + + console.log("🎉 Banjar seed selesai"); +} diff --git a/prisma/data/keamanan/tips-keamanan/tips-keamanan.json b/prisma/data/keamanan/tips-keamanan/tips-keamanan.json index fcf6d4d5..64736201 100644 --- a/prisma/data/keamanan/tips-keamanan/tips-keamanan.json +++ b/prisma/data/keamanan/tips-keamanan/tips-keamanan.json @@ -3,12 +3,12 @@ "id": "cmkp70zau0002vnu9o1jtpi1i", "judul": "Keamanan Rumah", "deskripsi": "

", - "imageName": "dSe0xyvNLkP2t2f6iq-Hk-mobile.webp" + "imageName": "vwZsaxcoFWDlxG1PW7FC0-mobile.webp" }, { "id": "cmkp71pzo0005vnu9p3n9646d", "judul": "Keamanan Lingkungan Tanggungjawab Bersama", "deskripsi": "

Pemerintah Desa Darmasaba melaksanakan sosialisasi dan pembinaan tentang keamanan dan ketertiban lingkungan kepada warga Perumahan Darmasaba Permai. Warga diajak berperan aktif dalam menjaga keamanan lingkungan serta mendukung penyediaan lampu penerangan jalan untuk mencegah tindak kriminal dan kecelakaan. Bhabinkamtibmas dan Babinsa turut memberikan materi keamanan dan ketertiban kepada warga, menekankan pentingnya partisipasi masyarakat dalam menjaga keamanan desa.

", - "imageName": "vwZsaxcoFWDlxG1PW7FC0-mobile.webp" + "imageName": "dSe0xyvNLkP2t2f6iq-Hk-mobile.webp" } ] \ No newline at end of file diff --git a/prisma/data/kesehatan/banjar/banjar.json b/prisma/data/kesehatan/banjar/banjar.json new file mode 100644 index 00000000..f84fad1f --- /dev/null +++ b/prisma/data/kesehatan/banjar/banjar.json @@ -0,0 +1,10 @@ +[ + { "id": "banjar_pudak_amara_001", "name": "Banjar Pudak Amara" }, + { "id": "banjar_mawar_001", "name": "Banjar Mawar" }, + { "id": "banjar_melati_001", "name": "Banjar Melati" }, + { "id": "banjar_dahlia_001", "name": "Banjar Dahlia" }, + { "id": "banjar_anggrek_001", "name": "Banjar Anggrek" }, + { "id": "banjar_kamboja_001", "name": "Banjar Kamboja" }, + { "id": "banjar_melur_001", "name": "Banjar Melur" }, + { "id": "banjar_kenanga_001", "name": "Banjar Kenanga" } +] diff --git a/prisma/data/kesehatan/posyandu/posyandu.json b/prisma/data/kesehatan/posyandu/posyandu.json index 8c7a84e0..5892e7db 100644 --- a/prisma/data/kesehatan/posyandu/posyandu.json +++ b/prisma/data/kesehatan/posyandu/posyandu.json @@ -5,55 +5,63 @@ "nomor": "(0361) 8463263", "deskripsi": "

Posyandu Pudak Amara merupakan salah satu posyandu aktif di Desa Darmasaba dan pernah berkompetisi dalam lomba kader dan posyandu berprestasi tingkat Provinsi Bali tahun 2025.

", "jadwalPelayanan": "Senin, 10 Feb 2026, 08:00 - 11:00 WITA", - "imageName": "TDQReg1lQ73s39crXW0ra-mobile.webp" + "imageName": "TDQReg1lQ73s39crXW0ra-mobile.webp", + "banjarId": "banjar_pudak_amara_001" }, { "id": "posyandu_mawar_001", "name": "Posyandu Mawar", "nomor": "(0361) 8463264", "deskripsi": "

Posyandu Mawar melayani kesehatan ibu dan anak di wilayah Banjar Mawar, Desa Darmasaba, dengan fokus pada pemantauan tumbuh kembang balita dan kesehatan ibu hamil.

", - "jadwalPelayanan": "Senin, 15 Feb 2026, 08:00 - 11:00 WITA" + "jadwalPelayanan": "Senin, 15 Feb 2026, 08:00 - 11:00 WITA", + "banjarId": "banjar_mawar_001" }, { "id": "posyandu_melati_001", "name": "Posyandu Melati", "nomor": "(0361) 8463265", "deskripsi": "

Posyandu Melati berperan aktif dalam pelayanan kesehatan dasar masyarakat di Banjar Melati, meliputi imunisasi, penimbangan balita, dan konsultasi gizi.

", - "jadwalPelayanan": "Selasa, 16 Feb 2026, 08:00 - 11:00 WITA" + "jadwalPelayanan": "Selasa, 16 Feb 2026, 08:00 - 11:00 WITA", + "banjarId": "banjar_melati_001" }, { "id": "posyandu_dahlia_001", "name": "Posyandu Dahlia", "nomor": "(0361) 8463266", "deskripsi": "

Posyandu Dahlia aktif melayani masyarakat Banjar Dahlia dengan program unggulan pemantauan stunting dan pemberian makanan tambahan bagi balita berisiko.

", - "jadwalPelayanan": "Rabu, 17 Feb 2026, 08:00 - 11:00 WITA" + "jadwalPelayanan": "Rabu, 17 Feb 2026, 08:00 - 11:00 WITA", + "banjarId": "banjar_dahlia_001" }, { "id": "posyandu_anggrek_001", "name": "Posyandu Anggrek", "nomor": "(0361) 8463267", "deskripsi": "

Posyandu Anggrek melayani ibu hamil, ibu menyusui, dan balita di wilayah Banjar Anggrek dengan dukungan tenaga kesehatan dari Puskesmas Abiansemal 3.

", - "jadwalPelayanan": "Kamis, 18 Feb 2026, 08:00 - 11:00 WITA" + "jadwalPelayanan": "Kamis, 18 Feb 2026, 08:00 - 11:00 WITA", + "banjarId": "banjar_anggrek_001" }, { "id": "posyandu_kamboja_001", "name": "Posyandu Kamboja", "nomor": "(0361) 8463268", "deskripsi": "

Posyandu Kamboja hadir untuk mendukung kesehatan masyarakat Banjar Kamboja melalui layanan pemeriksaan rutin, imunisasi lengkap, dan edukasi gizi keluarga.

", - "jadwalPelayanan": "Jumat, 19 Feb 2026, 08:00 - 11:00 WITA" + "jadwalPelayanan": "Jumat, 19 Feb 2026, 08:00 - 11:00 WITA", + "banjarId": "banjar_kamboja_001" }, { "id": "posyandu_melur_001", "name": "Posyandu Melur", "nomor": "(0361) 8463269", "deskripsi": "

Posyandu Melur aktif memberikan layanan kesehatan preventif bagi ibu dan anak di Banjar Melur, termasuk deteksi dini stunting dan pemantauan gizi balita.

", - "jadwalPelayanan": "Sabtu, 20 Feb 2026, 08:00 - 11:00 WITA" + "jadwalPelayanan": "Sabtu, 20 Feb 2026, 08:00 - 11:00 WITA", + "banjarId": "banjar_melur_001" }, { "id": "posyandu_kenanga_001", "name": "Posyandu Kenanga", "nomor": "(0361) 8463270", "deskripsi": "

Posyandu Kenanga melayani masyarakat Banjar Kenanga dengan program kesehatan ibu dan anak, pemberian vitamin A, dan konseling laktasi bagi ibu menyusui.

", - "jadwalPelayanan": "Senin, 23 Feb 2026, 08:00 - 11:00 WITA" + "jadwalPelayanan": "Senin, 23 Feb 2026, 08:00 - 11:00 WITA", + "banjarId": "banjar_kenanga_001" } ] diff --git a/prisma/data/ppid/struktur-organisasi-ppid/struktur-organisasi-ppid.json b/prisma/data/ppid/struktur-organisasi-ppid/struktur-organisasi-ppid.json index b63819e3..e4ca38db 100644 --- a/prisma/data/ppid/struktur-organisasi-ppid/struktur-organisasi-ppid.json +++ b/prisma/data/ppid/struktur-organisasi-ppid/struktur-organisasi-ppid.json @@ -1,8 +1,8 @@ [ { "id": "struktur-org-ppid-001", - "posisiOrganisasiId": "posisi-001", - "pegawaiId": "pegawai-001", + "posisiOrganisasiId": "kepala_desa", + "pegawaiId": "cmgewz4gt000704ib91i3f169", "hubunganOrganisasiId": "hubungan-001" } ] diff --git a/prisma/migrations/20260528100000_add_banjar_to_posyandu/migration.sql b/prisma/migrations/20260528100000_add_banjar_to_posyandu/migration.sql new file mode 100644 index 00000000..990d01e8 --- /dev/null +++ b/prisma/migrations/20260528100000_add_banjar_to_posyandu/migration.sql @@ -0,0 +1,16 @@ +-- CreateTable +CREATE TABLE "Banjar" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Banjar_pkey" PRIMARY KEY ("id") +); + +-- AlterTable +ALTER TABLE "Posyandu" ADD COLUMN "banjarId" TEXT; + +-- AddForeignKey +ALTER TABLE "Posyandu" ADD CONSTRAINT "Posyandu_banjarId_fkey" FOREIGN KEY ("banjarId") REFERENCES "Banjar"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 068ff545..3f5157f6 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1150,6 +1150,16 @@ model DoctorSign { ArtikelKesehatan ArtikelKesehatan[] } +// ========================================= BANJAR ========================================= // +model Banjar { + id String @id @default(cuid()) + name String + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + posyandus Posyandu[] +} + // ========================================= POSYANDU ========================================= // model Posyandu { id String @id @default(cuid()) @@ -1159,6 +1169,8 @@ model Posyandu { jadwalPelayanan String image FileStorage? @relation(fields: [imageId], references: [id]) imageId String? + banjar Banjar? @relation(fields: [banjarId], references: [id]) + banjarId String? ibuHamil IbuHamil[] balita Balita[] createdAt DateTime @default(now()) diff --git a/prisma/seed.ts b/prisma/seed.ts index c0520f77..3922f027 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -38,6 +38,7 @@ import { seedKontakDaruratKeamanan } from "./_seeder_list/keamanan/seed_kontak_d import { seedLaporanPublik } from "./_seeder_list/keamanan/seed_laporan_publik"; import { seedPencegahanKriminalitas } from "./_seeder_list/keamanan/seed_pencegahan_kriminalitas"; import { seedPolsekTerdekat } from "./_seeder_list/keamanan/seed_polsek_terdekat"; +import { seedTipsKeamanan } from "./_seeder_list/keamanan/seed_tips_keamanan"; import { seedArtikelKesehatan } from "./_seeder_list/kesehatan/artikel-kesehatan/seed_artikel_kesehatan"; import { seedFasilitasKesehatan } from "./_seeder_list/kesehatan/fasilitas-kesehatan/seed_fasilitas_kesehatan"; import { seedInfoWabahPenyakit } from "./_seeder_list/kesehatan/info-wabah-penyakit/seed_info_wabah_penyakit"; @@ -49,6 +50,7 @@ import { seedProgramKesehatan } from "./_seeder_list/kesehatan/program-kesehatan import { seedPuskesmas } from "./_seeder_list/kesehatan/puskesmas/seed_puskesmas"; import { seedGrafikKepuasan } from "./_seeder_list/kesehatan/seed_grafik_kepuasan"; import { seedKelahiranKematian } from "./_seeder_list/kesehatan/seed_kelahiran_kematian"; +import { seedBanjar } from "./_seeder_list/kesehatan/seed_banjar"; import { seedRingkasanKesehatan } from "./_seeder_list/kesehatan/seed_ringkasan_kesehatan"; import { seedIbuHamil } from "./_seeder_list/kesehatan/seed_ibu_hamil"; import { seedBalita } from "./_seeder_list/kesehatan/seed_balita"; @@ -84,6 +86,7 @@ import { seedIkmPpid } from "./_seeder_list/ppid/ikm/seed_ikm"; import { seedProfilPpd } from "./_seeder_list/ppid/profil-ppid/seed_profil_ppd"; import { seedPegawaiPpid } from "./_seeder_list/ppid/struktur-ppid/seed_struktur_ppid"; import { seedVisiMisiPpid } from "./_seeder_list/ppid/visi-misi-ppid/seed_visi_misi_ppid"; +import { seedStrukturOrganisasiPpid, seedFormulirPermohonanKeberatan, seedIndeksKepuasanMasyarakat, seedGrafikBerdasarkanJenisKelamin, seedGrafikBerdasarkanResponden, seedGrafikBerdasarkanUmur } from "./_seeder_list/ppid/seed_ppid_extra"; import roles from "./data/user/roles.json"; import users from "./data/user/users.json"; import { safeSeedUnique } from "./safeseedUnique"; @@ -219,6 +222,12 @@ import seedAssets from "./seed_assets"; // // =========== SUBMENU INDEKS KEPUASAN MASYARAKAT =========== await seedIkmPpid(); + await seedStrukturOrganisasiPpid(); + await seedFormulirPermohonanKeberatan(); + await seedIndeksKepuasanMasyarakat(); + await seedGrafikBerdasarkanJenisKelamin(); + await seedGrafikBerdasarkanResponden(); + await seedGrafikBerdasarkanUmur(); // // =========== MENU DESA =========== // // =========== SUBMENU PROFILE =========== @@ -245,6 +254,9 @@ import seedAssets from "./seed_assets"; await seedPenghargaan(); // // ====================== MENU KESEHATAN ======================== + // // ==================== SUBMENU BANJAR ========================= + await seedBanjar(); + // // ==================== SUBMENU POSYANDU ========================= await seedPosyandu(); @@ -285,7 +297,7 @@ import seedAssets from "./seed_assets"; await seedCctv(); // // ==================== SUBMENU TIPS KEAMANAN ================== - await seedKeamananLingkungan(); + await seedTipsKeamanan(); // // ====================== MENU EKONOMI ======================== // // ==================== SUBMENU UMKM ========================== diff --git a/src/app/admin/(dashboard)/_state/kesehatan/balita/balita.ts b/src/app/admin/(dashboard)/_state/kesehatan/balita/balita.ts index e7f1a0c1..be20148d 100644 --- a/src/app/admin/(dashboard)/_state/kesehatan/balita/balita.ts +++ b/src/app/admin/(dashboard)/_state/kesehatan/balita/balita.ts @@ -82,7 +82,15 @@ const balitaState = proxy({ findMany: { data: null as | Prisma.BalitaGetPayload<{ - include: { posyandu: { select: { id: true; name: true } } }; + include: { + posyandu: { + select: { + id: true; + name: true; + banjar: { select: { id: true; name: true } }; + }; + }; + }; }>[] | null, page: 1, diff --git a/src/app/admin/(dashboard)/_state/kesehatan/ibu-hamil/ibuHamil.ts b/src/app/admin/(dashboard)/_state/kesehatan/ibu-hamil/ibuHamil.ts index 906541f4..2b410205 100644 --- a/src/app/admin/(dashboard)/_state/kesehatan/ibu-hamil/ibuHamil.ts +++ b/src/app/admin/(dashboard)/_state/kesehatan/ibu-hamil/ibuHamil.ts @@ -72,7 +72,15 @@ const ibuHamilState = proxy({ findMany: { data: null as | Prisma.IbuHamilGetPayload<{ - include: { posyandu: { select: { id: true; name: true } } }; + include: { + posyandu: { + select: { + id: true; + name: true; + banjar: { select: { id: true; name: true } }; + }; + }; + }; }>[] | null, page: 1, diff --git a/src/app/admin/(dashboard)/_state/kesehatan/posyandu/posyandu.ts b/src/app/admin/(dashboard)/_state/kesehatan/posyandu/posyandu.ts index 38ccec4c..bca47df1 100644 --- a/src/app/admin/(dashboard)/_state/kesehatan/posyandu/posyandu.ts +++ b/src/app/admin/(dashboard)/_state/kesehatan/posyandu/posyandu.ts @@ -19,6 +19,7 @@ const defaultForm = { deskripsi: "", imageId: "", jadwalPelayanan: "", + banjarId: "", }; const posyandustate = proxy({ @@ -57,6 +58,7 @@ const posyandustate = proxy({ | Prisma.PosyanduGetPayload<{ include: { image: true; + banjar: { select: { id: true; name: true } }; }; }>[] | null, @@ -92,10 +94,11 @@ const posyandustate = proxy({ }, }, findUnique: { - data: null as + data: null as | Prisma.PosyanduGetPayload<{ include: { image: true; + banjar: { select: { id: true; name: true } }; } }> | null, async load(id: string) { @@ -176,6 +179,7 @@ const posyandustate = proxy({ deskripsi: data.deskripsi, imageId: data.imageId || "", jadwalPelayanan: data.jadwalPelayanan || "", + banjarId: data.banjarId || "", }; return data; } else { @@ -210,6 +214,7 @@ const posyandustate = proxy({ deskripsi: this.form.deskripsi, imageId: this.form.imageId, jadwalPelayanan: this.form.jadwalPelayanan, + banjarId: this.form.banjarId || undefined, }), }); diff --git a/src/app/admin/(dashboard)/_state/kesehatan/ringkasan-kesehatan/ringkasanKesehatan.ts b/src/app/admin/(dashboard)/_state/kesehatan/ringkasan-kesehatan/ringkasanKesehatan.ts index 5728bac9..a4a7db76 100644 --- a/src/app/admin/(dashboard)/_state/kesehatan/ringkasan-kesehatan/ringkasanKesehatan.ts +++ b/src/app/admin/(dashboard)/_state/kesehatan/ringkasan-kesehatan/ringkasanKesehatan.ts @@ -18,14 +18,39 @@ const intPct = z .min(0, { message: "Minimal 0" }) .max(100, { message: "Maksimal 100" }); +type BanjarOption = { id: string; name: string }; + const ringkasanKesehatanState = proxy({ + banjarId: "" as string, + + findBanjar: { + data: [] as BanjarOption[], + loading: false, + async load() { + try { + ringkasanKesehatanState.findBanjar.loading = true; + const res = await fetch(`/api/kesehatan/banjar/find-many`); + if (res.ok) { + const result = await res.json(); + ringkasanKesehatanState.findBanjar.data = result?.data ?? []; + } + } catch (error) { + console.error("Error fetching banjar:", error); + } finally { + ringkasanKesehatanState.findBanjar.loading = false; + } + }, + }, + findStats: { data: null as StatsData | null, loading: false, async load() { try { ringkasanKesehatanState.findStats.loading = true; - const res = await fetch(`/api/kesehatan/ringkasankesehatan/stats`); + const banjarId = ringkasanKesehatanState.banjarId; + const params = banjarId ? `?banjarId=${encodeURIComponent(banjarId)}` : ""; + const res = await fetch(`/api/kesehatan/ringkasankesehatan/stats${params}`); if (res.ok) { const result = await res.json(); ringkasanKesehatanState.findStats.data = result?.data ?? null; diff --git a/src/app/admin/(dashboard)/kesehatan/posyandu/balita/page.tsx b/src/app/admin/(dashboard)/kesehatan/posyandu/balita/page.tsx index 7be1ae07..4f8f7eb7 100644 --- a/src/app/admin/(dashboard)/kesehatan/posyandu/balita/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/posyandu/balita/page.tsx @@ -115,13 +115,14 @@ function ListBalita({ search }: { search: string }) { - Nama - JK - Tgl Lahir - Imunisasi - Gizi - Pemeriksaan - Stunting + Nama + JK + Tgl Lahir + Banjar + Imunisasi + Gizi + Pemeriksaan + Stunting Aksi @@ -136,6 +137,7 @@ function ListBalita({ search }: { search: string }) { ? new Date(d.tanggalLahir).toLocaleDateString('id-ID') : '-'} + {d.posyandu?.banjar?.name ?? '-'} {d.imunisasiLengkap ? 'Lengkap' : 'Belum'} @@ -190,7 +192,7 @@ function ListBalita({ search }: { search: string }) { )) ) : ( - +
Tidak ada data balita yang cocok @@ -212,19 +214,22 @@ function ListBalita({ search }: { search: string }) { {d.nama} - + {d.jenisKelamin} - - · - + · {d.tanggalLahir ? new Date(d.tanggalLahir).toLocaleDateString('id-ID') : '-'} + {d.posyandu?.banjar?.name && ( + + Banjar: {d.posyandu.banjar.name} + + )} - Nama - NIK - Usia Kehamilan - No. HP - Status - Aksi + Nama + NIK + Usia Kehamilan + No. HP + Banjar + Status + Aksi @@ -133,6 +134,7 @@ function ListIbuHamil({ search }: { search: string }) { {d.nik || '-'} {d.usiaKehamilan} minggu {d.noHp || '-'} + {d.posyandu?.banjar?.name ?? '-'} - +
Tidak ada data ibu hamil yang cocok @@ -194,17 +196,20 @@ function ListIbuHamil({ search }: { search: string }) { {d.nama} - + NIK: {d.nik || '-'} - - · - + · {d.usiaKehamilan} minggu + {d.posyandu?.banjar?.name && ( + + Banjar: {d.posyandu.banjar.name} + + )} { + ringkasanKesehatanState.findBanjar.load(); const loadPosyandu = async () => { const id = params?.id as string; if (!id) return; @@ -82,6 +88,7 @@ function EditPosyandu() { deskripsi: data.deskripsi || '', imageId: data.imageId || '', jadwalPelayanan: data.jadwalPelayanan || '', + banjarId: data.banjarId || '', }); setOriginalData({ name: data.name || '', @@ -89,6 +96,7 @@ function EditPosyandu() { deskripsi: data.deskripsi || '', imageId: data.imageId || '', jadwalPelayanan: data.jadwalPelayanan || '', + banjarId: data.banjarId || '', imageUrl: data.image?.link || '', }); if (data?.image?.link) setPreviewImage(data.image.link); @@ -129,7 +137,7 @@ function EditPosyandu() { try { setIsSubmitting(true); - const updatedForm = { ...statePosyandu.edit.form, ...formData }; + const updatedForm = { ...statePosyandu.edit.form, ...formData, banjarId: formData.banjarId }; // Upload file jika ada if (file) { @@ -160,6 +168,7 @@ function EditPosyandu() { deskripsi: originalData.deskripsi, imageId: originalData.imageId, jadwalPelayanan: originalData.jadwalPelayanan, + banjarId: originalData.banjarId, }); setPreviewImage(originalData.imageUrl || null); setFile(null); @@ -282,6 +291,15 @@ function EditPosyandu() { required /> + ({ value: b.id, label: b.name }))} + value={statePosyandu.create.form.banjarId || null} + onChange={(val) => { statePosyandu.create.form.banjarId = val ?? ''; }} + /> Deskripsi Posyandu diff --git a/src/app/admin/(dashboard)/kesehatan/posyandu/list-posyandu/page.tsx b/src/app/admin/(dashboard)/kesehatan/posyandu/list-posyandu/page.tsx index f7468bbf..7b30c83a 100644 --- a/src/app/admin/(dashboard)/kesehatan/posyandu/list-posyandu/page.tsx +++ b/src/app/admin/(dashboard)/kesehatan/posyandu/list-posyandu/page.tsx @@ -96,27 +96,33 @@ function ListPosyandu({ search }: { search: string }) { > - Nama Posyandu - Nomor Posyandu - Deskripsi - Aksi + Nama Posyandu + Banjar + Nomor Posyandu + Deskripsi + Aksi {filteredData.length > 0 ? ( filteredData.map((item) => ( - + {item.name} - + + + {item.banjar?.name || '-'} + + + {item.nomor || '-'} - + - + + {stBalita.findMany.loading ? ( + + {Array.from({ length: 4 }).map((_, i) => ( + + ))} - - ))} - + ) : !stBalita.findMany.data?.length ? ( + + Tidak ada data balita ditemukan + + ) : ( + <> + + Total: {stBalita.findMany.total} balita terdaftar + + + {stBalita.findMany.data.map((v, i) => ( + + + + + {v.nama} + + {v.jenisKelamin === "L" ? "Laki-laki" : "Perempuan"} + {v.tanggalLahir + ? ` · ${new Date(v.tanggalLahir).toLocaleDateString("id-ID", { + day: "numeric", + month: "long", + year: "numeric", + })}` + : ""} + + + + {v.statusStunting} + + -
- load(newPage)} - total={totalPages} - radius="lg" - size="md" - withControls - mt="md" - /> -
+ {v.posyandu && ( + + + + {v.posyandu.name} + {v.posyandu.banjar + ? ` · Banjar ${v.posyandu.banjar.name}` + : ""} + + + )} - - - - - Layanan Utama Posyandu - - - - Penimbangan bayi dan balita - Pemantauan status gizi - Imunisasi dasar lengkap - Konseling kesehatan - Pemantauan kesehatan ibu hamil - - -
+ + + {v.imunisasiLengkap + ? "Imunisasi Lengkap" + : "Imunisasi Belum Lengkap"} + + + {v.giziBaik ? "Gizi Baik" : "Gizi Kurang"} + + + {v.pemeriksaanRutin ? "Periksa Rutin" : "Tidak Rutin"} + + + +
+ ))} +
+ +
+ + balitaState.findMany.load( + p, + 10, + searchBalita, + filterStunting ?? "" + ) + } + total={stBalita.findMany.totalPages} + radius="lg" + color={colors["blue-button"]} + /> +
+ + )} + + + + {/* ===== IBU HAMIL ===== */} + + + + } + value={searchIbuHamil} + onChange={(e) => setSearchIbuHamil(e.currentTarget.value)} + style={{ flex: 1, minWidth: 200 }} + /> +