Skip to content

Commit

Permalink
feat: Profile page integrate API (#401)
Browse files Browse the repository at this point in the history
  • Loading branch information
whDongRui authored and sunnywx committed Sep 27, 2018
1 parent f3042aa commit ab484c0
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 49 deletions.
26 changes: 8 additions & 18 deletions server/routes/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,14 @@ router.post('/api/*', async ctx => {
if (access_token) {
header.Authorization = token_type + ' ' + access_token;
} else if (refresh_token) {
const res = await agent
.post([apiServer, 'oauth2/token'].join('/'))
.set(header)
.send({
grant_type: 'refresh_token',
client_id: ctx.store.clientId,
client_secret: ctx.store.clientSecret,
scope: '',
refresh_token: refresh_token
});
const refreshUrl = [apiServer, 'oauth2/token'].join('/');
const res = await agent.post(refreshUrl).send({
grant_type: 'refresh_token',
client_id: ctx.store.clientId,
client_secret: ctx.store.clientSecret,
scope: '',
refresh_token: refresh_token
});
const result = (res && res.body) || {};

if (result.access_token) {
Expand All @@ -67,14 +65,6 @@ router.post('/api/*', async ctx => {
ctx.body = await agent.send(forwardMethod, url, body, {
header: header
});

if (endpoint === 'oauth2/token' && ctx.body.access_token) {
const { access_token, token_type, refresh_token, expires_in } = ctx.body;
sessConfig.maxAge = expires_in * 1000;
ctx.cookies.set('access_token', access_token, sessConfig);
ctx.cookies.set('token_type', token_type, sessConfig);
ctx.cookies.set('refresh_token', refresh_token);
}
});

module.exports = router;
14 changes: 10 additions & 4 deletions src/pages/Admin/Users/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export default class Users extends Component {
onCancel={userStore.hideModal}
hideFooter
>
<form className="formContent" onSubmit={userStore.createOrModify} method="post">
<form className="formContent" onSubmit={e => userStore.createOrModify(e)} method="post">
{userDetail.user_id && (
<div className="inputItem">
<label>{t('Name')}</label>
Expand Down Expand Up @@ -287,7 +287,7 @@ export default class Users extends Component {
onChange={e => {
changeUser(e, 'password');
}}
required
required={!Boolean(userDetail.user_id)}
/>
</div>
<div className="textareaItem">
Expand All @@ -305,7 +305,7 @@ export default class Users extends Component {
<Button type="primary" htmlType="submit">
{t('Confirm')}
</Button>
<Button>{t('Cancel')}</Button>
<Button onClick={userStore.hideModal}>{t('Cancel')}</Button>
</div>
</form>
</Modal>
Expand Down Expand Up @@ -379,6 +379,12 @@ export default class Users extends Component {
}
];

const roleMap = {
global_admin: 'Administrator',
developer: 'Developer',
user: 'Normal User'
};

const data = userStore.users.toJSON();

const columns = [
Expand All @@ -400,7 +406,7 @@ export default class Users extends Component {
{
title: 'Role',
key: 'role',
render: item => item.role
render: item => t(roleMap[item.role])
},
{
title: 'Updated At',
Expand Down
63 changes: 49 additions & 14 deletions src/pages/Profile/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import classNames from 'classnames';

import { Button, Input } from 'components/Base';
import Layout, { Grid, Section, Card } from 'components/Layout';
import { getCookie } from 'utils';

import styles from './index.scss';

Expand All @@ -14,17 +15,19 @@ import styles from './index.scss';
}))
@observer
export default class Profile extends Component {
static async onEnter({ userStore }) {
await userStore.fetchDetail();
}

constructor(props) {
super(props);
this.state = {
currentForm: 'basic'
};
}

componentDidMount() {
const { fetchDetail } = this.props.userStore;
const userId = getCookie('userId');
fetchDetail(userId);
}

changeForm = (name, flag) => {
if (!flag) {
this.setState({
Expand All @@ -35,64 +38,96 @@ export default class Profile extends Component {

renderBasic() {
const { userStore, t } = this.props;
const { userDetail, changeUser, changeUserRole } = userStore;
const { userDetail, changeUser, modifyUser } = userStore;
const emailRegexp = '^[A-Za-z0-9._%-]+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$';

return (
<div className={styles.form}>
<form className={styles.form} onSubmit={e => modifyUser(e)} method="post">
<div>
<label className={styles.name}>{t('ID')}</label>
<Input className={styles.input} name="id" value={userDetail.user_id} disabled readOnly />
<Input
className={styles.input}
name="user_id"
value={userDetail.user_id}
disabled
readOnly
/>
</div>
<div>
<label className={styles.name}>{t('User Name')}</label>
<Input
className={styles.input}
name="name"
maxLength="50"
maxLength={50}
value={userDetail.username}
onChange={e => {
changeUser(e, 'username');
}}
required
/>
</div>
<div>
<label className={styles.name}>{t('Email')}</label>
<Input
className={styles.input}
name="email"
maxLength={50}
value={userDetail.email}
onChange={e => {
changeUser(e, 'email');
}}
pattern={emailRegexp}
required
/>
</div>
<div className={styles.submitBtn}>
<Button type={`primary`} onClick={changeUserRole}>
<Button type={`primary`} htmlType="submit">
{t('Modify')}
</Button>
<Button onClick={() => history.back()}>{t('Cancel')}</Button>
</div>
</div>
</form>
);
}

renderPassword() {
const { userStore, t } = this.props;
const { modifyPassword, changeUser } = userStore;

return (
<form className={styles.form}>
<form className={styles.form} onSubmit={e => modifyPassword(e)} method="post">
<div>
<label className={styles.name}>{t('Current Password')}</label>
<Input className={styles.input} name="current" type="password" />
<Input
className={styles.input}
name="password"
type="password"
maxLength={50}
required
ref={input => (this.input = input)}
/>
</div>
<div>
<label className={styles.name}>{t('New Password')}</label>
<Input className={styles.input} name="new" type="password" />
<Input
className={styles.input}
name="new_password"
type="password"
maxLength={50}
required
ref={input => (this.input = input)}
/>
</div>
<div>
<label className={styles.name}>{t('Confirm New Password')}</label>
<Input className={styles.input} name="confirm" type="password" />
<Input
className={styles.input}
name="confirm_password"
type="password"
maxLength={50}
required
ref={input => (this.input = input)}
/>
</div>
<div className={styles.submitBtn}>
<Button type={`primary`} htmlType="submit">
Expand Down
8 changes: 8 additions & 0 deletions src/scss/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,12 @@
cursor: not-allowed;
pointer-events: none;
}

input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
box-shadow:0 0 0 60px white inset;
-webkit-text-fill-color: #878787;
}

}
70 changes: 62 additions & 8 deletions src/stores/UserStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { observable, action } from 'mobx';
import { get, pick, assign } from 'lodash';
import { Base64 } from 'js-base64';
import Store from './Store';
import { setCookie, getUrlParam } from 'utils';
import { setCookie, getUrlParam, getFormData } from 'utils';

const defaultStatus = ['active'];

Expand Down Expand Up @@ -38,6 +38,7 @@ export default class UserStore extends Store {

@observable
userDetail = {
user_id: '',
username: '',
email: '',
password: '',
Expand All @@ -60,7 +61,7 @@ export default class UserStore extends Store {
defaultParams.search_word = this.searchWord;
}
if (this.selectRoleId) {
defaultParams.role = this.selectRoleId;
defaultParams.role = [this.selectRoleId];
}

this.isLoading = true;
Expand Down Expand Up @@ -98,7 +99,8 @@ export default class UserStore extends Store {
};

@action
createOrModify = async () => {
createOrModify = async e => {
e.preventDefault();
const params = pick({ ...this.userDetail }, [
'user_id',
'username',
Expand All @@ -121,9 +123,6 @@ export default class UserStore extends Store {
if (get(this.operateResult, 'user_id')) {
this.hideModal();
await this.fetchAll();
} else {
const { err, errDetail } = this.operateResult;
this.error(errDetail || err);
}
};

Expand All @@ -137,8 +136,10 @@ export default class UserStore extends Store {
@action
modify = async (params = {}) => {
this.isLoading = true;
this.operateResult = await this.request.patch('users', params);
const result = await this.request.patch('users', params);
this.isLoading = false;
this.operateResult = result;
return result;
};

@action
Expand Down Expand Up @@ -187,7 +188,7 @@ export default class UserStore extends Store {
};

@action
oauth2Check = async params => {
oauth2Check = async (params = {}) => {
const data = {
grant_type: 'password',
scope: '',
Expand Down Expand Up @@ -217,6 +218,59 @@ export default class UserStore extends Store {
}
};

@action
modifyUser = async e => {
e.preventDefault();

const data = getFormData(e.target);
data.user_id = this.userDetail.user_id;
const result = await this.modify(data);

if (get(result, 'user_id')) {
this.success('Modify user successful.');
}
};

@action
modifyPassword = async e => {
e.preventDefault();

const data = getFormData(e.target);
if (data.new_password !== data.confirm_password) {
this.error('New password is different entered twice.');
return;
}

const resetResult = this.resetPassword({
user_id: this.userDetail.user_id,
password: data.password
});

const resetId = get(resetResult, 'reset_id');
if (resetId) {
const result = this.changePassword({
new_password: data.new_password,
reset_id: resetId
});

if (get(result, 'user_id')) {
this.success('Change password successful.');
}
}
};

@action
resetPassword = async (params = {}) => {
return await this.request.post('users/password:reset', params);
};

@action
changePassword = async (params = {}) => {
this.isLoading = true;
await this.request.post('users/password:change', params);
this.isLoading = false;
};

@action
onSearch = async word => {
this.searchWord = word;
Expand Down
2 changes: 1 addition & 1 deletion test/components/Base/__snapshots__/Button.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exports[`Base/Button basic render 1`] = `
class="qicon qicon-spinner qicon-light"
>
<use
href="#spinner"
href="#qui-spinner"
/>
</svg>
</span>
Expand Down
4 changes: 2 additions & 2 deletions test/components/Base/__snapshots__/Checkbox.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ exports[`Base/Checkbox group render 1`] = `
class="qicon qicon-check qicon-light"
>
<use
href="#check"
href="#qui-check"
/>
</svg>
</span>
Expand Down Expand Up @@ -58,7 +58,7 @@ exports[`Base/Checkbox group render 1`] = `
class="qicon qicon-check qicon-light"
>
<use
href="#check"
href="#qui-check"
/>
</svg>
</span>
Expand Down
Loading

0 comments on commit ab484c0

Please sign in to comment.