feat(kesehatan): slim ringkasan kesehatan schema + tambah seeder balita & ibu hamil - bump 0.1.52

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-05 10:31:40 +08:00
parent afe0d9d04b
commit fd2060405f
10 changed files with 760 additions and 159 deletions

View File

@@ -0,0 +1,502 @@
import prisma from "@/lib/prisma";
import { JenisKelaminBalita, StatusStunting } from "@prisma/client";
// Fokus data: proporsi stunting realistis untuk simulasi dashboard
// 10 STUNTING, 7 ALERT, 8 NORMAL dari 25 total
const BALITA_DATA = [
// ===== STUNTING (TB/U < -2 SD dari median WHO) =====
{
id: "balita_001",
nama: "Wayan Aditya Pratama",
nik: "5101014505230001",
tanggalLahir: new Date("2023-05-04"), // 36 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 11.5,
tinggiBadanCm: 83.0, // median 96cm, -2SD ~89cm
namaOrtu: "I Wayan Suardika",
alamat: "Banjar Pudak, Desa Darmasaba",
noHpOrtu: "08123456801",
posyanduId: "cmkanjnmx0006vntz1cn7owpb",
imunisasiLengkap: true,
giziBaik: false,
pemeriksaanRutin: true,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -2.8 SD. Dalam program PMT (Pemberian Makanan Tambahan). Orang tua sudah mendapat konseling gizi.",
},
{
id: "balita_002",
nama: "Ni Kadek Mira Sari",
nik: "5101014501240002",
tanggalLahir: new Date("2024-01-04"), // 16 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 7.8,
tinggiBadanCm: 70.5, // median ~78cm
namaOrtu: "I Kadek Suartha",
alamat: "Banjar Dahlia, Desa Darmasaba",
noHpOrtu: "08123456802",
posyanduId: "posyandu_dahlia_001",
imunisasiLengkap: false,
giziBaik: false,
pemeriksaanRutin: false,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -3.1 SD. Imunisasi belum lengkap. Ibu bekerja, kunjungan posyandu tidak rutin. Perlu pendampingan kader.",
},
{
id: "balita_003",
nama: "Putu Rian Saputra",
nik: "5101014501220003",
tanggalLahir: new Date("2022-01-04"), // 40 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 12.5,
tinggiBadanCm: 89.0, // median 103cm
namaOrtu: "Ni Putu Sumiati",
alamat: "Banjar Dahlia, Desa Darmasaba",
noHpOrtu: "08123456803",
posyanduId: "posyandu_dahlia_001",
imunisasiLengkap: true,
giziBaik: false,
pemeriksaanRutin: true,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -3.2 SD. Sudah dirujuk ke Puskesmas Abiansemal 3 untuk pemeriksaan lebih lanjut.",
},
{
id: "balita_004",
nama: "Ni Komang Ayu Lestari",
nik: "5101014507230004",
tanggalLahir: new Date("2023-07-04"), // 22 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 8.2,
tinggiBadanCm: 74.0, // median ~84cm
namaOrtu: "I Komang Sudiarta",
alamat: "Banjar Anggrek, Desa Darmasaba",
noHpOrtu: "08123456804",
posyanduId: "posyandu_anggrek_001",
imunisasiLengkap: true,
giziBaik: false,
pemeriksaanRutin: true,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -2.5 SD. Riwayat BBLR (berat lahir rendah) 2.3 kg.",
},
{
id: "balita_005",
nama: "Ketut Agus Pratama",
nik: "5101014507240005",
tanggalLahir: new Date("2024-07-04"), // 10 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 6.9,
tinggiBadanCm: 66.0, // median ~72cm
namaOrtu: "Ni Ketut Sariani",
alamat: "Banjar Kamboja, Desa Darmasaba",
noHpOrtu: "08123456805",
posyanduId: "posyandu_kamboja_001",
imunisasiLengkap: false,
giziBaik: false,
pemeriksaanRutin: false,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -2.3 SD. Lahir prematur 35 minggu. Keluarga prasejahtera, masuk program PKH.",
},
{
id: "balita_006",
nama: "Ni Made Sinta Dewi",
nik: "5101014507220006",
tanggalLahir: new Date("2022-07-04"), // 34 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 11.0,
tinggiBadanCm: 84.5, // median ~94cm
namaOrtu: "I Made Sudarsana",
alamat: "Banjar Melur, Desa Darmasaba",
noHpOrtu: "08123456806",
posyanduId: "posyandu_melur_001",
imunisasiLengkap: true,
giziBaik: false,
pemeriksaanRutin: true,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -2.6 SD. Nafsu makan rendah, sedang dalam pantauan ahli gizi Puskesmas.",
},
{
id: "balita_007",
nama: "Made Dani Putra",
nik: "5101014501250007",
tanggalLahir: new Date("2025-01-04"), // 4 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 5.0,
tinggiBadanCm: 57.0, // median ~63cm
namaOrtu: "Ni Made Suparni",
alamat: "Banjar Kenanga, Desa Darmasaba",
noHpOrtu: "08123456807",
posyanduId: "posyandu_kenanga_001",
imunisasiLengkap: false,
giziBaik: false,
pemeriksaanRutin: true,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -2.4 SD. BBLR 2.1 kg, ibu ASI eksklusif. Kunjungan rutin ke posyandu.",
},
{
id: "balita_008",
nama: "Ni Putu Ratna Sari",
nik: "5101014507210008",
tanggalLahir: new Date("2021-07-04"), // 46 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 13.0,
tinggiBadanCm: 92.0, // median ~106cm
namaOrtu: "I Putu Suarjana",
alamat: "Banjar Mawar, Desa Darmasaba",
noHpOrtu: "08123456808",
posyanduId: "posyandu_mawar_001",
imunisasiLengkap: true,
giziBaik: false,
pemeriksaanRutin: true,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -2.9 SD. Sudah 6 bulan dalam program intervensi stunting desa.",
},
{
id: "balita_009",
nama: "Gede Yoga Pratama",
nik: "5101014505210009",
tanggalLahir: new Date("2021-05-04"), // 48 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 13.5,
tinggiBadanCm: 91.0, // median ~108cm
namaOrtu: "Ni Wayan Suarningsih",
alamat: "Banjar Pudak, Desa Darmasaba",
noHpOrtu: "08123456809",
posyanduId: "cmkanjnmx0006vntz1cn7owpb",
imunisasiLengkap: true,
giziBaik: false,
pemeriksaanRutin: false,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -3.0 SD. Keluarga baru pindah dari luar desa. Sedang proses pendataan ulang.",
},
{
id: "balita_010",
nama: "Ni Nyoman Sari Utami",
nik: "5101014505230010",
tanggalLahir: new Date("2023-05-04"), // 24 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 9.5,
tinggiBadanCm: 80.0, // median ~87cm
namaOrtu: "I Nyoman Sueca",
alamat: "Banjar Melati, Desa Darmasaba",
noHpOrtu: "08123456810",
posyanduId: "posyandu_melati_001",
imunisasiLengkap: true,
giziBaik: false,
pemeriksaanRutin: true,
statusStunting: StatusStunting.STUNTING,
catatan: "TB/U -2.2 SD. Batas bawah stunting. Perlu dipantau ketat tiap bulan.",
},
// ===== ALERT (TB/U antara -1 SD dan -2 SD) =====
{
id: "balita_011",
nama: "Wayan Krisna Dewa",
nik: "5101014501240011",
tanggalLahir: new Date("2024-01-04"), // 16 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 9.8,
tinggiBadanCm: 74.0, // median ~78cm, -1SD ~75cm
namaOrtu: "I Wayan Artana",
alamat: "Banjar Mawar, Desa Darmasaba",
noHpOrtu: "08123456811",
posyanduId: "posyandu_mawar_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.ALERT,
catatan: "TB/U -1.5 SD. Perlu pemantauan lebih lanjut, gizi cukup baik.",
},
{
id: "balita_012",
nama: "Ni Wayan Novi Andriani",
nik: "5101014505230012",
tanggalLahir: new Date("2023-05-04"), // 24 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 10.8,
tinggiBadanCm: 83.0, // median ~87cm
namaOrtu: "Ni Wayan Artini",
alamat: "Banjar Melati, Desa Darmasaba",
noHpOrtu: "08123456812",
posyanduId: "posyandu_melati_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.ALERT,
catatan: "TB/U -1.8 SD. Nafsu makan baik, BB naik konsisten.",
},
{
id: "balita_013",
nama: "Putu Deva Mahendra",
nik: "5101014511240013",
tanggalLahir: new Date("2024-11-04"), // 6 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 6.8,
tinggiBadanCm: 63.5, // median ~67cm
namaOrtu: "I Putu Ariana",
alamat: "Banjar Anggrek, Desa Darmasaba",
noHpOrtu: "08123456813",
posyanduId: "posyandu_anggrek_001",
imunisasiLengkap: false,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.ALERT,
catatan: "TB/U -1.6 SD. ASI eksklusif. Jadwal imunisasi DPT ketiga belum terlaksana.",
},
{
id: "balita_014",
nama: "Ni Komang Dewi Lestari",
nik: "5101014501220014",
tanggalLahir: new Date("2022-01-04"), // 40 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 14.0,
tinggiBadanCm: 96.0, // median ~103cm
namaOrtu: "I Komang Wirawan",
alamat: "Banjar Kamboja, Desa Darmasaba",
noHpOrtu: "08123456814",
posyanduId: "posyandu_kamboja_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.ALERT,
catatan: "TB/U -1.4 SD. Konsumsi protein hewani belum cukup, edukasi diberikan.",
},
{
id: "balita_015",
nama: "Made Surya Darma",
nik: "5101014511230015",
tanggalLahir: new Date("2023-11-04"), // 18 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 10.2,
tinggiBadanCm: 76.0, // median ~82cm
namaOrtu: "Ni Made Sudarmi",
alamat: "Banjar Melur, Desa Darmasaba",
noHpOrtu: "08123456815",
posyanduId: "posyandu_melur_001",
imunisasiLengkap: true,
giziBaik: false,
pemeriksaanRutin: true,
statusStunting: StatusStunting.ALERT,
catatan: "TB/U -1.9 SD. Sedang mendapat PMT (makanan tambahan) dari desa.",
},
{
id: "balita_016",
nama: "Ni Kadek Ayu Purnami",
nik: "5101014505250016",
tanggalLahir: new Date("2025-05-04"), // 0 bulan (baru lahir - 1 bulan)
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 3.5,
tinggiBadanCm: 49.0, // median ~52cm
namaOrtu: "I Kadek Suartha",
alamat: "Banjar Kenanga, Desa Darmasaba",
noHpOrtu: "08123456816",
posyanduId: "posyandu_kenanga_001",
imunisasiLengkap: false,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.ALERT,
catatan: "TB/U -1.7 SD. Bayi baru, lahir 2.8 kg. Dipantau dari awal.",
},
{
id: "balita_017",
nama: "Ketut Bayu Setiawan",
nik: "5101014511220017",
tanggalLahir: new Date("2022-11-04"), // 30 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 13.2,
tinggiBadanCm: 88.0, // median ~93cm
namaOrtu: "Ni Ketut Suarni",
alamat: "Banjar Dahlia, Desa Darmasaba",
noHpOrtu: "08123456817",
posyanduId: "posyandu_dahlia_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.ALERT,
catatan: "TB/U -1.3 SD. Tumbuh kembang membaik dalam 3 bulan terakhir.",
},
// ===== NORMAL =====
{
id: "balita_018",
nama: "Ni Made Intan Permata",
nik: "5101014501240018",
tanggalLahir: new Date("2024-01-04"), // 16 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 10.5,
tinggiBadanCm: 78.0,
namaOrtu: "I Made Sudiarsa",
alamat: "Banjar Mawar, Desa Darmasaba",
noHpOrtu: "08123456818",
posyanduId: "posyandu_mawar_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.NORMAL,
},
{
id: "balita_019",
nama: "Wayan Arya Nugraha",
nik: "5101014505230019",
tanggalLahir: new Date("2023-05-04"), // 24 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 12.0,
tinggiBadanCm: 87.0,
namaOrtu: "Ni Wayan Suarni",
alamat: "Banjar Pudak, Desa Darmasaba",
noHpOrtu: "08123456819",
posyanduId: "cmkanjnmx0006vntz1cn7owpb",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.NORMAL,
},
{
id: "balita_020",
nama: "Ni Putu Cantika Dewi",
nik: "5101014501220020",
tanggalLahir: new Date("2022-01-04"), // 40 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 15.5,
tinggiBadanCm: 103.0,
namaOrtu: "I Putu Sudiarta",
alamat: "Banjar Melati, Desa Darmasaba",
noHpOrtu: "08123456820",
posyanduId: "posyandu_melati_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.NORMAL,
},
{
id: "balita_021",
nama: "Komang Danu Mahesa",
nik: "5101014505250021",
tanggalLahir: new Date("2025-05-04"), // 0 bulan (newborn)
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 3.8,
tinggiBadanCm: 52.0,
namaOrtu: "Ni Komang Artini",
alamat: "Banjar Anggrek, Desa Darmasaba",
noHpOrtu: "08123456821",
posyanduId: "posyandu_anggrek_001",
imunisasiLengkap: false,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.NORMAL,
},
{
id: "balita_022",
nama: "Ni Nyoman Suka Rani",
nik: "5101014505210022",
tanggalLahir: new Date("2021-05-04"), // 48 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 16.5,
tinggiBadanCm: 105.0,
namaOrtu: "I Nyoman Suarman",
alamat: "Banjar Kamboja, Desa Darmasaba",
noHpOrtu: "08123456822",
posyanduId: "posyandu_kamboja_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.NORMAL,
},
{
id: "balita_023",
nama: "Made Giri Putra Santosa",
nik: "5101014511240023",
tanggalLahir: new Date("2024-11-04"), // 6 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 8.1,
tinggiBadanCm: 67.5,
namaOrtu: "Ni Made Suciati",
alamat: "Banjar Melur, Desa Darmasaba",
noHpOrtu: "08123456823",
posyanduId: "posyandu_melur_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.NORMAL,
},
{
id: "balita_024",
nama: "Ni Wayan Arta Yanti",
nik: "5101014511230024",
tanggalLahir: new Date("2023-11-04"), // 18 bulan
jenisKelamin: JenisKelaminBalita.P,
beratBadanKg: 11.0,
tinggiBadanCm: 82.0,
namaOrtu: "I Wayan Suarsa",
alamat: "Banjar Kenanga, Desa Darmasaba",
noHpOrtu: "08123456824",
posyanduId: "posyandu_kenanga_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.NORMAL,
},
{
id: "balita_025",
nama: "Kadek Dika Permana",
nik: "5101014511220025",
tanggalLahir: new Date("2022-11-04"), // 30 bulan
jenisKelamin: JenisKelaminBalita.L,
beratBadanKg: 14.0,
tinggiBadanCm: 93.0,
namaOrtu: "Ni Kadek Suriati",
alamat: "Banjar Dahlia, Desa Darmasaba",
noHpOrtu: "08123456825",
posyanduId: "posyandu_dahlia_001",
imunisasiLengkap: true,
giziBaik: true,
pemeriksaanRutin: true,
statusStunting: StatusStunting.NORMAL,
},
];
export async function seedBalita() {
console.log("🔄 Seeding Balita...");
for (const d of BALITA_DATA) {
await prisma.balita.upsert({
where: { id: d.id },
update: {
nama: d.nama,
nik: d.nik,
tanggalLahir: d.tanggalLahir,
jenisKelamin: d.jenisKelamin,
beratBadanKg: d.beratBadanKg,
tinggiBadanCm: d.tinggiBadanCm,
namaOrtu: d.namaOrtu,
alamat: d.alamat,
noHpOrtu: d.noHpOrtu,
posyanduId: d.posyanduId,
imunisasiLengkap: d.imunisasiLengkap,
giziBaik: d.giziBaik,
pemeriksaanRutin: d.pemeriksaanRutin,
statusStunting: d.statusStunting,
catatan: d.catatan ?? null,
},
create: {
id: d.id,
nama: d.nama,
nik: d.nik,
tanggalLahir: d.tanggalLahir,
jenisKelamin: d.jenisKelamin,
beratBadanKg: d.beratBadanKg,
tinggiBadanCm: d.tinggiBadanCm,
namaOrtu: d.namaOrtu,
alamat: d.alamat,
noHpOrtu: d.noHpOrtu,
posyanduId: d.posyanduId,
imunisasiLengkap: d.imunisasiLengkap,
giziBaik: d.giziBaik,
pemeriksaanRutin: d.pemeriksaanRutin,
statusStunting: d.statusStunting,
catatan: d.catatan ?? null,
},
});
console.log(`✅ Balita seeded: ${d.nama} (${d.statusStunting})`);
}
console.log("🎉 Balita seed selesai");
}

