Skip to content

Feat/payments redesign 4 activity - #2193

Closed
arseniy-nikitochkin wants to merge 51 commits into
feat/payments-redesign-4a-transactionsfrom
feat/payments-redesign-4-activity
Closed

arseniy-nikitochkin wants to merge 51 commits into
feat/payments-redesign-4a-transactionsfrom
feat/payments-redesign-4-activity

Conversation

@arseniy-nikitochkin

Copy link
Copy Markdown
Collaborator

No description provided.

arseniy-nikitochkin and others added 30 commits September 29, 2026 22:43
…s and Schedules

Moves the overview, Transactions (with a page per transaction and CSV export), Requests (with
New request and a page per request), Schedules and the API playground layout to the refresh
design. Every Payments route is now redesigned, so the per-route previous-design switch in the
header and theme scope gives way to the NEW DESIGN flag alone.

Files main has keep main's code at their paths. A redesigned file gets a .redesign sibling
with the new version; a route's page.tsx or loading.tsx keeps main's code and picks its
.redesign sibling on NEW DESIGN. With the flag off every page runs main's code.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

# Conflicts:
#	apps/sdp-web/src/components/dashboard-header.tsx
#	apps/sdp-web/src/lib/theme-scope-routes.ts
…tivity flag

The Payments overview and its API playground, Transactions, Requests and
Schedules become the activity design module, a catch-all for the Payments
routes Contacts and Pay & Deposit don't cover. Their routes, loading
skeletons, theme scope, header and the Schedules sidebar label follow
new-design-activity (SDP_FLAG_NEW_DESIGN_ACTIVITY, on by default), and only
while NEW DESIGN is on.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…mmand center e2e

A project with no transfers shows the empty state, whose one way on is "Open
Transactions"; "View all transactions" only follows a list with rows. CI's
fresh project has none, so the assertion now accepts either link to
Transactions inside the activity section.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The .redesign sibling differed from main's screen only in importing walletHref from the
redesigned hrefs module, where it is the same function. React Doctor flagged the duplicated
JSX; the ramp step contents and the test now use main's screen again, which leaves the ramp
files exactly as PR #2169 has them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
React Doctor flagged the run history's and the Requests list's header rows as one JSX tree
written twice. PaymentsTableHeader renders the row from a column list in the design's 13px
regular type, and both tables use it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The busy flag was cleared only on the error response, so a request that rejected left the
Create button disabled for good (React Doctor: loading flag reset outside finally). The reset
now runs in a finally block unless the link was made, when the page stays busy on its way to
the request so a second press cannot make a second link.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…est by id

The list loaded up to 500 requests on every visit, and listing reconciles each open request
on chain, so a routine load could run hundreds of checks. The detail page looked only as far
as that cap, so an older request's URL redirected to the list. The list now reads one page as
the URL names it (page, size, status), with a "from-to of total" summary and a page past the
end landing on the last; search runs over the loaded page. The detail lookup pages until it
finds the request or the pages run out.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…acks it

Changing the funding wallet kept the old token even when the new wallet did not hold it; the
picker showed a placeholder but Save sent the pair, leaving a schedule that cannot collect.
Switching wallets now keeps the token only if the new wallet offers it, Save asks for a token
otherwise, and returning to the schedule's own wallet restores its token.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… e2e

The Schedules row's link is its "<amount> to <contact>" title, not a bare amount, and the
detail page is headed by that title with Pays/To/From/Repeats/Next run/Schedule ID lines in
place of the legacy labels. The test timed out clicking the old amount text.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

# Conflicts:
#	apps/sdp-web/src/app/dashboard/payments/payments-route-skeletons.redesign.tsx
…e Requests list

Paging the Requests list on the server left search filtering only the loaded page, and the
API's status filter reads the stored status, so a request paid since the last read was missed
by Paid and shown as paid under Awaiting payment. Search now lives in the URL and the server
reads up to 500 requests to match and page it, with a note when that cap is reached. Awaiting
payment and Paid read the open requests first; listing settles any that has been paid, so the
server's filter then matches the status the list shows. Other views keep one-page reads.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ps none

Listing settles open requests as it reads them, so paging status=awaiting_payment
moved every later offset up as earlier rows left the filter, and later pages
skipped rows. The scan now reads all statuses newest first, whose order only a
new request moves: repeated rows are dropped by id, and a grown total reads on.
Awaiting payment and Paid are matched from that read; the 500 cap stays.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eline

The i18n guide forbids new baseline entries. Neither was copy: "allow" is the
policy API's enum value and "activity" a design-module id, so they move into
named constants and the baseline matches the base branch again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…arch

A search under a status read only the newest 500 requests of every status, so a request
within its status's newest 500 but outside that window was missed. Past the cap, a status
search now also reads that status's newest requests by the API's filter (Paid reads the open
ones too, which listing settles when paid), drops the rows already read, and keeps the
unfiltered window first so its reconciled statuses still decide the match. The cap note shows
only when a status read was itself capped.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n finally

The submit flag now always clears in finally, and a separate link-created flag keeps the
form busy on its way to the request, so a second press still cannot make a second link.
Tests cover the form staying busy after success and freeing when the request throws.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eces

