redirect to password screen if toggling sync from settings page

This commit is contained in:
Sean Yesmunt 2019-10-16 01:01:18 -04:00
parent d7c0f5c6b7
commit 2ec3f62407
17 changed files with 66 additions and 115 deletions

View file

@ -130,8 +130,8 @@
"husky": "^0.14.3",
"json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#0090f195eb88f4620db7d038f7b01eaa76119836",
"lbryinc": "lbryio/lbryinc#b8e1708ee4491db342c81576265e1b58f542bedb",
"lbry-redux": "lbryio/lbry-redux#b09e1699eb92fef8087986a0f35b3df3977af87f",
"lbryinc": "lbryio/lbryinc#fb2e73ab31c2b9f80a53f082843a01e3f213ca45",
"lint-staged": "^7.0.2",
"localforage": "^1.7.1",
"lodash-es": "^4.17.14",

View file

@ -124,7 +124,7 @@ function App(props: Props) {
}, [hasVerifiedEmail, signIn, hasSignedIn]);
useEffect(() => {
if (userId && hasVerifiedEmail && syncEnabled) {
if (hasVerifiedEmail && syncEnabled) {
checkSync();
let syncInterval = setInterval(() => {
@ -135,7 +135,7 @@ function App(props: Props) {
clearInterval(syncInterval);
};
}
}, [hasVerifiedEmail, syncEnabled, checkSync, userId]);
}, [hasVerifiedEmail, syncEnabled, checkSync]);
if (!user) {
return null;

View file

@ -69,7 +69,6 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
...otherProps
} = props;
const currentPath = pathname.split('/$/')[1];
const combinedClassName = classnames(
'button',
button
@ -120,7 +119,7 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
<NavLink
ref={ref}
exact
to={`/$/${PAGES.AUTH}?redirect=${currentPath}`}
to={`/$/${PAGES.AUTH}?redirect=${pathname}`}
title={title}
disabled={disabled}
className={combinedClassName}

View file

@ -3,7 +3,8 @@ import React from 'react';
import { Form, FormField } from 'component/common/form';
import Button from 'component/button';
import Card from 'component/common/card';
import { setSavedPassword, deleteSavedPassword } from 'util/saved-passwords';
import { setSavedPassword } from 'util/saved-passwords';
import usePersistedState from 'effects/use-persisted-state';
type Props = {
getSync: (?string) => void,
@ -13,15 +14,10 @@ type Props = {
function SyncPassword(props: Props) {
const { getSync, getSyncIsPending } = props;
const [password, setPassword] = React.useState('');
const [rememberPassword, setRememberPassword] = React.useState(true);
const [rememberPassword, setRememberPassword] = usePersistedState(true);
function handleSubmit() {
if (rememberPassword) {
setSavedPassword(password);
} else {
deleteSavedPassword();
}
setSavedPassword(password, rememberPassword);
getSync(password);
}
@ -39,6 +35,7 @@ function SyncPassword(props: Props) {
onChange={e => setPassword(e.target.value)}
/>
<FormField
name="remember-password"
type="checkbox"
label={__('Remember My Password')}
checked={rememberPassword}

View file

@ -1,6 +1,6 @@
import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux';
import { selectUserVerifiedEmail } from 'lbryinc';
import { selectUserVerifiedEmail, selectGetSyncErrorMessage } from 'lbryinc';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetClientSetting } from 'redux/actions/settings';
import SyncToggle from './view';
@ -8,6 +8,7 @@ import SyncToggle from './view';
const select = state => ({
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
verifiedEmail: selectUserVerifiedEmail(state),
getSyncError: selectGetSyncErrorMessage(state),
});
const perform = dispatch => ({

View file

@ -1,25 +1,44 @@
// @flow
import * as PAGES from 'constants/pages';
import React from 'react';
import { FormField } from 'component/common/form';
import Button from 'component/button';
import { FormField } from 'component/common/form';
import { withRouter } from 'react-router';
type Props = {
setSyncEnabled: boolean => void,
syncEnabled: boolean,
verifiedEmail: ?string,
history: { push: string => void },
location: UrlLocation,
getSyncError: ?string,
};
function SyncToggle(props: Props) {
const { setSyncEnabled, syncEnabled, verifiedEmail } = props;
console.log('??', syncEnabled);
const {
setSyncEnabled,
syncEnabled,
verifiedEmail,
getSyncError,
history,
location: { pathname },
} = props;
function handleChange() {
setSyncEnabled(!syncEnabled);
}
if (getSyncError) {
return history.push(`/$/${PAGES.AUTH}?redirect=${pathname}&immediate=true`);
}
return (
<div>
{!verifiedEmail ? (
<Button requiresAuth button="primary" label={__('Start Syncing')} />
<div>
<Button requiresAuth button="primary" label={__('Add Email')} />
<p className="help">{__('An email address is required to sync your account.')}</p>
</div>
) : (
<FormField
type="checkbox"
@ -33,4 +52,4 @@ function SyncToggle(props: Props) {
);
}
export default SyncToggle;
export default withRouter(SyncToggle);

View file

@ -56,6 +56,8 @@ function UserSignIn(props: Props) {
const { search } = location;
const urlParams = new URLSearchParams(search);
const redirect = urlParams.get('redirect');
const shouldRedirectImmediately = urlParams.get('immediate');
const [initialSignInStep, setInitialSignInStep] = React.useState();
const hasVerifiedEmail = user && user.has_verified_email;
const rewardsApproved = user && user.is_reward_approved;
const hasFetchedReward = useFetched(claimingReward);
@ -80,7 +82,7 @@ function UserSignIn(props: Props) {
const showEmail = !emailToVerify && !hasVerifiedEmail;
const showEmailVerification = emailToVerify && !hasVerifiedEmail;
const showUserVerification = hasVerifiedEmail && !rewardsApproved;
const showSyncPassword = syncEnabled && getSyncError && !hasSynced;
const showSyncPassword = syncEnabled && getSyncError;
const showChannelCreation =
hasVerifiedEmail &&
balance !== undefined &&
@ -111,7 +113,7 @@ function UserSignIn(props: Props) {
const SIGN_IN_FLOW = [
showEmail && <UserEmailNew />,
showEmailVerification && <UserEmailVerify />,
showUserVerification && <UserVerify />,
showUserVerification && <UserVerify skipLink={redirect} />,
showChannelCreation && <UserFirstChannel />,
// @if TARGET='app'
showYoutubeTransfer && (
@ -132,6 +134,17 @@ function UserSignIn(props: Props) {
for (var i = SIGN_IN_FLOW.length - 1; i > -1; i--) {
const Component = SIGN_IN_FLOW[i];
if (Component) {
// If we want to redirect immediately,
// remember the first step so we can redirect once a new step has been reached
// Ignore the loading step
if (redirect && shouldRedirectImmediately) {
if (!initialSignInStep) {
setInitialSignInStep(i);
} else if (i !== initialSignInStep && i !== SIGN_IN_FLOW.length - 1) {
history.replace(redirect);
}
}
return Component;
}
}

View file

@ -12,6 +12,7 @@ type Props = {
verifyUserIdentity: string => void,
verifyPhone: () => void,
fetchUser: () => void,
skipLink?: string,
};
class UserVerify extends React.PureComponent<Props> {
@ -26,7 +27,7 @@ class UserVerify extends React.PureComponent<Props> {
}
render() {
const { errorMessage, isPending, verifyPhone, fetchUser } = this.props;
const { errorMessage, isPending, verifyPhone, fetchUser, skipLink } = this.props;
return (
<React.Fragment>
<section className="section__header">
@ -36,7 +37,7 @@ class UserVerify extends React.PureComponent<Props> {
"We weren't able to auto-approve you for rewards. Please complete one of the steps below to unlock them."
)}{' '}
<Button onClick={() => fetchUser()} button="link" label={__('Refresh')} /> {'or'}{' '}
<Button navigate="/" button="link" label={__('Skip')} />
<Button navigate={skipLink || '/'} button="link" label={__('Skip')} />.
</p>
</section>

View file

@ -13,7 +13,6 @@ export const PHONE_COLLECTION = 'phone_collection';
export const FIRST_REWARD = 'first_reward';
export const AUTHENTICATION_FAILURE = 'auth_failure';
export const TRANSACTION_FAILED = 'transaction_failed';
export const REWARD_APPROVAL_REQUIRED = 'reward_approval_required';
export const REWARD_GENERATED_CODE = 'reward_generated_code';
export const AFFIRM_PURCHASE = 'affirm_purchase';
export const CONFIRM_CLAIM_REVOKE = 'confirm_claim_revoke';

View file

@ -125,12 +125,8 @@ rewards.setCallback('claimFirstRewardSuccess', () => {
app.store.dispatch(doOpenModal(MODALS.FIRST_REWARD));
});
rewards.setCallback('rewardApprovalRequired', () => {
app.store.dispatch(doOpenModal(MODALS.REWARD_APPROVAL_REQUIRED));
});
rewards.setCallback('claimRewardSuccess', () => {
app.store.dispatch(doHideModal(MODALS.REWARD_APPROVAL_REQUIRED));
app.store.dispatch(doHideModal());
});
// @if TARGET='app'

View file

@ -1,25 +0,0 @@
import * as PAGES from 'constants/pages';
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import { withRouter } from 'react-router-dom';
import ModalRewardApprovalRequired from './view';
const perform = (dispatch, ownProps) => ({
doAuth: () => {
const {
location: { pathname },
history,
} = ownProps;
const currentPath = pathname.split('/$/')[1];
dispatch(doHideModal());
history.push(`/$/${PAGES.AUTH}?redirect=${currentPath}`);
},
closeModal: () => dispatch(doHideModal()),
});
export default withRouter(
connect(
null,
perform
)(ModalRewardApprovalRequired)
);

View file

@ -1,35 +0,0 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
type Props = {
closeModal: () => void,
doAuth: () => void,
};
class ModalRewardApprovalRequired extends React.PureComponent<Props> {
render() {
const { closeModal, doAuth } = this.props;
return (
<Modal
isOpen
title={__('Hmm. Are you real?')}
contentLabel={__('Human Verification Required')}
onConfirmed={doAuth}
onAborted={closeModal}
type="confirm"
confirmButtonLabel={__("I'm Totally Real")}
abortButtonLabel={__('Never Mind')}
>
<p>
{__(
"Before we can give you any credits, we need to perform a brief check to make sure you're a new and unique person."
)}
</p>
</Modal>
);
}
}
export default ModalRewardApprovalRequired;

View file

@ -8,7 +8,6 @@ import ModalAutoUpdateDownloaded from 'modal/modalAutoUpdateDownloaded';
import ModalUpgrade from 'modal/modalUpgrade';
import ModalWelcome from 'modal/modalWelcome';
import ModalFirstReward from 'modal/modalFirstReward';
import ModalRewardApprovalRequired from 'modal/modalRewardApprovalRequired';
import ModalRemoveFile from 'modal/modalRemoveFile';
import ModalTransactionFailed from 'modal/modalTransactionFailed';
import ModalFileTimeout from 'modal/modalFileTimeout';
@ -65,8 +64,6 @@ function ModalRouter(props: Props) {
return <ModalFirstReward {...modalProps} />;
case MODALS.TRANSACTION_FAILED:
return <ModalTransactionFailed {...modalProps} />;
case MODALS.REWARD_APPROVAL_REQUIRED:
return <ModalRewardApprovalRequired {...modalProps} />;
case MODALS.CONFIRM_FILE_REMOVE:
return <ModalRemoveFile {...modalProps} />;
case MODALS.AFFIRM_PURCHASE:

View file

@ -11,7 +11,7 @@ const select = state => ({
});
const perform = (dispatch, ownProps) => ({
doAuth: () => ownProps.history.push(`/$/${PAGES.AUTH}?redirect=help`),
doAuth: () => ownProps.history.push(`/$/${PAGES.AUTH}?redirect=/$/${PAGES.HELP}`),
fetchAccessToken: () => dispatch(doFetchAccessToken()),
});

View file

@ -90,7 +90,6 @@ class SettingsPage extends React.PureComponent<Props, State> {
(this: any).onInstantPurchaseMaxChange = this.onInstantPurchaseMaxChange.bind(this);
(this: any).onThemeChange = this.onThemeChange.bind(this);
(this: any).onAutomaticDarkModeChange = this.onAutomaticDarkModeChange.bind(this);
(this: any).clearCache = this.clearCache.bind(this);
(this: any).onChangeTime = this.onChangeTime.bind(this);
(this: any).onConfirmForgetPassword = this.onConfirmForgetPassword.bind(this);
}
@ -175,19 +174,6 @@ class SettingsPage extends React.PureComponent<Props, State> {
this.props.setDaemonSetting(name, value);
}
clearCache() {
this.setState({
clearingCache: true,
});
const success = () => {
this.setState({ clearingCache: false });
window.location.reload();
};
const clear = () => this.props.clearCache().then(success);
setTimeout(clear, 1000, { once: true });
}
render() {
const {
daemonSettings,
@ -210,6 +196,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
floatingPlayer,
clearPlayingUri,
darkModeTimes,
clearCache,
} = this.props;
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
@ -651,7 +638,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
<Button
button="inverse"
label={this.state.clearingCache ? __('Clearing') : __('Clear Cache')}
onClick={this.clearCache}
onClick={clearCache}
disabled={this.state.clearingCache}
/>
}

View file

@ -2,14 +2,16 @@ import { ipcRenderer } from 'electron';
let sessionPassword;
export const setSavedPassword = value => {
export const setSavedPassword = (value, saveToDisk) => {
return new Promise(resolve => {
ipcRenderer.once('set-password-response', (event, success) => {
resolve(success);
});
sessionPassword = value;
if (saveToDisk && value) {
ipcRenderer.send('set-password', value);
}
});
};

View file

@ -6870,17 +6870,17 @@ lazy-val@^1.0.3, lazy-val@^1.0.4:
yargs "^13.2.2"
zstd-codec "^0.1.1"
lbry-redux@lbryio/lbry-redux#0090f195eb88f4620db7d038f7b01eaa76119836:
lbry-redux@lbryio/lbry-redux#b09e1699eb92fef8087986a0f35b3df3977af87f:
version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/0090f195eb88f4620db7d038f7b01eaa76119836"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/b09e1699eb92fef8087986a0f35b3df3977af87f"
dependencies:
proxy-polyfill "0.1.6"
reselect "^3.0.0"
uuid "^3.3.2"
lbryinc@lbryio/lbryinc#b8e1708ee4491db342c81576265e1b58f542bedb:
lbryinc@lbryio/lbryinc#fb2e73ab31c2b9f80a53f082843a01e3f213ca45:
version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/b8e1708ee4491db342c81576265e1b58f542bedb"
resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/fb2e73ab31c2b9f80a53f082843a01e3f213ca45"
dependencies:
reselect "^3.0.0"