Skip to content

Conversation

@0xFirekeeper
Copy link
Member

@0xFirekeeper 0xFirekeeper commented Nov 4, 2025

Reorganized wallet-related routes under a new sidebar structure, replacing legacy pages with redirects to new user, server, and sponsored gas wallet sections. Added new layout and overview/configuration pages for server wallets and sponsored gas, updated sidebar navigation to reflect new wallet grouping, and removed legacy Account Abstraction and Vault pages in favor of the new structure.


PR-Codex overview

This PR focuses on enhancing the wallet management feature within the dashboard by introducing new components for country selection in SMS configurations, improving navigation, and redirecting old pages to new ones.

Detailed summary

  • Added CountrySelector component for SMS country selection.
  • Implemented redirection for old pages to new wallet configurations.
  • Updated layouts for user-wallets, sponsored-gas, and server-wallets.
  • Enhanced API calls for fetching SMS country tiers and wallet details.
  • Introduced new utility functions for country data handling.

The following files were skipped due to too many changes: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/sms-country-select/utils.ts, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/index.tsx

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Wallet management reorganized into dedicated sections: User Wallets, Server Wallets, and Sponsored Gas with corresponding overviews and configuration pages.
    • In-App Wallet configuration UI added with customizable branding, authentication settings, and SMS country tier selection.
    • Sidebar navigation enhanced with submenu structure for improved link organization.
  • Refactor

    • Legacy account abstraction and transaction pages consolidated into new wallet management structure with automatic redirects.

Reorganized wallet-related routes under a new sidebar structure, replacing legacy pages with redirects to new user, server, and sponsored gas wallet sections. Added new layout and overview/configuration pages for server wallets and sponsored gas, updated sidebar navigation to reflect new wallet grouping, and removed legacy Account Abstraction and Vault pages in favor of the new structure.
@0xFirekeeper 0xFirekeeper requested review from a team as code owners November 4, 2025 22:37
@changeset-bot
Copy link

changeset-bot bot commented Nov 4, 2025

⚠️ No Changeset found

Latest commit: 2b13c3f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@0xFirekeeper 0xFirekeeper added the DO NOT MERGE This pull request is still in progress and is not ready to be merged. label Nov 4, 2025
@vercel
Copy link

vercel bot commented Nov 4, 2025

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

Project Deployment Preview Comments Updated (UTC)
thirdweb-www Ready Ready Preview Comment Nov 4, 2025 10:45pm
4 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 Skipped Skipped Nov 4, 2025 10:45pm
nebula Skipped Skipped Nov 4, 2025 10:45pm
thirdweb_playground Skipped Skipped Nov 4, 2025 10:45pm
wallet-ui Skipped Skipped Nov 4, 2025 10:45pm

@graphite-app
Copy link
Contributor

graphite-app bot commented Nov 4, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Nov 4, 2025
@0xFirekeeper 0xFirekeeper changed the title Refactor wallet and sidebar routes, add new wallet pages [WIP] Refactor wallet and sidebar routes, add new wallet pages Nov 4, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

This PR restructures wallet management and project routing by replacing old account abstraction, vault, and transactions pages with redirects to new wallet subsections. It introduces new layout, overview, and configuration pages for user-wallets, server-wallets, and sponsored-gas features, alongside updated sidebar navigation and in-app wallet settings UI.

Changes

