2023-11-19 05:48:35 +01:00
|
|
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
2023-11-17 05:00:53 +01:00
|
|
|
import AnonIcon from '../svgs/spy-fill.svg'
|
|
|
|
import { useRouter } from 'next/router'
|
|
|
|
import cookie from 'cookie'
|
|
|
|
import { useMe, useMeRefresh } from './me'
|
|
|
|
import Image from 'react-bootstrap/Image'
|
|
|
|
import Link from 'next/link'
|
2023-11-19 05:49:35 +01:00
|
|
|
import { SSR } from '../lib/constants'
|
2023-11-17 05:00:53 +01:00
|
|
|
|
|
|
|
const AccountContext = createContext()
|
|
|
|
|
2023-11-19 03:04:29 +01:00
|
|
|
const b64Decode = str => Buffer.from(str, 'base64').toString('utf-8')
|
|
|
|
|
2023-11-17 05:00:53 +01:00
|
|
|
export const AccountProvider = ({ children }) => {
|
|
|
|
const me = useMe()
|
2023-11-20 23:43:34 +01:00
|
|
|
const [accounts, setAccounts] = useState([])
|
2023-11-17 05:00:53 +01:00
|
|
|
|
|
|
|
useEffect(() => {
|
2023-11-19 03:04:29 +01:00
|
|
|
try {
|
|
|
|
const { multi_auth: multiAuthCookie } = cookie.parse(document.cookie)
|
|
|
|
const accounts = multiAuthCookie
|
|
|
|
? JSON.parse(b64Decode(multiAuthCookie))
|
|
|
|
: me ? [{ id: me.id, name: me.name, photoId: me.photoId }] : []
|
|
|
|
setAccounts(accounts)
|
|
|
|
} catch (err) {
|
|
|
|
console.error('error parsing cookies:', err)
|
|
|
|
}
|
2023-11-17 05:00:53 +01:00
|
|
|
}, [])
|
|
|
|
|
|
|
|
const addAccount = useCallback(user => {
|
|
|
|
setAccounts(accounts => [...accounts, user])
|
|
|
|
}, [setAccounts])
|
|
|
|
|
|
|
|
const removeAccount = useCallback(userId => {
|
|
|
|
setAccounts(accounts => accounts.filter(({ id }) => id !== userId))
|
|
|
|
}, [setAccounts])
|
|
|
|
|
2023-11-19 05:48:35 +01:00
|
|
|
const isAnon = useMemo(() => {
|
2023-11-19 05:49:35 +01:00
|
|
|
// document not defined on server
|
|
|
|
if (SSR) return false
|
2023-11-19 05:48:35 +01:00
|
|
|
const { 'multi_auth.user-id': multiAuthUserIdCookie } = cookie.parse(document.cookie)
|
|
|
|
if (!multiAuthUserIdCookie) return false
|
|
|
|
return multiAuthUserIdCookie === 'anonymous'
|
2023-11-19 05:49:35 +01:00
|
|
|
}, [accounts])
|
2023-11-19 05:48:35 +01:00
|
|
|
|
|
|
|
return <AccountContext.Provider value={{ accounts, addAccount, removeAccount, isAnon }}>{children}</AccountContext.Provider>
|
2023-11-17 05:00:53 +01:00
|
|
|
}
|
|
|
|
|
2023-11-19 05:48:35 +01:00
|
|
|
export const useAccounts = () => useContext(AccountContext)
|
2023-11-17 05:00:53 +01:00
|
|
|
|
|
|
|
const AnonAccount = () => {
|
|
|
|
const me = useMe()
|
|
|
|
const refreshMe = useMeRefresh()
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className='d-flex flex-column me-2 my-1 text-center'
|
|
|
|
>
|
|
|
|
<AnonIcon
|
|
|
|
className='fill-muted'
|
|
|
|
width='135' height='135' style={{ cursor: 'pointer' }} onClick={() => {
|
|
|
|
document.cookie = 'multi_auth.user-id=anonymous'
|
|
|
|
refreshMe()
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<div className='fst-italic'>anonymous</div>
|
|
|
|
{!me && <div className='text-muted fst-italic'>selected</div>}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const Account = ({ account, className }) => {
|
|
|
|
const me = useMe()
|
|
|
|
const refreshMe = useMeRefresh()
|
|
|
|
const src = account.photoId ? `https://${process.env.NEXT_PUBLIC_MEDIA_DOMAIN}/${account.photoId}` : '/dorian400.jpg'
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className='d-flex flex-column me-2 my-1 text-center'
|
|
|
|
>
|
|
|
|
<Image
|
|
|
|
width='135' height='135' src={src} style={{ cursor: 'pointer' }} onClick={() => {
|
|
|
|
document.cookie = `multi_auth.user-id=${account.id}`
|
|
|
|
refreshMe()
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<Link href={`/${account.name}`}>@{account.name}</Link>
|
|
|
|
{Number(me?.id) === Number(account.id) && <div className='text-muted fst-italic'>selected</div>}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const AddAccount = () => {
|
|
|
|
const router = useRouter()
|
|
|
|
return (
|
|
|
|
<div className='d-flex flex-column me-2 my-1 text-center'>
|
|
|
|
<Image
|
|
|
|
width='135' height='135' src='https://imgs.search.brave.com/t8qv-83e1m_kaajLJoJ0GNID5ch0WvBGmy7Pkyr4kQY/rs:fit:860:0:0/g:ce/aHR0cHM6Ly91cGxv/YWQud2lraW1lZGlh/Lm9yZy93aWtpcGVk/aWEvY29tbW9ucy84/Lzg5L1BvcnRyYWl0/X1BsYWNlaG9sZGVy/LnBuZw' style={{ cursor: 'pointer' }} onClick={() => {
|
|
|
|
router.push({
|
|
|
|
pathname: '/login',
|
|
|
|
query: { callbackUrl: window.location.origin + router.asPath, multiAuth: true }
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<div className='fst-italic'>+ add account</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default function SwitchAccountDialog () {
|
|
|
|
const { accounts } = useAccounts()
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<h3>Switch Account</h3>
|
|
|
|
<div className='my-2'>
|
|
|
|
<div className='d-flex flex-row flex-wrap'>
|
|
|
|
<AnonAccount />
|
|
|
|
{
|
|
|
|
accounts.map((account) => <Account key={account.id} account={account} />)
|
|
|
|
}
|
|
|
|
<AddAccount />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|