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
8 changes: 4 additions & 4 deletions apps/dashboard/src/@/api/team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export type Team = {
slug: string;
createdAt: string;
updatedAt: string;
deletedAt: string | null;
bannedAt: string | null;
// image: string; // -> TODO
deletedAt?: string;
bannedAt?: string;
image?: string;
billingPlan: "pro" | "growth" | "free";
billingStatus: "validPayment" | (string & {}); // what's the other value?
// billingEmail: string;
billingEmail: string;
// billingExternalId: string;
// billingType: "STRIPE" | ??
// billingCustomerPayload: ?? | null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ const testTeam: Team = {
slug: "team-slug-foo-bar",
createdAt: "2023-07-07T19:21:33.604Z",
updatedAt: "2024-07-11T00:01:02.241Z",
deletedAt: null,
bannedAt: null,
billingStatus: "validPayment",
billingPlan: "free",
billingEmail: "[email protected]",
};

function Story() {
Expand All @@ -52,6 +51,10 @@ function Story() {
updateTeamImage={async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
}}
updateTeamField={async (value) => {
console.log(value);
await new Promise((resolve) => setTimeout(resolve, 1000));
}}
/>
<ComponentVariantions />
<Toaster richColors />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,51 @@
"use client";

import type { Team } from "@/api/team";
import type { ThirdwebClient } from "thirdweb";
import { getThirdwebClient } from "@/constants/thirdweb.server";
import { useDashboardRouter } from "@/lib/DashboardRouter";
import { upload } from "thirdweb/storage";
import { TeamGeneralSettingsPageUI } from "./TeamGeneralSettingsPageUI";
import { updateTeam } from "./updateTeam";

export function TeamGeneralSettingsPage(props: {
team: Team;
client: ThirdwebClient;
authToken: string;
}) {
const router = useDashboardRouter();

return (
<TeamGeneralSettingsPageUI
team={props.team}
updateTeamField={async (teamValue) => {
await updateTeam({
teamId: props.team.id,
value: teamValue,
});

// Current page's slug is updated
if (teamValue.slug) {
router.replace(`/team/${teamValue.slug}/~/settings`);
} else {
router.refresh();
}
}}
updateTeamImage={async (file) => {
let uri: string | undefined = undefined;

if (file) {
// upload to IPFS
const uri = await upload({
client: props.client,
uri = await upload({
client: getThirdwebClient(props.authToken),
files: [file],
});

// TODO - Implement updating the account image with uri
console.log(uri);
} else {
// TODO - Implement deleting the account image
}

throw new Error("Not implemented");
await updateTeam({
teamId: props.team.id,
value: {
image: uri,
},
});
}}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,37 @@ import { DangerSettingCard } from "@/components/blocks/DangerSettingCard";
import { SettingsCard } from "@/components/blocks/SettingsCard";
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { Input } from "@/components/ui/input";
import { useThirdwebClient } from "@/constants/thirdweb.client";
import { useDashboardRouter } from "@/lib/DashboardRouter";
import { useMutation } from "@tanstack/react-query";
import { FileInput } from "components/shared/FileInput";
import { useState } from "react";
import { toast } from "sonner";
import { resolveScheme } from "thirdweb/storage";

type UpdateTeamField = (team: Partial<Team>) => Promise<void>;

export function TeamGeneralSettingsPageUI(props: {
team: Team;
updateTeamImage: (file: File | undefined) => Promise<void>;
updateTeamField: UpdateTeamField;
}) {
const hasPermissionToDelete = false; // TODO
return (
<div className="flex flex-col gap-8">
<TeamNameFormControl team={props.team} />
<TeamSlugFormControl team={props.team} />
<TeamAvatarFormControl updateTeamImage={props.updateTeamImage} />
<TeamNameFormControl
team={props.team}
updateTeamField={props.updateTeamField}
/>
<TeamSlugFormControl
team={props.team}
updateTeamField={props.updateTeamField}
/>
{/* THIS IS NOT WORKING - CAN"T UPDATE IMAGE */}
<TeamAvatarFormControl
updateTeamImage={props.updateTeamImage}
avatar={props.team.image}
/>
<TeamIdCard team={props.team} />
<LeaveTeamCard enabled={false} teamName={props.team.name} />
<DeleteTeamCard
Expand All @@ -33,17 +48,13 @@ export function TeamGeneralSettingsPageUI(props: {

function TeamNameFormControl(props: {
team: Team;
updateTeamField: UpdateTeamField;
}) {
const [teamName, setTeamName] = useState(props.team.name);
const maxTeamNameLength = 32;

// TODO - implement
const updateTeamMutation = useMutation({
mutationFn: async (teamName: string) => {
await new Promise((resolve) => setTimeout(resolve, 3000));
console.log("Updating team name to", teamName);
throw new Error("Not implemented");
},
mutationFn: (name: string) => props.updateTeamField({ name }),
});

function handleSave() {
Expand Down Expand Up @@ -82,20 +93,14 @@ function TeamNameFormControl(props: {

function TeamSlugFormControl(props: {
team: Team;
updateTeamField: (team: Partial<Team>) => Promise<void>;
}) {
const [teamSlug, setTeamSlug] = useState(props.team.slug);
const [isTeamTaken] = useState(false);
const maxTeamURLLength = 48;

// TODO - implement
const updateTeamMutation = useMutation({
mutationFn: async (_slug: string) => {
// set isTeamTaken to true if team URL is taken
// Fake loading
await new Promise((resolve) => setTimeout(resolve, 3000));
console.log("Updating team slug to", _slug);
throw new Error("Not implemented");
},
mutationFn: (slug: string) => props.updateTeamField({ slug: slug }),
});

function handleSave() {
Expand Down Expand Up @@ -144,8 +149,17 @@ function TeamSlugFormControl(props: {

function TeamAvatarFormControl(props: {
updateTeamImage: (file: File | undefined) => Promise<void>;
avatar: string | undefined;
}) {
const [teamAvatar, setTeamAvatar] = useState<File>(); // TODO: prefill with team avatar
const client = useThirdwebClient();
const teamUrl = props.avatar
? resolveScheme({
client: client,
uri: props.avatar,
})
: undefined;

const [teamAvatar, setTeamAvatar] = useState<File | undefined>();

const updateTeamAvatarMutation = useMutation({
mutationFn: async (_avatar: File | undefined) => {
Expand Down Expand Up @@ -186,6 +200,7 @@ function TeamAvatarFormControl(props: {
setValue={setTeamAvatar}
className="w-20 rounded-full lg:w-28"
disableHelperText
fileUrl={teamUrl}
/>
</div>
</SettingsCard>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use server";

import type { Team } from "@/api/team";
import { API_SERVER_URL } from "@/constants/env";
import { getAuthToken } from "../../../../../../api/lib/getAuthToken";

export async function updateTeam(params: {
teamId: string;
value: Partial<Team>;
}) {
const authToken = getAuthToken();

if (!authToken) {
throw new Error("No auth token");
}

const res = await fetch(`${API_SERVER_URL}/v1/teams/${params.teamId}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${authToken}`,
},
body: JSON.stringify(params.value),
});

if (!res.ok) {
throw new Error("failed to update team");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@ const freeTeam: Team = {
slug: "team-slug-foo-bar",
createdAt: "2023-07-07T19:21:33.604Z",
updatedAt: "2024-07-11T00:01:02.241Z",
deletedAt: null,
bannedAt: null,
billingStatus: "validPayment",
billingPlan: "free",
billingEmail: "[email protected]",
};

const proTeam: Team = {
Expand All @@ -52,10 +51,9 @@ const proTeam: Team = {
slug: "team-slug-foo-bar",
createdAt: "2023-07-07T19:21:33.604Z",
updatedAt: "2024-07-11T00:01:02.241Z",
deletedAt: null,
bannedAt: null,
billingStatus: "validPayment",
billingPlan: "pro",
billingEmail: "[email protected]",
};

function createMemberStub(id: string, role: TeamAccountRole): TeamMember {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getTeamBySlug } from "@/api/team";
import { getThirdwebClient } from "@/constants/thirdweb.server";
import { notFound } from "next/navigation";
import { getAuthToken } from "../../../../../api/lib/getAuthToken";
import { TeamGeneralSettingsPage } from "./general/TeamGeneralSettingsPage";
Expand All @@ -15,7 +14,5 @@ export default async function Page(props: {
notFound();
}

return (
<TeamGeneralSettingsPage team={team} client={getThirdwebClient(token)} />
);
return <TeamGeneralSettingsPage team={team} authToken={token} />;
}
4 changes: 3 additions & 1 deletion apps/dashboard/src/components/shared/FileInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface IFileInputProps {
children?: React.ReactNode;
className?: string;
disableHelperText?: boolean;
fileUrl?: string;
}

export const FileInput: React.FC<IFileInputProps> = ({
Expand All @@ -45,6 +46,7 @@ export const FileInput: React.FC<IFileInputProps> = ({
className,
previewMaxWidth,
disableHelperText,
fileUrl: fileUrlFallback,
}) => {
const onDrop = useCallback<
<T extends File>(
Expand All @@ -67,7 +69,7 @@ export const FileInput: React.FC<IFileInputProps> = ({

const file: File | null =
typeof window !== "undefined" && value instanceof File ? value : null;
const fileUrl = useImageFileOrUrl(value);
const fileUrl = useImageFileOrUrl(value) || fileUrlFallback || "";

const helperTextOrFile = helperText
? helperText
Expand Down
3 changes: 1 addition & 2 deletions apps/dashboard/src/stories/stubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ export function teamStub(
billingStatus: "validPayment",
name: `Team ${id}`,
slug: `team-${id}`,
bannedAt: null,
createdAt: new Date().toISOString(),
deletedAt: null,
updatedAt: new Date().toISOString(),
billingEmail: "[email protected]",
};

return team;
Expand Down
Loading