Merge pull request 'amalia/07-apr-26' (#30) from amalia/07-apr-26 into join

Reviewed-on: #30
This commit is contained in:
2026-04-07 17:31:04 +08:00
2 changed files with 408 additions and 2 deletions

View File

@@ -1,7 +1,8 @@
import formatDateTime from "@/lib/formatDateTime";
import { prisma } from "@/module/_global";
import cors from "@elysiajs/cors";
import { swagger } from "@elysiajs/swagger";
import Elysia from "elysia";
import Elysia, { t } from "elysia";
import _ from "lodash";
import moment from "moment";
import "moment/locale/id";
@@ -225,8 +226,402 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
},
}
)
.get(
"/get-villages",
async ({ query, set }) => {
const { search, page } = query;
const pageNum = Number(page ?? 1);
try {
const data = await prisma.village.findMany({
where: {
isDummy: false,
...(search && { name: { contains: search, mode: 'insensitive' } })
},
select: {
id: true,
name: true,
isActive: true,
createdAt: true,
User: {
where: {
idUserRole: "supadmin"
},
select: {
name: true,
},
take: 1,
},
},
skip: (pageNum - 1) * 10,
take: 10,
})
;
const result = data.map((village) => ({
id: village.id,
name: village.name,
isActive: village.isActive,
createdAt: formatDateTime(village.createdAt),
perbekel: village.User[0]?.name || null,
}));
return {
success: true,
message: "Berhasil mendapatkan data",
data: result,
};
} catch (error) {
console.error("[villages] get-villages error:", error);
set.status = 500;
return {
success: false,
message: "Terjadi kesalahan pada server",
data: null,
};
}
},
{
query: t.Object({
search: t.Optional(t.String({ description: "Kata kunci pencarian nama desa" })),
page: t.Optional(t.String({ description: "Halaman data (default: 1)" })),
}),
detail: {
summary: "Get Villages",
description: "Menu Villages - Mendapatkan semua data desa.",
tags: ["villages"],
},
}
)
.get(
"/info-villages",
async ({ query, set }) => {
const { id } = query;
try {
const data = await prisma.village.findUnique({
where: {
id: id,
},
select: {
id: true,
name: true,
isActive: true,
createdAt: true,
User: {
where: {
idUserRole: "supadmin"
},
select: {
name: true,
},
take: 1,
},
},
})
if (!data) {
set.status = 404;
return {
success: false,
message: "Desa tidak ditemukan",
data: null,
};
}
const result = data ? {
id: data?.id,
name: data?.name,
isActive: data?.isActive,
createdAt: data?.createdAt ? formatDateTime(data.createdAt) : null,
perbekel: data?.User[0]?.name || null,
} : null;
return {
success: true,
message: "Berhasil mendapatkan data",
data: result,
};
} catch (error) {
console.error("[detail-villages] info-villages error:", error);
set.status = 500;
return {
success: false,
message: "Terjadi kesalahan pada server",
data: null,
};
}
},
{
query: t.Object({
id: t.Optional(t.String({ description: "ID desa" })),
}),
detail: {
summary: "Info Villages",
description: "Menu Detail Villages - Mendapatkan info data desa untuk header dan kolom Informasi Sistem.",
tags: ["detail-villages"],
},
}
)
.get(
"/grid-villages",
async ({ query, set }) => {
const { id } = query;
try {
const village = await prisma.village.findUnique({
where: { id: id }
});
if (!village) {
set.status = 404;
return {
success: false,
message: "Desa tidak ditemukan",
data: null,
};
}
const dataUser = await prisma.user.findMany({
where: {
idVillage: id,
NOT: {
idUserRole: "developer"
}
}
})
const dataGroup = await prisma.group.findMany({
where: {
idVillage: id,
}
})
const dataDivision = await prisma.division.findMany({
where: {
idVillage: id,
}
})
const dataProject = await prisma.project.findMany({
where: {
idVillage: id
}
})
const result = {
user: {
active: dataUser.filter((user) => user.isActive).length,
nonActive: dataUser.filter((user) => !user.isActive).length,
},
group: {
active: dataGroup.filter((group) => group.isActive).length,
nonActive: dataGroup.filter((group) => !group.isActive).length,
},
division: {
active: dataDivision.filter((division) => division.isActive).length,
nonActive: dataDivision.filter((division) => !division.isActive).length,
},
project: {
active: dataProject.filter((project) => project.isActive).length,
nonActive: dataProject.filter((project) => !project.isActive).length,
}
};
return {
success: true,
message: "Berhasil mendapatkan data",
data: result,
};
} catch (error) {
console.error("[detail-villages] grid-villages error:", error);
set.status = 500;
return {
success: false,
message: "Terjadi kesalahan pada server",
data: null,
};
}
},
{
query: t.Object({
id: t.Optional(t.String({ description: "ID desa" })),
}),
detail: {
summary: "Grid Villages",
description: "Menu Grid Villages - Mendapatkan info data desa untuk 4 grid untuk halaman detail desa.",
tags: ["detail-villages"],
},
}
)
.get("/log-villages", async ({ query, set }) => {
const { id, time } = query;
try {
const village = await prisma.village.findUnique({
where: { id },
});
if (!village) {
set.status = 404;
return {
success: false,
message: "Desa tidak ditemukan",
data: null,
};
}
const now = new Date();
let startDate: Date;
if (time === "daily") {
startDate = new Date();
startDate.setDate(now.getDate() - 13); // 14 hari
} else if (time === "monthly") {
startDate = new Date(now.getFullYear(), 0, 1); // awal tahun
} else if (time === "yearly") {
startDate = new Date(now.getFullYear() - 4, 0, 1); // 5 tahun terakhir (opsional)
} else {
startDate = new Date(0);
}
const dataLog = await prisma.userLog.findMany({
where: {
createdAt: {
gte: startDate,
},
User: {
idVillage: id,
},
},
select: {
createdAt: true,
},
});
// =========================
// 🔥 GROUPING
// =========================
const map: Record<string, number> = {};
dataLog.forEach((log) => {
const date = new Date(log.createdAt);
let label = "";
if (time === "daily") {
label = date.toLocaleDateString("id-ID", {
day: "2-digit",
month: "short",
});
} else if (time === "monthly") {
label = date.toLocaleDateString("id-ID", {
month: "short",
});
} else if (time === "yearly") {
label = date.getFullYear().toString();
}
map[label] = (map[label] || 0) + 1;
});
// =========================
// 🔥 FORMAT FINAL
// =========================
let result: any[] = [];
if (time === "daily") {
for (let i = 13; i >= 0; i--) {
const d = new Date();
d.setDate(d.getDate() - i);
const label = d.toLocaleDateString("id-ID", {
day: "2-digit",
month: "short",
});
result.push({
label,
aktivitas: map[label] || 0,
});
}
} else if (time === "monthly") {
const year = now.getFullYear();
for (let m = 0; m <= 11; m++) {
const d = new Date(year, m, 1);
const label = d.toLocaleDateString("id-ID", {
month: "short",
});
result.push({
label,
aktivitas: map[label] || 0,
});
}
} else if (time === "yearly") {
const years = Object.keys(map).map(Number);
if (years.length === 0) {
const currentYear = new Date().getFullYear();
result = [
{ label: currentYear.toString(), aktivitas: 0 }
];
} else {
const minYear = Math.min(...years);
const maxYear = Math.max(...years);
result = [];
for (let y = minYear; y <= maxYear; y++) {
const label = y.toString();
result.push({
label,
aktivitas: map[label] || 0,
});
}
}
}
return {
success: true,
message: "Berhasil mendapatkan data",
data: result,
};
} catch (error) {
console.error("[log-villages] error:", error);
set.status = 500;
return {
success: false,
message: "Terjadi kesalahan pada server",
data: null,
};
}
},
{
query: t.Object({
id: t.String({ description: "ID desa" }),
time: t.Enum(
{
daily: "daily",
monthly: "monthly",
yearly: "yearly",
},
{
description: "Rentang waktu (daily = 14 hari, monthly = 1 tahun, yearly = per tahun)",
}
),
}),
detail: {
summary: "Log Villages",
description:
"Mendapatkan data log aktivitas desa berdasarkan rentang waktu (harian, bulanan, tahunan)",
tags: ["detail-villages"],
},
}
);
;
export const GET = MonitoringServer.handle;

11
src/lib/formatDateTime.ts Normal file
View File

@@ -0,0 +1,11 @@
function formatDateTime(date: Date) {
return new Intl.DateTimeFormat('id-ID', {
hour: '2-digit',
minute: '2-digit',
day: '2-digit',
month: 'short',
year: 'numeric',
}).format(date);
}
export default formatDateTime