From 795c79dd5fc91d4b5a8edf449e949f83a2ecb1a1 Mon Sep 17 00:00:00 2001 From: nico Date: Tue, 6 May 2025 13:57:33 +0800 Subject: [PATCH 1/2] Tambahan Admin Di Menu PPID --- prisma/schema.prisma | 60 ++++ .../daftarInformasiPublik.ts | 65 ++++ .../grafikBerdasarkanJenisKelamin.ts | 77 +++++ .../grafikBerdasarkanResponden.ts | 84 +++++ .../grafikBerdasarkanUmur.ts | 84 +++++ .../grafikHasilKepuasan.ts | 76 +++++ .../(dashboard)/ppid/_com/ppid_Editor.tsx | 94 ++++++ .../page.tsx | 104 +++++- .../page.tsx | 138 ++++++++ .../_ui/grafik_berdasarkan_responden/page.tsx | 166 ++++++++++ .../_ui/grafik_berdasarkan_umur/page.tsx | 156 +++++++++ .../grafik_hasil_kepuasan_masyarakat/page.tsx | 88 +++++ .../ppid/ikm-desa-darmasaba/page.tsx | 40 ++- .../ppid/daftar_informasi_publik/create.ts | 29 ++ .../ppid/daftar_informasi_publik/find-many.ts | 9 + .../ppid/daftar_informasi_publik/index.ts | 18 ++ .../create.ts | 27 ++ .../find-many.ts | 8 + .../grafik_berdasarkan_jenis_kelamin/index.ts | 17 + .../ikm/grafik_berdasarkan_umur/create.ts | 31 ++ .../ikm/grafik_berdasarkan_umur/find-many.ts | 8 + .../ppid/ikm/grafik_berdasarkan_umur/index.ts | 19 ++ .../create.ts | 27 ++ .../find-many.ts | 8 + .../grafik_hasil_kepuasan_masyarakat/index.ts | 17 + .../_lib/ppid/ikm/grafik_responden/create.ts | 31 ++ .../ppid/ikm/grafik_responden/find-many.ts | 8 + .../_lib/ppid/ikm/grafik_responden/index.ts | 20 ++ src/app/api/[[...slugs]]/_lib/ppid/index.ts | 19 ++ src/app/api/[[...slugs]]/route.ts | 3 + src/app/percobaan/_lib/ClientRouter.txt | 300 ------------------ src/app/percobaan/_router/router.txt | 20 -- src/app/percobaan/dashboard/berita/page.txt | 11 - src/app/percobaan/dashboard/page.txt | 33 -- src/app/percobaan/page.txt | 105 ------ src/app/percobaan/page2.txt | 18 -- 36 files changed, 1525 insertions(+), 493 deletions(-) create mode 100644 src/app/admin/(dashboard)/_state/ppid/daftar_informasi_publik/daftarInformasiPublik.ts create mode 100644 src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin.ts create mode 100644 src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanResponden.ts create mode 100644 src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanUmur.ts create mode 100644 src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikHasilKepuasan.ts create mode 100644 src/app/admin/(dashboard)/ppid/_com/ppid_Editor.tsx create mode 100644 src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_jenis_kelamin_responden/page.tsx create mode 100644 src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_responden/page.tsx create mode 100644 src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_umur/page.tsx create mode 100644 src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_hasil_kepuasan_masyarakat/page.tsx create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/index.ts delete mode 100644 src/app/percobaan/_lib/ClientRouter.txt delete mode 100644 src/app/percobaan/_router/router.txt delete mode 100644 src/app/percobaan/dashboard/berita/page.txt delete mode 100644 src/app/percobaan/dashboard/page.txt delete mode 100644 src/app/percobaan/page.txt delete mode 100644 src/app/percobaan/page2.txt diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 81e339c1..96e49b8c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -47,6 +47,66 @@ model AppMenuChild { appMenuId String? } +//========================================= MENU PPID ========================================= // +// ========================================= DAFTAR INFORMASI PUBLIK ========================================= // +model DaftarInformasiPublik { + id String @id @default(cuid()) + nomor Int @default(autoincrement()) + jenisInformasi String + deskripsi String + tanggal String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + +//========================================= MENU PPID ========================================= // +// ========================================= IKM ========================================= // +model IndeksKepuasanMasyarakat { + id Int @id @default(autoincrement()) + label String + kepuasan String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + +model GrafikBerdasarkanJenisKelamin { + id String @id @default(cuid()) + perempuan String + laki String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + +model GrafikBerdasarkanResponden { + id String @id @default(cuid()) + sangatbaik String + baik String + kurangbaik String + tidakbaik String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + +model GrafikBerdasarkanUmur { + id String @id @default(cuid()) + remaja String + dewasa String + orangtua String + lansia String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + // ========================================= MENU DESA ========================================= // // ========================================= BERITA ========================================= // model Berita { diff --git a/src/app/admin/(dashboard)/_state/ppid/daftar_informasi_publik/daftarInformasiPublik.ts b/src/app/admin/(dashboard)/_state/ppid/daftar_informasi_publik/daftarInformasiPublik.ts new file mode 100644 index 00000000..ff0b2792 --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ppid/daftar_informasi_publik/daftarInformasiPublik.ts @@ -0,0 +1,65 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateDaftarInformasi = z.object({ + jenisInformasi: z.string().min(3, "Jenis Informasi minimal 3 karakter"), + deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"), + tanggal: z.string().min(3, "Tanggal minimal 3 karakter"), +}) + +type DaftarInformasi = Prisma.DaftarInformasiPublikGetPayload<{ + select: { + jenisInformasi: true; + deskripsi: true; + tanggal: true; + }; +}>; + +const daftarInformasi = proxy({ + create: { + form: {} as DaftarInformasi, + loading: false, + async create() { + const cek = templateDaftarInformasi.safeParse(daftarInformasi.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + daftarInformasi.create.loading = true; + const res = await ApiFetch.api.ppid.daftarinformasipublik["create"].post(daftarInformasi.create.form); + if (res.status === 200) { + daftarInformasi.findMany.load(); + return toast.success("success create"); + } + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + daftarInformasi.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.DaftarInformasiPublikGetPayload<{ omit: { isActive: true } }>[] + | null, + async load() { + const res = await ApiFetch.api.ppid.daftarinformasipublik["find-many"].get(); + if (res.status === 200) { + daftarInformasi.findMany.data = res.data?.data ?? []; + } + } + } + }); + + const stateDaftarInformasiPublik = proxy({ + daftarInformasi + }) + + export default stateDaftarInformasiPublik; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin.ts b/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin.ts new file mode 100644 index 00000000..5e2c0192 --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin.ts @@ -0,0 +1,77 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateGrafikJenisKelamin = z.object({ + laki: z.string().min(2, "Data laki-laki harus diisi"), + perempuan: z.string().min(2, "Data perempuan harus diisi"), +}); + +type GrafikJenisKelamin = Prisma.GrafikBerdasarkanJenisKelaminGetPayload<{ + select: { + laki: true; + perempuan: true; + }; +}>; + +const defaultForm: GrafikJenisKelamin = { + laki: "", + perempuan: "", +}; + +const grafikBerdasarkanJenisKelamin = proxy({ + create: { + form: defaultForm, + loading: false, + async create() { + const cek = templateGrafikJenisKelamin.safeParse( + grafikBerdasarkanJenisKelamin.create.form + ); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + grafikBerdasarkanJenisKelamin.create.loading = true; + const res = await ApiFetch.api.ppid.grafikberdasarkanjeniskelamin[ + "create" + ].post(grafikBerdasarkanJenisKelamin.create.form); + if (res.status === 200) { + grafikBerdasarkanJenisKelamin.create.form = defaultForm; + grafikBerdasarkanJenisKelamin.findMany.load(); + return toast.success("success create"); + } + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + grafikBerdasarkanJenisKelamin.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.GrafikBerdasarkanJenisKelaminGetPayload<{ + omit: { isActive: true }; + }>[] + | null, + loading: false, + async load() { + const res = await ApiFetch.api.ppid.grafikberdasarkanjeniskelamin[ + "find-many" + ].get(); + if (res.status === 200) { + grafikBerdasarkanJenisKelamin.findMany.data = res.data?.data ?? []; + } + }, + }, +}); + +const stateGrafikBerdasarkanJenisKelamin = proxy({ + grafikBerdasarkanJenisKelamin, +}); +export default stateGrafikBerdasarkanJenisKelamin; diff --git a/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanResponden.ts b/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanResponden.ts new file mode 100644 index 00000000..4fd2e69b --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanResponden.ts @@ -0,0 +1,84 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateGrafikResponden = z.object({ + sangatbaik: z.string().min(1, "Data sangat baik harus diisi"), + baik: z.string().min(1, "Data baik harus diisi"), + kurangbaik: z.string().min(1, "Data kurang baik harus diisi"), + tidakbaik: z.string().min(1, "Data tidak baik harus diisi"), +}); + +type GrafikResponden = Prisma.GrafikBerdasarkanRespondenGetPayload<{ + select: { + sangatbaik: true; + baik: true; + kurangbaik: true; + tidakbaik: true; + }; +}>; + +const defaultForm: GrafikResponden = { + sangatbaik: "", + baik: "", + kurangbaik: "", + tidakbaik: "", +}; + +const grafikBerdasarkanResponden = proxy({ + create: { + form: defaultForm, + loading: false, + async create() { + const cek = templateGrafikResponden.safeParse( + grafikBerdasarkanResponden.create.form + ); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + grafikBerdasarkanResponden.create.loading = true; + const res = await ApiFetch.api.ppid.grafikberdasarkanresponden[ + "create" + ].post(grafikBerdasarkanResponden.create.form); + if (res.status === 200) { + grafikBerdasarkanResponden.create.form = defaultForm; + grafikBerdasarkanResponden.findMany.load(); + return toast.success("success create"); + } + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + grafikBerdasarkanResponden.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.GrafikBerdasarkanRespondenGetPayload<{ + omit: { isActive: true }; + }>[] + | null, + loading: false, + async load() { + const res = await ApiFetch.api.ppid.grafikberdasarkanresponden[ + "find-many" + ].get(); + if (res.status === 200) { + grafikBerdasarkanResponden.findMany.data = res.data?.data ?? []; + } + }, + }, +}); + +const stateGrafikResponden = proxy({ + grafikBerdasarkanResponden, +}); + +export default stateGrafikResponden; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanUmur.ts b/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanUmur.ts new file mode 100644 index 00000000..3d05f6cf --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanUmur.ts @@ -0,0 +1,84 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateGrafikUmur = z.object({ + remaja: z.string().min(2, "Data remaja harus diisi"), + dewasa: z.string().min(2, "Data dewasa harus diisi"), + orangtua: z.string().min(2, "Data orangtua harus diisi"), + lansia: z.string().min(2, "Data lansia harus diisi"), +}); + +type GrafikUmur = Prisma.GrafikBerdasarkanUmurGetPayload<{ + select: { + remaja: true; + dewasa: true; + orangtua: true; + lansia: true; + }; +}>; + +const defaultForm: GrafikUmur = { + remaja: "", + dewasa: "", + orangtua: "", + lansia: "", +}; + +const grafikBerdasarkanUmur = proxy({ + create: { + form: defaultForm, + loading: false, + async create() { + const cek = templateGrafikUmur.safeParse( + grafikBerdasarkanUmur.create.form + ); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + grafikBerdasarkanUmur.create.loading = true; + const res = await ApiFetch.api.ppid.grafikberdasarkanumur[ + "create" + ].post(grafikBerdasarkanUmur.create.form); + if (res.status === 200) { + grafikBerdasarkanUmur.create.form = defaultForm; + grafikBerdasarkanUmur.findMany.load(); + return toast.success("success create"); + } + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + grafikBerdasarkanUmur.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.GrafikBerdasarkanUmurGetPayload<{ + omit: { isActive: true }; + }>[] + | null, + loading: false, + async load() { + const res = await ApiFetch.api.ppid.grafikberdasarkanumur[ + "find-many" + ].get(); + if (res.status === 200) { + grafikBerdasarkanUmur.findMany.data = res.data?.data ?? []; + } + }, + }, +}) + +const stateGrafikBerdasarkanUmur = proxy({ + grafikBerdasarkanUmur, +}) + +export default stateGrafikBerdasarkanUmur; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikHasilKepuasan.ts b/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikHasilKepuasan.ts new file mode 100644 index 00000000..b8badf0c --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikHasilKepuasan.ts @@ -0,0 +1,76 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateGrafikHasilKepuasanMasyarakat = z.object({ + label: z.string().min(2, "Label harus diisi"), + kepuasan: z.string().min(2, "Kepuasan harus diisi"), +}); + +type GrafikHasilKepuasanMasyarakat = Prisma.IndeksKepuasanMasyarakatGetPayload<{ + select: { + label: true; + kepuasan: true; + }; +}>; + +const defaultForm: GrafikHasilKepuasanMasyarakat = { + label: "", + kepuasan: "", +}; + +const grafikHasilKepuasanMasyarakat = proxy({ + create: { + form: defaultForm, + loading: false, + async create() { + const cek = templateGrafikHasilKepuasanMasyarakat.safeParse( + grafikHasilKepuasanMasyarakat.create.form + ); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + grafikHasilKepuasanMasyarakat.create.loading = true; + const res = await ApiFetch.api.ppid.grafikhasilkepuasamanmasyarakat["create"].post( + grafikHasilKepuasanMasyarakat.create.form + ); + if (res.status === 200) { + grafikHasilKepuasanMasyarakat.create.form = { + label: "", + kepuasan: "" + }; + grafikHasilKepuasanMasyarakat.findMany.load(); + return toast.success("success create"); + } + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + grafikHasilKepuasanMasyarakat.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.IndeksKepuasanMasyarakatGetPayload<{ omit: { isActive: true } }>[] + | null, + async load() { + const res = await ApiFetch.api.ppid.grafikhasilkepuasamanmasyarakat["find-many"].get(); + if (res.status === 200) { + grafikHasilKepuasanMasyarakat.findMany.data = res.data?.data ?? []; + } + } + } +}); + +const stateGrafikHasilKepuasanMasyarakat = proxy({ + grafikHasilKepuasanMasyarakat, +}); + +export default stateGrafikHasilKepuasanMasyarakat; diff --git a/src/app/admin/(dashboard)/ppid/_com/ppid_Editor.tsx b/src/app/admin/(dashboard)/ppid/_com/ppid_Editor.tsx new file mode 100644 index 00000000..29954bc9 --- /dev/null +++ b/src/app/admin/(dashboard)/ppid/_com/ppid_Editor.tsx @@ -0,0 +1,94 @@ +'use client' +import { Button, Stack } from '@mantine/core'; +import { Link, RichTextEditor } from '@mantine/tiptap'; +import Highlight from '@tiptap/extension-highlight'; +import SubScript from '@tiptap/extension-subscript'; +import Superscript from '@tiptap/extension-superscript'; +import TextAlign from '@tiptap/extension-text-align'; +import Underline from '@tiptap/extension-underline'; +import { useEditor } from '@tiptap/react'; +import StarterKit from '@tiptap/starter-kit'; + +const content = + '