View File

@@ -0,0 +1,222 @@
import prisma from "@/lib/prisma";
import { IbuHamilStatus } from "@prisma/client";
const IBU_HAMIL_DATA = [
{
id: "ibu_hamil_001",
nama: "Ni Wayan Sari Dewi",
nik: "5101014504960001",
usiaKehamilan: 28,
hpht: new Date("2025-10-20"),
taksiranLahir: new Date("2026-07-26"),
alamat: "Banjar Pudak, Desa Darmasaba",
noHp: "08123456701",
posyanduId: "cmkanjnmx0006vntz1cn7owpb",
status: IbuHamilStatus.AKTIF,
},
{
id: "ibu_hamil_002",
nama: "Ni Made Artini",
nik: "5101012808980002",
usiaKehamilan: 16,
hpht: new Date("2026-01-13"),
taksiranLahir: new Date("2026-10-20"),
alamat: "Banjar Mawar, Desa Darmasaba",
noHp: "08123456702",
posyanduId: "posyandu_mawar_001",
status: IbuHamilStatus.AKTIF,
},
{
id: "ibu_hamil_003",
nama: "Ni Putu Rahayu",
nik: "5101010109000003",
usiaKehamilan: 32,
hpht: new Date("2025-09-22"),
taksiranLahir: new Date("2026-06-29"),
alamat: "Banjar Melati, Desa Darmasaba",
noHp: "08123456703",
posyanduId: "posyandu_melati_001",
status: IbuHamilStatus.AKTIF,
},
{
id: "ibu_hamil_004",
nama: "Ni Komang Lestari",
nik: "5101011505010004",
usiaKehamilan: 8,
hpht: new Date("2026-03-10"),
taksiranLahir: new Date("2026-12-14"),
alamat: "Banjar Dahlia, Desa Darmasaba",
noHp: "08123456704",
posyanduId: "posyandu_dahlia_001",
status: IbuHamilStatus.AKTIF,
},
{
id: "ibu_hamil_005",
nama: "Ni Nyoman Suartini",
nik: "5101012012990005",
usiaKehamilan: 24,
hpht: new Date("2025-11-17"),
taksiranLahir: new Date("2026-08-24"),
alamat: "Banjar Anggrek, Desa Darmasaba",
noHp: "08123456705",
posyanduId: "posyandu_anggrek_001",
status: IbuHamilStatus.AKTIF,
},
{
id: "ibu_hamil_006",
nama: "Ni Ketut Suriani",
nik: "5101010307970006",
usiaKehamilan: 20,
hpht: new Date("2025-12-15"),
taksiranLahir: new Date("2026-09-21"),
alamat: "Banjar Kamboja, Desa Darmasaba",
noHp: "08123456706",
posyanduId: "posyandu_kamboja_001",
status: IbuHamilStatus.AKTIF,
},
{
id: "ibu_hamil_007",
nama: "Ni Wayan Rustini",
nik: "5101011806960007",
usiaKehamilan: 36,
hpht: new Date("2025-08-25"),
taksiranLahir: new Date("2026-06-01"),
alamat: "Banjar Melur, Desa Darmasaba",
noHp: "08123456707",
posyanduId: "posyandu_melur_001",
status: IbuHamilStatus.AKTIF,
catatan: "Tekanan darah perlu dipantau rutin",
},
{
id: "ibu_hamil_008",
nama: "Ni Made Sudiani",
nik: "5101010202020008",
usiaKehamilan: 12,
hpht: new Date("2026-02-10"),
taksiranLahir: new Date("2026-11-17"),
alamat: "Banjar Kenanga, Desa Darmasaba",
noHp: "08123456708",
posyanduId: "posyandu_kenanga_001",
status: IbuHamilStatus.AKTIF,
},
{
id: "ibu_hamil_009",
nama: "Ni Putu Yuliani",
nik: "5101011507980009",
usiaKehamilan: 28,
hpht: new Date("2025-10-20"),
taksiranLahir: new Date("2026-07-26"),
alamat: "Banjar Pudak, Desa Darmasaba",
noHp: "08123456709",
posyanduId: "cmkanjnmx0006vntz1cn7owpb",
status: IbuHamilStatus.AKTIF,
},
{
id: "ibu_hamil_010",
nama: "Ni Nyoman Darmayanti",
nik: "5101012309010010",
usiaKehamilan: 16,
hpht: new Date("2026-01-13"),
taksiranLahir: new Date("2026-10-20"),
alamat: "Banjar Mawar, Desa Darmasaba",
noHp: "08123456710",
posyanduId: "posyandu_mawar_001",
status: IbuHamilStatus.AKTIF,
catatan: "Anemia ringan, konsumsi suplemen zat besi",
},
{
id: "ibu_hamil_011",
nama: "Ni Wayan Purwati",
nik: "5101010905950011",
usiaKehamilan: 40,
hpht: new Date("2025-07-28"),
taksiranLahir: new Date("2026-05-04"),
alamat: "Banjar Melati, Desa Darmasaba",
noHp: "08123456711",
posyanduId: "posyandu_melati_001",
status: IbuHamilStatus.MELAHIRKAN,
catatan: "Melahirkan normal di Puskesmas Abiansemal 3",
},
{
id: "ibu_hamil_012",
nama: "Ni Made Suarningsih",
nik: "5101011403930012",
usiaKehamilan: 39,
hpht: new Date("2025-08-04"),
taksiranLahir: new Date("2026-05-11"),
alamat: "Banjar Dahlia, Desa Darmasaba",
noHp: "08123456712",
posyanduId: "posyandu_dahlia_001",
status: IbuHamilStatus.MELAHIRKAN,
},
{
id: "ibu_hamil_013",
nama: "Ni Komang Sugiantari",
nik: "5101012706010013",
usiaKehamilan: 10,
alamat: "Banjar Anggrek, Desa Darmasaba",
noHp: "08123456713",
posyanduId: "posyandu_anggrek_001",
status: IbuHamilStatus.KEGUGURAN,
catatan: "Keguguran pada usia kehamilan 10 minggu, sudah ditangani",
},
{
id: "ibu_hamil_014",
nama: "Ni Putu Aryanti",
nik: "5101010508940014",
usiaKehamilan: 0,
alamat: "Banjar Kamboja, Desa Darmasaba",
noHp: "08123456714",
posyanduId: "posyandu_kamboja_001",
status: IbuHamilStatus.NONAKTIF,
catatan: "Data lama, tidak aktif terdaftar",
},
{
id: "ibu_hamil_015",
nama: "Ni Ketut Suparmi",
nik: "5101011912920015",
usiaKehamilan: 0,
alamat: "Banjar Melur, Desa Darmasaba",
noHp: "08123456715",
posyanduId: "posyandu_melur_001",
status: IbuHamilStatus.NONAKTIF,
},
];
export async function seedIbuHamil() {
console.log("🔄 Seeding Ibu Hamil...");
for (const d of IBU_HAMIL_DATA) {
await prisma.ibuHamil.upsert({
where: { id: d.id },
update: {
nama: d.nama,
nik: d.nik,
usiaKehamilan: d.usiaKehamilan,
hpht: d.hpht ?? null,
taksiranLahir: d.taksiranLahir ?? null,
alamat: d.alamat,
noHp: d.noHp,
posyanduId: d.posyanduId,
status: d.status,
catatan: d.catatan ?? null,
},
create: {
id: d.id,
nama: d.nama,
nik: d.nik,
usiaKehamilan: d.usiaKehamilan,
hpht: d.hpht ?? null,
taksiranLahir: d.taksiranLahir ?? null,
alamat: d.alamat,
noHp: d.noHp,
posyanduId: d.posyanduId,
status: d.status,
catatan: d.catatan ?? null,
},
});
console.log(`✅ Ibu hamil seeded: ${d.nama} (${d.status})`);
}
console.log("🎉 Ibu Hamil seed selesai");
}

