rewritten-session-context
This commit is contained in:
parent
9e6ba5a523
commit
2b6738d35b
|
@ -14,21 +14,22 @@ import styles from './AuthModal.module.scss'
|
||||||
export const EmailConfirm = () => {
|
export const EmailConfirm = () => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const {
|
const {
|
||||||
actions: { confirmEmail },
|
actions: { confirmEmail, loadSession, loadAuthor },
|
||||||
|
session,
|
||||||
} = useSession()
|
} = useSession()
|
||||||
const { user } = useSession()
|
const confirmedEmail = createMemo(() => session()?.user?.email_verified)
|
||||||
|
|
||||||
const [isTokenExpired, setIsTokenExpired] = createSignal(false)
|
const [isTokenExpired, setIsTokenExpired] = createSignal(false)
|
||||||
const [isTokenInvalid, setIsTokenInvalid] = createSignal(false)
|
const [isTokenInvalid, setIsTokenInvalid] = createSignal(false)
|
||||||
|
const { searchParams, changeSearchParam } = useRouter<ConfirmEmailSearchParams>()
|
||||||
const confirmedEmail = createMemo(() => user?.email || '')
|
|
||||||
|
|
||||||
const { searchParams } = useRouter<ConfirmEmailSearchParams>()
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const token = searchParams().token
|
const token = searchParams().access_token
|
||||||
|
if (token) {
|
||||||
try {
|
try {
|
||||||
await confirmEmail({ token })
|
await confirmEmail({ token })
|
||||||
|
await loadSession()
|
||||||
|
await loadAuthor()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ApiError) {
|
if (error instanceof ApiError) {
|
||||||
if (error.code === 'token_expired') {
|
if (error.code === 'token_expired') {
|
||||||
|
@ -44,6 +45,7 @@ export const EmailConfirm = () => {
|
||||||
|
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -14,7 +14,8 @@ export type AuthModalSearchParams = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ConfirmEmailSearchParams = {
|
export type ConfirmEmailSearchParams = {
|
||||||
token: string
|
access_token?: string
|
||||||
|
token?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CreateChatSearchParams = {
|
export type CreateChatSearchParams = {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { showModal } from '../stores/ui'
|
||||||
|
|
||||||
import { useLocalize } from './localize'
|
import { useLocalize } from './localize'
|
||||||
import { useSnackbar } from './snackbar'
|
import { useSnackbar } from './snackbar'
|
||||||
|
import { useRouter } from '../stores/router'
|
||||||
|
|
||||||
const config: ConfigType = {
|
const config: ConfigType = {
|
||||||
authorizerURL: 'https://auth.discours.io',
|
authorizerURL: 'https://auth.discours.io',
|
||||||
|
@ -34,17 +35,18 @@ const config: ConfigType = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SessionContextType = {
|
export type SessionContextType = {
|
||||||
user: User | null
|
|
||||||
config: ConfigType
|
config: ConfigType
|
||||||
session: Resource<AuthToken>
|
session: Resource<AuthToken>
|
||||||
|
author: Resource<Author | null>
|
||||||
isSessionLoaded: Accessor<boolean>
|
isSessionLoaded: Accessor<boolean>
|
||||||
subscriptions: Accessor<Result>
|
subscriptions: Accessor<Result>
|
||||||
author: Resource<Author | null>
|
|
||||||
isAuthenticated: Accessor<boolean>
|
isAuthenticated: Accessor<boolean>
|
||||||
isAuthWithCallback: Accessor<() => void>
|
isAuthWithCallback: Accessor<() => void>
|
||||||
actions: {
|
actions: {
|
||||||
getToken: () => string
|
getToken: () => string
|
||||||
loadSession: () => AuthToken | Promise<AuthToken>
|
loadSession: () => AuthToken | Promise<AuthToken>
|
||||||
|
setSession: (token: AuthToken | null) => void // setSession
|
||||||
|
loadAuthor: (info?: unknown) => Author | Promise<Author>
|
||||||
loadSubscriptions: () => Promise<void>
|
loadSubscriptions: () => Promise<void>
|
||||||
requireAuthentication: (
|
requireAuthentication: (
|
||||||
callback: (() => Promise<void>) | (() => void),
|
callback: (() => Promise<void>) | (() => void),
|
||||||
|
@ -52,10 +54,8 @@ export type SessionContextType = {
|
||||||
) => void
|
) => void
|
||||||
signIn: (params: LoginInput) => Promise<void>
|
signIn: (params: LoginInput) => Promise<void>
|
||||||
signOut: () => Promise<void>
|
signOut: () => Promise<void>
|
||||||
confirmEmail: (input: VerifyEmailInput) => Promise<void>
|
confirmEmail: (input: VerifyEmailInput) => Promise<void> // email confirm callback is in auth.discours.io
|
||||||
setIsSessionLoaded: (loaded: boolean) => void
|
setIsSessionLoaded: (loaded: boolean) => void
|
||||||
setToken: (token: AuthToken | null) => void // setSession
|
|
||||||
setUser: (user: User | null) => void
|
|
||||||
authorizer: () => Authorizer
|
authorizer: () => Authorizer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,28 +79,9 @@ export const SessionProvider = (props: {
|
||||||
const {
|
const {
|
||||||
actions: { showSnackbar },
|
actions: { showSnackbar },
|
||||||
} = useSnackbar()
|
} = useSnackbar()
|
||||||
|
const { searchParams, changeSearchParam } = useRouter()
|
||||||
const [isSessionLoaded, setIsSessionLoaded] = createSignal(false)
|
const [isSessionLoaded, setIsSessionLoaded] = createSignal(false)
|
||||||
const [subscriptions, setSubscriptions] = createSignal<Result>(EMPTY_SUBSCRIPTIONS)
|
const [subscriptions, setSubscriptions] = createSignal<Result>(EMPTY_SUBSCRIPTIONS)
|
||||||
const [token, setToken] = createSignal<AuthToken>()
|
|
||||||
const [user, setUser] = createSignal<User>()
|
|
||||||
|
|
||||||
const loadSubscriptions = async (): Promise<void> => {
|
|
||||||
const result = await apiClient.getMySubscriptions()
|
|
||||||
if (result) {
|
|
||||||
setSubscriptions(result)
|
|
||||||
} else {
|
|
||||||
setSubscriptions(EMPTY_SUBSCRIPTIONS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setAuth = (auth: AuthToken | void) => {
|
|
||||||
if (auth) {
|
|
||||||
setToken(auth)
|
|
||||||
setUser(auth.user)
|
|
||||||
mutate(auth)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSession = async (): Promise<AuthToken> => {
|
const getSession = async (): Promise<AuthToken> => {
|
||||||
try {
|
try {
|
||||||
|
@ -110,14 +91,14 @@ export const SessionProvider = (props: {
|
||||||
Authorization: tkn,
|
Authorization: tkn,
|
||||||
})
|
})
|
||||||
if (authResult?.access_token) {
|
if (authResult?.access_token) {
|
||||||
setAuth(authResult)
|
mutate(authResult)
|
||||||
console.debug('[context.session] token after: ', authResult.access_token)
|
console.debug('[context.session] token after: ', authResult.access_token)
|
||||||
await loadSubscriptions()
|
await loadSubscriptions()
|
||||||
return authResult
|
return authResult
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[context.session] getSession error:', error)
|
console.error('[context.session] getSession error:', error)
|
||||||
setAuth(null)
|
mutate(null)
|
||||||
return null
|
return null
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -131,6 +112,32 @@ export const SessionProvider = (props: {
|
||||||
initialValue: null,
|
initialValue: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const user = createMemo(() => session().user)
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
// detect confirm redirect
|
||||||
|
const params = searchParams()
|
||||||
|
if (params?.access_token) {
|
||||||
|
console.debug('[context.session] access token presented, changing search params')
|
||||||
|
changeSearchParam({ modal: 'auth', mode: 'confirm-email', access_token: params?.access_token })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
// authorized graphql client
|
||||||
|
const tkn = getToken()
|
||||||
|
if (tkn) apiClient.connect(tkn)
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadSubscriptions = async (): Promise<void> => {
|
||||||
|
const result = await apiClient.private?.getMySubscriptions()
|
||||||
|
if (result) {
|
||||||
|
setSubscriptions(result)
|
||||||
|
} else {
|
||||||
|
setSubscriptions(EMPTY_SUBSCRIPTIONS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const [author, { refetch: loadAuthor }] = createResource<Author | null>(
|
const [author, { refetch: loadAuthor }] = createResource<Author | null>(
|
||||||
async () => {
|
async () => {
|
||||||
const u = session()?.user
|
const u = session()?.user
|
||||||
|
@ -151,7 +158,7 @@ export const SessionProvider = (props: {
|
||||||
const authResult: AuthToken | void = await authorizer().login(params)
|
const authResult: AuthToken | void = await authorizer().login(params)
|
||||||
|
|
||||||
if (authResult && authResult.access_token) {
|
if (authResult && authResult.access_token) {
|
||||||
setAuth(authResult)
|
mutate(authResult)
|
||||||
await loadSubscriptions()
|
await loadSubscriptions()
|
||||||
console.debug('[context.session] signed in')
|
console.debug('[context.session] signed in')
|
||||||
} else {
|
} else {
|
||||||
|
@ -172,7 +179,7 @@ export const SessionProvider = (props: {
|
||||||
on(
|
on(
|
||||||
() => props.onStateChangeCallback,
|
() => props.onStateChangeCallback,
|
||||||
() => {
|
() => {
|
||||||
props.onStateChangeCallback(token())
|
props.onStateChangeCallback(session())
|
||||||
},
|
},
|
||||||
{ defer: true },
|
{ defer: true },
|
||||||
),
|
),
|
||||||
|
@ -200,7 +207,7 @@ export const SessionProvider = (props: {
|
||||||
setIsAuthWithCallback(() => callback)
|
setIsAuthWithCallback(() => callback)
|
||||||
|
|
||||||
const userdata = await authorizer().getProfile()
|
const userdata = await authorizer().getProfile()
|
||||||
if (userdata) setUser(userdata)
|
if (userdata) mutate({ ...session(), user: userdata })
|
||||||
|
|
||||||
if (!isAuthenticated()) {
|
if (!isAuthenticated()) {
|
||||||
showModal('auth', modalSource)
|
showModal('auth', modalSource)
|
||||||
|
@ -209,17 +216,19 @@ export const SessionProvider = (props: {
|
||||||
|
|
||||||
const signOut = async () => {
|
const signOut = async () => {
|
||||||
await authorizer().logout()
|
await authorizer().logout()
|
||||||
setAuth(null)
|
mutate(null)
|
||||||
setSubscriptions(EMPTY_SUBSCRIPTIONS)
|
setSubscriptions(EMPTY_SUBSCRIPTIONS)
|
||||||
showSnackbar({ body: t("You've successfully logged out") })
|
showSnackbar({ body: t("You've successfully logged out") })
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmEmail = async (input: VerifyEmailInput) => {
|
const confirmEmail = async (input: VerifyEmailInput) => {
|
||||||
|
console.log(`[context.session] calling authorizer's verify email with ${input}`)
|
||||||
const at: void | AuthToken = await authorizer().verifyEmail(input)
|
const at: void | AuthToken = await authorizer().verifyEmail(input)
|
||||||
setAuth(at)
|
if (at) mutate(at)
|
||||||
|
console.log(`[context.session] confirmEmail got result ${at}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getToken = createMemo(() => token()?.access_token)
|
const getToken = createMemo(() => session()?.access_token)
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
getToken,
|
getToken,
|
||||||
|
@ -230,12 +239,11 @@ export const SessionProvider = (props: {
|
||||||
signOut,
|
signOut,
|
||||||
confirmEmail,
|
confirmEmail,
|
||||||
setIsSessionLoaded,
|
setIsSessionLoaded,
|
||||||
setToken,
|
setSession: mutate,
|
||||||
setUser,
|
|
||||||
authorizer,
|
authorizer,
|
||||||
|
loadAuthor,
|
||||||
}
|
}
|
||||||
const value: SessionContextType = {
|
const value: SessionContextType = {
|
||||||
user: user(),
|
|
||||||
config: configuration(),
|
config: configuration(),
|
||||||
session,
|
session,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user