2023-11-14 15:10:00 +00:00
|
|
|
import type { AuthModalSource } from '../components/Nav/AuthModal/types'
|
2023-11-28 13:18:25 +00:00
|
|
|
import type { Author, Result } from '../graphql/schema/core.gen'
|
2023-06-16 14:47:24 +00:00
|
|
|
import type { Accessor, JSX, Resource } from 'solid-js'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
2023-11-28 15:36:00 +00:00
|
|
|
import { VerifyEmailInput, LoginInput, AuthToken, User } from '@authorizerdev/authorizer-js'
|
2023-11-29 12:37:27 +00:00
|
|
|
import { cookieStorage, createStorage } from '@solid-primitives/storage'
|
2023-11-28 18:04:51 +00:00
|
|
|
import { createContext, createMemo, createResource, createSignal, onMount, useContext } from 'solid-js'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
import { apiClient } from '../graphql/client/core'
|
2023-06-14 17:19:30 +00:00
|
|
|
import { showModal } from '../stores/ui'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
2023-11-28 15:36:00 +00:00
|
|
|
import { useAuthorizer } from './authorizer'
|
2023-11-14 15:10:00 +00:00
|
|
|
import { useLocalize } from './localize'
|
|
|
|
import { useSnackbar } from './snackbar'
|
2023-12-03 10:22:42 +00:00
|
|
|
import { getToken, resetToken, setToken } from '../stores/token'
|
2022-11-13 19:35:57 +00:00
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
export type SessionContextType = {
|
|
|
|
session: Resource<AuthToken>
|
2022-12-06 16:03:55 +00:00
|
|
|
isSessionLoaded: Accessor<boolean>
|
2023-11-28 13:18:25 +00:00
|
|
|
subscriptions: Accessor<Result>
|
2023-03-29 08:51:27 +00:00
|
|
|
user: Accessor<User>
|
2023-11-28 13:18:25 +00:00
|
|
|
author: Resource<Author | null>
|
2022-11-13 19:35:57 +00:00
|
|
|
isAuthenticated: Accessor<boolean>
|
|
|
|
actions: {
|
2023-12-03 10:22:42 +00:00
|
|
|
getToken: () => string
|
2023-11-28 13:18:25 +00:00
|
|
|
loadSession: () => AuthToken | Promise<AuthToken>
|
2023-10-19 15:05:22 +00:00
|
|
|
loadSubscriptions: () => Promise<void>
|
2023-06-14 17:19:30 +00:00
|
|
|
requireAuthentication: (
|
|
|
|
callback: (() => Promise<void>) | (() => void),
|
2023-11-14 15:10:00 +00:00
|
|
|
modalSource: AuthModalSource,
|
2023-06-14 17:19:30 +00:00
|
|
|
) => void
|
2023-11-28 13:18:25 +00:00
|
|
|
signIn: (params: LoginInput) => Promise<void>
|
2022-11-13 19:35:57 +00:00
|
|
|
signOut: () => Promise<void>
|
2023-11-28 13:18:25 +00:00
|
|
|
confirmEmail: (input: VerifyEmailInput) => Promise<void>
|
2022-11-13 19:35:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-14 10:02:08 +00:00
|
|
|
const SessionContext = createContext<SessionContextType>()
|
2022-11-13 19:35:57 +00:00
|
|
|
|
2022-11-14 10:02:08 +00:00
|
|
|
export function useSession() {
|
|
|
|
return useContext(SessionContext)
|
2022-11-13 19:35:57 +00:00
|
|
|
}
|
|
|
|
|
2023-11-02 17:43:22 +00:00
|
|
|
const EMPTY_SUBSCRIPTIONS = {
|
|
|
|
topics: [],
|
2023-11-14 15:10:00 +00:00
|
|
|
authors: [],
|
2023-11-02 17:43:22 +00:00
|
|
|
}
|
|
|
|
|
2022-11-14 10:02:08 +00:00
|
|
|
export const SessionProvider = (props: { children: JSX.Element }) => {
|
2022-12-06 16:03:55 +00:00
|
|
|
const [isSessionLoaded, setIsSessionLoaded] = createSignal(false)
|
2023-11-28 13:18:25 +00:00
|
|
|
const [subscriptions, setSubscriptions] = createSignal<Result>(EMPTY_SUBSCRIPTIONS)
|
2023-02-17 09:21:02 +00:00
|
|
|
const { t } = useLocalize()
|
2023-02-10 11:11:24 +00:00
|
|
|
const {
|
2023-11-14 15:10:00 +00:00
|
|
|
actions: { showSnackbar },
|
2023-02-10 11:11:24 +00:00
|
|
|
} = useSnackbar()
|
2023-11-28 13:18:25 +00:00
|
|
|
const [, { authorizer }] = useAuthorizer()
|
2023-02-10 11:11:24 +00:00
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
const loadSubscriptions = async (): Promise<void> => {
|
|
|
|
const result = await apiClient.getMySubscriptions()
|
|
|
|
if (result) {
|
|
|
|
setSubscriptions(result)
|
|
|
|
} else {
|
|
|
|
setSubscriptions(EMPTY_SUBSCRIPTIONS)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const getSession = async (): Promise<AuthToken> => {
|
2022-12-06 16:03:55 +00:00
|
|
|
try {
|
2023-12-03 10:22:42 +00:00
|
|
|
const token = getToken()
|
2023-12-10 13:59:50 +00:00
|
|
|
if (token) {
|
|
|
|
const authResult = await authorizer().getSession({
|
|
|
|
Authorization: token,
|
|
|
|
})
|
|
|
|
if (authResult && authResult.access_token) {
|
|
|
|
console.log(authResult)
|
|
|
|
setToken(authResult.access_token)
|
|
|
|
loadSubscriptions()
|
|
|
|
return authResult
|
|
|
|
}
|
2022-12-06 16:03:55 +00:00
|
|
|
}
|
2023-12-10 13:59:50 +00:00
|
|
|
return null
|
2022-12-06 16:03:55 +00:00
|
|
|
} catch (error) {
|
|
|
|
console.error('getSession error:', error)
|
|
|
|
resetToken()
|
|
|
|
return null
|
2022-12-07 11:06:26 +00:00
|
|
|
} finally {
|
2023-11-01 11:17:31 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
setIsSessionLoaded(true)
|
|
|
|
}, 0)
|
2022-12-06 16:03:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
const [session, { refetch: loadSession, mutate }] = createResource<AuthToken>(getSession, {
|
2022-12-06 16:03:55 +00:00
|
|
|
ssrLoadFrom: 'initial',
|
2023-11-14 15:10:00 +00:00
|
|
|
initialValue: null,
|
2022-12-06 16:03:55 +00:00
|
|
|
})
|
2022-11-13 19:35:57 +00:00
|
|
|
|
2023-03-29 08:51:27 +00:00
|
|
|
const user = createMemo(() => session()?.user)
|
2022-11-25 11:03:51 +00:00
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
const [author, { refetch: loadAuthor }] = createResource<Author | null>(
|
|
|
|
async () => {
|
2023-11-28 18:04:51 +00:00
|
|
|
const u = session()?.user
|
|
|
|
if (u) {
|
2023-12-13 23:56:44 +00:00
|
|
|
return (await apiClient.getAuthorId({ user: u.id })) ?? null
|
2023-11-28 13:18:25 +00:00
|
|
|
}
|
|
|
|
return null
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ssrLoadFrom: 'initial',
|
|
|
|
initialValue: null,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
const isAuthenticated = createMemo(() => Boolean(session()?.user))
|
|
|
|
|
|
|
|
const signIn = async (params: LoginInput) => {
|
2023-12-03 16:41:59 +00:00
|
|
|
const authResult: AuthToken | void = await authorizer().login(params)
|
|
|
|
|
|
|
|
if (authResult && authResult.access_token) {
|
2023-12-03 10:22:42 +00:00
|
|
|
setToken(authResult.access_token)
|
2023-11-28 13:18:25 +00:00
|
|
|
mutate(authResult)
|
2023-12-03 16:41:59 +00:00
|
|
|
loadSubscriptions()
|
|
|
|
console.debug('signed in')
|
|
|
|
} else {
|
|
|
|
console.info((authResult as AuthToken).message)
|
2023-11-28 13:18:25 +00:00
|
|
|
}
|
2022-11-13 19:35:57 +00:00
|
|
|
}
|
|
|
|
|
2023-06-14 17:19:30 +00:00
|
|
|
const [isAuthWithCallback, setIsAuthWithCallback] = createSignal(null)
|
|
|
|
|
2023-11-02 17:43:22 +00:00
|
|
|
const requireAuthentication = async (callback: () => void, modalSource: AuthModalSource) => {
|
2023-06-14 17:19:30 +00:00
|
|
|
setIsAuthWithCallback(() => callback)
|
|
|
|
|
2023-11-02 17:43:22 +00:00
|
|
|
await loadSession()
|
|
|
|
|
2023-06-14 17:19:30 +00:00
|
|
|
if (!isAuthenticated()) {
|
|
|
|
showModal('auth', modalSource)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
onMount(async () => {
|
|
|
|
// Load the session and author data on mount
|
|
|
|
await loadSession()
|
|
|
|
loadAuthor()
|
2023-06-14 17:19:30 +00:00
|
|
|
})
|
|
|
|
|
2022-11-13 19:35:57 +00:00
|
|
|
const signOut = async () => {
|
2023-11-28 13:18:25 +00:00
|
|
|
await authorizer().logout()
|
2022-11-13 19:35:57 +00:00
|
|
|
mutate(null)
|
|
|
|
resetToken()
|
2023-11-02 17:43:22 +00:00
|
|
|
setSubscriptions(EMPTY_SUBSCRIPTIONS)
|
2023-02-10 11:11:24 +00:00
|
|
|
showSnackbar({ body: t("You've successfully logged out") })
|
2022-11-13 19:35:57 +00:00
|
|
|
}
|
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
const confirmEmail = async (input: VerifyEmailInput) => {
|
2023-11-28 18:04:51 +00:00
|
|
|
const at: void | AuthToken = await authorizer().verifyEmail(input)
|
|
|
|
if (at) {
|
|
|
|
setToken(at.access_token)
|
|
|
|
mutate(at)
|
2023-11-28 13:18:25 +00:00
|
|
|
}
|
2022-11-13 19:35:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const actions = {
|
2022-12-01 18:45:35 +00:00
|
|
|
loadSession,
|
2023-06-14 17:19:30 +00:00
|
|
|
requireAuthentication,
|
2022-11-13 19:35:57 +00:00
|
|
|
signIn,
|
|
|
|
signOut,
|
2023-10-19 15:05:22 +00:00
|
|
|
confirmEmail,
|
2023-11-14 15:10:00 +00:00
|
|
|
loadSubscriptions,
|
2023-12-03 10:22:42 +00:00
|
|
|
getToken,
|
2022-11-13 19:35:57 +00:00
|
|
|
}
|
2023-10-19 15:05:22 +00:00
|
|
|
const value: SessionContextType = {
|
|
|
|
session,
|
|
|
|
subscriptions,
|
|
|
|
isSessionLoaded,
|
2023-11-28 13:18:25 +00:00
|
|
|
author,
|
2023-10-19 15:05:22 +00:00
|
|
|
user,
|
|
|
|
isAuthenticated,
|
2023-11-14 15:10:00 +00:00
|
|
|
actions,
|
2023-10-19 15:05:22 +00:00
|
|
|
}
|
2022-11-13 19:35:57 +00:00
|
|
|
|
|
|
|
onMount(() => {
|
2022-12-01 18:45:35 +00:00
|
|
|
loadSession()
|
2022-11-13 19:35:57 +00:00
|
|
|
})
|
2022-11-14 10:02:08 +00:00
|
|
|
return <SessionContext.Provider value={value}>{props.children}</SessionContext.Provider>
|
2022-11-13 19:35:57 +00:00
|
|
|
}
|