Skip to content

Commit

Permalink
Merge branch 'feature/code-refactor' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
gocreating committed Oct 28, 2016
2 parents 3b0b475 + a896caa commit 8f12ffd
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 63 deletions.
2 changes: 1 addition & 1 deletion src/common/api/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default (apiEngine) => ({
}),
login: (user) => apiEngine.post('/api/users/login', { data: user }),
logout: () => apiEngine.get('/api/users/logout'),
show: () => apiEngine.get('/api/users/me'),
read: () => apiEngine.get('/api/users/me'),
update: (user) => apiEngine.put('/api/users/me', { data: user }),
updateAvatarURL: (form) => apiEngine.put('/api/users/me/avatarURL', {
data: form,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React, { Component, PropTypes } from 'react';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import Image from 'react-bootstrap/lib/Image';
import Button from 'react-bootstrap/lib/Button';
import configs from '../../../../configs/project/client';
import firebaseAPI from '../../api/firebase';
import userAPI from '../../api/user';
import { pushErrors } from '../../actions/errorActions';
import { Form, FormField, FormFooter } from '../utils/BsForm';
import configs from '../../../../../configs/project/client';
import firebaseAPI from '../../../api/firebase';
import userAPI from '../../../api/user';
import { pushErrors } from '../../../actions/errorActions';
import { setCookies } from '../../../actions/cookieActions';
import { Form, FormField, FormFooter } from '../../utils/BsForm';
import RefreshImage from '../../utils/RefreshImage';
import toRefreshURL from '../../../utils/toRefreshURL';

const initialValues = {
storage: 'local',
Expand Down Expand Up @@ -36,7 +39,9 @@ class AvatarForm extends Component {
}

_uploadToLocal(formData) {
return userAPI(this.context.store.getState().apiEngine)
let { apiEngine } = this.props;

return userAPI(apiEngine)
.uploadAvatar(formData.avatar[0])
.catch((err) => {
return Promise.reject(err);
Expand All @@ -47,10 +52,12 @@ class AvatarForm extends Component {
}

_signInFirebase() {
return firebaseAPI(this.context.store.getState().apiEngine)
let { dispatch, apiEngine } = this.props;

return firebaseAPI(apiEngine)
.readToken()
.catch((err) => {
this.context.store.dispatch(pushErrors([{
dispatch(pushErrors([{
title: 'Fail To Read Token',
detail: 'Read firebase token fail.',
}]));
Expand All @@ -69,7 +76,7 @@ class AvatarForm extends Component {
return firebase.auth()
.signInWithCustomToken(json.token)
.catch(function(err) {
this.context.store.dispatch(pushErrors([{
dispatch(pushErrors([{
title: 'Fail To Signin Firebase',
detail: 'Signin firebase fail.',
}]));
Expand All @@ -80,15 +87,14 @@ class AvatarForm extends Component {

_uploadToFirebase(formData) {
let _this = this;
let { store } = this.context;
let userId = JSON.parse(store.getState().cookies.user)._id;
let { user } = this.props;

return new Promise((resolve, reject) => {
_this.signInFirebase().then(() => {
// ref: <https://firebase.google.com/docs/storage/web/upload-files#upload_files>
let storageRef = firebase.storage().ref();
let avatarRef = storageRef.child(
`${process.env.NODE_ENV}/${userId}/avatar.jpg`);
`${process.env.NODE_ENV}/${user._id}/avatar.jpg`);
let uploadTask = avatarRef.put(formData.avatar[0]);

uploadTask.on('state_changed', function(snapshot) {
Expand All @@ -114,13 +120,14 @@ class AvatarForm extends Component {
}

_handleSubmit(formData) {
let { store: { dispatch, getState } } = this.context;
let { dispatch, apiEngine } = this.props;
let uploadProcedure;
if (formData.storage === 'firebase') {
uploadProcedure = this.uploadToFirebase(formData);
} else if (formData.storage === 'local') {
uploadProcedure = this.uploadToLocal(formData);
}

return uploadProcedure
.catch((err) => {
dispatch(pushErrors([{
Expand All @@ -131,7 +138,7 @@ class AvatarForm extends Component {
throw err;
})
.then((downloadURL) => {
return userAPI(getState().apiEngine)
return userAPI(apiEngine)
.updateAvatarURL({
avatarURL: downloadURL,
})
Expand All @@ -144,28 +151,29 @@ class AvatarForm extends Component {
throw err;
})
.then((json) => {
let forceUpdate = (downloadURL.indexOf('?') >= 0 ?
'&' : '?') + `forceUpdate=${Math.random()}`;
this.setState({
avatarURL: downloadURL + forceUpdate,
});
let newAvatarURL = toRefreshURL(downloadURL);
json.user.avatarURL = newAvatarURL;
dispatch(setCookies({
user: json.user,
}));
this.clearFileField();
});
});
}

render() {
const {
user,
handleSubmit,
pristine,
submitting,
invalid,
} = this.props;
let avatarURL = this.state.avatarURL || this.props.avatarURL;
let avatarURL = this.state.avatarURL || user.avatarURL;

return (
<Form onSubmit={handleSubmit(this.handleSubmit)}>
{avatarURL && <Image thumbnail src={avatarURL} />}
{avatarURL && <RefreshImage thumbnail src={avatarURL} />}
<Field
name="avatar"
component={FormField}
Expand Down Expand Up @@ -194,16 +202,11 @@ class AvatarForm extends Component {
}
};

AvatarForm.propTypes = {
avatarURL: PropTypes.string,
};

AvatarForm.contextTypes = {
store: PropTypes.object.isRequired,
};

export default reduxForm({
form: 'avatar',
initialValues,
validate,
})(AvatarForm);
})(connect(({ apiEngine, cookies: { user } }) => ({
apiEngine: apiEngine,
user: (user && JSON.parse(user)) || {},
}))(AvatarForm));
2 changes: 1 addition & 1 deletion src/common/components/forms/user/EditForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class EditForm extends Component {
let { dispatch, apiEngine } = this.props;

userAPI(apiEngine)
.show()
.read()
.catch((err) => {
dispatch(pushErrors(err));
throw err;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Field, reduxForm } from 'redux-form';
import { Field, reduxForm, SubmissionError } from 'redux-form';
import Alert from 'react-bootstrap/lib/Alert';
import Button from 'react-bootstrap/lib/Button';
// import validator from 'validator';
import userAPI from '../../api/user';
import { pushErrors } from '../../actions/errorActions';
import { loginUser } from '../../actions/userActions';
import { Form, FormField, FormFooter } from '../utils/BsForm';
import userAPI from '../../../api/user';
import { pushErrors } from '../../../actions/errorActions';
import { loginUser } from '../../../actions/userActions';
import { Form, FormField, FormFooter } from '../../utils/BsForm';

const validate = (values) => {
const errors = {};
Expand Down Expand Up @@ -59,24 +60,28 @@ class LoginForm extends Component {
dispatch(push(next || '/'));
});
} else {
dispatch(pushErrors([{
title: 'User Not Exists',
detail: 'You may type wrong email or password.',
}]));
throw new SubmissionError({
email: 'You may type wrong email or password',
password: 'You may type wrong email or password',
_error: 'Login failed',
});
}
});
}

render() {
const {
handleSubmit,
submitFailed,
error,
pristine,
submitting,
invalid,
} = this.props;

return (
<Form horizontal onSubmit={handleSubmit(this.handleSubmit)}>
{submitFailed && error && (<Alert bsStyle="danger">{error}</Alert>)}
<Field
label="Email"
name="email"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Field, reduxForm } from 'redux-form';
import Alert from 'react-bootstrap/lib/Alert';
import Button from 'react-bootstrap/lib/Button';
// import validator from 'validator';
import userAPI from '../../api/user';
import { validateForm } from '../../actions/formActions';
import { pushErrors } from '../../actions/errorActions';
import { Form, FormField, FormFooter } from '../utils/BsForm';
import configs from '../../../../configs/project/client';
import userAPI from '../../../api/user';
import { validateForm } from '../../../actions/formActions';
import { pushErrors } from '../../../actions/errorActions';
import { Form, FormField, FormFooter } from '../../utils/BsForm';
import configs from '../../../../../configs/project/client';

const validate = (values) => {
const errors = {};
Expand Down Expand Up @@ -66,6 +67,8 @@ class RegisterForm extends Component {
render() {
const {
handleSubmit,
submitFailed,
error,
pristine,
asyncValidating,
submitting,
Expand All @@ -74,6 +77,7 @@ class RegisterForm extends Component {

return (
<Form horizontal onSubmit={handleSubmit(this.handleSubmit)}>
{submitFailed && error && (<Alert bsStyle="danger">{error}</Alert>)}
<Field
label="Name"
name="name"
Expand Down
5 changes: 5 additions & 0 deletions src/common/components/pages/user/EditPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Col from 'react-bootstrap/lib/Col';
import Button from 'react-bootstrap/lib/Button';
import PageLayout from '../../layouts/PageLayout';
import EditForm from '../../forms/user/EditForm';
import AvatarForm from '../../forms/user/AvatarForm';
import ChangePasswordForm from '../../forms/user/ChangePasswordForm';

let EditPage = () => {
Expand All @@ -24,6 +25,10 @@ let EditPage = () => {
<PageHeader>Edit Profile</PageHeader>
<EditForm />
</Col>
<Col md={6}>
<PageHeader>Upload Avatar</PageHeader>
<AvatarForm />
</Col>
<Col md={6}>
<PageHeader>Change Password</PageHeader>
<ChangePasswordForm />
Expand Down
2 changes: 1 addition & 1 deletion src/common/components/pages/user/LoginPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import PageLayout from '../../layouts/PageLayout';
import Head from '../../widgets/Head';
import LoginForm from '../../forms/LoginForm';
import LoginForm from '../../forms/user/LoginForm';

let LoginPage = ({ location }) => {
let { next } = location.query;
Expand Down
2 changes: 1 addition & 1 deletion src/common/components/pages/user/RegisterPage.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import PageHeader from 'react-bootstrap/lib/PageHeader';
import PageLayout from '../../layouts/PageLayout';
import RegisterForm from '../../forms/RegisterForm';
import RegisterForm from '../../forms/user/RegisterForm';

const RegisterPage = (props) => (
<PageLayout>
Expand Down
27 changes: 15 additions & 12 deletions src/common/components/pages/user/ShowPage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import PageHeader from 'react-bootstrap/lib/PageHeader';
import Row from 'react-bootstrap/lib/Row';
Expand All @@ -8,23 +9,24 @@ import userAPI from '../../../api/user';
import { pushErrors } from '../../../actions/errorActions';
import Head from '../../widgets/Head';
import PageLayout from '../../layouts/PageLayout';
import AvatarForm from '../../forms/AvatarForm';
import Time from '../../widgets/Time';
import RefreshImage from '../../utils/RefreshImage';

class ShowPage extends Component {
constructor(props) {
super(props);
this.state = {
user: {},
user: props.initialUser,
};
}

componentDidMount() {
let { store } = this.context;
userAPI(store.getState().apiEngine)
.show()
let { dispatch, apiEngine } = this.props;

userAPI(apiEngine)
.read()
.catch((err) => {
store.dispatch(pushErrors(err));
dispatch(pushErrors(err));
throw err;
})
.then((json) => {
Expand Down Expand Up @@ -56,7 +58,9 @@ class ShowPage extends Component {
<dt>_id</dt>
<dd>{user._id}</dd>
<dt>avatar</dt>
<dd><AvatarForm avatarURL={user.avatarURL} /></dd>
<dd>
{user.avatarURL && <RefreshImage thumbnail src={user.avatarURL} />}
</dd>
<dt>name</dt>
<dd>{user.name}</dd>
<dt>email</dt>
Expand All @@ -79,8 +83,7 @@ class ShowPage extends Component {
}
};

ShowPage.contextTypes = {
store: React.PropTypes.object.isRequired,
};

export default ShowPage;
export default connect(({ apiEngine, cookies: { user } }) => ({
apiEngine: apiEngine,
initialUser: (user && JSON.parse(user)) || {},
}))(ShowPage);
9 changes: 8 additions & 1 deletion src/common/components/utils/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import Grid from 'react-bootstrap/lib/Grid';
import Image from 'react-bootstrap/lib/Image';
import Roles from '../../constants/Roles';
import { updateLocale } from '../../actions/intlActions';
import { pushErrors } from '../../actions/errorActions';
Expand Down Expand Up @@ -67,7 +68,13 @@ class Navigation extends Component {
title={
!isAuth ?
<Text id="nav.user" /> :
(user.name || user.email)}
user.avatarURL ? (
<Image
style={{ height: 18 }}
src={user.avatarURL} rounded
/>
) : (user.name || user.email)
}
>
{!isAuth &&
<NavLink to="/user/login">
Expand Down
9 changes: 9 additions & 0 deletions src/common/components/utils/RefreshImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import Image from 'react-bootstrap/lib/Image';
import toRefreshURL from '../../utils/toRefreshURL';

let RefreshImage = ({ src, ...rest }) => (
<Image src={toRefreshURL(src)} {...rest} />
);

export default RefreshImage;
Loading

0 comments on commit 8f12ffd

Please sign in to comment.