Skip to content

feat(components): extract WalletConnectionGuard shared component (#4)#98

Closed
devcarole wants to merge 3 commits intoFundable-Protocol:mainfrom
devcarole:feature/4-wallet-connection-guard
Closed

feat(components): extract WalletConnectionGuard shared component (#4)#98
devcarole wants to merge 3 commits intoFundable-Protocol:mainfrom
devcarole:feature/4-wallet-connection-guard

Conversation

@devcarole
Copy link
Copy Markdown

@devcarole devcarole commented Mar 29, 2026

Summary

Closes #4

This PR adds wallet connection guards to the Distribution and Payment Stream pages by extracting the existing pattern from the Offramp page into a shared WalletConnectionGuard component.

Changes

  • ✅ Extract WalletConnectionGuard shared component from ProtectedRoute pattern
  • ✅ Update offramp page to use WalletConnectionGuard
  • ✅ Add wallet guard to distribution page wrapping form content
  • ✅ Add wallet guard to payment-stream page wrapping CreatePaymentStream component

Behavior

  • Users cannot access forms without connecting wallet first
  • Consistent "Connect Wallet" prompt across all three pages
  • Same visual styling and connection flow as existing offramp page

Summary by CodeRabbit

  • New Features

    • Wallet connection gate added to Distribution, Offramp, and Payment Stream pages with contextual messaging and a prominent "Connect Wallet" prompt when disconnected.
  • Refactor

    • History view simplified to a single table layout (removed mobile card/list view and per-row expanders) and streamlined top controls for a cleaner, more consistent experience.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

Added a new WalletConnectionGuard component and integrated it into distribution, offramp, and payment-stream pages so page content renders only when a Stellar wallet is connected; offramp replaces its ProtectedRoute with the guard, distribution/payment-stream render their content inside the guard.

Changes

Cohort / File(s) Summary
New Wallet Guard
apps/web/src/components/modules/wallet/WalletConnectionGuard.tsx
New client React component that reads wallet state via useWallet(). Renders a centered "Connect Wallet" prompt (with contextLabel) when no address; otherwise renders children. Exports both named and default.
Pages — integration
apps/web/src/app/(overview)/distribution/page.tsx, apps/web/src/app/(overview)/payment-stream/page.tsx
Wrapped main page content (distribution form, create-payment-stream UI) inside WalletConnectionGuard with a contextLabel; kept outer ProtectedRoute in distribution/payment-stream.
Pages — offramp change
apps/web/src/app/(overview)/offramp/page.tsx
Replaced ProtectedRoute wrapper with WalletConnectionGuard (provides contextLabel) around the off‑ramp page content; internal page logic unchanged.
History table simplification
apps/web/src/components/modules/history/HistoryTable.tsx
Removed mobile card list and per-row expansion state/logic, deleted related imports (clipboard/toasts/icons/date formatting/actions). Component now renders only the table layout and simplified controls.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant Page
participant WalletGuard
participant WalletProvider
participant ProtectedRoute
User->>Page: navigate to Distribution/Offramp/PaymentStream
Page->>ProtectedRoute: route-level auth check
ProtectedRoute->>WalletGuard: render guarded content
WalletGuard->>WalletProvider: useWallet() (address, openModal)
alt address falsy
WalletGuard->>User: show "Connect Wallet" prompt
User->>WalletGuard: clicks "Connect Wallet"
WalletGuard->>WalletProvider: openModal()
WalletProvider->>User: display wallet modal / connect flow
WalletProvider-->>WalletGuard: connection established (address)
WalletGuard->>Page: render children (page content)
else address truthy
WalletGuard->>Page: immediately render children
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through routes to guard each gate,

Wallet closed — I gently pause your fate.
Connect, sign, then onward you may go,
No lost forms in the meadow's flow. ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive The HistoryTable.tsx changes (removal of mobile UI, row expansion, and unused imports) appear unrelated to the wallet guard feature specified in issue #4. Clarify whether the HistoryTable.tsx refactoring is intentional or should be separated into a distinct pull request focused on simplifying table layout.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: extracting and introducing the WalletConnectionGuard shared component as the primary feature of this pull request.
Linked Issues check ✅ Passed The pull request successfully addresses all primary objectives from issue #4: shows wallet connection guard on Distribution and Payment Stream pages, uses consistent visual pattern and connection flow, and extracts the shared WalletConnectionGuard component as recommended.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feature/4-wallet-connection-guard

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@drips-wave
Copy link
Copy Markdown

drips-wave bot commented Mar 29, 2026

@devcarole 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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/web/src/components/modules/wallet/WalletConnectionGuard.tsx (1)

7-7: Remove unused import.

cn is imported but not used anywhere in this component.

🧹 Proposed fix
 import { Button } from "@/components/ui/button";
-import { cn } from "@/lib/utils";
 import { useWallet } from "@/providers/StellarWalletProvider";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/modules/wallet/WalletConnectionGuard.tsx` at line 7,
Remove the unused import 'cn' from the top of the WalletConnectionGuard
component file; locate the import statement "import { cn } from '@/lib/utils';"
in WalletConnectionGuard.tsx and delete it so there are no unused imports
remaining.
apps/web/src/app/(overview)/payment-stream/page.tsx (1)

24-33: Redundant guards and potential inconsistency in child placement.

Similar to the distribution page, ProtectedRoute (line 24) and WalletConnectionGuard (line 27) both check wallet connection status, making the inner guard redundant when disconnected.

Additionally, StreamsHistory (line 31) is placed outside WalletConnectionGuard but inside ProtectedRoute. This creates ambiguity:

  • Currently, ProtectedRoute blocks everything when disconnected, so StreamsHistory is hidden.
  • If ProtectedRoute is removed (to use WalletConnectionGuard consistently), StreamsHistory would render even when the wallet is disconnected.

Clarify the intended behavior:

  1. If StreamsHistory should be hidden when disconnected, wrap it inside WalletConnectionGuard as well.
  2. If StreamsHistory can be viewed without a wallet, remove ProtectedRoute and keep the current structure.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/app/`(overview)/payment-stream/page.tsx around lines 24 - 33,
ProtectedRoute and WalletConnectionGuard are redundant and StreamsHistory sits
outside WalletConnectionGuard causing ambiguous visibility; decide the intended
UX and update the JSX accordingly: either (A) keep ProtectedRoute but move
StreamsHistory inside WalletConnectionGuard so both CreatePaymentStream and
StreamsHistory are only shown when the wallet is connected (wrap
StreamsHistory/Suspense/StreamsTableSkeleton with WalletConnectionGuard), or (B)
remove ProtectedRoute entirely so StreamsHistory can render without a wallet
while keeping CreatePaymentStream inside WalletConnectionGuard; adjust the
component tree around ProtectedRoute, WalletConnectionGuard,
CreatePaymentStream, StreamsHistory, and StreamsTableSkeleton to reflect the
chosen behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/app/`(overview)/distribution/page.tsx:
- Around line 387-388: The page nests two components that both guard on
useWallet().address—ProtectedRoute and WalletConnectionGuard—making one
redundant; remove the extra wrapper so only one guard remains. Decide which to
keep: if you want the customizable title/description/actionLabel/container/card
classes, keep ProtectedRoute and remove the WalletConnectionGuard wrapper around
the page content; if you prefer WalletConnectionGuard semantics, remove
ProtectedRoute and re-add any needed metadata/props
(title/description/actionLabel/container/card classes) to WalletConnectionGuard
or the page layout. Make the change by editing the JSX that currently wraps the
page (references: ProtectedRoute, WalletConnectionGuard, and
useWallet().address) so only the chosen guard remains.

In `@apps/web/src/components/modules/wallet/WalletConnectionGuard.tsx`:
- Around line 19-21: The guard currently shows the "Connect Wallet" prompt
whenever address is falsy, causing a hydration flash because address is restored
asynchronously; update WalletConnectionGuard (which uses useWallet and currently
reads address and openModal) to also read connectionStatus from useWallet and if
connectionStatus === "idle" and address is null return null (or a loading
skeleton) instead of the connect UI, and only render the connect prompt when
connectionStatus !== "idle" && !address; this mirrors the NetworkSwitcher
pattern and ensures StellarWalletProvider's initial restore phase doesn't
trigger the connect prompt.

---

Nitpick comments:
In `@apps/web/src/app/`(overview)/payment-stream/page.tsx:
- Around line 24-33: ProtectedRoute and WalletConnectionGuard are redundant and
StreamsHistory sits outside WalletConnectionGuard causing ambiguous visibility;
decide the intended UX and update the JSX accordingly: either (A) keep
ProtectedRoute but move StreamsHistory inside WalletConnectionGuard so both
CreatePaymentStream and StreamsHistory are only shown when the wallet is
connected (wrap StreamsHistory/Suspense/StreamsTableSkeleton with
WalletConnectionGuard), or (B) remove ProtectedRoute entirely so StreamsHistory
can render without a wallet while keeping CreatePaymentStream inside
WalletConnectionGuard; adjust the component tree around ProtectedRoute,
WalletConnectionGuard, CreatePaymentStream, StreamsHistory, and
StreamsTableSkeleton to reflect the chosen behavior.

In `@apps/web/src/components/modules/wallet/WalletConnectionGuard.tsx`:
- Line 7: Remove the unused import 'cn' from the top of the
WalletConnectionGuard component file; locate the import statement "import { cn }
from '@/lib/utils';" in WalletConnectionGuard.tsx and delete it so there are no
unused imports remaining.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76d7f729-35f7-4b86-b97c-46200b06493f

📥 Commits

Reviewing files that changed from the base of the PR and between f63af83 and 19d72a4.

📒 Files selected for processing (4)
  • apps/web/src/app/(overview)/distribution/page.tsx
  • apps/web/src/app/(overview)/offramp/page.tsx
  • apps/web/src/app/(overview)/payment-stream/page.tsx
  • apps/web/src/components/modules/wallet/WalletConnectionGuard.tsx

Comment on lines 387 to +388
<ProtectedRoute description="Connect your Stellar wallet to create token distributions.">
<div
ref={pageRef}
className="h-screen mt-10 bg-black text-white overflow-y-auto scroll-smooth distribution-scrollbar"
>
<WalletConnectionGuard contextLabel="Connect your Stellar wallet to create token distributions.">
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.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check ProtectedRoute implementation for additional functionality

ast-grep --pattern $'export default function ProtectedRoute($$$) {
  $$$
}'

# Also check the full file for any additional logic
fd -t f 'ProtectedRoute.tsx' --exec cat {}

Repository: Fundable-Protocol/stellar_client_os

Length of output: 4286


🏁 Script executed:

fd -type f -name '*WalletConnectionGuard*' --exec cat {}

Repository: Fundable-Protocol/stellar_client_os

Length of output: 249


🏁 Script executed:

fd -t f 'WalletConnectionGuard' --exec cat {}

Repository: Fundable-Protocol/stellar_client_os

Length of output: 1869


Remove redundant wallet connection guard.

Both ProtectedRoute (line 387) and WalletConnectionGuard (line 388) check useWallet().address and render a wallet connection prompt when disconnected. Since ProtectedRoute wraps WalletConnectionGuard, it will always intercept first, making WalletConnectionGuard unreachable when the wallet is disconnected.

Remove one of the wrappers. If migrating to WalletConnectionGuard, remove ProtectedRoute. If keeping ProtectedRoute for its customization options (title, description, actionLabel, container/card classes), remove WalletConnectionGuard from this page.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/app/`(overview)/distribution/page.tsx around lines 387 - 388,
The page nests two components that both guard on
useWallet().address—ProtectedRoute and WalletConnectionGuard—making one
redundant; remove the extra wrapper so only one guard remains. Decide which to
keep: if you want the customizable title/description/actionLabel/container/card
classes, keep ProtectedRoute and remove the WalletConnectionGuard wrapper around
the page content; if you prefer WalletConnectionGuard semantics, remove
ProtectedRoute and re-add any needed metadata/props
(title/description/actionLabel/container/card classes) to WalletConnectionGuard
or the page layout. Make the change by editing the JSX that currently wraps the
page (references: ProtectedRoute, WalletConnectionGuard, and
useWallet().address) so only the chosen guard remains.

@devcarole devcarole marked this pull request as draft March 29, 2026 15:30
@devcarole devcarole marked this pull request as ready for review March 29, 2026 15:38
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/components/modules/history/HistoryTable.tsx`:
- Around line 94-95: The mobile card layout was removed from HistoryTable,
causing poor small-screen UX; restore responsive rendering so small screens show
the card-based stacked view and larger screens render the Table. Update the
HistoryTable component to conditionally render the previous card-style markup
(or a Card/List component) for screens below the md breakpoint and keep <Table>
for md and up—use existing Tailwind responsive classes or a small media-query
hook (e.g., useMediaQuery) to switch views, and ensure the container classes
around the card (rounded-xl border bg-zinc-900/50) are applied to the mobile
card variant so the mobile styling/spacing is preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 231d40e5-2981-4244-bff2-1129d85287b3

📥 Commits

Reviewing files that changed from the base of the PR and between 19d72a4 and e051f46.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • apps/web/src/components/modules/history/HistoryTable.tsx

Comment on lines +94 to +95
<div className="rounded-xl border border-zinc-800 bg-zinc-900/50 overflow-hidden">
<Table>
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.

⚠️ Potential issue | 🟠 Major

Mobile UX regression: card-based layout removed.

The mobile-specific card view has been removed, leaving only the table layout. Tables typically provide a poor experience on small screens due to horizontal scrolling and cramped content. Consider preserving mobile-responsive behavior or confirming this regression is acceptable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/modules/history/HistoryTable.tsx` around lines 94 -
95, The mobile card layout was removed from HistoryTable, causing poor
small-screen UX; restore responsive rendering so small screens show the
card-based stacked view and larger screens render the Table. Update the
HistoryTable component to conditionally render the previous card-style markup
(or a Card/List component) for screens below the md breakpoint and keep <Table>
for md and up—use existing Tailwind responsive classes or a small media-query
hook (e.g., useMediaQuery) to switch views, and ensure the container classes
around the card (rounded-xl border bg-zinc-900/50) are applied to the mobile
card variant so the mobile styling/spacing is preserved.

@devcarole devcarole marked this pull request as draft March 29, 2026 15:49
@pragmaticAweds
Copy link
Copy Markdown
Contributor

Hi @devcarole

Please resolve this merge conflicts.

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 wallet connection guard to Distribution and Payment Stream pages

2 participants