import { createLazyFileRoute } from "@tanstack/react-router"; import { Card, Flex, Pagination, Stack, Radio, Text, Textarea, Loader, ActionIcon, CloseButton, Group, } from "@mantine/core"; import { useQuery, useMutation } from "@tanstack/react-query"; import { submitOptionMutationOptions, getAverageScoreSubAspectQueryOptions, getAverageScoreQueryOptions, fetchAspects, getQuestionsAllQueryOptions, toggleFlagAnswer, } from "@/modules/assessmentManagement/queries/assessmentQueries"; import { TbFlagFilled, TbUpload, TbChevronRight, TbChevronUp } from "react-icons/tb"; import FinishAssessmentModal from "@/modules/assessmentManagement/modals/ConfirmModal"; import { useState, useRef, useEffect } from "react"; const getQueryParam = (param: string) => { const urlParams = new URLSearchParams(window.location.search); return urlParams.get(param); }; export const Route = createLazyFileRoute("/_dashboardLayout/assessment/")({ component: AssessmentPage, }); interface ToggleFlagResponse { message: string; answer: { id: string; createdAt: string | null; updatedAt: string | null; optionId: string | null; assessmentId: string | null; isFlagged: boolean | null; filename: string | null; validationInformation: string; }; } export default function AssessmentPage() { const [page, setPage] = useState(1); const limit = 10; const questionRefs = useRef<{ [key: string]: HTMLDivElement | null }>({}); const [files, setFiles] = useState([]); const [dragActive, setDragActive] = useState(false); const [flaggedQuestions, setFlaggedQuestions] = useState<{ [key: string]: boolean; }>({}); const fileInputRef = useRef(null); const [modalOpen, setModalOpen] = useState(false); const [selectedAspectId, setSelectedAspectId] = useState(null); const [selectedSubAspectId, setSelectedSubAspectId] = useState(null); const [assessmentId, setAssessmentId] = useState(null); const [answers, setAnswers] = useState<{ [key: string]: string }>({}); // Fetch aspects and sub-aspects const aspectsQuery = useQuery({ queryKey: ["aspects"], queryFn: fetchAspects, }); // Fetching questions data using useQuery const { data, isLoading, isError, error } = useQuery( getQuestionsAllQueryOptions(page, limit) ); const handleFinishClick = () => { setModalOpen(true); }; useEffect(() => { const id = getQueryParam("id"); if (!id) { // Handle if no ID found setAssessmentId(null); } else { setAssessmentId(id); } // Check if aspectsQuery.data and aspectsQuery.data.data are defined if (aspectsQuery.data?.data && aspectsQuery.data.data.length > 0) { // If no sub-aspect is selected, find a suitable default if (selectedSubAspectId === null) { const firstMatchingSubAspect = aspectsQuery.data.data .flatMap(aspect => aspect.subAspects) // Get all sub-aspects .find(subAspect => data?.data.some(question => question.subAspectId === subAspect.id)); // Filter based on available questions if (firstMatchingSubAspect) { setSelectedSubAspectId(firstMatchingSubAspect.id); setSelectedAspectId(aspectsQuery.data.data.find(aspect => aspect.subAspects.some(sub => sub.id === firstMatchingSubAspect.id) )?.id || null); // Set selectedAspectId based on the found sub-aspect } } } }, [aspectsQuery.data, selectedSubAspectId, data?.data]) const handleConfirmFinish = () => { if (assessmentId) { // Menggunakan history.pushState untuk mengubah URL tanpa reload const newUrl = `/assessmentResult?id=${assessmentId}`; window.history.pushState({}, "", newUrl); // Setelah mengubah URL, Anda bisa menjalankan logika lain jika diperlukan console.log("Navigated to:", newUrl); } }; // Tambahkan state untuk aspek yang terbuka const [openAspects, setOpenAspects] = useState<{ [key: string]: boolean }>({}); const toggleAspect = (aspectId: string) => { setOpenAspects((prev) => ({ ...prev, [aspectId]: !prev[aspectId], // Toggle state untuk aspek yang diklik })); }; // Fetch average scores by aspect const averageScoreQuery = useQuery(getAverageScoreQueryOptions(assessmentId || "")); // Fetch average scores by sub-aspect const averageScoreSubAspectQuery = useQuery(getAverageScoreSubAspectQueryOptions(assessmentId || "")); // Filter average score aspect berdasarkan sub-aspect yang dipilih const filteredAverageScores = averageScoreQuery.data?.aspects?.filter(aspect => aspect.subAspects.some(subAspect => subAspect.subAspectId === selectedSubAspectId) ); // Filter average scores for the selected sub-aspect const averageScoresForSelectedSubAspect = averageScoreSubAspectQuery.data?.subAspects?.filter( (subAspect) => subAspect.aspectId === selectedAspectId // Use the appropriate property for filtering ); // Mutation function to toggle flag const toggleFlagMutation = useMutation({ mutationFn: toggleFlagAnswer, onSuccess: (response) => { if (response && response.answer) { const { answer } = response; setFlaggedQuestions((prevFlags) => ({ ...prevFlags, [answer.id]: answer.isFlagged !== null ? answer.isFlagged : false, })); } }, onError: (error) => { console.error("Error toggling flag:", error); }, }); // Mutation function to submit answer const submitOptionMutation = useMutation(submitOptionMutationOptions()); useEffect(() => { const savedAnswers = localStorage.getItem("assessmentAnswers"); if (savedAnswers) { setAnswers(JSON.parse(savedAnswers)); } }, []); const handleAnswerChange = (questionId: string, optionId: string) => { const assessmentId = getQueryParam("id"); if (!assessmentId) { console.error("Assessment ID tidak ditemukan"); return; } // Simpan jawaban ke localStorage const updatedAnswers = { ...answers, [questionId]: optionId }; localStorage.setItem("assessmentAnswers", JSON.stringify(updatedAnswers)); // Update state setAnswers(updatedAnswers); submitOptionMutation.mutate({ optionId, assessmentId, questionId, isFlagged: false, filename: undefined, }); }; // Drag and Drop handlers const handleDragOver = (event: React.DragEvent) => { event.preventDefault(); setDragActive(true); }; const handleDragLeave = () => { setDragActive(false); }; const handleDrop = (event: React.DragEvent) => { event.preventDefault(); setDragActive(false); const droppedFiles = Array.from(event.dataTransfer.files); setFiles((prevFiles) => [...prevFiles, ...droppedFiles]); }; const handleClick = () => { if (fileInputRef.current) { fileInputRef.current.click(); } }; const handleFileChange = (event: React.ChangeEvent) => { if (event.target.files) { const fileArray = Array.from(event.target.files); // Ubah ke array hanya jika files tidak null setFiles((prevFiles) => [...prevFiles, ...fileArray]); } }; const handleRemoveFile = (fileIndex: number) => { setFiles((prevFiles) => prevFiles.filter((_, index) => index !== fileIndex) ); }; // Function to scroll to the specific question const scrollToQuestion = (questionId: string) => { const questionElement = questionRefs.current[questionId]; if (questionElement) { questionElement.scrollIntoView({ behavior: "smooth" }); } }; // Handle pagination const handlePageChange = (newPage: number) => { setPage(newPage); }; // Render conditions if (isLoading) { return ; } if (isError) { return ( Error: {error?.message || "Terjadi kesalahan saat memuat pertanyaan."} ); } const totalQuestions = data?.data?.length || 0; if (!assessmentId) { return ( Error: Data Asesmen tidak ditemukan. Harap akses halaman melalui link yang valid. ); } const startIndex = (page - 1) * limit; const endIndex = startIndex + limit; const paginatedQuestions = data?.data.slice(startIndex, endIndex) || []; const filteredQuestions = paginatedQuestions.filter((question) => { return question.subAspectId === selectedSubAspectId; // Misalnya, jika `question` memiliki `subAspectId` }); return ( {/* LEFT-SIDE */} {/* Aspek dan Sub-Aspek */}
{aspectsQuery.data?.data .filter((aspect) => aspect.subAspects.some((subAspect) => data?.data.some((question) => question.subAspectId === subAspect.id) ) ) .map((aspect) => (
toggleAspect(aspect.id)} >
{aspect.name}
{openAspects[aspect.id] ? ( ) : ( )}
{openAspects[aspect.id] && (
{aspect.subAspects .filter((subAspect) => data?.data.some((question) => question.subAspectId === subAspect.id) ) .map((subAspect) => (
setSelectedSubAspectId(subAspect.id)} >
{subAspect.name}
))}
)}
))}
{/* Pertanyaan */} Harap menjawab semua pertanyaan yang tersedia Semua jawaban Anda akan ditinjau {filteredQuestions.length === 0 ? ( Pertanyaan tidak ada untuk sub-aspek yang dipilih. ) : ( filteredQuestions.map((question: any, index: number) => { const questionId = question.questionId; if (!questionId) return null; return ( (questionRefs.current[questionId] = el)} style={{ position: "relative" }} > {startIndex + index + 1}. {question.questionText} { setFlaggedQuestions((prevFlags) => ({ ...prevFlags, [questionId]: !prevFlags[questionId], })); toggleFlagMutation.mutate(questionId); }} title="Tandai" color={flaggedQuestions[questionId] ? "red" : "white"} style={{ border: "1px gray solid ", borderRadius: "4px", backgroundColor: flaggedQuestions[questionId] ? "red" : "white", }} > {question.options?.length > 0 ? (
{question.options.map((option: any) => ( ))}
) : ( Tidak ada opsi untuk pertanyaan ini. )}