Welcome to Mantine rich text editor

RichTextEditor component focuses on usability and is designed to be as simple as possible to bring a familiar editing experience to regular users. RichTextEditor is based on Tiptap.dev and supports all of its features:

'; + +export function PPIDEditor({ onSubmit, onChange, showSubmit = true }: { + onSubmit?: (val: string) => void, + onChange: (val: string) => void, + showSubmit?: boolean }) { + const editor = useEditor({ + extensions: [ + StarterKit, + Underline, + Link, + Superscript, + SubScript, + Highlight, + TextAlign.configure({ types: ['heading', 'paragraph'] }), + ], + immediatelyRender: false, + content, + onUpdate : ({editor}) => { + onChange(editor.getHTML()) + } + }); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {showSubmit && ( + + )} + + ); +} \ No newline at end of file diff --git a/src/app/admin/(dashboard)/ppid/daftar-informasi-publik-desa-darmasaba/page.tsx b/src/app/admin/(dashboard)/ppid/daftar-informasi-publik-desa-darmasaba/page.tsx index 2ea8f73f..60d146dd 100644 --- a/src/app/admin/(dashboard)/ppid/daftar-informasi-publik-desa-darmasaba/page.tsx +++ b/src/app/admin/(dashboard)/ppid/daftar-informasi-publik-desa-darmasaba/page.tsx @@ -1,11 +1,109 @@ +'use client' +import { Box, Button, Group, SimpleGrid, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, TextInput, Title } from '@mantine/core'; import React from 'react'; +import { useProxy } from 'valtio/utils'; +import stateDaftarInformasiPublik from '../../_state/ppid/daftar_informasi_publik/daftarInformasiPublik'; +import { PPIDEditor } from '../_com/ppid_Editor'; +import colors from '@/con/colors'; +import { useShallowEffect } from '@mantine/hooks'; function Page() { + const daftarInformasi = useProxy(stateDaftarInformasiPublik.daftarInformasi) + const submit = () => { + if (daftarInformasi.create.form.jenisInformasi && + daftarInformasi.create.form.deskripsi && + daftarInformasi.create.form.tanggal) { + daftarInformasi.create.create() + } + } return ( -
- daftar-informasi-publik-desa-darmasaba -
+ + + + + Daftar Informasi Publik Desa Darmasaba + { + daftarInformasi.create.form.jenisInformasi = val.target.value + }} + /> + { + daftarInformasi.create.form.deskripsi = val + }} + /> + { + daftarInformasi.create.form.tanggal = val.target.value + }} + /> + + + + + + + + + + ); } +function ListDaftarInformasi() { + const listData = useProxy(stateDaftarInformasiPublik.daftarInformasi) + useShallowEffect(() => { + listData.findMany.load() + }, []) + if (!listData.findMany.data) return + {Array.from({length: 10}).map((v, k) => )} + + return + List Daftar Informasi Publik Desa Darmasaba + + + + + No + + + Jenis Informasi + + + Deskripsi + + + Tanggal Publikasi + + + + + {listData.findMany.data?.map((item) => ( + + {item.nomor} + {item.jenisInformasi} + + {item.tanggal} + + ))} + +
+
+} + export default Page; diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_jenis_kelamin_responden/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_jenis_kelamin_responden/page.tsx new file mode 100644 index 00000000..93b30c06 --- /dev/null +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_jenis_kelamin_responden/page.tsx @@ -0,0 +1,138 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +'use client' +import stateGrafikBerdasarkanJenisKelamin from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin'; +import colors from '@/con/colors'; +import { Box, Button, Center, Flex, Stack, Text, TextInput, Title } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { useEffect, useState } from 'react'; +import { Cell, Pie, PieChart } from 'recharts'; +import { useProxy } from 'valtio/utils'; + +function GrafikBerdasarkanJenisKelamin() { + const grafikBerdasarkanJenisKelamin = useProxy(stateGrafikBerdasarkanJenisKelamin.grafikBerdasarkanJenisKelamin) + const [donutData, setDonutData] = useState([]); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []) + + const updateChartData = (data: any) => { + if (data && data.length > 0) { + const totalLaki = data.reduce((acc: number, cur: any) => acc + Number(cur.laki || 0), 0); + const totalPerempuan = data.reduce((acc: number, cur: any) => acc + Number(cur.perempuan || 0), 0); + + setDonutData([ + { name: 'Laki-laki', value: totalLaki, color: colors['blue-button'], key: 'laki-laki' }, + { name: 'Perempuan', value: totalPerempuan, color: '#FF6384', key: 'perempuan' } + ]); + } + }; + + useShallowEffect(() => { + fetchData(); + }, []); + + const fetchData = async () => { + await grafikBerdasarkanJenisKelamin.findMany.load(); + if (grafikBerdasarkanJenisKelamin.findMany.data) { + updateChartData(grafikBerdasarkanJenisKelamin.findMany.data); + } + }; + + const handleSubmit = async () => { + try { + // Simpan data baru + await grafikBerdasarkanJenisKelamin.create.create(); + + // Muat ulang data + await grafikBerdasarkanJenisKelamin.findMany.load(); + + // Update chart dengan data baru + if (grafikBerdasarkanJenisKelamin.findMany.data) { + updateChartData(grafikBerdasarkanJenisKelamin.findMany.data); + } + + // Reset form setelah submit + grafikBerdasarkanJenisKelamin.create.form.laki = ''; + grafikBerdasarkanJenisKelamin.create.form.perempuan = ''; + } catch (error) { + console.error("Error submitting data:", error); + } + }; + + return ( + + + Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik + { + grafikBerdasarkanJenisKelamin.create.form.laki = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanJenisKelamin.create.form.perempuan = val.currentTarget.value; + }} + /> + + + + {/* Chart */} + + + Grafik Berdasarkan Jenis Kelamin Responden + {mounted && donutData.length > 0 && ( + +
+ + + + {donutData.map((entry, index) => ( + + ))} + + +
+ + + Perempuan: {donutData.find((entry) => entry.name === 'Perempuan')?.value} + + + + Laki-laki: {donutData.find((entry) => entry.name === 'Laki-laki')?.value} + +
+ )} +
+
+
+ ); +} + +export default GrafikBerdasarkanJenisKelamin; diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_responden/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_responden/page.tsx new file mode 100644 index 00000000..f4d8651d --- /dev/null +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_responden/page.tsx @@ -0,0 +1,166 @@ +'use client' +/* eslint-disable @typescript-eslint/no-explicit-any */ +import stateGrafikResponden from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanResponden'; +import colors from '@/con/colors'; +import { Box, Button, Center, Flex, Stack, Text, TextInput, Title } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import React, { useEffect, useState } from 'react'; +import { PieChart, Pie, Cell } from 'recharts'; +import { useProxy } from 'valtio/utils'; + +function GrafikBerdasarkanResponden() { + const grafikBerdasarkanResponden = useProxy(stateGrafikResponden.grafikBerdasarkanResponden) + const [donutData, setDonutData] = useState([]); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []) + + const updateChartData = (data: any) => { + if (data && data.length > 0) { + const totalSangatBaik = data.reduce((acc: number, cur: any) => acc + Number(cur.sangatbaik || 0), 0); + const totalBaik = data.reduce((acc: number, cur: any) => acc + Number(cur.baik || 0), 0); + const totalKurangBaik = data.reduce((acc: number, cur: any) => acc + Number(cur.kurangbaik || 0), 0); + const totalTidakBaik = data.reduce((acc: number, cur: any) => acc + Number(cur.tidakbaik || 0), 0); + setDonutData([ + { name: 'sangatbaik', value: totalSangatBaik, color: colors['blue-button'], key: 'sangatbaik' }, + { name: 'baik', value: totalBaik, color: '#10A85AFF', key: 'baik' }, + { name: 'kurangbaik', value: totalKurangBaik, color: '#B3AA12FF', key: 'kurangbaik' }, + { name: 'tidakbaik', value: totalTidakBaik, color: '#B21313FF', key: 'tidakbaik' } + ]); + } + }; + + useShallowEffect(() => { + fetchData(); + }, []); + + const fetchData = async () => { + await grafikBerdasarkanResponden.findMany.load(); + if (grafikBerdasarkanResponden.findMany.data) { + updateChartData(grafikBerdasarkanResponden.findMany.data); + } + }; + + const handleSubmit = async () => { + try { + // Simpan data baru + await grafikBerdasarkanResponden.create.create(); + + // Muat ulang data + await grafikBerdasarkanResponden.findMany.load(); + + // Update chart dengan data baru + if (grafikBerdasarkanResponden.findMany.data) { + updateChartData(grafikBerdasarkanResponden.findMany.data); + } + + // Reset form setelah submit + grafikBerdasarkanResponden.create.form.sangatbaik = ''; + grafikBerdasarkanResponden.create.form.baik = ''; + grafikBerdasarkanResponden.create.form.kurangbaik = ''; + grafikBerdasarkanResponden.create.form.tidakbaik = ''; + } catch (error) { + console.error("Error submitting data:", error); + } + }; + return ( + + + Grafik Berdasarkan Responden + { + grafikBerdasarkanResponden.create.form.sangatbaik = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanResponden.create.form.baik = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanResponden.create.form.kurangbaik = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanResponden.create.form.tidakbaik = val.currentTarget.value; + }} + /> + + + + {/* Chart */} + + + Grafik Berdasarkan Responden + {mounted && donutData.length > 0 && ( + +
+ + + {donutData.map((entry, index) => ( + + ))} + + +
+ + + Sangat Baik: {donutData.find((entry) => entry.name === 'sangatbaik')?.value} + + + + Baik: {donutData.find((entry) => entry.name === 'baik')?.value} + + + + Kurang Baik: {donutData.find((entry) => entry.name === 'kurangbaik')?.value} + + + + Tidak Baik: {donutData.find((entry) => entry.name === 'tidakbaik')?.value} + +
+ )} +
+
+
+ ); +} + +export default GrafikBerdasarkanResponden; diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_umur/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_umur/page.tsx new file mode 100644 index 00000000..b85ed036 --- /dev/null +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_umur/page.tsx @@ -0,0 +1,156 @@ +'use client' +/* eslint-disable @typescript-eslint/no-explicit-any */ +import colors from '@/con/colors'; +import { Box, Button, Center, Flex, Stack, Text, TextInput, Title } from '@mantine/core'; +import React, { useEffect, useState } from 'react'; +import { useProxy } from 'valtio/utils'; +import stateGrafikBerdasarkanUmur from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanUmur'; +import { useShallowEffect } from '@mantine/hooks'; +import { PieChart, Pie, Cell } from 'recharts'; + +function GrafikBerdasarakanUmur() { + const grafikBerdasarkanUmur = useProxy(stateGrafikBerdasarkanUmur.grafikBerdasarkanUmur) + const [donutData, setDonutData] = useState([]); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + const updateChartData = (data: any) => { + if (data && data.length > 0) { + const totalRemaja = data.reduce((acc: number, cur: any) => acc + Number(cur.remaja || 0), 0); + const totalDewasa = data.reduce((acc: number, cur: any) => acc + Number(cur.dewasa || 0), 0); + const totalOrangtua = data.reduce((acc: number, cur: any) => acc + Number(cur.orangtua || 0), 0); + const totalLansia = data.reduce((acc: number, cur: any) => acc + Number(cur.lansia || 0), 0); + + setDonutData([ + { name: 'Remaja', value: totalRemaja, color: colors['blue-button'], key: 'remaja' }, + { name: 'Dewasa', value: totalDewasa, color: '#D32711FF', key: 'dewasa' }, + { name: 'Orangtua', value: totalOrangtua, color: '#B46B04FF', key: 'orangtua' }, + { name: 'Lansia', value: totalLansia, color: '#038617FF', key: 'lansia' } + ]); + } + }; + + useShallowEffect(() => { + fetchData(); + }, []); + +const fetchData = async () => { + await grafikBerdasarkanUmur.findMany.load(); + if (grafikBerdasarkanUmur.findMany.data) { + updateChartData(grafikBerdasarkanUmur.findMany.data); + } +} + +const handleSubmit = async () => { + try { + await grafikBerdasarkanUmur.create.create(); + await grafikBerdasarkanUmur.findMany.load(); + if (grafikBerdasarkanUmur.findMany.data) { + updateChartData(grafikBerdasarkanUmur.findMany.data); + } + } catch (error) { + console.error("Error submitting data:", error); + } +} + return ( + + + Grafik Berdasarkan Umur Responden + { + grafikBerdasarkanUmur.create.form.remaja = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanUmur.create.form.dewasa = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanUmur.create.form.orangtua = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanUmur.create.form.lansia = val.currentTarget.value; + }} + /> + + + + {/* Chart */} + + + Grafik Berdasarkan Umur Responden + {mounted && donutData.length > 0 && ( + +
+ + + {donutData.map((entry, index) => ( + + ))} + + +
+ + + 17 - 25 tahun: {donutData.find((entry) => entry.name === 'remaja')?.value} + + + + 26 - 45 tahun: {donutData.find((entry) => entry.name === 'dewasa')?.value} + + + + 46 - 60 tahun: {donutData.find((entry) => entry.name === 'orangtua')?.value} + + + + di atas 60 tahun: {donutData.find((entry) => entry.name === 'lansia')?.value} + +
+ )} +
+
+
+ ); +} + +export default GrafikBerdasarakanUmur; diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_hasil_kepuasan_masyarakat/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_hasil_kepuasan_masyarakat/page.tsx new file mode 100644 index 00000000..92596971 --- /dev/null +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_hasil_kepuasan_masyarakat/page.tsx @@ -0,0 +1,88 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +'use client' +import stateGrafikHasilKepuasanMasyarakat from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikHasilKepuasan'; +import colors from '@/con/colors'; +import { Box, Button, TextInput, Title } from '@mantine/core'; +import { useMediaQuery, useShallowEffect } from '@mantine/hooks'; +import React, { useEffect, useState } from 'react'; +import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts'; +import { useProxy } from 'valtio/utils'; + +function GrafikHasilKepuasan() { + const grafikHasilKepuasan = useProxy(stateGrafikHasilKepuasanMasyarakat.grafikHasilKepuasanMasyarakat) + const [chartData, setChartData] = useState([]); + const [mounted, setMounted] = useState(false); + const isTablet = useMediaQuery('(max-width: 1024px)') + const isMobile = useMediaQuery('(max-width: 768px)') + + useEffect(() => { + setMounted(true); + }, []) + + useShallowEffect(() => { + const fetchData = async () => { + await grafikHasilKepuasan.findMany.load(); + if (grafikHasilKepuasan.findMany.data && grafikHasilKepuasan.findMany.data.length > 0) { + setChartData(grafikHasilKepuasan.findMany.data); + } + }; + fetchData(); + }, []); + + return ( + + + Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik + { + grafikHasilKepuasan.create.form.label = val.currentTarget.value; + }} + /> + { + grafikHasilKepuasan.create.form.kepuasan = val.currentTarget.value; + }} + /> + + + + {/* Chart */} + + Data Kepuasan Masyarakat + {mounted && chartData.length > 0 && ( + + + + + + + + )} + + + + ); +} + +export default GrafikHasilKepuasan; diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/page.tsx index c5444919..f3c7cbbd 100644 --- a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/page.tsx +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/page.tsx @@ -1,10 +1,44 @@ +import { Stack, Tabs, TabsList, TabsPanel, TabsTab } from '@mantine/core'; import React from 'react'; +import colors from '@/con/colors'; +import GrafikHasilKepuasan from './_ui/grafik_hasil_kepuasan_masyarakat/page'; +import GrafikBerdasarkanJenisKelamin from './_ui/grafik_berdasarkan_jenis_kelamin_responden/page'; +import GrafikBerdasarkanResponden from './_ui/grafik_berdasarkan_responden/page'; +import GrafikBerdasarakanUmur from './_ui/grafik_berdasarkan_umur/page'; function Page() { return ( -
- ikm-desa-darmasaba -
+ + + + + Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik + + + Grafik Berdasarkan Jenis Kelamin Responden + + + Grafik Berdasarkan Pilihan Responden + + + Grafik Berdasarkan Umur Responden + + + + + + + + + + + + + + + + + ); } diff --git a/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/create.ts b/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/create.ts new file mode 100644 index 00000000..79a95c98 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/create.ts @@ -0,0 +1,29 @@ +import prisma from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; + +type FormCreate = Prisma.DaftarInformasiPublikGetPayload<{ + select: { + jenisInformasi: true; + deskripsi: true; + tanggal: true; + } +}> +export default async function daftarInformasiPublikCreate(context: Context) { + const body = context.body as FormCreate; + + await prisma.daftarInformasiPublik.create({ + data: { + jenisInformasi: body.jenisInformasi, + deskripsi: body.deskripsi, + tanggal: body.tanggal, + }, + }) + return { + success: true, + message: "Success create daftar informasi publik", + data: { + ...body, + }, + }; +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/find-many.ts b/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/find-many.ts new file mode 100644 index 00000000..12bb8881 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/find-many.ts @@ -0,0 +1,9 @@ +import prisma from "@/lib/prisma"; + +export default async function daftarInformasiPublikFindMany() { + const res = await prisma.daftarInformasiPublik.findMany(); + return { + data: res + } +} + \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/index.ts b/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/index.ts new file mode 100644 index 00000000..36b0fcf4 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/daftar_informasi_publik/index.ts @@ -0,0 +1,18 @@ +import Elysia, { t } from "elysia"; +import daftarInformasiPublikCreate from "./create"; +import daftarInformasiPublikFindMany from "./find-many"; + +const DaftarInformasiPublik = new Elysia({ + prefix: "/daftarinformasipublik", + tags: ["PPID/Daftar Informasi Publik"] +}) + .get("/find-many", daftarInformasiPublikFindMany) + .post("/create", daftarInformasiPublikCreate, { + body: t.Object({ + jenisInformasi: t.String(), + deskripsi: t.String(), + tanggal: t.String(), + }), + }) + +export default DaftarInformasiPublik \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/create.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/create.ts new file mode 100644 index 00000000..3c58f22d --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/create.ts @@ -0,0 +1,27 @@ +import prisma from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; + +type FormCreate = Prisma.GrafikBerdasarkanJenisKelaminGetPayload<{ + select: { + perempuan: true; + laki: true; + } +}> +export default async function grafikBerdasarkanJenisKelaminCreate(context: Context) { + const body = context.body as FormCreate; + + await prisma.grafikBerdasarkanJenisKelamin.create({ + data: { + perempuan: body.perempuan, + laki: body.laki, + }, + }); + return { + success: true, + message: "Success create grafik berdasarkan jenis kelamin", + data: { + ...body, + }, + }; +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/find-many.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/find-many.ts new file mode 100644 index 00000000..0960c1d6 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/find-many.ts @@ -0,0 +1,8 @@ +import prisma from "@/lib/prisma"; + +export default async function grafikBerdasarkanJenisKelaminFindMany() { + const res = await prisma.grafikBerdasarkanJenisKelamin.findMany(); + return { + data: res + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/index.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/index.ts new file mode 100644 index 00000000..88c7ddd7 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_jenis_kelamin/index.ts @@ -0,0 +1,17 @@ +import Elysia, { t } from "elysia"; +import grafikBerdasarkanJenisKelaminCreate from "./create"; +import grafikBerdasarkanJenisKelaminFindMany from "./find-many"; + + +const GrafikBerdasarkanJenisKelamin = new Elysia({ + prefix: "/grafikberdasarkanjeniskelamin", + tags: ["PPID/IKM/grafikberdasarkanjeniskelamin"], +}) + .get("/find-many", grafikBerdasarkanJenisKelaminFindMany) + .post("/create", grafikBerdasarkanJenisKelaminCreate, { + body: t.Object({ + perempuan: t.String(), + laki: t.String(), + }), + }); +export default GrafikBerdasarkanJenisKelamin; diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/create.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/create.ts new file mode 100644 index 00000000..8444d0df --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/create.ts @@ -0,0 +1,31 @@ +import prisma from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; + +type FormCreate = Prisma.GrafikBerdasarkanUmurGetPayload<{ + select: { + remaja: true; + dewasa: true; + orangtua: true; + lansia: true; + } +}> +export async function grafikBerdasarkanUmurCreate(context: Context) { + const body = context.body as FormCreate; + + await prisma.grafikBerdasarkanUmur.create({ + data: { + remaja: body.remaja, + dewasa: body.dewasa, + orangtua: body.orangtua, + lansia: body.lansia, + }, + }); + return { + success: true, + message: "Success create grafik berdasarkan umur", + data: { + ...body, + }, + }; +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/find-many.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/find-many.ts new file mode 100644 index 00000000..d050abfc --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/find-many.ts @@ -0,0 +1,8 @@ +import prisma from "@/lib/prisma"; + +export async function grafikBerdasarkanUmurFindMany(){ + const res = await prisma.grafikBerdasarkanUmur.findMany(); + return { + data: res + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/index.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/index.ts new file mode 100644 index 00000000..94051b31 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_berdasarkan_umur/index.ts @@ -0,0 +1,19 @@ +import Elysia, { t } from "elysia"; +import { grafikBerdasarkanUmurFindMany } from "./find-many"; +import { grafikBerdasarkanUmurCreate } from "./create"; + +const GrafikBerdasarkanUmur = new Elysia({ + prefix: "/grafikberdasarkanumur", + tags: ["PPID/IKM/grafikberdasarkanumur"] +}) + .get("/find-many", grafikBerdasarkanUmurFindMany) + .post("/create", grafikBerdasarkanUmurCreate, { + body: t.Object({ + remaja: t.String(), + dewasa: t.String(), + orangtua: t.String(), + lansia: t.String(), + }), + }); + +export default GrafikBerdasarkanUmur; \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/create.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/create.ts new file mode 100644 index 00000000..8d57d7e4 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/create.ts @@ -0,0 +1,27 @@ +import prisma from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; + +type FormCreate = Prisma.IndeksKepuasanMasyarakatGetPayload<{ + select: { + label: true; + kepuasan: true; + }; +}>; +export default async function grafikHasilKepuasanMasyarakatCreate(context: Context) { + const body = context.body as FormCreate; + + await prisma.indeksKepuasanMasyarakat.create({ + data: { + label: body.label, + kepuasan: body.kepuasan, + }, + }); + return { + success: true, + message: "Success create grafik hasil kepuasan masyarakat", + data: { + ...body, + }, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/find-many.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/find-many.ts new file mode 100644 index 00000000..6e39d8a5 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/find-many.ts @@ -0,0 +1,8 @@ +import prisma from "@/lib/prisma"; + +export default async function grafikHasilKepuasanMasyarakatFindMany() { + const res = await prisma.indeksKepuasanMasyarakat.findMany(); + return { + data: res, + }; +} diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/index.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/index.ts new file mode 100644 index 00000000..29358dd5 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_hasil_kepuasan_masyarakat/index.ts @@ -0,0 +1,17 @@ +import Elysia, { t } from "elysia"; +import grafikHasilKepuasanMasyarakatCreate from "./create"; +import grafikHasilKepuasanMasyarakatFindMany from "./find-many"; + +const GrafikHasilKepuasanMasyarakat = new Elysia({ + prefix: "/grafikhasilkepuasamanmasyarakat", + tags: ["PPID/IKM/grafikhasilkepuasanmasyarakat"], +}) + .get("/find-many", grafikHasilKepuasanMasyarakatFindMany) + .post("/create", grafikHasilKepuasanMasyarakatCreate, { + body: t.Object({ + label: t.String(), + kepuasan: t.String(), + }), + }); + +export default GrafikHasilKepuasanMasyarakat; diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/create.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/create.ts new file mode 100644 index 00000000..89c71102 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/create.ts @@ -0,0 +1,31 @@ +import prisma from "@/lib/prisma"; +import { Prisma } from "@prisma/client"; +import { Context } from "elysia"; + +type FormCreate = Prisma.GrafikBerdasarkanRespondenGetPayload<{ + select: { + sangatbaik: true; + baik: true; + kurangbaik: true; + tidakbaik: true + }; +}>; +export default async function grafikRespondenCreate(context: Context) { + const body = context.body as FormCreate; + + await prisma.grafikBerdasarkanResponden.create({ + data: { + sangatbaik: body.sangatbaik, + baik: body.baik, + kurangbaik: body.kurangbaik, + tidakbaik: body.tidakbaik, + }, + }); + return { + success: true, + message: "Success create grafik berdasarkan responden", + data: { + ...body, + }, + }; +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/find-many.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/find-many.ts new file mode 100644 index 00000000..cd853f5c --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/find-many.ts @@ -0,0 +1,8 @@ +import prisma from "@/lib/prisma"; + +export default async function grafikRespondenFindMany(){ + const res = await prisma.grafikBerdasarkanResponden.findMany(); + return{ + data: res + } +} \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/index.ts b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/index.ts new file mode 100644 index 00000000..4bae7832 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/ikm/grafik_responden/index.ts @@ -0,0 +1,20 @@ +import Elysia, { t } from "elysia"; +import grafikRespondenCreate from "./create"; +import grafikRespondenFindMany from "./find-many"; + +const GrafikBerdasarkanResponden = new Elysia({ + prefix: "/grafikberdasarkanresponden", + tags: ["PPID/IKM/grafikberdasarkanresponden"] +}) +.get("/find-many", grafikRespondenFindMany) +.post("/create", grafikRespondenCreate, { + body: t.Object({ + sangatbaik: t.String(), + baik: t.String(), + kurangbaik: t.String(), + tidakbaik: t.String(), + }), +}) + + +export default GrafikBerdasarkanResponden \ No newline at end of file diff --git a/src/app/api/[[...slugs]]/_lib/ppid/index.ts b/src/app/api/[[...slugs]]/_lib/ppid/index.ts new file mode 100644 index 00000000..2f43aba6 --- /dev/null +++ b/src/app/api/[[...slugs]]/_lib/ppid/index.ts @@ -0,0 +1,19 @@ +import Elysia from "elysia"; +import DaftarInformasiPublik from "./daftar_informasi_publik"; +import GrafikHasilKepuasanMasyarakat from "./ikm/grafik_hasil_kepuasan_masyarakat"; +import GrafikBerdasarkanJenisKelamin from "./ikm/grafik_berdasarkan_jenis_kelamin"; +import GrafikBerdasarkanResponden from "./ikm/grafik_responden"; +import GrafikBerdasarkanUmur from "./ikm/grafik_berdasarkan_umur"; + + +const PPID = new Elysia({ prefix: "/api/ppid", tags: ["PPID"] }) +.use(DaftarInformasiPublik) +.use(GrafikHasilKepuasanMasyarakat) +.use(GrafikBerdasarkanJenisKelamin) +.use(GrafikBerdasarkanResponden) +.use(GrafikBerdasarkanUmur) + + + +export default PPID + diff --git a/src/app/api/[[...slugs]]/route.ts b/src/app/api/[[...slugs]]/route.ts index e811da0a..840f15ae 100644 --- a/src/app/api/[[...slugs]]/route.ts +++ b/src/app/api/[[...slugs]]/route.ts @@ -14,6 +14,8 @@ import uplImg from "./_lib/upl-img"; import { uplImgSingle } from "./_lib/upl-img-single"; import Desa from "./_lib/desa"; import Kesehatan from "./_lib/kesehatan"; +import PPID from "./_lib/ppid"; + const ROOT = process.cwd(); if (!process.env.WIBU_UPLOAD_DIR) @@ -61,6 +63,7 @@ const Utils = new Elysia({ const ApiServer = new Elysia() .use(swagger({ path: "/api/docs" })) .use(cors(corsConfig)) + .use(PPID) .use(Kesehatan) .use(Desa) .use(Utils) diff --git a/src/app/percobaan/_lib/ClientRouter.txt b/src/app/percobaan/_lib/ClientRouter.txt deleted file mode 100644 index b666bba3..00000000 --- a/src/app/percobaan/_lib/ClientRouter.txt +++ /dev/null @@ -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> = { - get: () => string; - query: (params: z.infer) => string; - parse: (searchParams: URLSearchParams) => z.infer; -}; - -// Helper type to convert dashes to camelCase -type DashToCamelCase = S extends `${infer F}-${infer R}` - ? `${F}${Capitalize>}` - : 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]: RouterPath } - : RouterLeaf; - -type RemoveLeadingSlash = S extends `/${infer Rest}` - ? Rest - : S; - -type SplitPath = S extends `${infer Head}/${infer Tail}` - ? [Head, ...SplitPath] - : S extends "" - ? [] - : [S]; - -type WibuRouterOptions = { - prefix?: string; - name?: string; -}; - -export class V2ClientRouter { - private tree: any = {}; - private prefix: string = ""; - private name: string = ""; - private querySchemas: Map = 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, - Segments extends string[] = SplitPath, - T extends z.ZodType = z.ZodObject<{}> - >( - path: Path, - schema?: { query: T } - ): V2ClientRouter< - Routes & - (NormalizedPath extends "" - ? RouterLeaf - : { - [K in Segments[0] as DashToCamelCase]: 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 = {}; - 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( - name: N, - childRouter: V2ClientRouter - ): V2ClientRouter, 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 = {}; - 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; \ No newline at end of file diff --git a/src/app/percobaan/_router/router.txt b/src/app/percobaan/_router/router.txt deleted file mode 100644 index e394a306..00000000 --- a/src/app/percobaan/_router/router.txt +++ /dev/null @@ -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; diff --git a/src/app/percobaan/dashboard/berita/page.txt b/src/app/percobaan/dashboard/berita/page.txt deleted file mode 100644 index 4bba2a3f..00000000 --- a/src/app/percobaan/dashboard/berita/page.txt +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -function Page() { - return ( -
- berita -
- ); -} - -export default Page; diff --git a/src/app/percobaan/dashboard/page.txt b/src/app/percobaan/dashboard/page.txt deleted file mode 100644 index cc00a4fd..00000000 --- a/src/app/percobaan/dashboard/page.txt +++ /dev/null @@ -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 - case "2": - return - case "3": - return - default: - return - } -} - -const Page1 = () => { - return Page 1 -} - -const Page2 = () => { - return Page 2 -} - -const Page3 = () => { - return Page 3 -} - -export default Page; diff --git a/src/app/percobaan/page.txt b/src/app/percobaan/page.txt deleted file mode 100644 index e74f0edd..00000000 --- a/src/app/percobaan/page.txt +++ /dev/null @@ -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 ( - - - - 1 - - - 1 - - - - {Array.from({ length: 10 }).map((_, i) => ( - 1 - ))} - - - 1 - - {tx} - {tx} - apa kabar - - - - - - - ); -} - -export default Page; - -const Halaman = [Halaman1, Halaman2, Halaman3] - -function Page2() { - const page = useSearchParams().get("p"); - if (!page) return - - halo 1 - {Array.from({ length: 4 }).map((v, k) => )} - - - - - return ( - - - halo 2 - {Halaman[Number(page)-1]()} - - - - ); -} - - - -function Halaman1() { - return - ini halaman 1 - -} - - -function Halaman2() { - return - ini halaman 2 - -} - - -function Halaman3() { - return - ini halaman 3 - -} - diff --git a/src/app/percobaan/page2.txt b/src/app/percobaan/page2.txt deleted file mode 100644 index 69f2114b..00000000 --- a/src/app/percobaan/page2.txt +++ /dev/null @@ -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 - - {[1, 2, 3].map((v) => ())} - - - - -} - -export default Page \ No newline at end of file From 8a34a122d045e05a305c18dcb6ee29195d76cf23 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 9 May 2025 10:35:30 +0800 Subject: [PATCH 2/2] Tambahan Di menu PPID --- prisma/data/list-caraMemperolehInformasi.json | 5 + .../list-caraMemperolehSalinanInformasi.json | 5 + prisma/data/list-jenisInfromasi.json | 6 + .../data/ppid/profile-ppid/profilePPid.json | 7 + prisma/schema.prisma | 98 ++++++++- prisma/seed.ts | 57 ++++- .../admin/(dashboard)/_state/desa/berita.ts | 2 +- .../permohonanInformasiPublik.ts | 120 +++++++++++ .../permohonanKeberatanInformasi.ts | 68 ++++++ .../_state/ppid/profile_ppid/profile_PPID.ts | 69 ++++++ .../admin/(dashboard)/desa/berita/page.tsx | 4 +- .../(dashboard)/ppid/_com/PPIDTextEditor.tsx | 94 ++++++++ .../page.tsx | 142 ++++++------ .../page.tsx | 134 ++++++------ .../_ui/grafik_berdasarkan_responden/page.tsx | 177 +++++++-------- .../_ui/grafik_berdasarkan_umur/page.tsx | 204 +++++++++--------- .../grafik_hasil_kepuasan_masyarakat/page.tsx | 96 +++++---- .../jenisInformasi.tsx | 41 ++++ .../memperolehInformasi.tsx | 38 ++++ .../memperolehSalinan.tsx | 45 ++++ .../ppid/permohonan-informasi-publik/page.tsx | 114 +++++++++- .../page.tsx | 93 +++++++- .../ppid/profile-ppid/biodata/page.tsx | 24 +++ .../(dashboard)/ppid/profile-ppid/page.tsx | 99 ++++++++- .../pengalaman_organisasi/page.tsx | 22 ++ .../program_kerja_unggulan/page.tsx | 22 ++ .../ppid/profile-ppid/riwayat_karir/page.tsx | 30 +++ src/app/api/[[...slugs]]/_lib/ppid/index.ts | 11 + .../permohonan_informasi_publik/create.ts | 40 ++++ .../permohonan_informasi_publik/find-many.ts | 8 + .../ppid/permohonan_informasi_publik/index.ts | 29 +++ .../jenisInformasi.ts | 8 + .../memperolehInformasi.ts | 8 + .../salinanInformasi.ts | 9 + .../create.ts | 33 +++ .../find-many.ts | 8 + .../index.ts | 19 ++ .../_lib/ppid/profile_ppid/create.ts | 34 +++ .../_lib/ppid/profile_ppid/find-many.ts | 9 + .../_lib/ppid/profile_ppid/index.ts | 21 ++ .../_lib/ppid/visi_misi_ppid/index.ts | 7 + .../ppid/visi_misi_ppid/misi_ppid/create.ts | 27 +++ .../ppid/visi_misi_ppid/misi_ppid/delete.ts | 17 ++ .../visi_misi_ppid/misi_ppid/find-many.ts | 8 + .../ppid/visi_misi_ppid/misi_ppid/index.ts | 24 +++ .../ppid/visi_misi_ppid/misi_ppid/update.ts | 29 +++ src/lib/api-fetch.ts | 4 +- 47 files changed, 1788 insertions(+), 381 deletions(-) create mode 100644 prisma/data/list-caraMemperolehInformasi.json create mode 100644 prisma/data/list-caraMemperolehSalinanInformasi.json create mode 100644 prisma/data/list-jenisInfromasi.json create mode 100644 prisma/data/ppid/profile-ppid/profilePPid.json create mode 100644 src/app/admin/(dashboard)/_state/ppid/permohonan_informasi_publik/permohonanInformasiPublik.ts create mode 100644 src/app/admin/(dashboard)/_state/ppid/permohonan_keberatan_informasi_publik/permohonanKeberatanInformasi.ts create mode 100644 src/app/admin/(dashboard)/_state/ppid/profile_ppid/profile_PPID.ts create mode 100644 src/app/admin/(dashboard)/ppid/_com/PPIDTextEditor.tsx create mode 100644 src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/jenisInformasi.tsx create mode 100644 src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/memperolehInformasi.tsx create mode 100644 src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/memperolehSalinan.tsx create mode 100644 src/app/admin/(dashboard)/ppid/profile-ppid/biodata/page.tsx create mode 100644 src/app/admin/(dashboard)/ppid/profile-ppid/pengalaman_organisasi/page.tsx create mode 100644 src/app/admin/(dashboard)/ppid/profile-ppid/program_kerja_unggulan/page.tsx create mode 100644 src/app/admin/(dashboard)/ppid/profile-ppid/riwayat_karir/page.tsx create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_informasi_publik/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_informasi_publik/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_informasi_publik/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_informasi_publik/jenisInformasi.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_informasi_publik/memperolehInformasi.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_informasi_publik/salinanInformasi.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_keberatan_informasi_publik/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_keberatan_informasi_publik/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/permohonan_keberatan_informasi_publik/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/profile_ppid/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/profile_ppid/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/profile_ppid/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/visi_misi_ppid/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/visi_misi_ppid/misi_ppid/create.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/visi_misi_ppid/misi_ppid/delete.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/visi_misi_ppid/misi_ppid/find-many.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/visi_misi_ppid/misi_ppid/index.ts create mode 100644 src/app/api/[[...slugs]]/_lib/ppid/visi_misi_ppid/misi_ppid/update.ts diff --git a/prisma/data/list-caraMemperolehInformasi.json b/prisma/data/list-caraMemperolehInformasi.json new file mode 100644 index 00000000..c3f7fdad --- /dev/null +++ b/prisma/data/list-caraMemperolehInformasi.json @@ -0,0 +1,5 @@ +[ + {"name": "Melihat/Membaca/Mendengarkan/Mencatat"}, + {"name": "Mendapatkan Salinan Informasi (Hardcopy)"}, + {"name": "Mendapatkan Salinan Informasi (Softcopy)"} +] \ No newline at end of file diff --git a/prisma/data/list-caraMemperolehSalinanInformasi.json b/prisma/data/list-caraMemperolehSalinanInformasi.json new file mode 100644 index 00000000..6587f648 --- /dev/null +++ b/prisma/data/list-caraMemperolehSalinanInformasi.json @@ -0,0 +1,5 @@ +[ + { "name": "Mengambil Langsung" }, + { "name": "Dikirim Via Post" }, + { "name": "Dikirim Via Email" } +] diff --git a/prisma/data/list-jenisInfromasi.json b/prisma/data/list-jenisInfromasi.json new file mode 100644 index 00000000..393523e8 --- /dev/null +++ b/prisma/data/list-jenisInfromasi.json @@ -0,0 +1,6 @@ +[ + { "name": "Keuangan Desa" }, + { "name": "Pembangunan Desa" }, + { "name": "Data Demografi" }, + { "name": "Lainnya" } +] diff --git a/prisma/data/ppid/profile-ppid/profilePPid.json b/prisma/data/ppid/profile-ppid/profilePPid.json new file mode 100644 index 00000000..04d71d97 --- /dev/null +++ b/prisma/data/ppid/profile-ppid/profilePPid.json @@ -0,0 +1,7 @@ +[ + {"name": "

I.B Surya Prabhawa Manuaba, S.H., M.H.

"}, + {"biodata" : "

Biodata

I.B Surya Prabhawa Manuaba, S.H., M.H., adalah Perbekel Darmasaba periode 2021-2027, seorang advokat, pendiri Mantra Legal Consultants & Advocates, serta aktif di bidang musik dan akademis. Dia menempuh pendidikan hukum di Universitas Udayana dan Universitas Mahasaraswati Denpasar, serta memiliki pengalaman luas di berbagai organisasi dan kepemimpinan.

"}, + {"riwayat" : "

Riwayat Karir

  • 2021 - 2027: Perbekel Desa Darmasaba
  • 2015 - Sekarang: Founder & Managing Director Mantra Legal Consultants & Advocates
  • 2020 - Sekarang: Founder Ugawa Record Music Studio
  • 2010 - 2016: Dosen Fakultas Hukum Universitas Mahasaraswati Denpasar
"}, + {"pengalaman" : "

Pengalaman Organisasi

  • 1996 – 1997: Ketua OSIS SMP Negeri 1 Abiansemal
  • 1999 – 2000: Ketua OSIS SMA Negeri 1 Mengwi
  • 2008 – 2009: Ketua BEM Universitas Mahasaraswati Denpasar
  • 2008 – 2010: Ketua Sekaa Taruna Sila Dharma, Banjar Tengah, Desa Adat Tegal, Darmasaba
  • 2020 – Sekarang: Pengurus Young Lawyer Committee Peradi Denpasar
  • 2021 – Sekarang: Dewan Kehormatan Himpunan Pengusaha Muda Indonesia (HIPMI) Badung
  • 2023 – 2028: Komite Tetap Advokasi – Bidang Hukum dan Regulasi Kamar Dagang dan Industri Badung
"}, + {"unggulan" : "

Program Kerja Unggulan

Pemberdayaan Ekonomi dan UMKM

  • Pelatihan dan pendampingan UMKM lokal
  • Program bantuan modal usaha bagi pelaku usaha kecil
  • Digitalisasi UMKM untuk meningkatkan pemasaran produk lokal

Peningkatan Infrastruktur Desa

  • Pembangunan dan perbaikan jalan desa
  • Penyediaan fasilitas umum dan ruang terbuka hijau
  • Optimalisasi layanan publik berbasis digital
"} +] \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 96e49b8c..34be5b4e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -48,6 +48,39 @@ model AppMenuChild { } //========================================= MENU PPID ========================================= // +// ========================================= VISI MISI PPID ========================================= // +model VisiPPID { + id String @id @default(cuid()) + content String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + +model MisiPPID { + id String @id @default(cuid()) + content String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + +// ========================================= PROFILE PPID ========================================= // +model ProfilePPID { + id String @id @default(cuid()) + name String @unique + biodata String + riwayat String + pengalaman String + unggulan String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + // ========================================= DAFTAR INFORMASI PUBLIK ========================================= // model DaftarInformasiPublik { id String @id @default(cuid()) @@ -61,7 +94,70 @@ model DaftarInformasiPublik { isActive Boolean @default(true) } -//========================================= MENU PPID ========================================= // +//=========================================PERMOHONAN INFORMASI PUBLIK========================= // +model PermohonanInformasiPublik { + id String @id @default(cuid()) + nomor Int @default(autoincrement()) + name String + nik String + notelp String + alamat String + email String + jenisInformasiDiminta JenisInformasiDiminta? @relation(fields: [jenisInformasiDimintaId], references: [id]) + jenisInformasiDimintaId String? + caraMemperolehInformasi CaraMemperolehInformasi? @relation(fields: [caraMemperolehInformasiId], references: [id]) + caraMemperolehInformasiId String? + caraMemperolehSalinanInformasi CaraMemperolehSalinanInformasi? @relation(fields: [caraMemperolehSalinanInformasiId], references: [id]) + caraMemperolehSalinanInformasiId String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + +model JenisInformasiDiminta { + id String @id @default(cuid()) + name String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) + PermohonanInformasiPublik PermohonanInformasiPublik[] +} + +model CaraMemperolehInformasi { + id String @id @default(cuid()) + name String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) + PermohonanInformasiPublik PermohonanInformasiPublik[] +} + +model CaraMemperolehSalinanInformasi { + id String @id @default(cuid()) + name String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) + PermohonanInformasiPublik PermohonanInformasiPublik[] +} + +//=========================================PERMOHONAN INFORMASI KEBERATAN PUBLIK========================= // +model FormulirPermohonanKeberatan { + id String @id @default(cuid()) + name String + email String + notelp String + alasan String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime @default(now()) + isActive Boolean @default(true) +} + // ========================================= IKM ========================================= // model IndeksKepuasanMasyarakat { id Int @id @default(autoincrement()) diff --git a/prisma/seed.ts b/prisma/seed.ts index 5f296d13..b334bc9e 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,8 +1,11 @@ +import prisma from '@/lib/prisma' +import categoryPengumuman from './data/category-pengumuman.json' +import katagoryBerita from './data/katagory-berita.json' +import caraMemperolehInformasi from './data/list-caraMemperolehInformasi.json' +import caraMemperolehSalinanInformasi from './data/list-caraMemperolehSalinanInformasi.json' +import jenisInformasiDiminta from './data/list-jenisInfromasi.json' import layanan from './data/list-layanan.json' import potensi from './data/list-potensi.json' -import katagoryBerita from './data/katagory-berita.json' -import categoryPengumuman from './data/category-pengumuman.json' -import prisma from '@/lib/prisma'; (async () => { for (const l of layanan) { await prisma.layanan.upsert({ @@ -67,6 +70,54 @@ import prisma from '@/lib/prisma'; } console.log("category pengumuman success ...") + + for (const j of jenisInformasiDiminta) { + await prisma.jenisInformasiDiminta.upsert({ + where: { + name: j.name + }, + update: { + name: j.name + }, + create: { + name: j.name + } + }) + } + console.log("jenis informasi diminta success ...") + + for (const c of caraMemperolehInformasi) { + await prisma.caraMemperolehInformasi.upsert({ + where: { + name: c.name + }, + update: { + name: c.name + }, + create: { + name: c.name + } + }) + } + console.log("cara memperoleh informasi success ...") + + for (const c of caraMemperolehSalinanInformasi) { + await prisma.caraMemperolehSalinanInformasi.upsert({ + where: { + name: c.name + }, + update: { + name: c.name + }, + create: { + name: c.name + } + }) + } + console.log("cara memperoleh salinan informasi success ...") + + + })().then(() => prisma.$disconnect()).catch((e) => { console.error(e) prisma.$disconnect() diff --git a/src/app/admin/(dashboard)/_state/desa/berita.ts b/src/app/admin/(dashboard)/_state/desa/berita.ts index 817c5127..ea5bdfbf 100644 --- a/src/app/admin/(dashboard)/_state/desa/berita.ts +++ b/src/app/admin/(dashboard)/_state/desa/berita.ts @@ -87,4 +87,4 @@ const stateDashboardBerita = proxy({ berita, }); -export default stateDashboardBerita; +export default stateDashboardBerita; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/_state/ppid/permohonan_informasi_publik/permohonanInformasiPublik.ts b/src/app/admin/(dashboard)/_state/ppid/permohonan_informasi_publik/permohonanInformasiPublik.ts new file mode 100644 index 00000000..4487056f --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ppid/permohonan_informasi_publik/permohonanInformasiPublik.ts @@ -0,0 +1,120 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateForm = z.object({ + name: z.string().min(3, "Nama minimal 3 karakter"), + nik: z.string().min(3, "NIK minimal 3 karakter"), + notelp: z.string().min(3, "Nomor Telepon minimal 3 karakter"), + alamat: z.string().min(3, "Alamat minimal 3 karakter"), + email: z.string().min(3, "Email minimal 3 karakter"), + jenisInformasiDimintaId: z.string().nonempty(), + caraMemperolehInformasiId: z.string().nonempty(), + caraMemperolehSalinanInformasiId: z.string().nonempty(), +}) + +const jenisInformasiDiminta = proxy({ + findMany: { + data: null as + | null + | Prisma.JenisInformasiDimintaGetPayload<{ omit: { isActive: true } }>[], + async load(){ + const res = await ApiFetch.api.ppid.permohonaninformasipublik.jenisInformasi["find-many"].get(); + if (res.status === 200) { + jenisInformasiDiminta.findMany.data = res.data?.data ?? []; + } + } + } +}) + +const caraMemperolehInformasi = proxy({ + findMany: { + data: null as + | null + | Prisma.CaraMemperolehInformasiGetPayload<{ omit: { isActive: true } }>[], + async load() { + const res = await ApiFetch.api.ppid.permohonaninformasipublik.memperolehInformasi["find-many"].get(); + if (res.status === 200) { + caraMemperolehInformasi.findMany.data = res.data?.data ?? []; + } + } + } +}) + +const caraMemperolehSalinanInformasi = proxy({ + findMany: { + data: null as + | null + | Prisma.CaraMemperolehSalinanInformasiGetPayload<{ omit: { isActive: true } }>[], + async load() { + const res = await ApiFetch.api.ppid.permohonaninformasipublik.salinanInformasi["find-many"].get(); + if (res.status === 200) { + caraMemperolehSalinanInformasi.findMany.data = res.data?.data ?? []; + } + } + } +}) + +type PermohonanInformasiPublikForm = Prisma.PermohonanInformasiPublikGetPayload<{ + select: { + name: true; + nik: true; + notelp: true; + alamat: true; + email: true; + jenisInformasiDimintaId: true; + caraMemperolehInformasiId: true; + caraMemperolehSalinanInformasiId: true; + }; +}>; + +const permohonanInformasiPublikForm = proxy({ + create: { + form: {} as PermohonanInformasiPublikForm, + loading: false, + async create(){ + const cek = templateForm.safeParse(permohonanInformasiPublikForm.create.form); + if(!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + permohonanInformasiPublikForm.create.loading = true; + const res = await ApiFetch.api.ppid.permohonaninformasipublik["create"].post(permohonanInformasiPublikForm.create.form); + if (res.status === 200) { + permohonanInformasiPublikForm.findMany.load(); + return toast.success("success create"); + } + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + permohonanInformasiPublikForm.create.loading = false; + } + } + }, + findMany: { + data: null as + | Prisma.PermohonanInformasiPublikGetPayload<{ omit: { isActive: true } }>[] + | null, + async load() { + const res = await ApiFetch.api.ppid.permohonaninformasipublik["find-many"].get(); + if (res.status === 200) { + permohonanInformasiPublikForm.findMany.data = res.data?.data ?? []; + } + } + } +}) + +const statePermohonanInformasi = proxy({ + permohonanInformasiPublikForm, + jenisInformasiDiminta, + caraMemperolehInformasi, + caraMemperolehSalinanInformasi +}) + +export default statePermohonanInformasi; diff --git a/src/app/admin/(dashboard)/_state/ppid/permohonan_keberatan_informasi_publik/permohonanKeberatanInformasi.ts b/src/app/admin/(dashboard)/_state/ppid/permohonan_keberatan_informasi_publik/permohonanKeberatanInformasi.ts new file mode 100644 index 00000000..3e8f4f41 --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ppid/permohonan_keberatan_informasi_publik/permohonanKeberatanInformasi.ts @@ -0,0 +1,68 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateForm = z.object({ + name: z.string().min(3, "Nama minimal 3 karakter"), + email: z.string().min(3, "Email minimal 3 karakter"), + notelp: z.string().min(3, "Nomor Telepon minimal 3 karakter"), + alasan: z.string().min(3, "Alasan minimal 3 karakter"), +}) + +type PermohonanKeberatanInformasiForm = Prisma.FormulirPermohonanKeberatanGetPayload<{ + select: { + name: true; + email: true; + notelp: true; + alasan: true; + }; +}>; + +const permohonanKeberatanInformasiForm = proxy({ + create: { + form: {} as PermohonanKeberatanInformasiForm, + loading: false, + async create(){ + const cek = templateForm.safeParse(permohonanKeberatanInformasiForm.create.form); + if(!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + permohonanKeberatanInformasiForm.create.loading = true; + const res = await ApiFetch.api.ppid.permohonankeberataninformasipublik["create"].post(permohonanKeberatanInformasiForm.create.form); + if (res.status === 200) { + permohonanKeberatanInformasiForm.findMany.load(); + return toast.success("success create"); + } + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + permohonanKeberatanInformasiForm.create.loading = false; + } + }, + }, + findMany: { + data: null as + | Prisma.FormulirPermohonanKeberatanGetPayload<{omit: {isActive: true}}>[] + | null, + async load() { + const res = await ApiFetch.api.ppid.permohonankeberataninformasipublik["find-many"].get(); + if (res.status === 200) { + permohonanKeberatanInformasiForm.findMany.data = res.data?.data ?? []; + } + } + } +}); + +const statePermohonanKeberatan = proxy({ + permohonanKeberatanInformasiForm, +}) + +export default statePermohonanKeberatan; + diff --git a/src/app/admin/(dashboard)/_state/ppid/profile_ppid/profile_PPID.ts b/src/app/admin/(dashboard)/_state/ppid/profile_ppid/profile_PPID.ts new file mode 100644 index 00000000..e35f6062 --- /dev/null +++ b/src/app/admin/(dashboard)/_state/ppid/profile_ppid/profile_PPID.ts @@ -0,0 +1,69 @@ +import ApiFetch from "@/lib/api-fetch"; +import { Prisma } from "@prisma/client"; +import { toast } from "react-toastify"; +import { proxy } from "valtio"; +import { z } from "zod"; + +const templateForm = z.object({ + name: z.string().min(3, "Nama minimal 3 karakter"), + biodata: z.string().min(3, "Biodata minimal 3 karakter"), + riwayat: z.string().min(3, "Riwayat minimal 3 karakter"), + pengalaman: z.string().min(3, "Pengalaman minimal 3 karakter"), + unggulan: z.string().min(3, "Unggulan minimal 3 karakter"), +}) + +type ProfilePPIDForm = Prisma.ProfilePPIDGetPayload<{ + select: { + name: true; + biodata: true; + riwayat: true; + pengalaman: true; + unggulan: true; + } +}> + +const profilePPID = proxy({ + create: { + form: {} as ProfilePPIDForm, + loading: false, + async create() { + const cek = templateForm.safeParse(profilePPID.create.form); + if (!cek.success) { + const err = `[${cek.error.issues + .map((v) => `${v.path.join(".")}`) + .join("\n")}] required`; + return toast.error(err); + } + try { + profilePPID.create.loading = true; + const res = await ApiFetch.api.ppid.profileppid["create"].post(profilePPID.create.form); + if (res.status === 200) { + profilePPID.findMany.load(); + return toast.success("success create"); + } + return toast.error("failed create"); + } catch (error) { + console.log((error as Error).message); + } finally { + profilePPID.create.loading = false; + } + } + }, + findMany: { + data: null as + | Prisma.ProfilePPIDGetPayload<{omit: {isActive: true}}>[] + | null, + async load() { + const res = await ApiFetch.api.ppid.profileppid["find-many"].get(); + if (res.status === 200) { + profilePPID.findMany.data = res.data?.data ?? []; + } + } + } +}) + +const stateProfilePPID = proxy({ + profilePPID +}) + +export default stateProfilePPID; \ No newline at end of file diff --git a/src/app/admin/(dashboard)/desa/berita/page.tsx b/src/app/admin/(dashboard)/desa/berita/page.tsx index 26c3df72..fd79b4d3 100644 --- a/src/app/admin/(dashboard)/desa/berita/page.tsx +++ b/src/app/admin/(dashboard)/desa/berita/page.tsx @@ -10,9 +10,9 @@ import { BeritaEditor } from './_com/BeritaEditor'; function Page() { return ( - - + + ); diff --git a/src/app/admin/(dashboard)/ppid/_com/PPIDTextEditor.tsx b/src/app/admin/(dashboard)/ppid/_com/PPIDTextEditor.tsx new file mode 100644 index 00000000..b540c2e2 --- /dev/null +++ b/src/app/admin/(dashboard)/ppid/_com/PPIDTextEditor.tsx @@ -0,0 +1,94 @@ +'use client' +import { Button, Stack } from '@mantine/core'; +import { Link, RichTextEditor } from '@mantine/tiptap'; +import Highlight from '@tiptap/extension-highlight'; +import SubScript from '@tiptap/extension-subscript'; +import Superscript from '@tiptap/extension-superscript'; +import TextAlign from '@tiptap/extension-text-align'; +import Underline from '@tiptap/extension-underline'; +import { useEditor } from '@tiptap/react'; +import StarterKit from '@tiptap/starter-kit'; + +const content = + '

Welcome to Mantine rich text editor

RichTextEditor component focuses on usability and is designed to be as simple as possible to bring a familiar editing experience to regular users. RichTextEditor is based on Tiptap.dev and supports all of its features:

  • General text formatting: bold, italic, underline, strike-through
  • Headings (h1-h6)
  • Sub and super scripts (<sup /> and <sub /> tags)
  • Ordered and bullet lists
  • Text align 
  • And all other extensions
'; + +export function PPIDTextEditor({ onSubmit, onChange, showSubmit = true }: { + onSubmit?: (val: string) => void, + onChange: (val: string) => void, + showSubmit?: boolean }) { + const editor = useEditor({ + extensions: [ + StarterKit, + Underline, + Link, + Superscript, + SubScript, + Highlight, + TextAlign.configure({ types: ['heading', 'paragraph'] }), + ], + immediatelyRender: false, + content, + onUpdate : ({editor}) => { + onChange(editor.getHTML()) + } + }); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {showSubmit && ( + + )} + + ); +} \ No newline at end of file diff --git a/src/app/admin/(dashboard)/ppid/daftar-informasi-publik-desa-darmasaba/page.tsx b/src/app/admin/(dashboard)/ppid/daftar-informasi-publik-desa-darmasaba/page.tsx index 60d146dd..9ee3ca61 100644 --- a/src/app/admin/(dashboard)/ppid/daftar-informasi-publik-desa-darmasaba/page.tsx +++ b/src/app/admin/(dashboard)/ppid/daftar-informasi-publik-desa-darmasaba/page.tsx @@ -1,5 +1,5 @@ 'use client' -import { Box, Button, Group, SimpleGrid, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, TextInput, Title } from '@mantine/core'; +import { Box, Button, Group, Paper, SimpleGrid, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, TextInput, Title } from '@mantine/core'; import React from 'react'; import { useProxy } from 'valtio/utils'; import stateDaftarInformasiPublik from '../../_state/ppid/daftar_informasi_publik/daftarInformasiPublik'; @@ -20,35 +20,37 @@ function Page() { - - Daftar Informasi Publik Desa Darmasaba - { - daftarInformasi.create.form.jenisInformasi = val.target.value - }} - /> - { - daftarInformasi.create.form.deskripsi = val - }} - /> - { - daftarInformasi.create.form.tanggal = val.target.value - }} - /> - - - - + + + Daftar Informasi Publik Desa Darmasaba + { + daftarInformasi.create.form.jenisInformasi = val.target.value + }} + /> + { + daftarInformasi.create.form.deskripsi = val + }} + /> + { + daftarInformasi.create.form.tanggal = val.target.value + }} + /> + + + + + @@ -64,46 +66,48 @@ function ListDaftarInformasi() { listData.findMany.load() }, []) if (!listData.findMany.data) return - {Array.from({length: 10}).map((v, k) => )} + {Array.from({ length: 10 }).map((v, k) => )} - return - List Daftar Informasi Publik Desa Darmasaba - - - - - No - - - Jenis Informasi - - - Deskripsi - - - Tanggal Publikasi - - - - - {listData.findMany.data?.map((item) => ( - - {item.nomor} - {item.jenisInformasi} - - {item.tanggal} - - ))} - -
-
+ return + + List Daftar Informasi Publik Desa Darmasaba + + + + + No + + + Jenis Informasi + + + Deskripsi + + + Tanggal Publikasi + + + + + {listData.findMany.data?.map((item) => ( + + {item.nomor} + {item.jenisInformasi} + + {item.tanggal} + + ))} + +
+
+
} export default Page; diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_jenis_kelamin_responden/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_jenis_kelamin_responden/page.tsx index 93b30c06..18a8bf35 100644 --- a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_jenis_kelamin_responden/page.tsx +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_jenis_kelamin_responden/page.tsx @@ -2,7 +2,7 @@ 'use client' import stateGrafikBerdasarkanJenisKelamin from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin'; import colors from '@/con/colors'; -import { Box, Button, Center, Flex, Stack, Text, TextInput, Title } from '@mantine/core'; +import { Box, Button, Center, Flex, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import { useEffect, useState } from 'react'; import { Cell, Pie, PieChart } from 'recharts'; @@ -21,7 +21,7 @@ function GrafikBerdasarkanJenisKelamin() { if (data && data.length > 0) { const totalLaki = data.reduce((acc: number, cur: any) => acc + Number(cur.laki || 0), 0); const totalPerempuan = data.reduce((acc: number, cur: any) => acc + Number(cur.perempuan || 0), 0); - + setDonutData([ { name: 'Laki-laki', value: totalLaki, color: colors['blue-button'], key: 'laki-laki' }, { name: 'Perempuan', value: totalPerempuan, color: '#FF6384', key: 'perempuan' } @@ -44,15 +44,15 @@ function GrafikBerdasarkanJenisKelamin() { try { // Simpan data baru await grafikBerdasarkanJenisKelamin.create.create(); - + // Muat ulang data await grafikBerdasarkanJenisKelamin.findMany.load(); - + // Update chart dengan data baru if (grafikBerdasarkanJenisKelamin.findMany.data) { updateChartData(grafikBerdasarkanJenisKelamin.findMany.data); } - + // Reset form setelah submit grafikBerdasarkanJenisKelamin.create.form.laki = ''; grafikBerdasarkanJenisKelamin.create.form.perempuan = ''; @@ -64,72 +64,76 @@ function GrafikBerdasarkanJenisKelamin() { return ( - Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik - { - grafikBerdasarkanJenisKelamin.create.form.laki = val.currentTarget.value; - }} - /> - { - grafikBerdasarkanJenisKelamin.create.form.perempuan = val.currentTarget.value; - }} - /> - + + Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik + { + grafikBerdasarkanJenisKelamin.create.form.laki = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanJenisKelamin.create.form.perempuan = val.currentTarget.value; + }} + /> + + {/* Chart */} - - Grafik Berdasarkan Jenis Kelamin Responden - {mounted && donutData.length > 0 && ( - -
- - - + + Grafik Berdasarkan Jenis Kelamin Responden + {mounted && donutData.length > 0 && ( + +
+ - {donutData.map((entry, index) => ( - - ))} - - -
- - - Perempuan: {donutData.find((entry) => entry.name === 'Perempuan')?.value} - - - - Laki-laki: {donutData.find((entry) => entry.name === 'Laki-laki')?.value} - -
- )} -
+ + + {donutData.map((entry, index) => ( + + ))} + +
+
+ + + Perempuan: {donutData.find((entry) => entry.name === 'Perempuan')?.value} + + + + Laki-laki: {donutData.find((entry) => entry.name === 'Laki-laki')?.value} + +
+ )} +
+
); diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_responden/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_responden/page.tsx index f4d8651d..1a578cba 100644 --- a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_responden/page.tsx +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_responden/page.tsx @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import stateGrafikResponden from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanResponden'; import colors from '@/con/colors'; -import { Box, Button, Center, Flex, Stack, Text, TextInput, Title } from '@mantine/core'; +import { Box, Button, Center, Flex, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; import { useShallowEffect } from '@mantine/hooks'; import React, { useEffect, useState } from 'react'; import { PieChart, Pie, Cell } from 'recharts'; @@ -68,96 +68,103 @@ function GrafikBerdasarkanResponden() { return ( - Grafik Berdasarkan Responden - { - grafikBerdasarkanResponden.create.form.sangatbaik = val.currentTarget.value; - }} - /> - { - grafikBerdasarkanResponden.create.form.baik = val.currentTarget.value; - }} - /> - { - grafikBerdasarkanResponden.create.form.kurangbaik = val.currentTarget.value; - }} - /> - { - grafikBerdasarkanResponden.create.form.tidakbaik = val.currentTarget.value; - }} - /> - + + + Grafik Berdasarkan Responden + { + grafikBerdasarkanResponden.create.form.sangatbaik = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanResponden.create.form.baik = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanResponden.create.form.kurangbaik = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanResponden.create.form.tidakbaik = val.currentTarget.value; + }} + /> + + + + + {/* Chart */} - - Grafik Berdasarkan Responden - {mounted && donutData.length > 0 && ( - -
- - + + Grafik Berdasarkan Responden + {mounted && donutData.length > 0 && ( + +
+ - {donutData.map((entry, index) => ( - - ))} - - -
- - - Sangat Baik: {donutData.find((entry) => entry.name === 'sangatbaik')?.value} - - - - Baik: {donutData.find((entry) => entry.name === 'baik')?.value} - - - - Kurang Baik: {donutData.find((entry) => entry.name === 'kurangbaik')?.value} - - - - Tidak Baik: {donutData.find((entry) => entry.name === 'tidakbaik')?.value} - -
- )} -
+ + {donutData.map((entry, index) => ( + + ))} + +
+
+ + + Sangat Baik: {donutData.find((entry) => entry.name === 'sangatbaik')?.value} + + + + Baik: {donutData.find((entry) => entry.name === 'baik')?.value} + + + + Kurang Baik: {donutData.find((entry) => entry.name === 'kurangbaik')?.value} + + + + Tidak Baik: {donutData.find((entry) => entry.name === 'tidakbaik')?.value} + +
+ )} +
+
); diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_umur/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_umur/page.tsx index b85ed036..5e3d0e1f 100644 --- a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_umur/page.tsx +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_berdasarkan_umur/page.tsx @@ -1,7 +1,7 @@ 'use client' /* eslint-disable @typescript-eslint/no-explicit-any */ import colors from '@/con/colors'; -import { Box, Button, Center, Flex, Stack, Text, TextInput, Title } from '@mantine/core'; +import { Box, Button, Center, Flex, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core'; import React, { useEffect, useState } from 'react'; import { useProxy } from 'valtio/utils'; import stateGrafikBerdasarkanUmur from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanUmur'; @@ -37,117 +37,125 @@ function GrafikBerdasarakanUmur() { fetchData(); }, []); -const fetchData = async () => { - await grafikBerdasarkanUmur.findMany.load(); - if (grafikBerdasarkanUmur.findMany.data) { - updateChartData(grafikBerdasarkanUmur.findMany.data); - } -} - -const handleSubmit = async () => { - try { - await grafikBerdasarkanUmur.create.create(); + const fetchData = async () => { await grafikBerdasarkanUmur.findMany.load(); if (grafikBerdasarkanUmur.findMany.data) { updateChartData(grafikBerdasarkanUmur.findMany.data); } - } catch (error) { - console.error("Error submitting data:", error); } -} + + const handleSubmit = async () => { + try { + await grafikBerdasarkanUmur.create.create(); + await grafikBerdasarkanUmur.findMany.load(); + if (grafikBerdasarkanUmur.findMany.data) { + updateChartData(grafikBerdasarkanUmur.findMany.data); + } + } catch (error) { + console.error("Error submitting data:", error); + } + } return ( - Grafik Berdasarkan Umur Responden - { - grafikBerdasarkanUmur.create.form.remaja = val.currentTarget.value; - }} - /> - { - grafikBerdasarkanUmur.create.form.dewasa = val.currentTarget.value; - }} - /> - { - grafikBerdasarkanUmur.create.form.orangtua = val.currentTarget.value; - }} - /> - { - grafikBerdasarkanUmur.create.form.lansia = val.currentTarget.value; - }} - /> - + + + Grafik Berdasarkan Umur Responden + { + grafikBerdasarkanUmur.create.form.remaja = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanUmur.create.form.dewasa = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanUmur.create.form.orangtua = val.currentTarget.value; + }} + /> + { + grafikBerdasarkanUmur.create.form.lansia = val.currentTarget.value; + }} + /> + + + + + {/* Chart */} - - Grafik Berdasarkan Umur Responden - {mounted && donutData.length > 0 && ( - -
- - + + Grafik Berdasarkan Umur Responden + {mounted && donutData.length > 0 && ( + +
+ - {donutData.map((entry, index) => ( - - ))} - - -
- - - 17 - 25 tahun: {donutData.find((entry) => entry.name === 'remaja')?.value} - - - - 26 - 45 tahun: {donutData.find((entry) => entry.name === 'dewasa')?.value} - - - - 46 - 60 tahun: {donutData.find((entry) => entry.name === 'orangtua')?.value} - - - - di atas 60 tahun: {donutData.find((entry) => entry.name === 'lansia')?.value} - -
- )} -
+ + {donutData.map((entry, index) => ( + + ))} + +
+
+ + + 17 - 25 tahun: {donutData.find((entry) => entry.name === 'remaja')?.value} + + + + 26 - 45 tahun: {donutData.find((entry) => entry.name === 'dewasa')?.value} + + + + 46 - 60 tahun: {donutData.find((entry) => entry.name === 'orangtua')?.value} + + + + di atas 60 tahun: {donutData.find((entry) => entry.name === 'lansia')?.value} + +
+ )} +
+
); diff --git a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_hasil_kepuasan_masyarakat/page.tsx b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_hasil_kepuasan_masyarakat/page.tsx index 92596971..5ece0a34 100644 --- a/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_hasil_kepuasan_masyarakat/page.tsx +++ b/src/app/admin/(dashboard)/ppid/ikm-desa-darmasaba/_ui/grafik_hasil_kepuasan_masyarakat/page.tsx @@ -2,7 +2,7 @@ 'use client' import stateGrafikHasilKepuasanMasyarakat from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikHasilKepuasan'; import colors from '@/con/colors'; -import { Box, Button, TextInput, Title } from '@mantine/core'; +import { Box, Button, Paper, Stack, TextInput, Title } from '@mantine/core'; import { useMediaQuery, useShallowEffect } from '@mantine/hooks'; import React, { useEffect, useState } from 'react'; import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts'; @@ -32,53 +32,61 @@ function GrafikHasilKepuasan() { return ( - Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik - { - grafikHasilKepuasan.create.form.label = val.currentTarget.value; - }} - /> - { - grafikHasilKepuasan.create.form.kepuasan = val.currentTarget.value; - }} - /> - + + + Grafik Hasil Kepuasan Masyarakat Terhadap Pelayanan Publik + { + grafikHasilKepuasan.create.form.label = val.currentTarget.value; + }} + /> + { + grafikHasilKepuasan.create.form.kepuasan = val.currentTarget.value; + }} + /> + + + {/* Chart */} - Data Kepuasan Masyarakat - {mounted && chartData.length > 0 && ( - - - - - - - - )} + + + Data Kepuasan Masyarakat + {mounted && chartData.length > 0 && ( + + + + + + + + )} + + diff --git a/src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/jenisInformasi.tsx b/src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/jenisInformasi.tsx new file mode 100644 index 00000000..90a1c6f7 --- /dev/null +++ b/src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/jenisInformasi.tsx @@ -0,0 +1,41 @@ +import { Prisma } from '@prisma/client'; +import React from 'react'; +import { useProxy } from 'valtio/utils'; +import statePermohonanInformasi from '../../_state/ppid/permohonan_informasi_publik/permohonanInformasiPublik'; +import { useShallowEffect } from '@mantine/hooks'; +import { Group, Select, Skeleton } from '@mantine/core'; + +function JenisInformasi({ onChange }: { + onChange: (value: Prisma.JenisInformasiDimintaGetPayload<{ + select: { + id: true, + name: true + } + }>) => void +}) { + const jenisInformasiState = useProxy(statePermohonanInformasi.jenisInformasiDiminta) + useShallowEffect(() => { + jenisInformasiState.findMany.load() + }, []) + + if (!jenisInformasiState.findMany.data) return + return ( + + ({ + value: item.id, + label: item.name + }))} onChange={(v) => { + const data = memperolehInformasiState.findMany.data?.find((item) => item.id === v) + if (!data) return + onChange(data) + }} /> + + ); +} + +export default MemperolehInformasi; diff --git a/src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/memperolehSalinan.tsx b/src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/memperolehSalinan.tsx new file mode 100644 index 00000000..b5dfc2b8 --- /dev/null +++ b/src/app/admin/(dashboard)/ppid/permohonan-informasi-publik/memperolehSalinan.tsx @@ -0,0 +1,45 @@ +import { Group, Select, Skeleton } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { Prisma } from '@prisma/client'; +import React from 'react'; +import { useProxy } from 'valtio/utils'; +import statePermohonanInformasi from '../../_state/ppid/permohonan_informasi_publik/permohonanInformasiPublik'; + +function MemperolehSalinan({ onChange }: { + onChange: (value: Prisma.CaraMemperolehSalinanInformasiGetPayload<{ + select: { + id: true, + name: true + } + }>) => void +}) { + const memperolehSalinanInformasiState = useProxy(statePermohonanInformasi.caraMemperolehSalinanInformasi) + useShallowEffect(() => { + memperolehSalinanInformasiState.findMany.load() + }, []) + + if (!memperolehSalinanInformasiState.findMany.data) return + return ( + +