feat(username): Add Username updating

This commit is contained in:
Bouncey
2018-09-13 18:28:23 +01:00
committed by Stuart Taylor
parent 99e025699a
commit 4f54803674
14 changed files with 807 additions and 171 deletions

View File

@@ -8,6 +8,8 @@ import { createReportUserSaga } from './report-user-saga';
import { createShowCertSaga } from './show-cert-saga';
import { createUpdateMyEmailSaga } from './update-email-saga';
import { types as settingsTypes } from './settings';
const ns = 'app';
const defaultFetchState = {
@@ -74,6 +76,9 @@ export const updateMyEmailError = createAction(types.updateMyEmailError);
export const isSignedInSelector = state => !!Object.keys(state[ns].user).length;
export const signInLoadingSelector = state =>
userFetchStateSelector(state).pending;
export const showCertSelector = state => state[ns].showCert;
export const showCertFetchStateSelector = state => state[ns].showCertFetchState;
@@ -83,7 +88,11 @@ export const userByNameSelector = username => state => {
};
export const userFetchStateSelector = state => state[ns].userFetchState;
export const usernameSelector = state => state[ns].appUsername;
export const userSelector = state => state[ns].user;
export const userSelector = state => {
const username = usernameSelector(state);
return state[ns].user[username] || {};
};
export const reducer = handleActions(
{
@@ -93,7 +102,10 @@ export const reducer = handleActions(
}),
[types.fetchUserComplete]: (state, { payload: { user, username } }) => ({
...state,
user,
user: {
...state.user,
[username]: user
},
appUsername: username,
userFetchState: {
pending: false,
@@ -135,7 +147,20 @@ export const reducer = handleActions(
errored: true,
error: payload
}
})
}),
[settingsTypes.submitNewUsernameComplete]: (state, { payload }) =>
payload
? {
...state,
user: {
...state.user,
[state.appUsername]: {
...state.user[state.appUsername],
username: payload
}
}
}
: state
},
initialState
);

View File

@@ -2,8 +2,10 @@ import { combineReducers } from 'redux';
import { reducer as app } from './';
import { reducer as flash } from '../components/Flash/redux';
import { reducer as settings } from './settings';
export default combineReducers({
app,
flash
flash,
settings
});

View File

@@ -1,7 +1,8 @@
import { all } from 'redux-saga/effects';
import { sagas as appSagas } from './';
import { sagas as settingsSagas } from './settings';
export default function* rootSaga() {
yield all([...appSagas]);
yield all([...appSagas, ...settingsSagas]);
}

View File

@@ -0,0 +1,73 @@
import { createAction, handleActions } from 'redux-actions';
import { createTypes, createAsyncTypes } from '../../utils/createTypes';
import { createSettingsSagas } from './settings-sagas';
const ns = 'settings';
const defaultFetchState = {
pending: false,
complete: false,
errored: false,
error: null
};
const initialState = {
usernameValidation: {
isValidUsername: false,
fetchState: { ...defaultFetchState }
}
};
export const types = createTypes(
[
...createAsyncTypes('validateUsername'),
...createAsyncTypes('submitNewUsername')
],
ns
);
export const sagas = [...createSettingsSagas(types)];
export const submitNewUsername = createAction(types.submitNewUsername);
export const submitNewUsernameComplete = createAction(
types.submitNewUsernameComplete,
({ type, username }) => (type === 'success' ? username : null)
);
export const submitNewUsernameError = createAction(
types.submitNewUsernameError
);
export const validateUsername = createAction(types.validateUsername);
export const validateUsernameComplete = createAction(
types.validateUsernameComplete
);
export const validateUsernameError = createAction(types.validateUsernameError);
export const usernameValidationSelector = state => state[ns].usernameValidation;
export const reducer = handleActions(
{
[types.submitNewUsernameComplete]: state => ({
...state,
usernameValidation: { ...initialState.usernameValidation }
}),
[types.validateUsername]: state => ({
...state,
usernameValidation: {
...state.usernameValidation,
isValidUsername: false,
fetchState: { ...defaultFetchState, pending: true }
}
}),
[types.validateUsernameComplete]: (state, { payload }) => ({
...state,
usernameValidation: {
...state.usernameValidation,
isValidUsername: !payload,
fetchState: { ...defaultFetchState, pending: false, complete: true }
}
})
},
initialState
);

View File

@@ -0,0 +1,41 @@
import { delay } from 'redux-saga';
import { call, put, takeLatest } from 'redux-saga/effects';
import {
validateUsernameComplete,
validateUsernameError,
submitNewUsernameComplete,
submitNewUsernameError
} from './';
import { getUsernameExists, putUpdateMyUsername } from '../../utils/ajax';
import { createFlashMessage } from '../../components/Flash/redux';
function* validateUsernameSaga({ payload }) {
try {
yield delay(500);
const {
data: { exists }
} = yield call(getUsernameExists, payload);
yield put(validateUsernameComplete(exists));
} catch (e) {
yield put(validateUsernameError(e));
}
}
function* submitNEwUswernameSaga({ payload: username }) {
try {
const { data: response } = yield call(putUpdateMyUsername, username);
yield put(submitNewUsernameComplete({...response, username}));
yield put(createFlashMessage(response));
} catch (e) {
yield put(submitNewUsernameError(e));
}
}
export function createSettingsSagas(types) {
return [
takeLatest(types.validateUsername, validateUsernameSaga),
takeLatest(types.submitNewUsername, submitNEwUswernameSaga)
];
}