Cohort / File(s) Change Summary
Sidebar Layout & Type Exports
apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
Exports ShadcnSidebarBaseLink and ShadcnSidebarLink types; adds submenu variant support; refactors useActiveShadcnSidebarLink with recursive link traversal logic; introduces findParentSubmenu helper for locating parent submenus.
Sidebar Navigation Update
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
Replaces inline sidebar content with contentSidebarLinks and footerSidebarLinks arrays; reorganizes Build, Scale groups with wallet submenus; moves Webhooks, Settings, Documentation, Playground to footer; imports new ShadcnSidebarLink type.
Old Pages → Redirects (Account Abstraction)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/{account-abstraction,settings/account-abstraction}/page.tsx
Replaces multi-step data-fetching and UI rendering with single redirect() calls to sponsored-gas paths.
Old Pages → Redirects (Wallets & Vault)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/{settings/wallets,transactions,vault,wallets}/page.tsx
Replaces complex page logic with immediate redirects; removes searchParams prop and dynamic = "force-dynamic" exports where applicable.
New Wallets Layout Structure
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/layout.tsx, wallets/{user-wallets,server-wallets,sponsored-gas}/layout.tsx
Adds new async layout components; top-level wallets layout includes auth/project fetching and ProjectPage wrapper; subsection layouts render TabPathLinks with Overview and Configuration tabs.
New Redirect Pages
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/{page.tsx,server-wallets/page.tsx,user-wallets/page.tsx,sponsored-gas/page.tsx}
Minimal async pages that immediately redirect to corresponding overview routes.
Server Wallets Dashboard
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
New force-dynamic page fetching vault client, project, EOA, and Solana account data; renders EngineChecklist, TransactionAnalyticsSummary, and ServerWalletsTable with pagination support.
Server Wallets Configuration
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/configuration/page.tsx
New page fetching auth and project; extracts engineCloud service and renders KeyManagement component.
Sponsored Gas Dashboard
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/sponsored-gas/overview/page.tsx
New force-dynamic page with auth/team/project fetching, time-range calculation, bundler service checks, billing alerts, and user operation stats; renders AccountAbstractionSummary, AccountAbstractionAnalytics.
Sponsored Gas Configuration
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/sponsored-gas/configuration/page.tsx
New page fetching bundler service; renders AccountAbstractionSettingsPage with default and custom factory sections.
User Wallets Dashboard
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/overview/page.tsx
New force-dynamic page with auth/project fetching, time-filter setup; renders InAppWalletsSummary, InAppWalletAnalytics, and InAppWalletUsersPageContent.
User Wallets Configuration & Settings
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/{page.tsx,components/index.tsx}
New page and comprehensive settings UI for in-app wallet branding, authentication, SMS support, and native redirects; includes InAppWalletSettingsPage and InAppWalletSettingsUI with plan-gated form controls and image upload.
SMS Country Selection Utilities & Components
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/{api/sms.ts,components/sms-country-select/{country-selector.tsx,utils.ts,index.ts}}
New SMS API module fetching country tier data; CountrySelector component with tier-based country grid UI; utilities for country names, prefixes, flags, and tier pricing.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Browser
    participant Dashboard as Dashboard Page
    participant Auth as Auth Service
    participant Project as Project Service
    participant Wallet as Wallet Service

    User->>Browser: Navigate to /wallets
    Browser->>Dashboard: Request /wallets/user-wallets/layout
    Dashboard->>Dashboard: Resolve params
    Dashboard->>Auth: getAuthToken()
    Dashboard->>Project: getProject(team_slug, project_slug)
    alt Auth missing
        Dashboard->>User: Redirect to login
    end
    alt Project missing
        Dashboard->>User: Redirect to team page
    end
    Dashboard->>Dashboard: Create thirdweb client
    Dashboard->>Browser: Render TabPathLinks (Overview, Configuration)
    
    Note over Browser: User on Overview tab
    Dashboard->>Auth: getAuthToken()
    Dashboard->>Project: getProject() + getTeamBySlug()
    Dashboard->>Wallet: Fetch wallet analytics & users
    Dashboard->>Browser: Render InAppWalletsSummary, InAppWalletAnalytics
    
    Note over Browser: User navigates to Configuration
    Dashboard->>Dashboard: getValidTeamPlan(), getSMSCountryTiers()
    Dashboard->>Browser: Render InAppWalletSettingsUI (plan-gated)
    User->>Browser: Update branding/auth settings
    Browser->>Dashboard: updateProjectClient mutation
    Dashboard->>Project: Update project.services.embeddedWallets
    Dashboard->>User: Show success toast
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Areas requiring extra attention:
    • Recursive link traversal logic in full-width-sidebar-layout.tsx (findParentSubmenu, refactored useActiveShadcnSidebarLink) — verify correct handling of nested groups and submenu structures.
    • Complex data-fetching orchestration in server-wallets/overview/page.tsx and sponsored-gas/overview/page.tsx — check error handling paths, pagination state, and conditional rendering of analytics/alerts.
    • Plan-gating logic in InAppWalletSettingsUI — ensure planToTierRecordForGating correctly gates features and that form state persists through updates.
    • SMS country selector component integration with react-hook-form — verify tier selection, indeterminate checkbox states, and onChange callbacks.
    • Image upload and file handling in AppImageFormControl — check Thirdweb storage API integration and error boundaries.
    • Multiple new layout structures — confirm params resolution, tab path construction, and nesting consistency across wallet subsections.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description provides a clear summary of changes, but does not follow the repository's template structure with required sections like title format, Linear issue tag, notes for reviewer, or testing instructions. Update the description to follow the template: add proper title format with [Dashboard], include Linear issue tag, add explicit 'Notes for the reviewer' and 'How to test' sections with testing guidance.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately reflects the main objective: refactoring wallet and sidebar routes while adding new wallet pages, which aligns with the comprehensive changes across multiple files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch firekeeper/wallets-dashboard-revamp

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

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2025

