Compare commits
1 Commits
nico/2-may
...
nico/push-
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f3ee2f831 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "desa-darmasaba",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
|
||||
@@ -323,73 +323,3 @@ model GrafikKepuasan {
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
// ========================================= ARTIKEL KESEHATAN ========================================= //
|
||||
model ArtikelKesehatan {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model Introduction {
|
||||
id Int @id @default(autoincrement())
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model Symptom {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model Prevention {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model FirstAid {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model MythVsFact {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
mitos String
|
||||
fakta String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model DoctorSign {
|
||||
id Int @id @default(autoincrement())
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
/* Introduction */
|
||||
const templateIntroduction = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type Introduction = Prisma.IntroductionGetPayload<{
|
||||
select: {
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const introduction = proxy({
|
||||
create: {
|
||||
form: {} as Introduction,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateIntroduction.safeParse(introduction.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
introduction.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.introduction["create"].post(introduction.create.form);
|
||||
if (res.status === 200) {
|
||||
introduction.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
introduction.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.IntroductionGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.introduction["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
introduction.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* symptom */
|
||||
const templateSymptom = z.object({
|
||||
title: z.string().min(3, "Title minimal 3 karakter"),
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type Symptom = Prisma.SymptomGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const symptom = proxy({
|
||||
create: {
|
||||
form: {} as Symptom,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateSymptom.safeParse(symptom.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
symptom.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.symptom["create"].post(symptom.create.form);
|
||||
if (res.status === 200) {
|
||||
symptom.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
symptom.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.SymptomGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.symptom["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
symptom.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Prevention */
|
||||
const templatePrevention = z.object({
|
||||
title: z.string().min(3, "Title minimal 3 karakter"),
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type Prevention = Prisma.PreventionGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const prevention = proxy({
|
||||
create: {
|
||||
form: {} as Prevention,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templatePrevention.safeParse(prevention.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
prevention.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.prevention["create"].post(prevention.create.form);
|
||||
if (res.status === 200) {
|
||||
prevention.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
prevention.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PreventionGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.prevention["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
prevention.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
/* ======================================================================= */
|
||||
|
||||
/* First Aid */
|
||||
const templateFirstAid = z.object({
|
||||
title: z.string().min(3, "Title minimal 3 karakter"),
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type FirstAid = Prisma.FirstAidGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const firstAid = proxy({
|
||||
create: {
|
||||
form: {} as FirstAid,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateFirstAid.safeParse(firstAid.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
firstAid.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.firstaid["create"].post(firstAid.create.form);
|
||||
if (res.status === 200) {
|
||||
firstAid.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
firstAid.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.FirstAidGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.firstaid["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
firstAid.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Myth vs Fact */
|
||||
const templateMythFact = z.object({
|
||||
title: z.string().min(3, "Title minimal 3 karakter"),
|
||||
mitos: z.string().min(3, "Mitos minimal 3 karakter"),
|
||||
fakta: z.string().min(3, "Fakta minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type MythFact = Prisma.MythVsFactGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
mitos: true;
|
||||
fakta: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
const mythFact = proxy({
|
||||
create: {
|
||||
form: {} as MythFact,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateMythFact.safeParse(mythFact.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
mythFact.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.mythvsfact["create"].post(mythFact.create.form);
|
||||
if (res.status === 200) {
|
||||
mythFact.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
mythFact.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.MythVsFactGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.mythvsfact["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
mythFact.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
/* ======================================================================= */
|
||||
|
||||
/* Doctor Sign */
|
||||
const templateDoctorSign = z.object({
|
||||
content: z.string().min(3, "Content minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type DoctorSign = Prisma.DoctorSignGetPayload<{
|
||||
select: {
|
||||
content: true
|
||||
}
|
||||
}>
|
||||
|
||||
const doctorSign = proxy({
|
||||
create: {
|
||||
form: {} as DoctorSign,
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateDoctorSign.safeParse(doctorSign.create.form);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
doctorSign.create.loading = true;
|
||||
const res = await ApiFetch.api.kesehatan.doctor_sign["create"].post(doctorSign.create.form);
|
||||
if (res.status === 200) {
|
||||
doctorSign.findMany.load();
|
||||
return toast.success("success create");
|
||||
}
|
||||
return toast.error("failed create");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
doctorSign.create.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.DoctorSignGetPayload<{ omit: { isActive: true } }>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.kesehatan.doctor_sign["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
doctorSign.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
const stateArtikelKesehatan = proxy({
|
||||
introduction,
|
||||
symptom,
|
||||
prevention,
|
||||
firstAid,
|
||||
mythFact,
|
||||
doctorSign
|
||||
})
|
||||
|
||||
export default stateArtikelKesehatan
|
||||
@@ -24,14 +24,8 @@ export function BeritaEditor({ onSubmit }: { onSubmit: (val: string) => void })
|
||||
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
||||
],
|
||||
content,
|
||||
immediatelyRender: false
|
||||
});
|
||||
|
||||
if (!editor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<RichTextEditor editor={editor}>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
'use client'
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
|
||||
function DoctorSignUI() {
|
||||
const doctorSign = useProxy(stateArtikelKesehatan.doctorSign)
|
||||
return (
|
||||
<Box>
|
||||
<Text fw={"bold"}>Kapan Harus ke Dokter</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
doctorSign.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default DoctorSignUI;
|
||||
@@ -1,29 +0,0 @@
|
||||
'use client'
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
|
||||
function FirstAidUI() {
|
||||
const firstAidState = useProxy(stateArtikelKesehatan.firstAid)
|
||||
return (
|
||||
<Box>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Title Pertolongan Pertama</Text>}
|
||||
placeholder="Masukkan title"
|
||||
onChange={(val) => {
|
||||
firstAidState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
firstAidState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default FirstAidUI;
|
||||
@@ -1,23 +0,0 @@
|
||||
'use client'
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
|
||||
function IntoductionUI() {
|
||||
const introduction = useProxy(stateArtikelKesehatan.introduction)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Text fw={"bold"}>Pendahuluan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
introduction.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default IntoductionUI;
|
||||
@@ -1,35 +0,0 @@
|
||||
'use client'
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function MythFactUI() {
|
||||
const mythFact = useProxy(stateArtikelKesehatan.mythFact)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Title Pertolongan Pertama Penyakit</Text>}
|
||||
placeholder="Masukkan title"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Mitos</Text>}
|
||||
placeholder="Masukkan mitos"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.mitos = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Fakta</Text>}
|
||||
placeholder="Masukkan fakta"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.fakta = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default MythFactUI;
|
||||
@@ -1,149 +1,26 @@
|
||||
'use client'
|
||||
import { Box, Button, Center, SimpleGrid, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import IntoductionUI from './introduction/page';
|
||||
import SymptomUI from './symptom/page';
|
||||
import PreventionUI from './prevention/page';
|
||||
import MythFactUI from './mythVsfact/page';
|
||||
import DoctorSignUI from './doctor_sign/page';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import FirstAidUI from './first_aid/page';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, SimpleGrid, Stack, TextInput, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ArtikelKesehatan() {
|
||||
const state = useProxy(stateArtikelKesehatan)
|
||||
const submitAllForms = () => {
|
||||
if (state.introduction.create.form.content) {
|
||||
state.introduction.create.create()
|
||||
}
|
||||
if (state.symptom.create.form.title && state.symptom.create.form.content) {
|
||||
state.symptom.create.create()
|
||||
}
|
||||
if (state.prevention.create.form.title && state.prevention.create.form.content) {
|
||||
state.prevention.create.create()
|
||||
}
|
||||
if (state.firstAid.create.form.title && state.firstAid.create.form.content) {
|
||||
state.firstAid.create.create()
|
||||
}
|
||||
if (state.mythFact.create.form.title && state.mythFact.create.form.mitos && state.mythFact.create.form.fakta) {
|
||||
state.mythFact.create.create()
|
||||
}
|
||||
if (state.doctorSign.create.form.content) {
|
||||
state.doctorSign.create.create()
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<SimpleGrid cols={{
|
||||
base: 1, md: 2
|
||||
}}>
|
||||
<Box >
|
||||
<Box>
|
||||
<Title order={3}>Artikel Kesehatan</Title>
|
||||
<IntoductionUI />
|
||||
<SymptomUI />
|
||||
<PreventionUI />
|
||||
<FirstAidUI />
|
||||
<MythFactUI />
|
||||
<DoctorSignUI />
|
||||
<Button mt={10} onClick={submitAllForms}>Submit</Button>
|
||||
<TextInput
|
||||
label="Jadwal"
|
||||
placeholder='masukkan artikel kesehatan'
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Title order={3}>List Artikel Kesehatan</Title>
|
||||
<AllList />
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
function AllList() {
|
||||
const listState = useProxy(stateArtikelKesehatan)
|
||||
useShallowEffect(() => {
|
||||
listState.introduction.findMany.load();
|
||||
listState.symptom.findMany.load();
|
||||
listState.prevention.findMany.load();
|
||||
listState.firstAid.findMany.load();
|
||||
listState.mythFact.findMany.load();
|
||||
listState.doctorSign.findMany.load();
|
||||
}, [])
|
||||
|
||||
if (!listState.introduction.findMany.data
|
||||
|| !listState.symptom.findMany.data
|
||||
|| !listState.prevention.findMany.data
|
||||
|| !listState.firstAid.findMany.data
|
||||
|| !listState.mythFact.findMany.data
|
||||
|| !listState.doctorSign.findMany.data
|
||||
) return <Stack>
|
||||
{Array.from({ length: 10 }).map((v, k) => <Skeleton key={k} h={40} />)}
|
||||
</Stack>
|
||||
return <Stack>
|
||||
<Title order={4}>Intoduction</Title>
|
||||
{listState.introduction.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
{/* Symptom */}
|
||||
{listState.symptom.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
{/* Prevention */}
|
||||
{listState.prevention.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
{/* First Aid */}
|
||||
{listState.firstAid.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
{/* Myth Fact */}
|
||||
{listState.mythFact.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Table
|
||||
striped
|
||||
highlightOnHover
|
||||
withTableBorder
|
||||
withColumnBorders
|
||||
bg={colors['white-1']}
|
||||
>
|
||||
<TableThead >
|
||||
<TableTr >
|
||||
<TableTh >
|
||||
<Center>Mitos</Center>
|
||||
</TableTh>
|
||||
<TableTh >
|
||||
<Center>Fakta</Center>
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody >
|
||||
<TableTr>
|
||||
<TableTd ta="center">{item.mitos}</TableTd>
|
||||
<TableTd ta="center">{item.fakta}</TableTd>
|
||||
</TableTr>
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
))}
|
||||
{/* Doctor Sign */}
|
||||
<Title order={4}>Kapan Harus Ke Dokter?</Title>
|
||||
{listState.doctorSign.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}/>
|
||||
</Box>
|
||||
))}
|
||||
</Stack>
|
||||
}
|
||||
|
||||
export default ArtikelKesehatan;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
'use client'
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
|
||||
function PreventionUI() {
|
||||
const preventionState = useProxy(stateArtikelKesehatan.prevention)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label={<Text fw={"bold"}>Title Pencegahan Penyakit</Text>}
|
||||
placeholder="Masukkan title"
|
||||
onChange={(val) => {
|
||||
preventionState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
preventionState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default PreventionUI;
|
||||
@@ -1,29 +0,0 @@
|
||||
'use client'
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
|
||||
function SymptomUI() {
|
||||
const symptomState = useProxy(stateArtikelKesehatan.symptom)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label={<Text fw={"bold"}>Title Gejala Penyakit</Text>}
|
||||
placeholder='masukkan title'
|
||||
onChange={(val) => {
|
||||
symptomState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
symptomState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default SymptomUI;
|
||||
@@ -1,20 +1,16 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client'
|
||||
import stategrafikKepuasan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/grafikKepuasan';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useState } from 'react';
|
||||
import { Bar, Legend, RadialBarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function GrafikHasilKepuasan() {
|
||||
const grafikkepuasan = useProxy(stategrafikKepuasan.grafikkepuasan)
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const isTablet = useMediaQuery('(max-width: 1024px)')
|
||||
const isMobile = useMediaQuery('(max-width: 768px)')
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [chartData, setChartData] = useState<any[]>([])
|
||||
|
||||
useShallowEffect(() => {
|
||||
const fetchData = async () => {
|
||||
await grafikkepuasan.findMany.load();
|
||||
@@ -24,22 +20,11 @@ function GrafikHasilKepuasan() {
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true); // setelah komponen siap di client
|
||||
}, []);
|
||||
|
||||
if (!mounted) {
|
||||
return null; // Jangan render apa-apa dulu sebelum mounted
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Grafik Hasil Kepuasan</Title>
|
||||
<Box>
|
||||
<TextInput
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
label="Label"
|
||||
placeholder='Masukkan label yang diinginkan'
|
||||
value={grafikkepuasan.create.form.label}
|
||||
@@ -48,10 +33,9 @@ function GrafikHasilKepuasan() {
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
label="Jumlah Penderita"
|
||||
label="Jumlah Penderita Farangitis Akut"
|
||||
type='number'
|
||||
placeholder='Masukkan jumlah penderita'
|
||||
placeholder='Masukkan jumlah penderita farangitis akut'
|
||||
value={grafikkepuasan.create.form.jumlah}
|
||||
onChange={(val) => {
|
||||
grafikkepuasan.create.form.jumlah = val.currentTarget.value
|
||||
@@ -59,29 +43,29 @@ function GrafikHasilKepuasan() {
|
||||
/>
|
||||
</Box>
|
||||
<Group>
|
||||
<Button mt={10}
|
||||
onClick={async () => {
|
||||
await grafikkepuasan.create.create();
|
||||
await grafikkepuasan.findMany.load();
|
||||
if (grafikkepuasan.findMany.data) {
|
||||
setChartData(grafikkepuasan.findMany.data);
|
||||
}
|
||||
}}
|
||||
<Button mt={10}
|
||||
onClick={async () => {
|
||||
await grafikkepuasan.create.create();
|
||||
await grafikkepuasan.findMany.load();
|
||||
if (grafikkepuasan.findMany.data) {
|
||||
setChartData(grafikkepuasan.findMany.data);
|
||||
}
|
||||
}}
|
||||
>Submit</Button>
|
||||
</Group>
|
||||
<Box h={400} w={{ base: "100%", md: "80%" }}>
|
||||
<Title py={15} order={3}>Data Kelahiran & Kematian</Title>
|
||||
<BarChart
|
||||
width={isMobile ? 450 : isTablet ? 600 : 900}
|
||||
height={380}
|
||||
<Title order={3}>Data Kelahiran & Kematian</Title>
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<RadialBarChart
|
||||
data={chartData}
|
||||
>
|
||||
<XAxis dataKey="label" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="jumlah" fill={colors['blue-button']} name="Jumlah" />
|
||||
</BarChart>
|
||||
>
|
||||
<XAxis dataKey="label" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="jumlah" fill={colors['blue-button']} name="Jumlah" />
|
||||
</RadialBarChart>
|
||||
</ResponsiveContainer>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import statePersentase from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran';
|
||||
import { Box, Button, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
import { Bar, BarChart, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function PersentaseDataKelahiranKematian() {
|
||||
const persentase = useProxy(statePersentase.persentasekelahiran);
|
||||
const [chartData, setChartData] = useState<any[]>([]);
|
||||
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
|
||||
const isTablet = useMediaQuery('(max-width: 1024px)')
|
||||
const isMobile = useMediaQuery('(max-width: 768px)')
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
@@ -89,17 +87,19 @@ function PersentaseDataKelahiranKematian() {
|
||||
|
||||
{/* Chart */}
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||
<Title pb={10} order={3}>Data Kelahiran & Kematian</Title>
|
||||
<Title order={3}>Data Kelahiran & Kematian</Title>
|
||||
{mounted && chartData.length > 0 && (
|
||||
<BarChart width={isMobile ? 450 : isTablet ? 600 : 900} height={380} data={chartData} >
|
||||
<XAxis dataKey="tahun" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="kematianKasar" fill="#f03e3e" name="Kematian Kasar" />
|
||||
<Bar dataKey="kematianBayi" fill="#ff922b" name="Kematian Bayi" />
|
||||
<Bar dataKey="kelahiranKasar" fill="#4dabf7" name="Kelahiran Kasar" />
|
||||
</BarChart>
|
||||
<ResponsiveContainer width="100%" aspect={2}>
|
||||
<BarChart width={300} data={chartData}>
|
||||
<XAxis dataKey="tahun" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="kematianKasar" fill="#f03e3e" name="Kematian Kasar" />
|
||||
<Bar dataKey="kematianBayi" fill="#ff922b" name="Kematian Bayi" />
|
||||
<Bar dataKey="kelahiranKasar" fill="#4dabf7" name="Kelahiran Kasar" />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
)}
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { Context } from "elysia";
|
||||
|
||||
type FormCreate = Prisma.DoctorSignGetPayload<{
|
||||
select: {
|
||||
content: true;
|
||||
}
|
||||
}>
|
||||
|
||||
export default async function doctorSignCreate(context: Context) {
|
||||
const body = context.body as FormCreate;
|
||||
|
||||
await prisma.doctorSign.create({
|
||||
data: {
|
||||
content: body.content,
|
||||
},
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: "Success create doctor sign",
|
||||
data: {
|
||||
...body,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
export default async function doctorSignFindMany() {
|
||||
const data = await prisma.doctorSign.findMany();
|
||||
return {
|
||||
success: true,
|
||||
message: "Success get doctor sign",
|
||||
data,
|
||||
};
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import Elysia, { t } from "elysia"
|
||||
import doctorSignCreate from "./create"
|
||||
import doctorSignFindMany from "./find-many"
|
||||
|
||||
const DoctorSign = new Elysia({
|
||||
prefix: "/doctor_sign",
|
||||
tags: ["Data Kesehatan/Artikel Kesehatan/Doctor Sign"],
|
||||
})
|
||||
.get("/find-many", doctorSignFindMany)
|
||||
.post("/create", doctorSignCreate, {
|
||||
body: t.Object({
|
||||
content: t.String(),
|
||||
}),
|
||||
})
|
||||
export default DoctorSign
|
||||
@@ -1,27 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { Context } from "elysia";
|
||||
|
||||
type FormCreate = Prisma.FirstAidGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
}
|
||||
}>
|
||||
export default async function firstAidCreate(context: Context) {
|
||||
const body = context.body as FormCreate;
|
||||
|
||||
await prisma.firstAid.create({
|
||||
data: {
|
||||
title: body.title,
|
||||
content: body.content,
|
||||
},
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: "Success create first aid",
|
||||
data: {
|
||||
...body,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import prisma from "@/lib/prisma"
|
||||
|
||||
export default async function firstAidFindMany() {
|
||||
const res = await prisma.firstAid.findMany()
|
||||
return {
|
||||
data: res
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import Elysia, { t } from "elysia"
|
||||
import firstAidCreate from "./create"
|
||||
import firstAidFindMany from "./find-many"
|
||||
|
||||
const FirstAid = new Elysia({
|
||||
prefix: "/firstaid",
|
||||
tags: ["Data Kesehatan/Artikel Kesehatan/First Aid"]
|
||||
})
|
||||
.get("/find-many", firstAidFindMany)
|
||||
.post("/create", firstAidCreate, {
|
||||
body: t.Object({
|
||||
title: t.String(),
|
||||
content: t.String(),
|
||||
}),
|
||||
})
|
||||
export default FirstAid
|
||||
@@ -1,26 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { Context } from "elysia";
|
||||
|
||||
type FormCreate = Prisma.IntroductionGetPayload<{
|
||||
select: {
|
||||
content: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
export default async function introductionCreate(context: Context) {
|
||||
const body = context.body as FormCreate;
|
||||
|
||||
await prisma.introduction.create({
|
||||
data: {
|
||||
content: body.content,
|
||||
},
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: "Success create introduction",
|
||||
data: {
|
||||
...body,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
export default async function introductionFindMany() {
|
||||
const res = await prisma.introduction.findMany();
|
||||
return {
|
||||
data: res,
|
||||
};
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import Elysia, { t } from "elysia";
|
||||
import introductionCreate from "./create";
|
||||
import introductionFindMany from "./find-many";
|
||||
|
||||
const Introduction = new Elysia({
|
||||
prefix: "/introduction",
|
||||
tags: ["Data Kesehatan/Artikel Kesehatan/Introduction"]
|
||||
})
|
||||
.get("/find-many", introductionFindMany)
|
||||
.post("/create", introductionCreate, {
|
||||
body: t.Object({
|
||||
content: t.String(),
|
||||
}),
|
||||
})
|
||||
|
||||
export default Introduction;
|
||||
@@ -1,30 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
type FormCreate = Prisma.MythVsFactGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
mitos: true;
|
||||
fakta: true;
|
||||
}
|
||||
}>
|
||||
|
||||
export default async function mythVsFactCreate(context: Context) {
|
||||
const body = context.body as FormCreate;
|
||||
|
||||
await prisma.mythVsFact.create({
|
||||
data: {
|
||||
title: body.title,
|
||||
mitos: body.mitos,
|
||||
fakta: body.fakta,
|
||||
},
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: "Success create myth vs fact",
|
||||
data: {
|
||||
...body,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
export default async function mythVsFactFindMany() {
|
||||
const mythVsFacts = await prisma.mythVsFact.findMany();
|
||||
return {
|
||||
success: true,
|
||||
message: "Success get myth vs fact",
|
||||
data: mythVsFacts,
|
||||
};
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import Elysia, { t } from "elysia";
|
||||
import mythVsFactCreate from "./create";
|
||||
import mythVsFactFindMany from "./find-many";
|
||||
|
||||
const MythVsFact = new Elysia({
|
||||
prefix: "/mythvsfact",
|
||||
tags: ["Data Kesehatan/Artikel Kesehatan/Myth vs Fact"]
|
||||
})
|
||||
.get("/find-many", mythVsFactFindMany)
|
||||
.post("/create", mythVsFactCreate, {
|
||||
body: t.Object({
|
||||
title: t.String(),
|
||||
mitos: t.String(),
|
||||
fakta: t.String(),
|
||||
}),
|
||||
})
|
||||
export default MythVsFact
|
||||
@@ -1,28 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { Context } from "elysia";
|
||||
|
||||
type FormCreate = Prisma.PreventionGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
}
|
||||
}>
|
||||
|
||||
export default async function preventionCreate(context: Context) {
|
||||
const body = context.body as FormCreate;
|
||||
|
||||
await prisma.prevention.create({
|
||||
data: {
|
||||
title: body.title,
|
||||
content: body.content,
|
||||
},
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: "Success create prevention",
|
||||
data: {
|
||||
...body,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import prisma from "@/lib/prisma"
|
||||
|
||||
export default async function preventionFindMany() {
|
||||
const res = await prisma.prevention.findMany()
|
||||
return {
|
||||
data: res
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import Elysia, { t } from "elysia"
|
||||
import preventionCreate from "./create"
|
||||
import preventionFindMany from "./find-many"
|
||||
|
||||
const Prevention = new Elysia({
|
||||
prefix: "/prevention",
|
||||
tags: ["Data Kesehatan/Artikel Kesehatan/Prevention"]
|
||||
})
|
||||
.get("/find-many", preventionFindMany)
|
||||
.post("/create", preventionCreate, {
|
||||
body: t.Object({
|
||||
title: t.String(),
|
||||
content: t.String(),
|
||||
}),
|
||||
})
|
||||
export default Prevention
|
||||
@@ -1,27 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { Context } from "elysia";
|
||||
|
||||
type FormCreate = Prisma.SymptomGetPayload<{
|
||||
select: {
|
||||
title: true;
|
||||
content: true;
|
||||
}
|
||||
}>
|
||||
export default async function symptomCreate(context: Context) {
|
||||
const body = context.body as FormCreate;
|
||||
|
||||
await prisma.symptom.create({
|
||||
data: {
|
||||
title: body.title,
|
||||
content: body.content,
|
||||
},
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: "Success create symptom",
|
||||
data: {
|
||||
...body,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import prisma from "@/lib/prisma"
|
||||
|
||||
export default async function symptomFindMany() {
|
||||
const res = await prisma.symptom.findMany()
|
||||
return {
|
||||
data: res
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import Elysia, { t } from "elysia";
|
||||
import symptomCreate from "./create";
|
||||
import symptomFindMany from "./find-many";
|
||||
|
||||
const Syptom = new Elysia({
|
||||
prefix: "/symptom",
|
||||
tags: ["Data Kesehatan/Artikel Kesehatan/Syptom"]
|
||||
})
|
||||
.get("/find-many", symptomFindMany)
|
||||
.post("/create", symptomCreate, {
|
||||
body: t.Object({
|
||||
title: t.String(),
|
||||
content: t.String(),
|
||||
}),
|
||||
})
|
||||
export default Syptom
|
||||
@@ -13,12 +13,6 @@ import DokumenDiperlukan from "./data_kesehatan_warga/jadwal_kegiatan/dokumen_ya
|
||||
import PendaftaranJadwal from "./data_kesehatan_warga/jadwal_kegiatan/pendaftaran";
|
||||
import PersentaseKelahiranKematian from "./data_kesehatan_warga/persentase_kelahiran_kematian";
|
||||
import GrafikKepuasan from "./data_kesehatan_warga/grafik_kepuasan";
|
||||
import Introduction from "./data_kesehatan_warga/artikel_kesehatan/introduction";
|
||||
import Syptom from "./data_kesehatan_warga/artikel_kesehatan/syptom";
|
||||
import Prevention from "./data_kesehatan_warga/artikel_kesehatan/prevention";
|
||||
import FirstAid from "./data_kesehatan_warga/artikel_kesehatan/first_aid";
|
||||
import MythVsFact from "./data_kesehatan_warga/artikel_kesehatan/myth_vs_fact";
|
||||
import DoctorSign from "./data_kesehatan_warga/artikel_kesehatan/doctor_sign";
|
||||
|
||||
|
||||
const Kesehatan = new Elysia({
|
||||
@@ -39,10 +33,4 @@ const Kesehatan = new Elysia({
|
||||
.use(PendaftaranJadwal)
|
||||
.use(PersentaseKelahiranKematian)
|
||||
.use(GrafikKepuasan)
|
||||
.use(Introduction)
|
||||
.use(Syptom)
|
||||
.use(Prevention)
|
||||
.use(FirstAid)
|
||||
.use(MythVsFact)
|
||||
.use(DoctorSign)
|
||||
export default Kesehatan;
|
||||
|
||||
@@ -45,25 +45,11 @@ async function layanan() {
|
||||
const data = await prisma.layanan.findMany();
|
||||
return { data };
|
||||
}
|
||||
|
||||
const Utils = new Elysia({
|
||||
prefix: "/api/utils",
|
||||
tags: ["Utils"],
|
||||
}).get("/version", async () => {
|
||||
const packageJson = await fs.readFile(
|
||||
path.join(ROOT, "package.json"),
|
||||
"utf-8"
|
||||
);
|
||||
const version = JSON.parse(packageJson).version;
|
||||
return { version };
|
||||
});
|
||||
|
||||
const ApiServer = new Elysia()
|
||||
.use(swagger({ path: "/api/docs" }))
|
||||
.use(cors(corsConfig))
|
||||
.use(Kesehatan)
|
||||
.use(Desa)
|
||||
.use(Utils)
|
||||
.onError(({ code }) => {
|
||||
if (code === "NOT_FOUND") {
|
||||
return {
|
||||
|
||||
@@ -8,7 +8,7 @@ const data = [
|
||||
title: "Olahraga dan Kepemudaan",
|
||||
deskripsi: "Tim Bola Voli Putri Dharma Temaja meraih juara 3 dalam Turnamen Bola Voli Mangupura Cup 2024 kategori Putri Se-Bali ",
|
||||
image: "/api/img/prestasi-voli.jpeg",
|
||||
link: "/darmasaba/prestasi-desa/tim-bola-voli-putri-dharma-temaja-meraih-juara-3-dalam-turnamen-bola-voli-mangupura-cup-2024-kategori-putri-se-bali"
|
||||
link: "/darmasaba/prestasi/tim-bola-voli-putri-dharma-temaja-meraih-juara-3-dalam-turnamen-bola-voli-mangupura-cup-2024-kategori-putri-se-bali"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
"use client";
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
||||
import { z } from "zod";
|
||||
|
||||
type RouterLeaf<T extends z.ZodType = z.ZodObject<{}>> = {
|
||||
get: () => string;
|
||||
query: (params: z.infer<T>) => string;
|
||||
parse: (searchParams: URLSearchParams) => z.infer<T>;
|
||||
};
|
||||
|
||||
// Helper type to convert dashes to camelCase
|
||||
type DashToCamelCase<S extends string> = S extends `${infer F}-${infer R}`
|
||||
? `${F}${Capitalize<DashToCamelCase<R>>}`
|
||||
: S;
|
||||
|
||||
// Modified RouterPath to handle dash conversion
|
||||
type RouterPath<
|
||||
T extends z.ZodType = z.ZodObject<{}>,
|
||||
Segments extends string[] = []
|
||||
> = Segments extends [infer Head extends string, ...infer Tail extends string[]]
|
||||
? { [K in DashToCamelCase<Head>]: RouterPath<T, Tail> }
|
||||
: RouterLeaf<T>;
|
||||
|
||||
type RemoveLeadingSlash<S extends string> = S extends `/${infer Rest}`
|
||||
? Rest
|
||||
: S;
|
||||
|
||||
type SplitPath<S extends string> = S extends `${infer Head}/${infer Tail}`
|
||||
? [Head, ...SplitPath<Tail>]
|
||||
: S extends ""
|
||||
? []
|
||||
: [S];
|
||||
|
||||
type WibuRouterOptions = {
|
||||
prefix?: string;
|
||||
name?: string;
|
||||
};
|
||||
|
||||
export class V2ClientRouter<Routes = {}> {
|
||||
private tree: any = {};
|
||||
private prefix: string = "";
|
||||
private name: string = "";
|
||||
private querySchemas: Map<string, z.ZodType> = new Map();
|
||||
|
||||
constructor(options?: WibuRouterOptions) {
|
||||
if (options?.prefix) {
|
||||
// Ensure prefix starts with / and doesn't end with /
|
||||
this.prefix = options.prefix.startsWith("/")
|
||||
? options.prefix
|
||||
: `/${options.prefix}`;
|
||||
|
||||
if (this.prefix.endsWith("/")) {
|
||||
this.prefix = this.prefix.slice(0, -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (options?.name) {
|
||||
this.name = options.name;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert dash-case to camelCase
|
||||
private toCamelCase(str: string): string {
|
||||
return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
||||
}
|
||||
|
||||
add<
|
||||
Path extends string,
|
||||
NormalizedPath extends string = RemoveLeadingSlash<Path>,
|
||||
Segments extends string[] = SplitPath<NormalizedPath>,
|
||||
T extends z.ZodType = z.ZodObject<{}>
|
||||
>(
|
||||
path: Path,
|
||||
schema?: { query: T }
|
||||
): V2ClientRouter<
|
||||
Routes &
|
||||
(NormalizedPath extends ""
|
||||
? RouterLeaf<T>
|
||||
: {
|
||||
[K in Segments[0] as DashToCamelCase<K>]: RouterPath<
|
||||
T,
|
||||
Segments extends [any, ...infer Rest] ? Rest : []
|
||||
>;
|
||||
})
|
||||
> {
|
||||
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
||||
const fullPath = `${this.prefix}${normalizedPath}`;
|
||||
const segments = normalizedPath.split("/").filter(Boolean);
|
||||
|
||||
// Store the Zod schema for this path
|
||||
if (schema) {
|
||||
this.querySchemas.set(fullPath, schema.query);
|
||||
} else {
|
||||
// Default empty schema
|
||||
this.querySchemas.set(fullPath, z.object({}));
|
||||
}
|
||||
|
||||
const handleQuery = (params: any): string => {
|
||||
if (!params || Object.keys(params).length === 0) return fullPath;
|
||||
|
||||
// Validate params against schema
|
||||
const schema = this.querySchemas.get(fullPath);
|
||||
if (schema) {
|
||||
try {
|
||||
schema.parse(params);
|
||||
} catch (error) {
|
||||
console.error("Query params validation failed:", error);
|
||||
throw new Error("Invalid query parameters");
|
||||
}
|
||||
}
|
||||
|
||||
const queryString = Object.entries(params)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`
|
||||
)
|
||||
.join("&");
|
||||
return `${fullPath}?${queryString}`;
|
||||
};
|
||||
|
||||
const handleGet = () => fullPath;
|
||||
|
||||
const handleParse = (searchParams: URLSearchParams): any => {
|
||||
const schema = this.querySchemas.get(fullPath);
|
||||
if (!schema) return {};
|
||||
|
||||
// Convert URLSearchParams to object
|
||||
const queryObject: Record<string, any> = {};
|
||||
searchParams.forEach((value, key) => {
|
||||
queryObject[key] = value;
|
||||
});
|
||||
|
||||
// Parse through Zod schema
|
||||
try {
|
||||
return schema.parse(queryObject);
|
||||
} catch (error) {
|
||||
console.error("Failed to parse search params:", error);
|
||||
// Return safe default values
|
||||
const safeParsed = schema.safeParse(queryObject);
|
||||
if (safeParsed.success) {
|
||||
return safeParsed.data;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// Special case for root path "/"
|
||||
if (segments.length === 0) {
|
||||
this.tree.get = handleGet;
|
||||
this.tree.query = handleQuery;
|
||||
this.tree.parse = handleParse;
|
||||
} else {
|
||||
let current = this.tree;
|
||||
for (const segment of segments) {
|
||||
// Use camelCase version for the property name
|
||||
const camelSegment = this.toCamelCase(segment);
|
||||
if (!current[camelSegment]) {
|
||||
current[camelSegment] = {};
|
||||
}
|
||||
current = current[camelSegment];
|
||||
}
|
||||
|
||||
current.get = handleGet;
|
||||
current.query = handleQuery;
|
||||
current.parse = handleParse;
|
||||
}
|
||||
|
||||
return this as any;
|
||||
}
|
||||
|
||||
// Add a method to incorporate another router's routes into this one
|
||||
use<N extends string, ChildRoutes>(
|
||||
name: N,
|
||||
childRouter: V2ClientRouter<ChildRoutes>
|
||||
): V2ClientRouter<Routes & Record<DashToCamelCase<N>, ChildRoutes>> {
|
||||
const camelName = this.toCamelCase(name);
|
||||
|
||||
if (!this.tree[camelName]) {
|
||||
this.tree[camelName] = {};
|
||||
}
|
||||
|
||||
// Copy query schemas from child router
|
||||
childRouter.querySchemas.forEach((schema, path) => {
|
||||
const newPath = `${this.prefix}/${name}${path.substring(
|
||||
childRouter.prefix.length
|
||||
)}`;
|
||||
this.querySchemas.set(newPath, schema);
|
||||
});
|
||||
|
||||
// Create a deep copy of the child router's tree with updated paths
|
||||
const updatePaths = (obj: any, childPrefix: string): any => {
|
||||
const result: any = {};
|
||||
|
||||
for (const key in obj) {
|
||||
if (key === "get" && typeof obj[key] === "function") {
|
||||
// Capture the original path from the child router
|
||||
const originalPath = obj[key]();
|
||||
// Create a new function that returns the combined path
|
||||
result[key] = () => {
|
||||
const newPath = `${this.prefix}/${name}${originalPath.substring(
|
||||
childPrefix.length
|
||||
)}`;
|
||||
return newPath;
|
||||
};
|
||||
} else if (key === "query" && typeof obj[key] === "function") {
|
||||
// Capture the child router's prefix for path adjustment
|
||||
result[key] = (params: any) => {
|
||||
// Get the original result without query params
|
||||
const originalPathWithoutParams = obj["get"]();
|
||||
// Create the proper path with our parent prefix
|
||||
const newBasePath = `${
|
||||
this.prefix
|
||||
}/${name}${originalPathWithoutParams.substring(
|
||||
childPrefix.length
|
||||
)}`;
|
||||
|
||||
// Add query params if any
|
||||
if (!params || Object.keys(params).length === 0) return newBasePath;
|
||||
|
||||
// Validate params against schema
|
||||
const newPath = `${
|
||||
this.prefix
|
||||
}/${name}${originalPathWithoutParams.substring(
|
||||
childPrefix.length
|
||||
)}`;
|
||||
const schema = this.querySchemas.get(newPath);
|
||||
|
||||
if (schema) {
|
||||
try {
|
||||
schema.parse(params);
|
||||
} catch (error) {
|
||||
console.error("Query params validation failed:", error);
|
||||
throw new Error("Invalid query parameters");
|
||||
}
|
||||
}
|
||||
|
||||
const queryString = Object.entries(params)
|
||||
.map(
|
||||
([k, v]) =>
|
||||
`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`
|
||||
)
|
||||
.join("&");
|
||||
return `${newBasePath}?${queryString}`;
|
||||
};
|
||||
} else if (key === "parse" && typeof obj[key] === "function") {
|
||||
result[key] = (searchParams: URLSearchParams) => {
|
||||
const originalPath = obj["get"]();
|
||||
const newPath = `${this.prefix}/${name}${originalPath.substring(
|
||||
childPrefix.length
|
||||
)}`;
|
||||
const schema = this.querySchemas.get(newPath);
|
||||
|
||||
if (!schema) return {};
|
||||
|
||||
// Convert URLSearchParams to object
|
||||
const queryObject: Record<string, any> = {};
|
||||
searchParams.forEach((value, key) => {
|
||||
queryObject[key] = value;
|
||||
});
|
||||
|
||||
// Parse through Zod schema
|
||||
try {
|
||||
return schema.parse(queryObject);
|
||||
} catch (error) {
|
||||
console.error("Failed to parse search params:", error);
|
||||
// Return safe default values
|
||||
const safeParsed = schema.safeParse(queryObject);
|
||||
if (safeParsed.success) {
|
||||
return safeParsed.data;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
} else if (typeof obj[key] === "object" && obj[key] !== null) {
|
||||
result[key] = updatePaths(obj[key], childPrefix);
|
||||
} else {
|
||||
result[key] = obj[key];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// Copy the child router's tree into this router
|
||||
this.tree[camelName] = updatePaths(
|
||||
(childRouter as any).tree,
|
||||
childRouter.prefix
|
||||
);
|
||||
|
||||
return this as any;
|
||||
}
|
||||
|
||||
// Allow access to the tree with strong typing
|
||||
get routes(): Routes {
|
||||
return this.tree as Routes;
|
||||
}
|
||||
}
|
||||
|
||||
export default V2ClientRouter;
|
||||
@@ -1,20 +0,0 @@
|
||||
import { z } from "zod";
|
||||
import V2ClientRouter from "../_lib/ClientRouter";
|
||||
|
||||
const dashboard = new V2ClientRouter({
|
||||
prefix: "/dashboard",
|
||||
name: "dashboard",
|
||||
})
|
||||
.add("/", {
|
||||
query: z.object({
|
||||
page: z.string(),
|
||||
}),
|
||||
})
|
||||
.add("/berita");
|
||||
|
||||
const router = new V2ClientRouter({
|
||||
prefix: "/percobaan",
|
||||
name: "percobaan",
|
||||
}).use("dashboard", dashboard);
|
||||
|
||||
export default router;
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<div>
|
||||
berita
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -1,33 +0,0 @@
|
||||
'use client'
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import router from '../_router/router';
|
||||
import { Box } from '@mantine/core';
|
||||
|
||||
|
||||
function Page() {
|
||||
const { page } = router.routes.dashboard.parse(useSearchParams())
|
||||
switch (page) {
|
||||
case "1":
|
||||
return <Page1 />
|
||||
case "2":
|
||||
return <Page2 />
|
||||
case "3":
|
||||
return <Page3 />
|
||||
default:
|
||||
return <Page1 />
|
||||
}
|
||||
}
|
||||
|
||||
const Page1 = () => {
|
||||
return <Box h={200} bg="red">Page 1</Box>
|
||||
}
|
||||
|
||||
const Page2 = () => {
|
||||
return <Box h={200} bg="blue">Page 2</Box>
|
||||
}
|
||||
|
||||
const Page3 = () => {
|
||||
return <Box h={200} bg="green">Page 3</Box>
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -1,105 +0,0 @@
|
||||
'use client'
|
||||
import { Box, Container, Flex, Grid, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import React from 'react';
|
||||
|
||||
const tx = `
|
||||
Untuk menambahkan fitur berbagi nomor WhatsApp di kode yang Anda miliki, saya akan menjelaskan beberapa pendekatan yang bisa digunakan. Biasanya ini dilakukan dengan membuat link yang ketika diklik akan membuka aplikasi WhatsApp dengan nomor tujuan yang sudah diatur.
|
||||
Berikut adalah cara mengimplementasikannya pada kode React Anda:
|
||||
`
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack>
|
||||
<Grid>
|
||||
<Grid.Col span={{
|
||||
base: 12,
|
||||
sm: 6,
|
||||
md: 4,
|
||||
xl: 10
|
||||
}}>
|
||||
<Box h={"200"} bg={"blue"}>1</Box>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={{
|
||||
base: 12,
|
||||
sm: 6,
|
||||
md: 8,
|
||||
xl: 2
|
||||
}}>
|
||||
<Box h={"200"} bg={"red"}>1</Box>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<SimpleGrid cols={{
|
||||
base: 1,
|
||||
sm: 2,
|
||||
md: 4,
|
||||
xl: 20
|
||||
}}>
|
||||
{Array.from({ length: 10 }).map((_, i) => (
|
||||
<Box key={i} h={"60"} bg={"blue"}>1</Box>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
<Flex >
|
||||
<Box w={400} h={"200"} bg={"blue"}>1</Box>
|
||||
<Box w={400} bg={"red"}>
|
||||
<Text fz={"42"} lineClamp={1} >{tx}</Text>
|
||||
<Text bg={"blue"} style={{
|
||||
fontSize: "2rem"
|
||||
}} lineClamp={1} >{tx}</Text>
|
||||
<Title order={1}>apa kabar</Title>
|
||||
</Box>
|
||||
|
||||
</Flex>
|
||||
|
||||
<Page2/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
|
||||
const Halaman = [Halaman1, Halaman2, Halaman3]
|
||||
|
||||
function Page2() {
|
||||
const page = useSearchParams().get("p");
|
||||
if (!page) return <Container >
|
||||
<Stack>
|
||||
<Text>halo 1</Text>
|
||||
{Array.from({ length: 4 }).map((v, k) => <Skeleton h={100} key={k} />)}
|
||||
</Stack>
|
||||
</Container>
|
||||
|
||||
|
||||
return (
|
||||
<Container w={"100%"}>
|
||||
<Stack>
|
||||
<Text>halo 2</Text>
|
||||
{Halaman[Number(page)-1]()}
|
||||
</Stack>
|
||||
</Container>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Halaman1() {
|
||||
return <Stack bg={"blue"}>
|
||||
ini halaman 1
|
||||
</Stack>
|
||||
}
|
||||
|
||||
|
||||
function Halaman2() {
|
||||
return <Stack bg={"red"}>
|
||||
ini halaman 2
|
||||
</Stack>
|
||||
}
|
||||
|
||||
|
||||
function Halaman3() {
|
||||
return <Stack bg={"grape"}>
|
||||
ini halaman 3
|
||||
</Stack>
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
'use client'
|
||||
import { Button, Group, Stack } from "@mantine/core"
|
||||
import { Link } from "next-view-transitions"
|
||||
import router from "./_router/router"
|
||||
|
||||
const Page = () => {
|
||||
return <Group>
|
||||
<Stack>
|
||||
{[1, 2, 3].map((v) => (<Button component={Link} href={router.routes.dashboard.query({
|
||||
page: v.toString(),
|
||||
})} key={v}>ke dashboard {v}</Button>))}
|
||||
|
||||
<Button component={Link} href={router.routes.dashboard.berita.get()}>berita</Button>
|
||||
</Stack>
|
||||
</Group>
|
||||
}
|
||||
|
||||
export default Page
|
||||
Reference in New Issue
Block a user