feat(theme): Add theme updating functionality
This commit is contained in:
@ -19,14 +19,6 @@ export default function settingsController(app) {
|
|||||||
ifNoUser401,
|
ifNoUser401,
|
||||||
refetchCompletedChallenges
|
refetchCompletedChallenges
|
||||||
);
|
);
|
||||||
api.post('/update-flags', ifNoUser401, updateFlags);
|
|
||||||
api.put(
|
|
||||||
'/update-my-email',
|
|
||||||
ifNoUser401,
|
|
||||||
updateMyEmailValidators,
|
|
||||||
createValidatorErrorHandler(alertTypes.danger),
|
|
||||||
updateMyEmail
|
|
||||||
);
|
|
||||||
api.post(
|
api.post(
|
||||||
'/update-my-current-challenge',
|
'/update-my-current-challenge',
|
||||||
ifNoUser401,
|
ifNoUser401,
|
||||||
@ -51,8 +43,16 @@ export default function settingsController(app) {
|
|||||||
createValidatorErrorHandler(alertTypes.danger),
|
createValidatorErrorHandler(alertTypes.danger),
|
||||||
updateMyTheme
|
updateMyTheme
|
||||||
);
|
);
|
||||||
|
api.put(
|
||||||
|
'/update-my-email',
|
||||||
|
ifNoUser401,
|
||||||
|
updateMyEmailValidators,
|
||||||
|
createValidatorErrorHandler(alertTypes.danger),
|
||||||
|
updateMyEmail
|
||||||
|
);
|
||||||
api.put('/update-my-about', ifNoUser401, updateMyAbout);
|
api.put('/update-my-about', ifNoUser401, updateMyAbout);
|
||||||
api.put('/update-my-username', ifNoUser401, updateMyUsername);
|
api.put('/update-my-username', ifNoUser401, updateMyUsername);
|
||||||
|
api.put('/update-user-flag', ifNoUser401, updateUserFlag);
|
||||||
|
|
||||||
app.use('/internal', api);
|
app.use('/internal', api);
|
||||||
app.use(api);
|
app.use(api);
|
||||||
@ -69,19 +69,6 @@ const standardSuccessMessage = {
|
|||||||
message: 'We have updated your preferences'
|
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) {
|
function refetchCompletedChallenges(req, res, next) {
|
||||||
const { user } = req;
|
const { user } = req;
|
||||||
return user
|
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) {
|
function updateMyPortfolio(req, res, next) {
|
||||||
const {
|
const {
|
||||||
user,
|
user,
|
||||||
@ -195,7 +168,7 @@ function updateMyAbout(req, res, next) {
|
|||||||
user,
|
user,
|
||||||
body: { name, location, about, picture }
|
body: { name, location, about, picture }
|
||||||
} = req;
|
} = req;
|
||||||
log(name, location, picture, about)
|
log(name, location, picture, about);
|
||||||
return user.updateAttributes({ name, location, about, picture }, err => {
|
return user.updateAttributes({ name, location, about, picture }, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.status(500).json(standardErrorMessage);
|
res.status(500).json(standardErrorMessage);
|
||||||
@ -240,7 +213,7 @@ function createUpdateMyUsername(app) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatePrivacyTerms = (req, res) => {
|
const updatePrivacyTerms = (req, res, next) => {
|
||||||
const {
|
const {
|
||||||
user,
|
user,
|
||||||
body: { quincyEmails }
|
body: { quincyEmails }
|
||||||
@ -251,7 +224,8 @@ const updatePrivacyTerms = (req, res) => {
|
|||||||
};
|
};
|
||||||
return user.updateAttributes(update, err => {
|
return user.updateAttributes(update, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(500).json(standardErrorMessage);
|
res.status(500).json(standardErrorMessage);
|
||||||
|
return next(err);
|
||||||
}
|
}
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
type: 'success',
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ import { createSelector } from 'reselect';
|
|||||||
import { Grid, Button } from '@freecodecamp/react-bootstrap';
|
import { Grid, Button } from '@freecodecamp/react-bootstrap';
|
||||||
|
|
||||||
import { signInLoadingSelector, userSelector } from '../redux';
|
import { signInLoadingSelector, userSelector } from '../redux';
|
||||||
import { submitNewAbout } from '../redux/settings';
|
import { submitNewAbout, updateUserFlag } from '../redux/settings';
|
||||||
|
|
||||||
import Layout from '../components/Layout';
|
import Layout from '../components/Layout';
|
||||||
import Spacer from '../components/helpers/Spacer';
|
import Spacer from '../components/helpers/Spacer';
|
||||||
@ -23,6 +23,7 @@ const propTypes = {
|
|||||||
showLoading: PropTypes.bool,
|
showLoading: PropTypes.bool,
|
||||||
submitNewAbout: PropTypes.func.isRequired,
|
submitNewAbout: PropTypes.func.isRequired,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
|
toggleNightMode: PropTypes.func.isRequired,
|
||||||
username: PropTypes.string
|
username: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,7 +46,10 @@ const mapStateToProps = createSelector(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators({ submitNewAbout }, dispatch);
|
bindActionCreators(
|
||||||
|
{ submitNewAbout, toggleNightMode: theme => updateUserFlag({theme}) },
|
||||||
|
dispatch
|
||||||
|
);
|
||||||
|
|
||||||
function ShowSettings(props) {
|
function ShowSettings(props) {
|
||||||
const {
|
const {
|
||||||
@ -57,7 +61,8 @@ function ShowSettings(props) {
|
|||||||
theme,
|
theme,
|
||||||
location,
|
location,
|
||||||
name,
|
name,
|
||||||
submitNewAbout
|
submitNewAbout,
|
||||||
|
toggleNightMode
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
if (showLoading) {
|
if (showLoading) {
|
||||||
@ -104,6 +109,7 @@ function ShowSettings(props) {
|
|||||||
picture={picture}
|
picture={picture}
|
||||||
points={points}
|
points={points}
|
||||||
submitNewAbout={submitNewAbout}
|
submitNewAbout={submitNewAbout}
|
||||||
|
toggleNightMode={toggleNightMode}
|
||||||
username={username}
|
username={username}
|
||||||
/>
|
/>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
|
@ -19,6 +19,7 @@ const propTypes = {
|
|||||||
picture: PropTypes.string,
|
picture: PropTypes.string,
|
||||||
points: PropTypes.number,
|
points: PropTypes.number,
|
||||||
submitNewAbout: PropTypes.func.isRequired,
|
submitNewAbout: PropTypes.func.isRequired,
|
||||||
|
toggleNightMode: PropTypes.func.isRequired,
|
||||||
username: PropTypes.string
|
username: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,8 +125,7 @@ class AboutSettings extends Component {
|
|||||||
const {
|
const {
|
||||||
formValues: { name, location, picture, about }
|
formValues: { name, location, picture, about }
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { currentTheme, username } = this.props;
|
const { currentTheme, username, toggleNightMode } = this.props;
|
||||||
const toggleTheme = () => {};
|
|
||||||
return (
|
return (
|
||||||
<div className='about-settings'>
|
<div className='about-settings'>
|
||||||
<UsernameSettings username={username} />
|
<UsernameSettings username={username} />
|
||||||
@ -180,7 +180,7 @@ class AboutSettings extends Component {
|
|||||||
<FullWidthRow>
|
<FullWidthRow>
|
||||||
<ThemeSettings
|
<ThemeSettings
|
||||||
currentTheme={currentTheme}
|
currentTheme={currentTheme}
|
||||||
toggleNightMode={toggleTheme}
|
toggleNightMode={toggleNightMode}
|
||||||
/>
|
/>
|
||||||
</FullWidthRow>
|
</FullWidthRow>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,9 @@ export default function ThemeSettings({ currentTheme, toggleNightMode }) {
|
|||||||
</ControlLabel>
|
</ControlLabel>
|
||||||
<TB
|
<TB
|
||||||
name='night-mode'
|
name='night-mode'
|
||||||
onChange={() => toggleNightMode(currentTheme)}
|
onChange={() =>
|
||||||
|
toggleNightMode(currentTheme === 'night' ? 'default' : 'night')
|
||||||
|
}
|
||||||
value={currentTheme === 'night'}
|
value={currentTheme === 'night'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -161,17 +161,32 @@ export const reducer = handleActions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
: state,
|
: state,
|
||||||
[settingsTypes.submitNewAboutComplete]: (state, {payload}) => payload ? {
|
[settingsTypes.submitNewAboutComplete]: (state, { payload }) =>
|
||||||
...state,
|
payload
|
||||||
user: {
|
? {
|
||||||
...state.user,
|
...state,
|
||||||
[state.appUsername]: {
|
user: {
|
||||||
...state.user[state.appUsername],
|
...state.user,
|
||||||
...payload
|
[state.appUsername]: {
|
||||||
}
|
...state.user[state.appUsername],
|
||||||
}
|
...payload
|
||||||
}
|
}
|
||||||
: state
|
}
|
||||||
|
}
|
||||||
|
: state,
|
||||||
|
[settingsTypes.updateUserFlagComplete]: (state, { payload }) =>
|
||||||
|
payload
|
||||||
|
? {
|
||||||
|
...state,
|
||||||
|
user: {
|
||||||
|
...state.user,
|
||||||
|
[state.appUsername]: {
|
||||||
|
...state.user[state.appUsername],
|
||||||
|
...payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: state
|
||||||
},
|
},
|
||||||
initialState
|
initialState
|
||||||
);
|
);
|
||||||
|
@ -23,17 +23,20 @@ export const types = createTypes(
|
|||||||
[
|
[
|
||||||
...createAsyncTypes('validateUsername'),
|
...createAsyncTypes('validateUsername'),
|
||||||
...createAsyncTypes('submitNewAbout'),
|
...createAsyncTypes('submitNewAbout'),
|
||||||
...createAsyncTypes('submitNewUsername')
|
...createAsyncTypes('submitNewUsername'),
|
||||||
|
...createAsyncTypes('updateUserFlag')
|
||||||
],
|
],
|
||||||
ns
|
ns
|
||||||
);
|
);
|
||||||
|
const checkForSuccessPayload = ({ type, payload }) =>
|
||||||
|
type === 'success' ? payload : null;
|
||||||
|
|
||||||
export const sagas = [...createSettingsSagas(types)];
|
export const sagas = [...createSettingsSagas(types)];
|
||||||
|
|
||||||
export const submitNewAbout = createAction(types.submitNewAbout);
|
export const submitNewAbout = createAction(types.submitNewAbout);
|
||||||
export const submitNewAboutComplete = createAction(
|
export const submitNewAboutComplete = createAction(
|
||||||
types.submitNewAboutComplete,
|
types.submitNewAboutComplete,
|
||||||
({ type, payload }) => (type === 'success' ? payload : null)
|
checkForSuccessPayload
|
||||||
);
|
);
|
||||||
export const submitNewAboutError = createAction(types.submitNewAboutError);
|
export const submitNewAboutError = createAction(types.submitNewAboutError);
|
||||||
|
|
||||||
@ -46,6 +49,13 @@ export const submitNewUsernameError = createAction(
|
|||||||
types.submitNewUsernameError
|
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 validateUsername = createAction(types.validateUsername);
|
||||||
export const validateUsernameComplete = createAction(
|
export const validateUsernameComplete = createAction(
|
||||||
types.validateUsernameComplete
|
types.validateUsernameComplete
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { delay } from 'redux-saga';
|
import { delay } from 'redux-saga';
|
||||||
import { call, put, takeLatest } from 'redux-saga/effects';
|
import { call, put, takeLatest, takeEvery } from 'redux-saga/effects';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
updateUserFlagComplete,
|
||||||
|
updateUserFlagError,
|
||||||
validateUsernameComplete,
|
validateUsernameComplete,
|
||||||
validateUsernameError,
|
validateUsernameError,
|
||||||
submitNewAboutComplete,
|
submitNewAboutComplete,
|
||||||
@ -12,7 +14,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
getUsernameExists,
|
getUsernameExists,
|
||||||
putUpdateMyAbout,
|
putUpdateMyAbout,
|
||||||
putUpdateMyUsername
|
putUpdateMyUsername,
|
||||||
|
putUpdateUserFlag
|
||||||
} from '../../utils/ajax';
|
} from '../../utils/ajax';
|
||||||
import { createFlashMessage } from '../../components/Flash/redux';
|
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 }) {
|
function* validateUsernameSaga({ payload }) {
|
||||||
try {
|
try {
|
||||||
yield delay(500);
|
yield delay(500);
|
||||||
@ -50,6 +63,7 @@ function* validateUsernameSaga({ payload }) {
|
|||||||
|
|
||||||
export function createSettingsSagas(types) {
|
export function createSettingsSagas(types) {
|
||||||
return [
|
return [
|
||||||
|
takeEvery(types.updateUserFlag, updateUserFlagSaga),
|
||||||
takeLatest(types.submitNewAbout, submitNewAboutSaga),
|
takeLatest(types.submitNewAbout, submitNewAboutSaga),
|
||||||
takeLatest(types.submitNewUsername, submitNewUsernameSaga),
|
takeLatest(types.submitNewUsername, submitNewUsernameSaga),
|
||||||
takeLatest(types.validateUsername, validateUsernameSaga)
|
takeLatest(types.validateUsername, validateUsernameSaga)
|
||||||
|
@ -48,6 +48,10 @@ export function putUpdateMyUsername(username) {
|
|||||||
return put('/update-my-username', { username });
|
return put('/update-my-username', { username });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function putUpdateUserFlag(update) {
|
||||||
|
return put('/update-user-flag', update);
|
||||||
|
}
|
||||||
|
|
||||||
export function putUserAcceptsTerms(quincyEmails) {
|
export function putUserAcceptsTerms(quincyEmails) {
|
||||||
return put('/update-privacy-terms', { quincyEmails });
|
return put('/update-privacy-terms', { quincyEmails });
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user