Skip to content

Commit acd14f9

Browse files
author
Scott Prue
committed
Merge branch 'master' into v1.4.0
2 parents 27d64e7 + 67d0f78 commit acd14f9

File tree

14 files changed

+332
-47
lines changed

14 files changed

+332
-47
lines changed

examples/complete/material/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"react-tap-event-plugin": "1.0.0",
7272
"redux": "^3.6.0",
7373
"redux-auth-wrapper": "^1.0.0",
74-
"redux-form": "^6.4.3",
74+
"redux-form": "^6.6.1",
7575
"redux-thunk": "^2.2.0"
7676
},
7777
"devDependencies": {
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
export const ACCOUNT_FORM_NAME = 'account'
2+
export const RECOVER_CODE_FORM_NAME = 'recoverCode'
3+
export const RECOVER_EMAIL_FORM_NAME = 'recoverEmail'
24

35
export default {
46
ACCOUNT_FORM_NAME,
5-
account: ACCOUNT_FORM_NAME
7+
RECOVER_CODE_FORM_NAME,
8+
RECOVER_EMAIL_FORM_NAME,
9+
account: ACCOUNT_FORM_NAME,
10+
recoverCode: RECOVER_CODE_FORM_NAME,
11+
recoverEmail: RECOVER_EMAIL_FORM_NAME
612
}

examples/complete/material/src/constants/paths.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ export const LIST_PATH = '/projects'
22
export const ACCOUNT_PATH = '/account'
33
export const LOGIN_PATH = '/login'
44
export const SIGNUP_PATH = '/signup'
5+
export const RECOVER_PATH = '/recover'
56

67
export default {
78
LIST_PATH,
89
ACCOUNT_PATH,
910
LOGIN_PATH,
10-
SIGNUP_PATH
11+
SIGNUP_PATH,
12+
RECOVER_PATH
1113
}
Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,69 @@
11
import React, { PropTypes } from 'react'
2-
3-
import classes from './AccountForm.scss'
4-
import ProviderDataForm from '../ProviderDataForm/ProviderDataForm'
5-
6-
import { Field } from 'redux-form'
2+
import { connect } from 'react-redux'
3+
import { Field, reduxForm, submit } from 'redux-form'
4+
import { firebaseConnect, pathToJS, isLoaded } from 'react-redux-firebase'
5+
import RaisedButton from 'material-ui/RaisedButton'
76
import TextField from 'components/TextField'
7+
import { List, ListItem } from 'material-ui/List'
8+
import AccountCircle from 'material-ui/svg-icons/action/account-circle'
9+
import { ACCOUNT_FORM_NAME } from 'constants/formNames'
10+
import classes from './AccountForm.scss'
811

9-
export const AccountForm = ({ account, handleSubmit, submitting }) => (
10-
<div className={classes.container}>
12+
export const AccountForm = ({ account, handleSubmit, submitForm, submitting }) => (
13+
<form className={classes.container} onSubmit={handleSubmit}>
1114
<h4>Account</h4>
12-
<div>
13-
<Field
14-
name='username'
15-
component={TextField}
16-
label='Username'
17-
/>
18-
</div>
19-
<div>
20-
<Field
21-
name='email'
22-
component={TextField}
23-
label='Email'
24-
/>
25-
</div>
15+
<Field
16+
name='displayName'
17+
component={TextField}
18+
label='Name'
19+
/>
20+
<Field
21+
name='email'
22+
component={TextField}
23+
label='Email'
24+
/>
2625
<div>
2726
<h4>Linked Accounts</h4>
2827
{
29-
account.providerData &&
30-
<ProviderDataForm providerData={account.providerData} />
28+
account.providerData
29+
?
30+
<List>
31+
{
32+
account.providerData.map((providerAccount, i) =>
33+
<ListItem
34+
key={i}
35+
primaryText={providerAccount.providerId}
36+
leftIcon={<AccountCircle />}
37+
nestedItems={[
38+
<ListItem
39+
key='display_name'
40+
primaryText={providerAccount.displayName}
41+
/>,
42+
<ListItem
43+
key='email'
44+
label='email'
45+
primaryText={providerAccount.email}
46+
disabled
47+
/>
48+
]}
49+
/>
50+
)
51+
}
52+
</List>
53+
:
54+
null
3155
}
3256
</div>
33-
</div>
57+
<div>
58+
<RaisedButton
59+
label='Save'
60+
primary
61+
type='submit'
62+
onTouchTap={submitForm}
63+
disabled={submitting}
64+
/>
65+
</div>
66+
</form>
3467
)
3568

3669
AccountForm.propTypes = {
@@ -40,4 +73,14 @@ AccountForm.propTypes = {
4073
handleSubmit: PropTypes.func,
4174
submitting: PropTypes.bool
4275
}
43-
export default AccountForm
76+
77+
const form = reduxForm({
78+
form: ACCOUNT_FORM_NAME,
79+
enableReinitialization: true
80+
})(AccountForm)
81+
82+
export default connect(
83+
({ firebase }) => ({
84+
initialValues: pathToJS(firebase, 'profile')
85+
}),
86+
)(form)

examples/complete/material/src/routes/Account/containers/AccountContainer.js

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import Paper from 'material-ui/Paper'
33
import { connect } from 'react-redux'
44
import { reduxForm } from 'redux-form'
55
import { firebaseConnect, pathToJS, isLoaded } from 'react-redux-firebase'
6+
import { submit } from 'redux-form'
7+
import { reduxFirebase as rfConfig } from 'config'
68
import { ACCOUNT_FORM_NAME } from 'constants/formNames'
79
import { UserIsAuthenticated } from 'utils/router'
810
import defaultUserImageUrl from 'static/User.png'
@@ -11,31 +13,25 @@ import AccountForm from '../components/AccountForm/AccountForm'
1113
import classes from './AccountContainer.scss'
1214

1315
@UserIsAuthenticated // redirect to /login if user is not authenticated
14-
@firebaseConnect()
16+
@firebaseConnect() // add this.props.firebase
1517
@connect(
16-
// Map state to props
18+
// Map redux state to props
1719
({ firebase }) => ({
18-
authError: pathToJS(firebase, 'authError'),
20+
auth: pathToJS(firebase, 'auth'),
1921
account: pathToJS(firebase, 'profile'),
20-
initialValues: pathToJS(firebase, 'profile')
21-
})
22+
}),
23+
{
24+
// action for submitting redux-form
25+
submitForm: () => (dispatch) => dispatch(submit(ACCOUNT_FORM_NAME))
26+
}
2227
)
23-
@reduxForm({
24-
form: ACCOUNT_FORM_NAME,
25-
enableReinitialization: true
26-
})
2728
export default class Account extends Component {
28-
29-
static contextTypes = {
30-
router: React.PropTypes.object.isRequired
31-
}
32-
3329
static propTypes = {
3430
account: PropTypes.object,
3531
firebase: PropTypes.shape({
32+
update: PropTypes.func.isRequired,
3633
logout: PropTypes.func.isRequired,
37-
uploadAvatar: PropTypes.func,
38-
updateAccount: PropTypes.func
34+
uploadAvatar: PropTypes.func
3935
})
4036
}
4137

@@ -51,8 +47,17 @@ export default class Account extends Component {
5147
})
5248
}
5349

