Skip to content

feat(storybook): build Storybook interface mocks for notification_bell - #365

Merged
godamongstmen897 merged 255 commits into
Goldii-locks:mainfrom
Max-Owolabi:feature/notification-bell-storybook-328
Sep 1, 2026
Merged

feat(storybook): build Storybook interface mocks for notification_bell#365
godamongstmen897 merged 255 commits into
Goldii-locks:mainfrom
Max-Owolabi:feature/notification-bell-storybook-328

Conversation

@Max-Owolabi

Copy link
Copy Markdown
Contributor

Summary

Closes #328.

Builds comprehensive Storybook interface mocks and a reusable component for
otification_bell (Navbar alert bell badge).

Changes Included

  • �pp/components/NotificationBell.tsx: New interactive alert bell component with badge count indicators, open/closed dropdown list, loading spinner, error state, and ARIA accessibility attributes.
  • �pp/components/NotificationBell.stories.tsx: Comprehensive Storybook stories covering 9 UI states (Default zero unread, WithUnreadBadge, HighUnreadCount 99+, OpenWithNotifications, OpenEmpty, LoadingState, ErrorState, Disabled, AllRead).
  • �pp/components/Navbar.tsx: Integrated NotificationBell into top navigation bar when a wallet is connected.
  • tests/notification-bell.test.tsx: 13 unit tests validating component rendering, badge formatting, dropdown toggles, error/loading states, click handlers, and accessibility attributes.
  • tests/notification-bell-stories.test.tsx: 9 unit tests validating rendering of each defined Storybook story.

Verification

px vitest run tests/notification-bell.test.tsx tests/notification-bell-stories.test.tsx: 22/22 tests passing.

px tsc --noEmit: Type check passing with zero errors.

px eslint: Passed cleanly with zero errors/warnings on new files.

Rayhab2000 and others added 30 commits August 26, 2026 12:45
- Add DEFAULT_SIGNING_TIMEOUT_MS = 60_000 configurable constant
- Add TxSignRequest interface, TxSignatureTimeoutError class,
  clearTxSensitiveMemory helper, and signTxWithTimeout function to
  app/lib/transactions.ts, matching the setTimeout + Promise.race
  pattern used by all other connector helpers in the codebase
- Wire signTxWithTimeout into submitContractTransaction via optional
  signingTimeoutMs param (defaults to the constant); on timeout the
  operation is aborted and any sensitive payload memory is zeroed
- Add __tests__/transactions_timeout.test.ts with 21 test cases
  covering: timeout fires, memory cleared, successful signing flow,
  pre-deadline no-early-fire, timer cleanup, error propagation,
  default constant, TxSignatureTimeoutError class, and
  clearTxSensitiveMemory helper
Adds app/components/TransactionSignerPanel.tsx — a wallet-agnostic
sign-transaction interface that unblocks issue Goldii-locks#222 (RTL tests).

- Parses supplied XDR on mount via useWalletMultiSigAssembly.parseStructure
  and displays a structure preview (source account, fee, operation count,
  existing signatures)
- States: idle -> signing -> success | error | parse-error
- Sign button delegates to hook.signTransaction(xdr, signTransaction) —
  no new XDR parsing or signing logic introduced
- Retry button returns to idle on signing failure
- Cancel/Dismiss calls onRejected() and resets state
- onSigned, onRejected, onError callbacks for parent integration
- Works for all four supported wallets (freighter, albedo, xbull, hana)
  through the unified useWalletMultiSigAssembly hook
- Replace hardcoded empty message with EmptyStateCard component
- Display briefcase icon for job-related context
- Show descriptive title and explanation text
- Include role badges (Client, Freelancer, Arbiter) showing available participation options
- Add comprehensive test coverage with 16 test cases
- Ensure proper accessibility with region landmarks and aria-labels
- Validates placeholder display under empty data states
…, desktop

