Commit 76ec4c90 authored by Eric Rosenbaum's avatar Eric Rosenbaum

More error handling, moved to confirmation step

parent a305a096
...@@ -101,6 +101,7 @@ ...@@ -101,6 +101,7 @@
"studio.transfer.forgotPassword": "Forgot password?", "studio.transfer.forgotPassword": "Forgot password?",
"studio.transfer.alert.somethingWentWrong": "Something went wrong transferring this studio to a new host.", "studio.transfer.alert.somethingWentWrong": "Something went wrong transferring this studio to a new host.",
"studio.transfer.alert.wasntTheRightPassword": "Hmm, that wasn’t the right password.", "studio.transfer.alert.wasntTheRightPassword": "Hmm, that wasn’t the right password.",
"studio.transfer.alert.thisUserCannotBecomeHost": "This user cannot become the host — try transfering to another manager",
"studio.remove": "Remove", "studio.remove": "Remove",
"studio.promote": "Promote", "studio.promote": "Promote",
......
...@@ -15,6 +15,7 @@ const Errors = keyMirror({ ...@@ -15,6 +15,7 @@ const Errors = keyMirror({
UNKNOWN_USERNAME: null, UNKNOWN_USERNAME: null,
RATE_LIMIT: null, RATE_LIMIT: null,
MANAGER_LIMIT: null, MANAGER_LIMIT: null,
CONFLICT: null,
UNHANDLED: null UNHANDLED: null
}); });
...@@ -28,6 +29,7 @@ const normalizeError = (err, body, res) => { ...@@ -28,6 +29,7 @@ const normalizeError = (err, body, res) => {
if (res.statusCode === 403 && body.mute_status) return Errors.USER_MUTED; if (res.statusCode === 403 && body.mute_status) return Errors.USER_MUTED;
if (res.statusCode === 401 || res.statusCode === 403) return Errors.PERMISSION; if (res.statusCode === 401 || res.statusCode === 403) return Errors.PERMISSION;
if (res.statusCode === 404) return Errors.UNKNOWN_USERNAME; if (res.statusCode === 404) return Errors.UNKNOWN_USERNAME;
if (res.statusCode === 409) return Errors.CONFLICT;
if (res.statusCode === 429) return Errors.RATE_LIMIT; if (res.statusCode === 429) return Errors.RATE_LIMIT;
if (res.statusCode !== 200) return Errors.SERVER; if (res.statusCode !== 200) return Errors.SERVER;
if (body && body.status === 'error') { if (body && body.status === 'error') {
......
...@@ -2,6 +2,7 @@ import React, {useState} from 'react'; ...@@ -2,6 +2,7 @@ import React, {useState} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
const {injectIntl, intlShape} = require('react-intl');
import ModalInnerContent from '../../../components/modal/base/modal-inner-content.jsx'; import ModalInnerContent from '../../../components/modal/base/modal-inner-content.jsx';
...@@ -11,11 +12,16 @@ import ValidationMessage from '../../../components/forms/validation-message.jsx' ...@@ -11,11 +12,16 @@ import ValidationMessage from '../../../components/forms/validation-message.jsx'
import {managers} from '../lib/redux-modules'; import {managers} from '../lib/redux-modules';
import {useAlertContext} from '../../../components/alert/alert-context';
import {Errors, transferHost} from '../lib/studio-member-actions';
import './transfer-host-modal.scss'; import './transfer-host-modal.scss';
const TransferHostConfirmation = ({ const TransferHostConfirmation = ({
handleBack, handleBack,
handleTransfer, handleClose,
handleTransferHost,
intl,
items, items,
hostId, hostId,
selectedId selectedId
...@@ -25,12 +31,45 @@ const TransferHostConfirmation = ({ ...@@ -25,12 +31,45 @@ const TransferHostConfirmation = ({
const newHostUsername = items.find(item => item.id === selectedId).username; const newHostUsername = items.find(item => item.id === selectedId).username;
const newHostImage = items.find(item => item.id === selectedId).profile.images['90x90']; const newHostImage = items.find(item => item.id === selectedId).profile.images['90x90'];
const [passwordInputValue, setPasswordInputValue] = useState(''); const [passwordInputValue, setPasswordInputValue] = useState('');
const [validationError, setValidationError] = useState(null);
const {errorAlert, successAlert} = useAlertContext();
const errorToMessageId = error => {
switch (error) {
case Errors.RATE_LIMIT: return 'studio.alertTransferRateLimit';
case Errors.CONFLICT: return 'studio.transfer.alert.thisUserCannotBecomeHost';
default: return 'studio.transfer.alert.somethingWentWrong';
}
};
const handleSubmit = () => { const handleSubmit = () => {
handleTransfer(passwordInputValue, newHostUsername, selectedId); handleTransferHost(passwordInputValue, newHostUsername, selectedId)
.then(() => {
handleClose();
successAlert({
id: 'studio.alertTransfer',
values: {name: newHostUsername}
});
})
.catch(e => {
// For password errors, show validation alert without closing the modal
if (e === Errors.PERMISSION) {
setValidationError(e);
return;
}
// For other errors, close the modal and show an alert
handleClose();
errorAlert({
id: errorToMessageId(e)
});
});
}; };
const handleChangePasswordInput = e => { const handleChangePasswordInput = e => {
setPasswordInputValue(e.target.value); setPasswordInputValue(e.target.value);
setValidationError(null);
}; };
return ( return (
<ModalInnerContent> <ModalInnerContent>
<div className="transfer-outcome"> <div className="transfer-outcome">
...@@ -84,11 +123,11 @@ const TransferHostConfirmation = ({ ...@@ -84,11 +123,11 @@ const TransferHostConfirmation = ({
value={passwordInputValue} value={passwordInputValue}
onChange={handleChangePasswordInput} // eslint-disable-line react/jsx-no-bind onChange={handleChangePasswordInput} // eslint-disable-line react/jsx-no-bind
/> />
<ValidationMessage {validationError && <ValidationMessage
className="transfer-password-validation" className="transfer-password-validation"
message={<FormattedMessage id="studio.transfer.alert.wasntTheRightPassword" />} message={intl.formatMessage({id: 'studio.transfer.alert.wasntTheRightPassword'})}
mode="error" mode="error"
/> />}
</div> </div>
<div className="transfer-forgot-link"> <div className="transfer-forgot-link">
<a <a
...@@ -122,7 +161,8 @@ const TransferHostConfirmation = ({ ...@@ -122,7 +161,8 @@ const TransferHostConfirmation = ({
TransferHostConfirmation.propTypes = { TransferHostConfirmation.propTypes = {
handleBack: PropTypes.func, handleBack: PropTypes.func,
handleTransfer: PropTypes.func, handleClose: PropTypes.func,
intl: intlShape,
items: PropTypes.arrayOf(PropTypes.shape({ items: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.id, id: PropTypes.id,
username: PropTypes.string, username: PropTypes.string,
...@@ -132,13 +172,18 @@ TransferHostConfirmation.propTypes = { ...@@ -132,13 +172,18 @@ TransferHostConfirmation.propTypes = {
}) })
}) })
})), })),
handleTransferHost: PropTypes.func,
selectedId: PropTypes.number, selectedId: PropTypes.number,
hostId: PropTypes.number hostId: PropTypes.number
}; };
export default connect( const connectedConfirmationStep = connect(
state => ({ state => ({
hostId: state.studio.owner, hostId: state.studio.owner,
...managers.selector(state) ...managers.selector(state)
}) }), {
handleTransferHost: transferHost
}
)(TransferHostConfirmation); )(TransferHostConfirmation);
export default injectIntl(connectedConfirmationStep);
...@@ -19,8 +19,7 @@ const STEPS = keyMirror({ ...@@ -19,8 +19,7 @@ const STEPS = keyMirror({
}); });
const TransferHostModal = ({ const TransferHostModal = ({
handleClose, handleClose
handleTransfer
}) => { }) => {
const [step, setStep] = useState(STEPS.info); const [step, setStep] = useState(STEPS.info);
const [selectedId, setSelectedId] = useState(null); const [selectedId, setSelectedId] = useState(null);
...@@ -47,15 +46,13 @@ const TransferHostModal = ({ ...@@ -47,15 +46,13 @@ const TransferHostModal = ({
{step === STEPS.confirmation && <TransferHostConfirmation {step === STEPS.confirmation && <TransferHostConfirmation
handleClose={handleClose} handleClose={handleClose}
handleBack={() => setStep(STEPS.selection)} // eslint-disable-line react/jsx-no-bind handleBack={() => setStep(STEPS.selection)} // eslint-disable-line react/jsx-no-bind
handleTransfer={handleTransfer}
selectedId={selectedId} selectedId={selectedId}
/>} />}
</Modal>); </Modal>);
}; };
TransferHostModal.propTypes = { TransferHostModal.propTypes = {
handleClose: PropTypes.func, handleClose: PropTypes.func
handleTransfer: PropTypes.func
}; };
export default TransferHostModal; export default TransferHostModal;
...@@ -18,8 +18,7 @@ import { ...@@ -18,8 +18,7 @@ import {
Errors, Errors,
promoteCurator, promoteCurator,
removeCurator, removeCurator,
removeManager, removeManager
transferHost
} from './lib/studio-member-actions'; } from './lib/studio-member-actions';
import {selectStudioHasReachedManagerLimit} from '../../redux/studio'; import {selectStudioHasReachedManagerLimit} from '../../redux/studio';
...@@ -30,7 +29,7 @@ import removeIcon from './icons/remove-icon.svg'; ...@@ -30,7 +29,7 @@ import removeIcon from './icons/remove-icon.svg';
import promoteIcon from './icons/curator-icon.svg'; import promoteIcon from './icons/curator-icon.svg';
const StudioMemberTile = ({ const StudioMemberTile = ({
canRemove, canPromote, onRemove, canTransferHost, onPromote, onTransferHost, canRemove, canPromote, onRemove, canTransferHost, onPromote,
isCreator, hasReachedManagerLimit, // mapState props isCreator, hasReachedManagerLimit, // mapState props
username, image // own props username, image // own props
}) => { }) => {
...@@ -135,22 +134,6 @@ const StudioMemberTile = ({ ...@@ -135,22 +134,6 @@ const StudioMemberTile = ({
{transferHostModalOpen && {transferHostModalOpen &&
<TransferHostModal <TransferHostModal
handleClose={() => setTransferHostModalOpen(false)} handleClose={() => setTransferHostModalOpen(false)}
handleTransfer={(password, newHostUsername, newHostUsernameId) => {
onTransferHost(password, newHostUsername, newHostUsernameId)
.then(() => {
setTransferHostModalOpen(false);
successAlert({
id: 'studio.alertTransfer',
values: {name: newHostUsername}
});
})
.catch(() => {
setTransferHostModalOpen(false);
errorAlert({
id: 'studio.transfer.alert.somethingWentWrong'
});
});
}}
/> />
} }
</div> </div>
...@@ -163,7 +146,6 @@ StudioMemberTile.propTypes = { ...@@ -163,7 +146,6 @@ StudioMemberTile.propTypes = {
canTransferHost: PropTypes.bool, canTransferHost: PropTypes.bool,
onRemove: PropTypes.func, onRemove: PropTypes.func,
onPromote: PropTypes.func, onPromote: PropTypes.func,
onTransferHost: PropTypes.func,
username: PropTypes.string, username: PropTypes.string,
image: PropTypes.string, image: PropTypes.string,
isCreator: PropTypes.bool, isCreator: PropTypes.bool,
...@@ -179,8 +161,7 @@ const ManagerTile = connect( ...@@ -179,8 +161,7 @@ const ManagerTile = connect(
isCreator: state.studio.owner === ownProps.id isCreator: state.studio.owner === ownProps.id
}), }),
{ {
onRemove: removeManager, onRemove: removeManager
onTransferHost: transferHost
} }
)(StudioMemberTile); )(StudioMemberTile);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment