[darmasaba-dashboard][2026-03-27] feat: modular seeders and database-backed dashboard

- Split seeders into modular files per feature category
- Added seed:auth, seed:demographics, seed:divisions, seed:services, seed:dashboard commands
- Connected dashboard components to live database (Budget, SDGs, Satisfaction)
- Added API endpoints: /api/dashboard/budget, /api/dashboard/sdgs, /api/dashboard/satisfaction
- Updated prisma schema with dashboard metrics models
- Added loading states to dashboard components
- Fixed header navigation to /admin

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-03-27 12:14:19 +08:00
parent 34804127c5
commit 44b6b158ef
17 changed files with 1616 additions and 416 deletions

72
src/api/dashboard.ts Normal file
View File

@@ -0,0 +1,72 @@
import { Elysia, t } from "elysia";
import { prisma } from "../utils/db";
export const dashboard = new Elysia({ prefix: "/dashboard" })
.get(
"/budget",
async () => {
const data = await prisma.budget.findMany({
where: { fiscalYear: 2025 },
orderBy: { category: "asc" },
});
return { data };
},
{
response: {
200: t.Object({
data: t.Array(
t.Object({
category: t.String(),
amount: t.Number(),
percentage: t.Number(),
color: t.String(),
}),
),
}),
},
},
)
.get(
"/sdgs",
async () => {
const data = await prisma.sdgsScore.findMany({
orderBy: { score: "desc" },
});
return { data };
},
{
response: {
200: t.Object({
data: t.Array(
t.Object({
title: t.String(),
score: t.Number(),
image: t.Nullable(t.String()),
}),
),
}),
},
},
)
.get(
"/satisfaction",
async () => {
const data = await prisma.satisfactionRating.findMany({
orderBy: { value: "desc" },
});
return { data };
},
{
response: {
200: t.Object({
data: t.Array(
t.Object({
category: t.String(),
value: t.Number(),
color: t.String(),
}),
),
}),
},
},
);

View File

@@ -5,6 +5,7 @@ import { apiMiddleware } from "../middleware/apiMiddleware";
import { auth } from "../utils/auth";
import { apikey } from "./apikey";
import { complaint } from "./complaint";
import { dashboard } from "./dashboard";
import { division } from "./division";
import { event } from "./event";
import { profile } from "./profile";
@@ -40,7 +41,8 @@ const api = new Elysia({
.use(division)
.use(complaint)
.use(resident)
.use(event);
.use(event)
.use(dashboard);
if (!isProduction) {
api.use(