diff --git a/package-lock.json b/package-lock.json
index c43ce70..9abb81e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4248,6 +4248,27 @@
"integrity": "sha512-4diPfzWbLEIElVG4AnqP+00SULlPzNuyJFNnmMrLgyaxG6tZXJ1sn7mjBu4fHrJE+Yp/jgylOweJn2xsLMFggQ==",
"dev": true
},
+ "adjust-sourcemap-loader": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz",
+ "integrity": "sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA==",
+ "dev": true,
+ "requires": {
+ "assert": "1.4.1",
+ "camelcase": "5.0.0",
+ "loader-utils": "1.2.3",
+ "object-path": "0.11.4",
+ "regex-parser": "2.2.10"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
+ "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
+ "dev": true
+ }
+ }
+ },
"agent-base": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
@@ -4495,6 +4516,12 @@
"commander": "^2.11.0"
}
},
+ "arity-n": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz",
+ "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=",
+ "dev": true
+ },
"arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@@ -6631,6 +6658,15 @@
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
"dev": true
},
+ "compose-function": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz",
+ "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=",
+ "dev": true,
+ "requires": {
+ "arity-n": "^1.0.4"
+ }
+ },
"compressible": {
"version": "2.0.15",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz",
@@ -7131,6 +7167,18 @@
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
"dev": true
},
+ "css": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
+ "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "source-map": "^0.6.1",
+ "source-map-resolve": "^0.5.2",
+ "urix": "^0.1.0"
+ }
+ },
"css-color-names": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
@@ -7462,6 +7510,16 @@
"integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
"dev": true
},
+ "d": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+ "dev": true,
+ "requires": {
+ "es5-ext": "^0.10.50",
+ "type": "^1.0.1"
+ }
+ },
"damerau-levenshtein": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz",
@@ -8344,6 +8402,28 @@
"is-symbol": "^1.0.2"
}
},
+ "es5-ext": {
+ "version": "0.10.51",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz",
+ "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==",
+ "dev": true,
+ "requires": {
+ "es6-iterator": "~2.0.3",
+ "es6-symbol": "~3.1.1",
+ "next-tick": "^1.0.0"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "dev": true,
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
"es6-promise": {
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz",
@@ -8357,6 +8437,16 @@
"es6-promise": "^4.0.3"
}
},
+ "es6-symbol": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz",
+ "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==",
+ "dev": true,
+ "requires": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.51"
+ }
+ },
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -14901,6 +14991,12 @@
}
}
},
+ "next-tick": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+ "dev": true
+ },
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -15334,6 +15430,12 @@
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
"integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag=="
},
+ "object-path": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz",
+ "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk=",
+ "dev": true
+ },
"object-visit": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
@@ -18373,6 +18475,12 @@
"safe-regex": "^1.1.0"
}
},
+ "regex-parser": {
+ "version": "2.2.10",
+ "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.10.tgz",
+ "integrity": "sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA==",
+ "dev": true
+ },
"regexp-tree": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.13.tgz",
@@ -18595,6 +18703,32 @@
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
"dev": true
},
+ "resolve-url-loader": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.0.tgz",
+ "integrity": "sha512-2QcrA+2QgVqsMJ1Hn5NnJXIGCX1clQ1F6QJTqOeiaDw9ACo1G2k+8/shq3mtqne03HOFyskAClqfxKyFBriXZg==",
+ "dev": true,
+ "requires": {
+ "adjust-sourcemap-loader": "2.0.0",
+ "camelcase": "5.0.0",
+ "compose-function": "3.0.3",
+ "convert-source-map": "1.6.0",
+ "es6-iterator": "2.0.3",
+ "loader-utils": "1.2.3",
+ "postcss": "7.0.14",
+ "rework": "1.0.1",
+ "rework-visit": "1.0.0",
+ "source-map": "0.6.1"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
+ "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
+ "dev": true
+ }
+ }
+ },
"responselike": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
@@ -18626,6 +18760,30 @@
"integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
"dev": true
},
+ "rework": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz",
+ "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=",
+ "dev": true,
+ "requires": {
+ "convert-source-map": "^0.3.3",
+ "css": "^2.0.0"
+ },
+ "dependencies": {
+ "convert-source-map": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz",
+ "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=",
+ "dev": true
+ }
+ }
+ },
+ "rework-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz",
+ "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=",
+ "dev": true
+ },
"rgb-regex": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
@@ -21406,6 +21564,12 @@
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true
},
+ "type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+ "dev": true
+ },
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
diff --git a/package.json b/package.json
index 9111cb8..e8136c1 100755
--- a/package.json
+++ b/package.json
@@ -6,6 +6,10 @@
"type": "git",
"url": "git+https://github.com/edx/frontend-app-profile.git"
},
+ "browserslist": [
+ "last 2 versions",
+ "ie 11"
+ ],
"scripts": {
"build": "NODE_ENV=production BABEL_ENV=production webpack --config=webpack/webpack.prod.config.js",
"i18n_extract": "BABEL_ENV=i18n babel src --quiet > /dev/null",
@@ -113,6 +117,7 @@
"react-test-renderer": "16.9.0",
"reactifex": "1.1.1",
"redux-mock-store": "1.5.3",
+ "resolve-url-loader": "^3.1.0",
"sass-loader": "6.0.7",
"source-map-loader": "0.2.4",
"style-loader": "0.20.3",
diff --git a/src/index.jsx b/src/index.jsx
index d45b8a3..2f079b0 100755
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -4,20 +4,27 @@ import { App, AppProvider, APP_ERROR, APP_READY, ErrorPage } from '@edx/frontend
import { NewRelicLoggingService } from '@edx/frontend-logging';
import React from 'react';
import ReactDOM from 'react-dom';
+import { Route, Switch } from 'react-router-dom';
import Header, { messages as headerMessages } from '@edx/frontend-component-header';
import Footer from '../footer/Footer';
import appMessages from './i18n';
import './index.scss';
-import ProfileMain from './profile/components/ProfileMain';
+import { ProfilePage, NotFoundPage } from './profile';
import configureStore from './store';
App.subscribe(APP_READY, () => {
ReactDOM.render(
-
+
+
+
+
+
+
+
,
document.getElementById('root'),
@@ -29,4 +36,3 @@ App.subscribe(APP_ERROR, (error) => {
});
App.initialize({ messages: [appMessages, headerMessages], loggingService: NewRelicLoggingService });
-
diff --git a/src/index.scss b/src/index.scss
index 141c238..fe0864e 100755
--- a/src/index.scss
+++ b/src/index.scss
@@ -1,145 +1,7 @@
@import '~@edx/paragon/scss/edx/theme.scss';
@import '~@edx/paragon/scss/edx/fonts.scss'; // Roboto
-$fa-font-path: "~font-awesome/fonts";
-@import "~font-awesome/scss/font-awesome";
+@import './profile/index.scss';
@import "~@edx/frontend-component-header/src/index";
@import "~@edx/frontend-component-footer/src/lib/scss/site-footer";
-
-.word-break-all {
- word-break: break-all !important;
-}
-
-// TODO: Update edx-bootstrap theme to incorporate these edits.
-.btn, a.btn {
- text-decoration: none;
- &:hover {
- text-decoration: none;
- }
-}
-.btn-link {
- text-decoration: underline;
- &:hover {
- text-decoration: underline;
- }
-}
-
-.profile-page-bg-banner {
- height: 12rem;
- background-image: url('./assets/dot-pattern-light.png');
- background-repeat: repeat-x;
- background-size: auto 85%;
-}
-
-.profile-page {
- .edit-section-header {
- @extend .h6;
- display: block;
- font-weight: normal;
- letter-spacing: 0;
- margin: 0;
- }
- label.edit-section-header {
- margin-bottom: $spacer * .5;
- }
- .profile-avatar-wrap {
- @include media-breakpoint-up(md) {
- max-width: 12rem;
- margin-right: 0;
- margin-top: -8rem;
- margin-bottom: 2rem;
- }
- }
-
- .profile-avatar-menu-container {
- background: rgba(0,0,0,.65);
- position: absolute;
- width: 100%;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- border-radius: 50%;
- @include media-breakpoint-up(md) {
- background: linear-gradient(to top, rgba(0,0,0,.65) 4rem, rgba(0,0,0,0) 4rem);
- align-items: flex-end;
- }
- .btn {
- text-decoration: none;
- @include media-breakpoint-up(md) {
- margin-bottom: 1.2rem;
- }
- }
-
- .dropdown {
- @include media-breakpoint-up(md) {
- margin-bottom: 1.2rem;
- }
- .btn {
- color: $white;
- background: transparent;
- border-color: transparent;
- margin: 0;
- }
- }
- }
-
- .profile-avatar {
- width: 5rem;
- height: 5rem;
- position: relative;
-
- @include media-breakpoint-up(md) {
- width: 12rem;
- height: 12rem;
- }
-
- .profile-avatar-edit-button {
- border: none;
- position: absolute;
- height: 100%;
- left: 0;
- width: 100%;
- bottom: 0;
- display: flex;
- justify-content: center;
- padding-top: .1rem;
- font-weight: 600;
- background: rgba(0,0,0,.5);
- border-radius:0;
- transition: opacity 200ms ease;
-
- @include media-breakpoint-up(md) {
- height: 4rem;
- }
-
- &:focus, &:hover, &:active, &.active {
- opacity: 1;
- }
- }
- }
-
- .certificate {
- position: relative;
- .certificate-title {
- font-family: $font-family-serif;
- font-weight: 400;
- }
- .certificate-type-illustration {
- position: absolute;
- top: 1rem;
- right: 1rem;
- bottom: 0;
- width: 12rem;
- opacity: .06;
- background-size: 90%;
- background-repeat: no-repeat;
- background-position: right top;
- }
- .card-body {
- position: relative;
- }
- }
-}
-
diff --git a/src/profile/components/AgeMessage.jsx b/src/profile/AgeMessage.jsx
similarity index 100%
rename from src/profile/components/AgeMessage.jsx
rename to src/profile/AgeMessage.jsx
diff --git a/src/profile/components/Banner.jsx b/src/profile/Banner.jsx
similarity index 100%
rename from src/profile/components/Banner.jsx
rename to src/profile/Banner.jsx
diff --git a/src/profile/components/DateJoined.jsx b/src/profile/DateJoined.jsx
similarity index 100%
rename from src/profile/components/DateJoined.jsx
rename to src/profile/DateJoined.jsx
diff --git a/src/profile/components/NotFoundPage.jsx b/src/profile/NotFoundPage.jsx
similarity index 100%
rename from src/profile/components/NotFoundPage.jsx
rename to src/profile/NotFoundPage.jsx
diff --git a/src/profile/components/PageLoading.jsx b/src/profile/PageLoading.jsx
similarity index 100%
rename from src/profile/components/PageLoading.jsx
rename to src/profile/PageLoading.jsx
diff --git a/src/profile/components/ProfilePage.jsx b/src/profile/ProfilePage.jsx
similarity index 96%
rename from src/profile/components/ProfilePage.jsx
rename to src/profile/ProfilePage.jsx
index e7ba58f..2e1aea6 100644
--- a/src/profile/components/ProfilePage.jsx
+++ b/src/profile/ProfilePage.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { sendTrackingLogEvent } from '@edx/frontend-analytics';
-import { App, AppContext } from '@edx/frontend-base';
+import { App, AppContext, fetchUserAccount } from '@edx/frontend-base';
import { injectIntl, intlShape } from '@edx/frontend-i18n';
import { StatusAlert, Hyperlink } from '@edx/paragon';
@@ -16,7 +16,7 @@ import {
openForm,
closeForm,
updateDraft,
-} from '../actions';
+} from './data/actions';
// Components
import ProfileAvatar from './forms/ProfileAvatar';
@@ -33,14 +33,14 @@ import PageLoading from './PageLoading';
import Banner from './Banner';
// Selectors
-import { profilePageSelector } from '../selectors';
+import { profilePageSelector } from './data/selectors';
// i18n
import messages from './ProfilePage.messages';
App.requireConfig(['CREDENTIALS_BASE_URL', 'LMS_BASE_URL'], 'ProfilePage');
-export class ProfilePage extends React.Component {
+class ProfilePage extends React.Component {
constructor(props, context) {
super(props, context);
@@ -58,6 +58,7 @@ export class ProfilePage extends React.Component {
}
componentDidMount() {
+ this.props.fetchUserAccount(this.context.authenticatedUser.username);
this.props.fetchProfile(this.props.match.params.username);
sendTrackingLogEvent('edx.profile.viewed', {
username: this.props.match.params.username,
@@ -331,6 +332,7 @@ ProfilePage.propTypes = {
photoUploadError: PropTypes.objectOf(PropTypes.string),
// Actions
+ fetchUserAccount: PropTypes.func.isRequired,
fetchProfile: PropTypes.func.isRequired,
saveProfile: PropTypes.func.isRequired,
saveProfilePhoto: PropTypes.func.isRequired,
@@ -370,6 +372,7 @@ ProfilePage.defaultProps = {
export default connect(
profilePageSelector,
{
+ fetchUserAccount,
fetchProfile,
saveProfilePhoto,
deleteProfilePhoto,
diff --git a/src/profile/components/ProfilePage.messages.jsx b/src/profile/ProfilePage.messages.jsx
similarity index 100%
rename from src/profile/components/ProfilePage.messages.jsx
rename to src/profile/ProfilePage.messages.jsx
diff --git a/src/profile/components/ProfilePage.test.jsx b/src/profile/ProfilePage.test.jsx
similarity index 91%
rename from src/profile/components/ProfilePage.test.jsx
rename to src/profile/ProfilePage.test.jsx
index d4d280f..9e28223 100644
--- a/src/profile/components/ProfilePage.test.jsx
+++ b/src/profile/ProfilePage.test.jsx
@@ -7,11 +7,12 @@ import React from 'react';
import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';
import configureMockStore from 'redux-mock-store';
+import thunk from 'redux-thunk';
-import messages from '../../i18n';
-import ConnectedProfilePage from './ProfilePage';
+import messages from '../i18n';
+import ProfilePage from './ProfilePage';
-const mockStore = configureMockStore();
+const mockStore = configureMockStore([thunk]);
const storeMocks = {
loadingApp: require('./__mocks__/loadingApp.mockStore.js'),
viewOwnProfile: require('./__mocks__/viewOwnProfile.mockStore.js'),
@@ -19,6 +20,7 @@ const storeMocks = {
savingEditedBio: require('./__mocks__/savingEditedBio.mockStore.js'),
};
const requiredProfilePageProps = {
+ fetchUserAccount: () => {},
fetchProfile: () => {},
saveProfile: () => {},
saveProfilePhoto: () => {},
@@ -33,6 +35,7 @@ Object.defineProperty(global.document, 'cookie', {
writable: true,
value: `${App.config.LANGUAGE_PREFERENCE_COOKIE_NAME}=en`,
});
+App.apiClient = jest.fn();
configureI18n(App.config, messages);
@@ -49,7 +52,7 @@ describe('', () => {
>
-
+
@@ -69,7 +72,7 @@ describe('', () => {
>
-
+
@@ -89,7 +92,7 @@ describe('', () => {
>
-
@@ -112,7 +115,7 @@ describe('', () => {
>
-
+
@@ -134,7 +137,7 @@ describe('', () => {
>
-
diff --git a/src/profile/components/__mocks__/loadingApp.mockStore.js b/src/profile/__mocks__/loadingApp.mockStore.js
similarity index 100%
rename from src/profile/components/__mocks__/loadingApp.mockStore.js
rename to src/profile/__mocks__/loadingApp.mockStore.js
diff --git a/src/profile/components/__mocks__/savingEditedBio.mockStore.js b/src/profile/__mocks__/savingEditedBio.mockStore.js
similarity index 100%
rename from src/profile/components/__mocks__/savingEditedBio.mockStore.js
rename to src/profile/__mocks__/savingEditedBio.mockStore.js
diff --git a/src/profile/components/__mocks__/viewOtherProfile.mockStore.js b/src/profile/__mocks__/viewOtherProfile.mockStore.js
similarity index 100%
rename from src/profile/components/__mocks__/viewOtherProfile.mockStore.js
rename to src/profile/__mocks__/viewOtherProfile.mockStore.js
diff --git a/src/profile/components/__mocks__/viewOwnProfile.mockStore.js b/src/profile/__mocks__/viewOwnProfile.mockStore.js
similarity index 100%
rename from src/profile/components/__mocks__/viewOwnProfile.mockStore.js
rename to src/profile/__mocks__/viewOwnProfile.mockStore.js
diff --git a/src/profile/components/__snapshots__/ProfilePage.test.jsx.snap b/src/profile/__snapshots__/ProfilePage.test.jsx.snap
similarity index 100%
rename from src/profile/components/__snapshots__/ProfilePage.test.jsx.snap
rename to src/profile/__snapshots__/ProfilePage.test.jsx.snap
diff --git a/src/profile/_index.scss b/src/profile/_index.scss
new file mode 100644
index 0000000..f9c7f1a
--- /dev/null
+++ b/src/profile/_index.scss
@@ -0,0 +1,141 @@
+
+
+$fa-font-path: "~font-awesome/fonts";
+@import "~font-awesome/scss/font-awesome";
+
+.word-break-all {
+ word-break: break-all !important;
+}
+
+// TODO: Update edx-bootstrap theme to incorporate these edits.
+.btn, a.btn {
+ text-decoration: none;
+ &:hover {
+ text-decoration: none;
+ }
+}
+.btn-link {
+ text-decoration: underline;
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+.profile-page-bg-banner {
+ height: 12rem;
+ background-image: url('./assets/dot-pattern-light.png');
+ background-repeat: repeat-x;
+ background-size: auto 85%;
+}
+
+.profile-page {
+ .edit-section-header {
+ @extend .h6;
+ display: block;
+ font-weight: normal;
+ letter-spacing: 0;
+ margin: 0;
+ }
+ label.edit-section-header {
+ margin-bottom: $spacer * .5;
+ }
+ .profile-avatar-wrap {
+ @include media-breakpoint-up(md) {
+ max-width: 12rem;
+ margin-right: 0;
+ margin-top: -8rem;
+ margin-bottom: 2rem;
+ }
+ }
+
+ .profile-avatar-menu-container {
+ background: rgba(0,0,0,.65);
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: 50%;
+ @include media-breakpoint-up(md) {
+ background: linear-gradient(to top, rgba(0,0,0,.65) 4rem, rgba(0,0,0,0) 4rem);
+ align-items: flex-end;
+ }
+ .btn {
+ text-decoration: none;
+ @include media-breakpoint-up(md) {
+ margin-bottom: 1.2rem;
+ }
+ }
+
+ .dropdown {
+ @include media-breakpoint-up(md) {
+ margin-bottom: 1.2rem;
+ }
+ .btn {
+ color: $white;
+ background: transparent;
+ border-color: transparent;
+ margin: 0;
+ }
+ }
+ }
+
+ .profile-avatar {
+ width: 5rem;
+ height: 5rem;
+ position: relative;
+
+ @include media-breakpoint-up(md) {
+ width: 12rem;
+ height: 12rem;
+ }
+
+ .profile-avatar-edit-button {
+ border: none;
+ position: absolute;
+ height: 100%;
+ left: 0;
+ width: 100%;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ padding-top: .1rem;
+ font-weight: 600;
+ background: rgba(0,0,0,.5);
+ border-radius:0;
+ transition: opacity 200ms ease;
+
+ @include media-breakpoint-up(md) {
+ height: 4rem;
+ }
+
+ &:focus, &:hover, &:active, &.active {
+ opacity: 1;
+ }
+ }
+ }
+
+ .certificate {
+ position: relative;
+ .certificate-title {
+ font-family: $font-family-serif;
+ font-weight: 400;
+ }
+ .certificate-type-illustration {
+ position: absolute;
+ top: 1rem;
+ right: 1rem;
+ bottom: 0;
+ width: 12rem;
+ opacity: .06;
+ background-size: 90%;
+ background-repeat: no-repeat;
+ background-position: right top;
+ }
+ .card-body {
+ position: relative;
+ }
+ }
+}
+
diff --git a/src/assets/dot-pattern-light.png b/src/profile/assets/dot-pattern-light.png
similarity index 100%
rename from src/assets/dot-pattern-light.png
rename to src/profile/assets/dot-pattern-light.png
diff --git a/src/profile/components/ProfileMain.jsx b/src/profile/components/ProfileMain.jsx
deleted file mode 100644
index a775d35..0000000
--- a/src/profile/components/ProfileMain.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { AppContext, fetchUserAccount } from '@edx/frontend-base';
-import PropTypes from 'prop-types';
-import React, { useContext, useEffect } from 'react';
-import { connect } from 'react-redux';
-import { Route, Switch } from 'react-router-dom';
-
-import NotFoundPage from './NotFoundPage';
-import ConnectedProfilePage from './ProfilePage';
-
-function ProfileMain(props) {
- const { authenticatedUser } = useContext(AppContext);
-
- useEffect(() => {
- props.fetchUserAccount(authenticatedUser.username);
- }, [authenticatedUser.username]);
-
- return (
-
-
-
-
-
-
-
- );
-}
-
-ProfileMain.propTypes = {
- fetchUserAccount: PropTypes.func.isRequired,
-};
-
-export default connect(
- null,
- {
- fetchUserAccount,
- },
-)(ProfileMain);
diff --git a/src/profile/actions.js b/src/profile/data/actions.js
similarity index 100%
rename from src/profile/actions.js
rename to src/profile/data/actions.js
diff --git a/src/profile/actions.test.js b/src/profile/data/actions.test.js
similarity index 100%
rename from src/profile/actions.test.js
rename to src/profile/data/actions.test.js
diff --git a/src/profile/constants.js b/src/profile/data/constants.js
similarity index 100%
rename from src/profile/constants.js
rename to src/profile/data/constants.js
diff --git a/src/profile/reducers.js b/src/profile/data/reducers.js
similarity index 100%
rename from src/profile/reducers.js
rename to src/profile/data/reducers.js
diff --git a/src/profile/sagas.js b/src/profile/data/sagas.js
similarity index 100%
rename from src/profile/sagas.js
rename to src/profile/data/sagas.js
diff --git a/src/profile/sagas.test.js b/src/profile/data/sagas.test.js
similarity index 100%
rename from src/profile/sagas.test.js
rename to src/profile/data/sagas.test.js
diff --git a/src/profile/selectors.js b/src/profile/data/selectors.js
similarity index 100%
rename from src/profile/selectors.js
rename to src/profile/data/selectors.js
diff --git a/src/profile/services.js b/src/profile/data/services.js
similarity index 100%
rename from src/profile/services.js
rename to src/profile/data/services.js
diff --git a/src/profile/components/forms/Bio.jsx b/src/profile/forms/Bio.jsx
similarity index 98%
rename from src/profile/components/forms/Bio.jsx
rename to src/profile/forms/Bio.jsx
index 94b980c..fc62746 100644
--- a/src/profile/components/forms/Bio.jsx
+++ b/src/profile/forms/Bio.jsx
@@ -13,7 +13,7 @@ import EmptyContent from './elements/EmptyContent';
import SwitchContent from './elements/SwitchContent';
// Selectors
-import { editableFormSelector } from '../../selectors';
+import { editableFormSelector } from '../data/selectors';
class Bio extends React.Component {
constructor(props) {
diff --git a/src/profile/components/forms/Bio.messages.jsx b/src/profile/forms/Bio.messages.jsx
similarity index 100%
rename from src/profile/components/forms/Bio.messages.jsx
rename to src/profile/forms/Bio.messages.jsx
diff --git a/src/profile/components/forms/Certificates.jsx b/src/profile/forms/Certificates.jsx
similarity index 97%
rename from src/profile/components/forms/Certificates.jsx
rename to src/profile/forms/Certificates.jsx
index 613d55c..3e5c772 100644
--- a/src/profile/components/forms/Certificates.jsx
+++ b/src/profile/forms/Certificates.jsx
@@ -13,11 +13,11 @@ import EditableItemHeader from './elements/EditableItemHeader';
import SwitchContent from './elements/SwitchContent';
// Assets
-import professionalCertificateSVG from '../../assets/professional-certificate.svg';
-import verifiedCertificateSVG from '../../assets/verified-certificate.svg';
+import professionalCertificateSVG from '../assets/professional-certificate.svg';
+import verifiedCertificateSVG from '../assets/verified-certificate.svg';
// Selectors
-import { certificatesSelector } from '../../selectors';
+import { certificatesSelector } from '../data/selectors';
class Certificates extends React.Component {
constructor(props) {
diff --git a/src/profile/components/forms/Certificates.messages.jsx b/src/profile/forms/Certificates.messages.jsx
similarity index 100%
rename from src/profile/components/forms/Certificates.messages.jsx
rename to src/profile/forms/Certificates.messages.jsx
diff --git a/src/profile/components/forms/Country.jsx b/src/profile/forms/Country.jsx
similarity index 98%
rename from src/profile/components/forms/Country.jsx
rename to src/profile/forms/Country.jsx
index eb6ef0c..bb05f01 100644
--- a/src/profile/components/forms/Country.jsx
+++ b/src/profile/forms/Country.jsx
@@ -13,7 +13,7 @@ import EmptyContent from './elements/EmptyContent';
import SwitchContent from './elements/SwitchContent';
// Selectors
-import { countrySelector } from '../../selectors';
+import { countrySelector } from '../data/selectors';
class Country extends React.Component {
constructor(props) {
diff --git a/src/profile/components/forms/Country.messages.jsx b/src/profile/forms/Country.messages.jsx
similarity index 100%
rename from src/profile/components/forms/Country.messages.jsx
rename to src/profile/forms/Country.messages.jsx
diff --git a/src/profile/components/forms/Education.jsx b/src/profile/forms/Education.jsx
similarity index 98%
rename from src/profile/components/forms/Education.jsx
rename to src/profile/forms/Education.jsx
index 3702a9e..71a44a9 100644
--- a/src/profile/components/forms/Education.jsx
+++ b/src/profile/forms/Education.jsx
@@ -14,10 +14,10 @@ import EmptyContent from './elements/EmptyContent';
import SwitchContent from './elements/SwitchContent';
// Constants
-import { EDUCATION_LEVELS } from '../../constants';
+import { EDUCATION_LEVELS } from '../data/constants';
// Selectors
-import { editableFormSelector } from '../../selectors';
+import { editableFormSelector } from '../data/selectors';
class Education extends React.Component {
constructor(props) {
diff --git a/src/profile/components/forms/Education.messages.jsx b/src/profile/forms/Education.messages.jsx
similarity index 100%
rename from src/profile/components/forms/Education.messages.jsx
rename to src/profile/forms/Education.messages.jsx
diff --git a/src/profile/components/forms/Name.jsx b/src/profile/forms/Name.jsx
similarity index 98%
rename from src/profile/components/forms/Name.jsx
rename to src/profile/forms/Name.jsx
index a114cb4..b2781e3 100644
--- a/src/profile/components/forms/Name.jsx
+++ b/src/profile/forms/Name.jsx
@@ -12,7 +12,7 @@ import EmptyContent from './elements/EmptyContent';
import SwitchContent from './elements/SwitchContent';
// Selectors
-import { editableFormSelector } from '../../selectors';
+import { editableFormSelector } from '../data/selectors';
class Name extends React.Component {
constructor(props) {
diff --git a/src/profile/components/forms/Name.messages.jsx b/src/profile/forms/Name.messages.jsx
similarity index 100%
rename from src/profile/components/forms/Name.messages.jsx
rename to src/profile/forms/Name.messages.jsx
diff --git a/src/profile/components/forms/PreferredLanguage.jsx b/src/profile/forms/PreferredLanguage.jsx
similarity index 98%
rename from src/profile/components/forms/PreferredLanguage.jsx
rename to src/profile/forms/PreferredLanguage.jsx
index c053a25..c9ad46f 100644
--- a/src/profile/components/forms/PreferredLanguage.jsx
+++ b/src/profile/forms/PreferredLanguage.jsx
@@ -13,7 +13,7 @@ import EmptyContent from './elements/EmptyContent';
import SwitchContent from './elements/SwitchContent';
// Selectors
-import { preferredLanguageSelector } from '../../selectors';
+import { preferredLanguageSelector } from '../data/selectors';
class PreferredLanguage extends React.Component {
constructor(props) {
diff --git a/src/profile/components/forms/PreferredLanguage.messages.jsx b/src/profile/forms/PreferredLanguage.messages.jsx
similarity index 100%
rename from src/profile/components/forms/PreferredLanguage.messages.jsx
rename to src/profile/forms/PreferredLanguage.messages.jsx
diff --git a/src/profile/components/forms/ProfileAvatar.jsx b/src/profile/forms/ProfileAvatar.jsx
similarity index 98%
rename from src/profile/components/forms/ProfileAvatar.jsx
rename to src/profile/forms/ProfileAvatar.jsx
index a9ac4b4..ee3043b 100644
--- a/src/profile/components/forms/ProfileAvatar.jsx
+++ b/src/profile/forms/ProfileAvatar.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Button, Dropdown } from '@edx/paragon';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-i18n';
-import { ReactComponent as DefaultAvatar } from '../../assets/avatar.svg';
+import { ReactComponent as DefaultAvatar } from '../assets/avatar.svg';
import messages from './ProfileAvatar.messages';
diff --git a/src/profile/components/forms/ProfileAvatar.messages.jsx b/src/profile/forms/ProfileAvatar.messages.jsx
similarity index 100%
rename from src/profile/components/forms/ProfileAvatar.messages.jsx
rename to src/profile/forms/ProfileAvatar.messages.jsx
diff --git a/src/profile/components/forms/SocialLinks.jsx b/src/profile/forms/SocialLinks.jsx
similarity index 99%
rename from src/profile/components/forms/SocialLinks.jsx
rename to src/profile/forms/SocialLinks.jsx
index 0e0c375..3e193a1 100644
--- a/src/profile/components/forms/SocialLinks.jsx
+++ b/src/profile/forms/SocialLinks.jsx
@@ -16,7 +16,7 @@ import EmptyContent from './elements/EmptyContent';
import SwitchContent from './elements/SwitchContent';
// Selectors
-import { editableFormSelector } from '../../selectors';
+import { editableFormSelector } from '../data/selectors';
const platformDisplayInfo = {
facebook: {
diff --git a/src/profile/components/forms/SocialLinks.messages.jsx b/src/profile/forms/SocialLinks.messages.jsx
similarity index 100%
rename from src/profile/components/forms/SocialLinks.messages.jsx
rename to src/profile/forms/SocialLinks.messages.jsx
diff --git a/src/profile/components/forms/elements/EditButton.jsx b/src/profile/forms/elements/EditButton.jsx
similarity index 100%
rename from src/profile/components/forms/elements/EditButton.jsx
rename to src/profile/forms/elements/EditButton.jsx
diff --git a/src/profile/components/forms/elements/EditButton.messages.jsx b/src/profile/forms/elements/EditButton.messages.jsx
similarity index 100%
rename from src/profile/components/forms/elements/EditButton.messages.jsx
rename to src/profile/forms/elements/EditButton.messages.jsx
diff --git a/src/profile/components/forms/elements/EditableItemHeader.jsx b/src/profile/forms/elements/EditableItemHeader.jsx
similarity index 100%
rename from src/profile/components/forms/elements/EditableItemHeader.jsx
rename to src/profile/forms/elements/EditableItemHeader.jsx
diff --git a/src/profile/components/forms/elements/EmptyContent.jsx b/src/profile/forms/elements/EmptyContent.jsx
similarity index 100%
rename from src/profile/components/forms/elements/EmptyContent.jsx
rename to src/profile/forms/elements/EmptyContent.jsx
diff --git a/src/profile/components/forms/elements/FormControls.jsx b/src/profile/forms/elements/FormControls.jsx
similarity index 100%
rename from src/profile/components/forms/elements/FormControls.jsx
rename to src/profile/forms/elements/FormControls.jsx
diff --git a/src/profile/components/forms/elements/FormControls.messages.jsx b/src/profile/forms/elements/FormControls.messages.jsx
similarity index 100%
rename from src/profile/components/forms/elements/FormControls.messages.jsx
rename to src/profile/forms/elements/FormControls.messages.jsx
diff --git a/src/profile/components/forms/elements/SwitchContent.jsx b/src/profile/forms/elements/SwitchContent.jsx
similarity index 100%
rename from src/profile/components/forms/elements/SwitchContent.jsx
rename to src/profile/forms/elements/SwitchContent.jsx
diff --git a/src/profile/components/forms/elements/Visibility.jsx b/src/profile/forms/elements/Visibility.jsx
similarity index 100%
rename from src/profile/components/forms/elements/Visibility.jsx
rename to src/profile/forms/elements/Visibility.jsx
diff --git a/src/profile/components/forms/elements/Visibility.messages.jsx b/src/profile/forms/elements/Visibility.messages.jsx
similarity index 100%
rename from src/profile/components/forms/elements/Visibility.messages.jsx
rename to src/profile/forms/elements/Visibility.messages.jsx
diff --git a/src/profile/index.js b/src/profile/index.js
index 89d83e4..4cb72e8 100644
--- a/src/profile/index.js
+++ b/src/profile/index.js
@@ -1,9 +1,5 @@
-import profileReducer from './reducers';
-import profileSaga from './sagas';
-import ConnectedProfilePage from './components/ProfilePage';
-
-export {
- ConnectedProfilePage,
- profileReducer,
- profileSaga,
-};
+export { default as reducer } from './data/reducers';
+export { default as saga } from './data/sagas';
+export { default as ProfilePage } from './ProfilePage';
+export { default as NotFoundPage } from './NotFoundPage';
+export { default as messages } from './ProfilePage.messages';
diff --git a/src/utils.js b/src/profile/utils.js
similarity index 100%
rename from src/utils.js
rename to src/profile/utils.js
diff --git a/src/utils.test.js b/src/profile/utils.test.js
similarity index 100%
rename from src/utils.test.js
rename to src/profile/utils.test.js
diff --git a/src/reducers.js b/src/reducers.js
index 3603d59..b1767b5 100755
--- a/src/reducers.js
+++ b/src/reducers.js
@@ -1,7 +1,7 @@
import { combineReducers } from 'redux';
import { userAccount } from '@edx/frontend-auth';
-import { profileReducer } from './profile';
+import { reducer as profileReducer } from './profile';
const createRootReducer = () =>
combineReducers({
diff --git a/src/sagas.js b/src/sagas.js
index 134eeeb..b1cd5ef 100644
--- a/src/sagas.js
+++ b/src/sagas.js
@@ -1,6 +1,6 @@
import { all } from 'redux-saga/effects';
-import { profileSaga } from './profile';
+import { saga as profileSaga } from './profile';
export default function* rootSaga() {
yield all([
diff --git a/webpack/webpack.dev.config.js b/webpack/webpack.dev.config.js
index 9824337..d463561 100755
--- a/webpack/webpack.dev.config.js
+++ b/webpack/webpack.dev.config.js
@@ -55,6 +55,9 @@ module.exports = Merge.smart(commonConfig, {
plugins: () => [PostCssRtlPlugin()],
},
},
+ {
+ loader: 'resolve-url-loader',
+ },
{
loader: 'sass-loader', // compiles Sass to CSS
options: {
diff --git a/webpack/webpack.prod.config.js b/webpack/webpack.prod.config.js
index 1798e0b..effb579 100755
--- a/webpack/webpack.prod.config.js
+++ b/webpack/webpack.prod.config.js
@@ -67,11 +67,14 @@ module.exports = Merge.smart(commonConfig, {
options: {
plugins: () => [
PostCssRtlPlugin(),
- PostCssAutoprefixerPlugin({ grid: true, browsers: ['>1%'] }),
+ PostCssAutoprefixerPlugin({ grid: true }),
CssNano(),
],
},
},
+ {
+ loader: 'resolve-url-loader',
+ },
{
loader: 'sass-loader', // compiles Sass to CSS
options: {