Skip to content

feat(investor): WalletGate for my-investments + fix investments 401#99

Closed
andreMD287 wants to merge 1 commit intoTrustless-Work:developfrom
andreMD287:develop
Closed

feat(investor): WalletGate for my-investments + fix investments 401#99
andreMD287 wants to merge 1 commit intoTrustless-Work:developfrom
andreMD287:develop

Conversation

@andreMD287
Copy link
Copy Markdown
Contributor

@andreMD287 andreMD287 commented Mar 14, 2026

Summary

  • WalletGate: New component that protects /my-investments when the wallet is not connected. Shows a Card (instead of Dialog to avoid z-index conflicts with the Stellar wallet kit modal) with "Conectar tu billetera" and Connect/Volver buttons.
  • my-investments page: Wraps InvestmentsView with WalletGate. When not connected, only the connect card is shown. When connected, the full investments view is shown.
  • InvestmentsView: When the investments API fails (401 or endpoint missing), shows the normal empty state ("No Investments Yet") instead of the error message, since there is no backend for per-wallet investments yet.

Files changed

  • apps/investor-tokenization/src/components/shared/WalletGate.tsx — New component
  • apps/investor-tokenization/src/app/my-investments/page.tsx — Uses WalletGate + InvestmentsView
  • apps/investor-tokenization/src/features/investments/InvestmentsView.tsx — Treat API error as empty list

Test plan

  • Visit /my-investments without wallet → Connect card is shown
  • Click "Conectar Billetera" → Wallet kit modal opens and is usable
  • Connect wallet → Investments view is shown
  • With wallet connected → "No Investments Yet" is shown (no 401 error)

Summary by CodeRabbit

  • New Features
    • Investments page now requires users to connect their wallet before viewing investment details and portfolio information
  • Bug Fixes
    • Improved handling of data loading errors in the investments view, displaying an empty state instead of error messages when data fails to load

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 14, 2026

@andreMD287 is attempting to deploy a commit to the Trustless Work Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 14, 2026

📝 Walkthrough

Walkthrough

This PR refactors the my-investments page to replace embedded investments logic with a simplified component composition pattern. A new WalletGate component is introduced to protect content behind wallet connectivity requirements, while InvestmentsView error handling is simplified to silently show empty state instead of error UI.

Changes

Cohort / File(s) Summary
Page Composition Refactor
apps/investor-tokenization/src/app/my-investments/page.tsx
Removed 130+ lines of local state, data fetching, and business logic; replaced with composition of InvestmentsView and WalletGate components, maintaining the same export signature.
Wallet Protection
apps/investor-tokenization/src/components/shared/WalletGate.tsx
New client-side component that guards content behind wallet connection; renders children if wallet is connected, otherwise displays a Card-based prompt to connect wallet or navigate back.
Error Handling Simplification
apps/investor-tokenization/src/features/investments/InvestmentsView.tsx
Removed explicit error UI rendering; introduced investmentList derived value that returns empty list on error instead of displaying error message, streamlining error handling for parent composition.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • armandocodecr
  • zkCaleb-dev
  • JoelVR17

Poem

🐰 A wallet's gate, so neat and clean,
Guards the investments we've yet seen,
No errors loud, just silent grace—
An empty list saves the day with pace!
Component blocks in harmony blend,
Protecting riches from end to end. 🪙

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: introducing WalletGate component for the my-investments route and fixing 401 error handling in investments view.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Copy link
Copy Markdown

@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

🧹 Nitpick comments (3)
apps/investor-tokenization/src/app/my-investments/page.tsx (1)

8-10: Optional cleanup: avoid double wallet-gating on this route.

With WalletGate wrapping InvestmentsView, the no-wallet branch inside InvestmentsView is redundant for this page. Consolidating to one gate reduces UX drift between two connect prompts.

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

In `@apps/investor-tokenization/src/app/my-investments/page.tsx` around lines 8 -
10, This route currently double-applies wallet gating: the page wraps
<InvestmentsView /> with WalletGate while InvestmentsView itself contains a
no-wallet branch; pick one gating location and remove the redundant check.
Either remove the outer WalletGate wrapper in the page and let InvestmentsView
control its own connect UI, or keep the outer WalletGate and delete the
no-wallet branch inside InvestmentsView (remove its conditional rendering or
early-return that renders the connect prompt). Update references to WalletGate
and InvestmentsView accordingly so only a single wallet gate remains.
apps/investor-tokenization/src/components/shared/WalletGate.tsx (2)

5-6: Use the repository’s shared UI package import path.

