From 7556e19f08c73356d87c30e355fddae5b6c509b7 Mon Sep 17 00:00:00 2001 From: eemaanamir Date: Wed, 30 Oct 2024 14:19:34 +0500 Subject: [PATCH] test: updated tests according to the changes --- src/profile-v2/Certificates.jsx | 1 - src/profile-v2/ProfilePage.jsx | 31 - src/profile-v2/ProfilePage.test.jsx | 156 +- src/profile-v2/UsernameDescription.jsx | 2 - .../__snapshots__/ProfilePage.test.jsx.snap | 13237 +--------------- src/profile-v2/data/actions.js | 66 - src/profile-v2/data/actions.test.js | 108 +- src/profile-v2/data/reducers.js | 63 - src/profile-v2/data/sagas.js | 90 +- src/profile-v2/data/sagas.test.js | 123 +- src/profile-v2/data/selectors.js | 333 +- src/routes/routes.test.jsx | 2 +- 12 files changed, 331 insertions(+), 13881 deletions(-) diff --git a/src/profile-v2/Certificates.jsx b/src/profile-v2/Certificates.jsx index 36a34ea63..1813f7160 100644 --- a/src/profile-v2/Certificates.jsx +++ b/src/profile-v2/Certificates.jsx @@ -22,7 +22,6 @@ const Certificates = ({ }) => { const intl = useIntl(); - // Memoizing the renderCertificate function to prevent unnecessary re-renders const renderCertificate = useCallback(({ certificateType, courseDisplayName, courseOrganization, modifiedDate, downloadUrl, courseId, }) => { diff --git a/src/profile-v2/ProfilePage.jsx b/src/profile-v2/ProfilePage.jsx index 6e9d34318..9ca9083d3 100644 --- a/src/profile-v2/ProfilePage.jsx +++ b/src/profile-v2/ProfilePage.jsx @@ -8,12 +8,8 @@ import { injectIntl } from '@edx/frontend-platform/i18n'; import { Alert, Hyperlink } from '@openedx/paragon'; import { fetchProfile, - saveProfile, saveProfilePhoto, deleteProfilePhoto, - openForm, - closeForm, - updateDraft, } from './data/actions'; import ProfileAvatar from './forms/ProfileAvatar'; import Certificates from './Certificates'; @@ -35,7 +31,6 @@ const ProfilePage = ({ params, intl }) => { dateJoined, yearOfBirth, courseCertificates, - visibilityCourseCertificates, name, profileImage, savePhotoState, @@ -65,22 +60,6 @@ const ProfilePage = ({ params, intl }) => { dispatch(deleteProfilePhoto(context.authenticatedUser.username)); }; - const handleClose = (formId) => { - dispatch(closeForm(formId)); - }; - - const handleOpen = (formId) => { - dispatch(openForm(formId)); - }; - - const handleSubmit = (formId) => { - dispatch(saveProfile(formId, context.authenticatedUser.username)); - }; - - const handleChange = (fieldName, value) => { - dispatch(updateDraft(fieldName, value)); - }; - const isYOBDisabled = () => { const currentYear = new Date().getFullYear(); const isAgeOrNotCompliant = !yearOfBirth || ((currentYear - yearOfBirth) < 13); @@ -125,13 +104,6 @@ const ProfilePage = ({ params, intl }) => { return ; } - const commonFormProps = { - openHandler: handleOpen, - closeHandler: handleClose, - submitHandler: handleSubmit, - changeHandler: handleChange, - }; - return ( <>
@@ -174,9 +146,7 @@ const ProfilePage = ({ params, intl }) => { {isBlockVisible(courseCertificates.length) && ( )}
@@ -186,7 +156,6 @@ const ProfilePage = ({ params, intl }) => { return (
- {/* */} {renderContent()}
); diff --git a/src/profile-v2/ProfilePage.test.jsx b/src/profile-v2/ProfilePage.test.jsx index e347ba8c5..505b84109 100644 --- a/src/profile-v2/ProfilePage.test.jsx +++ b/src/profile-v2/ProfilePage.test.jsx @@ -18,16 +18,10 @@ const storeMocks = { loadingApp: require('./__mocks__/loadingApp.mockStore'), viewOwnProfile: require('./__mocks__/viewOwnProfile.mockStore'), viewOtherProfile: require('./__mocks__/viewOtherProfile.mockStore'), - savingEditedBio: require('./__mocks__/savingEditedBio.mockStore'), }; const requiredProfilePageProps = { fetchUserAccount: () => {}, fetchProfile: () => {}, - saveProfile: () => {}, - saveProfilePhoto: () => {}, - deleteProfilePhoto: () => {}, - openField: () => {}, - closeField: () => {}, params: { username: 'staff' }, }; @@ -66,14 +60,14 @@ beforeEach(() => { }); const ProfilePageWrapper = ({ - contextValue, store, params, requiresParentalConsent, + contextValue, store, params, }) => ( - + @@ -81,14 +75,12 @@ const ProfilePageWrapper = ({ ProfilePageWrapper.defaultProps = { params: { username: 'staff' }, - requiresParentalConsent: null, }; ProfilePageWrapper.propTypes = { contextValue: PropTypes.shape({}).isRequired, store: PropTypes.shape({}).isRequired, params: PropTypes.shape({}), - requiresParentalConsent: PropTypes.bool, }; describe('', () => { @@ -147,92 +139,6 @@ describe('', () => { expect(tree).toMatchSnapshot(); }); - it('while saving an edited bio', () => { - const contextValue = { - authenticatedUser: { userId: 123, username: 'staff', administrator: true }, - config: getConfig(), - }; - const component = ( - - ); - const { container: tree } = render(component); - expect(tree).toMatchSnapshot(); - }); - - it('while saving an edited bio with error', () => { - const storeData = JSON.parse(JSON.stringify(storeMocks.savingEditedBio)); - storeData.profilePage.errors.bio = { userMessage: 'bio error' }; - const contextValue = { - authenticatedUser: { userId: 123, username: 'staff', administrator: true }, - config: getConfig(), - }; - const component = ( - - ); - const { container: tree } = render(component); - expect(tree).toMatchSnapshot(); - }); - - it('test country edit with error', () => { - const storeData = JSON.parse(JSON.stringify(storeMocks.savingEditedBio)); - storeData.profilePage.errors.country = { userMessage: 'country error' }; - storeData.profilePage.currentlyEditingField = 'country'; - const contextValue = { - authenticatedUser: { userId: 123, username: 'staff', administrator: true }, - config: getConfig(), - }; - const component = ( - - ); - const { container: tree } = render(component); - expect(tree).toMatchSnapshot(); - }); - - it('test education edit with error', () => { - const storeData = JSON.parse(JSON.stringify(storeMocks.savingEditedBio)); - storeData.profilePage.errors.levelOfEducation = { userMessage: 'education error' }; - storeData.profilePage.currentlyEditingField = 'levelOfEducation'; - const contextValue = { - authenticatedUser: { userId: 123, username: 'staff', administrator: true }, - config: getConfig(), - }; - const component = ( - - ); - const { container: tree } = render(component); - expect(tree).toMatchSnapshot(); - }); - - it('test preferreded language edit with error', () => { - const storeData = JSON.parse(JSON.stringify(storeMocks.savingEditedBio)); - storeData.profilePage.errors.languageProficiencies = { userMessage: 'preferred language error' }; - storeData.profilePage.currentlyEditingField = 'languageProficiencies'; - const contextValue = { - authenticatedUser: { userId: 123, username: 'staff', administrator: true }, - config: getConfig(), - }; - const component = ( - - ); - const { container: tree } = render(component); - expect(tree).toMatchSnapshot(); - }); - it('without credentials service', () => { const config = getConfig(); config.CREDENTIALS_BASE_URL = ''; @@ -250,64 +156,6 @@ describe('', () => { const { container: tree } = render(component); expect(tree).toMatchSnapshot(); }); - it('test age message alert', () => { - const storeData = JSON.parse(JSON.stringify(storeMocks.viewOwnProfile)); - storeData.userAccount.requiresParentalConsent = true; - storeData.profilePage.account.requiresParentalConsent = true; - const contextValue = { - authenticatedUser: { userId: 123, username: 'staff', administrator: true }, - config: { ...getConfig(), COLLECT_YEAR_OF_BIRTH: true }, - }; - const { container } = render( - , - ); - - expect(container.querySelector('.alert-info')).toHaveClass('show'); - }); - it('test photo error alert', () => { - const storeData = JSON.parse(JSON.stringify(storeMocks.viewOwnProfile)); - storeData.profilePage.errors.photo = { userMessage: 'error' }; - const contextValue = { - authenticatedUser: { userId: 123, username: 'staff', administrator: true }, - config: { ...getConfig(), COLLECT_YEAR_OF_BIRTH: true }, - }; - const { container } = render( - , - ); - - expect(container.querySelector('.alert-danger')).toHaveClass('show'); - }); - - it.each([ - ['test user with non-disabled country', 'PK'], - ['test user with disabled country', 'RU'], - ])('test user with %s', (_, accountCountry) => { - const storeData = JSON.parse(JSON.stringify(storeMocks.savingEditedBio)); - storeData.profilePage.errors.country = {}; - storeData.profilePage.currentlyEditingField = 'country'; - storeData.profilePage.disabledCountries = ['RU']; - storeData.profilePage.account.country = accountCountry; - const contextValue = { - authenticatedUser: { userId: 123, username: 'staff', administrator: true }, - config: getConfig(), - }; - const component = ( - - ); - const { container: tree } = render(component); - expect(tree).toMatchSnapshot(); - }); }); describe('handles analytics', () => { diff --git a/src/profile-v2/UsernameDescription.jsx b/src/profile-v2/UsernameDescription.jsx index af03b4eae..bbbd70333 100644 --- a/src/profile-v2/UsernameDescription.jsx +++ b/src/profile-v2/UsernameDescription.jsx @@ -1,7 +1,5 @@ import React from 'react'; import { FormattedMessage } from '@edx/frontend-platform/i18n'; -import { VisibilityOff } from '@openedx/paragon/icons'; -import { Icon } from '@openedx/paragon'; import { getConfig } from '@edx/frontend-platform'; const UsernameDescription = () => ( diff --git a/src/profile-v2/__snapshots__/ProfilePage.test.jsx.snap b/src/profile-v2/__snapshots__/ProfilePage.test.jsx.snap index 843a2c931..0f1236898 100644 --- a/src/profile-v2/__snapshots__/ProfilePage.test.jsx.snap +++ b/src/profile-v2/__snapshots__/ProfilePage.test.jsx.snap @@ -5,9 +5,6 @@ exports[` Renders correctly in various states app loading 1`] = `
-
Renders correctly in various states app loading 1`] = `
`; -exports[` Renders correctly in various states test country edit with error 1`] = ` +exports[` Renders correctly in various states viewing other profile with all fields 1`] = `
-
Renders correctly in various states test country edit w
-
- -
-
Renders correctly in various states test country edit w />
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
- -
-
-
-
-
-

staff

- Member since - 2017 -

-
-
-
- -
-
-

- Full Name - -

-

+ Member since - - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-
-
- - -
-
- country error -
-
-
-
-
- - - - - - - -
-
- - -
-
-
-
-
-
-
-
-
-

- Primary Language Spoken - -

-

- - + 2017 - Everyone on localhost -

+
-

- Yoruba -

-
-
-
-

- Education - -

-

- - - - Just me - -

-
-

- Elementary/primary school -

+ View My Records +
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
+ Your learner records information is only visible to you. Only your username is visible to others on localhost. +

+
+
+
+
+
-
-
-

- About Me - -

-

- - - - Everyone on localhost - -

-
-

- This is my bio -

-
+ Your certificates +
-
-
-

- My Certificates - -

-

- - - - Everyone on localhost - -

-
-
-
-
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
-
-
-
-
+ Your learner records information is only visible to you. Only your username is visible to others on localhost. +

+ You don't have any certificates yet.
`; -exports[` Renders correctly in various states test education edit with error 1`] = ` +exports[` Renders correctly in various states viewing own profile 1`] = `
-
Renders correctly in various states test education edit />
-
-
-
-
-

staff

- Member since - 2017 -

-
-
-
- -
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
- -
-
-
-

- Full Name - -

-

- - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-

- Location - -

-

- - + 1 - Everyone on localhost -

+ certifications +
-

- Montenegro -

-
-
-
-

- Primary Language Spoken - -

-

- - - - Everyone on localhost - -

-
-

- Yoruba -

+ View My Records +
+
+
+
+
+
+
+
+
-
-
-
-
- - -
-
- education error -
-
-
-
-
- - - - - - - -
-
- - -
-
-
-
-
+ Your certificates +
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
+ Your learner records information is only visible to you. Only your username is visible to others on localhost. +

-

+
- About Me - -

-

- -

- - - - Everyone on localhost - -

-
-

- This is my bio -

-
-
-
-
-
-

- My Certificates - -

-

- -

- - - - Everyone on localhost - -

-
-
-
+ edX +

+

+ Completed on + 3/4/2019 +

+
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
+ View Certificate +
@@ -3233,25 +378,22 @@ exports[` Renders correctly in various states test education edit
`; -exports[` Renders correctly in various states test preferreded language edit with error 1`] = ` +exports[` Renders correctly in various states without credentials service 1`] = `
-
Renders correctly in various states test preferreded la />
-
-
- +
+
+
-
+
+
+
- -

- staff -

-

- Member since - 2017 -

-
-
+ Your certificates +
- - View My Records - - - - - in a new tab - - - - + Your learner records information is only visible to you. Only your username is visible to others on localhost. +

+
+
-

+
- Full Name - -

-

- +

+ edX Demonstration Course +
+

+ From +

+

+ edX +

+

+ Completed on + 3/4/2019 +

+
+
- - - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-

- Location - -

-

- - - - Everyone on localhost - -

-
-

- Montenegro -

-
-
-
-
-
-
-
- - -
-
- preferred language error -
-
-
-
-
- - - - - - - -
-
- - -
-
-
-
-
-
-
-
-
-

- Education - -

-

- - - - Just me - -

-
-

- Elementary/primary school -

-
-
-
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
-
-
-
-
-
-
-

- About Me - -

-

- - - - Everyone on localhost - -

-
-

- This is my bio -

-
-
-
-
-
-

- My Certificates - -

-

- - - - Everyone on localhost - -

-
-
-
-
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` Renders correctly in various states test user with test user with disabled country 1`] = ` -
-
-
-
-
-
-
-
-
-
- -
- profile avatar -
-
- -
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
-
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
-
-
-
-
-

- Full Name - -

-

- - - - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-
-
- - -
-
-
- - - - - - - -
-
- - -
-
-
-
-
-
-
-
-
-

- Primary Language Spoken - -

-

- - - - Everyone on localhost - -

-
-

- Yoruba -

-
-
-
-
-
-

- Education - -

-

- - - - Just me - -

-
-

- Elementary/primary school -

-
-
-
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
-
-
-
-
-
-
-

- About Me - -

-

- - - - Everyone on localhost - -

-
-

- This is my bio -

-
-
-
-
-
-

- My Certificates - -

-

- - - - Everyone on localhost - -

-
-
-
-
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` Renders correctly in various states test user with test user with non-disabled country 1`] = ` -
-
-
-
-
-
-
-
-
-
- -
- profile avatar -
-
- -
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
-
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
-
-
-
-
-

- Full Name - -

-

- - - - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-
-
- - -
-
-
- - - - - - - -
-
- - -
-
-
-
-
-
-
-
-
-

- Primary Language Spoken - -

-

- - - - Everyone on localhost - -

-
-

- Yoruba -

-
-
-
-
-
-

- Education - -

-

- - - - Just me - -

-
-

- Elementary/primary school -

-
-
-
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
-
-
-
-
-
-
-

- About Me - -

-

- - - - Everyone on localhost - -

-
-

- This is my bio -

-
-
-
-
-
-

- My Certificates - -

-

- - - - Everyone on localhost - -

-
-
-
-
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` Renders correctly in various states viewing other profile with all fields 1`] = ` -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
- - - -
- Your profile information is only visible to you. Only your username is visible to others on localhost. -
-
-
-
-
- -
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
- - - -
- Your profile information is only visible to you. Only your username is visible to others on localhost. -
-
-
-
-
- -
-
-
-

- Full Name -

-
-

- user -

-
-
-
-
-
-

- Location -

-
-

-

-
-
-
-
-

- Primary Language Spoken -

-
-

-

-
-
-
-
-

- Education -

-
-

- Other education -

-
-
-
-
-
-

- Social Links -

-
-
    -
-
-
-
-
-
-
-

- About Me -

-
-

- bio -

-
-
-
-
-
-

- My Certificates -

-
- You don't have any certificates yet. -
-
-
-
-
-
-
-`; - -exports[` Renders correctly in various states viewing own profile 1`] = ` -
-
-
-
-
-
-
-
-
-
- -
- profile avatar -
-
- -
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
- -
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
- -
-
-
-

- Full Name - -

-

- - - - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-

- Location - -

-

- - - - Everyone on localhost - -

-
-

- Montenegro -

-
-
-
-
-
-

- Primary Language Spoken - -

-

- - - - Everyone on localhost - -

-
-

- Yoruba -

-
-
-
-
-
-

- Education - -

-

- - - - Just me - -

-
-

- Elementary/primary school -

-
-
-
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
-
-
-
-
-
-
-

- About Me - -

-

- - - - Everyone on localhost - -

-
-

- This is my bio -

-
-
-
-
-
-

- My Certificates - -

-

- - - - Everyone on localhost - -

-
-
-
-
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` Renders correctly in various states while saving an edited bio 1`] = ` -
-
-
-
-
-
-
-
-
-
- -
- profile avatar -
-
- -
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
- -
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
- -
-
-
-

- Full Name - -

-

- - - - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-

- Location - -

-

- - - - Everyone on localhost - -

-
-

- Montenegro -

-
-
-
-
-
-

- Primary Language Spoken - -

-

- - - - Everyone on localhost - -

-
-

- Yoruba -

-
-
-
-
-
-

- Education - -

-

- - - - Just me - -

-
-

- Elementary/primary school -

-
-
-
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
-
-
-
-
-
-
-
-
- - -
-
-
- - - - - - - -
-
- - -
-
-
-
-
-
-
-
-
-

- My Certificates - -

-

- - - - Everyone on localhost - -

-
-
-
-
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` Renders correctly in various states while saving an edited bio with error 1`] = ` -
-
-
-
-
-
-
-
-
-
- -
- profile avatar -
-
- -
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
- -
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
- -
-
-
-

- Full Name - -

-

- - - - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-

- Location - -

-

- - - - Everyone on localhost - -

-
-

- Montenegro -

-
-
-
-
-
-

- Primary Language Spoken - -

-

- - - - Everyone on localhost - -

-
-

- Yoruba -

-
-
-
-
-
-

- Education - -

-

- - - - Just me - -

-
-

- Elementary/primary school -

-
-
-
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
-
-
-
-
-
-
-
-
- - -
-
- bio error -
-
-
-
-
- - - - - - - -
-
- - -
-
-
-
-
-
-
-
-
-

- My Certificates - -

-

- - - - Everyone on localhost - -

-
-
-
-
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` Renders correctly in various states without credentials service 1`] = ` -
-
-
-
-
-
-
-
-
-
- -
- profile avatar -
-
- -
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
-
-
-
-
-
-
- -

- staff -

-

- Member since - 2017 -

-
-
-
-
-
-
-
-

- Full Name - -

-

- - - - Just me - -

-
-

- Lemon Seltzer -

- - This is the name that appears in your account and on your certificates. - -
-
-
-
-
-

- Location - -

-

- - - - Everyone on localhost - -

-
-

- Montenegro -

-
-
-
-
-
-

- Primary Language Spoken - -

-

- - - - Everyone on localhost - -

-
-

- Yoruba -

-
-
-
-
-
-

- Education - -

-

- - - - Just me - -

-
-

- Elementary/primary school -

-
-
-
-
-
-

- Social Links - -

-

- - - - Everyone on localhost - -

-
- -
-
-
-
-
-
-
-

- About Me - -

-

- - - - Everyone on localhost - -

-
-

- This is my bio -

-
-
-
-
-
-

- My Certificates - -

-

- - - - Everyone on localhost - -

-
-
-
-
-
-
-
-

- Verified Certificate -

-

- edX Demonstration Course -

-
-

- From -

-

- edX -

-
-

- Completed on - 3/4/2019 -

- -
+ View Certificate +
diff --git a/src/profile-v2/data/actions.js b/src/profile-v2/data/actions.js index 38a5b7968..ddf8c34cf 100644 --- a/src/profile-v2/data/actions.js +++ b/src/profile-v2/data/actions.js @@ -1,13 +1,8 @@ import { AsyncActionType } from '../utils'; export const FETCH_PROFILE = new AsyncActionType('PROFILE', 'FETCH_PROFILE'); -export const SAVE_PROFILE = new AsyncActionType('PROFILE', 'SAVE_PROFILE'); export const SAVE_PROFILE_PHOTO = new AsyncActionType('PROFILE', 'SAVE_PROFILE_PHOTO'); export const DELETE_PROFILE_PHOTO = new AsyncActionType('PROFILE', 'DELETE_PROFILE_PHOTO'); -export const OPEN_FORM = 'OPEN_FORM'; -export const CLOSE_FORM = 'CLOSE_FORM'; -export const UPDATE_DRAFT = 'UPDATE_DRAFT'; -export const RESET_DRAFTS = 'RESET_DRAFTS'; // FETCH PROFILE ACTIONS @@ -37,37 +32,6 @@ export const fetchProfileReset = () => ({ type: FETCH_PROFILE.RESET, }); -// SAVE PROFILE ACTIONS - -export const saveProfile = (formId, username) => ({ - type: SAVE_PROFILE.BASE, - payload: { - formId, - username, - }, -}); - -export const saveProfileBegin = () => ({ - type: SAVE_PROFILE.BEGIN, -}); - -export const saveProfileSuccess = (account, preferences) => ({ - type: SAVE_PROFILE.SUCCESS, - payload: { - account, - preferences, - }, -}); - -export const saveProfileReset = () => ({ - type: SAVE_PROFILE.RESET, -}); - -export const saveProfileFailure = errors => ({ - type: SAVE_PROFILE.FAILURE, - payload: { errors }, -}); - // SAVE PROFILE PHOTO ACTIONS export const saveProfilePhoto = (username, formData) => ({ @@ -117,33 +81,3 @@ export const deleteProfilePhotoSuccess = profileImage => ({ export const deleteProfilePhotoReset = () => ({ type: DELETE_PROFILE_PHOTO.RESET, }); - -// FIELD STATE ACTIONS - -export const openForm = formId => ({ - type: OPEN_FORM, - payload: { - formId, - }, -}); - -export const closeForm = formId => ({ - type: CLOSE_FORM, - payload: { - formId, - }, -}); - -// FORM STATE ACTIONS - -export const updateDraft = (name, value) => ({ - type: UPDATE_DRAFT, - payload: { - name, - value, - }, -}); - -export const resetDrafts = () => ({ - type: RESET_DRAFTS, -}); diff --git a/src/profile-v2/data/actions.test.js b/src/profile-v2/data/actions.test.js index 626888840..275d695ca 100644 --- a/src/profile-v2/data/actions.test.js +++ b/src/profile-v2/data/actions.test.js @@ -1,14 +1,4 @@ import { - openForm, - closeForm, - OPEN_FORM, - CLOSE_FORM, - SAVE_PROFILE, - saveProfileBegin, - saveProfileSuccess, - saveProfileFailure, - saveProfileReset, - saveProfile, SAVE_PROFILE_PHOTO, saveProfilePhotoBegin, saveProfilePhotoSuccess, @@ -22,76 +12,6 @@ import { deleteProfilePhoto, } from './actions'; -describe('editable field actions', () => { - it('should create an open action', () => { - const expectedAction = { - type: OPEN_FORM, - payload: { - formId: 'name', - }, - }; - expect(openForm('name')).toEqual(expectedAction); - }); - - it('should create a closed action', () => { - const expectedAction = { - type: CLOSE_FORM, - payload: { - formId: 'name', - }, - }; - expect(closeForm('name')).toEqual(expectedAction); - }); -}); - -describe('SAVE profile actions', () => { - it('should create an action to signal the start of a profile save', () => { - const expectedAction = { - type: SAVE_PROFILE.BASE, - payload: { - formId: 'name', - }, - }; - expect(saveProfile('name')).toEqual(expectedAction); - }); - - it('should create an action to signal user profile save success', () => { - const accountData = { name: 'Full Name' }; - const preferencesData = { visibility: { name: 'private' } }; - const expectedAction = { - type: SAVE_PROFILE.SUCCESS, - payload: { - account: accountData, - preferences: preferencesData, - }, - }; - expect(saveProfileSuccess(accountData, preferencesData)).toEqual(expectedAction); - }); - - it('should create an action to signal user profile save beginning', () => { - const expectedAction = { - type: SAVE_PROFILE.BEGIN, - }; - expect(saveProfileBegin()).toEqual(expectedAction); - }); - - it('should create an action to signal user profile save success', () => { - const expectedAction = { - type: SAVE_PROFILE.RESET, - }; - expect(saveProfileReset()).toEqual(expectedAction); - }); - - it('should create an action to signal user account save failure', () => { - const errors = ['Test failure']; - const expectedAction = { - type: SAVE_PROFILE.FAILURE, - payload: { errors }, - }; - expect(saveProfileFailure(errors)).toEqual(expectedAction); - }); -}); - describe('SAVE profile photo actions', () => { it('should create an action to signal the start of a profile photo save', () => { const formData = 'multipart form data'; @@ -123,7 +43,7 @@ describe('SAVE profile photo actions', () => { expect(saveProfilePhotoSuccess(newPhotoData)).toEqual(expectedAction); }); - it('should create an action to signal user profile photo save success', () => { + it('should create an action to signal user profile photo save reset', () => { const expectedAction = { type: SAVE_PROFILE_PHOTO.RESET, }; @@ -169,34 +89,10 @@ describe('DELETE profile photo actions', () => { expect(deleteProfilePhotoSuccess(defaultPhotoData)).toEqual(expectedAction); }); - it('should create an action to signal user profile photo deletion success', () => { + it('should create an action to signal user profile photo deletion reset', () => { const expectedAction = { type: DELETE_PROFILE_PHOTO.RESET, }; expect(deleteProfilePhotoReset()).toEqual(expectedAction); }); }); - -describe('Editable field opening and closing actions', () => { - const formId = 'name'; - - it('should create an action to signal the opening a field', () => { - const expectedAction = { - type: OPEN_FORM, - payload: { - formId, - }, - }; - expect(openForm(formId)).toEqual(expectedAction); - }); - - it('should create an action to signal the closing a field', () => { - const expectedAction = { - type: CLOSE_FORM, - payload: { - formId, - }, - }; - expect(closeForm(formId)).toEqual(expectedAction); - }); -}); diff --git a/src/profile-v2/data/reducers.js b/src/profile-v2/data/reducers.js index 88a1bc9c0..684fa71cb 100644 --- a/src/profile-v2/data/reducers.js +++ b/src/profile-v2/data/reducers.js @@ -1,25 +1,17 @@ import { - SAVE_PROFILE, SAVE_PROFILE_PHOTO, DELETE_PROFILE_PHOTO, - CLOSE_FORM, - OPEN_FORM, FETCH_PROFILE, - UPDATE_DRAFT, - RESET_DRAFTS, } from './actions'; export const initialState = { errors: {}, - saveState: null, savePhotoState: null, - currentlyEditingField: null, account: { socialLinks: [], }, preferences: {}, courseCertificates: [], - drafts: {}, isLoadingProfile: true, isAuthenticatedUserProfile: false, disabledCountries: ['RU'], @@ -44,34 +36,6 @@ const profilePage = (state = initialState, action = {}) => { isLoadingProfile: false, isAuthenticatedUserProfile: action.isAuthenticatedUserProfile, }; - case SAVE_PROFILE.BEGIN: - return { - ...state, - saveState: 'pending', - errors: {}, - }; - case SAVE_PROFILE.SUCCESS: - return { - ...state, - saveState: 'complete', - errors: {}, - // Account is always replaced completely. - account: action.payload.account !== null ? action.payload.account : state.account, - // Preferences changes get merged in. - preferences: { ...state.preferences, ...action.payload.preferences }, - }; - case SAVE_PROFILE.FAILURE: - return { - ...state, - saveState: 'error', - errors: { ...state.errors, ...action.payload.errors }, - }; - case SAVE_PROFILE.RESET: - return { - ...state, - saveState: null, - errors: {}, - }; case SAVE_PROFILE_PHOTO.BEGIN: return { @@ -127,33 +91,6 @@ const profilePage = (state = initialState, action = {}) => { errors: {}, }; - case UPDATE_DRAFT: - return { - ...state, - drafts: { ...state.drafts, [action.payload.name]: action.payload.value }, - }; - - case RESET_DRAFTS: - return { - ...state, - drafts: {}, - }; - case OPEN_FORM: - return { - ...state, - currentlyEditingField: action.payload.formId, - drafts: {}, - }; - case CLOSE_FORM: - // Only close if the field to close is undefined or matches the field that is currently open - if (action.payload.formId === state.currentlyEditingField) { - return { - ...state, - currentlyEditingField: null, - drafts: {}, - }; - } - return state; default: return state; } diff --git a/src/profile-v2/data/sagas.js b/src/profile-v2/data/sagas.js index cfece88bb..5e869dd48 100644 --- a/src/profile-v2/data/sagas.js +++ b/src/profile-v2/data/sagas.js @@ -1,16 +1,13 @@ import { history } from '@edx/frontend-platform'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; -import pick from 'lodash.pick'; import { all, call, - delay, put, select, takeEvery, } from 'redux-saga/effects'; import { - closeForm, deleteProfilePhotoBegin, deleteProfilePhotoReset, deleteProfilePhotoSuccess, @@ -19,19 +16,12 @@ import { fetchProfileReset, fetchProfileSuccess, FETCH_PROFILE, - resetDrafts, - saveProfileBegin, - saveProfileFailure, saveProfilePhotoBegin, - saveProfilePhotoFailure, saveProfilePhotoReset, saveProfilePhotoSuccess, - saveProfileReset, - saveProfileSuccess, - SAVE_PROFILE, SAVE_PROFILE_PHOTO, } from './actions'; -import { handleSaveProfileSelector, userAccountSelector } from './selectors'; +import { userAccountSelector } from './selectors'; import * as ProfileApiService from './services'; export function* handleFetchProfile(action) { @@ -102,73 +92,6 @@ export function* handleFetchProfile(action) { } } -export function* handleSaveProfile(action) { - try { - const { drafts, preferences } = yield select(handleSaveProfileSelector); - - const accountDrafts = pick(drafts, [ - 'bio', - 'courseCertificates', - 'country', - 'levelOfEducation', - 'languageProficiencies', - 'name', - 'socialLinks', - ]); - - const preferencesDrafts = pick(drafts, [ - 'visibilityBio', - 'visibilityCourseCertificates', - 'visibilityCountry', - 'visibilityLevelOfEducation', - 'visibilityLanguageProficiencies', - 'visibilityName', - 'visibilitySocialLinks', - ]); - - if (Object.keys(preferencesDrafts).length > 0) { - preferencesDrafts.accountPrivacy = 'custom'; - } - - yield put(saveProfileBegin()); - let accountResult = null; - // Build the visibility drafts into a structure the API expects. - - if (Object.keys(accountDrafts).length > 0) { - accountResult = yield call( - ProfileApiService.patchProfile, - action.payload.username, - accountDrafts, - ); - } - - let preferencesResult = preferences; // assume it hasn't changed. - if (Object.keys(preferencesDrafts).length > 0) { - yield call(ProfileApiService.patchPreferences, action.payload.username, preferencesDrafts); - // TODO: Temporary deoptimization since the patchPreferences call doesn't return anything. - // Remove this second call once we can get a result from the one above. - preferencesResult = yield call(ProfileApiService.getPreferences, action.payload.username); - } - - // The account result is returned from the server. - // The preferences draft is valid if the server didn't complain, so - // pass it through directly. - yield put(saveProfileSuccess(accountResult, preferencesResult)); - yield delay(1000); - yield put(closeForm(action.payload.formId)); - yield delay(300); - yield put(saveProfileReset()); - yield put(resetDrafts()); - } catch (e) { - if (e.processedData && e.processedData.fieldErrors) { - yield put(saveProfileFailure(e.processedData.fieldErrors)); - } else { - yield put(saveProfileReset()); - throw e; - } - } -} - export function* handleSaveProfilePhoto(action) { const { username, formData } = action.payload; @@ -178,12 +101,8 @@ export function* handleSaveProfilePhoto(action) { yield put(saveProfilePhotoSuccess(photoResult)); yield put(saveProfilePhotoReset()); } catch (e) { - if (e.processedData) { - yield put(saveProfilePhotoFailure(e.processedData)); - } else { - yield put(saveProfilePhotoReset()); - throw e; - } + // Just reset on error, since editing functionality is deprecated + yield put(saveProfilePhotoReset()); } } @@ -196,14 +115,13 @@ export function* handleDeleteProfilePhoto(action) { yield put(deleteProfilePhotoSuccess(photoResult)); yield put(deleteProfilePhotoReset()); } catch (e) { + // Just reset on error, since editing functionality is deprecated yield put(deleteProfilePhotoReset()); - throw e; } } export default function* profileSaga() { yield takeEvery(FETCH_PROFILE.BASE, handleFetchProfile); - yield takeEvery(SAVE_PROFILE.BASE, handleSaveProfile); yield takeEvery(SAVE_PROFILE_PHOTO.BASE, handleSaveProfilePhoto); yield takeEvery(DELETE_PROFILE_PHOTO.BASE, handleDeleteProfilePhoto); } diff --git a/src/profile-v2/data/sagas.test.js b/src/profile-v2/data/sagas.test.js index 379c0cfd6..9482d8907 100644 --- a/src/profile-v2/data/sagas.test.js +++ b/src/profile-v2/data/sagas.test.js @@ -2,40 +2,39 @@ import { takeEvery, put, call, - delay, select, all, } from 'redux-saga/effects'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; import * as profileActions from './actions'; -import { handleSaveProfileSelector, userAccountSelector } from './selectors'; +import { userAccountSelector } from './selectors'; + +import profileSaga, { + handleFetchProfile, + handleSaveProfilePhoto, + handleDeleteProfilePhoto, +} from './sagas'; +import * as ProfileApiService from './services'; +import { + deleteProfilePhotoBegin, + deleteProfilePhotoReset, + saveProfilePhotoBegin, + saveProfilePhotoReset, +} from './actions'; jest.mock('./services', () => ({ - getProfile: jest.fn(), - patchProfile: jest.fn(), - postProfilePhoto: jest.fn(), - deleteProfilePhoto: jest.fn(), - getPreferences: jest.fn(), getAccount: jest.fn(), getCourseCertificates: jest.fn(), + getPreferences: jest.fn(), + postProfilePhoto: jest.fn(), + deleteProfilePhoto: jest.fn(), })); jest.mock('@edx/frontend-platform/auth', () => ({ getAuthenticatedUser: jest.fn(), })); -// RootSaga and ProfileApiService must be imported AFTER the mock above. -/* eslint-disable import/first */ -import profileSaga, { - handleFetchProfile, - handleSaveProfile, - handleSaveProfilePhoto, - handleDeleteProfilePhoto, -} from './sagas'; -import * as ProfileApiService from './services'; -/* eslint-enable import/first */ - describe('RootSaga', () => { describe('profileSaga', () => { it('should pass actions to the correct sagas', () => { @@ -43,8 +42,6 @@ describe('RootSaga', () => { expect(gen.next().value) .toEqual(takeEvery(profileActions.FETCH_PROFILE.BASE, handleFetchProfile)); - expect(gen.next().value) - .toEqual(takeEvery(profileActions.SAVE_PROFILE.BASE, handleSaveProfile)); expect(gen.next().value) .toEqual(takeEvery(profileActions.SAVE_PROFILE_PHOTO.BASE, handleSaveProfilePhoto)); expect(gen.next().value) @@ -111,55 +108,51 @@ describe('RootSaga', () => { }); }); - describe('handleSaveProfile', () => { - const selectorData = { - username: 'my username', - drafts: { - name: 'Full Name', - }, - preferences: {}, - }; - - it('should successfully process a saveProfile request if there are no exceptions', () => { - const action = profileActions.saveProfile('ze form id', 'my username'); - const gen = handleSaveProfile(action); - const profile = { - name: 'Full Name', - levelOfEducation: 'b', - }; - expect(gen.next().value).toEqual(select(handleSaveProfileSelector)); - expect(gen.next(selectorData).value).toEqual(put(profileActions.saveProfileBegin())); - expect(gen.next().value).toEqual(call(ProfileApiService.patchProfile, 'my username', { - name: 'Full Name', - })); - // The library would supply the result of the above call - // as the parameter to the NEXT yield. Here: - expect(gen.next(profile).value).toEqual(put(profileActions.saveProfileSuccess(profile, {}))); - expect(gen.next().value).toEqual(delay(1000)); - expect(gen.next().value).toEqual(put(profileActions.closeForm('ze form id'))); - expect(gen.next().value).toEqual(delay(300)); - expect(gen.next().value).toEqual(put(profileActions.saveProfileReset())); - expect(gen.next().value).toEqual(put(profileActions.resetDrafts())); + describe('handleSaveProfilePhoto', () => { + it('should publish a reset action on error', () => { + const action = profileActions.saveProfilePhoto('my username', {}); + const gen = handleSaveProfilePhoto(action); + const error = new Error('Error occurred'); + + expect(gen.next().value).toEqual(put(saveProfilePhotoBegin())); + expect(gen.throw(error).value).toEqual(put(saveProfilePhotoReset())); expect(gen.next().value).toBeUndefined(); }); + }); - it('should successfully publish a failure action on exception', () => { - const error = new Error('uhoh'); - error.processedData = { - fieldErrors: { - uhoh: 'not good', - }, - }; - const action = profileActions.saveProfile( - 'ze form id', - 'my username', - ); - const gen = handleSaveProfile(action); - - expect(gen.next().value).toEqual(select(handleSaveProfileSelector)); - expect(gen.next(selectorData).value).toEqual(put(profileActions.saveProfileBegin())); + describe('handleDeleteProfilePhoto', () => { + it('should publish a reset action on error', () => { + const action = profileActions.deleteProfilePhoto('my username'); + const gen = handleDeleteProfilePhoto(action); + const error = new Error('Error occurred'); + + expect(gen.next().value).toEqual(put(deleteProfilePhotoBegin())); + expect(gen.throw(error).value).toEqual(put(deleteProfilePhotoReset())); + expect(gen.next().value).toBeUndefined(); + }); + }); + + describe('handleDeleteProfilePhoto', () => { + it('should successfully process a deleteProfilePhoto request if there are no exceptions', () => { + const action = profileActions.deleteProfilePhoto('my username'); + const gen = handleDeleteProfilePhoto(action); + const photoResult = {}; + + expect(gen.next().value).toEqual(put(profileActions.deleteProfilePhotoBegin())); + expect(gen.next().value).toEqual(call(ProfileApiService.deleteProfilePhoto, 'my username')); + expect(gen.next(photoResult).value).toEqual(put(profileActions.deleteProfilePhotoSuccess(photoResult))); + expect(gen.next().value).toEqual(put(profileActions.deleteProfilePhotoReset())); + expect(gen.next().value).toBeUndefined(); + }); + + it('should publish a failure action on exception', () => { + const error = new Error('Error occurred'); + const action = profileActions.deleteProfilePhoto('my username'); + const gen = handleDeleteProfilePhoto(action); + + expect(gen.next().value).toEqual(put(profileActions.deleteProfilePhotoBegin())); const result = gen.throw(error); - expect(result.value).toEqual(put(profileActions.saveProfileFailure({ uhoh: 'not good' }))); + expect(result.value).toEqual(put(profileActions.deleteProfilePhotoReset())); expect(gen.next().value).toBeUndefined(); }); }); diff --git a/src/profile-v2/data/selectors.js b/src/profile-v2/data/selectors.js index 211cdf0d4..5241c5acd 100644 --- a/src/profile-v2/data/selectors.js +++ b/src/profile-v2/data/selectors.js @@ -1,152 +1,16 @@ import { createSelector } from 'reselect'; -import { - getLocale, - getLanguageList, - getCountryList, - getCountryMessages, - getLanguageMessages, -} from '@edx/frontend-platform/i18n'; // eslint-disable-line -export const formIdSelector = (state, props) => props.formId; export const userAccountSelector = state => state.userAccount; export const profileAccountSelector = state => state.profilePage.account; -export const profileDraftsSelector = state => state.profilePage.drafts; -export const accountPrivacySelector = state => state.profilePage.preferences.accountPrivacy; -export const profilePreferencesSelector = state => state.profilePage.preferences; export const profileCourseCertificatesSelector = state => state.profilePage.courseCertificates; -export const profileAccountDraftsSelector = state => state.profilePage.accountDrafts; -export const profileVisibilityDraftsSelector = state => state.profilePage.visibilityDrafts; -export const saveStateSelector = state => state.profilePage.saveState; export const savePhotoStateSelector = state => state.profilePage.savePhotoState; export const isLoadingProfileSelector = state => state.profilePage.isLoadingProfile; -export const currentlyEditingFieldSelector = state => state.profilePage.currentlyEditingField; export const accountErrorsSelector = state => state.profilePage.errors; -export const isAuthenticatedUserProfileSelector = state => state.profilePage.isAuthenticatedUserProfile; -export const disabledCountriesSelector = state => state.profilePage.disabledCountries; - -export const editableFormModeSelector = createSelector( - profileAccountSelector, - isAuthenticatedUserProfileSelector, - profileCourseCertificatesSelector, - formIdSelector, - currentlyEditingFieldSelector, - (account, isAuthenticatedUserProfile, certificates, formId, currentlyEditingField) => { - // If the prop doesn't exist, that means it hasn't been set (for the current user's profile) - // or is being hidden from us (for other users' profiles) - let propExists = account[formId] != null && account[formId].length > 0; - propExists = formId === 'certificates' ? certificates.length > 0 : propExists; // overwrite for certificates - // If this isn't the current user's profile - if (!isAuthenticatedUserProfile) { - return 'static'; - } - // the current user has no age set / under 13 ... - if (account.requiresParentalConsent) { - // then there are only two options: static or nothing. - // We use 'null' as a return value because the consumers of - // getMode render nothing at all on a mode of null. - return propExists ? 'static' : null; - } - // Otherwise, if this is the current user's profile... - if (formId === currentlyEditingField) { - return 'editing'; - } - - if (!propExists) { - return 'empty'; - } - - return 'editable'; - }, -); - -export const accountDraftsFieldSelector = createSelector( - formIdSelector, - profileDraftsSelector, - (formId, drafts) => drafts[formId], -); - -export const visibilityDraftsFieldSelector = createSelector( - formIdSelector, - profileVisibilityDraftsSelector, - (formId, visibilityDrafts) => visibilityDrafts[formId], -); - -// Note: Error messages are delivered from the server -// localized according to a user's account settings -export const formErrorSelector = createSelector( - accountErrorsSelector, - formIdSelector, - (errors, formId) => (errors[formId] ? errors[formId].userMessage : null), -); - -export const editableFormSelector = createSelector( - editableFormModeSelector, - formErrorSelector, - saveStateSelector, - (editMode, error, saveState) => ({ - editMode, - error, - saveState, - }), -); - -// Because this selector has no input selectors, it will only be evaluated once. This is fine -// for now because we don't allow users to change the locale after page load. -// Once we DO allow this, we should create an actual action which dispatches the locale into redux, -// then we can modify this to get the locale from state rather than from getLocale() directly. -// Once we do that, this will work as expected and be re-evaluated when the locale changes. -export const localeSelector = () => getLocale(); -export const countryMessagesSelector = createSelector( - localeSelector, - locale => getCountryMessages(locale), -); -export const languageMessagesSelector = createSelector( - localeSelector, - locale => getLanguageMessages(locale), -); - -export const sortedLanguagesSelector = createSelector( - localeSelector, - locale => getLanguageList(locale), -); - -export const sortedCountriesSelector = createSelector( - localeSelector, - locale => getCountryList(locale), -); - -export const preferredLanguageSelector = createSelector( - editableFormSelector, - sortedLanguagesSelector, - languageMessagesSelector, - (editableForm, sortedLanguages, languageMessages) => ({ - ...editableForm, - sortedLanguages, - languageMessages, - }), -); - -export const countrySelector = createSelector( - editableFormSelector, - sortedCountriesSelector, - countryMessagesSelector, - disabledCountriesSelector, - profileAccountSelector, - (editableForm, sortedCountries, countryMessages, disabledCountries, account) => ({ - ...editableForm, - sortedCountries, - countryMessages, - disabledCountries, - committedCountry: account.country, - }), -); export const certificatesSelector = createSelector( - editableFormSelector, profileCourseCertificatesSelector, - (editableForm, certificates) => ({ - ...editableForm, + (certificates) => ({ certificates, value: certificates, }), @@ -162,180 +26,19 @@ export const profileImageSelector = createSelector( : {}), ); -/** - * This is used by a saga to pull out data to process. - */ -export const handleSaveProfileSelector = createSelector( - profileDraftsSelector, - profilePreferencesSelector, - (drafts, preferences) => ({ - drafts, - preferences, - }), -); - -// Reformats the social links in a platform-keyed hash. -const socialLinksByPlatformSelector = createSelector( - profileAccountSelector, - (account) => { - const linksByPlatform = {}; - if (Array.isArray(account.socialLinks)) { - account.socialLinks.forEach((socialLink) => { - linksByPlatform[socialLink.platform] = socialLink; - }); - } - return linksByPlatform; - }, -); - -const draftSocialLinksByPlatformSelector = createSelector( - profileDraftsSelector, - (drafts) => { - const linksByPlatform = {}; - if (Array.isArray(drafts.socialLinks)) { - drafts.socialLinks.forEach((socialLink) => { - linksByPlatform[socialLink.platform] = socialLink; - }); - } - return linksByPlatform; - }, -); - -// Fleshes out our list of existing social links with all the other ones the user can set. -export const formSocialLinksSelector = createSelector( - socialLinksByPlatformSelector, - draftSocialLinksByPlatformSelector, - (linksByPlatform, draftLinksByPlatform) => { - const knownPlatforms = ['twitter', 'facebook', 'linkedin']; - const socialLinks = []; - // For each known platform - knownPlatforms.forEach((platform) => { - // If the link is in our drafts. - if (draftLinksByPlatform[platform] !== undefined) { - // Use the draft one. - socialLinks.push(draftLinksByPlatform[platform]); - } else if (linksByPlatform[platform] !== undefined) { - // Otherwise use the real one. - socialLinks.push(linksByPlatform[platform]); - } else { - // And if it's not in either, use a stub. - socialLinks.push({ - platform, - socialLink: null, - }); - } - }); - return socialLinks; - }, -); - -export const visibilitiesSelector = createSelector( - profilePreferencesSelector, - accountPrivacySelector, - (preferences, accountPrivacy) => { - switch (accountPrivacy) { - case 'custom': - return { - visibilityBio: preferences.visibilityBio || 'all_users', - visibilityCourseCertificates: preferences.visibilityCourseCertificates || 'all_users', - visibilityCountry: preferences.visibilityCountry || 'all_users', - visibilityLevelOfEducation: preferences.visibilityLevelOfEducation || 'all_users', - visibilityLanguageProficiencies: preferences.visibilityLanguageProficiencies || 'all_users', - visibilityName: preferences.visibilityName || 'all_users', - visibilitySocialLinks: preferences.visibilitySocialLinks || 'all_users', - }; - case 'private': - return { - visibilityBio: 'private', - visibilityCourseCertificates: 'private', - visibilityCountry: 'private', - visibilityLevelOfEducation: 'private', - visibilityLanguageProficiencies: 'private', - visibilityName: 'private', - visibilitySocialLinks: 'private', - }; - case 'all_users': - default: - // All users is intended to fall through to default. - // If there is no value for accountPrivacy in perferences, that means it has not been - // explicitly set yet. The server assumes - today - that this means "all_users", - // so we emulate that here in the client. - return { - visibilityBio: 'all_users', - visibilityCourseCertificates: 'all_users', - visibilityCountry: 'all_users', - visibilityLevelOfEducation: 'all_users', - visibilityLanguageProficiencies: 'all_users', - visibilityName: 'all_users', - visibilitySocialLinks: 'all_users', - }; - } - }, -); - -/** - * If there's no draft present at all (undefined), use the original committed value. - */ -function chooseFormValue(draft, committed) { - return draft !== undefined ? draft : committed; -} - -export const formValuesSelector = createSelector( - profileAccountSelector, - visibilitiesSelector, - profileDraftsSelector, - profileCourseCertificatesSelector, - formSocialLinksSelector, - (account, visibilities, drafts, courseCertificates, socialLinks) => ({ - bio: chooseFormValue(drafts.bio, account.bio), - visibilityBio: chooseFormValue(drafts.visibilityBio, visibilities.visibilityBio), - courseCertificates, - visibilityCourseCertificates: chooseFormValue( - drafts.visibilityCourseCertificates, - visibilities.visibilityCourseCertificates, - ), - country: chooseFormValue(drafts.country, account.country), - visibilityCountry: chooseFormValue(drafts.visibilityCountry, visibilities.visibilityCountry), - levelOfEducation: chooseFormValue(drafts.levelOfEducation, account.levelOfEducation), - visibilityLevelOfEducation: chooseFormValue( - drafts.visibilityLevelOfEducation, - visibilities.visibilityLevelOfEducation, - ), - languageProficiencies: chooseFormValue( - drafts.languageProficiencies, - account.languageProficiencies, - ), - visibilityLanguageProficiencies: chooseFormValue( - drafts.visibilityLanguageProficiencies, - visibilities.visibilityLanguageProficiencies, - ), - name: chooseFormValue(drafts.name, account.name), - visibilityName: chooseFormValue(drafts.visibilityName, visibilities.visibilityName), - socialLinks, // Social links is calculated in its own selector, since it's complicated. - visibilitySocialLinks: chooseFormValue( - drafts.visibilitySocialLinks, - visibilities.visibilitySocialLinks, - ), - }), -); - export const profilePageSelector = createSelector( profileAccountSelector, - formValuesSelector, + profileCourseCertificatesSelector, profileImageSelector, - saveStateSelector, savePhotoStateSelector, isLoadingProfileSelector, - draftSocialLinksByPlatformSelector, accountErrorsSelector, ( account, - formValues, + courseCertificates, profileImage, - saveState, savePhotoState, isLoadingProfile, - draftSocialLinksByPlatform, errors, ) => ({ // Account data we need @@ -345,37 +48,9 @@ export const profilePageSelector = createSelector( dateJoined: account.dateJoined, yearOfBirth: account.yearOfBirth, - // Bio form data - bio: formValues.bio, - visibilityBio: formValues.visibilityBio, - - // Certificates form data - courseCertificates: formValues.courseCertificates, - visibilityCourseCertificates: formValues.visibilityCourseCertificates, - - // Country form data - country: formValues.country, - visibilityCountry: formValues.visibilityCountry, - - // Education form data - levelOfEducation: formValues.levelOfEducation, - visibilityLevelOfEducation: formValues.visibilityLevelOfEducation, - - // Language proficiency form data - languageProficiencies: formValues.languageProficiencies, - visibilityLanguageProficiencies: formValues.visibilityLanguageProficiencies, - - // Name form data - name: formValues.name, - visibilityName: formValues.visibilityName, - - // Social links form data - socialLinks: formValues.socialLinks, - visibilitySocialLinks: formValues.visibilitySocialLinks, - draftSocialLinksByPlatform, + courseCertificates, // Other data we need - saveState, savePhotoState, isLoadingProfile, photoUploadError: errors.photo || null, diff --git a/src/routes/routes.test.jsx b/src/routes/routes.test.jsx index 9bd40dfea..5c2bf5acd 100644 --- a/src/routes/routes.test.jsx +++ b/src/routes/routes.test.jsx @@ -12,7 +12,7 @@ jest.mock('@edx/frontend-platform/auth', () => ({ getLoginRedirectUrl: jest.fn(), })); -jest.mock('../profile', () => ({ +jest.mock('../profile-v2', () => ({ ProfilePage: () => (
Profile page
), NotFoundPage: () => (
Not found page
), }));