Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create read only profile page #244

Merged
merged 17 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
mariembencheikh marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,4 @@

* add info about what storage includes ([077f997](https://github.com/graasp/graasp-account/commit/077f997bbf63f05dd65912159e7a6803a33d56fb))
* add translation ([1eed95f](https://github.com/graasp/graasp-account/commit/1eed95fbee0331bef0bff257b1a00e6b956b37bb))
* update member profile view ([fff2de1](https://github.com/graasp/graasp-account/commit/fff2de144ca27897b081a1d59237e4892c410024))
* update member profile view ([fff2de1](https://github.com/graasp/graasp-account/commit/fff2de144ca27897b081a1d59237e4892c410024))
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PROFILE_PATH } from 'config/paths';
import { EDIT_MEMBER_INFO } from 'config/paths';

import {
MEMBER_PROFILE_ANALYTICS_SWITCH_ID,
Expand Down Expand Up @@ -57,7 +57,7 @@ const changeUsername = (newUserName: string) => {
describe('Change username', () => {
beforeEach(() => {
cy.setUpApi({ currentMember: BOB });
cy.visit(PROFILE_PATH);
cy.visit(EDIT_MEMBER_INFO);
});

it('Username field cannot be empty', () => {
Expand Down Expand Up @@ -116,7 +116,7 @@ describe('Checks the analytics switch', () => {
enableSaveActions: true,
},
});
cy.visit(PROFILE_PATH);
cy.visit(EDIT_MEMBER_INFO);
// wait on current member request to update then the mock response for current member
cy.wait('@getCurrentMember');
});
Expand All @@ -138,7 +138,7 @@ describe('Checks the analytics switch', () => {
enableSaveActions: false,
},
});
cy.visit(PROFILE_PATH);
cy.visit(EDIT_MEMBER_INFO);
// wait on current member request to update then the mock response for current member
cy.wait('@getCurrentMember');
});
Expand All @@ -158,7 +158,7 @@ describe('Checks the language switch', () => {
cy.setUpApi({
currentMember,
});
cy.visit(PROFILE_PATH);
cy.visit(EDIT_MEMBER_INFO);
cy.wait('@getCurrentMember');
});
it('should select an option from the select component', () => {
Expand All @@ -177,7 +177,7 @@ describe('Checks the current member language', () => {
cy.setUpApi({
currentMember: { ...currentMember, extra: { lang: 'es' } },
});
cy.visit(PROFILE_PATH);
cy.visit(EDIT_MEMBER_INFO);
cy.wait('@getCurrentMember');
});

Expand Down
95 changes: 95 additions & 0 deletions cypress/e2e/memberProfile.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { PROFILE_PATH } from '@/config/paths';
import {
MEMBER_PROFILE_EMAIL_ID,
PUBLIC_PROFILE_BIO_ID,
PUBLIC_PROFILE_FACEBOOK_ID,
PUBLIC_PROFILE_LINKEDIN_ID,
PUBLIC_PROFILE_TWITTER_ID,
USERNAME_DISPLAY_ID,
} from '@/config/selectors';

import {
BOB,
MEMBER_EMPTY_PUBLIC_PROFILE,
MEMBER_PUBLIC_PROFILE,
} from '../fixtures/members';

describe('Check member info', () => {
beforeEach(() => {
cy.setUpApi({
currentMember: BOB,
currentProfile: MEMBER_PUBLIC_PROFILE,
});
cy.visit(PROFILE_PATH);
cy.wait('@getCurrentMember');
cy.wait('@getOwnProfile');
});

it('displays the correct member info', () => {
// displays the correct member name
cy.get(`#${USERNAME_DISPLAY_ID}`).should('contain', BOB.name);
// displays the correct member email
cy.get(`#${MEMBER_PROFILE_EMAIL_ID}`).should('contain', BOB.email);
});

it('displays the correct public profile info', () => {
mariembencheikh marked this conversation as resolved.
Show resolved Hide resolved
// displays the correct bio
cy.get(`#${PUBLIC_PROFILE_BIO_ID}`).should(
'contain',
MEMBER_PUBLIC_PROFILE.bio,
);
// displays the correct member linkedin
cy.get(`#${PUBLIC_PROFILE_LINKEDIN_ID}`).should(
'contain',
MEMBER_PUBLIC_PROFILE.linkedinID,
);
// displays the correct member twitter
cy.get(`#${PUBLIC_PROFILE_TWITTER_ID}`).should(
'contain',
MEMBER_PUBLIC_PROFILE.twitterID,
);
// displays the correct member facebook
cy.get(`#${PUBLIC_PROFILE_FACEBOOK_ID}`).should(
'contain',
MEMBER_PUBLIC_PROFILE.facebookID,
);
});
});

describe('Check empty member public profile info', () => {
beforeEach(() => {
cy.setUpApi({
currentMember: BOB,
currentProfile: MEMBER_EMPTY_PUBLIC_PROFILE,
});
cy.visit(PROFILE_PATH);
cy.wait('@getCurrentMember');
cy.wait('@getOwnProfile');
});

it('displays the correct public profile info when profile is empty', () => {
// displays a message indicating no bio is available
cy.get(`#${PUBLIC_PROFILE_BIO_ID}`).should(
'contain',
'No biography has been specified',
);

// displays a message indicating no LinkedIn ID is available
cy.get(`#${PUBLIC_PROFILE_LINKEDIN_ID}`).should(
'contain',
'No LinkedIn username has been specified',
);

// displays a message indicating no Twitter ID is available
cy.get(`#${PUBLIC_PROFILE_TWITTER_ID}`).should(
'contain',
'No Twitter username has been specified',
);

// displays a message indicating no Facebook ID is available
cy.get(`#${PUBLIC_PROFILE_FACEBOOK_ID}`).should(
'contain',
'No Facebook username has been specified',
);
});
});
26 changes: 25 additions & 1 deletion cypress/fixtures/members.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Member, MemberFactory } from '@graasp/sdk';
import { Member, MemberFactory, PublicProfile } from '@graasp/sdk';

import { MemberForTest } from '../support/utils';
import { AVATAR_LINK } from './thumbnails/links';
Expand All @@ -9,6 +9,7 @@ export const BOB = MemberFactory({
name: 'BOB',
email: '[email protected]',
createdAt: '2021-04-13 14:56:34.749946',
extra: { lang: 'en', hasAvatar: true },
});
export const MEMBERS: {
[name: string]: Member & {
Expand Down Expand Up @@ -40,3 +41,26 @@ export const MEMBER_WITH_AVATAR: MemberForTest = {
// this only exists for test
thumbnail: AVATAR_LINK,
};

export const MEMBER_PUBLIC_PROFILE: PublicProfile = {
id: 'ecafbd2a-5642-31fb-ae93-0242ac130004',
member: BOB,
bio: 'text',
twitterID: 'twitter_handle',
facebookID: 'fb_handle',
linkedinID: 'linkedin_handle',
createdAt: '2021-04-13 14:56:34.749946',
updatedAt: '2021-04-13 14:56:34.749946',
visibility: false,
};
export const MEMBER_EMPTY_PUBLIC_PROFILE: PublicProfile = {
id: 'ecafbd2a-5642-31fb-ae93-0242ac130004',
member: BOB,
bio: '',
twitterID: '',
facebookID: '',
linkedinID: '',
createdAt: '2021-04-13 14:56:34.749946',
updatedAt: '2021-04-13 14:56:34.749946',
visibility: false,
};
14 changes: 11 additions & 3 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
/// <reference types="cypress" />
import { CookieKeys } from '@graasp/sdk';

import { CURRENT_MEMBER, MEMBERS } from '../fixtures/members';
import {
CURRENT_MEMBER,
MEMBERS,
MEMBER_PUBLIC_PROFILE,
} from '../fixtures/members';
import {
mockEditMember,
mockGetCurrentMember,
mockGetCurrentMemberAvatar,
mockGetMember,
mockGetOwnProfile,
mockPostAvatar,
mockSignInRedirection,
mockSignOut,
Expand All @@ -18,21 +23,24 @@ Cypress.Commands.add(
({
members = Object.values(MEMBERS),
currentMember = CURRENT_MEMBER,
currentProfile = MEMBER_PUBLIC_PROFILE,
getCurrentMemberError = false,
getCurrentProfileError = false,
editMemberError = false,
getAvatarUrlError = false,
postAvatarError = false,
updatePasswordError = false,
} = {}) => {
const cachedMembers = JSON.parse(JSON.stringify(members));
const cachedCurrentMember = JSON.parse(JSON.stringify(currentMember));
const cachedCurrentProfile = JSON.parse(JSON.stringify(currentProfile));

// hide cookie banner by default
cy.setCookie(CookieKeys.AcceptCookies, 'true');

mockGetMember(cachedMembers);

mockGetCurrentMember(cachedCurrentMember, getCurrentMemberError);
mockGetMember(cachedMembers);
mockGetOwnProfile(cachedCurrentProfile, getCurrentProfileError);

mockSignInRedirection();

Expand Down
23 changes: 22 additions & 1 deletion cypress/support/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {

import { StatusCodes } from 'http-status-codes';

import { CURRENT_MEMBER } from '../fixtures/members';
import { CURRENT_MEMBER, MEMBER_PUBLIC_PROFILE } from '../fixtures/members';
import { ID_FORMAT, MemberForTest } from './utils';

const {
Expand All @@ -18,6 +18,7 @@ const {
buildPatchMember,
buildUploadAvatarRoute,
buildUpdateMemberPasswordRoute,
GET_OWN_PROFILE,
} = API_ROUTES;

export const SIGN_IN_PATH = buildSignInPath({
Expand All @@ -31,6 +32,26 @@ export const redirectionReply = {
body: '<h1>Mock Auth Page</h1>',
};

export const mockGetOwnProfile = (
publicProfile = MEMBER_PUBLIC_PROFILE,
shouldThrowError = false,
): void => {
cy.intercept(
{
method: HttpMethod.Get,
url: `${API_HOST}/members/${GET_OWN_PROFILE}`,
},
({ reply }) => {
if (shouldThrowError) {
return reply({
statusCode: StatusCodes.INTERNAL_SERVER_ERROR,
body: null,
});
}
return reply({ statusCode: StatusCodes.OK, body: publicProfile });
},
).as('getOwnProfile');
};
export const mockGetCurrentMember = (
currentMember = CURRENT_MEMBER,
shouldThrowError = false,
Expand Down
18 changes: 14 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CustomInitialLoader, withAuthorization } from '@graasp/ui';

import { GRAASP_AUTH_HOST } from './config/env';
import {
EDIT_MEMBER_INFO,
HOME_PATH,
MANAGE_ACCOUNT_PATH,
PASSWORD_SETTINGS_PATH,
Expand All @@ -18,11 +19,12 @@ import {
} from './config/paths';
import { hooks } from './config/queryClient';
import DestructiveSettingsScreen from './pages/DestructiveSettingsScreen';
import EditMemberPersonalInformation from './pages/EditMemberPersonalInformation';
import EditPublicProfileScreen from './pages/EditPublicProfileScreen';
import HomePage from './pages/HomePage';
import MemberScreen from './pages/MemberScreen';
import MemberProfileScreen from './pages/MemberProfileScreen';
import PageWrapper from './pages/PageWrapper';
import PasswordSettingsScreen from './pages/PasswordSettingsScreen';
import PublicProfileScreen from './pages/PublicProfileScreen';
import StorageScreen from './pages/StorageScreen';

export const App = (): JSX.Element => {
Expand Down Expand Up @@ -52,7 +54,11 @@ export const App = (): JSX.Element => {
withAuthorizationProps,
);
const MemberProfileWithAuthorization = withAuthorization(
MemberScreen,
MemberProfileScreen,
withAuthorizationProps,
);
const EditMemberProfileWithAuthorization = withAuthorization(
EditMemberPersonalInformation,
withAuthorizationProps,
);
const PasswordSettingsWithAuthorization = withAuthorization(
Expand All @@ -64,7 +70,7 @@ export const App = (): JSX.Element => {
withAuthorizationProps,
);
const PublicProfileWithAuthorization = withAuthorization(
PublicProfileScreen,
EditPublicProfileScreen,
withAuthorizationProps,
);
const DestructiveSettingsWithAuthorization = withAuthorization(
Expand All @@ -81,6 +87,10 @@ export const App = (): JSX.Element => {
path={PROFILE_PATH}
element={<MemberProfileWithAuthorization />}
/>
<Route
path={EDIT_MEMBER_INFO}
element={<EditMemberProfileWithAuthorization />}
/>
<Route
path={PASSWORD_SETTINGS_PATH}
element={<PasswordSettingsWithAuthorization />}
Expand Down
20 changes: 20 additions & 0 deletions src/components/common/RoundedStack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ReactNode } from 'react';

import { Stack } from '@mui/material';

type Props = {
children: ReactNode;
};
const RoundedStack = ({ children }: Props): JSX.Element => (
<Stack
border="1px solid"
borderColor="divider"
borderRadius={1}
p={2}
spacing={1}
>
{children}
</Stack>
);

export default RoundedStack;
27 changes: 27 additions & 0 deletions src/components/main/DisplayingMemberPublicProfileLinks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Link } from 'react-router-dom';

import { Stack, Typography } from '@mui/material';

type Props = {
icon?: JSX.Element;
contentId: string;
content?: string;
href?: string;
};
const DisplayingMemberPublicProfileLinks = ({
icon,
contentId,
content,
href,
}: Props): JSX.Element => (
<Stack direction="row" spacing={1}>
<Typography variant="body1" color="textSecondary">
{icon}
</Typography>

<Typography variant="body1" id={contentId}>
{href ? <Link to={href}>{content}</Link> : content}
</Typography>
</Stack>
);
export default DisplayingMemberPublicProfileLinks;
Loading