import { and, eq, isNull, sql } from "drizzle-orm"; import { Hono } from "hono"; import { z } from "zod"; import db from "../../drizzle"; import { assessments } from "../../drizzle/schema/assessments"; import { respondents } from "../../drizzle/schema/respondents"; import { users } from "../../drizzle/schema/users"; import { aspects } from "../../drizzle/schema/aspects"; // Import schema aspek import { subAspects } from "../../drizzle/schema/subAspects"; // Import schema subAspek import { questions } from "../../drizzle/schema/questions"; // Import schema question import { options } from "../../drizzle/schema/options"; import { answers } from "../../drizzle/schema/answers"; import { answerRevisions } from "../../drizzle/schema/answerRevisions"; import HonoEnv from "../../types/HonoEnv"; import authInfo from "../../middlewares/authInfo"; import checkPermission from "../../middlewares/checkPermission"; import requestValidator from "../../utils/requestValidator"; import { notFound } from "../../errors/DashboardError"; const assessmentRoute = new Hono() .use(authInfo) // Get All List of Assessment Results .get( "/", checkPermission("assessmentResult.readAll"), requestValidator( "query", z.object({ page: z.coerce.number().int().min(0).default(0), limit: z.coerce.number().int().min(1).max(1000).default(40), }) ), async (c) => { const { page, limit } = c.req.valid("query"); const result = await db .select({ id: assessments.id, respondentName: users.name, // Mengambil `name` langsung dari tabel `users` companyName: respondents.companyName, statusAssessments: assessments.status, statusVerification: sql` CASE WHEN ${assessments.validatedAt} IS NOT NULL THEN 'sudah diverifikasi' ELSE 'belum diverifikasi' END` .as("statusVerification"), assessmentsResult: sql` (SELECT ROUND(AVG(${options.score}), 2) FROM ${answers} JOIN ${options} ON ${options.id} = ${answers.optionId} JOIN ${questions} ON ${questions.id} = ${options.questionId} JOIN ${subAspects} ON ${subAspects.id} = ${questions.subAspectId} JOIN ${aspects} ON ${aspects.id} = ${subAspects.aspectId} WHERE ${answers.assessmentId} = ${assessments.id})` .as("assessmentsResult"), }) .from(assessments) .leftJoin(respondents, eq(assessments.respondentId, respondents.id)) .leftJoin(users, eq(respondents.userId, users.id)) // Menghubungkan `respondents` dengan `users` melalui `userId` .offset(page * limit) .limit(limit); const totalItems = await db .select({ count: sql`COUNT(*)`, }) .from(assessments); return c.json({ data: result, _metadata: { currentPage: page, totalPages: Math.ceil(totalItems[0].count / limit), totalItems: totalItems[0].count, perPage: limit, }, }); } ) // Get Assessment Result by ID .get( "/:id", checkPermission("assessmentResult.read"), async (c) => { const assessmentId = c.req.param("id"); const result = await db .select({ respondentName: users.name, // Nama Responden position: respondents.position, // Jabatan workExperience: respondents.workExperience, // Pengalaman Kerja email: users.email, // Email companyName: respondents.companyName, // Instansi/Perusahaan address: respondents.address, // Alamat phoneNumber: respondents.phoneNumber, // Nomor Telepon username: users.username, // Username assessmentDate: assessments.createdAt, // Tanggal Asesmen statusAssessment: assessments.status, // Status Asesmen assessmentsResult: sql` (SELECT ROUND(AVG(${options.score}), 2) FROM ${answers} JOIN ${options} ON ${options.id} = ${answers.optionId} JOIN ${questions} ON ${questions.id} = ${options.questionId} JOIN ${subAspects} ON ${subAspects.id} = ${questions.subAspectId} JOIN ${aspects} ON ${aspects.id} = ${subAspects.aspectId} WHERE ${answers.assessmentId} = ${assessments.id})` .as("assessmentsResult"), }) .from(assessments) .leftJoin(respondents, eq(assessments.respondentId, respondents.id)) .leftJoin(users, eq(respondents.userId, users.id)) .where(eq(assessments.id, assessmentId)); if (!result.length) { throw notFound({ message: "Assessment not found", }); } return c.json(result[0]); } ) // Get all Questions and Options that relate to Sub Aspects and Aspects based on Assessment ID .get( "getAllQuestion/:id", checkPermission("assessmentResult.readAllQuestions"), async (c) => { const assessmentId = c.req.param("id"); if (!assessmentId) { throw notFound({ message: "Assessment ID is missing", }); } // Total count of options related to the assessment const totalCountQuery = sql` SELECT count(*) FROM ${options} LEFT JOIN ${questions} ON ${options.questionId} = ${questions.id} LEFT JOIN ${subAspects} ON ${questions.subAspectId} = ${subAspects.id} LEFT JOIN ${aspects} ON ${subAspects.aspectId} = ${aspects.id} LEFT JOIN ${answers} ON ${options.id} = ${answers.optionId} WHERE ${questions.deletedAt} IS NULL AND ${answers.assessmentId} = ${assessmentId} `; // Query to get detailed information about options const result = await db .select({ optionId: options.id, aspectsId: aspects.id, aspectsName: aspects.name, subAspectId: subAspects.id, subAspectName: subAspects.name, questionId: questions.id, questionText: questions.question, answerId: answers.id, answerText: options.text, answerScore: options.score, }) .from(options) .leftJoin(questions, eq(options.questionId, questions.id)) .leftJoin(subAspects, eq(questions.subAspectId, subAspects.id)) .leftJoin(aspects, eq(subAspects.aspectId, aspects.id)) .leftJoin(answers, eq(options.id, answers.optionId)) .where(sql`${questions.deletedAt} IS NULL AND ${answers.assessmentId} = ${assessmentId}`); // Execute the total count query const totalCountResult = await db.execute(totalCountQuery); if (result.length === 0) { throw notFound({ message: "Data does not exist", }); } return c.json({ data: result, totalCount: totalCountResult[0]?.count || 0 }); } ) // POST Endpoint for creating a new answer revision .post( "/answer-revisions", checkPermission("assessmentResult.create"), requestValidator( "json", z.object({ answerId: z.string(), newOptionId: z.string(), revisedBy: z.string(), newValidationInformation: z.string(), }) ), async (c) => { const { answerId, newOptionId, revisedBy, newValidationInformation } = c.req.valid("json"); // Check if the answer exists const existingAnswer = await db .select() .from(answers) .where(eq(answers.id, answerId)); if (!existingAnswer.length) { throw notFound({ message: "Answer not found", }); } // Insert new revision const [newRevision] = await db .insert(answerRevisions) .values({ answerId, newOptionId, revisedBy, newValidationInformation }) .returning(); return c.json( { message: "Answer revision created successfully", data: newRevision }, 201 ); } ); export default assessmentRoute;