SmartInboxHotkeys.tsxrefactor(mail): stop announcing success, and fix the qualified-date parser
Toasts now only fire when something went wrong. 416 success confirmations
across 151 files told the user that the thing they had just watched happen had
happened — the row was already gone, the draft already sent, the text already in
the clipboard. Removing them took the variables and callbacks that existed only
to build those messages with them.
Thirteen survive, minus the success styling: the ones carrying an Undo button,
where the toast is the affordance rather than a notification. Those now use the
neutral toast() so they read as "here is your undo", not congratulation.
toast.info / toast.warning are untouched — those report neutral or unwanted
outcomes, which is not the same thing as celebrating one.
Also fixes "mid august" resolving to August 1st in every date picker. chrono has
no notion of early/mid/late, so it finds the month, discards the qualifier and
answers the 1st — and near a month boundary forwardDate then pushed that past
date into NEXT YEAR, so scheduling a send three days out landed eleven months
away. resolveQualifiedPeriod runs ahead of chrono and takes the words it cannot
express: named months, relative months, weeks and years, each with early / mid /
late, rolling forward only when the resolved date has actually passed.
And the scheduled email in a thread now renders as an ordinary message rather
than a bespoke card: same MailDisplay, a Scheduled badge in the tracking-badge
slot, and Edit / Delete replacing reply / reply-all / forward — there is nothing
to reply to on mail that has not gone out yet. Edit unschedules before reopening,
because the send payload is a frozen snapshot and would otherwise fire the old
text alongside the edited one.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 12, 2026, 10:13 PMSmartInboxLayout.tsxfix(mail): decode bare postgres timestamps as UTC; roll date buckets at midnight
The inbox showed Jul 20 threads under "Today" while the row itself rendered
"Jul 20". Two independent causes:
postgres.js parses `timestamp without time zone` with `new Date(x)`, resolving
the bare wall clock against the server process TZ. On a non-UTC dev machine
crm_email_threads.latest_message_at came back seven hours late (a message
Gmail dates 01:55:28Z surfaced as 08:55:28Z), which is enough to move a thread
into the next calendar day. The rendered date is unaffected because it comes
from the provider payload via mail.get, not the mirror — hence the mismatch.
These columns are written as .toISOString() and are UTC, so pin the parse to
UTC instead of inheriting process.env.TZ. No-op on AWS, where TZ=UTC already.
Separately, the group headers derived their start-of-day inside a useMemo keyed
only on the thread list, so a tab left open past midnight kept rendering the
previous day's buckets. Hoist the boundary into a hook that re-emits at local
midnight, backed by visibility/focus re-checks since background timers get
throttled. Also de-duplicates two identical copies of the grouping logic and
makes the "Last 7 days" edge DST-safe.
Co-Authored-By: Claude Opus 4.8 (1M context) <<email>>Jul 21, 2026, 1:20 PMuseSmartInboxData.tsfix: stabilize split inbox routing and reminder state
Normalize split-inbox query behavior across client/server and apply optimistic reminder updates so thread state stays consistent while async reminder workflows complete.
Co-authored-by: Cursor <<email>>May 31, 2026, 8:22 PM