From 3b080012acf44eca23043009f50c8f00fc6d551a Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Thu, 5 Aug 2021 16:42:37 +0800 Subject: [PATCH 01/36] Styles for new Settings Page --- ui/component/settingsRow/index.js | 2 + ui/component/settingsRow/view.jsx | 36 +++++++++++++ ui/scss/component/section.scss | 90 ++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 ui/component/settingsRow/index.js create mode 100644 ui/component/settingsRow/view.jsx diff --git a/ui/component/settingsRow/index.js b/ui/component/settingsRow/index.js new file mode 100644 index 000000000..a8d6ab489 --- /dev/null +++ b/ui/component/settingsRow/index.js @@ -0,0 +1,2 @@ +import SettingsRow from './view'; +export default SettingsRow; diff --git a/ui/component/settingsRow/view.jsx b/ui/component/settingsRow/view.jsx new file mode 100644 index 000000000..a59b7e52b --- /dev/null +++ b/ui/component/settingsRow/view.jsx @@ -0,0 +1,36 @@ +// @flow +import React from 'react'; +import classnames from 'classnames'; + +type Props = { + title: string, + subtitle?: string, + multirow?: boolean, // Displays the Value widget(s) below the Label instead of on the right. + useVerticalSeparator?: boolean, // Show a separator line between Label and Value. Useful when there are multiple Values. + children?: React$Node, +}; + +export default function SettingsRow(props: Props) { + const { title, subtitle, multirow, useVerticalSeparator, children } = props; + + return ( +
+
+

{title}

