[Dashboard][UI] - User's teams on profile page (#885)

<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md

-->

Adds new team section on user profile pages in the dashboard.
<!-- ELLIPSIS_HIDDEN -->


----

> [!IMPORTANT]
> Adds a new `UserTeamsSection` to display user's teams on the profile
page in `page-client.tsx`.
> 
>   - **New Features**:
> - Adds `UserTeamsSection` component in `page-client.tsx` to display
user's teams on profile page.
> - Displays a table with Team ID, Display Name, Created At, and an
action to open each team in a new tab.
>     - Shows an empty-state card when no teams are found.
> - Integrated the section after the `ContactChannelsSection` on the
user page.
> 
> <sup>This description was created by </sup>[<img alt="Ellipsis"
src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=stack-auth%2Fstack-auth&utm_source=github&utm_medium=referral)<sup>
for e3080a923c. You can
[customize](https://app.ellipsis.dev/stack-auth/settings/summaries) this
summary. It will automatically update as commits are pushed.</sup>

----


<!-- ELLIPSIS_HIDDEN -->

<!-- RECURSEML_SUMMARY:START -->
## Review by RecurseML

_🔍 Review performed on
[9318e2b..7b9e098](9318e2b6ce...7b9e098b22)_

 No bugs found, your code is sparkling clean

<details>
<summary> Files analyzed, no issues (1)</summary>

•
`apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/[userId]/page-client.tsx`
</details>

[![Need help? Join our
Discord](https://img.shields.io/badge/Need%20help%3F%20Join%20our%20Discord-5865F2?style=plastic&logo=discord&logoColor=white)](https://discord.gg/n3SsVDAW6U)
<!-- RECURSEML_SUMMARY:END -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a "Teams" section to the user page showing teams the user
belongs to.
* Displays a table with Team ID, Display Name, Created At, and an action
to open each team in a new tab.
  * Shows an empty-state card when no teams are found.
* Integrated the section after the Contact Channels area on the user
page.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Konsti Wohlwend <n2d4xc@gmail.com>
This commit is contained in:
Madison 2025-09-11 15:37:42 -05:00 committed by GitHub
parent a03774f018
commit 32b42adfbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -854,6 +854,80 @@ function ContactChannelsSection({ user }: ContactChannelsSectionProps) {
);
}
type UserTeamsSectionProps = {
user: ServerUser,
};
function UserTeamsSection({ user }: UserTeamsSectionProps) {
const stackAdminApp = useAdminApp();
const teams = user.useTeams();
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg font-semibold">Teams</h2>
<p className="text-sm text-muted-foreground">Teams this user belongs to</p>
</div>
</div>
{teams.length === 0 ? (
<div className="flex flex-col items-center gap-2 p-4 border rounded-md bg-muted/10">
<p className='text-sm text-gray-500 text-center'>
No teams found
</p>
</div>
) : (
<div className='border rounded-md'>
<Table>
<TableHeader>
<TableRow>
<TableHead>Team ID</TableHead>
<TableHead>Display Name</TableHead>
<TableHead>Created At</TableHead>
<TableHead className="w-[80px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{teams.map((team) => (
<TableRow key={team.id}>
<TableCell>
<div className="font-mono text-xs bg-muted px-2 py-1 rounded max-w-[120px] truncate">
{team.id}
</div>
</TableCell>
<TableCell>
<div className="font-medium">
{team.displayName || '-'}
</div>
</TableCell>
<TableCell>
<div className="text-sm text-muted-foreground">
{team.createdAt.toLocaleDateString()}
</div>
</TableCell>
<TableCell align="right">
<ActionCell
items={[
{
item: "View Team",
onClick: () => {
window.open(`/projects/${stackAdminApp.projectId}/teams/${team.id}`, '_blank', 'noopener');
},
},
]}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
</div>
);
}
type OAuthProvidersSectionProps = {
user: ServerUser,
};
@ -1230,8 +1304,8 @@ function UserPage({ user }: { user: ServerUser }) {
<UserDetails user={user} />
<Separator />
<ContactChannelsSection user={user} />
<UserTeamsSection user={user} />
<OAuthProvidersSection user={user} />
<div />
<MetadataSection user={user} />
</div>
</PageLayout>