diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 5034611..d30cbbb 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -193,7 +193,7 @@ model SuratPelayanan {
model Configuration {
id String @id @default(cuid())
- category String
+ name String
value String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
diff --git a/prisma/seed.ts b/prisma/seed.ts
index dca6791..56b5941 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -1,4 +1,5 @@
import { categoryPelayananSurat } from "@/lib/categoryPelayananSurat";
+import { confDesa } from "@/lib/configurationDesa";
import { prisma } from "@/server/lib/prisma";
const category = [
@@ -51,7 +52,6 @@ const user = [
(async () => {
for (const r of role) {
- console.log(`Seeding role ${r.name}`)
await prisma.role.upsert({
where: { id: r.id },
create: r,
@@ -81,7 +81,7 @@ const user = [
console.log(`✅ Category ${c.name} seeded successfully`)
}
- for (const cp of categoryPelayananSurat){
+ for (const cp of categoryPelayananSurat) {
await prisma.categoryPelayanan.upsert({
where: { id: cp.id },
create: cp,
@@ -91,6 +91,15 @@ const user = [
console.log(`✅ Category Pelayanan ${cp.name} seeded successfully`)
}
+ for (const c of confDesa) {
+ await prisma.configuration.upsert({
+ where: { id: c.id },
+ create: c,
+ update: c
+ })
+
+ console.log(`✅ Configuration ${c.name} seeded successfully`)
+ }
diff --git a/src/AppRoutes.tsx b/src/AppRoutes.tsx
index 14289f7..18589c7 100644
--- a/src/AppRoutes.tsx
+++ b/src/AppRoutes.tsx
@@ -1,27 +1,28 @@
// ⚡ Auto-generated by generateRoutes.ts — DO NOT EDIT MANUALLY
-import { BrowserRouter, Routes, Route } from "react-router-dom";
-import Login from "./pages/Login";
-import DarmasabaLayout from "./pages/darmasaba/darmasaba_layout";
-import FormSuratKeteranganUsaha from "./pages/darmasaba/form_surat_keterangan_usaha";
-import FormSuratKeteranganTidakMampu from "./pages/darmasaba/form_surat_keterangan_tidak_mampu";
+import { BrowserRouter, Route, Routes } from "react-router-dom";
import DarmasabaHome from "./pages/darmasaba/darmasaba_home";
-import FormKartuTandaPenduduk from "./pages/darmasaba/form_kartu_tanda_penduduk";
+import DarmasabaLayout from "./pages/darmasaba/darmasaba_layout";
import FormKartuKeluarga from "./pages/darmasaba/form_kartu_keluarga";
-import FormLaporanSampah from "./pages/darmasaba/form_laporan_sampah";
-import FormSuratKeteranganPenghasilan from "./pages/darmasaba/form_surat_keterangan_penghasilan";
-import FormSuratKeteranganDomisiliOrganisasi from "./pages/darmasaba/form_surat_keterangan_domisili_organisasi";
-import FormSuratKeteranganBelumKawin from "./pages/darmasaba/form_surat_keterangan_belum_kawin";
+import FormKartuTandaPenduduk from "./pages/darmasaba/form_kartu_tanda_penduduk";
import FormKeteranganKelahiran from "./pages/darmasaba/form_keterangan_kelahiran";
-import FormSuratKeteranganTempatUsaha from "./pages/darmasaba/form_surat_keterangan_tempat_usaha";
+import FormLaporanSampah from "./pages/darmasaba/form_laporan_sampah";
+import FormSuratKeteranganBelumKawin from "./pages/darmasaba/form_surat_keterangan_belum_kawin";
+import FormSuratKeteranganDomisiliOrganisasi from "./pages/darmasaba/form_surat_keterangan_domisili_organisasi";
import FormSuratKeteranganKelakuanBaik from "./pages/darmasaba/form_surat_keterangan_kelakuan_baik";
+import FormSuratKeteranganPenghasilan from "./pages/darmasaba/form_surat_keterangan_penghasilan";
+import FormSuratKeteranganTempatUsaha from "./pages/darmasaba/form_surat_keterangan_tempat_usaha";
+import FormSuratKeteranganTidakMampu from "./pages/darmasaba/form_surat_keterangan_tidak_mampu";
+import FormSuratKeteranganUsaha from "./pages/darmasaba/form_surat_keterangan_usaha";
+import DirPage from "./pages/dir/dir_page";
import Home from "./pages/Home";
+import Login from "./pages/Login";
+import NotFound from "./pages/NotFound";
+import ApikeyPage from "./pages/scr/dashboard/apikey/apikey_page";
import CredentialPage from "./pages/scr/dashboard/credential/credential_page";
import DashboardHome from "./pages/scr/dashboard/dashboard_home";
-import ApikeyPage from "./pages/scr/dashboard/apikey/apikey_page";
import DashboardLayout from "./pages/scr/dashboard/dashboard_layout";
+import ListPage from "./pages/scr/dashboard/pengaduan/list_page";
import ScrLayout from "./pages/scr/scr_layout";
-import DirPage from "./pages/dir/dir_page";
-import NotFound from "./pages/NotFound";
export default function AppRoutes() {
return (
@@ -92,6 +93,10 @@ export default function AppRoutes() {
path="/scr/dashboard/dashboard-home"
element={}
/>
+ }
+ />
}
diff --git a/src/clientRoutes.ts b/src/clientRoutes.ts
index 6c4d06c..5db3d11 100644
--- a/src/clientRoutes.ts
+++ b/src/clientRoutes.ts
@@ -19,6 +19,7 @@ const clientRoutes = {
"/scr/dashboard": "/scr/dashboard",
"/scr/dashboard/credential/credential": "/scr/dashboard/credential/credential",
"/scr/dashboard/dashboard-home": "/scr/dashboard/dashboard-home",
+ "/scr/dashboard/pengaduan/list": "/scr/dashboard/pengaduan/list",
"/scr/dashboard/apikey/apikey": "/scr/dashboard/apikey/apikey",
"/dir/dir": "/dir/dir",
"/*": "/*"
diff --git a/src/lib/configurationDesa.ts b/src/lib/configurationDesa.ts
new file mode 100644
index 0000000..fe8dd0e
--- /dev/null
+++ b/src/lib/configurationDesa.ts
@@ -0,0 +1,57 @@
+export const confDesa = [
+ {
+ id: "desaNama",
+ name: "Nama Desa",
+ value: "Darmasaba"
+ },
+ {
+ id: "desaKabupaten",
+ name: "Kabupaten",
+ value: "Badung"
+ },
+ {
+ id: "desaKecamatan",
+ name: "Kecamatan",
+ value: "Abiansemal"
+ },
+ {
+ id: "desaAlamat",
+ name: "Alamat Kantor Desa",
+ value: "Jl. Raya Darmasaba No.22, Darmasaba"
+ },
+ {
+ id: "desaPos",
+ name: "Kode Pos",
+ value: "80352"
+ },
+ {
+ id: "desaTelepon",
+ name: "Telepon",
+ value: "081239580000"
+ },
+ {
+ id: "desaEmail",
+ name: "Email",
+ value: "desadarmasaba@badungkab.go.id"
+ },
+ {
+ id: "perbekelNama",
+ name: "Nama Perbekel",
+ value: "Ida Bagus Surya Prabhawa Manuaba, S.H., M.H., N.L.P."
+ },
+ {
+ id: "perbekelJabatan",
+ name: "Jabatan",
+ value: "Perbekel"
+ },
+ {
+ id: "perbekelNIP",
+ name: "NIP",
+ value: ""
+ },
+ {
+ id: "perbekelTTD",
+ name: "TTD",
+ value: ""
+ },
+];
diff --git a/src/pages/dir/dir_page.tsx b/src/pages/dir/dir_page.tsx
index c28ac42..61d0028 100644
--- a/src/pages/dir/dir_page.tsx
+++ b/src/pages/dir/dir_page.tsx
@@ -2,16 +2,16 @@ import { Tree } from "@mantine/core";
// ✅ Valid data, all values are unique
const data = [
- {
- value: 'src',
- label: 'src',
- children: [
- { value: 'src/components', label: 'components' },
- { value: 'src/hooks', label: 'hooks' },
- ],
- },
- { value: 'package.json', label: 'package.json' },
- ];
+ {
+ value: "src",
+ label: "src",
+ children: [
+ { value: "src/components", label: "components" },
+ { value: "src/hooks", label: "hooks" },
+ ],
+ },
+ { value: "package.json", label: "package.json" },
+];
export default function DirPage() {
return (
diff --git a/src/pages/scr/dashboard/dashboard_layout.tsx b/src/pages/scr/dashboard/dashboard_layout.tsx
index f902969..21c53bb 100644
--- a/src/pages/scr/dashboard/dashboard_layout.tsx
+++ b/src/pages/scr/dashboard/dashboard_layout.tsx
@@ -1,4 +1,8 @@
-import { useEffect, useState } from "react";
+import {
+ default as clientRoute,
+ default as clientRoutes,
+} from "@/clientRoutes";
+import apiFetch from "@/lib/apiFetch";
import {
ActionIcon,
AppShell,
@@ -22,17 +26,17 @@ import {
IconChevronLeft,
IconChevronRight,
IconDashboard,
+ IconFileCertificate,
IconKey,
IconLock,
+ IconMessageReport,
+ IconSettings,
IconUser,
+ IconUsersGroup,
} from "@tabler/icons-react";
import type { User } from "generated/prisma";
+import { useEffect, useState } from "react";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
-import {
- default as clientRoute,
- default as clientRoutes,
-} from "@/clientRoutes";
-import apiFetch from "@/lib/apiFetch";
function Logout() {
return (
@@ -98,7 +102,7 @@ export default function DashboardLayout() {
size="lg"
style={{
backgroundColor: "rgba(255,255,255,0.05)",
- boxShadow: "0 0 6px rgba(0,255,200,0.2)",
+ boxShadow: "0 0 6px hsla(167, 100%, 50%, 0.20), 0.20)",
}}
>
{opened ? : }
@@ -186,7 +190,7 @@ function HostView() {
{host.name}
- {host.email}
+ {host.roleId}
@@ -219,6 +223,31 @@ function NavigationDashboard() {
label: "Dashboard Overview",
description: "Quick summary and insights",
},
+ {
+ path: "/scr/dashboard/pengaduan/list",
+ icon: ,
+ label: "Pengaduan Warga",
+ description: "Manage pengaduan warga",
+ },
+ {
+ path: "/scr/dashboard/pelayanan",
+ icon: ,
+ label: "Pelayanan Surat",
+ description: "Manage pelayanan surat",
+ },
+ {
+ path: "/scr/dashboard/user",
+ icon: ,
+ label: "User",
+ description: "Manage user",
+ },
+ {
+ path: "/scr/dashboard/setting",
+ icon: ,
+ label: "Setting",
+ description:
+ "Manage setting (category pengaduan dan pelayanan surat, desa, etc)",
+ },
{
path: "/scr/dashboard/apikey/apikey",
icon: ,
diff --git a/src/pages/scr/dashboard/pengaduan/list_page.tsx b/src/pages/scr/dashboard/pengaduan/list_page.tsx
new file mode 100644
index 0000000..7682a34
--- /dev/null
+++ b/src/pages/scr/dashboard/pengaduan/list_page.tsx
@@ -0,0 +1,186 @@
+import apiFetch from "@/lib/apiFetch";
+import {
+ Badge,
+ Card,
+ Container,
+ Divider,
+ Flex,
+ Group,
+ Stack,
+ Tabs,
+ Text,
+ Title
+} from "@mantine/core";
+import { useShallowEffect } from "@mantine/hooks";
+import { showNotification } from "@mantine/notifications";
+import { IconAlignJustified, IconClockHour3, IconMapPin } from "@tabler/icons-react";
+import { useLocation, useNavigate } from "react-router-dom";
+import useSwr from "swr";
+import { proxy, subscribe } from "valtio";
+
+const state = proxy({ reload: "" });
+function reloadState() {
+ state.reload = Math.random().toString();
+}
+
+export default function PengaduanListPage() {
+ const { search } = useLocation();
+ const query = new URLSearchParams(search);
+
+ const status = query.get("status");
+ console.log(status, "status");
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+function TabListPengaduan({ status }: { status: string }) {
+ const navigate = useNavigate();
+ return (
+
+
+ { navigate("?status=all") }}>Semua
+ { navigate("?status=antrian") }}>Antrian
+ { navigate("?status=diterima") }}>Diterima
+ { navigate("?status=dikerjakan") }}>Dikerjakan
+ { navigate("?status=ditolak") }}>Ditolak
+ { navigate("?status=selesai") }}>Selesai
+
+
+ );
+}
+
+function ListPengaduan() {
+ const { data, mutate, isLoading } = useSwr("/", () =>
+ apiFetch.api.credential.list.get(),
+ );
+
+ useShallowEffect(() => {
+ const unsubscribe = subscribe(state, () => mutate());
+ return () => unsubscribe();
+ }, []);
+
+ async function handleRemove(id: string) {
+ try {
+ await apiFetch.api.credential.rm.delete({ id });
+ showNotification({
+ color: "teal",
+ title: "Credential Deleted",
+ message: "The credential was successfully removed.",
+ });
+ reloadState();
+ } catch {
+ showNotification({
+ color: "red",
+ title: "Error",
+ message: "Failed to delete credential. Please try again.",
+ });
+ }
+ }
+
+ if (isLoading)
+ return (
+
+
+ Loading credentials...
+
+
+ );
+
+ const list = data?.data?.list || [];
+
+ return (
+
+
+
+
+
+ Dompet Hilang
+
+
+
+ #PGD-061125-001
+
+
+ updated 2 minutes ago
+
+
+
+
+ Antrian
+
+
+
+
+
+
+
+
+ Tanggal Aduan
+
+
+
+ 05 November 2025
+
+
+
+
+
+
+ Lokasi
+
+
+
+ Jalan Darmasaba Raya no 77
+
+
+
+
+
+
+ Detail
+
+
+
+ Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quis, obcaecati. Sint natus culpa temporibus neque quasi expedita ratione, facere optio incidunt quibusdam suscipit nam nemo delectus beatae similique velit obcaecati?
+
+
+
+
+
+ );
+}
diff --git a/src/server/lib/seafile.ts b/src/server/lib/seafile.ts
index 8fd380a..776478f 100644
--- a/src/server/lib/seafile.ts
+++ b/src/server/lib/seafile.ts
@@ -158,7 +158,6 @@ export async function uploadFile(config: Config, file: File): Promise {
});
const text = await res.text();
- console.log(text);
if (!res.ok) throw new Error(`Upload failed: ${text}`);
return `✅ Uploaded ${file.name} successfully`;
diff --git a/src/server/routes/pelayanan_surat_route.ts b/src/server/routes/pelayanan_surat_route.ts
index 43cb9fe..69fdc98 100644
--- a/src/server/routes/pelayanan_surat_route.ts
+++ b/src/server/routes/pelayanan_surat_route.ts
@@ -2,6 +2,7 @@ import Elysia, { StatusMap, t } from "elysia"
import { generateNoPengajuanSurat } from "../lib/no-pengajuan-surat"
import { prisma } from "../lib/prisma"
import type { StatusPengaduan } from "generated/prisma"
+import { normalizePhoneNumber } from "../lib/normalizePhone"
const PelayananRoute = new Elysia({
prefix: "pelayanan",
@@ -22,7 +23,7 @@ const PelayananRoute = new Elysia({
}, {
detail: {
summary: "List Kategori Pelayanan Surat",
- description: `tool untuk mendapatkan list kategori pelayanan surat`,
+ description: `tool untuk mendapatkan list kategori pelayanan surat beserta syaratnya untuk memenuhi syarat dokumen sesuai kategori yg dipilih saat melakukan pengajuan surat`,
tags: ["mcp"]
}
})
@@ -175,9 +176,10 @@ const PelayananRoute = new Elysia({
})
if (!warga) {
+ const nomorHP = normalizePhoneNumber({ phone })
const cariWarga = await prisma.warga.findFirst({
where: {
- phone,
+ phone: nomorHP,
}
})
@@ -185,7 +187,7 @@ const PelayananRoute = new Elysia({
const wargaCreate = await prisma.warga.create({
data: {
name: idWarga,
- phone,
+ phone: nomorHP,
},
select: {
id: true
@@ -210,7 +212,7 @@ const PelayananRoute = new Elysia({
})
if (!pengaduan.id) {
- throw new Error("gagal membuat pengaduan")
+ throw new Error("gagal membuat pengajuan surat")
}
let dataInsertSyaratDokumen = []
@@ -270,7 +272,7 @@ const PelayananRoute = new Elysia({
}),
detail: {
summary: "Create Pengajuan Pelayanan Surat",
- description: `tool untuk membuat pengajuan pelayanan surat`,
+ description: `tool untuk membuat pengajuan pelayanan surat dengan syarat dokumen serta data text sesuai kategori pelayanan surat yang dipilih`,
tags: ["mcp"]
}
})
diff --git a/src/server/routes/pengaduan_route.ts b/src/server/routes/pengaduan_route.ts
index 2895ea7..cf62aa9 100644
--- a/src/server/routes/pengaduan_route.ts
+++ b/src/server/routes/pengaduan_route.ts
@@ -1,10 +1,9 @@
-import { swagger } from "@elysiajs/swagger"
import Elysia, { t } from "elysia"
import type { StatusPengaduan } from "generated/prisma"
import { generateNoPengaduan } from "../lib/no-pengaduan"
-import { prisma } from "../lib/prisma"
-import { defaultConfigSF, testConnection, uploadFile } from "../lib/seafile"
import { normalizePhoneNumber } from "../lib/normalizePhone"
+import { prisma } from "../lib/prisma"
+import { defaultConfigSF, uploadFile } from "../lib/seafile"
const PengaduanRoute = new Elysia({
prefix: "pengaduan",
@@ -432,7 +431,6 @@ const PengaduanRoute = new Elysia({
tags: ["mcp"]
}
})
- .use(swagger())
.post("/upload",
async ({ body }) => {
const { file } = body;
@@ -442,16 +440,10 @@ const PengaduanRoute = new Elysia({
return { success: false, message: "File tidak ditemukan" };
}
- // Contoh: cek koneksi ke Seafile
- const coba = await testConnection(defaultConfigSF);
- console.log("Seafile Connection:", coba);
-
// Upload ke Seafile (pastikan uploadFile menerima Blob atau ArrayBuffer)
// const buffer = await file.arrayBuffer();
const result = await uploadFile(defaultConfigSF, file);
- console.log("Upload result:", result);
-
return {
success: true,
message: "Upload berhasil",