- {/* Peta Keamanan CCTV */}
-
-
-
- Peta Keamanan CCTV
-
-
- Titik Lokasi CCTV
-
-
- {/* Placeholder for map */}
-
-
-
- Peta Lokasi CCTV
-
- Integrasi dengan Google Maps atau Mapbox akan ditampilkan di
- sini
-
-
-
-
- {/* CCTV Locations List */}
-
-
- Daftar CCTV
+
+ Peta Keamanan CCTV
- {cctvLocations.map((cctv, index) => (
-
-
-
-
-
- {cctv.id}
+
+ Titik Lokasi CCTV
+
+
+ {/* Placeholder for map */}
+
+
+
+ Peta Lokasi CCTV
+
+ Integrasi dengan Google Maps atau Mapbox akan ditampilkan di
+ sini
+
+
+
+
+ {/* CCTV Locations List */}
+
+
+ Daftar CCTV
+
+ {cctvLocations.map((cctv, index) => (
+
+
+
+
+
+ {cctv.id}
+
+
+ {cctv.status === "active" ? "Online" : "Offline"}
+
+
+
+ {cctv.location}
+
+
+
+
+
+ {cctv.lastSeen}
-
- {cctv.status === "active" ? "Online" : "Offline"}
-
-
- {cctv.location}
-
-
-
-
-
- {cctv.lastSeen}
-
-
-
- ))}
-
-
+
+ ))}
+
+
+
{/* Daftar Laporan Keamanan */}
diff --git a/src/components/sosial-page.tsx b/src/components/sosial-page.tsx
index c313fac..24c2fd6 100644
--- a/src/components/sosial-page.tsx
+++ b/src/components/sosial-page.tsx
@@ -1,463 +1,45 @@
-import {
- Badge,
- Card,
- Grid,
- GridCol,
- Group,
- List,
- Progress,
- Stack,
- Text,
- ThemeIcon,
- Title,
- useMantineColorScheme,
-} from "@mantine/core";
-import {
- IconAward,
- IconBabyCarriage,
- IconBook,
- IconCalendarEvent,
- IconHeartbeat,
- IconMedicalCross,
- IconSchool,
- IconStethoscope,
-} from "@tabler/icons-react";
-import { useState } from "react";
+import { Grid, GridCol, Stack } from "@mantine/core";
+import { SummaryCards } from "./sosial/summary-cards";
+import { HealthStats } from "./sosial/health-stats";
+import { PosyanduSchedule } from "./sosial/posyandu-schedule";
+import { Pendidikan } from "./sosial/pendidikan";
+import { Beasiswa } from "./sosial/beasiswa";
+import { EventCalendar } from "./sosial/event-calendar";
const SosialPage = () => {
- const { colorScheme } = useMantineColorScheme();
- const dark = colorScheme === "dark";
-
- // Sample data for health statistics
- const healthStats = {
- ibuHamil: 87,
- balita: 342,
- alertStunting: 12,
- posyanduAktif: 8,
- };
-
- // Sample data for health progress
- const healthProgress = [
- { label: "Imunisasi Lengkap", value: 92, color: "green" },
- { label: "Pemeriksaan Rutin", value: 88, color: "blue" },
- { label: "Gizi Baik", value: 86, color: "teal" },
- { label: "Target Stunting", value: 14, color: "red" },
- ];
-
- // Sample data for posyandu schedule
- const posyanduSchedule = [
- {
- nama: "Posyandu Mawar",
- tanggal: "Senin, 15 Feb 2026",
- jam: "08:00 - 11:00",
- },
- {
- nama: "Posyandu Melati",
- tanggal: "Selasa, 16 Feb 2026",
- jam: "08:00 - 11:00",
- },
- {
- nama: "Posyandu Dahlia",
- tanggal: "Rabu, 17 Feb 2026",
- jam: "08:00 - 11:00",
- },
- {
- nama: "Posyandu Anggrek",
- tanggal: "Kamis, 18 Feb 2026",
- jam: "08:00 - 11:00",
- },
- ];
-
- // Sample data for education stats
- const educationStats = {
- siswa: {
- tk: 125,
- sd: 480,
- smp: 210,
- sma: 150,
- },
- sekolah: {
- jumlah: 8,
- guru: 42,
- },
- };
-
- // Sample data for scholarships
- const scholarshipData = {
- penerima: 45,
- dana: "Rp 1.200.000.000",
- tahunAjaran: "2025/2026",
- };
-
- // Sample data for cultural events
- const culturalEvents = [
- {
- nama: "Hari Kesaktian Pancasila",
- tanggal: "1 Oktober 2025",
- lokasi: "Balai Desa",
- },
- {
- nama: "Festival Budaya Desa",
- tanggal: "20 Mei 2026",
- lokasi: "Lapangan Desa",
- },
- {
- nama: "Perayaan HUT Desa",
- tanggal: "17 Agustus 2026",
- lokasi: "Balai Desa",
- },
- ];
-
return (
- {/* Health Statistics Cards */}
+ {/* Top Summary Cards - 4 Grid */}
+
+
+ {/* Second Row - 2 Column Grid */}
-
-
-
-
-
- Ibu Hamil Aktif
-
-
- {healthStats.ibuHamil}
-
-
-
-
-
-
-
+ {/* Left - Statistik Kesehatan */}
+
+
-
-
-
-
-
- Balita Terdaftar
-
-
- {healthStats.balita}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Alert Stunting
-
-
- {healthStats.alertStunting}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Posyandu Aktif
-
-
- {healthStats.posyanduAktif}
-
-
-
-
-
-
-
+ {/* Right - Jadwal Posyandu */}
+
+
- {/* Health Progress Bars */}
-
-
- Statistik Kesehatan
-
-
- {healthProgress.map((item, index) => (
-
-
-
- {item.label}
-
-
- {item.value}%
-
-
-
-
- ))}
-
-
-
+ {/* Third Row - 2 Column Grid */}
- {/* Jadwal Posyandu */}
+ {/* Left - Pendidikan */}
-
-
- Jadwal Posyandu
-
-
- {posyanduSchedule.map((item, index) => (
-
-
-
-
- {item.nama}
-
-
- {item.tanggal}
-
-
-
- {item.jam}
-
-
-
- ))}
-
-
+
- {/* Pendidikan */}
+ {/* Right - Beasiswa Desa */}
-
-
- Pendidikan
-
-
-
-
- TK / PAUD
-
-
- {educationStats.siswa.tk}
-
-
-
-
- SD
-
-
- {educationStats.siswa.sd}
-
-
-
-
- SMP
-
-
- {educationStats.siswa.smp}
-
-
-
-
- SMA
-
-
- {educationStats.siswa.sma}
-
-
-
-
-
-
- Jumlah Lembaga Pendidikan
-
-
- {educationStats.sekolah.jumlah}
-
-
-
-
- Jumlah Tenaga Pengajar
-
-
- {educationStats.sekolah.guru}
-
-
-
-
-
+
-
- {/* Beasiswa Desa */}
-
-
-
-
-
- Beasiswa Desa
-
-
- Penerima: {scholarshipData.penerima}
-
-
-
-
-
-
-
- Dana Tersalurkan:{" "}
-
- {scholarshipData.dana}
-
-
-
- Tahun Ajaran: {scholarshipData.tahunAjaran}
-
-
-
-
- {/* Kalender Event Budaya */}
-
-
-
- Kalender Event Budaya
-
-
- {culturalEvents.map((event, index) => (
-
-
-
- }
- >
-
-
- {event.nama}
-
-
- {event.lokasi}
-
-
-
- {event.tanggal}
-
-
- ))}
-
-
-
-
+ {/* Bottom Section - Event Budaya */}
+
);
};
diff --git a/src/components/sosial/beasiswa.tsx b/src/components/sosial/beasiswa.tsx
new file mode 100644
index 0000000..79ab93c
--- /dev/null
+++ b/src/components/sosial/beasiswa.tsx
@@ -0,0 +1,69 @@
+import { Card, Group, Stack, Text, ThemeIcon, Title } from "@mantine/core";
+import { useMantineColorScheme } from "@mantine/core";
+import { IconAward } from "@tabler/icons-react";
+
+interface ScholarshipData {
+ penerima: number;
+ dana: string;
+ tahunAjaran: string;
+}
+
+interface BeasiswaProps {
+ data?: ScholarshipData;
+}
+
+export const Beasiswa = ({ data }: BeasiswaProps) => {
+ const { colorScheme } = useMantineColorScheme();
+ const dark = colorScheme === "dark";
+
+ const defaultData: ScholarshipData = {
+ penerima: 45,
+ dana: "Rp 1.200.000.000",
+ tahunAjaran: "2025/2026",
+ };
+
+ const displayData = data || defaultData;
+
+ return (
+
+
+
+
+ Beasiswa Desa
+
+
+ Penerima: {displayData.penerima}
+
+
+
+
+
+
+
+
+ Dana Tersalurkan:
+
+ {displayData.dana}
+
+
+
+ Tahun Ajaran:
+ {displayData.tahunAjaran}
+
+
+
+ );
+};
diff --git a/src/components/sosial/event-calendar.tsx b/src/components/sosial/event-calendar.tsx
new file mode 100644
index 0000000..92d72ee
--- /dev/null
+++ b/src/components/sosial/event-calendar.tsx
@@ -0,0 +1,94 @@
+import { Card, Group, Stack, Text, Title, ThemeIcon } from "@mantine/core";
+import { useMantineColorScheme } from "@mantine/core";
+import { IconCalendarEvent } from "@tabler/icons-react";
+
+interface EventItem {
+ id: string;
+ nama: string;
+ tanggal: string;
+ lokasi: string;
+}
+
+interface EventCalendarProps {
+ data?: EventItem[];
+}
+
+export const EventCalendar = ({ data }: EventCalendarProps) => {
+ const { colorScheme } = useMantineColorScheme();
+ const dark = colorScheme === "dark";
+
+ const defaultData: EventItem[] = [
+ {
+ id: "1",
+ nama: "Hari Kesaktian Pancasila",
+ tanggal: "1 Oktober 2025",
+ lokasi: "Balai Desa",
+ },
+ {
+ id: "2",
+ nama: "Festival Budaya Desa",
+ tanggal: "20 Mei 2026",
+ lokasi: "Lapangan Desa",
+ },
+ {
+ id: "3",
+ nama: "Perayaan HUT Desa",
+ tanggal: "17 Agustus 2026",
+ lokasi: "Balai Desa",
+ },
+ ];
+
+ const displayData = data || defaultData;
+
+ return (
+
+
+ Kalender Event Budaya
+
+
+ {displayData.map((event) => (
+
+
+
+
+
+
+
+ {event.nama}
+
+
+
+ {event.lokasi}
+
+
+
+
+ {event.tanggal}
+
+
+
+ ))}
+
+
+ );
+};
diff --git a/src/components/sosial/health-stats.tsx b/src/components/sosial/health-stats.tsx
new file mode 100644
index 0000000..8dca29d
--- /dev/null
+++ b/src/components/sosial/health-stats.tsx
@@ -0,0 +1,66 @@
+import { Card, Group, Progress, Stack, Text, Title } from "@mantine/core";
+import { useMantineColorScheme } from "@mantine/core";
+
+interface HealthProgressItem {
+ label: string;
+ value: number;
+ color: string;
+}
+
+interface HealthStatsProps {
+ data?: HealthProgressItem[];
+}
+
+export const HealthStats = ({ data }: HealthStatsProps) => {
+ const { colorScheme } = useMantineColorScheme();
+ const dark = colorScheme === "dark";
+
+ const defaultData: HealthProgressItem[] = [
+ { label: "Imunisasi Lengkap", value: 92, color: "green" },
+ { label: "Pemeriksaan Rutin", value: 88, color: "blue" },
+ { label: "Gizi Baik", value: 86, color: "teal" },
+ { label: "Target Stunting", value: 14, color: "red" },
+ ];
+
+ const displayData = data || defaultData;
+
+ return (
+
+
+ Statistik Kesehatan
+
+
+ {displayData.map((item, index) => (
+
+
+
+ {item.label}
+
+
+ {item.value}%
+
+
+
+
+ ))}
+
+
+ );
+};
diff --git a/src/components/sosial/pendidikan.tsx b/src/components/sosial/pendidikan.tsx
new file mode 100644
index 0000000..b3afc60
--- /dev/null
+++ b/src/components/sosial/pendidikan.tsx
@@ -0,0 +1,114 @@
+import { Card, Group, Stack, Text, Title } from "@mantine/core";
+import { useMantineColorScheme } from "@mantine/core";
+
+interface EducationData {
+ siswa: {
+ tk: number;
+ sd: number;
+ smp: number;
+ sma: number;
+ };
+ sekolah: {
+ jumlah: number;
+ guru: number;
+ };
+}
+
+interface PendidikanProps {
+ data?: EducationData;
+}
+
+export const Pendidikan = ({ data }: PendidikanProps) => {
+ const { colorScheme } = useMantineColorScheme();
+ const dark = colorScheme === "dark";
+
+ const defaultData: EducationData = {
+ siswa: {
+ tk: 125,
+ sd: 480,
+ smp: 210,
+ sma: 150,
+ },
+ sekolah: {
+ jumlah: 8,
+ guru: 42,
+ },
+ };
+
+ const displayData = data || defaultData;
+
+ return (
+
+
+ Pendidikan
+
+
+
+
+ TK / PAUD
+
+
+ {displayData.siswa.tk}
+
+
+
+
+ SD
+
+
+ {displayData.siswa.sd}
+
+
+
+
+ SMP
+
+
+ {displayData.siswa.smp}
+
+
+
+
+ SMA
+
+
+ {displayData.siswa.sma}
+
+
+
+
+
+
+ Jumlah Lembaga Pendidikan
+
+
+ {displayData.sekolah.jumlah}
+
+
+
+
+ Jumlah Tenaga Pengajar
+
+
+ {displayData.sekolah.guru}
+
+
+
+
+
+ );
+};
diff --git a/src/components/sosial/posyandu-schedule.tsx b/src/components/sosial/posyandu-schedule.tsx
new file mode 100644
index 0000000..e180c4d
--- /dev/null
+++ b/src/components/sosial/posyandu-schedule.tsx
@@ -0,0 +1,89 @@
+import { Badge, Card, Group, Stack, Text, Title } from "@mantine/core";
+import { useMantineColorScheme } from "@mantine/core";
+
+interface PosyanduItem {
+ id: string;
+ nama: string;
+ tanggal: string;
+ jam: string;
+}
+
+interface PosyanduScheduleProps {
+ data?: PosyanduItem[];
+}
+
+export const PosyanduSchedule = ({ data }: PosyanduScheduleProps) => {
+ const { colorScheme } = useMantineColorScheme();
+ const dark = colorScheme === "dark";
+
+ const defaultData: PosyanduItem[] = [
+ {
+ id: "1",
+ nama: "Posyandu Mawar",
+ tanggal: "Senin, 15 Feb 2026",
+ jam: "08:00 - 11:00",
+ },
+ {
+ id: "2",
+ nama: "Posyandu Melati",
+ tanggal: "Selasa, 16 Feb 2026",
+ jam: "08:00 - 11:00",
+ },
+ {
+ id: "3",
+ nama: "Posyandu Dahlia",
+ tanggal: "Rabu, 17 Feb 2026",
+ jam: "08:00 - 11:00",
+ },
+ {
+ id: "4",
+ nama: "Posyandu Anggrek",
+ tanggal: "Kamis, 18 Feb 2026",
+ jam: "08:00 - 11:00",
+ },
+ ];
+
+ const displayData = data || defaultData;
+
+ return (
+
+
+ Jadwal Posyandu
+
+
+ {displayData.map((item) => (
+
+
+
+
+ {item.nama}
+
+
+ {item.tanggal}
+
+
+
+ {item.jam}
+
+
+
+ ))}
+
+
+ );
+};
diff --git a/src/components/sosial/summary-cards.tsx b/src/components/sosial/summary-cards.tsx
new file mode 100644
index 0000000..1268969
--- /dev/null
+++ b/src/components/sosial/summary-cards.tsx
@@ -0,0 +1,132 @@
+import { Card, Grid, GridCol, Group, Stack, Text, ThemeIcon } from "@mantine/core";
+import { useMantineColorScheme } from "@mantine/core";
+import {
+ IconBabyCarriage,
+ IconHeartbeat,
+ IconMedicalCross,
+ IconStethoscope,
+} from "@tabler/icons-react";
+
+interface SummaryCardProps {
+ title: string;
+ value: number;
+ subtitle?: string;
+ icon: React.ReactNode;
+ color: string;
+ highlight?: boolean;
+ backgroundColor: string;
+}
+
+const SummaryCard = ({
+ title,
+ value,
+ subtitle,
+ icon,
+ color,
+ highlight = false,
+ backgroundColor,
+}: SummaryCardProps) => {
+ const { colorScheme } = useMantineColorScheme();
+ const dark = colorScheme === "dark";
+
+ return (
+
+
+
+
+ {title}
+
+
+ {value}
+
+ {subtitle && (
+
+ {subtitle}
+
+ )}
+
+
+ {icon}
+
+
+
+ );
+};
+
+interface HealthSummaryData {
+ ibuHamil: number;
+ balita: number;
+ alertStunting: number;
+ posyanduAktif: number;
+}
+
+interface SummaryCardsProps {
+ data?: HealthSummaryData;
+}
+
+export const SummaryCards = ({ data }: SummaryCardsProps) => {
+ const defaultData: HealthSummaryData = {
+ ibuHamil: 87,
+ balita: 342,
+ alertStunting: 12,
+ posyanduAktif: 8,
+ };
+
+ const displayData = data || defaultData;
+
+ return (
+
+
+ }
+ color= "white"
+ backgroundColor= "#1E3A5F"
+ />
+
+
+ }
+ color= "white"
+ backgroundColor= "#1E3A5F"
+ />
+
+
+ }
+ color= "white"
+ backgroundColor= "#1E3A5F"
+ />
+
+
+ }
+ color= "white"
+ backgroundColor= "#1E3A5F"
+ />
+
+
+ );
+};
diff --git a/src/components/ui/help-card.tsx b/src/components/ui/help-card.tsx
index 08f2448..30f1351 100644
--- a/src/components/ui/help-card.tsx
+++ b/src/components/ui/help-card.tsx
@@ -52,8 +52,8 @@ export const HelpCard = ({
({
+ selectedYear: new Date().getFullYear().toString(),
+ filters: {
+ dusun: null,
+ kategori: null,
+ },
+});
+
+export const setYear = (year: SelectedYear) => {
+ sosialStore.selectedYear = year;
+};
+
+export const setFilter = (
+ key: keyof SosialState["filters"],
+ value: string | null,
+) => {
+ sosialStore.filters[key] = value;
+};