Skip to content

004-04: Subscriptions UI (Plans → Wallet Sign → Status) - #38

Merged
jaswinder6991 merged 1 commit into
mainfrom
004-04-subscriptions-ui
Jul 14, 2026
Merged

jaswinder6991 merged 1 commit into
mainfrom
004-04-subscriptions-ui

Conversation

@jaswinder6991

Copy link
Copy Markdown
Contributor

Closes #31. Part of Epic 004 (#27). Depends on #36 + #37 (merged).

What

New auth-gated /subscriptions route (TanStack file-based, patterns copied from payments.tsx — react-query + useApiClient(), semantic Tailwind, kebab-case files):

  • Provider cards from subscriptionProviders; plan cards from subscriptionPlans showing period, NEAR range (or fixed card price), and a stake-amount input for range plans — validated against min/max with BigInt yocto math before the wallet ever opens.
  • Subscribe + lifecycle dispatch on SubscriptionAction.kind — the single switch the epic's action union was designed for:
    • wallet_intent → signs via the better-near-auth session wallet: authClient.near.client.transaction(account) chaining one near-kit functionCall per intent action (multi-action, single receiver — so storage_deposit + lock land in one transaction), then polls subscriptionGet (3s / 2min cap) until the chain reflects the target state. Network mismatch (mainnet wallet vs testnet intent) fails with a clear error before signing.
    • redirect → hosted checkout navigation (Stripe); ?checkout=success return shows a toast.
    • executed → the returned subscription lands straight in the query cache.
  • Status panel per plan: locked amount, period end, distinct rendering for cancel_at_period_end and pending_unstake (with the epoch-settlement hint), cancel/resume actions, and a "switch here from X" change-plan action when actively subscribed to a sibling plan.
  • Empty state for zero registered subscription providers.

The polling helper is a generic pollUntil(fetcher, predicate, {intervalMs, timeoutMs}) in ui/src/lib/poll.ts — the reusable pattern for any pull-verified provider. Yocto↔NEAR conversion is string/BigInt-safe (ui/src/lib/near-amount.ts), no float math on amounts.

payerRef is never sent for NEAR-signed-in users — the API defaults it server-side from the session wallet (context.walletAddress, #37). Email is the explicit fallback for hosted providers.

Verified

  • cd ui && bun run typecheck green (route tree regenerated); biome clean on the three new files; zero changes to existing files — payments flow untouched by construction.
  • Full-stack smoke against bos dev with all three plugins registered: GET /api/subscriptions/providers returns only stake2pay (discovery correctly excludes one-time-only providers), plans render from the live HoS testnet catalog, and POST /api/subscriptions/stake2pay returns the signable two-action intent (storage_deposit + lock with duration_ns: null).

Scope note (per epic discussion)

v1 targets in-page signing through the better-near-auth wallet connection. Redirect-style wallets (page navigation mid-flow) are an explicit follow-up. The one remaining manual verification — signing a real lock on testnet — needs a funded testnet wallet in a browser session; the flow up to the wallet call is exercised end-to-end above.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FdKukDnRTrshKqkQ8JXwVj

…004-04)

New auth-gated /subscriptions route following the payments.tsx patterns:
provider cards from subscriptionProviders, plan cards with period, NEAR
range and validated stake-amount input, and a status panel per plan.

Subscribe and lifecycle ops dispatch on SubscriptionAction.kind:
- wallet_intent: chained near-kit functionCall actions signed through the
  better-near-auth session wallet (single receiver, multi-action), then a
  generic pollUntil helper (3s interval, 2min cap) waits for chain state
- redirect: hosted checkout navigation (Stripe)
- executed: query cache updated from the returned subscription

Range validation blocks out-of-range stakes before the wallet opens;
pending_unstake and cancel_at_period_end render distinctly; empty state
covers zero registered providers. payerRef defaults server-side from the
session NEAR account; email is the fallback for hosted providers.

Closes #31

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdKukDnRTrshKqkQ8JXwVj
@jaswinder6991
jaswinder6991 merged commit 17a27cd into main Jul 14, 2026
1 check passed
@jaswinder6991
jaswinder6991 deleted the 004-04-subscriptions-ui branch July 14, 2026 15:32
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.

004-04: Subscriptions UI (Plans → Wallet Sign → Status)

1 participant