Commit f7d1fb60 authored by nano's avatar nano

complete

parent 35196841
......@@ -14,7 +14,7 @@ const formItemLayout = {
class EmailForm extends React.Component {
onSubmit = (e) => {
const { form, dispatch, data: {id} } = this.props
const { form, dispatch, user: {id} } = this.props
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
......@@ -30,9 +30,9 @@ class EmailForm extends React.Component {
render(){
const {form, dispatch, data, checkEmail, isEmailExists} = this.props
const {form, dispatch, user, checkEmail, isEmailExists} = this.props
const {getFieldDecorator} = form
const {id, email} = data
const {id, email} = user
const emailProps = {
......@@ -95,11 +95,11 @@ class EmailForm extends React.Component {
function mapStateToProps(state, props) {
const {
user: {data},
user: {user},
auth: {isEmailExists, checkEmail}
} = state
return {
data,
user,
checkEmail,
isEmailExists
};
......
......@@ -31,7 +31,7 @@ class EmailForm extends React.Component {
}
onSubmit = (e) => {
const { form, dispatch, data: {id} } = this.props
const { form, dispatch, user: {id} } = this.props
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
......@@ -117,10 +117,10 @@ class EmailForm extends React.Component {
function mapStateToProps(state, props) {
const {
user: {data}
user: {user}
} = state
return {
data,
user,
};
}
......
......@@ -14,7 +14,7 @@ const formItemLayout = {
class EmailForm extends React.Component {
onSubmit = (e) => {
const { form, dispatch, data: { id } } = this.props
const { form, dispatch, user: { id } } = this.props
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
......@@ -30,9 +30,9 @@ class EmailForm extends React.Component {
render() {
const { form, dispatch, data, checkEmail, isEmailExists, isSendEmailActive } = this.props
const { form, dispatch, user, checkEmail, isEmailExists, isSendEmailActive } = this.props
const { getFieldDecorator } = form;
const { id, email } = data;
const { id, email } = user;
const emailProps = {
fromItem: {
......@@ -88,11 +88,11 @@ class EmailForm extends React.Component {
function mapStateToProps(state, props) {
const {
user: { data },
user: { user },
auth: { isEmailExists, checkEmail, isSendEmailActive }
} = state
return {
data,
user,
checkEmail,
isEmailExists,
isSendEmailActive
......
......@@ -13,7 +13,7 @@ const formItemLayout = {
class EmailForm extends React.Component {
onSubmit = (e) => {
const { form, dispatch, data: { id } } = this.props;
const { form, dispatch, user: { id } } = this.props;
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
......@@ -29,9 +29,9 @@ class EmailForm extends React.Component {
render() {
const { form, dispatch, data, checkUsername, isUserNameExists } = this.props;
const { form, dispatch, user, checkUsername, isUserNameExists } = this.props;
const { getFieldDecorator } = form;
const { id, username } = data;
const { id, username } = user;
const usernameProps = {
fromItem: {
......@@ -91,11 +91,11 @@ class EmailForm extends React.Component {
function mapStateToProps(state, props) {
const {
user: { data },
user: { user },
auth: { isUserNameExists, checkUsername },
} = state;
return {
data,
user,
checkUsername,
isUserNameExists,
};
......
export default {
apiRoot: 'http://localhost:3000',
apiRoot: 'http://192.168.1.9:3000',
};
......@@ -25,6 +25,8 @@ app.use(createLoading())
app.model(require('./models/user'));
app.model(require("./models/upload"));
app.model(require('./models/auth'));
app.model(require('./models/haha'));
......
......@@ -209,12 +209,15 @@ export default {
const { data } = yield call(register, payload)
if (data) {
yield put({ type: 'registerSuccess' })
yield put({ type: 'user/loginSuccess', payload: { data } })
yield put({ type: 'loginSuccess', payload: { input: payload } })
message.info("注册成功, 请验证激活邮件~", 3)
yield put(routerRedux.replace("/verify"))
}
} catch (error) {
yield put({ type: 'registerFail' })
message.error("注册失败")
message.error(error.message, 3)
}
},
*reset({ payload }, { call, put }) {
......
import { uploadImage } from '../services/upload'
import { message } from 'antd'
export default {
namespace: 'upload',
state: {
imageUrl: "",
isUpload: false,
uploadedImage: {}
},
reducers: {
start(state, action) {
return {
...state, ...{
isUpload: true
}
}
},
getfile(state, action) {
return {
...state, ...action.payload
}
},
uploadSuccess(state, action) {
return {
...state, ...action.payload, ...{
isUpload: false
}
}
}
},
effects: {
*upload({ payload }, { call, put }) {
try {
const { data } = yield call(uploadImage, payload)
if(data){
const [ image ] = data
yield put({ type: 'uploadSuccess', payload: { uploadedImage : image } })
const {user_id} = payload
yield put({ type: 'user/updateProfile', payload: { avatar: image["Key"], user_id }})
}
} catch (error) {
yield put({ type: 'uploadFail' })
message.error(error.message)
}
},
},
subscriptions: {},
};
import { routerRedux } from 'dva/router'
import { updateProfile, updateAccount } from '../services/user'
import { getAuthUser } from '../services/auth'
import { message } from 'antd'
export default {
namespace: 'user',
state: {
data: {},
token: "",
user: {},
isUpdateSubmit: false
},
reducers: {
......@@ -17,7 +20,7 @@ export default {
},
loginSuccess(state, action) {
return {
...state, ...action.payload
...state, ...action.payload.data
}
},
updateProfile(state, action) {
......@@ -62,55 +65,78 @@ export default {
}
}
},
storeToken(state, action) {
return {
...state, ...action.payload
}
},
preLoginSuccess(state, action) {
return {
...state, ...action.payload
}
}
},
effects: {
*loginSuccess({ payload }, { call, put }) {
const {data} = payload
const { data: {user, token} } = payload
if(!data) {
if(!payload.data) {
message.error("error ")
}
if(token) {
yield put({ type: 'storeToken', payload: { token }})
localStorage.setItem("token", token)
}
if(data.active) {
if(user && user.active) {
yield put(routerRedux.replace("/profiles"))
message.info("登录成功")
localStorage.setItem("user", JSON.stringify(payload.data))
// message.info("登录成功")
} else {
yield put(routerRedux.replace(`/verify`))
}
},
*preLogin({ payload }, { call, put }) {
let user = localStorage.getItem("user")
let token = localStorage.getItem("token")
if (!user) {
yield put(routerRedux.replace("/signin"))
}
try {
let { data } = yield call(getAuthUser, { token })
if (data ) {
yield put({ type: 'preLoginSuccess', payload: { user: data, token }})
yield put({ type: 'loginFromStorage', payload: { data: JSON.parse(user) } })
if(data.active) {
// yield put(routerRedux.replace("/profiles"))
}
}
} catch (error) {
message.error("自动登录失败")
}
},
*updateProfile({ payload }, { call, put }) {
*updateProfile({ payload }, { call, put, select }) {
message.destroy()
try {
let { data } = yield call(updateProfile, payload)
let token = yield select(state => state.user.token)
let { data } = yield call(updateProfile, {...payload, token})
if (data) {
yield put({ type: 'updateProfileSuccess', payload: { data } })
yield put({ type: 'updateProfileSuccess', payload: { user: data, token } })
message.info("更新成功")
}
} catch (error) {
yield put({ type: 'updateProfileFail' })
message.error("更新失败")
message.error(error.message)
}
},
*updateEmail({ payload }, { call, put }) {
*updateEmail({ payload }, { call, put, select }) {
try {
let { data } = yield call(updateAccount, payload)
let token = yield select(state => state.user.token)
let { data } = yield call(updateAccount, {...payload, token})
if (data) {
yield put({ type: 'updateAccountSuccess', payload: { data } })
yield put({ type: 'updateAccountSuccess', payload: { user: data, token } })
message.info("验证邮件已发送")
}
} catch (error) {
......@@ -119,13 +145,14 @@ export default {
}
},
*updateAccount({ payload }, { call, put }) {
*updateAccount({ payload }, { call, put, select }) {
try {
let { data } = yield call(updateAccount, payload)
let token = yield select(state => state.user.token)
let { data } = yield call(updateAccount, {...payload, token})
if (data) {
yield put({ type: 'updateAccountSuccess', payload: { data } })
yield put({ type: 'updateAccountSuccess', payload: { user: data, token } })
message.info("更新成功")
}
} catch (error) {
......
import { Button, Form, Icon, Input, Spin, Tabs } from 'antd';
import { Button, Form, Icon, Input, Spin, Tabs, Upload, message } from 'antd';
import { connect } from 'dva';
import Cropper from 'react-cropper'
import 'cropperjs/dist/cropper.css';
import React, { PropTypes } from 'react';
import { FormattedMessage as Format } from 'react-intl';
import EmailForm from '../components/EmailForm';
import PasswordForm from '../components/PasswordForm';
import UserNameForm from '../components/UserNameForm';
import styles from './Profiles.less';
import config from '../config'
const FormItem = Form.Item;
const TabPane = Tabs.TabPane;
const defaultAvatar = "https://r.my-card.in/accounts/images/default_avatar.jpg"
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 15 },
};
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
class Profiles extends React.Component {
static contextTypes = {
intl: PropTypes.object.isRequired,
}
handleUpload = () => {
if (typeof this.cropper.getCroppedCanvas() === 'undefined') {
return;
}
const { user: {id} } = this.props
this.cropper.getCroppedCanvas().toBlob(blob => {
console.log(blob)
this.props.dispatch({ type: 'upload/upload', payload: { image: blob, user_id: id}})
})
}
onGetFile = (e) => {
let files;
if (e.dataTransfer) {
files = e.dataTransfer.files;
} else if (e.target) {
files = e.target.files;
}
const reader = new FileReader();
reader.onload = () => {
this.props.dispatch({ type: 'upload/getfile', payload: { imageUrl: reader.result } });
};
reader.readAsDataURL(files[0])
}
onUpdateSubmit = (e) => {
const { form, dispatch, data: { id } } = this.props;
const { form, dispatch, user: { id }, } = this.props;
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
......@@ -32,16 +70,16 @@ class Profiles extends React.Component {
const { username, name, password } = values;
dispatch({type: "user/updateProfile", payload: { username, name, password, user_id: id }})
dispatch({ type: "user/updateProfile", payload: { username, name, password, user_id: id } })
}
});
};
render() {
const { dispatch, form, data, isUpdateSubmit=false, checkUsername, isUserNameExists, loading } = this.props
const { dispatch, form, user, loading, progress, status, imageUrl, isUpload, uploadedImage } = this.props
const { getFieldDecorator } = form;
const { username, name, id } = data;
const { intl: {messages} } = this.context;
const { username, name, id, avatar } = user;
const { intl: { messages } } = this.context;
const nameProps = {
fromItem: {
......@@ -56,38 +94,72 @@ class Profiles extends React.Component {
}
}
const crop = {
maxHeight: 80,
width: 30,
aspect: 16 / 16
}
return (
<Spin spinning={loading} delay={100}>
<Tabs defaultActiveKey="1" className="app-detail-nav">
<TabPane tab={<span><Icon type="setting" /><Format id={'user-info'} /> </span>} key="1">
<Form onSubmit={this.onUpdateSubmit}>
<FormItem style={{ display: 'flex', justifyContent: 'center' }}>
{
isUpload ?
<div>
<Cropper
ref={cropper => { this.cropper = cropper }}
src={ imageUrl || defaultAvatar}
style={{height: '20vw', width: '20vw' }}
aspectRatio={1 / 1}
guides={true}
/>
<Button>
<label >
<Icon type="plus"/> add file
<input type="file" onChange={this.onGetFile} ref={file => { this.file = file}} style={{ display: "none" }}/>
</label>
</Button>
<Button type="primary" onClick={ this.handleUpload}>
<Icon type="upload" /> upload
</Button>
</div>
:
<img src={ avatar || imageUrl || defaultAvatar } onClick={() => dispatch({ type: "upload/start" })} />
}
</FormItem>
<FormItem {...nameProps.fromItem}>
{getFieldDecorator(`name`, {...nameProps.decorator})(
<Input {...nameProps.input}/>
{getFieldDecorator(`name`, { ...nameProps.decorator })(
<Input {...nameProps.input} />
)}
</FormItem>
<FormItem>
<div className={styles.wrapSubmit}>
<Button type="primary" htmlType="submit" size="large"><Format id={'save'}/></Button>
<Button type="primary" htmlType="submit" size="large"><Format id={'save'} /></Button>
</div>
</FormItem>
</Form>
</TabPane>
<TabPane tab={<span><Icon type="setting" /><Format id={'account-info'}/></span>} key="2">
<TabPane tab={<span><Icon type="setting" /><Format id={'account-info'} /></span>} key="2">
<Tabs type="card" className="app-detail-nav">
<TabPane tab={messages['reset-username']} key={0}>
<UserNameForm />
</TabPane>
<TabPane tab={messages['reset-email']}key={1}>
<TabPane tab={messages['reset-email']} key={1}>
<EmailForm />
</TabPane>
<TabPane tab={messages['reset-password']}key={2}>
<TabPane tab={messages['reset-password']} key={2}>
<PasswordForm />
</TabPane>
</Tabs>
......@@ -101,16 +173,20 @@ class Profiles extends React.Component {
function mapStateToProps(state) {
const {
user: { data, isUpdateSubmit },
user: { user, isUpdateSubmit },
auth: { checkUsername, isEmailExists, isUserNameExists },
upload: {imageUrl, isUpload, uploadedImage }
} = state;
const loading = state.loading.global || false
return {
data,
user,
loading,
imageUrl,
isUpload,
checkUsername,
uploadedImage,
isEmailExists,
isUserNameExists,
isUpdateSubmit,
......
......@@ -18,6 +18,10 @@
font-size: 12px;
color: #666;
}
label > .anticon {
vertical-align: baseline
}
}
.wrapSubmit {
......
......@@ -23,9 +23,9 @@ class Register extends React.Component {
if (!err) {
console.log('Received values of form: ', values);
const { email, username, nickname, password, confirm } = values;
const { email, username, password, } = values;
dispatch({ type: 'auth/register', payload: { email, username, nickname, password } });
dispatch({ type: 'auth/register', payload: { email, username, password } });
}
});
};
......@@ -51,7 +51,7 @@ class Register extends React.Component {
render() {
const { dispatch, register, form, checkEmail, checkUsername, isEmailExists, isUserNameExists, isRegisterSubmit, loading } = this.props;
const { getFieldDecorator, } = form;
const { email = {}, username = {}, password = {} } = register;
const { email, username, password } = register;
const { intl: { messages } } = this.context;
const emailProps = {
......@@ -110,12 +110,6 @@ class Register extends React.Component {
)}
</FormItem>
<FormItem >
{getFieldDecorator('nickname', {})(
<Input placeholder={messages.nickname} />,
)}
</FormItem>
<FormItem hasFeedback>
{getFieldDecorator('password', {
rules: [{ required: true, message: '密码至少为8-24位', pattern: /^.{8,24}$/ }],
......
......@@ -15,7 +15,7 @@ class Verify extends React.Component {
}
onSubmit = (e) => {
const { form, dispatch, input: { password }, data: { id }} = this.props;
const { form, dispatch, input: { password }, user: { id }} = this.props;
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
......@@ -30,7 +30,7 @@ class Verify extends React.Component {
};
onReSend = (e) => {
const { dispatch, input: { password }, data: { id, email }} = this.props;
const { dispatch, input: { password }, user: { id, email }} = this.props;
e && e.preventDefault();
......@@ -38,9 +38,9 @@ class Verify extends React.Component {
};
render() {
const { form, dispatch, data, checkEmail, isEmailExists, loading, input } = this.props
const { form, dispatch, user, checkEmail, isEmailExists, loading, input } = this.props
const { getFieldDecorator } = form;
const { id, email } = data;
const { id, email } = user;
const emailProps = {
fromItem: {
......@@ -121,7 +121,7 @@ class Verify extends React.Component {
function mapStateToProps(state, props) {
const {
user: { data } ,
user: { user } ,
auth: { input, isEmailExists, checkEmail }
} = state
......@@ -129,7 +129,7 @@ function mapStateToProps(state, props) {
return {
input,
data,
user,
loading,
checkEmail,
isEmailExists,
......
......@@ -56,3 +56,12 @@ export async function checkUserExists(params) {
});
}
export async function getAuthUser(params) {
return request(`/authUser`, {
method: 'GET',
headers: {
Authorization: `Bearer ${params.token}`
}
})
}
\ No newline at end of file
import request from '../utils/request';
export async function uploadImage(params) {
console.log(params)
let data = new FormData()
data.append("file", params["image"])
return request('/upload/image', {
method: 'POST',
body: data,
headers: {
}
});
}
......@@ -4,6 +4,10 @@ export async function updateProfile(params) {
return request(`/user/profiles`, {
method: 'PATCH',
body: JSON.stringify(params),
headers: {
Authorization: `Bearer ${params.token}`,
"content-type": "application/json"
}
});
}
......@@ -11,6 +15,12 @@ export async function updateAccount(params) {
return request(`/user/account`, {
method: 'PATCH',
body: JSON.stringify(params),
headers: {
Authorization: `Bearer ${params.token}`,
"content-type": "application/json"
}
});
}
......@@ -31,7 +31,7 @@ async function checkStatus(response) {
*/
export default function request(url, options) {
url = `${config.apiRoot}${url}`
if(options && !options.headers && (options.method == 'POST' || options.method == 'PATCH')) {
if(options && !options.headers) {
options.headers = {
"content-type": "application/json"
}
......
......@@ -1422,6 +1422,10 @@ cosmiconfig@^2.1.0, cosmiconfig@^2.1.1:
parse-json "^2.2.0"
require-from-string "^1.1.0"
cropperjs@^0.8.0:
version "0.8.1"
resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-0.8.1.tgz#3dc01813e2f6d1df2c8909e1ce092146c692548e"
cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
......@@ -4482,6 +4486,12 @@ react-addons-transition-group@^15.4.2:
fbjs "^0.8.4"
object-assign "^4.1.0"
react-cropper@^0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/react-cropper/-/react-cropper-0.10.1.tgz#827df18166581ea3a42da983a49f90ebce066e22"
dependencies:
cropperjs "^0.8.0"
react-dev-utils@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-0.4.2.tgz#ba6fae581fe945a2fc402e9b27c71fda4f62f6a1"
......@@ -4512,6 +4522,10 @@ react-hammerjs@~0.5.0:
dependencies:
hammerjs "^2.0.8"
react-image-crop@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-2.0.3.tgz#81dcbaecc39553f0ac93e9d0e748cdc3216b2cf0"
react-intl@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.2.3.tgz#8eebb03cddc38b337ed22fab78037ab53a594270"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment