Factor out firebase.tsx, FirebaseAppContext (#216)

This factors out a ` firebase.tsx` file and a `FirebaseAppContext` in preparation for gallery work (#26).
pull/217/head
Atul Varma 2021-08-22 09:10:17 -04:00 zatwierdzone przez GitHub
rodzic bec2c4eb49
commit 22ae85c512
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 139 dodań i 112 usunięć

Wyświetl plik

@ -0,0 +1,38 @@
import React from "react";
/**
* Generic interface for authentication.
*/
export interface AuthContext {
/**
* The currently logged-in user. This will be
* null if the user isn't logged in, otherwise it will
* be their name.
*/
loggedInUser: string | null;
/**
* The name of the authentication provider, e.g. "GitHub",
* or null if auth is disabled.
*/
providerName: string | null;
/**
* If authentication failed for some reason, this will
* be a string describing the error.
*/
error?: string;
/** Begin the login UI flow. */
login(): void;
/** Log out the user. */
logout(): void;
}
export const AuthContext = React.createContext<AuthContext>({
loggedInUser: null,
providerName: null,
login() {},
logout() {},
});

Wyświetl plik

@ -1,105 +0,0 @@
import { FirebaseApp, FirebaseOptions, initializeApp } from "firebase/app";
import {
getAuth,
signInWithPopup,
GithubAuthProvider,
onAuthStateChanged,
signOut,
Auth,
User,
} from "firebase/auth";
import React, { useCallback, useEffect, useState } from "react";
const DEFAULT_APP_CONFIG: FirebaseOptions = {
apiKey: "AIzaSyAV1kkVvSKEicEa8rLke9o_BxYBu1rb8kw",
authDomain: "mystic-addaf.firebaseapp.com",
projectId: "mystic-addaf",
storageBucket: "mystic-addaf.appspot.com",
messagingSenderId: "26787182745",
appId: "1:26787182745:web:e4fbd9439b9279fe966008",
measurementId: "G-JHKRSK1PR6",
};
/**
* Generic interface for authentication.
*/
export interface AuthContext {
/**
* The currently logged-in user. This will be
* null if the user isn't logged in, otherwise it will
* be their name.
*/
loggedInUser: string | null;
/**
* The name of the authentication provider, e.g. "GitHub",
* or null if auth is disabled.
*/
providerName: string | null;
/**
* If authentication failed for some reason, this will
* be a string describing the error.
*/
error?: string;
/** Begin the login UI flow. */
login(): void;
/** Log out the user. */
logout(): void;
}
type FirebaseGithubAuthState = {
app: FirebaseApp;
auth: Auth;
provider: GithubAuthProvider;
};
/**
* A Firebase GitHub authentication provider.
*
* Note this component is assumed to never be unmounted, nor
* for its props to change.
*/
export const FirebaseGithubAuthProvider: React.FC<{
config?: FirebaseOptions;
}> = ({ config, children }) => {
const [state, setState] = useState<FirebaseGithubAuthState | null>(null);
const [user, setUser] = useState<User | null>(null);
const [error, setError] = useState<string | undefined>(undefined);
const handleError = (e: Error) => setError(e.message);
useEffect(() => {
const app = initializeApp(config || DEFAULT_APP_CONFIG);
const auth = getAuth(app);
const provider = new GithubAuthProvider();
setState({ app, auth, provider });
onAuthStateChanged(auth, setUser);
}, [config]);
const context: AuthContext = {
loggedInUser: user && user.displayName,
providerName: "GitHub",
error,
login: useCallback(() => {
setError(undefined);
state && signInWithPopup(state.auth, state.provider).catch(handleError);
}, [state]),
logout: useCallback(() => {
setError(undefined);
state && signOut(state.auth).catch(handleError);
}, [state]),
};
return <AuthContext.Provider value={context} children={children} />;
};
export const AuthContext = React.createContext<AuthContext>({
loggedInUser: null,
providerName: null,
login() {},
logout() {},
});

Wyświetl plik

@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import ReactDOM from "react-dom";
import { FirebaseGithubAuthProvider } from "./auth";
import { FirebaseAppProvider, FirebaseGithubAuthProvider } from "./firebase";
import { PageContext, PAGE_QUERY_ARG } from "./page";
import { pageNames, Pages, toPageName, DEFAULT_PAGE } from "./pages";
@ -57,11 +57,13 @@ const App: React.FC<{}> = (props) => {
};
return (
<FirebaseGithubAuthProvider>
<PageContext.Provider value={ctx}>
<PageComponent />
</PageContext.Provider>
</FirebaseGithubAuthProvider>
<FirebaseAppProvider>
<FirebaseGithubAuthProvider>
<PageContext.Provider value={ctx}>
<PageComponent />
</PageContext.Provider>
</FirebaseGithubAuthProvider>
</FirebaseAppProvider>
);
};

92
lib/firebase.tsx 100644
Wyświetl plik

@ -0,0 +1,92 @@
import { FirebaseApp, FirebaseOptions, initializeApp } from "firebase/app";
import {
getAuth,
signInWithPopup,
GithubAuthProvider,
onAuthStateChanged,
signOut,
Auth,
User,
} from "firebase/auth";
import React, { useCallback, useContext, useEffect, useState } from "react";
import { AuthContext } from "./auth-context";
const DEFAULT_APP_CONFIG: FirebaseOptions = {
apiKey: "AIzaSyAV1kkVvSKEicEa8rLke9o_BxYBu1rb8kw",
authDomain: "mystic-addaf.firebaseapp.com",
projectId: "mystic-addaf",
storageBucket: "mystic-addaf.appspot.com",
messagingSenderId: "26787182745",
appId: "1:26787182745:web:e4fbd9439b9279fe966008",
measurementId: "G-JHKRSK1PR6",
};
type FirebaseAppContext = {
app: FirebaseApp;
auth: Auth;
provider: GithubAuthProvider;
};
export const FirebaseAppContext =
React.createContext<FirebaseAppContext | null>(null);
/**
* A Firebase app provider. Any other components that use Firebase must
* be a child of this.
*
* Note this component is assumed to never be unmounted, nor
* for its non-children props to change.
*/
export const FirebaseAppProvider: React.FC<{ config?: FirebaseOptions }> = ({
config,
children,
}) => {
const [value, setValue] = useState<FirebaseAppContext | null>(null);
useEffect(() => {
const app = initializeApp(config || DEFAULT_APP_CONFIG);
const auth = getAuth(app);
const provider = new GithubAuthProvider();
setValue({ app, auth, provider });
}, [config]);
return <FirebaseAppContext.Provider value={value} children={children} />;
};
/**
* A Firebase GitHub authentication provider. Must be a child of a
* `FirebaseAppProvider`.
*
* Note this component is assumed to never be unmounted.
*/
export const FirebaseGithubAuthProvider: React.FC<{}> = ({ children }) => {
const appCtx = useContext(FirebaseAppContext);
const [user, setUser] = useState<User | null>(null);
const [error, setError] = useState<string | undefined>(undefined);
const handleError = (e: Error) => setError(e.message);
useEffect(() => {
if (!appCtx) return;
onAuthStateChanged(appCtx.auth, setUser);
}, [appCtx]);
const context: AuthContext = {
loggedInUser: user && user.displayName,
providerName: appCtx && "GitHub",
error,
login: useCallback(() => {
setError(undefined);
appCtx &&
signInWithPopup(appCtx.auth, appCtx.provider).catch(handleError);
}, [appCtx]),
logout: useCallback(() => {
setError(undefined);
appCtx && signOut(appCtx.auth).catch(handleError);
}, [appCtx]),
};
return <AuthContext.Provider value={context} children={children} />;
};

Wyświetl plik

@ -1,5 +1,5 @@
import React, { useContext, useState } from "react";
import { AuthContext } from "../auth";
import { AuthContext } from "../auth-context";
import { AutoSizingSvg } from "../auto-sizing-svg";
import { CreatureContext, CreatureContextType } from "../creature-symbol";
import { createCreatureSymbolFactory } from "../creature-symbol-factory";