From a93dc4e3b19486f2089672e6e6cc8fcec4ee1aa8 Mon Sep 17 00:00:00 2001 From: Adam Butterworth Date: Wed, 15 May 2019 13:08:53 -0600 Subject: [PATCH] feat: add jump nav (#43) --- package-lock.json | 55 ++-- package.json | 3 +- src/account-settings/AccountSettingsPage.jsx | 298 ++++++++++--------- src/account-settings/_style.scss | 20 ++ src/account-settings/components/JumpNav.jsx | 48 +++ 5 files changed, 250 insertions(+), 174 deletions(-) create mode 100644 src/account-settings/components/JumpNav.jsx diff --git a/package-lock.json b/package-lock.json index 3e13eec..7417cdc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1009,9 +1009,9 @@ "integrity": "sha512-APBpZvdQrC1MJWMzk33V7FR2RhBRtnH2QPLqZzS+qia7PixwgWNlnX7UfHjhx+YWkM53GdsZKs40EBkSwADuMA==" }, "@edx/edx-bootstrap": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@edx/edx-bootstrap/-/edx-bootstrap-2.1.0.tgz", - "integrity": "sha512-9/CkIP1IsldKvOAS/T2OYeBnyuNWwX+u5GVR1kxw1YUCQbFw0W2M/Nz0HbIhG82H4O64uQqfdxnd1QpRJn07LA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@edx/edx-bootstrap/-/edx-bootstrap-2.2.1.tgz", + "integrity": "sha512-HkQ45u46ejX7WYwJX6ar/0FGBjx4F7bZvt3Dd4A677st0ic/47X5vQlqMqmK/M08C+GXaunNbZdbyF/ROrmwxw==", "requires": { "bootstrap": "^4.3.1" } @@ -8638,8 +8638,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -8660,14 +8659,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8682,20 +8679,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -8812,8 +8806,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -8825,7 +8818,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -8840,7 +8832,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -8848,14 +8839,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -8874,7 +8863,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -8955,8 +8943,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -8968,7 +8955,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -9054,8 +9040,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -9091,7 +9076,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -9111,7 +9095,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -9155,14 +9138,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -15759,6 +15740,14 @@ "warning": "^4.0.1" } }, + "react-router-hash-link": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/react-router-hash-link/-/react-router-hash-link-1.2.1.tgz", + "integrity": "sha512-ddkCtmk/JwMmuU087TGShQHYyNjsJ+/9CTyuVdvvKf6ACgqk2Ma9ndX2xogo7WWmyq9AjuziBm5bmJ12zBxtsQ==", + "requires": { + "prop-types": "^15.6.0" + } + }, "react-test-renderer": { "version": "16.8.6", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.8.6.tgz", diff --git a/package.json b/package.json index 6665ca2..b661ab1 100755 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@cospired/i18n-iso-languages": "^2.0.2", - "@edx/edx-bootstrap": "^2.1.0", + "@edx/edx-bootstrap": "^2.2.1", "@edx/frontend-analytics": "^1.0.0", "@edx/frontend-auth": "^5.3.0", "@edx/frontend-component-footer": "^4.1.2", @@ -62,6 +62,7 @@ "react-redux": "^5.1.1", "react-router": "^4.2.0", "react-router-dom": "^4.2.2", + "react-router-hash-link": "^1.2.1", "react-transition-group": "^2.5.3", "redux": "^4.0.1", "redux-devtools-extension": "^2.13.2", diff --git a/src/account-settings/AccountSettingsPage.jsx b/src/account-settings/AccountSettingsPage.jsx index 4e7f958..72abcfa 100644 --- a/src/account-settings/AccountSettingsPage.jsx +++ b/src/account-settings/AccountSettingsPage.jsx @@ -16,6 +16,7 @@ import { fetchSettings, saveSettings, updateDraft } from './actions'; import { accountSettingsPageSelector } from './selectors'; import { PageLoading } from '../common'; +import JumpNav from './components/JumpNav'; import Alert from './components/Alert'; import EditableField from './components/EditableField'; import PasswordReset from './components/PasswordReset'; @@ -152,150 +153,158 @@ class AccountSettingsPage extends React.Component { ); return ( -
-
-
+ +
+

+ {this.props.intl.formatMessage(messages['account.settings.section.account.information'])} +

+

{this.props.intl.formatMessage(messages['account.settings.section.account.information.description'])}

+ {this.renderManagedProfileMessage()} -

{this.props.intl.formatMessage(messages['account.settings.section.account.information'])}

-

{this.props.intl.formatMessage(messages['account.settings.section.account.information.description'])}

- {this.renderManagedProfileMessage()} + + + + {this.renderSecondaryEmailField(editableFieldProps)} + + + +
- - - - {this.renderSecondaryEmailField(editableFieldProps)} - - - +
+

+ {this.props.intl.formatMessage(messages['account.settings.section.profile.information'])} +

+ + + +
-

{this.props.intl.formatMessage(messages['account.settings.section.profile.information'])}

+
+

+ {this.props.intl.formatMessage(messages['account.settings.section.social.media'])} +

+

{this.props.intl.formatMessage(messages['account.settings.section.social.media.description'])}

- - - + + + +
+
+

+ {this.props.intl.formatMessage(messages['account.settings.section.site.preferences'])} +

-

{this.props.intl.formatMessage(messages['account.settings.section.social.media'])}

-

{this.props.intl.formatMessage(messages['account.settings.section.social.media.description'])}

+ + + { + // the endpoint will not accept an empty string. it must be null + this.handleSubmit(formId, value || null); + }} + /> +
- - - - - -

{this.props.intl.formatMessage(messages['account.settings.section.site.preferences'])}

- - - - { - // the endpoint will not accept an empty string. it must be null - this.handleSubmit(formId, value || null); - }} - /> - - -

{this.props.intl.formatMessage(messages['account.settings.section.linked.accounts'])}

-

{this.props.intl.formatMessage(messages['account.settings.section.linked.accounts.description'])}

- - -
-
-
+
+

{this.props.intl.formatMessage(messages['account.settings.section.linked.accounts'])}

+

{this.props.intl.formatMessage(messages['account.settings.section.linked.accounts.description'])}

+ +
+ ); } @@ -325,12 +334,21 @@ class AccountSettingsPage extends React.Component { return (
{this.renderDuplicateTpaProviderMessage()} -

+

{this.props.intl.formatMessage(messages['account.settings.page.heading'])}

- {loading ? this.renderLoading() : null} - {loaded ? this.renderContent() : null} - {loadingError ? this.renderError() : null} +
+
+
+ +
+
+ {loading ? this.renderLoading() : null} + {loaded ? this.renderContent() : null} + {loadingError ? this.renderError() : null} +
+
+
); } diff --git a/src/account-settings/_style.scss b/src/account-settings/_style.scss index 0867c54..3dfb42d 100644 --- a/src/account-settings/_style.scss +++ b/src/account-settings/_style.scss @@ -11,4 +11,24 @@ padding: 0; display: inline-block; } + + .jump-nav { + @media (min-width: map-get($grid-breakpoints, "sm")) { + padding-top: 1rem; + position: sticky; + top: 1rem; + } + li { + margin-bottom: .5rem; + } + } + + .section-heading { + @extend .h4; + margin-bottom: map-get($spacers, 3); + } + section { + // These properties together will shift the hashlink position + padding-top: 1rem; + } } diff --git a/src/account-settings/components/JumpNav.jsx b/src/account-settings/components/JumpNav.jsx new file mode 100644 index 0000000..b4a9276 --- /dev/null +++ b/src/account-settings/components/JumpNav.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line +import { NavHashLink } from 'react-router-hash-link'; + +import messages from '../AccountSettingsPage.messages'; + + +function JumpNav({ intl }) { + return ( +
+ +
+ ); +} + + +JumpNav.propTypes = { + intl: intlShape.isRequired, +}; + + +export default injectIntl(JumpNav);