diff --git a/src/types/src/api/requests.ts b/src/types/src/api/requests.ts index 974b4d98..61516710 100644 --- a/src/types/src/api/requests.ts +++ b/src/types/src/api/requests.ts @@ -161,6 +161,7 @@ export interface GenerateExtensionTokensRequest { export interface GetProfileParams { identifier: string; // Can be DID or handle + includeStats?: boolean; // Include card and collection counts } export interface GetUrlMetadataParams { diff --git a/src/webapp/api-client/ApiClient.ts b/src/webapp/api-client/ApiClient.ts index e4da5b23..1e174e30 100644 --- a/src/webapp/api-client/ApiClient.ts +++ b/src/webapp/api-client/ApiClient.ts @@ -172,8 +172,10 @@ export class ApiClient { return this.queryClient.getLibrariesForCard(cardId); } - async getMyProfile(): Promise { - return this.queryClient.getMyProfile(); + async getMyProfile(params?: { + includeStats?: boolean; + }): Promise { + return this.queryClient.getMyProfile(params); } async getProfile(params: GetProfileParams): Promise { diff --git a/src/webapp/api-client/clients/QueryClient.ts b/src/webapp/api-client/clients/QueryClient.ts index 6a8bf975..f09a51b9 100644 --- a/src/webapp/api-client/clients/QueryClient.ts +++ b/src/webapp/api-client/clients/QueryClient.ts @@ -124,14 +124,29 @@ export class QueryClient extends BaseClient { ); } - async getMyProfile(): Promise { - return this.request('GET', '/api/users/me'); + async getMyProfile(params?: { + includeStats?: boolean; + }): Promise { + const queryParams = new URLSearchParams(); + if (params?.includeStats !== undefined) { + queryParams.set('includeStats', params.includeStats.toString()); + } + const queryString = queryParams.toString(); + return this.request( + 'GET', + `/api/users/me${queryString ? `?${queryString}` : ''}`, + ); } async getUserProfile(params: GetProfileParams): Promise { + const queryParams = new URLSearchParams(); + if (params.includeStats !== undefined) { + queryParams.set('includeStats', params.includeStats.toString()); + } + const queryString = queryParams.toString(); return this.request( 'GET', - `/api/users/${params.identifier}`, + `/api/users/${params.identifier}${queryString ? `?${queryString}` : ''}`, ); } diff --git a/src/webapp/features/profile/components/profileTabs/ProfileTabs.tsx b/src/webapp/features/profile/components/profileTabs/ProfileTabs.tsx index 0ad6f80b..be6d8eed 100644 --- a/src/webapp/features/profile/components/profileTabs/ProfileTabs.tsx +++ b/src/webapp/features/profile/components/profileTabs/ProfileTabs.tsx @@ -4,6 +4,7 @@ import { Group, Paper, ScrollAreaAutosize, Tabs } from '@mantine/core'; import TabItem from './TabItem'; import { usePathname } from 'next/navigation'; import { useFeatureFlags } from '@/lib/clientFeatureFlags'; +import useProfile from '../../lib/queries/useProfile'; interface Props { handle: string; @@ -15,6 +16,10 @@ export default function ProfileTabs(props: Props) { const currentTab = segment || 'profile'; // treat base route as 'profile' const basePath = `/profile/${props.handle}`; const { data: featureFlags } = useFeatureFlags(); + const { data: profile } = useProfile({ + didOrHandle: props.handle, + includeStats: true, + }); return ( @@ -26,10 +31,10 @@ export default function ProfileTabs(props: Props) { Profile - Cards + {`Cards${profile.urlCardCount !== undefined ? ` (${profile.urlCardCount})` : ''}`} - Collections + {`Collections${profile.collectionCount !== undefined ? ` (${profile.collectionCount})` : ''}`} {featureFlags?.connections && ( diff --git a/src/webapp/features/profile/lib/dal.server.ts b/src/webapp/features/profile/lib/dal.server.ts index 06e629d6..80c0e52f 100644 --- a/src/webapp/features/profile/lib/dal.server.ts +++ b/src/webapp/features/profile/lib/dal.server.ts @@ -9,11 +9,14 @@ import { cache } from 'react'; * Use this in Server Components only. * For Client Components, use getProfile from dal.ts instead. */ -export const getProfile = cache(async (didOrHandle: string) => { - const client = await createServerSembleClient(); - const response = await client.getProfile({ - identifier: didOrHandle, - }); +export const getProfile = cache( + async (didOrHandle: string, includeStats?: boolean) => { + const client = await createServerSembleClient(); + const response = await client.getProfile({ + identifier: didOrHandle, + includeStats, + }); - return response; -}); + return response; + }, +); diff --git a/src/webapp/features/profile/lib/dal.ts b/src/webapp/features/profile/lib/dal.ts index be09c6a1..59031776 100644 --- a/src/webapp/features/profile/lib/dal.ts +++ b/src/webapp/features/profile/lib/dal.ts @@ -2,20 +2,23 @@ import { verifySessionOnClient } from '@/lib/auth/dal'; import { createSembleClient } from '@/services/client.apiClient'; import { cache } from 'react'; -export const getProfile = cache(async (didOrHandle: string) => { - const client = createSembleClient(); - const response = await client.getProfile({ - identifier: didOrHandle, - }); +export const getProfile = cache( + async (didOrHandle: string, includeStats?: boolean) => { + const client = createSembleClient(); + const response = await client.getProfile({ + identifier: didOrHandle, + includeStats, + }); - return response; -}); + return response; + }, +); -export const getMyProfile = cache(async () => { +export const getMyProfile = cache(async (includeStats?: boolean) => { const session = await verifySessionOnClient({ redirectOnFail: true }); if (!session) throw new Error('No session found'); const client = createSembleClient(); - const response = await client.getMyProfile(); + const response = await client.getMyProfile({ includeStats }); return response; }); diff --git a/src/webapp/features/profile/lib/profileKeys.ts b/src/webapp/features/profile/lib/profileKeys.ts index 50e31418..70a821cc 100644 --- a/src/webapp/features/profile/lib/profileKeys.ts +++ b/src/webapp/features/profile/lib/profileKeys.ts @@ -1,6 +1,6 @@ export const profileKeys = { all: () => ['profiles'] as const, - profile: (didOrHandle: string) => - [...profileKeys.all(), didOrHandle] as const, + profile: (didOrHandle: string, includeStats?: boolean) => + [...profileKeys.all(), didOrHandle, { includeStats }] as const, mine: () => [...profileKeys.all(), 'mine'] as const, }; diff --git a/src/webapp/features/profile/lib/queries/useProfile.tsx b/src/webapp/features/profile/lib/queries/useProfile.tsx index fc270b8a..326d6dfc 100644 --- a/src/webapp/features/profile/lib/queries/useProfile.tsx +++ b/src/webapp/features/profile/lib/queries/useProfile.tsx @@ -4,12 +4,13 @@ import { profileKeys } from '../profileKeys'; interface Props { didOrHandle: string; + includeStats?: boolean; } export default function useProfile(props: Props) { const profile = useSuspenseQuery({ - queryKey: profileKeys.profile(props.didOrHandle), - queryFn: () => getProfile(props.didOrHandle), + queryKey: profileKeys.profile(props.didOrHandle, props.includeStats), + queryFn: () => getProfile(props.didOrHandle, props.includeStats), }); return profile;