Pull Request branch dev-clone to main #1
|
|
@ -4,14 +4,15 @@ import {
|
|||
Flex,
|
||||
Pagination,
|
||||
Stack,
|
||||
Radio,
|
||||
Text,
|
||||
Textarea,
|
||||
Loader,
|
||||
ActionIcon,
|
||||
CloseButton,
|
||||
Group,
|
||||
} from "@mantine/core";
|
||||
import { Textarea } from "@/shadcn/components/ui/textarea";
|
||||
import { Label } from "@/shadcn/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/shadcn/components/ui/radio-group";
|
||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||
import {
|
||||
submitAssessmentMutationOptions,
|
||||
|
|
@ -26,6 +27,7 @@ import {
|
|||
import { TbFlagFilled, TbUpload, TbChevronRight, TbChevronDown } from "react-icons/tb";
|
||||
import FinishAssessmentModal from "@/modules/assessmentManagement/modals/ConfirmModal";
|
||||
import ValidationModal from "@/modules/assessmentManagement/modals/ValidationModal";
|
||||
import FileSizeValidationModal from "@/modules/assessmentManagement/modals/FileSizeValidationModal";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
|
||||
const getQueryParam = (param: string) => {
|
||||
|
|
@ -62,6 +64,7 @@ export default function AssessmentPage() {
|
|||
}>({});
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [modalOpenFileSize, setModalOpenFileSize] = useState(false);
|
||||
const [selectedAspectId, setSelectedAspectId] = useState<string | null>(null);
|
||||
const [selectedSubAspectId, setSelectedSubAspectId] = useState<string | null>(null);
|
||||
const [assessmentId, setAssessmentId] = useState<string | null>(null);
|
||||
|
|
@ -70,6 +73,7 @@ export default function AssessmentPage() {
|
|||
const [uploadedFiles, setUploadedFiles] = useState<{ [key: string]: File | null }>({});
|
||||
const [unansweredQuestions, setUnansweredQuestions] = useState(0);
|
||||
const [validationModalOpen, setValidationModalOpen] = useState(false);
|
||||
const [exceededFileName, setExceededFileName] = useState("");
|
||||
|
||||
// Fetch aspects and sub-aspects
|
||||
const aspectsQuery = useQuery({
|
||||
|
|
@ -380,13 +384,26 @@ export default function AssessmentPage() {
|
|||
});
|
||||
}, [assessmentId]);
|
||||
|
||||
// Max file size in bytes (25 MB)
|
||||
const MAX_FILE_SIZE = 25 * 1024 * 1024;
|
||||
|
||||
const handleDrop = (event: React.DragEvent<HTMLDivElement>, question: { questionId: string }) => {
|
||||
event.preventDefault();
|
||||
setDragActive(false);
|
||||
const droppedFiles = Array.from(event.dataTransfer.files);
|
||||
|
||||
if (droppedFiles.length > 0) {
|
||||
const file = droppedFiles[0];
|
||||
|
||||
// Validate file size
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
setExceededFileName(file.name); // Simpan nama file yang melebihi ukuran
|
||||
setModalOpenFileSize(true); // Tampilkan modal
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', droppedFiles[0]); // Hanya menyertakan file pertama
|
||||
formData.append('file', file); // Hanya menyertakan file pertama
|
||||
|
||||
// Pastikan assessmentId tidak null sebelum menambahkannya ke FormData
|
||||
if (assessmentId) {
|
||||
|
|
@ -409,13 +426,14 @@ export default function AssessmentPage() {
|
|||
// Simpan file dalam state dan local storage menggunakan questionId dan assessmentId sebagai kunci
|
||||
setUploadedFiles(prev => ({
|
||||
...prev,
|
||||
[question.questionId]: droppedFiles[0], // Simpan file berdasarkan questionId
|
||||
[question.questionId]: file, // Simpan file berdasarkan questionId
|
||||
}));
|
||||
|
||||
localStorage.setItem(`uploadedFile_${assessmentId}_${question.questionId}`, JSON.stringify({
|
||||
name: droppedFiles[0].name,
|
||||
type: droppedFiles[0].type,
|
||||
lastModified: droppedFiles[0].lastModified,
|
||||
})); // Simpan info file ke local storage
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
lastModified: file.lastModified,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -429,8 +447,17 @@ export default function AssessmentPage() {
|
|||
if (event.target.files) {
|
||||
const fileArray = Array.from(event.target.files);
|
||||
if (fileArray.length > 0) {
|
||||
const file = fileArray[0];
|
||||
|
||||
// Validate file size
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
setExceededFileName(file.name); // Simpan nama file yang melebihi ukuran
|
||||
setModalOpenFileSize(true); // Tampilkan modal
|
||||
return; // Hentikan eksekusi fungsi jika ukuran file melebihi batas
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', fileArray[0]); // Hanya menyertakan file pertama
|
||||
formData.append('file', file); // Hanya menyertakan file pertama
|
||||
|
||||
// Tambahkan assessmentId ke FormData
|
||||
if (assessmentId) {
|
||||
|
|
@ -453,13 +480,14 @@ export default function AssessmentPage() {
|
|||
// Simpan file dalam state dan local storage menggunakan questionId dan assessmentId sebagai kunci
|
||||
setUploadedFiles(prev => ({
|
||||
...prev,
|
||||
[question.questionId]: fileArray[0], // Simpan file berdasarkan questionId
|
||||
[question.questionId]: file, // Simpan file berdasarkan questionId
|
||||
}));
|
||||
|
||||
localStorage.setItem(`uploadedFile_${assessmentId}_${question.questionId}`, JSON.stringify({
|
||||
name: fileArray[0].name,
|
||||
type: fileArray[0].type,
|
||||
lastModified: fileArray[0].lastModified,
|
||||
})); // Simpan info file ke local storage
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
lastModified: file.lastModified,
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -652,33 +680,36 @@ export default function AssessmentPage() {
|
|||
{/* Opsi Radio Button */}
|
||||
{question.options?.length > 0 ? (
|
||||
<div className="mx-11">
|
||||
<Radio.Group value={answers[question.questionId] || ""}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<RadioGroup
|
||||
value={answers[question.questionId] || ""}
|
||||
onValueChange={(value) => handleAnswerChange(question.questionId, value)}
|
||||
className="flex flex-col gap-2"
|
||||
>
|
||||
{question.options.map((option: any) => (
|
||||
<label
|
||||
<div
|
||||
key={option.optionId}
|
||||
className={`cursor-pointer transition-transform transform hover:scale-105 shadow-md hover:shadow-lg flex items-center border rounded-lg p-3 text-sm ${
|
||||
answers[question.questionId] === option.optionId
|
||||
? "bg-blue-500 text-white"
|
||||
: "bg-gray-200 text-black"
|
||||
}`}
|
||||
onClick={() => document.getElementById(option.optionId)?.click()}
|
||||
onClick={() => handleAnswerChange(question.questionId, option.optionId)}
|
||||
>
|
||||
<Radio
|
||||
id={option.optionId}
|
||||
className="font-bold"
|
||||
<RadioGroupItem
|
||||
value={option.optionId}
|
||||
label={option.optionText}
|
||||
size="xs"
|
||||
radius="xl"
|
||||
style={{ pointerEvents: "none" }}
|
||||
checked={answers[question.questionId] === option.optionId} // Untuk menampilkan jawaban yang sudah dipilih
|
||||
onChange={() => handleAnswerChange(question.questionId, option.optionId)} // Memanggil handleAnswerChange dengan questionId dan optionId
|
||||
id={option.optionId}
|
||||
checked={answers[question.questionId] === option.optionId}
|
||||
className="bg-white checked:bg-white checked:border-blue-500 pointer-events-none rounded-full"
|
||||
/>
|
||||
</label>
|
||||
))}
|
||||
<Label
|
||||
htmlFor={option.optionId}
|
||||
className="ml-2 font-bold cursor-pointer flex-1"
|
||||
>
|
||||
{option.optionText}
|
||||
</Label>
|
||||
</div>
|
||||
</Radio.Group>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</div>
|
||||
) : (
|
||||
<Text color="red">Tidak ada opsi untuk pertanyaan ini.</Text>
|
||||
|
|
@ -717,6 +748,9 @@ export default function AssessmentPage() {
|
|||
<Text className="text-sm text-gray-400">
|
||||
PNG, JPG, PDF
|
||||
</Text>
|
||||
<Text className="text-sm text-gray-400">
|
||||
(Max.File size : 25 MB)
|
||||
</Text>
|
||||
</div>
|
||||
</Flex>
|
||||
<input
|
||||
|
|
@ -746,6 +780,13 @@ export default function AssessmentPage() {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* File Size Validation Modal */}
|
||||
<FileSizeValidationModal
|
||||
opened={modalOpenFileSize}
|
||||
onClose={() => setModalOpenFileSize(false)}
|
||||
fileName={exceededFileName}
|
||||
/>
|
||||
|
||||
{/* Garis pembatas setiap soal */}
|
||||
<div>
|
||||
<hr className="border-t-2 border-gray-300 mx-11 mt-6 mb-6" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user