UI & API Submenu Sektor Unggulan, Menu Ekonomi

This commit is contained in:
2025-07-08 17:16:13 +08:00
parent d105293149
commit 46c79b8ded
15 changed files with 784 additions and 149 deletions

View File

@@ -1237,4 +1237,16 @@ model GrafikJumlahPendudukMiskin {
updatedAt DateTime @updatedAt
deletedAt DateTime @default(now())
isActive Boolean @default(true)
}
// ========================================= SEKTOR UNGGULAN DESA ========================================= //
model SektorUnggulanDesa {
id String @id @default(uuid()) @db.Uuid // Menggunakan UUID sebagai primary key
name String @unique @db.VarChar(100) // Nama sektor (e.g., "Sektor Pertanian", "Sektor Peternakan")
description String? @db.Text // Deskripsi lengkap tentang sektor
value Float? // Nilai kuantitatif sektor (misalnya, kontribusi PDB, jumlah produksi, dll.)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime @default(now())
isActive Boolean @default(true)
}

View File

@@ -0,0 +1,202 @@
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 templateGrafikSektorUnggulan = z.object({
name: z.string().min(2, "Nama harus diisi"),
description: z.string().min(2, "Deskripsi harus diisi"),
value: z.number().min(1, "Nilai harus diisi"),
});
interface SektorUnggulanForm {
id?: string;
name: string;
description: string;
value: number;
}
const defaultForm: SektorUnggulanForm = {
name: "",
description: "",
value: 0,
};
const grafikSektorUnggulan = proxy({
create: {
form: defaultForm,
loading: false,
async create() {
const cek = templateGrafikSektorUnggulan.safeParse(
grafikSektorUnggulan.create.form
);
if (!cek.success) {
const err = `[${cek.error.issues
.map((v) => `${v.path.join(".")}`)
.join("\n")}] required`;
return toast.error(err);
}
try {
grafikSektorUnggulan.create.loading = true;
const res = await ApiFetch.api.ekonomi.sektourunggulandesa[
"create"
].post(grafikSektorUnggulan.create.form);
if (res.status === 200) {
const id = res.data?.data?.id;
if (id) {
toast.success("Success create");
grafikSektorUnggulan.create.form = {
name: "",
description: "",
value: 0,
};
grafikSektorUnggulan.findMany.load();
return id;
}
}
return toast.error("failed create");
} catch (error) {
console.log((error as Error).message);
} finally {
grafikSektorUnggulan.create.loading = false;
}
},
},
findMany: {
data: null as
| Prisma.SektorUnggulanDesaGetPayload<{
select: {
id: true;
name: true;
description: true;
value: true;
createdAt: true;
updatedAt: true;
};
}>[]
| null,
loading: false,
async load() {
const res = await ApiFetch.api.ekonomi.sektourunggulandesa[
"find-many"
].get();
if (res.status === 200) {
grafikSektorUnggulan.findMany.data = res.data?.data ?? [];
}
},
},
findUnique: {
data: null as Prisma.SektorUnggulanDesaGetPayload<{
select: {
id: true;
name: true;
description: true;
value: true;
createdAt: true;
updatedAt: true;
};
}> | null,
async load(id: string) {
try {
const res = await fetch(`/api/ekonomi/sektourunggulandesa/${id}`);
if (res.ok) {
const data = await res.json();
grafikSektorUnggulan.findUnique.data = data.data ?? null;
} else {
console.error("Failed to fetch data", res.status, res.statusText);
grafikSektorUnggulan.findUnique.data = null;
}
} catch (error) {
console.error("Error loading grafik sektor unggulan desa:", error);
grafikSektorUnggulan.findUnique.data = null;
}
},
},
update: {
id: "",
form: { ...defaultForm },
loading: false,
async byId() {
// Method implementation if needed
},
async submit() {
const id = this.id;
if (!id) {
toast.warn("ID tidak valid");
return null;
}
const cek = templateGrafikSektorUnggulan.safeParse(this.form);
if (!cek.success) {
const err = `[${cek.error.issues
.map((v) => `${v.path.join(".")}`)
.join("\n")}] required`;
toast.error(err);
return null;
}
this.loading = true;
try {
const response = await fetch(`/api/ekonomi/sektourunggulandesa/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(this.form),
});
const result = await response.json();
if (!response.ok || !result?.success) {
throw new Error(result?.message || "Gagal update data");
}
toast.success("Berhasil update data!");
await grafikSektorUnggulan.findMany.load();
return result.data;
} catch (error) {
console.error("Error update data:", error);
toast.error("Gagal update data grafik sektor unggulan desa");
} finally {
this.loading = false;
}
},
},
delete: {
loading: false,
async byId(id: string) {
if (!id) return toast.warn("ID tidak valid");
try {
grafikSektorUnggulan.delete.loading = true;
const response = await fetch(
`/api/ekonomi/sektourunggulandesa/del/${id}`,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}
);
const result = await response.json();
if (response.ok && result?.success) {
toast.success(
result.message || "Grafik sektor unggulan desa berhasil dihapus"
);
await grafikSektorUnggulan.findMany.load(); // refresh list
} else {
toast.error(
result?.message || "Gagal menghapus grafik sektor unggulan desa"
);
}
} catch (error) {
console.error("Gagal delete:", error);
toast.error(
"Terjadi kesalahan saat menghapus grafik sektor unggulan desa"
);
} finally {
grafikSektorUnggulan.delete.loading = false;
}
},
},
});
export default grafikSektorUnggulan;

View File

@@ -0,0 +1,89 @@
/* eslint-disable react-hooks/exhaustive-deps */
'use client'
import grafikSektorUnggulan from '@/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa';
import colors from '@/con/colors';
import { Box, Button, Paper, Stack, TextInput, Title } from '@mantine/core';
import { IconArrowBack } from '@tabler/icons-react';
import { useParams, useRouter } from 'next/navigation';
import { useEffect } from 'react';
import { useProxy } from 'valtio/utils';
function EditSektorUnggulanDesa() {
const router = useRouter()
const params = useParams() as { id: string }
const stateGrafik = useProxy(grafikSektorUnggulan)
const id = params.id
// Load data saat komponen mount
useEffect(() => {
if (id) {
stateGrafik.findUnique.load(id).then(() => {
const data = stateGrafik.findUnique.data
if (data) {
stateGrafik.update.form = {
name: data.name || '',
description: data.description || '',
value: data.value || 0,
}
}
})
}
}, [id])
const handleSubmit = async () => {
// Set the ID before submitting
stateGrafik.update.id = id;
await stateGrafik.update.submit();
router.push('/admin/ekonomi/sektor-unggulan-desa')
}
return (
<Box>
<Box mb={10}>
<Button variant="subtle" onClick={() => router.back()}>
<IconArrowBack size={20} />
</Button>
</Box>
<Paper bg={colors['white-1']} w={{ base: '100%', md: '50%' }} p={'md'}>
<Stack>
<Title order={3}>Edit Sektor Unggulan Desa</Title>
<TextInput
label="Nama Sektor Unggulan"
placeholder="masukkan nama sektor unggulan"
value={stateGrafik.update.form.name}
onChange={(val) => {
stateGrafik.update.form.name = val.currentTarget.value;
}}
/>
<TextInput
label="Deskripsi Sektor Unggulan"
placeholder="masukkan deskripsi sektor unggulan"
value={stateGrafik.update.form.description}
onChange={(val) => {
stateGrafik.update.form.description = val.currentTarget.value;
}}
/>
<TextInput
label="Jumlah"
type="number"
placeholder="masukkan jumlah"
value={stateGrafik.update.form.value}
onChange={(val) => {
stateGrafik.update.form.value = Number(val.currentTarget.value);
}}
/>
<Button
mt={10}
bg={colors['blue-button']}
onClick={handleSubmit}
>
Simpan
</Button>
</Stack>
</Paper>
</Box>
)
}
export default EditSektorUnggulanDesa;

View File

@@ -0,0 +1,105 @@
'use client'
import { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus';
import colors from '@/con/colors';
import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react';
import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react';
import { useProxy } from 'valtio/utils';
import grafikSektorUnggulan from '../../../_state/ekonomi/sektor-unggulan-desa';
function DetailSektorUnggulanDesa() {
const stateGrafik = useProxy(grafikSektorUnggulan)
const [modalHapus, setModalHapus] = useState(false)
const [selectedId, setSelectedId] = useState<string | null>(null)
const params = useParams()
const router = useRouter();
useShallowEffect(() => {
stateGrafik.findUnique.load(params?.id as string)
}, [])
const handleHapus = () => {
if (selectedId) {
stateGrafik.delete.byId(selectedId)
setModalHapus(false)
setSelectedId(null)
router.push("/admin/ekonomi/sektor-unggulan-desa")
}
}
if (!stateGrafik.findUnique.data) {
return (
<Stack py={10}>
<Skeleton h={500} />
</Stack>
)
}
return (
<Box>
<Box mb={10}>
<Button variant="subtle" onClick={() => router.back()}>
<IconArrowBack color={colors['blue-button']} size={25} />
</Button>
</Box>
<Paper w={{ base: "100%", md: "50%" }} bg={colors['white-1']} p={'md'}>
<Stack>
<Text fz={"xl"} fw={"bold"}>Detail Sektor Unggulan Desa</Text>
<Paper bg={colors['BG-trans']} p={'md'}>
<Stack gap={"xs"}>
<Box>
<Text fz={"lg"} fw={"bold"}>Nama Sektor Unggulan</Text>
<Text fz={"lg"}>{stateGrafik.findUnique.data?.name}</Text>
</Box>
<Box>
<Text fz={"lg"} fw={"bold"}>Deskripsi Sektor Unggulan</Text>
<Text fz={"lg"}>{stateGrafik.findUnique.data?.description}</Text>
</Box>
<Box>
<Text fz={"lg"} fw={"bold"}>Jumlah Sektor Unggulan</Text>
<Text fz={"lg"}>{stateGrafik.findUnique.data?.value}</Text>
</Box>
<Box>
<Flex gap={"xs"}>
<Button
onClick={() => {
if (stateGrafik.findUnique.data) {
setSelectedId(stateGrafik.findUnique.data.id);
setModalHapus(true);
}
}}
disabled={!stateGrafik.findUnique.data}
color="red">
<IconX size={20} />
</Button>
<Button
onClick={() => {
if (stateGrafik.findUnique.data) {
router.push(`/admin/ekonomi/sektor-unggulan-desa/${stateGrafik.findUnique.data.id}/edit`);
}
}}
disabled={!stateGrafik.findUnique.data}
color="green">
<IconEdit size={20} />
</Button>
</Flex>
</Box>
</Stack>
</Paper>
</Stack>
</Paper>
{/* Modal Hapus */}
<ModalKonfirmasiHapus
opened={modalHapus}
onClose={() => setModalHapus(false)}
onConfirm={handleHapus}
text="Apakah anda yakin ingin menghapus sektor unggulan ini?"
/>
</Box>
);
}
export default DetailSektorUnggulanDesa;

View File

@@ -1,43 +1,89 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client'
import colors from '@/con/colors';
import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
import { Box, Button, Group, Paper, Stack, TextInput, Title } from '@mantine/core';
import { IconArrowBack } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { KeamananEditor } from '../../../keamanan/_com/keamananEditor';
import { useState } from 'react';
import { useProxy } from 'valtio/utils';
import grafikSektorUnggulan from '../../../_state/ekonomi/sektor-unggulan-desa';
function CreateSektorUnggulanDesa() {
const router = useRouter();
const stateGrafik= useProxy(grafikSektorUnggulan);
const [chartData, setChartData] = useState<any[]>([]);
const router = useRouter()
const resetForm = () => {
stateGrafik.create.form = {
name: "",
description: "",
value: 0,
}
}
const handleSubmit = async () => {
const id = await stateGrafik.create.create();
if (id) {
const idStr = String(id);
await stateGrafik.findUnique.load(idStr);
if (stateGrafik.findUnique.data) {
setChartData([stateGrafik.findUnique.data]);
}
}
resetForm();
router.push("/admin/ekonomi/sektor-unggulan-desa");
}
return (
<Box>
<Box mb={10}>
<Button onClick={() => router.back()} variant='subtle' color={'blue'}>
<IconArrowBack color={colors['blue-button']} size={25} />
<Button variant="subtle" onClick={() => router.back()}>
<IconArrowBack size={20} />
</Button>
</Box>
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
<Stack gap={"xs"}>
<Title order={4}>Create Sektor Unggulan Desa</Title>
<TextInput
label={<Text fw={"bold"} fz={"sm"}>Nama Sektor Unggulan</Text>}
placeholder='Masukkan nama sektor unggulan'
/>
<Box>
<Text fw={"bold"} fz={"sm"}>Deskripsi Sektor Unggulan</Text>
<KeamananEditor
showSubmit={false}
<Box>
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
<Title order={4}>Tambah Grafik Hasil Kepuasan Masyarakat</Title>
<Stack gap={"xs"}>
<TextInput
label="Nama Sektor Unggulan"
type="text"
value={stateGrafik.create.form.name}
placeholder="Masukkan nama sektor unggulan"
onChange={(val) => {
stateGrafik.create.form.name = val.currentTarget.value;
}}
/>
</Box>
<TextInput
label={<Text fw={"bold"} fz={"sm"}>Jumlah Sektor Unggulan</Text>}
placeholder='Masukkan jumlah sektor unggulan'
/>
<Group>
<Button bg={colors['blue-button']}>Submit</Button>
</Group>
</Stack>
</Paper>
<TextInput
label="Deskripsi Sektor Unggulan"
type="text"
value={stateGrafik.create.form.description}
placeholder="Masukkan deskripsi sektor unggulan"
onChange={(val) => {
stateGrafik.create.form.description = val.currentTarget.value;
}}
/>
<TextInput
label="Jumlah"
type="number"
value={stateGrafik.create.form.value}
placeholder="Masukkan jumlah"
onChange={(val) => {
stateGrafik.create.form.value = Number(val.currentTarget.value);
}}
/>
<Group>
<Button
bg={colors['blue-button']}
mt={10}
onClick={handleSubmit}
>
Submit
</Button>
</Group>
</Stack>
</Paper>
</Box>
</Box>
);
}

View File

@@ -1,62 +0,0 @@
'use client'
import colors from '@/con/colors';
import { Box, Button, Flex, Paper, Stack, Text } from '@mantine/core';
import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
function DetailSektorUnggulanDesa() {
const router = useRouter();
return (
<Box>
<Box mb={10}>
<Button variant="subtle" onClick={() => router.back()}>
<IconArrowBack color={colors['blue-button']} size={25} />
</Button>
</Box>
<Paper w={{ base: "100%", md: "50%" }} bg={colors['white-1']} p={'md'}>
<Stack>
<Text fz={"xl"} fw={"bold"}>Detail Sektor Unggulan Desa</Text>
<Paper bg={colors['BG-trans']} p={'md'}>
<Stack gap={"xs"}>
<Box>
<Text fw={"bold"}>Nama Sektor Unggulan</Text>
<Text>Petani</Text>
</Box>
<Box>
<Text fw={"bold"}>Deskripsi Sektor Unggulan</Text>
<Text>BIBD</Text>
</Box>
<Box>
<Text fw={"bold"}>Jumlah Sektor Unggulan</Text>
<Text>200</Text>
</Box>
<Box>
<Flex gap={"xs"}>
<Button color="red">
<IconX size={20} />
</Button>
<Button onClick={() => router.push('/admin/ekonomi/sektor-unggulan-desa/edit')} color="green">
<IconEdit size={20} />
</Button>
</Flex>
</Box>
</Stack>
</Paper>
</Stack>
</Paper>
{/* Modal Hapus
<ModalKonfirmasiHapus
opened={modalHapus}
onClose={() => setModalHapus(false)}
onConfirm={handleHapus}
text="Apakah anda yakin ingin menghapus potensi ini?"
/> */}
</Box>
);
}
export default DetailSektorUnggulanDesa;

View File

@@ -1,45 +0,0 @@
'use client'
import colors from '@/con/colors';
import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
import { IconArrowBack } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { KeamananEditor } from '../../../keamanan/_com/keamananEditor';
function EditSektorUnggulanDesa() {
const router = useRouter();
return (
<Box>
<Box mb={10}>
<Button onClick={() => router.back()} variant='subtle' color={'blue'}>
<IconArrowBack color={colors['blue-button']} size={25} />
</Button>
</Box>
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
<Stack gap={"xs"}>
<Title order={4}>Edit Sektor Unggulan Desa</Title>
<TextInput
label={<Text fw={"bold"} fz={"sm"}>Nama Sektor Unggulan</Text>}
placeholder='Masukkan nama sektor unggulan'
/>
<Box>
<Text fw={"bold"} fz={"sm"}>Deskripsi Sektor Unggulan</Text>
<KeamananEditor
showSubmit={false}
/>
</Box>
<TextInput
label={<Text fw={"bold"} fz={"sm"}>Jumlah Sektor Unggulan</Text>}
placeholder='Masukkan jumlah sektor unggulan'
/>
<Group>
<Button bg={colors['blue-button']}>Submit</Button>
</Group>
</Stack>
</Paper>
</Box>
);
}
export default EditSektorUnggulanDesa;

View File

@@ -1,26 +1,65 @@
'use client'
import colors from '@/con/colors';
import { Box, Button, Paper, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
import { Box, Button, Paper, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
import HeaderSearch from '../../_com/header';
import JudulList from '../../_com/judulList';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import grafikSektorUnggulan from '../../_state/ekonomi/sektor-unggulan-desa';
import { useProxy } from 'valtio/utils';
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts';
function SektorUnggulanDesa() {
const [search, setSearch] = useState('');
return (
<Box>
<HeaderSearch
title='Sektor Unggulan Desa'
placeholder='pencarian'
searchIcon={<IconSearch size={20} />}
value={search}
onChange={(e) => setSearch(e.currentTarget.value)}
/>
<ListSektorUnggulanDesa/>
<ListSektorUnggulanDesa search={search} />
</Box>
);
}
function ListSektorUnggulanDesa() {
function ListSektorUnggulanDesa({ search }: { search: string }) {
const router = useRouter();
const state = useProxy(grafikSektorUnggulan);
const [chartData, setChartData] = useState<{id: string; name: string; description: string | null; value: number | null}[]>([]);
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
const isTablet = useMediaQuery('(max-width: 1024px)')
const isMobile = useMediaQuery('(max-width: 768px)')
const filteredData = (state.findMany.data || []).filter(item => {
const keyword = search.toLowerCase();
return (
item.name.toLowerCase().includes(keyword) ||
(item.value?.toString() || '').toLowerCase().includes(keyword)
);
});
useShallowEffect(() => {
setMounted(true)
state.findMany.load()
}, [])
useEffect(() => {
setMounted(true);
if (state.findMany.data) {
setChartData(state.findMany.data.map((item) => ({
id: item.id,
name: item.name,
description: item.description,
value: Number(item.value),
})));
}
}, [state.findMany.data]);
return (
<Box py={10}>
<Paper bg={colors['white-1']} p={'md'}>
@@ -34,21 +73,48 @@ function ListSektorUnggulanDesa() {
<TableTh>Nama Sektor Unggulan</TableTh>
<TableTh>Deskripsi Sektor Unggulan</TableTh>
<TableTh>Detail</TableTh>
</TableTr>
</TableTr>
</TableThead>
<TableTbody>
<TableTr>
<TableTd>Sektor 1</TableTd>
<TableTd>Deskripsi Sektor 1</TableTd>
<TableTd>
<Button onClick={() => router.push('/admin/ekonomi/sektor-unggulan-desa/detail')}>
<IconDeviceImac size={20} />
</Button>
</TableTd>
</TableTr>
{filteredData.map((item) => (
<TableTr key={item.id}>
<TableTd>{item.name}</TableTd>
<TableTd>{item.description}</TableTd>
<TableTd>
<Button onClick={() => router.push(`/admin/ekonomi/sektor-unggulan-desa/${item.id}`)}>
<IconDeviceImac size={20} />
</Button>
</TableTd>
</TableTr>
))}
</TableTbody>
</Table>
</Table>
</Paper>
{/* Chart */}
{!mounted && !chartData ? (
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
<Paper bg={colors['white-1']} p={'md'}>
<Title pb={10} order={3}>Grafik Hasil Kepuasan Masyarakat</Title>
<Text c='dimmed'>Belum ada data untuk ditampilkan dalam grafik</Text>
</Paper>
</Box>
) : (
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
<Paper bg={colors['white-1']} p={'md'}>
<Title pb={10} order={4}>Grafik Sektor Unggulan Desa</Title>
{mounted && chartData.length > 0 && (
<BarChart width={isMobile ? 450 : isTablet ? 500 : 550} height={350} data={chartData} >
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Bar dataKey="value" fill={colors['blue-button']} name="Jumlah" />
</BarChart>
)}
</Paper>
</Box>
)}
</Box>
);
}

View File

@@ -7,6 +7,7 @@ import StrukturOrganisasi from "./struktur-organisasi";
import GrafikUsiaKerjaYangMenganggur from "./usia-kerja-yang-menganggur";
import GrafikMenganggurBerdasarkanPendidikan from "./usia-kerja-yang-menganggur/pengangguran-berdasrkan-pendidikan";
import JumlahPendudukMiskin from "./jumlah-penduduk-miskin";
import SektorUnggulanDesa from "./sektor-unggulan-desa";
const Ekonomi = new Elysia({
prefix: "/api/ekonomi",
@@ -20,5 +21,6 @@ const Ekonomi = new Elysia({
.use(GrafikUsiaKerjaYangMenganggur)
.use(GrafikMenganggurBerdasarkanPendidikan)
.use(JumlahPendudukMiskin)
.use(SektorUnggulanDesa)
export default Ekonomi

View File

@@ -0,0 +1,33 @@
import prisma from "@/lib/prisma";
import { Prisma } from "@prisma/client";
import { Context } from "elysia";
type FormCreate = Prisma.SektorUnggulanDesaGetPayload<{
select: {
name: true;
description: true;
value: true;
}
}>;
export default async function sektorUnggulanDesaCreate(context: Context) {
const body = context.body as FormCreate;
const created = await prisma.sektorUnggulanDesa.create({
data: {
name: body.name,
description: body.description,
value: body.value,
},
select: {
id: true,
name: true,
description: true,
value: true,
}
});
return {
success: true,
message: "Success create sektor unggulan desa",
data: created,
};
}

View File

@@ -0,0 +1,44 @@
import prisma from "@/lib/prisma"
import { Context } from "elysia"
export default async function sektorUnggulanDesaDelete(context: Context) {
const {id} = context.params as {id: string}
try {
const existingData = await prisma.sektorUnggulanDesa.findUnique({
where: {
id: id,
}
})
if (!existingData) {
return {
success: false,
message: "Data tidak ditemukan",
data: null,
}
}
await prisma.sektorUnggulanDesa.delete({
where: {
id: id
}
})
return {
success: true,
message: "Data berhasil dihapus",
data: {
id: id,
deleted: true,
}
}
} catch (error) {
console.error("Error deleting data:", error);
return {
success: false,
message: "Gagal menghapus data",
data: null,
};
}
}

View File

@@ -0,0 +1,8 @@
import prisma from "@/lib/prisma";
export default async function sektorUnggulanDesaFindMany() {
const res = await prisma.sektorUnggulanDesa.findMany();
return {
data: res,
};
}

View File

@@ -0,0 +1,47 @@
import prisma from "@/lib/prisma";
export default async function sektorUnggulanDesaFindUnique(request: Request) {
const url = new URL(request.url);
const pathSegments = url.pathname.split('/');
const id = pathSegments[pathSegments.length - 1];
if (!id) {
return Response.json({
success: false,
message: "ID tidak boleh kosong",
}, { status: 400 });
}
try {
if (typeof id !== 'string') {
return Response.json({
success: false,
message: "ID tidak valid",
}, { status: 400 });
}
const data = await prisma.sektorUnggulanDesa.findUnique({
where: { id },
});
if (!data) {
return Response.json({
success: false,
message: "Data tidak ditemukan",
}, { status: 404 });
}
return Response.json({
success: true,
message: "Berhasil mengambil data berdasarkan ID",
data,
}, { status: 200 });
} catch (e) {
console.error("Find by ID error:", e);
return Response.json({
success: false,
message: "Gagal mengambil data: " + (e instanceof Error ? e.message : 'Unknown error'),
}, { status: 500 });
}
}

View File

@@ -0,0 +1,39 @@
import Elysia, { t } from "elysia";
import sektorUnggulanDesaFindMany from "./findMany";
import sektorUnggulanDesaFindUnique from "./findUnique";
import sektorUnggulanDesaCreate from "./create";
import sektorUnggulanDesaUpdate from "./updt";
import sektorUnggulanDesaDelete from "./del";
const SektorUnggulanDesa = new Elysia({
prefix: "/sektourunggulandesa",
tags: ["Ekonomi/Sektor Unggulan Desa"],
})
.get("/find-many", sektorUnggulanDesaFindMany)
.get("/:id", async (context) => {
const response = await sektorUnggulanDesaFindUnique(new Request(context.request));
return response;
})
.post("/create", sektorUnggulanDesaCreate, {
body: t.Object({
name: t.String(),
description: t.String(),
value: t.Number(),
}),
})
.put("/:id", sektorUnggulanDesaUpdate, {
params: t.Object({
id: t.String(),
}),
body: t.Object({
name: t.String(),
description: t.String(),
value: t.Number(),
}),
})
.delete("/del/:id", sektorUnggulanDesaDelete, {
params: t.Object({
id: t.String(),
}),
});
export default SektorUnggulanDesa;

View File

@@ -0,0 +1,49 @@
import prisma from "@/lib/prisma";
import { Context } from "elysia";
export default async function sektorUnggulanDesaUpdate(context: Context) {
const id = context.params?.id;
if (!id) {
return {
success: false,
message: "Id tidak ditemukan",
}
}
const {name, description, value} = context.body as {
name: string;
description: string;
value: number;
}
const existing = await prisma.sektorUnggulanDesa.findUnique({
where: {
id: id,
},
})
if (!existing) {
return {
success: false,
message: "Data tidak ditemukan",
}
}
const updated = await prisma.sektorUnggulanDesa.update({
where: {
id: id,
},
data: {
name,
description,
value,
},
})
return {
success: true,
message: "Data berhasil diupdate",
data: updated,
}
}