Skip to content

feat: create/delete teams #7293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

arcoraven
Copy link
Contributor

@arcoraven arcoraven commented Jun 6, 2025

[Dashboard] Feature: Add Team Creation and Deletion

Notes for the reviewer

This PR adds the ability for users to create and delete teams from the dashboard. It includes:

  1. Server actions for creating and deleting teams
  2. UI integration in the account header, team selector, and account teams page
  3. Team deletion functionality in the team settings page

How to test

  • Try creating a new team from the account header dropdown
  • Try creating a new team from the account teams page
  • Try deleting a team from the team settings page (only available for team owners)

Summary by CodeRabbit

  • New Features

    • Enabled team creation directly from the account and team selection interfaces, allowing users to create a new team and be redirected to its page immediately.
    • Activated the "Create Team" button in relevant menus and headers, making team creation accessible across both desktop and mobile views.
  • Bug Fixes

    • Improved error handling and user feedback with toast notifications when team creation fails.
  • Refactor

    • Updated team deletion to use real permission checks and improved the user interface for deleting teams.
  • Documentation

    • Marked the default team retrieval function as deprecated in the documentation.

Copy link

vercel bot commented Jun 6, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
thirdweb-www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 6, 2025 7:43am
4 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs-v2 ⬜️ Skipped (Inspect) Jun 6, 2025 7:43am
login ⬜️ Skipped (Inspect) Jun 6, 2025 7:43am
thirdweb_playground ⬜️ Skipped (Inspect) Jun 6, 2025 7:43am
wallet-ui ⬜️ Skipped (Inspect) Jun 6, 2025 7:43am

@vercel vercel bot temporarily deployed to Preview – docs-v2 June 6, 2025 07:36 Inactive
@vercel vercel bot temporarily deployed to Preview – login June 6, 2025 07:36 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground June 6, 2025 07:36 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui June 6, 2025 07:36 Inactive
Copy link

changeset-bot bot commented Jun 6, 2025

⚠️ No Changeset found

Latest commit: d649c61

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

Copy link
Contributor

coderabbitai bot commented Jun 6, 2025

Walkthrough

The changes introduce full support for team creation and deletion in the dashboard application. New asynchronous actions for creating and deleting teams are added, and corresponding UI components are updated to enable these features. Disabled or placeholder "Create Team" buttons are now active, and the delete functionality now performs real permission checks and API calls.

Changes

File(s) Change Summary
apps/dashboard/src/@/actions/createTeam.ts
apps/dashboard/src/@/actions/deleteTeam.ts
Added async createTeam and deleteTeam functions for team creation and deletion via API with auth handling.
apps/dashboard/src/@/api/team.ts Marked getDefaultTeam as deprecated via JSDoc annotation.
apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx
.../team-header-logged-in.client.tsx
Added createTeam async handler to header props; handles team creation and navigation, with error toasts.
apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
.../TeamHeaderUI.tsx
Extended component prop types to include createTeam: () => void and passed down to relevant child components.
apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.stories.tsx
.../TeamHeaderUI.stories.tsx
Updated stories to include the new createTeam prop with empty function implementations.
apps/dashboard/src/app/(app)/account/overview/AccountTeamsUI.tsx Replaced disabled "Create Team" button with active one; added createTeamAndRedirect async handler.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx Refactored team deletion: replaced stubbed permission with real check, updated props, and implemented deletion.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx Updated DeleteTeamCard props: renamed enabled to canDelete, added teamId.
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamAndProjectSelectorPopoverButton.tsx Extended props to include createTeam and passed it to TeamSelectionUI, closing popover on invocation.
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamSelectionUI.tsx Added createTeam prop; enabled "Create Team" button and removed "Soon™️" badge and disabled state.
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamSelectorMobileMenuButton.tsx Extended props to include createTeam and passed it to TeamSelectionUI in dialog.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI_Component
    participant Actions_Module
    participant API_Server
    participant Router
    participant Toast

    User->>UI_Component: Click "Create Team"
    UI_Component->>Actions_Module: createTeam({})
    Actions_Module->>API_Server: POST /v1/teams (with auth)
    API_Server-->>Actions_Module: Team data / Error
    Actions_Module-->>UI_Component: { ok: true, data } or { ok: false, errorMessage }
    alt Success
        UI_Component->>Router: Navigate to /team/[slug]
    else Failure
        UI_Component->>Toast: Show "Failed to create team"
    end
Loading
sequenceDiagram
    participant User
    participant UI_Component
    participant Actions_Module
    participant API_Server
    participant Router
    participant Toast

    User->>UI_Component: Click "Delete Team"
    UI_Component->>Actions_Module: deleteTeam({ teamId })
    Actions_Module->>API_Server: DELETE /v1/teams/{teamId} (with auth)
    API_Server-->>Actions_Module: 200 OK / Error
    alt Success
        UI_Component->>Router: Navigate to /team
        UI_Component->>Toast: Show "Team deleted"
    else Failure
        UI_Component->>Toast: Show error message
    end
Loading

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Jun 6, 2025
Copy link
Contributor Author


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.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@arcoraven arcoraven marked this pull request as ready for review June 6, 2025 07:36
@arcoraven arcoraven requested review from a team as code owners June 6, 2025 07:36
Copy link

codecov bot commented Jun 6, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 55.58%. Comparing base (c95c0dc) to head (d649c61).
Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7293   +/-   ##
=======================================
  Coverage   55.58%   55.58%           
=======================================
  Files         909      909           
  Lines       58670    58670           
  Branches     4158     4158           
=======================================
  Hits        32609    32609           
  Misses      25954    25954           
  Partials      107      107           
Flag Coverage Δ
packages 55.58% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

github-actions bot commented Jun 6, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 62.57 KB (0%) 1.3 s (0%) 235 ms (+129.18% 🔺) 1.5 s
thirdweb (cjs) 345.55 KB (0%) 7 s (0%) 844 ms (+4.27% 🔺) 7.8 s
thirdweb (minimal + tree-shaking) 5.7 KB (0%) 114 ms (0%) 82 ms (+1114.16% 🔺) 196 ms
thirdweb/chains (tree-shaking) 531 B (0%) 11 ms (0%) 30 ms (+1136.87% 🔺) 40 ms
thirdweb/react (minimal + tree-shaking) 19.56 KB (0%) 392 ms (0%) 89 ms (+460.66% 🔺) 480 ms

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: 3

🧹 Nitpick comments (4)
apps/dashboard/src/@/api/team.ts (1)

70-70: Enhance the deprecation annotation with more context.

The deprecation annotation should include the reason for deprecation and what developers should use instead to provide better guidance.

-/** @deprecated */
+/** @deprecated Use the new createTeam and deleteTeam actions instead. This function will be removed in a future version. */
apps/dashboard/src/@/actions/createTeam.ts (3)

39-39: Consider shorter slug generation for better UX.

The current implementation generates a 40-character slug using randomBytes(20).toString("hex"), which may be too long for user-friendly URLs. Consider using a shorter identifier or a more URL-friendly generation method.

-      slug: options.slug ?? randomBytes(20).toString("hex"),
+      slug: options.slug ?? randomBytes(8).toString("hex"),

Or consider using a more readable format:

-      slug: options.slug ?? randomBytes(20).toString("hex"),
+      slug: options.slug ?? `team-${randomBytes(4).toString("hex")}`,

9-21: Consider adding input validation for robustness.

The function accepts optional parameters but doesn't validate them. Consider adding basic validation to ensure name and slug meet expected criteria (length limits, character restrictions, etc.).