size-limit report 📦

Path Size
@thirdweb-dev/nexus (esm) 104.88 KB (0%)
@thirdweb-dev/nexus (cjs) 316.6 KB (0%)

Copy link
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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx (1)

121-159: Restore custom active matching for sidebar links

ShadcnSidebarBaseLink exposes an isActive hook so callers can override the matching logic. The new walk helper no longer consults that callback, so any link relying on custom matching (or non-prefix URLs) stops lighting up both in the sidebar and mobile trigger. Please wire the callback back in before falling back to the default comparisons.

-    function isActive(link: ShadcnSidebarBaseLink) {
-      if (link.exactMatch) {
-        return link.href === pathname;
-      }
-      return pathname?.startsWith(link.href);
-    }
+    function isActive(link: ShadcnSidebarBaseLink) {
+      const currentPath = pathname ?? "";
+      if (link.isActive) {
+        return link.isActive(currentPath);
+      }
+      if (link.exactMatch) {
+        return link.href === currentPath;
+      }
+      return currentPath.startsWith(link.href);
+    }
🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx (1)

1-11: Clean redirect pattern, but consider adding server-only directive.

The refactor from a complex page to a simple redirect is well-executed and follows the pattern established in other wallet redirect pages in this PR. The target page (wallets/server-wallets/overview/page.tsx) properly handles the full implementation including authorization, data fetching, and UI rendering.

However, per coding guidelines, server components should start with import "server-only" to enforce server-side-only execution. This applies to all similar redirect pages in this PR (vault, account-abstraction, wallets, server-wallets).

Consider adding the directive at the top of the file:

+import "server-only";
+
 import { redirect } from "next/navigation";

Note: This same pattern should be applied to the other redirect pages in this PR for consistency with the coding guidelines.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/layout.tsx (1)

19-23: Consider using a constant or helper for the redirect path.

The hardcoded redirect path /team/${params.team_slug}/${params.project_slug}/wallets/user-wallets could be extracted to a constant or helper function to improve maintainability and reduce duplication if this path is used elsewhere in the wallets section.

@@ -0,0 +1,62 @@
import { redirect } from "next/navigation";
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add "server-only" import at the top.

This server component uses server-side APIs and should begin with import "server-only"; to prevent accidental client-side bundling.

As per coding guidelines

Apply this diff:

+import "server-only";
+
 import { redirect } from "next/navigation";
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/layout.tsx
at line 1, this server component must include the server-only marker to avoid
client-side bundling; add the statement import "server-only"; as the very first
line of the file (before any other imports) so Next treats this module as
server-only.

Comment on lines +1 to +40
import { redirect } from "next/navigation";
import { getAuthToken } from "@/api/auth-token";
import { getProject } from "@/api/project/projects";
import { loginRedirect } from "@/utils/redirects";
import { KeyManagement } from "../../../vault/components/key-management";

