-
Andreas Ellewsen authoredAndreas Ellewsen authored
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Page from 'components/page'
import Loading from 'components/loading'
import { styled } from '@mui/material/styles'
import { useUserContext } from 'contexts'
import { HrefButton } from 'components/button'
import { HrefLineButton } from 'components/button/linebutton'
import { submitJsonOpts } from 'utils'
const FlexDiv = styled('div')(() => ({
display: 'flex',
gap: '0.5rem',
}))
function ChooseRegistrationMethod() {
const { t } = useTranslation(['invite'])
return (
<Page>
<h1>{t('header')}</h1>
<p>{t('description')}</p>
<FlexDiv>
<HrefButton to="/oidc/authenticate/">{t('login')}</HrefButton>
<HrefLineButton to="/guestregister">{t('manual')}</HrefLineButton>
</FlexDiv>
</Page>
)
}
interface ShowFeedbackProps {
title: string
description: string
}
function ShowFeedback(props: ShowFeedbackProps) {
const { title, description } = props
return (
<Page>
<h1>{title}</h1>
<p>{description}</p>
</Page>
)
}
function Invite() {
const { t } = useTranslation(['invite'])
const { user, fetchUserInfo } = useUserContext()
const [inviteToken, setInviteToken] = useState('')
const [tokenChecked, setTokenChecked] = useState(false)
const [isCheckingToken, setIsCheckingToken] = useState(false)
const [tokenOk, setTokenOk] = useState(false)
const [checkError, setCheckError] = useState('')
async function checkToken(token: string) {
try {
const response = await fetch(
'/api/ui/v1/invitecheck/',
submitJsonOpts('POST', { invite_token: token })
)
if (response.status === 200) {
setTokenOk(true)
return
}
const data = await response.json()
if ('code' in data) {
setCheckError(data.code)
} else {
setCheckError('unknown')
}
} catch (error) {
console.error(error)
setCheckError('unknown')
} finally {
setTokenChecked(true)
setIsCheckingToken(false)
}
}
console.log({ inviteToken, isCheckingToken, tokenChecked, tokenOk, user })
useEffect(() => {
setIsCheckingToken(true)
// This may seem unecessary, but race conditions have been
// observed where the userinfo endpoint is called too fast
// and no invite_id is found in the server-side session
setTimeout(fetchUserInfo, 100)
}, [setTokenOk])
if (user.auth) {
return <ChooseRegistrationMethod />
}
if (isCheckingToken || (tokenOk && !user.auth)) {
return <Loading />
}
if (inviteToken !== '' && !tokenChecked) {
checkToken(inviteToken)
return <Loading />
}
if (checkError !== '') {
if (
checkError === 'missing_invite_token' ||
checkError === 'invalid_invite_token'
) {
// Missing or invalid token
return (
<ShowFeedback
title={t('common:error.error')}
description={t('invite:errors.invalidToken')}
/>
)
}
if (checkError === 'expired_invite_token') {
// Expired token
return (
<ShowFeedback
title={t('common:error.error')}
description={t('invite:errors.expiredToken')}
/>
)
}
// Unknown error
return (
<ShowFeedback
title={t('common:error.error')}
description={t('common:error.unknown')}
/>
)
}
const providedToken = window.location.hash.slice(1).trim()
if (!inviteToken && providedToken) {
setInviteToken(providedToken)
return <Loading />
}
// We'll end up here if no token was provided in the URL
return (
<ShowFeedback
title={t('common:error.error')}
description={t('invite:errors.invalidToken')}
/>
)
}
export default Invite