From 7d1686bf9495e63a744dec08e658326bb02307b6 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:35:47 -0400 Subject: [PATCH] Update dashboard: split scheduled by method, outstanding checks with 90-day buckets, remove cleared section --- src/slackAppHome.js | 96 +++++++++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 25 deletions(-) diff --git a/src/slackAppHome.js b/src/slackAppHome.js index 44959b6..10cf945 100644 --- a/src/slackAppHome.js +++ b/src/slackAppHome.js @@ -104,11 +104,13 @@ function buildHomeView(payments, metadata) { today.setHours(0, 0, 0, 0); // Categorize payments - const scheduled = []; // future payments not yet due - const outstanding = []; // past-due checks not yet cleared, or returned by BoA - const cleared = []; // confirmed cleared by BoA or ACH past due date + const scheduledChecks = []; + const scheduledACH = []; + const outstandingChecks = []; - const skipStatuses = ["voided", "cancelled"]; + const skipStatuses = ["voided", "cancelled", "canceled", "marked as void", "cleared"]; + const ninetyDaysAgo = new Date(today); + ninetyDaysAgo.setDate(ninetyDaysAgo.getDate() - 90); for (const p of payments) { if (p.method !== "ACH" && p.method !== "Check") continue; @@ -116,21 +118,16 @@ function buildHomeView(payments, metadata) { const dt = parseMDYLocal(p.send_payment_on); if (!dt) continue; - // Skip voided/cancelled payments entirely - if (skipStatuses.includes((p.status || "").toLowerCase())) continue; + const status = (p.status || "").toLowerCase(); + if (skipStatuses.includes(status)) continue; - if (p.clear_status === "Returned") { - outstanding.push(p); - } else if (p.clear_status === "Cleared") { - cleared.push(p); - } else if (p.method === "ACH" && dt < today) { - // ACH assumed cleared once past due date - cleared.push(p); - } else if (dt < today) { - // Check past due date but not yet confirmed by BoA - outstanding.push(p); - } else { - scheduled.push(p); + if (dt >= today) { + // Future — scheduled + if (p.method === "Check") scheduledChecks.push(p); + else scheduledACH.push(p); + } else if (p.method === "Check") { + // Past-due check not cleared — outstanding + outstandingChecks.push(p); } } @@ -140,11 +137,14 @@ function buildHomeView(payments, metadata) { const db = parseMDYLocal(b.send_payment_on); return (da || 0) - (db || 0); }; - scheduled.sort(byDate); - outstanding.sort(byDate); - cleared.sort(byDate); + scheduledChecks.sort(byDate); + scheduledACH.sort(byDate); - const buildSectionBlocks = (title, emoji, items) => { + // Split outstanding into <=90 days and >90 days + const outstanding90 = outstandingChecks.filter((p) => parseMDYLocal(p.send_payment_on) >= ninetyDaysAgo); + const outstandingOver90 = outstandingChecks.filter((p) => parseMDYLocal(p.send_payment_on) < ninetyDaysAgo); + + const buildScheduledBlocks = (title, emoji, items) => { const total = items.reduce((sum, p) => sum + p.amount_usd, 0); const blocks = [ @@ -197,6 +197,52 @@ function buildHomeView(payments, metadata) { return blocks; }; + const buildOutstandingBlocks = () => { + const totalAll = outstandingChecks.reduce((sum, p) => sum + p.amount_usd, 0); + + const blocks = [ + { + type: "section", + text: { + type: "mrkdwn", + text: `*:warning: Outstanding Checks*\n${outstandingChecks.length} checks • ${formatCurrency(totalAll)}`, + }, + }, + { type: "divider" }, + ]; + + if (!outstandingChecks.length) { + blocks.push({ + type: "section", + text: { type: "mrkdwn", text: "_None_" }, + }); + blocks.push({ type: "divider" }); + return blocks; + } + + const total90 = outstanding90.reduce((sum, p) => sum + p.amount_usd, 0); + const totalOver90 = outstandingOver90.reduce((sum, p) => sum + p.amount_usd, 0); + + blocks.push({ + type: "section", + fields: [ + { type: "mrkdwn", text: `*90 days or less*` }, + { type: "mrkdwn", text: `${outstanding90.length} checks • ${formatCurrency(total90)}` }, + ], + }); + + blocks.push({ + type: "section", + fields: [ + { type: "mrkdwn", text: `*Over 90 days*` }, + { type: "mrkdwn", text: `${outstandingOver90.length} checks • ${formatCurrency(totalOver90)}` }, + ], + }); + + blocks.push({ type: "divider" }); + return blocks; + }; + return { type: "home", blocks: [ @@ -212,9 +258,9 @@ function buildHomeView(payments, metadata) { ], }, { type: "divider" }, - ...buildSectionBlocks("Scheduled", ":calendar:", scheduled), - ...buildSectionBlocks("Outstanding", ":warning:", outstanding), - ...buildSectionBlocks("Cleared", ":white_check_mark:", cleared), + ...buildScheduledBlocks("Scheduled Checks", ":calendar:", scheduledChecks), + ...buildScheduledBlocks("Scheduled ACH", ":calendar:", scheduledACH), + ...buildOutstandingBlocks(), ], }; }