2023-01-22 19:46:56 +01:00
|
|
|
import Link from 'next/link'
|
|
|
|
import { useTranslation } from 'next-i18next'
|
2023-03-24 17:43:38 +01:00
|
|
|
import { useAccount } from 'shared/hooks/use-account.mjs'
|
2023-08-15 17:32:47 +02:00
|
|
|
import { useBackend } from 'shared/hooks/use-backend.mjs'
|
2023-05-08 09:31:37 +02:00
|
|
|
import { roles } from 'config/roles.mjs'
|
2023-08-14 19:16:47 +02:00
|
|
|
import { useEffect, useState } from 'react'
|
|
|
|
import { Loading } from 'shared/components/spinner.mjs'
|
2023-01-22 19:46:56 +01:00
|
|
|
|
2023-01-28 18:10:29 +01:00
|
|
|
export const ns = ['auth']
|
2023-01-22 19:46:56 +01:00
|
|
|
|
|
|
|
const Wrap = ({ children }) => (
|
2023-08-15 17:32:47 +02:00
|
|
|
<div className="m-auto max-w-xl text-center mt-24 p-8">{children}</div>
|
2023-01-22 19:46:56 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
const ContactSupport = ({ t }) => (
|
|
|
|
<div className="flex flex-row items-center justify-center gap-4 mt-8">
|
2023-08-15 17:32:47 +02:00
|
|
|
<Link href="/support" className="btn btn-success w-full">
|
2023-01-22 19:46:56 +01:00
|
|
|
{t('contactSupport')}
|
|
|
|
</Link>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const AuthRequired = ({ t, banner }) => (
|
2023-01-22 19:46:56 +01:00
|
|
|
<Wrap>
|
2023-08-15 17:32:47 +02:00
|
|
|
{banner}
|
2023-01-22 19:46:56 +01:00
|
|
|
<h1>{t('authRequired')}</h1>
|
|
|
|
<p>{t('membersOnly')}</p>
|
|
|
|
<div className="flex flex-row items-center justify-center gap-4 mt-8">
|
|
|
|
<Link href="/signup" className="btn btn-primary w-32">
|
|
|
|
{t('signUp')}
|
|
|
|
</Link>
|
2023-03-19 19:11:50 +01:00
|
|
|
<Link href="/signin" className="btn btn-primary btn-outline w-32">
|
|
|
|
{t('signIn')}
|
2023-01-22 19:46:56 +01:00
|
|
|
</Link>
|
|
|
|
</div>
|
|
|
|
</Wrap>
|
|
|
|
)
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const AccountInactive = ({ t, banner }) => (
|
2023-01-22 19:46:56 +01:00
|
|
|
<Wrap>
|
2023-08-15 17:32:47 +02:00
|
|
|
{banner}
|
2023-01-22 19:46:56 +01:00
|
|
|
<h1>{t('accountInactive')}</h1>
|
|
|
|
<p>{t('accountInactiveMsg')}</p>
|
|
|
|
<p>{t('signupAgain')}</p>
|
|
|
|
<div className="flex flex-row items-center justify-center gap-4 mt-8">
|
|
|
|
<Link href="/signup" className="btn btn-primary w-full">
|
|
|
|
{t('signUp')}
|
|
|
|
</Link>
|
|
|
|
</div>
|
|
|
|
</Wrap>
|
|
|
|
)
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const AccountDisabled = ({ t, banner }) => (
|
2023-01-22 19:46:56 +01:00
|
|
|
<Wrap>
|
2023-08-15 17:32:47 +02:00
|
|
|
{banner}
|
2023-01-22 19:46:56 +01:00
|
|
|
<h1>{t('accountDisabled')}</h1>
|
|
|
|
<p>{t('accountDisabledMsg')}</p>
|
|
|
|
<ContactSupport t={t} />
|
|
|
|
</Wrap>
|
|
|
|
)
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const AccountProhibited = ({ t, banner }) => (
|
2023-01-22 19:46:56 +01:00
|
|
|
<Wrap>
|
2023-08-15 17:32:47 +02:00
|
|
|
{banner}
|
2023-01-22 19:46:56 +01:00
|
|
|
<h1>{t('accountProhibited')}</h1>
|
|
|
|
<p>{t('accountProhibitedMsg')}</p>
|
|
|
|
<ContactSupport t={t} />
|
|
|
|
</Wrap>
|
|
|
|
)
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const AccountStatusUnknown = ({ t, banner }) => (
|
2023-01-22 19:46:56 +01:00
|
|
|
<Wrap>
|
2023-08-15 17:32:47 +02:00
|
|
|
{banner}
|
2023-01-22 19:46:56 +01:00
|
|
|
<h1>{t('statusUnknown')}</h1>
|
|
|
|
<p>{t('statusUnknownMsg')}</p>
|
|
|
|
<ContactSupport t={t} />
|
|
|
|
</Wrap>
|
|
|
|
)
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const RoleLacking = ({ t, requiredRole, role, banner }) => (
|
2023-05-08 09:31:37 +02:00
|
|
|
<Wrap>
|
2023-08-15 17:32:47 +02:00
|
|
|
{banner}
|
2023-05-08 09:31:37 +02:00
|
|
|
<h1>{t('roleLacking')}</h1>
|
|
|
|
<p dangerouslySetInnerHTML={{ __html: t('roleLackingMsg', { requiredRole, role }) }} />
|
|
|
|
<ContactSupport t={t} />
|
|
|
|
</Wrap>
|
|
|
|
)
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const ConsentLacking = ({ t, banner }) => (
|
2023-01-22 19:46:56 +01:00
|
|
|
<Wrap>
|
2023-08-15 17:32:47 +02:00
|
|
|
{banner}
|
2023-01-22 19:46:56 +01:00
|
|
|
<h1>{t('consentLacking')}</h1>
|
|
|
|
<p>{t('membersOnly')}</p>
|
|
|
|
<div className="flex flex-row items-center justify-center gap-4 mt-8">
|
|
|
|
<Link href="/signup" className="btn btn-primary w-32">
|
|
|
|
{t('signUp')}
|
|
|
|
</Link>
|
2023-03-19 19:11:50 +01:00
|
|
|
<Link href="/signin" className="btn btn-primary btn-outline w-32">
|
|
|
|
{t('signIn')}
|
2023-01-22 19:46:56 +01:00
|
|
|
</Link>
|
|
|
|
</div>
|
|
|
|
</Wrap>
|
|
|
|
)
|
|
|
|
|
2023-05-08 09:31:37 +02:00
|
|
|
export const AuthWrapper = ({ children, app, requiredRole = 'user' }) => {
|
2023-01-28 18:10:29 +01:00
|
|
|
const { t } = useTranslation(ns)
|
2023-08-15 17:32:47 +02:00
|
|
|
const { account, token, admin, stopImpersonating } = useAccount()
|
|
|
|
const backend = useBackend()
|
2023-08-14 19:16:47 +02:00
|
|
|
|
|
|
|
const [ready, setReady] = useState(false)
|
2023-08-15 17:32:47 +02:00
|
|
|
const [impersonating, setImpersonating] = useState(false)
|
2023-08-14 19:16:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Avoid hydration errors
|
|
|
|
*/
|
2023-08-15 17:32:47 +02:00
|
|
|
useEffect(() => {
|
|
|
|
const verifyAdmin = async () => {
|
|
|
|
const result = await backend.adminPing(admin.token)
|
|
|
|
if (result.success && result.data.account.role === 'admin') {
|
|
|
|
setImpersonating({
|
|
|
|
admin: result.data.account.username,
|
|
|
|
user: account.username,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (admin && admin.token) verifyAdmin()
|
|
|
|
setReady(true)
|
|
|
|
}, [admin])
|
2023-08-14 19:16:47 +02:00
|
|
|
|
|
|
|
if (!ready) return <Loading />
|
|
|
|
|
2023-08-15 17:32:47 +02:00
|
|
|
const banner = impersonating ? (
|
|
|
|
<div className="bg-warning rounded-lg shadow py-4 px-6 flex flex-row items-center gap-4 justify-between">
|
|
|
|
<span className="text-base-100 text-left">
|
|
|
|
Hi <b>{impersonating.admin}</b>, you are currently impersonating <b>{impersonating.user}</b>
|
|
|
|
</span>
|
|
|
|
<button className="btn btn-neutral" onClick={stopImpersonating}>
|
|
|
|
Stop Impersonating
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
) : null
|
|
|
|
|
|
|
|
const childProps = { t, banner }
|
|
|
|
|
|
|
|
if (!token || !account.username) return <AuthRequired {...childProps} />
|
2023-03-24 17:43:38 +01:00
|
|
|
if (account.status !== 1) {
|
2023-08-15 17:32:47 +02:00
|
|
|
if (account.status === 0) return <AccountInactive {...childProps} />
|
|
|
|
if (account.status === -1) return <AccountDisabled {...childProps} />
|
|
|
|
if (account.status === -2) return <AccountProhibited {...childProps} />
|
|
|
|
return <AccountStatusUnknown {...childProps} />
|
2023-01-22 19:46:56 +01:00
|
|
|
}
|
2023-08-15 17:32:47 +02:00
|
|
|
if (account.consent < 1) return <ConsentLacking {...childProps} />
|
2023-01-22 19:46:56 +01:00
|
|
|
|
2023-05-08 09:31:37 +02:00
|
|
|
if (!roles.levels[account.role] || roles.levels[account.role] < roles.levels[requiredRole]) {
|
2023-08-15 17:32:47 +02:00
|
|
|
return <RoleLacking {...childProps} role={account.role} requiredRole={requiredRole} />
|
2023-05-08 09:31:37 +02:00
|
|
|
}
|
|
|
|
|
2023-01-22 19:46:56 +01:00
|
|
|
return children
|
|
|
|
}
|