Fix Admin Submenu Posyandu, Menu Kesehatan, dan Sinkronisasi UI & API Admin - User Submenu Posyandu
This commit is contained in:
@@ -1027,16 +1027,17 @@ model DoctorSign {
|
|||||||
|
|
||||||
// ========================================= POSYANDU ========================================= //
|
// ========================================= POSYANDU ========================================= //
|
||||||
model Posyandu {
|
model Posyandu {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
nomor String
|
nomor String
|
||||||
deskripsi String
|
deskripsi String
|
||||||
image FileStorage @relation(fields: [imageId], references: [id])
|
jadwalPelayanan String
|
||||||
imageId String
|
image FileStorage @relation(fields: [imageId], references: [id])
|
||||||
createdAt DateTime @default(now())
|
imageId String
|
||||||
updatedAt DateTime @updatedAt
|
createdAt DateTime @default(now())
|
||||||
deletedAt DateTime @default(now())
|
updatedAt DateTime @updatedAt
|
||||||
isActive Boolean @default(true)
|
deletedAt DateTime @default(now())
|
||||||
|
isActive Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================= PUSKESMAS ========================================= //
|
// ========================================= PUSKESMAS ========================================= //
|
||||||
|
|||||||
@@ -125,8 +125,8 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
}
|
}
|
||||||
console.log("penghargaan success ...");
|
console.log("penghargaan success ...");
|
||||||
|
|
||||||
// =========== LAYANAN DESA ===========
|
// =========== LAYANAN DESA ===========
|
||||||
for (const p of pelayananSuratKeterangan) {
|
for (const p of pelayananSuratKeterangan) {
|
||||||
await prisma.pelayananSuratKeterangan.upsert({
|
await prisma.pelayananSuratKeterangan.upsert({
|
||||||
where: { id: p.id },
|
where: { id: p.id },
|
||||||
update: {
|
update: {
|
||||||
@@ -317,63 +317,42 @@ import pelayananTelunjukSaktiDesa from "./data/desa/layanan/pelayananTelunjukSak
|
|||||||
|
|
||||||
console.log("visi misi desa success ...");
|
console.log("visi misi desa success ...");
|
||||||
|
|
||||||
// Flatten the nested array structure for posisiOrganisasiPPID
|
const flattenedPosisi = posisiOrganisasiPPID.flat();
|
||||||
const flattenedPosisiOrganisasiPPID = posisiOrganisasiPPID.flat();
|
|
||||||
|
// ✅ Urutkan berdasarkan hierarki
|
||||||
|
const sortedPosisi = flattenedPosisi.sort((a, b) => a.hierarki - b.hierarki);
|
||||||
|
|
||||||
|
for (const p of sortedPosisi) {
|
||||||
|
console.log(`Seeding: ${p.nama} (id: ${p.id}, parent: ${p.parentId})`);
|
||||||
|
|
||||||
|
if (p.parentId) {
|
||||||
|
const parentExists = flattenedPosisi.some((pos) => pos.id === p.parentId);
|
||||||
|
if (!parentExists) {
|
||||||
|
console.warn(
|
||||||
|
`⚠️ Parent tidak ditemukan: ${p.parentId} untuk ${p.nama}`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const p of flattenedPosisiOrganisasiPPID) {
|
|
||||||
await prisma.posisiOrganisasiPPID.upsert({
|
await prisma.posisiOrganisasiPPID.upsert({
|
||||||
where: {
|
where: { id: p.id },
|
||||||
id: p.id,
|
update: p,
|
||||||
},
|
create: p,
|
||||||
update: {
|
|
||||||
nama: p.nama,
|
|
||||||
deskripsi: p.deskripsi,
|
|
||||||
hierarki: p.hierarki,
|
|
||||||
parentId: p.parentId,
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
id: p.id,
|
|
||||||
nama: p.nama,
|
|
||||||
deskripsi: p.deskripsi,
|
|
||||||
hierarki: p.hierarki,
|
|
||||||
parentId: p.parentId,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("posisi organisasi success ...");
|
console.log("✅ Posisi organisasi berhasil");
|
||||||
|
|
||||||
// Flatten the nested array structure for pegawaiPPID
|
// 2. Seed Pegawai
|
||||||
const flattenedPegawaiPPID = pegawaiPPID.flat();
|
const flattenedPegawai = pegawaiPPID.flat();
|
||||||
|
for (const p of flattenedPegawai) {
|
||||||
for (const p of flattenedPegawaiPPID) {
|
|
||||||
await prisma.pegawaiPPID.upsert({
|
await prisma.pegawaiPPID.upsert({
|
||||||
where: {
|
where: { id: p.id },
|
||||||
id: p.id,
|
update: p,
|
||||||
},
|
create: p,
|
||||||
update: {
|
|
||||||
namaLengkap: p.namaLengkap,
|
|
||||||
tanggalMasuk: new Date(p.tanggalMasuk),
|
|
||||||
email: p.email,
|
|
||||||
gelarAkademik: p.gelarAkademik,
|
|
||||||
telepon: p.telepon,
|
|
||||||
alamat: p.alamat,
|
|
||||||
posisiId: p.posisiId,
|
|
||||||
isActive: p.isActive,
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
id: p.id,
|
|
||||||
namaLengkap: p.namaLengkap,
|
|
||||||
tanggalMasuk: new Date(p.tanggalMasuk),
|
|
||||||
email: p.email,
|
|
||||||
gelarAkademik: p.gelarAkademik,
|
|
||||||
telepon: p.telepon,
|
|
||||||
alamat: p.alamat,
|
|
||||||
posisiId: p.posisiId,
|
|
||||||
isActive: p.isActive,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("pegawai success ...");
|
console.log("✅ Pegawai berhasil");
|
||||||
|
|
||||||
for (const l of pelayananPerizinanBerusaha) {
|
for (const l of pelayananPerizinanBerusaha) {
|
||||||
await prisma.pelayananPerizinanBerusaha.upsert({
|
await prisma.pelayananPerizinanBerusaha.upsert({
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import ApiFetch from "@/lib/api-fetch";
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@@ -9,6 +10,7 @@ const templateForm = z.object({
|
|||||||
nomor: z.string().min(1, { message: "Nomor is required" }),
|
nomor: z.string().min(1, { message: "Nomor is required" }),
|
||||||
deskripsi: z.string().min(1, { message: "Deskripsi is required" }),
|
deskripsi: z.string().min(1, { message: "Deskripsi is required" }),
|
||||||
imageId: z.string().nonempty(),
|
imageId: z.string().nonempty(),
|
||||||
|
jadwalPelayanan: z.string().min(1, { message: "Jadwal Pelayanan is required" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultForm = {
|
const defaultForm = {
|
||||||
@@ -16,6 +18,7 @@ const defaultForm = {
|
|||||||
nomor: "",
|
nomor: "",
|
||||||
deskripsi: "",
|
deskripsi: "",
|
||||||
imageId: "",
|
imageId: "",
|
||||||
|
jadwalPelayanan: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
const posyandustate = proxy({
|
const posyandustate = proxy({
|
||||||
@@ -51,18 +54,42 @@ const posyandustate = proxy({
|
|||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.PosyanduGetPayload<{
|
| Prisma.PosyanduGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
image: true;
|
image: true;
|
||||||
|
};
|
||||||
|
}>[]
|
||||||
|
| null,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
loading: false,
|
||||||
|
search: "",
|
||||||
|
load: async (page = 1, limit = 10, search = "") => {
|
||||||
|
posyandustate.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||||
|
posyandustate.findMany.page = page;
|
||||||
|
posyandustate.findMany.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = { page, limit };
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.kesehatan.posyandu["find-many"].get({ query });
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
posyandustate.findMany.data = res.data.data ?? [];
|
||||||
|
posyandustate.findMany.totalPages = res.data.totalPages ?? 1;
|
||||||
|
} else {
|
||||||
|
posyandustate.findMany.data = [];
|
||||||
|
posyandustate.findMany.totalPages = 1;
|
||||||
}
|
}
|
||||||
}>[]
|
} catch (err) {
|
||||||
| null,
|
console.error("Gagal fetch posyandu paginated:", err);
|
||||||
async load() {
|
posyandustate.findMany.data = [];
|
||||||
const res = await ApiFetch.api.kesehatan.posyandu["find-many"].get();
|
posyandustate.findMany.totalPages = 1;
|
||||||
if (res.status === 200) {
|
} finally {
|
||||||
posyandustate.findMany.data = res.data?.data ?? [];
|
posyandustate.findMany.loading = false;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as
|
data: null as
|
||||||
@@ -148,6 +175,7 @@ const posyandustate = proxy({
|
|||||||
nomor: data.nomor,
|
nomor: data.nomor,
|
||||||
deskripsi: data.deskripsi,
|
deskripsi: data.deskripsi,
|
||||||
imageId: data.imageId || "",
|
imageId: data.imageId || "",
|
||||||
|
jadwalPelayanan: data.jadwalPelayanan || "",
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
@@ -181,6 +209,7 @@ const posyandustate = proxy({
|
|||||||
nomor: this.form.nomor,
|
nomor: this.form.nomor,
|
||||||
deskripsi: this.form.deskripsi,
|
deskripsi: this.form.deskripsi,
|
||||||
imageId: this.form.imageId,
|
imageId: this.form.imageId,
|
||||||
|
jadwalPelayanan: this.form.jadwalPelayanan,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ function EditPosyandu() {
|
|||||||
nomor: statePosyandu.edit.form.nomor || '',
|
nomor: statePosyandu.edit.form.nomor || '',
|
||||||
deskripsi: statePosyandu.edit.form.deskripsi || '',
|
deskripsi: statePosyandu.edit.form.deskripsi || '',
|
||||||
imageId: statePosyandu.edit.form.imageId || '',
|
imageId: statePosyandu.edit.form.imageId || '',
|
||||||
|
jadwalPelayanan: statePosyandu.edit.form.jadwalPelayanan || '',
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -40,6 +41,7 @@ function EditPosyandu() {
|
|||||||
nomor: data.nomor || '',
|
nomor: data.nomor || '',
|
||||||
deskripsi: data.deskripsi || '',
|
deskripsi: data.deskripsi || '',
|
||||||
imageId: data.imageId || '',
|
imageId: data.imageId || '',
|
||||||
|
jadwalPelayanan: data.jadwalPelayanan || '',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (data?.image?.link) {
|
if (data?.image?.link) {
|
||||||
@@ -62,6 +64,7 @@ function EditPosyandu() {
|
|||||||
nomor: formData.nomor,
|
nomor: formData.nomor,
|
||||||
deskripsi: formData.deskripsi,
|
deskripsi: formData.deskripsi,
|
||||||
imageId: formData.imageId,
|
imageId: formData.imageId,
|
||||||
|
jadwalPelayanan: formData.jadwalPelayanan,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
@@ -173,6 +176,16 @@ function EditPosyandu() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fw={"bold"} fz={"sm"}>Jadwal Pelayanan</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={formData.jadwalPelayanan}
|
||||||
|
onChange={(htmlContent) => {
|
||||||
|
setFormData({ ...formData, jadwalPelayanan: htmlContent });
|
||||||
|
statePosyandu.edit.form.jadwalPelayanan = htmlContent;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
<Group>
|
<Group>
|
||||||
<Button onClick={handleSubmit} bg={colors['blue-button']}>Submit</Button>
|
<Button onClick={handleSubmit} bg={colors['blue-button']}>Submit</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ function DetailPosyandu() {
|
|||||||
<Text fz={"lg"} fw={"bold"}>Deskripsi Posyandu</Text>
|
<Text fz={"lg"} fw={"bold"}>Deskripsi Posyandu</Text>
|
||||||
<Text fz={"lg"} dangerouslySetInnerHTML={{ __html: statePosyandu.findUnique.data.deskripsi }} />
|
<Text fz={"lg"} dangerouslySetInnerHTML={{ __html: statePosyandu.findUnique.data.deskripsi }} />
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"lg"} fw={"bold"}>Jadwal Pelayanan</Text>
|
||||||
|
<Text fz={"lg"} dangerouslySetInnerHTML={{ __html: statePosyandu.findUnique.data.jadwalPelayanan }} />
|
||||||
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz={"lg"} fw={"bold"}>Gambar</Text>
|
<Text fz={"lg"} fw={"bold"}>Gambar</Text>
|
||||||
<Image src={statePosyandu.findUnique.data.image?.link} alt="gambar" />
|
<Image src={statePosyandu.findUnique.data.image?.link} alt="gambar" />
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ function CreatePosyandu() {
|
|||||||
nomor: "",
|
nomor: "",
|
||||||
deskripsi: "",
|
deskripsi: "",
|
||||||
imageId: "",
|
imageId: "",
|
||||||
|
jadwalPelayanan: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
setFile(null);
|
setFile(null);
|
||||||
@@ -147,6 +148,15 @@ function CreatePosyandu() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fw={"bold"} fz={"sm"}>Jadwal Pelayanan</Text>
|
||||||
|
<CreateEditor
|
||||||
|
value={statePosyandu.create.form.jadwalPelayanan}
|
||||||
|
onChange={(htmlContent) => {
|
||||||
|
statePosyandu.create.form.jadwalPelayanan = htmlContent;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
<Group>
|
<Group>
|
||||||
<Button onClick={handleSubmit} bg={colors['blue-button']}>Submit</Button>
|
<Button onClick={handleSubmit} bg={colors['blue-button']}>Submit</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Paper, Skeleton, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
import { Box, Button, Center, Pagination, Paper, Skeleton, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import HeaderSearch from '../../_com/header';
|
import HeaderSearch from '../../_com/header';
|
||||||
import JudulList from '../../_com/judulList';
|
import JudulList from '../../_com/judulList';
|
||||||
@@ -30,19 +30,21 @@ function ListPosyandu({ search }: { search: string }) {
|
|||||||
const statePosyandu = useProxy(posyandustate)
|
const statePosyandu = useProxy(posyandustate)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
loading,
|
||||||
|
load,
|
||||||
|
} = statePosyandu.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
statePosyandu.findMany.load()
|
load(page, 10, search)
|
||||||
}, [])
|
}, [page, search])
|
||||||
|
|
||||||
const filteredData = (statePosyandu.findMany.data || []).filter(item => {
|
const filteredData = data || [];
|
||||||
const keyword = search.toLowerCase();
|
|
||||||
return (
|
|
||||||
item.name.toLowerCase().includes(keyword) ||
|
|
||||||
item.nomor.toString().toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!statePosyandu.findMany.data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={10}>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
@@ -70,10 +72,20 @@ function ListPosyandu({ search }: { search: string }) {
|
|||||||
<TableTbody>
|
<TableTbody>
|
||||||
{filteredData.map((item) => (
|
{filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>{item.name}</TableTd>
|
|
||||||
<TableTd>{item.nomor}</TableTd>
|
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
<Box w={100}>
|
||||||
|
<Text truncate="end" lineClamp={1} fz={"sm"}>{item.name}</Text>
|
||||||
|
</Box>
|
||||||
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Box w={100}>
|
||||||
|
<Text truncate="end" lineClamp={1} fz={"sm"}>{item.nomor}</Text>
|
||||||
|
</Box>
|
||||||
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Box w={100}>
|
||||||
|
<Text truncate="end" lineClamp={1} fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||||
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Button onClick={() => router.push(`/admin/kesehatan/posyandu/${item.id}`)}>
|
<Button onClick={() => router.push(`/admin/kesehatan/posyandu/${item.id}`)}>
|
||||||
@@ -86,6 +98,15 @@ function ListPosyandu({ search }: { search: string }) {
|
|||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)} // ini penting!
|
||||||
|
total={totalPages}
|
||||||
|
mt="md"
|
||||||
|
mb="md"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ type FormCreate = Prisma.PosyanduGetPayload<{
|
|||||||
nomor: true;
|
nomor: true;
|
||||||
deskripsi: true;
|
deskripsi: true;
|
||||||
imageId: true;
|
imageId: true;
|
||||||
|
jadwalPelayanan: true;
|
||||||
};
|
};
|
||||||
}>;
|
}>;
|
||||||
export default async function posyanduCreate(context: Context) {
|
export default async function posyanduCreate(context: Context) {
|
||||||
@@ -19,6 +20,7 @@ export default async function posyanduCreate(context: Context) {
|
|||||||
nomor: body.nomor,
|
nomor: body.nomor,
|
||||||
deskripsi: body.deskripsi,
|
deskripsi: body.deskripsi,
|
||||||
imageId: body.imageId,
|
imageId: body.imageId,
|
||||||
|
jadwalPelayanan: body.jadwalPelayanan,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,26 +1,59 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
// /api/berita/findManyPaginated.ts
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
export default async function posyanduFindMany() {
|
async function posyanduFindMany(context: Context) {
|
||||||
try {
|
// Ambil parameter dari query
|
||||||
const data = await prisma.posyandu.findMany({
|
const page = Number(context.query.page) || 1;
|
||||||
where: {
|
const limit = Number(context.query.limit) || 10;
|
||||||
isActive: true,
|
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' } },
|
||||||
|
{ deskripsi: { contains: search, mode: 'insensitive' } },
|
||||||
|
{ nomor: { contains: search, mode: 'insensitive' } },
|
||||||
|
{ jadwalPelayanan: { contains: search, mode: 'insensitive' } }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Ambil data dan total count secara paralel
|
||||||
|
const [data, total] = await Promise.all([
|
||||||
|
prisma.posyandu.findMany({
|
||||||
|
where,
|
||||||
include: {
|
include: {
|
||||||
image: true,
|
image: true,
|
||||||
}
|
},
|
||||||
})
|
skip,
|
||||||
|
take: limit,
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
}),
|
||||||
|
prisma.posyandu.count({ where }),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Success fetch posyandu",
|
message: "Berhasil ambil posyandu dengan pagination",
|
||||||
data,
|
data,
|
||||||
}
|
page,
|
||||||
} catch (error) {
|
limit,
|
||||||
console.error("Find many error:", error);
|
total,
|
||||||
|
totalPages: Math.ceil(total / limit),
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error di posyanduFindMany paginated:", e);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "Failed fetch posyandu",
|
message: "Gagal mengambil data posyandu",
|
||||||
}
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
export default posyanduFindMany;
|
||||||
@@ -15,6 +15,7 @@ const Posyandu = new Elysia({
|
|||||||
nomor: t.String(),
|
nomor: t.String(),
|
||||||
deskripsi: t.String(),
|
deskripsi: t.String(),
|
||||||
imageId: t.String(),
|
imageId: t.String(),
|
||||||
|
jadwalPelayanan: t.String(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.get("/find-many", posyanduFindMany)
|
.get("/find-many", posyanduFindMany)
|
||||||
@@ -35,6 +36,7 @@ const Posyandu = new Elysia({
|
|||||||
nomor: t.String(),
|
nomor: t.String(),
|
||||||
deskripsi: t.String(),
|
deskripsi: t.String(),
|
||||||
imageId: t.String(),
|
imageId: t.String(),
|
||||||
|
jadwalPelayanan: t.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ type FormUpdate = Prisma.PosyanduGetPayload<{
|
|||||||
nomor: true;
|
nomor: true;
|
||||||
deskripsi: true;
|
deskripsi: true;
|
||||||
imageId: true;
|
imageId: true;
|
||||||
|
jadwalPelayanan: true;
|
||||||
}
|
}
|
||||||
}>
|
}>
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ export default async function posyanduUpdate(context: Context) {
|
|||||||
nomor,
|
nomor,
|
||||||
deskripsi,
|
deskripsi,
|
||||||
imageId,
|
imageId,
|
||||||
|
jadwalPelayanan,
|
||||||
} = body;
|
} = body;
|
||||||
|
|
||||||
if(!id) {
|
if(!id) {
|
||||||
@@ -79,6 +81,7 @@ export default async function posyanduUpdate(context: Context) {
|
|||||||
nomor,
|
nomor,
|
||||||
deskripsi,
|
deskripsi,
|
||||||
imageId,
|
imageId,
|
||||||
|
jadwalPelayanan,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +1,58 @@
|
|||||||
|
'use client'
|
||||||
import colors from "@/con/colors";
|
import colors from "@/con/colors";
|
||||||
import { Stack, Box, Text, SimpleGrid, Paper, Center, Image, Flex, List, ListItem } from "@mantine/core";
|
import { Box, Center, Flex, Image, List, ListItem, Pagination, Paper, SimpleGrid, Skeleton, Spoiler, Stack, Text, TextInput } from "@mantine/core";
|
||||||
import BackButton from "../../desa/layanan/_com/BackButto";
|
import BackButton from "../../desa/layanan/_com/BackButto";
|
||||||
|
// import { useTransitionRouter } from "next-view-transitions";
|
||||||
|
import posyandustate from "@/app/admin/(dashboard)/_state/kesehatan/posyandu/posyandu";
|
||||||
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
|
import { useProxy } from "valtio/utils";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { IconSearch } from "@tabler/icons-react";
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
judul: 'Posyandu Banjar Bucu',
|
|
||||||
nomor: '082345678910',
|
|
||||||
image: '/api/img/posyandu.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
judul: 'Posyandu Banjar Bucu',
|
|
||||||
nomor: '082345678910',
|
|
||||||
image: '/api/img/posyandu.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
judul: 'Posyandu Banjar Bucu',
|
|
||||||
nomor: '082345678910',
|
|
||||||
image: '/api/img/posyandu.png'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
|
const state = useProxy(posyandustate)
|
||||||
|
// const router = useTransitionRouter()
|
||||||
|
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 (
|
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 />
|
||||||
|
<Flex mt={10} justify={"space-between"} align={"center"}>
|
||||||
|
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
|
Posyandu Darmasaba
|
||||||
|
</Text>
|
||||||
|
<TextInput
|
||||||
|
placeholder="Cari Posyandu"
|
||||||
|
radius="lg"
|
||||||
|
leftSection={<IconSearch size={20} />}
|
||||||
|
w={{ base: "25%", md: "30%" }}
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
|
||||||
Posyandu Darmasaba
|
|
||||||
</Text>
|
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Stack gap={'lg'}>
|
<Stack gap={'lg'}>
|
||||||
<SimpleGrid
|
<SimpleGrid
|
||||||
@@ -39,49 +61,46 @@ export default function Page() {
|
|||||||
base: 1,
|
base: 1,
|
||||||
md: 3,
|
md: 3,
|
||||||
}}>
|
}}>
|
||||||
{data.map((v, k) => {
|
{data?.map((v, k) => {
|
||||||
return (
|
return (
|
||||||
<Paper key={k} p={"xl"} bg={colors["white-trans-1"]}>
|
<Paper key={k} p={"xl"} bg={colors["white-trans-1"]}>
|
||||||
<Stack gap={'xs'}>
|
<Stack gap={'xs'}>
|
||||||
<Text c={colors["blue-button"]} fw={"bold"} fz={"h3"}>
|
<Text c={colors["blue-button"]} fw={"bold"} fz={"h3"}>
|
||||||
{v.judul}
|
{v.name}
|
||||||
</Text>
|
|
||||||
<Text fz={'h4'}>
|
|
||||||
{v.nomor}
|
|
||||||
</Text>
|
</Text>
|
||||||
<Center>
|
<Center>
|
||||||
<Image src={v.image} alt="" />
|
<Image src={v.image.link} alt="" />
|
||||||
</Center>
|
</Center>
|
||||||
<Text fz={'h4'}>
|
<Text fz={'h4'}>
|
||||||
Jadwal Pelayanan
|
No.Telp : {v.nomor}
|
||||||
</Text>
|
|
||||||
<Text fz={'h4'}>
|
|
||||||
Setiap tanggal 5, Pukul 09:00 -
|
|
||||||
12:00 WITA
|
|
||||||
</Text>
|
</Text>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex justify={'space-between'}>
|
<Text fz={'h4'}>
|
||||||
<Text fz={'h4'}>Balita</Text>
|
Jadwal Pelayanan
|
||||||
<Box>
|
</Text>
|
||||||
<Text fz={'h4'}>Selasa minggu pertama</Text>
|
<Text fz={'h4'} dangerouslySetInnerHTML={{ __html: v.jadwalPelayanan }} />
|
||||||
<Text fz={'h4'}>(09:00-11:00 WITA)</Text>
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Flex justify={'space-between'}>
|
|
||||||
<Text fz={'h4'}>Lansia</Text>
|
|
||||||
<Box>
|
|
||||||
<Text fz={'h4'}>Selasa minggu pertama</Text>
|
|
||||||
<Text fz={'h4'}>(09:00-11:00 WITA)</Text>
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
<Spoiler
|
||||||
|
maxHeight={60} // tinggi maksimum sebelum di-collapse
|
||||||
|
showLabel="Read more"
|
||||||
|
hideLabel="Read less"
|
||||||
|
>
|
||||||
|
<Text fz={'h4'} dangerouslySetInnerHTML={{ __html: v.deskripsi }} />
|
||||||
|
</Spoiler>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
<Center>
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={(newPage) => load(newPage)} // ini penting!
|
||||||
|
total={totalPages}
|
||||||
|
mt="md"
|
||||||
|
mb="md"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
<Text fz={'h4'} fw={"bold"}>
|
<Text fz={'h4'} fw={"bold"}>
|
||||||
Pelayanan Posyandu
|
Pelayanan Posyandu
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
Reference in New Issue
Block a user