Skip to content

feat: /payee dashboard (M3-11) - #31

Merged
YazarAyobami merged 1 commit into
mainfrom
feat/payee-dashboard
Oct 8, 2026
Merged

YazarAyobami merged 1 commit into
mainfrom
feat/payee-dashboard

Conversation

@YazarAyobami

Copy link
Copy Markdown
Contributor

What and why

/payee was still a PageStub. Builds it: a payee connects their wallet and sees every lock sent to them, filterable by status and by one specific payment. Was blocked on M2-12 (indexer list API, DONE) and the indexer actually existing; both are true now (M2-18 live on Railway).

Changes

  • lib/indexer/index.ts: new listLocks(payeeId, state?) and IndexedLock type/schema, matching the indexer's /locks contract. Unlike listPayees (server-only, absolute URL), this one also works from the browser, resolving to the same-origin /locks rewrite next.config.ts already has, since the dashboard only learns which payeeId to query after a wallet connects client-side.
  • app/payee/payee-logic.ts (+ tests): matchingPayeeIds (wallet address → every payeeId it's the payout for, matched against the already-fetched payee list, no extra round-trip), findByReference (a pasted claim link → the one matching lock, reusing parseClaimLink + computeRefHash, same as /claim/[id]), byNewest.
  • app/payee/usePayeeDashboard.ts, PayeeView.tsx, page.tsx: the page itself, following the house page.tsx → View.tsx → useX.ts → x-logic.ts split.
  • messages/en.json: new pages.payee.* keys; reuses pages.claim.state.* for lock-state labels rather than duplicating them.

Hard rules / invariants touched

  • Rule 5 (claim-link fragment never reaches a server): the reference-search feature parses a pasted claim link and computes ref_hash entirely in the browser; only the hash is ever compared, never sent anywhere.
  • Rule 3 (chain is truth): this page is list-only by design (locks, status, totals for browsing); the actual release/decline actions it links out to already read chain state on /claim/[id], untouched here.

Tests

pnpm lint, pnpm typecheck, pnpm test (103/103, 9 new), pnpm build all green.

Verified the data layer end-to-end against real testnet data: with the real indexer URL in .env.local, curl'd the app's own /locks?payee_id=... (the same-origin rewrite path the browser uses) and got back real, already-created locks in the exact shape listLocks's Zod schema expects. Visually confirmed the pre-connect page with Playwright: renders cleanly, no console errors.

Not independently verified: the post-wallet-connect render with real data. Driving a real wallet browser extension isn't automatable; this is the same limitation already accepted for /send's wallet step earlier this session. The rendering code reuses already-verified components (AmountDisplay, DateTimeDisplay) and an already-verified pattern (/claim/[id]'s isPayout/WalletBar), and the data it renders is unit-tested and confirmed real, but the actual connected-wallet screen hasn't been eyeballed.

Docs / ADR

None needed.

Roadmap

M3-11 → DONE. Phase 4 App: 11→12 DONE, 9→8 TODO (42%→46%). All rows: 41→42 DONE, 120→119 TODO (23%→24%). Changelog entry added.

Assumptions and open questions

If a human can try this with a real testnet wallet that happens to be one of the three fixture payees' payout address (NG: GDPUY733T3UNZWG4EQMEBHBDGKD33YSFPOI2RB4AIK2JMOENKEXWK7ZG, KE: GCLMHF7LAR34TSELDNEREYPTNE4K7MMESPS62WXE7ZDLPWIJUF3MC5QM, PH: GBXKOYQ4MJ6UJGQBFXVXOP7XL7SKKJTFTYJUSNREP5FW4IHXPMWY2WSX), that would close the one remaining verification gap. The KE payee already has several real locks in various states on testnet, which would be a good exercise of the status filter.

Connect a wallet; find every registered payee it's the payout address
for (matched against the already-fetched indexer payee list); list
each one's locks via a new listLocks(payeeId, state?) in
lib/indexer/index.ts, filterable by status and by one specific
payment (pasting a claim link reuses /claim/[id]'s own parseClaimLink
+ computeRefHash check, entirely client-side; the reference and salt
never leave the browser).

listLocks is callable from the browser too, unlike listPayees, since
the dashboard doesn't know which payeeId to ask for until a wallet
connects. Each row links to /claim/[id] for the actual release/decline
actions; nothing here moves money.
@YazarAyobami
YazarAyobami requested a review from a team as a code owner October 8, 2026 14:23
@YazarAyobami
YazarAyobami merged commit 4291642 into main Oct 8, 2026
4 checks 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.

2 participants