|
'use client'; |
|
|
|
import { useState } from 'react'; |
|
import { Check, X, Calculator } from 'lucide-react'; |
|
|
|
const operations = ['+', '-', '*', '/'] as const; |
|
type Operation = typeof operations[number]; |
|
|
|
const difficulties = ['easy', 'medium', 'hard'] as const; |
|
type Difficulty = typeof difficulties[number]; |
|
|
|
interface Question { |
|
num1: number; |
|
num2: number; |
|
operation: Operation; |
|
answer: number; |
|
} |
|
|
|
const generateQuestion = (difficulty: Difficulty): Question => { |
|
const operation = operations[Math.floor(Math.random() * operations.length)]; |
|
let num1 = 0; |
|
let num2 = 0; |
|
|
|
switch (difficulty) { |
|
case 'easy': |
|
num1 = Math.floor(Math.random() * 10) + 1; |
|
num2 = Math.floor(Math.random() * 10) + 1; |
|
break; |
|
case 'medium': |
|
num1 = Math.floor(Math.random() * 50) + 1; |
|
num2 = Math.floor(Math.random() * 50) + 1; |
|
break; |
|
case 'hard': |
|
num1 = Math.floor(Math.random() * 100) + 1; |
|
num2 = Math.floor(Math.random() * 100) + 1; |
|
break; |
|
} |
|
|
|
|
|
if (operation === '/') { |
|
|
|
num2 = num2 === 0 ? 1 : num2; |
|
|
|
if (difficulty === 'easy' || difficulty === 'medium') { |
|
num1 = num2 * Math.floor(Math.random() * 10) + 1; |
|
} |
|
} |
|
|
|
const answer = eval(`${num1} ${operation} ${num2}`); |
|
|
|
const roundedAnswer = Number.isInteger(answer) ? answer : parseFloat(answer.toFixed(2)); |
|
|
|
return { |
|
num1, |
|
num2, |
|
operation, |
|
answer: roundedAnswer, |
|
}; |
|
}; |
|
|
|
interface CalculatorComponentProps { |
|
onClose: () => void; |
|
} |
|
|
|
const CalculatorComponent: React.FC<CalculatorComponentProps> = ({ onClose }) => { |
|
const [display, setDisplay] = useState('0'); |
|
const [firstOperand, setFirstOperand] = useState<number | null>(null); |
|
const [operator, setOperator] = useState<string | null>(null); |
|
const [waitingForSecondOperand, setWaitingForSecondOperand] = useState(false); |
|
|
|
const inputDigit = (digit: string) => { |
|
if (waitingForSecondOperand) { |
|
setDisplay(digit); |
|
setWaitingForSecondOperand(false); |
|
} else { |
|
setDisplay(display === '0' ? digit : display + digit); |
|
} |
|
}; |
|
|
|
const inputDecimal = () => { |
|
if (waitingForSecondOperand) { |
|
setDisplay('0.'); |
|
setWaitingForSecondOperand(false); |
|
return; |
|
} |
|
if (!display.includes('.')) { |
|
setDisplay(display + '.'); |
|
} |
|
}; |
|
|
|
const clear = () => { |
|
setDisplay('0'); |
|
setFirstOperand(null); |
|
setOperator(null); |
|
setWaitingForSecondOperand(false); |
|
}; |
|
|
|
const calculate = (firstOp: number, secondOp: number, op: string): number | string => { |
|
switch (op) { |
|
case '+': return firstOp + secondOp; |
|
case '-': return firstOp - secondOp; |
|
case '*': return firstOp * secondOp; |
|
case '/': return secondOp === 0 ? 'Error' : firstOp / secondOp; |
|
default: return secondOp; |
|
} |
|
}; |
|
|
|
const performOperation = (nextOperator: string) => { |
|
const inputValue = parseFloat(display); |
|
|
|
if (nextOperator === '=') { |
|
if (operator && firstOperand !== null) { |
|
const result = calculate(firstOperand, inputValue, operator); |
|
setDisplay(String(result)); |
|
setFirstOperand(null); |
|
setOperator(null); |
|
setWaitingForSecondOperand(false); |
|
} |
|
} else { |
|
if (firstOperand === null) { |
|
setFirstOperand(inputValue); |
|
} else if (operator) { |
|
const result = calculate(firstOperand, inputValue, operator); |
|
setDisplay(String(result)); |
|
setFirstOperand(typeof result === 'number' ? result : null); |
|
} |
|
|
|
setWaitingForSecondOperand(true); |
|
setOperator(nextOperator); |
|
} |
|
}; |
|
|
|
return ( |
|
<div className="bg-gray-100 p-4 rounded-lg shadow-lg w-full max-w-md"> |
|
<div className="flex justify-between items-center mb-4"> |
|
<h2 className="text-xl font-bold">Calculator</h2> |
|
<button onClick={onClose} className="text-gray-600 hover:text-gray-800"> |
|
<X className="w-6 h-6" /> |
|
</button> |
|
</div> |
|
<div className="bg-gray-200 p-4 rounded mb-4 text-right text-2xl font-bold"> |
|
{display} |
|
</div> |
|
<div className="grid grid-cols-4 gap-2"> |
|
<button onClick={clear} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">C</button> |
|
<button onClick={() => performOperation('/')} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">/</button> |
|
<button onClick={() => performOperation('*')} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">*</button> |
|
<button onClick={() => performOperation('-')} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">-</button> |
|
|
|
<button onClick={() => inputDigit('7')} className="p-3 bg-white hover:bg-gray-100 rounded">7</button> |
|
<button onClick={() => inputDigit('8')} className="p-3 bg-white hover:bg-gray-100 rounded">8</button> |
|
<button onClick={() => inputDigit('9')} className="p-3 bg-white hover:bg-gray-100 rounded">9</button> |
|
<button onClick={() => performOperation('+')} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">+</button> |
|
|
|
<button onClick={() => inputDigit('4')} className="p-3 bg-white hover:bg-gray-100 rounded">4</button> |
|
<button onClick={() => inputDigit('5')} className="p-3 bg-white hover:bg-gray-100 rounded">5</button> |
|
<button onClick={() => inputDigit('6')} className="p-3 bg-white hover:bg-gray-100 rounded">6</button> |
|
<button onClick={() => performOperation('=')} className="p-3 bg-blue-500 hover:bg-blue-600 text-white rounded row-span-2">=</button> |
|
|
|
<button onClick={() => inputDigit('1')} className="p-3 bg-white hover:bg-gray-100 rounded">1</button> |
|
<button onClick={() => inputDigit('2')} className="p-3 bg-white hover:bg-gray-100 rounded">2</button> |
|
<button onClick={() => inputDigit('3')} className="p-3 bg-white hover:bg-gray-100 rounded">3</button> |
|
|
|
<button onClick={() => inputDigit('0')} className="p-3 bg-white hover:bg-gray-100 rounded col-span-2">0</button> |
|
<button onClick={inputDecimal} className="p-3 bg-white hover:bg-gray-100 rounded">.</button> |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|
|
const MathQuizApp: React.FC = () => { |
|
const [question, setQuestion] = useState<Question>(generateQuestion('easy')); |
|
const [userAnswer, setUserAnswer] = useState(''); |
|
const [result, setResult] = useState(''); |
|
const [score, setScore] = useState(0); |
|
const [wrongAnswers, setWrongAnswers] = useState(0); |
|
const [difficulty, setDifficulty] = useState<Difficulty>('easy'); |
|
const [showCalculator, setShowCalculator] = useState(false); |
|
|
|
const handleSubmit = (e: React.FormEvent) => { |
|
e.preventDefault(); |
|
|
|
|
|
const parsedAnswer = parseFloat(userAnswer); |
|
|
|
|
|
const isCorrect = Math.abs(parsedAnswer - question.answer) < 0.001; |
|
|
|
if (isCorrect) { |
|
setResult('Correct!'); |
|
setScore(score + 1); |
|
} else { |
|
setResult(`Incorrect. The correct answer is ${question.answer}.`); |
|
setWrongAnswers(wrongAnswers + 1); |
|
} |
|
|
|
setUserAnswer(''); |
|
setQuestion(generateQuestion(difficulty)); |
|
}; |
|
|
|
const handleDifficultyChange = (e: React.ChangeEvent<HTMLSelectElement>) => { |
|
const newDifficulty = e.target.value as Difficulty; |
|
setDifficulty(newDifficulty); |
|
setQuestion(generateQuestion(newDifficulty)); |
|
setScore(0); |
|
setWrongAnswers(0); |
|
setResult(''); |
|
}; |
|
|
|
return ( |
|
<div className="bg-gray-50 min-h-screen flex items-center justify-center p-4"> |
|
<div className="max-w-4xl w-full mx-auto bg-white rounded-lg shadow-md p-8"> |
|
<div className="flex justify-between items-center mb-6"> |
|
<h1 className="text-4xl font-bold">Math Quiz App</h1> |
|
<button |
|
onClick={() => setShowCalculator(!showCalculator)} |
|
className="flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg" |
|
> |
|
<Calculator className="w-5 h-5" /> |
|
{showCalculator ? 'Hide Calculator' : 'Show Calculator'} |
|
</button> |
|
</div> |
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8"> |
|
<div className="space-y-6"> |
|
<form onSubmit={handleSubmit} className="space-y-6"> |
|
<div className="flex flex-col items-center gap-6"> |
|
<div className="flex gap-8 items-center justify-center"> |
|
<div className="text-xl font-bold">Correct: {score}</div> |
|
<div className="text-xl font-bold text-red-500">Wrong: {wrongAnswers}</div> |
|
</div> |
|
<select |
|
value={difficulty} |
|
onChange={handleDifficultyChange} |
|
className="bg-gray-50 border border-gray-300 text-gray-900 text-lg rounded-lg focus:ring-blue-500 focus:border-blue-500 p-2.5 w-48 text-center" |
|
> |
|
{difficulties.map((diff) => ( |
|
<option key={diff} value={diff}> |
|
{diff.charAt(0).toUpperCase() + diff.slice(1)} |
|
</option> |
|
))} |
|
</select> |
|
</div> |
|
<div className="text-center"> |
|
<p className="text-3xl font-bold mb-6"> |
|
What is {question.num1} {question.operation} {question.num2}? |
|
</p> |
|
<input |
|
type="number" |
|
value={userAnswer} |
|
onChange={(e) => setUserAnswer(e.target.value)} |
|
className="bg-gray-50 border border-gray-300 text-gray-900 text-xl rounded-lg focus:ring-blue-500 focus:border-blue-500 p-4 w-full text-center" |
|
step="any" |
|
/> |
|
</div> |
|
<div className="text-center"> |
|
<button |
|
type="submit" |
|
className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-lg px-8 py-3 text-center" |
|
> |
|
Submit |
|
</button> |
|
</div> |
|
{result && ( |
|
<p |
|
className={`text-xl font-bold text-center ${ |
|
result === 'Correct!' ? 'text-green-500' : 'text-red-500' |
|
}`} |
|
> |
|
{result}{' '} |
|
{result === 'Correct!' ? ( |
|
<Check className="inline-block w-6 h-6" /> |
|
) : ( |
|
<X className="inline-block w-6 h-6" /> |
|
)} |
|
</p> |
|
)} |
|
</form> |
|
</div> |
|
|
|
{showCalculator && ( |
|
<div className="flex justify-center"> |
|
<CalculatorComponent onClose={() => setShowCalculator(false)} /> |
|
</div> |
|
)} |
|
</div> |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|
|
export default MathQuizApp; |