From 3798e402dfe774ec50e6dd542943af951cdd304e Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月20日 09:23:22 +0800
Subject: [PATCH 01/36] access hsitory directly from props
---
.gitignore | 2 ++
src/components/SignIn/index.js | 4 +---
src/components/SignUp/index.js | 4 +---
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index f53349d9..f5c26112 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,8 @@
# misc
.DS_Store
.env
+.env.development
+.env.production
.env.local
.env.development.local
.env.test.local
diff --git a/src/components/SignIn/index.js b/src/components/SignIn/index.js
index 56ef13f9..e6f83705 100644
--- a/src/components/SignIn/index.js
+++ b/src/components/SignIn/index.js
@@ -32,13 +32,11 @@ class SignInFormBase extends Component {
onSubmit = event => {
const { email, password } = this.state;
- const { history } = this.props;
-
this.props.firebase
.doSignInWithEmailAndPassword(email, password)
.then(() => {
this.setState({ ...INITIAL_STATE });
- history.push(ROUTES.HOME);
+ this.props.history.push(ROUTES.HOME);
})
.catch(error => {
this.setState({ error });
diff --git a/src/components/SignUp/index.js b/src/components/SignUp/index.js
index 5fd525af..fbddbeca 100644
--- a/src/components/SignUp/index.js
+++ b/src/components/SignUp/index.js
@@ -37,8 +37,6 @@ class SignUpFormBase extends Component {
roles.push(ROLES.ADMIN);
}
- const { history } = this.props;
-
this.props.firebase
.doCreateUserWithEmailAndPassword(email, passwordOne)
.then(authUser => {
@@ -52,7 +50,7 @@ class SignUpFormBase extends Component {
})
.then(() => {
this.setState({ ...INITIAL_STATE });
- history.push(ROUTES.HOME);
+ this.props.history.push(ROUTES.HOME);
})
.catch(error => {
this.setState({ error });
From 0bb3aef7ba70af7123396dad670fc1219e912993 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月20日 12:22:19 +0800
Subject: [PATCH 02/36] clean up Session module
---
src/components/Account/index.js | 15 ++++++++-------
src/components/Admin/index.js | 2 +-
src/components/App/index.js | 2 +-
src/components/Home/index.js | 3 +--
src/components/Navigation/index.js | 2 +-
.../Session/{AuthUserContext.js => context.js} | 0
src/components/Session/index.js | 5 +++++
src/components/Session/withAuthentication.js | 2 +-
src/components/Session/withAuthorization.js | 2 +-
9 files changed, 19 insertions(+), 14 deletions(-)
rename src/components/Session/{AuthUserContext.js => context.js} (100%)
create mode 100644 src/components/Session/index.js
diff --git a/src/components/Account/index.js b/src/components/Account/index.js
index 10c59c81..cdaaf11d 100644
--- a/src/components/Account/index.js
+++ b/src/components/Account/index.js
@@ -1,21 +1,22 @@
import React from 'react';
-import AuthUserContext from '../Session/AuthUserContext';
+import { AuthUserContext } from '../Session';
import { PasswordForgetForm } from '../PasswordForget';
import PasswordChangeForm from '../PasswordChange';
-import withAuthorization from '../Session/withAuthorization';
+import { withAuthorization } from '../Session';
-const AccountPage = () =>
+const AccountPage = () => (
- {authUser =>
+ {authUser => (
Account: {authUser.email}
- }
+ )}
+);
-const authCondition = (authUser) => !!authUser;
+const authCondition = authUser => !!authUser;
-export default withAuthorization(authCondition)(AccountPage);
\ No newline at end of file
+export default withAuthorization(authCondition)(AccountPage);
diff --git a/src/components/Admin/index.js b/src/components/Admin/index.js
index 5f005de8..166d4f5c 100644
--- a/src/components/Admin/index.js
+++ b/src/components/Admin/index.js
@@ -2,8 +2,8 @@ import React, { Component } from 'react';
import { compose } from 'recompose';
import { withFirebase } from '../Firebase';
+import { withAuthorization } from '../Session';
import * as ROLES from '../../constants/roles';
-import withAuthorization from '../Session/withAuthorization';
class AdminPage extends Component {
constructor(props) {
diff --git a/src/components/App/index.js b/src/components/App/index.js
index 8492d3e1..4a2fbb21 100644
--- a/src/components/App/index.js
+++ b/src/components/App/index.js
@@ -9,7 +9,7 @@ import PasswordForgetPage from '../PasswordForget';
import HomePage from '../Home';
import AccountPage from '../Account';
import AdminPage from '../Admin';
-import withAuthentication from '../Session/withAuthentication';
+import { withAuthentication } from '../Session';
import * as ROUTES from '../../constants/routes';
import './index.css';
diff --git a/src/components/Home/index.js b/src/components/Home/index.js
index bde121d5..35230fc6 100644
--- a/src/components/Home/index.js
+++ b/src/components/Home/index.js
@@ -1,8 +1,7 @@
import React, { Component } from 'react';
import { compose } from 'recompose';
-import AuthUserContext from '../Session/AuthUserContext';
-import withAuthorization from '../Session/withAuthorization';
+import { AuthUserContext, withAuthorization } from '../Session';
import { withFirebase } from '../Firebase';
class HomePage extends Component {
diff --git a/src/components/Navigation/index.js b/src/components/Navigation/index.js
index df9c0c47..156e27ae 100644
--- a/src/components/Navigation/index.js
+++ b/src/components/Navigation/index.js
@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
-import AuthUserContext from '../Session/AuthUserContext';
+import { AuthUserContext } from '../Session';
import SignOutButton from '../SignOut';
import * as ROUTES from '../../constants/routes';
import * as ROLES from '../../constants/roles';
diff --git a/src/components/Session/AuthUserContext.js b/src/components/Session/context.js
similarity index 100%
rename from src/components/Session/AuthUserContext.js
rename to src/components/Session/context.js
diff --git a/src/components/Session/index.js b/src/components/Session/index.js
new file mode 100644
index 00000000..c13e0265
--- /dev/null
+++ b/src/components/Session/index.js
@@ -0,0 +1,5 @@
+import AuthUserContext from './context';
+import withAuthentication from './withAuthentication';
+import withAuthorization from './withAuthorization';
+
+export { AuthUserContext, withAuthentication, withAuthorization };
diff --git a/src/components/Session/withAuthentication.js b/src/components/Session/withAuthentication.js
index 2a92fd6a..6dbe2aaf 100644
--- a/src/components/Session/withAuthentication.js
+++ b/src/components/Session/withAuthentication.js
@@ -1,6 +1,6 @@
import React from 'react';
-import AuthUserContext from './AuthUserContext';
+import AuthUserContext from './context';
import { withFirebase } from '../Firebase';
const withAuthentication = Component => {
diff --git a/src/components/Session/withAuthorization.js b/src/components/Session/withAuthorization.js
index 2e899818..7230c6ee 100644
--- a/src/components/Session/withAuthorization.js
+++ b/src/components/Session/withAuthorization.js
@@ -2,7 +2,7 @@ import React from 'react';
import { withRouter } from 'react-router-dom';
import { compose } from 'recompose';
-import AuthUserContext from './AuthUserContext';
+import AuthUserContext from './context';
import { withFirebase } from '../Firebase';
import * as ROUTES from '../../constants/routes';
From a65b43ab68afcac26a64e472c3d8805f9ce64369 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月20日 18:44:47 +0800
Subject: [PATCH 03/36] authcondition to condition
---
src/components/Account/index.js | 4 ++--
src/components/Admin/index.js | 4 ++--
src/components/Home/index.js | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/components/Account/index.js b/src/components/Account/index.js
index cdaaf11d..e5c8ad40 100644
--- a/src/components/Account/index.js
+++ b/src/components/Account/index.js
@@ -17,6 +17,6 @@ const AccountPage = () => (
);
-const authCondition = authUser => !!authUser;
+const condition = authUser => !!authUser;
-export default withAuthorization(authCondition)(AccountPage);
+export default withAuthorization(condition)(AccountPage);
diff --git a/src/components/Admin/index.js b/src/components/Admin/index.js
index 166d4f5c..e3c62800 100644
--- a/src/components/Admin/index.js
+++ b/src/components/Admin/index.js
@@ -84,10 +84,10 @@ const UserList = ({ users, onRemove }) => (
);
-const authCondition = authUser =>
+const condition = authUser =>
authUser && authUser.roles.includes(ROLES.ADMIN);
export default compose(
- withAuthorization(authCondition),
+ withAuthorization(condition),
withFirebase,
)(AdminPage);
diff --git a/src/components/Home/index.js b/src/components/Home/index.js
index 35230fc6..001c5652 100644
--- a/src/components/Home/index.js
+++ b/src/components/Home/index.js
@@ -122,9 +122,9 @@ const MessageItem = ({ message, user }) => (
);
-const authCondition = authUser => !!authUser;
+const condition = authUser => !!authUser;
export default compose(
- withAuthorization(authCondition),
+ withAuthorization(condition),
withFirebase,
)(HomePage);
From 2d4ef4ed4d0ec7ee26372c816297b948948434b4 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月22日 09:24:56 +0800
Subject: [PATCH 04/36] add social login google
---
src/components/Firebase/firebase.js | 5 +++
src/components/SignIn/index.js | 55 ++++++++++++++++++++++++++++-
src/components/SignUp/index.js | 2 +-
3 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/src/components/Firebase/firebase.js b/src/components/Firebase/firebase.js
index cc9b55a0..0041567f 100644
--- a/src/components/Firebase/firebase.js
+++ b/src/components/Firebase/firebase.js
@@ -29,6 +29,8 @@ class Firebase {
this.db = app.database();
this.auth = app.auth();
+
+ this.googleProvider = new app.auth.GoogleAuthProvider();
}
// *** Auth API ***
@@ -39,6 +41,9 @@ class Firebase {
doSignInWithEmailAndPassword = (email, password) =>
this.auth.signInWithEmailAndPassword(email, password);
+ doSignInWithGoogle = () =>
+ this.auth.signInWithPopup(new app.auth.GoogleAuthProvider());
+
doSignOut = () => this.auth.signOut();
doPasswordReset = email => this.auth.sendPasswordResetEmail(email);
diff --git a/src/components/SignIn/index.js b/src/components/SignIn/index.js
index e6f83705..001ba519 100644
--- a/src/components/SignIn/index.js
+++ b/src/components/SignIn/index.js
@@ -11,6 +11,7 @@ const SignInPage = () => (
@@ -80,11 +81,63 @@ class SignInFormBase extends Component {
}
}
+class SignInGoogleBase extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = { error: null };
+ }
+
+ onSubmit = event => {
+ this.props.firebase
+ .doSignInWithGoogle()
+ .then(socialAuthUser => {
+ // Create a user in your Firebase Realtime Database too
+ this.props.firebase
+ .user(socialAuthUser.user.uid)
+ .set({
+ username: socialAuthUser.user.displayName,
+ email: socialAuthUser.user.email,
+ roles: [],
+ })
+ .then(() => {
+ this.setState({ error: null });
+ this.props.history.push(ROUTES.HOME);
+ })
+ .catch(error => {
+ this.setState({ error });
+ });
+ })
+ .catch(error => {
+ this.setState({ error });
+ });
+
+ event.preventDefault();
+ };
+
+ render() {
+ const { error } = this.state;
+
+ return (
+
+ );
+ }
+}
+
const SignInForm = compose(
withRouter,
withFirebase,
)(SignInFormBase);
+const SignInGoogle = compose(
+ withRouter,
+ withFirebase,
+)(SignInGoogleBase);
+
export default SignInPage;
-export { SignInForm };
+export { SignInForm, SignInGoogle };
diff --git a/src/components/SignUp/index.js b/src/components/SignUp/index.js
index fbddbeca..e69e63e6 100644
--- a/src/components/SignUp/index.js
+++ b/src/components/SignUp/index.js
@@ -40,7 +40,7 @@ class SignUpFormBase extends Component {
this.props.firebase
.doCreateUserWithEmailAndPassword(email, passwordOne)
.then(authUser => {
- // Create a user in your own accessible Firebase Database too
+ // Create a user in your Firebase Realtime Database too
this.props.firebase
.user(authUser.user.uid)
.set({
From 83ed4e85d489b6485226c23d640ade911125a8ef Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月22日 10:59:49 +0800
Subject: [PATCH 05/36] add social login facebook
---
src/components/Firebase/firebase.js | 6 +++-
src/components/SignIn/index.js | 55 ++++++++++++++++++++++++++++-
2 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/src/components/Firebase/firebase.js b/src/components/Firebase/firebase.js
index 0041567f..2fa78706 100644
--- a/src/components/Firebase/firebase.js
+++ b/src/components/Firebase/firebase.js
@@ -31,6 +31,7 @@ class Firebase {
this.auth = app.auth();
this.googleProvider = new app.auth.GoogleAuthProvider();
+ this.facebookProvider = new app.auth.FacebookAuthProvider();
}
// *** Auth API ***
@@ -42,7 +43,10 @@ class Firebase {
this.auth.signInWithEmailAndPassword(email, password);
doSignInWithGoogle = () =>
- this.auth.signInWithPopup(new app.auth.GoogleAuthProvider());
+ this.auth.signInWithPopup(this.googleProvider);
+
+ doSignInWithFacebook = () =>
+ this.auth.signInWithPopup(this.facebookProvider);
doSignOut = () => this.auth.signOut();
diff --git a/src/components/SignIn/index.js b/src/components/SignIn/index.js
index 001ba519..75d5df13 100644
--- a/src/components/SignIn/index.js
+++ b/src/components/SignIn/index.js
@@ -12,6 +12,7 @@ const SignInPage = () => (
SignIn
+
@@ -128,6 +129,53 @@ class SignInGoogleBase extends Component {
}
}
+class SignInFacebookBase extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = { error: null };
+ }
+
+ onSubmit = event => {
+ this.props.firebase
+ .doSignInWithFacebook()
+ .then(socialAuthUser => {
+ // Create a user in your Firebase Realtime Database too
+ this.props.firebase
+ .user(socialAuthUser.user.uid)
+ .set({
+ username: socialAuthUser.additionalUserInfo.profile.name,
+ email: socialAuthUser.additionalUserInfo.profile.email,
+ roles: [],
+ })
+ .then(() => {
+ this.setState({ error: null });
+ this.props.history.push(ROUTES.HOME);
+ })
+ .catch(error => {
+ this.setState({ error });
+ });
+ })
+ .catch(error => {
+ this.setState({ error });
+ });
+
+ event.preventDefault();
+ };
+
+ render() {
+ const { error } = this.state;
+
+ return (
+
+ );
+ }
+}
+
const SignInForm = compose(
withRouter,
withFirebase,
@@ -138,6 +186,11 @@ const SignInGoogle = compose(
withFirebase,
)(SignInGoogleBase);
+const SignInFacebook = compose(
+ withRouter,
+ withFirebase,
+)(SignInFacebookBase);
+
export default SignInPage;
-export { SignInForm, SignInGoogle };
+export { SignInForm, SignInGoogle, SignInFacebook };
From 33e2ca5c04b70bc6be52d9129670273cb17abe37 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月22日 11:38:16 +0800
Subject: [PATCH 06/36] add social login twitter 1/2
---
src/components/Firebase/firebase.js | 4 +++
src/components/SignIn/index.js | 45 ++++++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/src/components/Firebase/firebase.js b/src/components/Firebase/firebase.js
index 2fa78706..46fc9af9 100644
--- a/src/components/Firebase/firebase.js
+++ b/src/components/Firebase/firebase.js
@@ -32,6 +32,7 @@ class Firebase {
this.googleProvider = new app.auth.GoogleAuthProvider();
this.facebookProvider = new app.auth.FacebookAuthProvider();
+ this.twitterProvider = new app.auth.TwitterAuthProvider();
}
// *** Auth API ***
@@ -48,6 +49,9 @@ class Firebase {
doSignInWithFacebook = () =>
this.auth.signInWithPopup(this.facebookProvider);
+ doSignInWithTwitter = () =>
+ this.auth.signInWithPopup(this.twitterProvider);
+
doSignOut = () => this.auth.signOut();
doPasswordReset = email => this.auth.sendPasswordResetEmail(email);
diff --git a/src/components/SignIn/index.js b/src/components/SignIn/index.js
index 75d5df13..3338d28a 100644
--- a/src/components/SignIn/index.js
+++ b/src/components/SignIn/index.js
@@ -13,6 +13,7 @@ const SignInPage = () => (
+
@@ -176,6 +177,43 @@ class SignInFacebookBase extends Component {
}
}
+class SignInTwitterBase extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = { error: null };
+ }
+
+ onSubmit = event => {
+ this.props.firebase
+ .doSignInWithTwitter()
+ .then(socialAuthUser => {
+ // TODO change in Tutorial
+ // TODO change credentials in FIrebase
+ console.log(socialAuthUser);
+ // this.setState({ error: null });
+ // this.props.history.push(ROUTES.HOME);
+ })
+ .catch(error => {
+ this.setState({ error });
+ });
+
+ event.preventDefault();
+ };
+
+ render() {
+ const { error } = this.state;
+
+ return (
+
+ );
+ }
+}
+
const SignInForm = compose(
withRouter,
withFirebase,
@@ -191,6 +229,11 @@ const SignInFacebook = compose(
withFirebase,
)(SignInFacebookBase);
+const SignInTwitter = compose(
+ withRouter,
+ withFirebase,
+)(SignInTwitterBase);
+
export default SignInPage;
-export { SignInForm, SignInGoogle, SignInFacebook };
+export { SignInForm, SignInGoogle, SignInFacebook, SignInTwitter };
From 6a922cc0e8a973e0163b2e9324df1095f3df5f74 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月22日 14:34:44 +0800
Subject: [PATCH 07/36] add social login twitter 2/2
---
src/components/SignIn/index.js | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/components/SignIn/index.js b/src/components/SignIn/index.js
index 3338d28a..e78fc9a7 100644
--- a/src/components/SignIn/index.js
+++ b/src/components/SignIn/index.js
@@ -188,11 +188,21 @@ class SignInTwitterBase extends Component {
this.props.firebase
.doSignInWithTwitter()
.then(socialAuthUser => {
- // TODO change in Tutorial
- // TODO change credentials in FIrebase
- console.log(socialAuthUser);
- // this.setState({ error: null });
- // this.props.history.push(ROUTES.HOME);
+ // Create a user in your Firebase Realtime Database too
+ this.props.firebase
+ .user(socialAuthUser.user.uid)
+ .set({
+ username: socialAuthUser.additionalUserInfo.profile.name,
+ email: socialAuthUser.additionalUserInfo.profile.email,
+ roles: [],
+ })
+ .then(() => {
+ this.setState({ error: null });
+ this.props.history.push(ROUTES.HOME);
+ })
+ .catch(error => {
+ this.setState({ error });
+ });
})
.catch(error => {
this.setState({ error });
From a57e09ba504bd0e989389bde974880eb478b734e Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月22日 18:46:25 +0800
Subject: [PATCH 08/36] give custom error message
---
src/components/SignIn/index.js | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/components/SignIn/index.js b/src/components/SignIn/index.js
index e78fc9a7..7ea11a4b 100644
--- a/src/components/SignIn/index.js
+++ b/src/components/SignIn/index.js
@@ -25,6 +25,16 @@ const INITIAL_STATE = {
error: null,
};
+const ERROR_CODE_ACCOUNT_EXISTS =
+ 'auth/account-exists-with-different-credential';
+
+const ERROR_MSG_ACCOUNT_EXISTS = `
+ An account with an E-Mail address to
+ this social login already exists. Try to login from
+ this account instead and associate your social logins on
+ your account page.
+`;
+
class SignInFormBase extends Component {
constructor(props) {
super(props);
@@ -111,6 +121,10 @@ class SignInGoogleBase extends Component {
});
})
.catch(error => {
+ if (error.code === ERROR_CODE_ACCOUNT_EXISTS) {
+ error.message = ERROR_MSG_ACCOUNT_EXISTS;
+ }
+
this.setState({ error });
});
@@ -158,6 +172,10 @@ class SignInFacebookBase extends Component {
});
})
.catch(error => {
+ if (error.code === ERROR_CODE_ACCOUNT_EXISTS) {
+ error.message = ERROR_MSG_ACCOUNT_EXISTS;
+ }
+
this.setState({ error });
});
@@ -205,6 +223,10 @@ class SignInTwitterBase extends Component {
});
})
.catch(error => {
+ if (error.code === ERROR_CODE_ACCOUNT_EXISTS) {
+ error.message = ERROR_MSG_ACCOUNT_EXISTS;
+ }
+
this.setState({ error });
});
From 2c98263a4ef582a501c0559016f0fa33882b58ab Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月22日 19:33:40 +0800
Subject: [PATCH 09/36] link social accounts: 1
---
src/components/Account/index.js | 80 +++++++++++++++++++++++++++--
src/components/Firebase/firebase.js | 9 ++++
2 files changed, 86 insertions(+), 3 deletions(-)
diff --git a/src/components/Account/index.js b/src/components/Account/index.js
index e5c8ad40..da18a882 100644
--- a/src/components/Account/index.js
+++ b/src/components/Account/index.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import React, { Component } from 'react';
-import { AuthUserContext } from '../Session';
+import { AuthUserContext, withAuthorization } from '../Session';
+import { withFirebase } from '../Firebase';
import { PasswordForgetForm } from '../PasswordForget';
import PasswordChangeForm from '../PasswordChange';
-import { withAuthorization } from '../Session';
const AccountPage = () => (
@@ -12,11 +12,85 @@ const AccountPage = () => (
Account: {authUser.email}
+
)}
);
+class LoginManagementBase extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ activeSignInMethods: [],
+ error: null,
+ };
+ }
+
+ componentDidMount() {
+ this.fetchSignInMethods();
+ }
+
+ fetchSignInMethods = () => {
+ this.props.firebase.auth
+ .fetchSignInMethodsForEmail(this.props.authUser.email)
+ .then(activeSignInMethods =>
+ this.setState({ activeSignInMethods }),
+ );
+ };
+
+ onLinkWithGoogle = () => {
+ this.props.firebase
+ .doLinkWithGoogle()
+ .then(this.fetchSignInMethods)
+ .catch(error => this.setState({ error }));
+ };
+
+ onLinkWithFacebook = () => {
+ this.props.firebase
+ .doLinkWithFacebook()
+ .then(this.fetchSignInMethods)
+ .catch(error => this.setState({ error }));
+ };
+
+ onLinkWithTwitter = () => {
+ this.props.firebase
+ .doLinkWithTwitter()
+ .then(this.fetchSignInMethods)
+ .catch(error => this.setState({ error }));
+ };
+
+ render() {
+ const { activeSignInMethods, error } = this.state;
+
+ return (
+
+
+ Active Sign In Methods:
+
+ {activeSignInMethods.map(login => (
+ {login}
+ ))}
+
+
+ Link Google
+
+
+ Link Facebook
+
+
+ Link Twitter
+
+ {error && error.message}
+
+
+ );
+ }
+}
+
+const LoginManagement = withFirebase(LoginManagementBase);
+
const condition = authUser => !!authUser;
export default withAuthorization(condition)(AccountPage);
diff --git a/src/components/Firebase/firebase.js b/src/components/Firebase/firebase.js
index 46fc9af9..838f9fcd 100644
--- a/src/components/Firebase/firebase.js
+++ b/src/components/Firebase/firebase.js
@@ -52,6 +52,15 @@ class Firebase {
doSignInWithTwitter = () =>
this.auth.signInWithPopup(this.twitterProvider);
+ doLinkWithGoogle = () =>
+ this.auth.currentUser.linkWithPopup(this.googleProvider);
+
+ doLinkWithFacebook = () =>
+ this.auth.currentUser.linkWithPopup(this.facebookProvider);
+
+ doLinkWithTwitter = () =>
+ this.auth.currentUser.linkWithPopup(this.twitterProvider);
+
doSignOut = () => this.auth.signOut();
doPasswordReset = email => this.auth.sendPasswordResetEmail(email);
From 28aad4417406fdb4ddf75f747e8b33ea3834791c Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月22日 20:25:27 +0800
Subject: [PATCH 10/36] link social accounts: 2
---
src/components/Account/index.js | 73 +++++++++++++++++++----------
src/components/Firebase/firebase.js | 9 ----
2 files changed, 47 insertions(+), 35 deletions(-)
diff --git a/src/components/Account/index.js b/src/components/Account/index.js
index da18a882..d527d521 100644
--- a/src/components/Account/index.js
+++ b/src/components/Account/index.js
@@ -18,6 +18,25 @@ const AccountPage = () => (
);
+const SIGN_IN_METHODS = [
+ {
+ id: 'password',
+ provider: '',
+ },
+ {
+ id: 'google.com',
+ provider: 'googleProvider',
+ },
+ {
+ id: 'facebook.com',
+ provider: 'facebookProvider',
+ },
+ {
+ id: 'twitter.com',
+ provider: 'twitterProvider',
+ },
+];
+
class LoginManagementBase extends Component {
constructor(props) {
super(props);
@@ -36,27 +55,21 @@ class LoginManagementBase extends Component {
this.props.firebase.auth
.fetchSignInMethodsForEmail(this.props.authUser.email)
.then(activeSignInMethods =>
- this.setState({ activeSignInMethods }),
- );
- };
-
- onLinkWithGoogle = () => {
- this.props.firebase
- .doLinkWithGoogle()
- .then(this.fetchSignInMethods)
+ this.setState({ activeSignInMethods, error: null }),
+ )
.catch(error => this.setState({ error }));
};
- onLinkWithFacebook = () => {
- this.props.firebase
- .doLinkWithFacebook()
+ onLink = provider => {
+ this.props.firebase.auth.currentUser
+ .linkWithPopup(this.props.firebase[provider])
.then(this.fetchSignInMethods)
.catch(error => this.setState({ error }));
};
- onLinkWithTwitter = () => {
- this.props.firebase
- .doLinkWithTwitter()
+ onUnlink = providerId => {
+ this.props.firebase.auth.currentUser
+ .unlink(providerId)
.then(this.fetchSignInMethods)
.catch(error => this.setState({ error }));
};
@@ -67,21 +80,29 @@ class LoginManagementBase extends Component {
return (
- Active Sign In Methods:
+ Sign In Methods:
- {activeSignInMethods.map(login => (
- {login}
+ {SIGN_IN_METHODS.map(signInMethod => (
+
+ {activeSignInMethods.includes(signInMethod.id) ? (
+ this.onUnlink(signInMethod.id)}
+ disabled={activeSignInMethods.length <= 1} +>
+ Deactivate {signInMethod.id}
+
+ ) : (
+ this.onLink(signInMethod.provider)}
+>
+ Link {signInMethod.id}
+
+ )}
+
))}
-
- Link Google
-
-
- Link Facebook
-
-
- Link Twitter
-
{error && error.message}
diff --git a/src/components/Firebase/firebase.js b/src/components/Firebase/firebase.js
index 838f9fcd..46fc9af9 100644
--- a/src/components/Firebase/firebase.js
+++ b/src/components/Firebase/firebase.js
@@ -52,15 +52,6 @@ class Firebase {
doSignInWithTwitter = () =>
this.auth.signInWithPopup(this.twitterProvider);
- doLinkWithGoogle = () =>
- this.auth.currentUser.linkWithPopup(this.googleProvider);
-
- doLinkWithFacebook = () =>
- this.auth.currentUser.linkWithPopup(this.facebookProvider);
-
- doLinkWithTwitter = () =>
- this.auth.currentUser.linkWithPopup(this.twitterProvider);
-
doSignOut = () => this.auth.signOut();
doPasswordReset = email => this.auth.sendPasswordResetEmail(email);
From 536de624e7727b21968f7b6c69d62f2585ef6201 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年11月23日 09:16:37 +0800
Subject: [PATCH 11/36] link social accounts: 3
---
src/components/Account/index.js | 154 +++++++++++++++++++++++-----
src/components/Firebase/firebase.js | 3 +-
2 files changed, 133 insertions(+), 24 deletions(-)
diff --git a/src/components/Account/index.js b/src/components/Account/index.js
index d527d521..19a7c5ca 100644
--- a/src/components/Account/index.js
+++ b/src/components/Account/index.js
@@ -60,13 +60,25 @@ class LoginManagementBase extends Component {
.catch(error => this.setState({ error }));
};
- onLink = provider => {
+ onSocialLoginLink = provider => {
this.props.firebase.auth.currentUser
.linkWithPopup(this.props.firebase[provider])
.then(this.fetchSignInMethods)
.catch(error => this.setState({ error }));
};
+ onDefaultLoginLink = password => {
+ const credential = this.props.firebase.emailAuthProvider.credential(
+ this.props.authUser.email,
+ password,
+ );
+
+ this.props.firebase.auth.currentUser
+ .linkAndRetrieveDataWithCredential(credential)
+ .then(this.fetchSignInMethods)
+ .catch(error => this.setState({ error }));
+ };
+
onUnlink = providerId => {
this.props.firebase.auth.currentUser
.unlink(providerId)
@@ -79,37 +91,133 @@ class LoginManagementBase extends Component {
return (
-
- Sign In Methods:
-
- {SIGN_IN_METHODS.map(signInMethod => (
+ Sign In Methods:
+
+ {SIGN_IN_METHODS.map(signInMethod => {
+ const onlyOneLeft = activeSignInMethods.length === 1;
+ const isEnabled = activeSignInMethods.includes(
+ signInMethod.id,
+ );
+
+ return (
- {activeSignInMethods.includes(signInMethod.id) ? (
- this.onUnlink(signInMethod.id)}
- disabled={activeSignInMethods.length <= 1} ->
- Deactivate {signInMethod.id}
-
+ {signInMethod.id === 'password' ? (
+
) : (
- this.onLink(signInMethod.provider)}
->
- Link {signInMethod.id}
-
+
)}
- ))}
-
- {error && error.message}
-
+ );
+ })}
+
+ {error && error.message}
);
}
}
+const SocialLoginToggle = ({
+ onlyOneLeft,
+ isEnabled,
+ signInMethod,
+ onLink,
+ onUnlink,
+}) =>
+ isEnabled ? (
+ onUnlink(signInMethod.id)}
+ disabled={onlyOneLeft}
+>
+ Deactivate {signInMethod.id}
+
+ ) : (
+ onLink(signInMethod.provider)}
+>
+ Link {signInMethod.id}
+
+ );
+
+class DefaultLoginToggle extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = { passwordOne: '', passwordTwo: '' };
+ }
+
+ onSubmit = event => {
+ event.preventDefault();
+
+ const { passwordOne } = this.state;
+
+ this.props.onLink(passwordOne);
+ this.setState({ passwordOne: '', passwordTwo: '' });
+ };
+
+ onChange = event => {
+ this.setState({ [event.target.name]: event.target.value });
+ };
+
+ render() {
+ const {
+ onlyOneLeft,
+ isEnabled,
+ signInMethod,
+ onUnlink,
+ } = this.props;
+
+ const { passwordOne, passwordTwo } = this.state;
+
+ const isInvalid =
+ passwordOne !== passwordTwo || passwordOne === '';
+
+ return isEnabled ? (
+ onUnlink(signInMethod.id)}
+ disabled={onlyOneLeft}
+>
+ Deactivate {signInMethod.id}
+
+ ) : (
+
+ );
+ }
+}
+
const LoginManagement = withFirebase(LoginManagementBase);
const condition = authUser => !!authUser;
diff --git a/src/components/Firebase/firebase.js b/src/components/Firebase/firebase.js
index 46fc9af9..20078afe 100644
--- a/src/components/Firebase/firebase.js
+++ b/src/components/Firebase/firebase.js
@@ -27,8 +27,9 @@ class Firebase {
constructor() {
app.initializeApp(config);
- this.db = app.database();
+ this.emailAuthProvider = app.auth.EmailAuthProvider;
this.auth = app.auth();
+ this.db = app.database();
this.googleProvider = new app.auth.GoogleAuthProvider();
this.facebookProvider = new app.auth.FacebookAuthProvider();
From 1f4a77ea901886f23e7c5b772c367a38469a3f80 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Mon, 3 Dec 2018 08:39:02 +0800
Subject: [PATCH 12/36] update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 85d8861b..bd0a5700 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# react-firebase-authentication
-[](https://travis-ci.org/taming-the-state-in-react/react-firebase-authentication) [](https://slack-the-road-to-learn-react.wieruch.com/) [](https://greenkeeper.io/)
+[](https://travis-ci.org/the-road-to-react-with-firebase/react-firebase-authentication) [](https://slack-the-road-to-learn-react.wieruch.com/) [](https://greenkeeper.io/)
* Found in [Taming the State in React](https://roadtoreact.com/course-details?courseId=TAMING_THE_STATE)
* [Live](https://react-firebase-authentication.wieruch.com/)
@@ -27,7 +27,7 @@
## Installation
-* `git clone git@github.com:taming-the-state-in-react/react-firebase-authentication.git`
+* `git clone git@github.com:the-road-to-react-with-firebase/react-firebase-authentication.git`
* `cd react-firebase-authentication`
* `npm install`
* `npm start`
From 92457db6a343d056d4fda774326bb74d70b11973 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Mon, 3 Dec 2018 08:42:51 +0800
Subject: [PATCH 13/36] update README.md
---
README.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index bd0a5700..8bb1e925 100644
--- a/README.md
+++ b/README.md
@@ -15,15 +15,19 @@
* no Redux/MobX
* [Redux Version](https://github.com/taming-the-state-in-react/react-redux-firebase-authentication)
* [MobX Version](https://github.com/taming-the-state-in-react/react-mobx-firebase-authentication)
- * [React's 16.3 context API](https://reactjs.org/blog/2018/03/29/react-v-16-3.html)
* features:
* Sign In
* Sign Up
* Sign Out
* Password Forget
* Password Change
+ * Verification Email
* Protected Routes with Authorization
- * Database: Users
+ * Roles-based Authorization
+ * Social Logins with Google, Facebook and Twitter
+ * Linking of Social Logins on Account dashboard
+ * Auth Persistence with Local Storage
+ * Database with Users and Messages
## Installation
From b38b64c22fd3c2922f67e776ac29a42a4145dc08 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Mon, 3 Dec 2018 08:43:58 +0800
Subject: [PATCH 14/36] update README.md
---
README.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 8bb1e925..1b0a96e9 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,8 @@
[](https://travis-ci.org/the-road-to-react-with-firebase/react-firebase-authentication) [](https://slack-the-road-to-learn-react.wieruch.com/) [](https://greenkeeper.io/)
-* Found in [Taming the State in React](https://roadtoreact.com/course-details?courseId=TAMING_THE_STATE)
-* [Live](https://react-firebase-authentication.wieruch.com/)
* [Tutorial](https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/)
+* [Live Version of half of the Tutorial](https://react-firebase-authentication.wieruch.com/)
## Features
From 34199a198bd489f17e693744b9f97d790fced971 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Mon, 3 Dec 2018 11:17:18 +0800
Subject: [PATCH 15/36] deploy to firebase
---
.gitignore | 8 ++++++++
firebase.json | 16 ++++++++++++++++
2 files changed, 24 insertions(+)
create mode 100644 firebase.json
diff --git a/.gitignore b/.gitignore
index f5c26112..13c55066 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,8 @@
# misc
.DS_Store
+
+# env
.env
.env.development
.env.production
@@ -19,6 +21,12 @@
.env.test.local
.env.production.local
+# log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+
+# firebase
+
+.firebase
+.firebaserc
diff --git a/firebase.json b/firebase.json
new file mode 100644
index 00000000..340ed5b7
--- /dev/null
+++ b/firebase.json
@@ -0,0 +1,16 @@
+{
+ "hosting": {
+ "public": "build",
+ "ignore": [
+ "firebase.json",
+ "**/.*",
+ "**/node_modules/**"
+ ],
+ "rewrites": [
+ {
+ "source": "**",
+ "destination": "/index.html"
+ }
+ ]
+ }
+}
From ef6150035183a77ee533575490a648650daef3f8 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Mon, 3 Dec 2018 11:21:35 +0800
Subject: [PATCH 16/36] update installation instructions
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 1b0a96e9..ad04b235 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,6 @@
### Use your own Firebase Credentials
-* visit https://firebase.google.com/ and create a Firebase App
-* copy and paste your Credentials from your Firebase App into src/firebase/firebase.js
-* activate Email/Password Sign-In Method in your Firebase App
+* visit https://firebase.google.com and create a Firebase App
+* copy and paste your Credentials from your Firebase App into *src/components/Firebase/firebase.js* file or in .env file
+* activate Email/Password, Google, Facebook and Twitter Sign-In Methods for your Firebase App
From bffcfe82f1e9696f29d7dfe7e61432b9f6707c15 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Mon, 3 Dec 2018 11:26:52 +0800
Subject: [PATCH 17/36] adjust version
---
LICENSE | 21 ---------------------
package.json | 2 +-
2 files changed, 1 insertion(+), 22 deletions(-)
delete mode 100644 LICENSE
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index a4c00ae1..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018 Robin Wieruch
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/package.json b/package.json
index c6cce3df..1eb98e4c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-firebase-authentication",
- "version": "0.1.0",
+ "version": "0.2.0",
"private": true,
"dependencies": {
"firebase": "^5.6.0",
From ee909897dd697e47a59cb7d38ed2b5fe9656d1bb Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Tue, 4 Dec 2018 21:31:17 +0800
Subject: [PATCH 18/36] 20-How to use Firebase Realtime Database in React
---
src/components/Home/index.js | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/src/components/Home/index.js b/src/components/Home/index.js
index 0b7828f4..4e29b76f 100644
--- a/src/components/Home/index.js
+++ b/src/components/Home/index.js
@@ -13,17 +13,14 @@ class HomePage extends Component {
super(props);
this.state = {
- loading: false,
users: null,
};
}
componentDidMount() {
- this.setState({ loading: true });
this.props.firebase.users().on('value', snapshot => {
this.setState({
users: snapshot.val(),
- loading: false,
});
});
}
@@ -33,14 +30,12 @@ class HomePage extends Component {
}
render() {
- const { users, loading } = this.state;
-
return (
Home Page
The Home Page is accessible by every signed in user.
-
+
);
}
@@ -128,7 +123,7 @@ class MessagesBase extends Component {
};
render() {
- const { users, usersLoading } = this.props;
+ const { users } = this.props;
const { text, messages, loading } = this.state;
return (
@@ -141,13 +136,15 @@ class MessagesBase extends Component {
)}
- {loading && usersLoading && Loading ...
}
+ {loading && Loading ...
}
- {users && messages && (
+ {messages && (
({
...message,
- user: users[message.userId],
+ user: users
+ ? users[message.userId]
+ : { userId: message.userId },
}))}
onEditMessage={this.onEditMessage}
onRemoveMessage={this.onRemoveMessage}
@@ -233,8 +230,10 @@ class MessageItem extends Component {
/>
) : (
- {message.user.username} {message.text}{' '}
- {message.editedAt && (Edited) }
+
+ {message.user.username || message.user.userId}
+ {' '}
+ {message.text} {message.editedAt && (Edited) }
)}
From 6f66bb9f7dacc172e47018e2328a4353fbeb9dda Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Tue, 4 Dec 2018 21:55:18 +0800
Subject: [PATCH 19/36] 20-Refactor Exercise
---
src/components/Admin/index.js | 148 +---------------
src/components/Home/index.js | 227 +------------------------
src/components/Messages/MessageItem.js | 73 ++++++++
src/components/Messages/MessageList.js | 22 +++
src/components/Messages/Messages.js | 138 +++++++++++++++
src/components/Messages/index.js | 3 +
src/components/Users/UserItem.js | 75 ++++++++
src/components/Users/UserList.js | 76 +++++++++
src/components/Users/index.js | 4 +
9 files changed, 396 insertions(+), 370 deletions(-)
create mode 100644 src/components/Messages/MessageItem.js
create mode 100644 src/components/Messages/MessageList.js
create mode 100644 src/components/Messages/Messages.js
create mode 100644 src/components/Messages/index.js
create mode 100644 src/components/Users/UserItem.js
create mode 100644 src/components/Users/UserList.js
create mode 100644 src/components/Users/index.js
diff --git a/src/components/Admin/index.js b/src/components/Admin/index.js
index 79d7ea66..cd0c7b63 100644
--- a/src/components/Admin/index.js
+++ b/src/components/Admin/index.js
@@ -1,9 +1,9 @@
-import React, { Component } from 'react';
-import { Switch, Route, Link } from 'react-router-dom';
+import React from 'react';
+import { Switch, Route } from 'react-router-dom';
import { compose } from 'recompose';
-import { withFirebase } from '../Firebase';
import { withAuthorization, withEmailVerification } from '../Session';
+import { UserList, UserItem } from '../Users';
import * as ROLES from '../../constants/roles';
import * as ROUTES from '../../constants/routes';
@@ -19,148 +19,6 @@ const AdminPage = () => (
);
-class UserListBase extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- loading: false,
- users: [],
- };
- }
-
- componentDidMount() {
- this.setState({ loading: true });
-
- this.props.firebase.users().on('value', snapshot => {
- const usersObject = snapshot.val();
-
- const usersList = Object.keys(usersObject).map(key => ({
- ...usersObject[key],
- uid: key,
- }));
-
- this.setState({
- users: usersList,
- loading: false,
- });
- });
- }
-
- componentWillUnmount() {
- this.props.firebase.users().off();
- }
-
- render() {
- const { users, loading } = this.state;
-
- return (
-
-
Users
- {loading &&
Loading ...
}
-
- {users.map(user => (
-
-
- ID: {user.uid}
-
-
- E-Mail: {user.email}
-
-
- Username: {user.username}
-
-
-
- Details
-
-
-
- ))}
-
-
- );
- }
-}
-
-class UserItemBase extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- loading: false,
- user: null,
- ...props.location.state,
- };
- }
-
- componentDidMount() {
- if (this.state.user) {
- return;
- }
-
- this.setState({ loading: true });
-
- this.props.firebase
- .user(this.props.match.params.id)
- .on('value', snapshot => {
- this.setState({
- user: snapshot.val(),
- loading: false,
- });
- });
- }
-
- componentWillUnmount() {
- this.props.firebase.user(this.props.match.params.id).off();
- }
-
- onSendPasswordResetEmail = () => {
- this.props.firebase.doPasswordReset(this.state.user.email);
- };
-
- render() {
- const { user, loading } = this.state;
-
- return (
-
-
User ({this.props.match.params.id})
- {loading &&
Loading ...
}
-
- {user && (
-
-
- ID: {user.uid}
-
-
- E-Mail: {user.email}
-
-
- Username: {user.username}
-
-
-
- Send Password Reset
-
-
-
- )}
-
- );
- }
-}
-
-const UserList = withFirebase(UserListBase);
-const UserItem = withFirebase(UserItemBase);
-
const condition = authUser =>
authUser && authUser.roles.includes(ROLES.ADMIN);
diff --git a/src/components/Home/index.js b/src/components/Home/index.js
index 4e29b76f..0bec512b 100644
--- a/src/components/Home/index.js
+++ b/src/components/Home/index.js
@@ -1,12 +1,9 @@
import React, { Component } from 'react';
import { compose } from 'recompose';
-import {
- AuthUserContext,
- withAuthorization,
- withEmailVerification,
-} from '../Session';
+import { withAuthorization, withEmailVerification } from '../Session';
import { withFirebase } from '../Firebase';
+import Messages from '../Messages';
class HomePage extends Component {
constructor(props) {
@@ -41,226 +38,6 @@ class HomePage extends Component {
}
}
-class MessagesBase extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- text: '',
- loading: false,
- messages: [],
- limit: 5,
- };
- }
-
- componentDidMount() {
- this.onListenForMessages();
- }
-
- onListenForMessages = () => {
- this.setState({ loading: true });
-
- this.props.firebase
- .messages()
- .orderByChild('createdAt')
- .limitToLast(this.state.limit)
- .on('value', snapshot => {
- const messageObject = snapshot.val();
-
- if (messageObject) {
- const messageList = Object.keys(messageObject).map(key => ({
- ...messageObject[key],
- uid: key,
- }));
-
- this.setState({
- messages: messageList,
- loading: false,
- });
- } else {
- this.setState({ messages: null, loading: false });
- }
- });
- };
-
- componentWillUnmount() {
- this.props.firebase.messages().off();
- }
-
- onChangeText = event => {
- this.setState({ text: event.target.value });
- };
-
- onCreateMessage = (event, authUser) => {
- this.props.firebase.messages().push({
- text: this.state.text,
- userId: authUser.uid,
- createdAt: this.props.firebase.serverValue.TIMESTAMP,
- });
-
- this.setState({ text: '' });
-
- event.preventDefault();
- };
-
- onEditMessage = (message, text) => {
- this.props.firebase.message(message.uid).set({
- ...message,
- text,
- editedAt: this.props.firebase.serverValue.TIMESTAMP,
- });
- };
-
- onRemoveMessage = uid => {
- this.props.firebase.message(uid).remove();
- };
-
- onNextPage = () => {
- this.setState(
- state => ({ limit: state.limit + 5 }),
- this.onListenForMessages,
- );
- };
-
- render() {
- const { users } = this.props;
- const { text, messages, loading } = this.state;
-
- return (
-
- {authUser => (
-
- {!loading && messages && (
-
- More
-
- )}
-
- {loading &&
Loading ...
}
-
- {messages && (
-
({
- ...message,
- user: users
- ? users[message.userId]
- : { userId: message.userId },
- }))}
- onEditMessage={this.onEditMessage}
- onRemoveMessage={this.onRemoveMessage}
- />
- )}
-
- {!messages && There are no messages ...
}
-
-
-
- )}
-
- );
- }
-}
-
-const MessageList = ({
- messages,
- onEditMessage,
- onRemoveMessage,
-}) => (
-
- {messages.map(message => (
-
- ))}
-
-);
-
-class MessageItem extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- editMode: false,
- editText: this.props.message.text,
- };
- }
-
- onToggleEditMode = () => {
- this.setState(state => ({
- editMode: !state.editMode,
- editText: this.props.message.text,
- }));
- };
-
- onChangeEditText = event => {
- this.setState({ editText: event.target.value });
- };
-
- onSaveEditText = () => {
- this.props.onEditMessage(this.props.message, this.state.editText);
-
- this.setState({ editMode: false });
- };
-
- render() {
- const { message, onRemoveMessage } = this.props;
- const { editMode, editText } = this.state;
-
- return (
-
- {editMode ? (
-
- ) : (
-
-
- {message.user.username || message.user.userId}
- {' '}
- {message.text} {message.editedAt && (Edited) }
-
- )}
-
- {editMode ? (
-
- Save
- Reset
-
- ) : (
- Edit
- )}
-
- {!editMode && (
- onRemoveMessage(message.uid)}
->
- Delete
-
- )}
-
- );
- }
-}
-
-const Messages = withFirebase(MessagesBase);
-
const condition = authUser => !!authUser;
export default compose(
diff --git a/src/components/Messages/MessageItem.js b/src/components/Messages/MessageItem.js
new file mode 100644
index 00000000..78a9bb20
--- /dev/null
+++ b/src/components/Messages/MessageItem.js
@@ -0,0 +1,73 @@
+import React, { Component } from 'react';
+
+class MessageItem extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ editMode: false,
+ editText: this.props.message.text,
+ };
+ }
+
+ onToggleEditMode = () => {
+ this.setState(state => ({
+ editMode: !state.editMode,
+ editText: this.props.message.text,
+ }));
+ };
+
+ onChangeEditText = event => {
+ this.setState({ editText: event.target.value });
+ };
+
+ onSaveEditText = () => {
+ this.props.onEditMessage(this.props.message, this.state.editText);
+
+ this.setState({ editMode: false });
+ };
+
+ render() {
+ const { message, onRemoveMessage } = this.props;
+ const { editMode, editText } = this.state;
+
+ return (
+
+ {editMode ? (
+
+ ) : (
+
+
+ {message.user.username || message.user.userId}
+ {' '}
+ {message.text} {message.editedAt && (Edited) }
+
+ )}
+
+ {editMode ? (
+
+ Save
+ Reset
+
+ ) : (
+ Edit
+ )}
+
+ {!editMode && (
+ onRemoveMessage(message.uid)}
+>
+ Delete
+
+ )}
+
+ );
+ }
+}
+
+export default MessageItem;
diff --git a/src/components/Messages/MessageList.js b/src/components/Messages/MessageList.js
new file mode 100644
index 00000000..4e0c49ba
--- /dev/null
+++ b/src/components/Messages/MessageList.js
@@ -0,0 +1,22 @@
+import React from 'react';
+
+import MessageItem from './MessageItem';
+
+const MessageList = ({
+ messages,
+ onEditMessage,
+ onRemoveMessage,
+}) => (
+
+ {messages.map(message => (
+
+ ))}
+
+);
+
+export default MessageList;
diff --git a/src/components/Messages/Messages.js b/src/components/Messages/Messages.js
new file mode 100644
index 00000000..e6e70fd2
--- /dev/null
+++ b/src/components/Messages/Messages.js
@@ -0,0 +1,138 @@
+import React, { Component } from 'react';
+
+import { AuthUserContext } from '../Session';
+import { withFirebase } from '../Firebase';
+import MessageList from './MessageList';
+
+class Messages extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ text: '',
+ loading: false,
+ messages: [],
+ limit: 5,
+ };
+ }
+
+ componentDidMount() {
+ this.onListenForMessages();
+ }
+
+ onListenForMessages = () => {
+ this.setState({ loading: true });
+
+ this.props.firebase
+ .messages()
+ .orderByChild('createdAt')
+ .limitToLast(this.state.limit)
+ .on('value', snapshot => {
+ const messageObject = snapshot.val();
+
+ if (messageObject) {
+ const messageList = Object.keys(messageObject).map(key => ({
+ ...messageObject[key],
+ uid: key,
+ }));
+
+ this.setState({
+ messages: messageList,
+ loading: false,
+ });
+ } else {
+ this.setState({ messages: null, loading: false });
+ }
+ });
+ };
+
+ componentWillUnmount() {
+ this.props.firebase.messages().off();
+ }
+
+ onChangeText = event => {
+ this.setState({ text: event.target.value });
+ };
+
+ onCreateMessage = (event, authUser) => {
+ this.props.firebase.messages().push({
+ text: this.state.text,
+ userId: authUser.uid,
+ createdAt: this.props.firebase.serverValue.TIMESTAMP,
+ });
+
+ this.setState({ text: '' });
+
+ event.preventDefault();
+ };
+
+ onEditMessage = (message, text) => {
+ this.props.firebase.message(message.uid).set({
+ ...message,
+ text,
+ editedAt: this.props.firebase.serverValue.TIMESTAMP,
+ });
+ };
+
+ onRemoveMessage = uid => {
+ this.props.firebase.message(uid).remove();
+ };
+
+ onNextPage = () => {
+ this.setState(
+ state => ({ limit: state.limit + 5 }),
+ this.onListenForMessages,
+ );
+ };
+
+ render() {
+ const { users } = this.props;
+ const { text, messages, loading } = this.state;
+
+ return (
+
+ {authUser => (
+
+ {!loading && messages && (
+
+ More
+
+ )}
+
+ {loading &&
Loading ...
}
+
+ {messages && (
+
({
+ ...message,
+ user: users
+ ? users[message.userId]
+ : { userId: message.userId },
+ }))}
+ onEditMessage={this.onEditMessage}
+ onRemoveMessage={this.onRemoveMessage}
+ />
+ )}
+
+ {!messages && There are no messages ...
}
+
+
+
+ )}
+
+ );
+ }
+}
+
+export default withFirebase(Messages);
diff --git a/src/components/Messages/index.js b/src/components/Messages/index.js
new file mode 100644
index 00000000..091383f2
--- /dev/null
+++ b/src/components/Messages/index.js
@@ -0,0 +1,3 @@
+import Messages from './Messages';
+
+export default Messages;
diff --git a/src/components/Users/UserItem.js b/src/components/Users/UserItem.js
new file mode 100644
index 00000000..05e43193
--- /dev/null
+++ b/src/components/Users/UserItem.js
@@ -0,0 +1,75 @@
+import React, { Component } from 'react';
+
+import { withFirebase } from '../Firebase';
+
+class UserItem extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ loading: false,
+ user: null,
+ ...props.location.state,
+ };
+ }
+
+ componentDidMount() {
+ if (this.state.user) {
+ return;
+ }
+
+ this.setState({ loading: true });
+
+ this.props.firebase
+ .user(this.props.match.params.id)
+ .on('value', snapshot => {
+ this.setState({
+ user: snapshot.val(),
+ loading: false,
+ });
+ });
+ }
+
+ componentWillUnmount() {
+ this.props.firebase.user(this.props.match.params.id).off();
+ }
+
+ onSendPasswordResetEmail = () => {
+ this.props.firebase.doPasswordReset(this.state.user.email);
+ };
+
+ render() {
+ const { user, loading } = this.state;
+
+ return (
+
+
User ({this.props.match.params.id})
+ {loading &&
Loading ...
}
+
+ {user && (
+
+
+ ID: {user.uid}
+
+
+ E-Mail: {user.email}
+
+
+ Username: {user.username}
+
+
+
+ Send Password Reset
+
+
+
+ )}
+
+ );
+ }
+}
+
+export default withFirebase(UserItem);
diff --git a/src/components/Users/UserList.js b/src/components/Users/UserList.js
new file mode 100644
index 00000000..85b49553
--- /dev/null
+++ b/src/components/Users/UserList.js
@@ -0,0 +1,76 @@
+import React, { Component } from 'react';
+import { Link } from 'react-router-dom';
+
+import { withFirebase } from '../Firebase';
+import * as ROUTES from '../../constants/routes';
+
+class UserList extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ loading: false,
+ users: [],
+ };
+ }
+
+ componentDidMount() {
+ this.setState({ loading: true });
+
+ this.props.firebase.users().on('value', snapshot => {
+ const usersObject = snapshot.val();
+
+ const usersList = Object.keys(usersObject).map(key => ({
+ ...usersObject[key],
+ uid: key,
+ }));
+
+ this.setState({
+ users: usersList,
+ loading: false,
+ });
+ });
+ }
+
+ componentWillUnmount() {
+ this.props.firebase.users().off();
+ }
+
+ render() {
+ const { users, loading } = this.state;
+
+ return (
+
+
Users
+ {loading &&
Loading ...
}
+
+ {users.map(user => (
+
+
+ ID: {user.uid}
+
+
+ E-Mail: {user.email}
+
+
+ Username: {user.username}
+
+
+
+ Details
+
+
+
+ ))}
+
+
+ );
+ }
+}
+
+export default withFirebase(UserList);
diff --git a/src/components/Users/index.js b/src/components/Users/index.js
new file mode 100644
index 00000000..8ba9cffa
--- /dev/null
+++ b/src/components/Users/index.js
@@ -0,0 +1,4 @@
+import UserList from './UserList';
+import UserItem from './UserItem';
+
+export { UserList, UserItem };
From 9d3526f3bbb0936f233199b099e6879a1362259b Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Wed, 5 Dec 2018 16:47:36 +0800
Subject: [PATCH 20/36] add social sign in methods manual
---
README.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index ad04b235..82cac7f6 100644
--- a/README.md
+++ b/README.md
@@ -41,4 +41,8 @@
* visit https://firebase.google.com and create a Firebase App
* copy and paste your Credentials from your Firebase App into *src/components/Firebase/firebase.js* file or in .env file
-* activate Email/Password, Google, Facebook and Twitter Sign-In Methods for your Firebase App
+* [activate Sign-In Methods in your Firebase App](https://www.robinwieruch.de/react-firebase-social-login/)
+ * Email/Password
+ * Google
+ * Facebook
+ * Twitter
From 7bcbc18878d4b1894e053c206bb6571daf112c56 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Thu, 6 Dec 2018 09:27:23 +0800
Subject: [PATCH 21/36] add license
---
README.md | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/README.md b/README.md
index 82cac7f6..068304ca 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,22 @@
* Auth Persistence with Local Storage
* Database with Users and Messages
+## License
+
+### Commercial license
+
+If you want to use this starter project to develop commercial sites, themes, projects, and applications, the Commercial license is the appropriate license. With this option, your source code is kept proprietary. Purchase an commercial license for different team sizes:
+
+* [1 Developer](https://gum.co/react-with-firebase-starter-pack-developer)
+* [Team of up to 8 Developers](https://gum.co/react-with-firebase-starter-pack-team)
+* [Unlimited Developers of an Organization](https://gum.co/react-with-firebase-starter-pack-organization)
+
+It grants you also access to the other starter projects in this GitHub organization.
+
+### Open source license
+
+If you are creating an open source application under a license compatible with the [GNU GPL license v3](https://www.gnu.org/licenses/gpl-3.0.html), you may use this starter project under the terms of the GPLv3.
+
## Installation
* `git clone git@github.com:the-road-to-react-with-firebase/react-firebase-authentication.git`
From 7e7a6905a85b9d4a9f17b33d5e9b699a387b4450 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Thu, 6 Dec 2018 19:32:29 +0800
Subject: [PATCH 22/36] fix travis to node 10
---
.travis.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 1968f21a..1d8352ca 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,10 @@
language: node_js
node_js:
- - stable
+ - '10'
install:
- npm install
script:
- - npm test
\ No newline at end of file
+ - npm test
From f049c8491036bd8fde6a58d2c682751f6a510925 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Sat, 8 Dec 2018 23:53:03 +0800
Subject: [PATCH 23/36] fine-tune README.md
---
README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 48 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index 068304ca..65b5c366 100644
--- a/README.md
+++ b/README.md
@@ -50,15 +50,54 @@ If you are creating an open source application under a license compatible with t
* `cd react-firebase-authentication`
* `npm install`
* `npm start`
-* visit http://localhost:3000/
-* Use your own Firebase Credentials
+* visit http://localhost:3000
-### Use your own Firebase Credentials
+### Firebase Configuration
* visit https://firebase.google.com and create a Firebase App
-* copy and paste your Credentials from your Firebase App into *src/components/Firebase/firebase.js* file or in .env file
-* [activate Sign-In Methods in your Firebase App](https://www.robinwieruch.de/react-firebase-social-login/)
- * Email/Password
- * Google
- * Facebook
- * Twitter
+* copy/paste your configuration from your Firebase project's dashboard into one of these files
+ * *src/components/Firebase/firebase.js* file
+ * *.env* file
+ * *.env.development*/*.env.production* files
+
+The *.env* or *.env.development*/*.env.production* files could look like the following then:
+
+```
+REACT_APP_API_KEY=AIzaSyBtxZ3phPeXcsZsRTySIXa7n33NtQ
+REACT_APP_AUTH_DOMAIN=react-firebase-s2233d64f8.firebaseapp.com
+REACT_APP_DATABASE_URL=https://react-firebase-s2233d64f8.firebaseio.com
+REACT_APP_PROJECT_ID=react-firebase-s2233d64f8
+REACT_APP_STORAGE_BUCKET=react-firebase-s2233d64f8.appspot.com
+REACT_APP_MESSAGING_SENDER_ID=701928454501
+```
+
+### Activate Sign-In Methods
+
+
+
+* Email/Password
+* [Google](https://www.robinwieruch.de/react-firebase-social-login/)
+* [Facebook](https://www.robinwieruch.de/firebase-facebook-login/)
+* [Twitter](https://www.robinwieruch.de/firebase-twitter-login/)
+* [Troubleshoot](https://www.robinwieruch.de/react-firebase-social-login/)
+
+### Activate Verification E-Mail
+
+* add a redirect URL for redirecting a user after an email verification into one of these files
+ * *src/components/Firebase/firebase.js* file
+ * *.env* file
+ * *.env.development*/*.env.production* files
+
+The *.env* or *.env.development*/*.env.production* files could look like the following then (excl. the Firebase configuration).
+
+**Development:**
+
+```
+REACT_APP_CONFIRMATION_EMAIL_REDIRECT=http://localhost:3000
+```
+
+**Production:**
+
+```
+REACT_APP_CONFIRMATION_EMAIL_REDIRECT=https://mydomain.com
+```
\ No newline at end of file
From a61df19ac4fd365efa74b19fb91ddc2daf7e5f16 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Sat, 8 Dec 2018 23:54:35 +0800
Subject: [PATCH 24/36] fine-tune README.md
---
README.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 65b5c366..ebedf65f 100644
--- a/README.md
+++ b/README.md
@@ -58,9 +58,9 @@ If you are creating an open source application under a license compatible with t
* copy/paste your configuration from your Firebase project's dashboard into one of these files
* *src/components/Firebase/firebase.js* file
* *.env* file
- * *.env.development*/*.env.production* files
+ * *.env.development* and *.env.production* files
-The *.env* or *.env.development*/*.env.production* files could look like the following then:
+The *.env* or *.env.development* and *.env.production* files could look like the following then:
```
REACT_APP_API_KEY=AIzaSyBtxZ3phPeXcsZsRTySIXa7n33NtQ
@@ -86,9 +86,9 @@ REACT_APP_MESSAGING_SENDER_ID=701928454501
* add a redirect URL for redirecting a user after an email verification into one of these files
* *src/components/Firebase/firebase.js* file
* *.env* file
- * *.env.development*/*.env.production* files
+ * *.env.development* and *.env.production* files
-The *.env* or *.env.development*/*.env.production* files could look like the following then (excl. the Firebase configuration).
+The *.env* or *.env.development* and *.env.production* files could look like the following then (excl. the Firebase configuration).
**Development:**
From 1de063e139e2bdb8107a6dce05a58c3470e98fa8 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Sun, 9 Dec 2018 01:44:44 +0800
Subject: [PATCH 25/36] fine-tune README.md
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index ebedf65f..07375e34 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,8 @@ If you are creating an open source application under a license compatible with t
### Firebase Configuration
-* visit https://firebase.google.com and create a Firebase App
+Get an overview of Firebase, how to create a project, what kind of features Firebase offers, and how to navigate through the Firebase project dashboard in this [visual tutorial for Firebase](https://www.robinwieruch.de/firebase-tutorial/).
+
* copy/paste your configuration from your Firebase project's dashboard into one of these files
* *src/components/Firebase/firebase.js* file
* *.env* file
From 77ce58e0c3a1dd233caacfad5b4bc1236a2432f7 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Sun, 9 Dec 2018 15:29:25 +0800
Subject: [PATCH 26/36] imrpove README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 07375e34..8e8ac49d 100644
--- a/README.md
+++ b/README.md
@@ -52,10 +52,10 @@ If you are creating an open source application under a license compatible with t
* `npm start`
* visit http://localhost:3000
-### Firebase Configuration
-
Get an overview of Firebase, how to create a project, what kind of features Firebase offers, and how to navigate through the Firebase project dashboard in this [visual tutorial for Firebase](https://www.robinwieruch.de/firebase-tutorial/).
+### Firebase Configuration
+
* copy/paste your configuration from your Firebase project's dashboard into one of these files
* *src/components/Firebase/firebase.js* file
* *.env* file
From 92c5ac6e0289e5f11a848caeddda3911e739dba5 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年12月12日 13:41:47 +0800
Subject: [PATCH 27/36] Update README.md
---
README.md | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 8e8ac49d..d65ec92f 100644
--- a/README.md
+++ b/README.md
@@ -5,15 +5,20 @@
* [Tutorial](https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/)
* [Live Version of half of the Tutorial](https://react-firebase-authentication.wieruch.com/)
+## Variations
+
+* [Redux Version](https://github.com/the-road-to-react-with-firebase/react-redux-firebase-authentication)
+* [MobX Version](https://github.com/the-road-to-react-with-firebase/react-mobx-firebase-authentication)
+* [Gatsby Version](https://github.com/the-road-to-react-with-firebase/react-gatsby-firebase-authentication)
+* [Firestore Version](https://github.com/the-road-to-react-with-firebase/react-firestore-authentication)
+* [Semantic UI Version](https://github.com/the-road-to-react-with-firebase/react-semantic-ui-firebase-authentication)
+
## Features
* uses:
* only React (create-react-app)
- * firebase 5
- * react-router 4
- * no Redux/MobX
- * [Redux Version](https://github.com/taming-the-state-in-react/react-redux-firebase-authentication)
- * [MobX Version](https://github.com/taming-the-state-in-react/react-mobx-firebase-authentication)
+ * firebase
+ * react-router
* features:
* Sign In
* Sign Up
@@ -101,4 +106,4 @@ REACT_APP_CONFIRMATION_EMAIL_REDIRECT=http://localhost:3000
```
REACT_APP_CONFIRMATION_EMAIL_REDIRECT=https://mydomain.com
-```
\ No newline at end of file
+```
From 301f4b577355d153a810d2f0ebeefd1380cf82bc Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2018年12月13日 13:39:57 +0800
Subject: [PATCH 28/36] refactor: use compose
---
src/components/SignUp/index.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/components/SignUp/index.js b/src/components/SignUp/index.js
index f10e50b8..f25d5804 100644
--- a/src/components/SignUp/index.js
+++ b/src/components/SignUp/index.js
@@ -1,5 +1,6 @@
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
+import { compose } from 'recompose';
import { withFirebase } from '../Firebase';
import * as ROUTES from '../../constants/routes';
@@ -153,7 +154,10 @@ const SignUpLink = () => (
);
-const SignUpForm = withRouter(withFirebase(SignUpFormBase));
+const SignUpForm = compose(
+ withRouter,
+ withFirebase,
+)(SignUpFormBase);
export default SignUpPage;
From 7a9d26398a6c4ffd8b33f474180151e408e832b1 Mon Sep 17 00:00:00 2001
From: Bastien
Date: Tue, 5 Feb 2019 10:53:14 -0800
Subject: [PATCH 29/36] Correct typo
---
src/components/Session/withEmailVerification.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/Session/withEmailVerification.js b/src/components/Session/withEmailVerification.js
index 9ce73340..1e6ff57f 100644
--- a/src/components/Session/withEmailVerification.js
+++ b/src/components/Session/withEmailVerification.js
@@ -32,13 +32,13 @@ const withEmailVerification = Component => {
{this.state.isSent ? (
- E-Mail confirmation sent: Check you E-Mails (Spam
+ E-Mail confirmation sent: Check your E-Mails (Spam
folder included) for a confirmation E-Mail.
Refresh this page once you confirmed your E-Mail.
) : (
- Verify your E-Mail: Check you E-Mails (Spam folder
+ Verify your E-Mail: Check your E-Mails (Spam folder
included) for a confirmation E-Mail or send
another confirmation E-Mail.
From 2a895f96fcd3365390baff147ee222d143cd3e53 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Wed, 6 Feb 2019 12:45:58 +0800
Subject: [PATCH 30/36] fix role to object instead of array
---
src/components/Admin/index.js | 2 +-
src/components/Firebase/firebase.js | 2 +-
src/components/Navigation/index.js | 2 +-
src/components/SignIn/index.js | 6 +++---
src/components/SignUp/index.js | 4 ++--
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/components/Admin/index.js b/src/components/Admin/index.js
index cd0c7b63..1038e5e7 100644
--- a/src/components/Admin/index.js
+++ b/src/components/Admin/index.js
@@ -20,7 +20,7 @@ const AdminPage = () => (
);
const condition = authUser =>
- authUser && authUser.roles.includes(ROLES.ADMIN);
+ authUser && !!authUser.roles[ROLES.ADMIN];
export default compose(
withEmailVerification,
diff --git a/src/components/Firebase/firebase.js b/src/components/Firebase/firebase.js
index b791945d..719e6dcd 100644
--- a/src/components/Firebase/firebase.js
+++ b/src/components/Firebase/firebase.js
@@ -73,7 +73,7 @@ class Firebase {
// default empty roles
if (!dbUser.roles) {
- dbUser.roles = [];
+ dbUser.roles = {};
}
// merge auth and db user
diff --git a/src/components/Navigation/index.js b/src/components/Navigation/index.js
index 156e27ae..ba3571ea 100644
--- a/src/components/Navigation/index.js
+++ b/src/components/Navigation/index.js
@@ -29,7 +29,7 @@ const NavigationAuth = ({ authUser }) => (
Account
- {authUser.roles.includes(ROLES.ADMIN) && (
+ {!!authUser.roles[ROLES.ADMIN] && (
Admin
diff --git a/src/components/SignIn/index.js b/src/components/SignIn/index.js
index 91e3f562..d32937c1 100644
--- a/src/components/SignIn/index.js
+++ b/src/components/SignIn/index.js
@@ -108,7 +108,7 @@ class SignInGoogleBase extends Component {
return this.props.firebase.user(socialAuthUser.user.uid).set({
username: socialAuthUser.user.displayName,
email: socialAuthUser.user.email,
- roles: [],
+ roles: {},
});
})
.then(() => {
@@ -154,7 +154,7 @@ class SignInFacebookBase extends Component {
return this.props.firebase.user(socialAuthUser.user.uid).set({
username: socialAuthUser.additionalUserInfo.profile.name,
email: socialAuthUser.additionalUserInfo.profile.email,
- roles: [],
+ roles: {},
});
})
.then(() => {
@@ -200,7 +200,7 @@ class SignInTwitterBase extends Component {
return this.props.firebase.user(socialAuthUser.user.uid).set({
username: socialAuthUser.additionalUserInfo.profile.name,
email: socialAuthUser.additionalUserInfo.profile.email,
- roles: [],
+ roles: {},
});
})
.then(() => {
diff --git a/src/components/SignUp/index.js b/src/components/SignUp/index.js
index f25d5804..a319cac2 100644
--- a/src/components/SignUp/index.js
+++ b/src/components/SignUp/index.js
@@ -41,10 +41,10 @@ class SignUpFormBase extends Component {
onSubmit = event => {
const { username, email, passwordOne, isAdmin } = this.state;
- const roles = [];
+ const roles = {};
if (isAdmin) {
- roles.push(ROLES.ADMIN);
+ roles[ROLES.ADMIN] = ROLES.ADMIN;
}
this.props.firebase
From 52d24d09a76f717c54642a6c547c4856c0799865 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Wed, 6 Feb 2019 13:01:34 +0800
Subject: [PATCH 31/36] remove: fetch across entities, because users cannot be
fetched anymore
---
src/components/Home/index.js | 42 +++++---------------------
src/components/Messages/MessageItem.js | 6 ++--
src/components/Messages/Messages.js | 12 +++-----
3 files changed, 14 insertions(+), 46 deletions(-)
diff --git a/src/components/Home/index.js b/src/components/Home/index.js
index 0bec512b..75510b2e 100644
--- a/src/components/Home/index.js
+++ b/src/components/Home/index.js
@@ -1,47 +1,21 @@
-import React, { Component } from 'react';
+import React from 'react';
import { compose } from 'recompose';
import { withAuthorization, withEmailVerification } from '../Session';
-import { withFirebase } from '../Firebase';
import Messages from '../Messages';
-class HomePage extends Component {
- constructor(props) {
- super(props);
+const HomePage = () => (
+
+
Home Page
+
The Home Page is accessible by every signed in user.
- this.state = {
- users: null,
- };
- }
-
- componentDidMount() {
- this.props.firebase.users().on('value', snapshot => {
- this.setState({
- users: snapshot.val(),
- });
- });
- }
-
- componentWillUnmount() {
- this.props.firebase.users().off();
- }
-
- render() {
- return (
-
-
Home Page
-
The Home Page is accessible by every signed in user.
-
-
-
- );
- }
-}
+
+
+);
const condition = authUser => !!authUser;
export default compose(
- withFirebase,
withEmailVerification,
withAuthorization(condition),
)(HomePage);
diff --git a/src/components/Messages/MessageItem.js b/src/components/Messages/MessageItem.js
index 78a9bb20..0935d469 100644
--- a/src/components/Messages/MessageItem.js
+++ b/src/components/Messages/MessageItem.js
@@ -41,10 +41,8 @@ class MessageItem extends Component {
/>
) : (
-
- {message.user.username || message.user.userId}
- {' '}
- {message.text} {message.editedAt && (Edited) }
+ {message.userId} {message.text}
+ {message.editedAt && (Edited) }
)}
diff --git a/src/components/Messages/Messages.js b/src/components/Messages/Messages.js
index e6e70fd2..bfd76d45 100644
--- a/src/components/Messages/Messages.js
+++ b/src/components/Messages/Messages.js
@@ -67,8 +67,10 @@ class Messages extends Component {
};
onEditMessage = (message, text) => {
+ const { uid, ...messageSnapshot } = message;
+
this.props.firebase.message(message.uid).set({
- ...message,
+ ...messageSnapshot,
text,
editedAt: this.props.firebase.serverValue.TIMESTAMP,
});
@@ -86,7 +88,6 @@ class Messages extends Component {
};
render() {
- const { users } = this.props;
const { text, messages, loading } = this.state;
return (
@@ -103,12 +104,7 @@ class Messages extends Component {
{messages && (
({
- ...message,
- user: users
- ? users[message.userId]
- : { userId: message.userId },
- }))}
+ messages={messages}
onEditMessage={this.onEditMessage}
onRemoveMessage={this.onRemoveMessage}
/>
From 8cb594e957eb3571c11653e96e8f119518822f0c Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: Wed, 6 Feb 2019 13:12:38 +0800
Subject: [PATCH 32/36] only allow owner of message to edit/delete
---
src/components/Messages/MessageItem.js | 34 ++++++++++++++------------
src/components/Messages/MessageList.js | 2 ++
src/components/Messages/Messages.js | 1 +
3 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/src/components/Messages/MessageItem.js b/src/components/Messages/MessageItem.js
index 0935d469..b92f9545 100644
--- a/src/components/Messages/MessageItem.js
+++ b/src/components/Messages/MessageItem.js
@@ -28,7 +28,7 @@ class MessageItem extends Component {
};
render() {
- const { message, onRemoveMessage } = this.props;
+ const { authUser, message, onRemoveMessage } = this.props;
const { editMode, editText } = this.state;
return (
@@ -46,22 +46,26 @@ class MessageItem extends Component {
)}
- {editMode ? (
+ {authUser.uid === message.userId && (
- Save
- Reset
-
- ) : (
- Edit
- )}
+ {editMode ? (
+
+ Save
+ Reset
+
+ ) : (
+ Edit
+ )}
- {!editMode && (
- onRemoveMessage(message.uid)}
->
- Delete
-
+ {!editMode && (
+ onRemoveMessage(message.uid)}
+>
+ Delete
+
+ )}
+
)}
);
diff --git a/src/components/Messages/MessageList.js b/src/components/Messages/MessageList.js
index 4e0c49ba..fb18585e 100644
--- a/src/components/Messages/MessageList.js
+++ b/src/components/Messages/MessageList.js
@@ -3,6 +3,7 @@ import React from 'react';
import MessageItem from './MessageItem';
const MessageList = ({
+ authUser,
messages,
onEditMessage,
onRemoveMessage,
@@ -10,6 +11,7 @@ const MessageList = ({
{messages.map(message => (
Date: Fri, 5 Apr 2019 10:06:55 +0200
Subject: [PATCH 33/36] Update README.md
---
README.md | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/README.md b/README.md
index d65ec92f..9e9634d8 100644
--- a/README.md
+++ b/README.md
@@ -107,3 +107,30 @@ REACT_APP_CONFIRMATION_EMAIL_REDIRECT=http://localhost:3000
```
REACT_APP_CONFIRMATION_EMAIL_REDIRECT=https://mydomain.com
```
+
+### Security Rules
+
+```
+{
+ "rules": {
+ ".read": false,
+ ".write": false,
+ "users": {
+ "$uid": {
+ ".read": "$uid === auth.uid || root.child('users/'+auth.uid).child('roles').hasChildren(['ADMIN'])",
+ ".write": "$uid === auth.uid || root.child('users/'+auth.uid).child('roles').hasChildren(['ADMIN'])"
+ },
+ ".read": "root.child('users/'+auth.uid).child('roles').hasChildren(['ADMIN'])",
+ ".write": "root.child('users/'+auth.uid).child('roles').hasChildren(['ADMIN'])"
+ },
+ "messages": {
+ ".indexOn": ["createdAt"],
+ "$uid": {
+ ".write": "data.exists() ? data.child('userId').val() === auth.uid : newData.child('userId').val() === auth.uid"
+ },
+ ".read": "auth != null",
+ ".write": "auth != null",
+ },
+ }
+}
+```
From 4aecf93021673ec6fc650bc20d05ac125a5b7fe4 Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2019年6月17日 08:56:39 +0200
Subject: [PATCH 34/36] Create FUNDING.yml
---
.github/FUNDING.yml | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 .github/FUNDING.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..a6b07651
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: rwieruch
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with a single custom sponsorship URL
From e27383216816591a1076a41cb95bc40ee757614f Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2020年5月21日 12:45:48 +0200
Subject: [PATCH 35/36] Update README.md
---
README.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/README.md b/README.md
index 9e9634d8..179eeae2 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,6 @@
[](https://travis-ci.org/the-road-to-react-with-firebase/react-firebase-authentication) [](https://slack-the-road-to-learn-react.wieruch.com/) [](https://greenkeeper.io/)
* [Tutorial](https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/)
-* [Live Version of half of the Tutorial](https://react-firebase-authentication.wieruch.com/)
## Variations
From fac903f8e6c767909d6be54356eea246bb397dff Mon Sep 17 00:00:00 2001
From: Robin Wieruch
Date: 2020年6月12日 10:39:46 +0200
Subject: [PATCH 36/36] Update FUNDING.yml
---
.github/FUNDING.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index a6b07651..52826782 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,7 +1,7 @@
# These are supported funding model platforms
-github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
-patreon: rwieruch
+github: rwieruch
+patreon: # rwieruch
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel