Fix stale me used on switch to anon
This commit is contained in:
		
							parent
							
								
									d0a47fd304
								
							
						
					
					
						commit
						c610f20773
					
				@ -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>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user