Sinkronisasi UI & API Admin - User Submenu Program Kesehatan

This commit is contained in:
2025-08-18 17:14:33 +08:00
parent bcc51aec12
commit 1e154ced86
11 changed files with 665 additions and 331 deletions

View File

@@ -1,7 +0,0 @@
import { Stack } from "@mantine/core";
export default function Page() {
return <Stack>
kesehatan
</Stack>
}

View File

@@ -0,0 +1,66 @@
'use client'
import programKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan';
import colors from '@/con/colors';
import { Box, Center, Group, Image, Paper, Skeleton, Stack, Text } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { IconCalendar, IconUser } from '@tabler/icons-react';
import { useParams } from 'next/navigation';
import { useProxy } from 'valtio/utils';
import BackButton from '../../../desa/layanan/_com/BackButto';
function Page() {
const state = useProxy(programKesehatan)
const params = useParams()
useShallowEffect(() => {
state.findUnique.load(params.id as string)
}, [params.id])
if (!state.findUnique.data) {
return (
<div>
<Skeleton h={500} />
</div>
)
}
return (
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
<Box px={{ base: 'md', md: 100 }}>
<BackButton />
</Box>
<Paper px={{ base: 'md', md: 100 }} radius={10} bg={colors["white-trans-1"]}>
<Stack gap={'xs'}>
<Center my={20}>
<Image radius={"lg"} src={state.findUnique.data.image?.link} alt="" />
</Center>
<Box px={'lg'}>
<Box>
<Text pb={10} c={colors["blue-button"]} fw={"bold"} fz={"h3"}>
{state.findUnique.data.name}
</Text>
<Text ta={'justify'} fz={'h4'} dangerouslySetInnerHTML={{ __html: state.findUnique.data.deskripsi }}></Text>
</Box>
<Group py={20}>
<Group gap="xs">
<IconCalendar size={18} />
<Text size="sm">
{state.findUnique.data.createdAt ? new Date(state.findUnique.data.createdAt).toLocaleDateString('id-ID', {
day: 'numeric',
month: 'long',
year: 'numeric',
}) : 'No date available'}
</Text>
</Group>
<Group gap="xs">
<IconUser size={18} />
<Text size="sm">Admin Desa</Text>
</Group>
</Group>
</Box>
</Stack>
</Paper>
</Stack>
);
}
export default Page;

View File

