Fix(settings): Add separate delete page
This commit is contained in:
@ -8,7 +8,6 @@ import {
|
|||||||
reducer as challengesApp,
|
reducer as challengesApp,
|
||||||
projectNormalizer
|
projectNormalizer
|
||||||
} from './routes/challenges/redux';
|
} from './routes/challenges/redux';
|
||||||
import { reducer as settingsApp } from './routes/settings/redux';
|
|
||||||
|
|
||||||
export default function createReducer(sideReducers = {}) {
|
export default function createReducer(sideReducers = {}) {
|
||||||
return combineReducers({
|
return combineReducers({
|
||||||
@ -17,7 +16,6 @@ export default function createReducer(sideReducers = {}) {
|
|||||||
app,
|
app,
|
||||||
toasts,
|
toasts,
|
||||||
challengesApp,
|
challengesApp,
|
||||||
settingsApp,
|
|
||||||
form: formReducer.normalize({ ...projectNormalizer })
|
form: formReducer.normalize({ ...projectNormalizer })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
import React, { PropTypes } from 'react';
|
|
||||||
import { Modal, Button } from 'react-bootstrap';
|
|
||||||
|
|
||||||
export default function DeleteModal({ isOpen }) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
block={ true }
|
|
||||||
bsSize='lg'
|
|
||||||
bsStyle='danger'
|
|
||||||
className='btn-link-social'
|
|
||||||
>
|
|
||||||
Delete my Free Code Camp account
|
|
||||||
</Button>
|
|
||||||
<Modal
|
|
||||||
backdrop={ true }
|
|
||||||
show={ isOpen }
|
|
||||||
>
|
|
||||||
<Modal.Header>
|
|
||||||
<h3>You don't really want to delete your account, do you?</h3>
|
|
||||||
</Modal.Header>
|
|
||||||
<Modal.Body>
|
|
||||||
<p>
|
|
||||||
This will really delete all your data, including
|
|
||||||
all your progress and brownie points.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
We won't be able to recover any of it for you later,
|
|
||||||
even if you change your mind.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If there's something we could do better, send
|
|
||||||
us an email instead and we'll do our best:  
|
|
||||||
<a href='mailto:team@freecodecamp.com'>
|
|
||||||
team@freecodecamp.com
|
|
||||||
</a>.
|
|
||||||
</p>
|
|
||||||
</Modal.Body>
|
|
||||||
<Modal.Footer>
|
|
||||||
<Button
|
|
||||||
block={ true }
|
|
||||||
bsStyle='success'
|
|
||||||
>
|
|
||||||
Nevermind, I don't want to delete all of my progress
|
|
||||||
</Button>
|
|
||||||
<div className='spacer' />
|
|
||||||
<Button
|
|
||||||
block={ true }
|
|
||||||
bsStyle='danger'
|
|
||||||
>
|
|
||||||
I am 100% sure I want to delete my account and all of my progress
|
|
||||||
</Button>
|
|
||||||
</Modal.Footer>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeleteModal.propTypes = {
|
|
||||||
isOpen: PropTypes.bool
|
|
||||||
};
|
|
@ -7,23 +7,13 @@ import LockedSettings from './Locked-Settings.jsx';
|
|||||||
import SocialSettings from './Social-Settings.jsx';
|
import SocialSettings from './Social-Settings.jsx';
|
||||||
import EmailSettings from './Email-Setting.jsx';
|
import EmailSettings from './Email-Setting.jsx';
|
||||||
import LangaugeSettings from './Language-Settings.jsx';
|
import LangaugeSettings from './Language-Settings.jsx';
|
||||||
import DeleteModal from './Delete-Modal.jsx';
|
|
||||||
|
|
||||||
import {
|
import { toggleUserFlag } from '../redux/actions';
|
||||||
toggleUserFlag,
|
import { toggleNightMode, updateTitle } from '../../../redux/actions';
|
||||||
openDeleteModal,
|
|
||||||
hideDeleteModal
|
|
||||||
} from '../redux/actions';
|
|
||||||
import {
|
|
||||||
toggleNightMode,
|
|
||||||
updateTitle
|
|
||||||
} from '../../../redux/actions';
|
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
updateTitle,
|
updateTitle,
|
||||||
toggleNightMode,
|
toggleNightMode,
|
||||||
openDeleteModal,
|
|
||||||
hideDeleteModal,
|
|
||||||
toggleIsLocked: () => toggleUserFlag('isLocked'),
|
toggleIsLocked: () => toggleUserFlag('isLocked'),
|
||||||
toggleQuincyEmail: () => toggleUserFlag('sendQuincyEmail'),
|
toggleQuincyEmail: () => toggleUserFlag('sendQuincyEmail'),
|
||||||
toggleNotificationEmail: () => toggleUserFlag('sendNotificationEmail'),
|
toggleNotificationEmail: () => toggleUserFlag('sendNotificationEmail'),
|
||||||
@ -33,8 +23,7 @@ const actions = {
|
|||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
const {
|
const {
|
||||||
app: { user: username },
|
app: { user: username },
|
||||||
entities: { user: userMap },
|
entities: { user: userMap }
|
||||||
settingsApp: { isDeleteOpen }
|
|
||||||
} = state;
|
} = state;
|
||||||
const {
|
const {
|
||||||
email,
|
email,
|
||||||
@ -49,7 +38,6 @@ const mapStateToProps = state => {
|
|||||||
return {
|
return {
|
||||||
username,
|
username,
|
||||||
email,
|
email,
|
||||||
isDeleteOpen,
|
|
||||||
isLocked,
|
isLocked,
|
||||||
isGithubCool,
|
isGithubCool,
|
||||||
isTwitter,
|
isTwitter,
|
||||||
@ -69,7 +57,6 @@ export class Settings extends React.Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.element,
|
children: PropTypes.element,
|
||||||
username: PropTypes.string,
|
username: PropTypes.string,
|
||||||
isDeleteOpen: PropTypes.bool,
|
|
||||||
isLocked: PropTypes.bool,
|
isLocked: PropTypes.bool,
|
||||||
isGithubCool: PropTypes.bool,
|
isGithubCool: PropTypes.bool,
|
||||||
isTwitter: PropTypes.bool,
|
isTwitter: PropTypes.bool,
|
||||||
@ -84,8 +71,6 @@ export class Settings extends React.Component {
|
|||||||
toggleQuincyEmail: PropTypes.func.isRequired,
|
toggleQuincyEmail: PropTypes.func.isRequired,
|
||||||
toggleMonthlyEmail: PropTypes.func.isRequired,
|
toggleMonthlyEmail: PropTypes.func.isRequired,
|
||||||
toggleNotificationEmail: PropTypes.func.isRequired,
|
toggleNotificationEmail: PropTypes.func.isRequired,
|
||||||
openDeleteModal: PropTypes.func.isRequired,
|
|
||||||
hideDeleteModal: PropTypes.func.isRequired,
|
|
||||||
lang: PropTypes.string,
|
lang: PropTypes.string,
|
||||||
initialLang: PropTypes.string,
|
initialLang: PropTypes.string,
|
||||||
updateMyLang: PropTypes.func
|
updateMyLang: PropTypes.func
|
||||||
@ -105,7 +90,6 @@ export class Settings extends React.Component {
|
|||||||
const {
|
const {
|
||||||
children,
|
children,
|
||||||
username,
|
username,
|
||||||
isDeleteOpen,
|
|
||||||
isLocked,
|
isLocked,
|
||||||
isGithubCool,
|
isGithubCool,
|
||||||
isTwitter,
|
isTwitter,
|
||||||
@ -118,9 +102,7 @@ export class Settings extends React.Component {
|
|||||||
toggleIsLocked,
|
toggleIsLocked,
|
||||||
toggleQuincyEmail,
|
toggleQuincyEmail,
|
||||||
toggleMonthlyEmail,
|
toggleMonthlyEmail,
|
||||||
toggleNotificationEmail,
|
toggleNotificationEmail
|
||||||
openDeleteModal,
|
|
||||||
hideDeleteModal
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (children) {
|
if (children) {
|
||||||
return (
|
return (
|
||||||
@ -267,11 +249,15 @@ export class Settings extends React.Component {
|
|||||||
smOffset={ 2 }
|
smOffset={ 2 }
|
||||||
xs={ 12 }
|
xs={ 12 }
|
||||||
>
|
>
|
||||||
<DeleteModal
|
<Button
|
||||||
hide={ hideDeleteModal }
|
block={ true }
|
||||||
isOpen={ isDeleteOpen }
|
bsSize='lg'
|
||||||
open={ openDeleteModal }
|
bsStyle='danger'
|
||||||
/>
|
className='btn-link-social'
|
||||||
|
href='/delete-my-account'
|
||||||
|
>
|
||||||
|
Delete my Free Code Camp account
|
||||||
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,37 +1,16 @@
|
|||||||
import { createAction, handleActions } from 'redux-actions';
|
import { createAction } from 'redux-actions';
|
||||||
|
|
||||||
import createTypes from '../../../utils/create-types';
|
import createTypes from '../../../utils/create-types';
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
showDeleteModal: false
|
|
||||||
};
|
|
||||||
export const types = createTypes([
|
export const types = createTypes([
|
||||||
'toggleUserFlag',
|
'toggleUserFlag',
|
||||||
'openDeleteModal',
|
|
||||||
'hideDeleteModal',
|
|
||||||
'updateMyEmail',
|
'updateMyEmail',
|
||||||
'updateMyLang'
|
'updateMyLang'
|
||||||
], 'settings');
|
], 'settings');
|
||||||
|
|
||||||
export const toggleUserFlag = createAction(types.toggleUserFlag);
|
export const toggleUserFlag = createAction(types.toggleUserFlag);
|
||||||
export const openDeleteModal = createAction(types.openDeleteModal);
|
|
||||||
export const hideDeleteModal = createAction(types.hideDeleteModal);
|
|
||||||
export const updateMyEmail = createAction(types.updateMyEmail);
|
export const updateMyEmail = createAction(types.updateMyEmail);
|
||||||
export const updateMyLang = createAction(
|
export const updateMyLang = createAction(
|
||||||
types.updateMyLang,
|
types.updateMyLang,
|
||||||
(values) => values.lang
|
(values) => values.lang
|
||||||
);
|
);
|
||||||
|
|
||||||
export default handleActions(
|
|
||||||
{
|
|
||||||
[openDeleteModal]: state => ({
|
|
||||||
...state,
|
|
||||||
isDeleteOpen: true
|
|
||||||
}),
|
|
||||||
[hideDeleteModal]: state => ({
|
|
||||||
...state,
|
|
||||||
isDeleteOpen: false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
initialState
|
|
||||||
);
|
|
||||||
|
@ -2,7 +2,6 @@ import userUpdateSaga from './update-user-saga';
|
|||||||
|
|
||||||
export { types } from './actions';
|
export { types } from './actions';
|
||||||
export * as actions from './actions';
|
export * as actions from './actions';
|
||||||
export { default as reducer } from './actions';
|
|
||||||
|
|
||||||
export const sagas = [
|
export const sagas = [
|
||||||
userUpdateSaga
|
userUpdateSaga
|
||||||
|
@ -167,6 +167,7 @@ module.exports = function(app) {
|
|||||||
router.get('/email-signin', getEmailSignin);
|
router.get('/email-signin', getEmailSignin);
|
||||||
router.get('/deprecated-signin', getDepSignin);
|
router.get('/deprecated-signin', getDepSignin);
|
||||||
router.get('/update-email', getUpdateEmail);
|
router.get('/update-email', getUpdateEmail);
|
||||||
|
router.get('/delete-my-account', showDelete);
|
||||||
api.post(
|
api.post(
|
||||||
'/account/delete',
|
'/account/delete',
|
||||||
ifNoUser401,
|
ifNoUser401,
|
||||||
@ -431,6 +432,10 @@ module.exports = function(app) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showDelete(req, res) {
|
||||||
|
return res.render('account/delete', { title: 'Delete My Account!' });
|
||||||
|
}
|
||||||
|
|
||||||
function postDeleteAccount(req, res, next) {
|
function postDeleteAccount(req, res, next) {
|
||||||
User.destroyById(req.user.id, function(err) {
|
User.destroyById(req.user.id, function(err) {
|
||||||
if (err) { return next(err); }
|
if (err) { return next(err); }
|
||||||
|
28
server/views/account/delete.jade
Normal file
28
server/views/account/delete.jade
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
extends ../layout
|
||||||
|
block content
|
||||||
|
include ../partials/flyer
|
||||||
|
#modal-dialog.modal.animated.wobble
|
||||||
|
.modal-dialog
|
||||||
|
.modal-content
|
||||||
|
.modal-header
|
||||||
|
a.close(href='#', data-dismiss='modal', aria-hidden='true') ×
|
||||||
|
h3 You don't really want to delete your account, do you?
|
||||||
|
.modal-body
|
||||||
|
p This will really delete all your data, including all your progress and brownie points.
|
||||||
|
p We won't be able to recover any of it for you later, even if you change your mind.
|
||||||
|
p If there's something we could do better, send us an email instead and we'll do our best:  
|
||||||
|
a(href="mailto:team@freecodecamp.com") team@freecodecamp.com
|
||||||
|
| .
|
||||||
|
.modal-footer
|
||||||
|
a.btn.btn-success.btn-block(href='/map', data-dismiss='modal', aria-hidden='true')
|
||||||
|
| Nevermind, I don't want to delete all of my progress
|
||||||
|
.spacer
|
||||||
|
form(action='/account/delete', method='POST')
|
||||||
|
input(type='hidden', name='_csrf', value=_csrf)
|
||||||
|
button.btn.btn-danger.btn-block(type='submit')
|
||||||
|
| I am 100% sure I want to delete my account and all of my progress
|
||||||
|
script.
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const modal$ = document.getElementById('modal-dialog');
|
||||||
|
modal$.classList.add('show');
|
||||||
|
});
|
Reference in New Issue
Block a user