From c17587f656b8b2b2079d22b2e07040e5ea960cae Mon Sep 17 00:00:00 2001 From: Moshe Date: Fri, 3 May 2024 10:34:07 +0300 Subject: [PATCH] feat: add bio component to profile page (#54285) Co-authored-by: sembauke Co-authored-by: ahmad abdolsaheb --- client/i18n/locales/english/translations.json | 1 + .../__snapshots__/profile.test.tsx.snap | 504 ++++++++++-------- .../src/components/profile/components/bio.tsx | 67 +++ .../components/profile/components/camper.css | 26 +- .../components/profile/components/camper.tsx | 59 +- .../profile/components/social-icons.tsx | 2 +- .../src/components/profile/profile.test.tsx | 18 +- 7 files changed, 393 insertions(+), 284 deletions(-) create mode 100644 client/src/components/profile/components/bio.tsx diff --git a/client/i18n/locales/english/translations.json b/client/i18n/locales/english/translations.json index a4790789e0f..ad7e4c4ca5d 100644 --- a/client/i18n/locales/english/translations.json +++ b/client/i18n/locales/english/translations.json @@ -314,6 +314,7 @@ "tweet": "I just earned the {{certTitle}} certification @freeCodeCamp! Check it out here: {{certURL}}", "avatar": "{{username}}'s avatar", "joined": "Joined {{date}}", + "from": "From {{location}}", "total-points": "Total Points:", "points": "{{count}} point on {{date}}", "points_plural": "{{count}} points on {{date}}", diff --git a/client/src/components/profile/__snapshots__/profile.test.tsx.snap b/client/src/components/profile/__snapshots__/profile.test.tsx.snap index 30b8b63fe06..ba99723108a 100644 --- a/client/src/components/profile/__snapshots__/profile.test.tsx.snap +++ b/client/src/components/profile/__snapshots__/profile.test.tsx.snap @@ -13,100 +13,149 @@ exports[` renders correctly 1`] = ` class="spacer" style="padding: 15px 0px;" /> -
+
- - buttons.profile - - + +
+

+ @ + string +

+

+ string +

+
+

+ string +

+
+
+ + + profile.joined + +
+
+ + + profile.from + +
+
+ +
- -
-

- @ - string -

- - - -
{ + const { t } = useTranslation(); + const { + joinDate, + location, + username, + name, + about, + githubProfile, + linkedin, + twitter, + website, + isDonating, + yearsTopContributor, + picture + } = useSelector(userSelector) as User; + + return ( + +
+ 0} + picture={picture} + /> +
+

@{username}

+ {name &&

{name}

} + + {about &&

{about}

} +
+ {joinDate && ( +
+ + {parseDate(joinDate, t)} +
+ )} + {location && ( +
+ + {t('profile.from', { location })} +
+ )} +
+ +
+
+ ); +}; +export default Bio; diff --git a/client/src/components/profile/components/camper.css b/client/src/components/profile/components/camper.css index 30c7de28358..a6135982554 100644 --- a/client/src/components/profile/components/camper.css +++ b/client/src/components/profile/components/camper.css @@ -7,7 +7,6 @@ .avatar-camper { display: flex; - justify-content: center; } .avatar-camper .avatar { @@ -29,3 +28,28 @@ width: auto; margin: 0 0.2em -0.3em 0.2em; } + +.profile-meta-container { + display: flex; + flex-direction: row; + margin-bottom: 2rem; + color: var(--quaternary-color); +} + +.profile-meta-container div { + margin-inline-end: 12px; +} + +.profile-meta-container svg { + margin-inline-end: 4px; +} + +.social-icons-row a { + display: inline-block; + margin-inline-end: 12px; + color: var(--quaternary-color); +} + +.bio-container h2 { + color: var(--quaternary-color); +} diff --git a/client/src/components/profile/components/camper.tsx b/client/src/components/profile/components/camper.tsx index 727772759b9..5890ebd6606 100644 --- a/client/src/components/profile/components/camper.tsx +++ b/client/src/components/profile/components/camper.tsx @@ -1,15 +1,12 @@ -import { faAward, faCalendar } from '@fortawesome/free-solid-svg-icons'; +import { faAward } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import { Col, Row } from '@freecodecamp/ui'; import type { User } from '../../../redux/prop-types'; -import { AvatarRenderer } from '../../helpers'; import Link from '../../helpers/link'; -import SupporterBadge from '../../../assets/icons/supporter-badge'; -import SocialIcons from './social-icons'; -import { formatYears, parseDate } from './utils'; +import { formatYears } from './utils'; import './camper.css'; +import Bio from './bio'; export type CamperProps = Pick< User, @@ -27,56 +24,12 @@ export type CamperProps = Pick< | 'joinDate' >; -function Camper({ - name, - username, - location, - picture, - about, - yearsTopContributor, - githubProfile, - isDonating, - joinDate, - linkedin, - twitter, - website -}: CamperProps): JSX.Element { +function Camper({ yearsTopContributor }: CamperProps): JSX.Element { const { t } = useTranslation(); return ( -
- - - 0} - picture={picture} - /> - - - -
-

@{username}

- {name &&

{name}

} - {location &&

{location}

} - {isDonating && ( -

- - {t('profile.supporter')} -

- )} - {about &&

{about}

} - {joinDate && ( -

- {parseDate(joinDate, t)} -

- )} +
+ {yearsTopContributor.filter(Boolean).length > 0 && (

diff --git a/client/src/components/profile/components/social-icons.tsx b/client/src/components/profile/components/social-icons.tsx index e0cd47f8428..d55780c6888 100644 --- a/client/src/components/profile/components/social-icons.tsx +++ b/client/src/components/profile/components/social-icons.tsx @@ -86,7 +86,7 @@ function SocialIcons(props: SocialIconsProps): JSX.Element | null { return ( - + {linkedin ? LinkedInIcon(linkedin, username) : null} {githubProfile ? GitHubIcon(githubProfile, username) : null} {website ? WebsiteIcon(website, username) : null} diff --git a/client/src/components/profile/profile.test.tsx b/client/src/components/profile/profile.test.tsx index ce08042aef7..8dfee898c8a 100644 --- a/client/src/components/profile/profile.test.tsx +++ b/client/src/components/profile/profile.test.tsx @@ -1,10 +1,13 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; +import { Provider } from 'react-redux'; +import { createStore } from 'redux'; import { Themes } from '../settings/theme'; - import Profile from './profile'; jest.mock('../../analytics'); +//workaround to avoid some strange gatsby error: +window.___loader = { enqueue: () => {}, hovering: () => {} }; const userProps = { user: { @@ -77,17 +80,24 @@ const notMyProfileProps = { isSessionUser: false, ...userProps }; - +function reducer() { + return { + app: { appUsername: 'vasili', user: { vasili: userProps.user } } + }; +} +function renderWithRedux(ui: JSX.Element) { + return render({ui}); +} describe('', () => { it('renders the report button on another persons profile', () => { - render(); + renderWithRedux(); const reportButton: HTMLElement = screen.getByText('buttons.flag-user'); expect(reportButton).toHaveAttribute('href', '/user/string/report-user'); }); it('renders correctly', () => { - const { container } = render(); + const { container } = renderWithRedux(); expect(container).toMatchSnapshot(); });