@@ -1,28 +1,14 @@
'use client'
import colors from "@/con/colors";
import { Box, Button, Center, Group, Image, Paper, SimpleGrid, Stack, Text } from "@mantine/core";
import { IconBarbell, IconCalendar, IconOld, IconUser, IconUsersGroup } from "@tabler/icons-react";
import { Box, Button, Center, Grid, GridCol, Group, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from "@mantine/core";
import { IconBarbell, IconCalendar, IconOld, IconSearch, IconUser, IconUsersGroup } from "@tabler/icons-react";
import BackButton from "../../desa/layanan/_com/BackButto";
import { useProxy } from "valtio/utils";
import programKesehatan from "@/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan";
import { useState } from "react";
import { useShallowEffect } from "@mantine/hooks";
import { useRouter } from "next/navigation";
const data1 = [
{
id: 1,
judul: 'Posyandu Terintegrasi',
image: '/api/img/pk-1.png',
deskripsi: 'Program pemantauan kesehatan terpadu untuk balita, ibu hamil, dan lansia di Banjar Gulingan dengan sistem pencatatan digital. Layanan meliputi penimbangan, imunisasi, dan konsultasi kesehatan'
},
{
id: 2,
judul: 'Senam Lansia',
image: '/api/img/pk-2.png',
deskripsi: 'Kegiatan olahraga teratur untuk warga lanjut usia dengan gerakan yang disesuaikan untuk menjaga kebugaran dan kesehatan. Program ini didampingi oleh instruktur profesional dan pemantauan kesehatan rutin.'
},
{
id: 3,
judul: 'Vaksinasi & Sterilasi HPR',
image: '/api/img/pk-3.png',
deskripsi: 'Program pengendalian hewan penular rabies melalui vaksinasi dan sterilisasi untuk mencegah penyebaran penyakit zoonosis. Dilengkapi dengan sistem pendataan digital untuk memantau cakupan dan efektivitas program.'
}
]
const data2 = [
{
id: 1,
@@ -44,21 +30,49 @@ const data2 = [
},
]
export default function Page() {
const state = useProxy(programKesehatan)
const router = useRouter()
const [search, setSearch] = useState('')
const {
data,
page,
totalPages,
loading,
load,
} = state.findMany;
useShallowEffect(() => {
load(page, 3, search)
}, [page, search])
if (loading || !data) {
return (
<Box py={10}>
<Skeleton h={500} />
</Box>
)
}
return (
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
<Box px={{ base: 'md', md: 100 }}>
<BackButton />
</Box>
<Box>
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
Program Kesehatan Unggulan
</Text>
<Text px={{base: 20, md: 90}} ta={"center"} fz={{ base: "h4", md: "h3" }} >
Desa Darmasaba mengembangkan berbagai program kesehatan terpadu untuk meningkatkan kualitas
hidup masyarakat, dengan pendekatan preventif dan promotif bebrbasis teknologi serta prtisipasi aktif
warga.
</Text>
</Box>
<Grid px={{ base: 'md', md: 100 }} align="center">
<GridCol span={{ base: 12, md: 9 }}>
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
Program Kesehatan Unggulan
</Text>
</GridCol>
<GridCol span={{ base: 12, md: 3 }}>
<TextInput
placeholder='Cari Program Kesehatan'
value={search}
onChange={(e) => setSearch(e.target.value)}
leftSection={<IconSearch size={20} />}
w={{ base: "50%", md: "100%" }}
/>
</GridCol>
</Grid>
<Box px={{ base: "md", md: 100 }}>
<Stack gap={'lg'}>
<SimpleGrid
@@ -67,27 +81,33 @@ export default function Page() {
base: 1,
md: 3,
}}>
{data1.map((v, k) => {
{data.map((v, k) => {
return (
<Paper radius={10} key={k} bg={colors["white-trans-1"]}>
<Stack gap={'xs'}>
<Center>
<Image src={v.image} alt="" style={{ borderRadius: '14px 14px 0 0' }} />
<Image src={v.image?.link} alt="" style={{ borderRadius: '14px 14px 0 0' }} />
</Center>
<Box px={'lg'}>
<Box>
<Text pb={10} c={colors["blue-button"]} fw={"bold"} fz={"h3"}>
{v.judul}
{v.name}
</Text>
<Text ta={'justify'} fz={'h4'}>{v.deskripsi}</Text>
<Text ta={'justify'} fz={'h4'} dangerouslySetInnerHTML={{ __html: v.deskripsi }}></Text>
</Box>
<Box py={15}>
<Box py={15} onClick={() => router.push(`/darmasaba/kesehatan/program-kesehatan/${v.id}`)}>
<Button fw={'bold'} fz={'h5'} c={colors["blue-button"]} bg={colors["BG-trans"]}>Detail Program</Button>
</Box>
<Group py={20}>
<Group gap="xs">
<IconCalendar size={18} />
<Text size="sm">Selasa, 11 Januari 2025</Text>
<Text size="sm">
{v.createdAt ? new Date(v.createdAt).toLocaleDateString('id-ID', {
day: 'numeric',
month: 'long',
year: 'numeric',
}) : 'No date available'}
</Text>
</Group>
<Group gap="xs">
<IconUser size={18} />
@@ -100,6 +120,15 @@ export default function Page() {
)
})}
</SimpleGrid>
<Center>
<Pagination
value={page}
onChange={(newPage) => load(newPage)} // ini penting!
total={totalPages}
mt="md"
mb="md"
/>
</Center>
</Stack>
</Box>
<Box py={10} px={{ base: "md", md: 100 }}>
@@ -141,6 +170,5 @@ export default function Page() {
</SimpleGrid>
</Box>
</Stack>
)
}
}

View File

@@ -0,0 +1,114 @@
'use client'
import puskesmasState from '@/app/admin/(dashboard)/_state/kesehatan/puskesmas/puskesmas';
import colors from '@/con/colors';
import { BackgroundImage, Box, Grid, GridCol, Paper, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { useParams } from 'next/navigation';
import { useProxy } from 'valtio/utils';
import BackButton from '../../../desa/layanan/_com/BackButto';
function Page() {
const state = useProxy(puskesmasState)
const params = useParams()
useShallowEffect(() => {
state.findUnique.load(params.id as string)
}, [])
if (!state.findUnique.data) {
return (
<Stack py={10}>
<Skeleton h={500} />
</Stack>
)
}
return (
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
<Box px={{ base: 'md', md: 100 }}>
<BackButton />
</Box>
<Stack gap={'lg'} px={{ base: 'md', md: 100 }}>
<Box>
<Paper p={"xl"} bg={colors['white-trans-1']}>
<Box pb={30}>
<BackgroundImage
pb={30}
radius={16}
h={{ base: 250, md: 500 }}
src={state.findUnique.data.image.link}
style={{ position: 'relative' }}
>
<Box
style={{
borderRadius: 16,
zIndex: 0
}}
pos={"absolute"}
w={"100%"}
h={"100%"}
bg={colors.trans.dark[2]}
/>
<Text style={{
position: 'absolute',
bottom: 35,
left: 15,
}} fw={'bold'} fz={{ base: 'md', md: 'h3' }} c={colors['white-1']}>{state.findUnique.data.name}</Text>
<Text style={{
position: 'absolute',
bottom: 10,
left: 15,
}} fw={'bold'} fz={{ base: 'md', md: 'h4' }} c={colors['white-1']}>{state.findUnique.data.alamat}</Text>
</BackgroundImage>
<Grid
py={20}>
<GridCol span={{ base: 12, md: 6 }}>
<Box>
<Stack>
<Title order={3}>Informasi</Title>
<Box>
<Text>Alamat: {state.findUnique.data.alamat}</Text>
<Text>Telepon: {state.findUnique.data.kontak.kontakPuskesmas}</Text>
<Text>Email: {state.findUnique.data.kontak.email}</Text>
</Box>
<Title order={3}>Jam Operasional</Title>
<Box>
<Text pb={10} fz={'h4'} fw={"bold"}>
Senin - Kamis: <Text span fz={'h4'}>{state.findUnique.data?.jam.workDays} - {state.findUnique.data?.jam.weekDays}</Text>
</Text>
</Box>
</Stack>
</Box>
</GridCol>
<GridCol span={{ base: 12, md: 6 }}>
<Box>
<Paper p={"xl"} bg={'#B1C5F2'}>
<SimpleGrid
cols={{
base: 1,
md: 2
}}>
<Paper p={"xl"} bg={colors['white-trans-1']}>
<Text fw={"bold"} fz={'h3'} ta={'center'}>Poliklinik Umum</Text>
<Text ta={'center'} fz={{ base: 45, md: 65 }} fw={'bold'} c={colors['blue-button']}>26</Text>
</Paper>
<Paper p={"xl"} bg={colors['white-trans-1']}>
<Text ta={'center'} fz={'h3'} fw={"bold"}>Poli Gigi</Text>
<Text ta={'center'} fz={{ base: 45, md: 65 }} fw={'bold'} c={colors['blue-button']}>26</Text>
</Paper>
</SimpleGrid>
</Paper>
</Box>
</GridCol>
<Box>
</Box>
</Grid>
</Box>
</Paper>
</Box>
</Stack>
</Stack>
);
}
export default Page;

View File

@@ -1,125 +1,97 @@
'use client'
import puskesmasState from '@/app/admin/(dashboard)/_state/kesehatan/puskesmas/puskesmas';
import colors from '@/con/colors';
import { Stack, Box, Paper, Text, BackgroundImage, SimpleGrid, Title, Flex } from '@mantine/core';
import React from 'react';
import { Anchor, Box, Center, Grid, GridCol, Image, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { IconSearch } from '@tabler/icons-react';
import { useState } from 'react';
import { useProxy } from 'valtio/utils';
import BackButton from '../../desa/layanan/_com/BackButto';
function Page() {
const state = useProxy(puskesmasState)
const [search, setSearch] = useState('')
const {
data,
page,
totalPages,
loading,
load,
} = state.findMany;
useShallowEffect(() => {
load(page, 3, search)
}, [page, search])
if (loading || !data) {
return (
<Box py={10}>
<Skeleton h={500} />
</Box>
)
}
return (
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
<Box px={{ base: 'md', md: 100 }}>
<BackButton />
</Box>
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
Puskesmas Darmasaba
</Text>
<Grid align='center' px={{ base: 'md', md: 100 }}>
<GridCol span={{ base: 12, md: 9 }}>
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
Puskesmas Darmasaba
</Text>
</GridCol>
<GridCol span={{ base: 12, md: 3 }}>
<TextInput
radius={"lg"}
placeholder='Cari Puskesmas'
value={search}
onChange={(e) => setSearch(e.target.value)}
leftSection={<IconSearch size={20} />}
w={{ base: "50%", md: "100%" }}
/>
</GridCol>
</Grid>
<Box px={{ base: "md", md: 100 }}>
<Stack gap={'lg'}>
<Box>
<Paper p={"xl"} bg={colors['white-trans-1']}>
<Box pb={30}>
<BackgroundImage
pb={30}
radius={16}
h={{ base: 250, md: 500 }}
src='/api/img/posyandu.png'
style={{ position: 'relative' }}
>
<Box
style={{
borderRadius: 16,
zIndex: 0
}}
pos={"absolute"}
w={"100%"}
h={"100%"}
bg={colors.trans.dark[2]}
<SimpleGrid
cols={{
base: 1,
md: 3,
}}
>
{data.map((v, k) => {
return (
<Paper p={"xl"} bg={colors['white-trans-1']} key={k}>
<Stack gap={"xs"}>
<Text fw={"bold"} fz={"h3"}>{v.name}</Text>
<Image
src={v.image.link}
alt={v.name}
/>
<Text style={{
position: 'absolute',
bottom: 35,
left: 15,
}} fw={'bold'} fz={{ base: 'md', md: 'h3' }} c={colors['white-1']}>Puskesmas Darmasaba</Text>
<Text style={{
position: 'absolute',
bottom: 10,
left: 15,
}} fw={'bold'} fz={{ base: 'md', md: 'h4' }} c={colors['white-1']}>Jl. Raya Darmasaba No.45, Badung, Bali</Text>
</BackgroundImage>
<SimpleGrid
py={20}
cols={{
base: 1,
md: 2
}}>
<Box>
<Stack>
<Title order={3}>Jam Operasional</Title>
<Box>
<Flex justify={'space-between'} align={'center'}>
<Box>
<Text>Senin - Kamis</Text>
<Text>Jumat</Text>
<Text>Sabtu</Text>
<Text> Minggu & Libur</Text>
</Box>
<Box>
<Text>08:00 - 15:00 WITA</Text>
<Text>08:00 - 15:00 WITA</Text>
<Text>08:00 - 15:00 WITA</Text>
<Text>Tutp (UGD 24 JAM)</Text>
</Box>
</Flex>
</Box>
</Stack>
<Text>Alamat: {v.alamat}</Text>
<Text>Telepon: {v.kontak.kontakPuskesmas}</Text>
<Text>Email: {v.kontak.email}</Text>
</Box>
<Box>
<Stack>
<Title order={3}>Jam Operasional</Title>
<Box>
<Flex justify={'space-between'} align={'center'}>
<Box>
<Text>Senin - Kamis</Text>
<Text>Jumat</Text>
<Text>Sabtu</Text>
<Text> Minggu & Libur</Text>
</Box>
<Box>
<Text>08:00 - 15:00 WITA</Text>
<Text>08:00 - 15:00 WITA</Text>
<Text>08:00 - 15:00 WITA</Text>
<Text>Tutp (UGD 24 JAM)</Text>
</Box>
</Flex>
</Box>
</Stack>
</Box>
<Box>
</Box>
</SimpleGrid>
</Box>
<Box>
<Paper p={"xl"} bg={'#B1C5F2'}>
<SimpleGrid
cols={{
base: 1,
md: 2
}}>
<Paper p={"xl"} bg={colors['white-trans-1']}>
<Text fw={"bold"} fz={'h3'} ta={'center'}>Poliklinik Umum</Text>
<Text ta={'center'} fz={{ base: 45, md: 65 }} fw={'bold'} c={colors['blue-button']}>26</Text>
</Paper>
<Paper p={"xl"} bg={colors['white-trans-1']}>
<Text ta={'center'} fz={'h3'} fw={"bold"}>Poli Gigi</Text>
<Text ta={'center'} fz={{ base: 45, md: 65 }} fw={'bold'} c={colors['blue-button']}>26</Text>
</Paper>
</SimpleGrid>
</Paper>
</Box>
</Paper>
</Box>
</Stack>
<Anchor c={colors['blue-button']} href={`/darmasaba/kesehatan/puskesmas/${v.id}`}>Lihat Detail &gt;</Anchor>
</Stack>
</Paper>
)
})}
</SimpleGrid>
</Box>
<Center>
<Pagination
value={page}
onChange={(newPage) => load(newPage)} // ini penting!
total={totalPages}
mt="md"
mb="md"
/>
</Center>
</Stack>
);
}