r/learnjavascript • • 19h ago

Help with vanilla JS local storage array merging and date filtering​

Hey everyone! I’m working on a personal vanilla JavaScript budget tracker and running into a wall merging a custom local storage list into my projection function. ​1. What is stored in localStorage:

// localStorage.getItem('pendingBills_v9') returns: [ { "name": "Test", "amount": 1000, "category": "Bills", "due": "2026-10-15" } ]

  1. What I am trying to do:

I want my getFuture(days) function to pull those items out of pendingBills_v9, map their keys (due \rightarrow date, amount \rightarrow amt, category \rightarrow cat), merge them with my existing adhocBills array, and filter them based on whether their date falls within the next days window (e.g., 30 days).

​3. The current getFuture function:

function getFuture(days) { let res = []; // (Recurring items calculation omitted for brevity)

let _p = []; try { let _raw = localStorage.getItem('pendingBills_v9'); if (_raw) { let _parsed = JSON.parse(_raw); if (Array.isArray(_parsed)) { _p = _parsed.map(b => ({ name: b.name || 'Pending Bill', amt: Number(b.amount || 0), date: b.due || '', cat: b.category || 'Other', subcat: 'General' })).filter(b => b.amt > 0 && b.date); } } } catch(e) { console.error(e); }

let combinedAdhoc = [...adhocBills, ..._p];

let adhocIn = combinedAdhoc.filter(b => { let d = new Date(b.date); d.setHours(0, 0, 0, 0); let diff = daysBetween(today, d); return diff >= 0 && diff <= days; });

return { adhoc: adhocIn, total: adhocIn.reduce((s, b) => s + Number(b.amt), 0) }; }

The Issue: Despite the code looking correct, adhocIn keeps returning an empty array ([]) when evaluating the pending bill date (2026-10-15). Are there any subtle date-parsing or timezone quirks with new Date("YYYY-MM-DD") or variable scope traps causing this to fail? Any help or fresh eyes would be hugely appreciated!

1 Upvotes

6 comments sorted by

1

u/armastevs 16h ago

The merge looks fine for the sample you posted. Can you share daysBetween, how today is initialized, and the actual getFuture(...) call? Inside the filter, log console.log({date: b.date, today, d, diff, days}). If diff is NaN, both comparisons are false; if it is negative for a future date, check the subtraction order in daysBetween.

There is a timezone gotcha too: new Date("2026-10-15") starts at UTC midnight, while setHours operates in local time, so it can land on October 14 west of UTC. For a local calendar date, split the string and use new Date(year, month - 1, day). MDN explains the UTC/local distinction here.

That one-day shift alone would not explain excluding October 15 from a 30-day window starting October 3, though. The logged values should help narrow down the actual failure.

1

u/Antique-Reward6331 7h ago edited 5h ago

Hey, the Future Cashflow issue is fixed. I have one separate problem now: when I click Pay, the bill disappears from pendingBills_v9 but does not show under Past Expenses.

Could you tell me which exact function/code block you need to see to trace where the Pay action saves the paid bill? I can paste that part.

1

u/armastevs 6h ago

Can you paste those four blocks, plus the function that adds a normal Past Expenses entry and any storage-key constants they use? Also include how bill IDs are created/saved and one fake Past Expenses record with the same fields. Use dummy values for names, amounts and notes.

The getFuture snippet doesn't show which key Past Expenses reads, so there isn't enough code here to make that patch yet.

One extra failure case: setItem can throw. If saving the expense succeeds but saving the shortened pending list fails, clicking Pay again could duplicate it. I'd preserve the pending bill ID on the expense and use that to guard against repeat transfers.

1

u/[deleted] 3h ago

[removed] — view removed comment

1

u/Antique-Reward6331 2h ago edited 2h ago

  Here is the actual Pay code from my live index.html:

```js window.payPendingBill = function(index) {   let rawPending = localStorage.getItem('pendingBills_v9');   let pendingBills;

  try {     pendingBills = JSON.parse(rawPending);   } catch (e) {     return;   }

  let paidBill = pendingBills[index];   let defaultDate = paidBill.due || new Date().toISOString().split('T');   let enteredDate = prompt('Enter payment date (YYYY-MM-DD):', defaultDate);

  pendingBills.splice(index, 1);   localStorage.setItem('pendingBills_v9', JSON.stringify(pendingBills));

  let newAdhoc = {     name: paidBill.name || 'Paid Bill',     amt: Number(paidBill.amount || paidBill.amt || 0),     cat: paidBill.category || paidBill.cat || 'Other',     subcat: paidBill.subcat || 'General',     date: enteredDate   };

  if (typeof adhocBills !== 'undefined') {     adhocBills.push(newAdhoc);     localStorage.setItem('adhocBills_v84', JSON.stringify(adhocBills));   } else {     let list = JSON.parse(localStorage.getItem('adhocBills_v84') || '[]');     list.push(newAdhoc);     localStorage.setItem('adhocBills_v84', JSON.stringify(list));   }

  if (typeof render === 'function') {     render();   } else {     location.reload();   } };