Reason working
This commit is contained in:
parent
c87ebf0a74
commit
845e3ab3d6
4 changed files with 85 additions and 39 deletions
|
|
@ -14,6 +14,7 @@ export const QuizCreator: React.FC<QuizCreatorProps> = ({ onFinalize, onCancel }
|
|||
const [questions, setQuestions] = useState<Question[]>([]);
|
||||
const [qText, setQText] = useState('');
|
||||
const [options, setOptions] = useState<string[]>(['', '', '', '']);
|
||||
const [reasons, setReasons] = useState<string[]>(['', '', '', '']);
|
||||
const [correctIdx, setCorrectIdx] = useState<number>(0);
|
||||
|
||||
const handleAddQuestion = () => {
|
||||
|
|
@ -28,7 +29,8 @@ export const QuizCreator: React.FC<QuizCreatorProps> = ({ onFinalize, onCancel }
|
|||
text,
|
||||
isCorrect: idx === correctIdx,
|
||||
shape: shapes[idx],
|
||||
color: colors[idx]
|
||||
color: colors[idx],
|
||||
reason: reasons[idx].trim() || undefined
|
||||
}));
|
||||
|
||||
const newQuestion: Question = {
|
||||
|
|
@ -41,6 +43,7 @@ export const QuizCreator: React.FC<QuizCreatorProps> = ({ onFinalize, onCancel }
|
|||
setQuestions([...questions, newQuestion]);
|
||||
setQText('');
|
||||
setOptions(['', '', '', '']);
|
||||
setReasons(['', '', '', '']);
|
||||
setCorrectIdx(0);
|
||||
};
|
||||
|
||||
|
|
@ -123,26 +126,39 @@ export const QuizCreator: React.FC<QuizCreatorProps> = ({ onFinalize, onCancel }
|
|||
const bgClass = COLORS[['red','blue','yellow','green'][idx] as any];
|
||||
|
||||
return (
|
||||
<div key={idx} className={`flex items-center gap-3 p-3 rounded-2xl border-4 ${borderColor} bg-white shadow-sm transition-all`}>
|
||||
<button
|
||||
onClick={() => setCorrectIdx(idx)}
|
||||
className={`p-1 rounded-full ${isSelected ? 'text-green-500' : 'text-gray-200 hover:text-gray-400'}`}
|
||||
>
|
||||
{isSelected ? <CheckCircle size={32} fill="currentColor" className="text-white" /> : <Circle size={32} />}
|
||||
</button>
|
||||
|
||||
<div className={`w-4 h-full rounded-full ${bgClass}`}></div>
|
||||
<div key={idx} className={`flex flex-col gap-2 p-3 rounded-2xl border-4 ${borderColor} bg-white shadow-sm transition-all`}>
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => setCorrectIdx(idx)}
|
||||
className={`p-1 rounded-full ${isSelected ? 'text-green-500' : 'text-gray-200 hover:text-gray-400'}`}
|
||||
>
|
||||
{isSelected ? <CheckCircle size={32} fill="currentColor" className="text-white" /> : <Circle size={32} />}
|
||||
</button>
|
||||
|
||||
<div className={`w-4 h-8 rounded-full ${bgClass}`}></div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
value={opt}
|
||||
onChange={(e) => {
|
||||
const newOpts = [...options];
|
||||
newOpts[idx] = e.target.value;
|
||||
setOptions(newOpts);
|
||||
}}
|
||||
className="w-full p-2 outline-none font-bold text-gray-700 bg-transparent placeholder:font-normal"
|
||||
placeholder={`Option ${idx + 1}`}
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={opt}
|
||||
value={reasons[idx]}
|
||||
onChange={(e) => {
|
||||
const newOpts = [...options];
|
||||
newOpts[idx] = e.target.value;
|
||||
setOptions(newOpts);
|
||||
const newReasons = [...reasons];
|
||||
newReasons[idx] = e.target.value;
|
||||
setReasons(newReasons);
|
||||
}}
|
||||
className="w-full p-2 outline-none font-bold text-gray-700 bg-transparent placeholder:font-normal"
|
||||
placeholder={`Option ${idx + 1}`}
|
||||
className="w-full p-2 ml-12 text-sm outline-none text-gray-500 bg-gray-50 rounded-lg placeholder:text-gray-400"
|
||||
placeholder={isSelected ? "Why is this correct? (optional)" : "Why is this wrong? (optional)"}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ export const RevealScreen: React.FC<RevealScreenProps> = ({
|
|||
<h1 className="text-5xl md:text-7xl font-black font-display text-center drop-shadow-md leading-tight">
|
||||
{correctOption.text}
|
||||
</h1>
|
||||
{correctOption.reason && (
|
||||
<motion.p
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="mt-6 text-xl md:text-2xl text-center opacity-90 bg-black/20 px-6 py-4 rounded-2xl max-w-2xl"
|
||||
>
|
||||
{correctOption.reason}
|
||||
</motion.p>
|
||||
)}
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -110,9 +120,16 @@ export const RevealScreen: React.FC<RevealScreenProps> = ({
|
|||
className="flex flex-col items-center"
|
||||
>
|
||||
{isCorrect ? (
|
||||
<div className="bg-black/20 px-8 py-4 rounded-3xl backdrop-blur-sm border-4 border-white/30 flex items-center gap-4 mb-8">
|
||||
<span className="text-4xl font-black">+{pointsEarned}</span>
|
||||
<span className="font-bold uppercase opacity-80">Points</span>
|
||||
<div className="flex flex-col items-center gap-4 mb-8">
|
||||
<div className="bg-black/20 px-8 py-4 rounded-3xl backdrop-blur-sm border-4 border-white/30 flex items-center gap-4">
|
||||
<span className="text-4xl font-black">+{pointsEarned}</span>
|
||||
<span className="font-bold uppercase opacity-80">Points</span>
|
||||
</div>
|
||||
{correctOption.reason && (
|
||||
<p className="text-center text-lg opacity-90 max-w-md bg-black/10 px-4 py-2 rounded-xl">
|
||||
{correctOption.reason}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-2xl font-bold opacity-90 mb-8 max-w-md text-center">
|
||||
|
|
@ -133,24 +150,34 @@ export const RevealScreen: React.FC<RevealScreenProps> = ({
|
|||
</div>
|
||||
</motion.div>
|
||||
|
||||
{!isCorrect && (
|
||||
<motion.div
|
||||
initial={{ y: 100 }}
|
||||
animate={{ y: 0 }}
|
||||
transition={{ delay: 0.5, type: 'spring' }}
|
||||
className="absolute bottom-0 left-0 right-0 bg-black/30 backdrop-blur-md p-6 pb-12"
|
||||
>
|
||||
<p className="text-center text-sm font-bold uppercase tracking-widest mb-4 opacity-70">The correct answer was</p>
|
||||
<div className="flex items-center justify-center gap-4">
|
||||
<div className={`${COLORS[correctOption.color]} p-3 rounded-xl shadow-lg`}>
|
||||
<ShapeIcon size={24} fill="currentColor" />
|
||||
</div>
|
||||
<span className="text-2xl font-black">{correctOption.text}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
</motion.div>
|
||||
|
||||
{!isCorrect && (
|
||||
<div className="absolute bottom-0 left-0 right-0 overflow-hidden z-20">
|
||||
<motion.div
|
||||
initial={{ y: "100%" }}
|
||||
animate={{ y: 0 }}
|
||||
transition={{ delay: 0.5, type: 'spring' }}
|
||||
className="bg-black/30 backdrop-blur-md p-6 pb-12"
|
||||
>
|
||||
<p className="text-center text-sm font-bold uppercase tracking-widest mb-4 opacity-70">The correct answer was</p>
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`${COLORS[correctOption.color]} p-3 rounded-xl shadow-lg`}>
|
||||
<ShapeIcon size={24} fill="currentColor" />
|
||||
</div>
|
||||
<span className="text-2xl font-black">{correctOption.text}</span>
|
||||
</div>
|
||||
{correctOption.reason && (
|
||||
<p className="text-center text-sm opacity-80 max-w-md mt-2">
|
||||
{correctOption.reason}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const getClient = () => {
|
|||
export const generateQuiz = async (topic: string): Promise<Quiz> => {
|
||||
const ai = getClient();
|
||||
|
||||
const prompt = `Generate a trivia quiz about "${topic}". Create 10 engaging multiple-choice questions. Each question must have exactly 4 options, and exactly one correct answer. Vary the difficulty.`;
|
||||
const prompt = `Generate a trivia quiz about "${topic}". Create 10 engaging multiple-choice questions. Each question must have exactly 4 options, and exactly one correct answer. Vary the difficulty. For each option, provide a brief reason explaining why it is correct or incorrect - this helps players learn.`;
|
||||
|
||||
const response = await ai.models.generateContent({
|
||||
model: "gemini-3-flash-preview",
|
||||
|
|
@ -36,9 +36,10 @@ export const generateQuiz = async (topic: string): Promise<Quiz> => {
|
|||
type: Type.OBJECT,
|
||||
properties: {
|
||||
text: { type: Type.STRING },
|
||||
isCorrect: { type: Type.BOOLEAN }
|
||||
isCorrect: { type: Type.BOOLEAN },
|
||||
reason: { type: Type.STRING, description: "Brief explanation of why this answer is correct or incorrect" }
|
||||
},
|
||||
required: ["text", "isCorrect"]
|
||||
required: ["text", "isCorrect", "reason"]
|
||||
},
|
||||
}
|
||||
},
|
||||
|
|
@ -68,7 +69,8 @@ export const generateQuiz = async (topic: string): Promise<Quiz> => {
|
|||
text: opt.text,
|
||||
isCorrect: opt.isCorrect,
|
||||
shape: shapes[index % 4],
|
||||
color: colors[index % 4]
|
||||
color: colors[index % 4],
|
||||
reason: opt.reason
|
||||
}));
|
||||
|
||||
return {
|
||||
|
|
|
|||
1
types.ts
1
types.ts
|
|
@ -16,6 +16,7 @@ export interface AnswerOption {
|
|||
isCorrect: boolean;
|
||||
shape: 'triangle' | 'diamond' | 'circle' | 'square';
|
||||
color: 'red' | 'blue' | 'yellow' | 'green';
|
||||
reason?: string; // Explanation for why this answer is correct or incorrect
|
||||
}
|
||||
|
||||
export interface Question {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue