Skip to content

Feat/dashboard interactive states - #305

Merged
godamongstmen897 merged 113 commits into
Goldii-locks:mainfrom
vicajohn:feat/dashboard-interactive-states
Aug 31, 2026
Merged

Feat/dashboard interactive states#305
godamongstmen897 merged 113 commits into
Goldii-locks:mainfrom
vicajohn:feat/dashboard-interactive-states

Conversation

@vicajohn

Copy link
Copy Markdown
Contributor

closes #264

- 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
@drips-wave

drips-wave Bot commented Aug 27, 2026

Copy link
Copy Markdown

@vicajohn Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

hunter-baddie and others added 26 commits August 27, 2026 19:57
Implements the app dark/light theme toggle as a keyboard-operable,
ARIA-compliant switch (role=switch, aria-checked, aria-label) that
persists the chosen theme to localStorage and applies it to the document
root. Adds React Testing Library tests verifying node rendering,
accessible state, theme application, keyboard operation and persistence.

Closes Goldii-locks#319
Implements the navbar alert bell badge as a keyboard-operable
(role=button) disclosure with ARIA compliance (Goldii-locks#320): accessible name,
aria-haspopup/aria-expanded/aria-controls, aria-live announcement
regions, aria-hidden on decorative glyphs, focus-visible rings and
design-token contrast.

Adds field error indicators and alerts (Goldii-locks#324): validation field configs
render role=alert error text that toggles as validation triggers, wired
via aria-describedby and counted toward the unread badge.

Adds React Testing Library tests covering both requirements.

Closes Goldii-locks#320
Closes Goldii-locks#324
Stack the stat grid and content rows to a single column on mobile,
two on tablet, three on desktop, and use responsive padding/spacing
so LoadingSkeleton scales cleanly at every breakpoint.

Closes Goldii-locks#275
Fade the skeleton in on mount (animate-fade-in) instead of popping in
abruptly, and stagger each placeholder bar's pulse animation-delay so
the loading state reads as a smooth wave rather than a flat blink.

Closes Goldii-locks#278
Replace the bare "No jobs found" line with a reusable EmptyState
component (icon, heading, supporting copy) shown once loading
finishes with zero jobs for the connected wallet.

Closes Goldii-locks#276
… mobile

Cap the skeleton's height on small viewports and let it scroll
internally (overscroll-contain) instead of pushing surrounding
controls off-screen, while keeping the wrapper free of fixed/absolute
positioning so it never traps taps on other elements.

Closes Goldii-locks#279
Closes Goldii-locks#240, Goldii-locks#238, Goldii-locks#236, Goldii-locks#332.

wallet_disconnect_handler (Goldii-locks#240, Goldii-locks#238, Goldii-locks#236)
- Goldii-locks#240 Gas estimation warnings: checkDisconnectSimulationFeeWarning inspects
  a Soroban simulation result and flags fees above the 1_000_000 stroop
  (0.1 XLM) bound, plus simulation errors and non-finite fee estimates.
  Simulation errors take precedence over the fee check, since a failed
  simulation's reported fee is not trustworthy. Surfaced by
  WalletDisconnectGasWarningBanner.
- Goldii-locks#238 Loading spinner: a counter-based loader lifecycle
  (start/end/reset/subscribe/withWalletDisconnectLoader) so overlapping
  disconnects do not hide the overlay early, clamped at zero so an
  unbalanced end cannot wedge it open. disconnectWalletWithCheck now runs
  entirely inside the lifecycle, so the spinner clears on every exit path
  (success, missing wallet, throw). Surfaced by
  WalletDisconnectLoaderOverlay.
- Goldii-locks#236 Network mismatch: checkDisconnectNetworkMatch compares the wallet
  chain against the app chain, normalising bare labels, the public/test
  aliases, and full Stellar passphrases, since wallets report them
  interchangeably. An unrecognised network is reported as a mismatch rather
  than silently ignored. Surfaced by WalletDisconnectNetworkWarningBar.

dispute_raise_modal (Goldii-locks#332)
- The module did not exist; added app/lib/dispute_raise_modal.ts and
  DisputeRaiseModal alongside it. Sizing is mobile-first: a full-bleed
  bottom sheet with stacked full-width actions on phones, a centered
  sm:max-w-lg dialog on tablets, and a lg:max-w-2xl panel on desktop. The
  summary grid collapses to one column below sm: and long addresses wrap,
  so nothing forces horizontal scroll at 375/414px. Touch targets meet the
  44px minimum used elsewhere in the repo.
- useDisputeViewport uses useSyncExternalStore rather than an effect plus
  setState, avoiding the cascading render the react-hooks
  set-state-in-effect rule targets.

Tests: 4 new files, 204 cases covering fee bounds and simulation errors,
spinner toggling on start/end across every exit path, network mismatch
detection and warning-bar rendering, and modal layout at 320-1920px
including live resize. Type-check and lint clean.

Pre-existing failures unchanged and unrelated: 4 cases in
freighter_multisig_hook.test.ts (invalid XDR fixtures) and 2 files that
cannot collect due to a @stellar/freighter-api CJS/ESM interop error via
WalletContext. Both reproduce on a clean checkout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…oldii-locks#216)

Build chain network checks in a new TransactionSigner component to alert
users when their wallet network does not match the app (e.g. Mainnet vs
Testnet). Includes network mismatch warning bar, sign button disabled on
mismatch, and comprehensive unit/component/integration tests.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…handled rejections

- vitest.config.mts: inline @stellar/freighter-api + @creit.tech/stellar-wallets-kit
  so Vite (not Node) does the CJS->ESM interop. Node's named-export detection on
  freighter-api's minified UMD bundle only yields {default, freighterApi}, so the
  kit's 'import { getAddress }' threw a SyntaxError that killed every suite
  importing app/context/WalletContext.tsx.
- freighter_multisig_hook.test.ts: replace base64('aaaa...') fixtures with real
  signed testnet envelopes built via TransactionBuilder.
- signature_timeout_alert_timeout.test.ts: attach rejection handlers before
  advancing fake timers so Node's unhandled-rejection sweep does not fire.
- signature_timeout_alert.test.tsx: await the loader overlay instead of querying
  synchronously after a React state update.
- SignatureTimeoutAlert.tsx: remove the dangling expression left behind by the
  useMemo refactor.
…pinner

Add comprehensive unit tests covering correct node rendering,
accessibility attributes, CSS design-token classes, and prop
behavior for both loading_spinner_skeleton components.

- LoadingSkeleton: root node, aria-live, sr-only text, outer card
  structure, header/stat/milestone placeholders, structural invariants
- ButtonSpinner: SVG rendering, circle/path elements, default and
  custom className prop, aria-hidden, structural invariants

Coverage: 100% statements, branches, functions, lines on both files.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
godamongstmen897 and others added 29 commits August 31, 2026 12:52
…gas-warning

 feat: Add gas estimation warning banners to network_sync_checker
The PR imported EmptyStateCard but never added the component, so the
dashboard would not build. Added it, satisfying this PR's contract
(dashboard-empty-state test id, region role with an aria-label, an SVG
briefcase icon and role badges) while also carrying the shared
empty-state/-title/-description ids the existing dashboard empty-state
test queries.

The description now carries both wordings so the existing assertion
(/create one to get started/i) and this PR's fuller copy both hold.
…y-state-ui

feat: implement descriptive empty state UI for dashboard jobs list
…torybook-318

Build Storybook interface mocks for dark_mode_switcher
The branch was pushed with a botched conflict resolution: the `>>>>>>>`
markers were stripped but the branch-name lines and both sides of each
conflict were left in place. That left four stray
`Write-React-Testing-Library-assertions-...-Goldii-locks#242-FIX` lines, a duplicate
`@stellar/stellar-sdk` import block, a second `parseMessage` useMemo in
SignatureTimeoutAlert, and a duplicate `server` key in vitest.config.mts.

Resolved by taking main for the five files the branch only touched
incidentally -- main already carries the equivalent, deduplicated work
(the same parseMessage useMemo derivation and the same freighter-api
inline config the branch was re-adding).

The branch's actual deliverable for Goldii-locks#242 is kept intact:
WALLET_DISCONNECT_HANDLER_TESTS.md and the 851-line
wallet_disconnect_handler.component.test.ts.

lint 0 errors / tsc 0 errors / 1776 tests passing / build OK
…Testing-Library-assertions-for-wallet-disconnect-handler-#242-FIX

Write React Testing Library assertions for wallet disconnect handler …
…ns target

The two design-token cases rendered WalletSelectorModal with its default
props, where `errorMessage` defaults to null and `activeAddress` defaults
to null. Both surfaces under test are gated on those props, so
`wallet-selector-error-message` and `wallet-selector-connected-badge`
were never in the tree and the queries threw.

Passed an errorMessage to the first case and an activeAddress to the
second. The component's design tokens were already correct -- only the
test setup needed the props.

lint 0 errors / tsc 0 errors / 1778 tests passing / build OK
…e-modal-design-tokens

Feat: Dispute Raise ModaL
…n tokens

The suite hardcoded the raw Tailwind palette LoadingSkeleton used when
the branch was written. main has since migrated the component to
semantic design tokens, so the class assertions and the querySelector
calls that locate the cards no longer matched anything.

Remapped throughout:
  bg-gray-900                  -> bg-surface-card
  bg-gray-800 (bars, stat card)-> bg-surface-field
  bg-gray-700 (stat placehold.)-> bg-border-subtle
  border-gray-800              -> border-border-strong

Worth noting three cases were passing vacuously: the stat- and
milestone-card selectors returned empty NodeLists, so their forEach
assertion bodies never ran. With the selectors fixed they now iterate
and pass for real -- 54 of 54 in this file, up from 49.

lint 0 errors / tsc 0 errors / 1832 tests passing / build OK
…ng-spinner-skeleton

test: Add React Testing Library tests for LoadingSkeleton and ButtonSpinner (Goldii-locks#282)
… design tokens

The branch was cut before main migrated LoadingSkeleton to semantic
design tokens and added the skeleton-* test ids, so its side of the
conflict still carried bg-gray-*/no-testid markup. Resolved by applying
the branch's responsive layout on top of main's tokenised markup rather
than taking either side whole.

Two adjustments to keep the sibling suites passing:

- The branch's new test ids (loading-skeleton-card/-stats/-rows) name
  elements that already carry ids on main (skeleton-container,
  skeleton-stats-grid, skeleton-milestones). An element can only hold
  one data-testid, so the test now queries main's names -- every
  assertion is unchanged.

- Placeholder bars are expressed desktop-first (w-32 max-sm:w-24) rather
  than mobile-first (w-24 sm:w-32). Same computed result at both
  breakpoints, but it keeps the fixed widths on the element so the
  structural selectors in loading-spinner-skeleton.test.tsx still match.

The two card-padding assertions there did have to move to the responsive
class (p-6 -> sm:p-6, space-y-6 -> sm:space-y-6), since the branch
deliberately makes those breakpoint-dependent.

lint 0 errors / tsc 0 errors / 1841 tests passing / build OK
…skeleton-responsive-275

feat(loading-skeleton): responsive sizing across mobile/tablet/desktop
Same situation as Goldii-locks#349: the branch predates the design-token migration,
so its side of the LoadingSkeleton conflict still carried the old
bg-gray-* markup. Applied the branch's animation work on top of main's
current component instead of taking either side whole -- animate-fade-in
on the root, and animate-pulse plus the staggered
[animation-delay:...] utilities on the three stat cards (100/175/250ms)
and two milestone rows (325/400ms).

The branch's test ids (loading-skeleton-card/-stat-N/-row-N) name
elements that already carry ids on main, so the test queries main's
names (skeleton-container, skeleton-stat-card-N,
skeleton-milestone-card-N). Assertions and delay values are unchanged.

Delays are written as literal class names rather than interpolated,
since Tailwind only emits CSS for classes it can see statically.

lint 0 errors / tsc 0 errors / 1847 tests passing / build OK
…skeleton-animations-278

feat(loading-skeleton): CSS micro-animations on mount and pulse stagger
Same conflict shape as Goldii-locks#349 and Goldii-locks#351 -- the branch predates the
design-token migration, so its side of LoadingSkeleton still carried the
old bg-gray-* markup. Applied the branch's mobile work on top of main's
current component: a max-h-[70vh] sm:max-h-none overflow-y-auto
overscroll-contain wrapper between the status root and the card, so the
skeleton scrolls internally on small viewports rather than pushing the
surrounding controls off-screen.

The wrapper sits outside the card, so the card's first child is still
the header row that Goldii-locks#349's responsive assertions rely on.

lint 0 errors / tsc 0 errors / 1852 tests passing / build OK
…skeleton-mobile-279

feat(loading-skeleton): constrain height and preserve clickability on mobile
Same conflict shape as the other LoadingSkeleton branches -- this one
predates the design-token migration, the responsive sizing, the stagger
animations and the mobile wrapper, so its side still carried the old
markup. Applied the branch's props to main's current component rather
than taking either side whole: interactive swaps the root to
role="button" and adds the hover/focus-visible treatment, disabled adds
opacity-50 cursor-not-allowed and blocks click and key handling.

The interactive styling is the branch's own gray-* palette, which is
fine here: it is only emitted when interactive is set, and the
design-token suite renders the default (non-interactive) skeleton, so
its "no hardcoded gray-*" assertion still holds.

One correction to the branch's test -- it asserted the loading label as
"Loading job data..." with three ASCII dots, but the component has
always used a U+2026 ellipsis, so the query could never match. Aligned
the assertion to the character the component renders.

ButtonSpinner takes the branch's version as-is (disabled prop,
transition classes, button-spinner test id).

lint 0 errors / tsc 0 errors / 1858 tests passing / build OK
…er-skeleton-states-274

feat(ui): add interactive hover focus and disabled states to loading …
…he row animations

Two conflicts in app/dashboard/page.tsx, both resolved by taking each
side's contribution rather than picking one:

- Job row button: the branch's responsive padding (px-3 sm:px-5 py-3
  sm:py-4) with main's interaction feedback (transition-colors
  duration-150, active:scale-[0.99], active:bg-gray-800/70). The
  branch's own assertion only covers px-3/sm:px-5, and nothing asserts
  the active: classes, so keeping both loses nothing.

- Expanded panel: the branch's responsive spacing and border-t, plus
  main's data-testid="dashboard-expanded-panel" and animate-fade-in.
  The branch's side had dropped the test id, which
  dashboard-list-animations.test.tsx queries.

lint 0 errors / tsc 0 errors / 1878 tests passing / build OK
…onsive-design

Feat/dashboard responsive design
…classes

One conflict on the job row button in app/dashboard/page.tsx. Both
sides styled the same element, so the resolution keeps every class
either side contributed:

  responsive padding      px-3 sm:px-5 py-3 sm:py-4   (from Goldii-locks#304)
  press feedback          active:scale-[0.99]         (from main)
  focus ring              focus-visible:ring-2/-inset/-indigo-500 (this branch)

Transition widened to transition-all duration-200 (this branch's value)
rather than transition-colors -- the branch adds a focus ring, and
main's side adds a scale, neither of which transition-colors animates.

lint 0 errors / tsc 0 errors / 1903 tests passing / build OK
@godamongstmen897
godamongstmen897 merged commit f794522 into Goldii-locks:main Aug 31, 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.

Add premium interactive states to dashboard_list