Fix QC Kak Inno 21 Oktober, QC Kak Ayu 21 Oktober, QC Keano, && QC Pak Jun 21 Oktober
This commit is contained in:
@@ -55,9 +55,9 @@ function EditProgramKemiskinan() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
stateProgram.findUnique
|
const loadData = async () => {
|
||||||
.load(id)
|
try {
|
||||||
.then(() => {
|
await stateProgram.findUnique.load(id);
|
||||||
const data = stateProgram.findUnique.data;
|
const data = stateProgram.findUnique.data;
|
||||||
if (data) {
|
if (data) {
|
||||||
setFormData({
|
setFormData({
|
||||||
@@ -70,12 +70,16 @@ function EditProgramKemiskinan() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
} catch (err) {
|
||||||
.catch((err) => {
|
|
||||||
console.error('Error load data:', err);
|
console.error('Error load data:', err);
|
||||||
toast.error('Gagal mengambil data program');
|
toast.error('Gagal mengambil data program');
|
||||||
});
|
}
|
||||||
}, [id, stateProgram.findUnique]);
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [id]); // ✅ hanya trigger saat id berubah
|
||||||
|
|
||||||
|
|
||||||
// generic handler untuk field top-level
|
// generic handler untuk field top-level
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
|
|||||||
@@ -62,11 +62,23 @@ function Page() {
|
|||||||
Informasi dan Pelayanan Administrasi Digital
|
Informasi dan Pelayanan Administrasi Digital
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Image src={state.findUnique.data?.image?.link || ''} alt='' w={"100%"} loading="lazy"/>
|
<Image src={state.findUnique.data?.image?.link || ''} alt='' w={"100%"} loading="lazy" />
|
||||||
</Container>
|
</Container>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Text py={20} fz={{ base: "sm", md: "lg" }} ta={"justify"} style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: state.findUnique.data?.content || '' }} />
|
<Text
|
||||||
|
py={20}
|
||||||
|
fz={{ base: "sm", md: "lg" }}
|
||||||
|
lh={{ base: 1.6, md: 1.8 }} // ✅ line-height lebih rapat dan responsif
|
||||||
|
ta="justify"
|
||||||
|
style={{
|
||||||
|
wordBreak: "break-word",
|
||||||
|
whiteSpace: "normal",
|
||||||
|
}}
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: state.findUnique.data?.content || "",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -186,12 +186,11 @@ function Page() {
|
|||||||
stateCreate.create.form.kategoriId = '';
|
stateCreate.create.form.kategoriId = '';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
searchable
|
// searchable
|
||||||
clearable
|
clearable
|
||||||
nothingFoundMessage="Tidak ditemukan"
|
nothingFoundMessage="Tidak ditemukan"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button bg={colors['blue-button']} onClick={handleSubmit}>
|
<Button bg={colors['blue-button']} onClick={handleSubmit}>
|
||||||
Simpan
|
Simpan
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -240,15 +240,8 @@ function Page() {
|
|||||||
</Table>
|
</Table>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
</Stack>
|
|
||||||
</Grid.Col>
|
|
||||||
</Grid>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Card radius="xl" p="lg" withBorder>
|
||||||
<Grid gutter="lg">
|
|
||||||
<Grid.Col span={{ base: 12, md: 8 }}>
|
|
||||||
<Card radius="xl" p="lg" withBorder>
|
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Title order={3}>Fasilitas Pendukung</Title>
|
<Title order={3}>Fasilitas Pendukung</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
@@ -264,8 +257,7 @@ function Page() {
|
|||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
</Grid.Col>
|
|
||||||
<Grid.Col span={{ base: 12, md: 4 }}>
|
|
||||||
<Card radius="xl" p="lg" withBorder>
|
<Card radius="xl" p="lg" withBorder>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Title order={3}>Layanan & Tarif</Title>
|
<Title order={3}>Layanan & Tarif</Title>
|
||||||
@@ -303,10 +295,11 @@ function Page() {
|
|||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
|
</Stack>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box px={{ base: 'md', md: 100 }} pb="xl">
|
<Box px={{ base: 'md', md: 100 }} pb="xl">
|
||||||
<Paper radius="xl" p="lg" withBorder>
|
<Paper radius="xl" p="lg" withBorder>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
|
|||||||
@@ -4,14 +4,16 @@ import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
|||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
Button,
|
||||||
Divider,
|
Divider,
|
||||||
Group,
|
Group,
|
||||||
|
Modal,
|
||||||
Paper,
|
Paper,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
Stack,
|
Stack,
|
||||||
Text
|
Text
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDisclosure, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconMail, IconPhone, IconUser } from '@tabler/icons-react';
|
import { IconMail, IconPhone, IconUser } from '@tabler/icons-react';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
@@ -21,6 +23,7 @@ import CreatePendaftaran from '../create/page';
|
|||||||
function Page() {
|
function Page() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const state = useProxy(jadwalkegiatanState);
|
const state = useProxy(jadwalkegiatanState);
|
||||||
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
state.findUnique.load(params?.id as string);
|
state.findUnique.load(params?.id as string);
|
||||||
@@ -66,28 +69,38 @@ function Page() {
|
|||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Deskripsi Kegiatan</Text>
|
<Text fz="lg" fw="bold">Deskripsi Kegiatan</Text>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text ta="justify" fz="md" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: state.findUnique.data.deskripsijadwalkegiatan.deskripsi }} />
|
<Text ta="justify" fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.deskripsijadwalkegiatan.deskripsi }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Layanan yang Tersedia</Text>
|
<Text fz="lg" fw="bold">Layanan yang Tersedia</Text>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text ta="justify" fz="md" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: state.findUnique.data.layananjadwalkegiatan.content }} />
|
<Text ta="justify" fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.layananjadwalkegiatan.content }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Syarat & Ketentuan</Text>
|
<Text fz="lg" fw="bold">Syarat & Ketentuan</Text>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text ta="justify" fz="md" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: state.findUnique.data.syaratketentuanjadwalkegiatan.content }} />
|
<Text ta="justify" fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.syaratketentuanjadwalkegiatan.content }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Dokumen yang Perlu Dibawa</Text>
|
<Text fz="lg" fw="bold">Dokumen yang Perlu Dibawa</Text>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text ta="justify" fz="md" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: state.findUnique.data.dokumenjadwalkegiatan.content }} />
|
<Text ta="justify" fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.dokumenjadwalkegiatan.content }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<CreatePendaftaran />
|
<Stack gap="sm">
|
||||||
|
<Text fz="lg" fw="bold">Pendaftaran Kegiatan</Text>
|
||||||
|
<Divider />
|
||||||
|
<Group>
|
||||||
|
<Button onClick={open}>Buat Pendaftaran</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Modal opened={opened} onClose={close}>
|
||||||
|
<CreatePendaftaran />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<Paper p="lg" radius="md" bg={colors['blue-button-trans']} shadow="sm">
|
<Paper p="lg" radius="md" bg={colors['blue-button-trans']} shadow="sm">
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
|
|||||||
@@ -49,12 +49,10 @@ function Page() {
|
|||||||
<Paper p={20} bg={colors['white-trans-1']} shadow="md" radius="md" style={{ width: '100%', display: 'flex', flexDirection: 'column' }}>
|
<Paper p={20} bg={colors['white-trans-1']} shadow="md" radius="md" style={{ width: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Box>
|
<Box>
|
||||||
<Tooltip label={tujuan.data?.judul} position="top" withArrow>
|
<Tooltip label={<Text fz={"sm"} c={"white"} dangerouslySetInnerHTML={{ __html: tujuan.data?.judul || '' }} /> } position="top" withArrow>
|
||||||
<Stack gap={4} align="center">
|
<Stack gap={4} align="center">
|
||||||
<IconLeaf size={28} color={colors['blue-button']} />
|
<IconLeaf size={28} color={colors['blue-button']} />
|
||||||
<Text fz="h3" fw="bold" c={colors['blue-button']} ta="center">
|
<Text dangerouslySetInnerHTML={{ __html: tujuan.data?.judul || '' }} fz="h3" fw="bold" c={colors['blue-button']} ta="center" />
|
||||||
{tujuan.data?.judul}
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ function Page() {
|
|||||||
<Title fz={55} fw={900} c={colors['blue-button']}>
|
<Title fz={55} fw={900} c={colors['blue-button']}>
|
||||||
Wujudkan Mimpi Pendidikanmu di Desa Darmasaba
|
Wujudkan Mimpi Pendidikanmu di Desa Darmasaba
|
||||||
</Title>
|
</Title>
|
||||||
<Text fz="lg" mt="md" c="dimmed">
|
<Text fz="lg" mt="md" fw={"bold"}>
|
||||||
Program beasiswa untuk mendukung pendidikan berkualitas bagi generasi muda Desa Darmasaba.
|
Program beasiswa untuk mendukung pendidikan berkualitas bagi generasi muda Desa Darmasaba.
|
||||||
</Text>
|
</Text>
|
||||||
<Group mt="xl">
|
<Group mt="xl">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
Timeline,
|
Timeline,
|
||||||
Title
|
Title
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { IconArrowLeft } from '@tabler/icons-react';
|
import { IconArrowLeft, IconChecklist, IconInfoCircle, IconQuote, IconSchool, IconTimeline, IconUserPlus } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
@@ -69,10 +69,11 @@ export default function BeasiswaPage() {
|
|||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
<Container size="lg" py="xl">
|
<Container size="lg" py="xl">
|
||||||
<Stack gap="md" maw={600}>
|
<Stack gap="md" maw={600}>
|
||||||
<Title order={2} c="blue.9">
|
<Group>
|
||||||
Program Beasiswa Pendidikan Desa Darmasaba
|
<IconSchool size={30} color={colors["blue-button"]} />
|
||||||
</Title>
|
<Title order={2}>Program Beasiswa Pendidikan Desa Darmasaba</Title>
|
||||||
<Text c="dimmed">
|
</Group>
|
||||||
|
<Text>
|
||||||
Program ini bertujuan untuk mendukung pendidikan generasi muda di Desa Darmasaba
|
Program ini bertujuan untuk mendukung pendidikan generasi muda di Desa Darmasaba
|
||||||
agar dapat melanjutkan studi ke jenjang lebih tinggi dengan dukungan finansial dan pendampingan.
|
agar dapat melanjutkan studi ke jenjang lebih tinggi dengan dukungan finansial dan pendampingan.
|
||||||
</Text>
|
</Text>
|
||||||
@@ -81,21 +82,35 @@ export default function BeasiswaPage() {
|
|||||||
|
|
||||||
{/* Tentang Program */}
|
{/* Tentang Program */}
|
||||||
<Container size="lg" py="xl">
|
<Container size="lg" py="xl">
|
||||||
<Title order={3} mb="sm">
|
<Group mb="sm">
|
||||||
Tentang Program
|
<IconInfoCircle size={24} color={colors["blue-button"]} />
|
||||||
</Title>
|
<Title order={3}>Tentang Program</Title>
|
||||||
|
</Group>
|
||||||
<Text>
|
<Text>
|
||||||
Program Beasiswa Desa Darmasaba adalah inisiatif pemerintah desa untuk meningkatkan akses
|
Program Beasiswa Desa Darmasaba adalah inisiatif pemerintah desa untuk meningkatkan akses
|
||||||
pendidikan bagi siswa berprestasi dan kurang mampu. Melalui program ini, desa memberikan bantuan
|
pendidikan bagi siswa berprestasi dan kurang mampu. Melalui program ini, desa memberikan bantuan
|
||||||
biaya sekolah, bimbingan akademik, serta pelatihan soft skill bagi peserta terpilih.
|
biaya sekolah, bimbingan akademik, serta pelatihan soft skill bagi peserta terpilih.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
|
{/* Tambahkan info tahun berjalan di sini */}
|
||||||
|
<Paper mt="md" p="md" radius="lg" shadow="xs" bg="#f8fbff" withBorder>
|
||||||
|
<Text fw={500} c={colors["blue-button"]}>
|
||||||
|
📅 Periode Beasiswa Tahun 2025
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" c="dimmed">
|
||||||
|
Pendaftaran beasiswa dibuka mulai <strong>1 Januari 2025</strong> dan ditutup pada
|
||||||
|
<strong>31 Mei 2025</strong>.
|
||||||
|
Pengumuman hasil seleksi akan diumumkan pada pertengahan Juni 2025 melalui website resmi Desa Darmasaba.
|
||||||
|
</Text>
|
||||||
|
</Paper>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
{/* Syarat dan Ketentuan */}
|
{/* Syarat dan Ketentuan */}
|
||||||
<Container size="lg" py="xl">
|
<Container size="lg" py="xl">
|
||||||
<Title order={3} mb="sm">
|
<Group mb="sm">
|
||||||
Syarat Pendaftaran
|
<IconChecklist size={24} color={colors["blue-button"]} />
|
||||||
</Title>
|
<Title order={3}>Syarat Pendaftaran</Title>
|
||||||
|
</Group>
|
||||||
|
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, md: 3 }} spacing="lg">
|
<SimpleGrid cols={{ base: 1, sm: 2, md: 3 }} spacing="lg">
|
||||||
<Paper shadow="sm" p="md" radius="lg" withBorder>
|
<Paper shadow="sm" p="md" radius="lg" withBorder>
|
||||||
@@ -123,42 +138,61 @@ export default function BeasiswaPage() {
|
|||||||
|
|
||||||
{/* Proses Seleksi */}
|
{/* Proses Seleksi */}
|
||||||
<Container size="lg" py="xl">
|
<Container size="lg" py="xl">
|
||||||
<Title order={3} mb="sm">
|
<Group mb="sm">
|
||||||
Proses Seleksi
|
<IconTimeline size={24} color={colors["blue-button"]} />
|
||||||
</Title>
|
<Title order={3}>Proses Seleksi</Title>
|
||||||
|
</Group>
|
||||||
|
|
||||||
<Timeline active={4} bulletSize={24} lineWidth={2}>
|
<Timeline active={4} bulletSize={24} lineWidth={2}>
|
||||||
<Timeline.Item title="Pendaftaran Online">
|
<Timeline.Item title="Pendaftaran Online">
|
||||||
<Text c="dimmed" size="sm">
|
<Text c="dimmed" size="sm">
|
||||||
Calon peserta mengisi formulir pendaftaran dan mengunggah dokumen pendukung.
|
Calon peserta mengisi formulir pendaftaran dan mengunggah dokumen pendukung.
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text size="sm" fw={500} c={colors["blue-button"]} mt={4}>
|
||||||
|
⏰ Estimasi waktu: 1 Februari – 31 Mei 2025
|
||||||
|
</Text>
|
||||||
</Timeline.Item>
|
</Timeline.Item>
|
||||||
|
|
||||||
<Timeline.Item title="Seleksi Administrasi">
|
<Timeline.Item title="Seleksi Administrasi">
|
||||||
<Text c="dimmed" size="sm">
|
<Text c="dimmed" size="sm">
|
||||||
Panitia memverifikasi kelengkapan dan validitas berkas.
|
Panitia memverifikasi kelengkapan dan validitas berkas.
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text size="sm" fw={500} c={colors["blue-button"]} mt={4}>
|
||||||
|
⏰ Estimasi waktu: 5–7 hari kerja setelah penutupan pendaftaran
|
||||||
|
</Text>
|
||||||
</Timeline.Item>
|
</Timeline.Item>
|
||||||
|
|
||||||
<Timeline.Item title="Wawancara dan Penilaian">
|
<Timeline.Item title="Wawancara dan Penilaian">
|
||||||
<Text c="dimmed" size="sm">
|
<Text c="dimmed" size="sm">
|
||||||
Peserta yang lolos administrasi akan diundang untuk wawancara langsung dengan tim seleksi.
|
Peserta yang lolos administrasi akan diundang untuk wawancara langsung dengan tim seleksi.
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text size="sm" fw={500} c={colors["blue-button"]} mt={4}>
|
||||||
|
⏰ Estimasi waktu: 7–10 hari kerja setelah pengumuman seleksi administrasi
|
||||||
|
</Text>
|
||||||
</Timeline.Item>
|
</Timeline.Item>
|
||||||
|
|
||||||
<Timeline.Item title="Pengumuman Penerima">
|
<Timeline.Item title="Pengumuman Penerima">
|
||||||
<Text c="dimmed" size="sm">
|
<Text c="dimmed" size="sm">
|
||||||
Daftar penerima beasiswa diumumkan melalui website resmi Desa Darmasaba.
|
Daftar penerima beasiswa diumumkan melalui website resmi Desa Darmasaba.
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text size="sm" fw={500} c={colors["blue-button"]} mt={4}>
|
||||||
|
⏰ Estimasi waktu: 5 hari kerja setelah tahap wawancara selesai
|
||||||
|
</Text>
|
||||||
</Timeline.Item>
|
</Timeline.Item>
|
||||||
</Timeline>
|
</Timeline>
|
||||||
|
|
||||||
|
<Text c="dimmed" size="sm" mt="lg" ta="center">
|
||||||
|
🗓️ Total estimasi keseluruhan proses: sekitar 3–4 minggu setelah penutupan pendaftaran
|
||||||
|
</Text>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
|
|
||||||
{/* Testimoni */}
|
{/* Testimoni */}
|
||||||
<Container size="lg" py="xl">
|
<Container size="lg" py="xl">
|
||||||
<Title order={3} mb="sm">
|
<Group mb="sm">
|
||||||
Cerita Sukses Penerima Beasiswa
|
<IconQuote size={24} color={colors["blue-button"]} />
|
||||||
</Title>
|
<Title order={3}>Cerita Sukses Penerima Beasiswa</Title>
|
||||||
|
</Group>
|
||||||
|
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing="lg">
|
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing="lg">
|
||||||
<Paper shadow="md" p="lg" radius="lg">
|
<Paper shadow="md" p="lg" radius="lg">
|
||||||
@@ -183,7 +217,10 @@ export default function BeasiswaPage() {
|
|||||||
|
|
||||||
{/* CTA Akhir */}
|
{/* CTA Akhir */}
|
||||||
<Container size="lg" py="xl" ta="center">
|
<Container size="lg" py="xl" ta="center">
|
||||||
<Title order={3}>Siap Bergabung dengan Program Ini?</Title>
|
<Group justify="center" mb="sm">
|
||||||
|
<IconUserPlus size={28} color={colors["blue-button"]} />
|
||||||
|
<Title order={3}>Siap Bergabung dengan Program Ini?</Title>
|
||||||
|
</Group>
|
||||||
<Text c="dimmed" mb="md">
|
<Text c="dimmed" mb="md">
|
||||||
Segera daftar dan wujudkan mimpimu bersama Desa Darmasaba.
|
Segera daftar dan wujudkan mimpimu bersama Desa Darmasaba.
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ function Page() {
|
|||||||
Pendidikan Non Formal
|
Pendidikan Non Formal
|
||||||
</Title>
|
</Title>
|
||||||
<Text ta="center" fz="lg" lh={1.6} c="black" maw={800} mx="auto">
|
<Text ta="center" fz="lg" lh={1.6} c="black" maw={800} mx="auto">
|
||||||
Bentuk pendidikan di luar sekolah yang terstruktur, bertujuan memberikan keterampilan, pengetahuan, dan pengembangan karakter masyarakat dari berbagai usia serta latar belakang.
|
Pendidikan non formal merupakan bentuk pendidikan di luar sekolah yang terstruktur, bertujuan untuk memberikan keterampilan, pengetahuan, serta pengembangan karakter masyarakat dari berbagai usia dan latar belakang.
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<SimpleGrid
|
<SimpleGrid
|
||||||
|
|||||||
@@ -16,16 +16,11 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { DateInput } from '@mantine/dates';
|
import { DateInput } from '@mantine/dates';
|
||||||
import {
|
import { IconArrowRight, IconBook2, IconUser } from '@tabler/icons-react';
|
||||||
IconArrowRight,
|
|
||||||
IconBook2,
|
|
||||||
IconUser
|
|
||||||
} from '@tabler/icons-react';
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { useSnapshot } from 'valtio';
|
import { useSnapshot } from 'valtio';
|
||||||
|
|
||||||
|
|
||||||
export interface ModalPeminjamanProps {
|
export interface ModalPeminjamanProps {
|
||||||
opened: boolean;
|
opened: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -45,11 +40,12 @@ export default function ModalPeminjaman({
|
|||||||
}: ModalPeminjamanProps) {
|
}: ModalPeminjamanProps) {
|
||||||
const snap = useSnapshot(perpustakaanDigitalState.peminjamanBuku);
|
const snap = useSnapshot(perpustakaanDigitalState.peminjamanBuku);
|
||||||
|
|
||||||
// reset form setiap modal dibuka
|
const BATAS_HARI_PINJAM = 4;
|
||||||
|
|
||||||
|
// Reset form setiap modal dibuka
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (opened && buku) {
|
if (opened && buku) {
|
||||||
perpustakaanDigitalState.peminjamanBuku.create.form = {
|
perpustakaanDigitalState.peminjamanBuku.create.form = {
|
||||||
...perpustakaanDigitalState.peminjamanBuku.create.form,
|
|
||||||
bukuId: buku.id,
|
bukuId: buku.id,
|
||||||
nama: '',
|
nama: '',
|
||||||
noTelp: '',
|
noTelp: '',
|
||||||
@@ -99,7 +95,14 @@ export default function ModalPeminjaman({
|
|||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Text fz="sm" c="dimmed" lineClamp={3} dangerouslySetInnerHTML={{ __html: buku.deskripsi || 'Tidak ada deskripsi' }} />
|
<Text
|
||||||
|
fz="sm"
|
||||||
|
c="dimmed"
|
||||||
|
lineClamp={3}
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: buku.deskripsi || 'Tidak ada deskripsi',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
@@ -112,7 +115,8 @@ export default function ModalPeminjaman({
|
|||||||
leftSection={<IconUser size={16} />}
|
leftSection={<IconUser size={16} />}
|
||||||
value={snap.create.form.nama}
|
value={snap.create.form.nama}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
(perpustakaanDigitalState.peminjamanBuku.create.form.nama = e.currentTarget.value)
|
(perpustakaanDigitalState.peminjamanBuku.create.form.nama =
|
||||||
|
e.currentTarget.value)
|
||||||
}
|
}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@@ -123,7 +127,8 @@ export default function ModalPeminjaman({
|
|||||||
leftSection={<IconUser size={16} />}
|
leftSection={<IconUser size={16} />}
|
||||||
value={snap.create.form.noTelp}
|
value={snap.create.form.noTelp}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
(perpustakaanDigitalState.peminjamanBuku.create.form.noTelp = e.currentTarget.value)
|
(perpustakaanDigitalState.peminjamanBuku.create.form.noTelp =
|
||||||
|
e.currentTarget.value)
|
||||||
}
|
}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@@ -134,11 +139,13 @@ export default function ModalPeminjaman({
|
|||||||
leftSection={<IconUser size={16} />}
|
leftSection={<IconUser size={16} />}
|
||||||
value={snap.create.form.alamat}
|
value={snap.create.form.alamat}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
(perpustakaanDigitalState.peminjamanBuku.create.form.alamat = e.currentTarget.value)
|
(perpustakaanDigitalState.peminjamanBuku.create.form.alamat =
|
||||||
|
e.currentTarget.value)
|
||||||
}
|
}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* === OTOMATIS SET BATAS DAN TANGGAL KEMBALI === */}
|
||||||
<DateInput
|
<DateInput
|
||||||
label="Tanggal Pinjam"
|
label="Tanggal Pinjam"
|
||||||
placeholder="Pilih tanggal pinjam"
|
placeholder="Pilih tanggal pinjam"
|
||||||
@@ -148,64 +155,83 @@ export default function ModalPeminjaman({
|
|||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
onChange={(date) => {
|
onChange={(date) => {
|
||||||
perpustakaanDigitalState.peminjamanBuku.create.form.tanggalPinjam =
|
if (date) {
|
||||||
date ? new Date(date).toISOString() : '';
|
const tanggalPinjam = new Date(date);
|
||||||
|
|
||||||
|
// simpan tanggal pinjam
|
||||||
|
perpustakaanDigitalState.peminjamanBuku.create.form.tanggalPinjam =
|
||||||
|
tanggalPinjam.toISOString();
|
||||||
|
|
||||||
|
// hitung batas +4 hari
|
||||||
|
const batasKembali = new Date(tanggalPinjam);
|
||||||
|
batasKembali.setDate(batasKembali.getDate() + BATAS_HARI_PINJAM);
|
||||||
|
|
||||||
|
// set batas & tanggal kembali otomatis
|
||||||
|
perpustakaanDigitalState.peminjamanBuku.create.form.batasKembali =
|
||||||
|
batasKembali.toISOString();
|
||||||
|
perpustakaanDigitalState.peminjamanBuku.create.form.tanggalKembali =
|
||||||
|
batasKembali.toISOString();
|
||||||
|
|
||||||
|
toast.info(
|
||||||
|
`Batas pengembalian otomatis diset ke ${batasKembali.toLocaleDateString('id-ID')} (+${BATAS_HARI_PINJAM} hari).`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
perpustakaanDigitalState.peminjamanBuku.create.form.tanggalPinjam = '';
|
||||||
|
perpustakaanDigitalState.peminjamanBuku.create.form.batasKembali = '';
|
||||||
|
perpustakaanDigitalState.peminjamanBuku.create.form.tanggalKembali = '';
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text>Catatan</Text>
|
<Text fw={500}>Catatan</Text>
|
||||||
<CreateEditor
|
<CreateEditor
|
||||||
value={snap.create.form.catatan}
|
value={snap.create.form.catatan}
|
||||||
onChange={(e) =>
|
onChange={(val) =>
|
||||||
(perpustakaanDigitalState.peminjamanBuku.create.form.catatan = e)
|
(perpustakaanDigitalState.peminjamanBuku.create.form.catatan =
|
||||||
|
val)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<DateInput
|
|
||||||
label="Tanggal Kembali"
|
|
||||||
placeholder="Pilih tanggal kembali"
|
|
||||||
value={
|
|
||||||
snap.create.form.tanggalKembali
|
|
||||||
? new Date(snap.create.form.tanggalKembali)
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
onChange={(date) => {
|
|
||||||
perpustakaanDigitalState.peminjamanBuku.create.form.tanggalKembali =
|
|
||||||
date ? new Date(date).toISOString() : '';
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DateInput
|
<DateInput
|
||||||
label="Batas Pengembalian"
|
label="Batas Pengembalian"
|
||||||
placeholder="Pilih tanggal kembali"
|
placeholder="Otomatis diatur +4 hari dari tanggal pinjam"
|
||||||
value={
|
value={
|
||||||
snap.create.form.batasKembali
|
snap.create.form.batasKembali
|
||||||
? new Date(snap.create.form.batasKembali)
|
? new Date(snap.create.form.batasKembali)
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
onChange={(date) => {
|
disabled
|
||||||
perpustakaanDigitalState.peminjamanBuku.create.form.batasKembali =
|
readOnly
|
||||||
date ? new Date(date).toISOString() : '';
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<DateInput
|
||||||
|
label="Tanggal Kembali"
|
||||||
|
placeholder="Otomatis sama dengan batas pengembalian"
|
||||||
|
value={
|
||||||
|
snap.create.form.tanggalKembali
|
||||||
|
? new Date(snap.create.form.tanggalKembali)
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
disabled
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
loading={snap.create.loading}
|
loading={snap.create.loading}
|
||||||
disabled={
|
disabled={
|
||||||
!snap.create.form.nama ||
|
!snap.create.form.nama || !snap.create.form.tanggalPinjam
|
||||||
!snap.create.form.tanggalPinjam ||
|
|
||||||
!snap.create.form.batasKembali ||
|
|
||||||
!snap.create.form.tanggalKembali
|
|
||||||
}
|
}
|
||||||
rightSection={<IconArrowRight size={16} />}
|
rightSection={<IconArrowRight size={16} />}
|
||||||
radius="xl"
|
radius="xl"
|
||||||
|
style={{
|
||||||
|
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
|
||||||
|
color: '#fff',
|
||||||
|
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Pinjam Buku
|
Pinjam Buku
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
import indeksKepuasanState from "@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan";
|
import indeksKepuasanState from "@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan";
|
||||||
import colors from "@/con/colors";
|
import colors from "@/con/colors";
|
||||||
import { BarChart, PieChart } from '@mantine/charts';
|
import { BarChart, PieChart } from '@mantine/charts';
|
||||||
import { Box, Button, Center, Container, Flex, Group, Modal, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from "@mantine/core";
|
import { Box, Button, Center, Container, Flex, Modal, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from "@mantine/core";
|
||||||
import { useDisclosure, useMediaQuery, useShallowEffect } from "@mantine/hooks";
|
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useProxy } from "valtio/utils";
|
import { useProxy } from "valtio/utils";
|
||||||
|
|
||||||
@@ -18,14 +18,13 @@ interface ChartDataItem {
|
|||||||
|
|
||||||
|
|
||||||
function Kepuasan() {
|
function Kepuasan() {
|
||||||
const state = useProxy(indeksKepuasanState.responden);
|
const state = useProxy(indeksKepuasanState.responden);
|
||||||
const { data, loading } = state.findMany;
|
const { data, loading } = state.findMany;
|
||||||
const [donutDataJenisKelamin, setDonutDataJenisKelamin] = useState<ChartDataItem[]>([]);
|
const [donutDataJenisKelamin, setDonutDataJenisKelamin] = useState<ChartDataItem[]>([]);
|
||||||
const [donutDataRating, setDonutDataRating] = useState<ChartDataItem[]>([]);
|
const [donutDataRating, setDonutDataRating] = useState<ChartDataItem[]>([]);
|
||||||
const [donutDataKelompokUmur, setDonutDataKelompokUmur] = useState<ChartDataItem[]>([]);
|
const [donutDataKelompokUmur, setDonutDataKelompokUmur] = useState<ChartDataItem[]>([]);
|
||||||
const [barChartData, setBarChartData] = useState<Array<{ month: string; count: number }>>([]);
|
const [barChartData, setBarChartData] = useState<Array<{ month: string; Responden: number }>>([]);
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false)
|
||||||
const isMobile = useMediaQuery("(max-width: 768px)");
|
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
state.create.form = {
|
state.create.form = {
|
||||||
@@ -122,18 +121,18 @@ function Kepuasan() {
|
|||||||
|
|
||||||
// Convert map to array and sort by date
|
// Convert map to array and sort by date
|
||||||
const barData = Array.from(monthYearMap.entries())
|
const barData = Array.from(monthYearMap.entries())
|
||||||
.map(([key, count]) => {
|
.map(([key, Responden]) => {
|
||||||
const [year, month] = key.split('-');
|
const [year, month] = key.split('-');
|
||||||
const monthName = new Date(Number(year), Number(month) - 1, 1)
|
const monthName = new Date(Number(year), Number(month) - 1, 1)
|
||||||
.toLocaleString('id-ID', { month: 'long' });
|
.toLocaleString('id-ID', { month: 'long' });
|
||||||
return {
|
return {
|
||||||
month: `${monthName} ${year}`,
|
month: `${monthName} ${year}`,
|
||||||
count,
|
Responden,
|
||||||
sortKey: parseInt(`${year}${String(month).padStart(2, '0')}`, 10)
|
sortKey: parseInt(`${year}${String(month).padStart(2, '0')}`, 10)
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.sort((a, b) => a.sortKey - b.sortKey)
|
.sort((a, b) => a.sortKey - b.sortKey)
|
||||||
.map(({ month, count }) => ({ month, count }));
|
.map(({ month, Responden }) => ({ month, Responden }));
|
||||||
|
|
||||||
setBarChartData(barData);
|
setBarChartData(barData);
|
||||||
}
|
}
|
||||||
@@ -141,12 +140,12 @@ function Kepuasan() {
|
|||||||
|
|
||||||
if ((loading && !data) || !data) {
|
if ((loading && !data) || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10} px="sm">
|
<Stack py={10} px="xl">
|
||||||
<Skeleton height={200} mb="md" />
|
<Skeleton height={300} mb="md" />
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, md: 3 }} spacing="md">
|
<SimpleGrid cols={{ base: 1, md: 3 }}>
|
||||||
<Skeleton height={200} />
|
<Skeleton height={300} />
|
||||||
<Skeleton height={200} />
|
<Skeleton height={300} />
|
||||||
<Skeleton height={200} />
|
<Skeleton height={300} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
@@ -157,10 +156,16 @@ function Kepuasan() {
|
|||||||
<Stack p="sm">
|
<Stack p="sm">
|
||||||
<Container w={{ base: "100%", md: "80%" }} p={"xl"}>
|
<Container w={{ base: "100%", md: "80%" }} p={"xl"}>
|
||||||
<Center>
|
<Center>
|
||||||
<Text ta={"center"} fz={{ base: "2.4rem", md: "3.4rem" }}>Indeks Kepuasan Masyarakat</Text>
|
<Text fw={"bold"} fz={{ base: "1.8rem", md: "3.4rem" }}>Indeks Kepuasan Masyarakat</Text>
|
||||||
</Center>
|
</Center>
|
||||||
|
<Text ta={"center"} fz={{ base: "1rem", md: "1.3rem" }}>Ukur kebahagiaan warga, tingkatkan layanan desa! Dengan partisipasi aktif masyarakat, kami berkomitmen untuk terus memperbaiki layanan agar lebih transparan, efektif, dan sesuai dengan kebutuhan warga. Kepuasan Anda adalah prioritas utama kami dalam membangun desa yang lebih baik!</Text>
|
||||||
<Center mt={10}>
|
<Center mt={10}>
|
||||||
<Button radius={"lg"} bg={colors["blue-button"]} onClick={open}>Ajukan Responden</Button>
|
<Button
|
||||||
|
radius={"lg"}
|
||||||
|
onClick={open}
|
||||||
|
variant="gradient"
|
||||||
|
gradient={{ from: "#26667F", to: "#124170" }}
|
||||||
|
>Ajukan Responden</Button>
|
||||||
</Center>
|
</Center>
|
||||||
</Container>
|
</Container>
|
||||||
<Box px={"xl"}>
|
<Box px={"xl"}>
|
||||||
@@ -177,10 +182,10 @@ function Kepuasan() {
|
|||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
<BarChart
|
<BarChart
|
||||||
h={300}
|
h={window.innerWidth < 480 ? 200 : 300}
|
||||||
data={barChartData}
|
data={barChartData}
|
||||||
dataKey="month"
|
dataKey="month"
|
||||||
series={[{ name: 'count', color: colors['blue-button'] }]}
|
series={[{ name: 'Responden', color: colors['blue-button'] }]}
|
||||||
tickLine="y"
|
tickLine="y"
|
||||||
xAxisLabel="Bulan"
|
xAxisLabel="Bulan"
|
||||||
yAxisLabel="Jumlah Responden"
|
yAxisLabel="Jumlah Responden"
|
||||||
@@ -191,12 +196,9 @@ function Kepuasan() {
|
|||||||
</Paper>
|
</Paper>
|
||||||
<Box py={"xl"}>
|
<Box py={"xl"}>
|
||||||
<SimpleGrid
|
<SimpleGrid
|
||||||
cols={{
|
cols={{ base: 1, sm: 2, lg: 3 }}
|
||||||
base: 1,
|
spacing="md"
|
||||||
md: 1,
|
verticalSpacing="md"
|
||||||
lg: 1,
|
|
||||||
xl: 3
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{/* Chart Jenis Kelamin */}
|
{/* Chart Jenis Kelamin */}
|
||||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||||
@@ -215,7 +217,7 @@ function Kepuasan() {
|
|||||||
withLabels
|
withLabels
|
||||||
withTooltip
|
withTooltip
|
||||||
labelsType="percent"
|
labelsType="percent"
|
||||||
size={200}
|
size={250} // Fixed size in pixels
|
||||||
data={donutDataJenisKelamin}
|
data={donutDataJenisKelamin}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -254,7 +256,7 @@ function Kepuasan() {
|
|||||||
labelsPosition="outside"
|
labelsPosition="outside"
|
||||||
labelsType="percent"
|
labelsType="percent"
|
||||||
withLabelsLine
|
withLabelsLine
|
||||||
size={200}
|
size={250}
|
||||||
data={donutDataRating}
|
data={donutDataRating}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -297,7 +299,7 @@ function Kepuasan() {
|
|||||||
labelsPosition="outside"
|
labelsPosition="outside"
|
||||||
labelsType="percent"
|
labelsType="percent"
|
||||||
withLabelsLine
|
withLabelsLine
|
||||||
size={190}
|
size={250}
|
||||||
data={donutDataKelompokUmur}
|
data={donutDataKelompokUmur}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -330,7 +332,7 @@ function Kepuasan() {
|
|||||||
<TextInput
|
<TextInput
|
||||||
label="Nama"
|
label="Nama"
|
||||||
type='text'
|
type='text'
|
||||||
placeholder="masukkan nama"
|
placeholder="Masukkan nama"
|
||||||
defaultValue={state.create.form.name}
|
defaultValue={state.create.form.name}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
state.create.form.name = val.currentTarget.value;
|
state.create.form.name = val.currentTarget.value;
|
||||||
@@ -413,41 +415,57 @@ function Kepuasan() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Stack p="sm">
|
<Stack p={"sm"}>
|
||||||
<Container w={{ base: "100%", md: "80%" }} p={isMobile ? "md" : "xl"}>
|
<Container size="lg" px="md">
|
||||||
<Stack gap="xs">
|
<Center>
|
||||||
<Text ta="center" fz={{ base: "2rem", md: "3rem" }}>Indeks Kepuasan Masyarakat</Text>
|
<Text ta={"center"} fz={{ base: "2.4rem", md: "3.4rem" }}>Indeks Kepuasan Masyarakat</Text>
|
||||||
<Group justify="center">
|
</Center>
|
||||||
<Button radius="lg" bg={colors["blue-button"]} onClick={open}>
|
<Text fz={{ base: "1.2rem", md: "1.4rem" }} ta={"center"}>Ukur kebahagiaan warga, tingkatkan layanan desa! Dengan partisipasi aktif masyarakat, kami berkomitmen untuk terus memperbaiki layanan agar lebih transparan, efektif, dan sesuai dengan kebutuhan warga. Kepuasan Anda adalah prioritas utama kami dalam membangun desa yang lebih baik!</Text>
|
||||||
Ajukan Responden
|
<Center mt={10}>
|
||||||
</Button>
|
<Button radius={"lg"} bg={colors["blue-button"]} onClick={open}>Ajukan Responden</Button>
|
||||||
</Group>
|
</Center>
|
||||||
</Stack>
|
|
||||||
</Container>
|
</Container>
|
||||||
<Box px={isMobile ? "sm" : "xl"}>
|
<Box px={"xl"}>
|
||||||
<Paper p="lg" bg={colors.Bg}>
|
<Paper p={"lg"} bg={colors.Bg}>
|
||||||
<Paper p={isMobile ? "sm" : "lg"}>
|
<Paper p={"lg"}>
|
||||||
<Stack gap="xs">
|
<Stack gap={"xs"}>
|
||||||
<Flex direction={isMobile ? "column" : "row"} justify="space-between" align={isMobile ? "start" : "center"}>
|
<Flex
|
||||||
<Text fw="bold" mb={isMobile ? "sm" : 0}>Pelayanan Terhadap Publik Desa Darmasaba</Text>
|
direction={{ base: "column", sm: "row" }}
|
||||||
<Box>
|
justify="space-between"
|
||||||
<Text fz="sm" fw="bold" c={colors["blue-button"]}>Total Responden</Text>
|
align={{ base: "flex-start", sm: "center" }}
|
||||||
<Text ta="end" fz="h1" fw="bold" c={colors["blue-button"]}>
|
>
|
||||||
{state.findMany.total.toLocaleString("id-ID")}
|
<Text fw="bold" ta={{ base: "center", sm: "left" }}>
|
||||||
|
Pelayanan Terhadap Publik Desa Darmasaba
|
||||||
|
</Text>
|
||||||
|
<Box mt={{ base: "sm", sm: 0 }}>
|
||||||
|
<Text fz={"sm"} fw={"bold"} c={colors["blue-button"]}>Total Responden</Text>
|
||||||
|
<Text ta={"end"} fz={"h1"} fw={"bold"} c={colors["blue-button"]}>
|
||||||
|
{state.findMany.total.toLocaleString('id-ID')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
<BarChart
|
<BarChart
|
||||||
h={isMobile ? 200 : 300}
|
h={300}
|
||||||
data={barChartData}
|
data={barChartData}
|
||||||
dataKey="month"
|
dataKey="month"
|
||||||
series={[{ name: "count", color: colors["blue-button"] }]}
|
series={[{ name: 'Responden', color: colors['blue-button'] }]}
|
||||||
|
tickLine="y"
|
||||||
|
xAxisLabel="Bulan"
|
||||||
|
yAxisLabel="Jumlah Responden"
|
||||||
withTooltip
|
withTooltip
|
||||||
|
tooltipAnimationDuration={200}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Box py="xl">
|
<Box py={"xl"}>
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, xl: 3 }} spacing="lg">
|
<SimpleGrid
|
||||||
|
cols={{
|
||||||
|
base: 1,
|
||||||
|
md: 1,
|
||||||
|
lg: 1,
|
||||||
|
xl: 3
|
||||||
|
}}
|
||||||
|
>
|
||||||
{/* Chart Jenis Kelamin */}
|
{/* Chart Jenis Kelamin */}
|
||||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||||
<Stack>
|
<Stack>
|
||||||
@@ -457,17 +475,28 @@ function Kepuasan() {
|
|||||||
Belum ada data untuk ditampilkan dalam grafik
|
Belum ada data untuk ditampilkan dalam grafik
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Paper p="md" radius="md">
|
<Paper p="md" radius="md" withBorder>
|
||||||
<Stack>
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
<Center>
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
<PieChart
|
<Center>
|
||||||
size={isMobile ? 150 : 200}
|
<PieChart
|
||||||
withLabels
|
withLabels
|
||||||
data={donutDataJenisKelamin}
|
withTooltip
|
||||||
withTooltip
|
labelsType="percent"
|
||||||
/>
|
size={200}
|
||||||
</Center>
|
data={donutDataJenisKelamin}
|
||||||
</Stack>
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<Stack gap="sm" mt="md">
|
||||||
|
{donutDataJenisKelamin.map((entry) => (
|
||||||
|
<Flex key={entry.name} gap="md" align="center">
|
||||||
|
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
||||||
|
<Text size="sm">{entry.name}: {entry.value}</Text>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -482,18 +511,35 @@ function Kepuasan() {
|
|||||||
Belum ada data untuk ditampilkan dalam grafik
|
Belum ada data untuk ditampilkan dalam grafik
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Paper p="md" radius="md">
|
<Paper p="md" radius="md" withBorder>
|
||||||
<Stack>
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
<Center>
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
<PieChart
|
<Center>
|
||||||
size={isMobile ? 150 : 200}
|
<PieChart
|
||||||
withLabels
|
withTooltip
|
||||||
labelsPosition="outside"
|
tooltipAnimationDuration={200}
|
||||||
withLabelsLine
|
withLabels
|
||||||
data={donutDataRating}
|
labelsPosition="outside"
|
||||||
/>
|
labelsType="percent"
|
||||||
</Center>
|
withLabelsLine
|
||||||
</Stack>
|
size={200}
|
||||||
|
data={donutDataRating}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<Box mt="md" style={{ width: '100%' }}>
|
||||||
|
<SimpleGrid cols={2} spacing="xs" verticalSpacing="xs">
|
||||||
|
{donutDataRating.map((entry) => (
|
||||||
|
<Flex key={entry.name} gap="sm" align="center" style={{ overflow: 'hidden' }}>
|
||||||
|
<Box bg={entry.color} w={16} h={16} style={{ flexShrink: 0 }} />
|
||||||
|
<Text size="xs" lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||||
|
{entry.name}: {entry.value}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -508,18 +554,35 @@ function Kepuasan() {
|
|||||||
Belum ada data untuk ditampilkan dalam grafik
|
Belum ada data untuk ditampilkan dalam grafik
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Paper p="md" radius="md">
|
<Paper p="md" radius="md" withBorder>
|
||||||
<Stack>
|
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
<Center>
|
<Box style={{ position: 'relative', width: '100%' }}>
|
||||||
<PieChart
|
<Center>
|
||||||
size={isMobile ? 150 : 200}
|
<PieChart
|
||||||
withLabels
|
withTooltip
|
||||||
labelsPosition="outside"
|
tooltipAnimationDuration={200}
|
||||||
withLabelsLine
|
withLabels
|
||||||
data={donutDataKelompokUmur}
|
labelsPosition="outside"
|
||||||
/>
|
labelsType="percent"
|
||||||
</Center>
|
withLabelsLine
|
||||||
</Stack>
|
size={190}
|
||||||
|
data={donutDataKelompokUmur}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
<Box mt="md" style={{ width: '100%' }}>
|
||||||
|
<SimpleGrid cols={2} spacing="xs" verticalSpacing="xs">
|
||||||
|
{donutDataKelompokUmur.map((entry) => (
|
||||||
|
<Flex key={entry.name} gap="sm" align="center" style={{ overflow: 'hidden' }}>
|
||||||
|
<Box bg={entry.color} w={16} h={16} style={{ flexShrink: 0 }} />
|
||||||
|
<Text size="xs" lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||||
|
{entry.name}: {entry.value}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</SimpleGrid>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -542,7 +605,7 @@ function Kepuasan() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Tanggal"
|
label="Tanggal Pengisian"
|
||||||
type="date"
|
type="date"
|
||||||
placeholder="masukkan tanggal"
|
placeholder="masukkan tanggal"
|
||||||
defaultValue={state.create.form.tanggal}
|
defaultValue={state.create.form.tanggal}
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ function Page() {
|
|||||||
<Text
|
<Text
|
||||||
fz={{ base: 'md', md: 'lg' }}
|
fz={{ base: 'md', md: 'lg' }}
|
||||||
lh={1.7}
|
lh={1.7}
|
||||||
ta="center"
|
|
||||||
dangerouslySetInnerHTML={{ __html: item.misi }}
|
dangerouslySetInnerHTML={{ __html: item.misi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function Navbar() {
|
|||||||
stateNav.mobileOpen = false;
|
stateNav.mobileOpen = false;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tooltip label="Go to homepage" position="bottom" withArrow>
|
<Tooltip label="Kembali ke Beranda" position="bottom" withArrow>
|
||||||
<Image
|
<Image
|
||||||
src="/darmasaba-icon.png"
|
src="/darmasaba-icon.png"
|
||||||
alt="Village Logo"
|
alt="Village Logo"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export function NavbarMainMenu({ listNavbar }: { listNavbar: MenuItem[] }) {
|
|||||||
<Stack gap={0} visibleFrom="sm" bg={colors["white-trans-1"]}>
|
<Stack gap={0} visibleFrom="sm" bg={colors["white-trans-1"]}>
|
||||||
<Container pos="relative" w={{ base: '100%', md: '80%' }} fluid>
|
<Container pos="relative" w={{ base: '100%', md: '80%' }} fluid>
|
||||||
<Flex align="center" justify="space-between" wrap={{ base: "wrap", md: "nowrap" }}>
|
<Flex align="center" justify="space-between" wrap={{ base: "wrap", md: "nowrap" }}>
|
||||||
<Tooltip label="Go to Homepage" position="bottom" withArrow>
|
<Tooltip label="Kembali ke Beranda" position="bottom" withArrow>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
radius="xl"
|
radius="xl"
|
||||||
variant="transparent"
|
variant="transparent"
|
||||||
@@ -55,7 +55,7 @@ export function NavbarMainMenu({ listNavbar }: { listNavbar: MenuItem[] }) {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<Tooltip label="Search content" position="bottom" withArrow>
|
<Tooltip label="Cari Konten" position="bottom" withArrow>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
variant="transparent"
|
variant="transparent"
|
||||||
c={isSearch ? 'gray' : colors["blue-button"]}
|
c={isSearch ? 'gray' : colors["blue-button"]}
|
||||||
@@ -71,7 +71,7 @@ export function NavbarMainMenu({ listNavbar }: { listNavbar: MenuItem[] }) {
|
|||||||
|
|
||||||
{/* hanya tampil kalau role = admin */}
|
{/* hanya tampil kalau role = admin */}
|
||||||
{stateAuth.role === "admin" && (
|
{stateAuth.role === "admin" && (
|
||||||
<Tooltip label="My Profile" position="bottom" withArrow>
|
<Tooltip label="Profil Saya" position="bottom" withArrow>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
next.push("/admin/landing-page/profile/program-inovasi")
|
next.push("/admin/landing-page/profile/program-inovasi")
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ function Kepuasan() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Tanggal"
|
label="Tanggal Pengisian"
|
||||||
type="date"
|
type="date"
|
||||||
placeholder="masukkan tanggal"
|
placeholder="masukkan tanggal"
|
||||||
defaultValue={state.create.form.tanggal}
|
defaultValue={state.create.form.tanggal}
|
||||||
|
|||||||
Reference in New Issue
Block a user