Pull Request branch dev-clone to main #1
|
|
@ -24,9 +24,10 @@ import {
|
||||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||||
import {
|
import {
|
||||||
getAnswersQueryOptions,
|
getAnswersQueryOptions,
|
||||||
|
getAllAnswer,
|
||||||
submitAssessmentMutationOptions,
|
submitAssessmentMutationOptions,
|
||||||
uploadFileMutationOptions,
|
uploadFileMutationOptions,
|
||||||
submitValidationMutationOptions,
|
submitValidationQuery,
|
||||||
submitOptionMutationOptions,
|
submitOptionMutationOptions,
|
||||||
getAverageScoreQueryOptions,
|
getAverageScoreQueryOptions,
|
||||||
fetchAspects,
|
fetchAspects,
|
||||||
|
|
@ -35,6 +36,7 @@ import {
|
||||||
} from "@/modules/assessmentManagement/queries/assessmentQueries";
|
} from "@/modules/assessmentManagement/queries/assessmentQueries";
|
||||||
import { TbFlagFilled, TbUpload, TbChevronRight, TbChevronDown } from "react-icons/tb";
|
import { TbFlagFilled, TbUpload, TbChevronRight, TbChevronDown } from "react-icons/tb";
|
||||||
import FinishAssessmentModal from "@/modules/assessmentManagement/modals/ConfirmModal";
|
import FinishAssessmentModal from "@/modules/assessmentManagement/modals/ConfirmModal";
|
||||||
|
import FileUpload from "@/modules/assessmentManagement/fileUpload/fileUpload";
|
||||||
import ValidationModal from "@/modules/assessmentManagement/modals/ValidationModal";
|
import ValidationModal from "@/modules/assessmentManagement/modals/ValidationModal";
|
||||||
import FileSizeValidationModal from "@/modules/assessmentManagement/modals/FileSizeValidationModal";
|
import FileSizeValidationModal from "@/modules/assessmentManagement/modals/FileSizeValidationModal";
|
||||||
import { useState, useRef, useEffect } from "react";
|
import { useState, useRef, useEffect } from "react";
|
||||||
|
|
@ -98,23 +100,6 @@ export default function AssessmentPage() {
|
||||||
getQuestionsAllQueryOptions(page, limit)
|
getQuestionsAllQueryOptions(page, limit)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Fungsi untuk memeriksa pertanyaan yang belum dijawab
|
|
||||||
const checkUnansweredQuestions = () => {
|
|
||||||
// Misalkan data berisi pertanyaan dan jawaban
|
|
||||||
const unanswered = data?.data.filter(question => {
|
|
||||||
// Pastikan questionId tidak null dan tidak ada jawaban untuk questionId tersebut
|
|
||||||
return question.questionId !== null && !answers[question.questionId];
|
|
||||||
}) || []; // Ganti question.id dengan question.questionId dan tambahkan pengecekan null
|
|
||||||
setUnansweredQuestions(unanswered.length); // Aman, karena unanswered selalu array
|
|
||||||
|
|
||||||
// Jika ada pertanyaan yang belum dijawab, buka modal peringatan
|
|
||||||
if (unanswered.length > 0) {
|
|
||||||
setValidationModalOpen(true);
|
|
||||||
} else {
|
|
||||||
setModalOpen(true); // Jika tidak ada, buka modal konfirmasi selesai asesmen
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFinishClick = () => {
|
const handleFinishClick = () => {
|
||||||
// Memanggil fungsi untuk memeriksa pertanyaan yang belum dijawab
|
// Memanggil fungsi untuk memeriksa pertanyaan yang belum dijawab
|
||||||
checkUnansweredQuestions();
|
checkUnansweredQuestions();
|
||||||
|
|
@ -172,65 +157,74 @@ export default function AssessmentPage() {
|
||||||
|
|
||||||
// Fetching answers for the assessment
|
// Fetching answers for the assessment
|
||||||
const { data: answersData } = useQuery(
|
const { data: answersData } = useQuery(
|
||||||
getAnswersQueryOptions(assessmentId || "", page, limit) // Memanggil query untuk mengambil jawaban dengan argumen yang diperlukan
|
getAnswersQueryOptions(assessmentId || "", page, limit),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (answersData && answersData.data) {
|
||||||
|
const transformedData = answersData.data.reduce(
|
||||||
|
(acc: Record<string, string>, item: any) => {
|
||||||
|
if (item.questionId && item.optionId) {
|
||||||
|
acc[item.questionId] = item.optionId;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.error("No data found or data is undefined.");
|
||||||
|
}
|
||||||
|
|
||||||
// Effect untuk mengatur answers dari data yang diambil
|
// Effect untuk mengatur answers dari data yang diambil
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const assessmentId = getQueryParam("id"); // Ambil assessmentId dari query params
|
const assessmentId = getQueryParam("id");
|
||||||
if (!assessmentId) {
|
if (!assessmentId) {
|
||||||
console.error("Assessment ID tidak ditemukan");
|
console.error("Assessment ID tidak ditemukan");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ambil jawaban dari localStorage berdasarkan ID assessment
|
// Set answers from `answersData` if data is available
|
||||||
const savedAnswers = localStorage.getItem(`assessmentAnswers_${assessmentId}`);
|
if (answersData && Array.isArray(answersData.data)) {
|
||||||
if (savedAnswers) {
|
const answersFromDatabase = answersData.data.reduce(
|
||||||
setAnswers(JSON.parse(savedAnswers)); // Set state answers dengan data dari local storage
|
(acc: Record<string, string>, item: any) => {
|
||||||
|
if (item.questionId && item.optionId) {
|
||||||
|
acc[item.questionId] = item.optionId;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
setAnswers(answersFromDatabase); // Set the transformed data directly to state
|
||||||
|
} else {
|
||||||
|
console.error("No data found or data is undefined.");
|
||||||
}
|
}
|
||||||
}, []);
|
}, [answersData]);
|
||||||
|
|
||||||
// Mengambil jawaban dari local storage saat komponen dimuat
|
// Fungsi untuk memeriksa pertanyaan yang belum dijawab
|
||||||
useEffect(() => {
|
const checkUnansweredQuestions = () => {
|
||||||
const storedAnswers = localStorage.getItem('assessmentAnswers');
|
|
||||||
if (storedAnswers) {
|
// Filter pertanyaan yang belum dijawab berdasarkan data `answers`
|
||||||
setAnswers(JSON.parse(storedAnswers)); // Set state answers dengan data dari local storage
|
const unanswered = data?.data.filter(question => {
|
||||||
|
return question.questionId !== null && !answers[question.questionId];
|
||||||
|
}) || [];
|
||||||
|
|
||||||
|
setUnansweredQuestions(unanswered.length);
|
||||||
|
|
||||||
|
// Tampilkan modal berdasarkan jumlah pertanyaan yang belum dijawab
|
||||||
|
if (unanswered.length > 0) {
|
||||||
|
setValidationModalOpen(true);
|
||||||
|
} else {
|
||||||
|
setModalOpen(true);
|
||||||
}
|
}
|
||||||
}, []);
|
};
|
||||||
|
|
||||||
const handleConfirmFinish = async (assessmentId: string) => {
|
const handleConfirmFinish = async (assessmentId: string) => {
|
||||||
try {
|
try {
|
||||||
// Cek pertanyaan yang belum dijawab
|
// Skip counting unanswered questions here to prevent duplication
|
||||||
let unansweredCount = 0;
|
|
||||||
|
|
||||||
// Cek radio button
|
|
||||||
data?.data.forEach((question) => {
|
|
||||||
// Pastikan questionId tidak null sebelum memeriksa answers
|
|
||||||
if (question.questionId && !answers[question.questionId]) {
|
|
||||||
unansweredCount += 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Cek textarea
|
|
||||||
Object.keys(validationInformation).forEach((key) => {
|
|
||||||
// Pastikan key tidak null dan tidak ada validasi informasi untuk key tersebut
|
|
||||||
if (key && !validationInformation[key]) {
|
|
||||||
unansweredCount += 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (unansweredCount > 0) {
|
|
||||||
// Tampilkan modal validasi jika ada pertanyaan yang belum dijawab
|
|
||||||
setUnansweredQuestions(unansweredCount);
|
|
||||||
setValidationModalOpen(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Memanggil mutation untuk mengubah status asesmen menjadi 'selesai' di backend
|
|
||||||
const mutation = submitAssessmentMutationOptions(assessmentId);
|
const mutation = submitAssessmentMutationOptions(assessmentId);
|
||||||
const response = await mutation.mutationFn();
|
const response = await mutation.mutationFn();
|
||||||
|
|
||||||
// Setelah status diubah, navigasikan ke halaman hasil asesmen
|
// Navigate to results
|
||||||
const newUrl = `/assessmentResult?id=${assessmentId}`;
|
const newUrl = `/assessmentResult?id=${assessmentId}`;
|
||||||
window.history.pushState({}, "", newUrl);
|
window.history.pushState({}, "", newUrl);
|
||||||
console.log("Navigated to:", newUrl);
|
console.log("Navigated to:", newUrl);
|
||||||
|
|
@ -238,7 +232,7 @@ export default function AssessmentPage() {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error finishing assessment:", error);
|
console.error("Error finishing assessment:", error);
|
||||||
} finally {
|
} finally {
|
||||||
setModalOpen(false); // Menutup modal setelah selesai
|
setModalOpen(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -265,44 +259,50 @@ export default function AssessmentPage() {
|
||||||
const currentAspect = aspects.find(aspect => aspect.aspectId === selectedAspectId);
|
const currentAspect = aspects.find(aspect => aspect.aspectId === selectedAspectId);
|
||||||
const filteredSubAspects = currentAspect ? currentAspect.subAspects : [];
|
const filteredSubAspects = currentAspect ? currentAspect.subAspects : [];
|
||||||
|
|
||||||
// Inisialisasi flaggedQuestions dari localStorage saat komponen dimuat
|
// Inisialisasi flaggedQuestions dari database saat komponen dimuat
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const savedFlags = localStorage.getItem("flaggedQuestions");
|
const initialFlagData = answersData?.data.reduce((acc, item) => {
|
||||||
if (savedFlags) {
|
if (item.questionId != null && item.isFlagged != null) {
|
||||||
setFlaggedQuestions(JSON.parse(savedFlags));
|
acc[item.questionId] = item.isFlagged;
|
||||||
}
|
}
|
||||||
}, []);
|
return acc;
|
||||||
|
}, {} as Record<string, boolean>);
|
||||||
|
|
||||||
// Simpan perubahan flag ke localStorage setiap kali flaggedQuestions berubah
|
if (initialFlagData) {
|
||||||
useEffect(() => {
|
setFlaggedQuestions(initialFlagData);
|
||||||
if (Object.keys(flaggedQuestions).length > 0) {
|
|
||||||
localStorage.setItem("flaggedQuestions", JSON.stringify(flaggedQuestions));
|
|
||||||
}
|
}
|
||||||
}, [flaggedQuestions]);
|
}, [answersData]);
|
||||||
|
|
||||||
// Mutation function to toggle flag
|
// Mutation function to toggle flag
|
||||||
const toggleFlagMutation = useMutation<ToggleFlagResponse, Error, string>({
|
const { mutate: toggleFlag } = useMutation({
|
||||||
mutationFn: toggleFlagAnswer,
|
mutationFn: (questionId: string) => toggleFlagAnswer(questionId),
|
||||||
onSuccess: (response) => {
|
onSuccess: (response) => {
|
||||||
if (response && response.answer) {
|
if (response && response.answer) {
|
||||||
const { answer } = response;
|
const { answer } = response;
|
||||||
setFlaggedQuestions((prevFlags) => {
|
setFlaggedQuestions((prevFlags) => ({
|
||||||
const newFlags = {
|
...prevFlags,
|
||||||
...prevFlags,
|
[answer.id]: answer.isFlagged !== null ? answer.isFlagged : false,
|
||||||
[answer.id]: answer.isFlagged !== null ? answer.isFlagged : false,
|
}));
|
||||||
};
|
|
||||||
// Simpan perubahan ke localStorage
|
|
||||||
localStorage.setItem("flaggedQuestions", JSON.stringify(newFlags));
|
|
||||||
return newFlags;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error("Error toggling flag:", error);
|
console.error("Error toggling flag:", error);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Fungsi untuk toggle flag
|
||||||
|
const handleToggleFlag = (questionId: string) => {
|
||||||
|
const newFlagState = !flaggedQuestions[questionId];
|
||||||
|
|
||||||
|
// Update flaggedQuestions dan kirim ke server
|
||||||
|
setFlaggedQuestions((prevFlags) => ({
|
||||||
|
...prevFlags,
|
||||||
|
[questionId]: newFlagState,
|
||||||
|
}));
|
||||||
|
|
||||||
|
toggleFlag(questionId);
|
||||||
|
};
|
||||||
|
|
||||||
// Usage of the mutation in your component
|
// Usage of the mutation in your component
|
||||||
const submitOptionMutation = useMutation({
|
const submitOptionMutation = useMutation({
|
||||||
...submitOptionMutationOptions, // Spread the mutation options here
|
...submitOptionMutationOptions, // Spread the mutation options here
|
||||||
|
|
@ -315,90 +315,98 @@ export default function AssessmentPage() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const assessmentId = getQueryParam("id");
|
|
||||||
|
|
||||||
if (!assessmentId) {
|
|
||||||
console.error("Assessment ID tidak ditemukan");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ambil jawaban dari localStorage berdasarkan ID assessment
|
|
||||||
const savedAnswers = localStorage.getItem(`assessmentAnswers_${assessmentId}`);
|
|
||||||
if (savedAnswers) {
|
|
||||||
setAnswers(JSON.parse(savedAnswers));
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleAnswerChange = (questionId: string, optionId: string) => {
|
const handleAnswerChange = (questionId: string, optionId: string) => {
|
||||||
const assessmentId = getQueryParam("id");
|
const assessmentId = getQueryParam("id");
|
||||||
|
|
||||||
if (!assessmentId) {
|
if (!assessmentId) {
|
||||||
console.error("Assessment ID tidak ditemukan");
|
console.error("Assessment ID tidak ditemukan");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simpan jawaban ke localStorage dengan ID assessment
|
// Update answers in the state
|
||||||
const updatedAnswers = { ...answers, [questionId]: optionId };
|
const updatedAnswers = { ...answers, [questionId]: optionId };
|
||||||
localStorage.setItem(`assessmentAnswers_${assessmentId}`, JSON.stringify(updatedAnswers)); // Simpan berdasarkan ID assessment
|
|
||||||
|
|
||||||
// Update state
|
|
||||||
setAnswers(updatedAnswers);
|
setAnswers(updatedAnswers);
|
||||||
|
|
||||||
// Call the mutation to submit the option
|
// Send the updated answer to the backend
|
||||||
submitOptionMutation.mutate({
|
submitOptionMutation.mutate({
|
||||||
optionId,
|
optionId,
|
||||||
assessmentId,
|
assessmentId,
|
||||||
questionId,
|
questionId,
|
||||||
isFlagged: false,
|
isFlagged: false,
|
||||||
filename: undefined,
|
filename: undefined,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mutation untuk mengirim data ke backend
|
const validationResult = answersData?.data.reduce((acc, item) => {
|
||||||
const { mutate: submitValidation } = useMutation(submitValidationMutationOptions());
|
if (item.questionId != null && item.validationInformation != null) {
|
||||||
|
acc[item.questionId] = item.validationInformation;
|
||||||
// Mengambil data dari localStorage saat komponen dimuat
|
|
||||||
useEffect(() => {
|
|
||||||
const storedValidationInfo = localStorage.getItem(`validationInfo_${assessmentId}`);
|
|
||||||
if (storedValidationInfo) {
|
|
||||||
try {
|
|
||||||
const parsedValidationInfo = JSON.parse(storedValidationInfo);
|
|
||||||
setValidationInformation(parsedValidationInfo);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error parsing validation information:", error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [assessmentId]);
|
return acc;
|
||||||
|
}, {} as Record<string, string>);
|
||||||
|
|
||||||
|
// Mengambil data dari database saat komponen dimuat
|
||||||
|
useEffect(() => {
|
||||||
|
if (validationResult) {
|
||||||
|
setValidationInformation(validationResult);
|
||||||
|
}
|
||||||
|
}, [answersData, assessmentId]);
|
||||||
|
|
||||||
|
// Mutation untuk mengirim data ke backend
|
||||||
|
const { mutate: submitValidation } = useMutation({
|
||||||
|
mutationFn: (form: {
|
||||||
|
assessmentId: string;
|
||||||
|
questionId: string;
|
||||||
|
validationInformation: string;
|
||||||
|
}) => submitValidationQuery(form),
|
||||||
|
onSuccess: () => {
|
||||||
|
// Tindakan yang diambil setelah berhasil
|
||||||
|
console.log("Validation updated successfully!");
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.error("Error updating validation:", error);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Handle perubahan di Textarea
|
// Handle perubahan di Textarea
|
||||||
const handleTextareaChange = (questionId: string, value: string) => {
|
const handleTextareaChange = (questionId: string, value: string) => {
|
||||||
|
// Memperbarui state validationInformation
|
||||||
setValidationInformation((prev) => ({
|
setValidationInformation((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[questionId]: value,
|
[questionId]: value,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Update the localStorage with the new validation information as JSON
|
// Pastikan assessmentId tidak null sebelum mengirimkan data ke server
|
||||||
const updatedValidationInformation = {
|
if (assessmentId) {
|
||||||
...validationInformation,
|
// Kirim data validasi ke server
|
||||||
[questionId]: value,
|
submitValidation({
|
||||||
};
|
assessmentId,
|
||||||
localStorage.setItem(`validationInfo_${assessmentId}`, JSON.stringify(updatedValidationInformation));
|
questionId,
|
||||||
|
validationInformation: value,
|
||||||
// Ensure assessmentId and questionId are not null before submitting
|
});
|
||||||
if (assessmentId && questionId) {
|
} else {
|
||||||
// Send the validation data to the server
|
console.error("Assessment ID tidak ditemukan");
|
||||||
submitValidation({
|
|
||||||
assessmentId,
|
|
||||||
questionId,
|
|
||||||
validationInformation: value,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mutation for file upload
|
// Mutation for file upload
|
||||||
const uploadFileMutation = useMutation(uploadFileMutationOptions());
|
const uploadFileMutation = useMutation(uploadFileMutationOptions());
|
||||||
|
|
||||||
|
// Inisialisasi uploadedFiles dari data yang diterima (answersData)
|
||||||
|
useEffect(() => {
|
||||||
|
if (answersData && answersData.data) {
|
||||||
|
|
||||||
|
const transformedFileData = answersData.data.reduce((acc, item) => {
|
||||||
|
|
||||||
|
if (item.questionId && item.filename) {
|
||||||
|
acc[item.questionId] = new File([""], item.filename, { type: "application/pdf" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, File | null>);
|
||||||
|
|
||||||
|
setUploadedFiles(transformedFileData);
|
||||||
|
}
|
||||||
|
}, [answersData]);
|
||||||
|
|
||||||
// Drag and Drop handlers
|
// Drag and Drop handlers
|
||||||
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
|
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -409,21 +417,6 @@ export default function AssessmentPage() {
|
||||||
setDragActive(false);
|
setDragActive(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load uploaded files from local storage when the component mounts
|
|
||||||
useEffect(() => {
|
|
||||||
const keys = Object.keys(localStorage);
|
|
||||||
keys.forEach((key) => {
|
|
||||||
if (key.startsWith(`uploadedFile_${assessmentId}_`)) { // Menggunakan assessmentId
|
|
||||||
const fileData = JSON.parse(localStorage.getItem(key) || '{}');
|
|
||||||
const questionId = key.replace(`uploadedFile_${assessmentId}_`, ''); // Ambil questionId dari kunci
|
|
||||||
setUploadedFiles(prev => ({
|
|
||||||
...prev,
|
|
||||||
[questionId]: new File([fileData], fileData.name, { type: fileData.type }), // Buat objek File baru
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [assessmentId]);
|
|
||||||
|
|
||||||
// Max file size in bytes (64 MB)
|
// Max file size in bytes (64 MB)
|
||||||
const MAX_FILE_SIZE = 64 * 1024 * 1024;
|
const MAX_FILE_SIZE = 64 * 1024 * 1024;
|
||||||
|
|
||||||
|
|
@ -437,42 +430,34 @@ export default function AssessmentPage() {
|
||||||
|
|
||||||
// Validate file size
|
// Validate file size
|
||||||
if (file.size > MAX_FILE_SIZE) {
|
if (file.size > MAX_FILE_SIZE) {
|
||||||
setExceededFileName(file.name); // Simpan nama file yang melebihi ukuran
|
setExceededFileName(file.name);
|
||||||
setModalOpenFileSize(true); // Tampilkan modal
|
setModalOpenFileSize(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file); // Hanya menyertakan file pertama
|
formData.append('file', file);
|
||||||
|
|
||||||
// Pastikan assessmentId tidak null sebelum menambahkannya ke FormData
|
|
||||||
if (assessmentId) {
|
if (assessmentId) {
|
||||||
formData.append('assessmentId', assessmentId);
|
formData.append('assessmentId', assessmentId);
|
||||||
} else {
|
} else {
|
||||||
console.error("assessmentId is null");
|
console.error("assessmentId is null");
|
||||||
return; // Atau tangani sesuai kebutuhan
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tambahkan questionId ke FormData
|
|
||||||
if (question.questionId) {
|
if (question.questionId) {
|
||||||
formData.append('questionId', question.questionId);
|
formData.append('questionId', question.questionId);
|
||||||
} else {
|
} else {
|
||||||
console.error("questionId is null");
|
console.error("questionId is null");
|
||||||
return; // Atau tangani sesuai kebutuhan
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadFileMutation.mutate(formData); // Unggah file
|
uploadFileMutation.mutate(formData); // Upload file
|
||||||
|
|
||||||
// Simpan file dalam state dan local storage menggunakan questionId dan assessmentId sebagai kunci
|
// Update state to reflect the uploaded file (store the File object, not just the name)
|
||||||
setUploadedFiles(prev => ({
|
setUploadedFiles(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[question.questionId]: file, // Simpan file berdasarkan questionId
|
[question.questionId]: file, // Store the file itself
|
||||||
}));
|
|
||||||
|
|
||||||
localStorage.setItem(`uploadedFile_${assessmentId}_${question.questionId}`, JSON.stringify({
|
|
||||||
name: file.name,
|
|
||||||
type: file.type,
|
|
||||||
lastModified: file.lastModified,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -491,53 +476,44 @@ export default function AssessmentPage() {
|
||||||
|
|
||||||
// Validate file size
|
// Validate file size
|
||||||
if (file.size > MAX_FILE_SIZE) {
|
if (file.size > MAX_FILE_SIZE) {
|
||||||
setExceededFileName(file.name); // Simpan nama file yang melebihi ukuran
|
setExceededFileName(file.name);
|
||||||
setModalOpenFileSize(true); // Tampilkan modal
|
setModalOpenFileSize(true);
|
||||||
return; // Hentikan eksekusi fungsi jika ukuran file melebihi batas
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file); // Hanya menyertakan file pertama
|
formData.append('file', file);
|
||||||
|
|
||||||
// Tambahkan assessmentId ke FormData
|
|
||||||
if (assessmentId) {
|
if (assessmentId) {
|
||||||
formData.append('assessmentId', assessmentId);
|
formData.append('assessmentId', assessmentId);
|
||||||
} else {
|
} else {
|
||||||
console.error("assessmentId is null");
|
console.error("assessmentId is null");
|
||||||
return; // Atau tangani sesuai kebutuhan
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tambahkan questionId ke FormData
|
|
||||||
if (question.questionId) {
|
if (question.questionId) {
|
||||||
formData.append('questionId', question.questionId);
|
formData.append('questionId', question.questionId);
|
||||||
} else {
|
} else {
|
||||||
console.error("questionId is null");
|
console.error("questionId is null");
|
||||||
return; // Atau tangani sesuai kebutuhan
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadFileMutation.mutate(formData); // Unggah file
|
uploadFileMutation.mutate(formData); // Upload file
|
||||||
|
|
||||||
// Simpan file dalam state dan local storage menggunakan questionId dan assessmentId sebagai kunci
|
// Update state to reflect the uploaded file (store the File object)
|
||||||
setUploadedFiles(prev => ({
|
setUploadedFiles(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[question.questionId]: file, // Simpan file berdasarkan questionId
|
[question.questionId]: file, // Store the File object, not just the name
|
||||||
}));
|
|
||||||
|
|
||||||
localStorage.setItem(`uploadedFile_${assessmentId}_${question.questionId}`, JSON.stringify({
|
|
||||||
name: file.name,
|
|
||||||
type: file.type,
|
|
||||||
lastModified: file.lastModified,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveFile = (question: { questionId: string }) => {
|
const handleRemoveFile = (question: { questionId: string }) => {
|
||||||
setUploadedFiles(prev => ({
|
setUploadedFiles((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[question.questionId]: null, // Hapus file yang diunggah untuk pertanyaan ini
|
[question.questionId]: null,
|
||||||
}));
|
}));
|
||||||
localStorage.removeItem(`uploadedFile_${assessmentId}_${question.questionId}`); // Hapus info file dari local storage
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to scroll to the specific question
|
// Function to scroll to the specific question
|
||||||
|
|
@ -694,18 +670,7 @@ export default function AssessmentPage() {
|
||||||
|
|
||||||
{/* Action Icon/Flag */}
|
{/* Action Icon/Flag */}
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
onClick={() => {
|
onClick={() => handleToggleFlag(questionId)}
|
||||||
setFlaggedQuestions((prevFlags) => {
|
|
||||||
const newFlags = {
|
|
||||||
...prevFlags,
|
|
||||||
[questionId]: !prevFlags[questionId],
|
|
||||||
};
|
|
||||||
// Simpan perubahan ke localStorage
|
|
||||||
localStorage.setItem("flaggedQuestions", JSON.stringify(newFlags));
|
|
||||||
return newFlags;
|
|
||||||
});
|
|
||||||
toggleFlagMutation.mutate(questionId);
|
|
||||||
}}
|
|
||||||
title="Tandai"
|
title="Tandai"
|
||||||
className={`m-2 rounded-md border-1 flex items-center justify-center h-7 w-7 ${flaggedQuestions[questionId] ? "border-white bg-red-500" : "border-gray-100 bg-white"}`}
|
className={`m-2 rounded-md border-1 flex items-center justify-center h-7 w-7 ${flaggedQuestions[questionId] ? "border-white bg-red-500" : "border-gray-100 bg-white"}`}
|
||||||
>
|
>
|
||||||
|
|
@ -760,70 +725,23 @@ export default function AssessmentPage() {
|
||||||
placeholder="Berikan keterangan terkait jawaban di atas"
|
placeholder="Berikan keterangan terkait jawaban di atas"
|
||||||
value={validationInformation[question.questionId] || ""}
|
value={validationInformation[question.questionId] || ""}
|
||||||
onChange={(event) => handleTextareaChange(question.questionId, event.currentTarget.value)}
|
onChange={(event) => handleTextareaChange(question.questionId, event.currentTarget.value)}
|
||||||
disabled={!answers[question.questionId]}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* File Upload */}
|
{/* File Upload */}
|
||||||
<div className="mx-11">
|
<FileUpload
|
||||||
{question.needFile === true && (
|
question={question}
|
||||||
<div
|
handleFileChange={handleFileChange}
|
||||||
className={`pt-5 pb-5 pr-5 pl-5 border-2 rounded-lg border-dashed ${dragActive ? "bg-gray-100" : "bg-transparent"
|
handleRemoveFile={handleRemoveFile}
|
||||||
} shadow-lg`}
|
uploadedFiles={uploadedFiles}
|
||||||
onDragOver={handleDragOver}
|
dragActive={dragActive}
|
||||||
onDragLeave={handleDragLeave}
|
handleDragOver={handleDragOver}
|
||||||
onDrop={(event) => handleDrop(event, question)} // Mengoper question sebagai argumen
|
handleDragLeave={handleDragLeave}
|
||||||
onClick={handleClick}
|
handleDrop={handleDrop}
|
||||||
>
|
modalOpenFileSize={modalOpenFileSize}
|
||||||
<Flex align="center" justify="space-between" gap="sm">
|
setModalOpenFileSize={setModalOpenFileSize}
|
||||||
<TbUpload
|
exceededFileName={exceededFileName}
|
||||||
size={24}
|
handleClick={handleClick}
|
||||||
style={{ marginLeft: "8px", marginRight: "8px" }}
|
|
||||||
/>
|
|
||||||
<div className="flex-grow text-right">
|
|
||||||
<Text className="font-bold">
|
|
||||||
Klik untuk unggah atau geser file disini
|
|
||||||
</Text>
|
|
||||||
<Text className="text-sm text-gray-400">
|
|
||||||
PNG, JPG, PDF
|
|
||||||
</Text>
|
|
||||||
<Text className="text-sm text-gray-400">
|
|
||||||
(Max.File size : 64 MB)
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</Flex>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
ref={fileInputRef}
|
|
||||||
onChange={(event) => handleFileChange(event, question)} // Mengoper question sebagai argumen
|
|
||||||
style={{ display: "none" }}
|
|
||||||
accept="image/png, image/jpeg, application/pdf"
|
|
||||||
disabled={!answers[question.questionId]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mx-11 px-1">
|
|
||||||
{uploadedFiles[question.questionId] && (
|
|
||||||
<Stack gap="sm" mt="sm">
|
|
||||||
<Text className="font-bold">File yang diunggah:</Text>
|
|
||||||
<Group align="center">
|
|
||||||
<Text>{uploadedFiles[question.questionId]?.name}</Text> {/* Tampilkan nama file yang diunggah */}
|
|
||||||
<CloseButton
|
|
||||||
title="Hapus file"
|
|
||||||
onClick={() => handleRemoveFile(question)} // Mengoper question sebagai argumen
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* File Size Validation Modal */}
|
|
||||||
<FileSizeValidationModal
|
|
||||||
opened={modalOpenFileSize}
|
|
||||||
onClose={() => setModalOpenFileSize(false)}
|
|
||||||
fileName={exceededFileName}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Garis pembatas setiap soal */}
|
{/* Garis pembatas setiap soal */}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user