import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { useOpenAiGlobal } from "../use-openai-global";
import { useWidgetState } from "../use-widget-state";
type CalculatorState = {
history: Array<{ expression: string; result: string }>;
};
function App() {
const toolOutput = useOpenAiGlobal("toolOutput") as any;
const theme = useOpenAiGlobal("theme");
const [widgetState, setWidgetState] = useWidgetState<CalculatorState>({
history: [],
});
const [display, setDisplay] = useState("0");
const [expression, setExpression] = useState("");
// Add result from tool output to history
React.useEffect(() => {
if (toolOutput?.expression && toolOutput?.result) {
const newHistory = [
...(widgetState?.history || []),
{ expression: toolOutput.expression, result: toolOutput.result },
];
setWidgetState({ history: newHistory.slice(-5) }); // Keep last 5
}
}, [toolOutput]);
const handleNumber = (num: string) => {
if (display === "0") {
setDisplay(num);
setExpression(num);
} else {
setDisplay(display + num);
setExpression(expression + num);
}
};
const handleOperator = (op: string) => {
setDisplay(display + " " + op + " ");
setExpression(expression + op);
};
const handleClear = () => {
setDisplay("0");
setExpression("");
};
const handleEquals = async () => {
try {
const result = String(eval(expression));
setDisplay(result);
// Call the MCP server tool to log the calculation
if (window.openai?.callTool) {
await window.openai.callTool("calculator", { expression });
}
} catch (error) {
setDisplay("Error");
}
};
const isDark = theme === "dark";
const bgClass = isDark ? "bg-gray-900" : "bg-white";
const textClass = isDark ? "text-white" : "text-gray-900";
const buttonClass = isDark ? "bg-gray-700 hover:bg-gray-600" : "bg-gray-200 hover:bg-gray-300";
const operatorClass = isDark ? "bg-blue-600 hover:bg-blue-500" : "bg-blue-500 hover:bg-blue-600";
return (
<div className={"w-full max-w-sm mx-auto p-4 rounded-2xl " + bgClass + " " + textClass}>
<div className="mb-4">
<div className="text-2xl font-bold mb-2">Calculator</div>
<div className={"text-right text-3xl font-mono p-4 rounded-lg " + (isDark ? "bg-gray-800" : "bg-gray-100")}>
{display}
</div>
</div>
<div className="grid grid-cols-4 gap-2 mb-4">
{["7", "8", "9"].map((num) => (
<button
key={num}
onClick={() => handleNumber(num)}
className={"p-4 rounded-lg font-semibold " + buttonClass}
>
{num}
</button>
))}
<button
onClick={() => handleOperator("/")}
className={"p-4 rounded-lg font-semibold text-white " + operatorClass}
>
÷
</button>
{["4", "5", "6"].map((num) => (
<button
key={num}
onClick={() => handleNumber(num)}
className={"p-4 rounded-lg font-semibold " + buttonClass}
>
{num}
</button>
))}
<button
onClick={() => handleOperator("*")}
className={"p-4 rounded-lg font-semibold text-white " + operatorClass}
>
×
</button>
{["1", "2", "3"].map((num) => (
<button
key={num}
onClick={() => handleNumber(num)}
className={"p-4 rounded-lg font-semibold " + buttonClass}
>
{num}
</button>
))}
<button
onClick={() => handleOperator("-")}
className={"p-4 rounded-lg font-semibold text-white " + operatorClass}
>
−
</button>
{["0", "."].map((num) => (
<button
key={num}
onClick={() => handleNumber(num)}
className={"p-4 rounded-lg font-semibold " + buttonClass}
>
{num}
</button>
))}
<button
onClick={handleClear}
className={"p-4 rounded-lg font-semibold " + (isDark ? "bg-red-600 hover:bg-red-500" : "bg-red-500 hover:bg-red-600") + " text-white"}
>
C
</button>
<button
onClick={() => handleOperator("+")}
className={"p-4 rounded-lg font-semibold text-white " + operatorClass}
>
+
</button>
<button
onClick={handleEquals}
className={"col-span-4 p-4 rounded-lg font-semibold text-white " + (isDark ? "bg-green-600 hover:bg-green-500" : "bg-green-500 hover:bg-green-600")}
>
=
</button>
</div>
{widgetState?.history && widgetState.history.length > 0 && (
<div className="mt-4">
<div className="text-sm font-semibold mb-2">History</div>
<div className="space-y-1">
{widgetState.history.slice().reverse().map((item, i) => (
<div
key={i}
className={"text-sm p-2 rounded " + (isDark ? "bg-gray-800" : "bg-gray-100")}
>
{item.expression} = {item.result}
</div>
))}
</div>
</div>
)}
</div>
);
}
const root = document.getElementById("calculator-root");
if (root) {
createRoot(root).render(<App />);
}