upd: list pengaduan dashboard

This commit is contained in:
2025-11-07 12:06:46 +08:00
parent 14ec81d98d
commit e0456b2dba
3 changed files with 267 additions and 109 deletions

View File

@@ -0,0 +1,21 @@
export function getLastUpdated(date: string | Date): string {
const now = new Date();
const updated = new Date(date);
const diffMs = now.getTime() - updated.getTime();
const diffMinutes = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffMinutes < 1) return "baru saja";
if (diffMinutes < 60) return `${diffMinutes} menit lalu`;
if (diffHours < 24) return `${diffHours} jam lalu`;
if (diffDays < 7) return `${diffDays} hari lalu`;
// kalau sudah lebih dari seminggu, tampilkan tanggal
return updated.toLocaleDateString("id-ID", {
day: "numeric",
month: "long",
year: "numeric",
});
}

View File

@@ -1,5 +1,6 @@
import Elysia, { t } from "elysia"
import type { StatusPengaduan } from "generated/prisma"
import { getLastUpdated } from "../lib/get-last-updated"
import { generateNoPengaduan } from "../lib/no-pengaduan"
import { normalizePhoneNumber } from "../lib/normalizePhone"
import { prisma } from "../lib/prisma"
@@ -462,7 +463,137 @@ const PengaduanRoute = new Elysia({
tags: ["mcp"],
consumes: ["multipart/form-data"]
},
})
.get("/list", async ({ query }) => {
const { take, page, search, status } = query
const skip = !page ? 0 : (Number(page) - 1) * (!take ? 10 : Number(take))
let where: any = {
isActive: true,
OR: [
{
title: {
contains: search ?? "",
mode: "insensitive"
},
},
{
noPengaduan: {
contains: search ?? "",
mode: "insensitive"
},
},
{
detail: {
contains: search ?? "",
mode: "insensitive"
},
},
{
Warga: {
phone: {
contains: search ?? "",
mode: "insensitive"
},
},
}
]
}
);
if (status && status !== "all") {
where = {
...where,
status: status
}
}
const data = await prisma.pengaduan.findMany({
skip,
take: !take ? 10 : Number(take),
orderBy: {
createdAt: "asc"
},
where,
select: {
id: true,
noPengaduan: true,
title: true,
detail: true,
location: true,
status: true,
createdAt: true,
updatedAt: true,
CategoryPengaduan: {
select: {
name: true
}
},
Warga: {
select: {
name: true,
}
}
}
})
const dataFix = data.map((item) => {
return {
noPengaduan: item.noPengaduan,
title: item.title,
detail: item.detail,
status: item.status,
location: item.location,
createdAt: item.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }),
updatedAt: 'terakhir diperbarui ' + getLastUpdated(item.updatedAt),
}
})
return dataFix
}, {
query: t.Object({
take: t.String({ optional: true }),
page: t.String({ optional: true }),
search: t.String({ optional: true }),
status: t.String({ optional: true }),
}),
detail: {
summary: "List Pengaduan Warga",
description: `tool untuk mendapatkan list pengaduan warga`,
}
})
.get("/count", async ({ query }) => {
const counts = await prisma.pengaduan.groupBy({
by: ['status'],
where: {
isActive: true,
},
_count: {
status: true,
},
});
const grouped = Object.fromEntries(
counts.map(c => [c.status, c._count.status])
);
const total = await prisma.pengaduan.count({
where: { isActive: true },
});
return {
antrian: grouped?.antrian || 0,
diterima: grouped?.diterima || 0,
dikerjakan: grouped?.dikerjakan || 0,
ditolak: grouped?.ditolak || 0,
selesai: grouped?.selesai || 0,
semua: total,
};
}, {
detail: {
summary: "Jumlah Pengaduan Warga",
description: `tool untuk mendapatkan jumlah pengaduan warga`,
}
})
;
export default PengaduanRoute