4 Commits

Author SHA1 Message Date
isra el
3eba8d3444 perf(web): register only the Prism languages used, scope Google OAuth
The API guide imported react-syntax-highlighter's default entry, which is
the highlight.js build with every language compiled in. It also applied
Prism themes to it, and the two use different class names, so the samples
were largely uncoloured on top of being heavy. Switch to PrismLight and
register the six languages the guide actually renders.

GoogleOAuthProvider wrapped the whole app but only the login and register
pages use it, so the Google Identity SDK initialised on every dashboard
page. Move it inside LoginWithGoogle, which is where both consumers go
through.

Total client chunks drop from 3.1M to 2.3M.

Also fixes four e2e tests that were relying on page.goto returning a
fully loaded page. Adding loading.tsx introduced a short skeleton state
that did not exist before, and each test measured or interacted during
it. They now wait on real signals instead of timing:

- bulk send waits for the dropzone row cap, which comes from
  useSubscription inside that page's own hook. The previous wait on the
  devices response was wrong: the dashboard layout requests the same
  query key, so it can resolve before the page hydrates.
- the mobile overflow sweep and the API guide replace networkidle, which
  needs a 500ms window with zero connections that link prefetching keeps
  pushing out of reach.
- the footer/tab-bar check re-scrolls as the page grows, instead of
  scrolling once while the skeleton is still short.
- the overflow sweep measures the billing tab rather than
  /dashboard/account, a redirect stub with no layout of its own whose
  client-side redirect tore down the measurement.

A new test asserts the samples carry Prism token markup in all five
languages, so a revert to the highlight.js entry fails instead of
silently dropping the colours.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 14:36:34 +03:00
isra el
b2acba4c2c fix: tidy the community page and close mobile layout gaps
community-links was the only file in the app still wrapping a Button in
a Link, four times, producing an anchor around a button: invalid markup
and a nested interactive control that assistive tech announces twice.
Everywhere else already uses Button asChild. Two whole Card blocks sat
commented out, with an icon imported solely for that dead code.

community/page.tsx was the only dashboard section that never got the
mobile pass, keeping p-6 with no p-4 step and an unconditional text-3xl.
It was also the only section missing from the 375px overflow guard,
which is presumably how it was missed. Extracting the shared PageHeader,
which the messaging, webhooks and account layouts all repeated by hand,
fixes that outlier by construction.

Both billing limit grids and the promo modal were locked to two columns
at every width, so the meter captions had no room on a phone.

window.open kept a live opener handle back to the app in four places.
Browsers imply noopener for anchor targets but not for window.open.

The share dialog grid moves to 3 columns then 7. Worth stating plainly:
this is not an overflow fix. I expected 7 icons at grid-cols-4 to
overflow at 375px and the extended guard proved they do not. It was
only an awkward 4 + 3 split.

The overflow guard now covers 12 routes instead of 6 and opens a dialog,
since the densest layouts in the app only exist inside modals.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 02:20:39 +03:00
isra el
99a3a79b3b feat: rebuild bulk send as a guided 4-step flow with validation
The old screen was one 425-line component with correctness bugs, not just a
weak layout.

Fixed defects:
- Empty recipients were sent. handleSendBulkSMS mapped every parsed row into
  the payload, so a blank phone cell produced a message addressed to "".
  There was no filtering, no phone validation and no dedupe, so the same
  number listed twice was texted twice.
- User-facing copy printed raw bytes: "max 1048576 bytes".
- The row limit could be wrong. maxRows fell back to 50 while the
  subscription query was still loading, so an unlimited-plan user could be
  told their file was too big. The cap is now only enforced once the real
  limit is known.
- Steps were gated with opacity-50 + pointer-events-none, which leaves
  controls in the tab order and unannounced. Locked steps now use `inert`.
- Data came from raw useQuery(['devices']) + devices?.data instead of the
  typed useDevices(), the same shared-cache-key shape hazard that caused the
  devices?.filter crash in round 1.

The new flow: upload (with parse summary and a preview table of the first 5
rows), map (auto-detected phone column plus live valid/invalid/duplicate
counts), compose (clickable variable chips, SMS segment counter, preview that
cycles through real recipients) and review (explicit count, an itemised list
of skipped rows and why, nothing sent until confirmed).

bulk-csv.ts holds the rules that decide who receives a message, as pure
functions with 24 unit tests. Those tests caught a real bug during
development: the short "to" hint substring-matched a column named "total",
which would have silently auto-selected the wrong column. Short hints are now
exact-match only.

Sample CSV at /samples/bulk-sms-sample.csv using 555 reserved-for-fiction US
and Canada numbers, so an unedited upload cannot text a real person, with an
order-confirmation template that demonstrates multi-variable interpolation.

E2e asserts the actual request payload contains exactly the two valid
recipients from a file seeded with a blank, an invalid and a duplicate row,
and that the parsed-CSV table does not reintroduce sideways scroll at 375px.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 20:42:55 +03:00
isra el
dda38204fa fix: eliminate mobile horizontal overflow and add scroll-width e2e guard
Root causes of the sideways-scroll blank strip at 375px:
- fixed-width auth cards (w-[400px]/w-[450px]) -> w-full + max-w so they
  shrink on small screens
- min-w-[500px] on the community-links dialog -> removed
- webhooks section header: two w-full buttons in a non-wrapping flex row
  (403px wide) -> stacks on mobile
- devices/api-keys cards blown past the grid track by min-content sizing
  -> min-w-0 max-w-full on the cards
- api-guide SyntaxHighlighter blocks get overflowX auto + maxWidth 100%
- safety net: overflow-x clip on body

Adds e2e/mobile-overflow.spec.ts: at 375px, scrollWidth must not exceed the
viewport on home, messaging, webhooks, account, and login. This guard caught
the webhooks-header and card offenders during the fix.

Build, 25 unit tests, and 11 e2e green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 07:27:04 +03:00