Skip to content

Commit

Permalink
feat: add member page profile
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia committed Jun 21, 2021
1 parent ffba93c commit fe80c8a
Show file tree
Hide file tree
Showing 30 changed files with 534 additions and 99 deletions.
18 changes: 16 additions & 2 deletions cypress/fixtures/members.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
export const MEMBERS = {
ANNA: { id: 'anna-id', name: 'anna', email: '[email protected]' },
BOB: { id: 'bob-id', name: 'bob', email: '[email protected]' },
ANNA: {
id: 'ecafbd2a-5642-31fb-ae93-0242ac130002',
name: 'anna',
email: '[email protected]',
createdAt: '2021-04-13 14:56:34.749946',
extra: {
lang: 'fr',
},
},
BOB: {
id: 'ecafbd2a-5688-11eb-fb52-3212ac130002',
name: 'bob',
email: '[email protected]',
createdAt: '2021-04-13 14:56:34.749946',
extra: { lang: 'en' },
},
};

export const CURRENT_USER = MEMBERS.ANNA;
12 changes: 7 additions & 5 deletions cypress/integration/authentication.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import {
HEADER_APP_BAR_ID,
HEADER_USER_ID,
ITEM_MAIN_CLASS,
REDIRECTION_CONTENT_ID,
USER_MENU_SIGN_OUT_OPTION_ID,
} from '../../src/config/selectors';
import { SAMPLE_ITEMS } from '../fixtures/items';
import { CURRENT_USER } from '../fixtures/members';
import {
REQUEST_FAILURE_LOADING_TIME,
PAGE_LOAD_WAITING_PAUSE,
REDIRECTION_CONTENT,
REDIRECTION_TIME,
} from '../support/constants';
import { REDIRECT_URL_LOCAL_STORAGE_KEY } from '../../src/config/constants';
Expand All @@ -33,7 +33,7 @@ describe('Authentication', () => {
'equal',
HOME_PATH,
);
cy.get('html').should('contain', REDIRECTION_CONTENT);
cy.get(`#${REDIRECTION_CONTENT_ID}`).should('exist');
});
it('Shared Items', () => {
cy.visit(SHARED_ITEMS_PATH);
Expand All @@ -42,7 +42,7 @@ describe('Authentication', () => {
'equal',
SHARED_ITEMS_PATH,
);
cy.get('html').should('contain', REDIRECTION_CONTENT);
cy.get(`#${REDIRECTION_CONTENT_ID}`).should('exist');
});
});

