Skip to content

Commit

Permalink
feat(Account): Enable a user to delete their own account
Browse files Browse the repository at this point in the history
  • Loading branch information
adlk committed Dec 4, 2017
1 parent 5a4a7f2 commit 1f3df73
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/actions/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ export default {
importLegacyServices: PropTypes.arrayOf(PropTypes.shape({
recipe: PropTypes.string.isRequired,
})).isRequired,
delete: {},
};
4 changes: 4 additions & 0 deletions src/api/UserApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ export default class UserApi {
getLegacyServices() {
return this.server.getLegacyServices();
}

delete() {
return this.server.deleteAccount();
}
}
13 changes: 13 additions & 0 deletions src/api/server/ServerApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,19 @@ export default class ServerApi {
return user;
}

async deleteAccount() {
const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/me`, this._prepareAuthRequest({
method: 'DELETE',
}));
if (!request.ok) {
throw request;
}
const data = await request.json();

console.debug('ServerApi::deleteAccount resolves', data);
return data;
}

// Services
async getServices() {
const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/me/services`, this._prepareAuthRequest({
Expand Down
49 changes: 46 additions & 3 deletions src/components/settings/account/AccountDashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const messages = defineMessages({
id: 'settings.account.headlineInvoices',
defaultMessage: '!!Invoices',
},
headlineDangerZone: {
id: 'settings.account.headlineDangerZone',
defaultMessage: '!!Danger Zone',
},
manageSubscriptionButtonLabel: {
id: 'settings.account.manageSubscription.label',
defaultMessage: '!!!Manage your subscription',
Expand Down Expand Up @@ -72,6 +76,18 @@ const messages = defineMessages({
id: 'settings.account.mining.cancel',
defaultMessage: '!!!Cancel mining',
},
deleteAccount: {
id: 'settings.account.deleteAccount',
defaultMessage: '!!!Delete account',
},
deleteInfo: {
id: 'settings.account.deleteInfo',
defaultMessage: '!!!If you don\'t need your Franz account any longer, you can delete your account and all related data here.',
},
deleteEmailSent: {
id: 'settings.account.deleteEmailSent',
defaultMessage: '!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!',
},
});

@observer
Expand All @@ -90,6 +106,9 @@ export default class AccountDashboard extends Component {
openExternalUrl: PropTypes.func.isRequired,
onCloseSubscriptionWindow: PropTypes.func.isRequired,
stopMiner: PropTypes.func.isRequired,
deleteAccount: PropTypes.func.isRequired,
isLoadingDeleteAccount: PropTypes.bool.isRequired,
isDeleteAccountSuccessful: PropTypes.bool.isRequired,
};

static contextTypes = {
Expand All @@ -111,6 +130,9 @@ export default class AccountDashboard extends Component {
retryUserInfoRequest,
onCloseSubscriptionWindow,
stopMiner,
deleteAccount,
isLoadingDeleteAccount,
isDeleteAccountSuccessful,
} = this.props;
const { intl } = this.context;

Expand Down Expand Up @@ -201,7 +223,7 @@ export default class AccountDashboard extends Component {
/>
</div>
</div>
<div className="account__box account__box--last">
<div className="account__box">
<h2>{intl.formatMessage(messages.headlineInvoices)}</h2>
<table className="invoices">
<tbody>
Expand Down Expand Up @@ -230,7 +252,7 @@ export default class AccountDashboard extends Component {

{user.isMiner && (
<div className="account franz-form">
<div className="account__box">
<div className="account__box account__box--last">
<h2>{intl.formatMessage(messages.headlineSubscription)}</h2>
<div className="account__subscription">
<div>
Expand Down Expand Up @@ -267,7 +289,7 @@ export default class AccountDashboard extends Component {
<Loader />
) : (
<div className="account franz-form">
<div className="account__box account__box--last">
<div className="account__box">
<h2>{intl.formatMessage(messages.headlineUpgrade)}</h2>
<SubscriptionForm
onCloseWindow={onCloseSubscriptionWindow}
Expand All @@ -276,8 +298,29 @@ export default class AccountDashboard extends Component {
</div>
)
)}

<div className="account franz-form">
<div className="account__box">
<h2>{intl.formatMessage(messages.headlineDangerZone)}</h2>
{!isDeleteAccountSuccessful && (
<div className="account__subscription">
<p>{intl.formatMessage(messages.deleteInfo)}</p>
<Button
label={intl.formatMessage(messages.deleteAccount)}
buttonType="danger"
onClick={() => deleteAccount()}
loaded={!isLoadingDeleteAccount}
/>
</div>
)}
{isDeleteAccountSuccessful && (
<p>{intl.formatMessage(messages.deleteEmailSent)}</p>
)}
</div>
</div>
</div>
)}

</div>
<ReactTooltip place="right" type="dark" effect="solid" />
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default class Button extends Component {
loaded={loaded}
lines={10}
scale={0.4}
color={buttonType === '' ? '#FFF' : '#373a3c'}
color={buttonType !== 'secondary' ? '#FFF' : '#373a3c'}
component="span"
/>
{label}
Expand Down
5 changes: 5 additions & 0 deletions src/containers/settings/AccountScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export default class AccountScreen extends Component {
render() {
const { user, payment, app } = this.props.stores;
const { openExternalUrl } = this.props.actions.app;
const { user: userActions } = this.props.actions;

const isLoadingUserInfo = user.getUserInfoRequest.isExecuting;
const isLoadingOrdersInfo = payment.ordersDataRequest.isExecuting;
Expand All @@ -89,6 +90,9 @@ export default class AccountScreen extends Component {
openExternalUrl={url => openExternalUrl({ url })}
onCloseSubscriptionWindow={() => this.onCloseWindow()}
stopMiner={() => this.stopMiner()}
deleteAccount={userActions.delete}
isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting}
isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError}
/>
);
}
Expand All @@ -109,6 +113,7 @@ AccountScreen.wrappedComponent.propTypes = {
}).isRequired,
user: PropTypes.shape({
update: PropTypes.func.isRequired,
delete: PropTypes.func.isRequired,
}).isRequired,
}).isRequired,
};
4 changes: 4 additions & 0 deletions src/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"settings.account.headlineSubscription": "Your subscription",
"settings.account.headlineUpgrade": "Upgrade your account & support Franz",
"settings.account.headlineInvoices": "Invoices",
"settings.account.headlineDangerZone": "Danger Zone",
"settings.account.manageSubscription.label": "Manage your subscription",
"settings.account.accountType.basic": "Basic Account",
"settings.account.accountType.premium": "Premium Supporter Account",
Expand All @@ -86,6 +87,9 @@
"settings.account.mining.active": "You are right now performing {hashes} calculations per second.",
"settings.account.mining.moreInformation": "Get more information",
"settings.account.mining.cancel": "Cancel mining",
"settings.account.deleteAccount": "Delete account",
"settings.account.deleteInfo": "If you don't need your Franz account any longer, you can delete your account and all related data here.",
"settings.account.deleteEmailSent": "You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!",
"settings.navigation.availableServices": "Available services",
"settings.navigation.yourServices": "Your services",
"settings.navigation.account": "Account",
Expand Down
6 changes: 6 additions & 0 deletions src/stores/UserStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default class UserStore extends Store {
@observable getUserInfoRequest = new CachedRequest(this.api.user, 'getInfo');
@observable updateUserInfoRequest = new Request(this.api.user, 'updateInfo');
@observable getLegacyServicesRequest = new CachedRequest(this.api.user, 'getLegacyServices');
@observable deleteAccountRequest = new CachedRequest(this.api.user, 'delete');
@observable isImportLegacyServicesExecuting = false;
@observable isImportLegacyServicesCompleted = false;
Expand Down Expand Up @@ -57,6 +58,7 @@ export default class UserStore extends Store {
this.actions.user.update.listen(this._update.bind(this));
this.actions.user.resetStatus.listen(this._resetStatus.bind(this));
this.actions.user.importLegacyServices.listen(this._importLegacyServices.bind(this));
this.actions.user.delete.listen(this._delete.bind(this));
// Reactions
this.registerReactions([
Expand Down Expand Up @@ -212,6 +214,10 @@ export default class UserStore extends Store {
this.isImportLegacyServicesCompleted = true;
}
@action async _delete() {
this.deleteAccountRequest.execute();
}
// This is a mobx autorun which forces the user to login if not authenticated
_requireAuthenticatedUser = () => {
if (this.isTokenExpired) {
Expand Down
4 changes: 4 additions & 0 deletions src/styles/settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@
margin-left: auto;
}

.franz-form__button {
white-space: nowrap;
}

div {
height: auto;
}
Expand Down

0 comments on commit 1f3df73

Please sign in to comment.