Pull the URL builder, status filter menu, pager and row labels out of
PaymentRequestsWorkspace to bring its complexity under React Doctor's limit. Behaviour is
unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ip no request

Reading a page settles its paid requests, which leave the stored Awaiting
payment set and pull every later row up a page. Read in parallel, a later
page could then miss requests past the unfiltered read's cap. A one-row probe
now reads the total, and the pages are read one at a time from the last to
the first, so a request leaving only repeats a row already read. Paid,
canceled and expired only gain requests, so their pages are read one at a
time from the first. The unfiltered scan stays parallel. Repeated rows keep
their first place and their freshest copy.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
arseniy-nikitochkin and others added 21 commits October 1, 2026 16:50
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… shared pieces

Switch New schedule's Source wallet and amount/token row to SourceWalletField and
AmountFields from ramps/components/payment-form-fields.tsx. Its hints, wallet
total and decimal limit pass through as props and children; classes and DOM are
unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…y request

The API lists requests only by page and stored status, so a search could only cover the
requests already read. The box is disabled and a search in the URL is ignored; the detail
lookup notes that it pages through the list until the API reads a request by id.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every page now comes from the API's own page, size and status. Under
Awaiting payment, rows the API reconciles to paid are left out and the
total drops by as many. The 500-request scan, its search matching and
the "search covers the newest requests" note are removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…l other pages are read

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nt without a count

The search box is back on: a search lives in the URL, as before, and the list matches it against
the page it has read, by amount, token, payer, destination and reference, carrying it along as the
user pages on. Under Awaiting payment the API's total counts by stored status, so the pager names
the page alone and offers the next while the API has one, instead of a count that could run high.
Other statuses keep their exact range.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…sts-page.data.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Measured against the design at 1536px: the balance label is 13px and the amount 6px under it;
the token rows carry a 36px mark beside a 16px name over a 13px amount, 16px apart, with the
USD value at 14px; the census sits 40px under them with 16px counts over 13px words; the
Activity rows are 61px, ruled beneath, a 14px line over a 13px line with a 13px status, 12px
from the heading row.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…esign-4-activity

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… the mockup measures

The transaction page's Provider and Proof headings sat 64px under the last row of the section
above; the design draws 54. The 32px between blocks stays, the section's own top space drops
from 32 to 22.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s-redesign-4-activity

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 2, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
sdp-docs Ready Ready Preview Oct 2, 2026 11:13pm UTC
sdp-web Ready Ready Preview Oct 2, 2026 11:13pm UTC

Request Review

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit 437e4af.

@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

[Medium risk] Redesigned payments dashboard UI with feature flag routing.

The PR should not merge until schedule editing and Awaiting payment pagination preserve access to valid records.

Findings

  1. P1 Issued tokens disappear during editing ▶
  2. P1 Pagination skips awaiting requests ▶
  3. P2 Copy reports false success ▶

Summary

The PR adds flagged Payments activity pages, including a redesigned command center, payment-request list and detail flow, recurring-schedule flow, and consolidated API playground.

  • Two workflow defects need attention: issued-token schedule edits can be blocked, and reconciliation can cause the Awaiting payment list to skip requests.
  • The Requests table can also report a clipboard copy that failed.

Reviews (1) · Last reviewed commit: "Merge branch 'feat/payments-redesign-4a-..."


const changeWallet = (sourceCustodyWalletId: string) => {
const nextWallet = liveWallets.find((entry) => entry.id === sourceCustodyWalletId);
const nextOptions = recurringPaymentAssetOptions(nextWallet ?? null, {}, t);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Issued tokens disappear during editing

When an active schedule uses an issued token identified by its mint, this picker receives no issued-token symbols. Switching to another wallet that holds the same token can therefore clear the token selection and block Save changes, even though the wallet can fund the schedule. Pass the issued-token symbols already loaded by the detail route into the edit form.

Knowledge Base Used: Dashboard product workflows

Comment on lines +219 to +224
const result = await fetchPaymentRequests(request, {
page,
pageSize,
...(status ? { status } : {}),
});
const hasNextPage = result.ok && page * pageSize < result.total;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Pagination skips awaiting requests

If reading an Awaiting payment page reconciles a request as paid, that request leaves the status-filtered result set. The next page still uses the original offset and can skip an awaiting request. For example, with 26 requests and a page size of 25, one reconciled payment can leave the second page empty while the remaining request is never shown.

Knowledge Base Used: Dashboard product workflows

Comment on lines +437 to +440
const copyLink = (request: PaymentRequest) => {
void navigator.clipboard.writeText(`${window.location.origin}/pay/${request.publicToken}`);
toast.success(t("DashboardPayments.requests.paymentLinkCopied"));
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Copy reports false success

The table shows “Payment link copied” without waiting for the clipboard write. If permission is denied or the write fails, the user gets a success message despite having no link to paste. Handle a failed write before reporting success.

This branch was successfully deployed

2 active deployments
Preview – sdp-web — 437e4afa Deployed Oct 2, 2026 by vercel[bot]
Preview – sdp-docs — 437e4afa Deployed Oct 2, 2026 by vercel[bot]
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.

1 participant