Expand All @@ -53,11 +53,13 @@ describe('Authentication', () => {

it('Signing Off redirect to sign in route', () => {
cy.visit(HOME_PATH);
// user name in header
cy.get(`#${HEADER_USER_ID}`).click();
cy.get(`#${USER_MENU_SIGN_OUT_OPTION_ID}`).click();
cy.wait(REQUEST_FAILURE_LOADING_TIME);
cy.get('html').should('contain', REDIRECTION_CONTENT);

// should refetch current member just after signing out
// this current member will be unauthorized and thus redirect
cy.wait(['@signOut', '@getCurrentMember']);
});

describe('Load page correctly', () => {
Expand Down
57 changes: 57 additions & 0 deletions cypress/integration/memberProfile.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { MEMBER_PROFILE_PATH } from '../../src/config/paths';
import { langs } from '../../src/config/i18n';
import {
MEMBER_PROFILE_MEMBER_ID_ID,
MEMBER_PROFILE_MEMBER_NAME_ID,
MEMBER_PROFILE_EMAIL_ID,
MEMBER_PROFILE_LANGUAGE_SWITCH_ID,
MEMBER_PROFILE_INSCRIPTION_DATE_ID,
MEMBER_PROFILE_MEMBER_ID_COPY_BUTTON_ID,
} from '../../src/config/selectors';
import { CURRENT_USER } from '../fixtures/members';
import { formatDate } from '../../src/utils/date';

describe('Member Profile', () => {
beforeEach(() => {
cy.setUpApi();
cy.visit(MEMBER_PROFILE_PATH);
});

it('Layout', () => {
const { id, name, email, extra, createdAt } = CURRENT_USER;
cy.get(`#${MEMBER_PROFILE_MEMBER_ID_ID}`).should('contain', id);
cy.get(`#${MEMBER_PROFILE_MEMBER_NAME_ID}`).should('contain', name);
cy.get(`#${MEMBER_PROFILE_EMAIL_ID}`).should('contain', email);
cy.get(`#${MEMBER_PROFILE_INSCRIPTION_DATE_ID}`).should(
'contain',
formatDate(createdAt),
);
cy.get(`#${MEMBER_PROFILE_LANGUAGE_SWITCH_ID}`).should(
'contain',
langs[extra.lang],
);
});

it('Changing Language edits user', () => {
const { id } = CURRENT_USER;

cy.get(`#${MEMBER_PROFILE_LANGUAGE_SWITCH_ID}`).select('en');

cy.wait('@editMember').then(({ request: { body, url } }) => {
expect(url).to.contain(id);
expect(body?.extra?.lang).to.equal('en');
});
});

it('Copy member ID to clipboard', () => {
const { id } = CURRENT_USER;

cy.get(`#${MEMBER_PROFILE_MEMBER_ID_COPY_BUTTON_ID}`).click();

cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.equal(id);
});
});
});
});
1 change: 1 addition & 0 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module.exports = (on, config) => {
root: '#root',
},
API_HOST: process.env.REACT_APP_API_HOST,
AUTHENTICATION_HOST: process.env.REACT_APP_AUTHENTICATION_HOST,
S3_FILES_HOST:
// calls to this host are mocked, but still should be reachable
// set an s3 host or fake it by using the same host as the api's
Expand Down
7 changes: 7 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import {
mockGetTags,
mockPostItemTag,
mockPutItemLogin,
mockEditMember,
mockGetSharedItems,
} from './server';
import './commands/item';
import './commands/navigation';
Expand Down Expand Up @@ -62,12 +64,15 @@ Cypress.Commands.add(
postItemTagError = false,
postItemLoginError = false,
putItemLoginError = false,
editMemberError = false,
} = {}) => {
const cachedItems = JSON.parse(JSON.stringify(items));
const cachedMembers = JSON.parse(JSON.stringify(members));

mockGetOwnItems(cachedItems);

mockGetSharedItems({ items: cachedItems, member: currentMember });

mockPostItem(cachedItems, postItemError);

mockDeleteItem(cachedItems, deleteItemError);
Expand Down Expand Up @@ -118,6 +123,8 @@ Cypress.Commands.add(
mockGetItemTags(items);

mockPostItemTag(items, postItemTagError);

mockEditMember(members, editMemberError);
},
);

Expand Down
2 changes: 1 addition & 1 deletion cypress/support/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export const EDIT_ITEM_PAUSE = 1000;
export const ITEM_LOGIN_PAUSE = 1000;
export const NAVIGATE_PAUSE = 500;
export const PAGE_LOAD_WAITING_PAUSE = 3000;
export const REQUEST_FAILURE_LOADING_TIME = 3000;
export const REQUEST_FAILURE_LOADING_TIME = 1500;
export const TREE_VIEW_PAUSE = 2000;

export const REDIRECTION_CONTENT = 'hello';
Expand Down
39 changes: 35 additions & 4 deletions cypress/support/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
getItemLoginSchema,
buildItemLoginSchemaExtra,
} from '../../src/utils/itemExtra';
import { REDIRECTION_CONTENT } from './constants';
import { SETTINGS } from '../../src/config/constants';
import { ITEM_LOGIN_TAG } from '../fixtures/itemTags';

Expand Down Expand Up @@ -53,15 +52,18 @@ const {
GET_TAGS_ROUTE,
buildPutItemLoginSchema,
buildPostItemTagRoute,
buildPatchMember,
SHARE_ITEM_WITH_ROUTE,
} = API_ROUTES;

const API_HOST = Cypress.env('API_HOST');
const S3_FILES_HOST = Cypress.env('S3_FILES_HOST');
const AUTHENTICATION_HOST = Cypress.env('AUTHENTICATION_HOST');

export const redirectionReply = {
headers: { 'content-type': 'text/html' },
headers: { 'content-type': 'application/json' },
statusCode: StatusCodes.OK,
body: REDIRECTION_CONTENT,
body: null,
};

export const mockGetCurrentMember = (
Expand Down Expand Up @@ -97,6 +99,19 @@ export const mockGetOwnItems = (items) => {
).as('getOwnItems');
};