50+
updateAccount = (newData) => {
51+
return this.props.firebase
52+
.update(`${rfConfig.userProfile}/${this.props.auth.uid}`, newData)
53+
.catch((err) => {
54+
console.error('Error updating account', err)
55+
// TODO: Display error to user
56+
})
57+
}
58+
5459
render () {
55-
const { account, firebase: { saveAccount } } = this.props
60+
const { account, submitForm } = this.props
5661

5762
if (!isLoaded(account)) {
5863
return <LoadingSpinner />
@@ -71,8 +76,9 @@ export default class Account extends Component {
7176
</div>
7277
<div className={classes.meta}>
7378
<AccountForm
74-
onSubmit={saveAccount}
7579
account={account}
80+
submitForm={submitForm}
81+
onSubmit={this.updateAccount}
7682
/>
7783
</div>
7884
</div>
@@ -81,3 +87,4 @@ export default class Account extends Component {
8187
)
8288
}
8389
}
90+
0
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React, { PropTypes } from 'react'
2+
import { connect } from 'react-redux'
3+
import { Field, reduxForm, submit } from 'redux-form'
4+
import { firebaseConnect, pathToJS, isLoaded } from 'react-redux-firebase'
5+
import RaisedButton from 'material-ui/RaisedButton'
6+
import TextField from 'components/TextField'
7+
import { List, ListItem } from 'material-ui/List'
8+
import AccountCircle from 'material-ui/svg-icons/action/account-circle'
9+
import { RECOVER_EMAIL_FORM_NAME } from 'constants/formNames'
10+
import classes from './EmailForm.scss'
11+
12+
const required = value => value ? undefined : 'Required'
13+
const email = value =>
14+
value && !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value) ?
15+
'Invalid email address' : undefined
16+
17+
export const EmailForm = ({ account, handleSubmit, submitting, pristine, valid }) => (
18+
<form className={classes.container} onSubmit={handleSubmit}>
19+
<h4>Send Recovery Code To Email</h4>
20+
<Field
21+
name='email'
22+
component={TextField}
23+
label='Email'
24+
validate={[required, email]}
25+
/>
26+
<div className={classes.submit}>
27+
<RaisedButton
28+
label='Send'
29+
primary
30+
type='submit'
31+
disabled={submitting}
32+
/>
33+
</div>
34+
</form>
35+
)
36+
37+
EmailForm.propTypes = {
38+
account: PropTypes.shape({
39+
providerData: PropTypes.array
40+
}),
41+
handleSubmit: PropTypes.func.isRequired,
42+
submitting: PropTypes.bool
43+
}
44+
45+
export default reduxForm({
46+
form: RECOVER_EMAIL_FORM_NAME
47+
})(EmailForm)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@import 'base';
2+
3+
.container {
4+
@extend .flex-column-center;
5+
padding: 3rem;
6+
}
7+
8+
.submit {
9+
margin-top: 2rem;
10+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import EmailForm from './EmailForm'
2+
3+
export default EmailForm
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React, { PropTypes } from 'react'
2+
import { connect } from 'react-redux'
3+
import { Field, reduxForm, submit } from 'redux-form'
4+
import { firebaseConnect, pathToJS, isLoaded } from 'react-redux-firebase'
5+
import RaisedButton from 'material-ui/RaisedButton'
6+
import Subheader from 'material-ui/Subheader'
7+
import TextField from 'components/TextField'
8+
import { List, ListItem } from 'material-ui/List'
9+
import AccountCircle from 'material-ui/svg-icons/action/account-circle'
10+
import { RECOVER_CODE_FORM_NAME } from 'constants/formNames'
11+
import classes from './RecoverForm.scss'
12+
13+
const required = value => value ? undefined : 'Required'
14+
15+
export const RecoverForm = ({ account, handleSubmit, onRecoverClick, submitting, pristine, valid }) => (
16+
<form className={classes.container} onSubmit={handleSubmit}>
17+
<h4>Recover Using Code From Email</h4>
18+
<div>
19+
<Subheader>
20+
<strong>Note:</strong> Not used for OAuth
21+
</Subheader>
22+
</div>
23+
<Field
24+
name='code'
25+
component={TextField}
26+
label='Recover Code'
27+
validate={[required]}
28+
/>
29+
<Field
30+
name='password'
31+
component={TextField}
32+
label='New Password'
33+
validate={[required]}
34+
/>
35+
<div className={classes.submit}>
36+
<RaisedButton
37+
label='Recover'
38+
primary
39+
type='submit'
40+
disabled={submitting}
41+
/>
42+
</div>
43+
</form>
44+
)
45+
46+
RecoverForm.propTypes = {
47+
account: PropTypes.shape({
48+
providerData: PropTypes.array
49+
}),
50+
handleSubmit: PropTypes.func,
51+
onRecoverClick: PropTypes.func,
52+
submitting: PropTypes.bool
53+
}
54+
55+
export default reduxForm({
56+
form: RECOVER_CODE_FORM_NAME
57+
})(RecoverForm)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@import 'base';
2+
3+
.container {
4+
@extend .flex-column-center;
5+
padding: 3rem;
6+
}
7+
8+
.submit {
9+
margin-top: 2rem;
10+
}

0 commit comments

Comments
 (0)