diff --git a/packages/shared/src/features/profile/components/Activity.helpers.tsx b/packages/shared/src/features/profile/components/Activity.helpers.tsx index 8eecd9ba726..caae4df2690 100644 --- a/packages/shared/src/features/profile/components/Activity.helpers.tsx +++ b/packages/shared/src/features/profile/components/Activity.helpers.tsx @@ -107,9 +107,11 @@ export const getUserPath = ( username: string | undefined, userId: string | undefined, path: string, + isPreviewMode?: boolean, ): string => { const userIdentifier = username || userId; - return `/${userIdentifier}${path}`; + const query = isPreviewMode ? '?preview=true' : ''; + return `/${userIdentifier}${path}${query}`; }; export const renderEmptyScreen = ( diff --git a/packages/shared/src/features/profile/components/Activity.tsx b/packages/shared/src/features/profile/components/Activity.tsx index 8dc16f0b154..e1c7ef736e4 100644 --- a/packages/shared/src/features/profile/components/Activity.tsx +++ b/packages/shared/src/features/profile/components/Activity.tsx @@ -33,6 +33,7 @@ export const Activity = ({ user }: ActivityProps): ReactElement | null => { { diff --git a/packages/shared/src/features/profile/components/ActivityRepliesTab.tsx b/packages/shared/src/features/profile/components/ActivityRepliesTab.tsx index 330c82ab9d8..8a205ab902b 100644 --- a/packages/shared/src/features/profile/components/ActivityRepliesTab.tsx +++ b/packages/shared/src/features/profile/components/ActivityRepliesTab.tsx @@ -136,6 +136,7 @@ export const ActivityRepliesTab = ({ user?.username, user?.id, activityTabs[ActivityTabIndex.Replies].path, + isPreviewMode, )} passHref > diff --git a/packages/shared/src/features/profile/components/ActivityUpvotedTab.tsx b/packages/shared/src/features/profile/components/ActivityUpvotedTab.tsx index ce0a54972e8..89477e82cc7 100644 --- a/packages/shared/src/features/profile/components/ActivityUpvotedTab.tsx +++ b/packages/shared/src/features/profile/components/ActivityUpvotedTab.tsx @@ -24,6 +24,7 @@ import { HorizontalFeedWithContext } from './HorizontalFeedWithContext'; export const ActivityUpvotedTab = ({ userId, isSameUser, + isPreviewMode, userName, user, selectedTab, @@ -31,6 +32,7 @@ export const ActivityUpvotedTab = ({ }: { userId: string; isSameUser: boolean; + isPreviewMode: boolean; userName: string; user: PublicProfile; selectedTab: string; @@ -82,6 +84,7 @@ export const ActivityUpvotedTab = ({ user?.username, user?.id, activityTabs[ActivityTabIndex.Upvoted].path, + isPreviewMode, )} passHref > diff --git a/packages/webapp/__tests__/ProfilePostsPage.tsx b/packages/webapp/__tests__/ProfilePostsPage.tsx index aa8d9852f7a..a0e64f83420 100644 --- a/packages/webapp/__tests__/ProfilePostsPage.tsx +++ b/packages/webapp/__tests__/ProfilePostsPage.tsx @@ -137,3 +137,32 @@ it('should show different empty screen when visiting your profile', async () => const el = await screen.findByText('New post'); expect(el).toBeInTheDocument(); }); + +it('should not offer the owner a new post CTA in preview mode', async () => { + jest.mocked(useRouter).mockImplementation( + () => + ({ + pathname: '/[userId]/posts', + query: { userId: 'dailydotdev', preview: 'true' }, + isFallback: false, + } as unknown as NextRouter), + ); + renderComponent( + [ + createFeedMock({ + pageInfo: { + hasNextPage: true, + endCursor: '', + }, + edges: [], + }), + ], + {}, + defaultProfile as unknown as LoggedUser, + ); + await waitForNock(); + expect( + await screen.findByText("Daily Dev hasn't posted yet"), + ).toBeInTheDocument(); + expect(screen.queryByText('New post')).not.toBeInTheDocument(); +}); diff --git a/packages/webapp/__tests__/ProfileRepliesPage.tsx b/packages/webapp/__tests__/ProfileRepliesPage.tsx index 0bee95947b1..c7c0e275f82 100644 --- a/packages/webapp/__tests__/ProfileRepliesPage.tsx +++ b/packages/webapp/__tests__/ProfileRepliesPage.tsx @@ -4,6 +4,7 @@ import { render, screen } from '@testing-library/react'; import type { LoggedUser, PublicProfile, + UserSocialLink, } from '@dailydotdev/shared/src/lib/user'; import nock from 'nock'; import { QueryClient } from '@tanstack/react-query'; @@ -20,11 +21,26 @@ import type { Author, } from '@dailydotdev/shared/src/graphql/comments'; import { USER_COMMENTS_QUERY } from '@dailydotdev/shared/src/graphql/comments'; +import type { NextRouter } from 'next/router'; +import { useRouter } from 'next/router'; import ProfilePage from '../pages/[userId]/replies'; +jest.mock('next/router', () => ({ + useRouter: jest.fn(), +})); + beforeEach(() => { nock.cleanAll(); jest.clearAllMocks(); + + jest.mocked(useRouter).mockImplementation( + () => + ({ + pathname: '/', + query: {}, + isFallback: false, + } as unknown as NextRouter), + ); }); const defaultProfile: PublicProfile = { @@ -37,10 +53,12 @@ const defaultProfile: PublicProfile = { cover: 'https://daily.dev/cover.png', bio: 'The best company!', createdAt: '2020-08-26T13:04:35.000Z', - twitter: 'dailydotdev', - github: 'dailydotdev', - hashnode: 'dailydotdev', - portfolio: 'https://daily.dev/?key=vaue', + socialLinks: [ + { platform: 'twitter', url: 'https://x.com/dailydotdev' }, + { platform: 'github', url: 'https://github.com/dailydotdev' }, + { platform: 'hashnode', url: 'https://dailydotdev.hashnode.dev' }, + { platform: 'portfolio', url: 'https://daily.dev/?key=vaue' }, + ] as UserSocialLink[], permalink: 'https://daily.dev/dailydotdev', }; @@ -56,6 +74,7 @@ export const defaultCommentsPage: Connection = { createdAt: '2020-07-26T13:04:35.000Z', content: 'My comment', numUpvotes: 50, + numAwards: 0, id: 'c1', contentHtml: 'My comment', post: defaultPost, @@ -93,7 +112,7 @@ const renderComponent = ( mocks.forEach(mockGraphQL); return render( - + , ); }; @@ -145,3 +164,32 @@ it('should show different empty screen when visiting your profile', async () => const el = await screen.findByText('Explore posts'); expect(el).toBeInTheDocument(); }); + +it('should show the visitor empty screen to the owner in preview mode', async () => { + jest.mocked(useRouter).mockImplementation( + () => + ({ + pathname: '/[userId]/replies', + query: { userId: 'dailydotdev', preview: 'true' }, + isFallback: false, + } as unknown as NextRouter), + ); + renderComponent( + [ + createCommentsMock({ + pageInfo: { + hasNextPage: true, + endCursor: '', + }, + edges: [], + }), + ], + {}, + defaultProfile as unknown as LoggedUser, + ); + await waitForNock(); + expect( + await screen.findByText("Daily Dev hasn't replied to any post yet"), + ).toBeInTheDocument(); + expect(screen.queryByText('Explore posts')).not.toBeInTheDocument(); +}); diff --git a/packages/webapp/__tests__/ProfileUpvotedPage.tsx b/packages/webapp/__tests__/ProfileUpvotedPage.tsx index 3f8f77df2f7..5c9383852cc 100644 --- a/packages/webapp/__tests__/ProfileUpvotedPage.tsx +++ b/packages/webapp/__tests__/ProfileUpvotedPage.tsx @@ -137,3 +137,32 @@ it('should show different empty screen when visiting your profile', async () => const el = await screen.findByText('Explore posts'); expect(el).toBeInTheDocument(); }); + +it('should show the visitor empty screen to the owner in preview mode', async () => { + jest.mocked(useRouter).mockImplementation( + () => + ({ + pathname: '/[userId]/upvoted', + query: { userId: 'dailydotdev', preview: 'true' }, + isFallback: false, + } as unknown as NextRouter), + ); + renderComponent( + [ + createFeedMock({ + pageInfo: { + hasNextPage: true, + endCursor: '', + }, + edges: [], + }), + ], + {}, + defaultProfile as unknown as LoggedUser, + ); + await waitForNock(); + expect( + await screen.findByText("Daily Dev hasn't upvoted yet"), + ).toBeInTheDocument(); + expect(screen.queryByText('Explore posts')).not.toBeInTheDocument(); +}); diff --git a/packages/webapp/pages/[userId]/posts.tsx b/packages/webapp/pages/[userId]/posts.tsx index 536596f24c3..ffab7f79e08 100644 --- a/packages/webapp/pages/[userId]/posts.tsx +++ b/packages/webapp/pages/[userId]/posts.tsx @@ -1,5 +1,5 @@ import type { ReactElement } from 'react'; -import React, { useContext } from 'react'; +import React from 'react'; import { link } from '@dailydotdev/shared/src/lib/links'; import { AUTHOR_FEED_QUERY } from '@dailydotdev/shared/src/graphql/feed'; import type { FeedProps } from '@dailydotdev/shared/src/components/Feed'; @@ -8,7 +8,7 @@ import { OtherFeedPage } from '@dailydotdev/shared/src/lib/query'; import { MyProfileEmptyScreen } from '@dailydotdev/shared/src/components/profile/MyProfileEmptyScreen'; import { ProfileEmptyScreen } from '@dailydotdev/shared/src/components/profile/ProfileEmptyScreen'; import { cloudinaryCharmNoPosts } from '@dailydotdev/shared/src/lib/image'; -import AuthContext from '@dailydotdev/shared/src/contexts/AuthContext'; +import { useProfilePreview } from '@dailydotdev/shared/src/hooks/profile/useProfilePreview'; import { useFeedLayout } from '@dailydotdev/shared/src/hooks'; import classNames from 'classnames'; import { NextSeo } from 'next-seo'; @@ -35,14 +35,13 @@ const ProfilePostsPage = ({ user, noindex, }: ProfileLayoutProps): ReactElement | null => { - const { user: loggedUser } = useContext(AuthContext); + const { isOwner } = useProfilePreview(user); const { shouldUseListFeedLayout } = useFeedLayout(); if (!user) { return null; } - const isSameUser = loggedUser?.id === user.id; const userId = user.id; const feedProps: FeedProps = { feedName: OtherFeedPage.Author, @@ -52,7 +51,7 @@ const ProfilePostsPage = ({ userId, }, disableAds: true, - emptyScreen: isSameUser ? ( + emptyScreen: isOwner ? ( { - const { user: loggedUser } = useContext(AuthContext); + const { isOwner } = useProfilePreview(user); if (!user) { return null; } - const isSameUser = loggedUser?.id === user.id; const userId = user.id; - const emptyScreen = isSameUser ? ( + const emptyScreen = isOwner ? ( { - const { user: loggedUser } = useContext(AuthContext); + const { isOwner } = useProfilePreview(user); const { shouldUseListFeedLayout } = useFeedLayout(); if (!user) { return null; } - const isSameUser = loggedUser?.id === user.id; const userId = user.id; const feedProps: FeedProps = { feedName: OtherFeedPage.UserUpvoted, @@ -51,7 +50,7 @@ const ProfileUpvotedPage = ({ userId, }, disableAds: true, - emptyScreen: isSameUser ? ( + emptyScreen: isOwner ? (