- Add responsive padding and spacing (px-3 sm:px-6) for mobile-first approach
- Implement responsive typography scaling (text-xl sm:text-2xl md:text-3xl)
- Stack layout vertically on mobile, horizontal on tablet/desktop
- Apply responsive grid layouts (grid-cols-1 sm:grid-cols-2 lg:grid-cols-3)
- Make search form full-width on mobile, inline on tablet+
- Add responsive gaps and margins throughout
- Implement horizontal overflow handling for pagination on mobile
- Reduce button padding and font sizes on mobile viewports
- Add comprehensive responsive design test suite with 20 test cases
- Validate layout at mobile (< 640px), tablet (640-1024px), desktop (> 1024px)
…yling

- Add focus-visible ring-2 styling on all interactive elements (indigo-500)
- Implement hover state transitions with smooth animations (transition-all duration-200)
- Add active state styling for button press feedback
- Style disabled buttons with opacity-50 and cursor-not-allowed
- Prevent hover effects on disabled buttons (disabled:hover:bg-gray-900)
- Apply ring-offset for focus states on dark background (ring-offset-gray-950)
- Use inset focus ring on job expand buttons for better UX
- Add focus-visible:outline-none to remove browser defaults
- Implement smooth transitions on all state changes
- Add comprehensive test suite with 25 test cases validating:
  - Search input focus and hover states
  - Search button focus, hover, and active states
  - Role filter button states and transitions
  - Job expand button interactive states
  - Pagination button states and disabled styling
  - Accessibility compliance and transitions
…onSignerPanel

- Move state declarations before closeModal callback (WalletSelectorModal)
- Remove eslint-disable and add missing hook dependency (TransactionSignerPanel)
…addresses

Add state serialization to rabe_connector so active wallet addresses
survive page reload cycles.

New exports:
- RABE_CACHE_KEY: localStorage key for the cache entry
- RabeActiveAddressCache: versioned interface (version, address, savedAt, network)
- validateRabeAddressCache: strict runtime validation (address format,
  timestamp, network)
- serializeRabeAddressCache / deserializeRabeAddressCache: JSON
  round-trip with validation on read-back; returns null on corrupt data
- saveRabeAddressCache: writes to localStorage; SSR-safe; logs warning
  on QuotaExceededError via existing logRabeWarning
- loadRabeAddressCache: reads + validates from localStorage; SSR-safe
- clearRabeAddressCache: removes entry on disconnect; no-op if absent

Tests: 33 new cases covering validation, serialization round-trips,
and all localStorage integration scenarios (save/load/clear, overwrite,
corrupt data, storage errors, timestamp bounds).

All 376 existing tests continue to pass. TypeScript: 0 errors.

Closes Goldii-locks#137
godamongstmen897 and others added 29 commits August 31, 2026 17:29
…pty-list-views-for-notification-bell

[323] Design empty list display views for notification_bell
…e modal

The branch predates Goldii-locks#375's rewrite of DisputeRaiseModal, and its own
edit to that file is broken independently of the merge: it deletes the
counterparty <dd>'s closing tags and splices a stray label/textarea
fragment in their place, so the branch does not parse. The merge
inherited that.

The lib half is sound and is the real contribution, so it was kept and
the component rebuilt around it: the panel becomes a plain flex column,
DISPUTE_MODAL_CLASSES.overlayWrapper takes the padding and the height
cap, and a scrollableContent region wraps everything between the header
and the actions -- so on a short viewport the middle scrolls while the
title and buttons stay pinned.

Two assertions in the responsive suite described the old arrangement and
now follow it: the p-4/sm:p-6/lg:p-8 checks moved from the panel to the
wrapper, and the panel's overflow-y-auto check became a query for the
scrollable region inside it.

The branch's own "keeps action buttons clickable" case also assumed the
confirm button is live with an empty reason, which Goldii-locks#375 changed -- it now
fills the field first, which is what a user reaching those buttons would
have done anyway.

lint 0 errors / tsc 0 errors / 2098 tests passing / build OK
…spute-modal-mobile-overlay-wrappers

