Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Setup Firebase Google OAuth #8

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"@material-ui/styles": "^4.11.4",
"firebase": "^9.0.2",
"firebase": "8.10.0",
"gatsby": "^3.12.1",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you downgrade the version?

"gatsby-plugin-robots-txt": "^1.6.10",
"gatsby-plugin-styled-components": "^4.13.0",
Expand Down
40 changes: 40 additions & 0 deletions src/components/SignInButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useContext } from 'react';

// Context
import { AuthContext } from '../contexts/AuthContext';

// Components
import { Button, Typography } from '@material-ui/core';

const SignInButton = () => {
const { signIn, signOut, userName, state } = useContext(AuthContext);
const { loading, loginSuccess, error } = state;
return (
<div>
{loading ? (
<h1>Loading...</h1>
) : error ? (
<h1>{error}</h1>
) : (
<div>
{!loginSuccess ? (
<div>
<Button onClick={signIn} variant='contained' color='primary'>
SignIn
</Button>
</div>
) : (
<div>
<Typography variant='h1'>Hello ,{userName}</Typography>
<Button onClick={signOut} variant='contained' color='primary'>
SignOut
</Button>
</div>
)}
</div>
)}
</div>
);
};

export default SignInButton;
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as SignInButton } from './SignInButton';
26 changes: 26 additions & 0 deletions src/config/firebase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';

const firebaseConfig = {
apiKey: process.env.APIKEY,
authDomain: process.env.AUTHDOMAIN,
projectId: process.env.PROJECTID,
storageBucket: process.env.STORAGEBUCKET,
messagingSenderId: process.env.MESSAGINGSENDERID,
appId: process.env.APPID,
measurementId: process.env.MEASUREMENTID,
};

export const provider = new firebase.auth.GoogleAuthProvider();

let instance = null;

export default function getFirebase() {
if (typeof window !== 'undefined') {
if (instance)
return instance;
instance = firebase.initializeApp(firebaseConfig);
return instance;
}
}
104 changes: 104 additions & 0 deletions src/contexts/AuthContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { createContext, useReducer, useEffect, useState } from 'react';

// Reducers
import { authReducer } from '../store/reducers/AuthReducers';

// Constants
import {
AUTH_FAIL,
AUTH_REQUEST,
LOGIN_SUCCESS,
LOGOUT_SUCCESS,
} from '../store/constants/AuthConstants';

//Firebase
import useFirebase from '../hooks/useFirebase';
import { provider } from '../config/firebase';

// Context Created
export const AuthContext = createContext();

//Context Provider
const AuthContextProvider = ({ children }) => {
const [userName, setuserName] = useState('Hacker');
const [state, dispatch] = useReducer(authReducer, {});

const firebase = useFirebase();

useEffect(() => {
if (!firebase) return;
firebase.auth().onAuthStateChanged((user) => {
if (user) {
setuserName(user.displayName);
}
});
}, [dispatch,state]);

const signIn = async (e) => {
e.preventDefault();
dispatch({ type: AUTH_REQUEST });

await firebase
.auth()
.signInWithPopup(provider)
.then((result) => {
dispatch({ type: LOGIN_SUCCESS });
var user = result.user;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use var


firebase
.firestore()
.collection('users')
.doc(user.uid)
.set({
name: user.displayName,
email: user.email,
imageUrl: user.providerData[0].photoURL,
points: 0,
codeIDs: [],
})
.then(() => {
console.log('login success');
dispatch({
type: LOGIN_SUCCESS,
});
})
.catch((error) => {
console.error(error);
});
})
.catch((error) => {
var errorMessage = error.message;
dispatch({
type: AUTH_FAIL,
payload: errorMessage,
});
});
};

const signOut = async (e) => {
e.preventDefault();
try {
dispatch({ type: AUTH_REQUEST });

await firebase
.auth()
.signOut()
.then(() => {
dispatch({ type: LOGOUT_SUCCESS });
});
} catch (error) {
dispatch({
type: AUTH_FAIL,
payload: error,
});
}
};

return (
<AuthContext.Provider value={{ signIn, signOut, userName, state, dispatch }}>
{children}
</AuthContext.Provider>
);
};

export default AuthContextProvider;
10 changes: 10 additions & 0 deletions src/hooks/useFirebase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useEffect, useState } from 'react';
import getFirebase from '../config/firebase';

export default function useFirebase() {
const [instance, setInstance] = useState(null);
useEffect(() => {
setInstance(getFirebase());
}, []);
return instance;
Comment on lines +5 to +9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to use useEffect and useState here?

Can't we do the following?

  const [instance] = useState(getFirebase());
  return instance;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can use do that also... I will take care of it.

}
15 changes: 15 additions & 0 deletions src/pages/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

import AuthContextProvider from '../contexts/AuthContext';

import { SignInButton } from '../components';

const App = () => {
return (
<AuthContextProvider>
<SignInButton />
</AuthContextProvider>
);
};

export default App;
7 changes: 6 additions & 1 deletion src/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import React from 'react';
import App from './App';

const Home = () => {
return <div>Project Kiwi</div>;
return (
<div>
<App />
</div>
);
};

export default Home;
4 changes: 4 additions & 0 deletions src/store/constants/AuthConstants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const AUTH_REQUEST = "AUTH_REQUEST";
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const AUTH_FAIL = "LOGINAUTH";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure about the value of this string?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay bhaiya, I will correct it.

export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS";
32 changes: 32 additions & 0 deletions src/store/reducers/AuthReducers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
AUTH_FAIL,
AUTH_REQUEST,
LOGIN_SUCCESS,
LOGOUT_SUCCESS,
} from '../constants/AuthConstants';

export const authReducer = (state = {}, action) => {
switch (action.type) {
case AUTH_REQUEST:
return {
loading: true,
};
case LOGIN_SUCCESS:
return {
loading: false,
loginSuccess: true,
};
case LOGOUT_SUCCESS:
return {
loading: false,
loginSuccess: false,
};
case AUTH_FAIL:
return {
loading: false,
error: action.payload,
};
default:
return state;
}
};
Loading