From 2725c2c064e4986a4da527912cc88f99fa5ac0f6 Mon Sep 17 00:00:00 2001 From: nico Date: Mon, 7 Jul 2025 22:24:46 +0800 Subject: [PATCH] UI & API Menu Struktur Organisasi Tabs Hubungan Organisasi --- .../hubungan-organisasi.json | 2 +- .../struktur-organisasi.ts | 8 +- .../hubungan-organisasi/[id]/page.tsx | 94 +++++++++++++++ .../hubungan-organisasi/create/page.tsx | 78 +++++++++++++ .../hubungan-organisasi/page.tsx | 110 +++++++++++++++++- .../pegawai/page.tsx | 7 +- .../hubungan-organisasi/index.ts | 5 +- .../hubungan-organisasi/updt.ts | 12 +- 8 files changed, 295 insertions(+), 21 deletions(-) create mode 100644 src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/[id]/page.tsx create mode 100644 src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/create/page.tsx diff --git a/prisma/data/ekonomi/struktur-organisasi/hubungan-organisasi.json b/prisma/data/ekonomi/struktur-organisasi/hubungan-organisasi.json index 1bef7d69..0f0e8271 100644 --- a/prisma/data/ekonomi/struktur-organisasi/hubungan-organisasi.json +++ b/prisma/data/ekonomi/struktur-organisasi/hubungan-organisasi.json @@ -3,6 +3,6 @@ "id": "650e8400-e29b-41d4-a716-446655440001", "atasanId": "550e8400-e29b-41d4-a716-446655440001", "bawahanId": "550e8400-e29b-41d4-a716-446655440002", - "tipe": "langsung_melapor" + "tipe": "Langsung Melapor" } ] diff --git a/src/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi.ts b/src/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi.ts index 1f540f8f..a8bc08aa 100644 --- a/src/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi.ts +++ b/src/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi.ts @@ -591,7 +591,7 @@ const hubunganOrganisasi = proxy({ async load(id: string) { try { - const res = await fetch(`/api/ekonomi/strukturorganisasi/hubunganorganisasi/${id}`); + const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`); const result = await res.json(); if (res.ok && result?.success) { @@ -616,7 +616,7 @@ const hubunganOrganisasi = proxy({ if (!id) return toast.warn("ID tidak valid"); try { - const res = await fetch(`/api/ekonomi/strukturorganisasi/hubunganorganisasi/${id}`); + const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${id}`); const result = await res.json(); if (res.ok && result?.success) { @@ -650,7 +650,7 @@ const hubunganOrganisasi = proxy({ try { this.loading = true; const res = await fetch( - `/api/ekonomi/strukturorganisasi/hubunganorganisasi/${this.id}`, + `/api/ekonomi/struktur-organisasi/hubungan-organisasi/${this.id}`, { method: "PUT", headers: { @@ -690,7 +690,7 @@ const hubunganOrganisasi = proxy({ try { hubunganOrganisasi.delete.loading = true; - const res = await fetch(`/api/strukturorganisasi/hubungan-organisasi/${id}`, { + const res = await fetch(`/api/ekonomi/struktur-organisasi/hubungan-organisasi/del/${id}`, { method: "DELETE", }); diff --git a/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/[id]/page.tsx b/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/[id]/page.tsx new file mode 100644 index 00000000..d063805e --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/[id]/page.tsx @@ -0,0 +1,94 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client'; + +import { useEffect, useState } from 'react'; +import { useParams, useRouter } from 'next/navigation'; +import { Box, Button, Paper, Select, Stack, TextInput, Title } from '@mantine/core'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; +import strukturorganisasiState from '@/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi'; + +export default function EditHubunganOrganisasi() { + const router = useRouter(); + const { id } = useParams<{ id: string }>(); + const state = useProxy(strukturorganisasiState.hubunganOrganisasi); + const pegawaiList = strukturorganisasiState.pegawai.findMany.data; + + const [form, setForm] = useState({ + atasanId: '', + bawahanId: '', + tipe: '', + }); + + useEffect(() => { + strukturorganisasiState.pegawai.findMany.load(); + + if (id) { + state.edit.load(id).then(data => { + if (data) { + setForm({ + atasanId: data.atasanId, + bawahanId: data.bawahanId, + tipe: data.tipe || '', + }); + } + }); + } + }, [id]); + + const handleSubmit = async () => { + if (!form.atasanId || !form.bawahanId) { + toast.warn("Atasan dan bawahan harus diisi"); + return; + } + + state.edit.id = id; + state.edit.form = form; + + const result = await state.edit.update(); + + if (result) { + toast.success("Data berhasil diperbarui"); + router.push('/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi'); + } + }; + + return ( + + + + Edit Hubungan Organisasi + ({ + value: p.id, + label: p.namaLengkap, + })) || []} + value={form.bawahanId} + onChange={(val) => setForm({ ...form, bawahanId: val || '' })} + /> + setForm({ ...form, tipe: e.currentTarget.value })} + /> + + + + + ); +} diff --git a/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/create/page.tsx b/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/create/page.tsx new file mode 100644 index 00000000..39e0a23a --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/create/page.tsx @@ -0,0 +1,78 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { Box, Button, Paper, Select, Stack, TextInput, Title } from '@mantine/core'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; +import strukturorganisasiState from '@/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi'; + +export default function CreateHubunganOrganisasi() { + const router = useRouter(); + const state = useProxy(strukturorganisasiState.hubunganOrganisasi); + const pegawaiList = strukturorganisasiState.pegawai.findMany.data; + + const [form, setForm] = useState({ + atasanId: '', + bawahanId: '', + tipe: '', + }); + + useEffect(() => { + strukturorganisasiState.pegawai.findMany.load(); + }, []); + + const handleSubmit = async () => { + if (!form.atasanId || !form.bawahanId) { + toast.warn("Atasan dan bawahan harus diisi"); + return; + } + + state.create.form = form; + const result = await state.create.create(); + + if (result) { + toast.success("Hubungan Organisasi berhasil ditambahkan"); + router.push('/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi'); + } + }; + + return ( + + + + Create Hubungan Organisasi + ({ + value: p.id, + label: p.namaLengkap, + })) || []} + value={form.bawahanId} + onChange={(val) => setForm({ ...form, bawahanId: val || '' })} + /> + setForm({ ...form, tipe: e.currentTarget.value })} + /> + + + + + ); +} diff --git a/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/page.tsx b/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/page.tsx index 69da2f21..6d312304 100644 --- a/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/page.tsx @@ -1,11 +1,109 @@ -import React from 'react'; +'use client' +import colors from '@/con/colors'; +import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { IconEdit, IconSearch, IconTrash } from '@tabler/icons-react'; +import { useRouter } from 'next/navigation'; +import { useProxy } from 'valtio/utils'; +import HeaderSearch from '../../../_com/header'; +import JudulList from '../../../_com/judulList'; +import strukturorganisasiState from '../../../_state/ekonomi/struktur-organisasi/struktur-organisasi'; +import { useState } from 'react'; +import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus'; -function Page() { +function HubunganOrganisasi() { return ( -
- Page -
+ + } + /> + + ); } -export default Page; +function ListHubunganOrganisasi() { + const stateOrganisasi = useProxy(strukturorganisasiState.hubunganOrganisasi); + const [modalHapus, setModalHapus] = useState(false) + const [selectedId, setSelectedId] = useState(null) + // const params = useParams() + const router = useRouter() + + useShallowEffect(() => { + stateOrganisasi.findMany.load() + }, []) + + const handleHapus = () => { + if (selectedId) { + stateOrganisasi.delete.byId(selectedId) + setModalHapus(false) + setSelectedId(null) + } + } + + if (!stateOrganisasi.findMany.data) { + return ( + + + + ) + } + return ( + + + + + + + Atasan + Bawahan + Tipe + Edit + Hapus + + + + {([...stateOrganisasi.findMany.data || []] + .sort((a, b) => { + return a.atasan?.namaLengkap.localeCompare(b.atasan?.namaLengkap); // kalau status sama, urut nama + }) // Aktif di atas + ).map((item) => ( + + {item.atasan?.namaLengkap} + {item.bawahan?.namaLengkap} + {item.tipe} + + + + + + + + ))} + +
+
+ {/* Modal Konfirmasi Hapus */} + setModalHapus(false)} + onConfirm={handleHapus} + text='Apakah anda yakin ingin menghapus hubungan organisasi ini?' + /> +
+ ); +} + +export default HubunganOrganisasi; diff --git a/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/page.tsx b/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/page.tsx index d3a110db..af61fc73 100644 --- a/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/page.tsx +++ b/src/app/admin/(dashboard)/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/pegawai/page.tsx @@ -108,7 +108,12 @@ function ListPegawai() { return null; })()} {([...stateOrganisasi.findMany.data || []] - .sort((a, b) => Number(b.isActive) - Number(a.isActive)) // Aktif di atas + .sort((a, b) => { + if (a.isActive === b.isActive) { + return a.namaLengkap.localeCompare(b.namaLengkap); // kalau status sama, urut nama + } + return Number(b.isActive) - Number(a.isActive); // aktif duluan + }) // Aktif di atas ).map((item) => ( {item.namaLengkap} diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-organisasi/hubungan-organisasi/index.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-organisasi/hubungan-organisasi/index.ts index 56c1440e..994bdd4a 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-organisasi/hubungan-organisasi/index.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-organisasi/hubungan-organisasi/index.ts @@ -35,14 +35,13 @@ const HubunganOrganisasi = new Elysia({ return response; }, { body: t.Object({ - id: t.String(), atasanId: t.Optional(t.String()), bawahanId: t.Optional(t.String()), tipe: t.Optional(t.String()), }), }) - // ❌ DELETE /:id - .delete("/:id", hubunganOrganisasiDelete); + // ❌ DELETE /del/:id + .delete("/del/:id", hubunganOrganisasiDelete); export default HubunganOrganisasi; diff --git a/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-organisasi/hubungan-organisasi/updt.ts b/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-organisasi/hubungan-organisasi/updt.ts index 0ec8abd6..3d3491cd 100644 --- a/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-organisasi/hubungan-organisasi/updt.ts +++ b/src/app/api/[[...slugs]]/_lib/ekonomi/struktur-organisasi/hubungan-organisasi/updt.ts @@ -1,27 +1,27 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import prisma from "@/lib/prisma"; import { Context } from "elysia"; +/* eslint-disable @typescript-eslint/no-explicit-any */ type FormUpdateHubungan = { - id: string; atasanId?: string; bawahanId?: string; tipe?: string; }; export default async function hubunganOrganisasiUpdate(context: Context) { - const body = await context.body as FormUpdateHubungan; + const body = await context.body as Omit; + const id = context.params?.id; - if (!body?.id) { + if (!id) { return { success: false, - message: "ID wajib diisi untuk update", + message: "ID wajib ada di URL", }; } try { const updated = await prisma.hubunganOrganisasi.update({ - where: { id: body.id }, + where: { id }, data: { atasanId: body.atasanId, bawahanId: body.bawahanId,