Skip to content

Feat/partner logo branding#8668

Merged
joaquim-verges merged 3 commits intomainfrom
feat/partner-logo-branding
Feb 10, 2026
Merged

Feat/partner logo branding#8668
joaquim-verges merged 3 commits intomainfrom
feat/partner-logo-branding

Conversation

@eabdelmoneim
Copy link
Contributor

@eabdelmoneim eabdelmoneim commented Feb 10, 2026

https://linear.app/thirdweb/issue/BLD-547/partner-branding-for-ecosystem-wallet-email-otp


PR-Codex overview

This PR introduces support for uploading and managing partner logos in the dashboard application. It adds optional imageUrl fields in relevant data structures and modifies forms to handle logo uploads, including validation for file types and sizes.

Detailed summary

  • Added imageUrl property to ecosystems.ts and related types.
  • Enhanced useUpdatePartner and useAddPartner hooks to include imageUrl.
  • Updated partnerFormSchema to validate logo file uploads.
  • Implemented logo upload functionality in AddPartnerForm and UpdatePartnerForm.
  • Added UI components for logo selection and preview in partner-form.client.tsx.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features
    • Partners can now upload and manage logos shown in OTP emails and partner settings.
    • Upload UI supports PNG, JPEG, and WebP images up to 500KB; users can add, change, or remove logos.
    • Upload progress and errors are surfaced during save operations so submissions reflect image upload state.

eabdelmoneim and others added 2 commits February 10, 2026 14:47
Add optional logo upload field to partner create/update forms so
ecosystem partners can have distinct branding in OTP emails.

- Add imageUrl to Partner type
- Add imageUrl to add/update partner mutation hooks
- Add ImageUpload component to partner form with existing logo preview
- Upload logo via useDashboardStorageUpload before sending URL to API
- Add logo File field to partner form Zod schema

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…nd validation

- Add file type validation (PNG, JPG, WEBP only) to logo upload schema
- Add removeLogo boolean to form schema for explicit logo removal
- Add X button on existing logo preview to allow clearing the logo
- Fix update form to handle 3 states: new upload, explicit removal, preserve existing
- Reset removeLogo when a new file is uploaded

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@eabdelmoneim eabdelmoneim requested review from a team as code owners February 10, 2026 21:33
@vercel
Copy link

vercel bot commented Feb 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
thirdweb-www Ready Ready Preview, Comment Feb 10, 2026 10:46pm
4 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs-v2 Skipped Skipped Feb 10, 2026 10:46pm
nebula Skipped Skipped Feb 10, 2026 10:46pm
thirdweb_playground Skipped Skipped Feb 10, 2026 10:46pm
wallet-ui Skipped Skipped Feb 10, 2026 10:46pm

@changeset-bot
Copy link

changeset-bot bot commented Feb 10, 2026

⚠️ No Changeset found

Latest commit: f64d114

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 10, 2026

Walkthrough

Adds optional partner imageUrl and UI for uploading/removing a partner logo in the dashboard. Wires storage upload into add/update partner flows, validates image file (image/png, image/jpeg, image/webp ≤500KB), and includes imageUrl in create/update API payloads.

Changes

