🐛(frontend) fix logout issues affecting support and analytics sessions

Fix logout functionality that was failing in 2 out of 3 scenarios where
support and analytics sessions weren't properly closed. Prevents bugs and
behavioral issues when enabling feature flags or advanced PostHog features.
This commit is contained in:
lebaudantoine
2025-02-28 13:49:34 +01:00
committed by aleb_the_flash
parent 4045662433
commit c0bcced3c0
5 changed files with 25 additions and 16 deletions

View File

@@ -3,8 +3,15 @@ import { keys } from '@/api/queryKeys'
import { fetchUser } from './fetchUser' import { fetchUser } from './fetchUser'
import { type ApiUser } from './ApiUser' import { type ApiUser } from './ApiUser'
import { useEffect } from 'react' import { useEffect } from 'react'
import { startAnalyticsSession } from '@/features/analytics/hooks/useAnalytics' import {
import { initializeSupportSession } from '@/features/support/hooks/useSupport' startAnalyticsSession,
terminateAnalyticsSession,
} from '@/features/analytics/hooks/useAnalytics'
import {
initializeSupportSession,
terminateSupportSession,
} from '@/features/support/hooks/useSupport'
import { logoutUrl } from '../utils/logoutUrl'
/** /**
* returns info about currently logged-in user * returns info about currently logged-in user
@@ -30,6 +37,12 @@ export const useUser = (
} }
}, [query.data]) }, [query.data])
const logout = () => {
terminateAnalyticsSession()
terminateSupportSession()
window.location.href = logoutUrl()
}
const isLoggedIn = const isLoggedIn =
query.status === 'success' ? query.data !== false : undefined query.status === 'success' ? query.data !== false : undefined
const isLoggedOut = isLoggedIn === false const isLoggedOut = isLoggedIn === false
@@ -38,5 +51,6 @@ export const useUser = (
...query, ...query,
user: isLoggedOut ? undefined : (query.data as ApiUser | undefined), user: isLoggedOut ? undefined : (query.data as ApiUser | undefined),
isLoggedIn, isLoggedIn,
logout,
} }
} }

View File

@@ -1,4 +1,3 @@
export { useUser } from './api/useUser' export { useUser } from './api/useUser'
export { authUrl } from './utils/authUrl' export { authUrl } from './utils/authUrl'
export { logoutUrl } from './utils/logoutUrl'
export { UserAware } from './components/UserAware' export { UserAware } from './components/UserAware'

View File

@@ -1,14 +1,14 @@
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
import { useLanguageLabels } from '@/i18n/useLanguageLabels' import { useLanguageLabels } from '@/i18n/useLanguageLabels'
import { A, Badge, Dialog, type DialogProps, Field, H, P } from '@/primitives' import { A, Badge, Dialog, type DialogProps, Field, H, P } from '@/primitives'
import { logoutUrl, useUser } from '@/features/auth' import { useUser } from '@/features/auth'
import { ProConnectButton } from '@/components/ProConnectButton' import { ProConnectButton } from '@/components/ProConnectButton'
export type SettingsDialogProps = Pick<DialogProps, 'isOpen' | 'onOpenChange'> export type SettingsDialogProps = Pick<DialogProps, 'isOpen' | 'onOpenChange'>
export const SettingsDialog = (props: SettingsDialogProps) => { export const SettingsDialog = (props: SettingsDialogProps) => {
const { t, i18n } = useTranslation('settings') const { t, i18n } = useTranslation('settings')
const { user, isLoggedIn } = useUser() const { user, isLoggedIn, logout } = useUser()
const { languagesList, currentLanguage } = useLanguageLabels() const { languagesList, currentLanguage } = useLanguageLabels()
return ( return (
<Dialog title={t('dialog.heading')} {...props}> <Dialog title={t('dialog.heading')} {...props}>
@@ -23,7 +23,7 @@ export const SettingsDialog = (props: SettingsDialogProps) => {
/> />
</P> </P>
<P> <P>
<A href={logoutUrl()}>{t('logout', { ns: 'global' })}</A> <A onPress={logout}>{t('logout', { ns: 'global' })}</A>
</P> </P>
</> </>
) : ( ) : (

View File

@@ -1,7 +1,7 @@
import { A, Badge, Button, DialogProps, Field, H, P } from '@/primitives' import { A, Badge, Button, DialogProps, Field, H, P } from '@/primitives'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
import { useRoomContext } from '@livekit/components-react' import { useRoomContext } from '@livekit/components-react'
import { logoutUrl, useUser } from '@/features/auth' import { useUser } from '@/features/auth'
import { css } from '@/styled-system/css' import { css } from '@/styled-system/css'
import { TabPanel, TabPanelProps } from '@/primitives/Tabs' import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
import { HStack } from '@/styled-system/jsx' import { HStack } from '@/styled-system/jsx'
@@ -16,7 +16,7 @@ export const AccountTab = ({ id, onOpenChange }: AccountTabProps) => {
const { t } = useTranslation('settings') const { t } = useTranslation('settings')
const { saveUsername } = usePersistentUserChoices() const { saveUsername } = usePersistentUserChoices()
const room = useRoomContext() const room = useRoomContext()
const { user, isLoggedIn } = useUser() const { user, isLoggedIn, logout } = useUser()
const [name, setName] = useState(room?.localParticipant.name || '') const [name, setName] = useState(room?.localParticipant.name || '')
const handleOnSubmit = () => { const handleOnSubmit = () => {
@@ -51,7 +51,7 @@ export const AccountTab = ({ id, onOpenChange }: AccountTabProps) => {
/> />
</P> </P>
<P> <P>
<A href={logoutUrl()}>{t('logout', { ns: 'global' })}</A> <A onPress={logout}>{t('logout', { ns: 'global' })}</A>
</P> </P>
</> </>
) : ( ) : (

View File

@@ -4,14 +4,12 @@ import { HStack, Stack } from '@/styled-system/jsx'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Button } from '@/primitives' import { Button } from '@/primitives'
import { SettingsButton } from '@/features/settings' import { SettingsButton } from '@/features/settings'
import { logoutUrl, useUser } from '@/features/auth' import { useUser } from '@/features/auth'
import { useMatchesRoute } from '@/navigation/useMatchesRoute' import { useMatchesRoute } from '@/navigation/useMatchesRoute'
import { FeedbackBanner } from '@/components/FeedbackBanner' import { FeedbackBanner } from '@/components/FeedbackBanner'
import { Menu } from '@/primitives/Menu' import { Menu } from '@/primitives/Menu'
import { MenuList } from '@/primitives/MenuList' import { MenuList } from '@/primitives/MenuList'
import { ProConnectButton } from '@/components/ProConnectButton' import { ProConnectButton } from '@/components/ProConnectButton'
import { terminateAnalyticsSession } from '@/features/analytics/hooks/useAnalytics'
import { terminateSupportSession } from '@/features/support/hooks/useSupport'
import LogoAsset from '@/assets/logo.svg' import LogoAsset from '@/assets/logo.svg'
@@ -97,7 +95,7 @@ export const Header = () => {
const { t } = useTranslation() const { t } = useTranslation()
const isHome = useMatchesRoute('home') const isHome = useMatchesRoute('home')
const isRoom = useMatchesRoute('room') const isRoom = useMatchesRoute('room')
const { user, isLoggedIn } = useUser() const { user, isLoggedIn, logout } = useUser()
return ( return (
<> <>
@@ -173,9 +171,7 @@ export const Header = () => {
items={[{ value: 'logout', label: t('logout') }]} items={[{ value: 'logout', label: t('logout') }]}
onAction={(value) => { onAction={(value) => {
if (value === 'logout') { if (value === 'logout') {
terminateAnalyticsSession() logout()
terminateSupportSession()
window.location.href = logoutUrl()
} }
}} }}
/> />