Merge pull request 'nico/12-des-25' (#41) from nico/12-des-25 into staggingweb
Reviewed-on: http://wibugit.wibudev.com/wibu/desa-darmasaba/pulls/41
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client';
|
||||||
import stateDashboardBerita from '@/app/admin/(dashboard)/_state/desa/berita';
|
import stateDashboardBerita from '@/app/admin/(dashboard)/_state/desa/berita';
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
@@ -51,10 +51,14 @@ export default function Content({ kategori }: { kategori: string }) {
|
|||||||
<Container size="xl" px={{ base: 'md', md: 'xl' }}>
|
<Container size="xl" px={{ base: 'md', md: 'xl' }}>
|
||||||
{/* === Berita Utama === */}
|
{/* === Berita Utama === */}
|
||||||
{featuredState.loading ? (
|
{featuredState.loading ? (
|
||||||
<Center><Skeleton h={400} /></Center>
|
<Center>
|
||||||
|
<Skeleton h={400} />
|
||||||
|
</Center>
|
||||||
) : featured ? (
|
) : featured ? (
|
||||||
<Box mb={50}>
|
<Box mb={50}>
|
||||||
<Text fz="h2" fw={700} mb="md">Berita Utama</Text>
|
<Title order={2} mb="md">
|
||||||
|
Berita Utama
|
||||||
|
</Title>
|
||||||
<Paper shadow="md" radius="md" withBorder>
|
<Paper shadow="md" radius="md" withBorder>
|
||||||
<Grid gutter={0}>
|
<Grid gutter={0}>
|
||||||
<GridCol span={{ base: 12, md: 6 }}>
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
@@ -74,13 +78,29 @@ export default function Content({ kategori }: { kategori: string }) {
|
|||||||
<Badge color="blue" variant="light" mb="md">
|
<Badge color="blue" variant="light" mb="md">
|
||||||
{featured.kategoriBerita?.name || kategori}
|
{featured.kategoriBerita?.name || kategori}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Title order={2} mb="md">{featured.judul}</Title>
|
<Title order={3} mb="md">
|
||||||
<Text c="dimmed" lineClamp={3} mb="md" dangerouslySetInnerHTML={{ __html: featured.deskripsi }} />
|
{featured.judul}
|
||||||
|
</Title>
|
||||||
|
<Text
|
||||||
|
c="dimmed"
|
||||||
|
lineClamp={3}
|
||||||
|
mb="md"
|
||||||
|
style={{ lineHeight: 1.6 }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: featured.deskripsi }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Group justify="apart" mt="auto">
|
<Group justify="apart" mt="auto">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconCalendar size={18} />
|
<IconCalendar size={18} />
|
||||||
<Text size="sm">
|
<Text
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
c="dimmed"
|
||||||
|
lh={1.5}
|
||||||
|
style={{
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
lineHeight: '1.5rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{new Date(featured.createdAt).toLocaleDateString('id-ID', {
|
{new Date(featured.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
@@ -91,7 +111,9 @@ export default function Content({ kategori }: { kategori: string }) {
|
|||||||
<Button
|
<Button
|
||||||
variant="light"
|
variant="light"
|
||||||
rightSection={<IconArrowRight size={16} />}
|
rightSection={<IconArrowRight size={16} />}
|
||||||
onClick={() => router.push(`/darmasaba/desa/berita/${kategori}/${featured.id}`)}
|
onClick={() =>
|
||||||
|
router.push(`/darmasaba/desa/berita/${kategori}/${featured.id}`)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Baca Selengkapnya
|
Baca Selengkapnya
|
||||||
</Button>
|
</Button>
|
||||||
@@ -105,19 +127,29 @@ export default function Content({ kategori }: { kategori: string }) {
|
|||||||
|
|
||||||
{/* === Daftar Berita === */}
|
{/* === Daftar Berita === */}
|
||||||
<Box mt={50}>
|
<Box mt={50}>
|
||||||
<Title order={2} mb="md">Daftar Berita</Title>
|
<Title order={2} mb="md">
|
||||||
|
Daftar Berita
|
||||||
|
</Title>
|
||||||
<Divider mb="xl" />
|
<Divider mb="xl" />
|
||||||
|
|
||||||
{state.findMany.loading ? (
|
{state.findMany.loading ? (
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="xl">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="xl">
|
||||||
{Array(3).fill(0).map((_, i) => (
|
{Array(3)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
<Skeleton key={i} h={300} radius="md" />
|
<Skeleton key={i} h={300} radius="md" />
|
||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
) : paginatedNews.length === 0 ? (
|
) : paginatedNews.length === 0 ? (
|
||||||
<Text c="dimmed" ta="center">Belum ada berita di kategori "{kategori}".</Text>
|
<Text c="dimmed" ta="center" fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||||
|
Belum ada berita di kategori "{kategori}".
|
||||||
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="xl" verticalSpacing="xl">
|
<SimpleGrid
|
||||||
|
cols={{ base: 1, sm: 2, lg: 3 }}
|
||||||
|
spacing="xl"
|
||||||
|
verticalSpacing="xl"
|
||||||
|
>
|
||||||
{paginatedNews.map((item) => (
|
{paginatedNews.map((item) => (
|
||||||
<Card
|
<Card
|
||||||
key={item.id}
|
key={item.id}
|
||||||
@@ -125,19 +157,51 @@ export default function Content({ kategori }: { kategori: string }) {
|
|||||||
p="lg"
|
p="lg"
|
||||||
radius="md"
|
radius="md"
|
||||||
withBorder
|
withBorder
|
||||||
onClick={() => router.push(`/darmasaba/desa/berita/${kategori}/${item.id}`)}
|
onClick={() =>
|
||||||
|
router.push(`/darmasaba/desa/berita/${kategori}/${item.id}`)
|
||||||
|
}
|
||||||
style={{ cursor: 'pointer' }}
|
style={{ cursor: 'pointer' }}
|
||||||
>
|
>
|
||||||
<Card.Section>
|
<Card.Section>
|
||||||
<Image src={item.image?.link} height={200} alt={item.judul} fit="cover" loading="lazy"/>
|
<Image
|
||||||
|
src={item.image?.link}
|
||||||
|
height={200}
|
||||||
|
alt={item.judul}
|
||||||
|
fit="cover"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
</Card.Section>
|
</Card.Section>
|
||||||
<Badge color="blue" variant="light" mt="md">
|
<Badge color="blue" variant="light" mt="md">
|
||||||
{item.kategoriBerita?.name || kategori}
|
{item.kategoriBerita?.name || kategori}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Text fw={600} size="lg" mt="sm" lineClamp={2}>{item.judul}</Text>
|
<Title
|
||||||
<Text size="sm" c="dimmed" lineClamp={3} style={{wordBreak: "break-word", whiteSpace: "normal"}} mt="xs" dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
order={4}
|
||||||
|
mt="sm"
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
style={{ lineHeight: 1.4 }}
|
||||||
|
lineClamp={2}
|
||||||
|
>
|
||||||
|
{item.judul}
|
||||||
|
</Title>
|
||||||
|
<Text
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
c="dimmed"
|
||||||
|
lineClamp={3}
|
||||||
|
style={{
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
whiteSpace: 'normal',
|
||||||
|
lineHeight: 1.5,
|
||||||
|
}}
|
||||||
|
mt="xs"
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
|
/>
|
||||||
<Group justify="apart" mt="md" gap="xs">
|
<Group justify="apart" mt="md" gap="xs">
|
||||||
<Text size="xs" c="dimmed">
|
<Text
|
||||||
|
fz={{ base: 'xs', md: 'xs' }}
|
||||||
|
c="dimmed"
|
||||||
|
lh={1.4}
|
||||||
|
style={{ fontSize: '0.75rem', lineHeight: '1.125rem' }}
|
||||||
|
>
|
||||||
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
|
|||||||
@@ -3,18 +3,16 @@
|
|||||||
import stateDashboardBerita from '@/app/admin/(dashboard)/_state/desa/berita';
|
import stateDashboardBerita from '@/app/admin/(dashboard)/_state/desa/berita';
|
||||||
import NewsReader from '@/app/darmasaba/_com/NewsReader';
|
import NewsReader from '@/app/darmasaba/_com/NewsReader';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Container, Group, Image, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Center, Container, Group, Image, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const params = useParams<{ id: string }>();
|
const params = useParams<{ id: string }>();
|
||||||
const id = Array.isArray(params.id) ? params.id[0] : params.id;
|
const id = Array.isArray(params.id) ? params.id[0] : params.id;
|
||||||
const state = useProxy(stateDashboardBerita.berita)
|
const state = useProxy(stateDashboardBerita.berita);
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
@@ -27,9 +25,9 @@ function Page() {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
loadData()
|
loadData();
|
||||||
}, [id])
|
}, [id]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@@ -47,41 +45,49 @@ function Page() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} pb={"xl"} gap={"xs"} px={{ base: "md", md: 0 }}>
|
<Stack pos="relative" bg={colors.Bg} pb="xl" gap="xs" px={{ base: 'md', md: 0 }}>
|
||||||
<Group px={{ base: "md", md: 100 }}>
|
<Group px={{ base: 'md', md: 100 }}>
|
||||||
<NewsReader />
|
<NewsReader />
|
||||||
</Group>
|
</Group>
|
||||||
<Container w={{ base: "100%", md: "50%" }} >
|
<Container w={{ base: '100%', md: '50%' }}>
|
||||||
<Box pb={20}>
|
<Box pb={20}>
|
||||||
<Text id='news-title' ta={"center"} fz={"2.4rem"} c={colors["blue-button"]} fw={"bold"}>
|
<Title
|
||||||
{state.findUnique.data?.judul}
|
id="news-title"
|
||||||
</Text>
|
order={1}
|
||||||
<Text
|
ta="center"
|
||||||
ta={"center"}
|
c={colors['blue-button']}
|
||||||
fw={"bold"}
|
fw="bold"
|
||||||
fz={"1.5rem"}
|
lh={{ base: 1.2, md: 1.25 }}
|
||||||
|
>
|
||||||
|
{state.findUnique.data.judul}
|
||||||
|
</Title>
|
||||||
|
<Title
|
||||||
|
order={2}
|
||||||
|
ta="center"
|
||||||
|
fw="bold"
|
||||||
|
fz={{ base: 'md', md: 'lg' }}
|
||||||
|
lh={{ base: 1.3, md: 1.35 }}
|
||||||
>
|
>
|
||||||
Informasi dan Pelayanan Administrasi Digital
|
Informasi dan Pelayanan Administrasi Digital
|
||||||
</Text>
|
</Title>
|
||||||
</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
|
<Text
|
||||||
id='news-content'
|
id="news-content"
|
||||||
py={20}
|
py={20}
|
||||||
fz={{ base: "sm", md: "lg" }}
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
lh={{ base: 1.6, md: 1.8 }} // ✅ line-height lebih rapat dan responsif
|
lh={{ base: 1.6, md: 1.8 }}
|
||||||
ta="justify"
|
ta="justify"
|
||||||
style={{
|
style={{
|
||||||
wordBreak: "break-word",
|
wordBreak: 'break-word',
|
||||||
whiteSpace: "normal",
|
whiteSpace: 'normal',
|
||||||
}}
|
}}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: state.findUnique.data?.content || "",
|
__html: state.findUnique.data.content || '',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -16,35 +16,30 @@ function Semua() {
|
|||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const router = useTransitionRouter();
|
const router = useTransitionRouter();
|
||||||
|
|
||||||
// Ambil parameter langsung dari URL
|
|
||||||
const search = searchParams.get('search') || '';
|
const search = searchParams.get('search') || '';
|
||||||
const page = parseInt(searchParams.get('page') || '1');
|
const page = parseInt(searchParams.get('page') || '1');
|
||||||
|
|
||||||
// Gunakan proxy untuk state global
|
|
||||||
const state = useProxy(stateDashboardBerita.berita);
|
const state = useProxy(stateDashboardBerita.berita);
|
||||||
const featured = useProxy(stateDashboardBerita.berita.findFirst);
|
const featured = useProxy(stateDashboardBerita.berita.findFirst);
|
||||||
const loadingGrid = state.findMany.loading;
|
const loadingGrid = state.findMany.loading;
|
||||||
const loadingFeatured = featured.loading;
|
const loadingFeatured = featured.loading;
|
||||||
|
|
||||||
// Load berita utama sekali saja
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!featured.data && !loadingFeatured) {
|
if (!featured.data && !loadingFeatured) {
|
||||||
stateDashboardBerita.berita.findFirst.load();
|
stateDashboardBerita.berita.findFirst.load();
|
||||||
}
|
}
|
||||||
}, [featured.data, loadingFeatured]);
|
}, [featured.data, loadingFeatured]);
|
||||||
|
|
||||||
// Load berita terbaru tiap page / search berubah
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const limit = 3;
|
const limit = 3;
|
||||||
state.findMany.load(page, limit, search);
|
state.findMany.load(page, limit, search);
|
||||||
}, [page, search]);
|
}, [page, search]);
|
||||||
|
|
||||||
// Handler pagination → langsung update URL
|
|
||||||
const handlePageChange = (newPage: number) => {
|
const handlePageChange = (newPage: number) => {
|
||||||
const url = new URLSearchParams(searchParams.toString());
|
const url = new URLSearchParams(searchParams.toString());
|
||||||
if (search) url.set('search', search);
|
if (search) url.set('search', search);
|
||||||
if (newPage > 1) url.set('page', newPage.toString());
|
if (newPage > 1) url.set('page', newPage.toString());
|
||||||
else url.delete('page'); // biar page=1 ga muncul di URL
|
else url.delete('page');
|
||||||
|
|
||||||
router.replace(`?${url.toString()}`);
|
router.replace(`?${url.toString()}`);
|
||||||
};
|
};
|
||||||
@@ -61,7 +56,7 @@ function Semua() {
|
|||||||
<Center><Skeleton h={400} /></Center>
|
<Center><Skeleton h={400} /></Center>
|
||||||
) : featuredData ? (
|
) : featuredData ? (
|
||||||
<Box mb={50}>
|
<Box mb={50}>
|
||||||
<Text fz="h2" fw={700} mb="md">Berita Utama</Text>
|
<Title order={2} mb="md">Berita Utama</Title>
|
||||||
<Paper shadow="md" radius="md" withBorder>
|
<Paper shadow="md" radius="md" withBorder>
|
||||||
<Grid gutter={0}>
|
<Grid gutter={0}>
|
||||||
<GridCol span={{ base: 12, md: 6 }}>
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
@@ -81,13 +76,24 @@ function Semua() {
|
|||||||
<Badge color="blue" variant="light" mb="md">
|
<Badge color="blue" variant="light" mb="md">
|
||||||
{featuredData.kategoriBerita?.name || 'Berita'}
|
{featuredData.kategoriBerita?.name || 'Berita'}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Title order={2} mb="md">{featuredData.judul}</Title>
|
<Title order={3} mb="md">{featuredData.judul}</Title>
|
||||||
<Text c="dimmed" lineClamp={3} mb="md" dangerouslySetInnerHTML={{ __html: featuredData.deskripsi }} />
|
<Text
|
||||||
|
c="dimmed"
|
||||||
|
lineClamp={3}
|
||||||
|
mb="md"
|
||||||
|
dangerouslySetInnerHTML={{ __html: featuredData.deskripsi }}
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Group justify="apart" mt="auto">
|
<Group justify="apart" mt="auto">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconCalendar size={18} />
|
<IconCalendar size={18} />
|
||||||
<Text size="sm">
|
<Text
|
||||||
|
c="dimmed"
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
lh={{ base: 1.4, md: 1.5 }}
|
||||||
|
>
|
||||||
{new Date(featuredData.createdAt).toLocaleDateString('id-ID', {
|
{new Date(featuredData.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
@@ -124,7 +130,9 @@ function Semua() {
|
|||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
) : paginatedNews.length === 0 ? (
|
) : paginatedNews.length === 0 ? (
|
||||||
<Text c="dimmed" ta="center">Tidak ada berita ditemukan.</Text>
|
<Text c="dimmed" ta="center" fz={{ base: 'sm', md: 'md' }} lh={{ base: 1.5, md: 1.6 }}>
|
||||||
|
Tidak ada berita ditemukan.
|
||||||
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="xl" verticalSpacing="xl">
|
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="xl" verticalSpacing="xl">
|
||||||
{paginatedNews.map((item) => (
|
{paginatedNews.map((item) => (
|
||||||
@@ -143,11 +151,24 @@ function Semua() {
|
|||||||
{item.kategoriBerita?.name || 'Berita'}
|
{item.kategoriBerita?.name || 'Berita'}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
||||||
<Text fw={600} size="lg" mt="sm" lineClamp={2}>{item.judul}</Text>
|
<Title order={4} mt="sm" lineClamp={2}>
|
||||||
<Text size="sm" c="dimmed" lineClamp={3} mt="xs" dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
{item.judul}
|
||||||
|
</Title>
|
||||||
|
<Text
|
||||||
|
c="dimmed"
|
||||||
|
lineClamp={3}
|
||||||
|
mt="xs"
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
|
/>
|
||||||
|
|
||||||
<Flex align="center" justify="apart" mt="md" gap="xs">
|
<Flex align="center" justify="apart" mt="md" gap="xs">
|
||||||
<Text size="xs" c="dimmed">
|
<Text
|
||||||
|
c="dimmed"
|
||||||
|
fz={{ base: 'xs', md: 'xs' }}
|
||||||
|
lh={{ base: 1.4, md: 1.4 }}
|
||||||
|
>
|
||||||
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
|
|||||||
@@ -17,17 +17,11 @@ import {
|
|||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconPhoto } from '@tabler/icons-react';
|
import { IconPhoto } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
// Komponen kartu foto
|
// Komponen kartu foto
|
||||||
function FotoCard({ item }: { item: any }) {
|
function FotoCard({ item }: { item: any }) {
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
router.push(`/darmasaba/galeri/foto/${item.id}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid.Col span={{ base: 12, xs: 6, md: 4 }}>
|
<Grid.Col span={{ base: 12, xs: 6, md: 4 }}>
|
||||||
@@ -35,19 +29,19 @@ function FotoCard({ item }: { item: any }) {
|
|||||||
shadow="sm"
|
shadow="sm"
|
||||||
radius="md"
|
radius="md"
|
||||||
p={0}
|
p={0}
|
||||||
onClick={handleClick}
|
style={{ transition: 'transform 0.2s' }}
|
||||||
style={{ cursor: 'pointer', transition: 'transform 0.2s' }}
|
|
||||||
onMouseEnter={(e) => (e.currentTarget.style.transform = 'scale(1.02)')}
|
onMouseEnter={(e) => (e.currentTarget.style.transform = 'scale(1.02)')}
|
||||||
onMouseLeave={(e) => (e.currentTarget.style.transform = 'scale(1)')}
|
onMouseLeave={(e) => (e.currentTarget.style.transform = 'scale(1)')}
|
||||||
|
|
||||||
>
|
>
|
||||||
{item.imageGalleryFoto?.link ? (
|
{item.imageGalleryFoto?.link ? (
|
||||||
<Box
|
<Box
|
||||||
pos="relative"
|
pos="relative"
|
||||||
style={{
|
style={{
|
||||||
paddingBottom: '100%', // ✅ Ubah ke 1:1 (square) — atau sesuaikan
|
paddingBottom: '100%',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
borderRadius: '4px 4px 0 0',
|
borderRadius: '4px 4px 0 0',
|
||||||
backgroundColor: '#f9f9f9', // ✅ background netral
|
backgroundColor: '#f9f9f9',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
@@ -61,8 +55,8 @@ function FotoCard({ item }: { item: any }) {
|
|||||||
left: 0,
|
left: 0,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
objectFit: 'contain', // ✅ Tampilkan utuh, jangan crop
|
objectFit: 'contain',
|
||||||
objectPosition: 'center', // rata tengah
|
objectPosition: 'center',
|
||||||
}}
|
}}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
@@ -74,13 +68,23 @@ function FotoCard({ item }: { item: any }) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Stack p="md" gap={4}>
|
<Stack p="md" gap={4}>
|
||||||
<Text fw={600} lineClamp={1}>
|
<Text fw={600} lineClamp={1} fz={{ base: 'sm', md: 'md' }} lh={{ base: '1.4', md: '1.5' }}>
|
||||||
{item.name || 'Tanpa Judul'}
|
{item.name || 'Tanpa Judul'}
|
||||||
</Text>
|
</Text>
|
||||||
{item.deskripsi && (
|
{item.deskripsi && (
|
||||||
<Text fz="sm" c="dimmed" lineClamp={2} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
<Text
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
c="dimmed"
|
||||||
|
lineClamp={2}
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
|
lh={{ base: '1.4', md: '1.5' }}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<Text fz="xs" c="dimmed">
|
<Text
|
||||||
|
fz={{ base: 11, md: 'xs' }}
|
||||||
|
c="dimmed"
|
||||||
|
lh={{ base: '1.3', md: '1.4' }}
|
||||||
|
>
|
||||||
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
@@ -99,7 +103,7 @@ export default function GaleriFotoUser() {
|
|||||||
return (
|
return (
|
||||||
<Box py="xl" px={{ base: 'md', md: 'lg' }}>
|
<Box py="xl" px={{ base: 'md', md: 'lg' }}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Title order={2} c={colors['blue-button']} mb="lg">
|
<Title order={2} c={colors['blue-button']} mb="lg" ta="center">
|
||||||
Galeri Foto Desa Darmasaba
|
Galeri Foto Desa Darmasaba
|
||||||
</Title>
|
</Title>
|
||||||
|
|
||||||
@@ -115,7 +119,7 @@ function FotoList({ search }: { search: string }) {
|
|||||||
const { data, page, totalPages, loading, load } = FotoState.findMany;
|
const { data, page, totalPages, loading, load } = FotoState.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 3, search); // ✅ 9 item per halaman
|
load(page, 3, search);
|
||||||
}, [page, search]);
|
}, [page, search]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@@ -135,7 +139,9 @@ function FotoList({ search }: { search: string }) {
|
|||||||
<Center py="xl">
|
<Center py="xl">
|
||||||
<Stack align="center" c="dimmed">
|
<Stack align="center" c="dimmed">
|
||||||
<IconPhoto size={48} />
|
<IconPhoto size={48} />
|
||||||
<Text>Tidak ada foto ditemukan</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} lh={{ base: '1.4', md: '1.5' }}>
|
||||||
|
Tidak ada foto ditemukan
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
);
|
);
|
||||||
@@ -150,7 +156,6 @@ function FotoList({ search }: { search: string }) {
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* Pagination */}
|
{/* Pagination */}
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import {
|
|||||||
Paper,
|
Paper,
|
||||||
SimpleGrid,
|
SimpleGrid,
|
||||||
Stack,
|
Stack,
|
||||||
Text
|
Text,
|
||||||
|
Title
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useTransitionRouter } from 'next-view-transitions';
|
import { useTransitionRouter } from 'next-view-transitions';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
@@ -19,15 +20,13 @@ import { useSnapshot } from 'valtio';
|
|||||||
|
|
||||||
export default function VideoContent() {
|
export default function VideoContent() {
|
||||||
const videoState = useSnapshot(stateGallery.video);
|
const videoState = useSnapshot(stateGallery.video);
|
||||||
const router = useTransitionRouter()
|
const router = useTransitionRouter();
|
||||||
const { data, page, totalPages, loading } = videoState.findMany;
|
const { data, page, totalPages, loading } = videoState.findMany;
|
||||||
|
|
||||||
// Handle search and pagination changes
|
|
||||||
const loadData = useCallback((pageNum: number, searchTerm: string) => {
|
const loadData = useCallback((pageNum: number, searchTerm: string) => {
|
||||||
stateGallery.video.findMany.load(pageNum, 3, searchTerm.trim());
|
stateGallery.video.findMany.load(pageNum, 3, searchTerm.trim());
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Initial load and URL change handler
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleRouteChange = () => {
|
const handleRouteChange = () => {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
@@ -57,13 +56,14 @@ export default function VideoContent() {
|
|||||||
loadData(newPage, search);
|
loadData(newPage, search);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const dataVideo = data || [];
|
const dataVideo = data || [];
|
||||||
|
|
||||||
if (loading && !data) {
|
if (loading && !data) {
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={10}>
|
||||||
<Text>Memuat Video...</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed" ta="center">
|
||||||
|
Memuat Video...
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -78,9 +78,8 @@ export default function VideoContent() {
|
|||||||
p="md"
|
p="md"
|
||||||
radius={26}
|
radius={26}
|
||||||
bg={colors['white-trans-1']}
|
bg={colors['white-trans-1']}
|
||||||
w={{ base: '100%', md: '100%' }}
|
w="100%"
|
||||||
>
|
>
|
||||||
<Box>
|
|
||||||
<Center>
|
<Center>
|
||||||
<Box
|
<Box
|
||||||
component="iframe"
|
component="iframe"
|
||||||
@@ -92,41 +91,58 @@ export default function VideoContent() {
|
|||||||
style={{ borderRadius: 8 }}
|
style={{ borderRadius: 8 }}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Stack gap="sm" py={10}>
|
<Stack gap="sm" py={10}>
|
||||||
<Text fz="sm" c="dimmed">
|
{/* Tanggal: Caption */}
|
||||||
|
<Text
|
||||||
|
fz={{ base: 12, md: 14 }}
|
||||||
|
c="dimmed"
|
||||||
|
ta="left"
|
||||||
|
>
|
||||||
{new Date(v.createdAt).toLocaleDateString('id-ID', {
|
{new Date(v.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
<Text fw="bold" fz="sm" lineClamp={1}>
|
|
||||||
|
{/* Judul Video: Subsection (H3) */}
|
||||||
|
<Title
|
||||||
|
order={3}
|
||||||
|
c="dark"
|
||||||
|
ta="left"
|
||||||
|
lh={1.3}
|
||||||
|
style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}
|
||||||
|
>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
|
{/* Deskripsi: Body kecil */}
|
||||||
<Text
|
<Text
|
||||||
ta="justify"
|
ta="justify"
|
||||||
fz="sm"
|
fz={{ base: 13, md: 14 }}
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
c="dimmed"
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: 'break-word' }}
|
||||||
lineClamp={3}
|
lineClamp={3}
|
||||||
truncate="end"
|
>
|
||||||
/>
|
<span dangerouslySetInnerHTML={{ __html: v.deskripsi }} />
|
||||||
<Group justify={"right"}>
|
</Text>
|
||||||
|
|
||||||
|
<Group justify="right">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => router.push(`/darmasaba/desa/galery/video/${v.id}`)}
|
onClick={() => router.push(`/darmasaba/desa/galery/video/${v.id}`)}
|
||||||
bg={colors['blue-button']}
|
bg={colors['blue-button']}
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
>
|
>
|
||||||
Detail
|
Detail
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
@@ -140,7 +156,6 @@ export default function VideoContent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ Fix: convert YouTube URL ke embed
|
|
||||||
function convertToEmbedUrl(youtubeUrl: string): string {
|
function convertToEmbedUrl(youtubeUrl: string): string {
|
||||||
try {
|
try {
|
||||||
const url = new URL(youtubeUrl);
|
const url = new URL(youtubeUrl);
|
||||||
|
|||||||
@@ -12,16 +12,17 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
ThemeIcon,
|
ThemeIcon,
|
||||||
|
Title,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconArrowBack, IconInfoCircle, IconVideo } from '@tabler/icons-react';
|
import { IconArrowBack, IconInfoCircle, IconVideo } from '@tabler/icons-react';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import stateGallery from '@/app/admin/(dashboard)/_state/desa/gallery'; // pastikan state bisa dipakai di publik
|
import stateGallery from '@/app/admin/(dashboard)/_state/desa/gallery';
|
||||||
import BackButton from '../../../layanan/_com/BackButto';
|
import BackButton from '../../../layanan/_com/BackButto';
|
||||||
|
|
||||||
// Fungsi helper: aman dan tanpa spasi
|
|
||||||
function convertToEmbedUrl(youtubeUrl: string): string {
|
function convertToEmbedUrl(youtubeUrl: string): string {
|
||||||
try {
|
try {
|
||||||
const url = new URL(youtubeUrl);
|
const url = new URL(youtubeUrl);
|
||||||
@@ -72,7 +73,9 @@ export default function DetailVideoUser() {
|
|||||||
color="red"
|
color="red"
|
||||||
radius="md"
|
radius="md"
|
||||||
>
|
>
|
||||||
|
<Text fz={{ base: 'sm', md: 'md' }} c="red.9">
|
||||||
Video yang Anda cari tidak tersedia.
|
Video yang Anda cari tidak tersedia.
|
||||||
|
</Text>
|
||||||
</Alert>
|
</Alert>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconArrowBack size={16} />}
|
leftSection={<IconArrowBack size={16} />}
|
||||||
@@ -91,20 +94,20 @@ export default function DetailVideoUser() {
|
|||||||
return (
|
return (
|
||||||
<Box py="xl" px={{ base: 'md', md: 100 }}>
|
<Box py="xl" px={{ base: 'md', md: 100 }}>
|
||||||
{/* Tombol Kembali */}
|
{/* Tombol Kembali */}
|
||||||
<Box >
|
<Box>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header - Dijadikan Title */}
|
||||||
<Text
|
<Title
|
||||||
|
order={1}
|
||||||
ta="center"
|
ta="center"
|
||||||
fz={{ base: 'xl', md: '2xl' }}
|
|
||||||
fw={700}
|
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
mb="lg"
|
mb="lg"
|
||||||
|
lh={{ base: 1.2, md: 1.25 }}
|
||||||
>
|
>
|
||||||
{data.name || 'Video Galeri Desa'}
|
{data.name || 'Video Galeri Desa'}
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
{/* Konten Utama */}
|
{/* Konten Utama */}
|
||||||
<Card
|
<Card
|
||||||
@@ -118,7 +121,7 @@ export default function DetailVideoUser() {
|
|||||||
{embedUrl ? (
|
{embedUrl ? (
|
||||||
<Box
|
<Box
|
||||||
pos="relative"
|
pos="relative"
|
||||||
style={{ paddingBottom: '56.25%', height: 0, overflow: 'hidden' }} // 16:9 aspect ratio
|
style={{ paddingBottom: '56.25%', height: 0, overflow: 'hidden' }}
|
||||||
>
|
>
|
||||||
<iframe
|
<iframe
|
||||||
src={embedUrl}
|
src={embedUrl}
|
||||||
@@ -144,7 +147,9 @@ export default function DetailVideoUser() {
|
|||||||
title="Gagal memuat video"
|
title="Gagal memuat video"
|
||||||
radius="md"
|
radius="md"
|
||||||
>
|
>
|
||||||
|
<Text fz={{ base: 'xs', md: 'sm' }} c="orange.9">
|
||||||
Mohon maaf, video tidak dapat diputar.
|
Mohon maaf, video tidak dapat diputar.
|
||||||
|
</Text>
|
||||||
</Alert>
|
</Alert>
|
||||||
) : (
|
) : (
|
||||||
<Alert
|
<Alert
|
||||||
@@ -153,7 +158,9 @@ export default function DetailVideoUser() {
|
|||||||
title="Tidak ada video"
|
title="Tidak ada video"
|
||||||
radius="md"
|
radius="md"
|
||||||
>
|
>
|
||||||
|
<Text fz={{ base: 'xs', md: 'sm' }} c="dimmed">
|
||||||
Konten video belum tersedia.
|
Konten video belum tersedia.
|
||||||
|
</Text>
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -163,7 +170,11 @@ export default function DetailVideoUser() {
|
|||||||
<ThemeIcon variant="light" size="sm" radius="xl">
|
<ThemeIcon variant="light" size="sm" radius="xl">
|
||||||
<IconInfoCircle size={14} />
|
<IconInfoCircle size={14} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
c="dimmed"
|
||||||
|
lh={{ base: 1.4, md: 1.5 }}
|
||||||
|
>
|
||||||
Diunggah pada{' '}
|
Diunggah pada{' '}
|
||||||
{new Date(data.createdAt).toLocaleDateString('id-ID', {
|
{new Date(data.createdAt).toLocaleDateString('id-ID', {
|
||||||
weekday: 'long',
|
weekday: 'long',
|
||||||
@@ -179,8 +190,9 @@ export default function DetailVideoUser() {
|
|||||||
{data.deskripsi && (
|
{data.deskripsi && (
|
||||||
<Paper p="md" bg="gray.0" radius="md">
|
<Paper p="md" bg="gray.0" radius="md">
|
||||||
<Text
|
<Text
|
||||||
fz="md"
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
c="dark"
|
c="dark"
|
||||||
|
ta={"justify"}
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
||||||
style={{
|
style={{
|
||||||
wordBreak: 'break-word',
|
wordBreak: 'break-word',
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { ActionIcon, Box, Divider, Flex, Group, Skeleton, Stack, Text, Tooltip } from '@mantine/core';
|
import { ActionIcon, Box, Divider, Flex, Group, Skeleton, Stack, Text, Title, Tooltip } from '@mantine/core';
|
||||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
@@ -39,30 +39,38 @@ function PelayananPendudukNonPermanent() {
|
|||||||
) : (
|
) : (
|
||||||
<Stack gap="xl">
|
<Stack gap="xl">
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz={{ base: "xl", md: "2xl" }} fw={700} lh={1.3} c="dark">
|
<Title
|
||||||
|
order={1}
|
||||||
|
fz={{ base: 'lg', md: 'xl' }}
|
||||||
|
fw={700}
|
||||||
|
lh={{ base: 1.3, md: 1.3 }}
|
||||||
|
c="dark"
|
||||||
|
>
|
||||||
{data?.name || "Judul belum tersedia"}
|
{data?.name || "Judul belum tersedia"}
|
||||||
</Text>
|
</Title>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
{data?.deskripsi ? (
|
{data?.deskripsi ? (
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: "sm", md: "md" }}
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
lh={1.7}
|
lh={{ base: 1.6, md: 1.7 }}
|
||||||
ta="justify"
|
ta="justify"
|
||||||
c="dimmed"
|
c="black"
|
||||||
dangerouslySetInnerHTML={{ __html: data?.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: data?.deskripsi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Text fz="sm" c="gray">Deskripsi belum tersedia.</Text>
|
<Text fz="xs" c="gray">
|
||||||
|
Deskripsi belum tersedia.
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Divider color={colors["blue-button"]} size="sm" />
|
<Divider color={colors["blue-button"]} size="sm" />
|
||||||
|
|
||||||
<Flex justify="space-between" align="center" wrap="wrap" gap="md">
|
<Flex justify="space-between" align="center" wrap="wrap" gap="md">
|
||||||
<Text fz={{ base: "xs", md: "sm" }} c="dimmed">
|
<Text fz={{ base: 'xs', md: 'sm' }} lh={{ base: 1.4, md: 1.5 }} c="black">
|
||||||
25 Mei 2021 • Darmasaba
|
25 Mei 2021 • Darmasaba
|
||||||
</Text>
|
</Text>
|
||||||
<Group gap="md">
|
<Group gap="md">
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ function PelayananPerizinanBerusaha() {
|
|||||||
return (
|
return (
|
||||||
<Center mih={300}>
|
<Center mih={300}>
|
||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<Text fz="lg" fw={500} c="dimmed">
|
<Text fz={{ base: 'md', md: 'lg' }} fw={500} c="dimmed" lh="sm">
|
||||||
Belum ada informasi layanan yang tersedia
|
Belum ada informasi layanan yang tersedia
|
||||||
</Text>
|
</Text>
|
||||||
<Button component="a" href="https://oss.go.id" target="_blank" radius="xl">
|
<Button component="a" href="https://oss.go.id" target="_blank" radius="xl">
|
||||||
@@ -67,10 +67,10 @@ function PelayananPerizinanBerusaha() {
|
|||||||
) : (
|
) : (
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<Box>
|
<Box>
|
||||||
<Title order={2} fw={700} fz={{ base: 22, md: 32 }} mb="sm">
|
<Title order={2} fw={700} mb="sm">
|
||||||
Perizinan Berusaha Berbasis Risiko melalui OSS
|
Perizinan Berusaha Berbasis Risiko melalui OSS
|
||||||
</Title>
|
</Title>
|
||||||
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed">
|
<Text fz={{ base: 'sm', md: 'md' }} c="black" lh="sm">
|
||||||
Sistem Online Single Submission (OSS) untuk pendaftaran NIB
|
Sistem Online Single Submission (OSS) untuk pendaftaran NIB
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -83,13 +83,13 @@ function PelayananPerizinanBerusaha() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={600} mb="sm" fz={{ base: 'sm', md: 'lg' }}>
|
<Title order={3} fw={600} mb="sm">
|
||||||
Alur pendaftaran NIB:
|
Alur pendaftaran NIB:
|
||||||
</Text>
|
</Title>
|
||||||
<Stepper
|
<Stepper
|
||||||
active={active}
|
active={active}
|
||||||
onStepClick={(step) => {
|
onStepClick={(step) => {
|
||||||
if (step <= active) { // Only allow clicking on previous or current steps
|
if (step <= active) {
|
||||||
setActive(step);
|
setActive(step);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -102,28 +102,42 @@ function PelayananPerizinanBerusaha() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StepperStep label="Langkah 1" description="Daftar Akun">
|
<StepperStep label="Langkah 1" description="Daftar Akun">
|
||||||
<Text fz="sm">Membuat akun di portal OSS</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} lh="sm">
|
||||||
|
Membuat akun di portal OSS
|
||||||
|
</Text>
|
||||||
</StepperStep>
|
</StepperStep>
|
||||||
<StepperStep label="Langkah 2" description="Isi Data Perusahaan">
|
<StepperStep label="Langkah 2" description="Isi Data Perusahaan">
|
||||||
<Text fz="sm">Lengkapi informasi perusahaan, data pemegang saham, dan alamat</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} lh="sm">
|
||||||
|
Lengkapi informasi perusahaan, data pemegang saham, dan alamat
|
||||||
|
</Text>
|
||||||
</StepperStep>
|
</StepperStep>
|
||||||
<StepperStep label="Langkah 3" description="Pilih KBLI">
|
<StepperStep label="Langkah 3" description="Pilih KBLI">
|
||||||
<Text fz="sm">Menentukan kode KBLI sesuai jenis usaha</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} lh="sm">
|
||||||
|
Menentukan kode KBLI sesuai jenis usaha
|
||||||
|
</Text>
|
||||||
</StepperStep>
|
</StepperStep>
|
||||||
<StepperStep label="Langkah 4" description="Unggah Dokumen">
|
<StepperStep label="Langkah 4" description="Unggah Dokumen">
|
||||||
<Text fz="sm">Unggah akta pendirian, surat izin, dan dokumen wajib lainnya</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} lh="sm">
|
||||||
|
Unggah akta pendirian, surat izin, dan dokumen wajib lainnya
|
||||||
|
</Text>
|
||||||
</StepperStep>
|
</StepperStep>
|
||||||
<StepperStep label="Langkah 5" description="Verifikasi Instansi">
|
<StepperStep label="Langkah 5" description="Verifikasi Instansi">
|
||||||
<Text fz="sm">Menunggu verifikasi dan persetujuan dari pihak berwenang</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} lh="sm">
|
||||||
|
Menunggu verifikasi dan persetujuan dari pihak berwenang
|
||||||
|
</Text>
|
||||||
</StepperStep>
|
</StepperStep>
|
||||||
<StepperStep label="Langkah 6" description="Terbit NIB">
|
<StepperStep label="Langkah 6" description="Terbit NIB">
|
||||||
<Text fz="sm">Menerima NIB sebagai identitas resmi usaha</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} lh="sm">
|
||||||
|
Menerima NIB sebagai identitas resmi usaha
|
||||||
|
</Text>
|
||||||
</StepperStep>
|
</StepperStep>
|
||||||
<StepperCompleted>
|
<StepperCompleted>
|
||||||
<Center>
|
<Center>
|
||||||
<Stack align="center" gap="xs">
|
<Stack align="center" gap="xs">
|
||||||
<IconCheck size={40} color="green" />
|
<IconCheck size={40} color="green" />
|
||||||
<Text fz="sm" fw={500}>Proses pendaftaran selesai</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} fw={500} lh="sm">
|
||||||
|
Proses pendaftaran selesai
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
</StepperCompleted>
|
</StepperCompleted>
|
||||||
@@ -159,7 +173,7 @@ function PelayananPerizinanBerusaha() {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Text fz="sm" ta="justify" c="dimmed" mt="md">
|
<Text fz={{ base: 'xs', md: 'sm' }} ta="justify" c="black" lh="sm" mt="md">
|
||||||
Catatan: Persyaratan dan prosedur dapat berubah sewaktu-waktu. Untuk informasi resmi terbaru, silakan kunjungi situs{' '}
|
Catatan: Persyaratan dan prosedur dapat berubah sewaktu-waktu. Untuk informasi resmi terbaru, silakan kunjungi situs{' '}
|
||||||
<a href="https://oss.go.id/" target="_blank" rel="noopener noreferrer">
|
<a href="https://oss.go.id/" target="_blank" rel="noopener noreferrer">
|
||||||
oss.go.id
|
oss.go.id
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { BackgroundImage, Box, Button, Center, Group, Pagination, SimpleGrid, Skeleton, Stack, Text, Tooltip } from '@mantine/core';
|
import { BackgroundImage, Box, Button, Center, Group, Pagination, SimpleGrid, Skeleton, Stack, Text, Title, Tooltip } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconFileDescription, IconInfoCircle } from '@tabler/icons-react';
|
import { IconFileDescription, IconInfoCircle } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -35,7 +35,7 @@ function PelayananSuratKeterangan({ search }: { search: string }) {
|
|||||||
<Center py="xl">
|
<Center py="xl">
|
||||||
<Stack align="center" gap="xs">
|
<Stack align="center" gap="xs">
|
||||||
<IconFileDescription size={40} stroke={1.5} color={colors["blue-button"]} />
|
<IconFileDescription size={40} stroke={1.5} color={colors["blue-button"]} />
|
||||||
<Text c="dimmed" ta="center">
|
<Text c="dimmed" ta="center" fz={{ base: 'sm', md: 'md' }} lh="sm">
|
||||||
Tidak ada layanan surat keterangan yang ditemukan
|
Tidak ada layanan surat keterangan yang ditemukan
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -48,9 +48,9 @@ function PelayananSuratKeterangan({ search }: { search: string }) {
|
|||||||
<Group justify="space-between" align="center" mb="md">
|
<Group justify="space-between" align="center" mb="md">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconFileDescription size={28} stroke={1.8} />
|
<IconFileDescription size={28} stroke={1.8} />
|
||||||
<Text fz={{ base: "h4", md: "h2" }} fw={700}>
|
<Title order={2} c="black">
|
||||||
Layanan Surat Keterangan
|
Layanan Surat Keterangan
|
||||||
</Text>
|
</Title>
|
||||||
</Group>
|
</Group>
|
||||||
<Tooltip label="Pilih layanan surat keterangan sesuai kebutuhan Anda" withArrow>
|
<Tooltip label="Pilih layanan surat keterangan sesuai kebutuhan Anda" withArrow>
|
||||||
<IconInfoCircle size={22} stroke={1.8} />
|
<IconInfoCircle size={22} stroke={1.8} />
|
||||||
@@ -82,15 +82,15 @@ function PelayananSuratKeterangan({ search }: { search: string }) {
|
|||||||
style={{ borderRadius: 16 }}
|
style={{ borderRadius: 16 }}
|
||||||
/>
|
/>
|
||||||
<Stack justify="space-between" h="100%" gap="md" p="lg" pos="relative">
|
<Stack justify="space-between" h="100%" gap="md" p="lg" pos="relative">
|
||||||
<Text
|
<Title
|
||||||
|
order={3}
|
||||||
c="white"
|
c="white"
|
||||||
fw={600}
|
|
||||||
fz="lg"
|
|
||||||
ta="center"
|
ta="center"
|
||||||
lineClamp={2}
|
lineClamp={2}
|
||||||
|
lh="sm"
|
||||||
>
|
>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Group justify="center">
|
<Group justify="center">
|
||||||
<Button
|
<Button
|
||||||
size="md"
|
size="md"
|
||||||
|
|||||||
@@ -42,9 +42,10 @@ function PelayananTelunjukSaktiDesa() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Title order={2} mb="lg" fz={{ base: 22, md: 28 }} fw={700} style={{ lineHeight: 1.4 }}>
|
<Title order={2} mb="lg" fw={700} style={{ lineHeight: 1.3 }} ta="left">
|
||||||
Layanan Telunjuk Sakti Desa <br />
|
Layanan Telunjuk Sakti Desa
|
||||||
<Text span c="dimmed" fz="lg" fw={400}>
|
<Text span c="black" fz={{ base: 'sm', md: 'md' }} fw={400} style={{ lineHeight: 1.5 }}>
|
||||||
|
{' '}
|
||||||
Terwujudnya sistem administrasi kependudukan terintegrasi berbasis elektronik, cerdas, dan aman
|
Terwujudnya sistem administrasi kependudukan terintegrasi berbasis elektronik, cerdas, dan aman
|
||||||
</Text>
|
</Text>
|
||||||
</Title>
|
</Title>
|
||||||
@@ -53,7 +54,7 @@ function PelayananTelunjukSaktiDesa() {
|
|||||||
<Skeleton h={400} radius="lg" />
|
<Skeleton h={400} radius="lg" />
|
||||||
) : data.length === 0 ? (
|
) : data.length === 0 ? (
|
||||||
<Card shadow="sm" radius="lg" withBorder>
|
<Card shadow="sm" radius="lg" withBorder>
|
||||||
<Text c="dimmed" ta="center" py="xl">
|
<Text c="black" ta="center" py="xl" fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||||
Belum ada layanan tersedia untuk saat ini
|
Belum ada layanan tersedia untuk saat ini
|
||||||
</Text>
|
</Text>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -72,9 +73,9 @@ function PelayananTelunjukSaktiDesa() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fw={700} fz="lg" lh={1.4}>
|
<Title order={3} fw={700} lh={1.3}>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Flex gap="xs" align="center">
|
<Flex gap="xs" align="center">
|
||||||
<IconExternalLink size={18} stroke={1.5} />
|
<IconExternalLink size={18} stroke={1.5} />
|
||||||
<Text
|
<Text
|
||||||
@@ -82,7 +83,7 @@ function PelayananTelunjukSaktiDesa() {
|
|||||||
href={v.link}
|
href={v.link}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
fz="sm"
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
c="blue"
|
c="blue"
|
||||||
td="underline"
|
td="underline"
|
||||||
style={{ cursor: 'pointer' }}
|
style={{ cursor: 'pointer' }}
|
||||||
|
|||||||
@@ -1,58 +1,94 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import stateDesaPengumuman from '@/app/admin/(dashboard)/_state/desa/pengumuman';
|
import stateDesaPengumuman from '@/app/admin/(dashboard)/_state/desa/pengumuman';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Container, Group, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Container, Group, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../../layanan/_com/BackButto';
|
|
||||||
import NewsReader from '@/app/darmasaba/_com/NewsReader';
|
import NewsReader from '@/app/darmasaba/_com/NewsReader';
|
||||||
|
import BackButton from '../../../layanan/_com/BackButto';
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const detail = useProxy(stateDesaPengumuman.pengumuman.findUnique)
|
const detail = useProxy(stateDesaPengumuman.pengumuman.findUnique);
|
||||||
|
const params = useParams();
|
||||||
const params = useParams()
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
stateDesaPengumuman.pengumuman.findUnique.load(params?.id as string)
|
stateDesaPengumuman.pengumuman.findUnique.load(params?.id as string);
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
if (!detail.data) {
|
if (!detail.data) {
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Skeleton h={400} />
|
<Skeleton h={400} />
|
||||||
</Box>
|
</Box>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="md">
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="md">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Container size="lg" px="md">
|
<Container size="lg" px="md">
|
||||||
<Group>
|
<Group>
|
||||||
<NewsReader />
|
<NewsReader />
|
||||||
</Group>
|
</Group>
|
||||||
<Stack gap="xs" >
|
|
||||||
<Group justify={"space-between"} align={"center"}>
|
<Stack gap="xs">
|
||||||
<Text fz={{ base: "2rem", md: "2rem" }} c={colors["blue-button"]} fw="bold" >
|
<Group justify="space-between" align="flex-start" wrap="wrap">
|
||||||
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fz={{ base: 28, md: 36 }}
|
||||||
|
style={{
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
flex: '1 1 auto',
|
||||||
|
minWidth: 0
|
||||||
|
}}
|
||||||
|
>
|
||||||
{detail.data?.judul}
|
{detail.data?.judul}
|
||||||
|
</Title>
|
||||||
|
<Paper bg={colors['blue-button']} p={8} style={{ flexShrink: 0 }}>
|
||||||
|
<Text c={colors['white-1']} fz={{ base: 'xs', md: 'sm' }} lh={1.2}>
|
||||||
|
{detail.data?.CategoryPengumuman?.name}
|
||||||
</Text>
|
</Text>
|
||||||
<Group justify='end'>
|
|
||||||
<Paper bg={colors['blue-button']} p={5}>
|
|
||||||
<Text c={colors['white-1']}>{detail.data?.CategoryPengumuman?.name}</Text>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
|
||||||
<Paper bg={colors["white-1"]} p="md">
|
<Paper
|
||||||
<Text px="lg" id='news-content' fz={"md"} style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: detail.data?.content }} />
|
bg={colors['white-1']}
|
||||||
<Text px="lg" fz={"md"} c={colors["blue-button"]} fw="bold" >
|
p="md"
|
||||||
|
w="100%"
|
||||||
|
mih={{ base: 200, md: 300 }}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
px="lg"
|
||||||
|
id="news-content"
|
||||||
|
fz={{ base: 14, md: 16 }}
|
||||||
|
lh={{ base: 1.6, md: 1.6 }}
|
||||||
|
style={{
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
whiteSpace: 'normal',
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
dangerouslySetInnerHTML={{ __html: detail.data?.content }}
|
||||||
|
/>
|
||||||
|
<Text
|
||||||
|
px="lg"
|
||||||
|
fz={{ base: 12, md: 14 }}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fw="bold"
|
||||||
|
lh={{ base: 1.4, md: 1.4 }}
|
||||||
|
mt="md"
|
||||||
|
>
|
||||||
{new Date(detail.data?.createdAt).toLocaleDateString('id-ID', {
|
{new Date(detail.data?.createdAt).toLocaleDateString('id-ID', {
|
||||||
weekday: 'long',
|
weekday: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
year: 'numeric'
|
year: 'numeric',
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import stateDesaPengumuman from '@/app/admin/(dashboard)/_state/desa/pengumuman';
|
import stateDesaPengumuman from '@/app/admin/(dashboard)/_state/desa/pengumuman';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Container, Group, Paper, Stack, Text } from '@mantine/core';
|
import { Box, Container, Group, Paper, Stack, Text, Title } from '@mantine/core';
|
||||||
import { IconCalendar } from '@tabler/icons-react';
|
import { IconCalendar } from '@tabler/icons-react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../layanan/_com/BackButto';
|
import BackButton from '../../layanan/_com/BackButto';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const unwrappedParams = useParams();
|
const unwrappedParams = useParams();
|
||||||
const kategoriState = useProxy(stateDesaPengumuman);
|
const kategoriState = useProxy(stateDesaPengumuman);
|
||||||
@@ -26,45 +25,82 @@ function Page() {
|
|||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Container size="lg" px="md" >
|
|
||||||
<Stack align="center" gap="0" >
|
<Container size="lg" px="md">
|
||||||
<Text fz={{ base: "2rem", md: "3.4rem" }} c={colors["blue-button"]} fw="bold" ta="center">
|
<Stack align="center" gap="xs">
|
||||||
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors["blue-button"]}
|
||||||
|
ta="center"
|
||||||
|
style={{ fontWeight: 'bold' }}
|
||||||
|
>
|
||||||
{categoryName.split('-').map(word =>
|
{categoryName.split('-').map(word =>
|
||||||
word.charAt(0).toUpperCase() + word.slice(1)
|
word.charAt(0).toUpperCase() + word.slice(1)
|
||||||
).join(' ')}
|
).join(' ')}
|
||||||
</Text>
|
</Title>
|
||||||
<Text ta="center" px="md" pb={10}>
|
<Text
|
||||||
|
ta="center"
|
||||||
|
px="md"
|
||||||
|
pb="sm"
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
|
c="dimmed"
|
||||||
|
>
|
||||||
Informasi dan pengumuman resmi terkait {categoryName.split('-').join(' ')}
|
Informasi dan pengumuman resmi terkait {categoryName.split('-').join(' ')}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
{!kategoriState.pengumuman.findMany.data?.length ? (
|
{!kategoriState.pengumuman.findMany.data?.length ? (
|
||||||
<Paper p="lg" radius="md" shadow="md" bg={colors["white-1"]}>
|
<Paper p="lg" radius="md" shadow="md" bg={colors["white-1"]}>
|
||||||
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
ta="center"
|
||||||
|
c="dimmed"
|
||||||
|
>
|
||||||
Tidak ada pengumuman yang ditemukan
|
Tidak ada pengumuman yang ditemukan
|
||||||
|
</Text>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : kategoriState.pengumuman.findMany.data?.map((v, k) => {
|
) : (
|
||||||
return (
|
kategoriState.pengumuman.findMany.data?.map((v, k) => (
|
||||||
<Paper mb={10} key={k} withBorder p="lg" radius="md" shadow="md" bg={colors["white-1"]}>
|
<Paper
|
||||||
<Text fz={'h3'}>{v.judul}</Text>
|
mb="md"
|
||||||
<Group style={{ color: 'black' }} pb={20}>
|
key={k}
|
||||||
|
withBorder
|
||||||
|
p="lg"
|
||||||
|
radius="md"
|
||||||
|
shadow="md"
|
||||||
|
bg={colors["white-1"]}
|
||||||
|
>
|
||||||
|
<Title order={3}>{v.judul}</Title>
|
||||||
|
<Group style={{ color: 'black' }} pb="sm">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconCalendar size={18} />
|
<IconCalendar size={18} />
|
||||||
<Text size="sm">
|
<Text
|
||||||
{v.createdAt ? new Date(v.createdAt).toLocaleDateString('id-ID', {
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
lh={{ base: 1.4, md: 1.5 }}
|
||||||
|
>
|
||||||
|
{v.createdAt
|
||||||
|
? new Date(v.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
}) : 'No date available'}
|
})
|
||||||
|
: 'No date available'}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<Text ta={'justify'}>
|
<Text
|
||||||
|
ta="justify"
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: 1.6, md: 1.7 }}
|
||||||
|
>
|
||||||
{v.deskripsi}
|
{v.deskripsi}
|
||||||
</Text>
|
</Text>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
))
|
||||||
})}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
Center,
|
Center,
|
||||||
Container,
|
Container,
|
||||||
Divider,
|
Divider,
|
||||||
Flex,
|
|
||||||
Grid,
|
Grid,
|
||||||
GridCol,
|
GridCol,
|
||||||
Group,
|
Group,
|
||||||
@@ -22,7 +21,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Title,
|
Title,
|
||||||
UnstyledButton,
|
UnstyledButton
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { IconCalendar, IconClock, IconSearch } from '@tabler/icons-react';
|
import { IconCalendar, IconClock, IconSearch } from '@tabler/icons-react';
|
||||||
import { useTransitionRouter } from 'next-view-transitions';
|
import { useTransitionRouter } from 'next-view-transitions';
|
||||||
@@ -98,10 +97,14 @@ function Page() {
|
|||||||
|
|
||||||
<Container size="lg" px="md">
|
<Container size="lg" px="md">
|
||||||
<Stack align="center" gap="0">
|
<Stack align="center" gap="0">
|
||||||
<Text fz={{ base: '2rem', md: '3.4rem' }} c={colors['blue-button']} fw="bold" ta="center">
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
ta="center"
|
||||||
|
>
|
||||||
Pengumuman Desa Darmasaba
|
Pengumuman Desa Darmasaba
|
||||||
</Text>
|
</Title>
|
||||||
<Text ta="center" px="md" pb={10}>
|
<Text ta="center" px="md" pb={10} fz={{ base: 'sm', md: 'md' }} lh="sm">
|
||||||
Informasi dan pengumuman resmi terkait kegiatan dan kebijakan Desa Darmasaba
|
Informasi dan pengumuman resmi terkait kegiatan dan kebijakan Desa Darmasaba
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -126,17 +129,17 @@ function Page() {
|
|||||||
withCloseButton={false}
|
withCloseButton={false}
|
||||||
title={item.CategoryPengumuman?.name || 'Pengumuman'}
|
title={item.CategoryPengumuman?.name || 'Pengumuman'}
|
||||||
>
|
>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap="xs">
|
||||||
<Text fz="sm" fw="bold" c="black" style={{ textTransform: 'uppercase' }}>
|
<Text fz={{ base: 'sm', md: 'sm' }} fw="bold" c="black" style={{ textTransform: 'uppercase' }}>
|
||||||
{item.judul}
|
{item.judul}
|
||||||
</Text>
|
</Text>
|
||||||
<Text ta="justify" fz="sm" c="black" lineClamp={3} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
<Text ta="justify" fz={{ base: 'xs', md: 'sm' }} c="black" lineClamp={3} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
<Flex pt={20} gap="md" justify="space-between">
|
<Group pt={20} gap="md" justify="space-between">
|
||||||
<Group style={{ color: 'black' }}>
|
<Group style={{ color: 'black' }}>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconCalendar size={18} />
|
<IconCalendar size={18} />
|
||||||
<Text size="sm">
|
<Text fz={{ base: 'xs', md: 'sm' }}>
|
||||||
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
||||||
weekday: 'long',
|
weekday: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
@@ -147,7 +150,7 @@ function Page() {
|
|||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconClock size={18} />
|
<IconClock size={18} />
|
||||||
<Text size="sm">
|
<Text fz={{ base: 'xs', md: 'sm' }}>
|
||||||
{new Date(item.createdAt).toLocaleTimeString('id-ID', {
|
{new Date(item.createdAt).toLocaleTimeString('id-ID', {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
@@ -157,11 +160,11 @@ function Page() {
|
|||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<Anchor variant="transparent" href={`/darmasaba/desa/pengumuman/${item.CategoryPengumuman?.name}/${item.id}`}>
|
<Anchor variant="transparent" href={`/darmasaba/desa/pengumuman/${item.CategoryPengumuman?.name}/${item.id}`}>
|
||||||
<Text fs="unset" c={colors['blue-button']} fz="sm">
|
<Text fs="unset" c={colors['blue-button']} fz={{ base: 'xs', md: 'sm' }}>
|
||||||
Baca Selengkapnya
|
Baca Selengkapnya
|
||||||
</Text>
|
</Text>
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</Flex>
|
</Group>
|
||||||
</Notification>
|
</Notification>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
@@ -169,19 +172,19 @@ function Page() {
|
|||||||
|
|
||||||
<Paper p="md">
|
<Paper p="md">
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
<Text fw="bold" fz="lg" c={colors['blue-button']}>
|
<Title order={3} c={colors['blue-button']}>
|
||||||
Kategori
|
Kategori
|
||||||
</Text>
|
</Title>
|
||||||
{stateDesaPengumuman.category.findMany.data?.map((v: any, k) => {
|
{stateDesaPengumuman.category.findMany.data?.map((v: any, k) => {
|
||||||
const count = v._count?.pengumumans || 0;
|
const count = v._count?.pengumumans || 0;
|
||||||
return (
|
return (
|
||||||
<UnstyledButton component={Link} href={`/darmasaba/desa/pengumuman/${v.name}`} key={k}>
|
<UnstyledButton component={Link} href={`/darmasaba/desa/pengumuman/${v.name}`} key={k}>
|
||||||
<Paper bg={colors['BG-trans']} p={5}>
|
<Paper bg={colors['BG-trans']} p={5}>
|
||||||
<Group px={3} justify="space-between">
|
<Group px={3} justify="space-between">
|
||||||
<Text fz="md" c="black">
|
<Text fz={{ base: 'sm', md: 'md' }} c="black">
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text fz="md" c="black">
|
<Text fz={{ base: 'sm', md: 'md' }} c="black">
|
||||||
{count}
|
{count}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
@@ -200,7 +203,7 @@ function Page() {
|
|||||||
<Divider mb={10} color={colors['blue-button']} />
|
<Divider mb={10} color={colors['blue-button']} />
|
||||||
<Grid>
|
<Grid>
|
||||||
<GridCol span={{ base: 12, md: 8 }}>
|
<GridCol span={{ base: 12, md: 8 }}>
|
||||||
<Title order={3}>Daftar Pengumuman</Title>
|
<Title order={2}>Daftar Pengumuman</Title>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
<GridCol span={{ base: 12, md: 4 }}>
|
<GridCol span={{ base: 12, md: 4 }}>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -210,6 +213,7 @@ function Page() {
|
|||||||
w="100%"
|
w="100%"
|
||||||
value={searchInput}
|
value={searchInput}
|
||||||
onChange={(e) => setSearchInput(e.target.value)}
|
onChange={(e) => setSearchInput(e.target.value)}
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
/>
|
/>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -223,7 +227,9 @@ function Page() {
|
|||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
) : !state.findMany.data?.length ? (
|
) : !state.findMany.data?.length ? (
|
||||||
<Notification withCloseButton={false} h={100}>
|
<Notification withCloseButton={false} h={100}>
|
||||||
|
<Text fz={{ base: 'sm', md: 'md' }} ta="center">
|
||||||
Tidak ada pengumuman yang ditemukan
|
Tidak ada pengumuman yang ditemukan
|
||||||
|
</Text>
|
||||||
</Notification>
|
</Notification>
|
||||||
) : (
|
) : (
|
||||||
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="lg" verticalSpacing="lg">
|
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="lg" verticalSpacing="lg">
|
||||||
@@ -231,26 +237,26 @@ function Page() {
|
|||||||
<Paper key={item.id} p="md" withBorder radius="md" h="100%">
|
<Paper key={item.id} p="md" withBorder radius="md" h="100%">
|
||||||
<Stack h="100%" justify="space-between">
|
<Stack h="100%" justify="space-between">
|
||||||
<div>
|
<div>
|
||||||
<Text fw={600} c={colors['blue-button']} mb={5}>
|
<Text fw={600} c={colors['blue-button']} mb={5} fz={{ base: 'sm', md: 'md' }}>
|
||||||
{item.CategoryPengumuman?.name || 'Pengumuman'}
|
{item.CategoryPengumuman?.name || 'Pengumuman'}
|
||||||
</Text>
|
</Text>
|
||||||
<Text fz="lg" fw={700} mb="sm" lineClamp={2} style={{ textTransform: 'uppercase' }}>
|
<Text fw={700} mb="sm" lineClamp={2} style={{ textTransform: 'uppercase' }} fz={{ base: 'sm', md: 'lg' }}>
|
||||||
{item.judul}
|
{item.judul}
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
|
||||||
c="dimmed"
|
c="dimmed"
|
||||||
lineClamp={4}
|
lineClamp={4}
|
||||||
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
mb="md"
|
mb="md"
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Group mb="sm" c="dimmed">
|
<Group mb="sm" c="dimmed">
|
||||||
<Group gap={5}>
|
<Group gap={5}>
|
||||||
<IconCalendar size={16} />
|
<IconCalendar size={16} />
|
||||||
<Text size="xs">
|
<Text fz={{ base: 'xs', md: 'xs' }}>
|
||||||
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
{new Date(item.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
@@ -260,19 +266,19 @@ function Page() {
|
|||||||
</Group>
|
</Group>
|
||||||
<Group gap={5}>
|
<Group gap={5}>
|
||||||
<IconClock size={16} />
|
<IconClock size={16} />
|
||||||
<Text size="xs">
|
<Text fz={{ base: 'xs', md: 'xs' }}>
|
||||||
{new Date(item.createdAt).toLocaleTimeString('id-ID', {
|
{new Date(item.createdAt).toLocaleTimeString('id-ID', {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
|
||||||
<Anchor variant="transparent" href={`/darmasaba/desa/pengumuman/${item.CategoryPengumuman?.name}/${item.id}`}>
|
<Anchor variant="transparent" href={`/darmasaba/desa/pengumuman/${item.CategoryPengumuman?.name}/${item.id}`}>
|
||||||
<Text fw={600} c={colors['blue-button']} size="sm">
|
<Text fw={600} c={colors['blue-button']} fz={{ base: 'sm', md: 'sm' }}>
|
||||||
Baca Selengkapnya →
|
Baca Selengkapnya →
|
||||||
</Text>
|
</Text>
|
||||||
</Anchor>
|
</Anchor>
|
||||||
|
</Group>
|
||||||
</div>
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
@@ -289,6 +295,7 @@ function Page() {
|
|||||||
siblings={1}
|
siblings={1}
|
||||||
boundaries={1}
|
boundaries={1}
|
||||||
withEdges
|
withEdges
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../layanan/_com/BackButto';
|
import BackButton from '../../layanan/_com/BackButto';
|
||||||
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const params = useParams<{ id: string }>();
|
const params = useParams<{ id: string }>();
|
||||||
const id = Array.isArray(params.id) ? params.id[0] : params.id;
|
const id = Array.isArray(params.id) ? params.id[0] : params.id;
|
||||||
@@ -35,7 +36,9 @@ function Page() {
|
|||||||
<Center h="80vh">
|
<Center h="80vh">
|
||||||
<Stack align="center" gap="md">
|
<Stack align="center" gap="md">
|
||||||
<Loader size="lg" color="blue" />
|
<Loader size="lg" color="blue" />
|
||||||
<Text c="dimmed" fz="sm">Sedang memuat informasi...</Text>
|
<Text c="dimmed" fz={{ base: 'xs', md: 'sm' }} ta="center">
|
||||||
|
Sedang memuat informasi...
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
);
|
);
|
||||||
@@ -46,28 +49,31 @@ function Page() {
|
|||||||
<Center h="80vh">
|
<Center h="80vh">
|
||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<IconMoodSad size={64} stroke={1.5} color="var(--mantine-color-blue-6)" />
|
<IconMoodSad size={64} stroke={1.5} color="var(--mantine-color-blue-6)" />
|
||||||
<Title order={3}>Data Tidak Ditemukan</Title>
|
<Title order={3} ta="center">
|
||||||
<Text c="dimmed" fz="sm">Mohon periksa kembali atau coba beberapa saat lagi</Text>
|
Data Tidak Ditemukan
|
||||||
|
</Title>
|
||||||
|
<Text c="dimmed" fz={{ base: 'xs', md: 'sm' }} ta="center">
|
||||||
|
Mohon periksa kembali atau coba beberapa saat lagi
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="xl" px={{ base: "md", md: 0 }}>
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="xl" px={{ base: 'md', md: 0 }}>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Container w={{ base: "100%", md: "60%" }}>
|
<Container w={{ base: '100%', md: '60%' }}>
|
||||||
<Paper radius="2xl" shadow="lg" p="xl" withBorder>
|
<Paper radius="2xl" shadow="lg" p="xl" withBorder>
|
||||||
<Stack gap="lg" align="center">
|
<Stack gap="lg" align="center">
|
||||||
<Title ta="center" fz={{ base: "2rem", md: "3rem" }} c={colors["blue-button"]} fw={800}>
|
<Title order={1} ta="center" c={colors['blue-button']} fw={800}>
|
||||||
{state.findUnique.data?.name}
|
{state.findUnique.data?.name}
|
||||||
</Title>
|
</Title>
|
||||||
<Text ta="center" fw={600} fz={{ base: "md", md: "lg" }} c="dimmed">
|
<Text ta="center" fw={600} fz={{ base: 'md', md: 'lg' }} c="dimmed">
|
||||||
Informasi & Pelayanan Potensi Desa Digital
|
Informasi & Pelayanan Potensi Desa Digital
|
||||||
</Text>
|
</Text>
|
||||||
{/* ✅ Bagian gambar dibuat konsisten tanpa CSS manual */}
|
|
||||||
<Box
|
<Box
|
||||||
w="100%"
|
w="100%"
|
||||||
h={{ base: 220, md: 400 }}
|
h={{ base: 220, md: 400 }}
|
||||||
@@ -87,7 +93,15 @@ function Page() {
|
|||||||
radius="lg"
|
radius="lg"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Text py="md" fz={{ base: "sm", md: "md" }} ta="justify" lh={1.8} dangerouslySetInnerHTML={{ __html: state.findUnique.data?.deskripsi || 'Belum ada deskripsi untuk potensi desa ini.' }} />
|
<Text
|
||||||
|
py="md"
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
ta="justify"
|
||||||
|
lh={{ base: 1.6, md: 1.8 }}
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: state.findUnique.data?.content || 'Belum ada deskripsi untuk potensi desa ini.',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import potensiDesaState from '@/app/admin/(dashboard)/_state/desa/potensi';
|
import potensiDesaState from '@/app/admin/(dashboard)/_state/desa/potensi';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { BackgroundImage, Box, Button, Center, Flex, Group, Paper, SimpleGrid, Skeleton, Stack, Text } from '@mantine/core';
|
import { BackgroundImage, Box, Button, Flex, Group, Paper, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { IconEye } from '@tabler/icons-react';
|
import { IconEye } from '@tabler/icons-react';
|
||||||
import { useTransitionRouter } from 'next-view-transitions';
|
import { useTransitionRouter } from 'next-view-transitions';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -41,10 +41,10 @@ function Page() {
|
|||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Flex justify="space-between" align="center" direction={{ base: "column", md: "row" }} gap="lg">
|
<Flex justify="space-between" align="center" direction={{ base: "column", md: "row" }} gap="lg">
|
||||||
<Stack gap="sm" maw={600}>
|
<Stack gap="sm" maw={600}>
|
||||||
<Text fz={{ base: "2rem", md: "3rem" }} fw={900} c={colors["blue-button"]} lh={1.2}>
|
<Title order={1} fz={{ base: 28, md: 36 }} lh={1.2} c={colors["blue-button"]}>
|
||||||
Potensi Desa Darmasaba
|
Potensi Desa Darmasaba
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="lg" ta="justify">
|
<Text fz={{ base: 14, md: 16 }} lh={1.6} ta="justify">
|
||||||
Temukan berbagai potensi unggulan, peluang, dan daya tarik yang menjadikan Desa Darmasaba istimewa.
|
Temukan berbagai potensi unggulan, peluang, dan daya tarik yang menjadikan Desa Darmasaba istimewa.
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -58,18 +58,18 @@ function Page() {
|
|||||||
>
|
>
|
||||||
<Flex justify="center" align="center" gap="xl">
|
<Flex justify="center" align="center" gap="xl">
|
||||||
<Box>
|
<Box>
|
||||||
<Text ta="center" fz="2rem" fw={800} c="white">
|
<Text ta="center" fz={{ base: 20, md: 32 }} fw={800} c="white" lh={1.2}>
|
||||||
{data?.filter(item => item.kategori?.nama.toLowerCase() !== 'wisata').length || 0}
|
{data?.filter(item => item.kategori?.nama.toLowerCase() !== 'wisata').length || 0}
|
||||||
</Text>
|
</Text>
|
||||||
<Text ta="center" fz="sm" c="white" fw={500}>
|
<Text ta="center" fz={{ base: 12, md: 14 }} c="white" fw={500}>
|
||||||
Potensi
|
Potensi
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Text ta="center" fz="2rem" fw={800} c="white">
|
<Text ta="center" fz={{ base: 20, md: 32 }} fw={800} c="white" lh={1.2}>
|
||||||
{data?.filter(item => item.kategori?.nama.toLowerCase() === 'wisata').length || 0}
|
{data?.filter(item => item.kategori?.nama.toLowerCase() === 'wisata').length || 0}
|
||||||
</Text>
|
</Text>
|
||||||
<Text ta="center" fz="sm" c="white" fw={500}>
|
<Text ta="center" fz={{ base: 12, md: 14 }} c="white" fw={500}>
|
||||||
Wisata
|
Wisata
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -98,7 +98,6 @@ function Page() {
|
|||||||
transition: 'transform 0.3s ease'
|
transition: 'transform 0.3s ease'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Overlay with smooth transition */}
|
|
||||||
<Box
|
<Box
|
||||||
pos="absolute"
|
pos="absolute"
|
||||||
inset={0}
|
inset={0}
|
||||||
@@ -112,7 +111,6 @@ function Page() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Stack justify="space-between" h="100%" gap="md" p="lg" pos="relative">
|
<Stack justify="space-between" h="100%" gap="md" p="lg" pos="relative">
|
||||||
{/* Kategori badge - always visible */}
|
|
||||||
<Group>
|
<Group>
|
||||||
<Paper
|
<Paper
|
||||||
radius="lg"
|
radius="lg"
|
||||||
@@ -121,15 +119,12 @@ function Page() {
|
|||||||
shadow="md"
|
shadow="md"
|
||||||
withBorder
|
withBorder
|
||||||
bg="rgba(255,255,255,0.9)"
|
bg="rgba(255,255,255,0.9)"
|
||||||
style={{
|
style={{ transition: 'all 0.3s ease' }}
|
||||||
transition: 'all 0.3s ease'
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Text fz="sm" fw={600}>{v.kategori?.nama}</Text>
|
<Text fz={{ base: 11, md: 14 }} fw={600}>{v.kategori?.nama}</Text>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Nama potensi - visible on hover */}
|
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
opacity: hoveredId === v.id ? 1 : 0,
|
opacity: hoveredId === v.id ? 1 : 0,
|
||||||
@@ -138,19 +133,19 @@ function Page() {
|
|||||||
pointerEvents: hoveredId === v.id ? 'auto' : 'none'
|
pointerEvents: hoveredId === v.id ? 'auto' : 'none'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Title
|
||||||
|
order={3}
|
||||||
fw={800}
|
fw={800}
|
||||||
c="white"
|
c="white"
|
||||||
fz="xl"
|
fz={{ base: 18, md: 20 }}
|
||||||
ta="center"
|
ta="center"
|
||||||
lineClamp={2}
|
lineClamp={2}
|
||||||
lh={1.3}
|
lh={1.3}
|
||||||
>
|
>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Title>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Button - visible on hover */}
|
|
||||||
<Group
|
<Group
|
||||||
justify="center"
|
justify="center"
|
||||||
style={{
|
style={{
|
||||||
@@ -169,23 +164,21 @@ function Page() {
|
|||||||
gradient={{ from: colors["blue-button"], to: "#4dabf7", deg: 45 }}
|
gradient={{ from: colors["blue-button"], to: "#4dabf7", deg: 45 }}
|
||||||
onClick={() => router.push(`/darmasaba/desa/potensi/${v.id}`)}
|
onClick={() => router.push(`/darmasaba/desa/potensi/${v.id}`)}
|
||||||
>
|
>
|
||||||
Lihat Detail
|
<Text c={'white'} fz={{ base: 12, md: 14 }} fw={500}>Lihat Detail</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</BackgroundImage>
|
</BackgroundImage>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<Center h={240}>
|
|
||||||
<Stack align="center" gap="xs">
|
<Stack align="center" gap="xs">
|
||||||
<Text fz="lg" fw={600} c="dimmed">
|
<Text fz={{ base: 14, md: 16 }} fw={600} c="dimmed">
|
||||||
Belum ada potensi desa
|
Belum ada potensi desa
|
||||||
</Text>
|
</Text>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text fz={{ base: 12, md: 14 }} c="dimmed">
|
||||||
Data potensi akan tampil di sini setelah tersedia.
|
Data potensi akan tampil di sini setelah tersedia.
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
|
||||||
)}
|
)}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ function DetailPegawaiUser() {
|
|||||||
statePegawai.findUnique.load(params?.id as string);
|
statePegawai.findUnique.load(params?.id as string);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
if (!statePegawai.findUnique.data) {
|
if (!statePegawai.findUnique.data) {
|
||||||
return (
|
return (
|
||||||
<Stack py="lg">
|
<Stack py="lg">
|
||||||
@@ -41,7 +40,7 @@ function DetailPegawaiUser() {
|
|||||||
<Box px={{ base: 'md', md: 100 }} py="xl">
|
<Box px={{ base: 'md', md: 100 }} py="xl">
|
||||||
{/* Back button */}
|
{/* Back button */}
|
||||||
<Group mb="lg" px={{ base: 'md', md: 100 }}>
|
<Group mb="lg" px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton/>
|
<BackButton />
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Paper
|
<Paper
|
||||||
@@ -69,11 +68,17 @@ function DetailPegawaiUser() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Nama & Jabatan */}
|
{/* Nama & Jabatan */}
|
||||||
<Stack align="center" gap={2}>
|
<Stack align="center" gap={4}>
|
||||||
<Title order={3} fw={700} c={colors['blue-button']}>
|
{/* Title utama → H2 karena ini judul profil */}
|
||||||
|
<Title order={2} c={colors['blue-button']} lh={1.2}>
|
||||||
{data.namaLengkap || '-'} {data.gelarAkademik || ''}
|
{data.namaLengkap || '-'} {data.gelarAkademik || ''}
|
||||||
</Title>
|
</Title>
|
||||||
<Text fz="sm" c="dimmed">
|
|
||||||
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={1.4}
|
||||||
|
c="dimmed"
|
||||||
|
>
|
||||||
{data.posisi?.nama || 'Posisi tidak tersedia'}
|
{data.posisi?.nama || 'Posisi tidak tersedia'}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -82,7 +87,11 @@ function DetailPegawaiUser() {
|
|||||||
<Divider my="lg" />
|
<Divider my="lg" />
|
||||||
|
|
||||||
{/* Informasi Detail */}
|
{/* Informasi Detail */}
|
||||||
<Stack gap="md">
|
<Stack gap="lg">
|
||||||
|
<Title order={3} lh={1.3}>
|
||||||
|
Informasi Pegawai
|
||||||
|
</Title>
|
||||||
|
|
||||||
<InfoRow label="Email" value={data.email} />
|
<InfoRow label="Email" value={data.email} />
|
||||||
<InfoRow label="Telepon" value={data.telepon} />
|
<InfoRow label="Telepon" value={data.telepon} />
|
||||||
<InfoRow label="Alamat" value={data.alamat} multiline />
|
<InfoRow label="Alamat" value={data.alamat} multiline />
|
||||||
@@ -123,11 +132,18 @@ function InfoRow({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="sm" fw={600} c="dark">
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
fw={600}
|
||||||
|
lh={1.3}
|
||||||
|
c="dark"
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={1.5}
|
||||||
c={valueColor || 'dimmed'}
|
c={valueColor || 'dimmed'}
|
||||||
style={{
|
style={{
|
||||||
whiteSpace: multiline ? 'normal' : 'nowrap',
|
whiteSpace: multiline ? 'normal' : 'nowrap',
|
||||||
|
|||||||
@@ -36,11 +36,12 @@ import { useTransitionRouter } from 'next-view-transitions'
|
|||||||
import { OrganizationChart } from 'primereact/organizationchart'
|
import { OrganizationChart } from 'primereact/organizationchart'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useProxy } from 'valtio/utils'
|
import { useProxy } from 'valtio/utils'
|
||||||
import './struktur.css'
|
|
||||||
import BackButton from '../_com/BackButto'
|
|
||||||
import { useMediaQuery } from '@mantine/hooks'
|
|
||||||
|
|
||||||
export default function StrukturPerangkatDesa() {
|
import './struktur.css'
|
||||||
|
import { useMediaQuery } from '@mantine/hooks'
|
||||||
|
import BackButton from '../_com/BackButto'
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
@@ -59,10 +60,11 @@ export default function StrukturPerangkatDesa() {
|
|||||||
ta="center"
|
ta="center"
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
fz={{ base: 28, md: 36, lg: 44 }}
|
fz={{ base: 28, md: 36, lg: 44 }}
|
||||||
|
lh={{ base: 1.05, md: 1.03 }}
|
||||||
>
|
>
|
||||||
Struktur Perangkat Desa
|
Struktur Perangkat Desa
|
||||||
</Title>
|
</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
|
Gambaran visual peran dan pegawai yang ditugaskan. Arahkan kursor
|
||||||
untuk melihat detail atau klik node untuk fokus tampilan.
|
untuk melihat detail atau klik node untuk fokus tampilan.
|
||||||
</Text>
|
</Text>
|
||||||
@@ -105,8 +107,8 @@ function StrukturPerangkatDesaNode() {
|
|||||||
<Center py={48}>
|
<Center py={48}>
|
||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<Loader size="lg" />
|
<Loader size="lg" />
|
||||||
<Text fw={600}>Memuat struktur organisasi…</Text>
|
<Text fw={600} fz={{ base: 15, md: 16 }} lh={1.2}>Memuat struktur organisasi…</Text>
|
||||||
<Text c="dimmed" size="sm">
|
<Text c="dimmed" fz={{ base: 12, md: 13 }} lh={1.4}>
|
||||||
Mengambil data pegawai dan posisi. Mohon tunggu sebentar.
|
Mengambil data pegawai dan posisi. Mohon tunggu sebentar.
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -132,10 +134,10 @@ function StrukturPerangkatDesaNode() {
|
|||||||
<Center>
|
<Center>
|
||||||
<IconUsers size={56} />
|
<IconUsers size={56} />
|
||||||
</Center>
|
</Center>
|
||||||
<Title order={3} mt="md">
|
<Title order={3} mt="md" fz={{ base: 16, md: 18 }} lh={1.15}>
|
||||||
Data pegawai belum tersedia
|
Data pegawai belum tersedia
|
||||||
</Title>
|
</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.
|
Belum ada data pegawai yang tercatat untuk PPID.
|
||||||
</Text>
|
</Text>
|
||||||
<Group justify="center" mt="lg">
|
<Group justify="center" mt="lg">
|
||||||
@@ -232,11 +234,18 @@ function StrukturPerangkatDesaNode() {
|
|||||||
{/* 🔍 Controls */}
|
{/* 🔍 Controls */}
|
||||||
<Paper
|
<Paper
|
||||||
shadow="xs"
|
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"
|
p="md"
|
||||||
radius="md"
|
radius="md"
|
||||||
style={{
|
style={{
|
||||||
background: colors['blue-button'],
|
background: colors['blue-button'], // ⬅️ penting
|
||||||
width: '100%', // ⬅️ penting
|
|
||||||
maxWidth: '100%', // ⬅️ penting
|
maxWidth: '100%', // ⬅️ penting
|
||||||
overflowX: 'auto' // ⬅️ untuk mencegah overflow
|
overflowX: 'auto' // ⬅️ untuk mencegah overflow
|
||||||
}}
|
}}
|
||||||
@@ -269,30 +278,33 @@ function StrukturPerangkatDesaNode() {
|
|||||||
fontSize: '0.875rem',
|
fontSize: '0.875rem',
|
||||||
padding: '6px 12px',
|
padding: '6px 12px',
|
||||||
minHeight: 'auto',
|
minHeight: 'auto',
|
||||||
flexShrink: 0, // 👈 PENTING: mencegah tab mengecil
|
flexShrink: 0,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
style={{ width: '100%' }} // 👈 penting
|
||||||
>
|
>
|
||||||
<TabsList
|
<TabsList
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
overflowX: 'auto',
|
overflowX: 'auto',
|
||||||
overflowY: 'hidden', // 👈 tambahkan ini
|
overflowY: 'hidden',
|
||||||
gap: '4px',
|
gap: '4px',
|
||||||
paddingBottom: '4px',
|
paddingBottom: '4px',
|
||||||
flexWrap: 'nowrap',
|
flexWrap: 'nowrap',
|
||||||
WebkitOverflowScrolling: 'touch', // 👈 smooth scroll di iOS
|
WebkitOverflowScrolling: 'touch',
|
||||||
scrollbarWidth: 'thin', // 👈 scrollbar tipis di Firefox
|
scrollbarWidth: 'thin',
|
||||||
msOverflowStyle: '-ms-autohiding-scrollbar', // 👈 untuk IE/Edge
|
msOverflowStyle: '-ms-autohiding-scrollbar',
|
||||||
|
maxWidth: '100%',
|
||||||
|
scrollBehavior: 'smooth', // 👈 smooth scroll
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TabsTab
|
<TabsTab
|
||||||
value="zoom-out"
|
value="zoom-out"
|
||||||
onClick={handleZoomOut}
|
onClick={handleZoomOut}
|
||||||
leftSection={<IconZoomOut size={16} />}
|
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>
|
</TabsTab>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
@@ -301,7 +313,6 @@ function StrukturPerangkatDesaNode() {
|
|||||||
px={12}
|
px={12}
|
||||||
py={6}
|
py={6}
|
||||||
style={{
|
style={{
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
minWidth: 60,
|
minWidth: 60,
|
||||||
@@ -310,10 +321,12 @@ function StrukturPerangkatDesaNode() {
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
whiteSpace: 'nowrap', // 👈 mencegah text wrap
|
whiteSpace: 'nowrap',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Text fz={{ base: 12, sm: 13 }} lh={1} c={colors['blue-button']}>
|
||||||
{Math.round(scale * 100)}%
|
{Math.round(scale * 100)}%
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<TabsTab
|
<TabsTab
|
||||||
@@ -322,7 +335,7 @@ function StrukturPerangkatDesaNode() {
|
|||||||
leftSection={<IconZoomIn size={16} />}
|
leftSection={<IconZoomIn size={16} />}
|
||||||
style={{ flexShrink: 0 }}
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
Zoom In
|
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">Zoom In</Text>
|
||||||
</TabsTab>
|
</TabsTab>
|
||||||
|
|
||||||
<TabsTab
|
<TabsTab
|
||||||
@@ -330,7 +343,7 @@ function StrukturPerangkatDesaNode() {
|
|||||||
onClick={resetZoom}
|
onClick={resetZoom}
|
||||||
style={{ flexShrink: 0 }}
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
Reset
|
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">Reset</Text>
|
||||||
</TabsTab>
|
</TabsTab>
|
||||||
|
|
||||||
<TabsTab
|
<TabsTab
|
||||||
@@ -345,7 +358,9 @@ function StrukturPerangkatDesaNode() {
|
|||||||
}
|
}
|
||||||
style={{ flexShrink: 0 }}
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
|
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">
|
||||||
{isFullscreen ? 'Exit' : 'Fullscreen'}
|
{isFullscreen ? 'Exit' : 'Fullscreen'}
|
||||||
|
</Text>
|
||||||
</TabsTab>
|
</TabsTab>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
@@ -451,17 +466,17 @@ function NodeCard({ node, router }: any) {
|
|||||||
{/* Name */}
|
{/* Name */}
|
||||||
<Text
|
<Text
|
||||||
fw={700}
|
fw={700}
|
||||||
size="sm"
|
|
||||||
ta="center"
|
ta="center"
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
lineClamp={2}
|
lineClamp={2}
|
||||||
|
fz={{ base: 13, md: 15 }}
|
||||||
|
lh={1.2}
|
||||||
style={{
|
style={{
|
||||||
minHeight: 40,
|
minHeight: 40,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
wordBreak: 'break-word',
|
wordBreak: 'break-word',
|
||||||
lineHeight: 1.3,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
@@ -469,18 +484,18 @@ function NodeCard({ node, router }: any) {
|
|||||||
|
|
||||||
{/* Title/Position */}
|
{/* Title/Position */}
|
||||||
<Text
|
<Text
|
||||||
size="xs"
|
|
||||||
c="dimmed"
|
c="dimmed"
|
||||||
ta="center"
|
ta="center"
|
||||||
fw={500}
|
fw={500}
|
||||||
lineClamp={2}
|
lineClamp={2}
|
||||||
|
fz={{ base: 12, md: 13 }}
|
||||||
|
lh={1.3}
|
||||||
style={{
|
style={{
|
||||||
minHeight: 32,
|
minHeight: 32,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
wordBreak: 'break-word',
|
wordBreak: 'break-word',
|
||||||
lineHeight: 1.2,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
@@ -496,14 +511,14 @@ function NodeCard({ node, router }: any) {
|
|||||||
mt={8}
|
mt={8}
|
||||||
radius="md"
|
radius="md"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
router.push(`/darmasaba/desa/profile/struktur-perangkat-desa/${node.data.id}`)
|
router.push(`/darmasaba/desa/profil/struktur-perangkat-desa/${node.data.id}`)
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
height: 32,
|
height: 32,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Lihat Detail
|
<Text fz={{ base: 12, md: 13 }} lh={1} ta="center">Lihat Detail</Text>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile'
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile'
|
||||||
import colors from '@/con/colors'
|
import colors from '@/con/colors'
|
||||||
import { Box, Center, Image, Paper, Skeleton, Stack, Text } from '@mantine/core'
|
import { Box, Center, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useProxy } from 'valtio/utils'
|
import { useProxy } from 'valtio/utils'
|
||||||
|
|
||||||
@@ -26,6 +26,8 @@ function LambangDesa() {
|
|||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack align="center" gap="lg">
|
<Stack align="center" gap="lg">
|
||||||
|
|
||||||
|
{/* HEADER */}
|
||||||
<Box pb="lg">
|
<Box pb="lg">
|
||||||
<Center>
|
<Center>
|
||||||
<Image
|
<Image
|
||||||
@@ -36,17 +38,20 @@ function LambangDesa() {
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
<Text
|
|
||||||
|
{/* TITLE - H1 */}
|
||||||
|
<Title
|
||||||
|
order={1}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
ta="center"
|
ta="center"
|
||||||
fw={800}
|
|
||||||
fz={{ base: 28, md: 40 }}
|
|
||||||
mt="sm"
|
mt="sm"
|
||||||
style={{ letterSpacing: '-0.5px' }}
|
style={{ letterSpacing: '-0.5px' }}
|
||||||
>
|
>
|
||||||
Lambang Desa
|
Lambang Desa
|
||||||
</Text>
|
</Title>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* DESKRIPSI */}
|
||||||
<Paper
|
<Paper
|
||||||
p="xl"
|
p="xl"
|
||||||
radius="xl"
|
radius="xl"
|
||||||
@@ -59,14 +64,19 @@ function LambangDesa() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: '1.125rem', md: '1.375rem' }}
|
fz={{ base: 'sm', md: 'md' }} // Body text mobile & desktop
|
||||||
lh={1.8}
|
lh={1.7}
|
||||||
c="dark"
|
c="dark"
|
||||||
ta="justify"
|
ta="justify"
|
||||||
style={{ fontWeight: 400, wordBreak: "break-word", whiteSpace: "normal", }}
|
style={{
|
||||||
|
fontWeight: 400,
|
||||||
|
wordBreak: "break-word",
|
||||||
|
whiteSpace: "normal",
|
||||||
|
}}
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Card, Center, Group, Image, Loader, Paper, Stack, Text } from '@mantine/core';
|
import { Box, Card, Center, Group, Image, Loader, Paper, Stack, Text, Title } from '@mantine/core';
|
||||||
import { IconPhoto } from '@tabler/icons-react';
|
import { IconPhoto } from '@tabler/icons-react';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
@@ -21,7 +21,9 @@ function MaskotDesa() {
|
|||||||
<Center mih={500}>
|
<Center mih={500}>
|
||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<Loader size="lg" color="blue" />
|
<Loader size="lg" color="blue" />
|
||||||
<Text c="dimmed" fz="sm">Sedang memuat data maskot desa...</Text>
|
<Text c="dimmed" fz={{ base: 'xs', md: 'sm' }}>
|
||||||
|
Sedang memuat data maskot desa...
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
);
|
);
|
||||||
@@ -31,8 +33,21 @@ function MaskotDesa() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Stack align="center" gap="xl">
|
<Stack align="center" gap="xl">
|
||||||
<Stack align="center" gap={10}>
|
<Stack align="center" gap={10}>
|
||||||
<Image src="/pudak-icon.png" alt="Ikon Desa" w={{ base: 160, md: 240 }} loading="lazy"/>
|
<Image
|
||||||
<Text c={colors['blue-button']} ta="center" fw={700} fz={{ base: 28, md: 36 }}>Maskot Desa</Text>
|
src="/pudak-icon.png"
|
||||||
|
alt="Ikon Desa"
|
||||||
|
w={{ base: 160, md: 240 }}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Page Title */}
|
||||||
|
<Title
|
||||||
|
order={1}
|
||||||
|
ta="center"
|
||||||
|
c={colors['blue-button']}
|
||||||
|
>
|
||||||
|
Maskot Desa
|
||||||
|
</Title>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Paper
|
<Paper
|
||||||
@@ -42,13 +57,14 @@ function MaskotDesa() {
|
|||||||
withBorder
|
withBorder
|
||||||
style={{ background: 'linear-gradient(145deg, #ffffff, #f8f9fa)' }}
|
style={{ background: 'linear-gradient(145deg, #ffffff, #f8f9fa)' }}
|
||||||
>
|
>
|
||||||
|
{/* Body Description */}
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: 'sm', md: 'lg' }}
|
fz={{ base: 'sm', md: 'lg' }}
|
||||||
lh={1.7}
|
lh={1.7}
|
||||||
ta="justify"
|
ta="justify"
|
||||||
c="dark"
|
c="dark"
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Group justify="center" gap="lg" mt="lg">
|
<Group justify="center" gap="lg" mt="lg">
|
||||||
@@ -75,7 +91,15 @@ function MaskotDesa() {
|
|||||||
radius="md"
|
radius="md"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
<Text ta="center" mt="sm" fw={600} fz="sm" c="dark">
|
|
||||||
|
{/* Image Label */}
|
||||||
|
<Text
|
||||||
|
ta="center"
|
||||||
|
mt="sm"
|
||||||
|
fw={600}
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
c="dark"
|
||||||
|
>
|
||||||
{img.label}
|
{img.label}
|
||||||
</Text>
|
</Text>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -83,7 +107,10 @@ function MaskotDesa() {
|
|||||||
) : (
|
) : (
|
||||||
<Stack align="center" gap="xs" mt="lg">
|
<Stack align="center" gap="xs" mt="lg">
|
||||||
<IconPhoto size={48} stroke={1.5} color="gray" />
|
<IconPhoto size={48} stroke={1.5} color="gray" />
|
||||||
<Text c="dimmed" fz="sm">Belum ada gambar maskot yang ditambahkan</Text>
|
|
||||||
|
<Text c="dimmed" fz={{ base: 'xs', md: 'sm' }}>
|
||||||
|
Belum ada gambar maskot yang ditambahkan
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -1,35 +1,15 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { ActionIcon, Box, Flex, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
import { ActionIcon, Box, Flex, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { IconSparkles } from '@tabler/icons-react';
|
import { IconSparkles } from '@tabler/icons-react';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
|
|
||||||
const dataText = [
|
const dataText = [
|
||||||
{
|
{ id: 1, title: "Santun", description: "Pelayanan ramah, penuh empati, sopan, dan beretika." },
|
||||||
id: 1,
|
{ id: 2, title: "Adaptif", description: "Cepat menyesuaikan diri terhadap perubahan dan selalu proaktif." },
|
||||||
title: "Santun",
|
{ id: 3, title: "Inovatif", description: "Berani menciptakan pembaruan dan ide-ide kreatif." },
|
||||||
description: "Pelayanan ramah, penuh empati, sopan, dan beretika."
|
{ id: 4, title: "Profesional", description: "Berpengetahuan luas, terampil, dan bertanggung jawab." },
|
||||||
},
|
{ id: 5, title: "Gesit", description: "Cekatan, sigap, dan penuh inisiatif dalam bekerja." },
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: "Adaptif",
|
|
||||||
description: "Cepat menyesuaikan diri terhadap perubahan dan selalu proaktif."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
title: "Inovatif",
|
|
||||||
description: "Berani menciptakan pembaruan dan ide-ide kreatif."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
title: "Profesional",
|
|
||||||
description: "Berpengetahuan luas, terampil, dan bertanggung jawab."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
title: "Gesit",
|
|
||||||
description: "Cekatan, sigap, dan penuh inisiatif dalam bekerja."
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const letters = ["S", "I", "G", "A", "P"];
|
const letters = ["S", "I", "G", "A", "P"];
|
||||||
@@ -38,11 +18,14 @@ function MotoDesa() {
|
|||||||
return (
|
return (
|
||||||
<Box px={{ base: "md", md: "xl" }}>
|
<Box px={{ base: "md", md: "xl" }}>
|
||||||
<Stack align="center" gap="lg">
|
<Stack align="center" gap="lg">
|
||||||
|
{/* Page Title */}
|
||||||
<Box>
|
<Box>
|
||||||
<Text
|
<Title
|
||||||
|
order={1}
|
||||||
ta="center"
|
ta="center"
|
||||||
fw={800}
|
fw={800}
|
||||||
fz={{ base: "2rem", md: "2.8rem" }}
|
fz={{ base: 28, md: 36 }}
|
||||||
|
lh={{ base: 1.2, md: 1.3 }}
|
||||||
style={{
|
style={{
|
||||||
background: "linear-gradient(90deg, #0D5594FF, #094678FF)",
|
background: "linear-gradient(90deg, #0D5594FF, #094678FF)",
|
||||||
WebkitBackgroundClip: "text",
|
WebkitBackgroundClip: "text",
|
||||||
@@ -50,9 +33,10 @@ function MotoDesa() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Moto Desa Darmasaba
|
Moto Desa Darmasaba
|
||||||
</Text>
|
</Title>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Letter Icons */}
|
||||||
<Flex gap={30} pb={40} pt={10} wrap="wrap" justify="center">
|
<Flex gap={30} pb={40} pt={10} wrap="wrap" justify="center">
|
||||||
{letters.map((letter, i) => (
|
{letters.map((letter, i) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -71,7 +55,7 @@ function MotoDesa() {
|
|||||||
backdropFilter: "blur(6px)",
|
backdropFilter: "blur(6px)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text c="white" fw={800} fz="xl">
|
<Text c="white" fw={800} fz={{ base: 20, md: 24 }}>
|
||||||
{letter}
|
{letter}
|
||||||
</Text>
|
</Text>
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
@@ -79,6 +63,7 @@ function MotoDesa() {
|
|||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
{/* Values Card */}
|
||||||
<Paper
|
<Paper
|
||||||
radius="lg"
|
radius="lg"
|
||||||
p="xl"
|
p="xl"
|
||||||
@@ -90,19 +75,22 @@ function MotoDesa() {
|
|||||||
>
|
>
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="xl">
|
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="xl">
|
||||||
{dataText.map((v) => (
|
{dataText.map((v) => (
|
||||||
<motion.div
|
<motion.div key={v.id} whileHover={{ scale: 1.02 }} transition={{ duration: 0.2 }}>
|
||||||
key={v.id}
|
|
||||||
whileHover={{ scale: 1.02 }}
|
|
||||||
transition={{ duration: 0.2 }}
|
|
||||||
>
|
|
||||||
<Stack gap={4}>
|
<Stack gap={4}>
|
||||||
|
{/* Section Title */}
|
||||||
<Flex align="center" gap="sm">
|
<Flex align="center" gap="sm">
|
||||||
<IconSparkles size={20} color={colors['blue-button']} />
|
<IconSparkles size={20} color={colors['blue-button']} />
|
||||||
<Text fw={700} fz={{ base: "lg", md: "xl" }} c={colors['blue-button']}>
|
<Title
|
||||||
|
order={3}
|
||||||
|
fw={700}
|
||||||
|
fz={{ base: 20, md: 24 }}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
>
|
||||||
{v.title}
|
{v.title}
|
||||||
</Text>
|
</Title>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Text fz={{ base: "sm", md: "md" }} c="gray.7">
|
{/* Body Text */}
|
||||||
|
<Text fz={{ base: 14, md: 16 }} lh={{ base: 1.5, md: 1.6 }} c="gray.7">
|
||||||
{v.description}
|
{v.description}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -111,16 +99,15 @@ function MotoDesa() {
|
|||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
|
{/* Motto Description */}
|
||||||
<Text
|
<Text
|
||||||
ta="center"
|
ta="center"
|
||||||
fw={700}
|
fw={700}
|
||||||
fz={{ base: "md", md: "xl" }}
|
fz={{ base: 15, md: 20 }}
|
||||||
|
lh={{ base: 1.6, md: 1.8 }}
|
||||||
c="blue.8"
|
c="blue.8"
|
||||||
mt="md"
|
mt="md"
|
||||||
style={{
|
style={{ maxWidth: 720 }}
|
||||||
maxWidth: 720,
|
|
||||||
lineHeight: 1.6,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
"Berkomitmen menghadirkan pelayanan terbaik dengan semangat{" "}
|
"Berkomitmen menghadirkan pelayanan terbaik dengan semangat{" "}
|
||||||
<Text span fw={800} c="cyan.6">
|
<Text span fw={800} c="cyan.6">
|
||||||
|
|||||||
@@ -2,44 +2,45 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Divider, Image, Paper, SimpleGrid, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Divider, Image, Paper, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { IconBriefcase, IconTargetArrow, IconUser, IconUsers } from '@tabler/icons-react';
|
import { IconBriefcase, IconTargetArrow, IconUser, IconUsers } from '@tabler/icons-react';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
function ProfilPerbekel() {
|
function ProfilPerbekel() {
|
||||||
const state = useProxy(stateProfileDesa.profilPerbekel)
|
const state = useProxy(stateProfileDesa.profilPerbekel);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
state.findUnique.load("edit")
|
state.findUnique.load("edit");
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
const { data, loading } = state.findUnique
|
const { data, loading } = state.findUnique;
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Box py={20} px="md">
|
<Box py={20} px="md">
|
||||||
<Skeleton h={500} radius="lg" />
|
<Skeleton h={500} radius="lg" />
|
||||||
</Box>
|
</Box>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px="md">
|
<Box px="md">
|
||||||
|
{/* ===== PAGE TITLE ===== */}
|
||||||
<Stack align="center" gap={0} mb={40}>
|
<Stack align="center" gap={0} mb={40}>
|
||||||
<Text
|
<Title
|
||||||
|
order={1}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
ta="center"
|
ta="center"
|
||||||
fw="bold"
|
|
||||||
fz={{ base: "2rem", md: "2.8rem" }}
|
|
||||||
style={{ letterSpacing: "0.5px" }}
|
style={{ letterSpacing: "0.5px" }}
|
||||||
>
|
>
|
||||||
Profil Perbekel
|
Profil Perbekel
|
||||||
</Text>
|
</Title>
|
||||||
<Divider w={120} size="sm" color={colors['blue-button']} mt={10} />
|
<Divider w={120} size="sm" color={colors['blue-button']} mt={10} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="xl" pb={50}>
|
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="xl" pb={50}>
|
||||||
|
{/* ========== FOTO PERBEKEL ========== */}
|
||||||
<Box>
|
<Box>
|
||||||
<Paper
|
<Paper
|
||||||
bg={colors['white-trans-1']}
|
bg={colors['white-trans-1']}
|
||||||
@@ -60,6 +61,8 @@ function ProfilPerbekel() {
|
|||||||
}}
|
}}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* ===== NAMA DAN JABATAN ===== */}
|
||||||
<Paper
|
<Paper
|
||||||
bg={colors['blue-button']}
|
bg={colors['blue-button']}
|
||||||
px="lg"
|
px="lg"
|
||||||
@@ -67,22 +70,23 @@ function ProfilPerbekel() {
|
|||||||
className="glass3"
|
className="glass3"
|
||||||
py={{ base: 20, md: 50 }}
|
py={{ base: 20, md: 50 }}
|
||||||
>
|
>
|
||||||
<Text c={colors['white-1']} fz={{ base: "lg", md: "h3" }}>
|
<Title order={3} c={colors['white-1']}>
|
||||||
Perbekel Desa Darmasaba
|
Perbekel Desa Darmasaba
|
||||||
</Text>
|
</Title>
|
||||||
<Text
|
|
||||||
|
<Title
|
||||||
|
order={2}
|
||||||
c={colors['white-1']}
|
c={colors['white-1']}
|
||||||
fw="bolder"
|
|
||||||
fz={{ base: "xl", md: "h2" }}
|
|
||||||
mt={8}
|
mt={8}
|
||||||
>
|
>
|
||||||
{"I.B. Surya Prabhawa Manuaba, S.H.,M.H.,NL.P."}
|
{"I.B. Surya Prabhawa Manuaba, S.H.,M.H.,NL.P."}
|
||||||
</Text>
|
</Title>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* ========== BIODATA & PENGALAMAN ========== */}
|
||||||
<Paper
|
<Paper
|
||||||
p="xl"
|
p="xl"
|
||||||
bg={colors['white-trans-1']}
|
bg={colors['white-trans-1']}
|
||||||
@@ -92,34 +96,39 @@ function ProfilPerbekel() {
|
|||||||
withBorder
|
withBorder
|
||||||
>
|
>
|
||||||
<Stack gap="xl">
|
<Stack gap="xl">
|
||||||
|
|
||||||
|
{/* ===== BIODATA ===== */}
|
||||||
<Box>
|
<Box>
|
||||||
<Stack gap={6}>
|
<Stack gap={6}>
|
||||||
<Stack align="center" gap={6}>
|
<Stack align="center" gap={6}>
|
||||||
<IconUser size={22} />
|
<IconUser size={22} />
|
||||||
<Text fz={{ base: "1.2rem", md: "1.5rem" }} fw="bold">Biodata</Text>
|
<Title order={3}>Biodata</Title>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: "1rem", md: "1.2rem" }}
|
fz={{ base: "sm", md: "md" }}
|
||||||
ta="justify"
|
ta="justify"
|
||||||
lh={1.6}
|
lh={1.7}
|
||||||
dangerouslySetInnerHTML={{ __html: data.biodata }}
|
dangerouslySetInnerHTML={{ __html: data.biodata }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word" }}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* ===== PENGALAMAN ===== */}
|
||||||
<Box>
|
<Box>
|
||||||
<Stack gap={6}>
|
<Stack gap={6}>
|
||||||
<Stack align="center" gap={6}>
|
<Stack align="center" gap={6}>
|
||||||
<IconBriefcase size={22} />
|
<IconBriefcase size={22} />
|
||||||
<Text fz={{ base: "1.2rem", md: "1.5rem" }} fw="bold">Pengalaman</Text>
|
<Title order={3}>Pengalaman</Title>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: "1rem", md: "1.2rem" }}
|
fz={{ base: "sm", md: "md" }}
|
||||||
ta="left"
|
ta="left"
|
||||||
lh={1.6}
|
lh={1.7}
|
||||||
dangerouslySetInnerHTML={{ __html: data.pengalaman }}
|
dangerouslySetInnerHTML={{ __html: data.pengalaman }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word" }}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -127,6 +136,7 @@ function ProfilPerbekel() {
|
|||||||
</Paper>
|
</Paper>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
|
||||||
|
{/* ========== ORGANISASI & PROGRAM UNGGULAN ========== */}
|
||||||
<Paper
|
<Paper
|
||||||
p="xl"
|
p="xl"
|
||||||
bg={colors['white-trans-1']}
|
bg={colors['white-trans-1']}
|
||||||
@@ -136,35 +146,41 @@ function ProfilPerbekel() {
|
|||||||
withBorder
|
withBorder
|
||||||
>
|
>
|
||||||
<Stack gap="xl">
|
<Stack gap="xl">
|
||||||
|
|
||||||
|
{/* ===== PENGALAMAN ORGANISASI ===== */}
|
||||||
<Box>
|
<Box>
|
||||||
<Stack align="center" gap={6} >
|
<Stack align="center" gap={6}>
|
||||||
<IconUsers size={22} />
|
<IconUsers size={22} />
|
||||||
<Text fz={{ base: "1.2rem", md: "1.5rem" }} fw="bold">Pengalaman Organisasi</Text>
|
<Title order={3}>Pengalaman Organisasi</Title>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: "1rem", md: "1.2rem" }}
|
fz={{ base: "sm", md: "md" }}
|
||||||
ta="justify"
|
ta="justify"
|
||||||
lh={1.6}
|
lh={1.7}
|
||||||
dangerouslySetInnerHTML={{ __html: data.pengalamanOrganisasi }}
|
dangerouslySetInnerHTML={{ __html: data.pengalamanOrganisasi }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word" }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* ===== PROGRAM UNGGULAN ===== */}
|
||||||
<Box>
|
<Box>
|
||||||
<Stack align="center" gap={6} mb={6}>
|
<Stack align="center" gap={6} mb={6}>
|
||||||
<IconTargetArrow size={22} />
|
<IconTargetArrow size={22} />
|
||||||
<Text fz={{ base: "1.2rem", md: "1.5rem" }} fw="bold">Program Kerja Unggulan</Text>
|
<Title order={3}>Program Kerja Unggulan</Title>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Box px={10}>
|
<Box px={10}>
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: "1rem", md: "1.2rem" }}
|
fz={{ base: "sm", md: "md" }}
|
||||||
ta="justify"
|
ta="justify"
|
||||||
lh={1.6}
|
lh={1.7}
|
||||||
dangerouslySetInnerHTML={{ __html: data.programUnggulan }}
|
dangerouslySetInnerHTML={{ __html: data.programUnggulan }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word" }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Image, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Center, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
@@ -26,29 +26,32 @@ function SejarahDesa() {
|
|||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack align="center" gap="xl">
|
<Stack align="center" gap="xl">
|
||||||
|
{/* HEADER ICON + TITLE */}
|
||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<Center>
|
<Center>
|
||||||
<Image
|
<Image
|
||||||
src="/darmasaba-icon.png"
|
src="/darmasaba-icon.png"
|
||||||
alt="Ikon Desa Darmasaba"
|
alt="Ikon Desa Darmasaba"
|
||||||
w={{ base: 180, md: 260 }}
|
w={{ base: 160, md: 240 }}
|
||||||
radius="md"
|
radius="md"
|
||||||
style={{ filter: 'drop-shadow(0 4px 12px rgba(0,0,0,0.15))' }}
|
style={{ filter: 'drop-shadow(0 4px 12px rgba(0,0,0,0.15))' }}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Text
|
<Title
|
||||||
|
order={1}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
ta="center"
|
ta="center"
|
||||||
fw={700}
|
|
||||||
fz={{ base: '2rem', md: '2.8rem' }}
|
|
||||||
style={{ letterSpacing: '-0.5px' }}
|
style={{ letterSpacing: '-0.5px' }}
|
||||||
>
|
>
|
||||||
Sejarah Desa
|
Sejarah Desa
|
||||||
</Text>
|
</Title>
|
||||||
</Center>
|
</Center>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
|
{/* CONTENT */}
|
||||||
<Paper
|
<Paper
|
||||||
p="xl"
|
p="xl"
|
||||||
radius="lg"
|
radius="lg"
|
||||||
@@ -61,10 +64,14 @@ function SejarahDesa() {
|
|||||||
>
|
>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: 'md', md: 'lg' }}
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
lh={1.8}
|
lh={1.75}
|
||||||
ta="justify"
|
ta="justify"
|
||||||
style={{ color: '#2a2a2a', wordBreak: "break-word", whiteSpace: "normal" }}
|
c="dark.7"
|
||||||
|
style={{
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
whiteSpace: 'normal',
|
||||||
|
}}
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -28,8 +28,10 @@ function SemuaPerbekel() {
|
|||||||
<Center py="xl">
|
<Center py="xl">
|
||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<IconUser size={48} stroke={1.5} />
|
<IconUser size={48} stroke={1.5} />
|
||||||
<Title fw="bold" order={2}>Belum ada data Perbekel</Title>
|
<Title order={2} ta="center">Belum ada data Perbekel</Title>
|
||||||
<Text c="dimmed" fz="sm" ta="center">Data mantan Perbekel akan muncul di sini ketika sudah tersedia</Text>
|
<Text c="dimmed" fz={{ base: 'xs', md: 'sm' }} lh={{ base: 1.4, md: 1.6 }} ta="center">
|
||||||
|
Data mantan Perbekel akan muncul di sini ketika sudah tersedia
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
);
|
);
|
||||||
@@ -38,17 +40,20 @@ function SemuaPerbekel() {
|
|||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack align="center" gap="lg">
|
<Stack align="center" gap="lg">
|
||||||
<Box>
|
<Title
|
||||||
<Text
|
order={1}
|
||||||
ta="center"
|
ta="center"
|
||||||
|
style={{
|
||||||
|
background: 'linear-gradient(45deg, blue, cyan)',
|
||||||
|
WebkitBackgroundClip: 'text',
|
||||||
|
WebkitTextFillColor: 'transparent',
|
||||||
|
}}
|
||||||
|
fz={{ base: 28, md: 36 }}
|
||||||
|
lh={{ base: 1.2, md: 1.3 }}
|
||||||
fw={900}
|
fw={900}
|
||||||
fz={{ base: "2rem", md: "2.5rem" }}
|
|
||||||
variant="gradient"
|
|
||||||
gradient={{ from: "blue", to: "cyan", deg: 45 }}
|
|
||||||
>
|
>
|
||||||
Perbekel Dari Masa ke Masa
|
Perbekel Dari Masa ke Masa
|
||||||
</Text>
|
</Title>
|
||||||
</Box>
|
|
||||||
|
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2, md: 3 }} spacing="xl" w="100%">
|
<SimpleGrid cols={{ base: 1, sm: 2, md: 3 }} spacing="xl" w="100%">
|
||||||
{data.map((v: any, k: number) => (
|
{data.map((v: any, k: number) => (
|
||||||
@@ -59,9 +64,7 @@ function SemuaPerbekel() {
|
|||||||
withBorder
|
withBorder
|
||||||
p="lg"
|
p="lg"
|
||||||
bg="white"
|
bg="white"
|
||||||
style={{
|
style={{ transition: "all 250ms ease" }}
|
||||||
transition: "all 250ms ease",
|
|
||||||
}}
|
|
||||||
className="hover:shadow-xl hover:scale-[1.02]"
|
className="hover:shadow-xl hover:scale-[1.02]"
|
||||||
>
|
>
|
||||||
<Stack gap="md" align="center">
|
<Stack gap="md" align="center">
|
||||||
@@ -77,15 +80,15 @@ function SemuaPerbekel() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Stack gap={4} align="center">
|
<Stack gap={4} align="center">
|
||||||
<Text fw={700} fz="lg" ta="center">
|
<Title order={3} fz={{ base: 18, md: 20 }} ta="center" fw={700}>
|
||||||
{v.nama}
|
{v.nama}
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
<Text c="dimmed" fz="sm" ta="center">
|
<Text c="dimmed" fz={{ base: 12, md: 14 }} lh={{ base: 1.4, md: 1.6 }} ta="center">
|
||||||
{v.daerah}
|
{v.daerah}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text c="blue" fw={600} fz="sm" ta="center">
|
<Text c="blue" fw={600} fz={{ base: 12, md: 14 }} lh={{ base: 1.4, md: 1.6 }} ta="center">
|
||||||
{v.periode}
|
{v.periode}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Image, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
@@ -34,60 +34,57 @@ function VisiMisiDesa() {
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* VISI */}
|
||||||
<Paper
|
<Paper
|
||||||
p="xl"
|
p="xl"
|
||||||
radius="lg"
|
radius="lg"
|
||||||
shadow="md"
|
shadow="md"
|
||||||
withBorder
|
withBorder
|
||||||
w="100%"
|
w="100%"
|
||||||
style={{
|
style={{ background: 'linear-gradient(145deg, #ffffff, #f5f7fa)' }}
|
||||||
background: 'linear-gradient(145deg, #ffffff, #f5f7fa)',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Text
|
<Title
|
||||||
|
order={1}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
ta="center"
|
ta="center"
|
||||||
fw={700}
|
|
||||||
fz={{ base: '2rem', md: '2.5rem' }}
|
|
||||||
mb="md"
|
mb="md"
|
||||||
>
|
>
|
||||||
Visi Desa
|
Visi Desa
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: '1.125rem', md: '1.375rem' }}
|
fz={{ base: 'sm', md: 'md' }} // body text responsive
|
||||||
|
lh={1.7}
|
||||||
ta="center"
|
ta="center"
|
||||||
fw={500}
|
|
||||||
lh={1.6}
|
|
||||||
dangerouslySetInnerHTML={{ __html: data.visi }}
|
dangerouslySetInnerHTML={{ __html: data.visi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
|
{/* MISI */}
|
||||||
<Paper
|
<Paper
|
||||||
p="xl"
|
p="xl"
|
||||||
radius="lg"
|
radius="lg"
|
||||||
shadow="md"
|
shadow="md"
|
||||||
withBorder
|
withBorder
|
||||||
w="100%"
|
w="100%"
|
||||||
style={{
|
style={{ background: 'linear-gradient(145deg, #ffffff, #f5f7fa)' }}
|
||||||
background: 'linear-gradient(145deg, #ffffff, #f5f7fa)',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Text
|
<Title
|
||||||
|
order={1}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
ta="center"
|
ta="center"
|
||||||
fw={700}
|
|
||||||
fz={{ base: '2rem', md: '2.5rem' }}
|
|
||||||
mb="md"
|
mb="md"
|
||||||
>
|
>
|
||||||
Misi Desa
|
Misi Desa
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
fz={{ base: '1.125rem', md: '1.375rem' }}
|
fz={{ base: 'sm', md: 'md' }} // body text responsive
|
||||||
fw={500}
|
lh={1.7}
|
||||||
lh={1.6}
|
ta="left"
|
||||||
dangerouslySetInnerHTML={{ __html: data.misi }}
|
dangerouslySetInnerHTML={{ __html: data.misi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import PendapatanAsliDesa from '@/app/admin/(dashboard)/_state/ekonomi/PADesa';
|
import PendapatanAsliDesa from '@/app/admin/(dashboard)/_state/ekonomi/PADesa';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Grid, GridCol, Paper, SimpleGrid, Stack, Table, Text, Title } from '@mantine/core';
|
import { Box, Flex, Group, Paper, SimpleGrid, Stack, Table, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
@@ -30,196 +30,265 @@ function Page() {
|
|||||||
// Hasil akhir
|
// Hasil akhir
|
||||||
const sisaAnggaran = totalPendapatan - totalBelanja - totalPembiayaan;
|
const sisaAnggaran = totalPendapatan - totalBelanja - totalPembiayaan;
|
||||||
|
|
||||||
|
const formatCurrency = (value: number) => {
|
||||||
|
return new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="lg">
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="lg">
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Text ta="center" fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw="bold">
|
|
||||||
|
{/* Page Title */}
|
||||||
|
<Title
|
||||||
|
ta="center"
|
||||||
|
c={colors["blue-button"]}
|
||||||
|
fw="bold"
|
||||||
|
order={1}
|
||||||
|
fz={{ base: 28, md: 36 }}
|
||||||
|
>
|
||||||
Pendapatan Asli Desa
|
Pendapatan Asli Desa
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap="lg" justify="center">
|
<Stack gap="lg" justify="center">
|
||||||
<Paper bg={colors['white-1']} p="xl">
|
<Paper bg={colors['white-1']} p={{ base: 'md', md: 'xl' }}>
|
||||||
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="md">
|
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="lg">
|
||||||
{/* Pendapatan Card */}
|
{/* Pendapatan Card */}
|
||||||
<Box p="md" style={{ border: '1px solid #e9ecef', borderRadius: '8px' }}>
|
<Box
|
||||||
<Stack gap={"xs"}>
|
p="md"
|
||||||
<Title order={3}>Pendapatan</Title>
|
|
||||||
{latestApb?.pendapatan?.map((item) => (
|
|
||||||
<Box key={item.id}>
|
|
||||||
<Grid>
|
|
||||||
<GridCol span={{ base: 12, md: 6 }} style={{ maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
||||||
<Text fz="md" fw={500}>{item.name}</Text>
|
|
||||||
</GridCol>
|
|
||||||
<GridCol span={{ base: 12, md: 6 }} style={{ maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
||||||
<Text
|
|
||||||
fz="md"
|
|
||||||
fw={500}
|
|
||||||
style={{
|
style={{
|
||||||
wordBreak: 'break-word',
|
border: '1px solid #e9ecef',
|
||||||
whiteSpace: 'normal',
|
borderRadius: '8px',
|
||||||
textAlign: 'right',
|
height: '100%'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(item.value)}
|
<Stack gap="md">
|
||||||
|
<Title order={3} fz={{ base: 18, md: 20 }} c={colors['blue-button']}>
|
||||||
|
Pendapatan
|
||||||
|
</Title>
|
||||||
|
|
||||||
|
<Stack gap="sm">
|
||||||
|
{latestApb?.pendapatan?.map((item) => (
|
||||||
|
<Box key={item.id}>
|
||||||
|
<Flex gap={1}>
|
||||||
|
<Text
|
||||||
|
fz={{ base: 13, md: 14 }}
|
||||||
|
fw={500}
|
||||||
|
lh={1.4}
|
||||||
|
c="black"
|
||||||
|
style={{ wordBreak: 'break-word' }}
|
||||||
|
>
|
||||||
|
{item.name} {formatCurrency(item.value)}
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
</Flex>
|
||||||
</Grid>
|
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
<Grid>
|
</Stack>
|
||||||
<GridCol span={{ base: 12, md: 6 }} style={{ maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
||||||
<Text fz="lg" fw={600} mb="xs">Total Pendapatan</Text>
|
<Box
|
||||||
</GridCol>
|
pt="sm"
|
||||||
<GridCol span={{ base: 12, md: 6 }} style={{ maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
mt="auto"
|
||||||
<Text style={{
|
style={{
|
||||||
wordBreak: 'break-word',
|
borderTop: `2px solid ${colors['blue-button']}`
|
||||||
whiteSpace: 'normal'
|
}}
|
||||||
}} fz="xl" fw={700} c={colors['blue-button']}>
|
>
|
||||||
{new Intl.NumberFormat('id-ID', {
|
<Flex direction="column" gap={4}>
|
||||||
style: 'currency',
|
<Text fz={{ base: 14, md: 16 }} fw={600} lh={1.4}>
|
||||||
currency: 'IDR',
|
Total Pendapatan
|
||||||
minimumFractionDigits: 0
|
|
||||||
}).format(totalPendapatan)}
|
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
<Text
|
||||||
</Grid>
|
fz={{ base: 18, md: 22 }}
|
||||||
|
fw={700}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
lh={1.4}
|
||||||
|
>
|
||||||
|
{formatCurrency(totalPendapatan)}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Belanja Card */}
|
{/* Belanja Card */}
|
||||||
<Box p="md" style={{ border: '1px solid #e9ecef', borderRadius: '8px' }}>
|
<Box
|
||||||
<Stack gap={"xs"}>
|
p="md"
|
||||||
<Title order={3}>Belanja</Title>
|
|
||||||
{latestApb?.belanja?.map((item) => (
|
|
||||||
<Box key={item.id}>
|
|
||||||
<Grid>
|
|
||||||
<GridCol span={{ base: 12, md: 6 }} style={{ maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
||||||
<Text fz="md" fw={500}>{item.name}</Text>
|
|
||||||
</GridCol>
|
|
||||||
<GridCol span={{ base: 12, md: 6 }} style={{ maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
||||||
<Text
|
|
||||||
fz="md"
|
|
||||||
fw={500}
|
|
||||||
style={{
|
style={{
|
||||||
wordBreak: 'break-word',
|
border: '1px solid #e9ecef',
|
||||||
whiteSpace: 'normal',
|
borderRadius: '8px',
|
||||||
textAlign: 'right',
|
height: '100%'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{new Intl.NumberFormat('id-ID', {
|
<Stack gap="md">
|
||||||
style: 'currency',
|
<Title order={3} fz={{ base: 18, md: 20 }} c="orange">
|
||||||
currency: 'IDR',
|
Belanja
|
||||||
minimumFractionDigits: 0
|
</Title>
|
||||||
}).format(item.value)}
|
|
||||||
|
<Stack gap="sm">
|
||||||
|
{latestApb?.belanja?.map((item) => (
|
||||||
|
<Box key={item.id}>
|
||||||
|
<Group gap={1}>
|
||||||
|
<Text
|
||||||
|
fz={{ base: 13, md: 14 }}
|
||||||
|
fw={500}
|
||||||
|
lh={1.4}
|
||||||
|
c="black"
|
||||||
|
style={{ wordBreak: 'break-word' }}
|
||||||
|
>
|
||||||
|
{item.name} {formatCurrency(item.value)}
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
</Group>
|
||||||
</Grid>
|
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
<Grid>
|
</Stack>
|
||||||
<GridCol span={{ base: 12, md: 6 }}>
|
|
||||||
<Text fz="lg" fw={600} mb="xs">Total Belanja</Text>
|
<Box
|
||||||
</GridCol>
|
pt="sm"
|
||||||
<GridCol span={{ base: 12, md: 6 }}>
|
mt="auto"
|
||||||
<Text fz="xl" fw={700} c="orange">
|
style={{
|
||||||
{new Intl.NumberFormat('id-ID', {
|
borderTop: '2px solid orange'
|
||||||
style: 'currency',
|
}}
|
||||||
currency: 'IDR',
|
>
|
||||||
minimumFractionDigits: 0
|
<Flex direction="column" gap={4}>
|
||||||
}).format(totalBelanja)}
|
<Text fz={{ base: 14, md: 16 }} fw={600} lh={1.4}>
|
||||||
|
Total Belanja
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
<Text
|
||||||
</Grid>
|
fz={{ base: 18, md: 22 }}
|
||||||
|
fw={700}
|
||||||
|
c="orange"
|
||||||
|
lh={1.4}
|
||||||
|
>
|
||||||
|
{formatCurrency(totalBelanja)}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Pembiayaan Card */}
|
{/* Pembiayaan Card */}
|
||||||
<Box p="md" style={{ border: '1px solid #e9ecef', borderRadius: '8px' }}>
|
<Box
|
||||||
<Stack gap={"xs"}>
|
p="md"
|
||||||
<Title order={3}>Pembiayaan</Title>
|
|
||||||
{latestApb?.pembiayaan?.map((item) => (
|
|
||||||
<Box key={item.id}>
|
|
||||||
<Grid>
|
|
||||||
<GridCol span={{ base: 12, md: 6 }} style={{ maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
||||||
<Text fz="md" fw={500}>{item.name}</Text>
|
|
||||||
</GridCol>
|
|
||||||
<GridCol span={{ base: 12, md: 6 }} style={{ maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
||||||
<Text
|
|
||||||
fz="md"
|
|
||||||
fw={500}
|
|
||||||
style={{
|
style={{
|
||||||
wordBreak: 'break-word',
|
border: '1px solid #e9ecef',
|
||||||
whiteSpace: 'normal',
|
borderRadius: '8px',
|
||||||
textAlign: 'right',
|
height: '100%'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{new Intl.NumberFormat('id-ID', {
|
<Stack gap="md">
|
||||||
style: 'currency',
|
<Title order={3} fz={{ base: 18, md: 20 }} c="green">
|
||||||
currency: 'IDR',
|
Pembiayaan
|
||||||
minimumFractionDigits: 0
|
</Title>
|
||||||
}).format(item.value)}
|
|
||||||
|
<Stack gap="sm">
|
||||||
|
{latestApb?.pembiayaan?.map((item) => (
|
||||||
|
<Box key={item.id}>
|
||||||
|
<Group gap={1}>
|
||||||
|
<Text
|
||||||
|
fz={{ base: 13, md: 14 }}
|
||||||
|
fw={500}
|
||||||
|
lh={1.4}
|
||||||
|
c="black"
|
||||||
|
style={{ wordBreak: 'break-word' }}
|
||||||
|
>
|
||||||
|
{item.name} {formatCurrency(item.value)}
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
</Group>
|
||||||
</Grid>
|
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
<Grid>
|
</Stack>
|
||||||
<GridCol span={{ base: 12, md: 6 }}>
|
|
||||||
<Text fz="lg" fw={600} mb="xs">Total Pembiayaan</Text>
|
<Box
|
||||||
</GridCol>
|
pt="sm"
|
||||||
<GridCol span={{ base: 12, md: 6 }}>
|
mt="auto"
|
||||||
<Text fz="xl" fw={700} c="green">
|
style={{
|
||||||
{new Intl.NumberFormat('id-ID', {
|
borderTop: '2px solid green'
|
||||||
style: 'currency',
|
}}
|
||||||
currency: 'IDR',
|
>
|
||||||
minimumFractionDigits: 0
|
<Flex direction="column" gap={4}>
|
||||||
}).format(totalPembiayaan)}
|
<Text fz={{ base: 14, md: 16 }} fw={600} lh={1.4}>
|
||||||
|
Total Pembiayaan
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
<Text
|
||||||
</Grid>
|
fz={{ base: 18, md: 22 }}
|
||||||
|
fw={700}
|
||||||
|
c="green"
|
||||||
|
lh={1.4}
|
||||||
|
>
|
||||||
|
{formatCurrency(totalPembiayaan)}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* 🔽 Tambahan Ringkasan Anggaran */}
|
{/* Ringkasan Anggaran */}
|
||||||
<Paper bg={colors['white-1']} p="xl" shadow="sm" withBorder>
|
<Paper bg={colors['white-1']} p={{ base: 'md', md: 'xl' }} shadow="sm" withBorder>
|
||||||
<Title order={3} mb="md">Ringkasan Anggaran</Title>
|
<Title order={3} mb="md" fz={{ base: 18, md: 20 }}>
|
||||||
|
Ringkasan Anggaran
|
||||||
|
</Title>
|
||||||
<Table striped highlightOnHover withTableBorder>
|
<Table striped highlightOnHover withTableBorder>
|
||||||
<Table.Thead>
|
<Table.Thead>
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
<Table.Th>Keterangan</Table.Th>
|
<Table.Th>
|
||||||
<Table.Th ta={"right"}>Jumlah</Table.Th>
|
<Text fz={{ base: 13, md: 14 }} fw={600}>Keterangan</Text>
|
||||||
|
</Table.Th>
|
||||||
|
<Table.Th ta="right">
|
||||||
|
<Text fz={{ base: 13, md: 14 }} fw={600}>Jumlah</Text>
|
||||||
|
</Table.Th>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
</Table.Thead>
|
</Table.Thead>
|
||||||
<Table.Tbody>
|
<Table.Tbody>
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
<Table.Td>Total Pendapatan</Table.Td>
|
<Table.Td>
|
||||||
<Table.Td align="right">
|
<Text fz={{ base: 13, md: 14 }} lh={1.4}>Total Pendapatan</Text>
|
||||||
{new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(totalPendapatan)}
|
</Table.Td>
|
||||||
|
<Table.Td ta="right">
|
||||||
|
<Text fz={{ base: 13, md: 14 }} fw={600} lh={1.4}>
|
||||||
|
{formatCurrency(totalPendapatan)}
|
||||||
|
</Text>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
<Table.Td>Total Belanja</Table.Td>
|
<Table.Td>
|
||||||
<Table.Td align="right" c="orange">
|
<Text fz={{ base: 13, md: 14 }} lh={1.4} c="orange">Total Belanja</Text>
|
||||||
{new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(totalBelanja)}
|
</Table.Td>
|
||||||
|
<Table.Td ta="right">
|
||||||
|
<Text fz={{ base: 13, md: 14 }} fw={600} lh={1.4} c="orange">
|
||||||
|
{formatCurrency(totalBelanja)}
|
||||||
|
</Text>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
<Table.Td>Total Pembiayaan</Table.Td>
|
<Table.Td>
|
||||||
<Table.Td align="right" c="green">
|
<Text fz={{ base: 13, md: 14 }} lh={1.4} c="green">Total Pembiayaan</Text>
|
||||||
{new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(totalPembiayaan)}
|
</Table.Td>
|
||||||
|
<Table.Td ta="right">
|
||||||
|
<Text fz={{ base: 13, md: 14 }} fw={600} lh={1.4} c="green">
|
||||||
|
{formatCurrency(totalPembiayaan)}
|
||||||
|
</Text>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
<Table.Tr>
|
<Table.Tr style={{ backgroundColor: '#f8f9fa' }}>
|
||||||
<Table.Td><b>Sisa Anggaran</b></Table.Td>
|
<Table.Td>
|
||||||
<Table.Td align="right" c={sisaAnggaran >= 0 ? "blue" : "red"}>
|
<Text fz={{ base: 14, md: 15 }} fw={700} lh={1.4}>Sisa Anggaran</Text>
|
||||||
<b>
|
</Table.Td>
|
||||||
{new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0 }).format(sisaAnggaran)}
|
<Table.Td ta="right">
|
||||||
</b>
|
<Text
|
||||||
|
fz={{ base: 14, md: 15 }}
|
||||||
|
fw={700}
|
||||||
|
c={sisaAnggaran >= 0 ? colors['blue-button'] : "red"}
|
||||||
|
lh={1.4}
|
||||||
|
>
|
||||||
|
{formatCurrency(sisaAnggaran)}
|
||||||
|
</Text>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
</Table.Tbody>
|
</Table.Tbody>
|
||||||
|
|||||||
@@ -76,13 +76,13 @@ function Page() {
|
|||||||
</Box>
|
</Box>
|
||||||
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'}>
|
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'}>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
<Flex gap={{base: 7, md: 5}} align={'center'}>
|
||||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Laki-Laki</Text>
|
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Laki-Laki</Text>
|
||||||
<ColorSwatch color="#5082EE" size={30} />
|
<ColorSwatch color="#5082EE" size={30} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
<Flex gap={{base: 7, md: 5}} align={'center'}>
|
||||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Perempuan</Text>
|
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Perempuan</Text>
|
||||||
<ColorSwatch color="#6EDF9C" size={30} />
|
<ColorSwatch color="#6EDF9C" size={30} />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import pasarDesaState from '@/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pasar-desa';
|
import pasarDesaState from '@/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pasar-desa';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Flex, Grid, GridCol, Image, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
import { Box, Center, Flex, Grid, GridCol, Image, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconBrandWhatsapp, IconMapPinFilled, IconSearch, IconStarFilled } from '@tabler/icons-react';
|
import { IconBrandWhatsapp, IconMapPinFilled, IconSearch, IconStarFilled } from '@tabler/icons-react';
|
||||||
import { motion } from 'motion/react';
|
import { motion } from 'motion/react';
|
||||||
@@ -14,7 +14,7 @@ function Page() {
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const state = useProxy(pasarDesaState.pasarDesa)
|
const state = useProxy(pasarDesaState.pasarDesa)
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -28,7 +28,6 @@ function Page() {
|
|||||||
pasarDesaState.kategoriProduk.findManyAll.load()
|
pasarDesaState.kategoriProduk.findManyAll.load()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Filter data based on selected category
|
|
||||||
const filteredData = selectedCategory
|
const filteredData = selectedCategory
|
||||||
? data?.filter(item =>
|
? data?.filter(item =>
|
||||||
item.KategoriToPasar?.some(kategori => kategori.kategoriId === selectedCategory)
|
item.KategoriToPasar?.some(kategori => kategori.kategoriId === selectedCategory)
|
||||||
@@ -39,7 +38,6 @@ function Page() {
|
|||||||
load(page, 4, debouncedSearch, selectedCategory || undefined)
|
load(page, 4, debouncedSearch, selectedCategory || undefined)
|
||||||
}, [page, debouncedSearch, selectedCategory])
|
}, [page, debouncedSearch, selectedCategory])
|
||||||
|
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={10}>
|
||||||
@@ -49,44 +47,38 @@ function Page() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Grid align='center' px={{ base: 'md', md: 100 }}>
|
<Grid align="center" px={{ base: 'md', md: 100 }}>
|
||||||
<GridCol span={{ base: 12, md: 9 }}>
|
<GridCol span={{ base: 12, md: 9 }}>
|
||||||
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Title order={1} c={colors["blue-button"]} fw="bold">
|
||||||
Pasar Desa
|
Pasar Desa
|
||||||
</Text>
|
</Title>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
<GridCol span={{ base: 12, md: 3 }}>
|
<GridCol span={{ base: 12, md: 3 }}>
|
||||||
<TextInput
|
<TextInput
|
||||||
radius={"lg"}
|
radius="lg"
|
||||||
placeholder='Cari Produk'
|
placeholder="Cari Produk"
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
leftSection={<IconSearch size={20} />}
|
leftSection={<IconSearch size={20} />}
|
||||||
w={{ base: "50%", md: "100%" }}
|
w={"100%"}
|
||||||
/>
|
/>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Text px={{ base: 'md', md: 100 }} ta={"justify"} fz="md" >
|
|
||||||
Pasar Desa Online adalah media promosi untuk membantu warga memasarkan
|
<Text px={{ base: 'md', md: 100 }} pt={20} ta="justify" fz={{ base: 'sm', md: 'md' }}>
|
||||||
</Text>
|
Pasar Desa Online adalah media promosi untuk membantu warga memasarkan dan memperkenalkan produk mereka.
|
||||||
<Text px={{ base: 'md', md: 100 }} ta={"justify"} fz="md" >
|
|
||||||
dan memperkenalkan produk mereka.
|
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap={'lg'}>
|
<Stack gap="lg">
|
||||||
<SimpleGrid
|
<SimpleGrid pb={30} cols={{ base: 1, md: 2 }}>
|
||||||
pb={30}
|
|
||||||
cols={{
|
|
||||||
base: 1,
|
|
||||||
md: 2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box>
|
<Box>
|
||||||
<Select
|
<Select
|
||||||
placeholder="Pilih Kategori"
|
placeholder="Pilih Kategori"
|
||||||
@@ -103,36 +95,44 @@ function Page() {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
|
||||||
<SimpleGrid cols={{ base: 1, md: 4 }}>
|
<SimpleGrid cols={{ base: 1, md: 4 }}>
|
||||||
{filteredData?.map((v, k) => {
|
{filteredData?.map((v, k) => (
|
||||||
return (
|
|
||||||
<Stack key={k}>
|
<Stack key={k}>
|
||||||
<motion.div
|
<motion.div
|
||||||
onClick={() => router.push(`/darmasaba/ekonomi/pasar-desa/${v.id}`)}
|
onClick={() => router.push(`/darmasaba/ekonomi/pasar-desa/${v.id}`)}
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.8 }}
|
whileTap={{ scale: 0.8 }}
|
||||||
>
|
>
|
||||||
<Paper p={'lg'}>
|
<Paper p="lg">
|
||||||
<Image
|
<Image
|
||||||
radius={'lg'}
|
radius="lg"
|
||||||
src={v.image?.link || '/placeholder-product.jpg'}
|
src={v.image?.link || '/placeholder-product.jpg'}
|
||||||
alt={v.nama}
|
alt={v.nama}
|
||||||
h={200}
|
h={200}
|
||||||
w='100%'
|
w="100%"
|
||||||
style={{ objectFit: 'cover' }}
|
style={{ objectFit: 'cover' }}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
<Text py={10} fw={'bold'} fz={'lg'}>{v.nama}</Text>
|
<Text py="sm" fw="bold" fz={{ base: 'md', md: 'lg' }}>
|
||||||
<Text fz={'md'}>Rp {v.harga.toLocaleString('id-ID')}</Text>
|
{v.nama}
|
||||||
<Flex py={10} gap={'md'}>
|
</Text>
|
||||||
<IconStarFilled size={20} color='#EBCB09' />
|
<Text fz={{ base: 'sm', md: 'md' }}>
|
||||||
<Text fz={'sm'} ml={2}>{v.rating}</Text>
|
Rp {v.harga.toLocaleString('id-ID')}
|
||||||
|
</Text>
|
||||||
|
<Flex py="sm" gap="md">
|
||||||
|
<IconStarFilled size={20} color="#EBCB09" />
|
||||||
|
<Text fz={{ base: 'xs', md: 'sm' }} ml={2}>
|
||||||
|
{v.rating}
|
||||||
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex justify={'space-between'} align={'center'}>
|
<Flex justify="space-between" align="center">
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={'md'} align={'center'}>
|
<Flex gap="md" align="center">
|
||||||
<IconMapPinFilled size={20} color='red' />
|
<IconMapPinFilled size={20} color="red" />
|
||||||
<Text fz={'sm'} ml={2}>{v.alamatUsaha}</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} ml={2}>
|
||||||
|
{v.alamatUsaha}
|
||||||
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<IconBrandWhatsapp size={20} color={colors['blue-button']} />
|
<IconBrandWhatsapp size={20} color={colors['blue-button']} />
|
||||||
@@ -140,13 +140,13 @@ function Page() {
|
|||||||
</Paper>
|
</Paper>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
))}
|
||||||
})}
|
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
onChange={(newPage) => load(newPage)} // ini penting!
|
onChange={(newPage) => load(newPage)}
|
||||||
total={totalPages}
|
total={totalPages}
|
||||||
my="md"
|
my="md"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import programKemiskinanState from '@/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan';
|
import programKemiskinanState from '@/app/admin/(dashboard)/_state/ekonomi/program-kemiskinan';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Grid, GridCol, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
import { Box, Center, Grid, GridCol, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconSearch } from '@tabler/icons-react';
|
import { IconSearch } from '@tabler/icons-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -32,10 +32,9 @@ interface ProgramKemiskinanData {
|
|||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
const state = useProxy(programKemiskinanState)
|
const state = useProxy(programKemiskinanState)
|
||||||
|
|
||||||
// 🔧 Get valid statistics data with proper type checking
|
|
||||||
const statistikData = state.findMany.data
|
const statistikData = state.findMany.data
|
||||||
.filter((item): item is ProgramKemiskinanData & { statistik: StatistikData } => {
|
.filter((item): item is ProgramKemiskinanData & { statistik: StatistikData } => {
|
||||||
return !!item?.statistik &&
|
return !!item?.statistik &&
|
||||||
@@ -43,11 +42,11 @@ function Page() {
|
|||||||
item.statistik.jumlah !== undefined;
|
item.statistik.jumlah !== undefined;
|
||||||
})
|
})
|
||||||
.map(item => ({
|
.map(item => ({
|
||||||
tahun: Number(item.statistik.tahun) || 0, // Ensure tahun is a number
|
tahun: Number(item.statistik.tahun) || 0,
|
||||||
jumlah: Number(item.statistik.jumlah) || 0, // Ensure jumlah is a number
|
jumlah: Number(item.statistik.jumlah) || 0,
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => a.tahun - b.tahun)
|
.sort((a, b) => a.tahun - b.tahun)
|
||||||
.filter(item => !isNaN(item.tahun) && !isNaN(item.jumlah)); // Remove any invalid entries
|
.filter(item => !isNaN(item.tahun) && !isNaN(item.jumlah));
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -74,12 +73,18 @@ function Page() {
|
|||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: 'md', md: 100 }} >
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<Grid align='center'>
|
<Grid align='center'>
|
||||||
<GridCol span={{ base: 12, md: 9 }}>
|
<GridCol span={{ base: 12, md: 9 }}>
|
||||||
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors["blue-button"]}
|
||||||
|
fw={"bold"}
|
||||||
|
fz={{ base: '28px', md: '32px' }}
|
||||||
|
lh={{ base: '1.2', md: '1.25' }}
|
||||||
|
>
|
||||||
Program Kemiskinan
|
Program Kemiskinan
|
||||||
</Text>
|
</Title>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
<GridCol span={{ base: 12, md: 3 }}>
|
<GridCol span={{ base: 12, md: 3 }}>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -92,7 +97,15 @@ function Page() {
|
|||||||
/>
|
/>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Text fz={'h4'}>Berbagai program bantuan untuk mengurangi kemiskinan dan meningkatkan kesejahteraan masyarakat</Text>
|
<Text
|
||||||
|
fz={{ base: '14px', md: '16px' }}
|
||||||
|
lh={{ base: '1.5', md: '1.6' }}
|
||||||
|
c="black"
|
||||||
|
ta={{ base: 'left', md: 'left' }}
|
||||||
|
pt={20}
|
||||||
|
>
|
||||||
|
Berbagai program bantuan untuk mengurangi kemiskinan dan meningkatkan kesejahteraan masyarakat
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap={'lg'} justify='center'>
|
<Stack gap={'lg'} justify='center'>
|
||||||
@@ -106,8 +119,22 @@ function Page() {
|
|||||||
{state.findMany.data.map(v => {
|
{state.findMany.data.map(v => {
|
||||||
return (
|
return (
|
||||||
<Paper p={'xl'} key={v.id}>
|
<Paper p={'xl'} key={v.id}>
|
||||||
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']}>{v.nama}</Text>
|
<Title
|
||||||
<Text fz={'lg'} c={'black'} style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: v.deskripsi }}></Text>
|
order={3}
|
||||||
|
fw={'bold'}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fz={{ base: '18px', md: '20px' }}
|
||||||
|
lh={{ base: '1.3', md: '1.35' }}
|
||||||
|
>
|
||||||
|
{v.nama}
|
||||||
|
</Title>
|
||||||
|
<Text
|
||||||
|
fz={{ base: '14px', md: '16px' }}
|
||||||
|
lh={{ base: '1.5', md: '1.6' }}
|
||||||
|
c={'black'}
|
||||||
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -124,7 +151,16 @@ function Page() {
|
|||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
<Paper p={'xl'}>
|
<Paper p={'xl'}>
|
||||||
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']} mb="md">Statistik Kemiskinan Masyarakat</Text>
|
<Title
|
||||||
|
order={3}
|
||||||
|
fw={'bold'}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fz={{ base: '18px', md: '20px' }}
|
||||||
|
lh={{ base: '1.3', md: '1.35' }}
|
||||||
|
mb="md"
|
||||||
|
>
|
||||||
|
Statistik Kemiskinan Masyarakat
|
||||||
|
</Title>
|
||||||
<Box style={{ width: '100%', height: 'auto' }}>
|
<Box style={{ width: '100%', height: 'auto' }}>
|
||||||
{statistikData.length > 0 ? (
|
{statistikData.length > 0 ? (
|
||||||
<Box w="100%" style={{ overflowX: 'auto' }}>
|
<Box w="100%" style={{ overflowX: 'auto' }}>
|
||||||
@@ -162,7 +198,11 @@ function Page() {
|
|||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Box p="md" ta="center" bg="gray.0" style={{ borderRadius: '8px' }}>
|
<Box p="md" ta="center" bg="gray.0" style={{ borderRadius: '8px' }}>
|
||||||
<Text c="dimmed">
|
<Text
|
||||||
|
fz={{ base: '12px', md: '14px' }}
|
||||||
|
c="dimmed"
|
||||||
|
lh={{ base: '1.4', md: '1.5' }}
|
||||||
|
>
|
||||||
{state.findMany.loading
|
{state.findMany.loading
|
||||||
? 'Memuat data statistik...'
|
? 'Memuat data statistik...'
|
||||||
: 'Belum ada data statistik yang tersedia atau data tidak valid'}
|
: 'Belum ada data statistik yang tersedia atau data tidak valid'}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ function Page() {
|
|||||||
Ton: item.value,
|
Ton: item.value,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const chartWidth = Math.max(600, chartData.length * 150); // contoh: 150px per bar
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
@@ -78,7 +79,7 @@ function Page() {
|
|||||||
<Box style={{ width: '100%', overflowX: 'auto' }}>
|
<Box style={{ width: '100%', overflowX: 'auto' }}>
|
||||||
<Paper p="xl">
|
<Paper p="xl">
|
||||||
<Text pb={10} fw="bold" fz="h4">Statistik Sektor Unggulan Darmasaba</Text>
|
<Text pb={10} fw="bold" fz="h4">Statistik Sektor Unggulan Darmasaba</Text>
|
||||||
<Box style={{ width: '100%', minWidth: '600px' }}>
|
<Box style={{ width: '100%', overflowX: 'auto', maxWidth: `${chartWidth}px` }}>
|
||||||
<BarChart
|
<BarChart
|
||||||
p={10}
|
p={10}
|
||||||
h={300}
|
h={300}
|
||||||
@@ -90,11 +91,14 @@ function Page() {
|
|||||||
tickLine="y"
|
tickLine="y"
|
||||||
tooltipAnimationDuration={200}
|
tooltipAnimationDuration={200}
|
||||||
withTooltip
|
withTooltip
|
||||||
style={{
|
withXAxis
|
||||||
fontFamily: 'inherit',
|
withYAxis
|
||||||
}}
|
|
||||||
xAxisLabel="Sektor"
|
xAxisLabel="Sektor"
|
||||||
yAxisLabel="Ton"
|
yAxisLabel="Ton"
|
||||||
|
style={{
|
||||||
|
fontFamily: 'inherit',
|
||||||
|
fontSize: '12px', // ukuran font lebih kecil di mobile
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ import {
|
|||||||
Loader,
|
Loader,
|
||||||
Paper,
|
Paper,
|
||||||
Stack,
|
Stack,
|
||||||
|
Tabs,
|
||||||
|
TabsList,
|
||||||
|
TabsTab,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Title,
|
Title,
|
||||||
@@ -33,6 +36,8 @@ import { OrganizationChart } from 'primereact/organizationchart'
|
|||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useProxy } from 'valtio/utils'
|
import { useProxy } from 'valtio/utils'
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto'
|
import BackButton from '../../desa/layanan/_com/BackButto'
|
||||||
|
import { useMediaQuery } from '@mantine/hooks'
|
||||||
|
import { useTransitionRouter } from 'next-view-transitions'
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
@@ -51,11 +56,11 @@ export default function Page() {
|
|||||||
order={1}
|
order={1}
|
||||||
ta="center"
|
ta="center"
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
fz={{ base: 28, md: 36, lg: 44 }}
|
fz={{ base: 28, md: 36 }}
|
||||||
>
|
>
|
||||||
Struktur Organisasi & SK Pengurus BumDes
|
Struktur Organisasi & SK Pengurus BumDes
|
||||||
</Title>
|
</Title>
|
||||||
<Text ta="center" c="black" maw={800}>
|
<Text ta="center" c="black" maw={800} fz={{ base: 14, md: 16 }} lh={1.6}>
|
||||||
Gambaran visual peran dan pengurus yang ditugaskan. Gunakan kontrol
|
Gambaran visual peran dan pengurus yang ditugaskan. Gunakan kontrol
|
||||||
di bawah untuk mencari, memperbesar, atau melihat lebih jelas.
|
di bawah untuk mencari, memperbesar, atau melihat lebih jelas.
|
||||||
</Text>
|
</Text>
|
||||||
@@ -70,13 +75,14 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function StrukturOrganisasiBumDes() {
|
function StrukturOrganisasiBumDes() {
|
||||||
|
const router = useTransitionRouter()
|
||||||
const stateOrganisasi: any = useProxy(stateStrukturBumDes.pegawai)
|
const stateOrganisasi: any = useProxy(stateStrukturBumDes.pegawai)
|
||||||
const chartContainerRef = useRef<HTMLDivElement>(null)
|
const chartContainerRef = useRef<HTMLDivElement>(null)
|
||||||
const [scale, setScale] = useState(1)
|
const [scale, setScale] = useState(1)
|
||||||
const [isFullscreen, setFullscreen] = useState(false)
|
const [isFullscreen, setFullscreen] = useState(false)
|
||||||
const [searchQuery, setSearchQuery] = useState('')
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
const debouncedSearch = useRef(
|
const debouncedSearch = useRef(
|
||||||
debounce((value: string) => setSearchQuery(value), 400)
|
debounce((value: string) => setSearchQuery(value), 1000)
|
||||||
).current
|
).current
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -92,8 +98,10 @@ function StrukturOrganisasiBumDes() {
|
|||||||
<Center py={48}>
|
<Center py={48}>
|
||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<Loader size="lg" />
|
<Loader size="lg" />
|
||||||
<Text fw={600}>Memuat struktur organisasi…</Text>
|
<Text fw={600} fz={{ base: 15, md: 16 }} lh={1.4}>
|
||||||
<Text c="dimmed" size="sm">
|
Memuat struktur organisasi…
|
||||||
|
</Text>
|
||||||
|
<Text c="dimmed" fz={{ base: 12, md: 14 }} lh={1.4}>
|
||||||
Mengambil data pengurus dan posisi. Mohon tunggu sebentar.
|
Mengambil data pengurus dan posisi. Mohon tunggu sebentar.
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -119,10 +127,10 @@ function StrukturOrganisasiBumDes() {
|
|||||||
<Center>
|
<Center>
|
||||||
<IconUsers size={56} />
|
<IconUsers size={56} />
|
||||||
</Center>
|
</Center>
|
||||||
<Title order={3} mt="md">
|
<Title order={3} mt="md" ta="center">
|
||||||
Data pengurus belum tersedia
|
Data pengurus belum tersedia
|
||||||
</Title>
|
</Title>
|
||||||
<Text c="dimmed" mt="xs">
|
<Text c="dimmed" mt="xs" fz={{ base: 12, md: 14 }} lh={1.4}>
|
||||||
Belum ada data pengurus yang tercatat untuk BumDes.
|
Belum ada data pengurus yang tercatat untuk BumDes.
|
||||||
</Text>
|
</Text>
|
||||||
<Group justify="center" mt="lg">
|
<Group justify="center" mt="lg">
|
||||||
@@ -218,8 +226,26 @@ function StrukturOrganisasiBumDes() {
|
|||||||
return (
|
return (
|
||||||
<Stack align="center" mt="xl">
|
<Stack align="center" mt="xl">
|
||||||
{/* 🧭 Kontrol atas */}
|
{/* 🧭 Kontrol atas */}
|
||||||
<Paper shadow="xs" p="md" radius="md" bg={colors['blue-button']}>
|
<Paper
|
||||||
<Group gap="sm" wrap="wrap" justify="center">
|
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'], // ⬅️ penting
|
||||||
|
maxWidth: '100%', // ⬅️ penting
|
||||||
|
overflowX: 'auto' // ⬅️ untuk mencegah overflow
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack gap="sm">
|
||||||
|
<Group justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="Cari nama atau jabatan..."
|
placeholder="Cari nama atau jabatan..."
|
||||||
leftSection={<IconSearch size={16} />}
|
leftSection={<IconSearch size={16} />}
|
||||||
@@ -230,56 +256,91 @@ function StrukturOrganisasiBumDes() {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Group gap="xs">
|
</Group>
|
||||||
<Button
|
<Tabs
|
||||||
variant="light"
|
defaultValue="zoom-out"
|
||||||
bg={colors['blue-button-2']}
|
variant="outline"
|
||||||
c={colors['blue-button']}
|
radius="md"
|
||||||
size="sm"
|
styles={{
|
||||||
|
panel: { display: 'none' },
|
||||||
|
tab: {
|
||||||
|
color: colors['blue-button'],
|
||||||
|
backgroundColor: colors['blue-button-2'],
|
||||||
|
border: 'none',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
padding: '6px 12px',
|
||||||
|
minHeight: 'auto',
|
||||||
|
flexShrink: 0,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
style={{ width: '100%' }} // 👈 penting
|
||||||
|
>
|
||||||
|
<TabsList
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
overflowX: 'auto',
|
||||||
|
overflowY: 'hidden',
|
||||||
|
gap: '4px',
|
||||||
|
paddingBottom: '4px',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
WebkitOverflowScrolling: 'touch',
|
||||||
|
scrollbarWidth: 'thin',
|
||||||
|
msOverflowStyle: '-ms-autohiding-scrollbar',
|
||||||
|
maxWidth: '100%',
|
||||||
|
scrollBehavior: 'smooth', // 👈 smooth scroll
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TabsTab
|
||||||
|
value="zoom-out"
|
||||||
onClick={handleZoomOut}
|
onClick={handleZoomOut}
|
||||||
leftSection={<IconZoomOut size={16} />}
|
leftSection={<IconZoomOut size={16} />}
|
||||||
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
Zoom Out
|
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">Zoom Out</Text>
|
||||||
</Button>
|
</TabsTab>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
bg={colors['blue-button-2']}
|
bg={colors['blue-button-2']}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
px={16}
|
px={12}
|
||||||
py={8}
|
py={6}
|
||||||
style={{
|
style={{
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
borderRadius: '8px',
|
borderRadius: '6px',
|
||||||
minWidth: 70,
|
minWidth: 60,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexShrink: 0,
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Text fz={{ base: 12, sm: 13 }} lh={1} c={colors['blue-button']}>
|
||||||
{Math.round(scale * 100)}%
|
{Math.round(scale * 100)}%
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Button
|
|
||||||
variant="light"
|
<TabsTab
|
||||||
bg={colors['blue-button-2']}
|
value="zoom-in"
|
||||||
c={colors['blue-button']}
|
|
||||||
size="sm"
|
|
||||||
onClick={handleZoomIn}
|
onClick={handleZoomIn}
|
||||||
leftSection={<IconZoomIn size={16} />}
|
leftSection={<IconZoomIn size={16} />}
|
||||||
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
Zoom In
|
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">Zoom In</Text>
|
||||||
</Button>
|
</TabsTab>
|
||||||
<Button
|
|
||||||
variant="light"
|
<TabsTab
|
||||||
bg={colors['blue-button-2']}
|
value="reset"
|
||||||
c={colors['blue-button']}
|
|
||||||
size="sm"
|
|
||||||
onClick={resetZoom}
|
onClick={resetZoom}
|
||||||
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
Reset
|
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">Reset</Text>
|
||||||
</Button>
|
</TabsTab>
|
||||||
<Button
|
|
||||||
variant="light"
|
<TabsTab
|
||||||
bg={colors['blue-button-2']}
|
value="fullscreen"
|
||||||
c={colors['blue-button']}
|
|
||||||
size="sm"
|
|
||||||
onClick={toggleFullscreen}
|
onClick={toggleFullscreen}
|
||||||
leftSection={
|
leftSection={
|
||||||
isFullscreen ? (
|
isFullscreen ? (
|
||||||
@@ -288,14 +349,18 @@ function StrukturOrganisasiBumDes() {
|
|||||||
<IconArrowsMaximize size={16} />
|
<IconArrowsMaximize size={16} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
Fullscreen
|
<Text fz={{ base: 12, sm: 13 }} lh={1} ta="center">
|
||||||
</Button>
|
{isFullscreen ? 'Exit' : 'Fullscreen'}
|
||||||
</Group>
|
</Text>
|
||||||
</Group>
|
</TabsTab>
|
||||||
|
</TabsList>
|
||||||
|
</Tabs>
|
||||||
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* 📊 Chart Container */}
|
{/* 🧩 Chart Container */}
|
||||||
<Center style={{ width: '100%' }}>
|
<Center style={{ width: '100%' }}>
|
||||||
<Box
|
<Box
|
||||||
ref={chartContainerRef}
|
ref={chartContainerRef}
|
||||||
@@ -303,28 +368,36 @@ function StrukturOrganisasiBumDes() {
|
|||||||
overflowX: 'auto',
|
overflowX: 'auto',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
maxWidth: '100%',
|
||||||
padding: '32px 16px',
|
padding: '32px 16px',
|
||||||
transition: 'transform 0.2s ease',
|
transition: 'transform 0.2s ease',
|
||||||
transform: `scale(${scale})`,
|
|
||||||
transformOrigin: 'center top',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Box style={{
|
||||||
|
|
||||||
|
transform: `scale(${scale})`,
|
||||||
|
transformOrigin: 'center top',
|
||||||
|
display: 'inline-block', // 👈 agar tidak memenuhi lebar parent
|
||||||
|
minWidth: 'min-content', // 👈 penting agar chart tidak dipaksa muat di width 100%
|
||||||
|
}}>
|
||||||
<OrganizationChart
|
<OrganizationChart
|
||||||
value={chartData}
|
value={chartData}
|
||||||
nodeTemplate={(node) => <NodeCard node={node} />}
|
nodeTemplate={(node) => <NodeCard node={node} router={router} />}
|
||||||
className="p-organizationchart p-organizationchart-horizontal"
|
className="p-organizationchart p-organizationchart-horizontal"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Box>
|
||||||
</Center>
|
</Center>
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function NodeCard({ node }: any) {
|
function NodeCard({ node, router }: any) {
|
||||||
const imageSrc = node?.data?.image || '/img/default.png'
|
const imageSrc = node?.data?.image || '/img/default.png'
|
||||||
const name = node?.data?.name || 'Tanpa Nama'
|
const name = node?.data?.name || 'Tanpa Nama'
|
||||||
const title = node?.data?.title || 'Tanpa Jabatan'
|
const title = node?.data?.title || 'Tanpa Jabatan'
|
||||||
const description = node?.data?.description || ''
|
const hasId = Boolean(node?.data?.id)
|
||||||
|
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition mounted transition="pop" duration={300}>
|
<Transition mounted transition="pop" duration={300}>
|
||||||
@@ -333,40 +406,119 @@ function NodeCard({ node }: any) {
|
|||||||
shadow="md"
|
shadow="md"
|
||||||
radius="xl"
|
radius="xl"
|
||||||
withBorder
|
withBorder
|
||||||
|
|
||||||
style={{
|
style={{
|
||||||
...styles,
|
...styles,
|
||||||
width: 240,
|
width: '100%',
|
||||||
padding: 20,
|
maxWidth: isMobile ? 200 : 240, // lebih kecil di mobile
|
||||||
background:
|
minHeight: isMobile ? 240 : 280,
|
||||||
'linear-gradient(135deg, rgba(28,110,164,0.15) 0%, rgba(255,255,255,0.95) 100%)',
|
padding: isMobile ? 16 : 20,
|
||||||
|
background: 'linear-gradient(135deg, rgba(28,110,164,0.15) 0%, rgba(255,255,255,0.95) 100%)',
|
||||||
borderColor: 'rgba(28, 110, 164, 0.3)',
|
borderColor: 'rgba(28, 110, 164, 0.3)',
|
||||||
|
borderWidth: 2,
|
||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease',
|
||||||
|
cursor: hasId ? 'pointer' : 'default',
|
||||||
|
}}
|
||||||
|
onMouseEnter={(e) => {
|
||||||
|
if (hasId) {
|
||||||
|
e.currentTarget.style.transform = 'translateY(-4px)'
|
||||||
|
e.currentTarget.style.boxShadow = '0 8px 24px rgba(28, 110, 164, 0.25)'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseLeave={(e) => {
|
||||||
|
if (hasId) {
|
||||||
|
e.currentTarget.style.transform = 'translateY(0)'
|
||||||
|
e.currentTarget.style.boxShadow = ''
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack align="center" gap={10}>
|
<Stack align="center" gap={12}>
|
||||||
|
{/* Photo */}
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
width: 90,
|
width: 96,
|
||||||
height: 90,
|
height: 96,
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
border: '3px solid rgba(28, 110, 164, 0.4)',
|
border: '3px solid rgba(28, 110, 164, 0.4)',
|
||||||
|
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
|
||||||
|
background: 'white',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Image src={imageSrc} alt={name} fit="cover" loading="lazy" />
|
<Image
|
||||||
|
src={imageSrc}
|
||||||
|
alt={name}
|
||||||
|
width={96}
|
||||||
|
height={96}
|
||||||
|
fit="cover"
|
||||||
|
loading="lazy"
|
||||||
|
style={{
|
||||||
|
objectFit: 'cover',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Text fw={700} size="sm" ta="center" c={colors['blue-button']}>
|
|
||||||
|
{/* Name */}
|
||||||
|
<Text
|
||||||
|
fw={700}
|
||||||
|
ta="center"
|
||||||
|
c={colors['blue-button']}
|
||||||
|
lineClamp={2}
|
||||||
|
fz={{ base: 13, md: 15 }}
|
||||||
|
lh={1.2}
|
||||||
|
style={{
|
||||||
|
minHeight: 40,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{name}
|
{name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="xs" c="dimmed" ta="center">
|
|
||||||
|
{/* Title/Position */}
|
||||||
|
<Text
|
||||||
|
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',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{title}
|
{title}
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="xs" c="dimmed" ta="center" lineClamp={3}>
|
|
||||||
{description || 'Belum ada deskripsi.'}
|
{/* Detail Button */}
|
||||||
</Text>
|
{hasId && (
|
||||||
|
<Button
|
||||||
|
variant="gradient"
|
||||||
|
gradient={{ from: 'blue', to: 'cyan' }}
|
||||||
|
size="xs"
|
||||||
|
fullWidth
|
||||||
|
mt={8}
|
||||||
|
radius="md"
|
||||||
|
onClick={() =>
|
||||||
|
router.push(`/darmasaba/ppid/struktur-ppid/${node.data.id}`)
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
height: 32,
|
||||||
|
fontWeight: 600,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text fz={{ base: 12, md: 13 }} lh={1} ta="center">Lihat Detail</Text>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
</Transition>
|
</Transition>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,18 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import CreateEditor from '@/app/admin/(dashboard)/_com/createEditor';
|
||||||
import ajukanIdeInovatifState from '@/app/admin/(dashboard)/_state/inovasi/ajukan-ide-inovatif';
|
import ajukanIdeInovatifState from '@/app/admin/(dashboard)/_state/inovasi/ajukan-ide-inovatif';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { ActionIcon, Box, Button, Flex, List, ListItem, Modal, Paper, SimpleGrid, Stack, Text, TextInput, Title } from '@mantine/core';
|
import { ActionIcon, Box, Button, Flex, List, ListItem, Modal, Paper, SimpleGrid, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
import { IconArrowRight, IconBulbFilled } from '@tabler/icons-react';
|
import { IconBulbFilled } from '@tabler/icons-react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
import CreateEditor from '@/app/admin/(dashboard)/_com/createEditor';
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
const ideInovatif = useProxy(ajukanIdeInovatifState)
|
const ideInovatif = useProxy(ajukanIdeInovatifState);
|
||||||
|
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
// Reset state di valtio
|
|
||||||
ideInovatif.create.form = {
|
ideInovatif.create.form = {
|
||||||
name: "",
|
name: "",
|
||||||
deskripsi: "",
|
deskripsi: "",
|
||||||
@@ -23,53 +21,66 @@ function Page() {
|
|||||||
masalah: "",
|
masalah: "",
|
||||||
benefit: "",
|
benefit: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reset state lokal
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
// Submit data berita
|
|
||||||
await ideInovatif.create.create();
|
await ideInovatif.create.create();
|
||||||
|
|
||||||
// Reset form setelah submit
|
|
||||||
resetForm();
|
resetForm();
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: 'md', md: 100 }} >
|
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
Ajukan Ide Inovatif
|
<Title
|
||||||
</Text>
|
order={1}
|
||||||
<Text ta={'center'} fz={'h4'}>Desa Darmasaba percaya bahwa setiap warga memiliki potensi luar biasa untuk menciptakan perubahan positif. Platform "Ajukan Ide Inovatif" hadir sebagai ruang inklusif bagi seluruh masyarakat untuk mengembangkan dan mengusulkan gagasan transformatif.</Text>
|
ta="center"
|
||||||
</Box>
|
c={colors["blue-button"]}
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
fw="bold"
|
||||||
<Stack gap={'lg'} p={'lg'}>
|
style={{ fontSize: 'clamp(1.75rem, 4vw, 2.25rem)' }}
|
||||||
<SimpleGrid
|
|
||||||
cols={{
|
|
||||||
base: 1,
|
|
||||||
md: 2,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Paper p={'xl'} >
|
Ajukan Ide Inovatif
|
||||||
<Stack gap={"xs"}>
|
</Title>
|
||||||
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']}>Tujuan Ide Inovatif Ini</Text>
|
<Text ta="center" fz={{ base: 'sm', md: 'md' }} c="black" lh="1.6">
|
||||||
|
Desa Darmasaba percaya bahwa setiap warga memiliki potensi luar biasa untuk menciptakan perubahan positif. Platform "Ajukan Ide Inovatif" hadir sebagai ruang inklusif bagi seluruh masyarakat untuk mengembangkan dan mengusulkan gagasan transformatif.
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
|
<Stack gap="lg" p="lg">
|
||||||
|
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||||
|
<Paper p="xl">
|
||||||
|
<Stack gap="xs">
|
||||||
|
<Title order={2} c={colors['blue-button']} fw="bold">
|
||||||
|
Tujuan Ide Inovatif Ini
|
||||||
|
</Title>
|
||||||
<List>
|
<List>
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Mendorong partisipasi aktif masyarakat</ListItem>
|
<ListItem ta="justify" fz={{ base: 'sm', md: 'md' }} lh="1.5">
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Memfasilitasi inovasi berbasis lokal</ListItem>
|
Mendorong partisipasi aktif masyarakat
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Memecahkan tantangan komunal</ListItem>
|
</ListItem>
|
||||||
<ListItem ta={'justify'} fz={{ base: 'h4', md: 'lg' }}>Mengembangkan potensi kreativitas warga</ListItem>
|
<ListItem ta="justify" fz={{ base: 'sm', md: 'md' }} lh="1.5">
|
||||||
|
Memfasilitasi inovasi berbasis lokal
|
||||||
|
</ListItem>
|
||||||
|
<ListItem ta="justify" fz={{ base: 'sm', md: 'md' }} lh="1.5">
|
||||||
|
Memecahkan tantangan komunal
|
||||||
|
</ListItem>
|
||||||
|
<ListItem ta="justify" fz={{ base: 'sm', md: 'md' }} lh="1.5">
|
||||||
|
Mengembangkan potensi kreativitas warga
|
||||||
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Paper p={'xl'} >
|
|
||||||
<Flex align={'center'} justify={'space-between'}>
|
<Paper p="xl">
|
||||||
|
<Flex align="center" justify="space-between" direction={{ base: 'column', md: 'row' }} gap="md">
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz={'h4'} fw={'bold'} c={colors['blue-button']}>Apabila Anda Ingin Mengajukan Ide Inovatif Bisa Klik Pada Gambar Di Samping</Text>
|
<Title order={3} c={colors['blue-button']} fw="bold" ta={{ base: 'center', md: 'start' }}>
|
||||||
<IconArrowRight size={30} color={colors['blue-button']} />
|
Apabila Anda Ingin Mengajukan Ide Inovatif Bisa Klik Pada Gambar
|
||||||
|
</Title>
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: 5, md: 10 }} py={5}>
|
<Box px={{ base: 5, md: 10 }} py={5}>
|
||||||
<ActionIcon variant="transparent" size={150} onClick={open}>
|
<ActionIcon variant="transparent" size={150} onClick={open}>
|
||||||
@@ -88,32 +99,46 @@ function Page() {
|
|||||||
radius={0}
|
radius={0}
|
||||||
transitionProps={{ transition: 'fade', duration: 200 }}
|
transitionProps={{ transition: 'fade', duration: 200 }}
|
||||||
>
|
>
|
||||||
<Paper p={"md"} withBorder>
|
<Paper p="md" withBorder>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap="xs">
|
||||||
<Title order={3}>Ajukan Ide Inovatif</Title>
|
<Title order={3}>Ajukan Ide Inovatif</Title>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={<Text fz={"sm"} fw={"bold"}>Nama</Text>}
|
label={
|
||||||
|
<Text fz="sm" fw="bold">
|
||||||
|
Nama
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
placeholder="masukkan nama"
|
placeholder="masukkan nama"
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
ideInovatif.create.form.name = val.target.value
|
ideInovatif.create.form.name = val.target.value;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={<Text fz={"sm"} fw={"bold"}>Alamat</Text>}
|
label={
|
||||||
|
<Text fz="sm" fw="bold">
|
||||||
|
Alamat
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
placeholder="masukkan alamat"
|
placeholder="masukkan alamat"
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
ideInovatif.create.form.alamat = val.target.value
|
ideInovatif.create.form.alamat = val.target.value;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={<Text fz={"sm"} fw={"bold"}>Nama Ide</Text>}
|
label={
|
||||||
|
<Text fz="sm" fw="bold">
|
||||||
|
Nama Ide
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
placeholder="masukkan nama ide"
|
placeholder="masukkan nama ide"
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
ideInovatif.create.form.namaIde = val.target.value
|
ideInovatif.create.form.namaIde = val.target.value;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz={"sm"} fw={"bold"}>Deskripsi</Text>
|
<Text fz="sm" fw="bold">
|
||||||
|
Deskripsi
|
||||||
|
</Text>
|
||||||
<CreateEditor
|
<CreateEditor
|
||||||
value={ideInovatif.create.form.deskripsi}
|
value={ideInovatif.create.form.deskripsi}
|
||||||
onChange={(htmlContent) => {
|
onChange={(htmlContent) => {
|
||||||
@@ -122,24 +147,33 @@ function Page() {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={<Text fz={"sm"} fw={"bold"}>Masalah</Text>}
|
label={
|
||||||
|
<Text fz="sm" fw="bold">
|
||||||
|
Masalah
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
placeholder="masukkan masalah"
|
placeholder="masukkan masalah"
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
ideInovatif.create.form.masalah = val.target.value
|
ideInovatif.create.form.masalah = val.target.value;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={<Text fz={"sm"} fw={"bold"}>Benefit</Text>}
|
label={
|
||||||
|
<Text fz="sm" fw="bold">
|
||||||
|
Benefit
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
placeholder="masukkan benefit"
|
placeholder="masukkan benefit"
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
ideInovatif.create.form.benefit = val.target.value
|
ideInovatif.create.form.benefit = val.target.value;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button bg={colors['blue-button']} onClick={handleSubmit}>Simpan</Button>
|
<Button bg={colors['blue-button']} onClick={handleSubmit}>
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ function Page() {
|
|||||||
/>
|
/>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Text fz={'md'}>Menjadikan Desa Darmasaba pusat inovasi digital untuk pemberdayaan masyarakat</Text>
|
<Text pt={20} fz={'md'}>Menjadikan Desa Darmasaba pusat inovasi digital untuk pemberdayaan masyarakat</Text>
|
||||||
<Text fz={'md'}>dan peningkatan ekonomi berbasis teknologi.</Text>
|
<Text fz={'md'}>dan peningkatan ekonomi berbasis teknologi.</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
import { Box, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import infoTeknoState from '@/app/admin/(dashboard)/_state/inovasi/info-tekno';
|
import infoTeknoState from '@/app/admin/(dashboard)/_state/inovasi/info-tekno';
|
||||||
import { IconSearch } from '@tabler/icons-react';
|
import { IconSearch } from '@tabler/icons-react';
|
||||||
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const [search, setSearch] = useState("")
|
const [search, setSearch] = useState("")
|
||||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
const state = useProxy(infoTeknoState)
|
const state = useProxy(infoTeknoState)
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -34,17 +34,24 @@ function Page() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: 'md', md: 100 }} >
|
|
||||||
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<Grid align='center'>
|
<Grid align='center'>
|
||||||
<GridCol span={{ base: 12, md: 9 }}>
|
<GridCol span={{ base: 12, md: 9 }}>
|
||||||
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors["blue-button"]}
|
||||||
|
fw={"bold"}
|
||||||
|
ta={{ base: 'center', md: 'left' }}
|
||||||
|
>
|
||||||
Info Teknologi Tepat Guna
|
Info Teknologi Tepat Guna
|
||||||
</Text>
|
</Title>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
<GridCol span={{ base: 12, md: 3 }}>
|
<GridCol span={{ base: 12, md: 3 }}>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -53,13 +60,19 @@ function Page() {
|
|||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
leftSection={<IconSearch size={20} />}
|
leftSection={<IconSearch size={20} />}
|
||||||
w={{ base: "50%", md: "100%" }}
|
w={{ base: "100%", md: "100%" }}
|
||||||
/>
|
/>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Text fz={'md'}>Desa Darmasaba berkomitmen mengembangkan teknologi tepat guna yang sesuai dengan kebutuhan masyarakat,</Text>
|
|
||||||
<Text fz={'md'}>mendukung pembangunan berkelanjutan, dan meningkatkan kualitas hidup warga.</Text>
|
<Text pt={20} fz={{ base: 'sm', md: 'md' }} ta={{ base: 'center', md: 'left' }} lh={1.5}>
|
||||||
|
Desa Darmasaba berkomitmen mengembangkan teknologi tepat guna yang sesuai dengan kebutuhan masyarakat,
|
||||||
|
</Text>
|
||||||
|
<Text fz={{ base: 'sm', md: 'md' }} ta={{ base: 'center', md: 'left' }} lh={1.5}>
|
||||||
|
mendukung pembangunan berkelanjutan, dan meningkatkan kualitas hidup warga.
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap={'lg'} p={'lg'}>
|
<Stack gap={'lg'} p={'lg'}>
|
||||||
<SimpleGrid
|
<SimpleGrid
|
||||||
@@ -74,12 +87,14 @@ function Page() {
|
|||||||
<Paper p={'xl'} key={k}>
|
<Paper p={'xl'} key={k}>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Image src={v.image.link || ''} pb={10} radius={10} alt='' loading="lazy" />
|
<Image src={v.image.link || ''} pb={10} radius={10} alt='' loading="lazy" />
|
||||||
<Text fz={'h3'} fw={'bold'}>{v.name}</Text>
|
<Title order={3} fw={'bold'} ta="left">
|
||||||
|
{v.name}
|
||||||
|
</Title>
|
||||||
<Box pr={'lg'} pb={10}>
|
<Box pr={'lg'} pb={10}>
|
||||||
<Text
|
<Text
|
||||||
size="md"
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
ta="justify"
|
ta="justify"
|
||||||
lh={1} // line height biar enak dibaca
|
lh={1.5}
|
||||||
style={{
|
style={{
|
||||||
wordBreak: "break-word",
|
wordBreak: "break-word",
|
||||||
whiteSpace: "normal",
|
whiteSpace: "normal",
|
||||||
@@ -94,10 +109,11 @@ function Page() {
|
|||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
onChange={(newPage) => load(newPage)} // ini penting!
|
onChange={(newPage) => load(newPage)}
|
||||||
total={totalPages}
|
total={totalPages}
|
||||||
my="md"
|
my="md"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ function Page() {
|
|||||||
/>
|
/>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Text px={{ base: 'md', md: 100 }} ta={"justify"} fz="md" mt={4} >
|
<Text px={{ base: 'md', md: 100 }} pt={20} ta={"justify"} fz="md" mt={4} >
|
||||||
Pecalang dan Patwal (Patroli Pengawal) bertugas memastikan desa tetap aman, tertib, dan kondusif bagi seluruh warga.
|
Pecalang dan Patwal (Patroli Pengawal) bertugas memastikan desa tetap aman, tertib, dan kondusif bagi seluruh warga.
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -71,14 +71,14 @@ function Page() {
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={600} fz="lg" >Judul</Text>
|
<Text fw={600} fz="lg" >Judul</Text>
|
||||||
<Text fz="sm" c="dimmed">{data.judul || '-'}</Text>
|
<Text fz="sm" c="black">{data.judul || '-'}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={600} fz="lg" >Tanggal</Text>
|
<Text fw={600} fz="lg" >Tanggal</Text>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text fz="sm" c="black">
|
||||||
{data.tanggalWaktu
|
{data.tanggalWaktu
|
||||||
? new Date(data.tanggalWaktu).toLocaleString('id-ID', { dateStyle: 'full', timeStyle: 'short' })
|
? new Date(data.tanggalWaktu).toLocaleString('id-ID', { dateStyle: 'full', timeStyle: 'short' })
|
||||||
: '-'}
|
: '-'}
|
||||||
@@ -89,7 +89,7 @@ function Page() {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={600} fz="lg" >Lokasi</Text>
|
<Text fw={600} fz="lg" >Lokasi</Text>
|
||||||
<Text fz="sm" c="dimmed">{data.lokasi || '-'}</Text>
|
<Text fz="sm" c="black">{data.lokasi || '-'}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
@@ -120,7 +120,7 @@ function Page() {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={600} fz="lg" >Kronologi</Text>
|
<Text fw={600} fz="lg" >Kronologi</Text>
|
||||||
<Text fz="sm" c="dimmed" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: data.kronologi || '-' }} />
|
<Text fz="sm" c="black" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: data.kronologi || '-' }} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
@@ -136,11 +136,11 @@ function Page() {
|
|||||||
radius="md"
|
radius="md"
|
||||||
shadow="xs"
|
shadow="xs"
|
||||||
withBorder
|
withBorder
|
||||||
bg="dark.5"
|
bg={colors['blue-button-1']}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz="sm"
|
||||||
c="dimmed"
|
c="black"
|
||||||
dangerouslySetInnerHTML={{ __html: item.deskripsi || '-' }}
|
dangerouslySetInnerHTML={{ __html: item.deskripsi || '-' }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
import { Box, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import tipsKeamananState from '@/app/admin/(dashboard)/_state/keamanan/tips-keamanan';
|
import tipsKeamananState from '@/app/admin/(dashboard)/_state/keamanan/tips-keamanan';
|
||||||
@@ -8,11 +8,10 @@ import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { IconSearch } from '@tabler/icons-react';
|
import { IconSearch } from '@tabler/icons-react';
|
||||||
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const state = useProxy(tipsKeamananState)
|
const state = useProxy(tipsKeamananState);
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
page,
|
page,
|
||||||
@@ -22,84 +21,114 @@ function Page() {
|
|||||||
} = state.findMany;
|
} = state.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 3, debouncedSearch)
|
load(page, 3, debouncedSearch);
|
||||||
}, [page, debouncedSearch])
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Grid align='center' px={{ base: 'md', md: 100 }}>
|
<Grid align="center" px={{ base: 'md', md: 100 }}>
|
||||||
<GridCol span={{ base: 12, md: 9 }}>
|
<GridCol span={{ base: 12, md: 9 }}>
|
||||||
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
style={{ lineHeight: '1.2' }}
|
||||||
|
>
|
||||||
Tips Keamanan
|
Tips Keamanan
|
||||||
</Text>
|
</Title>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
<GridCol span={{ base: 12, md: 3 }}>
|
<GridCol span={{ base: 12, md: 3 }}>
|
||||||
<TextInput
|
<TextInput
|
||||||
radius={"lg"}
|
radius="lg"
|
||||||
placeholder='Cari Tips'
|
placeholder="Cari Tips"
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
leftSection={<IconSearch size={20} />}
|
leftSection={<IconSearch size={20} />}
|
||||||
w={{ base: "50%", md: "100%" }}
|
w={'100%'}
|
||||||
/>
|
/>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Text px={{ base: 'md', md: 100 }} ta={"justify"} fz="md" >
|
|
||||||
|
<Text
|
||||||
|
px={{ base: 'md', md: 100 }}
|
||||||
|
ta="justify"
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: '1.5', md: '1.6' }}
|
||||||
|
mt="sm"
|
||||||
|
>
|
||||||
Keamanan dan ketertiban lingkungan di Desa Darmasaba dijaga melalui peran aktif Pecalang dan Patwal (Patroli Pengawal).
|
Keamanan dan ketertiban lingkungan di Desa Darmasaba dijaga melalui peran aktif Pecalang dan Patwal (Patroli Pengawal).
|
||||||
</Text>
|
</Text>
|
||||||
<Text px={{ base: 'md', md: 100 }} ta={"justify"} fz="md" >
|
<Text
|
||||||
|
px={{ base: 'md', md: 100 }}
|
||||||
|
ta="justify"
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: '1.5', md: '1.6' }}
|
||||||
|
mt="xs"
|
||||||
|
>
|
||||||
Mereka bertugas memastikan desa tetap aman, tertib, dan kondusif bagi seluruh warga.
|
Mereka bertugas memastikan desa tetap aman, tertib, dan kondusif bagi seluruh warga.
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
|
||||||
<Stack gap={'lg'}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
|
<Stack gap="lg">
|
||||||
<SimpleGrid
|
<SimpleGrid
|
||||||
pb={10}
|
pb="10"
|
||||||
cols={{
|
cols={{ base: 1, md: 3 }}
|
||||||
base: 1,
|
>
|
||||||
md: 3,
|
{data.map((v, k) => (
|
||||||
}}>
|
<Paper radius={10} key={k} bg={colors['white-trans-1']}>
|
||||||
{data.map((v, k) => {
|
<Stack gap="xs">
|
||||||
return (
|
<Center p="10">
|
||||||
<Paper radius={10} key={k} bg={colors["white-trans-1"]}>
|
<Image
|
||||||
<Stack gap={'xs'}>
|
src={v.image?.link}
|
||||||
<Center p={10}>
|
radius={10}
|
||||||
<Image src={v.image?.link} radius={10} loading="lazy"
|
loading="lazy"
|
||||||
alt='' />
|
alt=""
|
||||||
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
<Box px={'xl'}>
|
<Box px="xl">
|
||||||
<Box pb={20}>
|
<Box pb="20">
|
||||||
<Text pb={10} c={colors["blue-button"]} fw={"bold"} fz={"h3"}>
|
<Title
|
||||||
|
order={3}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
style={{ lineHeight: '1.3' }}
|
||||||
|
>
|
||||||
{v.judul}
|
{v.judul}
|
||||||
</Text>
|
</Title>
|
||||||
<Box>
|
<Box>
|
||||||
<Text pb={10} fz={"md"} style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: v.deskripsi }} />
|
<Text
|
||||||
|
pb="10"
|
||||||
|
fz={{ base: 'xs', md: 'md' }}
|
||||||
|
lh={{ base: '1.5', md: '1.6' }}
|
||||||
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
))}
|
||||||
})}
|
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
onChange={(newPage) => load(newPage)} // ini penting!
|
onChange={(newPage) => load(newPage)}
|
||||||
total={totalPages}
|
total={totalPages}
|
||||||
my="md"
|
my="md"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import artikelKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
import artikelKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Divider, Flex, Group, Image, List, ListItem, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
import { Box, Divider, Flex, Group, Image, List, ListItem, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconAlertCircle, IconCalendar, IconInfoCircle } from '@tabler/icons-react';
|
import { IconAlertCircle, IconCalendar, IconInfoCircle } from '@tabler/icons-react';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
@@ -37,9 +37,9 @@ function Page() {
|
|||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<Paper radius="xl" shadow="md" withBorder>
|
<Paper radius="xl" shadow="md" withBorder>
|
||||||
<Box style={{ borderTopLeftRadius: 16, borderTopRightRadius: 16 }} bg={colors['blue-button']}>
|
<Box style={{ borderTopLeftRadius: 16, borderTopRightRadius: 16 }} bg={colors['blue-button']}>
|
||||||
<Text p="md" fz={{ base: 'h3', md: 'h2' }} c={colors['white-1']} fw="bold">
|
<Title order={1} p="md" c={colors['white-1']} fw="bold">
|
||||||
{state.findUnique.data.title || 'Detail Artikel Kesehatan'}
|
{state.findUnique.data.title || 'Detail Artikel Kesehatan'}
|
||||||
</Text>
|
</Title>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box p="lg">
|
<Box p="lg">
|
||||||
@@ -64,7 +64,7 @@ function Page() {
|
|||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconCalendar size={18} color={colors['blue-button']} />
|
<IconCalendar size={18} color={colors['blue-button']} />
|
||||||
<Text c="dimmed" fz="sm">
|
<Text fz={{ base: 'xs', md: 'sm' }} lh={1.5}>
|
||||||
{new Date(state.findUnique.data.createdAt).toLocaleDateString('id-ID', {
|
{new Date(state.findUnique.data.createdAt).toLocaleDateString('id-ID', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
@@ -74,48 +74,47 @@ function Page() {
|
|||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="h4" fw="bold">Pendahuluan</Text>
|
<Title order={2} fw="bold">Pendahuluan</Title>
|
||||||
<Divider my="xs" />
|
<Divider my="xs" />
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text fz="md" lh={1.6} ta="justify" dangerouslySetInnerHTML={{ __html: state.findUnique.data.introduction?.content }} />
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.6} ta="justify" dangerouslySetInnerHTML={{ __html: state.findUnique.data.introduction?.content }} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="h4" fw="bold">{state.findUnique.data.symptom?.title}</Text>
|
<Title order={2} fw="bold">{state.findUnique.data.symptom?.title}</Title>
|
||||||
<Divider my="xs" />
|
<Divider my="xs" />
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text fz="md" lh={1.6} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.symptom?.content }} />
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.6} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.symptom?.content }} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="h4" fw="bold">{state.findUnique.data.prevention?.title}</Text>
|
<Title order={2} fw="bold">{state.findUnique.data.prevention?.title}</Title>
|
||||||
<Divider my="xs" />
|
<Divider my="xs" />
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text fz="md" lh={1.6} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.prevention?.content }} />
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.6} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.prevention?.content }} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="h4" fw="bold">{state.findUnique.data.firstaid?.title}</Text>
|
<Title order={2} fw="bold">{state.findUnique.data.firstaid?.title}</Title>
|
||||||
<Divider my="xs" />
|
<Divider my="xs" />
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text fz="md" lh={1.6} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.firstaid?.content }} />
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.6} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.firstaid?.content }} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="h4" fw="bold">{state.findUnique.data.mythvsfact?.title}</Text>
|
<Title order={2} fw="bold">{state.findUnique.data.mythvsfact?.title}</Title>
|
||||||
<Divider my="xs" />
|
<Divider my="xs" />
|
||||||
<Box pb="md">
|
<Box pb="md">
|
||||||
<Table highlightOnHover withTableBorder withColumnBorders striped>
|
<Table highlightOnHover withTableBorder withColumnBorders striped>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh fz="sm" fw="bold">Mitos</TableTh>
|
<TableTh fz={{ base: 'xs', md: 'sm' }} fw="bold">Mitos</TableTh>
|
||||||
<TableTh fz="sm" fw="bold">Fakta</TableTh>
|
<TableTh fz={{ base: 'xs', md: 'sm' }} fw="bold">Fakta</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
@@ -123,12 +122,12 @@ function Page() {
|
|||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text fz="sm" lh={1.6} style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.mythvsfact.mitos }} />
|
<Text fz={{ base: 'xs', md: 'sm' }} lh={1.6} style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.mythvsfact.mitos }} />
|
||||||
</Box>
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text fz="sm" lh={1.6} style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.mythvsfact.fakta }} />
|
<Text fz={{ base: 'xs', md: 'sm' }} lh={1.6} style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.mythvsfact.fakta }} />
|
||||||
</Box>
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -143,34 +142,35 @@ function Page() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="h4" fw="bold">Kapan Harus ke Dokter?</Text>
|
<Title order={2} fw="bold">Kapan Harus ke Dokter?</Title>
|
||||||
<Divider my="xs" />
|
<Divider my="xs" />
|
||||||
<Flex justify={'flex-start'} gap={"xs"} align={"center"} mb="xs">
|
<Flex justify={'flex-start'} gap={"xs"} align={"center"} mb="xs">
|
||||||
<IconAlertCircle size={18} color="red" />
|
<IconAlertCircle size={18} color="red" />
|
||||||
<Text fz="md">Segera bawa penderita ke fasilitas kesehatan jika mengalami:</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5}>Segera bawa penderita ke fasilitas kesehatan jika mengalami:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text fz="md" lh={1.6} dangerouslySetInnerHTML={{ __html: state.findUnique.data.doctorsign.content }} /></Box>
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.6} dangerouslySetInnerHTML={{ __html: state.findUnique.data.doctorsign.content }} />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Paper p="lg" radius="md" bg={colors['blue-button-trans']} withBorder>
|
<Paper p="lg" radius="md" bg={colors['blue-button-trans']} withBorder>
|
||||||
<Group gap="xs" mb="sm">
|
<Group gap="xs" mb="sm">
|
||||||
<IconInfoCircle size={20} color={colors['white-1']} />
|
<IconInfoCircle size={20} color={colors['white-1']} />
|
||||||
<Text fz="h4" c={colors['white-1']} fw="bold">Informasi Lebih Lanjut</Text>
|
<Title order={3} c={colors['white-1']} fw="bold">Informasi Lebih Lanjut</Title>
|
||||||
</Group>
|
</Group>
|
||||||
<Stack gap={4}>
|
<Stack gap={4}>
|
||||||
<Text fz="sm" c={colors['white-1']}>Hotline DBD: <b>(0361) 123456</b></Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} c={colors['white-1']}>Hotline DBD: <b>(0361) 123456</b></Text>
|
||||||
<Text fz="sm" c={colors['white-1']}>WhatsApp Center: <b>081234567890</b></Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} c={colors['white-1']}>WhatsApp Center: <b>081234567890</b></Text>
|
||||||
<Text fz="sm" c={colors['white-1']}>Email: <b>p2p@dinkes.badungkab.go.id</b></Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} c={colors['white-1']}>Email: <b>p2p@dinkes.badungkab.go.id</b></Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="h4" fw="bold">Referensi</Text>
|
<Title order={2} fw="bold">Referensi</Title>
|
||||||
<Divider my="xs" />
|
<Divider my="xs" />
|
||||||
<List spacing="xs" size="sm" type="ordered">
|
<List spacing="xs" fz={{ base: 'xs', md: 'sm' }} type="ordered">
|
||||||
<ListItem>Kementerian Kesehatan RI. (2024). Pedoman Pencegahan dan Pengendalian DBD.</ListItem>
|
<ListItem>Kementerian Kesehatan RI. (2024). Pedoman Pencegahan dan Pengendalian DBD.</ListItem>
|
||||||
<ListItem>World Health Organization. (2024). Dengue Guidelines for Diagnosis, Treatment, Prevention and Control.</ListItem>
|
<ListItem>World Health Organization. (2024). Dengue Guidelines for Diagnosis, Treatment, Prevention and Control.</ListItem>
|
||||||
<ListItem>Dinas Kesehatan Kabupaten Badung. (2025). Laporan Surveilans DBD Triwulan I 2025.</ListItem>
|
<ListItem>Dinas Kesehatan Kabupaten Badung. (2025). Laporan Surveilans DBD Triwulan I 2025.</ListItem>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import artikelKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
import artikelKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Card, Divider, Group, Image, Loader, Paper, Stack, Text } from '@mantine/core';
|
import { Box, Button, Card, Divider, Group, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconCalendar, IconChevronRight } from '@tabler/icons-react';
|
import { IconCalendar, IconChevronRight } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -17,9 +17,8 @@ function ArtikelKesehatanPage() {
|
|||||||
|
|
||||||
if (!state.findMany.data) {
|
if (!state.findMany.data) {
|
||||||
return (
|
return (
|
||||||
<Box py="xl" ta="center">
|
<Box py="lg">
|
||||||
<Loader size="lg" color={colors['blue-button']} />
|
<Skeleton h={500} radius="lg" />
|
||||||
<Text mt="md" c="dimmed" fz="md">Memuat artikel kesehatan...</Text>
|
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -28,13 +27,13 @@ function ArtikelKesehatanPage() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Paper p="xl" bg={colors['white-trans-1']} radius="xl" shadow="md">
|
<Paper p="xl" bg={colors['white-trans-1']} radius="xl" shadow="md">
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<Text ta="center" fw={700} fz="32px" c={colors['blue-button']}>
|
<Title ta="center" order={1} c={colors['blue-button']}>
|
||||||
Artikel Kesehatan
|
Artikel Kesehatan
|
||||||
</Text>
|
</Title>
|
||||||
<Divider size="sm" color={colors['blue-button']} />
|
<Divider size="sm" color={colors['blue-button']} />
|
||||||
{state.findMany.data.length === 0 ? (
|
{state.findMany.data.length === 0 ? (
|
||||||
<Box py="xl" ta="center">
|
<Box py="xl" ta="center">
|
||||||
<Text fz="lg" c="dimmed">
|
<Text fz={{ base: 'sm', sm: 'md' }} c="dimmed">
|
||||||
Belum ada artikel kesehatan yang tersedia
|
Belum ada artikel kesehatan yang tersedia
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -51,17 +50,26 @@ function ArtikelKesehatanPage() {
|
|||||||
onMouseLeave={(e) => (e.currentTarget.style.transform = 'translateY(0)')}
|
onMouseLeave={(e) => (e.currentTarget.style.transform = 'translateY(0)')}
|
||||||
>
|
>
|
||||||
<Card.Section>
|
<Card.Section>
|
||||||
<Image style={{ borderTopLeftRadius: '10px', borderTopRightRadius: '10px' }} src={item.image?.link} alt={item.title} height={200} fit="cover" loading="lazy" />
|
<Image
|
||||||
|
style={{ borderTopLeftRadius: '10px', borderTopRightRadius: '10px' }}
|
||||||
|
src={item.image?.link}
|
||||||
|
alt={item.title}
|
||||||
|
height={200}
|
||||||
|
fit="cover"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
</Card.Section>
|
</Card.Section>
|
||||||
<Stack gap="xs" mt="md">
|
<Stack gap="xs" mt="md">
|
||||||
<Text fw="bold" fz="xl" c={colors['blue-button']}>{item.title}</Text>
|
<Title order={3} c={colors['blue-button']}>
|
||||||
|
{item.title}
|
||||||
|
</Title>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconCalendar size={16} color='gray' />
|
<IconCalendar size={16} color='gray' />
|
||||||
<Text fz="sm" c="dimmed">
|
<Text fz={{ base: 'xs', sm: 'sm' }} c="dimmed">
|
||||||
{new Date(item.createdAt).toLocaleDateString('id-ID', { year: 'numeric', month: 'long', day: 'numeric' })} • Dinas Kesehatan
|
{new Date(item.createdAt).toLocaleDateString('id-ID', { year: 'numeric', month: 'long', day: 'numeric' })} • Dinas Kesehatan
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Text fz="md" lineClamp={3}>
|
<Text fz={{ base: 'sm', sm: 'md' }} lh={{ base: 'sm', sm: 'md' }} lineClamp={3}>
|
||||||
{item.content}
|
{item.content}
|
||||||
</Text>
|
</Text>
|
||||||
<Group justify="flex-start">
|
<Group justify="flex-start">
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ interface Kontak {
|
|||||||
email: string;
|
email: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface Lokasi {
|
interface Lokasi {
|
||||||
mapsEmbed: string;
|
mapsEmbed: string;
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,7 @@ function Page() {
|
|||||||
state.findUnique.load(params?.id as string);
|
state.findUnique.load(params?.id as string);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const data = state.findUnique.data as any; // Temporary any to fix type issues
|
const data = state.findUnique.data as any;
|
||||||
|
|
||||||
const nama = data?.name || 'Fasilitas Kesehatan';
|
const nama = data?.name || 'Fasilitas Kesehatan';
|
||||||
const prosedur = data?.prosedurpendaftaran.content || '';
|
const prosedur = data?.prosedurpendaftaran.content || '';
|
||||||
@@ -111,11 +110,11 @@ function Page() {
|
|||||||
<Group gap="md" wrap="wrap">
|
<Group gap="md" wrap="wrap">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<ThemeIcon variant="light" radius="xl"><IconMapPin size={18} /></ThemeIcon>
|
<ThemeIcon variant="light" radius="xl"><IconMapPin size={18} /></ThemeIcon>
|
||||||
<Text>{alamat}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5}>{alamat}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<ThemeIcon variant="light" radius="xl"><IconDeviceLandlinePhone size={18} /></ThemeIcon>
|
<ThemeIcon variant="light" radius="xl"><IconDeviceLandlinePhone size={18} /></ThemeIcon>
|
||||||
<Text>{kontak.telepon}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5}>{kontak.telepon}</Text>
|
||||||
<CopyButton value={kontak.telepon}>
|
<CopyButton value={kontak.telepon}>
|
||||||
{({ copied, copy }) => (
|
{({ copied, copy }) => (
|
||||||
<Tooltip label={copied ? 'Disalin' : 'Salin nomor'}>
|
<Tooltip label={copied ? 'Disalin' : 'Salin nomor'}>
|
||||||
@@ -126,7 +125,7 @@ function Page() {
|
|||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<ThemeIcon variant="light" radius="xl"><IconBrandWhatsapp size={18} /></ThemeIcon>
|
<ThemeIcon variant="light" radius="xl"><IconBrandWhatsapp size={18} /></ThemeIcon>
|
||||||
<Text>{kontak.whatsapp}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5}>{kontak.whatsapp}</Text>
|
||||||
<CopyButton value={kontak.whatsapp}>
|
<CopyButton value={kontak.whatsapp}>
|
||||||
{({ copied, copy }) => (
|
{({ copied, copy }) => (
|
||||||
<Tooltip label={copied ? 'Disalin' : 'Salin WhatsApp'}>
|
<Tooltip label={copied ? 'Disalin' : 'Salin WhatsApp'}>
|
||||||
@@ -137,7 +136,7 @@ function Page() {
|
|||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<ThemeIcon variant="light" radius="xl"><IconMail size={18} /></ThemeIcon>
|
<ThemeIcon variant="light" radius="xl"><IconMail size={18} /></ThemeIcon>
|
||||||
<Text>{kontak.email}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5}>{kontak.email}</Text>
|
||||||
<CopyButton value={kontak.email}>
|
<CopyButton value={kontak.email}>
|
||||||
{({ copied, copy }) => (
|
{({ copied, copy }) => (
|
||||||
<Tooltip label={copied ? 'Disalin' : 'Salin email'}>
|
<Tooltip label={copied ? 'Disalin' : 'Salin email'}>
|
||||||
@@ -163,33 +162,43 @@ function Page() {
|
|||||||
<Divider />
|
<Divider />
|
||||||
<Group gap="xl" align="start">
|
<Group gap="xl" align="start">
|
||||||
<Stack gap={2}>
|
<Stack gap={2}>
|
||||||
<Text c="dimmed" fz="sm">Nama Fasilitas</Text>
|
<Text c="dimmed" fz={{ base: 'xs', md: 'sm' }}>Nama Fasilitas</Text>
|
||||||
<Text fw={600}>{nama}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} fw={600} lh={1.5}>{nama}</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack gap={2}>
|
<Stack gap={2}>
|
||||||
<Text c="dimmed" fz="sm">Jam Operasional</Text>
|
<Text c="dimmed" fz={{ base: 'xs', md: 'sm' }}>Jam Operasional</Text>
|
||||||
<Text fw={600}>{jam}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} fw={600} lh={1.5}>{jam}</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Group>
|
</Group>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Title order={4}>Layanan Unggulan</Title>
|
<Title order={4}>Layanan Unggulan</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
{layananUnggulan ? (
|
{layananUnggulan ? (
|
||||||
<Box pl={"lg"}>
|
<Box pl="lg">
|
||||||
<Text fz="md" style={{ lineHeight: 1.7, wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: layananUnggulan }} />
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: 1.6, md: 1.7 }}
|
||||||
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: layananUnggulan }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Paper withBorder radius="md" p="md">
|
<Paper withBorder radius="md" p="md">
|
||||||
<Group gap="sm">
|
<Group gap="sm">
|
||||||
<IconMoodEmpty />
|
<IconMoodEmpty />
|
||||||
<Text>Belum ada informasi fasilitas pendukung.</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed">Belum ada informasi layanan unggulan.</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
<Divider />
|
<Divider />
|
||||||
<Title order={4}>Peta Lokasi</Title>
|
<Title order={4}>Peta Lokasi</Title>
|
||||||
<AspectRatio ratio={16 / 9}>
|
<AspectRatio ratio={16 / 9}>
|
||||||
<iframe src={lokasi.mapsEmbed} style={{ border: 0, width: '100%', height: '100%', borderRadius: 16 }} loading="lazy" aria-label="Peta Lokasi" />
|
<iframe
|
||||||
|
src={lokasi.mapsEmbed}
|
||||||
|
style={{ border: 0, width: '100%', height: '100%', borderRadius: 16 }}
|
||||||
|
loading="lazy"
|
||||||
|
aria-label="Peta Lokasi"
|
||||||
|
/>
|
||||||
</AspectRatio>
|
</AspectRatio>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -201,9 +210,15 @@ function Page() {
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Title order={4}>Kontak Cepat</Title>
|
<Title order={4}>Kontak Cepat</Title>
|
||||||
<Group gap="sm" wrap="wrap">
|
<Group gap="sm" wrap="wrap">
|
||||||
<Button variant="light" leftSection={<IconDeviceLandlinePhone size={18} />} component="a" href={`tel:${kontak.telepon}`} aria-label="Hubungi Telepon">Telepon</Button>
|
<Button variant="light" leftSection={<IconDeviceLandlinePhone size={18} />} component="a" href={`tel:${kontak.telepon}`} aria-label="Hubungi Telepon">
|
||||||
<Button variant="light" leftSection={<IconBrandWhatsapp size={18} />} component="a" href={`https://wa.me/${kontak.whatsapp.replace(/\D/g, '')}`} target="_blank" aria-label="Hubungi WhatsApp">WhatsApp</Button>
|
<Text fz={{ base: 'xs', md: 'sm' }}>Telepon</Text>
|
||||||
<Button variant="light" leftSection={<IconMail size={18} />} component="a" href={`mailto:${kontak.email}`} aria-label="Kirim Email">Email</Button>
|
</Button>
|
||||||
|
<Button variant="light" leftSection={<IconBrandWhatsapp size={18} />} component="a" href={`https://wa.me/${kontak.whatsapp.replace(/\D/g, '')}`} target="_blank" aria-label="Hubungi WhatsApp">
|
||||||
|
<Text fz={{ base: 'xs', md: 'sm' }}>WhatsApp</Text>
|
||||||
|
</Button>
|
||||||
|
<Button variant="light" leftSection={<IconMail size={18} />} component="a" href={`mailto:${kontak.email}`} aria-label="Kirim Email">
|
||||||
|
<Text fz={{ base: 'xs', md: 'sm' }}>Email</Text>
|
||||||
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -214,9 +229,15 @@ function Page() {
|
|||||||
<Table highlightOnHover withTableBorder withColumnBorders aria-label="Tabel Dokter">
|
<Table highlightOnHover withTableBorder withColumnBorders aria-label="Tabel Dokter">
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Nama</TableTh>
|
<TableTh>
|
||||||
<TableTh>Spesialisasi</TableTh>
|
<Text fz={{ base: 'xs', md: 'sm' }} fw={600}>Nama</Text>
|
||||||
<TableTh>Jadwal</TableTh>
|
</TableTh>
|
||||||
|
<TableTh>
|
||||||
|
<Text fz={{ base: 'xs', md: 'sm' }} fw={600}>Spesialisasi</Text>
|
||||||
|
</TableTh>
|
||||||
|
<TableTh>
|
||||||
|
<Text fz={{ base: 'xs', md: 'sm' }} fw={600}>Jadwal</Text>
|
||||||
|
</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
@@ -226,11 +247,15 @@ function Page() {
|
|||||||
<TableTd>
|
<TableTd>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconUser size={16} />
|
<IconUser size={16} />
|
||||||
<Text>{dokter.name || '-'}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }}>{dokter.name || '-'}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>{dokter.specialist || '-'}</TableTd>
|
<TableTd>
|
||||||
<TableTd>{dokter.jadwal || '-'}</TableTd>
|
<Text fz={{ base: 'sm', md: 'md' }}>{dokter.specialist || '-'}</Text>
|
||||||
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Text fz={{ base: 'sm', md: 'md' }}>{dokter.jadwal || '-'}</Text>
|
||||||
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
@@ -238,7 +263,7 @@ function Page() {
|
|||||||
<TableTd colSpan={3}>
|
<TableTd colSpan={3}>
|
||||||
<Group justify="center" gap="xs" c="dimmed">
|
<Group justify="center" gap="xs" c="dimmed">
|
||||||
<IconSearch size={18} />
|
<IconSearch size={18} />
|
||||||
<Text>Tidak ada data tenaga medis.</Text>
|
<Text fz={{ base: 'sm', md: 'md' }}>Tidak ada data tenaga medis.</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -254,13 +279,18 @@ function Page() {
|
|||||||
<Divider />
|
<Divider />
|
||||||
{fasilitasPendukungHtml ? (
|
{fasilitasPendukungHtml ? (
|
||||||
<Box pl="lg">
|
<Box pl="lg">
|
||||||
<Text fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal", lineHeight: 1.7 }} dangerouslySetInnerHTML={{ __html: fasilitasPendukungHtml }} />
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: 1.6, md: 1.7 }}
|
||||||
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: fasilitasPendukungHtml }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Paper withBorder radius="md" p="md">
|
<Paper withBorder radius="md" p="md">
|
||||||
<Group gap="sm">
|
<Group gap="sm">
|
||||||
<IconMoodEmpty />
|
<IconMoodEmpty />
|
||||||
<Text>Belum ada informasi fasilitas pendukung.</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed">Belum ada informasi fasilitas pendukung.</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
@@ -274,16 +304,24 @@ function Page() {
|
|||||||
<Table highlightOnHover withTableBorder withColumnBorders aria-label="Tabel Layanan dan Tarif">
|
<Table highlightOnHover withTableBorder withColumnBorders aria-label="Tabel Layanan dan Tarif">
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Layanan</TableTh>
|
<TableTh>
|
||||||
<TableTh>Tarif</TableTh>
|
<Text fz={{ base: 'xs', md: 'sm' }} fw={600}>Layanan</Text>
|
||||||
|
</TableTh>
|
||||||
|
<TableTh>
|
||||||
|
<Text fz={{ base: 'xs', md: 'sm' }} fw={600}>Tarif</Text>
|
||||||
|
</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
{Array.isArray(data?.tarifdanlayanan) && data.tarifdanlayanan.length > 0 ? (
|
{Array.isArray(data?.tarifdanlayanan) && data.tarifdanlayanan.length > 0 ? (
|
||||||
data.tarifdanlayanan.map((item: any) => (
|
data.tarifdanlayanan.map((item: any) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>{item.layanan || '-'}</TableTd>
|
<TableTd>
|
||||||
<TableTd>{formatRupiah(item.tarif)}</TableTd>
|
<Text fz={{ base: 'sm', md: 'md' }}>{item.layanan || '-'}</Text>
|
||||||
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Text fz={{ base: 'sm', md: 'md' }}>{formatRupiah(item.tarif)}</Text>
|
||||||
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
@@ -291,7 +329,7 @@ function Page() {
|
|||||||
<TableTd colSpan={2}>
|
<TableTd colSpan={2}>
|
||||||
<Group justify="center" gap="xs" c="dimmed">
|
<Group justify="center" gap="xs" c="dimmed">
|
||||||
<IconSearch size={18} />
|
<IconSearch size={18} />
|
||||||
<Text>Tidak ada data tarif.</Text>
|
<Text fz={{ base: 'sm', md: 'md' }}>Tidak ada data tarif.</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -301,7 +339,7 @@ function Page() {
|
|||||||
{gratisBpjs && (
|
{gratisBpjs && (
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<ThemeIcon variant="light" radius="xl"><IconCheck size={18} /></ThemeIcon>
|
<ThemeIcon variant="light" radius="xl"><IconCheck size={18} /></ThemeIcon>
|
||||||
<Text fw={600}>Gratis dengan BPJS Kesehatan</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} fw={600}>Gratis dengan BPJS Kesehatan</Text>
|
||||||
</Group>
|
</Group>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -317,9 +355,16 @@ function Page() {
|
|||||||
<Title order={3}>Prosedur Pendaftaran</Title>
|
<Title order={3}>Prosedur Pendaftaran</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
{prosedur ? (
|
{prosedur ? (
|
||||||
<Box pl="lg"><Text fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal", lineHeight: 1.7 }} dangerouslySetInnerHTML={{ __html: prosedur }} /></Box>
|
<Box pl="lg">
|
||||||
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: 1.6, md: 1.7 }}
|
||||||
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: prosedur }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Text fz="md" c="dimmed">Belum ada prosedur pendaftaran</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed">Belum ada prosedur pendaftaran</Text>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
import fasilitasKesehatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Badge, Box, Button, Card, Divider, Group, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import { Badge, Box, Button, Card, Divider, Group, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconChevronRight, IconClock, IconMapPin } from '@tabler/icons-react';
|
import { IconChevronRight, IconClock, IconMapPin } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -17,12 +17,8 @@ function FasilitasKesehatanPage() {
|
|||||||
|
|
||||||
if (!state.findMany.data) {
|
if (!state.findMany.data) {
|
||||||
return (
|
return (
|
||||||
<Box py="xl" px="md">
|
<Box py="lg">
|
||||||
<Stack gap="md">
|
<Skeleton h={500} radius="lg" />
|
||||||
<Skeleton height={80} radius="lg" />
|
|
||||||
<Skeleton height={80} radius="lg" />
|
|
||||||
<Skeleton height={80} radius="lg" />
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -31,14 +27,24 @@ function FasilitasKesehatanPage() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Paper bg={colors['white-trans-1']} p="xl" radius="xl" shadow="md" h="100%">
|
<Paper bg={colors['white-trans-1']} p="xl" radius="xl" shadow="md" h="100%">
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<Text ta="center" fw={700} fz="32px" c={colors['blue-button']}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
ta="center"
|
||||||
|
fw={700}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
style={{ lineHeight: '1.2' }}
|
||||||
|
>
|
||||||
Fasilitas Kesehatan
|
Fasilitas Kesehatan
|
||||||
</Text>
|
</Title>
|
||||||
<Divider size="sm" color={colors['blue-button']} />
|
<Divider size="sm" color={colors['blue-button']} />
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
{state.findMany.data.length === 0 ? (
|
{state.findMany.data.length === 0 ? (
|
||||||
<Box py="xl" ta="center">
|
<Box py="xl" ta="center">
|
||||||
<Text fz="lg" c="dimmed">
|
<Text
|
||||||
|
fz={{ base: 'sm', sm: 'md' }}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
lh={{ base: '1.5', sm: '1.6' }}
|
||||||
|
>
|
||||||
Belum ada fasilitas kesehatan yang tersedia
|
Belum ada fasilitas kesehatan yang tersedia
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -65,22 +71,36 @@ function FasilitasKesehatanPage() {
|
|||||||
>
|
>
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Group justify="space-between" align="center">
|
<Group justify="space-between" align="center">
|
||||||
<Text fw={700} fz="lg" c={colors['blue-button']}>
|
<Title
|
||||||
|
order={3}
|
||||||
|
fw={700}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fz={{ base: 'sm', sm: 'md' }}
|
||||||
|
lh={{ base: '1.3', sm: '1.3' }}
|
||||||
|
>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Badge color="blue" radius="sm" variant="light" fz="xs">
|
<Badge color="blue" radius="sm" variant="light" size="xs">
|
||||||
Aktif
|
Aktif
|
||||||
</Badge>
|
</Badge>
|
||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconMapPin size={18} stroke={1.5} />
|
<IconMapPin size={18} stroke={1.5} />
|
||||||
<Text fz="sm">
|
<Text
|
||||||
|
fz={{ base: 'xs', sm: 'sm' }}
|
||||||
|
lh={{ base: '1.5', sm: '1.5' }}
|
||||||
|
c="text"
|
||||||
|
>
|
||||||
{item.informasiumum.alamat}
|
{item.informasiumum.alamat}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconClock size={18} stroke={1.5} />
|
<IconClock size={18} stroke={1.5} />
|
||||||
<Text fz="sm">
|
<Text
|
||||||
|
fz={{ base: 'xs', sm: 'sm' }}
|
||||||
|
lh={{ base: '1.5', sm: '1.5' }}
|
||||||
|
c="text"
|
||||||
|
>
|
||||||
{item.informasiumum.jamOperasional}
|
{item.informasiumum.jamOperasional}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import {
|
|||||||
Paper,
|
Paper,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
Stack,
|
Stack,
|
||||||
Text
|
Text,
|
||||||
|
Title
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDisclosure, 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';
|
||||||
@@ -51,55 +52,97 @@ function Page() {
|
|||||||
style={{ borderTopLeftRadius: 16, borderTopRightRadius: 16 }}
|
style={{ borderTopLeftRadius: 16, borderTopRightRadius: 16 }}
|
||||||
bg={colors['blue-button']}
|
bg={colors['blue-button']}
|
||||||
>
|
>
|
||||||
<Text p="md" fz={{ base: "h3", md: "h2" }} c={colors['white-1']} fw="bold">
|
<Title
|
||||||
|
p="md"
|
||||||
|
order={1}
|
||||||
|
c={colors['white-1']}
|
||||||
|
fw="bold"
|
||||||
|
ta={{ base: 'center', md: 'left' }}
|
||||||
|
>
|
||||||
Detail & Pendaftaran Kegiatan
|
Detail & Pendaftaran Kegiatan
|
||||||
</Text>
|
</Title>
|
||||||
</Box>
|
</Box>
|
||||||
<Box p="lg">
|
<Box p="lg">
|
||||||
<Stack gap="xl">
|
<Stack gap="xl">
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Informasi Kegiatan</Text>
|
<Title order={2} fw="bold">Informasi Kegiatan</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text fz="md" fw="bold">Nama Kegiatan: <Text span>{state.findUnique.data.informasijadwalkegiatan.name}</Text></Text>
|
<Text fw="bold">
|
||||||
<Text fz="md" fw="bold">Tanggal: <Text span>{state.findUnique.data.informasijadwalkegiatan.tanggal}</Text></Text>
|
Nama Kegiatan:
|
||||||
<Text fz="md" fw="bold">Waktu: <Text span>{state.findUnique.data.informasijadwalkegiatan.waktu}</Text></Text>
|
<Text span fw="normal">
|
||||||
<Text fz="md" fw="bold">Lokasi: <Text span>{state.findUnique.data.informasijadwalkegiatan.lokasi}</Text></Text>
|
{state.findUnique.data.informasijadwalkegiatan.name}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
<Text fw="bold">
|
||||||
|
Tanggal:
|
||||||
|
<Text span fw="normal">
|
||||||
|
{state.findUnique.data.informasijadwalkegiatan.tanggal}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
<Text fw="bold">
|
||||||
|
Waktu:
|
||||||
|
<Text span fw="normal">
|
||||||
|
{state.findUnique.data.informasijadwalkegiatan.waktu}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
<Text fw="bold">
|
||||||
|
Lokasi:
|
||||||
|
<Text span fw="normal">
|
||||||
|
{state.findUnique.data.informasijadwalkegiatan.lokasi}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Deskripsi Kegiatan</Text>
|
<Title order={2} fw="bold">Deskripsi Kegiatan</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text ta="justify" fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.deskripsijadwalkegiatan.deskripsi }} />
|
<Text
|
||||||
|
ta="justify"
|
||||||
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: state.findUnique.data.deskripsijadwalkegiatan.deskripsi }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Layanan yang Tersedia</Text>
|
<Title order={2} fw="bold">Layanan yang Tersedia</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text ta="justify" fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.layananjadwalkegiatan.content }} />
|
<Text
|
||||||
|
ta="justify"
|
||||||
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: state.findUnique.data.layananjadwalkegiatan.content }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Syarat & Ketentuan</Text>
|
<Title order={2} fw="bold">Syarat & Ketentuan</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text ta="justify" fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.syaratketentuanjadwalkegiatan.content }} />
|
<Text
|
||||||
|
ta="justify"
|
||||||
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: state.findUnique.data.syaratketentuanjadwalkegiatan.content }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Dokumen yang Perlu Dibawa</Text>
|
<Title order={2} fw="bold">Dokumen yang Perlu Dibawa</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text ta="justify" fz="md" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: state.findUnique.data.dokumenjadwalkegiatan.content }} />
|
<Text
|
||||||
|
ta="justify"
|
||||||
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: state.findUnique.data.dokumenjadwalkegiatan.content }}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Pendaftaran Kegiatan</Text>
|
<Title order={2} fw="bold">Pendaftaran Kegiatan</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Group>
|
<Group>
|
||||||
<Button onClick={open}>Buat Pendaftaran</Button>
|
<Button onClick={open}>Buat Pendaftaran</Button>
|
||||||
@@ -112,18 +155,21 @@ function Page() {
|
|||||||
|
|
||||||
<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">
|
||||||
<Text fz="lg" c={colors['white-1']} fw="bold">Informasi Kontak</Text>
|
<Title order={3} c={colors['white-1']} fw="bold">Informasi Kontak</Title>
|
||||||
<Group gap="xs">
|
<Group gap="xs" justify="flex-start">
|
||||||
<IconUser size={18} color="white" />
|
<IconUser size={18} color="white" />
|
||||||
<Text fz="md" c={colors['white-1']}>Penanggung Jawab: <Text span fw="bold">Bidan Komang Ayu</Text></Text>
|
<Text c={colors['white-1']}>
|
||||||
|
Penanggung Jawab:
|
||||||
|
<Text span fw="bold">Bidan Komang Ayu</Text>
|
||||||
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconPhone size={18} color="white" />
|
<IconPhone size={18} color="white" />
|
||||||
<Text fz="md" c={colors['white-1']}>081234567890</Text>
|
<Text c={colors['white-1']}>081234567890</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconMail size={18} color="white" />
|
<IconMail size={18} color="white" />
|
||||||
<Text fz="md" c={colors['white-1']}>puskesmasabiansemal3@gmail.com</Text>
|
<Text c={colors['white-1']}>puskesmasabiansemal3@gmail.com</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -2,15 +2,14 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import pendaftaranJadwalKegiatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/pendafataranJadwalKegiatan';
|
import pendaftaranJadwalKegiatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/pendafataranJadwalKegiatan';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Button, Divider, Stack, Text, Textarea, TextInput } from '@mantine/core';
|
import { Button, Divider, Stack, Text, Textarea, TextInput, Title } from '@mantine/core';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
function CreatePendaftaran() {
|
function CreatePendaftaran() {
|
||||||
const stateCreate = useProxy(pendaftaranJadwalKegiatanState);
|
const stateCreate = useProxy(pendaftaranJadwalKegiatanState);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
useEffect(() => {
|
|
||||||
stateCreate.findMany.load();
|
stateCreate.findMany.load();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -32,7 +31,7 @@ useEffect(() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text fz="lg" fw="bold">Formulir Pendaftaran</Text>
|
<Title order={2} ta="left">Formulir Pendaftaran</Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -41,6 +40,10 @@ useEffect(() => {
|
|||||||
size="md"
|
size="md"
|
||||||
value={stateCreate.create.form.name}
|
value={stateCreate.create.form.name}
|
||||||
onChange={(e) => stateCreate.create.form.name = e.target.value}
|
onChange={(e) => stateCreate.create.form.name = e.target.value}
|
||||||
|
styles={{
|
||||||
|
label: { fontSize: '14px', lineHeight: 1.4, fontWeight: 500 },
|
||||||
|
input: { fontSize: '16px', lineHeight: 1.5 },
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
type='date'
|
type='date'
|
||||||
@@ -50,6 +53,10 @@ useEffect(() => {
|
|||||||
w={{ base: '100%', md: '85%', lg: '75%', xl: '50%' }}
|
w={{ base: '100%', md: '85%', lg: '75%', xl: '50%' }}
|
||||||
value={stateCreate.create.form.tanggal}
|
value={stateCreate.create.form.tanggal}
|
||||||
onChange={(e) => stateCreate.create.form.tanggal = e.target.value}
|
onChange={(e) => stateCreate.create.form.tanggal = e.target.value}
|
||||||
|
styles={{
|
||||||
|
label: { fontSize: '14px', lineHeight: 1.4, fontWeight: 500 },
|
||||||
|
input: { fontSize: '16px', lineHeight: 1.5 },
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Nama Orang Tua / Wali"
|
label="Nama Orang Tua / Wali"
|
||||||
@@ -57,6 +64,10 @@ useEffect(() => {
|
|||||||
size="md"
|
size="md"
|
||||||
value={stateCreate.create.form.namaOrangtua}
|
value={stateCreate.create.form.namaOrangtua}
|
||||||
onChange={(e) => stateCreate.create.form.namaOrangtua = e.target.value}
|
onChange={(e) => stateCreate.create.form.namaOrangtua = e.target.value}
|
||||||
|
styles={{
|
||||||
|
label: { fontSize: '14px', lineHeight: 1.4, fontWeight: 500 },
|
||||||
|
input: { fontSize: '16px', lineHeight: 1.5 },
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Nomor Telepon"
|
label="Nomor Telepon"
|
||||||
@@ -64,6 +75,10 @@ useEffect(() => {
|
|||||||
size="md"
|
size="md"
|
||||||
value={stateCreate.create.form.nomor}
|
value={stateCreate.create.form.nomor}
|
||||||
onChange={(e) => stateCreate.create.form.nomor = e.target.value}
|
onChange={(e) => stateCreate.create.form.nomor = e.target.value}
|
||||||
|
styles={{
|
||||||
|
label: { fontSize: '14px', lineHeight: 1.4, fontWeight: 500 },
|
||||||
|
input: { fontSize: '16px', lineHeight: 1.5 },
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Alamat"
|
label="Alamat"
|
||||||
@@ -71,6 +86,10 @@ useEffect(() => {
|
|||||||
size="md"
|
size="md"
|
||||||
value={stateCreate.create.form.alamat}
|
value={stateCreate.create.form.alamat}
|
||||||
onChange={(e) => stateCreate.create.form.alamat = e.target.value}
|
onChange={(e) => stateCreate.create.form.alamat = e.target.value}
|
||||||
|
styles={{
|
||||||
|
label: { fontSize: '14px', lineHeight: 1.4, fontWeight: 500 },
|
||||||
|
input: { fontSize: '16px', lineHeight: 1.5 },
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Textarea
|
<Textarea
|
||||||
label="Catatan Khusus (Opsional)"
|
label="Catatan Khusus (Opsional)"
|
||||||
@@ -78,9 +97,15 @@ useEffect(() => {
|
|||||||
size="md"
|
size="md"
|
||||||
value={stateCreate.create.form.catatan}
|
value={stateCreate.create.form.catatan}
|
||||||
onChange={(e) => stateCreate.create.form.catatan = e.target.value}
|
onChange={(e) => stateCreate.create.form.catatan = e.target.value}
|
||||||
|
styles={{
|
||||||
|
label: { fontSize: '14px', lineHeight: 1.4, fontWeight: 500 },
|
||||||
|
input: { fontSize: '16px', lineHeight: 1.5 },
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Button size="md" radius="lg" bg={colors['blue-button']} onClick={handleSubmit}>
|
<Button size="md" radius="lg" bg={colors['blue-button']} onClick={handleSubmit}>
|
||||||
|
<Text fz={{ base: 'sm', md: 'md' }} fw={600} c="white">
|
||||||
Daftar Sekarang
|
Daftar Sekarang
|
||||||
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import jadwalkegiatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
import jadwalkegiatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Card, Divider, Group, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Button, Card, Divider, Group, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconChevronRight, IconClockHour4, IconMapPin } from '@tabler/icons-react';
|
import { IconChevronRight, IconClockHour4, IconMapPin } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
@@ -27,13 +27,13 @@ function JadwalKegiatanPage() {
|
|||||||
<Box>
|
<Box>
|
||||||
<Paper bg={colors['white-trans-1']} p="xl" radius="xl" shadow="md" h="auto" mih="100vh">
|
<Paper bg={colors['white-trans-1']} p="xl" radius="xl" shadow="md" h="auto" mih="100vh">
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<Text ta="center" fw={700} fz="32px" c={colors['blue-button']}>
|
<Title ta="center" order={1} c={colors['blue-button']} fw={700}>
|
||||||
Jadwal Kegiatan Warga
|
Jadwal Kegiatan Warga
|
||||||
</Text>
|
</Title>
|
||||||
<Divider size="sm" color={colors['blue-button']} />
|
<Divider size="sm" color={colors['blue-button']} />
|
||||||
{state.findMany.data.length === 0 ? (
|
{state.findMany.data.length === 0 ? (
|
||||||
<Box py="xl" ta="center">
|
<Box py="xl" ta="center">
|
||||||
<Text fz="lg" c="dimmed">
|
<Text fz={{ base: 'sm', sm: 'md' }} c="dimmed">
|
||||||
Belum ada jadwal kegiatan yang tersedia
|
Belum ada jadwal kegiatan yang tersedia
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -48,11 +48,11 @@ function JadwalKegiatanPage() {
|
|||||||
style={{ backdropFilter: 'blur(8px)' }}
|
style={{ backdropFilter: 'blur(8px)' }}
|
||||||
>
|
>
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Group justify="space-between">
|
<Group justify="space-between" wrap="nowrap">
|
||||||
<Text fw={700} fz="xl" c={colors['blue-button']}>
|
<Title order={2} c={colors['blue-button']} fw={700} fz={{ base: 'md', sm: 'xl' }}>
|
||||||
{item.informasijadwalkegiatan.name}
|
{item.informasijadwalkegiatan.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Text fw={600} fz="sm" c={colors['blue-button']}>
|
<Text fw={600} fz={{ base: 'xs', sm: 'sm' }} c={colors['blue-button']} lh="1.4">
|
||||||
{new Date(item.informasijadwalkegiatan.tanggal).toLocaleDateString('id-ID', {
|
{new Date(item.informasijadwalkegiatan.tanggal).toLocaleDateString('id-ID', {
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
@@ -63,12 +63,16 @@ function JadwalKegiatanPage() {
|
|||||||
|
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconClockHour4 size={18} />
|
<IconClockHour4 size={18} />
|
||||||
<Text fz="sm">{item.informasijadwalkegiatan.waktu}</Text>
|
<Text fz={{ base: 'xs', sm: 'sm' }} lh="1.5">
|
||||||
|
{item.informasijadwalkegiatan.waktu}
|
||||||
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconMapPin size={18} />
|
<IconMapPin size={18} />
|
||||||
<Text fz="sm">{item.informasijadwalkegiatan.lokasi}</Text>
|
<Text fz={{ base: 'xs', sm: 'sm' }} lh="1.5">
|
||||||
|
{item.informasijadwalkegiatan.lokasi}
|
||||||
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Divider my="sm" />
|
<Divider my="sm" />
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import { Box, Center, ColorSwatch, Flex, Paper, SimpleGrid, Skeleton, Stack, Tex
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
// import { useRouter } from 'next/navigation';
|
|
||||||
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
||||||
|
|
||||||
import persentasekelahiran from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran';
|
import persentasekelahiran from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
|
||||||
@@ -17,7 +15,6 @@ import GrafikPenyakit from './grafik-penyakit/page';
|
|||||||
import JadwalKegiatan from './jadwal-kegiatan-page/page';
|
import JadwalKegiatan from './jadwal-kegiatan-page/page';
|
||||||
import ArtikelKesehatanPage from './artikel-kesehatan-page/page';
|
import ArtikelKesehatanPage from './artikel-kesehatan-page/page';
|
||||||
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
type DataTahunan = {
|
type DataTahunan = {
|
||||||
tahun: string;
|
tahun: string;
|
||||||
@@ -31,7 +28,6 @@ function Page() {
|
|||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Count occurrences per year
|
|
||||||
const countByYear = (data: any[], dateField: string) => {
|
const countByYear = (data: any[], dateField: string) => {
|
||||||
const counts: Record<string, number> = {};
|
const counts: Record<string, number> = {};
|
||||||
data?.forEach(item => {
|
data?.forEach(item => {
|
||||||
@@ -43,28 +39,23 @@ function Page() {
|
|||||||
|
|
||||||
const statePersentase = useProxy(persentasekelahiran);
|
const statePersentase = useProxy(persentasekelahiran);
|
||||||
const [chartData, setChartData] = useState<DataTahunan[]>([]);
|
const [chartData, setChartData] = useState<DataTahunan[]>([]);
|
||||||
const isTablet = useMediaQuery('(max-width: 1024px)');
|
|
||||||
const isMobile = useMediaQuery('(max-width: 768px)');
|
const isMobile = useMediaQuery('(max-width: 768px)');
|
||||||
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
statePersentase.kelahiran.findMany.load(1, 1000); // Load all kelahiran data
|
statePersentase.kelahiran.findMany.load(1, 1000);
|
||||||
statePersentase.kematian.findMany.load(1, 1000); // Load all kematian data
|
statePersentase.kematian.findMany.load(1, 1000);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (statePersentase.kelahiran.findMany.data && statePersentase.kematian.findMany.data) {
|
if (statePersentase.kelahiran.findMany.data && statePersentase.kematian.findMany.data) {
|
||||||
// Count kelahiran and kematian by year
|
|
||||||
const kelahiranByYear = countByYear(statePersentase.kelahiran.findMany.data, 'tanggal');
|
const kelahiranByYear = countByYear(statePersentase.kelahiran.findMany.data, 'tanggal');
|
||||||
const kematianByYear = countByYear(statePersentase.kematian.findMany.data, 'tanggal');
|
const kematianByYear = countByYear(statePersentase.kematian.findMany.data, 'tanggal');
|
||||||
|
|
||||||
// Get all unique years
|
|
||||||
const allYears = new Set([
|
const allYears = new Set([
|
||||||
...Object.keys(kelahiranByYear),
|
...Object.keys(kelahiranByYear),
|
||||||
...Object.keys(kematianByYear)
|
...Object.keys(kematianByYear)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create data structure for the chart
|
|
||||||
const dataByYear = Array.from(allYears).reduce<Record<string, DataTahunan>>((acc, year) => {
|
const dataByYear = Array.from(allYears).reduce<Record<string, DataTahunan>>((acc, year) => {
|
||||||
acc[year] = {
|
acc[year] = {
|
||||||
tahun: year,
|
tahun: year,
|
||||||
@@ -93,32 +84,44 @@ function Page() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
|
||||||
|
{/* Page Title */}
|
||||||
|
<Title
|
||||||
|
order={1}
|
||||||
|
ta="center"
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fw="bold"
|
||||||
|
lh={1.2}
|
||||||
|
>
|
||||||
Data Kesehatan Masyarakat Puskesmas Darmasaba
|
Data Kesehatan Masyarakat Puskesmas Darmasaba
|
||||||
</Text>
|
</Title>
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
|
||||||
<Stack gap={'lg'}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
|
<Stack gap="lg">
|
||||||
{/* Bar Chart Kematian Kelahiran */}
|
{/* Bar Chart Kematian Kelahiran */}
|
||||||
<Box>
|
<Box>
|
||||||
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
<Paper p="xl" bg={colors['white-trans-1']}>
|
||||||
<Box pb={30}>
|
<Box pb={30}>
|
||||||
<Title order={2} mb="md">Data Kematian dan Kelahiran</Title>
|
<Title order={2} mb="md" ta="center">
|
||||||
|
Data Kematian dan Kelahiran
|
||||||
|
</Title>
|
||||||
|
|
||||||
{chartData.length === 0 ? (
|
{chartData.length === 0 ? (
|
||||||
<Text c="dimmed" ta="center" py="xl">
|
<Text c="dimmed" ta="center" py="xl" size="md">
|
||||||
Belum ada data yang tersedia untuk ditampilkan
|
Belum ada data yang tersedia untuk ditampilkan
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{/* Main Chart */}
|
|
||||||
<Center>
|
<Center>
|
||||||
<Box h={400}>
|
<Box h={400}>
|
||||||
<Box style={{
|
<Box style={{
|
||||||
width: isMobile ? '90vw' : isTablet ? '700px' : '800px',
|
width: isMobile ? '90vw' : '800px',
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
margin: '0 auto'
|
margin: '0 auto'
|
||||||
}}>
|
}}>
|
||||||
@@ -137,16 +140,21 @@ function Page() {
|
|||||||
</Center>
|
</Center>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'}>
|
|
||||||
|
<Flex pb={30} justify="center" gap="xl" align="center" wrap="wrap">
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
<Flex gap={{ base: 'xs', md: 'sm' }} align="center">
|
||||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Angka Kematian</Text>
|
<Text fw="bold" fz={{ base: 'sm', md: 'md' }}>
|
||||||
|
Angka Kematian
|
||||||
|
</Text>
|
||||||
<ColorSwatch color="#EF3E3E" size={30} />
|
<ColorSwatch color="#EF3E3E" size={30} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
<Flex gap={{ base: 'xs', md: 'sm' }} align="center">
|
||||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Angka Kelahiran</Text>
|
<Text fw="bold" fz={{ base: 'sm', md: 'md' }}>
|
||||||
|
Angka Kelahiran
|
||||||
|
</Text>
|
||||||
<ColorSwatch color="#3290CA" size={30} />
|
<ColorSwatch color="#3290CA" size={30} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -154,20 +162,13 @@ function Page() {
|
|||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<GrafikPenyakit />
|
<GrafikPenyakit />
|
||||||
{/* Artikel Kesehatan */}
|
|
||||||
<Box>
|
<Box>
|
||||||
<SimpleGrid
|
<SimpleGrid cols={{ base: 1, md: 3 }}>
|
||||||
cols={{
|
|
||||||
base: 1,
|
|
||||||
md: 3,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Fasilitas Kesehatan */}
|
|
||||||
<FasilitasKesehatan />
|
<FasilitasKesehatan />
|
||||||
{/* Jadwal Kegiatan */}
|
|
||||||
<JadwalKegiatan />
|
<JadwalKegiatan />
|
||||||
{/* Artikel Kesehatan */}
|
|
||||||
<ArtikelKesehatanPage />
|
<ArtikelKesehatanPage />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import infoWabahPenyakit from '@/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit';
|
import infoWabahPenyakit from '@/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Image, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Button, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconArrowBack } from '@tabler/icons-react';
|
import { IconArrowBack } from '@tabler/icons-react';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
@@ -51,10 +51,15 @@ function DetailInfoWabahPenyakitUser() {
|
|||||||
shadow="sm"
|
shadow="sm"
|
||||||
>
|
>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
{/* Judul */}
|
{/* Judul — H1 */}
|
||||||
<Text fz="xl" fw="bold" c={colors['blue-button']} ta="center">
|
<Title
|
||||||
|
order={1}
|
||||||
|
fw="bold"
|
||||||
|
c={colors['blue-button']}
|
||||||
|
ta="center"
|
||||||
|
>
|
||||||
{data.name || 'Kontak Darurat'}
|
{data.name || 'Kontak Darurat'}
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
{/* Gambar */}
|
{/* Gambar */}
|
||||||
{data.image?.link && (
|
{data.image?.link && (
|
||||||
@@ -69,16 +74,22 @@ function DetailInfoWabahPenyakitUser() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Deskripsi */}
|
{/* Deskripsi */}
|
||||||
<Box>
|
<Stack gap={"xs"}>
|
||||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
{/* Section Title — H2 */}
|
||||||
|
<Title order={3} fw="bold" ta="left">
|
||||||
|
Deskripsi
|
||||||
|
</Title>
|
||||||
<Box pl={20}>
|
<Box pl={20}>
|
||||||
<Text
|
<Text
|
||||||
fz="md"
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: '1.5', md: '1.6' }}
|
||||||
|
c="dark"
|
||||||
|
ta="justify"
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsiLengkap || '-' }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsiLengkap || '-' }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import {
|
|||||||
Skeleton,
|
Skeleton,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput
|
TextInput,
|
||||||
|
Title
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconInfoCircle, IconSearch } from '@tabler/icons-react';
|
import { IconInfoCircle, IconSearch } from '@tabler/icons-react';
|
||||||
@@ -30,7 +31,7 @@ function Page() {
|
|||||||
const state = useProxy(infoWabahPenyakit);
|
const state = useProxy(infoWabahPenyakit);
|
||||||
const router = useTransitionRouter();
|
const router = useTransitionRouter();
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(search, 1000)
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
const { data, page, totalPages, loading, load } = state.findMany;
|
const { data, page, totalPages, loading, load } = state.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
@@ -53,15 +54,19 @@ function Page() {
|
|||||||
|
|
||||||
<Grid align="center" px={{ base: 'md', md: 100 }}>
|
<Grid align="center" px={{ base: 'md', md: 100 }}>
|
||||||
<GridCol span={{ base: 12, md: 8 }}>
|
<GridCol span={{ base: 12, md: 8 }}>
|
||||||
<Text
|
<Title
|
||||||
fz={{ base: '1.8rem', md: '2.8rem' }}
|
order={1}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
fw="bold"
|
fw="bold"
|
||||||
lh={1.2}
|
lh={{ base: 1.2, md: 1.2 }}
|
||||||
>
|
>
|
||||||
Informasi Wabah & Penyakit
|
Informasi Wabah & Penyakit
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="md" mt={4}>
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: 1.5, md: 1.5 }}
|
||||||
|
mt={4}
|
||||||
|
>
|
||||||
Dapatkan informasi terbaru mengenai wabah dan penyakit yang sedang
|
Dapatkan informasi terbaru mengenai wabah dan penyakit yang sedang
|
||||||
diawasi.
|
diawasi.
|
||||||
</Text>
|
</Text>
|
||||||
@@ -84,9 +89,9 @@ function Page() {
|
|||||||
<Center py="6xl">
|
<Center py="6xl">
|
||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<IconInfoCircle size={50} color={colors['blue-button']} />
|
<IconInfoCircle size={50} color={colors['blue-button']} />
|
||||||
<Text fz="lg" fw={500} >
|
<Title order={2} fz={{ base: 'md', md: 'lg' }} fw={500}>
|
||||||
Tidak ada data yang cocok dengan pencarian Anda.
|
Tidak ada data yang cocok dengan pencarian Anda.
|
||||||
</Text>
|
</Title>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
) : (
|
) : (
|
||||||
@@ -131,15 +136,24 @@ function Page() {
|
|||||||
|
|
||||||
{/* Judul dan badge */}
|
{/* Judul dan badge */}
|
||||||
<Group justify="space-between" mt="sm">
|
<Group justify="space-between" mt="sm">
|
||||||
<Text fw={700} fz="lg" c={colors['blue-button']}>
|
<Title
|
||||||
|
order={3}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fw={700}
|
||||||
|
fz={{ base: 'sm', md: 'lg' }}
|
||||||
|
>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Badge color="blue" variant="light" radius="sm">
|
<Badge color="blue" variant="light" radius="sm">
|
||||||
Wabah
|
Wabah
|
||||||
</Badge>
|
</Badge>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Text fz="sm" c="dimmed">
|
<Text
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
c="dimmed"
|
||||||
|
lh={{ base: 1.4, md: 1.4 }}
|
||||||
|
>
|
||||||
Diposting:{' '}
|
Diposting:{' '}
|
||||||
{new Date(v.createdAt).toLocaleDateString('id-ID', {
|
{new Date(v.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
@@ -153,8 +167,8 @@ function Page() {
|
|||||||
{/* Bagian deskripsi dan tombol */}
|
{/* Bagian deskripsi dan tombol */}
|
||||||
<Box style={{ display: 'flex', flexDirection: 'column', flexGrow: 1 }}>
|
<Box style={{ display: 'flex', flexDirection: 'column', flexGrow: 1 }}>
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
lh={1.5}
|
lh={{ base: 1.5, md: 1.5 }}
|
||||||
lineClamp={3}
|
lineClamp={3}
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsiSingkat }}
|
dangerouslySetInnerHTML={{ __html: v.deskripsiSingkat }}
|
||||||
style={{ flexGrow: 1 }}
|
style={{ flexGrow: 1 }}
|
||||||
@@ -174,14 +188,11 @@ function Page() {
|
|||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
@@ -192,7 +203,6 @@ function Page() {
|
|||||||
mt="lg"
|
mt="lg"
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import kontakDarurat from '@/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat';
|
import kontakDarurat from '@/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Group, Image, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Button, Group, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconArrowBack, IconBrandWhatsapp } from '@tabler/icons-react';
|
import { IconArrowBack, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
@@ -27,15 +27,16 @@ function Page() {
|
|||||||
const data = state.findUnique.data;
|
const data = state.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{base: 'md', md: 100}} py={10}>
|
<Box px={{ base: 'md', md: 100 }} py={10}>
|
||||||
{/* Tombol Back */}
|
{/* Tombol Back */}
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
onClick={() => router.back()}
|
onClick={() => router.back()}
|
||||||
leftSection={<IconArrowBack size={24} color={colors['blue-button']} />}
|
leftSection={<IconArrowBack size={24} color={colors['blue-button']} />}
|
||||||
mb={15}
|
mb={15}
|
||||||
|
style={{ lineHeight: 1.2 }}
|
||||||
>
|
>
|
||||||
Kembali
|
<Text fz={{ base: 'sm', md: 'md' }} fw={500}>Kembali</Text>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{/* Wrapper Detail */}
|
{/* Wrapper Detail */}
|
||||||
@@ -48,34 +49,38 @@ function Page() {
|
|||||||
shadow="sm"
|
shadow="sm"
|
||||||
>
|
>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Text fz="2xl" fw="bold" c={colors['blue-button']}>
|
<Title order={1} c={colors['blue-button']}>
|
||||||
Detail Kontak Darurat
|
Detail Kontak Darurat
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
<Paper bg="#ECEEF8" p="md" radius="md" shadow="xs">
|
<Paper bg="#ECEEF8" p="md" radius="md" shadow="xs">
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Judul</Text>
|
<Title order={3}>Judul</Title>
|
||||||
<Text fz="md" c="dimmed">{data.name || '-'}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} c={data.name ? 'black' : 'dimmed'}>
|
||||||
|
{data.name || '-'}
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Whatsapp</Text>
|
<Title order={3}>Whatsapp</Title>
|
||||||
<Text fz="md" c="dimmed">{data.whatsapp || '-'}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} c={data.whatsapp ? 'black' : 'dimmed'}>
|
||||||
|
{data.whatsapp || '-'}
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
<Title order={3}>Deskripsi</Title>
|
||||||
<Text
|
<Text
|
||||||
fz="md"
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
c="dimmed"
|
c={data.deskripsi ? 'black' : 'dimmed'}
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal', lineHeight: 1.5 }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Gambar</Text>
|
<Title order={3}>Gambar</Title>
|
||||||
{data.image?.link ? (
|
{data.image?.link ? (
|
||||||
<Image
|
<Image
|
||||||
src={data.image.link}
|
src={data.image.link}
|
||||||
@@ -85,9 +90,10 @@ function Page() {
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Text fz="md" c="dimmed">-</Text>
|
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed">-</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Group>
|
<Group>
|
||||||
<Button
|
<Button
|
||||||
variant="light"
|
variant="light"
|
||||||
@@ -96,6 +102,7 @@ function Page() {
|
|||||||
href={`https://wa.me/${data.whatsapp.replace(/\D/g, '')}`}
|
href={`https://wa.me/${data.whatsapp.replace(/\D/g, '')}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
aria-label="Hubungi WhatsApp"
|
aria-label="Hubungi WhatsApp"
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
>
|
>
|
||||||
WhatsApp
|
WhatsApp
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
|
Title,
|
||||||
Tooltip
|
Tooltip
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
@@ -52,10 +53,21 @@ function Page() {
|
|||||||
|
|
||||||
<Grid align="center" px={{ base: 'md', md: 100 }} gutter="lg">
|
<Grid align="center" px={{ base: 'md', md: 100 }} gutter="lg">
|
||||||
<GridCol span={{ base: 12, md: 8 }}>
|
<GridCol span={{ base: 12, md: 8 }}>
|
||||||
<Text fz={{ base: '2rem', md: '2.8rem' }} c={colors['blue-button']} fw={800}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fw={800}
|
||||||
|
fz={{ base: '28px', md: '32px' }}
|
||||||
|
lh={{ base: 1.2, md: 1.25 }}
|
||||||
|
>
|
||||||
Kontak Darurat
|
Kontak Darurat
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="md" mt={4}>
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
|
mt={4}
|
||||||
|
c="dark.9"
|
||||||
|
>
|
||||||
Hubungi layanan penting dengan cepat dan mudah
|
Hubungi layanan penting dengan cepat dan mudah
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
@@ -79,10 +91,20 @@ function Page() {
|
|||||||
<Center mih={300}>
|
<Center mih={300}>
|
||||||
<Stack align="center" gap="xs">
|
<Stack align="center" gap="xs">
|
||||||
<IconSearch size={50} color={colors['blue-button']} />
|
<IconSearch size={50} color={colors['blue-button']} />
|
||||||
<Text fz="lg" fw={600} c={colors['blue-button']}>
|
<Title
|
||||||
|
order={2}
|
||||||
|
fw={600}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fz={{ base: '20px', md: '24px' }}
|
||||||
|
lh={{ base: 1.3, md: 1.35 }}
|
||||||
|
>
|
||||||
Tidak ada kontak ditemukan
|
Tidak ada kontak ditemukan
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
lh={{ base: 1.4, md: 1.5 }}
|
||||||
|
c="dark.7"
|
||||||
|
>
|
||||||
Coba kata kunci lain untuk pencarian
|
Coba kata kunci lain untuk pencarian
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -102,8 +124,8 @@ function Page() {
|
|||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'space-between', // ✅ biar button selalu di bawah
|
justifyContent: 'space-between',
|
||||||
height: '100%', // ✅ bikin tinggi seragam
|
height: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack align="center" gap="sm" style={{ flexGrow: 1 }}>
|
<Stack align="center" gap="sm" style={{ flexGrow: 1 }}>
|
||||||
@@ -131,27 +153,24 @@ function Page() {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Text ta="center" fw={700} fz="lg" c={colors['blue-button']}>
|
<Text ta="center" fw={700} fz={{ base: '18px', md: '20px' }} lh={1.3} c={colors['blue-button']}>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
ta="center"
|
ta="center"
|
||||||
lineClamp={3}
|
lineClamp={3}
|
||||||
lh={1.6}
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
style={{
|
style={{
|
||||||
minHeight: '4.8em', // tinggi tetap 3 baris
|
minHeight: '4.8em',
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
whiteSpace: 'normal',
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
/>
|
/>
|
||||||
</Text>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
{/* ✅ Tombol selalu di bagian bawah card */}
|
|
||||||
<Group mt="md" justify='center'>
|
<Group mt="md" justify='center'>
|
||||||
<Button
|
<Button
|
||||||
bg={colors['blue-button']}
|
bg={colors['blue-button']}
|
||||||
@@ -161,8 +180,6 @@ function Page() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
|
|
||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import penangananDarurat from '@/app/admin/(dashboard)/_state/kesehatan/penanganan-darurat/penangananDarurat';
|
import penangananDarurat from '@/app/admin/(dashboard)/_state/kesehatan/penanganan-darurat/penangananDarurat';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Image, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Center, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
@@ -31,24 +31,30 @@ function DetailPenangananDaruratUser() {
|
|||||||
<Box py={20}>
|
<Box py={20}>
|
||||||
{/* Tombol Back */}
|
{/* Tombol Back */}
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<BackButton/>
|
<BackButton />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Wrapper Detail */}
|
{/* Wrapper Detail */}
|
||||||
|
<Box pt={20} px={{ base: 'md', md: 100 }}>
|
||||||
<Paper
|
<Paper
|
||||||
withBorder
|
withBorder
|
||||||
w={{ base: '100%', md: '70%', lg: '60%' }}
|
w={'100%'}
|
||||||
mx="auto"
|
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
p="xl"
|
p="xl"
|
||||||
radius="lg"
|
radius="lg"
|
||||||
shadow="sm"
|
shadow="sm"
|
||||||
>
|
>
|
||||||
<Stack gap="md" align="center" ta="center">
|
<Stack gap="md">
|
||||||
<Text fz="xl" fw={700} c={colors['blue-button']}>
|
<Title
|
||||||
|
ta={"center"}
|
||||||
|
order={1}
|
||||||
|
fw={700}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
style={{ wordBreak: 'break-word' }}
|
||||||
|
>
|
||||||
{data.name || 'Penanganan Darurat'}
|
{data.name || 'Penanganan Darurat'}
|
||||||
</Text>
|
</Title>
|
||||||
|
<Center>
|
||||||
{data.image?.link && (
|
{data.image?.link && (
|
||||||
<Image
|
<Image
|
||||||
src={data.image.link}
|
src={data.image.link}
|
||||||
@@ -60,10 +66,10 @@ function DetailPenangananDaruratUser() {
|
|||||||
mb="md"
|
mb="md"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
</Center>
|
||||||
|
|
||||||
<Box>
|
<Box >
|
||||||
<Text
|
<Text
|
||||||
fz="md"
|
|
||||||
ta="justify"
|
ta="justify"
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
||||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
@@ -72,6 +78,7 @@ function DetailPenangananDaruratUser() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
|
Title,
|
||||||
Tooltip
|
Tooltip
|
||||||
} from '@mantine/core'
|
} from '@mantine/core'
|
||||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks'
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks'
|
||||||
@@ -49,10 +50,19 @@ function Page() {
|
|||||||
|
|
||||||
<Grid align="center" px={{ base: 'md', md: 100 }} mb="lg">
|
<Grid align="center" px={{ base: 'md', md: 100 }} mb="lg">
|
||||||
<GridCol span={{ base: 12, md: 9 }}>
|
<GridCol span={{ base: 12, md: 9 }}>
|
||||||
<Text fz={{ base: 30, md: 40 }} c={colors['blue-button']} fw={800} lh={1.2}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors['blue-button']}
|
||||||
|
fw={800}
|
||||||
|
lh={{ base: 1.3, md: 1.2 }}
|
||||||
|
>
|
||||||
Penanganan Darurat
|
Penanganan Darurat
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="md" mt={4}>
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
mt={4}
|
||||||
|
lh={{ base: 1.5, md: 1.5 }}
|
||||||
|
>
|
||||||
Informasi cepat dan jelas untuk situasi darurat kesehatan
|
Informasi cepat dan jelas untuk situasi darurat kesehatan
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
@@ -74,10 +84,10 @@ function Page() {
|
|||||||
{data.length === 0 ? (
|
{data.length === 0 ? (
|
||||||
<Center py={100}>
|
<Center py={100}>
|
||||||
<Stack align="center" gap="xs">
|
<Stack align="center" gap="xs">
|
||||||
<Text fz="lg" fw={600} c={colors['blue-button']}>
|
<Title order={2} fw={600} c={colors['blue-button']}>
|
||||||
Tidak ada data ditemukan
|
Tidak ada data ditemukan
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text fz={{ base: 'xs', md: 'sm' }}>
|
||||||
Coba gunakan kata kunci lain
|
Coba gunakan kata kunci lain
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -128,18 +138,21 @@ function Page() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Stack gap={4} w="100%">
|
<Stack gap={4} w="100%">
|
||||||
<Text
|
<Title
|
||||||
fz="lg"
|
order={3}
|
||||||
fw={700}
|
fw={700}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
ta="center"
|
ta="center"
|
||||||
lineClamp={2}
|
lineClamp={2}
|
||||||
|
fz={{ base: 'sm', md: 'lg' }}
|
||||||
|
lh={{ base: 1.4, md: 1.4 }}
|
||||||
>
|
>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Box>
|
<Box>
|
||||||
<Text
|
<Text
|
||||||
fz="md"
|
fz={{ base: 'xs', md: 'md' }}
|
||||||
|
lh={{ base: 1.5, md: 1.5 }}
|
||||||
lineClamp={3}
|
lineClamp={3}
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
@@ -177,10 +190,8 @@ function Page() {
|
|||||||
'&:hover': { backgroundColor: colors['blue-button'], color: 'white' },
|
'&:hover': { backgroundColor: colors['blue-button'], color: 'white' },
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,18 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Button, Center, Flex, Group, Image, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
import {
|
||||||
|
Button,
|
||||||
|
Center,
|
||||||
|
Flex,
|
||||||
|
Group,
|
||||||
|
Image,
|
||||||
|
Paper,
|
||||||
|
Skeleton,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
Title,
|
||||||
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconArrowBack, IconCalendar, IconInfoCircle, IconPhone } from '@tabler/icons-react';
|
import { IconArrowBack, IconCalendar, IconInfoCircle, IconPhone } from '@tabler/icons-react';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
@@ -53,15 +64,14 @@ export default function DetailPosyanduUser() {
|
|||||||
mx="auto"
|
mx="auto"
|
||||||
>
|
>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
{/* Header */}
|
{/* Header — Dijadikan Title */}
|
||||||
<Text
|
<Title
|
||||||
ta="center"
|
ta="center"
|
||||||
fz={{ base: '1.8rem', md: '2.2rem' }}
|
order={1}
|
||||||
fw={700}
|
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
>
|
>
|
||||||
{data.name || 'Posyandu Desa'}
|
{data.name || 'Posyandu Desa'}
|
||||||
</Text>
|
</Title>
|
||||||
|
|
||||||
{/* Gambar */}
|
{/* Gambar */}
|
||||||
{data.image?.link ? (
|
{data.image?.link ? (
|
||||||
@@ -78,7 +88,11 @@ export default function DetailPosyanduUser() {
|
|||||||
</Center>
|
</Center>
|
||||||
) : (
|
) : (
|
||||||
<Center>
|
<Center>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text
|
||||||
|
fz={{ base: 'xs', md: 'sm' }}
|
||||||
|
c="dimmed"
|
||||||
|
ta="center"
|
||||||
|
>
|
||||||
Tidak ada gambar
|
Tidak ada gambar
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -88,7 +102,11 @@ export default function DetailPosyanduUser() {
|
|||||||
<Stack gap="sm" mt="md">
|
<Stack gap="sm" mt="md">
|
||||||
<Flex align="center" gap="xs">
|
<Flex align="center" gap="xs">
|
||||||
<IconPhone size={18} stroke={1.5} />
|
<IconPhone size={18} stroke={1.5} />
|
||||||
<Text fz="sm" c="dimmed">
|
<Text
|
||||||
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
|
c="black"
|
||||||
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
|
>
|
||||||
{data.nomor || 'Nomor tidak tersedia'}
|
{data.nomor || 'Nomor tidak tersedia'}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -96,8 +114,9 @@ export default function DetailPosyanduUser() {
|
|||||||
<Flex align="center" gap="xs">
|
<Flex align="center" gap="xs">
|
||||||
<IconCalendar size={18} stroke={1.5} />
|
<IconCalendar size={18} stroke={1.5} />
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
c="dimmed"
|
c="black"
|
||||||
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
dangerouslySetInnerHTML={{ __html: data.jadwalPelayanan || '-' }}
|
dangerouslySetInnerHTML={{ __html: data.jadwalPelayanan || '-' }}
|
||||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
/>
|
/>
|
||||||
@@ -106,9 +125,9 @@ export default function DetailPosyanduUser() {
|
|||||||
<Flex align="center" gap="xs">
|
<Flex align="center" gap="xs">
|
||||||
<IconInfoCircle size={18} stroke={1.5} />
|
<IconInfoCircle size={18} stroke={1.5} />
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
c="dimmed"
|
c="black"
|
||||||
lh={1.6}
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
||||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import posyandustate from "@/app/admin/(dashboard)/_state/kesehatan/posyandu/posyandu";
|
import posyandustate from "@/app/admin/(dashboard)/_state/kesehatan/posyandu/posyandu";
|
||||||
import colors from "@/con/colors";
|
import colors from "@/con/colors";
|
||||||
import { Badge, Box, Button, Center, Flex, Group, Image, List, ListItem, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from "@mantine/core";
|
import { Badge, Box, Button, Center, Flex, Group, Image, List, ListItem, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from "@mantine/core";
|
||||||
import { useDebouncedValue, useShallowEffect } from "@mantine/hooks";
|
import { useDebouncedValue, useShallowEffect } from "@mantine/hooks";
|
||||||
import { IconCalendar, IconInfoCircle, IconPhone, IconSearch } from "@tabler/icons-react";
|
import { IconCalendar, IconInfoCircle, IconPhone, IconSearch } from "@tabler/icons-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -12,8 +12,8 @@ import { useTransitionRouter } from "next-view-transitions";
|
|||||||
export default function Page() {
|
export default function Page() {
|
||||||
const state = useProxy(posyandustate);
|
const state = useProxy(posyandustate);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
const router = useTransitionRouter()
|
const router = useTransitionRouter();
|
||||||
|
|
||||||
const { data, page, totalPages, loading, load } = state.findMany;
|
const { data, page, totalPages, loading, load } = state.findMany;
|
||||||
|
|
||||||
@@ -35,14 +35,13 @@ export default function Page() {
|
|||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
<Flex mt="md" justify="space-between" align="center" wrap="wrap" gap="md">
|
<Flex mt="md" justify="space-between" align="center" wrap="wrap" gap="md">
|
||||||
<Text
|
<Title
|
||||||
|
order={1}
|
||||||
ta="left"
|
ta="left"
|
||||||
fz={{ base: "1.8rem", md: "2.5rem" }}
|
|
||||||
c={colors["blue-button"]}
|
c={colors["blue-button"]}
|
||||||
fw="bold"
|
|
||||||
>
|
>
|
||||||
Posyandu Desa Darmasaba
|
Posyandu Desa Darmasaba
|
||||||
</Text>
|
</Title>
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="Cari posyandu berdasarkan nama..."
|
placeholder="Cari posyandu berdasarkan nama..."
|
||||||
aria-label="Pencarian Posyandu"
|
aria-label="Pencarian Posyandu"
|
||||||
@@ -55,6 +54,7 @@ export default function Page() {
|
|||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Title c={"dimmed"} order={3} ta={"center"}>Belum ada posyandu yang terdaftar</Title>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -64,14 +64,13 @@ export default function Page() {
|
|||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<BackButton />
|
<BackButton />
|
||||||
<Flex mt="md" justify="space-between" align="center" wrap="wrap" gap="md">
|
<Flex mt="md" justify="space-between" align="center" wrap="wrap" gap="md">
|
||||||
<Text
|
<Title
|
||||||
|
order={1}
|
||||||
ta="left"
|
ta="left"
|
||||||
fz={{ base: "1.8rem", md: "2.5rem" }}
|
|
||||||
c={colors["blue-button"]}
|
c={colors["blue-button"]}
|
||||||
fw="bold"
|
|
||||||
>
|
>
|
||||||
Posyandu Desa Darmasaba
|
Posyandu Desa Darmasaba
|
||||||
</Text>
|
</Title>
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder="Cari posyandu berdasarkan nama..."
|
placeholder="Cari posyandu berdasarkan nama..."
|
||||||
aria-label="Pencarian Posyandu"
|
aria-label="Pencarian Posyandu"
|
||||||
@@ -116,9 +115,9 @@ export default function Page() {
|
|||||||
>
|
>
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Group justify="space-between" align="center">
|
<Group justify="space-between" align="center">
|
||||||
<Text c={colors["blue-button"]} fw="bold" fz="lg" lineClamp={1}>
|
<Title order={3} c={colors["blue-button"]} fw="bold" lineClamp={1}>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Badge color="blue" variant="light" size="sm" radius="sm">
|
<Badge color="blue" variant="light" size="sm" radius="sm">
|
||||||
Aktif
|
Aktif
|
||||||
</Badge>
|
</Badge>
|
||||||
@@ -136,39 +135,45 @@ export default function Page() {
|
|||||||
</Center>
|
</Center>
|
||||||
<Flex align="flex-start" gap="xs">
|
<Flex align="flex-start" gap="xs">
|
||||||
<IconPhone size={18} stroke={1.5} style={{ marginTop: 3 }} />
|
<IconPhone size={18} stroke={1.5} style={{ marginTop: 3 }} />
|
||||||
<Box>
|
<Text
|
||||||
<Text fz="sm" c="dimmed" lh={1.4}>
|
fz={{ base: "sm", md: "md" }}
|
||||||
|
c="black"
|
||||||
|
lh={{ base: 1.4, md: 1.5 }}
|
||||||
|
>
|
||||||
{v.nomor || "Tidak tersedia"}
|
{v.nomor || "Tidak tersedia"}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex align="flex-start" gap="xs">
|
<Flex align="flex-start" gap="xs">
|
||||||
<IconCalendar size={18} stroke={1.5} style={{ marginTop: 3 }} />
|
<IconCalendar size={18} stroke={1.5} style={{ marginTop: 3 }} />
|
||||||
<Box>
|
<Text
|
||||||
<Text fz="sm" c="dimmed" lh={1.4}>
|
fz={{ base: "sm", md: "md" }}
|
||||||
|
c="black"
|
||||||
|
lh={{ base: 1.4, md: 1.5 }}
|
||||||
|
>
|
||||||
<strong>Jadwal:</strong>{" "}
|
<strong>Jadwal:</strong>{" "}
|
||||||
<span
|
<span
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
dangerouslySetInnerHTML={{ __html: v.jadwalPelayanan }}
|
dangerouslySetInnerHTML={{ __html: v.jadwalPelayanan }}
|
||||||
/>
|
/>
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex align="flex-start" gap="xs">
|
<Flex align="flex-start" gap="xs">
|
||||||
<IconInfoCircle size={18} stroke={1.5} style={{ marginTop: 3 }} />
|
<IconInfoCircle size={18} stroke={1.5} style={{ marginTop: 3 }} />
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz={{ base: "sm", md: "md" }}
|
||||||
lh={1.5}
|
lh={{ base: 1.4, md: 1.5 }}
|
||||||
c="dimmed"
|
c="black"
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
lineClamp={3}
|
lineClamp={3}
|
||||||
truncate="end"
|
truncate="end"
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Button radius="lg" size="md" variant="outline" onClick={() => router.push(`/darmasaba/kesehatan/posyandu/${v.id}`)}>Detail</Button>
|
<Button radius="lg" size="md" variant="outline" onClick={() => router.push(`/darmasaba/kesehatan/posyandu/${v.id}`)}>
|
||||||
|
Detail
|
||||||
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
))}
|
))}
|
||||||
@@ -191,11 +196,11 @@ export default function Page() {
|
|||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Flex align="center" gap="xs">
|
<Flex align="center" gap="xs">
|
||||||
<IconInfoCircle size={22} color={colors["blue-button"]} />
|
<IconInfoCircle size={22} color={colors["blue-button"]} />
|
||||||
<Text fz="lg" fw="bold" c={colors["blue-button"]}>
|
<Title order={2} c={colors["blue-button"]}>
|
||||||
Layanan Utama Posyandu
|
Layanan Utama Posyandu
|
||||||
</Text>
|
</Title>
|
||||||
</Flex>
|
</Flex>
|
||||||
<List spacing="xs" size="sm" center>
|
<List spacing="xs" fz={{ base: "sm", md: "md" }} lh={{ base: 1.4, md: 1.5 }} c="black">
|
||||||
<ListItem>Penimbangan bayi dan balita</ListItem>
|
<ListItem>Penimbangan bayi dan balita</ListItem>
|
||||||
<ListItem>Pemantauan status gizi</ListItem>
|
<ListItem>Pemantauan status gizi</ListItem>
|
||||||
<ListItem>Imunisasi dasar lengkap</ListItem>
|
<ListItem>Imunisasi dasar lengkap</ListItem>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import programKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan';
|
import programKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Group, Image, Loader, Paper, Skeleton, Stack, Text, Tooltip } from '@mantine/core';
|
import { Box, Center, Group, Image, Loader, Paper, Skeleton, Stack, Text, Title, Tooltip } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconCalendar, IconUser } from '@tabler/icons-react';
|
import { IconCalendar, IconUser } from '@tabler/icons-react';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
@@ -9,12 +9,12 @@ import { useProxy } from 'valtio/utils';
|
|||||||
import BackButton from '../../../desa/layanan/_com/BackButto';
|
import BackButton from '../../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const state = useProxy(programKesehatan)
|
const state = useProxy(programKesehatan);
|
||||||
const params = useParams()
|
const params = useParams();
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
state.findUnique.load(params.id as string)
|
state.findUnique.load(params.id as string);
|
||||||
}, [params.id])
|
}, [params.id]);
|
||||||
|
|
||||||
if (!state.findUnique.data) {
|
if (!state.findUnique.data) {
|
||||||
return (
|
return (
|
||||||
@@ -24,7 +24,7 @@ function Page() {
|
|||||||
<Text c="dimmed" fz="sm">Memuat data program kesehatan...</Text>
|
<Text c="dimmed" fz="sm">Memuat data program kesehatan...</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -44,36 +44,41 @@ function Page() {
|
|||||||
<Center>
|
<Center>
|
||||||
{state.findUnique.data.image?.link ? (
|
{state.findUnique.data.image?.link ? (
|
||||||
<Image
|
<Image
|
||||||
radius="xl"
|
|
||||||
src={state.findUnique.data.image?.link}
|
src={state.findUnique.data.image?.link}
|
||||||
alt={state.findUnique.data.name}
|
alt={state.findUnique.data.name}
|
||||||
w="100%"
|
radius="md"
|
||||||
maw={800}
|
mah={300}
|
||||||
fit="cover"
|
fit="contain"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Skeleton h={300} w="100%" radius="xl" />
|
<Skeleton h={300} w="100%" radius="xl" />
|
||||||
)}
|
)}
|
||||||
</Center>
|
</Center>
|
||||||
<Box>
|
<Box pl={20}>
|
||||||
<Text pb="sm" c={colors["blue-button"]} fw="bold" fz={{ base: 24, md: 32 }} lh={1.2}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
pb="sm"
|
||||||
|
c={colors["blue-button"]}
|
||||||
|
fw="bold"
|
||||||
|
lh={{ base: 1.2, md: 1.15 }}
|
||||||
|
>
|
||||||
{state.findUnique.data.name}
|
{state.findUnique.data.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Text
|
<Text
|
||||||
ta="justify"
|
ta="justify"
|
||||||
fz="md"
|
fz={{ base: 'sm', md: 'md' }}
|
||||||
lh={1.6}
|
lh={{ base: 1.5, md: 1.6 }}
|
||||||
dangerouslySetInnerHTML={{ __html: state.findUnique.data.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: state.findUnique.data.deskripsi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Group gap="xl">
|
<Group gap="xl">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<Tooltip label="Tanggal dibuat" withArrow>
|
<Tooltip label="Tanggal dibuat" withArrow>
|
||||||
<IconCalendar color='gray' size={20} stroke={1.5} />
|
<IconCalendar color="gray" size={20} stroke={1.5} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Text size="sm" c="dimmed">
|
<Text fz={{ base: 'xs', md: 'sm' }} c="dimmed">
|
||||||
{state.findUnique.data.createdAt
|
{state.findUnique.data.createdAt
|
||||||
? new Date(state.findUnique.data.createdAt).toLocaleDateString('id-ID', {
|
? new Date(state.findUnique.data.createdAt).toLocaleDateString('id-ID', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
@@ -85,9 +90,9 @@ function Page() {
|
|||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<Tooltip label="Dibuat oleh" withArrow>
|
<Tooltip label="Dibuat oleh" withArrow>
|
||||||
<IconUser color='gray' size={20} stroke={1.5} />
|
<IconUser color="gray" size={20} stroke={1.5} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Text size="sm" c="dimmed">Admin Desa</Text>
|
<Text fz={{ base: 'xs', md: 'sm' }} c="dimmed">Admin Desa</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
|
Title,
|
||||||
Transition
|
Transition
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useDebouncedValue, useShallowEffect } from "@mantine/hooks";
|
import { useDebouncedValue, useShallowEffect } from "@mantine/hooks";
|
||||||
@@ -57,7 +58,7 @@ export default function Page() {
|
|||||||
const state = useProxy(programKesehatan);
|
const state = useProxy(programKesehatan);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
const { data, page, totalPages, loading, load } = state.findMany;
|
const { data, page, totalPages, loading, load } = state.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
@@ -80,14 +81,19 @@ export default function Page() {
|
|||||||
|
|
||||||
<Grid px={{ base: "md", md: 100 }} align="center" gutter="lg">
|
<Grid px={{ base: "md", md: 100 }} align="center" gutter="lg">
|
||||||
<GridCol span={{ base: 12, md: 8 }}>
|
<GridCol span={{ base: 12, md: 8 }}>
|
||||||
<Text
|
<Title
|
||||||
fz={{ base: "2rem", md: "2.8rem" }}
|
order={1}
|
||||||
c={colors["blue-button"]}
|
c={colors["blue-button"]}
|
||||||
fw="bold"
|
fw="bold"
|
||||||
|
fz={{ base: '28px', md: '32px' }}
|
||||||
>
|
>
|
||||||
Program Kesehatan Desa
|
Program Kesehatan Desa
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="lg" mt="xs">
|
<Text
|
||||||
|
fz={{ base: '14px', md: '16px' }}
|
||||||
|
lh={{ base: '1.5', md: '1.6' }}
|
||||||
|
mt="xs"
|
||||||
|
>
|
||||||
Temukan berbagai program kesehatan untuk mendukung kualitas hidup
|
Temukan berbagai program kesehatan untuk mendukung kualitas hidup
|
||||||
masyarakat Darmasaba.
|
masyarakat Darmasaba.
|
||||||
</Text>
|
</Text>
|
||||||
@@ -129,11 +135,9 @@ export default function Page() {
|
|||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: 180, // 🔥 tinggi fix biar semua seragam
|
aspectRatio: '16/9', // thumbnail landscape aman untuk portrait/landscape
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
position: 'relative',
|
|
||||||
backgroundColor: '#f0f2f5', // fallback kalau gambar loading
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
@@ -142,32 +146,28 @@ export default function Page() {
|
|||||||
fit="cover"
|
fit="cover"
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
|
style={{ objectFit: 'cover', objectPosition: 'center' }}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
style={{
|
|
||||||
objectFit: 'cover',
|
|
||||||
objectPosition: 'center',
|
|
||||||
transition: 'transform 0.4s ease',
|
|
||||||
}}
|
|
||||||
onMouseEnter={(e) => (e.currentTarget.style.transform = 'scale(1.05)')}
|
onMouseEnter={(e) => (e.currentTarget.style.transform = 'scale(1.05)')}
|
||||||
onMouseLeave={(e) => (e.currentTarget.style.transform = 'scale(1)')}
|
onMouseLeave={(e) => (e.currentTarget.style.transform = 'scale(1)')}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
</Center>
|
</Center>
|
||||||
|
|
||||||
<Box px="lg" pb="lg">
|
<Box px="lg" pb="lg">
|
||||||
<Text
|
<Title
|
||||||
fw="bold"
|
order={3}
|
||||||
fz="xl"
|
|
||||||
c={colors["blue-button"]}
|
c={colors["blue-button"]}
|
||||||
|
fw="bold"
|
||||||
|
fz={{ base: '18px', md: '20px' }}
|
||||||
mb="xs"
|
mb="xs"
|
||||||
>
|
>
|
||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Text
|
<Text
|
||||||
fz="sm"
|
fz={{ base: '13px', md: '14px' }}
|
||||||
ta={"justify"}
|
lh="1.6"
|
||||||
|
ta="justify"
|
||||||
lineClamp={3}
|
lineClamp={3}
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
@@ -175,7 +175,10 @@ export default function Page() {
|
|||||||
<Group justify="space-between" mt="md">
|
<Group justify="space-between" mt="md">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconCalendar size={18} />
|
<IconCalendar size={18} />
|
||||||
<Text size="sm">
|
<Text
|
||||||
|
fz={{ base: '12px', md: '14px' }}
|
||||||
|
lh="1.5"
|
||||||
|
>
|
||||||
{v.createdAt
|
{v.createdAt
|
||||||
? new Date(v.createdAt).toLocaleDateString(
|
? new Date(v.createdAt).toLocaleDateString(
|
||||||
"id-ID",
|
"id-ID",
|
||||||
@@ -190,7 +193,12 @@ export default function Page() {
|
|||||||
</Group>
|
</Group>
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconUser size={18} />
|
<IconUser size={18} />
|
||||||
<Text size="sm">Admin Desa</Text>
|
<Text
|
||||||
|
fz={{ base: '12px', md: '14px' }}
|
||||||
|
lh="1.5"
|
||||||
|
>
|
||||||
|
Admin Desa
|
||||||
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<Button
|
<Button
|
||||||
@@ -239,14 +247,19 @@ export default function Page() {
|
|||||||
|
|
||||||
<Box px={{ base: "md", md: 100 }} py="xl">
|
<Box px={{ base: "md", md: 100 }} py="xl">
|
||||||
<Stack gap="sm" mb="lg">
|
<Stack gap="sm" mb="lg">
|
||||||
<Text
|
<Title
|
||||||
fz={{ base: "2rem", md: "2.5rem" }}
|
order={2}
|
||||||
c={colors["blue-button"]}
|
c={colors["blue-button"]}
|
||||||
fw="bold"
|
fw="bold"
|
||||||
|
fz={{ base: '24px', md: '28px' }}
|
||||||
>
|
>
|
||||||
Manfaat Program Kesehatan
|
Manfaat Program Kesehatan
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="lg" maw={700}>
|
<Text
|
||||||
|
fz={{ base: '14px', md: '16px' }}
|
||||||
|
lh={{ base: '1.5', md: '1.6' }}
|
||||||
|
maw={700}
|
||||||
|
>
|
||||||
Program kesehatan Desa Darmasaba berperan penting dalam meningkatkan
|
Program kesehatan Desa Darmasaba berperan penting dalam meningkatkan
|
||||||
kesejahteraan dan kualitas hidup warganya.
|
kesejahteraan dan kualitas hidup warganya.
|
||||||
</Text>
|
</Text>
|
||||||
@@ -273,10 +286,20 @@ export default function Page() {
|
|||||||
>
|
>
|
||||||
<Center>{v.icon}</Center>
|
<Center>{v.icon}</Center>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Text ta="center" fw="bold" fz="xl" c={colors["blue-button"]}>
|
<Title
|
||||||
|
order={3}
|
||||||
|
ta="center"
|
||||||
|
fw="bold"
|
||||||
|
c={colors["blue-button"]}
|
||||||
|
fz={{ base: '18px', md: '20px' }}
|
||||||
|
>
|
||||||
{v.title}
|
{v.title}
|
||||||
</Text>
|
</Title>
|
||||||
<Text ta="center" fz="sm">
|
<Text
|
||||||
|
ta="center"
|
||||||
|
fz={{ base: '13px', md: '14px' }}
|
||||||
|
lh="1.5"
|
||||||
|
>
|
||||||
{v.desc}
|
{v.desc}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -59,12 +59,16 @@ function Page() {
|
|||||||
left={20}
|
left={20}
|
||||||
gap={6}
|
gap={6}
|
||||||
>
|
>
|
||||||
<Text fw="bold" fz={{ base: 'lg', md: 'h2' }} c={colors['white-1']}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
c={colors['white-1']}
|
||||||
|
fz={{ base: 'lg', md: 'xl' }}
|
||||||
|
>
|
||||||
{data.name}
|
{data.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Group gap={6}>
|
<Group gap={6}>
|
||||||
<IconMapPin size={20} color="white" />
|
<IconMapPin size={20} color="white" />
|
||||||
<Text fz={{ base: 'sm', md: 'md' }} c={colors['white-1']}>
|
<Text fz={{ base: 'xs', md: 'sm' }} c={colors['white-1']}>
|
||||||
{data.alamat}
|
{data.alamat}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
@@ -75,35 +79,43 @@ function Page() {
|
|||||||
<GridCol span={{ base: 12, md: 6 }}>
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<Box>
|
<Box>
|
||||||
<Title order={3} mb={10}>Informasi Kontak</Title>
|
<Title order={2} mb="md">Informasi Kontak</Title>
|
||||||
<Stack gap={8}>
|
<Stack gap={8}>
|
||||||
<Group gap={8}>
|
<Group gap={8}>
|
||||||
<IconPhone size={18} />
|
<IconPhone size={18} />
|
||||||
<Text fz="md">{data.kontak.kontakPuskesmas || '-'}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }}>
|
||||||
|
{data.kontak.kontakPuskesmas || '-'}
|
||||||
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Group gap={8}>
|
<Group gap={8}>
|
||||||
<IconMail size={18} />
|
<IconMail size={18} />
|
||||||
<Text fz="md">{data.kontak.email || '-'}</Text>
|
<Text fz={{ base: 'sm', md: 'md' }}>
|
||||||
|
{data.kontak.email || '-'}
|
||||||
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Stack gap={"xs"}>
|
<Stack gap="xs">
|
||||||
<Title order={3} mb={10}>Jam Operasional</Title>
|
<Title order={2} mb="md">Jam Operasional</Title>
|
||||||
<Text fw="bold" fz="md">Senin - Jumat</Text>
|
<Text fw="bold" fz={{ base: 'sm', md: 'md' }}>Senin - Jumat</Text>
|
||||||
<Group gap={8}>
|
<Group gap={8}>
|
||||||
<IconClock size={18} />
|
<IconClock size={18} />
|
||||||
<Text fw="bold" fz="md">{data.jam.workDays} - {data.jam.weekDays}</Text>
|
<Text fw="bold" fz={{ base: 'sm', md: 'md' }}>
|
||||||
|
{data.jam.workDays} – {data.jam.weekDays}
|
||||||
|
</Text>
|
||||||
<Tooltip label="Hari aktif pelayanan puskesmas" position="top" withArrow>
|
<Tooltip label="Hari aktif pelayanan puskesmas" position="top" withArrow>
|
||||||
<Badge size="sm" variant="light" color="blue">Aktif</Badge>
|
<Badge size="sm" variant="light" color="blue">Aktif</Badge>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Group>
|
</Group>
|
||||||
<Text fw="bold" fz="md">Sabtu - Minggu / Hari Libur</Text>
|
<Text fw="bold" fz={{ base: 'sm', md: 'md' }}>Sabtu – Minggu / Hari Libur</Text>
|
||||||
<Group gap={8}>
|
<Group gap={8}>
|
||||||
<IconClock size={18} />
|
<IconClock size={18} />
|
||||||
<Text fw="bold" fz="md">{data.jam.holiday}</Text>
|
<Text fw="bold" fz={{ base: 'sm', md: 'md' }}>
|
||||||
|
{data.jam.holiday}
|
||||||
|
</Text>
|
||||||
<Tooltip label="Hari aktif pelayanan puskesmas" position="top" withArrow>
|
<Tooltip label="Hari aktif pelayanan puskesmas" position="top" withArrow>
|
||||||
<Badge size="sm" variant="light" color="blue">Aktif</Badge>
|
<Badge size="sm" variant="light" color="blue">Aktif</Badge>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -114,20 +126,24 @@ function Page() {
|
|||||||
|
|
||||||
<GridCol span={{ base: 12, md: 6 }}>
|
<GridCol span={{ base: 12, md: 6 }}>
|
||||||
<Paper p="xl" radius="lg" bg="linear-gradient(135deg, #EAF0FB, #BFD4F5)" shadow="sm">
|
<Paper p="xl" radius="lg" bg="linear-gradient(135deg, #EAF0FB, #BFD4F5)" shadow="sm">
|
||||||
<Title order={3} mb="lg" ta="center" c="dark">Layanan Unggulan</Title>
|
<Title order={2} mb="lg" ta="center" c="dark">Layanan Unggulan</Title>
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing="lg">
|
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing="lg">
|
||||||
<Paper p="lg" radius="lg" withBorder bg={colors['white-trans-1']} shadow="xs">
|
<Paper p="lg" radius="lg" withBorder bg={colors['white-trans-1']} shadow="xs">
|
||||||
<Stack align="center" gap={8}>
|
<Stack align="center" gap={8}>
|
||||||
<IconBuildingHospital size={36} color={colors['blue-button']} />
|
<IconBuildingHospital size={36} color={colors['blue-button']} />
|
||||||
<Text fw="bold" fz="lg">Poliklinik Umum</Text>
|
<Text fw="bold" fz={{ base: 'sm', md: 'md' }}>Poliklinik Umum</Text>
|
||||||
<Text fz={{ base: 36, md: 48 }} fw="bold" c={colors['blue-button']}>26</Text>
|
<Text fz={{ base: 'h1', md: 'h1' }} fw="bold" c={colors['blue-button']} lh={1}>
|
||||||
|
26
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
<Paper p="lg" radius="lg" withBorder bg={colors['white-trans-1']} shadow="xs">
|
<Paper p="lg" radius="lg" withBorder bg={colors['white-trans-1']} shadow="xs">
|
||||||
<Stack align="center" gap={8}>
|
<Stack align="center" gap={8}>
|
||||||
<IconBuildingHospital size={36} color={colors['blue-button']} />
|
<IconBuildingHospital size={36} color={colors['blue-button']} />
|
||||||
<Text fw="bold" fz="lg">Poli Gigi</Text>
|
<Text fw="bold" fz={{ base: 'sm', md: 'md' }}>Poli Gigi</Text>
|
||||||
<Text fz={{ base: 36, md: 48 }} fw="bold" c={colors['blue-button']}>26</Text>
|
<Text fz={{ base: 'h1', md: 'h1' }} fw="bold" c={colors['blue-button']} lh={1}>
|
||||||
|
26
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import puskesmasState from '@/app/admin/(dashboard)/_state/kesehatan/puskesmas/puskesmas';
|
import puskesmasState from '@/app/admin/(dashboard)/_state/kesehatan/puskesmas/puskesmas';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Anchor, Box, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput, Badge, Group } from '@mantine/core';
|
import { Anchor, Box, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput, Badge, Group, Title } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconSearch, IconMapPin, IconPhone, IconMail } from '@tabler/icons-react';
|
import { IconSearch, IconMapPin, IconPhone, IconMail } from '@tabler/icons-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -42,10 +42,10 @@ function Page() {
|
|||||||
|
|
||||||
<Grid align="center" px={{ base: 'md', md: 100 }} mb="md">
|
<Grid align="center" px={{ base: 'md', md: 100 }} mb="md">
|
||||||
<GridCol span={{ base: 12, md: 8 }}>
|
<GridCol span={{ base: 12, md: 8 }}>
|
||||||
<Text fz={{ base: "2rem", md: "2.5rem" }} c={colors["blue-button"]} fw="bold">
|
<Title order={1} c={colors["blue-button"]}>
|
||||||
Daftar Puskesmas
|
Daftar Puskesmas
|
||||||
</Text>
|
</Title>
|
||||||
<Text fz="md">
|
<Text fz={{ base: "sm", md: "md" }} ta="start">
|
||||||
Temukan informasi lengkap mengenai layanan, kontak, dan lokasi Puskesmas Darmasaba
|
Temukan informasi lengkap mengenai layanan, kontak, dan lokasi Puskesmas Darmasaba
|
||||||
</Text>
|
</Text>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
@@ -65,8 +65,8 @@ function Page() {
|
|||||||
{data.length === 0 ? (
|
{data.length === 0 ? (
|
||||||
<Center py="xl">
|
<Center py="xl">
|
||||||
<Stack align="center" gap="xs">
|
<Stack align="center" gap="xs">
|
||||||
<Text fz="lg" fw={500} c="dimmed">Tidak ada data ditemukan</Text>
|
<Title order={2} fw={500} c="dimmed">Tidak ada data ditemukan</Title>
|
||||||
<Text fz="sm" c="dimmed">Coba gunakan kata kunci pencarian yang berbeda</Text>
|
<Text fz={{ base: "xs", md: "sm" }} c="dimmed">Coba gunakan kata kunci pencarian yang berbeda</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
) : (
|
) : (
|
||||||
@@ -92,29 +92,29 @@ function Page() {
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
<Group justify="space-between">
|
<Group justify="space-between">
|
||||||
<Text fw={600} fz="lg" lineClamp={1}>{v.name}</Text>
|
<Title order={3} fw={600} lineClamp={1}>{v.name}</Title>
|
||||||
<Badge color="blue" variant="light" radius="sm" fz="xs">Aktif</Badge>
|
<Badge color="blue" variant="light" radius="sm" fz="xs">Aktif</Badge>
|
||||||
</Group>
|
</Group>
|
||||||
<Stack gap={6}>
|
<Stack gap={6}>
|
||||||
<Group gap="xs" align="flex-start" wrap="nowrap">
|
<Group gap="xs" align="flex-start" wrap="nowrap">
|
||||||
<Box pt={2}><IconMapPin size={20} /></Box>
|
<Box pt={2}><IconMapPin size={20} /></Box>
|
||||||
<Text fz="sm" c="dimmed">{v.alamat}</Text>
|
<Text fz={{ base: "sm", md: "md" }}>{v.alamat}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Group gap="xs" align="flex-start" wrap="nowrap">
|
<Group gap="xs" align="flex-start" wrap="nowrap">
|
||||||
<Box pt={2}><IconPhone size={20} /></Box>
|
<Box pt={2}><IconPhone size={20} /></Box>
|
||||||
<Text fz="sm" c="dimmed">{v.kontak.kontakPuskesmas}</Text>
|
<Text fz={{ base: "sm", md: "md" }}>{v.kontak.kontakPuskesmas}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Group gap="xs" align="flex-start" wrap="nowrap">
|
<Group gap="xs" align="flex-start" wrap="nowrap">
|
||||||
<Box pt={2}><IconMail size={20} /></Box>
|
<Box pt={2}><IconMail size={20} /></Box>
|
||||||
<Text fz="sm" c="dimmed">{v.kontak.email}</Text>
|
<Text fz={{ base: "sm", md: "md" }}>{v.kontak.email}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Anchor
|
<Anchor
|
||||||
href={`/darmasaba/kesehatan/puskesmas/${v.id}`}
|
href={`/darmasaba/kesehatan/puskesmas/${v.id}`}
|
||||||
fz="sm"
|
fz={{ base: "sm", md: "md" }}
|
||||||
fw={500}
|
fw={500}
|
||||||
c={colors['blue-button']}
|
c={colors['blue-button']}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -64,14 +64,14 @@ function Page() {
|
|||||||
</Text>
|
</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
radius="xl"
|
radius="xl"
|
||||||
w={'30%'}
|
w={{base: "100%", md: "30%"}}
|
||||||
placeholder="Cari Data Lingkungan Desa"
|
placeholder="Cari Data Lingkungan Desa"
|
||||||
leftSection={<IconSearch size={20} />}
|
leftSection={<IconSearch size={20} />}
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Text fz="md" >
|
<Text fz="md" pt={20}>
|
||||||
Desa Darmasaba menjaga dan mengembangkan lingkungan demi kesejahteraan warganya.
|
Desa Darmasaba menjaga dan mengembangkan lingkungan demi kesejahteraan warganya.
|
||||||
</Text>
|
</Text>
|
||||||
<Text fz="md">
|
<Text fz="md">
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ function StrukturOrganisasiPPID() {
|
|||||||
const debouncedSearch = useRef(
|
const debouncedSearch = useRef(
|
||||||
debounce((value: string) => {
|
debounce((value: string) => {
|
||||||
setSearchQuery(value)
|
setSearchQuery(value)
|
||||||
}, 400)
|
}, 1000)
|
||||||
).current
|
).current
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import penghargaanState from "@/app/admin/(dashboard)/_state/desa/penghargaan";
|
import penghargaanState from "@/app/admin/(dashboard)/_state/desa/penghargaan";
|
||||||
import colors from "@/con/colors";
|
import colors from "@/con/colors";
|
||||||
import { Box, Button, Container, Group, Paper, Skeleton, Stack, Text } from "@mantine/core";
|
import { Box, Button, Container, Group, Paper, Skeleton, Stack, Text, Title } from "@mantine/core";
|
||||||
import { useMediaQuery } from "@mantine/hooks";
|
import { useMediaQuery } from "@mantine/hooks";
|
||||||
import { IconArrowRight, IconAward } from "@tabler/icons-react";
|
import { IconArrowRight, IconAward } from "@tabler/icons-react";
|
||||||
import { useTransitionRouter } from "next-view-transitions";
|
import { useTransitionRouter } from "next-view-transitions";
|
||||||
@@ -20,11 +20,21 @@ export default function Page() {
|
|||||||
<Stack align="center" gap="sm">
|
<Stack align="center" gap="sm">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<IconAward size={40} color={colors["blue-button"]} />
|
<IconAward size={40} color={colors["blue-button"]} />
|
||||||
<Text fz={{ base: "2rem", md: "3.2rem" }} fw={800} variant="gradient" gradient={{ from: "#1C6EA4", to: "#69BFF8" }}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
fw={800}
|
||||||
|
c={colors["blue-button"]}
|
||||||
|
ta="center"
|
||||||
|
>
|
||||||
Penghargaan Desa
|
Penghargaan Desa
|
||||||
</Text>
|
</Title>
|
||||||
</Group>
|
</Group>
|
||||||
<Text fz="lg" c="dimmed" ta="center">
|
<Text
|
||||||
|
fz={{ base: "sm", md: "md" }}
|
||||||
|
lh={{ base: "1.5", md: "1.6" }}
|
||||||
|
c="black"
|
||||||
|
ta="center"
|
||||||
|
>
|
||||||
Desa Darmasaba berhasil meraih beragam penghargaan bergengsi yang mencerminkan dedikasi dan kerja keras masyarakat dalam membangun desa yang maju dan berkelanjutan.
|
Desa Darmasaba berhasil meraih beragam penghargaan bergengsi yang mencerminkan dedikasi dan kerja keras masyarakat dalam membangun desa yang maju dan berkelanjutan.
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -61,10 +71,8 @@ function Slider() {
|
|||||||
const data = state.findMany.data || [];
|
const data = state.findMany.data || [];
|
||||||
const loading = state.findMany.loading;
|
const loading = state.findMany.loading;
|
||||||
|
|
||||||
// Triple data untuk infinite loop (desktop only)
|
|
||||||
const slidesData = mobile ? data : [...data, ...data, ...data];
|
const slidesData = mobile ? data : [...data, ...data, ...data];
|
||||||
|
|
||||||
// Auto-scroll animation untuk desktop
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loading || !containerRef.current || data.length === 0 || mobile) return;
|
if (loading || !containerRef.current || data.length === 0 || mobile) return;
|
||||||
|
|
||||||
@@ -72,7 +80,6 @@ function Slider() {
|
|||||||
const slideWidth = container.scrollWidth / slidesData.length;
|
const slideWidth = container.scrollWidth / slidesData.length;
|
||||||
const originalLength = data.length;
|
const originalLength = data.length;
|
||||||
|
|
||||||
// Start dari middle set
|
|
||||||
scrollPosRef.current = slideWidth * originalLength;
|
scrollPosRef.current = slideWidth * originalLength;
|
||||||
container.scrollLeft = scrollPosRef.current;
|
container.scrollLeft = scrollPosRef.current;
|
||||||
|
|
||||||
@@ -88,7 +95,6 @@ function Slider() {
|
|||||||
const speed = isHoveredRef.current ? SPEED_HOVER : SPEED_NORMAL;
|
const speed = isHoveredRef.current ? SPEED_HOVER : SPEED_NORMAL;
|
||||||
scrollPosRef.current += speed;
|
scrollPosRef.current += speed;
|
||||||
|
|
||||||
// Reset untuk infinite loop
|
|
||||||
if (scrollPosRef.current >= slideWidth * (originalLength * 2)) {
|
if (scrollPosRef.current >= slideWidth * (originalLength * 2)) {
|
||||||
scrollPosRef.current -= slideWidth * originalLength;
|
scrollPosRef.current -= slideWidth * originalLength;
|
||||||
}
|
}
|
||||||
@@ -100,7 +106,6 @@ function Slider() {
|
|||||||
} else {
|
} else {
|
||||||
scrollPosRef.current = container.scrollLeft;
|
scrollPosRef.current = container.scrollLeft;
|
||||||
|
|
||||||
// Momentum untuk drag release
|
|
||||||
if (!isDraggingRef.current && Math.abs(velocityRef.current) > 0.1) {
|
if (!isDraggingRef.current && Math.abs(velocityRef.current) > 0.1) {
|
||||||
scrollPosRef.current += velocityRef.current;
|
scrollPosRef.current += velocityRef.current;
|
||||||
velocityRef.current *= VELOCITY_DECAY;
|
velocityRef.current *= VELOCITY_DECAY;
|
||||||
@@ -185,7 +190,7 @@ function Slider() {
|
|||||||
return (
|
return (
|
||||||
<Stack align="center" py="xl">
|
<Stack align="center" py="xl">
|
||||||
<IconAward size={56} color={colors["blue-button"]} />
|
<IconAward size={56} color={colors["blue-button"]} />
|
||||||
<Text fz="lg" fw={600} c="dimmed">
|
<Text fz={{ base: "sm", md: "md" }} fw={600} c="dimmed" ta="center">
|
||||||
Belum ada penghargaan yang ditambahkan
|
Belum ada penghargaan yang ditambahkan
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -213,7 +218,6 @@ function Slider() {
|
|||||||
msOverflowStyle: "none",
|
msOverflowStyle: "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Blur edges - hanya untuk desktop */}
|
|
||||||
{!mobile && (
|
{!mobile && (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
@@ -291,8 +295,8 @@ function Slider() {
|
|||||||
style={{ borderRadius: 16 }}
|
style={{ borderRadius: 16 }}
|
||||||
/>
|
/>
|
||||||
<Stack justify="flex-end" h="100%" gap="sm" p="lg" pos="relative">
|
<Stack justify="flex-end" h="100%" gap="sm" p="lg" pos="relative">
|
||||||
<Text
|
<Title
|
||||||
fz={{ base: "lg", sm: "xl", md: "1.5rem" }}
|
order={3}
|
||||||
fw={700}
|
fw={700}
|
||||||
ta="center"
|
ta="center"
|
||||||
c="white"
|
c="white"
|
||||||
@@ -300,7 +304,7 @@ function Slider() {
|
|||||||
style={{ textShadow: "0 2px 8px rgba(0,0,0,0.8)" }}
|
style={{ textShadow: "0 2px 8px rgba(0,0,0,0.8)" }}
|
||||||
>
|
>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Text>
|
</Title>
|
||||||
<Group justify="center">
|
<Group justify="center">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => router.push(`/darmasaba/penghargaan/${item.id}`)}
|
onClick={() => router.push(`/darmasaba/penghargaan/${item.id}`)}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export function NavbarMainMenu({ listNavbar }: { listNavbar: MenuItem[] }) {
|
|||||||
<Tooltip label="Profil Saya" 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/profil/program-inovasi")
|
||||||
}}
|
}}
|
||||||
color={colors["blue-button"]}
|
color={colors["blue-button"]}
|
||||||
radius="xl"
|
radius="xl"
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ function Potensi() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
) : (
|
) : (
|
||||||
/* CARD LIST */
|
/* CARD LIST */
|
||||||
<SimpleGrid cols={{ base: 1, sm: 2 }}>
|
<SimpleGrid cols={{ base: 1, sm: 2 }} px={{base: 'md', md: 80}}>
|
||||||
{_.take(data, 4).map((v, k) => (
|
{_.take(data, 4).map((v, k) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={k}
|
key={k}
|
||||||
|
|||||||
@@ -6,20 +6,20 @@ const getDetailUrl = (item: { type?: string; id: string | number;[key: string]:
|
|||||||
sdgsdesa: () => '/darmasaba/sdgs-desa',
|
sdgsdesa: () => '/darmasaba/sdgs-desa',
|
||||||
apbdes: () => '/darmasaba/apbdes',
|
apbdes: () => '/darmasaba/apbdes',
|
||||||
prestasidesa: () => '/darmasaba/prestasi-desa',
|
prestasidesa: () => '/darmasaba/prestasi-desa',
|
||||||
pejabatdesa: () => '/darmasaba/ppid/profile-ppid',
|
pejabatdesa: () => '/darmasaba/ppid/profil-ppid',
|
||||||
strukturppid: () => '/darmasaba/ppid/struktur-ppid',
|
strukturppid: () => '/darmasaba/ppid/struktur-ppid',
|
||||||
visimisippid: () => '/darmasaba/ppid/visi-misi',
|
visimisippid: () => '/darmasaba/ppid/visi-misi',
|
||||||
dasarhukumppid: () => '/darmasaba/ppid/dasar-hukum',
|
dasarhukumppid: () => '/darmasaba/ppid/dasar-hukum',
|
||||||
profileppid: () => '/darmasaba/ppid/profile',
|
profileppid: () => '/darmasaba/ppid/profil',
|
||||||
daftarinformasipublik: () => '/darmasaba/ppid/daftar-informasi-publik',
|
daftarinformasipublik: () => '/darmasaba/ppid/daftar-informasi-publik',
|
||||||
perbekeldarmasaba: () => '/darmasaba/desa/profile',
|
perbekeldarmasaba: () => '/darmasaba/desa/profil',
|
||||||
berita: (id, kategori) => `/darmasaba/desa/berita/${kategori}/${id}`,
|
berita: (id, kategori) => `/darmasaba/desa/berita/${kategori}/${id}`,
|
||||||
pengumuman: (id, kategori) => `/darmasaba/desa/pengumuman/${kategori}/${id}`,
|
pengumuman: (id, kategori) => `/darmasaba/desa/pengumuman/${kategori}/${id}`,
|
||||||
sejarahdesa: () => '/darmasaba/desa/profile',
|
sejarahdesa: () => '/darmasaba/desa/profil',
|
||||||
visimisidesa: () => '/darmasaba/desa/profile',
|
visimisidesa: () => '/darmasaba/desa/profil',
|
||||||
lambangdesa: () => '/darmasaba/desa/profile',
|
lambangdesa: () => '/darmasaba/desa/profil',
|
||||||
maskotdesa: () => '/darmasaba/desa/profile',
|
maskotdesa: () => '/darmasaba/desa/profil',
|
||||||
profilperbekel: () => '/darmasaba/desa/profile',
|
profilperbekel: () => '/darmasaba/desa/profil',
|
||||||
potensi: () => '/darmasaba/desa/potensi-desa',
|
potensi: () => '/darmasaba/desa/potensi-desa',
|
||||||
galleryFoto: () => '/darmasaba/desa/gallery/foto',
|
galleryFoto: () => '/darmasaba/desa/gallery/foto',
|
||||||
galleryVideo: () => '/darmasaba/desa/gallery/video',
|
galleryVideo: () => '/darmasaba/desa/gallery/video',
|
||||||
|
|||||||
Reference in New Issue
Block a user