Add terrible gallery page.
rodzic
22ae85c512
commit
b0802f82ba
|
@ -1,6 +1,10 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { FirebaseAppProvider, FirebaseGithubAuthProvider } from "./firebase";
|
||||
import {
|
||||
FirebaseAppProvider,
|
||||
FirebaseGalleryProvider,
|
||||
FirebaseGithubAuthProvider,
|
||||
} from "./firebase";
|
||||
import { PageContext, PAGE_QUERY_ARG } from "./page";
|
||||
import { pageNames, Pages, toPageName, DEFAULT_PAGE } from "./pages";
|
||||
|
||||
|
@ -59,9 +63,11 @@ const App: React.FC<{}> = (props) => {
|
|||
return (
|
||||
<FirebaseAppProvider>
|
||||
<FirebaseGithubAuthProvider>
|
||||
<PageContext.Provider value={ctx}>
|
||||
<PageComponent />
|
||||
</PageContext.Provider>
|
||||
<FirebaseGalleryProvider>
|
||||
<PageContext.Provider value={ctx}>
|
||||
<PageComponent />
|
||||
</PageContext.Provider>
|
||||
</FirebaseGalleryProvider>
|
||||
</FirebaseGithubAuthProvider>
|
||||
</FirebaseAppProvider>
|
||||
);
|
||||
|
|
|
@ -8,8 +8,18 @@ import {
|
|||
Auth,
|
||||
User,
|
||||
} from "firebase/auth";
|
||||
import {
|
||||
FirebaseFirestore,
|
||||
getFirestore,
|
||||
collection,
|
||||
getDocs,
|
||||
CollectionReference,
|
||||
} from "firebase/firestore";
|
||||
import React, { useCallback, useContext, useEffect, useState } from "react";
|
||||
import { AuthContext } from "./auth-context";
|
||||
import { GalleryComposition, GalleryContext } from "./gallery-context";
|
||||
|
||||
const GALLERY_COLLECTION = "compositions";
|
||||
|
||||
const DEFAULT_APP_CONFIG: FirebaseOptions = {
|
||||
apiKey: "AIzaSyAV1kkVvSKEicEa8rLke9o_BxYBu1rb8kw",
|
||||
|
@ -25,6 +35,7 @@ type FirebaseAppContext = {
|
|||
app: FirebaseApp;
|
||||
auth: Auth;
|
||||
provider: GithubAuthProvider;
|
||||
db: FirebaseFirestore;
|
||||
};
|
||||
|
||||
export const FirebaseAppContext =
|
||||
|
@ -47,8 +58,9 @@ export const FirebaseAppProvider: React.FC<{ config?: FirebaseOptions }> = ({
|
|||
const app = initializeApp(config || DEFAULT_APP_CONFIG);
|
||||
const auth = getAuth(app);
|
||||
const provider = new GithubAuthProvider();
|
||||
const db = getFirestore(app);
|
||||
|
||||
setValue({ app, auth, provider });
|
||||
setValue({ app, auth, provider, db });
|
||||
}, [config]);
|
||||
|
||||
return <FirebaseAppContext.Provider value={value} children={children} />;
|
||||
|
@ -90,3 +102,50 @@ export const FirebaseGithubAuthProvider: React.FC<{}> = ({ children }) => {
|
|||
|
||||
return <AuthContext.Provider value={context} children={children} />;
|
||||
};
|
||||
|
||||
type FirebaseCompositionDocument = Omit<GalleryComposition, "id">;
|
||||
|
||||
function getGalleryCollection(appCtx: FirebaseAppContext) {
|
||||
return collection(
|
||||
appCtx.db,
|
||||
GALLERY_COLLECTION
|
||||
) as CollectionReference<FirebaseCompositionDocument>;
|
||||
}
|
||||
|
||||
export const FirebaseGalleryProvider: React.FC<{}> = ({ children }) => {
|
||||
const appCtx = useContext(FirebaseAppContext);
|
||||
const [compositions, setCompositions] = useState<GalleryComposition[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | undefined>(undefined);
|
||||
|
||||
const handleError = (e: Error) => {
|
||||
setIsLoading(false);
|
||||
setError(e.message);
|
||||
};
|
||||
|
||||
const context: GalleryContext = {
|
||||
compositions,
|
||||
isLoading,
|
||||
error,
|
||||
refresh: useCallback(() => {
|
||||
if (!(appCtx && !isLoading)) return false;
|
||||
|
||||
setError(undefined);
|
||||
setIsLoading(true);
|
||||
getDocs(getGalleryCollection(appCtx))
|
||||
.then((snapshot) => {
|
||||
setIsLoading(false);
|
||||
setCompositions(
|
||||
snapshot.docs.map((doc) => ({
|
||||
id: doc.id,
|
||||
...doc.data(),
|
||||
}))
|
||||
);
|
||||
})
|
||||
.catch(handleError);
|
||||
return true;
|
||||
}, [appCtx, isLoading]),
|
||||
};
|
||||
|
||||
return <GalleryContext.Provider value={context} children={children} />;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import React from "react";
|
||||
|
||||
export type GalleryComposition = {
|
||||
id: string;
|
||||
kind: "creature" | "mandala";
|
||||
owner: string;
|
||||
ownerName: string;
|
||||
title: string;
|
||||
serializedValue: string;
|
||||
};
|
||||
|
||||
export interface GalleryContext {
|
||||
compositions: GalleryComposition[];
|
||||
isLoading: boolean;
|
||||
error?: string;
|
||||
refresh(): boolean;
|
||||
}
|
||||
|
||||
export const GalleryContext = React.createContext<GalleryContext>({
|
||||
compositions: [],
|
||||
isLoading: false,
|
||||
refresh: () => true,
|
||||
});
|
|
@ -112,3 +112,7 @@ ul.navbar li:last-child {
|
|||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ const AuthWidget: React.FC<{}> = () => {
|
|||
<button onClick={ctx.login}>Login with {ctx.providerName}</button>
|
||||
);
|
||||
|
||||
const error = ctx.error ? <p style={{ color: "red" }}>{ctx.error}</p> : null;
|
||||
const error = ctx.error ? <p className="error">{ctx.error}</p> : null;
|
||||
|
||||
return (
|
||||
<div className="thingy">
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { GalleryComposition, GalleryContext } from "../gallery-context";
|
||||
import { Page } from "../page";
|
||||
|
||||
const GalleryCompositionView: React.FC<GalleryComposition> = (props) => {
|
||||
return <p>{props.title}</p>;
|
||||
};
|
||||
|
||||
export const GalleryPage: React.FC<{}> = () => {
|
||||
const ctx = useContext(GalleryContext);
|
||||
const [refreshed, setRefreshed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!refreshed) {
|
||||
if (ctx.refresh()) {
|
||||
setRefreshed(true);
|
||||
}
|
||||
}
|
||||
}, [ctx, refreshed]);
|
||||
|
||||
return (
|
||||
<Page title="Gallery!">
|
||||
<div className="sidebar">
|
||||
<button onClick={() => setRefreshed(false)} disabled={ctx.isLoading}>
|
||||
{ctx.isLoading ? "Loading\u2026" : "Refresh"}
|
||||
</button>
|
||||
{ctx.error && <p className="error">{ctx.error}</p>}
|
||||
</div>
|
||||
<div className="canvas scrollable">
|
||||
{ctx.compositions.map((comp) => (
|
||||
<GalleryCompositionView key={comp.id} {...comp} />
|
||||
))}
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
};
|
|
@ -3,12 +3,14 @@ import { VocabularyPage } from "./vocabulary-page";
|
|||
import { CreaturePage } from "./creature-page";
|
||||
import { MandalaPage } from "./mandala-page";
|
||||
import { DebugPage } from "./debug-page";
|
||||
import { GalleryPage } from "./gallery-page";
|
||||
|
||||
export const Pages = {
|
||||
vocabulary: VocabularyPage,
|
||||
creature: CreaturePage,
|
||||
waves: WavesPage,
|
||||
mandala: MandalaPage,
|
||||
gallery: GalleryPage,
|
||||
debug: DebugPage,
|
||||
};
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue