Skip to content

feat(frontend): rework the vesting dApp UI and restructure the app - #112

Merged
gabitoesmiapodo merged 11 commits into
mainfrom
feat/109
Aug 26, 2026
Merged

feat(frontend): rework the vesting dApp UI and restructure the app#112
gabitoesmiapodo merged 11 commits into
mainfrom
feat/109

Conversation

@gabitoesmiapodo

@gabitoesmiapodo gabitoesmiapodo commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes #109

The demo dApp was a sidebar-and-table shell that displayed inferred numbers and could not be driven without a mouse. This reworks the UI, sources grant activity from the ledger, and moves the source tree onto the layout rules the app now documents for itself.

Review guide

  • 120 files, but 23 are renames and 8 of those are byte-identical moves; GitHub marks them, skip them
  • Logic worth reading lives in src/backend, src/store and src/utils
  • VestingBackend.ts owns the new claim lineage walk; useVestingStore.ts owns the shared clock and the filters
  • src/components, src/pages and src/icons are markup and styling only
  • dapp/frontend/CLAUDE.md is new and states the layout rules the move follows — read it before questioning where a file landed
  • Root CLAUDE.md and canton-dappbooster/CLAUDE.md only re-point paths the move invalidated
  • The last commit is a text-only sweep: comments, prose and dev-facing strings, no identifiers or logic

Changes

  • Top-bar layout replaces the sidebar: navigation and ledger status move up, grants serve at the root
  • Each page carries its own header; the grant filter and the role lens become page-scoped dropdowns
  • Grant creation runs as a modal stepper built on a native dialog
  • Toasts stay until dismissed, can carry a link, and expire off one store-owned clock
  • Withdraw history reads off the ledger and is attributed by contract chain instead of inferred
  • The invented claim floor is gone and the status filters mean what their labels say
  • Outsized amounts abbreviate with the exact figure still reachable; amount fields drop the zero USD line
  • Adds error screens, a real loading state, icon actions and a Canton Coin mark
  • Waiting states announce, controls carry accessible names, headings run in order, each route sets its own title
  • Focus ring and brand text meet contrast, small controls meet the minimum target size, navigation survives a narrow viewport
  • Copy to clipboard no longer assumes a secure context
  • The claim lineage walk moves behind the backend seam, and the session grace timer stops rebuilding the backend
  • The source tree follows the app's own layout rules: pages replace features, utils replace lib, icons are promoted, single-consumer modules sit beside their consumer

Deviations

  • Issue Improve the demo app UI / UX #109 has an empty body, so the criteria below are derived from the change rather than mirrored
  • Grant activity now comes off the ledger: a UI issue, but no screen could be made honest while the numbers were inferred
  • Root and canton-dappbooster CLAUDE.md updated in the same branch, since the move invalidated paths they name
  • biome.json $schema pin corrected to 2.5.10 to match the installed Biome; unrelated to the issue
  • Carpincho is genericised to "a CIP-0103 wallet" across the docs, dev scripts and wallet-service strings, since no wallet ships in this repo

Acceptance criteria

  • Grants, grant detail, proposals and grant creation are reachable and usable from the top bar
  • Every figure on screen traces to ledger data, with no inferred or placeholder values
  • The app is operable with a keyboard alone, and every visible state reaches a screen reader
  • Light and dark themes meet WCAG AA contrast on text and focus rings
  • Lint, typecheck, build and tests pass at the repo root

Test plan

Automated tests

  1. Run pnpm install at the repo root
  2. Run pnpm -C dapp/frontend test
  3. Run pnpm lint, pnpm typecheck and pnpm build at the root
  4. Expect 125 tests across 11 files green, and no lint or type errors

Manual verification

  1. Check out this branch and run ./scripts/dev-stack.sh install
  2. Start Docker, then run ./scripts/dev-stack.sh up — containers, DAR, vesting bootstrap and the dApp dev server
  3. Open http://localhost:3012 and connect a browser wallet, or any CIP-0103 compatible wallet
  4. Reach grants, a grant detail, proposals and grant creation using only Tab, Enter and Escape

