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

Table login #50

Merged
merged 9 commits into from
Nov 27, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,28 @@ on:
branches:
- master
jobs:
firestore_deploy:
runs-on: ubuntu-latest
env:
working-directory: ./firestore
steps:
- uses: actions/checkout@v3
- run: npm run deploy
working-directory: ${{env.working-directory}}

functions_deploy:
needs: firestore_deploy
runs-on: ubuntu-latest
env:
working-directory: ./functions
steps:
- uses: actions/checkout@v3
- run: npm ci && npm run build
working-directory: ${{env.working-directory}}
- run: npm run deploy

client_deploy:
needs: [firestore_deploy, functions_deploy]
runs-on: ubuntu-latest
env:
working-directory: ./client
Expand All @@ -21,3 +42,4 @@ jobs:
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_POOLSCORE_1973 }}'
channelId: live
projectId: poolscore-1973

11 changes: 7 additions & 4 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { CssBaseline, ThemeProvider, createTheme } from '@mui/material';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers';

import { Store } from './store/Store';
import Router from './Router';
import AuthProvider from './store/AuthProvider';
import ClubProvider from './store/ClubProvider';
import TableProvider from './store/TableProvider';
import { Store } from './store/Store';

const darkTheme = createTheme({
palette: {
Expand All @@ -19,9 +20,11 @@ export default function App() {
<LocalizationProvider dateAdapter={AdapterDayjs}>
<AuthProvider>
<ClubProvider>
<Store>
<Router />
</Store>
<TableProvider>
<Store>
<Router />
</Store>
</TableProvider>
</ClubProvider>
</AuthProvider>
<CssBaseline />
Expand Down
50 changes: 26 additions & 24 deletions client/src/components/AppDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
} from '@mui/material';
import {
CalendarMonth,
Close, Home, Logout, TableRestaurant,
Close, Home, Login, Logout, TableRestaurant,
} from '@mui/icons-material';
import { useAuth } from '../store/AuthProvider';
import { footerText } from './Footer';
Expand All @@ -22,8 +22,11 @@ const drawerBoxSx = {

export default memo((props: AppDrawerProps) => {
const theme = useTheme();
const { userId, userIdLoading, signOut } = useAuth();
const {
userId, userIdLoading, signOut, admin,
} = useAuth();
const isLoggedIn = userId && !userIdLoading;
const isAdmin = isLoggedIn && admin;

const drawerList = (
<List>
Expand All @@ -43,18 +46,7 @@ export default memo((props: AppDrawerProps) => {
</ListItemButton>
</ListItem>
<Divider />
{ /* isLoggedIn ? null
: (
<ListItem>
<ListItemButton component={Link} to="/login">
<ListItemIcon>
<Login />
</ListItemIcon>
<ListItemText primary="Login" />
</ListItemButton>
</ListItem>
) */}
{ isLoggedIn
{ isAdmin
? (
<>
<ListItem>
Expand All @@ -74,17 +66,27 @@ export default memo((props: AppDrawerProps) => {
</ListItemButton>
</ListItem>
<Divider />
<ListItem>
<ListItemButton onClick={signOut}>
<ListItemIcon>
<Logout />
</ListItemIcon>
<ListItemText primary="Logout" />
</ListItemButton>
</ListItem>
</>
)
: null}
) : null }
{ isLoggedIn ? (
<ListItem>
<ListItemButton onClick={signOut}>
<ListItemIcon>
<Logout />
</ListItemIcon>
<ListItemText primary="Logout" />
</ListItemButton>
</ListItem>
) : (
<ListItem>
<ListItemButton component={Link} to="/login">
<ListItemIcon>
<Login />
</ListItemIcon>
<ListItemText primary="Login" />
</ListItemButton>
</ListItem>
)}
<ListItem disablePadding sx={{ position: 'fixed', bottom: 0 }}>
<ListItemButton component={Link} to="/legal">
<ListItemText primary={footerText} secondary="Legal" />
Expand Down
18 changes: 11 additions & 7 deletions client/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import { useAuth } from '../store/AuthProvider';
import AppDrawer from './AppDrawer';

export default function Header() {
const { userId, userIdLoading, signOut } = useAuth();
const loggedIn = userId && !userIdLoading;
const {
userId, userIdLoading, signOut, admin,
} = useAuth();
const isLoggedIn = userId && !userIdLoading;
const isAdmin = isLoggedIn && admin;

const [open, setOpen] = useState(false);
const closeDrawer = useCallback(() => { setOpen(false); }, []);
Expand Down Expand Up @@ -39,14 +42,15 @@ export default function Header() {
<>
<Button component={Link} to="/home">Poolscore</Button>
<Box sx={{ flexGrow: 1 }} />
{ loggedIn ? (
{ isAdmin ? (
<>
<Button component={Link} to="/matchdays">Spieltage</Button>
<Button component={Link} to="/matchday">Spieltage</Button>
<Button component={Link} to="/tables">Tische</Button>
<Button onClick={signOut}>Logout</Button>
</>
)
: null /* <Button component={Link} to="/login">Login</Button> */}
) : null }
{ isLoggedIn
? <Button onClick={signOut}>Logout</Button>
: <Button component={Link} to="/login">Login</Button> }
</>
);

Expand Down
8 changes: 6 additions & 2 deletions client/src/components/HomeLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Stack, useMediaQuery, useTheme } from '@mui/material';
import {
Container, Stack, useMediaQuery, useTheme,
} from '@mui/material';
import Footer from './Footer';
import Header from './Header';

Expand All @@ -13,7 +15,9 @@ export default function Layout({ children }: LayoutProps) {
return (
<Stack height="100vh" spacing={5} alignItems="center">
<Header />
{children}
<Container>
{children}
</Container>
{isDesktop ? <Footer /> : null}
</Stack>
);
Expand Down
33 changes: 24 additions & 9 deletions client/src/store/AuthProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,25 @@ import {
ReactNode, createContext, useEffect, useContext, useMemo, useCallback,
} from 'react';
import { AuthError } from 'firebase/auth';
import { doc } from 'firebase/firestore';
import {
useAuthState, useCreateUserWithEmailAndPassword, useSignInWithEmailAndPassword, useSignOut,
} from 'react-firebase-hooks/auth';
import { useDocumentData } from 'react-firebase-hooks/firestore';

import { auth, db } from './Firebase';
import { auth } from './Firebase';
import useIdTokenResult from '../util/useIdTokenResult';
import useSignInWithTableToken from '../util/useSignInWithTableToken';

interface AuthState {
userId?: string;
userIdLoading: boolean;
clubId?: string;
admin?: boolean;
signUp: (email: string, password: string) => void;
signUpError?: AuthError;
signIn: (email: string, password: string) => void;
signInError?: AuthError;
signInWithToken: (token: string) => void;
signInWithTokenError?: AuthError;
signOut: () => void;
signOutError?: AuthError;
}
Expand All @@ -36,10 +39,7 @@ interface AuthProviderProps {
export default function AuthProvider({ children }: AuthProviderProps) {
const [user, userLoading, errorAuth] = useAuthState(auth, {});
useEffect(() => { if (errorAuth) throw errorAuth; }, [errorAuth]);

const userRef = user?.uid ? doc(db, 'users', user.uid) : null;
const [userData, , userDataError] = useDocumentData(userRef);
useEffect(() => { if (userDataError) throw userDataError; }, [userDataError]);
const tokenResult = useIdTokenResult(user);

const [firebaseSignUp, , , signUpError] = useCreateUserWithEmailAndPassword(auth);
const signUp = useCallback((email: string, password: string) => {
Expand All @@ -53,6 +53,8 @@ export default function AuthProvider({ children }: AuthProviderProps) {
firebaseSignIn(email, password);
}, [user, firebaseSignIn]);

const [signInWithToken, , , signInWithTokenError] = useSignInWithTableToken(auth);

const [firebaseSignOut, , signOutError] = useSignOut(auth);
const signOut = useCallback(() => {
if (!user) throw Error('To sign out you need to sign in first.');
Expand All @@ -62,15 +64,28 @@ export default function AuthProvider({ children }: AuthProviderProps) {
const value = useMemo(() => ({
userId: user?.uid,
userIdLoading: userLoading,
clubId: userData?.club.id,
clubId: tokenResult?.claims.clubId,
admin: tokenResult?.claims.admin,
signUp,
signUpError,
signIn,
signInError,
signInWithToken,
signInWithTokenError,
signOut,
signOutError: signOutError as AuthError,
}), [
user, userLoading, userData, signUp, signUpError, signIn, signInError, signOut, signOutError,
user,
userLoading,
tokenResult,
signUp,
signUpError,
signIn,
signInError,
signInWithToken,
signInWithTokenError,
signOut,
signOutError,
]);

return (
Expand Down
2 changes: 1 addition & 1 deletion client/src/store/ClubProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function ClubProvider({ children }: ClubProviderProps) {
useEffect(() => { if (clubDataError) throw clubDataError; }, [clubDataError]);

const setName = useCallback(async (name: string) => {
if (!clubId) throw Error("Club's id no given. Cannot update it's name.");
if (!clubId) throw Error("Club's id not given. Cannot update it's name.");

await updateDoc(doc(db, 'clubs', clubId), { name });
}, [clubId]);
Expand Down
2 changes: 1 addition & 1 deletion client/src/store/Firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ if (isDevelopment()) { connectFirestoreEmulator(db, 'localhost', 8080); }
const functions = getFunctions(app);
if (isDevelopment()) { connectFunctionsEmulator(functions, 'localhost', 5001); }

export { auth, db };
export { auth, db, functions };
30 changes: 2 additions & 28 deletions client/src/store/Store.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, {
useEffect, createContext, Dispatch, useReducer, useMemo, useCallback,
createContext, Dispatch, useReducer, useMemo, useCallback,
} from 'react';
import {
doc, collection, onSnapshot, addDoc, deleteDoc,
doc, collection, addDoc, deleteDoc,
} from 'firebase/firestore';

import { db } from './Firebase';
Expand Down Expand Up @@ -129,32 +129,6 @@ export function Store({ children } : StoreProps) {

const value = useMemo(() => [state, asyncDispatch] as ContextType, [state, asyncDispatch]);

useEffect(() => {
const clubRef = doc(db, 'club', state.id);
return onSnapshot(clubRef, (snapshot) => {
if (snapshot.exists()) {
dispatch({
type: 'set_name',
name: snapshot.data().name,
});
}
});
}, [state.id]);

useEffect(() => {
const tableRef = collection(db, 'club', state.id, 'tables');
return onSnapshot(tableRef, (snapshot) => {
const tmp = [] as Pooltable[];
snapshot.forEach((d) => {
tmp.push({ id: d.id, name: d.data().name });
});
dispatch({
type: 'set_tables',
tables: tmp.sort((a, b) => a.name.localeCompare(b.name)),
});
});
}, [state.id]);

return (
<Context.Provider value={value}>
{children}
Expand Down
Loading
Loading