From 0bbd0ecfa0a339f74a8df82a05ddde9419971872 Mon Sep 17 00:00:00 2001 From: CTO Agent Date: Mon, 6 Apr 2026 16:54:26 +0000 Subject: [PATCH] feat: show social PFP and username on connected artist connectors When an artist has a connected Instagram or TikTok connector, the connector card now displays the social profile picture and @username instead of the generic connector icon and description. Co-Authored-By: Paperclip --- .../ArtistSetting/ArtistConnectorsTab.tsx | 53 +++++++++++++------ components/ConnectorsPage/ConnectorCard.tsx | 34 ++++++++++-- lib/composio/matchSocialToConnector.ts | 18 +++++++ 3 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 lib/composio/matchSocialToConnector.ts diff --git a/components/ArtistSetting/ArtistConnectorsTab.tsx b/components/ArtistSetting/ArtistConnectorsTab.tsx index 50173bf9b..c3e792f98 100644 --- a/components/ArtistSetting/ArtistConnectorsTab.tsx +++ b/components/ArtistSetting/ArtistConnectorsTab.tsx @@ -1,8 +1,11 @@ "use client"; import { useMemo } from "react"; +import { useQuery } from "@tanstack/react-query"; import { useConnectors } from "@/hooks/useConnectors"; import { ALLOWED_ARTIST_CONNECTORS } from "@/lib/composio/allowedArtistConnectors"; +import { getArtistSocials } from "@/lib/api/artist/getArtistSocials"; +import { matchSocialToConnector } from "@/lib/composio/matchSocialToConnector"; import { ConnectorCard } from "@/components/ConnectorsPage/ConnectorCard"; import { Loader2, Plug } from "lucide-react"; @@ -14,15 +17,29 @@ interface ArtistConnectorsTabProps { * Connectors tab content for the Artist Settings modal. * Reuses ConnectorCard from the user-level ConnectorsPage (DRY). */ -export function ArtistConnectorsTab({ artistAccountId }: ArtistConnectorsTabProps) { - const config = useMemo(() => ({ - accountId: artistAccountId, - allowedSlugs: [...ALLOWED_ARTIST_CONNECTORS], - callbackUrl: `${window.location.origin}${window.location.pathname}?artist_connected=true&artist_id=${artistAccountId}`, - }), [artistAccountId]); +export function ArtistConnectorsTab({ + artistAccountId, +}: ArtistConnectorsTabProps) { + const config = useMemo( + () => ({ + accountId: artistAccountId, + allowedSlugs: [...ALLOWED_ARTIST_CONNECTORS], + callbackUrl: `${window.location.origin}${window.location.pathname}?artist_connected=true&artist_id=${artistAccountId}`, + }), + [artistAccountId], + ); const { connectors, isLoading, error, authorize, disconnect } = useConnectors(config); + const { data: socialsData } = useQuery({ + queryKey: ["artistSocials", artistAccountId], + queryFn: () => getArtistSocials(artistAccountId), + enabled: !!artistAccountId, + staleTime: 1000 * 60 * 5, + }); + + const socials = socialsData?.socials ?? []; + if (isLoading) { return (
@@ -51,17 +68,23 @@ export function ArtistConnectorsTab({ artistAccountId }: ArtistConnectorsTabProp return (

- Connect third-party services so the AI agent can take actions on behalf of this artist. + Connect third-party services so the AI agent can take actions on behalf + of this artist.

- {connectors.map((connector) => ( - - ))} + {connectors.map((connector) => { + const social = matchSocialToConnector(connector.slug, socials); + return ( + + ); + })}
); diff --git a/components/ConnectorsPage/ConnectorCard.tsx b/components/ConnectorsPage/ConnectorCard.tsx index 1dbeca5e9..34b30bfd0 100644 --- a/components/ConnectorsPage/ConnectorCard.tsx +++ b/components/ConnectorsPage/ConnectorCard.tsx @@ -12,6 +12,8 @@ interface ConnectorCardProps { connector: ConnectorInfo; onConnect: (slug: string) => Promise; onDisconnect: (connectedAccountId: string) => Promise; + socialAvatar?: string | null; + socialUsername?: string | null; } /** @@ -21,6 +23,8 @@ export function ConnectorCard({ connector, onConnect, onDisconnect, + socialAvatar, + socialUsername, }: ConnectorCardProps) { const { isConnecting, isDisconnecting, handleConnect, handleDisconnect } = useConnectorHandlers({ @@ -30,11 +34,31 @@ export function ConnectorCard({ onDisconnect, }); const meta = getConnectorMeta(connector.slug); + const showSocialProfile = + connector.isConnected && (socialAvatar || socialUsername); return (
-
- {getConnectorIcon(connector.slug, 22)} +
+ {showSocialProfile && socialAvatar ? ( +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {socialUsername +
+ {getConnectorIcon(connector.slug, 14)} +
+
+ ) : ( +
+ {getConnectorIcon(connector.slug, 22)} +
+ )}
@@ -42,7 +66,9 @@ export function ConnectorCard({ {formatConnectorName(connector.name, connector.slug)}

- {meta.description} + {showSocialProfile && socialUsername + ? `@${socialUsername}` + : meta.description}

@@ -53,7 +79,7 @@ export function ConnectorCard({ onReconnect={handleConnect} onDisconnect={handleDisconnect} /> - ) : ( + ) : ( = { + instagram: "instagram.com", + tiktok: "tiktok.com", +}; + +/** + * Find the matching social profile for a connector slug. + */ +export function matchSocialToConnector( + slug: string, + socials: Social[], +): Social | undefined { + const domain = CONNECTOR_SOCIAL_DOMAINS[slug]; + if (!domain) return undefined; + return socials.find((s) => s.profile_url?.toLowerCase().includes(domain)); +}