Pull Request branch dev-clone to main #1

Merged
gitea merged 429 commits from dev-clone into main 2024-12-23 09:31:34 +00:00
3 changed files with 33 additions and 101 deletions
Showing only changes of commit 09a6df9e66 - Show all commits

View File

@ -397,22 +397,8 @@ const assessmentRoute = new Hono<HonoEnv>()
.get( .get(
"/getAnswers/:id", "/getAnswers/:id",
checkPermission("assessments.readAnswers"), checkPermission("assessments.readAnswers"),
requestValidator(
"query",
z.object({
// assessmentId: z.string().min(1),
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(1000),
q: z.string().default(""),
})
),
async (c) => { async (c) => {
const assessmentId = c.req.param("id").toString(); const assessmentId = c.req.param("id").toString();
const { page, limit, q, withMetadata } = c.req.valid("query");
// Query to count total answers for the specific assessmentId // Query to count total answers for the specific assessmentId
const totalCountQuery = sql<number>`(SELECT count(*) const totalCountQuery = sql<number>`(SELECT count(*)
@ -428,36 +414,18 @@ const assessmentRoute = new Hono<HonoEnv>()
answerId: answerRevisions.answerId, answerId: answerRevisions.answerId,
newOptionId: answerRevisions.newOptionId, newOptionId: answerRevisions.newOptionId,
newValidationInformation: answerRevisions.newValidationInformation, newValidationInformation: answerRevisions.newValidationInformation,
questionId: options.questionId,
fullCount: totalCountQuery, fullCount: totalCountQuery,
}) })
.from(answerRevisions) .from(answerRevisions)
.innerJoin(answers, eq(answers.id, answerRevisions.answerId)) .leftJoin(answers, eq(answers.id, answerRevisions.answerId))
.innerJoin(assessments, eq(answers.assessmentId, assessments.id)) .leftJoin(options, eq(answerRevisions.newOptionId, options.id))
.where( .leftJoin(assessments, eq(answers.assessmentId, assessments.id))
and( .where(eq(assessments.id, assessmentId),
eq(assessments.id, assessmentId),
q
? or(
ilike(answers.filename, q),
ilike(answerRevisions.newValidationInformation, q),
eq(answerRevisions.answerId, q)
)
: undefined
)
) )
.offset(page * limit)
.limit(limit);
return c.json({ return c.json({
data: result.map((d) => ({ ...d, fullCount: undefined })), data: result.map((d) => ({ ...d, fullCount: undefined })),
_metadata: {
currentPage: page,
totalPages: withMetadata
? Math.ceil((Number(result[0]?.fullCount) ?? 0) / limit)
: null,
totalItems: withMetadata ? Number(result[0]?.fullCount) ?? 0 : null,
perPage: limit,
},
}); });
} }
) )

View File

@ -88,23 +88,13 @@ export const postAnswerRevisionMutation = () => {
// Query untuk mendapatkan jawaban berdasarkan assessment ID // Query untuk mendapatkan jawaban berdasarkan assessment ID
export const getAnswersRevisionQueryOptions = ( export const getAnswersRevisionQueryOptions = (
assessmentId: string, assessmentId: string,
page: number,
limit: number,
q: string = "",
withMetadata: string = "true"
) => { ) => {
return queryOptions({ return queryOptions({
queryKey: ["answerRevision", { assessmentId, page, limit, q }], queryKey: ["answerRevision", { assessmentId }],
queryFn: () => queryFn: () =>
fetchRPC( fetchRPC(
client.assessmentResult.getAnswers[":id"].$get({ client.assessmentResult.getAnswers[":id"].$get({
param: { id: assessmentId }, param: { id: assessmentId },
query: {
limit: String(limit),
page: String(page),
q,
withMetadata,
},
}) })
), ),
}); });

View File

@ -184,9 +184,15 @@ export default function AssessmentPage() {
// Fetching answers for the assessment // Fetching answers for the assessment
const { data: answersData } = useQuery( const { data: answersData } = useQuery(
getAnswersRevisionQueryOptions(assessmentId || "", page, limit) getAnswersRevisionQueryOptions(assessmentId || "")
); );
console.log("answersData:", answersData);
const formattedResult = answersData?.data.reduce((acc, item) => {
if (item.questionId != null && item.newOptionId != null) {
acc[item.questionId] = item.newOptionId;
}
return acc;
}, {} as Record<string, string>);
// Effect untuk mengatur answers dari data yang diambil // Effect untuk mengatur answers dari data yang diambil
useEffect(() => { useEffect(() => {
@ -195,18 +201,8 @@ console.log("answersData:", answersData);
return; return;
} }
// Ambil jawaban dari localStorage berdasarkan ID assessment if (formattedResult) {
const savedAnswers = JSON.parse(localStorage.getItem(`assessmentAnswers_${assessmentId}`) || "{}"); setAnswers(formattedResult);
// Gabungkan jawaban dari localStorage dan answersData
if (answersData) {
// Pastikan answersData adalah objek yang valid sebelum menggabungkan
setAnswers({
...savedAnswers, // Jawaban dari localStorage
...answersData // Jawaban dari query
});
} else {
setAnswers(savedAnswers); // Gunakan data dari localStorage jika answersData kosong
} }
}, [answersData, assessmentId]); }, [answersData, assessmentId]);
@ -343,8 +339,6 @@ console.log("answersData:", answersData);
// Update jawaban untuk pertanyaan tertentu // Update jawaban untuk pertanyaan tertentu
const updatedAnswers = { ...answers, [questionId]: optionId }; const updatedAnswers = { ...answers, [questionId]: optionId };
// Simpan jawaban ke localStorage dengan ID assessment
localStorage.setItem(`assessmentAnswers_${assessmentId}`, JSON.stringify(updatedAnswers));
// Update state // Update state
setAnswers(updatedAnswers); setAnswers(updatedAnswers);
@ -357,6 +351,22 @@ console.log("answersData:", answersData);
}); });
}; };
const validationResult = answersData?.data.reduce((acc, item) => {
if (item.questionId != null && item.newValidationInformation != null) {
acc[item.questionId] = item.newValidationInformation;
}
return acc;
}, {} as Record<string, string>);
// Mengambil data dari database saat komponen dimuat
useEffect(() => {
if (validationResult) {
setValidationInformation(validationResult);
}
}, [answersData, assessmentId]);
console.log(validationInformation);
// Mutation untuk mengirim data ke backend // Mutation untuk mengirim data ke backend
const { mutate: submitValidation } = useMutation({ const { mutate: submitValidation } = useMutation({
mutationFn: (form: { mutationFn: (form: {
@ -373,36 +383,6 @@ console.log("answersData:", answersData);
}, },
}); });
// Mengambil data dari localStorage saat komponen dimuat
useEffect(() => {
const storedValidationInfo = localStorage.getItem(`validationInfo_${assessmentId}`);
if (storedValidationInfo) {
try {
const parsedValidationInfo = JSON.parse(storedValidationInfo);
setValidationInformation(parsedValidationInfo);
// Iterasi melalui parsedValidationInfo untuk mengirimkan setiap validasi ke server
Object.keys(parsedValidationInfo).forEach((questionId) => {
const validationValue = parsedValidationInfo[questionId];
// Pastikan assessmentId tidak null sebelum memanggil submitValidation
if (assessmentId) {
submitValidation({
assessmentId,
questionId,
newValidationInformation: validationValue,
});
} else {
console.error("Assessment ID tidak ditemukan");
}
});
} catch (error) {
console.error("Error parsing validation information:", error);
}
}
}, [assessmentId, submitValidation]);
// Handle perubahan di Textarea // Handle perubahan di Textarea
const handleTextareaChange = (questionId: string, value: string) => { const handleTextareaChange = (questionId: string, value: string) => {
// Memperbarui state validationInformation // Memperbarui state validationInformation
@ -411,13 +391,6 @@ console.log("answersData:", answersData);
[questionId]: value, [questionId]: value,
})); }));
// Memperbarui localStorage dengan informasi validasi baru dalam format JSON
const updatedValidationInformation = {
...validationInformation,
[questionId]: value,
};
localStorage.setItem(`validationInfo_${assessmentId}`, JSON.stringify(updatedValidationInformation));
// Pastikan assessmentId tidak null sebelum mengirimkan data ke server // Pastikan assessmentId tidak null sebelum mengirimkan data ke server
if (assessmentId) { if (assessmentId) {
// Kirim data validasi ke server // Kirim data validasi ke server
@ -731,6 +704,7 @@ console.log("answersData:", answersData);
{/* Opsi Radio Button */} {/* Opsi Radio Button */}
{question.options?.length > 0 ? ( {question.options?.length > 0 ? (
<div className="mx-11"> <div className="mx-11">
<RadioGroup <RadioGroup
value={answers[questionId] || ""} value={answers[questionId] || ""}
onValueChange={(value) => handleAnswerChange(questionId, value)} onValueChange={(value) => handleAnswerChange(questionId, value)}