[PR #5515] [CLOSED] Fix: Crash when editing amount filter with locale-formatted numbers #5974

Closed
opened 2026-02-28 21:21:53 -06:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/actualbudget/actual/pull/5515
Author: @OmXDev
Created: 8/7/2025
Status: Closed

Base: masterHead: fix-currency-parsing


📝 Commits (4)

  • 620cb3e fix: correct currency parsing logic for loose decimals in filter condition
  • fd03bee 🔧 Fix: Typecheck, lint, and formatting cleanup for filter parsing
  • b88ee5e 🐛 Fix ESLint const declaration issue in parse logic
  • 653cc56 Merge branch 'master' into fix-currency-parsing

📊 Changes

3 files changed (+94 additions, -26 deletions)

View changed files

📝 packages/desktop-client/src/components/filters/FilterExpression.tsx (+20 -4)
📝 packages/loot-core/src/shared/util.test.ts (+2 -0)
📝 packages/loot-core/src/shared/util.ts (+72 -22)

📄 Description

🐛 Fix: Crash when editing amount filter with locale-formatted numbers

This PR fixes a bug where editing an amount filter causes a crash when using number formats that rely on commas or other locale-specific separators, such as:

  • 1.000,33 (German-style)
  • 1’000.33 (Swiss-style)
  • 1 000,33 (French-style with space)

Bug Behavior

  • Users can create an amount filter like “is less than 1.000,33” — which works fine.
  • However, when they edit the filter (e.g., change “is less than” to “is greater than”), the app crashes with:
Error: safeNumber: number is not an integer: null
at safeNumber (util.ts:307:15)
at integerToCurrency (util.ts:319:20)
at FilterExpression.tsx:166:78

This is because the internal number parsing fails for some localized number strings, leading to null being passed into safeNumber().


🔍 Root Cause

The previous implementation didn't fully handle:

  • Grouping separators: ., ', space
  • Decimal separators: ,, .
  • Variants like 1 000,33, 1’000.33, etc.

These would parse incorrectly or return NaN, eventually leading to a crash when safeNumber(null) is called.


Solution

The fix includes:

1. Locale-Aware Parsing Layer

  • Introduced parseCurrencyString (strict + loose modes).
  • Used by currencyToAmount() and parseAmountFromEditorInput().

2. Editor Value Handling

  • In FilterExpression.tsx, changed how filter inputs are parsed and displayed:
    • Use formatAmountForEditor() to format numbers properly for input.
    • On save, parse user input back using parseAmountFromEditorInput() and pass it as an integer.

3. Safe Fallbacks

  • If parsing fails, null or 0 is returned (depending on usage), and crashes are avoided.

🧪 Tests

  • All existing tests pass except two:
expect(currencyToAmount('3.45060')).toBe(3.4506);
expect(currencyToAmount('3.456')).toBe(3.456);
  • These fail because the new parsing enforces a strict 2-decimal precision (which aligns with typical currency formatting).

  • Let me know if that precision should be relaxed or adjusted in a follow-up.


🛠 Modified Files

packages/loot-core/src/shared/util.ts
packages/desktop-client/src/components/filters/FilterExpression.tsx


🧩 Notes

  • This fix supports localized formats like:

    • 1.000,33
    • 1’000.33
    • 1 000,33
    • 1,000.33
  • Gracefully handles invalid input without crashing.

  • Handles both strict parsing (for controlled logic) and loose parsing (for flexible user input).


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/actualbudget/actual/pull/5515 **Author:** [@OmXDev](https://github.com/OmXDev) **Created:** 8/7/2025 **Status:** ❌ Closed **Base:** `master` ← **Head:** `fix-currency-parsing` --- ### 📝 Commits (4) - [`620cb3e`](https://github.com/actualbudget/actual/commit/620cb3e9e29fad7eeae8daf89da03ab1622b445f) fix: correct currency parsing logic for loose decimals in filter condition - [`fd03bee`](https://github.com/actualbudget/actual/commit/fd03beef839576a84c3f5a225aa93b0becc3fdbb) 🔧 Fix: Typecheck, lint, and formatting cleanup for filter parsing - [`b88ee5e`](https://github.com/actualbudget/actual/commit/b88ee5e29516c8dd961119ef6f5d46745856bf0d) 🐛 Fix ESLint const declaration issue in parse logic - [`653cc56`](https://github.com/actualbudget/actual/commit/653cc569824e49b83d3aefd56c79136d3f8c5dce) Merge branch 'master' into fix-currency-parsing ### 📊 Changes **3 files changed** (+94 additions, -26 deletions) <details> <summary>View changed files</summary> 📝 `packages/desktop-client/src/components/filters/FilterExpression.tsx` (+20 -4) 📝 `packages/loot-core/src/shared/util.test.ts` (+2 -0) 📝 `packages/loot-core/src/shared/util.ts` (+72 -22) </details> ### 📄 Description ## 🐛 Fix: Crash when editing amount filter with locale-formatted numbers This PR fixes a bug where editing an **amount filter** causes a crash when using number formats that rely on **commas or other locale-specific separators**, such as: - `1.000,33` (German-style) - `1’000.33` (Swiss-style) - `1 000,33` (French-style with space) --- ### ❗ Bug Behavior - Users can create an amount filter like “**is less than 1.000,33**” — which works fine. - However, when they **edit** the filter (e.g., change “is less than” to “is greater than”), the app crashes with: ``` Error: safeNumber: number is not an integer: null at safeNumber (util.ts:307:15) at integerToCurrency (util.ts:319:20) at FilterExpression.tsx:166:78 ``` This is because the internal number parsing fails for some localized number strings, leading to `null` being passed into `safeNumber()`. --- ### 🔍 Root Cause The previous implementation didn't fully handle: - **Grouping separators**: `.`, `'`, space - **Decimal separators**: `,`, `.` - Variants like `1 000,33`, `1’000.33`, etc. These would parse incorrectly or return `NaN`, eventually leading to a crash when `safeNumber(null)` is called. --- ### ✅ Solution The fix includes: #### 1. **Locale-Aware Parsing Layer** - Introduced `parseCurrencyString` (strict + loose modes). - Used by `currencyToAmount()` and `parseAmountFromEditorInput()`. #### 2. **Editor Value Handling** - In `FilterExpression.tsx`, changed how filter inputs are parsed and displayed: - Use `formatAmountForEditor()` to format numbers properly for input. - On save, parse user input back using `parseAmountFromEditorInput()` and pass it as an integer. #### 3. **Safe Fallbacks** - If parsing fails, `null` or `0` is returned (depending on usage), and crashes are avoided. --- ### 🧪 Tests - All **existing tests** pass **except two**: ```ts expect(currencyToAmount('3.45060')).toBe(3.4506); expect(currencyToAmount('3.456')).toBe(3.456); ``` - These fail because the new parsing enforces a strict 2-decimal precision (which aligns with typical currency formatting). - Let me know if that precision should be relaxed or adjusted in a follow-up. --- ### 🛠 Modified Files > packages/loot-core/src/shared/util.ts > packages/desktop-client/src/components/filters/FilterExpression.tsx --- ### 🧩 Notes - This fix supports localized formats like: - 1.000,33 - 1’000.33 - 1 000,33 - 1,000.33 - Gracefully handles invalid input without crashing. - Handles both strict parsing (for controlled logic) and loose parsing (for flexible user input). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-02-28 21:21:53 -06:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#5974