From 88db5eaeab8919acb5791a37fea21f5d6471ea78 Mon Sep 17 00:00:00 2001 From: MananTank Date: Thu, 26 Sep 2024 20:43:18 +0000 Subject: [PATCH] Add upload to IPFS on teams & account avatar form fields (#4807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem solved Short description of the bug fixed or feature added --- ## PR-Codex overview This PR focuses on enhancing the account and team settings pages by adding image upload functionality for accounts and teams, updating component imports, and improving layout responsiveness. ### Detailed summary - Added `updateAccountImage` method to `AccountSettingsPage` and `AccountSettingsPageUI`. - Introduced `updateTeamImage` method in `TeamGeneralSettingsPage` and `TeamGeneralSettingsPageUI`. - Changed layout from `min-h-full` to `min-h-screen`. - Updated import statements to reflect new component names. - Implemented async image upload functionality with IPFS integration. - Added error handling for image update methods. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- apps/dashboard/src/app/account/layout.tsx | 2 +- .../account/settings/AccountSettingsPage.tsx | 33 +++++++++++++++++++ .../AccountSettingsPageUI.stories.tsx | 3 ++ .../settings/AccountSettingsPageUI.tsx | 13 ++++---- .../src/app/account/settings/page.tsx | 11 +++++-- .../general/GeneralSettingsPage.stories.tsx | 11 +++++-- .../general/TeamGeneralSettingsPage.tsx | 33 +++++++++++++++++++ ...Page.tsx => TeamGeneralSettingsPageUI.tsx} | 15 ++++----- .../[team_slug]/(team)/~/settings/page.tsx | 12 ++++--- .../ProjectGeneralSettingsPageForTeams.tsx | 2 ++ 10 files changed, 109 insertions(+), 26 deletions(-) create mode 100644 apps/dashboard/src/app/account/settings/AccountSettingsPage.tsx create mode 100644 apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPage.tsx rename apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/{GeneralSettingsPage.tsx => TeamGeneralSettingsPageUI.tsx} (96%) diff --git a/apps/dashboard/src/app/account/layout.tsx b/apps/dashboard/src/app/account/layout.tsx index bbcba3bdc2e..44468bd7e4f 100644 --- a/apps/dashboard/src/app/account/layout.tsx +++ b/apps/dashboard/src/app/account/layout.tsx @@ -10,7 +10,7 @@ export default async function AccountLayout(props: { children: React.ReactNode; }) { return ( -
+
diff --git a/apps/dashboard/src/app/account/settings/AccountSettingsPage.tsx b/apps/dashboard/src/app/account/settings/AccountSettingsPage.tsx new file mode 100644 index 00000000000..a1382d698d1 --- /dev/null +++ b/apps/dashboard/src/app/account/settings/AccountSettingsPage.tsx @@ -0,0 +1,33 @@ +"use client"; + +import type { Account } from "@3rdweb-sdk/react/hooks/useApi"; +import type { ThirdwebClient } from "thirdweb"; +import { upload } from "thirdweb/storage"; +import { AccountSettingsPageUI } from "./AccountSettingsPageUI"; + +export function AccountSettingsPage(props: { + account: Account; + client: ThirdwebClient; +}) { + return ( + { + if (file) { + // upload to IPFS + const ipfsUri = await upload({ + client: props.client, + files: [file], + }); + + // TODO - Implement updating the account image with uri + console.log(ipfsUri); + } else { + // TODO - Implement deleting the account image + } + + throw new Error("Not implemented"); + }} + /> + ); +} diff --git a/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.stories.tsx b/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.stories.tsx index 93db9894edd..52687d5699a 100644 --- a/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.stories.tsx +++ b/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.stories.tsx @@ -41,6 +41,9 @@ function Variants() { name: "John Doe", email: "johndoe@gmail.com", }} + updateAccountImage={async () => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + }} />
diff --git a/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.tsx b/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.tsx index 8c102a0b735..9d96fc6a3fe 100644 --- a/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.tsx +++ b/apps/dashboard/src/app/account/settings/AccountSettingsPageUI.tsx @@ -42,10 +42,11 @@ type MinimalAccount = Pick< export function AccountSettingsPageUI(props: { account: MinimalAccount; + updateAccountImage: (file: File | undefined) => Promise; }) { return (
- + Promise; +}) { const [avatar, setAvatar] = useState(); // TODO: prefill with account avatar - // TODO - implement const updateAvatarMutation = useMutation({ mutationFn: async (_avatar: File | undefined) => { - // Fake loading - await new Promise((resolve) => setTimeout(resolve, 3000)); - console.log("Updating account image to", _avatar); - throw new Error("Not implemented"); + await props.updateAccountImage(_avatar); }, }); diff --git a/apps/dashboard/src/app/account/settings/page.tsx b/apps/dashboard/src/app/account/settings/page.tsx index 0f8d695ccc1..55d9c096e3f 100644 --- a/apps/dashboard/src/app/account/settings/page.tsx +++ b/apps/dashboard/src/app/account/settings/page.tsx @@ -1,13 +1,18 @@ +import { getThirdwebClient } from "@/constants/thirdweb.server"; import { redirect } from "next/navigation"; -import { AccountSettingsPageUI } from "./AccountSettingsPageUI"; +import { getAuthToken } from "../../api/lib/getAuthToken"; +import { AccountSettingsPage } from "./AccountSettingsPage"; import { getAccount } from "./getAccount"; export default async function Page() { const account = await getAccount(); + const token = getAuthToken(); - if (!account) { + if (!account || !token) { redirect(`/login?next=${encodeURIComponent("/account")}`); } - return ; + return ( + + ); } diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx index 3a60b4019cf..7638a60ada7 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.stories.tsx @@ -4,9 +4,9 @@ import type { Meta, StoryObj } from "@storybook/react"; import { mobileViewport } from "../../../../../../../stories/utils"; import { DeleteTeamCard, - GeneralSettingsPage, LeaveTeamCard, -} from "./GeneralSettingsPage"; + TeamGeneralSettingsPageUI, +} from "./TeamGeneralSettingsPageUI"; const meta = { title: "Team/Settings/General", @@ -47,7 +47,12 @@ const testTeam: Team = { function Story() { return (
- + { + await new Promise((resolve) => setTimeout(resolve, 1000)); + }} + />
diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPage.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPage.tsx new file mode 100644 index 00000000000..53e4d5fedbc --- /dev/null +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPage.tsx @@ -0,0 +1,33 @@ +"use client"; + +import type { Team } from "@/api/team"; +import type { ThirdwebClient } from "thirdweb"; +import { upload } from "thirdweb/storage"; +import { TeamGeneralSettingsPageUI } from "./TeamGeneralSettingsPageUI"; + +export function TeamGeneralSettingsPage(props: { + team: Team; + client: ThirdwebClient; +}) { + return ( + { + if (file) { + // upload to IPFS + const uri = await upload({ + client: props.client, + 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"); + }} + /> + ); +} diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx similarity index 96% rename from apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.tsx rename to apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx index ea72012a124..41b7a3bb681 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/GeneralSettingsPage.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx @@ -11,15 +11,16 @@ import { FileInput } from "components/shared/FileInput"; import { useState } from "react"; import { toast } from "sonner"; -export function GeneralSettingsPage(props: { +export function TeamGeneralSettingsPageUI(props: { team: Team; + updateTeamImage: (file: File | undefined) => Promise; }) { const hasPermissionToDelete = false; // TODO return (
- + Promise; +}) { const [teamAvatar, setTeamAvatar] = useState(); // TODO: prefill with team avatar - // TODO - implement const updateTeamAvatarMutation = useMutation({ mutationFn: async (_avatar: File | undefined) => { - // Fake loading - await new Promise((resolve) => setTimeout(resolve, 3000)); - console.log("Updating team name to", _avatar); - throw new Error("Not implemented"); + await props.updateTeamImage(_avatar); }, }); diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/page.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/page.tsx index cfde7fff358..6b9e1ba84a0 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/page.tsx @@ -1,6 +1,8 @@ import { getTeamBySlug } from "@/api/team"; +import { getThirdwebClient } from "@/constants/thirdweb.server"; import { notFound } from "next/navigation"; -import { GeneralSettingsPage } from "./general/GeneralSettingsPage"; +import { getAuthToken } from "../../../../../api/lib/getAuthToken"; +import { TeamGeneralSettingsPage } from "./general/TeamGeneralSettingsPage"; export default async function Page(props: { params: { @@ -8,10 +10,12 @@ export default async function Page(props: { }; }) { const team = await getTeamBySlug(props.params.team_slug); - - if (!team) { + const token = getAuthToken(); + if (!team || !token) { notFound(); } - return ; + return ( + + ); } diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPageForTeams.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPageForTeams.tsx index 6748215aa2b..ac87800da7c 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPageForTeams.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPageForTeams.tsx @@ -13,6 +13,8 @@ export function ProjectGeneralSettingsPageForTeams(props: { const { team_slug, project_slug, apiKey } = props; const projectSettingsLayout = `/team/${team_slug}/${project_slug}/settings`; + // TODO - add a Project Image form field on this page + return (