import { and, eq, ilike, or, sql, asc, inArray } from "drizzle-orm"; import { Hono } from "hono"; import checkPermission from "../../middlewares/checkPermission"; import { z } from "zod"; import { HTTPException } from "hono/http-exception"; import db from "../../drizzle"; import { assessments } from "../../drizzle/schema/assessments"; import { respondents } from "../../drizzle/schema/respondents"; import { users } from "../../drizzle/schema/users"; import HonoEnv from "../../types/HonoEnv"; import requestValidator from "../../utils/requestValidator"; import authInfo from "../../middlewares/authInfo"; export const assessmentFormSchema = z.object({ respondentId: z.string().min(1), status: z.enum(["menunggu konfirmasi", "diterima", "ditolak", "dalam pengerjaan", "belum diverifikasi", "selesai"]), reviewedBy: z.string().min(1), verifiedBy: z.string().min(1), verifiedAt: z.string().optional(), }); export const assessmentUpdateSchema = assessmentFormSchema.extend({ verifiedAt: z.string().optional().or(z.literal("")), }); const assessmentsRequestManagementRoutes = new Hono() .use(authInfo) /** * Get All Assessments (With Metadata) * * Query params: * - withMetadata: boolean */ .get( "/", checkPermission("assessmentRequestManagement.readAll"), requestValidator( "query", z.object({ withMetadata: z .string() .optional() .transform((v) => v?.toLowerCase() === "true"), page: z.coerce.number().int().min(0).default(0), limit: z.coerce.number().int().min(1).max(1000).default(10), q: z.string().default(""), }) ), async (c) => { const { page, limit, q } = c.req.valid("query"); const validStatuses = [ "dalam pengerjaan", "menunggu konfirmasi", "diterima", "ditolak", ] as ("menunggu konfirmasi" | "diterima" | "ditolak" | "dalam pengerjaan")[]; // Query untuk menghitung total jumlah item (totalCountQuery) const assessmentCountQuery = await db .select({ count: sql`count(*)`, }) .from(assessments) .leftJoin(respondents, eq(assessments.respondentId, respondents.id)) .leftJoin(users, eq(respondents.userId, users.id)) .where( and( inArray(assessments.status, validStatuses), q ? or( ilike(users.name, `%${q}%`), ilike(respondents.companyName, `%${q}%`), sql`CAST(${assessments.status} AS TEXT) ILIKE ${'%' + q + '%'}`, eq(assessments.id, q) ) : undefined ) ); const totalItems = Number(assessmentCountQuery[0]?.count) || 0; // Query utama untuk mendapatkan data permohonan assessment const result = await db .select({ idPermohonan: assessments.id, namaResponden: users.name, namaPerusahaan: respondents.companyName, status: assessments.status, tanggal: assessments.createdAt, }) .from(assessments) .leftJoin(respondents, eq(assessments.respondentId, respondents.id)) .leftJoin(users, eq(respondents.userId, users.id)) .where( and( inArray(assessments.status, validStatuses), q ? or( ilike(users.name, `%${q}%`), ilike(respondents.companyName, `%${q}%`), sql`CAST(${assessments.status} AS TEXT) ILIKE ${'%' + q + '%'}`, eq(assessments.id, q) ) : undefined ) ) .orderBy( sql` CASE WHEN ${assessments.status} = 'menunggu konfirmasi' THEN 1 WHEN ${assessments.status} = 'dalam pengerjaan' THEN 2 WHEN ${assessments.status} = 'diterima' THEN 3 WHEN ${assessments.status} = 'ditolak' THEN 4 ELSE 5 END `, asc(assessments.createdAt) ) .offset(page * limit) .limit(limit); return c.json({ data: result.map((d) => ({ idPermohonan: d.idPermohonan, namaResponden: d.namaResponden, namaPerusahaan: d.namaPerusahaan, status: d.status, tanggal: d.tanggal, })), _metadata: { currentPage: page, totalPages: Math.ceil(totalItems / limit), totalItems, perPage: limit, }, }); } ) // Get assessment by id .get( "/:id", checkPermission("assessmentRequestManagement.read"), async (c) => { const assessmentId = c.req.param("id"); const queryResult = await db .select({ tanggal: assessments.createdAt, nama: users.name, posisi: respondents.position, pengalamanKerja: respondents.workExperience, email: users.email, namaPerusahaan: respondents.companyName, alamat: respondents.address, nomorTelepon: respondents.phoneNumber, username: users.username, status: assessments.status, }) .from(assessments) .leftJoin(respondents, eq(assessments.respondentId, respondents.id)) .leftJoin(users, eq(respondents.userId, users.id)) .where(eq(assessments.id, assessmentId)); if (!queryResult.length) throw new HTTPException(404, { message: "The assessment does not exist", }); const assessmentData = queryResult[0]; return c.json(assessmentData); } ) .patch( "/:id", checkPermission("assessmentRequestManagement.update"), requestValidator( "json", z.object({ status: z.enum(["menunggu konfirmasi", "diterima", "ditolak", "dalam pengerjaan", "belum diverifikasi", "selesai"]), }) ), async (c) => { const assessmentId = c.req.param("id"); const { status } = c.req.valid("json"); const userName = c.var.currentUser?.name; const assessment = await db .select() .from(assessments) .where(and(eq(assessments.id, assessmentId),)); if (!assessment[0]) throw new HTTPException(404, { message: "Assessment tidak ditemukan.", }); const currentDate = new Date(); await db .update(assessments) .set({ status, reviewedBy: userName, reviewedAt: currentDate, }) .where(eq(assessments.id, assessmentId)); return c.json({ message: "Status assessment berhasil diperbarui.", }); } ) export default assessmentsRequestManagementRoutes;