feat(investor): WalletGate for my-investments + fix investments 401#99
feat(investor): WalletGate for my-investments + fix investments 401#99andreMD287 wants to merge 1 commit intoTrustless-Work:developfrom
Conversation
…sing investments API
|
@andreMD287 is attempting to deploy a commit to the Trustless Work Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThis 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
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment |
There was a problem hiding this comment.
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
WalletGatewrappingInvestmentsView, the no-wallet branch insideInvestmentsViewis 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/uipackage (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.
WalletGatecurrently lives insrc/components/shared/, but this behavior is feature-scoped (my-investments access control). Moving it undersrc/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
📒 Files selected for processing (3)
apps/investor-tokenization/src/app/my-investments/page.tsxapps/investor-tokenization/src/components/shared/WalletGate.tsxapps/investor-tokenization/src/features/investments/InvestmentsView.tsx
| // 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 ?? []); | ||
|
|
There was a problem hiding this comment.
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'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).
Summary
/my-investmentswhen 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.InvestmentsViewwithWalletGate. When not connected, only the connect card is shown. When connected, the full investments view is shown.Files changed
apps/investor-tokenization/src/components/shared/WalletGate.tsx— New componentapps/investor-tokenization/src/app/my-investments/page.tsx— Uses WalletGate + InvestmentsViewapps/investor-tokenization/src/features/investments/InvestmentsView.tsx— Treat API error as empty listTest plan
/my-investmentswithout wallet → Connect card is shownSummary by CodeRabbit