Breaking changes

None.

Checklist

  • Self-reviewed my own diff
  • Tests added or updated
  • Docs updated (if applicable)
  • No unrelated changes bundled in

Screenshots

01-wallet.mp4
02-connect.mp4
03-tour.mp4
04-create.mp4
05-second.mp4
06-accept.mp4
07-grants.mp4
08-claim.mp4
09-cancel.mp4
10-wrap.mp4

Replace the table-and-card dashboard with a top-bar layout: navigation and
the ledger status move out of the sidebar, every page carries its own
header, grants are served at the root, and the grant filter and the role
lens become dropdowns scoped to the page that uses them. Grant creation
moves into a modal stepper built on a native dialog, and a toast now stays
until dismissed and can carry a link.

Restructure the source tree to match the layout rules the app now spells
out in its own CLAUDE.md. features becomes pages, lib becomes utils, the
icon collection is promoted, dialog components drop their Dialog suffix,
and anything with a single consumer moves beside it.
Withdraw history comes off the ledger and is attributed by contract chain
instead of being inferred, and the invented claim floor is gone. Outsized
amounts are abbreviated with the exact figure still reachable, amount
fields no longer quote a zero USD value, and the status filters now mean
what their labels say.

The app also gains its own error screens, a real loading state, icon
actions and a Canton Coin mark. The session grace timer stops rebuilding
the backend, and toast expiry runs off one clock owned by the store.
…seam

The claim lineage walk is ledger work, not page work, so it moves behind
the backend seam. Shared components take over the styling and the sums
each of them owns, rules that had been written down twice collapse into
one, and a dialog opens on mount instead of through a caller-managed flag
while the button owns its own pending state.

The token mark stays static until there is a second token to pick between,
and the empty grants state says the one thing it knows.
Every state a sighted user can see now reaches assistive tech: waiting
states announce, the milestone fields and the tooltip badge carry names,
headings run in order, and each route sets its own title. The focus ring
and the brand text meet contrast, the small controls meet the minimum
target size, and the navigation stays reachable on a narrow viewport.

Copy to clipboard no longer assumes a secure context, and the frontend
CLAUDE.md records why the brand hues needed readable companions.
@gabitoesmiapodo gabitoesmiapodo self-assigned this Aug 26, 2026
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
demo.canton-dappbooster Ready Ready Preview Aug 26, 2026 6:30pm
docs-canton-dappbooster Ready Ready Preview Aug 26, 2026 6:30pm
docs.canton-dappbooster Ready Ready Preview Aug 26, 2026 6:30pm

Request Review

No wallet ships in this monorepo, so the docs, dev scripts and wallet-service
strings no longer read as if one does. Carpincho survives in the root
CLAUDE.md alone, named as the wallet this stack was developed against rather
than as a component of it.
A participant rejects a package id in an ACS or update filter with
INVALID_FIELD and requires the package-name reference, while a command
still carries the resolved id. The two forms are not interchangeable, so
the filter builder now owns the name form and takes an entity name.

Verified against both a local participant and a hosted one.
Read by the project whose root directory is dapp/frontend, so it never
collides with the root config the reference site uses.

The build command runs from the workspace root because a production
build resolves canton-connect and canton-dappbooster to their dist,
which must exist before vite starts.
Its build shells out to dpm, which no build runner has, so the frontend
build now excludes it the same way the PR gate does.
The bootstrap wrote a file the app fetched, so the two drifted apart on
every run and a deployed build had no way to get one at all. The app now
finds the operator among the connected user's ledger rights and reads its
factory back for the package id and the disclosure blob.

Pointing the wallet at another participant is now the whole of switching
networks, and the bootstrap writes nothing.

The deployment needs a session to read through, so it resolves after
connect; a disconnected visitor gets each page's own connect card rather
than a config error.
@gabitoesmiapodo
gabitoesmiapodo deleted the feat/109 branch August 26, 2026 18:36
@github-project-automation github-project-automation Bot moved this from In review to Done in Canton - dAppBooster (#390) Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Improve the demo app UI / UX

1 participant