Fix stale me used on switch to anon

This commit is contained in:
ekzyis 2023-11-21 00:43:26 +01:00
parent d0a47fd304
commit c610f20773
2 changed files with 24 additions and 14 deletions

View File

@ -9,9 +9,13 @@ export const MeContext = React.createContext({
export function MeProvider ({ me, children }) { export function MeProvider ({ me, children }) {
const { data, refetch } = useQuery(ME, SSR ? {} : { pollInterval: 1000, nextFetchPolicy: 'cache-and-network' }) const { data, refetch } = useQuery(ME, SSR ? {} : { pollInterval: 1000, nextFetchPolicy: 'cache-and-network' })
// this makes sure that we always use the fetched data if it's null.
// without this, we would always fallback to the `me` object
// which was passed during page load which (visually) breaks switching to anon
const futureMe = data?.me ?? (data?.me === null ? null : me)
return ( return (
<MeContext.Provider value={{ me: data?.me || me, refetch }}> <MeContext.Provider value={{ me: futureMe, refetch }}>
{children} {children}
</MeContext.Provider> </MeContext.Provider>
) )

View File

@ -1,4 +1,4 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react' import { createContext, useCallback, useContext, useEffect, useState } from 'react'
import AnonIcon from '../svgs/spy-fill.svg' import AnonIcon from '../svgs/spy-fill.svg'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import cookie from 'cookie' import cookie from 'cookie'
@ -14,6 +14,7 @@ const b64Decode = str => Buffer.from(str, 'base64').toString('utf-8')
export const AccountProvider = ({ children }) => { export const AccountProvider = ({ children }) => {
const me = useMe() const me = useMe()
const [accounts, setAccounts] = useState([]) const [accounts, setAccounts] = useState([])
const [isAnon, setIsAnon] = useState(true)
useEffect(() => { useEffect(() => {
try { try {
@ -35,21 +36,21 @@ export const AccountProvider = ({ children }) => {
setAccounts(accounts => accounts.filter(({ id }) => id !== userId)) setAccounts(accounts => accounts.filter(({ id }) => id !== userId))
}, [setAccounts]) }, [setAccounts])
const isAnon = useMemo(() => { useEffect(() => {
// document not defined on server // document not defined on server
if (SSR) return false if (SSR) return
const { 'multi_auth.user-id': multiAuthUserIdCookie } = cookie.parse(document.cookie) const { 'multi_auth.user-id': multiAuthUserIdCookie } = cookie.parse(document.cookie)
if (!multiAuthUserIdCookie) return false if (!multiAuthUserIdCookie) return false
return multiAuthUserIdCookie === 'anonymous' setIsAnon(multiAuthUserIdCookie === 'anonymous')
}, [accounts]) }, [])
return <AccountContext.Provider value={{ accounts, addAccount, removeAccount, isAnon }}>{children}</AccountContext.Provider> return <AccountContext.Provider value={{ accounts, addAccount, removeAccount, isAnon, setIsAnon }}>{children}</AccountContext.Provider>
} }
export const useAccounts = () => useContext(AccountContext) export const useAccounts = () => useContext(AccountContext)
const AnonAccount = () => { const AnonAccount = ({ selected, onClick }) => {
const me = useMe() const { isAnon, setIsAnon } = useAccounts()
const refreshMe = useMeRefresh() const refreshMe = useMeRefresh()
return ( return (
<div <div
@ -57,13 +58,15 @@ const AnonAccount = () => {
> >
<AnonIcon <AnonIcon
className='fill-muted' className='fill-muted'
width='135' height='135' style={{ cursor: 'pointer' }} onClick={() => { width='135' height='135' style={{ cursor: 'pointer' }} onClick={async () => {
document.cookie = 'multi_auth.user-id=anonymous' document.cookie = 'multi_auth.user-id=anonymous'
refreshMe() // order is important to prevent flashes of no session
setIsAnon(true)
await refreshMe()
}} }}
/> />
<div className='fst-italic'>anonymous</div> <div className='fst-italic'>anonymous</div>
{!me && <div className='text-muted fst-italic'>selected</div>} {isAnon && <div className='text-muted fst-italic'>selected</div>}
</div> </div>
) )
} }
@ -71,15 +74,18 @@ const AnonAccount = () => {
const Account = ({ account, className }) => { const Account = ({ account, className }) => {
const me = useMe() const me = useMe()
const refreshMe = useMeRefresh() const refreshMe = useMeRefresh()
const { setIsAnon } = useAccounts()
const src = account.photoId ? `https://${process.env.NEXT_PUBLIC_MEDIA_DOMAIN}/${account.photoId}` : '/dorian400.jpg' const src = account.photoId ? `https://${process.env.NEXT_PUBLIC_MEDIA_DOMAIN}/${account.photoId}` : '/dorian400.jpg'
return ( return (
<div <div
className='d-flex flex-column me-2 my-1 text-center' className='d-flex flex-column me-2 my-1 text-center'
> >
<Image <Image
width='135' height='135' src={src} style={{ cursor: 'pointer' }} onClick={() => { width='135' height='135' src={src} style={{ cursor: 'pointer' }} onClick={async () => {
document.cookie = `multi_auth.user-id=${account.id}` document.cookie = `multi_auth.user-id=${account.id}`
refreshMe() await refreshMe()
// order is important to prevent flashes of inconsistent data in switch account dialog
setIsAnon(false)
}} }}
/> />
<Link href={`/${account.name}`}>@{account.name}</Link> <Link href={`/${account.name}`}>@{account.name}</Link>