forked from sharetribe/ftw-hourly
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request sharetribe#23 from Skillpickr/feature/delete-account
Delete account
- Loading branch information
Showing
13 changed files
with
778 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
const { getSdk, getTrustedSdk, handleError } = require('../api-util/sdk'); | ||
|
||
// The list of non-final transitions depends on the transaction processes | ||
// being used on the marketplace. This list contains the non-final transitions | ||
// of flex-default-process i.e. the ones where we do not want to allow the user | ||
// to delete their account. | ||
const nonFinalTransitions = [ | ||
'transition/request-payment', | ||
'transition/request-payment-after-enquiry', | ||
'transition/confirm-payment', | ||
'transition/accept', | ||
'transition/complete', | ||
'transition/review-1-by-customer', | ||
'transition/review-1-by-provider', | ||
]; | ||
|
||
module.exports = (req, res) => { | ||
const { currentPassword } = req.body; | ||
|
||
const sdk = getSdk(req, res); | ||
|
||
let incompleteTransactions = null; | ||
let deletable = false; | ||
|
||
sdk.transactions | ||
.query({ lastTransitions: nonFinalTransitions }) | ||
.then(resp => { | ||
// Determine whether user has transactions that are in a non-final | ||
// state. | ||
incompleteTransactions = resp.data.data; | ||
deletable = incompleteTransactions.length === 0; | ||
return getTrustedSdk(req); | ||
}) | ||
.then(trustedSdk => { | ||
// If the user has incomplete transactions, send a 409 Conflict response | ||
// indicating the number of unfinished transactions. | ||
if (!deletable) { | ||
sendConflictResponse(incompleteTransactions, res); | ||
return; | ||
} | ||
|
||
// You can use this response for client-side testing purposes before actually | ||
// deleting your users. Uncomment the rows below to call the SDK live. | ||
|
||
res.status(200).send({ status: 200, statusText: 'OK' }); | ||
|
||
// // If the user has only completed transactions, delete the user | ||
// trustedSdk.currentUser.delete({ currentPassword }) | ||
// .then(resp => { | ||
// res | ||
// .status(resp.status) | ||
// .send(resp); | ||
// }) | ||
// // If deleting fails, use the built-in handler to pass the error as a response | ||
// .catch(e => handleError(res, e)) | ||
}) | ||
.catch(e => handleError(res, e)); | ||
}; | ||
|
||
// Construct a 409 Conflict response with a message indicating the number of | ||
// incomplete transactions. If you want, you can also include the full list | ||
// of transactions as 'data' in the response body. | ||
const sendConflictResponse = (incompleteTransactions, res) => { | ||
const txLabel = incompleteTransactions.length === 1 ? 'transaction' : 'transactions'; | ||
const message = `${incompleteTransactions.length} unfinished ${txLabel}.`; | ||
|
||
res.status(409).send({ status: 409, statusText: 'Conflict', message }); | ||
}; |
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
117 changes: 117 additions & 0 deletions
117
src/containers/DeleteAccountPage/DeleteAccountPage.duck.js
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,117 @@ | ||
import { storableError } from '../../util/errors'; | ||
// import { deleteUserAccount } from '../../util/api'; | ||
|
||
// ================ Action types ================ // | ||
|
||
export const DELETE_ACCOUNT_REQUEST = 'app/DeleteAccountPage/DELETE_ACCOUNT_REQUEST'; | ||
export const DELETE_ACCOUNT_SUCCESS = 'app/DeleteAccountPage/DELETE_ACCOUNT_SUCCESS'; | ||
export const DELETE_ACCOUNT_ERROR = 'app/DeleteAccountPage/DELETE_ACCOUNT_ERROR'; | ||
export const DELETE_ACCOUNT_CLEANUP = 'app/DeleteAccountPage/DELETE_ACCOUNT_CLEANUP'; | ||
|
||
export const DELETE_ACCOUNT_CLEAR = 'app/DeleteAccountPage/DELETE_ACCOUNT_CLEAR'; | ||
|
||
export const RESET_PASSWORD_REQUEST = 'app/DeleteAccountPage/RESET_PASSWORD_REQUEST'; | ||
export const RESET_PASSWORD_SUCCESS = 'app/DeleteAccountPage/RESET_PASSWORD_SUCCESS'; | ||
export const RESET_PASSWORD_ERROR = 'app/DeleteAccountPage/RESET_PASSWORD_ERROR'; | ||
|
||
// ================ Reducer ================ // | ||
|
||
const initialState = { | ||
deleteAccountError: null, | ||
deleteAccountInProgress: false, | ||
accountDeleted: false, | ||
resetPasswordInProgress: false, | ||
resetPasswordError: null, | ||
}; | ||
|
||
export default function reducer(state = initialState, action = {}) { | ||
const { type, payload } = action; | ||
switch (type) { | ||
case DELETE_ACCOUNT_REQUEST: | ||
return { | ||
...state, | ||
deleteAccountInProgress: true, | ||
deleteAccountError: null, | ||
accountDeleted: false, | ||
}; | ||
case DELETE_ACCOUNT_SUCCESS: | ||
return { ...state, deleteAccountInProgress: false, accountDeleted: true }; | ||
case DELETE_ACCOUNT_ERROR: | ||
return { | ||
...state, | ||
deleteAccountInProgress: false, | ||
deleteAccountError: payload, | ||
}; | ||
|
||
case DELETE_ACCOUNT_CLEAR: | ||
return { ...initialState }; | ||
|
||
case RESET_PASSWORD_REQUEST: | ||
return { | ||
...state, | ||
resetPasswordInProgress: true, | ||
resetPasswordError: null, | ||
}; | ||
case RESET_PASSWORD_SUCCESS: | ||
return { ...state, resetPasswordInProgress: false }; | ||
case RESET_PASSWORD_ERROR: | ||
console.error(payload); // eslint-disable-line no-console | ||
return { | ||
...state, | ||
resetPasswordInProgress: false, | ||
resetPasswordError: payload, | ||
}; | ||
|
||
default: | ||
return state; | ||
} | ||
} | ||
|
||
// ================ Action creators ================ // | ||
|
||
export const deleteAccountRequest = () => ({ type: DELETE_ACCOUNT_REQUEST }); | ||
export const deleteAccountSuccess = () => ({ type: DELETE_ACCOUNT_SUCCESS }); | ||
export const deleteAccountError = error => ({ | ||
type: DELETE_ACCOUNT_ERROR, | ||
payload: error, | ||
error: true, | ||
}); | ||
|
||
export const deleteAccountClear = () => ({ type: DELETE_ACCOUNT_CLEAR }); | ||
|
||
export const resetPasswordRequest = () => ({ type: RESET_PASSWORD_REQUEST }); | ||
|
||
export const resetPasswordSuccess = () => ({ type: RESET_PASSWORD_SUCCESS }); | ||
|
||
export const resetPasswordError = e => ({ | ||
type: RESET_PASSWORD_ERROR, | ||
error: true, | ||
payload: e, | ||
}); | ||
|
||
// ================ Thunks ================ // | ||
|
||
export const deleteAccount = params => (dispatch, getState, sdk) => { | ||
dispatch(deleteAccountRequest()); | ||
const { currentPassword } = params; | ||
|
||
return deleteUserAccount({ currentPassword }) | ||
.then(() => { | ||
dispatch(deleteAccountSuccess()); | ||
return; | ||
}) | ||
.catch(e => { | ||
dispatch(deleteAccountError(storableError(storableError(e)))); | ||
// This is thrown so that form can be cleared | ||
// after a timeout on deleteAccount submit handler | ||
throw e; | ||
}); | ||
}; | ||
|
||
export const resetPassword = email => (dispatch, getState, sdk) => { | ||
dispatch(resetPasswordRequest()); | ||
return sdk.passwordReset | ||
.request({ email }) | ||
.then(() => dispatch(resetPasswordSuccess())) | ||
.catch(e => dispatch(resetPasswordError(storableError(e)))); | ||
}; |
Oops, something went wrong.