These imports use @tokenization/ui/*, but the project guideline requires shared UI components to be imported from @repo/ui.

Suggested import update
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@tokenization/ui/card";
-import { Button } from "@tokenization/ui/button";
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@repo/ui/card";
+import { Button } from "@repo/ui/button";

As per coding guidelines "Import shared UI components from @repo/ui package (button, card, etc.)".

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

In `@apps/investor-tokenization/src/components/shared/WalletGate.tsx` around lines
5 - 6, Replace the component imports that reference `@tokenization/ui/card` and
`@tokenization/ui/button` so they come from the shared package `@repo/ui`;
update the import line(s) in WalletGate.tsx to import Card, CardContent,
CardDescription, CardHeader, CardTitle and Button from `@repo/ui` (keep the same
named symbols so usages of Card, CardContent, CardDescription, CardHeader,
CardTitle, and Button in the file remain unchanged).

20-20: Place this route-gating component under a feature module.

WalletGate currently lives in src/components/shared/, but this behavior is feature-scoped (my-investments access control). Moving it under src/features/ aligns with the frontend structure rule and keeps ownership clearer.

As per coding guidelines "Organize Next.js frontends using feature-based folder structure in src/features/".

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

In `@apps/investor-tokenization/src/components/shared/WalletGate.tsx` at line 20,
Move the WalletGate component (export function WalletGate) out of the shared UI
folder into the my-investments feature module so the access-control logic lives
with its feature; after moving, update all imports referencing WalletGate to the
new feature location, ensure the WalletGateProps type and any related exports
are moved or re-exported from the feature module, and run/adjust any tests or
storybook entries that referenced the old path so they import from the feature
instead.
🤖 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/investor-tokenization/src/features/investments/InvestmentsView.tsx`:
- Around line 39-42: The current line unconditionally maps any fetch failure to
an empty list via investmentList = isError ? [] : (investments ?? []); instead
scope that fallback to only expected statuses (e.g., 401 or 404) by using the
actual error/status returned by your fetch hook (replace or augment isError with
the error object/status from the hook) and compute investmentList only when
error.status is 401 or 404; otherwise preserve the error state so the component
can render an explicit error UI for other failures. Update the code that renders
errors to show the real error when isError is true and error.status is not in
[401,404], and keep the empty-list fallback only for those specific statuses
(referencing investmentList, isError, investments and the hook’s error/status
field).

---

Nitpick comments:
In `@apps/investor-tokenization/src/app/my-investments/page.tsx`:
- Around line 8-10: This route currently double-applies wallet gating: the page
wraps <InvestmentsView /> with WalletGate while InvestmentsView itself contains
a no-wallet branch; pick one gating location and remove the redundant check.
Either remove the outer WalletGate wrapper in the page and let InvestmentsView
control its own connect UI, or keep the outer WalletGate and delete the
no-wallet branch inside InvestmentsView (remove its conditional rendering or
early-return that renders the connect prompt). Update references to WalletGate
and InvestmentsView accordingly so only a single wallet gate remains.

In `@apps/investor-tokenization/src/components/shared/WalletGate.tsx`:
- Around line 5-6: Replace the component imports that reference
`@tokenization/ui/card` and `@tokenization/ui/button` so they come from the
shared package `@repo/ui`; update the import line(s) in WalletGate.tsx to import
Card, CardContent, CardDescription, CardHeader, CardTitle and Button from
`@repo/ui` (keep the same named symbols so usages of Card, CardContent,
CardDescription, CardHeader, CardTitle, and Button in the file remain
unchanged).
- Line 20: Move the WalletGate component (export function WalletGate) out of the
shared UI folder into the my-investments feature module so the access-control
logic lives with its feature; after moving, update all imports referencing
WalletGate to the new feature location, ensure the WalletGateProps type and any
related exports are moved or re-exported from the feature module, and run/adjust
any tests or storybook entries that referenced the old path so they import from
the feature instead.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cce62789-f441-4f95-93f5-074d572fb5c3

📥 Commits

Reviewing files that changed from the base of the PR and between ac41138 and e0e3d00.

📒 Files selected for processing (3)
  • apps/investor-tokenization/src/app/my-investments/page.tsx
  • apps/investor-tokenization/src/components/shared/WalletGate.tsx
  • apps/investor-tokenization/src/features/investments/InvestmentsView.tsx

Comment on lines +39 to +42
// Sin backend de investments por wallet: mostrar vista normal con lista vacía
// en lugar de error (401 o endpoint inexistente)
const investmentList = isError ? [] : (investments ?? []);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t convert every fetch failure into “No Investments Yet.”

Line 41 currently treats all errors as empty data. That will hide genuine backend/runtime failures (e.g., 5xx/network) and mislead users with a false empty state. Scope this fallback to expected temporary cases (e.g., 401/404) and keep an explicit error path for everything else.

Scoped fallback example
   const {
     data: investments,
     isLoading,
     isError,
+    error,
   } = useUserInvestments();

-  // Sin backend de investments por wallet: mostrar vista normal con lista vacía
-  // en lugar de error (401 o endpoint inexistente)
-  const investmentList = isError ? [] : (investments ?? []);
+  const getStatusCode = (err: unknown): number | null => {
+    if (typeof err !== "object" || err === null || !("response" in err)) {
+      return null;
+    }
+    const response = (err as { response?: { status?: number } }).response;
+    return typeof response?.status === "number" ? response.status : null;
+  };
+
+  const statusCode = getStatusCode(error);
+  const treatAsEmptyState = statusCode === 401 || statusCode === 404;
+  const investmentList = treatAsEmptyState ? [] : (investments ?? []);

   if (isLoading) {
     return (
       <div className="container mx-auto px-4 py-8">
@@
     );
   }
+
+  if (isError && !treatAsEmptyState) {
+    return (
+      <div className="container mx-auto px-4 py-8">
+        <div className="max-w-2xl mx-auto text-center space-y-6">
+          <h2 className="text-2xl font-bold">My Investments</h2>
+          <p className="text-muted-foreground">
+            We couldn&apos;t load your investments right now. Please try again.
+          </p>
+        </div>
+      </div>
+    );
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/investor-tokenization/src/features/investments/InvestmentsView.tsx`
around lines 39 - 42, The current line unconditionally maps any fetch failure to
an empty list via investmentList = isError ? [] : (investments ?? []); instead
scope that fallback to only expected statuses (e.g., 401 or 404) by using the
actual error/status returned by your fetch hook (replace or augment isError with
the error object/status from the hook) and compute investmentList only when
error.status is 401 or 404; otherwise preserve the error state so the component
can render an explicit error UI for other failures. Update the code that renders
errors to show the real error when isError is true and error.status is not in
[401,404], and keep the empty-list fallback only for those specific statuses
(referencing investmentList, isError, investments and the hook’s error/status
field).

@JoelVR17 JoelVR17 closed this Mar 17, 2026
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