export const mockGetSharedItems = ({ items, member }) => {
cy.intercept(
{
method: DEFAULT_GET.method,
url: `${API_HOST}/${SHARE_ITEM_WITH_ROUTE}`,
},
(req) => {
const own = items.filter(({ creator }) => creator !== member.id);
req.reply(own);
},
).as('getSharedItems');
};

export const mockPostItem = (items, shouldThrowError) => {
cy.intercept(
{
Expand Down Expand Up @@ -336,6 +351,22 @@ export const mockGetMemberBy = (members, shouldThrowError) => {
).as('getMemberBy');
};

export const mockEditMember = (members, shouldThrowError) => {
cy.intercept(
{
method: DEFAULT_PATCH.method,
url: new RegExp(`${API_HOST}/${buildPatchMember(ID_FORMAT)}`),
},
({ reply }) => {
if (shouldThrowError) {
return reply({ statusCode: StatusCodes.BAD_REQUEST });
}

return reply('edit member');
},
).as('editMember');
};

// mock upload item for default and s3 upload methods
export const mockUploadItem = (items, shouldThrowError) => {
cy.intercept(
Expand Down Expand Up @@ -425,7 +456,7 @@ export const mockSignInRedirection = () => {
cy.intercept(
{
method: DEFAULT_GET.method,
url: new RegExp(buildSignInPath()),
url: `${AUTHENTICATION_HOST}/${buildSignInPath()}`,
},
({ reply }) => {
reply(redirectionReply);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"dependencies": {
"@graasp/query-client": "git://github.com/graasp/graasp-query-client.git",
"@graasp/ui": "git://github.com/graasp/graasp-ui.git",
"@graasp/ui": "git://github.com/graasp/graasp-ui.git#master",
"@material-ui/core": "4.11.2",
"@material-ui/icons": "4.11.2",
"@material-ui/lab": "4.0.0-alpha.57",
Expand Down
48 changes: 26 additions & 22 deletions src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,44 @@ import {
SHARED_ITEMS_PATH,
buildItemPath,
REDIRECT_PATH,
MEMBER_PROFILE_PATH,
} from '../config/paths';
import Home from './main/Home';
import ItemScreen from './main/ItemScreen';
import SharedItems from './SharedItems';
import Main from './main/Main';
import Authorization from './common/Authorization';
import ModalProviders from './context/ModalProviders';
import ItemLoginAuthorization from './common/ItemLoginAuthorization';
import Redirect from './main/Redirect';
import MemberProfileScreen from './member/MemberProfileScreen';

const App = () => (
<ModalProviders>
<Router>
<Main>
<Switch>
<Route path={HOME_PATH} exact component={Authorization()(Home)} />
<Route
path={SHARED_ITEMS_PATH}
exact
component={Authorization()(SharedItems)}
/>
<Route
path={buildItemPath()}
component={ItemLoginAuthorization()(ItemScreen)}
/>
<Route path={ITEMS_PATH} exact component={Authorization()(Home)} />
<Route
path={REDIRECT_PATH}
exact
component={Authorization()(Redirect)}
/>
<Redirect to={HOME_PATH} />
</Switch>
</Main>
<Switch>
<Route path={HOME_PATH} exact component={Authorization()(Home)} />
<Route
path={SHARED_ITEMS_PATH}
exact
component={Authorization()(SharedItems)}
/>
<Route
path={buildItemPath()}
component={ItemLoginAuthorization()(ItemScreen)}
/>
<Route
path={MEMBER_PROFILE_PATH}
exact
component={Authorization()(MemberProfileScreen)}
/>
<Route path={ITEMS_PATH} exact component={Authorization()(Home)} />
<Route
path={REDIRECT_PATH}
exact
component={Authorization()(Redirect)}
/>
<Redirect to={HOME_PATH} />
</Switch>
</Router>
</ModalProviders>
);
Expand Down
5 changes: 3 additions & 2 deletions src/components/SharedItems.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ErrorAlert from './common/ErrorAlert';
import Items from './main/Items';
import { hooks } from '../config/queryClient';
import Loader from './common/Loader';
import Main from './main/Main';

const SharedItems = () => {
const { t } = useTranslation();
Expand All @@ -24,14 +25,14 @@ const SharedItems = () => {
}

return (
<>
<Main>
<ItemHeader />
<Items
id={SHARED_ITEMS_ID}
title={t('Items Shared With Me')}
items={List(sharedItems)}
/>
</>
</Main>
);
};

Expand Down
Loading

0 comments on commit fe80c8a

Please sign in to comment.