Merge branch 'stg' into nico/27-feb-26/fix-gambar

This commit is contained in:
2026-03-12 14:47:03 +08:00
committed by GitHub
31 changed files with 3612 additions and 3757 deletions

View File

@@ -1,465 +1,477 @@
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,
IconUsers,
} from "@tabler/icons-react";
import { useState } from "react";
import { useMantineColorScheme, Title } from "@mantine/core";
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" },
// Health statistics data
const healthStats = [
{
title: "Ibu Hamil Aktif",
value: "87",
subtitle: "Aktif",
icon: IconHeartbeat,
},
{
title: "Balita Terdaftar",
value: "342",
subtitle: "Terdaftar",
icon: IconBabyCarriage,
},
{
title: "Alert Stunting",
value: "12",
subtitle: "Perlu perhatian",
icon: IconStethoscope,
alert: true,
},
{
title: "Posyandu Aktif",
value: "8",
subtitle: "Beroperasi",
icon: IconMedicalCross,
},
];
// Sample data for posyandu schedule
// Health progress data
const healthProgress = [
{ label: "Imunisasi Lengkap", value: 92 },
{ label: "Pemeriksaan Rutin", value: 88 },
{ label: "Gizi Baik", value: 86 },
{ label: "Target Stunting", value: 14, isAlert: true },
];
// Posyandu schedule data
const posyanduSchedule = [
{
nama: "Posyandu Mawar",
tanggal: "Senin, 15 Feb 2026",
nama: "Posyandu Barat",
tanggal: "5 Oktober 2025",
jam: "08:00 - 11:00",
},
{
nama: "Posyandu Melati",
tanggal: "Selasa, 16 Feb 2026",
nama: "Posyandu Timur",
tanggal: "6 Oktober 2025",
jam: "08:00 - 11:00",
},
{
nama: "Posyandu Dahlia",
tanggal: "Rabu, 17 Feb 2026",
nama: "Posyandu Utara",
tanggal: "7 Oktober 2025",
jam: "08:00 - 11:00",
},
{
nama: "Posyandu Anggrek",
tanggal: "Kamis, 18 Feb 2026",
nama: "Posyandu Selatan",
tanggal: "8 Oktober 2025",
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,
},
};
// Education stats data
const educationStats = [
{ level: "TK / PAUD", value: "500" },
{ level: "Siswa SD", value: "458" },
{ level: "Siswa SMP", value: "234" },
{ level: "Siswa SMA", value: "189" },
];
// Sample data for scholarships
// School info data
const schoolInfo = [
{ label: "Lembaga Pendidikan", value: "10" },
{ label: "Tenaga Pengajar", value: "3" },
];
// Scholarship data
const scholarshipData = {
penerima: 45,
dana: "Rp 1.200.000.000",
penerima: "250+",
dana: "1.5M",
tahunAjaran: "2025/2026",
};
// Sample data for cultural events
// Cultural events data
const culturalEvents = [
{
nama: "Hari Kesaktian Pancasila",
tanggal: "1 Oktober 2025",
lokasi: "Balai Desa",
},
{
nama: "Festival Budaya Desa",
tanggal: "20 Mei 2026",
nama: "Lomba Baris Berbaris",
tanggal: "1 Desember 2025",
lokasi: "Lapangan Desa",
},
{
nama: "Perayaan HUT Desa",
tanggal: "17 Agustus 2026",
lokasi: "Balai Desa",
nama: "Lomba Tari Tradisional",
tanggal: "10 Desember 2025",
lokasi: "Banjar Desa",
},
{
nama: "Davoz",
tanggal: "20 Desember 2025",
lokasi: "Kantor Desa",
},
];
return (
<Stack gap="lg">
{/* Health Statistics Cards */}
<Grid gutter="md">
<GridCol span={{ base: 12, sm: 6, md: 3 }}>
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
>
<Group justify="space-between" align="center">
<Stack gap={0}>
<Text size="sm" c={dark ? "dark.3" : "dimmed"}>
Ibu Hamil Aktif
</Text>
<Text size="xl" fw={700} c={dark ? "dark.0" : "black"}>
{healthStats.ibuHamil}
</Text>
</Stack>
<ThemeIcon
variant="light"
color="darmasaba-blue"
size="xl"
radius="xl"
>
<IconHeartbeat size={24} />
</ThemeIcon>
</Group>
</Card>
</GridCol>
<GridCol span={{ base: 12, sm: 6, md: 3 }}>
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
>
<Group justify="space-between" align="center">
<Stack gap={0}>
<Text size="sm" c={dark ? "dark.3" : "dimmed"}>
Balita Terdaftar
</Text>
<Text size="xl" fw={700} c={dark ? "dark.0" : "black"}>
{healthStats.balita}
</Text>
</Stack>
<ThemeIcon
variant="light"
color="darmasaba-success"
size="xl"
radius="xl"
>
<IconBabyCarriage size={24} />
</ThemeIcon>
</Group>
</Card>
</GridCol>
<GridCol span={{ base: 12, sm: 6, md: 3 }}>
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
>
<Group justify="space-between" align="center">
<Stack gap={0}>
<Text size="sm" c={dark ? "dark.3" : "dimmed"}>
Alert Stunting
</Text>
<Text size="xl" fw={700} c="red">
{healthStats.alertStunting}
</Text>
</Stack>
<ThemeIcon variant="light" color="red" size="xl" radius="xl">
<IconStethoscope size={24} />
</ThemeIcon>
</Group>
</Card>
</GridCol>
<GridCol span={{ base: 12, sm: 6, md: 3 }}>
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
>
<Group justify="space-between" align="center">
<Stack gap={0}>
<Text size="sm" c={dark ? "dark.3" : "dimmed"}>
Posyandu Aktif
</Text>
<Text size="xl" fw={700} c={dark ? "dark.0" : "black"}>
{healthStats.posyanduAktif}
</Text>
</Stack>
<ThemeIcon
variant="light"
color="darmasaba-warning"
size="xl"
radius="xl"
>
<IconMedicalCross size={24} />
</ThemeIcon>
</Group>
</Card>
</GridCol>
</Grid>
{/* Health Progress Bars */}
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
>
<Title order={3} mb="md" c={dark ? "dark.0" : "black"}>
Statistik Kesehatan
</Title>
<Stack gap="md">
{healthProgress.map((item, index) => (
<div key={index}>
<Group justify="space-between" mb={5}>
<Text size="sm" fw={500} c={dark ? "dark.0" : "black"}>
{item.label}
</Text>
<Text size="sm" fw={600} c={dark ? "dark.0" : "black"}>
{item.value}%
</Text>
</Group>
<Progress
value={item.value}
size="lg"
radius="xl"
color={item.color}
/>
<div
className={`min-h-screen py-6 px-4 sm:px-6 lg:px-8 ${
dark ? "bg-slate-900" : "bg-gray-100"
}`}
>
<div className="max-w-7xl mx-auto w-full">
{/* Row 1: Top 4 Metrics Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
{healthStats.map((stat, index) => (
<div
key={index}
className={`rounded-xl shadow-sm p-6 ${
dark ? "bg-slate-800 border border-slate-800" : "bg-white border border-white"
}`}
>
<div className="flex items-center justify-between">
<div className="flex-1">
<h3
className={`text-sm font-medium mb-1 ${
dark ? "text-gray-400" : "text-gray-500"
}`}
>
{stat.title}
</h3>
<p
className={`text-3xl font-bold mb-1 ${
stat.alert
? "text-red-500"
: dark
? "text-white"
: "text-gray-800"
}`}
>
{stat.value}
</p>
<p
className={`text-xs ${
dark ? "text-gray-400" : "text-gray-500"
}`}
>
{stat.subtitle}
</p>
</div>
<div className="flex-shrink-0 ml-4">
<div
className={`w-12 h-12 rounded-full flex items-center justify-center text-white ${
stat.alert ? "bg-red-500" : "bg-blue-900"
}`}
>
<stat.icon size={24} />
</div>
</div>
</div>
</div>
))}
</Stack>
</Card>
</div>
<Grid gutter="md">
{/* Jadwal Posyandu */}
<GridCol span={{ base: 12, lg: 6 }}>
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
{/* Row 2: Statistik Kesehatan */}
<div
className={`rounded-xl shadow-sm p-6 mb-6 ${
dark ? "bg-slate-800 border border-slate-800" : "bg-white border border-white"
}`}
>
<h3
className={`text-lg font-semibold mb-6 ${
dark ? "text-white" : "text-gray-800"
}`}
>
<Title order={3} mb="md" c={dark ? "dark.0" : "black"}>
Jadwal Posyandu
</Title>
<Stack gap="sm">
{posyanduSchedule.map((item, index) => (
<Card
key={index}
p="md"
radius="md"
withBorder
bg={dark ? "#263852ff" : "#F1F5F9"}
style={{ borderColor: dark ? "#263852ff" : "#F1F5F9" }}
h="100%"
Statistik Kesehatan
</h3>
<div className="space-y-4">
{healthProgress.map((item, index) => (
<div key={index}>
<div className="flex items-center justify-between mb-2">
<span
className={`text-sm font-medium ${
dark ? "text-white" : "text-gray-800"
}`}
>
{item.label}
</span>
<span
className={`text-sm font-semibold ${
item.isAlert
? "text-red-500"
: dark
? "text-white"
: "text-gray-800"
}`}
>
{item.value}%
</span>
</div>
<div
className={`w-full rounded-full h-2 ${
dark ? "bg-slate-700" : "bg-gray-200"
}`}
>
<Group justify="space-between">
<Stack gap={0}>
<Text fw={500} c={dark ? "dark.0" : "black"}>
<div
className={`h-2 rounded-full transition-all ${
item.isAlert ? "bg-red-500" : "bg-blue-900"
}`}
style={{ width: `${item.value}%` }}
/>
</div>
</div>
))}
</div>
</div>
{/* Row 3: Jadwal Posyandu & Pendidikan */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
{/* Jadwal Posyandu */}
<div
className={`rounded-xl shadow-sm p-6 ${
dark ? "bg-slate-800 border border-slate-800" : "bg-white border border-white"
}`}
>
<h3
className={`text-lg font-semibold mb-4 ${
dark ? "text-white" : "text-gray-800"
}`}
>
Jadwal Posyandu
</h3>
<div className="space-y-3">
{posyanduSchedule.map((item, index) => (
<div
key={index}
className={`p-4 rounded-lg ${
dark ? "bg-slate-700" : "bg-gray-50"
}`}
>
<div className="flex items-center justify-between">
<div>
<p
className={`text-sm font-medium ${
dark ? "text-white" : "text-gray-800"
}`}
>
{item.nama}
</Text>
<Text size="sm" c={dark ? "dark.0" : "black"}>
</p>
<p
className={`text-xs mt-1 ${
dark ? "text-gray-400" : "text-gray-500"
}`}
>
{item.tanggal}
</Text>
</Stack>
<Badge variant="light" color="darmasaba-blue">
</p>
</div>
<span
className="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-900"
>
{item.jam}
</Badge>
</Group>
</Card>
</span>
</div>
</div>
))}
</Stack>
</Card>
</GridCol>
</div>
</div>
{/* Pendidikan */}
<GridCol span={{ base: 12, lg: 6 }}>
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
h="100%"
{/* Pendidikan Section */}
<div
className={`rounded-xl shadow-sm p-6 ${
dark ? "bg-slate-800 border border-slate-800" : "bg-white border border-white"
}`}
>
<Title order={3} mb="md" c={dark ? "dark.0" : "black"}>
<h3
className={`text-lg font-semibold mb-4 ${
dark ? "text-white" : "text-gray-800"
}`}
>
Pendidikan
</Title>
<Stack gap="md">
<Group justify="space-between">
<Text fw={500} c={dark ? "dark.0" : "black"}>
TK / PAUD
</Text>
<Text fw={700} c={dark ? "dark.0" : "black"}>
{educationStats.siswa.tk}
</Text>
</Group>
<Group justify="space-between">
<Text fw={500} c={dark ? "dark.0" : "black"}>
SD
</Text>
<Text fw={700} c={dark ? "dark.0" : "black"}>
{educationStats.siswa.sd}
</Text>
</Group>
<Group justify="space-between">
<Text fw={500} c={dark ? "dark.0" : "black"}>
SMP
</Text>
<Text fw={700} c={dark ? "dark.0" : "black"}>
{educationStats.siswa.smp}
</Text>
</Group>
<Group justify="space-between">
<Text fw={500} c={dark ? "dark.0" : "black"}>
SMA
</Text>
<Text fw={700} c={dark ? "dark.0" : "black"}>
{educationStats.siswa.sma}
</Text>
</Group>
</h3>
<div className="space-y-3 mb-6">
{educationStats.map((item, index) => (
<div
key={index}
className={`flex items-center justify-between py-2 ${
dark ? "border-b border-slate-700" : "border-b border-gray-100"
}`}
>
<span className="text-sm" style={{ color: dark ? "#9CA3AF" : "#6B7280" }}>
{item.level}
</span>
<span
className={`text-sm font-semibold ${
dark ? "text-white" : "text-gray-800"
}`}
>
{item.value}
</span>
</div>
))}
</div>
<Card
withBorder
radius="md"
p="md"
mt="md"
bg={dark ? "#263852ff" : "#F1F5F9"}
style={{ borderColor: dark ? "#263852ff" : "#F1F5F9" }}
>
<Group justify="space-between">
<Text fw={500} c={dark ? "dark.0" : "black"}>
Jumlah Lembaga Pendidikan
</Text>
<Text fw={700} c={dark ? "dark.0" : "black"}>
{educationStats.sekolah.jumlah}
</Text>
</Group>
<Group justify="space-between" mt="sm">
<Text fw={500} c={dark ? "dark.0" : "black"}>
Jumlah Tenaga Pengajar
</Text>
<Text fw={700} c={dark ? "dark.0" : "black"}>
{educationStats.sekolah.guru}
</Text>
</Group>
</Card>
</Stack>
</Card>
</GridCol>
</Grid>
{/* Info Sekolah */}
<h4
className={`text-base font-semibold mb-4 ${
dark ? "text-white" : "text-gray-800"
}`}
>
Info Sekolah
</h4>
<div className="space-y-3">
{schoolInfo.map((item, index) => (
<div
key={index}
className={`flex items-center justify-between py-3 px-4 rounded-lg ${
dark ? "bg-slate-700" : "bg-gray-50"
}`}
>
<span className="text-sm" style={{ color: dark ? "#9CA3AF" : "#6B7280" }}>
{item.label}
</span>
<span
className={`text-lg font-bold ${
dark ? "text-white" : "text-gray-800"
}`}
>
{item.value}
</span>
</div>
))}
</div>
</div>
</div>
<Grid gutter="md">
{/* Beasiswa Desa */}
<GridCol span={{ base: 12, lg: 6 }}>
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
h="100%"
{/* Row 4: Beasiswa Desa & Kalender Event Budaya */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Beasiswa Desa */}
<div
className={`rounded-xl shadow-sm p-6 ${
dark ? "bg-slate-800 border border-slate-800" : "bg-white border border-white"
}`}
>
<Group justify="space-between" align="center">
<Stack gap={0}>
<Text size="sm" c={dark ? "dark.3" : "dimmed"}>
Beasiswa Desa
</Text>
<Text size="xl" fw={700} c={dark ? "dark.0" : "black"}>
Penerima: {scholarshipData.penerima}
</Text>
</Stack>
<ThemeIcon
variant="light"
color="darmasaba-success"
size="xl"
radius="xl"
<div className="flex items-center justify-between mb-6">
<h3
className={`text-lg font-semibold ${
dark ? "text-white" : "text-gray-800"
}`}
>
Beasiswa Desa
</h3>
<div
className="w-12 h-12 rounded-full flex items-center justify-center text-white bg-green-500"
>
<IconAward size={24} />
</ThemeIcon>
</Group>
<Text mt="md" c={dark ? "dark.0" : "black"}>
Dana Tersalurkan:{" "}
<Text span fw={700}>
{scholarshipData.dana}
</Text>
</Text>
<Text mt="sm" c={dark ? "dark.3" : "dimmed"}>
Tahun Ajaran: {scholarshipData.tahunAjaran}
</Text>
</Card>
</GridCol>
</div>
</div>
{/* Kalender Event Budaya */}
<GridCol span={{ base: 12, lg: 6 }}>
<Card
p="md"
radius="md"
withBorder
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
h="100%"
>
<Title order={3} mb="md" c={dark ? "dark.0" : "black"}>
Kalender Event Budaya
</Title>
<List spacing="sm">
{culturalEvents.map((event, index) => (
<List.Item
key={index}
icon={
<ThemeIcon color="darmasaba-blue" size={24} radius="xl">
<IconCalendarEvent size={12} />
</ThemeIcon>
}
{/* Two centered metrics */}
<div className="grid grid-cols-2 gap-4 mb-6">
<div
className={`p-4 rounded-lg text-center ${
dark ? "bg-slate-700" : "bg-gray-50"
}`}
>
<p
className={`text-3xl font-bold mb-1 ${
dark ? "text-white" : "text-gray-800"
}`}
>
<Group justify="space-between">
<Text fw={500} c={dark ? "dark.0" : "black"}>
{scholarshipData.penerima}
</p>
<p
className={`text-xs ${
dark ? "text-gray-400" : "text-gray-500"
}`}
>
Penerima Beasiswa
</p>
</div>
<div
className={`p-4 rounded-lg text-center ${
dark ? "bg-slate-700" : "bg-gray-50"
}`}
>
<p
className={`text-3xl font-bold mb-1 text-green-500`}
>
{scholarshipData.dana}
</p>
<p
className={`text-xs ${
dark ? "text-gray-400" : "text-gray-500"
}`}
>
Dana Tersalurkan
</p>
</div>
</div>
{/* Footer text */}
<p
className={`text-center text-sm ${
dark ? "text-gray-400" : "text-gray-500"
}`}
>
Tahun Ajaran {scholarshipData.tahunAjaran}
</p>
</div>
{/* Kalender Event Budaya */}
<div
className={`rounded-xl shadow-sm p-6 ${
dark ? "bg-slate-800 border border-slate-800" : "bg-white border border-white"
}`}
>
<Title order={3} mb="md" c={dark ? "dark.0" : "black"}>
Kalender Event Budaya
</Title>
<div className="space-y-4">
{culturalEvents.map((event, index) => (
<div
key={index}
className={`flex items-start gap-3 p-4 rounded-lg ${
dark ? "bg-slate-700" : "bg-gray-50"
}`}
>
<div
className="w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0 bg-blue-100 text-blue-900"
>
<IconCalendarEvent size={20} />
</div>
<div className="flex-1">
<p
className={`text-sm font-medium ${
dark ? "text-white" : "text-gray-800"
}`}
>
{event.nama}
</Text>
<Text size="sm" c={dark ? "dark.3" : "dimmed"}>
{event.lokasi}
</Text>
</Group>
<Text size="sm" c={dark ? "dark.3" : "dimmed"}>
{event.tanggal}
</Text>
</List.Item>
</p>
<p
className={`text-xs mt-1 ${
dark ? "text-gray-400" : "text-gray-500"
}`}
>
{event.tanggal}
</p>
<p
className={`text-xs mt-1 ${
dark ? "text-gray-400" : "text-gray-500"
}`}
>
Location: {event.lokasi}
</p>
</div>
</div>
))}
</List>
</Card>
</GridCol>
</Grid>
</Stack>
</div>
</div>
</div>
</div>
</div>
);
};