generated from muhtadeetaron/nextjs-template
234 lines
6.6 KiB
TypeScript
234 lines
6.6 KiB
TypeScript
import React, { useState } from "react";
|
|
|
|
const ExamBuilder = () => {
|
|
const [paper, setPaper] = useState({
|
|
id: "",
|
|
title: "",
|
|
data: {
|
|
metadata: {
|
|
type: "single",
|
|
marking: "",
|
|
duration: 0,
|
|
quantity: 0,
|
|
},
|
|
questions: [
|
|
{
|
|
id: 1,
|
|
type: "single",
|
|
options: {
|
|
a: "",
|
|
b: "",
|
|
c: "",
|
|
d: "",
|
|
},
|
|
question: "",
|
|
solution: "",
|
|
correctAnswer: "",
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const handleChange = (e) => {
|
|
const { name, value } = e.target;
|
|
setPaper((prev) => ({
|
|
...prev,
|
|
[name]: value,
|
|
}));
|
|
};
|
|
|
|
const handleMetadataChange = (e) => {
|
|
const { name, value } = e.target;
|
|
setPaper((prev) => ({
|
|
...prev,
|
|
data: {
|
|
...prev.data,
|
|
metadata: {
|
|
...prev.data.metadata,
|
|
[name]: value,
|
|
},
|
|
},
|
|
}));
|
|
};
|
|
|
|
const handleQuestionChange = (index, field, value) => {
|
|
const updatedQuestions = paper.data.questions.map((q, i) =>
|
|
i === index ? { ...q, [field]: value } : q
|
|
);
|
|
setPaper((prev) => ({
|
|
...prev,
|
|
data: { ...prev.data, questions: updatedQuestions },
|
|
}));
|
|
};
|
|
|
|
const handleOptionChange = (index, optionKey, value) => {
|
|
const updatedQuestions = paper.data.questions.map((q, i) =>
|
|
i === index ? { ...q, options: { ...q.options, [optionKey]: value } } : q
|
|
);
|
|
setPaper((prev) => ({
|
|
...prev,
|
|
data: { ...prev.data, questions: updatedQuestions },
|
|
}));
|
|
};
|
|
|
|
const addQuestion = () => {
|
|
setPaper((prev) => ({
|
|
...prev,
|
|
data: {
|
|
...prev.data,
|
|
questions: [
|
|
...prev.data.questions,
|
|
{
|
|
id: prev.data.questions.length + 1,
|
|
type: "single",
|
|
options: { a: "", b: "", c: "", d: "" },
|
|
question: "",
|
|
solution: "",
|
|
correctAnswer: "",
|
|
},
|
|
],
|
|
},
|
|
}));
|
|
};
|
|
|
|
const handleSubmit = (e) => {
|
|
e.preventDefault();
|
|
console.log("Exam Paper Submitted: ", paper);
|
|
};
|
|
|
|
return (
|
|
<section className="flex w-3/4 gap-10 h-fit">
|
|
<section className="border-1 border-blue-100 rounded-2xl mt-5 py-10 px-10 max-h-[70vh] w-1/2">
|
|
<h1 className="text-white text-3xl font-bold text-center mb-6">
|
|
Exam Builder
|
|
</h1>
|
|
<form className="flex flex-col gap-4" onSubmit={handleSubmit}>
|
|
<h2 className="text-white text-2xl">General Information</h2>
|
|
<input
|
|
type="text"
|
|
name="title"
|
|
value={paper.title}
|
|
onChange={handleChange}
|
|
placeholder="Exam Title"
|
|
className="bg-white w-full rounded-full py-3 px-6"
|
|
/>
|
|
|
|
<h2 className="text-white text-2xl">Metadata</h2>
|
|
<select
|
|
name="type"
|
|
value={paper.data.metadata.type}
|
|
onChange={handleMetadataChange}
|
|
className="bg-white p-4 rounded-full"
|
|
>
|
|
<option value="single">Multiple Choice Questions (Single)</option>
|
|
<option value="multiple">
|
|
Multiple Choice Questions (Multiple)
|
|
</option>
|
|
</select>
|
|
<input
|
|
type="text"
|
|
name="marking"
|
|
value={paper.data.metadata.marking}
|
|
onChange={handleMetadataChange}
|
|
placeholder="Marking"
|
|
className="bg-white w-full rounded-full py-3 px-6"
|
|
/>
|
|
<input
|
|
type="number"
|
|
name="duration"
|
|
value={paper.data.metadata.duration}
|
|
onChange={handleMetadataChange}
|
|
placeholder="Duration"
|
|
className="bg-white w-full rounded-full py-3 px-6"
|
|
/>
|
|
<input
|
|
type="number"
|
|
name="quantity"
|
|
value={paper.data.metadata.quantity}
|
|
onChange={handleMetadataChange}
|
|
placeholder="How many questions?"
|
|
className="bg-white w-full rounded-full py-3 px-6"
|
|
/>
|
|
|
|
<button
|
|
type="submit"
|
|
className="bg-blue-500 text-white p-3 rounded-full mt-4"
|
|
>
|
|
Submit Exam
|
|
</button>
|
|
</form>
|
|
</section>
|
|
<section className="border-1 border-blue-100 rounded-2xl mt-5 py-10 px-10 w-1/2">
|
|
<h1 className="text-white text-3xl font-bold text-center mb-6">
|
|
Questions
|
|
</h1>
|
|
{paper.data.questions.map((question, index) => (
|
|
<div key={index} className="rounded-lg">
|
|
<h2 className="text-white text-xl mb-4">Question {index + 1}</h2>
|
|
<input
|
|
type="text"
|
|
value={question.question}
|
|
onChange={(e) =>
|
|
handleQuestionChange(index, "question", e.target.value)
|
|
}
|
|
placeholder="Question"
|
|
className="bg-white w-full rounded-full py-3 px-6 mb-2"
|
|
/>
|
|
<div className="">
|
|
{Object.keys(question.options).map((key) => (
|
|
<div key={key} className="flex items-center gap-2 mb-2">
|
|
<h3 className="text-white uppercase py-3 px-5 rounded-full bg-blue-600">
|
|
{key}
|
|
</h3>
|
|
<input
|
|
type="text"
|
|
value={question.options[key]}
|
|
onChange={(e) =>
|
|
handleOptionChange(index, key, e.target.value)
|
|
}
|
|
placeholder={`Option ${key.toUpperCase()}`}
|
|
className="bg-white w-full rounded-full py-3 px-6"
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<input
|
|
type="text"
|
|
value={question.correctAnswer.toLowerCase()}
|
|
onChange={(e) =>
|
|
handleQuestionChange(index, "correctAnswer", e.target.value)
|
|
}
|
|
placeholder="Correct answer (a, b, c, d)"
|
|
className="bg-white w-full rounded-full py-3 px-6 mt-2"
|
|
/>
|
|
<input
|
|
type="text"
|
|
value={question.solution}
|
|
onChange={(e) =>
|
|
handleQuestionChange(index, "solution", e.target.value)
|
|
}
|
|
placeholder="Solution"
|
|
className="bg-white w-full rounded-full py-3 px-6 mt-2"
|
|
/>
|
|
</div>
|
|
))}
|
|
|
|
<button
|
|
type="button"
|
|
onClick={addQuestion}
|
|
className="bg-green-500 text-white p-3 rounded-full mt-2"
|
|
>
|
|
Add Question
|
|
</button>
|
|
</section>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default ExamBuilder;
|
|
|
|
{
|
|
/* */
|
|
}
|