session-connect-debug
Some checks failed
deploy / test (push) Failing after 55s
deploy / deploy (push) Has been skipped

This commit is contained in:
Untone 2023-12-15 16:45:34 +03:00
parent 070cd7ff2f
commit 9e6ba5a523
20 changed files with 151 additions and 117 deletions

View File

@ -75,7 +75,7 @@ export const FullArticle = (props: Props) => {
const main_topic_slug = props.article.topics.length > 0 ? props.article.main_topic : null const main_topic_slug = props.article.topics.length > 0 ? props.article.main_topic : null
const mt = props.article.topics.find((tpc: Topic) => tpc.slug === main_topic_slug) const mt = props.article.topics.find((tpc: Topic) => tpc.slug === main_topic_slug)
if (mt) { if (mt) {
mt.title = lang() == 'en' ? capitalize(mt.slug.replace('-', ' ')) : mt.title mt.title = lang() === 'en' ? capitalize(mt.slug.replace('-', ' ')) : mt.title
return mt return mt
} else { } else {
return props.article.topics[0] return props.article.topics[0]
@ -329,7 +329,7 @@ export const FullArticle = (props: Props) => {
> >
<figure class="img-align-column"> <figure class="img-align-column">
<Image width={800} alt={props.article.cover_caption} src={props.article.cover} /> <Image width={800} alt={props.article.cover_caption} src={props.article.cover} />
<figcaption>{props.article.cover_caption}</figcaption> <figcaption innerHTML={props.article.cover_caption} />
</figure> </figure>
</Show> </Show>
</div> </div>
@ -513,7 +513,7 @@ export const FullArticle = (props: Props) => {
{(topic) => ( {(topic) => (
<div class={styles.shoutTopic}> <div class={styles.shoutTopic}>
<a href={getPagePath(router, 'topic', { slug: topic.slug })}> <a href={getPagePath(router, 'topic', { slug: topic.slug })}>
{lang() == 'en' ? capitalize(topic.slug) : topic.title} {lang() === 'en' ? capitalize(topic.slug) : topic.title}
</a> </a>
</div> </div>
)} )}

View File

@ -4,6 +4,7 @@ import { clsx } from 'clsx'
import { createSignal, JSX, Show } from 'solid-js' import { createSignal, JSX, Show } from 'solid-js'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { useSession } from '../../../context/session'
import { ApiError } from '../../../graphql/error' import { ApiError } from '../../../graphql/error'
import { useRouter } from '../../../stores/router' import { useRouter } from '../../../stores/router'
import { validateEmail } from '../../../utils/validateEmail' import { validateEmail } from '../../../utils/validateEmail'
@ -11,7 +12,6 @@ import { validateEmail } from '../../../utils/validateEmail'
import { email, setEmail } from './sharedLogic' import { email, setEmail } from './sharedLogic'
import styles from './AuthModal.module.scss' import styles from './AuthModal.module.scss'
import { useSession } from '../../../context/session'
type FormFields = { type FormFields = {
email: string email: string
@ -71,7 +71,7 @@ export const ForgotPasswordForm = () => {
redirect_uri: window.location.href + '&success=1', // FIXME: redirect to success page accepting confirmation code redirect_uri: window.location.href + '&success=1', // FIXME: redirect to success page accepting confirmation code
}) })
if (response) { if (response) {
console.debug(response) console.debug('[ForgotPasswordForm]', response)
if (response.message) setMessage(response.message) if (response.message) setMessage(response.message)
} }
} catch (error) { } catch (error) {

View File

@ -5,6 +5,7 @@ import { clsx } from 'clsx'
import { Show, createSignal } from 'solid-js' import { Show, createSignal } from 'solid-js'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { useSession } from '../../../context/session'
import { ApiError } from '../../../graphql/error' import { ApiError } from '../../../graphql/error'
import { checkEmail, useEmailChecks } from '../../../stores/emailChecks' import { checkEmail, useEmailChecks } from '../../../stores/emailChecks'
import { useRouter } from '../../../stores/router' import { useRouter } from '../../../stores/router'
@ -17,7 +18,6 @@ import { email, setEmail } from './sharedLogic'
import { SocialProviders } from './SocialProviders' import { SocialProviders } from './SocialProviders'
import styles from './AuthModal.module.scss' import styles from './AuthModal.module.scss'
import { useSession } from '../../../context/session'
type FormFields = { type FormFields = {
fullName: string fullName: string

View File

@ -134,28 +134,23 @@ export const HeaderAuth = (props: Props) => {
</div> </div>
</Show> </Show>
<Show when={isNotificationsVisible()}> <Show when={isNotificationsVisible() || !author()}>
<div class={styles.userControlItem} onClick={handleBellIconClick}> <div class={styles.userControlItem} onClick={handleBellIconClick}>
<div class={styles.button}> <div class={styles.button}>
<Icon name="bell-white" counter={unreadNotificationsCount()} class={styles.icon} /> <Icon
name="bell-white"
counter={isAuthenticated() ? unreadNotificationsCount() : 1}
class={styles.icon}
/>
<Icon <Icon
name="bell-white-hover" name="bell-white-hover"
counter={unreadNotificationsCount()} counter={isAuthenticated() ? unreadNotificationsCount() : 1}
class={clsx(styles.icon, styles.iconHover)} class={clsx(styles.icon, styles.iconHover)}
/> />
</div> </div>
</div> </div>
</Show> </Show>
<Show when={!author()}>
<div class={styles.userControlItem} onClick={handleBellIconClick}>
<div class={styles.button}>
<Icon name="bell-white" counter={1} class={styles.icon} />
<Icon name="bell-white-hover" counter={1} class={clsx(styles.icon, styles.iconHover)} />
</div>
</div>
</Show>
<Show when={isSaveButtonVisible()}> <Show when={isSaveButtonVisible()}>
<div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}> <div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}>
{renderIconedButton({ {renderIconedButton({

View File

@ -26,7 +26,7 @@ export const NotificationView = (props: Props) => {
actions: { markNotificationAsRead, hideNotificationsPanel }, actions: { markNotificationAsRead, hideNotificationsPanel },
} = useNotifications() } = useNotifications()
const { changeSearchParam } = useRouter<ArticlePageSearchParams>() const { changeSearchParam } = useRouter<ArticlePageSearchParams>() // TODO: use search params
const { t, formatDate, formatTime } = useLocalize() const { t, formatDate, formatTime } = useLocalize()

View File

@ -4,10 +4,10 @@ import deepEqual from 'fast-deep-equal'
import { createEffect, createSignal, For, lazy, Match, onCleanup, onMount, Show, Switch } from 'solid-js' import { createEffect, createSignal, For, lazy, Match, onCleanup, onMount, Show, Switch } from 'solid-js'
import { createStore } from 'solid-js/store' import { createStore } from 'solid-js/store'
import { useSession } from '../../context/session'
import { useConfirm } from '../../context/confirm' import { useConfirm } from '../../context/confirm'
import { useLocalize } from '../../context/localize' import { useLocalize } from '../../context/localize'
import { useProfileForm } from '../../context/profile' import { useProfileForm } from '../../context/profile'
import { useSession } from '../../context/session'
import { useSnackbar } from '../../context/snackbar' import { useSnackbar } from '../../context/snackbar'
import { clone } from '../../utils/clone' import { clone } from '../../utils/clone'
import { getImageUrl } from '../../utils/getImageUrl' import { getImageUrl } from '../../utils/getImageUrl'

View File

@ -84,7 +84,7 @@ export const TopicCard = (props: TopicProps) => {
} }
const title = createMemo(() => const title = createMemo(() =>
capitalize(lang() == 'en' ? props.topic.slug.replaceAll('-', ' ') : props.topic.title || ''), capitalize(lang() === 'en' ? props.topic.slug.replaceAll('-', ' ') : props.topic.title || ''),
) )
return ( return (

View File

@ -54,7 +54,7 @@ export const TopicBadge = (props: Props) => {
/> />
<a href={`/topic/${props.topic.slug}`} class={styles.info}> <a href={`/topic/${props.topic.slug}`} class={styles.info}>
<span class={styles.title}> <span class={styles.title}>
{lang() == 'en' ? capitalize(props.topic.slug.replaceAll('-', ' ')) : props.topic.title} {lang() === 'en' ? capitalize(props.topic.slug.replaceAll('-', ' ')) : props.topic.title}
</span> </span>
<Show <Show
when={props.topic.body} when={props.topic.body}

View File

@ -54,7 +54,7 @@ export const AllTopicsView = (props: AllTopicsViewProps) => {
const byLetter = createMemo<{ [letter: string]: Topic[] }>(() => { const byLetter = createMemo<{ [letter: string]: Topic[] }>(() => {
return sortedTopics().reduce( return sortedTopics().reduce(
(acc, topic) => { (acc, topic) => {
let letter = lang() == 'en' ? topic.slug[0].toUpperCase() : topic.title[0].toUpperCase() let letter = lang() === 'en' ? topic.slug[0].toUpperCase() : topic.title[0].toUpperCase()
if (/[^ËА-яё]/.test(letter) && lang() === 'ru') letter = '#' if (/[^ËА-яё]/.test(letter) && lang() === 'ru') letter = '#'
if (/[^A-z]/.test(letter) && lang() === 'en') letter = '#' if (/[^A-z]/.test(letter) && lang() === 'en') letter = '#'
if (!acc[letter]) acc[letter] = [] if (!acc[letter]) acc[letter] = []
@ -147,7 +147,7 @@ export const AllTopicsView = (props: AllTopicsViewProps) => {
{(topic) => ( {(topic) => (
<div class={clsx(styles.topic, 'topic col-sm-12 col-md-8')}> <div class={clsx(styles.topic, 'topic col-sm-12 col-md-8')}>
<a href={`/topic/${topic.slug}`}> <a href={`/topic/${topic.slug}`}>
{lang() == 'en' {lang() === 'en'
? capitalize(topic.slug.replaceAll('-', ' ')) ? capitalize(topic.slug.replaceAll('-', ' '))
: topic.title} : topic.title}
</a> </a>

View File

@ -1,6 +1,6 @@
import { clsx } from 'clsx' import { clsx } from 'clsx'
import deepEqual from 'fast-deep-equal' import deepEqual from 'fast-deep-equal'
import { Accessor, createMemo, createSignal, lazy, onCleanup, onMount, Show, Suspense } from 'solid-js' import { Accessor, createMemo, createSignal, lazy, onCleanup, onMount, Show } from 'solid-js'
import { createStore } from 'solid-js/store' import { createStore } from 'solid-js/store'
import { ShoutForm, useEditorContext } from '../../context/editor' import { ShoutForm, useEditorContext } from '../../context/editor'

View File

@ -228,7 +228,7 @@ export const FeedView = (props: Props) => {
{(topic) => ( {(topic) => (
<span class={clsx(stylesTopic.shoutTopic, styles.topic)}> <span class={clsx(stylesTopic.shoutTopic, styles.topic)}>
<a href={`/topic/${topic.slug}`}> <a href={`/topic/${topic.slug}`}>
{lang() == 'en' ? topic.slug.replaceAll('-', ' ') : topic.title} {lang() === 'en' ? topic.slug.replaceAll('-', ' ') : topic.title}
</a>{' '} </a>{' '}
</span> </span>
)} )}

View File

@ -53,7 +53,7 @@ export const InboxView = () => {
const [isClear, setClear] = createSignal(false) const [isClear, setClear] = createSignal(false)
const [isScrollToNewVisible, setIsScrollToNewVisible] = createSignal(false) const [isScrollToNewVisible, setIsScrollToNewVisible] = createSignal(false)
const { author } = useSession() const { author } = useSession()
const currentUserId = createMemo(() => author().id) const currentUserId = createMemo(() => author()?.id)
const { changeSearchParam, searchParams } = useRouter<InboxSearchParams>() const { changeSearchParam, searchParams } = useRouter<InboxSearchParams>()
const messagesContainerRef: { current: HTMLDivElement } = { const messagesContainerRef: { current: HTMLDivElement } = {
@ -100,7 +100,7 @@ export const InboxView = () => {
const handleSubmit = async (message: string) => { const handleSubmit = async (message: string) => {
await sendMessage({ await sendMessage({
body: message, body: message,
chat_id: currentDialog().id.toString(), chat_id: currentDialog()?.id.toString(),
reply_to: messageToReply()?.id, reply_to: messageToReply()?.id,
}) })
setClear(true) setClear(true)

View File

@ -1,12 +1,11 @@
import { redirectPage } from '@nanostores/router' import { redirectPage } from '@nanostores/router'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { createSignal, lazy, onMount, Show } from 'solid-js' import { lazy, Show } from 'solid-js'
import { createStore } from 'solid-js/store' import { createStore } from 'solid-js/store'
import { ShoutForm, useEditorContext } from '../../../context/editor' import { ShoutForm, useEditorContext } from '../../../context/editor'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { useSession } from '../../../context/session' import { useSession } from '../../../context/session'
import { Topic } from '../../../graphql/schema/core.gen'
import { UploadedFile } from '../../../pages/types' import { UploadedFile } from '../../../pages/types'
import { router } from '../../../stores/router' import { router } from '../../../stores/router'
import { hideModal, showModal } from '../../../stores/ui' import { hideModal, showModal } from '../../../stores/ui'

View File

@ -1,5 +1,5 @@
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { createEffect, createSignal, For, Show, on, onMount, lazy, onCleanup } from 'solid-js' import { createEffect, createSignal, For, Show, on, onMount, onCleanup } from 'solid-js'
import SwiperCore, { Manipulation, Navigation, Pagination } from 'swiper' import SwiperCore, { Manipulation, Navigation, Pagination } from 'swiper'
import { throttle } from 'throttle-debounce' import { throttle } from 'throttle-debounce'

View File

@ -1,10 +1,12 @@
import type { Accessor, JSX } from 'solid-js' import type { Accessor, JSX } from 'solid-js'
import { fetchEventSource } from '@microsoft/fetch-event-source' import { EventStreamContentType, fetchEventSource } from '@microsoft/fetch-event-source'
import { createContext, useContext, createSignal, createEffect } from 'solid-js' import { createContext, useContext, createSignal, createEffect } from 'solid-js'
import { useSession } from './session' import { useSession } from './session'
const RECONNECT_TIMES = 2
export interface SSEMessage { export interface SSEMessage {
id: string id: string
entity: string entity: string
@ -36,42 +38,53 @@ export const ConnectProvider = (props: { children: JSX.Element }) => {
const addHandler = (handler: MessageHandler) => { const addHandler = (handler: MessageHandler) => {
setHandlers((hhh) => [...hhh, handler]) setHandlers((hhh) => [...hhh, handler])
} }
const [retried, setRetried] = createSignal<number>(0) const [retried, setRetried] = createSignal<number>(0)
const listen = () => { createEffect(async () => {
const token = getToken()
console.log(`[context.connect] token: ${token}`)
if (token && !connected() && retried() < 4) {
fetchEventSource('https://connect.discours.io', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: token,
},
onmessage(event) {
const m: SSEMessage = JSON.parse(event.data)
console.log('[context.connect] Received message:', m)
// Iterate over all registered handlers and call them
messageHandlers().forEach((handler) => handler(m))
},
onclose() {
console.log('[context.connect] sse connection closed by server')
setConnected(false)
},
onerror(err) {
console.error('[context.connect] sse connection error', err)
setRetried((r) => r + 1)
setConnected(false)
throw new Error(err) // NOTE: simple hack to close the connection
},
})
}
}
createEffect(() => {
if (isAuthenticated() && !connected()) { if (isAuthenticated() && !connected()) {
listen() const token = getToken()
setConnected(true) if (token) {
await fetchEventSource('https://connect.discours.io', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: token,
},
onmessage(event) {
const m: SSEMessage = JSON.parse(event.data)
console.log('[context.connect] Received message:', m)
// Iterate over all registered handlers and call them
messageHandlers().forEach((handler) => handler(m))
},
async onopen(response) {
console.log('[context.connect] SSE connection opened', response)
if (response.ok && response.headers.get('content-type') === EventStreamContentType) {
setConnected(true)
return
} else if (response.status === 401) {
throw new Error('unauthorized')
} else {
setRetried((r) => r + 1)
throw new Error()
}
},
onclose() {
console.log('[context.connect] SSE connection closed by server')
setConnected(false)
},
onerror(err) {
if (err.message == 'unauthorized' || retried() > RECONNECT_TIMES) {
throw err // rethrow to stop the operation
} else {
// do nothing to automatically retry. You can also
// return a specific retry interval here.
}
},
})
return
}
} }
}) })

View File

@ -46,18 +46,23 @@ export const InboxProvider = (props: { children: JSX.Element }) => {
} = useSession() } = useSession()
const apiClient = createMemo(() => { const apiClient = createMemo(() => {
const token = getToken() const token = getToken()
if (!inboxClient.private) inboxClient.connect(token) if (!inboxClient.private) {
return inboxClient inboxClient.connect(token)
return inboxClient
}
}) })
const { addHandler } = useConnect() const { addHandler } = useConnect()
addHandler(handleMessage) addHandler(handleMessage)
const loadChats = async () => { const loadChats = async () => {
try { try {
const newChats = await apiClient().loadChats({ limit: 50, offset: 0 }) const client = apiClient()
setChats(newChats) if (client) {
const newChats = await client.loadChats({ limit: 50, offset: 0 })
setChats(newChats)
}
} catch (error) { } catch (error) {
console.log('[loadChats]', error) console.log('[loadChats] error: ', error)
} }
} }

View File

@ -1,6 +1,6 @@
import type { Accessor, JSX } from 'solid-js' import type { Accessor, JSX } from 'solid-js'
import { createContext, createMemo, createSignal, onMount, useContext } from 'solid-js' import { createContext, createEffect, createMemo, createSignal, onMount, useContext } from 'solid-js'
import { createStore } from 'solid-js/store' import { createStore } from 'solid-js/store'
import { Portal } from 'solid-js/web' import { Portal } from 'solid-js/web'
@ -43,23 +43,35 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
isAuthenticated, isAuthenticated,
actions: { getToken }, actions: { getToken },
} = useSession() } = useSession()
const apiClient = createMemo(() => { const apiClient = createMemo(() => {
const token = getToken() const token = getToken()
if (!notifierClient.private && isAuthenticated()) notifierClient.connect(token) if (!notifierClient.private) {
return notifierClient notifierClient.connect(token)
return notifierClient
}
}) })
const { addHandler } = useConnect()
const loadNotifications = async (options: { limit?: number; offset?: number }) => {
const { notifications, unread, total } = await apiClient().getNotifications(options)
const newNotificationEntities = notifications.reduce((acc, notification) => {
acc[notification.id] = notification
return acc
}, {})
setTotalNotificationsCount(total) const { addHandler } = useConnect()
setUnreadNotificationsCount(unread)
setNotificationEntities(newNotificationEntities) const loadNotifications = async (options: { limit?: number; offset?: number }) => {
return notifications const client = apiClient()
if (isAuthenticated() && client) {
console.debug(client)
const { notifications, unread, total } = await client.getNotifications(options)
const newNotificationEntities = notifications.reduce((acc, notification) => {
acc[notification.id] = notification
return acc
}, {})
setTotalNotificationsCount(total)
setUnreadNotificationsCount(unread)
setNotificationEntities(newNotificationEntities)
console.debug(`[context.notifications] updated`)
return notifications
} else {
return []
}
} }
const sortedNotifications = createMemo(() => { const sortedNotifications = createMemo(() => {
@ -70,7 +82,7 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
onMount(() => { onMount(() => {
addHandler((data: SSEMessage) => { addHandler((data: SSEMessage) => {
if (data.entity === 'reaction') { if (data.entity === 'reaction' && isAuthenticated()) {
loadNotifications({ limit: Math.max(PAGE_SIZE, loadedNotificationsCount()) }) loadNotifications({ limit: Math.max(PAGE_SIZE, loadedNotificationsCount()) })
} else { } else {
console.error(`[NotificationsProvider] unhandled message type: ${JSON.stringify(data)}`) console.error(`[NotificationsProvider] unhandled message type: ${JSON.stringify(data)}`)
@ -79,14 +91,20 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
}) })
const markNotificationAsRead = async (notification: Notification) => { const markNotificationAsRead = async (notification: Notification) => {
await apiClient().markNotificationAsRead(notification.id) const client = apiClient()
if (client) {
await client.markNotificationAsRead(notification.id)
}
const nnn = new Set([...notification.seen, notification.id]) const nnn = new Set([...notification.seen, notification.id])
setNotificationEntities(notification.id, 'seen', [...nnn]) setNotificationEntities(notification.id, 'seen', [...nnn])
setUnreadNotificationsCount((oldCount) => oldCount - 1) setUnreadNotificationsCount((oldCount) => oldCount - 1)
} }
const markAllNotificationsAsRead = async () => { const markAllNotificationsAsRead = async () => {
await apiClient().markAllNotificationsAsRead() const client = apiClient()
loadNotifications({ limit: loadedNotificationsCount() }) if (isAuthenticated() && client) {
await client.markAllNotificationsAsRead()
await loadNotifications({ limit: loadedNotificationsCount() })
}
} }
const showNotificationsPanel = () => { const showNotificationsPanel = () => {

View File

@ -23,6 +23,7 @@ import {
import { apiClient } from '../graphql/client/core' import { apiClient } from '../graphql/client/core'
import { showModal } from '../stores/ui' import { showModal } from '../stores/ui'
import { useLocalize } from './localize' import { useLocalize } from './localize'
import { useSnackbar } from './snackbar' import { useSnackbar } from './snackbar'
@ -74,14 +75,16 @@ export const SessionProvider = (props: {
onStateChangeCallback(state: any): unknown onStateChangeCallback(state: any): unknown
children: JSX.Element children: JSX.Element
}) => { }) => {
const [isSessionLoaded, setIsSessionLoaded] = createSignal(false)
const [subscriptions, setSubscriptions] = createSignal<Result>(EMPTY_SUBSCRIPTIONS)
const { t } = useLocalize() const { t } = useLocalize()
const { const {
actions: { showSnackbar }, actions: { showSnackbar },
} = useSnackbar() } = useSnackbar()
const [isSessionLoaded, setIsSessionLoaded] = createSignal(false)
const [subscriptions, setSubscriptions] = createSignal<Result>(EMPTY_SUBSCRIPTIONS)
const [token, setToken] = createSignal<AuthToken>() const [token, setToken] = createSignal<AuthToken>()
const [user, setUser] = createSignal<User>() const [user, setUser] = createSignal<User>()
const loadSubscriptions = async (): Promise<void> => { const loadSubscriptions = async (): Promise<void> => {
const result = await apiClient.getMySubscriptions() const result = await apiClient.getMySubscriptions()
if (result) { if (result) {
@ -91,24 +94,30 @@ export const SessionProvider = (props: {
} }
} }
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 {
const t = getToken() const tkn = getToken()
console.debug(t) console.debug('[context.session] token before: ', tkn)
const authResult = await authorizer().getSession({ const authResult = await authorizer().getSession({
Authorization: t, Authorization: tkn,
}) })
if (authResult?.access_token) { if (authResult?.access_token) {
console.log(authResult) setAuth(authResult)
setToken(authResult) console.debug('[context.session] token after: ', authResult.access_token)
if (authResult.user) setUser(authResult.user) await loadSubscriptions()
loadSubscriptions()
return authResult return authResult
} }
} catch (error) { } catch (error) {
console.error('getSession error:', error) console.error('[context.session] getSession error:', error)
setToken(null) setAuth(null)
setUser(null)
return null return null
} finally { } finally {
setTimeout(() => { setTimeout(() => {
@ -142,10 +151,9 @@ 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) {
setToken(authResult) setAuth(authResult)
mutate(authResult) await loadSubscriptions()
loadSubscriptions() console.debug('[context.session] signed in')
console.debug('signed in')
} else { } else {
console.info((authResult as AuthToken).message) console.info((authResult as AuthToken).message)
} }
@ -179,10 +187,10 @@ export const SessionProvider = (props: {
setConfig({ ...config, ...metaRes, redirectURL: window.location.origin + '/?modal=auth' }) setConfig({ ...config, ...metaRes, redirectURL: window.location.origin + '/?modal=auth' })
console.log('[context.session] refreshing session...') console.log('[context.session] refreshing session...')
const s = await getSession() const s = await getSession()
console.debug(s) console.debug('[context.session] session: ', s)
setToken(s)
console.log('[context.session] loading author...') console.log('[context.session] loading author...')
await loadAuthor() const a = await loadAuthor()
console.debug('[context.session] author: ', a)
setIsSessionLoaded(true) setIsSessionLoaded(true)
console.log('[context.session] loaded') console.log('[context.session] loaded')
}) })
@ -191,7 +199,8 @@ export const SessionProvider = (props: {
const requireAuthentication = async (callback: () => void, modalSource: AuthModalSource) => { const requireAuthentication = async (callback: () => void, modalSource: AuthModalSource) => {
setIsAuthWithCallback(() => callback) setIsAuthWithCallback(() => callback)
await authorizer().getProfile() const userdata = await authorizer().getProfile()
if (userdata) setUser(userdata)
if (!isAuthenticated()) { if (!isAuthenticated()) {
showModal('auth', modalSource) showModal('auth', modalSource)
@ -200,19 +209,14 @@ export const SessionProvider = (props: {
const signOut = async () => { const signOut = async () => {
await authorizer().logout() await authorizer().logout()
mutate(null) setAuth(null)
setToken(null)
setUser(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) => {
const at: void | AuthToken = await authorizer().verifyEmail(input) const at: void | AuthToken = await authorizer().verifyEmail(input)
if (at) { setAuth(at)
setToken(at)
mutate(at)
}
} }
const getToken = createMemo(() => token()?.access_token) const getToken = createMemo(() => token()?.access_token)

View File

@ -10,7 +10,7 @@ export const notifierClient = {
getNotifications: async (params: QueryLoad_NotificationsArgs): Promise<NotificationsResult> => { getNotifications: async (params: QueryLoad_NotificationsArgs): Promise<NotificationsResult> => {
const resp = await notifierClient.private.query(loadNotifications, params).toPromise() const resp = await notifierClient.private.query(loadNotifications, params).toPromise()
return resp.data.load_notifications return resp.data?.load_notifications
}, },
markNotificationAsRead: async (notification_id: number): Promise<void> => { markNotificationAsRead: async (notification_id: number): Promise<void> => {
await notifierClient.private await notifierClient.private