Three Prompts: Demo Calculator

AI Assistant

Three Prompts: Demo Calculator

React Calculator Demo

Introduction

Calculators might seem simple, but implementing one correctly in JavaScript presents several challenges. Floating-point precision issues can lead to strange results (like 0.1 + 0.2 = 0.30000000000000004), responsive layouts need careful consideration, and adding features like calculation history requires thoughtful state management.

In this article, I'll walk through how I built a fully functional React calculator using just three AI prompts. The final product includes precise calculations with decimal.js, persistent history using localStorage, and a clean responsive design that works across all devices.

The Three Prompts

Here are the exact prompts that were used to create this project:

Prompt 1

/review @projects/demo-calculator 

Come up with a good plan to handle the following traits:
- Screen Size Responsive
- Allow for all normal operations on the calculator
- Handle weird JS math issues, by using a good math library
- Save history in localstorage and display in nice responsive UI


Then /execute 
- Write all important info to the README.md
- Then start executing on the plan right away

Prompt 2

Add decimal js to the package.json then run npm install in my terminal.

Then use that to make sure all the math is done exactly right, Don't make any breaking changes to what already works

Prompt 3


Now, Fix the localstorage logic only, Don't break anything else.

When refreshing the history should still show. Keep it simple.


Once finished with the localstorage changes. Then update the history on desktop view to show under the calculator like it does on mobile. This should be simple.

Building the Calculator Step by Step

Prompt 1: Planning and Initial Implementation

The first prompt established the core requirements for our calculator:

  1. Responsive design across all screen sizes
  2. Standard calculator operations (addition, subtraction, multiplication, division)
  3. Precise calculations using a math library to avoid JavaScript floating-point issues
  4. History feature with localStorage persistence

This prompt resulted in a complete project structure with the following components:

  • Calculator.jsx: The main component with state management and calculation logic
  • Display.jsx: A simple component to show the current input/result
  • Keypad.jsx: The grid of calculator buttons with event handlers
  • History.jsx: A component to display and interact with calculation history

The initial implementation included a responsive layout with CSS Grid and Flexbox, but there were still two key issues to address: mathematical precision and proper history persistence.

Prompt 2: Integrating decimal.js for Precision

JavaScript's native handling of floating-point arithmetic can lead to unexpected results due to how binary floating-point numbers are represented. For example:

0.1 + 0.2 // Returns 0.30000000000000004 instead of 0.3

The second prompt focused on integrating decimal.js, a library that provides arbitrary-precision decimal arithmetic. This ensures our calculator produces mathematically correct results.

Here's how decimal.js was implemented in the calculation function:

const calculate = (a, b, op) => {
  // Convert inputs to Decimal objects for precise calculations
  const decimalA = new Decimal(a);
  const decimalB = new Decimal(b);
  
  let result;
  switch (op) {
    case '+':
      result = decimalA.plus(decimalB);
      break;
    case '-':
      result = decimalA.minus(decimalB);
      break;
    case '×': // multiplication symbol
      result = decimalA.times(decimalB);
      break;
    case '÷': // division symbol
      // Handle division by zero
      if (decimalB.isZero()) {
        return 'Error';
      }
      result = decimalA.dividedBy(decimalB);
      break;
    default:
      result = decimalB;
  }
  
  // Convert result back to a string with appropriate precision
  return result.toString();
};

This implementation ensures that all mathematical operations are performed with the highest possible precision, eliminating the floating-point errors that plague many JavaScript calculators.

Prompt 3: Fixing localStorage and UI Consistency

The final prompt addressed two specific issues:

  1. Improving localStorage implementation to ensure history persists correctly across page refreshes
  2. Updating the UI layout to display the history panel consistently below the calculator on all screen sizes

For the localStorage implementation, we added proper error handling and made sure the history would automatically display if there were saved calculations:

// Load history from localStorage on component mount
useEffect(() => {
  try {
    const savedHistory = localStorage.getItem('calculatorHistory');
    if (savedHistory) {
      const parsedHistory = JSON.parse(savedHistory);
      if (Array.isArray(parsedHistory)) {
        setHistory(parsedHistory);
        // Also show history panel if there are saved calculations
        if (parsedHistory.length > 0) {
          setShowHistory(true);
        }
      }
    }
  } catch {
    // If there's any error parsing the stored history, just use an empty array
    localStorage.removeItem('calculatorHistory');
  }
}, []);

// Save history to localStorage whenever it changes
useEffect(() => {
  if (history.length === 0) {
    localStorage.removeItem('calculatorHistory');
  } else {
    localStorage.setItem('calculatorHistory', JSON.stringify(history));
  }
}, [history]);

For the UI layout, we updated the CSS to ensure the history panel always appears below the calculator, regardless of screen size:

/* Main calculator container */
.calculator-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  gap: 20px;
}

/* Keep calculator and history in column layout for all screen sizes */
.calculator-container {
  flex-direction: column;
  align-items: center;
}

This change simplified the layout and provided a consistent user experience across all devices.

Key Features of the Final Calculator

1. Precise Mathematical Operations

The calculator uses decimal.js to handle all mathematical operations with high precision. This eliminates the floating-point errors common in JavaScript and ensures that calculations like 0.1 + 0.2 correctly result in 0.3.

2. Responsive User Interface

The calculator features a clean, responsive design that works well on devices of all sizes. The layout adjusts appropriately for different screen widths, and the buttons are sized for easy touch interaction on mobile devices.

3. Calculation History

The history panel displays up to 10 recent calculations, which persist even when the page is refreshed. Users can click on any previous calculation to reuse the result, and a clear button allows for resetting the history when needed.

4. User Experience Enhancements

The calculator includes several features to improve usability:

  • Backspace button for correcting input mistakes
  • Percentage function for quick percentage calculations
  • Clear button to reset the calculator
  • Toggle button to show/hide the history panel
  • Dark mode support through CSS media queries

Technical Implementation Highlights

Component Architecture

The calculator is built with a clean component structure that separates concerns:

  • Calculator.jsx: Contains all state management and calculation logic
  • Display.jsx: A simple presentational component for showing output
  • Keypad.jsx: Handles user input through the button grid
  • History.jsx: Manages the display and interaction with calculation history

This separation makes the code more maintainable and easier to understand.

State Management

The calculator uses React's useState hook to manage several pieces of state:

const [input, setInput] = useState('0');
const [previousInput, setPreviousInput] = useState(null);
const [operation, setOperation] = useState(null);
const [waitingForOperand, setWaitingForOperand] = useState(false);
const [history, setHistory] = useState([]);
const [showHistory, setShowHistory] = useState(false);

This approach keeps track of the current input, previous input, selected operation, and calculation history, allowing for a complete calculator experience.

Error Handling

The calculator includes robust error handling for various scenarios:

  • Division by zero results in an "Error" message
  • Invalid operations are caught and handled gracefully
  • localStorage parsing errors are managed without crashing the application

This ensures a smooth user experience even when unexpected situations occur.

Conclusion

Building this calculator with just three AI prompts demonstrates how effective a well-structured, incremental approach can be. Each prompt addressed specific aspects of the implementation:

  1. Initial planning and structure
  2. Mathematical precision with decimal.js
  3. localStorage persistence and UI consistency

The result is a fully functional, responsive calculator that handles calculations precisely, maintains history across sessions, and provides a consistent user experience across all devices.

This project showcases how modern web technologies like React, combined with specialized libraries like decimal.js, can be used to create practical applications that solve real-world problems - even ones as seemingly simple as a calculator.

Feel free to try the calculator yourself and explore the code to see how these concepts come together in practice.