Cohort / File(s) Summary
API Type
apps/dashboard/src/@/api/team/ecosystems.ts
Added imageUrl?: string to Partner type.
Form Schema / Validation
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/constants.ts
Added logo (File, image/png
Add Partner UI & Upload
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/add-partner-form.client.tsx
Integrated useDashboardStorageUpload, upload flow in submit handler, error toast on upload failure, pass imageUrl to add mutation, and surface upload loading state.
Partner Form UI
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx
Added logo field UI: preview existing or newly selected image, remove/change controls, hidden file input & ImageUpload component, and form state for logo and removeLogo.
Update Partner UI & Upload
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/update-partner-form.client.tsx
Wired useDashboardStorageUpload, compute imageUrl (upload / remove / preserve), include in update payload, and combine upload state with submitting indicator.
API Hooks
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/hooks/use-add-partner.ts, .../use-update-partner.ts
Extended AddPartnerParams and UpdatePartnerParams with optional imageUrl and threaded imageUrl into POST/PATCH request bodies.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Form as Partner Form
    participant Storage as Storage Upload
    participant API as API Mutation
    participant DB as Database

    User->>Form: Select/logo file and submit
    Form->>Storage: Upload image file
    activate Storage
    Storage-->>Form: imageUrl or error
    deactivate Storage

    alt Upload success
        Form->>API: Create/Update partner with imageUrl
        activate API
        API->>DB: Persist partner (imageUrl optional)
        DB-->>API: OK
        API-->>Form: Success
        deactivate API
        Form->>User: Redirect / success UI
    else Upload failure
        Form->>User: Show upload error toast
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description references the Linear issue link and includes a PR-Codex overview with a detailed summary of changes. However, it does not explicitly follow the required template structure with sections for 'Notes for the reviewer' and 'How to test'. Add missing sections: 'Notes for the reviewer' to highlight important implementation details and 'How to test' with specific testing instructions for the logo upload functionality.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feat/partner logo branding' directly relates to the main objective of adding partner logo support and branding capabilities in the dashboard, clearly summarizing the primary change.
Linked Issues check ✅ Passed The PR implements all key requirements from BLD-547: imageUrl field added to Partner type, logo upload UI in forms with file validation, hooks updated to pass imageUrl, and backward compatibility maintained. All coding objectives are satisfied.
Out of Scope Changes check ✅ Passed All changes align with BLD-547 objectives: imageUrl field additions, form schema extensions, hook updates, and UI components for logo upload. No unrelated modifications detected outside the partner logo branding scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/partner-logo-branding

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Feb 10, 2026
@codecov
Copy link

codecov bot commented Feb 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 52.72%. Comparing base (b7dfde2) to head (f64d114).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8668   +/-   ##
=======================================
  Coverage   52.72%   52.72%           
=======================================
  Files         934      934           
  Lines       62975    62975           
  Branches     4136     4136           
=======================================
  Hits        33205    33205           
  Misses      29670    29670           
  Partials      100      100           
Flag Coverage Δ
packages 52.72% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 10, 2026

size-limit report 📦

Path Size
@thirdweb-dev/nexus (esm) 105.66 KB (0%)
@thirdweb-dev/nexus (cjs) 319.47 KB (0%)

…hange

- Show drag-and-drop only when no logo is set
- When logo exists, show image with X (remove) and pencil (change) overlays
- X button uses ghost variant with bg-background instead of destructive red
- New file upload shows preview immediately via URL.createObjectURL

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@vercel vercel bot temporarily deployed to Preview – nebula February 10, 2026 22:38 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground February 10, 2026 22:38 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 February 10, 2026 22:38 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui February 10, 2026 22:38 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/dashboard/src/app/`(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx:
- Around line 160-165: The preview URL is being created on every render
(newFilePreview = URL.createObjectURL(logoFile)) and never revoked; update the
partner-form.client.tsx component to import useEffect and useState alongside
useId/useRef, create a state like [newFilePreview, setNewFilePreview] in the
component, and move the blob creation into a useEffect that depends on the
watched logo file (logoFile from form.watch) and removeLogo as needed—inside the
effect call URL.createObjectURL(logoFile) and setNewFilePreview, and in the
effect cleanup revoke the previous URL with URL.revokeObjectURL and clear state
so URLs are revoked when the file changes or the component unmounts.

Comment on lines +160 to +165
render={() => {
const removeLogo = form.watch("removeLogo");
const logoFile = form.watch("logo");
const newFilePreview = logoFile
? URL.createObjectURL(logoFile)
: undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd "partner-form.client.tsx"

Repository: thirdweb-dev/js

Length of output: 480


🏁 Script executed:

wc -l "apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx"

Repository: thirdweb-dev/js

Length of output: 199


🏁 Script executed:

sed -n '140,180p' "apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx"

Repository: thirdweb-dev/js

Length of output: 1523


🏁 Script executed:

head -50 "apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx"

Repository: thirdweb-dev/js

Length of output: 1612


🏁 Script executed:

sed -n '50,120p' "apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx"

Repository: thirdweb-dev/js

Length of output: 2693


🏁 Script executed:

sed -n '155,210p' "apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx"

Repository: thirdweb-dev/js

Length of output: 2437


🏁 Script executed:

sed -n '200,250p' "apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx"

Repository: thirdweb-dev/js

Length of output: 2428


🏁 Script executed:

rg "URL.createObjectURL" -A 3 -B 3

Repository: thirdweb-dev/js

Length of output: 9859


🏁 Script executed:

sed -n '1,10p' "apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx"

Repository: thirdweb-dev/js

Length of output: 476


Move blob URL creation to an effect with proper cleanup to prevent memory leaks.

URL.createObjectURL is called during every render and never revoked, causing blob URLs to leak and potentially reload the preview. Move preview creation to a useEffect with a cleanup function that revokes the URL when the file changes or the component unmounts. This also requires adding useEffect and useState to the React import (currently only useId and useRef are imported).

♻️ Suggested fix (creates/revokes preview URLs safely)
-import { useId, useRef } from "react";
+import { useEffect, useId, useRef, useState } from "react";
@@
   const accessControlEnabled = form.watch("accessControlEnabled");
   const serverVerifierEnabled = form.watch("serverVerifierEnabled");
   const allowedOperationsEnabled = form.watch("allowedOperationsEnabled");
+  const logoFile = form.watch("logo");
+  const removeLogo = form.watch("removeLogo");
+  const [newFilePreview, setNewFilePreview] = useState<string | undefined>(
+    undefined,
+  );
+
+  useEffect(() => {
+    if (!logoFile) {
+      setNewFilePreview(undefined);
+      return;
+    }
+    const objectUrl = URL.createObjectURL(logoFile);
+    setNewFilePreview(objectUrl);
+    return () => URL.revokeObjectURL(objectUrl);
+  }, [logoFile]);
@@
-              const removeLogo = form.watch("removeLogo");
-              const logoFile = form.watch("logo");
-              const newFilePreview = logoFile
-                ? URL.createObjectURL(logoFile)
-                : undefined;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
render={() => {
const removeLogo = form.watch("removeLogo");
const logoFile = form.watch("logo");
const newFilePreview = logoFile
? URL.createObjectURL(logoFile)
: undefined;
render={() => {
🤖 Prompt for AI Agents
In
`@apps/dashboard/src/app/`(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/configuration/components/client/partner-form.client.tsx
around lines 160 - 165, The preview URL is being created on every render
(newFilePreview = URL.createObjectURL(logoFile)) and never revoked; update the
partner-form.client.tsx component to import useEffect and useState alongside
useId/useRef, create a state like [newFilePreview, setNewFilePreview] in the
component, and move the blob creation into a useEffect that depends on the
watched logo file (logoFile from form.watch) and removeLogo as needed—inside the
effect call URL.createObjectURL(logoFile) and setNewFilePreview, and in the
effect cleanup revoke the previous URL with URL.revokeObjectURL and clear state
so URLs are revoked when the file changes or the component unmounts.

@joaquim-verges joaquim-verges merged commit 1eb0cd9 into main Feb 10, 2026
25 checks passed
@joaquim-verges joaquim-verges deleted the feat/partner-logo-branding branch February 10, 2026 22:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants