Skip to content

Commit ab484c0

Browse files
whDongRuisunnywx
authored andcommitted
feat: Profile page integrate API (#401)
1 parent f3042aa commit ab484c0

File tree

8 files changed

+142
-49
lines changed

8 files changed

+142
-49
lines changed

server/routes/api.js

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,14 @@ router.post('/api/*', async ctx => {
3939
if (access_token) {
4040
header.Authorization = token_type + ' ' + access_token;
4141
} else if (refresh_token) {
42-
const res = await agent
43-
.post([apiServer, 'oauth2/token'].join('/'))
44-
.set(header)
45-
.send({
46-
grant_type: 'refresh_token',
47-
client_id: ctx.store.clientId,
48-
client_secret: ctx.store.clientSecret,
49-
scope: '',
50-
refresh_token: refresh_token
51-
});
42+
const refreshUrl = [apiServer, 'oauth2/token'].join('/');
43+
const res = await agent.post(refreshUrl).send({
44+
grant_type: 'refresh_token',
45+
client_id: ctx.store.clientId,
46+
client_secret: ctx.store.clientSecret,
47+
scope: '',
48+
refresh_token: refresh_token
49+
});
5250
const result = (res && res.body) || {};
5351

5452
if (result.access_token) {
@@ -67,14 +65,6 @@ router.post('/api/*', async ctx => {
6765
ctx.body = await agent.send(forwardMethod, url, body, {
6866
header: header
6967
});
70-
71-
if (endpoint === 'oauth2/token' && ctx.body.access_token) {
72-
const { access_token, token_type, refresh_token, expires_in } = ctx.body;
73-
sessConfig.maxAge = expires_in * 1000;
74-
ctx.cookies.set('access_token', access_token, sessConfig);
75-
ctx.cookies.set('token_type', token_type, sessConfig);
76-
ctx.cookies.set('refresh_token', refresh_token);
77-
}
7868
});
7969

8070
module.exports = router;

src/pages/Admin/Users/index.jsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ export default class Users extends Component {
240240
onCancel={userStore.hideModal}
241241
hideFooter
242242
>
243-
<form className="formContent" onSubmit={userStore.createOrModify} method="post">
243+
<form className="formContent" onSubmit={e => userStore.createOrModify(e)} method="post">
244244
{userDetail.user_id && (
245245
<div className="inputItem">
246246
<label>{t('Name')}</label>
@@ -287,7 +287,7 @@ export default class Users extends Component {
287287
onChange={e => {
288288
changeUser(e, 'password');
289289
}}
290-
required
290+
required={!Boolean(userDetail.user_id)}
291291
/>
292292
</div>
293293
<div className="textareaItem">
@@ -305,7 +305,7 @@ export default class Users extends Component {
305305
<Button type="primary" htmlType="submit">
306306
{t('Confirm')}
307307
</Button>
308-
<Button>{t('Cancel')}</Button>
308+
<Button onClick={userStore.hideModal}>{t('Cancel')}</Button>
309309
</div>
310310
</form>
311311
</Modal>
@@ -379,6 +379,12 @@ export default class Users extends Component {
379379
}
380380
];
381381

382+
const roleMap = {
383+
global_admin: 'Administrator',
384+
developer: 'Developer',
385+
user: 'Normal User'
386+
};
387+
382388
const data = userStore.users.toJSON();
383389

384390
const columns = [
@@ -400,7 +406,7 @@ export default class Users extends Component {
400406
{
401407
title: 'Role',
402408
key: 'role',
403-
render: item => item.role
409+
render: item => t(roleMap[item.role])
404410
},
405411
{
406412
title: 'Updated At',

src/pages/Profile/index.jsx

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import classNames from 'classnames';
55

66
import { Button, Input } from 'components/Base';
77
import Layout, { Grid, Section, Card } from 'components/Layout';
8+
import { getCookie } from 'utils';
89

910
import styles from './index.scss';
1011

@@ -14,17 +15,19 @@ import styles from './index.scss';
1415
}))
1516
@observer
1617
export default class Profile extends Component {
17-
static async onEnter({ userStore }) {
18-
await userStore.fetchDetail();
19-
}
20-
2118
constructor(props) {
2219
super(props);
2320
this.state = {
2421
currentForm: 'basic'
2522
};
2623
}
2724

25+
componentDidMount() {
26+
const { fetchDetail } = this.props.userStore;
27+
const userId = getCookie('userId');
28+
fetchDetail(userId);
29+
}
30+
2831
changeForm = (name, flag) => {
2932
if (!flag) {
3033
this.setState({
@@ -35,64 +38,96 @@ export default class Profile extends Component {
3538

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

4044
return (
41-
<div className={styles.form}>
45+
<form className={styles.form} onSubmit={e => modifyUser(e)} method="post">
4246
<div>
4347
<label className={styles.name}>{t('ID')}</label>
44-
<Input className={styles.input} name="id" value={userDetail.user_id} disabled readOnly />
48+
<Input
49+
className={styles.input}
50+
name="user_id"
51+
value={userDetail.user_id}
52+
disabled
53+
readOnly
54+
/>
4555
</div>
4656
<div>
4757
<label className={styles.name}>{t('User Name')}</label>
4858
<Input
4959
className={styles.input}
5060
name="name"
51-
maxLength="50"
61+
maxLength={50}
5262
value={userDetail.username}
5363
onChange={e => {
5464
changeUser(e, 'username');
5565
}}
66+
required
5667
/>
5768
</div>
5869
<div>
5970
<label className={styles.name}>{t('Email')}</label>
6071
<Input
6172
className={styles.input}
6273
name="email"
74+
maxLength={50}
6375
value={userDetail.email}
6476
onChange={e => {
6577
changeUser(e, 'email');
6678
}}
79+
pattern={emailRegexp}
6780
required
6881
/>
6982
</div>
7083
<div className={styles.submitBtn}>
71-
<Button type={`primary`} onClick={changeUserRole}>
84+
<Button type={`primary`} htmlType="submit">
7285
{t('Modify')}
7386
</Button>
7487
<Button onClick={() => history.back()}>{t('Cancel')}</Button>
7588
</div>
76-
</div>
89+
</form>
7790
);
7891
}
7992

8093
renderPassword() {
8194
const { userStore, t } = this.props;
95+
const { modifyPassword, changeUser } = userStore;
8296

8397
return (
84-
<form className={styles.form}>
98+
<form className={styles.form} onSubmit={e => modifyPassword(e)} method="post">
8599
<div>
86100
<label className={styles.name}>{t('Current Password')}</label>
87-
<Input className={styles.input} name="current" type="password" />
101+
<Input
102+
className={styles.input}
103+
name="password"
104+
type="password"
105+
maxLength={50}
106+
required
107+
ref={input => (this.input = input)}
108+
/>
88109
</div>
89110
<div>
90111
<label className={styles.name}>{t('New Password')}</label>
91-
<Input className={styles.input} name="new" type="password" />
112+
<Input
113+
className={styles.input}
114+
name="new_password"
115+
type="password"
116+
maxLength={50}
117+
required
118+
ref={input => (this.input = input)}
119+
/>
92120
</div>
93121
<div>
94122
<label className={styles.name}>{t('Confirm New Password')}</label>
95-
<Input className={styles.input} name="confirm" type="password" />
123+
<Input
124+
className={styles.input}
125+
name="confirm_password"
126+
type="password"
127+
maxLength={50}
128+
required
129+
ref={input => (this.input = input)}
130+
/>
96131
</div>
97132
<div className={styles.submitBtn}>
98133
<Button type={`primary`} htmlType="submit">

src/scss/index.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,12 @@
162162
cursor: not-allowed;
163163
pointer-events: none;
164164
}
165+
166+
input:-webkit-autofill,
167+
input:-webkit-autofill:hover,
168+
input:-webkit-autofill:focus {
169+
box-shadow:0 0 0 60px white inset;
170+
-webkit-text-fill-color: #878787;
171+
}
172+
165173
}

src/stores/UserStore.js

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { observable, action } from 'mobx';
22
import { get, pick, assign } from 'lodash';
33
import { Base64 } from 'js-base64';
44
import Store from './Store';
5-
import { setCookie, getUrlParam } from 'utils';
5+
import { setCookie, getUrlParam, getFormData } from 'utils';
66

77
const defaultStatus = ['active'];
88

@@ -38,6 +38,7 @@ export default class UserStore extends Store {
3838

3939
@observable
4040
userDetail = {
41+
user_id: '',
4142
username: '',
4243
email: '',
4344
password: '',
@@ -60,7 +61,7 @@ export default class UserStore extends Store {
6061
defaultParams.search_word = this.searchWord;
6162
}
6263
if (this.selectRoleId) {
63-
defaultParams.role = this.selectRoleId;
64+
defaultParams.role = [this.selectRoleId];
6465
}
6566

6667
this.isLoading = true;
@@ -98,7 +99,8 @@ export default class UserStore extends Store {
9899
};
99100

100101
@action
101-
createOrModify = async () => {
102+
createOrModify = async e => {
103+
e.preventDefault();
102104
const params = pick({ ...this.userDetail }, [
103105
'user_id',
104106
'username',
@@ -121,9 +123,6 @@ export default class UserStore extends Store {
121123
if (get(this.operateResult, 'user_id')) {
122124
this.hideModal();
123125
await this.fetchAll();
124-
} else {
125-
const { err, errDetail } = this.operateResult;
126-
this.error(errDetail || err);
127126
}
128127
};
129128

@@ -137,8 +136,10 @@ export default class UserStore extends Store {
137136
@action
138137
modify = async (params = {}) => {
139138
this.isLoading = true;
140-
this.operateResult = await this.request.patch('users', params);
139+
const result = await this.request.patch('users', params);
141140
this.isLoading = false;
141+
this.operateResult = result;
142+
return result;
142143
};
143144

144145
@action
@@ -187,7 +188,7 @@ export default class UserStore extends Store {
187188
};
188189

189190
@action
190-
oauth2Check = async params => {
191+
oauth2Check = async (params = {}) => {
191192
const data = {
192193
grant_type: 'password',
193194
scope: '',
@@ -217,6 +218,59 @@ export default class UserStore extends Store {
217218
}
218219
};
219220

221+
@action
222+
modifyUser = async e => {
223+
e.preventDefault();
224+
225+
const data = getFormData(e.target);
226+
data.user_id = this.userDetail.user_id;
227+
const result = await this.modify(data);
228+
229+
if (get(result, 'user_id')) {
230+
this.success('Modify user successful.');
231+
}
232+
};
233+
234+
@action
235+
modifyPassword = async e => {
236+
e.preventDefault();
237+
238+
const data = getFormData(e.target);
239+
if (data.new_password !== data.confirm_password) {
240+
this.error('New password is different entered twice.');
241+
return;
242+
}
243+
244+
const resetResult = this.resetPassword({
245+
user_id: this.userDetail.user_id,
246+
password: data.password
247+
});
248+
249+
const resetId = get(resetResult, 'reset_id');
250+
if (resetId) {
251+
const result = this.changePassword({
252+
new_password: data.new_password,
253+
reset_id: resetId
254+
});
255+
256+
if (get(result, 'user_id')) {
257+
this.success('Change password successful.');
258+
}
259+
}
260+
};
261+
262+
@action
263+
resetPassword = async (params = {}) => {
264+
return await this.request.post('users/password:reset', params);
265+
};
266+
267+
@action
268+
changePassword = async (params = {}) => {
269+
this.isLoading = true;
270+
await this.request.post('users/password:change', params);
271+
this.isLoading = false;
272+
};
273+
220274
@action
221275
onSearch = async word => {
222276
this.searchWord = word;

test/components/Base/__snapshots__/Button.test.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ exports[`Base/Button basic render 1`] = `
1313
class="qicon qicon-spinner qicon-light"
1414
>
1515
<use
16-
href="#spinner"
16+
href="#qui-spinner"
1717
/>
1818
</svg>
1919
</span>

test/components/Base/__snapshots__/Checkbox.test.js.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ exports[`Base/Checkbox group render 1`] = `
2727
class="qicon qicon-check qicon-light"
2828
>
2929
<use
30-
href="#check"
30+
href="#qui-check"
3131
/>
3232
</svg>
3333
</span>
@@ -58,7 +58,7 @@ exports[`Base/Checkbox group render 1`] = `
5858
class="qicon qicon-check qicon-light"
5959
>
6060
<use
61-
href="#check"
61+
href="#qui-check"
6262
/>
6363
</svg>
6464
</span>

0 commit comments

Comments
 (0)