-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update account deleted page to allow restore behind feature flag (#96446
) * Update layout for account deleted page * Add account restore functionality * Update layout for deleting state * rename ACCOUNT_RESTORE_ERROR to ACCOUNT_RESTORE_FAILED * Prefix unused variable * Use translate for Create an account * Align click handler names * Replace redux connect with useSelector and rename component * Update redirect copy
- Loading branch information
1 parent
9ffb111
commit b7fffd6
Showing
10 changed files
with
269 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,98 @@ | ||
import { Spinner } from '@automattic/components'; | ||
import { localize } from 'i18n-calypso'; | ||
import { Component } from 'react'; | ||
import { connect } from 'react-redux'; | ||
import EmptyContent from 'calypso/components/empty-content'; | ||
import getPreviousRoute from 'calypso/state/selectors/get-previous-route'; | ||
import config from '@automattic/calypso-config'; | ||
import { Button, Spinner } from '@wordpress/components'; | ||
import { useTranslate } from 'i18n-calypso'; | ||
import { useEffect } from 'react'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
import { BlankCanvas } from 'calypso/components/blank-canvas'; | ||
import FormattedHeader from 'calypso/components/formatted-header'; | ||
import { restoreAccount } from 'calypso/state/account/actions'; | ||
import { getIsRestoring, getRestoreToken } from 'calypso/state/account/selectors'; | ||
import isAccountClosed from 'calypso/state/selectors/is-account-closed'; | ||
|
||
import './closed.scss'; | ||
|
||
class AccountSettingsClosedComponent extends Component { | ||
onClick = () => { | ||
window.location = '/'; | ||
}; | ||
function AccountDeletedPage() { | ||
const translate = useTranslate(); | ||
const dispatch = useDispatch(); | ||
|
||
render() { | ||
const { isUserAccountClosed, translate } = this.props; | ||
const isRestoring = useSelector( getIsRestoring ); | ||
const isUserAccountClosed = useSelector( isAccountClosed ); | ||
|
||
if ( ! isUserAccountClosed ) { | ||
return ( | ||
<div className="account-close__spinner"> | ||
<Spinner size={ 32 } /> | ||
<p className="account-close__spinner-text"> | ||
{ translate( 'Your account is being deleted' ) } | ||
</p> | ||
</div> | ||
); | ||
// restore token is either in the URL or in the reducer | ||
const params = new URLSearchParams( window.location.search ); | ||
const urlToken = params.get( 'token' ); | ||
const storedToken = useSelector( getRestoreToken ); | ||
const restoreToken = urlToken || storedToken; | ||
|
||
// Sync token to URL if not already there | ||
useEffect( () => { | ||
if ( storedToken && ! urlToken ) { | ||
const newUrl = new URL( window.location.href ); | ||
newUrl.searchParams.set( 'token', storedToken ); | ||
window.history.replaceState( {}, '', newUrl.toString() ); | ||
} | ||
}, [ storedToken, urlToken ] ); | ||
|
||
const onCancelClick = () => { | ||
window.location.href = '/'; | ||
}; | ||
|
||
const onRestoreClick = () => { | ||
dispatch( restoreAccount( restoreToken ) ); | ||
}; | ||
|
||
if ( ( ! isUserAccountClosed && ! config.isEnabled( 'me/account-restore' ) ) || ! restoreToken ) { | ||
return ( | ||
<EmptyContent | ||
title={ translate( 'Your account has been closed' ) } | ||
line={ translate( 'Thanks for flying with WordPress.com' ) } | ||
secondaryAction={ translate( 'Return to WordPress.com' ) } | ||
secondaryActionCallback={ this.onClick } | ||
/> | ||
<BlankCanvas className="account-deleted"> | ||
<BlankCanvas.Header /> | ||
<BlankCanvas.Content> | ||
<FormattedHeader | ||
brandFont | ||
headerText={ translate( 'Your account is being deleted' ) } | ||
subHeaderText={ <Spinner style={ { width: '32px', height: '32px' } } /> } | ||
/> | ||
</BlankCanvas.Content> | ||
</BlankCanvas> | ||
); | ||
} | ||
|
||
return ( | ||
<BlankCanvas className="account-deleted"> | ||
<BlankCanvas.Header> | ||
<Button variant="link" className="account-deleted__button-link" href="/"> | ||
{ translate( 'Create an account' ) } | ||
</Button> | ||
</BlankCanvas.Header> | ||
<BlankCanvas.Content> | ||
<FormattedHeader | ||
brandFont | ||
headerText={ translate( 'Your account has been deleted' ) } | ||
subHeaderText={ | ||
config.isEnabled( 'me/account-restore' ) | ||
? translate( | ||
'Thanks for flying with WordPress.com. You have 30 days to restore your account if you change your mind.' | ||
) | ||
: translate( 'Thanks for flying with WordPress.com.' ) | ||
} | ||
/> | ||
<div className="account-deleted__buttons"> | ||
<Button variant="secondary" onClick={ onCancelClick }> | ||
{ translate( 'Return to WordPress.com' ) } | ||
</Button> | ||
{ config.isEnabled( 'me/account-restore' ) && ( | ||
<Button | ||
variant="link" | ||
className="account-deleted__button-link" | ||
onClick={ onRestoreClick } | ||
isBusy={ isRestoring } | ||
> | ||
{ translate( 'I made a mistake! Restore my account' ) } | ||
</Button> | ||
) } | ||
</div> | ||
</BlankCanvas.Content> | ||
</BlankCanvas> | ||
); | ||
} | ||
|
||
export default connect( ( state ) => { | ||
return { | ||
previousRoute: getPreviousRoute( state ), | ||
isUserAccountClosed: isAccountClosed( state ), | ||
}; | ||
} )( localize( AccountSettingsClosedComponent ) ); | ||
export default AccountDeletedPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,45 @@ | ||
.account-close__spinner { | ||
padding-top: 120px; | ||
text-align: center; | ||
@import "@wordpress/base-styles/breakpoints"; | ||
@import "@wordpress/base-styles/mixins"; | ||
|
||
.account-close__spinner-text { | ||
font-size: $font-body-small; | ||
font-weight: 400; | ||
margin-top: 8px; | ||
.account-deleted { | ||
&.blank-canvas { | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
&.blank-canvas .formatted-header .formatted-header__title { | ||
font-size: 2rem; | ||
} | ||
&.blank-canvas .formatted-header .formatted-header__subtitle { | ||
font-size: 0.875rem; | ||
} | ||
.blank-canvas__content { | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
flex-grow: 1; | ||
@include break-small { | ||
max-width: 450px; | ||
margin: -4rem auto 0; | ||
} | ||
} | ||
.blank-canvas__header { | ||
justify-content: space-between; | ||
} | ||
.blank-canvas__header-title { | ||
position: relative; | ||
} | ||
|
||
.account-deleted__button-link { | ||
color: var( --studio-gray-100 ); | ||
font-weight: 500; | ||
} | ||
.account-deleted__buttons { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: flex-start; | ||
gap: 1rem; | ||
@include break-small { | ||
align-items: center; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { AccountState } from './types'; | ||
|
||
export const getRestoreToken = ( state: { account?: AccountState } ) => | ||
state.account?.restoreToken || null; | ||
|
||
export const getIsRestoring = ( state: { account?: AccountState } ) => | ||
state.account?.isRestoring || false; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Action } from 'redux'; | ||
import { ACCOUNT_RESTORE } from '../action-types'; | ||
|
||
export interface AccountState { | ||
restoreToken?: string | null; | ||
isClosed?: boolean; | ||
isRestoring?: boolean; | ||
} | ||
|
||
export type AccountRestoreActionType = Action< typeof ACCOUNT_RESTORE > & { | ||
payload: { | ||
token: string; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { translate } from 'i18n-calypso'; | ||
import { AccountRestoreActionType } from 'calypso/state/account/types'; | ||
import { | ||
ACCOUNT_RESTORE, | ||
ACCOUNT_RESTORE_SUCCESS, | ||
ACCOUNT_RESTORE_FAILED, | ||
} from 'calypso/state/action-types'; | ||
import { registerHandlers } from 'calypso/state/data-layer/handler-registry'; | ||
import { http } from 'calypso/state/data-layer/wpcom-http/actions'; | ||
import { dispatchRequest } from 'calypso/state/data-layer/wpcom-http/utils'; | ||
import { errorNotice, successNotice } from 'calypso/state/notices/actions'; | ||
|
||
export function requestAccountRestore( action: AccountRestoreActionType ) { | ||
const { token } = action.payload; | ||
return http( | ||
{ | ||
method: 'POST', | ||
apiVersion: '1.1', | ||
path: `/me/account/restore`, | ||
body: { | ||
token, | ||
}, | ||
}, | ||
action | ||
); | ||
} | ||
|
||
function receiveAccountRestoreSuccess() { | ||
return [ | ||
{ type: ACCOUNT_RESTORE_SUCCESS }, | ||
() => { | ||
// wait before redirecting to let the user see the success notice | ||
setTimeout( () => { | ||
window.location.href = '/sites?restored=true'; | ||
}, 2000 ); | ||
}, | ||
successNotice( translate( 'Your account has been restored. Redirecting back to login.' ) ), | ||
]; | ||
} | ||
|
||
function receiveAccountRestoreError( action: AccountRestoreActionType, error: { error: string } ) { | ||
if ( error.error === 'invalid_token' ) { | ||
return [ | ||
{ type: ACCOUNT_RESTORE_FAILED }, | ||
errorNotice( | ||
translate( | ||
'Invalid token. Please check your account deleted email for the correct link or contact support.' | ||
) | ||
), | ||
]; | ||
} | ||
return [ | ||
{ type: ACCOUNT_RESTORE_FAILED }, | ||
errorNotice( | ||
translate( 'Sorry, there was a problem restoring your account. Please contact support.' ) | ||
), | ||
]; | ||
} | ||
|
||
registerHandlers( 'state/data-layer/wpcom/me/account/restore/index.js', { | ||
[ ACCOUNT_RESTORE ]: [ | ||
dispatchRequest( { | ||
fetch: requestAccountRestore, | ||
onSuccess: receiveAccountRestoreSuccess, | ||
onError: receiveAccountRestoreError, | ||
} ), | ||
], | ||
} ); |