ERP-node/frontend/components/dashboard/widgets/CalculatorWidget.tsx

287 lines
8.2 KiB
TypeScript
Raw Normal View History

'use client';
/**
*
* -
* -
* -
*/
import React, { useState } from 'react';
import { Button } from '@/components/ui/button';
interface CalculatorWidgetProps {
className?: string;
}
export default function CalculatorWidget({ className = '' }: CalculatorWidgetProps) {
const [display, setDisplay] = useState<string>('0');
const [previousValue, setPreviousValue] = useState<number | null>(null);
const [operation, setOperation] = useState<string | null>(null);
const [waitingForOperand, setWaitingForOperand] = useState<boolean>(false);
// 숫자 입력 처리
const handleNumber = (num: string) => {
if (waitingForOperand) {
setDisplay(num);
setWaitingForOperand(false);
} else {
setDisplay(display === '0' ? num : display + num);
}
};
// 소수점 입력
const handleDecimal = () => {
if (waitingForOperand) {
setDisplay('0.');
setWaitingForOperand(false);
} else if (display.indexOf('.') === -1) {
setDisplay(display + '.');
}
};
// 연산자 입력
const handleOperation = (nextOperation: string) => {
const inputValue = parseFloat(display);
if (previousValue === null) {
setPreviousValue(inputValue);
} else if (operation) {
const currentValue = previousValue || 0;
const newValue = calculate(currentValue, inputValue, operation);
setDisplay(String(newValue));
setPreviousValue(newValue);
}
setWaitingForOperand(true);
setOperation(nextOperation);
};
// 계산 수행
const calculate = (firstValue: number, secondValue: number, operation: string): number => {
switch (operation) {
case '+':
return firstValue + secondValue;
case '-':
return firstValue - secondValue;
case '×':
return firstValue * secondValue;
case '÷':
return secondValue !== 0 ? firstValue / secondValue : 0;
default:
return secondValue;
}
};
// 등호 처리
const handleEquals = () => {
const inputValue = parseFloat(display);
if (previousValue !== null && operation) {
const newValue = calculate(previousValue, inputValue, operation);
setDisplay(String(newValue));
setPreviousValue(null);
setOperation(null);
setWaitingForOperand(true);
}
};
// 초기화
const handleClear = () => {
setDisplay('0');
setPreviousValue(null);
setOperation(null);
setWaitingForOperand(false);
};
// 백스페이스
const handleBackspace = () => {
if (!waitingForOperand) {
const newDisplay = display.slice(0, -1);
setDisplay(newDisplay || '0');
}
};
// 부호 변경
const handleSign = () => {
const value = parseFloat(display);
setDisplay(String(value * -1));
};
// 퍼센트
const handlePercent = () => {
const value = parseFloat(display);
setDisplay(String(value / 100));
};
return (
<div className={`h-full w-full p-3 bg-gradient-to-br from-slate-50 to-gray-100 ${className}`}>
<div className="h-full flex flex-col justify-center gap-2">
{/* 디스플레이 */}
<div className="bg-white border-2 border-gray-200 rounded-lg p-4 shadow-inner min-h-[80px]">
<div className="text-right h-full flex flex-col justify-center">
<div className="h-4 mb-1">
{operation && previousValue !== null && (
<div className="text-xs text-gray-400">
{previousValue} {operation}
</div>
)}
</div>
<div className="text-2xl font-bold text-gray-900 truncate">
{display}
</div>
</div>
</div>
{/* 버튼 그리드 */}
<div className="flex-1 grid grid-cols-4 gap-2">
{/* 첫 번째 줄 */}
<Button
variant="outline"
onClick={handleClear}
className="h-full text-red-600 hover:bg-red-50 hover:text-red-700 font-semibold select-none"
>
AC
</Button>
<Button
variant="outline"
onClick={handleSign}
className="h-full text-gray-600 hover:bg-gray-100 font-semibold select-none"
>
+/-
</Button>
<Button
variant="outline"
onClick={handlePercent}
className="h-full text-gray-600 hover:bg-gray-100 font-semibold select-none"
>
%
</Button>
<Button
variant="default"
onClick={() => handleOperation('÷')}
className="h-full bg-blue-500 hover:bg-blue-600 text-white font-semibold select-none"
>
÷
</Button>
{/* 두 번째 줄 */}
<Button
variant="outline"
onClick={() => handleNumber('7')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
7
</Button>
<Button
variant="outline"
onClick={() => handleNumber('8')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
8
</Button>
<Button
variant="outline"
onClick={() => handleNumber('9')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
9
</Button>
<Button
variant="default"
onClick={() => handleOperation('×')}
className="h-full bg-blue-500 hover:bg-blue-600 text-white font-semibold select-none"
>
×
</Button>
{/* 세 번째 줄 */}
<Button
variant="outline"
onClick={() => handleNumber('4')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
4
</Button>
<Button
variant="outline"
onClick={() => handleNumber('5')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
5
</Button>
<Button
variant="outline"
onClick={() => handleNumber('6')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
6
</Button>
<Button
variant="default"
onClick={() => handleOperation('-')}
className="h-full bg-blue-500 hover:bg-blue-600 text-white font-semibold select-none"
>
-
</Button>
{/* 네 번째 줄 */}
<Button
variant="outline"
onClick={() => handleNumber('1')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
1
</Button>
<Button
variant="outline"
onClick={() => handleNumber('2')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
2
</Button>
<Button
variant="outline"
onClick={() => handleNumber('3')}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
3
</Button>
<Button
variant="default"
onClick={() => handleOperation('+')}
className="h-full bg-blue-500 hover:bg-blue-600 text-white font-semibold select-none"
>
+
</Button>
{/* 다섯 번째 줄 */}
<Button
variant="outline"
onClick={() => handleNumber('0')}
className="h-full col-span-2 hover:bg-gray-100 font-semibold text-lg select-none"
>
0
</Button>
<Button
variant="outline"
onClick={handleDecimal}
className="h-full hover:bg-gray-100 font-semibold text-lg select-none"
>
.
</Button>
<Button
variant="default"
onClick={handleEquals}
className="h-full bg-green-500 hover:bg-green-600 text-white font-semibold select-none"
>
=
</Button>
</div>
</div>
</div>
);
}