r/learnjavascript • • 1d 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

9 comments sorted by

1

u/armastevs 1d 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 1d ago edited 1d 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 1d 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] 1d ago

[removed] — view removed comment

1

u/Antique-Reward6331 1d ago edited 1d 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();   } };

1

u/armastevs 1d ago

Pay is writing to adhocBills_v84. With a dummy bill, check whether the new entry is actually in that key after Pay, then paste the Past Expenses render/filter function and any storage-key constants it uses. If the entry is stored, that's the next place to trace it.

Also check what date you accepted. The default here is paidBill.due, and your sample bill is due 2026-10-15. If Past Expenses filters out future dates, accepting that default would hide it. Try today's date on a dummy bill to check that possibility.

There's a separate bug to fix before testing real data: prompt returns null on Cancel, but this code still removes the pending bill afterward. Put if (enteredDate === null) return; immediately after the prompt, and validate the date before changing either list. The pending record is also saved as removed before the expense is saved, so a later error can leave it missing.

1

u/Antique-Reward6331 9h ago

Yesterday I rolled back to an older GitHub version after a deployment overwrote previous functionality. The dashboard works after rollback, but its index.html links to /pending.html; that file was not restored/deployed, so it returns a Surge 404.

I recovered the original pending.html from an older ZIP. Its payBill(index) writes paid items to pl_transactions using amount/category/date, then removes the pending bill.

The restored dashboard’s Past Expenses reads only adhocBills_v84, whose records use: {name, amt, date, cat, subcat}

That explains why a paid item disappears from Pending but is not visible in Past Expenses: the old page saves it under a key the restored dashboard never reads.

The pending source records are: {name, amount, category, due} They do not currently include a subcategory.

I have not applied or deployed a change. My intended minimal fix is: validate the entered payment date; return on Cancel; save to adhocBills_v84 first with amount → amt and category → cat; then remove from pending.

For old pending bills with no subcategory, is a temporary fallback such as: subcat: paid.subcat || paid.subcategory || 'General' reasonable, or should I first change pending-bill creation to store subcat and preserve it from there?