Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
♻️ refactor authentication with hooks (#822)
- Loading branch information
Showing
80 changed files
with
694 additions
and
804 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* eslint-disable react/jsx-filename-extension */ | ||
import React, { useState, useEffect, useContext, useCallback, useMemo } from 'react' | ||
import { inject } from '@k-ramel/react' | ||
import PropTypes from 'prop-types' | ||
import firebase from 'firebase/app' | ||
import pick from 'lodash/pick' | ||
|
||
import userCrud from 'firebase/user' | ||
import { preloadFunctions } from 'firebase/functionCalls' | ||
|
||
const AuthContext = React.createContext() | ||
|
||
export const useAuth = () => useContext(AuthContext) | ||
|
||
export const AuthContextProvider = ({ children, resetStore, goToHome }) => { | ||
const [user, setUser] = useState() | ||
const [loading, setLoading] = useState(true) | ||
|
||
useEffect(() => { | ||
firebase.auth().onAuthStateChanged(async (authUser) => { | ||
if (authUser) { | ||
// check if user exists in database | ||
const userRef = await userCrud.read(authUser.uid) | ||
if (userRef.exists) { | ||
// get user info from db | ||
setUser(userRef.data()) | ||
} else { | ||
// first connexion, add user in database | ||
const userData = pick(authUser, ['uid', 'displayName', 'photoURL', 'email']) | ||
await userCrud.create(userData) | ||
setUser(userData) | ||
} | ||
// preload cloud functions | ||
preloadFunctions() | ||
} else { | ||
setUser(null) | ||
resetStore() | ||
} | ||
setLoading(false) | ||
}) | ||
}, [resetStore]) | ||
|
||
const signin = useCallback(async (providerName) => { | ||
setLoading(true) | ||
|
||
let provider | ||
switch (providerName) { | ||
case 'google': | ||
provider = new firebase.auth.GoogleAuthProvider() | ||
break | ||
case 'twitter': | ||
provider = new firebase.auth.TwitterAuthProvider() | ||
break | ||
case 'github': | ||
provider = new firebase.auth.GithubAuthProvider() | ||
break | ||
case 'facebook': | ||
provider = new firebase.auth.FacebookAuthProvider() | ||
break | ||
default: | ||
return | ||
} | ||
provider.setCustomParameters({ | ||
prompt: 'select_account', | ||
}) | ||
|
||
firebase.auth().signInWithRedirect(provider) | ||
}, []) | ||
|
||
const signout = useCallback(async () => { | ||
setLoading(true) | ||
firebase.auth().signOut() | ||
goToHome() | ||
localStorage.removeItem('currentEventId') | ||
}, [goToHome]) | ||
|
||
const updateUser = useCallback( | ||
async (data) => { | ||
const updatedUser = { ...user, ...data } | ||
setUser(updatedUser) | ||
return userCrud.update(updatedUser) | ||
}, | ||
[user], | ||
) | ||
|
||
const resetUserFromProvider = useCallback(async () => { | ||
const data = pick(firebase.auth().currentUser, ['uid', 'email', 'displayName', 'photoURL']) | ||
return updateUser(data) | ||
}, [updateUser]) | ||
|
||
const value = useMemo( | ||
() => ({ user, loading, signin, signout, updateUser, resetUserFromProvider }), | ||
[user, loading, signin, signout, updateUser, resetUserFromProvider], | ||
) | ||
|
||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider> | ||
} | ||
|
||
AuthContextProvider.propTypes = { | ||
resetStore: PropTypes.func.isRequired, | ||
goToHome: PropTypes.func.isRequired, | ||
children: PropTypes.any.isRequired, | ||
} | ||
|
||
export const AuthProvider = inject((store, props, { router }) => { | ||
return { | ||
resetStore: () => store.data.reset(), | ||
goToHome: () => router.push('home'), | ||
} | ||
})(AuthContextProvider) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { AuthProvider, useAuth } from './context' | ||
export { default as protect } from './protect' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* eslint-disable react/jsx-filename-extension */ | ||
import React, { useEffect } from 'react' | ||
import PropTypes from 'prop-types' | ||
import { inject } from '@k-ramel/react' | ||
|
||
import { useAuth } from 'features/auth' | ||
import { LoadingIndicator } from 'components/loader' | ||
|
||
export default (Component) => { | ||
const ProtectedComponent = ({ redirectLogin, ...rest }) => { | ||
const { user, loading } = useAuth() | ||
|
||
useEffect(() => { | ||
if (!user && !loading) { | ||
redirectLogin() | ||
} | ||
}, [user, loading, redirectLogin]) | ||
|
||
if (loading) { | ||
return <LoadingIndicator /> | ||
} | ||
|
||
if (!user) { | ||
return null | ||
} | ||
|
||
return <Component userId={user.uid} {...rest} /> | ||
} | ||
|
||
ProtectedComponent.propTypes = { | ||
redirectLogin: PropTypes.func.isRequired, | ||
} | ||
|
||
return inject((store) => { | ||
return { | ||
redirectLogin: () => { | ||
store.dispatch({ type: '@@router/REPLACE_WITH_NEXT_URL', payload: 'login' }) | ||
}, | ||
} | ||
})(ProtectedComponent) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/* eslint-disable import/prefer-default-export */ | ||
export { default as restrictBeta } from './restrictBeta' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* eslint-disable react/jsx-filename-extension */ | ||
import React, { useEffect } from 'react' | ||
import PropTypes from 'prop-types' | ||
import { inject } from '@k-ramel/react' | ||
import { useAuth } from 'features/auth' | ||
|
||
const SKIP_BETA_ACCESS = process.env.NODE_ENV === 'development' | ||
|
||
export default (Component) => { | ||
const BetaRestricted = ({ redirectBetaAccess, ...rest }) => { | ||
const { user } = useAuth() | ||
const { betaAccess } = user | ||
|
||
useEffect(() => { | ||
if (SKIP_BETA_ACCESS) return | ||
if (!betaAccess) redirectBetaAccess() | ||
}, [betaAccess, redirectBetaAccess]) | ||
|
||
return SKIP_BETA_ACCESS || betaAccess ? <Component {...rest} /> : null | ||
} | ||
|
||
BetaRestricted.propTypes = { | ||
redirectBetaAccess: PropTypes.func.isRequired, | ||
} | ||
|
||
return inject((store) => { | ||
return { | ||
redirectBetaAccess: () => { | ||
store.dispatch({ type: '@@router/REPLACE_WITH_NEXT_URL', payload: 'beta-access' }) | ||
}, | ||
} | ||
})(BetaRestricted) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,9 @@ | ||
/* eslint-disable import/prefer-default-export */ | ||
import crud from './crud' | ||
|
||
export default crud('betaAccess', 'id') | ||
const betaAccess = crud('betaAccess', 'id') | ||
|
||
export const isValidBetaAccessKey = async (accessKey) => { | ||
const accessRef = await betaAccess.read(accessKey) | ||
return accessRef.exists | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
export { default } from './inviteLink.container' | ||
export { default } from './inviteLink' |
12 changes: 0 additions & 12 deletions
12
src/screens/components/addUserModal/inviteLink/inviteLink.container.js
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,27 @@ | ||
import { bool, node } from 'prop-types' | ||
import { node } from 'prop-types' | ||
import { useAuth } from 'features/auth' | ||
|
||
const HasRole = ({ authorized, children, otherwise }) => { | ||
if (!authorized) return otherwise | ||
// TODO Refactor later with a hook | ||
const HasRole = ({ of, orgaMembers, eventOwner, children, otherwise }) => { | ||
const { user } = useAuth() | ||
const roles = Array.isArray(of) ? of : [of] | ||
|
||
if (!roles.includes(orgaMembers?.[user.uid]) && eventOwner !== user.uid) { | ||
return otherwise | ||
} | ||
|
||
return children | ||
} | ||
|
||
HasRole.propTypes = { | ||
authorized: bool, | ||
children: node.isRequired, | ||
otherwise: node, | ||
} | ||
|
||
HasRole.defaultProps = { | ||
authorized: false, | ||
otherwise: null, | ||
orgaMembers: null, | ||
eventOwner: null, | ||
} | ||
|
||
export default HasRole |
Oops, something went wrong.