Remove multi auth error checking (#2018)

* Simplify state of selected account

* Remove multi auth error checking
This commit is contained in:
ekzyis 2025-03-25 12:24:15 -05:00 committed by GitHub
parent eaa15b3b43
commit d7e01d0186
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 11 additions and 84 deletions

View File

@ -1,26 +1,21 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react' import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import * as cookie from 'cookie' import * as cookie from 'cookie'
import { useMe } from '@/components/me'
import { USER_ID, SSR } from '@/lib/constants' import { USER_ID, SSR } from '@/lib/constants'
import { USER } from '@/fragments/users' import { USER } from '@/fragments/users'
import { useQuery } from '@apollo/client' import { useQuery } from '@apollo/client'
import { UserListRow } from '@/components/user-list' import { UserListRow } from '@/components/user-list'
import Link from 'next/link' import Link from 'next/link'
import AddIcon from '@/svgs/add-fill.svg' import AddIcon from '@/svgs/add-fill.svg'
import { MultiAuthErrorBanner } from '@/components/banners'
import { cookieOptions, MULTI_AUTH_ANON, MULTI_AUTH_LIST, MULTI_AUTH_POINTER } from '@/lib/auth' import { cookieOptions, MULTI_AUTH_ANON, MULTI_AUTH_LIST, MULTI_AUTH_POINTER } from '@/lib/auth'
const AccountContext = createContext() const AccountContext = createContext()
const CHECK_ERRORS_INTERVAL_MS = 5_000
const b64Decode = str => Buffer.from(str, 'base64').toString('utf-8') const b64Decode = str => Buffer.from(str, 'base64').toString('utf-8')
export const AccountProvider = ({ children }) => { export const AccountProvider = ({ children }) => {
const [accounts, setAccounts] = useState([]) const [accounts, setAccounts] = useState([])
const [meAnon, setMeAnon] = useState(true) const [selected, setSelected] = useState(null)
const [errors, setErrors] = useState([])
const updateAccountsFromCookie = useCallback(() => { const updateAccountsFromCookie = useCallback(() => {
const { [MULTI_AUTH_LIST]: listCookie } = cookie.parse(document.cookie) const { [MULTI_AUTH_LIST]: listCookie } = cookie.parse(document.cookie)
@ -39,51 +34,29 @@ export const AccountProvider = ({ children }) => {
return switchSuccess return switchSuccess
}, [updateAccountsFromCookie]) }, [updateAccountsFromCookie])
const checkErrors = useCallback(() => {
const {
[MULTI_AUTH_LIST]: listCookie,
[MULTI_AUTH_POINTER]: pointerCookie
} = cookie.parse(document.cookie)
const errors = []
if (!listCookie) errors.push(`${MULTI_AUTH_LIST} cookie not found`)
if (!pointerCookie) errors.push(`${MULTI_AUTH_POINTER} cookie not found`)
setErrors(errors)
}, [])
useEffect(() => { useEffect(() => {
if (SSR) return if (SSR) return
updateAccountsFromCookie() updateAccountsFromCookie()
const { [MULTI_AUTH_POINTER]: pointerCookie } = cookie.parse(document.cookie) const { [MULTI_AUTH_POINTER]: pointerCookie } = cookie.parse(document.cookie)
setMeAnon(pointerCookie === 'anonymous') setSelected(pointerCookie === MULTI_AUTH_ANON ? USER_ID.anon : Number(pointerCookie))
}, [updateAccountsFromCookie])
const interval = setInterval(checkErrors, CHECK_ERRORS_INTERVAL_MS)
return () => clearInterval(interval)
}, [updateAccountsFromCookie, checkErrors])
const value = useMemo( const value = useMemo(
() => ({ () => ({
accounts, accounts,
meAnon, selected,
setMeAnon, nextAccount
nextAccount,
multiAuthErrors: errors
}), }),
[accounts, meAnon, setMeAnon, nextAccount]) [accounts, selected, nextAccount])
return <AccountContext.Provider value={value}>{children}</AccountContext.Provider> return <AccountContext.Provider value={value}>{children}</AccountContext.Provider>
} }
export const useAccounts = () => useContext(AccountContext) export const useAccounts = () => useContext(AccountContext)
const AccountListRow = ({ account, ...props }) => { const AccountListRow = ({ account, ...props }) => {
const { meAnon, setMeAnon } = useAccounts() const { selected } = useAccounts()
const { me, refreshMe } = useMe()
const anonRow = account.id === USER_ID.anon
const selected = (meAnon && anonRow) || Number(me?.id) === Number(account.id)
const router = useRouter() const router = useRouter()
// fetch updated names and photo ids since they might have changed since we were issued the JWTs // fetch updated names and photo ids since they might have changed since we were issued the JWTs
@ -103,18 +76,8 @@ const AccountListRow = ({ account, ...props }) => {
// update pointer cookie // update pointer cookie
const options = cookieOptions({ httpOnly: false }) const options = cookieOptions({ httpOnly: false })
document.cookie = cookie.serialize(MULTI_AUTH_POINTER, anonRow ? MULTI_AUTH_ANON : account.id, options) const anon = account.id === USER_ID.anon
document.cookie = cookie.serialize(MULTI_AUTH_POINTER, anon ? MULTI_AUTH_ANON : account.id, options)
// update state
if (anonRow) {
// order is important to prevent flashes of no session
setMeAnon(true)
await refreshMe()
} else {
await refreshMe()
// order is important to prevent flashes of inconsistent data in switch account dialog
setMeAnon(account.id === USER_ID.anon)
}
// reload whatever page we're on to avoid any bugs due to missing authorization etc. // reload whatever page we're on to avoid any bugs due to missing authorization etc.
router.reload() router.reload()
@ -127,30 +90,16 @@ const AccountListRow = ({ account, ...props }) => {
className='d-flex align-items-center me-2' className='d-flex align-items-center me-2'
{...props} {...props}
onNymClick={onClick} onNymClick={onClick}
selected={selected} selected={selected === account.id}
/> />
</div> </div>
) )
} }
export default function SwitchAccountList () { export default function SwitchAccountList () {
const { accounts, multiAuthErrors } = useAccounts() const { accounts } = useAccounts()
const router = useRouter() const router = useRouter()
const hasError = multiAuthErrors.length > 0
if (hasError) {
return (
<>
<div className='my-2'>
<div className='d-flex flex-column flex-wrap mt-2 mb-3'>
<MultiAuthErrorBanner errors={multiAuthErrors} />
</div>
</div>
</>
)
}
// can't show hat since the streak is not included in the JWT payload // can't show hat since the streak is not included in the JWT payload
return ( return (
<> <>

View File

@ -6,7 +6,6 @@ import { useMutation } from '@apollo/client'
import { WELCOME_BANNER_MUTATION } from '@/fragments/users' import { WELCOME_BANNER_MUTATION } from '@/fragments/users'
import { useToast } from '@/components/toast' import { useToast } from '@/components/toast'
import Link from 'next/link' import Link from 'next/link'
import AccordianItem from '@/components/accordian-item'
export function WelcomeBanner ({ Banner }) { export function WelcomeBanner ({ Banner }) {
const { me } = useMe() const { me } = useMe()
@ -124,24 +123,3 @@ export function AuthBanner () {
</Alert> </Alert>
) )
} }
export function MultiAuthErrorBanner ({ errors }) {
return (
<Alert className={styles.banner} key='info' variant='danger'>
<div className='fw-bold mb-3'>Account switching is currently unavailable</div>
<AccordianItem
className='my-3'
header='We have detected the following issues:'
headerColor='var(--bs-danger-text-emphasis)'
body={
<ul>
{errors.map((err, i) => (
<li key={i}>{err}</li>
))}
</ul>
}
/>
<div className='mt-3'>To resolve these issues, please sign out and sign in again.</div>
</Alert>
)
}