export default async function Page(props: {
params: Promise<{ team_slug: string; project_slug: string }>;
}) {
const { team_slug, project_slug } = await props.params;
const [authToken, project] = await Promise.all([
getAuthToken(),
getProject(team_slug, project_slug),
]);

if (!authToken) {
loginRedirect(
`/team/${team_slug}/${project_slug}/wallets/server-wallets/configuration`,
);
}

if (!project) {
redirect(`/team/${team_slug}`);
}

const projectEngineCloudService = project.services.find(
(service) => service.name === "engineCloud",
);

const maskedAdminKey = projectEngineCloudService?.maskedAdminKey;
const isManagedVault = !!projectEngineCloudService?.encryptedAdminKey;

return (
<KeyManagement
maskedAdminKey={maskedAdminKey ?? undefined}
isManagedVault={isManagedVault}
project={project}
/>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add the server-only guard

This page executes on the server (auth token fetch, redirects, etc.), so it should start with import "server-only"; to keep it out of client bundles and align with our dashboard rules. As per coding guidelines.

+import "server-only";
 import { redirect } from "next/navigation";
 import { getAuthToken } from "@/api/auth-token";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { redirect } from "next/navigation";
import { getAuthToken } from "@/api/auth-token";
import { getProject } from "@/api/project/projects";
import { loginRedirect } from "@/utils/redirects";
import { KeyManagement } from "../../../vault/components/key-management";
export default async function Page(props: {
params: Promise<{ team_slug: string; project_slug: string }>;
}) {
const { team_slug, project_slug } = await props.params;
const [authToken, project] = await Promise.all([
getAuthToken(),
getProject(team_slug, project_slug),
]);
if (!authToken) {
loginRedirect(
`/team/${team_slug}/${project_slug}/wallets/server-wallets/configuration`,
);
}
if (!project) {
redirect(`/team/${team_slug}`);
}
const projectEngineCloudService = project.services.find(
(service) => service.name === "engineCloud",
);
const maskedAdminKey = projectEngineCloudService?.maskedAdminKey;
const isManagedVault = !!projectEngineCloudService?.encryptedAdminKey;
return (
<KeyManagement
maskedAdminKey={maskedAdminKey ?? undefined}
isManagedVault={isManagedVault}
project={project}
/>
);
}
import "server-only";
import { redirect } from "next/navigation";
import { getAuthToken } from "@/api/auth-token";
import { getProject } from "@/api/project/projects";
import { loginRedirect } from "@/utils/redirects";
import { KeyManagement } from "../../../vault/components/key-management";
export default async function Page(props: {
params: Promise<{ team_slug: string; project_slug: string }>;
}) {
const { team_slug, project_slug } = await props.params;
const [authToken, project] = await Promise.all([
getAuthToken(),
getProject(team_slug, project_slug),
]);
if (!authToken) {
loginRedirect(
`/team/${team_slug}/${project_slug}/wallets/server-wallets/configuration`,
);
}
if (!project) {
redirect(`/team/${team_slug}`);
}
const projectEngineCloudService = project.services.find(
(service) => service.name === "engineCloud",
);
const maskedAdminKey = projectEngineCloudService?.maskedAdminKey;
const isManagedVault = !!projectEngineCloudService?.encryptedAdminKey;
return (
<KeyManagement
maskedAdminKey={maskedAdminKey ?? undefined}
isManagedVault={isManagedVault}
project={project}
/>
);
}
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/configuration/page.tsx
lines 1-40, this server-rendered page must be explicitly marked server-only; add
import "server-only"; as the very first line of the file (before any other
imports) to ensure it is excluded from client bundles and follows the dashboard
server-only rule.

Comment on lines +36 to +40
if (!authToken) {
redirect(
`/team/${params.team_slug}/${params.project_slug}/wallets/server-wallets/overview`,
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix the auth redirect loop.

When authToken is missing, this code redirects back to the same /wallets/server-wallets/overview path, which will immediately re-run the page loader and redirect again—effectively an infinite loop that surfaces as a 500. Redirect to a safe auth entry point instead (e.g. /login with a return URL) so unauthenticated users can recover.

-  if (!authToken) {
-    redirect(
-      `/team/${params.team_slug}/${params.project_slug}/wallets/server-wallets/overview`,
-    );
-  }
+  if (!authToken) {
+    redirect(`/login?next=/team/${params.team_slug}/${params.project_slug}/wallets/server-wallets/overview`);
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!authToken) {
redirect(
`/team/${params.team_slug}/${params.project_slug}/wallets/server-wallets/overview`,
);
}
if (!authToken) {
redirect(`/login?next=/team/${params.team_slug}/${params.project_slug}/wallets/server-wallets/overview`);
}
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
at lines 36 to 40, the redirect when authToken is missing points back to the
same page path, creating an infinite redirect loop that causes a 500 error.
Replace the redirect destination with a login page endpoint and include a
returnUrl query parameter that points back to the original wallets overview page
so users can be redirected there after successful authentication. This allows
unauthenticated users to properly authenticate rather than getting stuck in a
loop.

Comment on lines +29 to +31
if (!authToken) {
notFound();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use loginRedirect instead of notFound for auth guard

If the auth token is missing we should redirect the user to the login flow, not surface a 404. The current notFound() call will show the Not Found page to logged-out users, which is inconsistent with the rest of the dashboard wallet routes and breaks the intended authentication UX. Please swap this for loginRedirect(...) (and drop the notFound import).

-import { notFound, redirect } from "next/navigation";
+import { redirect } from "next/navigation";
+import { loginRedirect } from "@/utils/redirects";
@@
-  if (!authToken) {
-    notFound();
-  }
+  if (!authToken) {
+    loginRedirect(
+      `/team/${params.team_slug}/${params.project_slug}/wallets/sponsored-gas/overview`,
+    );
+  }
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/sponsored-gas/overview/page.tsx
around lines 29-31, replace the current auth guard that calls notFound() when
authToken is missing with a loginRedirect call so unauthenticated users are sent
to the login flow; remove the notFound import, import the loginRedirect helper
instead, and invoke it passing the current request URL as the callback (e.g.
loginRedirect({ callbackUrl: currentUrl })) or otherwise ensure the user is
redirected back to this page after login.

Comment on lines +14 to +61
export async function getSMSCountryTiers() {
if (!API_SERVER_SECRET) {
throw new Error("API_SERVER_SECRET is not set");
}
const res = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/sms/list-country-tiers`,
{
headers: {
"Content-Type": "application/json",
"x-service-api-key": API_SERVER_SECRET,
},
next: {
revalidate: 15 * 60, //15 minutes
},
},
);

if (!res.ok) {
console.error(
"Failed to fetch sms country tiers",
res.status,
res.statusText,
);
res.body?.cancel();
return {
tier1: [],
tier2: [],
tier3: [],
tier4: [],
tier5: [],
tier6: [],
};
}

try {
return (await res.json()).data as SMSCountryTiers;
} catch (e) {
console.error("Failed to parse sms country tiers", e);
return {
tier1: [],
tier2: [],
tier3: [],
tier4: [],
tier5: [],
tier6: [],
};
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Declare the return type for getSMSCountryTiers

Our TypeScript guidelines require explicit return types for exported functions; without it we lose the compile-time contract that this helper always resolves to SMSCountryTiers. Please add the annotation.

-export async function getSMSCountryTiers() {
+export async function getSMSCountryTiers(): Promise<SMSCountryTiers> {
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/api/sms.ts
around lines 14 to 61, the exported async function getSMSCountryTiers is missing
an explicit return type; add an explicit return annotation
(Promise<SMSCountryTiers>) to the function signature and ensure SMSCountryTiers
is imported or declared in scope so the compiler can validate the returned
shape; no other logic changes are required but keep the existing fallback return
objects matching the SMSCountryTiers interface.

Comment on lines +1 to +9
import { redirect } from "next/navigation";

export default async function Page(props: {
params: Promise<{ team_slug: string; project_slug: string }>;
}) {
const params = await props.params;
redirect(
`/team/${params.team_slug}/${params.project_slug}/wallets/user-wallets/overview`,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add the server-only guard

This route runs entirely on the server; per our dashboard conventions we need import "server-only"; at the top so bundlers never treat it as a client component. Please add the guard. As per coding guidelines.

+import "server-only";
 import { redirect } from "next/navigation";
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/page.tsx
around lines 1 to 9, this route is server-only and needs the server-only guard;
add the statement import "server-only"; as the first line (above any other
imports) so bundlers treat the module as server-only per dashboard conventions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard. DO NOT MERGE This pull request is still in progress and is not ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants