UI & API Menu Struktur Organisasi Tabs Hubungan Organisasi
This commit is contained in:
@@ -3,6 +3,6 @@
|
|||||||
"id": "650e8400-e29b-41d4-a716-446655440001",
|
"id": "650e8400-e29b-41d4-a716-446655440001",
|
||||||
"atasanId": "550e8400-e29b-41d4-a716-446655440001",
|
"atasanId": "550e8400-e29b-41d4-a716-446655440001",
|
||||||
"bawahanId": "550e8400-e29b-41d4-a716-446655440002",
|
"bawahanId": "550e8400-e29b-41d4-a716-446655440002",
|
||||||
"tipe": "langsung_melapor"
|
"tipe": "Langsung Melapor"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -591,7 +591,7 @@ const hubunganOrganisasi = proxy({
|
|||||||
|
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
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();
|
const result = await res.json();
|
||||||
|
|
||||||
if (res.ok && result?.success) {
|
if (res.ok && result?.success) {
|
||||||
@@ -616,7 +616,7 @@ const hubunganOrganisasi = proxy({
|
|||||||
if (!id) return toast.warn("ID tidak valid");
|
if (!id) return toast.warn("ID tidak valid");
|
||||||
|
|
||||||
try {
|
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();
|
const result = await res.json();
|
||||||
|
|
||||||
if (res.ok && result?.success) {
|
if (res.ok && result?.success) {
|
||||||
@@ -650,7 +650,7 @@ const hubunganOrganisasi = proxy({
|
|||||||
try {
|
try {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`/api/ekonomi/strukturorganisasi/hubunganorganisasi/${this.id}`,
|
`/api/ekonomi/struktur-organisasi/hubungan-organisasi/${this.id}`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -690,7 +690,7 @@ const hubunganOrganisasi = proxy({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
hubunganOrganisasi.delete.loading = true;
|
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",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
<Box>
|
||||||
|
<Paper p="md" w={{ base: '100%', md: '50%' }}>
|
||||||
|
<Stack>
|
||||||
|
<Title order={3}>Edit Hubungan Organisasi</Title>
|
||||||
|
<Select
|
||||||
|
label="Atasan"
|
||||||
|
placeholder="Pilih atasan"
|
||||||
|
searchable
|
||||||
|
data={pegawaiList?.map(p => ({
|
||||||
|
value: p.id,
|
||||||
|
label: p.namaLengkap,
|
||||||
|
})) || []}
|
||||||
|
value={form.atasanId}
|
||||||
|
onChange={(val) => setForm({ ...form, atasanId: val || '' })}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Bawahan"
|
||||||
|
placeholder="Pilih bawahan"
|
||||||
|
searchable
|
||||||
|
data={pegawaiList?.map(p => ({
|
||||||
|
value: p.id,
|
||||||
|
label: p.namaLengkap,
|
||||||
|
})) || []}
|
||||||
|
value={form.bawahanId}
|
||||||
|
onChange={(val) => setForm({ ...form, bawahanId: val || '' })}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Tipe"
|
||||||
|
placeholder="Contoh: langsung_melapor"
|
||||||
|
value={form.tipe}
|
||||||
|
onChange={(e) => setForm({ ...form, tipe: e.currentTarget.value })}
|
||||||
|
/>
|
||||||
|
<Button onClick={handleSubmit} color="blue">Simpan</Button>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
||||||
|
<Box>
|
||||||
|
<Paper p="md" w={{ base: '100%', md: '50%' }}>
|
||||||
|
<Stack>
|
||||||
|
<Title order={3}>Create Hubungan Organisasi</Title>
|
||||||
|
<Select
|
||||||
|
label="Atasan"
|
||||||
|
placeholder="Pilih atasan"
|
||||||
|
searchable
|
||||||
|
data={pegawaiList?.map(p => ({
|
||||||
|
value: p.id,
|
||||||
|
label: p.namaLengkap,
|
||||||
|
})) || []}
|
||||||
|
value={form.atasanId}
|
||||||
|
onChange={(val) => setForm({ ...form, atasanId: val || '' })}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Bawahan"
|
||||||
|
placeholder="Pilih bawahan"
|
||||||
|
searchable
|
||||||
|
data={pegawaiList?.map(p => ({
|
||||||
|
value: p.id,
|
||||||
|
label: p.namaLengkap,
|
||||||
|
})) || []}
|
||||||
|
value={form.bawahanId}
|
||||||
|
onChange={(val) => setForm({ ...form, bawahanId: val || '' })}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Tipe"
|
||||||
|
placeholder="Contoh: langsung_melapor"
|
||||||
|
value={form.tipe}
|
||||||
|
onChange={(e) => setForm({ ...form, tipe: e.currentTarget.value })}
|
||||||
|
/>
|
||||||
|
<Button onClick={handleSubmit} color="blue">Simpan</Button>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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 (
|
return (
|
||||||
<div>
|
<Box>
|
||||||
Page
|
<HeaderSearch
|
||||||
</div>
|
title='Hubungan Organisasi'
|
||||||
|
placeholder='pencarian'
|
||||||
|
searchIcon={<IconSearch size={20} />}
|
||||||
|
/>
|
||||||
|
<ListHubunganOrganisasi />
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Page;
|
function ListHubunganOrganisasi() {
|
||||||
|
const stateOrganisasi = useProxy(strukturorganisasiState.hubunganOrganisasi);
|
||||||
|
const [modalHapus, setModalHapus] = useState(false)
|
||||||
|
const [selectedId, setSelectedId] = useState<string | null>(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 (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box py={10}>
|
||||||
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
|
<JudulList
|
||||||
|
title='List Hubungan Organisasi'
|
||||||
|
href='/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/create'
|
||||||
|
/>
|
||||||
|
<Table striped withTableBorder withRowBorders>
|
||||||
|
<TableThead>
|
||||||
|
<TableTr>
|
||||||
|
<TableTh>Atasan</TableTh>
|
||||||
|
<TableTh>Bawahan</TableTh>
|
||||||
|
<TableTh>Tipe</TableTh>
|
||||||
|
<TableTh>Edit</TableTh>
|
||||||
|
<TableTh>Hapus</TableTh>
|
||||||
|
</TableTr>
|
||||||
|
</TableThead>
|
||||||
|
<TableTbody>
|
||||||
|
{([...stateOrganisasi.findMany.data || []]
|
||||||
|
.sort((a, b) => {
|
||||||
|
return a.atasan?.namaLengkap.localeCompare(b.atasan?.namaLengkap); // kalau status sama, urut nama
|
||||||
|
}) // Aktif di atas
|
||||||
|
).map((item) => (
|
||||||
|
<TableTr key={item.id}>
|
||||||
|
<TableTd>{item.atasan?.namaLengkap}</TableTd>
|
||||||
|
<TableTd>{item.bawahan?.namaLengkap}</TableTd>
|
||||||
|
<TableTd>{item.tipe}</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Button bg={"green"} onClick={() => router.push(`/admin/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/hubungan-organisasi/${item.id}`)}>
|
||||||
|
<IconEdit size={25} />
|
||||||
|
</Button>
|
||||||
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Button color="red" onClick={() => {
|
||||||
|
setSelectedId(item.id)
|
||||||
|
setModalHapus(true)
|
||||||
|
}}>
|
||||||
|
<IconTrash size={20} />
|
||||||
|
</Button>
|
||||||
|
</TableTd>
|
||||||
|
</TableTr>
|
||||||
|
))}
|
||||||
|
</TableTbody>
|
||||||
|
</Table>
|
||||||
|
</Paper>
|
||||||
|
{/* Modal Konfirmasi Hapus */}
|
||||||
|
<ModalKonfirmasiHapus
|
||||||
|
opened={modalHapus}
|
||||||
|
onClose={() => setModalHapus(false)}
|
||||||
|
onConfirm={handleHapus}
|
||||||
|
text='Apakah anda yakin ingin menghapus hubungan organisasi ini?'
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HubunganOrganisasi;
|
||||||
|
|||||||
@@ -108,7 +108,12 @@ function ListPegawai() {
|
|||||||
return null;
|
return null;
|
||||||
})()}
|
})()}
|
||||||
{([...stateOrganisasi.findMany.data || []]
|
{([...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) => (
|
).map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>{item.namaLengkap}</TableTd>
|
<TableTd>{item.namaLengkap}</TableTd>
|
||||||
|
|||||||
@@ -35,14 +35,13 @@ const HubunganOrganisasi = new Elysia({
|
|||||||
return response;
|
return response;
|
||||||
}, {
|
}, {
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
id: t.String(),
|
|
||||||
atasanId: t.Optional(t.String()),
|
atasanId: t.Optional(t.String()),
|
||||||
bawahanId: t.Optional(t.String()),
|
bawahanId: t.Optional(t.String()),
|
||||||
tipe: t.Optional(t.String()),
|
tipe: t.Optional(t.String()),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
// ❌ DELETE /:id
|
// ❌ DELETE /del/:id
|
||||||
.delete("/:id", hubunganOrganisasiDelete);
|
.delete("/del/:id", hubunganOrganisasiDelete);
|
||||||
|
|
||||||
export default HubunganOrganisasi;
|
export default HubunganOrganisasi;
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
type FormUpdateHubungan = {
|
type FormUpdateHubungan = {
|
||||||
id: string;
|
|
||||||
atasanId?: string;
|
atasanId?: string;
|
||||||
bawahanId?: string;
|
bawahanId?: string;
|
||||||
tipe?: string;
|
tipe?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function hubunganOrganisasiUpdate(context: Context) {
|
export default async function hubunganOrganisasiUpdate(context: Context) {
|
||||||
const body = await context.body as FormUpdateHubungan;
|
const body = await context.body as Omit<FormUpdateHubungan, 'id'>;
|
||||||
|
const id = context.params?.id;
|
||||||
|
|
||||||
if (!body?.id) {
|
if (!id) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "ID wajib diisi untuk update",
|
message: "ID wajib ada di URL",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const updated = await prisma.hubunganOrganisasi.update({
|
const updated = await prisma.hubunganOrganisasi.update({
|
||||||
where: { id: body.id },
|
where: { id },
|
||||||
data: {
|
data: {
|
||||||
atasanId: body.atasanId,
|
atasanId: body.atasanId,
|
||||||
bawahanId: body.bawahanId,
|
bawahanId: body.bawahanId,
|
||||||
|
|||||||
Reference in New Issue
Block a user