diff --git a/api-server/server/boot/settings.js b/api-server/server/boot/settings.js index b2911bedef..87e6e9c4ca 100644 --- a/api-server/server/boot/settings.js +++ b/api-server/server/boot/settings.js @@ -19,14 +19,6 @@ export default function settingsController(app) { ifNoUser401, refetchCompletedChallenges ); - api.post('/update-flags', ifNoUser401, updateFlags); - api.put( - '/update-my-email', - ifNoUser401, - updateMyEmailValidators, - createValidatorErrorHandler(alertTypes.danger), - updateMyEmail - ); api.post( '/update-my-current-challenge', ifNoUser401, @@ -51,8 +43,16 @@ export default function settingsController(app) { createValidatorErrorHandler(alertTypes.danger), updateMyTheme ); + api.put( + '/update-my-email', + ifNoUser401, + updateMyEmailValidators, + createValidatorErrorHandler(alertTypes.danger), + updateMyEmail + ); api.put('/update-my-about', ifNoUser401, updateMyAbout); api.put('/update-my-username', ifNoUser401, updateMyUsername); + api.put('/update-user-flag', ifNoUser401, updateUserFlag); app.use('/internal', api); app.use(api); @@ -69,19 +69,6 @@ const standardSuccessMessage = { message: 'We have updated your preferences' }; -const toggleUserFlag = (flag, req, res, next) => { - const { user } = req; - const currentValue = user[flag]; - return user.update$({ [flag]: !currentValue }).subscribe( - () => - res.status(200).json({ - flag, - value: !currentValue - }), - next - ); -}; - function refetchCompletedChallenges(req, res, next) { const { user } = req; return user @@ -142,20 +129,6 @@ function updateMyTheme(req, res, next) { ); } -function updateFlags(req, res, next) { - const { - user, - body: { values } - } = req; - const keys = Object.keys(values); - if (keys.length === 1 && typeof keys[0] === 'boolean') { - return toggleUserFlag(keys[0], req, res, next); - } - return user - .requestUpdateFlags(values) - .subscribe(message => res.json({ message }), next); -} - function updateMyPortfolio(req, res, next) { const { user, @@ -195,7 +168,7 @@ function updateMyAbout(req, res, next) { user, body: { name, location, about, picture } } = req; - log(name, location, picture, about) + log(name, location, picture, about); return user.updateAttributes({ name, location, about, picture }, err => { if (err) { res.status(500).json(standardErrorMessage); @@ -240,7 +213,7 @@ function createUpdateMyUsername(app) { }; } -const updatePrivacyTerms = (req, res) => { +const updatePrivacyTerms = (req, res, next) => { const { user, body: { quincyEmails } @@ -251,7 +224,8 @@ const updatePrivacyTerms = (req, res) => { }; return user.updateAttributes(update, err => { if (err) { - return res.status(500).json(standardErrorMessage); + res.status(500).json(standardErrorMessage); + return next(err); } return res.status(200).json({ type: 'success', @@ -261,3 +235,14 @@ const updatePrivacyTerms = (req, res) => { }); }); }; + +function updateUserFlag(req, res, next) { + const { user, body: update } = req; + user.updateAttributes(update, err => { + if (err) { + res.status(500).json(standardErrorMessage); + return next(err); + } + return res.status(200).json(standardSuccessMessage); + }); +} diff --git a/client/src/client-only-routes/ShowSettings.js b/client/src/client-only-routes/ShowSettings.js index 94b49fd9d7..962cef94e7 100644 --- a/client/src/client-only-routes/ShowSettings.js +++ b/client/src/client-only-routes/ShowSettings.js @@ -6,7 +6,7 @@ import { createSelector } from 'reselect'; import { Grid, Button } from '@freecodecamp/react-bootstrap'; import { signInLoadingSelector, userSelector } from '../redux'; -import { submitNewAbout } from '../redux/settings'; +import { submitNewAbout, updateUserFlag } from '../redux/settings'; import Layout from '../components/Layout'; import Spacer from '../components/helpers/Spacer'; @@ -23,6 +23,7 @@ const propTypes = { showLoading: PropTypes.bool, submitNewAbout: PropTypes.func.isRequired, theme: PropTypes.string, + toggleNightMode: PropTypes.func.isRequired, username: PropTypes.string }; @@ -45,7 +46,10 @@ const mapStateToProps = createSelector( ); const mapDispatchToProps = dispatch => - bindActionCreators({ submitNewAbout }, dispatch); + bindActionCreators( + { submitNewAbout, toggleNightMode: theme => updateUserFlag({theme}) }, + dispatch + ); function ShowSettings(props) { const { @@ -57,7 +61,8 @@ function ShowSettings(props) { theme, location, name, - submitNewAbout + submitNewAbout, + toggleNightMode } = props; if (showLoading) { @@ -104,6 +109,7 @@ function ShowSettings(props) { picture={picture} points={points} submitNewAbout={submitNewAbout} + toggleNightMode={toggleNightMode} username={username} /> diff --git a/client/src/components/settings/About.js b/client/src/components/settings/About.js index 59ca790dfe..d4d79b7b05 100644 --- a/client/src/components/settings/About.js +++ b/client/src/components/settings/About.js @@ -19,6 +19,7 @@ const propTypes = { picture: PropTypes.string, points: PropTypes.number, submitNewAbout: PropTypes.func.isRequired, + toggleNightMode: PropTypes.func.isRequired, username: PropTypes.string }; @@ -124,8 +125,7 @@ class AboutSettings extends Component { const { formValues: { name, location, picture, about } } = this.state; - const { currentTheme, username } = this.props; - const toggleTheme = () => {}; + const { currentTheme, username, toggleNightMode } = this.props; return (
@@ -180,7 +180,7 @@ class AboutSettings extends Component {
diff --git a/client/src/components/settings/Theme.js b/client/src/components/settings/Theme.js index adf6975103..32d88a4d2e 100644 --- a/client/src/components/settings/Theme.js +++ b/client/src/components/settings/Theme.js @@ -19,7 +19,9 @@ export default function ThemeSettings({ currentTheme, toggleNightMode }) { toggleNightMode(currentTheme)} + onChange={() => + toggleNightMode(currentTheme === 'night' ? 'default' : 'night') + } value={currentTheme === 'night'} /> diff --git a/client/src/redux/index.js b/client/src/redux/index.js index 4e26ca7895..f7c18f58a9 100644 --- a/client/src/redux/index.js +++ b/client/src/redux/index.js @@ -161,17 +161,32 @@ export const reducer = handleActions( } } : state, - [settingsTypes.submitNewAboutComplete]: (state, {payload}) => payload ? { - ...state, - user: { - ...state.user, - [state.appUsername]: { - ...state.user[state.appUsername], - ...payload - } - } - } - : state + [settingsTypes.submitNewAboutComplete]: (state, { payload }) => + payload + ? { + ...state, + user: { + ...state.user, + [state.appUsername]: { + ...state.user[state.appUsername], + ...payload + } + } + } + : state, + [settingsTypes.updateUserFlagComplete]: (state, { payload }) => + payload + ? { + ...state, + user: { + ...state.user, + [state.appUsername]: { + ...state.user[state.appUsername], + ...payload + } + } + } + : state }, initialState ); diff --git a/client/src/redux/settings/index.js b/client/src/redux/settings/index.js index 69b50f8e1c..41f2dd3706 100644 --- a/client/src/redux/settings/index.js +++ b/client/src/redux/settings/index.js @@ -23,17 +23,20 @@ export const types = createTypes( [ ...createAsyncTypes('validateUsername'), ...createAsyncTypes('submitNewAbout'), - ...createAsyncTypes('submitNewUsername') + ...createAsyncTypes('submitNewUsername'), + ...createAsyncTypes('updateUserFlag') ], ns ); +const checkForSuccessPayload = ({ type, payload }) => + type === 'success' ? payload : null; export const sagas = [...createSettingsSagas(types)]; export const submitNewAbout = createAction(types.submitNewAbout); export const submitNewAboutComplete = createAction( types.submitNewAboutComplete, - ({ type, payload }) => (type === 'success' ? payload : null) + checkForSuccessPayload ); export const submitNewAboutError = createAction(types.submitNewAboutError); @@ -46,6 +49,13 @@ export const submitNewUsernameError = createAction( types.submitNewUsernameError ); +export const updateUserFlag = createAction(types.updateUserFlag); +export const updateUserFlagComplete = createAction( + types.updateUserFlagComplete, + checkForSuccessPayload +); +export const updateUserFlagError = createAction(types.updateUserFlagError); + export const validateUsername = createAction(types.validateUsername); export const validateUsernameComplete = createAction( types.validateUsernameComplete diff --git a/client/src/redux/settings/settings-sagas.js b/client/src/redux/settings/settings-sagas.js index 6488a92ce7..3cf07c98e3 100644 --- a/client/src/redux/settings/settings-sagas.js +++ b/client/src/redux/settings/settings-sagas.js @@ -1,7 +1,9 @@ import { delay } from 'redux-saga'; -import { call, put, takeLatest } from 'redux-saga/effects'; +import { call, put, takeLatest, takeEvery } from 'redux-saga/effects'; import { + updateUserFlagComplete, + updateUserFlagError, validateUsernameComplete, validateUsernameError, submitNewAboutComplete, @@ -12,7 +14,8 @@ import { import { getUsernameExists, putUpdateMyAbout, - putUpdateMyUsername + putUpdateMyUsername, + putUpdateUserFlag } from '../../utils/ajax'; import { createFlashMessage } from '../../components/Flash/redux'; @@ -36,6 +39,16 @@ function* submitNewUsernameSaga({ payload: username }) { } } +function* updateUserFlagSaga({ payload: update }) { + try { + const { data: response } = yield call(putUpdateUserFlag, update); + yield put(updateUserFlagComplete({ ...response, payload: update })); + yield put(createFlashMessage(response)); + } catch (e) { + yield put(updateUserFlagError(e)); + } +} + function* validateUsernameSaga({ payload }) { try { yield delay(500); @@ -50,6 +63,7 @@ function* validateUsernameSaga({ payload }) { export function createSettingsSagas(types) { return [ + takeEvery(types.updateUserFlag, updateUserFlagSaga), takeLatest(types.submitNewAbout, submitNewAboutSaga), takeLatest(types.submitNewUsername, submitNewUsernameSaga), takeLatest(types.validateUsername, validateUsernameSaga) diff --git a/client/src/utils/ajax.js b/client/src/utils/ajax.js index b12a3121d5..841c7b41d1 100644 --- a/client/src/utils/ajax.js +++ b/client/src/utils/ajax.js @@ -48,6 +48,10 @@ export function putUpdateMyUsername(username) { return put('/update-my-username', { username }); } +export function putUpdateUserFlag(update) { + return put('/update-user-flag', update); +} + export function putUserAcceptsTerms(quincyEmails) { return put('/update-privacy-terms', { quincyEmails }); }