Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions apps/dashboard/src/@/api/team-members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,26 @@ export async function getMembers(teamSlug: string) {

return undefined;
}

export async function getMemberById(teamSlug: string, memberId: string) {
const token = await getAuthToken();

if (!token) {
return undefined;
}

const res = await fetch(
`${API_SERVER_URL}/v1/teams/${teamSlug}/members/${memberId}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
},
);

if (res.ok) {
return (await res.json())?.result as TeamMember;
}

return undefined;
}
32 changes: 17 additions & 15 deletions apps/dashboard/src/@/components/blocks/DangerSettingCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
Expand All @@ -17,13 +16,14 @@ export function DangerSettingCard(props: {
title: string;
className?: string;
footerClassName?: string;
description: string;
description: React.ReactNode;
buttonLabel: string;
buttonOnClick: () => void;
isDisabled?: boolean;
isPending: boolean;
confirmationDialog: {
title: string;
description: string;
description: React.ReactNode;
};
children?: React.ReactNode;
}) {
Expand Down Expand Up @@ -55,28 +55,30 @@ export function DangerSettingCard(props: {
<Button
variant="destructive"
className="gap-2 bg-red-600 font-semibold text-white hover:bg-red-600/80"
disabled={props.isPending}
disabled={props.isDisabled || props.isPending}
>
{props.isPending && <Spinner className="size-3" />}
{props.buttonLabel}
</Button>
</DialogTrigger>

<DialogContent
className="z-[10001]"
className="z-[10001] overflow-hidden p-0"
dialogOverlayClassName="z-[10000]"
>
<DialogHeader className="pr-10">
<DialogTitle className="leading-snug">
{props.confirmationDialog.title}
</DialogTitle>
<div className="p-6">
<DialogHeader className="pr-10">
<DialogTitle className="leading-snug">
{props.confirmationDialog.title}
</DialogTitle>

<DialogDescription>
{props.confirmationDialog.description}
</DialogDescription>
</DialogHeader>
<DialogDescription>
{props.confirmationDialog.description}
</DialogDescription>
</DialogHeader>
</div>

<DialogFooter className="mt-4 gap-4 lg:gap-2">
<div className="flex justify-end gap-4 border-t bg-card p-6 lg:gap-2">
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
Expand All @@ -90,7 +92,7 @@ export function DangerSettingCard(props: {
{props.isPending && <Spinner className="size-3" />}
{props.buttonLabel}
</Button>
</DialogFooter>
</div>
</DialogContent>
</Dialog>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function TeamRow(props: {
<div className="flex items-center gap-4">
<GradientAvatar
className="size-8"
src={props.team.image || undefined}
src={props.team.image || ""}
id={props.team.id}
client={props.client}
/>
Expand Down
35 changes: 14 additions & 21 deletions apps/dashboard/src/app/account/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getTeams } from "@/api/team";
import { getMembers } from "@/api/team-members";
import { getMemberById } from "@/api/team-members";
import { getThirdwebClient } from "@/constants/thirdweb.server";
import { notFound } from "next/navigation";
import { getAuthToken } from "../api/lib/getAuthToken";
import { loginRedirect } from "../login/loginRedirect";
import { AccountTeamsUI } from "./overview/AccountTeamsUI";
Expand All @@ -17,28 +18,20 @@ export default async function Page() {
loginRedirect("/account");
}

const teamsWithRole = (
await Promise.all(
teams.map(async (team) => {
const members = await getMembers(team.slug);
if (!members) {
return {
team,
role: "MEMBER" as const,
};
}
const teamsWithRole = await Promise.all(
teams.map(async (team) => {
const member = await getMemberById(team.slug, account.id);

const accountMemberInfo = members.find(
(m) => m.accountId === account.id,
);
if (!member) {
notFound();
}

return {
team,
role: accountMemberInfo?.role || "MEMBER",
};
}),
)
).filter((x) => !!x);
return {
team,
role: member.role,
};
}),
);

return (
<div className="flex grow flex-col">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { getThirdwebClient } from "@/constants/thirdweb.server";
import type { Meta, StoryObj } from "@storybook/react";
import { Toaster } from "sonner";
import { projectStub } from "../../../../../stories/stubs";
import { mobileViewport } from "../../../../../stories/utils";
import { projectStub, teamStub } from "../../../../../stories/stubs";
import { ProjectGeneralSettingsPageUI } from "./ProjectGeneralSettingsPage";

const meta = {
title: "Project/Settings/General",
title: "Project/Settings",
component: Story,
parameters: {
nextjs: {
Expand All @@ -17,32 +17,56 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;

export const Desktop: Story = {
args: {},
export const OwnerAccount: Story = {
args: {
isOwnerAccount: true,
},
};

export const Mobile: Story = {
args: {},
parameters: {
viewport: mobileViewport("iphone14"),
export const MemberAccount: Story = {
args: {
isOwnerAccount: false,
},
};

function Story() {
function Story(props: {
isOwnerAccount: boolean;
}) {
const currentTeam = teamStub("currentTeam", "free");
return (
<div className="mx-auto w-full max-w-[1100px] px-4 py-6">
<ProjectGeneralSettingsPageUI
isOwnerAccount={props.isOwnerAccount}
transferProject={async (newTeam) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log("transferProject", newTeam);
}}
client={getThirdwebClient()}
teamsWithRole={[
{
role: props.isOwnerAccount ? "OWNER" : "MEMBER",
team: currentTeam,
},
{
role: "OWNER",
team: teamStub("bar", "growth"),
},
{
role: "MEMBER",
team: teamStub("baz", "starter"),
},
]}
updateProject={async (params) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log("updateProject", params);
return projectStub("foo", "team-1");
return projectStub("foo", "currentTeam");
}}
deleteProject={async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log("deleteProject");
}}
project={projectStub("foo", "team-1")}
teamSlug="foo"
project={projectStub("foo", currentTeam.id)}
teamSlug={currentTeam.slug}
onKeyUpdated={undefined}
rotateSecretKey={async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
Expand Down
Loading
Loading