Goldii-locks#336 Handle mobile viewports navigation styling in dispute_raise_modal
Two Navbar conflicts: this branch swaps the inline provider select and
Connect button for a <WalletSelectorModal>. That is incidental to the
PR -- its subject is TransactionSignerPanel (Goldii-locks#222) and none of its tests
touch the Navbar -- and main's navbar-wallet-kit suite queries the
select by label and the button by name, so main's Navbar was kept.

TransactionSignerPanel then failed lint: it parsed the XDR in a mount
effect and wrote the result to three pieces of state, which
react-hooks/set-state-in-effect flags as cascading renders.

Parsing is a pure function of the XDR and the wallet/network in play, so
it now derives during render through useMemo. The signing lifecycle is
still real state (idle -> signing -> success/error), so it stays in
useState as `signingState`, with a parse failure outranking it:

  const state = parseErrorMessage ? "parse-error" : signingState;

Rendering is unchanged -- `state`, `structure` and `parseErrorMessage`
mean exactly what they did before.

lint 0 errors / tsc 0 errors / 2140 tests passing / build OK
…on-signer-panel

Feat(wallet): build TransactionSignerPanel component (Goldii-locks#222)
…disconnect_handler (Goldii-locks#235)

- Add WalletDisconnectUserRejectedError class for user rejection scenarios
- Add isWalletDisconnectUserRejected() function to detect rejection errors
- Modify disconnectWalletWithCheck to handle rejections with toast notifications
- Return success=true when user rejects (intentional cancellation)
- Remove active key from persistent store even on rejection
- Add comprehensive test cases for rejection handling (23 new tests)
- Pattern mirrors albedo_connector and freighter_connector for consistency
…i-locks#273)

- Add aria-busy to advertise the in-progress loading state
- Add motion-reduce variants to disable pulse/fade animations
- Preserve role=status, aria-live, sr-only message, and keyboard support
- Add tests covering ARIA semantics, reduced motion, and keyboard nav
…oldii-locks#277)

- Add error and validationErrors props that render accessible role=alert
  messages with aria-live=assertive
- Link alerts to the skeleton via aria-describedby
- Support both field-keyed record and array-of-errors forms
- Apply high-contrast error styling (text-red-400 on bg-red-950)
- Add tests covering validation message rendering and toggling
- Add DashboardList.stories.tsx covering loading, error, empty, single/multiple
  jobs, expanded panels, role badges, and large milestone counts
…#272)

- Cover loading, error, empty, and disconnected-wallet states
- Verify job rendering, ID prefix, funded status, role badges, and search/filter
- Assert ARIA attributes for expand/collapse, filters, and accessibility
The rabe_connector conflict was structural, not semantic: this branch's
addition is a single append-only hunk at the end of the file (156 lines,
zero deletions), but main has grown past that point, so git aligned the
two additions and split an existing function in half. Rebuilt as main's
file plus the branch's block appended -- the persistent address cache
lands whole.

Running the suite then exposed a real defect in
dashboard-accessibility.test.tsx (from Goldii-locks#306): five waitFor calls that
are never awaited.

Three are nested inside an outer waitFor, so the click replays on every
retry and the inner assertions never gate the test; one of them leaked a
rejection that made vitest exit 1 while reporting all tests passed. Two
more sit in synchronous tests, where nothing inside them ever ran.

With the assertions actually running, two failed for a second reason:
the dashboard auto-expands the first job once the fetch resolves, so an
unconditional click closed the very panel they were looking for. They
now click only while the row is still collapsed, and go through
fireEvent so React flushes the update inside act().

lint 0 errors / tsc 0 errors / 2173 tests passing / build OK, exit 0
…e-connector-persistent-cache

feat(rabe_connector): implement secure persistent caching for active addresses
…-micro-animations-and-tests

fixed ci test
…eleton-a11y

feat: ensure a11y ARIA compliance for loading_spinner_skeleton (Goldii-locks#273)
…list-stories

feat: add Storybook stories for dashboard_list (Goldii-locks#271)
The suite merges cleanly but does not typecheck -- 8 errors, all from
untyped helpers in the new file:

- `mockJobsResponse(jobs = [])` infers `never[]` from the default, so
  every call that passes real job objects is rejected. It now takes
  `MockJob[]`, derived from mockJob's own return type so the fixture
  and its consumers cannot drift apart.
- `mockJob(overrides = {})` and `setupFetch(response)` were implicitly
  `any`.
- `let resolveFetch` is assigned inside a Promise executor, which
  TypeScript cannot see as definite; it now carries a definite-assignment
  annotation and its call signature.

No assertions were changed -- all 67 cases pass as written.

lint 0 errors / tsc 0 errors / 2240 tests passing / build OK
…gnature

The branch merges cleanly but fails tsc twice: toastSpy is declared as
ReturnType<typeof vi.fn>, which widens to Mock<Procedure | Constructable>
and will not satisfy disconnectWalletWithCheck's showToast parameter.

Declared the handler signature once and threaded it through both the
declaration and vi.fn<...>(), so the spy is checked against the shape it
is actually passed as. No assertions changed.

lint 0 errors / tsc 0 errors / 2242 tests passing / build OK
…list-tests

test: add comprehensive RTL tests for dashboard_list (Goldii-locks#272)
…llet-disconnect-user-rejection-handling

feat: gracefully catch user signature rejection exceptions in wallet_…
…eton

CI failed with "Parsing error: File appears to be binary" because
app/components/LoadingSkeleton.tsx was committed as UTF-16LE -- git
records it as a binary blob (Bin 6228 -> 17612 bytes), and eslint will
not parse it.

Converted back to UTF-8, that file is identical to main's apart from two
artefacts of the round-trip: a byte-order mark, and the ellipsis in
"Loading job data…" mangled to "ΓǪ" (its UTF-8 bytes re-read as a
single-byte codepage). The validation support the PR describes is
already on main, so the component carried no change of its own -- only
the damage. Took main's copy.

The new suite is the real contribution and passes as written against
main's component: 34 cases, all green.

Worth checking the editor that produced this -- saving .tsx as UTF-16
will keep breaking CI the same way.

lint 0 errors / tsc 0 errors / 2276 tests passing / build OK
…eleton-validation

feat: render validation messages and alerts in loading_spinner_skeleton (Goldii-locks#277)
Two independent designs of this component met here. main has a small
bell driven by count/onClick/ariaLabel, rendered by the Navbar and
covered by 23 assertions; this branch brings a 253-line version with a
dropdown, loading and error states, and its own 13 assertions plus
Storybook stories.

Both were kept rather than picking a winner:

- The component is the branch's, extended with count, onClick and
  ariaLabel as aliases for unreadCount, onBellClick and the derived
  label. Every internal use now reads through a resolved value, so the
  two prop shapes cannot diverge.
- The test file is the union of both suites. They sit under distinct
  top-level describes ("NotificationBell" and "NotificationBell
  Component"), so the only real work was reconciling the import blocks --
  the raw conflict had split main's closing braces from its describe.
- Navbar keeps the WalletBadge this branch predates, and its existing
  <NotificationBell count={0} /> call site is unchanged.

The branch styled with raw palette classes (bg-indigo-600,
ring-indigo-400, text-gray-300). The repo styles with design tokens and
the existing suite asserts them, so those were switched to
bg-accent, ring-accent-soft, text-text-secondary, hover:bg-surface-field
and border-surface-page. The badge also regained its
"N unread notifications" label and the button its aria-live="polite".

All 45 assertions across both suites pass together.

lint 0 errors / tsc 0 errors / 2298 tests passing / build OK
@godamongstmen897
godamongstmen897 merged commit 2f819d8 into Goldii-locks:main Sep 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build Storybook interface mocks for notification_bell