+const createTeamSchema = z.object({
+  name: z.string().max(50).optional(),
+  slug: z.string().max(30).regex(/^[a-z0-9-]+$/).optional(),
+});

 export async function createTeam(options: {
   name?: string;
   slug?: string;
 }): Promise<
   | {
       ok: true;
       data: Team;
     }
   | {
       ok: false;
       errorMessage: string;
     }
 > {
+  const validatedOptions = createTeamSchema.parse(options);

45-50: Consider more specific error handling.

The current error handling returns the raw response text, which might not always be user-friendly. Consider parsing the error response or providing more context about the failure.

   if (!res.ok) {
+    let errorMessage: string;
+    try {
+      const errorJson = await res.json();
+      errorMessage = errorJson.message || errorJson.error || "Failed to create team";
+    } catch {
+      errorMessage = `Failed to create team (${res.status})`;
+    }
     return {
       ok: false,
-      errorMessage: await res.text(),
+      errorMessage,
     };
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f89c15c and d649c61.

📒 Files selected for processing (15)
  • apps/dashboard/src/@/actions/createTeam.ts (1 hunks)
  • apps/dashboard/src/@/actions/deleteTeam.ts (1 hunks)
  • apps/dashboard/src/@/api/team.ts (1 hunks)
  • apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.stories.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/account/overview/AccountTeamsUI.tsx (5 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamAndProjectSelectorPopoverButton.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.stories.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamSelectionUI.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamSelectorMobileMenuButton.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/components/TeamHeader/team-header-logged-in.client.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx (1)
  • DeleteTeamCard (296-350)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx (1)
apps/dashboard/src/@/actions/deleteTeam.ts (1)
  • deleteTeam (5-25)
apps/dashboard/src/app/(app)/team/components/TeamHeader/team-header-logged-in.client.tsx (1)
apps/dashboard/src/@/actions/createTeam.ts (1)
  • createTeam (9-58)
apps/dashboard/src/@/actions/deleteTeam.ts (2)
apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts (1)
  • getAuthToken (6-14)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_THIRDWEB_API_HOST (21-22)
apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx (1)
apps/dashboard/src/@/actions/createTeam.ts (1)
  • createTeam (9-58)
apps/dashboard/src/@/actions/createTeam.ts (3)
apps/dashboard/src/@/api/team.ts (1)
  • Team (9-9)
apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts (1)
  • getAuthToken (6-14)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_THIRDWEB_API_HOST (21-22)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (24)
apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.stories.tsx (1)

62-62: LGTM! Consistent storybook prop addition.

The createTeam prop addition follows the same pattern as the existing createProject prop and uses an appropriate empty function for storybook testing.

apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.stories.tsx (1)

158-158: LGTM! Consistent storybook prop addition.

The createTeam prop addition is consistent with the pattern used in other storybook files and uses an appropriate empty function for testing purposes.

apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamSelectorMobileMenuButton.tsx (2)

20-20: LGTM! Proper prop type definition.

The createTeam callback prop type is correctly defined and follows TypeScript best practices with a clear function signature.


55-55: LGTM! Correct prop passing.

The createTeam prop is properly passed down to the TeamSelectionUI component, enabling the team creation functionality in the mobile menu.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx (1)

65-66: LGTM! Storybook stories correctly updated for new DeleteTeamCard interface.

The prop changes from enabled to canDelete and the addition of teamId are properly reflected in the story variants, providing good test coverage for both permission states.

apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamAndProjectSelectorPopoverButton.tsx (2)

25-25: LGTM! Clean addition of createTeam callback to component interface.


104-107: LGTM! Proper UX implementation for team creation.

The implementation correctly closes the popover before triggering team creation, preventing potential UI state issues.

apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx (2)

24-24: LGTM! Consistent addition of createTeam callback to component props.


68-68: LGTM! Proper callback propagation in both desktop and mobile UI.

The createTeam callback is consistently passed to both UI variants, maintaining feature parity across desktop and mobile experiences.

Also applies to: 122-122

apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx (2)

32-32: LGTM! Consistent addition of createTeam callback to component interface.


79-79: LGTM! Proper callback propagation to selector components.

The createTeam callback is correctly passed to both team-selection and project-selection focused popover buttons.

Also applies to: 107-107

apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx (3)

3-3: LGTM: Clean import addition

The import statement correctly imports the createTeam action from the expected location.


11-11: LGTM: Toast import added for error notifications

Adding the toast import from sonner aligns with the error handling pattern used in the createTeam function.


62-69: LGTM: Well-implemented team creation with proper error handling

The createTeam implementation follows good practices:

  • Proper async/await usage
  • Clear error handling with user-friendly toast messages
  • Navigation to the new team page on success
  • Consistent with the createTeam action's return type

The use of empty options {} is appropriate as the action provides sensible defaults for name and slug.

apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamSelectionUI.tsx (2)

27-27: LGTM: Clean prop addition for team creation

The createTeam callback prop is properly typed and follows the established pattern from other components in the codebase.


130-136: LGTM: Create Team button properly activated

The button implementation is correct:

  • Removed the disabled state that was previously preventing interaction
  • Added proper onClick handler that calls the createTeam prop
  • Maintains consistent styling and icon usage
  • The button text "Create Team" clearly indicates its purpose

This completes the integration that enables actual team creation functionality.

apps/dashboard/src/@/actions/deleteTeam.ts (1)

1-4: LGTM: Proper server action setup

The file correctly uses the "use server" directive and imports the necessary dependencies for authentication and API configuration.

apps/dashboard/src/app/(app)/account/overview/AccountTeamsUI.tsx (3)

3-3: LGTM: Proper imports for team creation functionality

The imports correctly bring in the necessary dependencies:

  • createTeam action for API interaction
  • useDashboardRouter for navigation
  • toast from sonner for error notifications

This aligns with the pattern established in other components.

Also applies to: 14-14, 18-18


31-31: LGTM: Well-implemented team creation with navigation

The implementation is excellent:

  • Proper use of the dashboard router hook
  • Clean async function that wraps the createTeam action
  • Consistent error handling with user-friendly toast messages
  • Navigation to the new team page on success
  • Follows the same pattern established in AccountHeader.tsx

The function name createTeamAndRedirect clearly describes its behavior.

Also applies to: 41-48


60-63: LGTM: Create Team button properly activated

The button transformation is well-executed:

  • Removed the disabled state that was blocking user interaction
  • Added proper onClick handler that calls the new createTeamAndRedirect function
  • Maintains consistent styling with the PlusIcon and responsive classes
  • Clear and descriptive button text

This completes the user flow from a disabled placeholder to a fully functional team creation feature.

apps/dashboard/src/app/(app)/team/components/TeamHeader/team-header-logged-in.client.tsx (1)

68-75: LGTM! Clean implementation with proper error handling.

The createTeam function correctly handles both success and error cases. The error toast provides good user feedback, and the navigation logic properly redirects to the newly created team's page using the slug from the API response.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx (3)

63-66: Good improvement from hardcoded to dynamic permissions.

The changes properly replace the hardcoded permission check with the actual isOwnerAccount prop and add the required teamId for the delete operation. This enables real permission-based access control.


306-313: Well-implemented delete mutation with proper error handling.

The mutation correctly integrates with the deleteTeam action and handles the success case by redirecting to the teams overview page. The async/await pattern is appropriate for the server action call.


323-337:

❓ Verification inconclusive

Verify deleteTeam action handles all error scenarios properly.

The permission-based rendering works well, but ensure that the deleteTeam action properly handles edge cases like network failures, authorization errors, or cases where the team is referenced by other entities.


🏁 Script executed:

#!/bin/bash
# Verify error handling in deleteTeam action and related components
rg -A 10 -B 5 "deleteTeam.*throw\|deleteTeam.*error" --type=ts

Length of output: 64


🏁 Script executed:

#!/bin/bash
# Locate the definition of deleteTeamAndRedirect to inspect how errors are handled
rg -nF "deleteTeamAndRedirect" -g '*.ts' -g '*.tsx'

Length of output: 524


🏁 Script executed:

#!/bin/bash
# Show context around deleteTeamAndRedirect definition to inspect error handling
rg -n "const deleteTeamAndRedirect = useMutation" -g '*.tsx' -B5 -A15

Length of output: 2946


🏁 Script executed:

#!/bin/bash
# Show import statement for deleteTeam in the UI component
rg -n "import.*deleteTeam" -g 'apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx'

Length of output: 284


🏁 Script executed:

#!/bin/bash
# Search across the repo for the import of deleteTeam
rg -n "import .* deleteTeam" -g '*.ts' -g '*.tsx'

Length of output: 206


🏁 Script executed:

#!/bin/bash
# Locate and display the deleteTeam action implementation to inspect error handling
rg -n "export (const|function) deleteTeam" -g '*.ts' -g '*.tsx' -B0 -A50

Length of output: 74


Verify deleteTeam action handles all error scenarios properly.

I wasn’t able to locate the implementation of deleteTeam in @/actions/deleteTeam, so please double-check that this function:

  • Catches network failures and request timeouts
  • Handles 401/403 authorization errors
  • Deals with referential-integrity issues (e.g. team still referenced elsewhere)
  • Propagates clear error messages back to toast.promise

Comment on lines +176 to +178
createTeam={() => {
alert("createTeam");
}}
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

Replace placeholder alert with proper createTeam implementation.

The current alert implementation appears to be placeholder code. This should use the actual createTeam prop passed from the parent component for consistency with other UI components.

Apply this diff to use the proper callback:

-            createTeam={() => {
-              alert("createTeam");
-            }}
+            createTeam={props.createTeam}
📝 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
createTeam={() => {
alert("createTeam");
}}
createTeam={props.createTeam}
🤖 Prompt for AI Agents
In apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
around lines 176 to 178, replace the placeholder alert in the createTeam prop
with the actual createTeam function passed down as a prop from the parent
component. This ensures the component uses the proper callback for creating a
team instead of just showing an alert.

Comment on lines +5 to +11
export async function deleteTeam(options: {
teamId: string;
}): Promise<void> {
const token = await getAuthToken();
if (!token) {
throw new Error("You are not authorized to perform this action");
}
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

Consider input validation and improve error handling consistency

The function signature and authorization check are good, but there are a few areas for improvement:

  1. Input validation: The teamId parameter is not validated. Consider adding validation to ensure it's a non-empty string.
  2. Error handling inconsistency: This action throws errors, while createTeam returns result objects with ok boolean. This inconsistency could confuse consumers.

Consider aligning the error handling pattern with createTeam:

export async function deleteTeam(options: {
  teamId: string;
}): Promise<
  | { ok: true }
  | { ok: false; errorMessage: string }
> {
  const token = await getAuthToken();
  if (!token) {
-   throw new Error("You are not authorized to perform this action");
+   return {
+     ok: false,
+     errorMessage: "You are not authorized to perform this action"
+   };
  }
+
+ if (!options.teamId?.trim()) {
+   return {
+     ok: false,
+     errorMessage: "Team ID is required"
+   };
+ }
🤖 Prompt for AI Agents
In apps/dashboard/src/@/actions/deleteTeam.ts around lines 5 to 11, add
validation to check that the teamId parameter is a non-empty string before
proceeding. Also, refactor the function to return a result object with an ok
boolean and error message instead of throwing errors, to align with the error
handling pattern used in createTeam. This will improve input validation and
maintain consistency in error handling across similar functions.

Comment on lines +13 to +25
const res = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${options.teamId}`,
{
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
},
},
);
if (!res.ok) {
throw new Error(await res.text());
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider enhanced error handling and security measures

The API call implementation is functional but could be improved:

  1. Error handling: Currently throws generic errors. Consider providing more specific error messages based on response status.
  2. Permission verification: The action only checks authentication but doesn't verify if the user has permission to delete the specific team.

Consider these improvements:

  const res = await fetch(
    `${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${options.teamId}`,
    {
      method: "DELETE",
      headers: {
        Authorization: `Bearer ${token}`,
      },
    },
  );
  if (!res.ok) {
-   throw new Error(await res.text());
+   const errorText = await res.text();
+   return {
+     ok: false,
+     errorMessage: res.status === 403 
+       ? "You don't have permission to delete this team"
+       : res.status === 404
+       ? "Team not found"
+       : errorText || "Failed to delete team"
+   };
  }
+ return { ok: true };

Let me verify if there are any existing permission checks for team deletion in the codebase:


🏁 Script executed:

#!/bin/bash
# Search for team permission/authorization patterns
rg -A 5 -B 5 "delete.*team|team.*delete" --type ts

Length of output: 9979


🏁 Script executed:

#!/bin/bash
# Display contents of deleteTeam action file for context
cat apps/dashboard/src/@/actions/deleteTeam.ts

Length of output: 683


Enhance error reporting in deleteTeam action

The server enforces authorization and team-deletion permissions; we only need to map common failure statuses to more descriptive errors rather than return a new result type. In apps/dashboard/src/@/actions/deleteTeam.ts, update the error block as follows:

   const res = await fetch(
     `${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${options.teamId}`,
     {
       method: "DELETE",
       headers: {
         Authorization: `Bearer ${token}`,
       },
     },
   );
-  if (!res.ok) {
-    throw new Error(await res.text());
-  }
+  if (!res.ok) {
+    const errorText = await res.text();
+    if (res.status === 403) {
+      throw new Error("You don’t have permission to delete this team");
+    }
+    if (res.status === 404) {
+      throw new Error("Team not found");
+    }
+    throw new Error(errorText || "Failed to delete team");
+  }

• Preserves the existing Promise<void> signature
• Leverages server-side permission checks and surfaces clear client-side messages
• UI’s toast.promise will display the thrown message automatically

📝 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
const res = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${options.teamId}`,
{
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
},
},
);
if (!res.ok) {
throw new Error(await res.text());
}
}
const res = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${options.teamId}`,
{
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
},
},
);
if (!res.ok) {
const errorText = await res.text();
if (res.status === 403) {
throw new Error("You don’t have permission to delete this team");
}
if (res.status === 404) {
throw new Error("Team not found");
}
throw new Error(errorText || "Failed to delete team");
}
}
🤖 Prompt for AI Agents
In apps/dashboard/src/@/actions/deleteTeam.ts around lines 13 to 25, improve
error handling by mapping common HTTP failure statuses to more descriptive error
messages instead of throwing a generic error. Keep the Promise<void> signature
and rely on server-side permission enforcement, but update the error block to
check res.status and throw specific errors like "Unauthorized" for 401,
"Forbidden" for 403, or a detailed message from the response text for other
failures. This will allow the UI toast.promise to display clearer messages
automatically.

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.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant