feat(privacy): Add privacy settings
This commit is contained in:
@ -232,6 +232,7 @@
|
|||||||
"isLocked": true,
|
"isLocked": true,
|
||||||
"showAbout": false,
|
"showAbout": false,
|
||||||
"showCerts": false,
|
"showCerts": false,
|
||||||
|
"showDonation": false,
|
||||||
"showHeatMap": false,
|
"showHeatMap": false,
|
||||||
"showLocation": false,
|
"showLocation": false,
|
||||||
"showName": false,
|
"showName": false,
|
||||||
|
@ -34,7 +34,6 @@ export default function settingsController(app) {
|
|||||||
updateMyCurrentChallenge
|
updateMyCurrentChallenge
|
||||||
);
|
);
|
||||||
api.post('/update-my-portfolio', ifNoUser401, updateMyPortfolio);
|
api.post('/update-my-portfolio', ifNoUser401, updateMyPortfolio);
|
||||||
api.post('/update-my-profile-ui', ifNoUser401, updateMyProfileUI);
|
|
||||||
api.post('/update-my-projects', ifNoUser401, updateMyProjects);
|
api.post('/update-my-projects', ifNoUser401, updateMyProjects);
|
||||||
api.post(
|
api.post(
|
||||||
'/update-my-theme',
|
'/update-my-theme',
|
||||||
@ -43,6 +42,7 @@ export default function settingsController(app) {
|
|||||||
createValidatorErrorHandler(alertTypes.danger),
|
createValidatorErrorHandler(alertTypes.danger),
|
||||||
updateMyTheme
|
updateMyTheme
|
||||||
);
|
);
|
||||||
|
api.put('/update-my-about', ifNoUser401, updateMyAbout);
|
||||||
api.put(
|
api.put(
|
||||||
'/update-my-email',
|
'/update-my-email',
|
||||||
ifNoUser401,
|
ifNoUser401,
|
||||||
@ -50,7 +50,7 @@ export default function settingsController(app) {
|
|||||||
createValidatorErrorHandler(alertTypes.danger),
|
createValidatorErrorHandler(alertTypes.danger),
|
||||||
updateMyEmail
|
updateMyEmail
|
||||||
);
|
);
|
||||||
api.put('/update-my-about', ifNoUser401, updateMyAbout);
|
api.put('/update-my-profileui', ifNoUser401, updateMyProfileUI);
|
||||||
api.put('/update-my-username', ifNoUser401, updateMyUsername);
|
api.put('/update-my-username', ifNoUser401, updateMyUsername);
|
||||||
api.put('/update-user-flag', ifNoUser401, updateUserFlag);
|
api.put('/update-user-flag', ifNoUser401, updateUserFlag);
|
||||||
|
|
||||||
@ -69,6 +69,14 @@ const standardSuccessMessage = {
|
|||||||
message: 'We have updated your preferences'
|
message: 'We have updated your preferences'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createStandardHandler = (req, res, next) => err => {
|
||||||
|
if (err) {
|
||||||
|
res.status(500).json(standardErrorMessage);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
return res.status(200).json(standardSuccessMessage);
|
||||||
|
};
|
||||||
|
|
||||||
function refetchCompletedChallenges(req, res, next) {
|
function refetchCompletedChallenges(req, res, next) {
|
||||||
const { user } = req;
|
const { user } = req;
|
||||||
return user
|
return user
|
||||||
@ -148,9 +156,11 @@ function updateMyProfileUI(req, res, next) {
|
|||||||
user,
|
user,
|
||||||
body: { profileUI }
|
body: { profileUI }
|
||||||
} = req;
|
} = req;
|
||||||
return user
|
user.updateAttribute(
|
||||||
.updateMyProfileUI(profileUI)
|
'profileUI',
|
||||||
.subscribe(message => res.json({ message }), next);
|
profileUI,
|
||||||
|
createStandardHandler(req, res, next)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMyProjects(req, res, next) {
|
function updateMyProjects(req, res, next) {
|
||||||
@ -169,13 +179,10 @@ function updateMyAbout(req, res, next) {
|
|||||||
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(
|
||||||
if (err) {
|
{ name, location, about, picture },
|
||||||
res.status(500).json(standardErrorMessage);
|
createStandardHandler(req, res, next)
|
||||||
return next(err);
|
);
|
||||||
}
|
|
||||||
return res.status(200).json(standardSuccessMessage);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createUpdateMyUsername(app) {
|
function createUpdateMyUsername(app) {
|
||||||
@ -238,11 +245,5 @@ const updatePrivacyTerms = (req, res, next) => {
|
|||||||
|
|
||||||
function updateUserFlag(req, res, next) {
|
function updateUserFlag(req, res, next) {
|
||||||
const { user, body: update } = req;
|
const { user, body: update } = req;
|
||||||
user.updateAttributes(update, err => {
|
user.updateAttributes(update, createStandardHandler(req, res, next));
|
||||||
if (err) {
|
|
||||||
res.status(500).json(standardErrorMessage);
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
return res.status(200).json(standardSuccessMessage);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import Spacer from '../components/helpers/Spacer';
|
|||||||
import Loader from '../components/helpers/Loader';
|
import Loader from '../components/helpers/Loader';
|
||||||
import { FullWidthRow } from '../components/helpers';
|
import { FullWidthRow } from '../components/helpers';
|
||||||
import About from '../components/settings/About';
|
import About from '../components/settings/About';
|
||||||
|
import Privacy from '../components/settings/Privacy';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
about: PropTypes.string,
|
about: PropTypes.string,
|
||||||
@ -117,9 +118,9 @@ function ShowSettings(props) {
|
|||||||
username={username}
|
username={username}
|
||||||
/>
|
/>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
{/* <PrivacySettings />
|
<Privacy />
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<EmailSettings />
|
{/* <EmailSettings />
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<InternetSettings />
|
<InternetSettings />
|
||||||
<Spacer />
|
<Spacer />
|
||||||
|
221
client/src/components/settings/Privacy.js
Normal file
221
client/src/components/settings/Privacy.js
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import { Button, Form } from '@freecodecamp/react-bootstrap';
|
||||||
|
import { isEqual } from 'lodash';
|
||||||
|
|
||||||
|
import { userSelector } from '../../redux';
|
||||||
|
import { submitProfileUI } from '../../redux/settings';
|
||||||
|
|
||||||
|
import FullWidthRow from '../helpers/FullWidthRow';
|
||||||
|
import Spacer from '../helpers/Spacer';
|
||||||
|
import ToggleSetting from './ToggleSetting';
|
||||||
|
import SectionHeader from './SectionHeader';
|
||||||
|
|
||||||
|
const mapStateToProps = createSelector(userSelector, user => ({
|
||||||
|
...user.profileUI,
|
||||||
|
user
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch =>
|
||||||
|
bindActionCreators({ submitProfileUI }, dispatch);
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
isLocked: PropTypes.bool,
|
||||||
|
showAbout: PropTypes.bool,
|
||||||
|
showCerts: PropTypes.bool,
|
||||||
|
showDonation: PropTypes.bool,
|
||||||
|
showHeatMap: PropTypes.bool,
|
||||||
|
showLocation: PropTypes.bool,
|
||||||
|
showName: PropTypes.bool,
|
||||||
|
showPoints: PropTypes.bool,
|
||||||
|
showPortfolio: PropTypes.bool,
|
||||||
|
showTimeLine: PropTypes.bool,
|
||||||
|
submitProfileUI: PropTypes.func.isRequired,
|
||||||
|
user: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
class PrivacySettings extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
const originalProfileUI = { ...props.user.profileUI };
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
privacyValues: {
|
||||||
|
...originalProfileUI
|
||||||
|
},
|
||||||
|
originalProfileUI: { ...originalProfileUI }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
const { profileUI: currentPropsProfileUI } = this.props.user;
|
||||||
|
const { originalProfileUI } = this.state;
|
||||||
|
if (!isEqual(originalProfileUI, currentPropsProfileUI)) {
|
||||||
|
/* eslint-disable-next-line react/no-did-update-set-state */
|
||||||
|
return this.setState(state => ({
|
||||||
|
...state,
|
||||||
|
originalProfileUI: { ...currentPropsProfileUI },
|
||||||
|
privacyValues: { ...currentPropsProfileUI }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit = e => e.preventDefault();
|
||||||
|
|
||||||
|
toggleFlag = flag => () =>
|
||||||
|
this.setState(
|
||||||
|
state => ({
|
||||||
|
privacyValues: {
|
||||||
|
...state.privacyValues,
|
||||||
|
[flag]: !state.privacyValues[flag]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
() => this.props.submitProfileUI(this.state.privacyValues)
|
||||||
|
);
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
privacyValues: {
|
||||||
|
isLocked = true,
|
||||||
|
showAbout = false,
|
||||||
|
showCerts = false,
|
||||||
|
showDonation = false,
|
||||||
|
showHeatMap = false,
|
||||||
|
showLocation = false,
|
||||||
|
showName = false,
|
||||||
|
showPoints = false,
|
||||||
|
showPortfolio = false,
|
||||||
|
showTimeLine = false
|
||||||
|
}
|
||||||
|
} = this.state;
|
||||||
|
const { user } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='privacy-settings'>
|
||||||
|
<SectionHeader>Privacy Settings</SectionHeader>
|
||||||
|
<FullWidthRow>
|
||||||
|
<p>
|
||||||
|
The settings in this section enable you to control what is shown on
|
||||||
|
your freeCodeCamp public portfolio.
|
||||||
|
</p>
|
||||||
|
<Form inline={true} onSubmit={this.handleSubmit}>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My profile'
|
||||||
|
explain='Your certifications will be disabled'
|
||||||
|
flag={isLocked}
|
||||||
|
flagName='isLocked'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('isLocked')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My name'
|
||||||
|
flag={!showName}
|
||||||
|
flagName='name'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showName')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My location'
|
||||||
|
flag={!showLocation}
|
||||||
|
flagName='showLocation'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showLocation')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My "about me"'
|
||||||
|
flag={!showAbout}
|
||||||
|
flagName='showAbout'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showAbout')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My points'
|
||||||
|
flag={!showPoints}
|
||||||
|
flagName='showPoints'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showPoints')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My heat map'
|
||||||
|
flag={!showHeatMap}
|
||||||
|
flagName='showHeatMap'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showHeatMap')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My certifications'
|
||||||
|
explain='Your certifications will be disabled'
|
||||||
|
flag={!showCerts}
|
||||||
|
flagName='showCerts'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showCerts')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My portfolio'
|
||||||
|
flag={!showPortfolio}
|
||||||
|
flagName='showPortfolio'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showPortfolio')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My time line'
|
||||||
|
explain='Your certifications will be disabled'
|
||||||
|
flag={!showTimeLine}
|
||||||
|
flagName='showTimeLine'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showTimeLine')}
|
||||||
|
/>
|
||||||
|
<ToggleSetting
|
||||||
|
action='My donations'
|
||||||
|
flag={!showDonation}
|
||||||
|
flagName='showPortfolio'
|
||||||
|
offLabel='Public'
|
||||||
|
onLabel='Private'
|
||||||
|
toggleFlag={this.toggleFlag('showDonation')}
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
</FullWidthRow>
|
||||||
|
<FullWidthRow>
|
||||||
|
<Spacer />
|
||||||
|
<p>
|
||||||
|
To see what data we hold on your account, click the 'Download your
|
||||||
|
data' button below
|
||||||
|
</p>
|
||||||
|
<Button
|
||||||
|
block={true}
|
||||||
|
bsSize='lg'
|
||||||
|
bsStyle='primary'
|
||||||
|
download={`${user.username}.json`}
|
||||||
|
href={`data:text/json;charset=utf-8,${encodeURIComponent(
|
||||||
|
JSON.stringify(user)
|
||||||
|
)}`}
|
||||||
|
>
|
||||||
|
Download your data
|
||||||
|
</Button>
|
||||||
|
</FullWidthRow>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivacySettings.displayName = 'PrivacySettings';
|
||||||
|
PrivacySettings.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(PrivacySettings);
|
26
client/src/components/settings/SectionHeader.js
Normal file
26
client/src/components/settings/SectionHeader.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import FullWidthRow from '../helpers/FullWidthRow';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
children: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.element,
|
||||||
|
PropTypes.node
|
||||||
|
])
|
||||||
|
};
|
||||||
|
|
||||||
|
function SectionHeader({ children }) {
|
||||||
|
return (
|
||||||
|
<FullWidthRow>
|
||||||
|
<h2 className='text-center'>{children}</h2>
|
||||||
|
<hr />
|
||||||
|
</FullWidthRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionHeader.displayName = 'SectionHeader';
|
||||||
|
SectionHeader.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default SectionHeader;
|
56
client/src/components/settings/ToggleSetting.js
Normal file
56
client/src/components/settings/ToggleSetting.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
FormGroup,
|
||||||
|
ControlLabel,
|
||||||
|
HelpBlock
|
||||||
|
} from '@freecodecamp/react-bootstrap';
|
||||||
|
|
||||||
|
import TB from '../helpers/ToggleButton';
|
||||||
|
import { ButtonSpacer } from '../helpers';
|
||||||
|
|
||||||
|
import './toggle-setting.css';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
action: PropTypes.string.isRequired,
|
||||||
|
explain: PropTypes.string,
|
||||||
|
flag: PropTypes.bool.isRequired,
|
||||||
|
flagName: PropTypes.string.isRequired,
|
||||||
|
toggleFlag: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ToggleSetting({
|
||||||
|
action,
|
||||||
|
explain,
|
||||||
|
flag,
|
||||||
|
flagName,
|
||||||
|
toggleFlag,
|
||||||
|
...restProps
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<div className='toggle-setting-container'>
|
||||||
|
<FormGroup>
|
||||||
|
<ControlLabel className='toggle-label' htmlFor={flagName}>
|
||||||
|
<strong>{action}</strong>
|
||||||
|
{explain ? (
|
||||||
|
<HelpBlock>
|
||||||
|
<em>{explain}</em>
|
||||||
|
</HelpBlock>
|
||||||
|
) : null}
|
||||||
|
</ControlLabel>
|
||||||
|
<TB
|
||||||
|
name={flagName}
|
||||||
|
onChange={toggleFlag}
|
||||||
|
value={flag}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</div>
|
||||||
|
<ButtonSpacer />
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleSetting.displayName = 'ToggleSetting';
|
||||||
|
ToggleSetting.propTypes = propTypes;
|
9
client/src/components/settings/toggle-setting.css
Normal file
9
client/src/components/settings/toggle-setting.css
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.toggle-setting-container .form-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-setting-container .form-group label {
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
@ -24,7 +24,8 @@ export const types = createTypes(
|
|||||||
...createAsyncTypes('validateUsername'),
|
...createAsyncTypes('validateUsername'),
|
||||||
...createAsyncTypes('submitNewAbout'),
|
...createAsyncTypes('submitNewAbout'),
|
||||||
...createAsyncTypes('submitNewUsername'),
|
...createAsyncTypes('submitNewUsername'),
|
||||||
...createAsyncTypes('updateUserFlag')
|
...createAsyncTypes('updateUserFlag'),
|
||||||
|
...createAsyncTypes('submitProfileUI')
|
||||||
],
|
],
|
||||||
ns
|
ns
|
||||||
);
|
);
|
||||||
@ -49,6 +50,13 @@ export const submitNewUsernameError = createAction(
|
|||||||
types.submitNewUsernameError
|
types.submitNewUsernameError
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const submitProfileUI = createAction(types.submitProfileUI);
|
||||||
|
export const submitProfileUIComplete = createAction(
|
||||||
|
types.submitProfileUIComplete,
|
||||||
|
checkForSuccessPayload
|
||||||
|
);
|
||||||
|
export const submitProfileUIError = createAction(types.submitProfileUIError);
|
||||||
|
|
||||||
export const updateUserFlag = createAction(types.updateUserFlag);
|
export const updateUserFlag = createAction(types.updateUserFlag);
|
||||||
export const updateUserFlagComplete = createAction(
|
export const updateUserFlagComplete = createAction(
|
||||||
types.updateUserFlagComplete,
|
types.updateUserFlagComplete,
|
||||||
|
@ -9,11 +9,14 @@ import {
|
|||||||
submitNewAboutComplete,
|
submitNewAboutComplete,
|
||||||
submitNewAboutError,
|
submitNewAboutError,
|
||||||
submitNewUsernameComplete,
|
submitNewUsernameComplete,
|
||||||
submitNewUsernameError
|
submitNewUsernameError,
|
||||||
|
submitProfileUIComplete,
|
||||||
|
submitProfileUIError
|
||||||
} from './';
|
} from './';
|
||||||
import {
|
import {
|
||||||
getUsernameExists,
|
getUsernameExists,
|
||||||
putUpdateMyAbout,
|
putUpdateMyAbout,
|
||||||
|
putUpdateMyProfileUI,
|
||||||
putUpdateMyUsername,
|
putUpdateMyUsername,
|
||||||
putUpdateUserFlag
|
putUpdateUserFlag
|
||||||
} from '../../utils/ajax';
|
} from '../../utils/ajax';
|
||||||
@ -39,6 +42,16 @@ function* submitNewUsernameSaga({ payload: username }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* sumbitProfileUISaga({ payload }) {
|
||||||
|
try {
|
||||||
|
const { data: response } = yield call(putUpdateMyProfileUI, payload);
|
||||||
|
yield put(submitProfileUIComplete({ ...response, payload }));
|
||||||
|
yield put(createFlashMessage(response));
|
||||||
|
} catch (e) {
|
||||||
|
yield put(submitProfileUIError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function* updateUserFlagSaga({ payload: update }) {
|
function* updateUserFlagSaga({ payload: update }) {
|
||||||
try {
|
try {
|
||||||
const { data: response } = yield call(putUpdateUserFlag, update);
|
const { data: response } = yield call(putUpdateUserFlag, update);
|
||||||
@ -66,6 +79,7 @@ export function createSettingsSagas(types) {
|
|||||||
takeEvery(types.updateUserFlag, updateUserFlagSaga),
|
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),
|
||||||
|
takeLatest(types.submitProfileUI, sumbitProfileUISaga)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,10 @@ export function putUpdateMyUsername(username) {
|
|||||||
return put('/update-my-username', { username });
|
return put('/update-my-username', { username });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function putUpdateMyProfileUI(profileUI) {
|
||||||
|
return put('/update-my-profileui', { profileUI });
|
||||||
|
}
|
||||||
|
|
||||||
export function putUpdateUserFlag(update) {
|
export function putUpdateUserFlag(update) {
|
||||||
return put('/update-user-flag', update);
|
return put('/update-user-flag', update);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user