fix(header): fix missing Divider, Badge, IconUserShield and navigate
This commit is contained in:
66
src/api/complaint.ts
Normal file
66
src/api/complaint.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import Elysia from "elysia";
|
||||
import { prisma } from "../utils/db";
|
||||
import logger from "../utils/logger";
|
||||
|
||||
export const complaint = new Elysia({
|
||||
prefix: "/complaint",
|
||||
})
|
||||
.get(
|
||||
"/stats",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const [total, baru, proses, selesai] = await Promise.all([
|
||||
prisma.complaint.count(),
|
||||
prisma.complaint.count({ where: { status: "BARU" } }),
|
||||
prisma.complaint.count({ where: { status: "DIPROSES" } }),
|
||||
prisma.complaint.count({ where: { status: "SELESAI" } }),
|
||||
]);
|
||||
return { data: { total, baru, proses, selesai } };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch complaint stats");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get complaint statistics" },
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/recent",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const recent = await prisma.complaint.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 10,
|
||||
});
|
||||
return { data: recent };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch recent complaints");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get recent complaints" },
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/service-stats",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const serviceStats = await prisma.serviceLetter.groupBy({
|
||||
by: ["letterType"],
|
||||
_count: { _all: true },
|
||||
});
|
||||
return { data: serviceStats };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch service stats");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get service letter statistics by type" },
|
||||
},
|
||||
);
|
||||
71
src/api/division.ts
Normal file
71
src/api/division.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import Elysia from "elysia";
|
||||
import { prisma } from "../utils/db";
|
||||
import logger from "../utils/logger";
|
||||
|
||||
export const division = new Elysia({
|
||||
prefix: "/division",
|
||||
})
|
||||
.get(
|
||||
"/",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const divisions = await prisma.division.findMany({
|
||||
include: {
|
||||
_count: {
|
||||
select: { activities: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
return { data: divisions };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch divisions");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get all divisions" },
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/activities",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const activities = await prisma.activity.findMany({
|
||||
include: {
|
||||
division: {
|
||||
select: { name: true, color: true },
|
||||
},
|
||||
},
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 10,
|
||||
});
|
||||
return { data: activities };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch activities");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get recent activities" },
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/metrics",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const metrics = await prisma.divisionMetric.findMany({
|
||||
include: { division: true },
|
||||
});
|
||||
return { data: metrics };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch division metrics");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get division performance metrics" },
|
||||
},
|
||||
);
|
||||
54
src/api/event.ts
Normal file
54
src/api/event.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import Elysia from "elysia";
|
||||
import { prisma } from "../utils/db";
|
||||
import logger from "../utils/logger";
|
||||
|
||||
export const event = new Elysia({
|
||||
prefix: "/event",
|
||||
})
|
||||
.get(
|
||||
"/",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const events = await prisma.event.findMany({
|
||||
orderBy: { startDate: "asc" },
|
||||
take: 20,
|
||||
});
|
||||
return { data: events };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch events");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get upcoming events" },
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/today",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const start = new Date();
|
||||
start.setHours(0, 0, 0, 0);
|
||||
const end = new Date();
|
||||
end.setHours(23, 59, 59, 999);
|
||||
|
||||
const events = await prisma.event.findMany({
|
||||
where: {
|
||||
startDate: {
|
||||
gte: start,
|
||||
lte: end,
|
||||
},
|
||||
},
|
||||
});
|
||||
return { data: events };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch today's events");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get events for today" },
|
||||
},
|
||||
);
|
||||
@@ -4,7 +4,11 @@ import Elysia from "elysia";
|
||||
import { apiMiddleware } from "../middleware/apiMiddleware";
|
||||
import { auth } from "../utils/auth";
|
||||
import { apikey } from "./apikey";
|
||||
import { complaint } from "./complaint";
|
||||
import { division } from "./division";
|
||||
import { event } from "./event";
|
||||
import { profile } from "./profile";
|
||||
import { resident } from "./resident";
|
||||
|
||||
const isProduction = process.env.NODE_ENV === "production";
|
||||
|
||||
@@ -20,7 +24,11 @@ const api = new Elysia({
|
||||
})
|
||||
.use(apiMiddleware)
|
||||
.use(apikey)
|
||||
.use(profile);
|
||||
.use(profile)
|
||||
.use(division)
|
||||
.use(complaint)
|
||||
.use(resident)
|
||||
.use(event);
|
||||
|
||||
if (!isProduction) {
|
||||
api.use(
|
||||
|
||||
@@ -2,12 +2,25 @@ import Elysia, { t } from "elysia";
|
||||
import { prisma } from "../utils/db";
|
||||
import logger from "../utils/logger";
|
||||
|
||||
interface AuthenticatedUser {
|
||||
id: string;
|
||||
email: string;
|
||||
name?: string | null;
|
||||
}
|
||||
|
||||
export const profile = new Elysia({
|
||||
prefix: "/profile",
|
||||
}).post(
|
||||
"/update",
|
||||
async (ctx) => {
|
||||
const { body, set, user } = ctx as any;
|
||||
async ({
|
||||
body,
|
||||
set,
|
||||
user,
|
||||
}: {
|
||||
body: { name?: string; image?: string };
|
||||
set: any;
|
||||
user?: AuthenticatedUser;
|
||||
}) => {
|
||||
try {
|
||||
if (!user) {
|
||||
set.status = 401;
|
||||
|
||||
76
src/api/resident.ts
Normal file
76
src/api/resident.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import Elysia from "elysia";
|
||||
import { prisma } from "../utils/db";
|
||||
import logger from "../utils/logger";
|
||||
|
||||
export const resident = new Elysia({
|
||||
prefix: "/resident",
|
||||
})
|
||||
.get(
|
||||
"/stats",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const [total, heads, poor] = await Promise.all([
|
||||
prisma.resident.count(),
|
||||
prisma.resident.count({ where: { isHeadOfHousehold: true } }),
|
||||
prisma.resident.count({ where: { isPoor: true } }),
|
||||
]);
|
||||
return { data: { total, heads, poor } };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch resident stats");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get resident statistics" },
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/banjar-stats",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const banjarStats = await prisma.banjar.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
totalPopulation: true,
|
||||
totalKK: true,
|
||||
totalPoor: true,
|
||||
},
|
||||
});
|
||||
return { data: banjarStats };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch banjar stats");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get population data per banjar" },
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/demographics",
|
||||
async ({ set }) => {
|
||||
try {
|
||||
const [religion, gender] = await Promise.all([
|
||||
prisma.resident.groupBy({
|
||||
by: ["religion"],
|
||||
_count: { _all: true },
|
||||
}),
|
||||
prisma.resident.groupBy({
|
||||
by: ["gender"],
|
||||
_count: { _all: true },
|
||||
}),
|
||||
]);
|
||||
return { data: { religion, gender } };
|
||||
} catch (error) {
|
||||
logger.error({ error }, "Failed to fetch demographics");
|
||||
set.status = 500;
|
||||
return { error: "Internal Server Error" };
|
||||
}
|
||||
},
|
||||
{
|
||||
detail: { summary: "Get religious and gender demographics" },
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user