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,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import ApiFetch from "@/lib/api-fetch";
import { Prisma } from "@prisma/client";
import { toast } from "react-toastify";
@@ -20,17 +21,43 @@ const defaultForm = {
const programKesehatan = proxy({
findMany: {
data: [] as Prisma.ProgramKesehatanGetPayload<{
data: null as
| Prisma.ProgramKesehatanGetPayload<{
include: {
image: true;
};
}>[],
async load() {
}>[]
| null,
page: 1,
totalPages: 1,
loading: false,
search: "",
load: async (page = 1, limit = 10, search = "") => {
programKesehatan.findMany.loading = true; // ✅ Akses langsung via nama path
programKesehatan.findMany.page = page;
programKesehatan.findMany.search = search;
try {
const query: any = { page, limit };
if (search) query.search = search;
const res = await ApiFetch.api.kesehatan.programkesehatan[
"find-many"
].get();
if (res.status === 200) {
programKesehatan.findMany.data = res.data?.data ?? [];
].get({ query });
if (res.status === 200 && res.data?.success) {
programKesehatan.findMany.data = res.data.data ?? [];
programKesehatan.findMany.totalPages = res.data.totalPages ?? 1;
} else {
programKesehatan.findMany.data = [];
programKesehatan.findMany.totalPages = 1;
}
} catch (err) {
console.error("Gagal fetch berita paginated:", err);
programKesehatan.findMany.data = [];
programKesehatan.findMany.totalPages = 1;
} finally {
programKesehatan.findMany.loading = false;
}
},
},
@@ -97,12 +124,15 @@ const programKesehatan = proxy({
try {
programKesehatan.delete.loading = true;
const response = await fetch(`/api/kesehatan/programkesehatan/del/${id}`, {
const response = await fetch(
`/api/kesehatan/programkesehatan/del/${id}`,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
});
}
);
const result = await response.json();
if (response.ok && result?.success) {
@@ -156,7 +186,9 @@ const programKesehatan = proxy({
}
} catch (error) {
console.error("Error fetching program kesehatan:", error);
toast.error(error instanceof Error ? error.message : "Gagal memuat data");
toast.error(
error instanceof Error ? error.message : "Gagal memuat data"
);
return null;
}
},
@@ -172,7 +204,9 @@ const programKesehatan = proxy({
try {
programKesehatan.edit.loading = true;
const response = await fetch(`/api/kesehatan/programkesehatan/${this.id}`, {
const response = await fetch(
`/api/kesehatan/programkesehatan/${this.id}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
@@ -183,14 +217,19 @@ const programKesehatan = proxy({
deskripsi: this.form.deskripsi,
imageId: this.form.imageId,
}),
});
}
);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
throw new Error(
errorData.message || `HTTP error! status: ${response.status}`
);
}
const result = await response.json();
if (result.success) {
toast.success(result.message || "Program kesehatan berhasil diupdate");
toast.success(
result.message || "Program kesehatan berhasil diupdate"
);
await programKesehatan.findMany.load();
return true;
} else {
@@ -198,7 +237,11 @@ const programKesehatan = proxy({
}
} catch (error) {
console.error("Gagal update:", error);
toast.error(error instanceof Error ? error.message : "Terjadi kesalahan saat mengupdate program kesehatan");
toast.error(
error instanceof Error
? error.message
: "Terjadi kesalahan saat mengupdate program kesehatan"
);
return false;
} finally {
programKesehatan.edit.loading = false;

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import ApiFetch from "@/lib/api-fetch";
import { Prisma } from "@prisma/client";
import { toast } from "react-toastify";
@@ -163,13 +164,43 @@ const puskesmasState = proxy({
},
findMany: {
data: null as Prisma.PuskesmasGetPayload<{
include: { image: true; jam: true; kontak: true };
}>[] | null,
async load() {
const res = await ApiFetch.api.kesehatan.puskesmas["find-many"].get();
if (res.status === 200) {
puskesmasState.findMany.data = res.data?.data ?? [];
data: null as
| Prisma.PuskesmasGetPayload<{
include: {
image: true;
jam: true;
kontak: true;
};
}>[]
| null,
page: 1,
totalPages: 1,
loading: false,
search: "",
load: async (page = 1, limit = 10, search = "") => {
puskesmasState.findMany.loading = true; // ✅ Akses langsung via nama path
puskesmasState.findMany.page = page;
puskesmasState.findMany.search = search;
try {
const query: any = { page, limit };
if (search) query.search = search;
const res = await ApiFetch.api.kesehatan.puskesmas["find-many"].get({ query });
if (res.status === 200 && res.data?.success) {
puskesmasState.findMany.data = res.data.data ?? [];
puskesmasState.findMany.totalPages = res.data.totalPages ?? 1;
} else {
puskesmasState.findMany.data = [];
puskesmasState.findMany.totalPages = 1;
}
} catch (err) {
console.error("Gagal fetch berita paginated:", err);
puskesmasState.findMany.data = [];
puskesmasState.findMany.totalPages = 1;
} finally {
puskesmasState.findMany.loading = false;
}
},
},

View File

@@ -1,6 +1,6 @@
'use client'
import colors from '@/con/colors';
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
import { Box, Button, Center, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
import JudulList from '../../_com/judulList';
import HeaderSearch from '../../_com/header';
@@ -30,19 +30,21 @@ function ListProgramKesehatan({ search }: { search: string }) {
const programKesehatanState = useProxy(programKesehatan)
const router = useRouter()
const {
data,
page,
totalPages,
loading,
load,
} = programKesehatanState.findMany;
useShallowEffect(() => {
programKesehatanState.findMany.load()
}, [])
load(page, 3, search)
}, [page, search])
const filteredData = (programKesehatanState.findMany.data || []).filter(item => {
const keyword = search.toLowerCase();
return (
item.name.toLowerCase().includes(keyword) ||
item.deskripsiSingkat.toLowerCase().includes(keyword)
);
});
const filteredData = data || []
if (!programKesehatanState.findMany.data) {
if (loading || !data) {
return (
<Box py={10}>
<Skeleton h={500} />
@@ -77,7 +79,9 @@ function ListProgramKesehatan({ search }: { search: string }) {
</Box>
</TableTd>
<TableTd>
<Box w={100}>
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsiSingkat }} />
</Box>
</TableTd>
<TableTd>
<Image w={100} src={item.image?.link} alt="image" />
@@ -94,6 +98,15 @@ function ListProgramKesehatan({ search }: { search: string }) {
</Box>
</Stack>
</Paper>
<Center>
<Pagination
value={page}
onChange={(newPage) => load(newPage)} // ini penting!
total={totalPages}
mt="md"
mb="md"
/>
</Center>
</Box>
)
}

View File

@@ -1,6 +1,6 @@
'use client'
import colors from '@/con/colors';
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
import { Box, Button, Center, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
@@ -30,19 +30,21 @@ function ListPuskesmas({ search }: { search: string }) {
const statePuskesmas = useProxy(puskesmasState)
const router = useRouter();
const {
data,
page,
totalPages,
loading,
load,
} = statePuskesmas.findMany;
useShallowEffect(() => {
statePuskesmas.findMany.load()
}, [])
load(page, 3, search)
}, [page, search])
const filteredData = (statePuskesmas.findMany.data || []).filter(item => {
const keyword = search.toLowerCase();
return (
item.name.toLowerCase().includes(keyword) ||
item.alamat.toLowerCase().includes(keyword)
);
});
const filteredData = data || []
if (!statePuskesmas.findMany.data) {
if (loading || !data) {
return (
<Box py={10}>
<Skeleton h={500} />
@@ -87,6 +89,15 @@ function ListPuskesmas({ search }: { search: string }) {
</Box>
</Stack>
</Paper>
<Center>
<Pagination
value={page}
onChange={(newPage) => load(newPage)} // ini penting!
total={totalPages}
mt="md"
mb="md"
/>
</Center>
</Box>
)
}

View File

@@ -1,25 +1,56 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// /api/berita/findManyPaginated.ts
import prisma from "@/lib/prisma";
import { Context } from "elysia";
async function programKesehatanFindMany(context: Context) {
// Ambil parameter dari query
const page = Number(context.query.page) || 1;
const limit = Number(context.query.limit) || 10;
const search = (context.query.search as string) || '';
const skip = (page - 1) * limit;
// Buat where clause
const where: any = { isActive: true };
// Tambahkan pencarian (jika ada)
if (search) {
where.OR = [
{ name: { contains: search, mode: 'insensitive' } }
];
}
export default async function programKesehatanFindMany() {
try {
const data = await prisma.programKesehatan.findMany({
where: {
isActive: true,
},
// Ambil data dan total count secara paralel
const [data, total] = await Promise.all([
prisma.programKesehatan.findMany({
where,
include: {
image: true,
}
})
},
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.programKesehatan.count({ where }),
]);
return {
success: true,
message: "Success fetch program kesehatan",
message: "Berhasil ambil program kesehatan dengan pagination",
data,
}
} catch (error) {
console.error("Find many error:", error);
page,
limit,
total,
totalPages: Math.ceil(total / limit),
};
} catch (e) {
console.error("Error di findMany paginated:", e);
return {
success: false,
message: "Failed fetch program kesehatan",
}
message: "Gagal mengambil data program kesehatan",
};
}
}
export default programKesehatanFindMany;

View File

@@ -1,27 +1,59 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
// /api/berita/findManyPaginated.ts
import prisma from "@/lib/prisma";
import { Context } from "elysia";
async function puskesmasFindMany(context: Context) {
// Ambil parameter dari query
const page = Number(context.query.page) || 1;
const limit = Number(context.query.limit) || 10;
const search = (context.query.search as string) || '';
const skip = (page - 1) * limit;
// Buat where clause
const where: any = { isActive: true };
// Tambahkan pencarian (jika ada)
if (search) {
where.OR = [
{ name: { contains: search, mode: 'insensitive' } },
{ alamat: { contains: search, mode: 'insensitive' } },
];
}
export default async function puskesmasFindMany() {
try {
const data = await prisma.puskesmas.findMany({
where: {
isActive: true,
},
// Ambil data dan total count secara paralel
const [data, total] = await Promise.all([
prisma.puskesmas.findMany({
where,
include: {
image: true,
jam: true,
kontak: true,
}
})
},
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.puskesmas.count({ where }),
]);
return {
success: true,
message: "Success fetch puskesmas",
message: "Berhasil ambil puskesmas dengan pagination",
data,
}
} catch (error) {
console.error("Find many error:", error);
page,
limit,
total,
totalPages: Math.ceil(total / limit),
};
} catch (e) {
console.error("Error di findMany paginated:", e);
return {
success: false,
message: "Failed fetch puskesmas",
}
message: "Gagal mengambil data berita",
};
}
}
export default puskesmasFindMany;

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"}>
<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>
<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>
</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"}>
<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>
<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]}
</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%" }}
/>
<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>
</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'}>
</GridCol>
</Grid>
<Box px={{ base: "md", md: 100 }}>
<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>
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}
/>
<Box>
<Text>Alamat: {v.alamat}</Text>
<Text>Telepon: {v.kontak.kontakPuskesmas}</Text>
<Text>Email: {v.kontak.email}</Text>
</Box>
<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>
);
}