+ {subtitle &&

{subtitle}

} +
+
+ {children && children} +
+
+ ); +} diff --git a/ui/scss/component/section.scss b/ui/scss/component/section.scss index 2c6fd46f8..a45b88a7e 100644 --- a/ui/scss/component/section.scss +++ b/ui/scss/component/section.scss @@ -140,7 +140,7 @@ margin-right: var(--spacing-s); } - @media (max-width: $breakpoint-small) { + @media (max-width: $breakpoint-medium) { flex-wrap: wrap; > * { @@ -203,3 +203,91 @@ margin-right: 10px; } } + +.settings__row { + &:first-child, + &:only-child { + border-top: none; + } +} + +.settings__row--title { + min-width: 100%; + align-self: flex-start; + + @media (min-width: $breakpoint-small) { + min-width: 60%; + max-width: 60%; + } +} + +.settings__row--subtitle { + @extend .section__subtitle; + font-size: var(--font-small); + margin-top: calc(var(--spacing-xxs) / 2); +} + +.settings__row--value { + width: 100%; + + fieldset-section:not(:only-child) { + margin-top: var(--spacing-s); + } + + fieldset-section.radio { + margin-top: var(--spacing-s); + } + + fieldset-group { + margin-top: var(--spacing-m); + } + + .tags--remove { + margin-bottom: 0; + } + + .tags__input-wrapper { + .tag__input { + height: unset; + max-width: unset; + } + } + + .form-field--price-amount { + max-width: unset; + } + + @media (min-width: $breakpoint-medium) { + width: 40%; + margin-left: var(--spacing-m); + padding-left: var(--spacing-m); + + .button, + .checkbox { + &:only-child { + float: right; + } + } + + input { + align-self: flex-end; + } + } +} + +.settings__row--value--multirow { + @media (min-width: $breakpoint-medium) { + width: 80%; + margin-top: var(--spacing-l); + + input { + align-self: flex-start; + } + } +} + +.settings__row--value--vertical-separator { + @media (min-width: $breakpoint-medium) { + border-left: 1px solid var(--color-border); + } +} From 04b510d88b9ba923b34d864da8412404e70a8a80 Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Thu, 5 Aug 2021 15:00:21 +0800 Subject: [PATCH 02/36] [Account] grab SyncToggle and AccountPassword Also made visual changes for the new Settings Page. ## SyncToggle: It will no longer be under a dedicated Card, so the "Sync" title is not there to give context for the case of "no verified email". Changed it such that the checkbox is always visible (it's label is self-explanatory) but disable when email is not set. The "Add Email" button will then appear below, so everything now makes sense in context. --- ui/component/settingAccount/index.js | 15 ++++ ui/component/settingAccount/view.jsx | 55 ++++++++++++ ui/component/settingAccountPassword/view.jsx | 95 ++++++++++---------- ui/component/syncToggle/view.jsx | 30 ++++--- ui/page/settings/index.js | 7 +- ui/page/settings/view.jsx | 50 ++--------- 6 files changed, 144 insertions(+), 108 deletions(-) create mode 100644 ui/component/settingAccount/index.js create mode 100644 ui/component/settingAccount/view.jsx diff --git a/ui/component/settingAccount/index.js b/ui/component/settingAccount/index.js new file mode 100644 index 000000000..9abbe808b --- /dev/null +++ b/ui/component/settingAccount/index.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; +import { doWalletStatus, selectWalletIsEncrypted } from 'lbry-redux'; +import { selectUserVerifiedEmail } from 'redux/selectors/user'; +import SettingAccount from './view'; + +const select = (state) => ({ + isAuthenticated: selectUserVerifiedEmail(state), + walletEncrypted: selectWalletIsEncrypted(state), +}); + +const perform = (dispatch) => ({ + doWalletStatus: () => dispatch(doWalletStatus()), +}); + +export default connect(select, perform)(SettingAccount); diff --git a/ui/component/settingAccount/view.jsx b/ui/component/settingAccount/view.jsx new file mode 100644 index 000000000..4097b532d --- /dev/null +++ b/ui/component/settingAccount/view.jsx @@ -0,0 +1,55 @@ +// @flow +import React from 'react'; +import Card from 'component/common/card'; +import SettingAccountPassword from 'component/settingAccountPassword'; +import SyncToggle from 'component/syncToggle'; +import { getPasswordFromCookie } from 'util/saved-passwords'; + +type Props = { + // --- select --- + isAuthenticated: boolean, + walletEncrypted: boolean, + // --- perform --- + doWalletStatus: () => void, +}; + +export default function SettingAccount(props: Props) { + const { isAuthenticated, walletEncrypted, doWalletStatus } = props; + const [storedPassword, setStoredPassword] = React.useState(false); + + // Determine if password is stored. + React.useEffect(() => { + if (isAuthenticated || !IS_WEB) { + doWalletStatus(); + getPasswordFromCookie().then((p) => { + if (typeof p === 'string') { + setStoredPassword(true); + } + }); + } + // enterSettings(); @KP need to do this at each component, or just at Settings Page? + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + + {isAuthenticated && ( +
+ +
+ )} + + {/* @if TARGET='app' */} +
+ +
+ {/* @endif */} + + } + /> + ); +} diff --git a/ui/component/settingAccountPassword/view.jsx b/ui/component/settingAccountPassword/view.jsx index a63dff59a..494d078e6 100644 --- a/ui/component/settingAccountPassword/view.jsx +++ b/ui/component/settingAccountPassword/view.jsx @@ -3,7 +3,6 @@ import React, { useState } from 'react'; import { FormField, Form } from 'component/common/form'; import Button from 'component/button'; import ErrorText from 'component/common/error-text'; -import Card from 'component/common/card'; import * as PAGES from 'constants/pages'; type Props = { @@ -38,54 +37,52 @@ export default function SettingAccountPassword(props: Props) { } }, [passwordSetSuccess, setOldPassword, setNewPassword, doClearPasswordEntry, doToast]); - return ( - -
- {hasPassword && ( - setOldPassword(e.target.value)} - /> - )} - setNewPassword(e.target.value)} - /> - -
-
- - {passwordSetError && ( -
- {passwordSetError} -
- )} - - ) : ( -