Skip to content

Commit

Permalink
Merge pull request #389 from mikefranze/authsession-context
Browse files Browse the repository at this point in the history
Cleaning up contexts
  • Loading branch information
mikefranze authored Nov 28, 2023
2 parents e5516bb + 73ede55 commit 8a84257
Show file tree
Hide file tree
Showing 26 changed files with 250 additions and 258 deletions.
76 changes: 29 additions & 47 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React from 'react'
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import theme from './theme'
import { ThemeProvider } from '@mui/material/styles'
Expand All @@ -8,61 +8,43 @@ import Login from './components/Login'
import CreateElectionTemplates from './components/ElectionForm/CreateElectionTemplates'
import Election from './components/Election/Election'
import Sandbox from './components/Sandbox'
import DebugPage from './components/DebugPage'
import LandingPage from './components/LandingPage'
import { Alert, Box, CssBaseline, Snackbar } from '@mui/material'
import { useAuthSession } from './hooks/useAuthSession'
import { Isnack, SnackbarContext } from './components/SnackbarContext'
import { Box, CssBaseline } from '@mui/material'
import { SnackbarContextProvider } from './components/SnackbarContext'
import Footer from './components/Footer'
import { ConfirmDialogProvider } from './components/ConfirmationDialogProvider'
import About from './components/About'
import { AuthSessionContextProvider } from './components/AuthSessionContextProvider'

