Add Google and Github auth providers (#350)

This commit is contained in:
Piotr Rogowski 2021-12-26 18:45:20 +01:00 committed by GitHub
parent f4ccecdd09
commit 25228fba25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 110 additions and 24 deletions

View File

@ -1,13 +1,19 @@
import { useState } from 'react';
import {
useCallback,
useState,
} from 'react';
import {
Form,
Input,
Button,
Divider,
Space,
} from 'antd';
import {
MailOutlined,
LockOutlined,
GoogleOutlined,
GithubOutlined,
} from '@ant-design/icons';
import {
Link,
@ -27,12 +33,39 @@ const { Item } = Form;
const Login = () => {
const [form] = Form.useForm();
const [isLoading, setIsLoading] = useState(false);
const { login } = useAuth();
const [isEmailLoading, setIsEmailLoading] = useState(false);
const [isGoogleLoading, setIsGoogleLoading] = useState(false);
const [isGithubLoading, setIsGithubLoading] = useState(false);
const { login, googleAuth, githubAuth } = useAuth();
const history = useHistory();
const isAnythingLoading = isEmailLoading || isGoogleLoading || isGithubLoading;
const onFinish = async ({ email, password }: { form: any, email: string, password: string }) => {
setIsLoading(true);
const googleLogin = useCallback(async () => {
setIsGoogleLoading(true);
try {
await googleAuth();
logInSuccessful();
history.push(Routes.ROOT);
} catch (error) {
logInFailed(error as Error);
setIsGoogleLoading(false);
}
}, [googleAuth, history]);
const githubLogin = useCallback(async () => {
setIsGithubLoading(true);
try {
await githubAuth();
logInSuccessful();
history.push(Routes.ROOT);
} catch (error) {
logInFailed(error as Error);
setIsGithubLoading(false);
}
}, [githubAuth, history]);
const emailLogin = async ({ email, password }: { form: any, email: string, password: string }) => {
setIsEmailLoading(true);
try {
const userCredentials = await login(email, password);
logInSuccessful();
@ -46,16 +79,16 @@ const Login = () => {
form.resetFields();
console.warn(error);
logInFailed(error as Error);
setIsLoading(false);
setIsEmailLoading(false);
}
};
return (
<div style={containerStyle}>
<Divider>Log In</Divider>
<Divider>Log In using email</Divider>
<Form
initialValues={{ remember: true }}
onFinish={onFinish}
onFinish={emailLogin}
validateMessages={validateMessages}
autoComplete="off"
form={form}
@ -68,6 +101,7 @@ const Login = () => {
<Input
prefix={<MailOutlined />}
placeholder="Email"
disabled={isAnythingLoading}
/>
</Item>
<Item
@ -78,6 +112,7 @@ const Login = () => {
<Input.Password
placeholder="Password"
prefix={<LockOutlined />}
disabled={isAnythingLoading}
/>
</Item>
<Item>
@ -85,16 +120,41 @@ const Login = () => {
type="primary"
htmlType="submit"
style={{ width: '100%' }}
loading={isLoading}
loading={isEmailLoading}
disabled={isAnythingLoading}
>
Log In
</Button>
</Item>
<Link to={Routes.SIGN_UP}>Sign Up now</Link>
<Link to={Routes.RESET_PASSWORD} style={{ float: 'right' }}>
</Form>
<Space direction="horizontal" style={{ width: '100%', justifyContent: 'center' }}>
<Item>
<Button
loading={isGoogleLoading}
onClick={googleLogin}
disabled={isAnythingLoading}
>
<GoogleOutlined />Google
</Button>
</Item>
<Item>
<Button
loading={isGithubLoading}
onClick={githubLogin}
disabled={isAnythingLoading}
>
<GithubOutlined />GitHub
</Button>
</Item>
</Space>
<Button type="link">
<Link to={Routes.SIGN_UP}>Sign Up</Link>
</Button>
<Button type="link" style={{ float: 'right' }}>
<Link to={Routes.RESET_PASSWORD}>
Forgot password?
</Link>
</Form>
</Button>
</div>
);
};

View File

@ -27,7 +27,7 @@ const ResetPassword = () => {
const { resetPassword } = useAuth();
const history = useHistory();
const onFinish = async ({ email, password }: { form: any, email: string, password: string }) => {
const onFinish = async ({ email }: { form: any, email: string }) => {
setIsLoading(true);
try {
await resetPassword(email);
@ -71,7 +71,7 @@ const ResetPassword = () => {
Reset password
</Button>
</Item>
<Link to={Routes.SIGN_UP}>Sign Up now</Link>
<Link to={Routes.SIGN_UP}>Sign Up</Link>
<Link to={Routes.LOGIN} style={{ float: 'right' }}>
Log In
</Link>

View File

@ -112,8 +112,10 @@ const SignUp = () => {
Sign Up
</Button>
</Item>
Or <Link to={Routes.LOGIN}>login</Link> if you already have an account!
</Form>
<Link to={Routes.LOGIN} style={{ float: 'right' }}>
Log In
</Link>
</div>
);
};

View File

@ -97,6 +97,7 @@ const TopBar = () => {
</Menu.Item>
</>
)}
<Menu.Divider />
<Menu.Item key="gh" icon={<GithubOutlined />}>
<a
href="https://github.com/speedy-tuner/speedy-tuner-cloud"
@ -106,7 +107,6 @@ const TopBar = () => {
GitHub
</a>
</Menu.Item>
<Menu.Divider />
<Menu.Item key="preferences" disabled icon={<SettingOutlined />}>
Preferences
</Menu.Item>

View File

@ -1,4 +1,7 @@
import { UserCredential } from 'firebase/auth';
import {
User,
UserCredential,
} from 'firebase/auth';
import {
createContext,
ReactNode,
@ -14,23 +17,28 @@ import {
sendEmailVerification,
signOut,
sendPasswordResetEmail,
GoogleAuthProvider,
GithubAuthProvider,
signInWithPopup,
} from '../firebase';
const AuthContext = createContext<any>(null);
interface AuthValue {
currentUser?: UserCredential,
signUp: (email: string, password: string) => Promise<UserCredential>,
currentUser: User | null,
signUp: (email: string, password: string) => Promise<void>,
login: (email: string, password: string) => Promise<UserCredential>,
logout: () => Promise<void>,
resetPassword: (email: string) => Promise<UserCredential>,
resetPassword: (email: string) => Promise<void>,
googleAuth: () => Promise<void>,
githubAuth: () => Promise<void>,
}
const useAuth = () => useContext<AuthValue>(AuthContext);
const AuthContext = createContext<AuthValue | null>(null);
const useAuth = () => useContext<AuthValue>(AuthContext as any);
const AuthProvider = (props: { children: ReactNode }) => {
const { children } = props;
const [currentUser, setCurrentUser] = useState<any | null>(null);
const [currentUser, setCurrentUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
const value = useMemo(() => ({
@ -40,6 +48,16 @@ const AuthProvider = (props: { children: ReactNode }) => {
login: (email: string, password: string) => signInWithEmailAndPassword(auth, email, password),
logout: () => signOut(auth),
resetPassword: (email: string) => sendPasswordResetEmail(auth, email),
googleAuth: async () => {
const provider = new GoogleAuthProvider().addScope('https://www.googleapis.com/auth/userinfo.email');
const credentials = await signInWithPopup(auth, provider);
setCurrentUser(credentials.user);
},
githubAuth: async () => {
const provider = new GithubAuthProvider().addScope('user:email');
const credentials = await signInWithPopup(auth, provider);
setCurrentUser(credentials.user);
},
}), [currentUser]);
useEffect(() => {

View File

@ -6,6 +6,9 @@ import {
signOut,
sendEmailVerification,
sendPasswordResetEmail,
GoogleAuthProvider,
GithubAuthProvider,
signInWithPopup,
} from 'firebase/auth';
import { getAnalytics } from 'firebase/analytics';
@ -31,4 +34,7 @@ export {
sendEmailVerification,
signOut,
sendPasswordResetEmail,
GoogleAuthProvider,
GithubAuthProvider,
signInWithPopup,
};