From 4165f4fe266c2487a3d2ab558f130a6ed0f41516 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Wed, 21 May 2025 10:49:20 -0700 Subject: [PATCH] [Dashboard] Add ecosystem logo upload functionality --- .../components/EcosystemSlugLayout.tsx | 10 ++ .../components/ecosystem-header.client.tsx | 147 +++++++++++++++++- 2 files changed, 152 insertions(+), 5 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/components/EcosystemSlugLayout.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/components/EcosystemSlugLayout.tsx index b6d4abc5531..5e17d197064 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/components/EcosystemSlugLayout.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/components/EcosystemSlugLayout.tsx @@ -1,3 +1,4 @@ +import { getTeamBySlug } from "@/api/team"; import { SidebarLayout } from "@/components/blocks/SidebarLayout"; import { redirect } from "next/navigation"; import { getAuthToken } from "../../../../../../../../api/lib/getAuthToken"; @@ -25,6 +26,13 @@ export async function EcosystemLayoutSlug({ params.team_slug, ); + // Fetch team details to obtain team ID for further authenticated updates + const team = await getTeamBySlug(params.team_slug); + + if (!team) { + redirect(ecosystemLayoutPath); + } + if (!ecosystem) { redirect(ecosystemLayoutPath); } @@ -35,6 +43,8 @@ export async function EcosystemLayoutSlug({ ecosystem={ecosystem} ecosystemLayoutPath={ecosystemLayoutPath} teamIdOrSlug={params.team_slug} + authToken={authToken} + teamId={team.id} /> (null); + + const storageUpload = useDashboardStorageUpload(); + const router = useDashboardRouter(); + + const { mutateAsync: updateEcosystem, isPending: isUpdating } = + useUpdateEcosystem( + { + authToken: props.authToken, + teamId: props.teamId, + }, + { + onSuccess: () => { + toast.success("Ecosystem image updated"); + setIsDialogOpen(false); + router.refresh(); + }, + onError: (error) => { + const message = + error instanceof Error ? error.message : "Failed to update image"; + toast.error(message); + }, + }, + ); + + const isUploading = storageUpload.isPending || isUpdating; + + async function handleUpload() { + if (!selectedFile) { + toast.error("Please select an image to upload"); + return; + } + + // Validate file type + const validTypes = ["image/png", "image/jpeg", "image/webp"]; + if (!validTypes.includes(selectedFile.type)) { + toast.error("Only PNG, JPG or WEBP images are allowed"); + return; + } + + try { + const [uri] = await storageUpload.mutateAsync([selectedFile]); + await updateEcosystem({ + ...ecosystem, + imageUrl: uri, + }); + } catch (err) { + console.error(err); + toast.error("Failed to upload image"); + } + } + return (
@@ -146,11 +220,74 @@ export function EcosystemHeader(props: { ) : ( ecosystemImageLink && ( - {ecosystem.name} +
+ {ecosystem.name} + + {/* Upload Dialog */} + + + + + + + Update Ecosystem Logo + + +
+ { + if (files?.[0]) { + setSelectedFile(files[0]); + } + }} + accept="image/png,image/jpeg,image/webp" + /> +
+ + + + + + + +
+
+
) )}