Fix konsisten font, menu landing page & PPID
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
Title,
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
@@ -41,9 +42,9 @@ export default function DetailInformasiPublikUser() {
|
||||
return (
|
||||
<Center py="xl">
|
||||
<Stack align="center" gap="sm">
|
||||
<Text fz="lg" fw="bold">
|
||||
<Title order={4} fz={{ base: 'lg', md: 'xl' }} lh={1.3}>
|
||||
Informasi tidak ditemukan
|
||||
</Text>
|
||||
</Title>
|
||||
<Button variant="light" onClick={() => router.push('/informasi-publik')}>
|
||||
Kembali ke Daftar
|
||||
</Button>
|
||||
@@ -75,53 +76,60 @@ export default function DetailInformasiPublikUser() {
|
||||
shadow="xs"
|
||||
>
|
||||
<Stack gap="xl">
|
||||
<Text
|
||||
fz={{ base: 'xl', md: '2xl' }}
|
||||
fw="bold"
|
||||
{/* MAIN TITLE */}
|
||||
<Title
|
||||
order={2}
|
||||
lh={1.2}
|
||||
ta="center"
|
||||
c={colors['blue-button']}
|
||||
>
|
||||
Detail Informasi Publik
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* CONTENT */}
|
||||
<Stack gap="lg">
|
||||
{/* Jenis Informasi */}
|
||||
<Box px="lg">
|
||||
<Text fz={{ base: 'md', md: 'lg' }} fw="bold" mb={4}>
|
||||
<Title order={5} fz={{ base: 'lg', md: 'xl' }} lh={1.3} mb={4}>
|
||||
Jenis Informasi
|
||||
</Text>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed">
|
||||
</Title>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5} c="black">
|
||||
{data.jenisInformasi || '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{/* Tanggal Publikasi */}
|
||||
<Box px="lg">
|
||||
<Text fz={{ base: 'md', md: 'lg' }} fw="bold" mb={4}>
|
||||
<Title order={5} fz={{ base: 'lg', md: 'xl' }} lh={1.3} mb={4}>
|
||||
Tanggal Publikasi
|
||||
</Text>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed">
|
||||
</Title>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5} c="black">
|
||||
{data.tanggal
|
||||
? new Date(data.tanggal).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
})
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
})
|
||||
: '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{/* Deskripsi */}
|
||||
<Box px="lg">
|
||||
<Text fz={{ base: 'md', md: 'lg' }} fw="bold" mb={4}>
|
||||
<Title order={5} fz={{ base: 'lg', md: 'xl' }} lh={1.3} mb={4}>
|
||||
Deskripsi
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<Box>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
className="prose max-w-none leading-relaxed"
|
||||
ta="justify"
|
||||
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
fz={{ base: 'md', md: 'lg' }}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.6}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
className="prose max-w-none"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -130,4 +138,4 @@ export default function DetailInformasiPublikUser() {
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
TableTr,
|
||||
Text,
|
||||
TextInput,
|
||||
Tooltip
|
||||
Tooltip,
|
||||
Title
|
||||
} from '@mantine/core';
|
||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||
import { IconBrandWhatsapp, IconDeviceImacCog, IconFileInfo, IconMail, IconSearch } from '@tabler/icons-react';
|
||||
@@ -33,7 +34,7 @@ import { useTransitionRouter } from 'next-view-transitions';
|
||||
function Page() {
|
||||
const listData = useProxy(daftarInformasiPublik)
|
||||
const [search, setSearch] = useState('')
|
||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
|
||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 1000ms delay
|
||||
const router = useTransitionRouter()
|
||||
const {
|
||||
data,
|
||||
@@ -65,20 +66,49 @@ function Page() {
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
|
||||
<Center>
|
||||
<Image src="/darmasaba-icon.png" w={{ base: 70, md: 100 }} alt="Logo Desa Darmasaba" loading="lazy" />
|
||||
<Image
|
||||
src="/darmasaba-icon.png"
|
||||
w={{ base: 70, md: 100 }}
|
||||
alt="Logo Desa Darmasaba"
|
||||
loading="lazy"
|
||||
/>
|
||||
</Center>
|
||||
<Text ta="center" fz={{ base: "1.8rem", md: "2.5rem" }} c={colors["blue-button"]} fw="bold" lh={1.4}>
|
||||
|
||||
<Title
|
||||
order={2}
|
||||
ta="center"
|
||||
fz={{ base: '1.6rem', md: '2.4rem' }}
|
||||
c={colors['blue-button']}
|
||||
lh={1.35}
|
||||
style={{ fontWeight: 700 }}
|
||||
>
|
||||
Daftar Informasi Publik
|
||||
</Text>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
</Title>
|
||||
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Stack gap="lg">
|
||||
<Paper p="lg" radius="xl" shadow="sm" withBorder>
|
||||
<Stack gap="sm">
|
||||
<Text ta={"center"} fz={{ base: 'lg', md: 'xl' }} fw="bold" c={colors["blue-button"]}>
|
||||
<Title
|
||||
order={4}
|
||||
ta="center"
|
||||
fz={{ base: 'lg', md: 'xl' }}
|
||||
c={colors['blue-button']}
|
||||
lh={1.2}
|
||||
style={{ fontWeight: 700 }}
|
||||
>
|
||||
Tentang Informasi Publik
|
||||
</Text>
|
||||
<Text ta={"center"} fz={{ base: 'sm', md: 'md' }} c="dimmed">
|
||||
</Title>
|
||||
|
||||
<Text
|
||||
ta="center"
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
c="black"
|
||||
lh={1.6}
|
||||
style={{ maxWidth: 900, margin: '0 auto' }}
|
||||
>
|
||||
Daftar Informasi Publik Desa Darmasaba adalah kumpulan data yang dapat diakses oleh masyarakat sesuai dengan ketentuan peraturan yang berlaku.
|
||||
</Text>
|
||||
</Stack>
|
||||
@@ -97,8 +127,8 @@ function Page() {
|
||||
{data.length === 0 ? (
|
||||
<Center py="xl">
|
||||
<Stack align="center" gap="sm">
|
||||
<IconFileInfo size={48} stroke={1.5} color={colors["blue-button"]} />
|
||||
<Text fz="md" c="dimmed">Tidak ada informasi publik yang ditemukan.</Text>
|
||||
<IconFileInfo size={48} stroke={1.5} color={colors['blue-button']} />
|
||||
<Text fz="md" c="dimmed" lh={1.5}>Tidak ada informasi publik yang ditemukan.</Text>
|
||||
</Stack>
|
||||
</Center>
|
||||
) : (
|
||||
@@ -113,27 +143,42 @@ function Page() {
|
||||
<TableTh fz="sm" ta="center" w="15%">Aksi</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
|
||||
<TableTbody bg={colors['white-1']}>
|
||||
{data.map((item, index) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd ta="center">{(page - 1) * 5 + index + 1}</TableTd>
|
||||
<TableTd ta="center">
|
||||
<Text fz="sm" lh={1.4}>
|
||||
{(page - 1) * 5 + index + 1}
|
||||
</Text>
|
||||
</TableTd>
|
||||
|
||||
<TableTd>
|
||||
<Box>
|
||||
<Badge variant="light" size="lg" color="blue">
|
||||
<Text fw={650} fz={"sm"} c={'blue'} lineClamp={1}>
|
||||
<Text fw={650} fz="sm" c="blue" lineClamp={1} lh={1.2}>
|
||||
{item.jenisInformasi}
|
||||
</Text>
|
||||
</Badge>
|
||||
</Box>
|
||||
</TableTd>
|
||||
|
||||
<TableTd>
|
||||
<Box>
|
||||
<Text lineClamp={1} fz="sm" c="dark" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
<Text
|
||||
lineClamp={1}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
c="dark"
|
||||
lh={1.5}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||
/>
|
||||
</Box>
|
||||
</TableTd>
|
||||
|
||||
<TableTd ta="center">
|
||||
<Box>
|
||||
<Text ta={"center"}>
|
||||
<Text ta="center" fz="sm" lh={1.4}>
|
||||
{item.tanggal ? new Date(item.tanggal).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
@@ -142,6 +187,7 @@ function Page() {
|
||||
</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
|
||||
<TableTd style={{ textAlign: 'center' }}>
|
||||
<Box>
|
||||
<Tooltip label="Lihat Detail" withArrow>
|
||||
@@ -152,8 +198,9 @@ function Page() {
|
||||
color="blue"
|
||||
leftSection={<IconDeviceImacCog size={16} />}
|
||||
onClick={() => router.push(`/darmasaba/ppid/daftar-informasi-publik/${item.id}`)}
|
||||
aria-label={`Detail ${item.jenisInformasi}`}
|
||||
>
|
||||
Detail
|
||||
<Text fz="xs" lh={1.2}>Detail</Text>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
@@ -178,17 +225,27 @@ function Page() {
|
||||
|
||||
<Paper p="lg" radius="xl" shadow="xs" withBorder>
|
||||
<Stack gap="xs">
|
||||
<Text fz="lg" fw="bold" c={colors["blue-button"]}>Kontak PPID</Text>
|
||||
<Title order={5} fz={{ base: 'lg', md: 'xl' }} fw="bold" c={colors['blue-button']} lh={1.2}>
|
||||
Kontak PPID
|
||||
</Title>
|
||||
|
||||
<Group>
|
||||
<IconMail color='gray' size={16} style={{ marginRight: 6 }} />
|
||||
<Text c={"dimmed"} fz="sm" lh={1.6}>
|
||||
Email: <Text c={"dimmed"} span fw="500">ppid@desadarmasaba.id</Text>
|
||||
<IconMail color="gray" size={16} style={{ marginRight: 6 }} />
|
||||
<Text c="dimmed" fz="sm" lh={1.6}>
|
||||
Email:{' '}
|
||||
<Text c="dimmed" span fw={500} fz="sm" lh={1.6}>
|
||||
ppid@desadarmasaba.id
|
||||
</Text>
|
||||
</Text>
|
||||
</Group>
|
||||
|
||||
<Group>
|
||||
<IconBrandWhatsapp color='gray' size={16} style={{ marginRight: 6 }} />
|
||||
<Text c={"dimmed"} fz="sm" lh={1.6}>
|
||||
WhatsApp: <Text c={"dimmed"} span fw="500">081-xxx-xxx-xxx</Text>
|
||||
<IconBrandWhatsapp color="gray" size={16} style={{ marginRight: 6 }} />
|
||||
<Text c="dimmed" fz="sm" lh={1.6}>
|
||||
WhatsApp:{' '}
|
||||
<Text c="dimmed" span fw={500} fz="sm" lh={1.6}>
|
||||
081-xxx-xxx-xxx
|
||||
</Text>
|
||||
</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import stateDasarHukum from '@/app/admin/(dashboard)/_state/ppid/dasar_hukum/dasarHukum';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Skeleton, Stack, Text, Transition } from '@mantine/core';
|
||||
import { Box, Paper, Skeleton, Stack, Text, Transition, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { IconBook2 } from '@tabler/icons-react';
|
||||
@@ -31,31 +31,39 @@ function Page() {
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Stack
|
||||
align="center"
|
||||
gap="xs"
|
||||
px={{ base: 'md', md: 100 }}
|
||||
>
|
||||
|
||||
{/* HEADER */}
|
||||
<Stack align="center" gap="xs" px={{ base: 'md', md: 100 }}>
|
||||
<IconBook2 size={42} stroke={1.5} color={colors["blue-button"]} />
|
||||
<Text
|
||||
|
||||
<Title
|
||||
order={1}
|
||||
ta="center"
|
||||
fz={{ base: "2rem", md: "2.5rem" }}
|
||||
c={colors["blue-button"]}
|
||||
fw="bold"
|
||||
fz={{ base: "1.8rem", md: "2.3rem" }}
|
||||
lh={1.2}
|
||||
style={{ letterSpacing: "-0.5px" }}
|
||||
>
|
||||
Dasar Hukum
|
||||
</Text>
|
||||
<Text ta="center" fz="md" c={"black"}>
|
||||
</Title>
|
||||
|
||||
<Text
|
||||
ta="center"
|
||||
fz={{ base: "sm", md: "md" }}
|
||||
lh={1.6}
|
||||
c="black"
|
||||
>
|
||||
Informasi regulasi dan kebijakan resmi yang menjadi dasar hukum
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
{/* CONTENT */}
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Stack gap="lg">
|
||||
{dataArray.map((item, k) => (
|
||||
<Transition
|
||||
key={k}
|
||||
mounted={true}
|
||||
mounted
|
||||
transition="fade-up"
|
||||
duration={400}
|
||||
timingFunction="ease"
|
||||
@@ -73,19 +81,27 @@ function Page() {
|
||||
}}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Text
|
||||
|
||||
{/* JUDUL */}
|
||||
<Title
|
||||
order={3}
|
||||
ta="center"
|
||||
c={"black"}
|
||||
fw="bold"
|
||||
fz={{ base: 'lg', md: 'xl' }}
|
||||
style={{ lineHeight: 1.4 }}
|
||||
c="black"
|
||||
fz={{ base: "lg", md: "xl" }}
|
||||
lh={1.3}
|
||||
dangerouslySetInnerHTML={{ __html: item.judul }}
|
||||
/>
|
||||
|
||||
{/* CONTENT */}
|
||||
<Text
|
||||
c={"black"}
|
||||
ta={"justify"}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
style={{ lineHeight: 1.7, wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
c="black"
|
||||
ta="justify"
|
||||
fz={{ base: "sm", md: "md" }}
|
||||
lh={1.7}
|
||||
style={{
|
||||
wordBreak: "break-word",
|
||||
whiteSpace: "normal",
|
||||
}}
|
||||
dangerouslySetInnerHTML={{ __html: item.content }}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
@@ -3,7 +3,22 @@
|
||||
import indeksKepuasanState from "@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan";
|
||||
import colors from "@/con/colors";
|
||||
import { BarChart, PieChart } from '@mantine/charts';
|
||||
import { Box, Button, Center, Container, Flex, 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, useShallowEffect } from "@mantine/hooks";
|
||||
import { useState } from "react";
|
||||
import { useProxy } from "valtio/utils";
|
||||
@@ -15,16 +30,14 @@ interface ChartDataItem {
|
||||
label?: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Kepuasan() {
|
||||
const state = useProxy(indeksKepuasanState.responden);
|
||||
const state = useProxy(indeksKepuasanState.responden);
|
||||
const { data, loading } = state.findMany;
|
||||
const [donutDataJenisKelamin, setDonutDataJenisKelamin] = useState<ChartDataItem[]>([]);
|
||||
const [donutDataRating, setDonutDataRating] = useState<ChartDataItem[]>([]);
|
||||
const [donutDataKelompokUmur, setDonutDataKelompokUmur] = useState<ChartDataItem[]>([]);
|
||||
const [barChartData, setBarChartData] = useState<Array<{ month: string; Responden: number }>>([]);
|
||||
const [opened, { open, close }] = useDisclosure(false)
|
||||
const [opened, { open, close }] = useDisclosure(false);
|
||||
|
||||
const resetForm = () => {
|
||||
state.create.form = {
|
||||
@@ -34,14 +47,14 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
jenisKelaminId: "",
|
||||
ratingId: "",
|
||||
kelompokUmurId: "",
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
useShallowEffect(() => {
|
||||
indeksKepuasanState.jenisKelaminResponden.findMany.load()
|
||||
indeksKepuasanState.pilihanRatingResponden.findMany.load()
|
||||
indeksKepuasanState.kelompokUmurResponden.findMany.load()
|
||||
},[])
|
||||
indeksKepuasanState.jenisKelaminResponden.findMany.load();
|
||||
indeksKepuasanState.pilihanRatingResponden.findMany.load();
|
||||
indeksKepuasanState.kelompokUmurResponden.findMany.load();
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
@@ -51,11 +64,11 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
await state.findUnique.load(idStr);
|
||||
}
|
||||
resetForm();
|
||||
close()
|
||||
close();
|
||||
} catch (error) {
|
||||
console.error('Error submitting form:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Load data on component mount
|
||||
useShallowEffect(() => {
|
||||
@@ -154,33 +167,52 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Stack p="sm">
|
||||
<Container w={{ base: "100%", md: "80%" }} p={"xl"}>
|
||||
<Container w={{ base: "100%", md: "80%" }} p="xl">
|
||||
<Center>
|
||||
<Text fw={"bold"} fz={{ base: "1.8rem", md: "3.4rem" }}>Indeks Kepuasan Masyarakat</Text>
|
||||
{/* Main page title — converted to Title, use order (don't set fz according to rules) */}
|
||||
<Title order={2} ta="center" c="dark">
|
||||
Indeks Kepuasan Masyarakat
|
||||
</Title>
|
||||
</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>
|
||||
|
||||
{/* Body lead text — responsive fz & lh */}
|
||||
<Text ta="center" fz={{ base: "1rem", md: "1.25rem" }} lh={{ base: 1.4, md: 1.6 }} c="dimmed" mt="sm">
|
||||
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}>
|
||||
<Button
|
||||
radius={"lg"}
|
||||
radius="lg"
|
||||
onClick={open}
|
||||
variant="gradient"
|
||||
gradient={{ from: "#26667F", to: "#124170" }}
|
||||
>Ajukan Responden</Button>
|
||||
>
|
||||
Ajukan Responden
|
||||
</Button>
|
||||
</Center>
|
||||
</Container>
|
||||
<Box px={"xl"}>
|
||||
<Paper p={"lg"} bg={colors.Bg}>
|
||||
<Paper p={"lg"}>
|
||||
<Stack gap={"xs"}>
|
||||
<Flex justify={"space-between"} align={"center"}>
|
||||
<Text fw={"bold"}>Pelayanan Terhadap Publik Desa Darmasaba</Text>
|
||||
|
||||
<Box px="xl">
|
||||
<Paper p="lg" bg={colors.Bg}>
|
||||
<Paper p="lg">
|
||||
<Stack gap="xs">
|
||||
<Flex justify="space-between" align="center">
|
||||
{/* Section heading — use Title order for hierarchy */}
|
||||
<Title order={4}>
|
||||
Pelayanan Terhadap Publik Desa Darmasaba
|
||||
</Title>
|
||||
|
||||
<Box>
|
||||
<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 fz={{ base: "0.9rem", md: "1rem" }} fw="bold" c={colors["blue-button"]}>
|
||||
Total Responden
|
||||
</Text>
|
||||
{/* Big number — use Title for emphasis */}
|
||||
<Title order={3} ta="end" c={colors["blue-button"]} fw="bold" mt="xs">
|
||||
{state.findMany.total.toLocaleString('id-ID')}
|
||||
</Title>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<BarChart
|
||||
h={window.innerWidth < 480 ? 200 : 300}
|
||||
data={barChartData}
|
||||
@@ -194,18 +226,16 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Box py={"xl"}>
|
||||
<SimpleGrid
|
||||
cols={{ base: 1, sm: 2, lg: 3 }}
|
||||
spacing="md"
|
||||
verticalSpacing="md"
|
||||
>
|
||||
|
||||
<Box py="xl">
|
||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md" verticalSpacing="md">
|
||||
{/* Chart Jenis Kelamin */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Jenis Kelamin</Title>
|
||||
<Title order={5}>Jenis Kelamin</Title>
|
||||
|
||||
{donutDataJenisKelamin.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
<Text c="dimmed" ta="center" my="md" fz={{ base: "0.95rem", md: "1rem" }}>
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
@@ -218,7 +248,7 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
withTooltip
|
||||
labelsPosition="inside"
|
||||
labelsType="percent"
|
||||
size={250} // Fixed size in pixels
|
||||
size={250}
|
||||
data={donutDataJenisKelamin}
|
||||
/>
|
||||
</Center>
|
||||
@@ -227,7 +257,7 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{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>
|
||||
<Text fz={{ base: "0.95rem", md: "1rem" }}>{entry.name}: {entry.value}</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Stack>
|
||||
@@ -240,9 +270,10 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{/* Chart Rating */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Ulasan</Title>
|
||||
<Title order={5}>Ulasan</Title>
|
||||
|
||||
{donutDataRating.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
<Text c="dimmed" ta="center" my="md" fz={{ base: "0.95rem", md: "1rem" }}>
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
@@ -267,7 +298,7 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{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' }}>
|
||||
<Text fz={{ base: "0.85rem", md: "0.95rem" }} lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
{entry.name}: {entry.value}
|
||||
</Text>
|
||||
</Flex>
|
||||
@@ -283,9 +314,10 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{/* Chart Kelompok Umur */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Umur</Title>
|
||||
<Title order={5}>Umur</Title>
|
||||
|
||||
{donutDataKelompokUmur.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
<Text c="dimmed" ta="center" my="md" fz={{ base: "0.95rem", md: "1rem" }}>
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
@@ -310,7 +342,7 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{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' }}>
|
||||
<Text fz={{ base: "0.85rem", md: "0.95rem" }} lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
{entry.name}: {entry.value}
|
||||
</Text>
|
||||
</Flex>
|
||||
@@ -326,18 +358,21 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* Modal */}
|
||||
<Modal opened={opened} onClose={close} title="Ajukan Responden" centered>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Paper bg={colors['white-1']} p="md">
|
||||
<Stack>
|
||||
<TextInput
|
||||
label="Nama"
|
||||
type='text'
|
||||
type="text"
|
||||
placeholder="Masukkan nama"
|
||||
value={state.create.form.name}
|
||||
onChange={(val) => {
|
||||
state.create.form.name = val.currentTarget.value;
|
||||
}}
|
||||
// label typography
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<TextInput
|
||||
label="Tanggal"
|
||||
@@ -347,10 +382,11 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
onChange={(val) => {
|
||||
state.create.form.tanggal = val.currentTarget.value;
|
||||
}}
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<Select
|
||||
key={"jenisKelamin"}
|
||||
label={"Jenis Kelamin"}
|
||||
key="jenisKelamin"
|
||||
label="Jenis Kelamin"
|
||||
placeholder={indeksKepuasanState.jenisKelaminResponden.findMany.loading ? 'Memuat...' : 'Pilih jenis kelamin'}
|
||||
value={state.create.form.jenisKelaminId || ""}
|
||||
onChange={(val) => {
|
||||
@@ -358,17 +394,19 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.jenisKelaminResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.filter(Boolean)
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.jenisKelaminResponden.findMany.loading}
|
||||
// label typography
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<Select
|
||||
key={"rating_responden"}
|
||||
label={"Rating"}
|
||||
key="rating_responden"
|
||||
label="Rating"
|
||||
placeholder={indeksKepuasanState.pilihanRatingResponden.findMany.loading ? 'Memuat...' : 'Pilih rating'}
|
||||
value={state.create.form.ratingId || ""}
|
||||
onChange={(val) => {
|
||||
@@ -376,17 +414,18 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.pilihanRatingResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.filter(Boolean)
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.pilihanRatingResponden.findMany.loading}
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<Select
|
||||
key={"kelompokUmur"}
|
||||
label={"Kelompok Umur"}
|
||||
key="kelompokUmur"
|
||||
label="Kelompok Umur"
|
||||
placeholder={indeksKepuasanState.kelompokUmurResponden.findMany.loading ? 'Memuat...' : 'Pilih kelompok umur'}
|
||||
value={state.create.form.kelompokUmurId || ""}
|
||||
onChange={(val) => {
|
||||
@@ -394,19 +433,16 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.kelompokUmurResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.filter(Boolean)
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
<Button mt={10} bg={colors['blue-button']} onClick={handleSubmit}>
|
||||
Submit
|
||||
</Button>
|
||||
</Stack>
|
||||
@@ -415,36 +451,47 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack p={"sm"}>
|
||||
<Container size="lg" px="md">
|
||||
<Stack p="sm">
|
||||
<Container size="lg" px="md">
|
||||
<Center>
|
||||
<Text ta={"center"} fz={{ base: "2.4rem", md: "3.4rem" }}>Indeks Kepuasan Masyarakat</Text>
|
||||
{/* Main page title — Title with order */}
|
||||
<Title order={2} ta="center" c="dark">
|
||||
Indeks Kepuasan Masyarakat
|
||||
</Title>
|
||||
</Center>
|
||||
<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>
|
||||
|
||||
<Text fz={{ base: "1rem", md: "1.125rem" }} lh={{ base: 1.4, md: 1.6 }} ta="center" c="dimmed" mt="sm">
|
||||
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}>
|
||||
<Button radius={"lg"} bg={colors["blue-button"]} onClick={open}>Ajukan Responden</Button>
|
||||
<Button radius="lg" bg={colors["blue-button"]} onClick={open}>Ajukan Responden</Button>
|
||||
</Center>
|
||||
</Container>
|
||||
<Box px={"xl"}>
|
||||
<Paper p={"lg"} bg={colors.Bg}>
|
||||
<Paper p={"lg"}>
|
||||
<Stack gap={"xs"}>
|
||||
|
||||
<Box px="xl">
|
||||
<Paper p="lg" bg={colors.Bg}>
|
||||
<Paper p="lg">
|
||||
<Stack gap="xs">
|
||||
<Flex
|
||||
direction={{ base: "column", sm: "row" }}
|
||||
justify="space-between"
|
||||
align={{ base: "flex-start", sm: "center" }}
|
||||
>
|
||||
<Text fw="bold" ta={{ base: "center", sm: "left" }}>
|
||||
<Title order={4} ta={{ base: "center", sm: "left" }}>
|
||||
Pelayanan Terhadap Publik Desa Darmasaba
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<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"]}>
|
||||
<Text fz={{ base: "0.9rem", md: "1rem" }} fw="bold" c={colors["blue-button"]}>Total Responden</Text>
|
||||
<Title order={3} ta="end" c={colors["blue-button"]} fw="bold" mt="xs">
|
||||
{state.findMany.total.toLocaleString('id-ID')}
|
||||
</Text>
|
||||
</Title>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<BarChart
|
||||
h={300}
|
||||
data={barChartData}
|
||||
@@ -458,21 +505,18 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Box py={"xl"}>
|
||||
|
||||
<Box py="xl">
|
||||
<SimpleGrid
|
||||
cols={{
|
||||
base: 1,
|
||||
md: 1,
|
||||
lg: 1,
|
||||
xl: 3
|
||||
}}
|
||||
cols={{ base: 1, md: 1, lg: 1, xl: 3 }}
|
||||
>
|
||||
{/* Chart Jenis Kelamin */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Jenis Kelamin</Title>
|
||||
<Title order={5}>Jenis Kelamin</Title>
|
||||
|
||||
{donutDataJenisKelamin.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
<Text c="dimmed" ta="center" my="md" fz={{ base: "0.95rem", md: "1rem" }}>
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
@@ -494,7 +538,7 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{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>
|
||||
<Text fz={{ base: "0.95rem", md: "1rem" }}>{entry.name}: {entry.value}</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Stack>
|
||||
@@ -507,9 +551,10 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{/* Chart Rating */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Ulasan</Title>
|
||||
<Title order={5}>Ulasan</Title>
|
||||
|
||||
{donutDataRating.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
<Text c="dimmed" ta="center" my="md" fz={{ base: "0.95rem", md: "1rem" }}>
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
@@ -534,7 +579,7 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{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' }}>
|
||||
<Text fz={{ base: "0.85rem", md: "0.95rem" }} lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
{entry.name}: {entry.value}
|
||||
</Text>
|
||||
</Flex>
|
||||
@@ -550,9 +595,10 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{/* Chart Kelompok Umur */}
|
||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||
<Stack>
|
||||
<Title order={4}>Umur</Title>
|
||||
<Title order={5}>Umur</Title>
|
||||
|
||||
{donutDataKelompokUmur.every(item => item.value === 0) ? (
|
||||
<Text c="dimmed" ta="center" my="md">
|
||||
<Text c="dimmed" ta="center" my="md" fz={{ base: "0.95rem", md: "1rem" }}>
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
) : (
|
||||
@@ -577,7 +623,7 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
{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' }}>
|
||||
<Text fz={{ base: "0.85rem", md: "0.95rem" }} lineClamp={1} style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
{entry.name}: {entry.value}
|
||||
</Text>
|
||||
</Flex>
|
||||
@@ -593,18 +639,20 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* Modal */}
|
||||
<Modal opened={opened} onClose={close} title="Ajukan Responden" centered>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Paper bg={colors['white-1']} p="md">
|
||||
<Stack>
|
||||
<TextInput
|
||||
label="Nama"
|
||||
type='text'
|
||||
type="text"
|
||||
placeholder="Masukkan nama"
|
||||
value={state.create.form.name}
|
||||
onChange={(val) => {
|
||||
state.create.form.name = val.currentTarget.value;
|
||||
}}
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<TextInput
|
||||
label="Tanggal Pengisian"
|
||||
@@ -614,10 +662,11 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
onChange={(val) => {
|
||||
state.create.form.tanggal = val.currentTarget.value;
|
||||
}}
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<Select
|
||||
key={"jenisKelamin"}
|
||||
label={"Jenis Kelamin"}
|
||||
key="jenisKelamin"
|
||||
label="Jenis Kelamin"
|
||||
placeholder={indeksKepuasanState.jenisKelaminResponden.findMany.loading ? 'Memuat...' : 'Pilih jenis kelamin'}
|
||||
value={state.create.form.jenisKelaminId || ""}
|
||||
onChange={(val) => {
|
||||
@@ -625,17 +674,18 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.jenisKelaminResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.filter(Boolean)
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.jenisKelaminResponden.findMany.loading}
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<Select
|
||||
key={"rating_responden"}
|
||||
label={"Rating"}
|
||||
key="rating_responden"
|
||||
label="Rating"
|
||||
placeholder={indeksKepuasanState.pilihanRatingResponden.findMany.loading ? 'Memuat...' : 'Pilih rating'}
|
||||
value={state.create.form.ratingId || ""}
|
||||
onChange={(val) => {
|
||||
@@ -643,17 +693,18 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.pilihanRatingResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.filter(Boolean)
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.pilihanRatingResponden.findMany.loading}
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<Select
|
||||
key={"kelompokUmur"}
|
||||
label={"Kelompok Umur"}
|
||||
key="kelompokUmur"
|
||||
label="Kelompok Umur"
|
||||
placeholder={indeksKepuasanState.kelompokUmurResponden.findMany.loading ? 'Memuat...' : 'Pilih kelompok umur'}
|
||||
value={state.create.form.kelompokUmurId || ""}
|
||||
onChange={(val) => {
|
||||
@@ -661,19 +712,16 @@ const state = useProxy(indeksKepuasanState.responden);
|
||||
}}
|
||||
data={
|
||||
(indeksKepuasanState.kelompokUmurResponden.findMany.data || [])
|
||||
.filter(Boolean) // Hapus null, undefined, dll
|
||||
.filter(Boolean)
|
||||
.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name || 'Tanpa Nama',
|
||||
}))
|
||||
}
|
||||
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
|
||||
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
|
||||
/>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
<Button mt={10} bg={colors['blue-button']} onClick={handleSubmit}>
|
||||
Submit
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
@@ -12,7 +12,8 @@ import {
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput
|
||||
TextInput,
|
||||
Title
|
||||
} from '@mantine/core';
|
||||
import { IconSend2 } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -55,7 +56,7 @@ function Page() {
|
||||
|
||||
const submitForms = async () => {
|
||||
const { create } = permohonanInformasiPublikState.statepermohonanInformasiPublik;
|
||||
const hasil = await create.create(); // tunggu hasilnya
|
||||
const hasil = await create.create();
|
||||
if (hasil) {
|
||||
router.push('/darmasaba/permohonan/berhasil');
|
||||
}
|
||||
@@ -67,14 +68,17 @@ function Page() {
|
||||
<BackButton />
|
||||
</Box>
|
||||
|
||||
<Text
|
||||
{/* MAIN PAGE TITLE */}
|
||||
<Title
|
||||
order={1}
|
||||
ta="center"
|
||||
fz={{ base: '2rem', md: '2.5rem' }}
|
||||
fz={{ base: '1.8rem', sm: '2.2rem', md: '2.6rem' }}
|
||||
lh={1.2}
|
||||
c={colors['blue-button']}
|
||||
fw="bold"
|
||||
style={{ fontWeight: 700 }}
|
||||
>
|
||||
Permohonan Informasi Publik
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Stack gap="xl">
|
||||
@@ -85,15 +89,18 @@ function Page() {
|
||||
shadow="sm"
|
||||
bg={colors['white-trans-1']}
|
||||
>
|
||||
<Text
|
||||
{/* SUBTITLE */}
|
||||
<Title
|
||||
order={2}
|
||||
pb={30}
|
||||
ta="center"
|
||||
fw="bold"
|
||||
fz={{ base: 'h4', md: 'h3' }}
|
||||
fz={{ base: '1.4rem', md: '1.8rem' }}
|
||||
lh={1.3}
|
||||
c={colors['blue-button']}
|
||||
style={{ fontWeight: 700 }}
|
||||
>
|
||||
Tata Cara Permohonan
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<SimpleGrid pb={30} cols={{ base: 1, sm: 2, lg: 4 }} spacing="lg">
|
||||
{steps.map((v) => (
|
||||
@@ -116,27 +123,38 @@ function Page() {
|
||||
c={colors['blue-button']}
|
||||
ta="center"
|
||||
fw="bold"
|
||||
fz="h3"
|
||||
fz="h2"
|
||||
lh={1}
|
||||
>
|
||||
{v.number}
|
||||
</Text>
|
||||
</ActionIcon>
|
||||
</Center>
|
||||
|
||||
<Title
|
||||
order={4}
|
||||
ta="center"
|
||||
c={colors['white-1']}
|
||||
fz="lg"
|
||||
lh={1.3}
|
||||
style={{ fontWeight: 700 }}
|
||||
>
|
||||
{v.title}
|
||||
</Title>
|
||||
|
||||
<Text
|
||||
ta="center"
|
||||
c={colors['white-1']}
|
||||
fw="bold"
|
||||
fz="lg"
|
||||
fz="sm"
|
||||
lh={1.4}
|
||||
>
|
||||
{v.title}
|
||||
</Text>
|
||||
<Text ta="center" c={colors['white-1']} fz="sm">
|
||||
{v.desc}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Paper>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
|
||||
<Group justify="center">
|
||||
<Paper
|
||||
p="xl"
|
||||
@@ -148,15 +166,20 @@ function Page() {
|
||||
maw={800}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Text
|
||||
fw="bold"
|
||||
fz={{ base: 'h4', md: 'h3' }}
|
||||
|
||||
{/* FORM TITLE */}
|
||||
<Title
|
||||
order={2}
|
||||
ta="center"
|
||||
fz={{ base: '1.4rem', md: '1.8rem' }}
|
||||
lh={1.3}
|
||||
c={colors['blue-button']}
|
||||
style={{ fontWeight: 700 }}
|
||||
>
|
||||
Formulir Permohonan Informasi
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
{/* INPUTS */}
|
||||
<TextInput
|
||||
label="Nama Lengkap"
|
||||
placeholder="Masukkan nama lengkap Anda"
|
||||
@@ -166,6 +189,7 @@ function Page() {
|
||||
val.target.value;
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Nomor Induk Kependudukan (NIK)"
|
||||
placeholder="Masukkan NIK"
|
||||
@@ -175,6 +199,7 @@ function Page() {
|
||||
val.target.value;
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Nomor Telepon"
|
||||
placeholder="Masukkan nomor telepon aktif"
|
||||
@@ -184,6 +209,7 @@ function Page() {
|
||||
val.target.value;
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Alamat Lengkap"
|
||||
placeholder="Masukkan alamat sesuai identitas"
|
||||
@@ -193,6 +219,7 @@ function Page() {
|
||||
val.target.value;
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Alamat Email"
|
||||
placeholder="Masukkan alamat email aktif"
|
||||
@@ -209,12 +236,14 @@ function Page() {
|
||||
val.id;
|
||||
}}
|
||||
/>
|
||||
|
||||
<MemperolehInformasi
|
||||
onChange={(val) => {
|
||||
permohonanInformasiPublikState.statepermohonanInformasiPublik.create.form.caraMemperolehInformasiId =
|
||||
val.id;
|
||||
}}
|
||||
/>
|
||||
|
||||
<MemperolehSalinan
|
||||
onChange={(val) => {
|
||||
permohonanInformasiPublikState.statepermohonanInformasiPublik.create.form.caraMemperolehSalinanInformasiId =
|
||||
@@ -241,6 +270,7 @@ function Page() {
|
||||
Kirim Permohonan
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Group>
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip,
|
||||
} from '@mantine/core';
|
||||
import {
|
||||
@@ -56,13 +57,8 @@ function Page() {
|
||||
const router = useRouter();
|
||||
|
||||
const submit = async () => {
|
||||
const { create } = stateKeberatan;
|
||||
|
||||
const hasil = await create.create(); // tunggu hasilnya
|
||||
|
||||
if (hasil) {
|
||||
router.push('/darmasaba/permohonan/berhasil');
|
||||
}
|
||||
const hasil = await stateKeberatan.create.create();
|
||||
if (hasil) router.push('/darmasaba/permohonan/berhasil');
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -72,15 +68,16 @@ function Page() {
|
||||
</Box>
|
||||
|
||||
<Stack align="center" px={{ base: 'md', md: 100 }}>
|
||||
<Text
|
||||
<Title
|
||||
order={1}
|
||||
ta="center"
|
||||
fz={{ base: '2rem', md: '2.8rem' }}
|
||||
fz={{ base: '1.8rem', md: '2.6rem' }}
|
||||
lh={1.2}
|
||||
c={colors['blue-button']}
|
||||
fw={800}
|
||||
style={{ letterSpacing: '-0.5px' }}
|
||||
style={{ letterSpacing: -0.5 }}
|
||||
>
|
||||
Permohonan Keberatan Informasi Publik
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<Paper
|
||||
p="xl"
|
||||
@@ -90,26 +87,36 @@ function Page() {
|
||||
withBorder
|
||||
>
|
||||
<Stack gap="xl">
|
||||
{/* Tentang */}
|
||||
<Box>
|
||||
<Text fw={700} fz={{ base: 'lg', md: 'xl' }} mb={8}>
|
||||
<Title order={3} fz={{ base: 'lg', md: 'xl' }} lh={1.3} mb={8}>
|
||||
Tentang Permohonan Keberatan
|
||||
</Text>
|
||||
<Text ta="justify" fz={{ base: 'sm', md: 'md' }} lh={1.6}>
|
||||
</Title>
|
||||
|
||||
<Text
|
||||
ta="justify"
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.7}
|
||||
c="black"
|
||||
>
|
||||
Jika Anda merasa permohonan informasi tidak ditanggapi dengan
|
||||
baik atau ditolak, Anda berhak mengajukan keberatan melalui
|
||||
formulir berikut.
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{/* Alur */}
|
||||
<Stack>
|
||||
<Text
|
||||
<Title
|
||||
order={3}
|
||||
ta="center"
|
||||
fw={700}
|
||||
fz={{ base: 'xl', md: '2xl' }}
|
||||
style={{ letterSpacing: '-0.5px' }}
|
||||
lh={1.2}
|
||||
style={{ letterSpacing: -0.5 }}
|
||||
>
|
||||
Alur Pengajuan Keberatan
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<SimpleGrid cols={{ base: 1, md: 4 }} spacing="lg">
|
||||
{data.map((v) => (
|
||||
@@ -124,15 +131,23 @@ function Page() {
|
||||
<Center>
|
||||
<v.icon size={48} color={colors['white-1']} />
|
||||
</Center>
|
||||
|
||||
<Text
|
||||
ta="center"
|
||||
c={colors['white-1']}
|
||||
fw={700}
|
||||
fz="lg"
|
||||
lh={1.3}
|
||||
>
|
||||
{v.title}
|
||||
</Text>
|
||||
<Text ta="center" c={colors['white-1']} fz="sm">
|
||||
|
||||
<Text
|
||||
ta="center"
|
||||
c={colors['white-1']}
|
||||
fz="sm"
|
||||
lh={1.6}
|
||||
>
|
||||
{v.desc}
|
||||
</Text>
|
||||
</Stack>
|
||||
@@ -141,6 +156,7 @@ function Page() {
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
|
||||
{/* Form */}
|
||||
<Group justify="center">
|
||||
<Paper
|
||||
p="xl"
|
||||
@@ -152,14 +168,16 @@ function Page() {
|
||||
w="100%"
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Text
|
||||
<Title
|
||||
order={3}
|
||||
ta="center"
|
||||
fw={700}
|
||||
fz={{ base: 'lg', md: 'xl' }}
|
||||
ta="center"
|
||||
lh={1.3}
|
||||
mb={4}
|
||||
>
|
||||
Formulir Keberatan
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<TextInput
|
||||
label="Nama Lengkap"
|
||||
@@ -196,7 +214,7 @@ function Page() {
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<Text fw={600} fz="sm" mb={6}>
|
||||
<Text fw={600} fz="sm" lh={1.4} mb={6}>
|
||||
Alasan Keberatan
|
||||
</Text>
|
||||
<PPIDTextEditor
|
||||
@@ -222,11 +240,13 @@ function Page() {
|
||||
</Paper>
|
||||
</Group>
|
||||
|
||||
{/* Kontak */}
|
||||
<Stack gap={4} pt="lg" align="center">
|
||||
<Text fw={700} fz="lg">
|
||||
<Title order={4} fw={700} fz="lg" lh={1.3}>
|
||||
Kontak PPID
|
||||
</Text>
|
||||
<Text fz="sm" c="dimmed">
|
||||
</Title>
|
||||
|
||||
<Text fz="sm" lh={1.5} c="dimmed" ta="center">
|
||||
Email: desadarmasaba@badungkab.go.id | WhatsApp: 081-xxx-xxx-xxx
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
@@ -1,79 +1,134 @@
|
||||
'use client'
|
||||
import stateProfilePPID from '@/app/admin/(dashboard)/_state/ppid/profile_ppid/profile_PPID';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Center, Divider, Flex, Image, List, Paper, SimpleGrid, Skeleton, Stack, Text } from '@mantine/core';
|
||||
import {
|
||||
Box,
|
||||
Center,
|
||||
Divider,
|
||||
Flex,
|
||||
Image,
|
||||
List,
|
||||
Paper,
|
||||
SimpleGrid,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
Title,
|
||||
} from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconBuildingCommunity, IconTargetArrow, IconTimeline, IconUser } from '@tabler/icons-react';
|
||||
import {
|
||||
IconBuildingCommunity,
|
||||
IconTargetArrow,
|
||||
IconTimeline,
|
||||
IconUser,
|
||||
} from '@tabler/icons-react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||
import ScrollToTopButton from '@/app/darmasaba/_com/scrollToTopButton';
|
||||
|
||||
function Page() {
|
||||
const allList = useProxy(stateProfilePPID)
|
||||
useShallowEffect(() => {
|
||||
allList.profile.load("edit")
|
||||
}, [])
|
||||
const allList = useProxy(stateProfilePPID);
|
||||
|
||||
if (!allList.profile.data) return (
|
||||
<Stack bg={colors.Bg} py="xl" gap="22">
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Skeleton h={40} />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Skeleton h={80} />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Paper p="xl" bg={colors['white-trans-1']}>
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<Skeleton key={i} h={40} mb="sm" />
|
||||
))}
|
||||
</Paper>
|
||||
</Box>
|
||||
</Stack>
|
||||
)
|
||||
useShallowEffect(() => {
|
||||
allList.profile.load('edit');
|
||||
}, []);
|
||||
|
||||
// LOADING SKELETON
|
||||
if (!allList.profile.data)
|
||||
return (
|
||||
<Stack bg={colors.Bg} py="xl" gap="22">
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Skeleton h={40} />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Skeleton h={80} />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Paper p="xl" bg={colors['white-trans-1']}>
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<Skeleton key={i} h={40} mb="sm" />
|
||||
))}
|
||||
</Paper>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
const dataArray = Array.isArray(allList.profile.data)
|
||||
? allList.profile.data
|
||||
: [allList.profile.data]
|
||||
: [allList.profile.data];
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||
{/* Back Button */}
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
|
||||
{/* Page Title */}
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Text ta="center" fz={{ base: "2rem", md: "2.5rem", lg: "3rem", xl: "3.4rem" }} c={colors["blue-button"]} fw="bold">
|
||||
<Title
|
||||
order={1}
|
||||
ta="center"
|
||||
c={colors['blue-button']}
|
||||
fz={{ base: '2rem', md: '2.7rem', lg: '3.2rem', xl: '3.6rem' }}
|
||||
lh={{ base: 1.1, md: 1.1 }}
|
||||
fw={900}
|
||||
>
|
||||
Profil PPID Desa Darmasaba
|
||||
</Text>
|
||||
</Title>
|
||||
</Box>
|
||||
|
||||
{dataArray.map((item) => (
|
||||
<Box key={item.id} px={{ base: "md", md: 100 }}>
|
||||
<Box key={item.id} px={{ base: 'md', md: 100 }}>
|
||||
<Paper p="xl" bg={colors['white-trans-1']} radius="lg" shadow="xl">
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
{/* LOGO & TITLE */}
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Center>
|
||||
<Image loading='lazy' src="/darmasaba-icon.png" h={{ base: 70, md: 120 }} w={{ base: 70, md: 120 }} alt="Logo Desa" />
|
||||
<Image
|
||||
loading="lazy"
|
||||
src="/darmasaba-icon.png"
|
||||
h={{ base: 70, md: 120 }}
|
||||
w={{ base: 70, md: 120 }}
|
||||
alt="Logo Desa"
|
||||
/>
|
||||
</Center>
|
||||
<Text ta="center" fz={{ base: "1.2rem", md: "2rem", lg: "2.5rem", xl: "3rem" }} fw="bold">
|
||||
|
||||
<Title
|
||||
order={2}
|
||||
ta="center"
|
||||
fz={{ base: '1.4rem', md: '2.2rem', lg: '2.6rem', xl: '3rem' }}
|
||||
lh={1.1}
|
||||
fw={800}
|
||||
mt="md"
|
||||
>
|
||||
Pejabat Pengelola Informasi dan Dokumentasi
|
||||
</Text>
|
||||
</Title>
|
||||
</Box>
|
||||
|
||||
<Divider my="lg" />
|
||||
|
||||
{/* GRID BLOCK */}
|
||||
<Box px={{ base: 0, md: 50 }} pb={40}>
|
||||
<SimpleGrid cols={{ base: 1, xl: 2 }} spacing="xl">
|
||||
{/* FOTO + NAMA */}
|
||||
<Box px={{ base: 0, md: 50 }}>
|
||||
<Paper bg={colors['white-trans-1']} radius="xl" shadow="md" withBorder>
|
||||
<Stack gap={0}>
|
||||
<Image
|
||||
pt={{ base: 0, md: 100 }}
|
||||
px="lg"
|
||||
src={item.image?.link ? `${item.image.link}?t=${Date.now()}` : "/perbekel.png"}
|
||||
src={
|
||||
item.image?.link
|
||||
? `${item.image.link}?t=${Date.now()}`
|
||||
: '/perbekel.png'
|
||||
}
|
||||
alt="Foto Pimpinan"
|
||||
radius="lg"
|
||||
onError={(e) => e.currentTarget.src = "/perbekel.png"}
|
||||
onError={(e) => (e.currentTarget.src = '/perbekel.png')}
|
||||
loading="lazy"
|
||||
/>
|
||||
|
||||
<Paper
|
||||
bg={colors['blue-button']}
|
||||
px="lg"
|
||||
@@ -81,33 +136,62 @@ function Page() {
|
||||
className="glass3"
|
||||
py={{ base: 20, md: 50 }}
|
||||
>
|
||||
<Text ta="center" c={colors['white-1']} fw="bolder" fz={{ base: "xl", md: "h2" }}>
|
||||
<Title
|
||||
order={3}
|
||||
ta="center"
|
||||
c={colors['white-1']}
|
||||
fz={{ base: '1.4rem', md: '2.2rem' }}
|
||||
lh={1.1}
|
||||
fw={900}
|
||||
>
|
||||
{item.name}
|
||||
</Text>
|
||||
</Title>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* BIOGRAFI & RIWAYAT */}
|
||||
<Box>
|
||||
<Stack gap="xl">
|
||||
{/* BIO */}
|
||||
<Box>
|
||||
<Flex align="center" gap="sm" mb="sm">
|
||||
<IconUser size={28} />
|
||||
<Text fz={{ base: "1.25rem", md: "1.5rem" }} fw="bold">Biografi</Text>
|
||||
<Title order={3} fz={{ base: '1.3rem', md: '1.6rem' }} lh={1.2} fw={800}>
|
||||
Biografi
|
||||
</Title>
|
||||
</Flex>
|
||||
|
||||
<Box px={20}>
|
||||
<Text fz={{ base: "1rem", md: "1.125rem", lg: "1.25rem" }} ta="justify" dangerouslySetInnerHTML={{ __html: item.biodata }} style={{ wordBreak: "break-word", whiteSpace: "normal" }} />
|
||||
<Text
|
||||
fz={{ base: '1rem', md: '1.1rem', lg: '1.2rem' }}
|
||||
lh={1.6}
|
||||
ta="justify"
|
||||
dangerouslySetInnerHTML={{ __html: item.biodata }}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* RIWAYAT */}
|
||||
<Box>
|
||||
<Flex align="center" gap="sm" mb="sm">
|
||||
<IconTimeline size={28} />
|
||||
<Text fz={{ base: "1.25rem", md: "1.5rem" }} fw="bold">Riwayat Karir</Text>
|
||||
<Title order={3} fz={{ base: '1.3rem', md: '1.6rem' }} lh={1.2} fw={800}>
|
||||
Riwayat Karir
|
||||
</Title>
|
||||
</Flex>
|
||||
|
||||
<List spacing="xs" size="sm">
|
||||
<Box px={20}>
|
||||
<Text fz={{ base: "1rem", md: "1.125rem", lg: "1.25rem" }} dangerouslySetInnerHTML={{ __html: item.riwayat }} style={{ wordBreak: "break-word", whiteSpace: "normal" }} />
|
||||
<Text
|
||||
fz={{ base: '1rem', md: '1.1rem', lg: '1.2rem' }}
|
||||
lh={1.6}
|
||||
ta="justify"
|
||||
dangerouslySetInnerHTML={{ __html: item.riwayat }}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
/>
|
||||
</Box>
|
||||
</List>
|
||||
</Box>
|
||||
@@ -116,26 +200,46 @@ function Page() {
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
|
||||
{/* ORGANISASI */}
|
||||
<Box pb={40}>
|
||||
<Flex align="center" gap="sm" mb="sm">
|
||||
<IconBuildingCommunity size={28} />
|
||||
<Text fz={{ base: "1.25rem", md: "1.5rem" }} fw="bold">Pengalaman Organisasi</Text>
|
||||
<Title order={3} fz={{ base: '1.3rem', md: '1.6rem' }} lh={1.2} fw={800}>
|
||||
Pengalaman Organisasi
|
||||
</Title>
|
||||
</Flex>
|
||||
|
||||
<List spacing="xs" size="sm">
|
||||
<Box px={20}>
|
||||
<Text fz={{ base: "1rem", md: "1.125rem" }} ta="justify" dangerouslySetInnerHTML={{ __html: item.pengalaman }} style={{ wordBreak: "break-word", whiteSpace: "normal" }} />
|
||||
<Text
|
||||
fz={{ base: '1rem', md: '1.1rem' }}
|
||||
lh={1.6}
|
||||
ta="justify"
|
||||
dangerouslySetInnerHTML={{ __html: item.pengalaman }}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
/>
|
||||
</Box>
|
||||
</List>
|
||||
</Box>
|
||||
|
||||
{/* PROGRAM UNGGULAN */}
|
||||
<Box>
|
||||
<Flex align="center" gap="sm" mb="sm">
|
||||
<IconTargetArrow size={28} />
|
||||
<Text fz={{ base: "1.25rem", md: "1.5rem" }} fw="bold">Program Unggulan</Text>
|
||||
<Title order={3} fz={{ base: '1.3rem', md: '1.6rem' }} lh={1.2} fw={800}>
|
||||
Program Unggulan
|
||||
</Title>
|
||||
</Flex>
|
||||
|
||||
<List spacing="xs" size="sm">
|
||||
<Box px={20}>
|
||||
<Text fz={{ base: "1rem", md: "1.125rem" }} ta="justify" dangerouslySetInnerHTML={{ __html: item.unggulan }} style={{ wordBreak: "break-word", whiteSpace: "normal" }} />
|
||||
<Text
|
||||
fz={{ base: '1rem', md: '1.1rem' }}
|
||||
lh={1.6}
|
||||
ta="justify"
|
||||
dangerouslySetInnerHTML={{ __html: item.unggulan }}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
/>
|
||||
</Box>
|
||||
</List>
|
||||
</Box>
|
||||
@@ -143,10 +247,11 @@ function Page() {
|
||||
</Box>
|
||||
))}
|
||||
</Stack>
|
||||
{/* Tombol Scroll ke Atas */}
|
||||
|
||||
{/* tombol scroll */}
|
||||
<ScrollToTopButton />
|
||||
</Box>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default Page
|
||||
export default Page;
|
||||
|
||||
@@ -27,7 +27,6 @@ function DetailPegawaiUser() {
|
||||
statePegawai.findUnique.load(params?.id as string);
|
||||
}, []);
|
||||
|
||||
|
||||
if (!statePegawai.findUnique.data) {
|
||||
return (
|
||||
<Stack py="lg">
|
||||
@@ -52,7 +51,7 @@ function DetailPegawaiUser() {
|
||||
}}
|
||||
>
|
||||
<IconArrowBack size={22} color={colors['blue-button']} />
|
||||
<Text c={colors['blue-button']} fw={500}>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} lh="1.4" fw={500} c={colors['blue-button']}>
|
||||
Kembali
|
||||
</Text>
|
||||
</Box>
|
||||
@@ -65,9 +64,7 @@ function DetailPegawaiUser() {
|
||||
radius="lg"
|
||||
shadow="sm"
|
||||
bg="white"
|
||||
style={{
|
||||
border: '1px solid #eaeaea',
|
||||
}}
|
||||
style={{ border: '1px solid #eaeaea' }}
|
||||
>
|
||||
<Stack align="center" gap="md">
|
||||
{/* Foto Profil */}
|
||||
@@ -84,10 +81,23 @@ function DetailPegawaiUser() {
|
||||
|
||||
{/* Nama & Jabatan */}
|
||||
<Stack align="center" gap={2}>
|
||||
<Title order={3} fw={700} c={colors['blue-button']}>
|
||||
<Title
|
||||
order={2}
|
||||
c={colors['blue-button']}
|
||||
fw={700}
|
||||
fz={{ base: 'xl', md: '28px' }}
|
||||
lh="1.2"
|
||||
ta="center"
|
||||
>
|
||||
{data.namaLengkap || '-'} {data.gelarAkademik || ''}
|
||||
</Title>
|
||||
<Text fz="sm" c="dimmed">
|
||||
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh="1.4"
|
||||
c="dimmed"
|
||||
ta="center"
|
||||
>
|
||||
{data.posisi?.nama || 'Posisi tidak tersedia'}
|
||||
</Text>
|
||||
</Stack>
|
||||
@@ -105,10 +115,10 @@ function DetailPegawaiUser() {
|
||||
value={
|
||||
data.tanggalMasuk
|
||||
? new Date(data.tanggalMasuk).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
})
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
})
|
||||
: '-'
|
||||
}
|
||||
/>
|
||||
@@ -123,7 +133,7 @@ function DetailPegawaiUser() {
|
||||
);
|
||||
}
|
||||
|
||||
/* Komponen kecil untuk menampilkan baris informasi */
|
||||
/* Komponen Baris Informasi */
|
||||
function InfoRow({
|
||||
label,
|
||||
value,
|
||||
@@ -137,11 +147,18 @@ function InfoRow({
|
||||
}) {
|
||||
return (
|
||||
<Box>
|
||||
<Text fz="sm" fw={600} c="dark">
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
fw={600}
|
||||
lh="1.3"
|
||||
c="dark"
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
fz="sm"
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh="1.5"
|
||||
c={valueColor || 'dimmed'}
|
||||
style={{
|
||||
whiteSpace: multiline ? 'normal' : 'nowrap',
|
||||
|
||||
@@ -59,10 +59,11 @@ export default function Page() {
|
||||
ta="center"
|
||||
c={colors['blue-button']}
|
||||
fz={{ base: 28, md: 36, lg: 44 }}
|
||||
lh={{ base: 1.05, md: 1.03 }}
|
||||
>
|
||||
Struktur Organisasi PPID
|
||||
</Title>
|
||||
<Text ta="center" c="black" maw={800}>
|
||||
<Text ta="center" c="black" maw={800} fz={{ base: 13, md: 15 }} lh={1.45}>
|
||||
Gambaran visual peran dan pegawai yang ditugaskan. Arahkan kursor
|
||||
untuk melihat detail atau klik node untuk fokus tampilan.
|
||||
</Text>
|
||||
@@ -105,8 +106,8 @@ function StrukturOrganisasiPPID() {
|
||||
<Center py={48}>
|
||||
<Stack align="center" gap="sm">
|
||||
<Loader size="lg" />
|
||||
<Text fw={600}>Memuat struktur organisasi…</Text>
|
||||
<Text c="dimmed" size="sm">
|
||||
<Text fw={600} fz={{ base: 15, md: 16 }} lh={1.2}>Memuat struktur organisasi…</Text>
|
||||
<Text c="dimmed" fz={{ base: 12, md: 13 }} lh={1.4}>
|
||||
Mengambil data pegawai dan posisi. Mohon tunggu sebentar.
|
||||
</Text>
|
||||
</Stack>
|
||||
@@ -132,10 +133,10 @@ function StrukturOrganisasiPPID() {
|
||||
<Center>
|
||||
<IconUsers size={56} />
|
||||
</Center>
|
||||
<Title order={3} mt="md">
|
||||
<Title order={3} mt="md" fz={{ base: 16, md: 18 }} lh={1.15}>
|
||||
Data pegawai belum tersedia
|
||||
</Title>
|
||||
<Text c="dimmed" mt="xs">
|
||||
<Text c="dimmed" mt="xs" fz={{ base: 13, md: 14 }} lh={1.4}>
|
||||
Belum ada data pegawai yang tercatat untuk PPID.
|
||||
</Text>
|
||||
<Group justify="center" mt="lg">
|
||||
@@ -232,11 +233,18 @@ function StrukturOrganisasiPPID() {
|
||||
{/* 🔍 Controls */}
|
||||
<Paper
|
||||
shadow="xs"
|
||||
w={{
|
||||
base: '100%', // Mobile: 100%
|
||||
sm: '40%', // Tablet: 95%
|
||||
md: '39%', // Desktop: 70%
|
||||
lg: '38%', // Desktop L: 60%
|
||||
xl: '37%', // 4K: 50%
|
||||
'2xl': '36%', // Ultra-wide: 45%
|
||||
}}
|
||||
p="md"
|
||||
radius="md"
|
||||
style={{
|
||||
background: colors['blue-button'],
|
||||
width: '100%', // ⬅️ penting
|
||||
background: colors['blue-button'], // ⬅️ penting
|
||||
maxWidth: '100%', // ⬅️ penting
|
||||
overflowX: 'auto' // ⬅️ untuk mencegah overflow
|
||||
}}
|
||||
@@ -269,30 +277,33 @@ function StrukturOrganisasiPPID() {
|
||||
fontSize: '0.875rem',
|
||||
padding: '6px 12px',
|
||||
minHeight: 'auto',
|
||||
flexShrink: 0, // 👈 PENTING: mencegah tab mengecil
|
||||
flexShrink: 0,
|
||||
},
|
||||
}}
|
||||
style={{ width: '100%' }} // 👈 penting
|
||||
>
|
||||
<TabsList
|
||||
style={{
|
||||
display: 'flex',
|
||||
overflowX: 'auto',
|
||||
overflowY: 'hidden', // 👈 tambahkan ini
|
||||
overflowY: 'hidden',
|
||||
gap: '4px',
|
||||
paddingBottom: '4px',
|
||||
flexWrap: 'nowrap',
|
||||
WebkitOverflowScrolling: 'touch', // 👈 smooth scroll di iOS
|
||||
scrollbarWidth: 'thin', // 👈 scrollbar tipis di Firefox
|
||||
msOverflowStyle: '-ms-autohiding-scrollbar', // 👈 untuk IE/Edge
|
||||
WebkitOverflowScrolling: 'touch',
|
||||
scrollbarWidth: 'thin',
|
||||
msOverflowStyle: '-ms-autohiding-scrollbar',
|
||||
maxWidth: '100%',
|
||||
scrollBehavior: 'smooth', // 👈 smooth scroll
|
||||
}}
|
||||
>
|
||||
<TabsTab
|
||||
value="zoom-out"
|
||||
onClick={handleZoomOut}
|
||||
leftSection={<IconZoomOut size={16} />}
|
||||
style={{ flexShrink: 0 }} // 👈 pastikan tidak mengecil
|
||||
style={{ flexShrink: 0 }}
|
||||
>
|
||||
Zoom Out
|
||||
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">Zoom Out</Text>
|
||||
</TabsTab>
|
||||
|
||||
<Box
|
||||
@@ -301,7 +312,6 @@ function StrukturOrganisasiPPID() {
|
||||
px={12}
|
||||
py={6}
|
||||
style={{
|
||||
fontSize: 14,
|
||||
fontWeight: 700,
|
||||
borderRadius: '6px',
|
||||
minWidth: 60,
|
||||
@@ -310,10 +320,12 @@ function StrukturOrganisasiPPID() {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
whiteSpace: 'nowrap', // 👈 mencegah text wrap
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{Math.round(scale * 100)}%
|
||||
<Text fz={{ base: 12, sm: 13 }} lh={1} c={colors['blue-button']}>
|
||||
{Math.round(scale * 100)}%
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<TabsTab
|
||||
@@ -322,7 +334,7 @@ function StrukturOrganisasiPPID() {
|
||||
leftSection={<IconZoomIn size={16} />}
|
||||
style={{ flexShrink: 0 }}
|
||||
>
|
||||
Zoom In
|
||||
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">Zoom In</Text>
|
||||
</TabsTab>
|
||||
|
||||
<TabsTab
|
||||
@@ -330,7 +342,7 @@ function StrukturOrganisasiPPID() {
|
||||
onClick={resetZoom}
|
||||
style={{ flexShrink: 0 }}
|
||||
>
|
||||
Reset
|
||||
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">Reset</Text>
|
||||
</TabsTab>
|
||||
|
||||
<TabsTab
|
||||
@@ -345,7 +357,9 @@ function StrukturOrganisasiPPID() {
|
||||
}
|
||||
style={{ flexShrink: 0 }}
|
||||
>
|
||||
{isFullscreen ? 'Exit' : 'Fullscreen'}
|
||||
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">
|
||||
{isFullscreen ? 'Exit' : 'Fullscreen'}
|
||||
</Text>
|
||||
</TabsTab>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
@@ -451,18 +465,17 @@ function NodeCard({ node, router }: any) {
|
||||
{/* Name */}
|
||||
<Text
|
||||
fw={700}
|
||||
size="sm"
|
||||
ta="center"
|
||||
c={colors['blue-button']}
|
||||
lineClamp={2}
|
||||
fz={{ base: 13, md: 15 }}
|
||||
lh={1.2}
|
||||
style={{
|
||||
// fontSize: 'clamp(12px, 4vw, 16px)', // 👈 responsif font size
|
||||
minHeight: 40,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
wordBreak: 'break-word',
|
||||
lineHeight: 1.3,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
@@ -470,18 +483,18 @@ function NodeCard({ node, router }: any) {
|
||||
|
||||
{/* Title/Position */}
|
||||
<Text
|
||||
size="xs"
|
||||
c="dimmed"
|
||||
ta="center"
|
||||
fw={500}
|
||||
lineClamp={2}
|
||||
fz={{ base: 12, md: 13 }}
|
||||
lh={1.3}
|
||||
style={{
|
||||
minHeight: 32,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
wordBreak: 'break-word',
|
||||
lineHeight: 1.2,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
@@ -504,7 +517,7 @@ function NodeCard({ node, router }: any) {
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Lihat Detail
|
||||
<Text fz={{ base: 12, md: 13 }} lh={1} ta="center">Lihat Detail</Text>
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
'use client'
|
||||
import stateVisiMisiPPID from '@/app/admin/(dashboard)/_state/ppid/visi_misi_ppid/visimisiPPID';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Center, Image, Paper, Skeleton, Stack, Text, Divider, Transition } from '@mantine/core';
|
||||
import {
|
||||
Box,
|
||||
Center,
|
||||
Image,
|
||||
Paper,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
Divider,
|
||||
Transition,
|
||||
Title
|
||||
} from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { IconSparkles } from '@tabler/icons-react';
|
||||
@@ -9,6 +20,7 @@ import BackButton from '../../desa/layanan/_com/BackButto';
|
||||
|
||||
function Page() {
|
||||
const allList = useProxy(stateVisiMisiPPID);
|
||||
|
||||
useShallowEffect(() => {
|
||||
allList.findById.load("1");
|
||||
}, []);
|
||||
@@ -35,7 +47,7 @@ function Page() {
|
||||
|
||||
{dataArray.map((item) => (
|
||||
<Box key={item.id} px={{ base: 'md', md: 100 }}>
|
||||
<Transition mounted={true} transition="fade" duration={500} timingFunction="ease">
|
||||
<Transition mounted transition="fade" duration={500} timingFunction="ease">
|
||||
{(styles) => (
|
||||
<Paper
|
||||
style={styles}
|
||||
@@ -46,56 +58,93 @@ function Page() {
|
||||
withBorder
|
||||
>
|
||||
<Stack gap="xl">
|
||||
|
||||
{/* ==== MOTTO SECTION ==== */}
|
||||
<Box>
|
||||
<Center mb="md">
|
||||
<Image src="/darmasaba-icon.png" w={{ base: 80, md: 130 }} alt="Logo Desa Darmasaba" loading='lazy' />
|
||||
<Image
|
||||
src="/darmasaba-icon.png"
|
||||
w={{ base: 80, md: 130 }}
|
||||
alt="Logo Desa Darmasaba"
|
||||
loading="lazy"
|
||||
/>
|
||||
</Center>
|
||||
<Text
|
||||
|
||||
<Title
|
||||
order={2}
|
||||
ta="center"
|
||||
fz={{ base: 28, md: 36 }}
|
||||
fw={800}
|
||||
fz={{ base: 26, md: 34 }}
|
||||
lh={1.2}
|
||||
c={colors['blue-button']}
|
||||
>
|
||||
Moto PPID Desa Darmasaba
|
||||
</Text>
|
||||
<Text ta="center" fz={{ base: 16, md: 20 }} mt="xs">
|
||||
</Title>
|
||||
|
||||
<Text
|
||||
ta="center"
|
||||
fz={{ base: 15, md: 18 }}
|
||||
lh={1.5}
|
||||
c={"black"}
|
||||
mt="xs"
|
||||
>
|
||||
Memberikan informasi yang cepat, mudah, tepat, dan transparan
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Divider my="sm" labelPosition="center" label={<IconSparkles size={18} />} />
|
||||
<Divider
|
||||
my="sm"
|
||||
labelPosition="center"
|
||||
label={<IconSparkles size={18} />}
|
||||
/>
|
||||
|
||||
{/* ==== VISI SECTION ==== */}
|
||||
<Box>
|
||||
<Text ta="center" fz={{ base: 24, md: 30 }} fw={800}
|
||||
c={colors['blue-button']} mb="sm">
|
||||
Visi PPID
|
||||
</Text>
|
||||
<Text
|
||||
fz={{ base: 'md', md: 'lg' }}
|
||||
lh={1.7}
|
||||
<Title
|
||||
order={3}
|
||||
ta="center"
|
||||
fz={{ base: 22, md: 28 }}
|
||||
lh={1.2}
|
||||
c={colors['blue-button']}
|
||||
mb="sm"
|
||||
>
|
||||
Visi PPID
|
||||
</Title>
|
||||
|
||||
<Text
|
||||
ta="center"
|
||||
fz={{ base: 15, md: 18 }}
|
||||
lh={1.7}
|
||||
dangerouslySetInnerHTML={{ __html: item.visi }}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Divider my="sm" />
|
||||
|
||||
{/* ==== MISI SECTION ==== */}
|
||||
<Box>
|
||||
<Text ta="center" fz={{ base: 24, md: 30 }} fw={800}
|
||||
c={colors['blue-button']} mb="sm">
|
||||
<Title
|
||||
order={3}
|
||||
ta="center"
|
||||
fz={{ base: 22, md: 28 }}
|
||||
lh={1.2}
|
||||
c={colors['blue-button']}
|
||||
mb="sm"
|
||||
>
|
||||
Misi PPID
|
||||
</Text>
|
||||
</Title>
|
||||
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
fz={{ base: 'md', md: 'lg' }}
|
||||
ta="justify"
|
||||
fz={{ base: 15, md: 18 }}
|
||||
lh={1.7}
|
||||
dangerouslySetInnerHTML={{ __html: item.misi }}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
</Stack>
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user