View File

@@ -7,17 +7,8 @@ export async function seedRingkasanKesehatan() {
await prisma.ringkasanKesehatanDesa.upsert({
where: { id: SINGLETON_ID },
update: {
ibuHamilAkh: 87,
balitaTerdaftar: 342,
alertStunting: 12,
},
create: {
id: SINGLETON_ID,
ibuHamilAkh: 87,
balitaTerdaftar: 342,
alertStunting: 12,
},
update: { targetStuntingPct: 10 },
create: { id: SINGLETON_ID, targetStuntingPct: 10 },
});
console.log("✅ Ringkasan Kesehatan Desa seeded");

View File

@@ -0,0 +1,9 @@
-- Drop redundant columns from RingkasanKesehatanDesa.
-- These values are auto-derived live from IbuHamil + Balita tables (see stats endpoint).
-- Only targetStuntingPct is a policy config that needs to be stored.
ALTER TABLE "RingkasanKesehatanDesa" DROP COLUMN "ibuHamilAkh";
ALTER TABLE "RingkasanKesehatanDesa" DROP COLUMN "balitaTerdaftar";
ALTER TABLE "RingkasanKesehatanDesa" DROP COLUMN "alertStunting";
ALTER TABLE "RingkasanKesehatanDesa" DROP COLUMN "imunisasiLengkapPct";
ALTER TABLE "RingkasanKesehatanDesa" DROP COLUMN "pemeriksaanRutinPct";
ALTER TABLE "RingkasanKesehatanDesa" DROP COLUMN "giziBaikPct";

View File

@@ -2546,16 +2546,10 @@ model Balita {
// ========================================= RINGKASAN KESEHATAN DESA ========================================= //
model RingkasanKesehatanDesa {
id String @id @default(cuid())
ibuHamilAkh Int @default(0)
balitaTerdaftar Int @default(0)
alertStunting Int @default(0)
imunisasiLengkapPct Int @default(0)
pemeriksaanRutinPct Int @default(0)
giziBaikPct Int @default(0)
targetStuntingPct Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
isActive Boolean @default(true)
id String @id @default(cuid())
targetStuntingPct Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
isActive Boolean @default(true)
}

View File

@@ -48,6 +48,8 @@ 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 { 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";
import { seedDesaAntiKorupsi } from "./_seeder_list/landing-page/desa-anti-korupsi/seed_desa_anti_korupsi";
import { seedPrestasiDesa } from "./_seeder_list/landing-page/prestasi-desa/seed_prestasi_desa";
import { seedMediaSosial } from "./_seeder_list/landing-page/profil_landing_page/seed_media_sosial";
@@ -244,6 +246,10 @@ import seedAssets from "./seed_assets";
// // ==================== SUBMENU POSYANDU =========================
await seedPosyandu();
// // ==================== SUBMENU IBU HAMIL + BALITA =========================
await seedIbuHamil();
await seedBalita();
// // ==================== SUBMENU PUSKESMAS =========================
await seedPuskesmas();

View File

@@ -1,4 +1,3 @@
import { Prisma } from "@prisma/client";
import { toast } from "react-toastify";
import { proxy } from "valtio";
import { z } from "zod";
@@ -19,33 +18,7 @@ const intPct = z
.min(0, { message: "Minimal 0" })
.max(100, { message: "Maksimal 100" });
const intCount = z
.number({ invalid_type_error: "Harus berupa angka" })
.int({ message: "Harus bilangan bulat" })
.min(0, { message: "Minimal 0" });
const templateForm = z.object({
ibuHamilAkh: intCount,
balitaTerdaftar: intCount,
alertStunting: intCount,
imunisasiLengkapPct: intPct,
pemeriksaanRutinPct: intPct,
giziBaikPct: intPct,
targetStuntingPct: intPct,
});
const defaultForm = {
ibuHamilAkh: 0,
balitaTerdaftar: 0,
alertStunting: 0,
imunisasiLengkapPct: 0,
pemeriksaanRutinPct: 0,
giziBaikPct: 0,
targetStuntingPct: 0,
};
const ringkasanKesehatanState = proxy({
// Derived stats aggregated from IbuHamil + Balita tables
findStats: {
data: null as StatsData | null,
loading: false,
@@ -57,7 +30,8 @@ const ringkasanKesehatanState = proxy({
const result = await res.json();
ringkasanKesehatanState.findStats.data = result?.data ?? null;
if (result?.data) {
ringkasanKesehatanState.update.form.targetStuntingPct = result.data.targetStuntingPct;
ringkasanKesehatanState.update.form.targetStuntingPct =
result.data.targetStuntingPct;
}
} else {
ringkasanKesehatanState.findStats.data = null;
@@ -71,42 +45,8 @@ const ringkasanKesehatanState = proxy({
},
},
// Kept for backward-compat — now only used internally for targetStuntingPct config
findUnique: {
data: null as Prisma.RingkasanKesehatanDesaGetPayload<object> | null,
loading: false,
async load() {
try {
ringkasanKesehatanState.findUnique.loading = true;
const res = await fetch(`/api/kesehatan/ringkasankesehatan/find`);
if (res.ok) {
const result = await res.json();
ringkasanKesehatanState.findUnique.data = result?.data ?? null;
if (result?.data) {
ringkasanKesehatanState.update.form = {
ibuHamilAkh: result.data.ibuHamilAkh,
balitaTerdaftar: result.data.balitaTerdaftar,
alertStunting: result.data.alertStunting,
imunisasiLengkapPct: result.data.imunisasiLengkapPct,
pemeriksaanRutinPct: result.data.pemeriksaanRutinPct,
giziBaikPct: result.data.giziBaikPct,
targetStuntingPct: result.data.targetStuntingPct,
};
}
} else {
ringkasanKesehatanState.findUnique.data = null;
}
} catch (error) {
console.error("Error fetching ringkasan kesehatan:", error);
ringkasanKesehatanState.findUnique.data = null;
} finally {
ringkasanKesehatanState.findUnique.loading = false;
}
},
},
update: {
form: { ...defaultForm },
form: { targetStuntingPct: 0 },
loading: false,
async submitTarget() {
const pct = ringkasanKesehatanState.update.form.targetStuntingPct;
@@ -120,7 +60,7 @@ const ringkasanKesehatanState = proxy({
const response = await fetch(`/api/kesehatan/ringkasankesehatan/update`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(ringkasanKesehatanState.update.form),
body: JSON.stringify({ targetStuntingPct: pct }),
});
const result = await response.json();
if (result.success) {
@@ -138,41 +78,6 @@ const ringkasanKesehatanState = proxy({
ringkasanKesehatanState.update.loading = false;
}
},
// Kept for backward-compat (full update)
async submit() {
const cek = templateForm.safeParse(ringkasanKesehatanState.update.form);
if (!cek.success) {
const err = `[${cek.error.issues
.map((v) => `${v.path.join(".")}`)
.join("\n")}] invalid`;
toast.error(err);
return false;
}
try {
ringkasanKesehatanState.update.loading = true;
const response = await fetch(`/api/kesehatan/ringkasankesehatan/update`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(ringkasanKesehatanState.update.form),
});
const result = await response.json();
if (result.success) {
toast.success(result.message || "Berhasil disimpan");
await ringkasanKesehatanState.findUnique.load();
return true;
}
throw new Error(result.message || "Gagal menyimpan");
} catch (error) {
console.error("Error updating ringkasan kesehatan:", error);
toast.error(error instanceof Error ? error.message : "Gagal menyimpan");
return false;
} finally {
ringkasanKesehatanState.update.loading = false;
}
},
reset() {
ringkasanKesehatanState.update.form = { ...defaultForm };
},
},
});

View File

@@ -24,7 +24,7 @@ import {
IconAlertTriangle,
} from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
import { useEffect, useCallback } from 'react';
import { useProxy } from 'valtio/utils';
import ringkasanKesehatanState from '../../_state/kesehatan/ringkasan-kesehatan/ringkasanKesehatan';
@@ -71,13 +71,8 @@ export default function RingkasanKesehatanPage() {
const state = useProxy(ringkasanKesehatanState);
const stats = state.findStats.data;
useEffect(() => {
state.findStats.load();
}, []); // eslint-disable-line react-hooks/exhaustive-deps
const handleSaveTarget = async () => {
await state.update.submitTarget();
};
const loadStats = useCallback(() => { ringkasanKesehatanState.findStats.load(); }, []);
useEffect(() => { loadStats(); }, [loadStats]);
const isLoading = state.findStats.loading;
@@ -175,7 +170,7 @@ export default function RingkasanKesehatanPage() {
style={{ flex: 1 }}
/>
<Button
onClick={handleSaveTarget}
onClick={() => state.update.submitTarget()}
radius="md"
disabled={state.update.loading}
style={{

View File

@@ -8,12 +8,6 @@ const RingkasanKesehatan = new Elysia({ prefix: "/ringkasankesehatan", tags: ["K
.get("/stats", ringkasanKesehatanStats)
.put("/update", ringkasanKesehatanUpdate, {
body: t.Object({
ibuHamilAkh: t.Number(),
balitaTerdaftar: t.Number(),
alertStunting: t.Number(),
imunisasiLengkapPct: t.Number({ minimum: 0, maximum: 100 }),
pemeriksaanRutinPct: t.Number({ minimum: 0, maximum: 100 }),
giziBaikPct: t.Number({ minimum: 0, maximum: 100 }),
targetStuntingPct: t.Number({ minimum: 0, maximum: 100 }),
}),
});

View File

@@ -1,45 +1,28 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma";
import { Context } from "elysia";
async function ringkasanKesehatanUpdate(context: Context) {
const body = context.body as any;
const body = context.body as { targetStuntingPct: number };
try {
const existing = await prisma.ringkasanKesehatanDesa.findFirst({
where: { isActive: true },
orderBy: { createdAt: 'desc' },
orderBy: { createdAt: "desc" },
});
const data = existing
? await prisma.ringkasanKesehatanDesa.update({
where: { id: existing.id },
data: {
ibuHamilAkh: Number(body.ibuHamilAkh),
balitaTerdaftar: Number(body.balitaTerdaftar),
alertStunting: Number(body.alertStunting),
imunisasiLengkapPct: Number(body.imunisasiLengkapPct),
pemeriksaanRutinPct: Number(body.pemeriksaanRutinPct),
giziBaikPct: Number(body.giziBaikPct),
targetStuntingPct: Number(body.targetStuntingPct),
},
data: { targetStuntingPct: Number(body.targetStuntingPct) },
})
: await prisma.ringkasanKesehatanDesa.create({
data: {
ibuHamilAkh: Number(body.ibuHamilAkh),
balitaTerdaftar: Number(body.balitaTerdaftar),
alertStunting: Number(body.alertStunting),
imunisasiLengkapPct: Number(body.imunisasiLengkapPct),
pemeriksaanRutinPct: Number(body.pemeriksaanRutinPct),
giziBaikPct: Number(body.giziBaikPct),
targetStuntingPct: Number(body.targetStuntingPct),
},
data: { targetStuntingPct: Number(body.targetStuntingPct) },
});
return { success: true, message: "Ringkasan kesehatan berhasil disimpan", data };
return { success: true, message: "Target stunting berhasil disimpan", data };
} catch (e) {
console.error("Error di ringkasanKesehatanUpdate:", e);
return { success: false, message: "Gagal menyimpan ringkasan kesehatan" };
return { success: false, message: "Gagal menyimpan target stunting" };
}
}