Sinkronisasi UI & API Admin - User Menu Inovasi

This commit is contained in:
2025-08-25 16:40:03 +08:00
parent bb8dab05ba
commit f63249327d
34 changed files with 1732 additions and 511 deletions

View File

@@ -1,23 +1,54 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma";
import { Context } from "elysia";
export default async function desaDigitalFindMany() {
try {
const data = await prisma.desaDigital.findMany({
include: {
image: true,
},
});
export default async function desaDigitalFindMany(context: Context) {
// Ambil parameter dari query
const page = Number(context.query.page) || 1;
const limit = Number(context.query.limit) || 10;
const search = (context.query.search as string) || '';
const skip = (page - 1) * limit;
return {
success: true,
message: "Success fetch desa digital",
data,
};
} catch (error) {
console.error("Find many error:", error);
return {
success: false,
message: "Failed fetch desa digital",
};
}
// Buat where clause
const where: any = { isActive: true };
// Tambahkan pencarian (jika ada)
if (search) {
where.OR = [
{ name: { contains: search, mode: 'insensitive' } },
{ deskripsi: { contains: search, mode: 'insensitive' } },
];
}
try {
// Ambil data dan total count secara paralel
const [data, total] = await Promise.all([
prisma.desaDigital.findMany({
where,
include: {
image: true,
},
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.desaDigital.count({ where }),
]);
return {
success: true,
message: "Berhasil ambil desa digital dengan pagination",
data,
page,
limit,
total,
totalPages: Math.ceil(total / limit),
};
} catch (e) {
console.error("Error di findMany paginated:", e);
return {
success: false,
message: "Gagal mengambil data desa digital",
};
}
}

View File

@@ -5,6 +5,7 @@ import KolaborasiInovasi from "./kolaborasi-inovasi";
import InfoTekno from "./info-teknologi";
import AjukanIdeInovatif from "./ajukan-ide-inovatif";
import LayananOnlineDesa from "./layanan-online-desa";
import MitraKolaborasi from "./kolaborasi-inovasi/mitra-kolaborasi";
const Inovasi = new Elysia({
prefix: "/api/inovasi",
@@ -16,5 +17,6 @@ const Inovasi = new Elysia({
.use(InfoTekno)
.use(AjukanIdeInovatif)
.use(LayananOnlineDesa)
.use(MitraKolaborasi)
export default Inovasi;

View File

@@ -1,23 +1,61 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma";
import { Context } from "elysia";
export default async function infoTeknoFindMany() {
try {
const data = await prisma.infoTekno.findMany({
include: {
image: true,
},
});
// Di findMany.ts
export default async function infoTeknoFindMany(context: Context) {
const page = Number(context.query.page) || 1;
const limit = Number(context.query.limit) || 10;
const search = (context.query.search as string) || '';
const skip = (page - 1) * limit;
return {
success: true,
message: "Success fetch info teknologi",
data,
};
} catch (error) {
console.error("Find many error:", error);
return {
success: false,
message: "Failed fetch info teknologi",
};
}
// Buat where clause
const where: any = { isActive: true };
// Tambahkan pencarian (jika ada)
if (search) {
where.OR = [
{ name: { contains: search, mode: 'insensitive' } },
{ deskripsi: { contains: search, mode: 'insensitive' } },
];
}
try {
const [data, total] = await Promise.all([
prisma.infoTekno.findMany({
where,
include: {
image: true,
},
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.infoTekno.count({
where
})
]);
const totalPages = Math.ceil(total / limit);
return {
success: true,
message: "Success fetch info teknologi with pagination",
data,
page,
totalPages,
total,
};
} catch (e) {
console.error("Find many paginated error:", e);
return {
success: false,
message: "Failed fetch info teknologi with pagination",
data: [],
page: 1,
totalPages: 1,
total: 0,
};
}
}

View File

@@ -1,34 +1,37 @@
import prisma from "@/lib/prisma";
import { Context } from "elysia";
import { Prisma } from "@prisma/client";
type FormCreateKolaborasiInovasi = {
name: string;
tahun: number;
slug: string;
deskripsi: string;
kolaborator: string;
imageId: string;
// Define validation schema
type FormCreateKolaborasiInovasi = Prisma.KolaborasiInovasiGetPayload<{
select: {
name: true;
tahun: true;
slug: true;
deskripsi: true;
kolaborator: true;
};
}>;
export default async function kolaborasiInovasiCreate(context: Context) {
const body = context.body as FormCreateKolaborasiInovasi;
// Create new kolaborasi inovasi
await prisma.kolaborasiInovasi.create({
data: {
name: body.name,
tahun: body.tahun,
slug: body.slug,
deskripsi: body.deskripsi,
kolaborator: body.kolaborator,
},
});
return {
success: true,
message: "Berhasil membuat kolaborasi inovasi",
data: {
...body,
},
};
}
export default async function kolaborasiInovasiCreate(context: Context){
const body = context.body as FormCreateKolaborasiInovasi;
await prisma.kolaborasiInovasi.create({
data: {
name: body.name,
tahun: body.tahun,
slug: body.slug,
deskripsi: body.deskripsi,
kolaborator: body.kolaborator,
imageId: body.imageId,
}
})
return {
success: true,
message: "Success create kolaborasi inovasi",
data: {
...body,
}
}
}

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma";
import { Context } from "elysia";
@@ -5,18 +6,42 @@ import { Context } from "elysia";
export default async function kolaborasiInovasiFindMany(context: Context) {
const page = Number(context.query.page) || 1;
const limit = Number(context.query.limit) || 10;
const search = (context.query.search as string) || '';
const year = (context.query.year as string) || '';
const skip = (page - 1) * limit;
// Buat where clause
const where: any = { isActive: true };
// Tambahkan filter tahun (jika ada)
if (year) {
const startDate = new Date(parseInt(year), 0, 1); // 1 Januari tahun tersebut
const endDate = new Date(parseInt(year) + 1, 0, 1); // 1 Januari tahun berikutnya
where.createdAt = {
gte: startDate,
lt: endDate,
};
}
// Tambahkan pencarian (jika ada)
if (search) {
where.OR = [
{ name: { contains: search, mode: 'insensitive' } },
{ slug: { contains: search, mode: 'insensitive' } },
];
}
try {
const [data, total] = await Promise.all([
prisma.kolaborasiInovasi.findMany({
where: { isActive: true },
where,
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.kolaborasiInovasi.count({
where: { isActive: true }
where
})
]);

View File

@@ -15,9 +15,6 @@ export default async function kolaborasiInovasiFindUnique(context: Context) {
try {
const kolaborasiInovasi = await prisma.kolaborasiInovasi.findUnique({
where: { id },
include: {
image: true,
}
});
if (!kolaborasiInovasi) {

View File

@@ -21,7 +21,6 @@ const KolaborasiInovasi = new Elysia({
slug: t.String(),
deskripsi: t.String(),
kolaborator: t.String(),
imageId: t.String(),
}),
})
.put(
@@ -37,7 +36,7 @@ const KolaborasiInovasi = new Elysia({
slug: t.String(),
deskripsi: t.String(),
kolaborator: t.String(),
imageId: t.String(),
}),
}
)

View File

@@ -0,0 +1,26 @@
import prisma from "@/lib/prisma";
import { Context } from "elysia";
type FormCreate = {
name: string;
imageId: string;
};
export default async function mitraKolaborasiCreate(context: Context) {
const body = context.body as FormCreate;
await prisma.mitraKolaborasi.create({
data: {
name: body.name,
imageId: body.imageId,
},
});
return {
success: true,
message: "Berhasil membuat mitra kolaborasi",
data: {
...body,
},
};
}

View File

@@ -0,0 +1,54 @@
import prisma from "@/lib/prisma";
import { Context } from "elysia";
import fs from "fs/promises";
import path from "path";
export default async function mitraKolaborasiDelete(context: Context) {
const id = context.params?.id as string;
if (!id) {
return {
status: 400,
body: "ID tidak diberikan",
};
}
const mitraKolaborasi = await prisma.mitraKolaborasi.findUnique({
where: { id },
include: {
image: true,
},
});
if (!mitraKolaborasi) {
return {
status: 404,
body: "Mitra kolaborasi tidak ditemukan",
};
}
if (mitraKolaborasi.image) {
try {
const filePath = path.join(
mitraKolaborasi.image.path,
mitraKolaborasi.image.name
);
await fs.unlink(filePath);
await prisma.fileStorage.delete({
where: { id: mitraKolaborasi.image.id },
});
} catch (error) {
console.error("Gagal hapus file image:", error);
}
}
await prisma.mitraKolaborasi.delete({
where: { id },
});
return {
success: true,
message: "Mitra kolaborasi berhasil dihapus",
status: 200,
};
}

View File

@@ -0,0 +1,53 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma";
import { Context } from "elysia";
export default async function mitraKolaborasiFindMany(context: Context) {
// Ambil parameter dari query
const page = Number(context.query.page) || 1;
const limit = Number(context.query.limit) || 10;
const search = (context.query.search as string) || '';
const skip = (page - 1) * limit;
// Buat where clause
const where: any = { isActive: true };
// Tambahkan pencarian (jika ada)
if (search) {
where.OR = [
{ name: { contains: search, mode: 'insensitive' } },
];
}
try {
// Ambil data dan total count secara paralel
const [data, total] = await Promise.all([
prisma.mitraKolaborasi.findMany({
where,
include: {
image: true,
},
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.mitraKolaborasi.count({ where }),
]);
return {
success: true,
message: "Berhasil ambil mitra kolaborasi dengan pagination",
data,
page,
limit,
total,
totalPages: Math.ceil(total / limit),
};
} catch (e) {
console.error("Error di findMany paginated:", e);
return {
success: false,
message: "Gagal mengambil data mitra kolaborasi",
};
}
}

View File

@@ -0,0 +1,49 @@
import prisma from "@/lib/prisma";
export default async function mitraKolaborasiFindUnique(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 ditemukan",
}, {status: 400});
}
try {
if (typeof id !== 'string') {
return Response.json({
success: false,
message: "ID tidak valid",
}, {status: 400});
}
const data = await prisma.mitraKolaborasi.findUnique({
where: { id },
include: {
image: true,
},
});
if (!data) {
return Response.json({
success: false,
message: "Mitra kolaborasi tidak ditemukan",
}, {status: 404});
}
return Response.json({
success: true,
message: "Success fetch mitra kolaborasi by ID",
data,
}, {status: 200});
} catch (error) {
console.error("Find by ID error:", error);
return Response.json({
success: false,
message: "Gagal mengambil mitra kolaborasi: " + (error instanceof Error ? error.message : 'Unknown error'),
}, {status: 500});
}
}

View File

@@ -0,0 +1,37 @@
import Elysia, { t } from "elysia";
import mitraKolaborasiCreate from "./create";
import mitraKolaborasiDelete from "./del";
import mitraKolaborasiUpdate from "./updt";
import mitraKolaborasiFindUnique from "./findUnique";
import mitraKolaborasiFindMany from "./findMany";
const MitraKolaborasi = new Elysia({
prefix: "/mitrakolaborasi",
tags: ["Inovasi/Mitra Kolaborasi"],
})
.post("/create", mitraKolaborasiCreate, {
body: t.Object({
name: t.String(),
imageId: t.String(),
}),
})
.get("/find-many", mitraKolaborasiFindMany)
.get("/:id", async (context) => {
const response = await mitraKolaborasiFindUnique(context.request);
return response;
})
.delete("/del/:id", mitraKolaborasiDelete)
.put(
"/:id",
async (context) => {
const response = await mitraKolaborasiUpdate(context);
return response;
},
{
body: t.Object({
name: t.String(),
imageId: t.String(),
}),
}
);
export default MitraKolaborasi;

View File

@@ -0,0 +1,97 @@
import prisma from "@/lib/prisma";
import { Context } from "elysia";
import fs from "fs/promises";
import path from "path";
type FormUpdate = {
id: string;
name: string;
imageId: string;
}
export default async function mitraKolaborasiUpdate(context: Context) {
try {
const id = context.params?.id as string;
const body = (await context.body) as Omit<FormUpdate, "id">;
const {
name,
imageId
} = body;
if (!id) {
return new Response(JSON.stringify({
success: false,
message: "ID tidak ditemukan",
}), {
status: 400,
headers: {
'Content-Type': 'application/json'
}
})
}
const existing = await prisma.mitraKolaborasi.findUnique({
where: {id},
include: {
image: true,
}
})
if (!existing) {
return new Response(JSON.stringify({
success: false,
message: "mitra kolaborasi tidak ditemukan",
}), {
status: 404,
headers: {
'Content-Type': 'application/json'
}
})
}
if (existing.imageId && existing.imageId !== imageId) {
const oldImage = existing.image;
if (oldImage) {
try {
const filePath = path.join(oldImage.path, oldImage.name);
await fs.unlink(filePath);
await prisma.fileStorage.delete({
where: { id: oldImage.id },
});
} catch (error) {
console.error("Gagal hapus gambar lama:", error);
}
}
}
const updated = await prisma.mitraKolaborasi.update({
where: { id },
data: {
name,
imageId,
}
})
return new Response(JSON.stringify({
success: true,
message: "Mitra kolaborasi berhasil diupdate",
data: updated,
}), {
status: 200,
headers: {
'Content-Type': 'application/json'
}
})
} catch (error) {
console.error("Error updating mitra kolaborasi:", error);
return new Response(JSON.stringify({
success: false,
message: "Terjadi kesalahan saat mengupdate mitra kolaborasi",
}), {
status: 500,
headers: {
'Content-Type': 'application/json'
}
})
}
}

View File

@@ -9,7 +9,7 @@ type FormUpdateKolaborasiInovasi = {
slug?: string;
deskripsi?: string;
kolaborator?: string;
imageId?: string;
};
export default async function kolaborasiInovasiUpdate(context: Context) {
const body = context.body as FormUpdateKolaborasiInovasi;
@@ -31,7 +31,6 @@ export default async function kolaborasiInovasiUpdate(context: Context) {
slug: body.slug,
deskripsi: body.deskripsi,
kolaborator: body.kolaborator,
imageId: body.imageId,
},
});