const App = () => {
const authSession = useAuthSession()
const [snack, setSnack] = useState({
message: '',
severity: "info",
open: false,
autoHideDuration: null,
} as Isnack)
const handleClose = (event?: React.SyntheticEvent | Event, reason?: string) => {
if (reason === 'clickaway') {
return;
}
setSnack({ ...snack, open: false })
}
return (
<Router>
<ThemeProvider theme={theme}>
<ConfirmDialogProvider>
<SnackbarContext.Provider value={{ snack, setSnack }}>
<Snackbar open={snack.open} autoHideDuration={snack.autoHideDuration} onClose={handleClose} anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}>
<Alert severity={snack.severity} onClose={handleClose}>
{snack.message}
</Alert>
</Snackbar>
<CssBaseline />
<Box display='flex' flexDirection='column' minHeight={'100vh'} >
<Header authSession={authSession} />
<Box
sx={{
width: '100%',
}}>
<Routes>
<Route path='/' element={<LandingPage authSession={authSession} />} />
<Route path='/About' element={<About/>}/>
<Route path='/Elections' element={<Elections authSession={authSession} />} />
<Route path='/Login' element={<Login />} />
<Route path='/Debug' element={<DebugPage authSession={authSession} />} />
<Route path='/CreateElection' element={<CreateElectionTemplates authSession={authSession} />} />
<Route path='/Election/:id/*' element={<Election authSession={authSession} />} />
<Route path='/Sandbox' element={<Sandbox />} />
</Routes>
</Box>
<Footer />
</Box>
</SnackbarContext.Provider>
</ConfirmDialogProvider>
<AuthSessionContextProvider>
<ConfirmDialogProvider>
<SnackbarContextProvider>
<CssBaseline />
<Box display='flex' flexDirection='column' minHeight={'100vh'} >
<Header />
<Box
sx={{
width: '100%',
}}>
<Routes>
<Route path='/' element={<LandingPage />} />
<Route path='/About' element={<About />} />
<Route path='/Elections' element={<Elections />} />
<Route path='/Login' element={<Login />} />
<Route path='/CreateElection' element={<CreateElectionTemplates />} />
<Route path='/Election/:id/*' element={<Election />} />
<Route path='/Sandbox' element={<Sandbox />} />
</Routes>
</Box>
<Footer />
</Box>
</SnackbarContextProvider>
</ConfirmDialogProvider>
</AuthSessionContextProvider>
</ThemeProvider>
</Router>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React, {
createContext,
useCallback,
useContext,
useRef,
useState,
} from 'react';
import { useEffect } from "react";
import { useCookie } from "./useCookie";
import { useCookie } from "../hooks/useCookie";
import jwt_decode from 'jwt-decode'
let keycloakBaseUrl = process.env.REACT_APP_KEYCLOAK_URL;

Expand Down Expand Up @@ -28,10 +35,12 @@ export interface IAuthSession {
getIdField: (fieldName: any) => any
}

export const useAuthSession = (): IAuthSession => {
const [accessToken, setAccessToken] = useCookie('access_token', null, 24*5)
const [idToken, setIdToken] = useCookie('id_token', null, 24*5)
const [refreshToken, setRefreshToken] = useCookie('refresh_token', null, 24*5)
const AuthSessionContext = createContext<IAuthSession>(null);

export function AuthSessionContextProvider({ children }) {
const [accessToken, setAccessToken] = useCookie('access_token', null, 24 * 5)
const [idToken, setIdToken] = useCookie('id_token', null, 24 * 5)
const [refreshToken, setRefreshToken] = useCookie('refresh_token', null, 24 * 5)

const isLoggedIn = () => {
return accessToken !== null
Expand All @@ -45,7 +54,7 @@ export const useAuthSession = (): IAuthSession => {
`scope=openid`,
].join('&');

window.location.href = authConfig.endpoints.login+"?"+queryString;
window.location.href = authConfig.endpoints.login + "?" + queryString;
}

const openLogout = () => {
Expand All @@ -59,7 +68,7 @@ export const useAuthSession = (): IAuthSession => {
setAccessToken(null)
setIdToken(null)
setRefreshToken(null)
window.location.href = authConfig.endpoints.logout+"?"+queryString;
window.location.href = authConfig.endpoints.logout + "?" + queryString;
}

const getIdField = (fieldName: string) => {
Expand All @@ -68,9 +77,9 @@ export const useAuthSession = (): IAuthSession => {
return id_map[fieldName];
}

useEffect( () => {
useEffect(() => {
refreshSession()
},[])
}, [])

const refreshSession = () => {
// This function refreshes our tokens (which we store as cookies)
Expand Down Expand Up @@ -135,7 +144,7 @@ export const useAuthSession = (): IAuthSession => {
// NOTE: Here I'm setting the cookies to expire after REFRESH_HOURS
// I should probably be configuring the expiration time through the oAuth provider instead
// but for now it's convenient to set the expiration time for the cookie and then force a refresh
setAccessToken( data['access_token'] );
setAccessToken(data['access_token']);
setIdToken(data['id_token']);
if (grant_type == 'authorization_code') { // we only receive refresh token on auth code flow
setRefreshToken(data['refresh_token']);
Expand All @@ -144,5 +153,20 @@ export const useAuthSession = (): IAuthSession => {
}

}
return {isLoggedIn, openLogin, openLogout, getIdField}

return (
<AuthSessionContext.Provider
value={{
isLoggedIn: isLoggedIn,
openLogin: openLogin,
openLogout: openLogout,
getIdField: getIdField,
}}>
{children}
</AuthSessionContext.Provider>
);
}

export default function useAuthSession() {
return useContext(AuthSessionContext);
}
44 changes: 0 additions & 44 deletions frontend/src/components/DebugPage.tsx

This file was deleted.

8 changes: 4 additions & 4 deletions frontend/src/components/Election/Admin/Admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import EditRoles from './EditRoles';
import ViewBallots from './ViewBallots';
import AdminHome from './AdminHome';
const Admin = ({ authSession, election, permissions, fetchElection }) => {
const Admin = () => {
return (
<Container>
<Routes>
<Route path='/' element={<AdminHome authSession={authSession}/>} />
<Route path='/' element={<AdminHome />} />
<Route path='/voters' element={<ViewElectionRolls />} />
<Route path='/roles' element={<EditRoles election={election} permissions={permissions} fetchElection={fetchElection} />} />
<Route path='/ballots' element={<ViewBallots election={election} permissions={permissions} />} />
<Route path='/roles' element={<EditRoles />} />
<Route path='/ballots' element={<ViewBallots />} />
</Routes>
</Container>
)
Expand Down
10 changes: 4 additions & 6 deletions frontend/src/components/Election/Admin/AdminHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import ElectionDetailsInlineForm from '../../ElectionForm/Details/ElectionDetail
import Races from '../../ElectionForm/Races/Races';
import ElectionSettings from '../../ElectionForm/ElectionSettings';
import structuredClone from '@ungap/structured-clone';
import { IAuthSession } from '../../../hooks/useAuthSession';
import useAuthSession from '../../AuthSessionContextProvider';
const hasPermission = (permissions: string[], requiredPermission: string) => {
return (permissions && permissions.includes(requiredPermission))
}
Expand Down Expand Up @@ -440,12 +440,10 @@ const FinalizeSection = ({ election, permissions, finalizeElection }: { election
</Grid>
</>)
}


type Props = {
authSession: IAuthSession}

const AdminHome = ({authSession}:Props) => {
const AdminHome = () => {

const authSession = useAuthSession()
const { election, refreshElection: fetchElection, permissions } = useElection()
const { makeRequest } = useSetPublicResults(election.election_id)
const togglePublicResults = async () => {
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/components/Election/Admin/EditRoles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ import PermissionHandler from "../../PermissionHandler";
import { usePutElectionRoles } from "../../../hooks/useAPI";
import { Election } from "../../../../../domain_model/Election";
import { StyledButton } from "../../styles";
import useAuthSession from "../../AuthSessionContextProvider";
import useElection from "../../ElectionContextProvider";

type Props = {
election: Election,
permissions: string[],
fetchElection: Function,
}

const EditRoles = ({ election, permissions, fetchElection }: Props) => {
const EditRoles = () => {
const authSession = useAuthSession()
const { election, voterAuth, refreshElection, permissions, updateElection } = useElection()

const [adminList, setAdminList] = useState(() => {
if (election.admin_ids === null) return ''
Expand Down Expand Up @@ -43,7 +47,7 @@ const EditRoles = ({ election, permissions, fetchElection }: Props) => {

const newRoles = await putRoles.makeRequest({ admin_ids, audit_ids, credential_ids })
if (newRoles) {
fetchElection()
refreshElection()
}
} catch (error) {
console.log(error)
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/Election/Admin/ViewBallot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import PermissionHandler from "../../PermissionHandler";
import { useParams } from "react-router";
import { useGetBallot } from "../../../hooks/useAPI";
import { formatDate } from "../../util";
import useElection from "../../ElectionContextProvider";

const ViewBallot = ({ election, ballot, onClose, fetchBallot, permissions }) => {
const ViewBallot = ({ ballot, onClose }) => {

const { election, refreshElection, permissions, updateElection } = useElection()
const { ballot_id } = useParams();

const { data, isPending, error, makeRequest: fetchBallots } = useGetBallot(election.election_id, ballot_id)
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/Election/Admin/ViewBallots.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import ViewBallot from "./ViewBallot";
import { CSVLink } from "react-csv";
import { useGetBallots } from "../../../hooks/useAPI";
import { formatDate } from "../../util";
import useElection from "../../ElectionContextProvider";

const ViewBallots = ({ election, permissions }) => {
const ViewBallots = () => {
const { election } = useElection()
const { data, isPending, error, makeRequest: fetchBallots } = useGetBallots(election.election_id)
useEffect(() => { fetchBallots() }, [])
const [isViewing, setIsViewing] = useState(false)
Expand Down Expand Up @@ -114,7 +116,7 @@ const ViewBallots = ({ election, permissions }) => {
</>
}
{isViewing && selectedBallot &&
<ViewBallot election={election} ballot={selectedBallot} onClose={onClose} fetchBallot={fetchBallots} permissions={permissions} />
<ViewBallot ballot={selectedBallot} onClose={onClose} />
}
</Container>
)
Expand Down
Loading

0 comments on commit 8a84257

Please sign in to comment.