Skip to content
Open
7 changes: 7 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## 2025-02-12 - Incorrect String Accumulation in Loop
**Learning:** Found a bug where `subTotal` was initialized as a number but `subTotal = parseFloat(subTotal + ...).toFixed(2)` turned it into a string after the first iteration. Subsequent iterations performed string concatenation instead of numeric addition (e.g., "10.00" + 20 -> "10.0020"). This resulted in incorrect totals for invoices with more than one item.
**Action:** When accumulating values in a loop, always ensure the accumulator remains a number. Apply `.toFixed()` only at the very end when displaying or storing the final result. Also, use `parseFloat` consistently to treat inputs as numbers.

## 2025-02-12 - Nested setState Calls vs Single Update
**Learning:** The `handleCalculateTotal` method was chaining 4 `setState` calls using callbacks. This forces multiple render cycles and is inefficient.
**Action:** Calculate all derived values first, then update the state in a single `setState` call. This batches the update and triggers only one re-render.
21,835 changes: 13,639 additions & 8,196 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Expand All @@ -40,5 +40,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"cross-env": "^10.1.0"
}
}
7 changes: 3 additions & 4 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import React, { Component } from 'react';
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import './App.css';
import Container from 'react-bootstrap/Container';
import InvoiceForm from './components/InvoiceForm';

class App extends Component {
render() {
const App = () => {
return (
<div className="App d-flex flex-column align-items-center justify-content-center w-100">
<Container>
<InvoiceForm/>
</Container>
</div>
);
}}
}

export default App;
59 changes: 28 additions & 31 deletions src/components/EditableField.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,33 @@ import 'bootstrap/dist/css/bootstrap.min.css';
import Form from 'react-bootstrap/Form';
import InputGroup from 'react-bootstrap/InputGroup';

class EditableField extends React.Component {
render() {
return (
<InputGroup className="my-1 flex-nowrap">
{
this.props.cellData.leading != null &&
<InputGroup.Text
className="bg-light fw-bold border-0 text-secondary px-2">
<span className="border border-2 border-secondary rounded-circle d-flex align-items-center justify-content-center small" style={{width: '20px', height: '20px'}}>
{this.props.cellData.leading}
</span>
</InputGroup.Text>
}
<Form.Control
className={this.props.cellData.textAlign}
type={this.props.cellData.type}
placeholder={this.props.cellData.placeholder}
min={this.props.cellData.min}
name={this.props.cellData.name}
id={this.props.cellData.id}
value={this.props.cellData.value}
step={this.props.cellData.step}
presicion={this.props.cellData.presicion}
aria-label={this.props.cellData.name}
onChange={this.props.onItemizedItemEdit}
required
/>
</InputGroup>
);
}
}
const EditableField = (props) => {
return (
<InputGroup className="my-1 flex-nowrap">
{
props.cellData.leading != null &&
<InputGroup.Text
className="bg-light fw-bold border-0 text-secondary px-2">
<span className="border border-2 border-secondary rounded-circle d-flex align-items-center justify-content-center small" style={{width: '20px', height: '20px'}}>
{props.cellData.leading}
</span>
</InputGroup.Text>
}
<Form.Control
className={props.cellData.textAlign}
type={props.cellData.type}
placeholder={props.cellData.placeholder}
min={props.cellData.min}
name={props.cellData.name}
value={props.cellData.value}
step={props.cellData.step}
presicion={props.cellData.presicion}
aria-label={props.cellData.name}
onChange={props.onItemizedItemEdit}
required
/>
</InputGroup>
);
};

export default EditableField;
Loading