diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx
index 6d7f4956..8e9b7ea4 100644
--- a/src/frontend/src/App.tsx
+++ b/src/frontend/src/App.tsx
@@ -6,11 +6,11 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import { useLang } from 'hoofd'
import { Route, Switch } from 'wouter'
-import { Screen } from './layout/Screen'
import { HomeRoute } from '@/features/home'
import { RoomRoute, roomIdRegex } from '@/features/rooms'
import { NotFound } from './routes/NotFound'
import './i18n/init'
+import { RenderIfUserFetched } from './features/auth'
const queryClient = new QueryClient()
@@ -19,12 +19,14 @@ function App() {
useLang(i18n.language)
return (
- }>
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/frontend/src/features/auth/api/useUser.tsx b/src/frontend/src/features/auth/api/useUser.tsx
index 6286ca12..84f5e601 100644
--- a/src/frontend/src/features/auth/api/useUser.tsx
+++ b/src/frontend/src/features/auth/api/useUser.tsx
@@ -2,16 +2,25 @@ import { useQuery } from '@tanstack/react-query'
import { keys } from '@/api/queryKeys'
import { fetchUser } from './fetchUser'
+/**
+ * returns info about currently logged in user
+ *
+ * `isLoggedIn` is undefined while query is loading and true/false when it's done
+ */
export const useUser = () => {
const query = useQuery({
queryKey: [keys.user],
queryFn: fetchUser,
})
+ let isLoggedIn = undefined
+ if (query.data !== undefined) {
+ isLoggedIn = query.data !== false
+ }
return {
...query,
// if fetchUser returns false, it means the user is not logged in: expose that
user: query.data === false ? undefined : query.data,
- isLoggedIn: query.data !== undefined && query.data !== false,
+ isLoggedIn,
}
}
diff --git a/src/frontend/src/features/auth/components/RenderIfUserFetched.tsx b/src/frontend/src/features/auth/components/RenderIfUserFetched.tsx
new file mode 100644
index 00000000..276a0133
--- /dev/null
+++ b/src/frontend/src/features/auth/components/RenderIfUserFetched.tsx
@@ -0,0 +1,17 @@
+import { type ReactNode } from 'react'
+import { useUser } from '@/features/auth'
+import { LoadingScreen } from '@/layout/LoadingScreen'
+
+/**
+ * wrapper that renders children only when user info has been actually fetched
+ *
+ * this is helpful to prevent flash of logged-out content for a few milliseconds when user is actually logged in
+ */
+export const RenderIfUserFetched = ({ children }: { children: ReactNode }) => {
+ const { isLoggedIn } = useUser()
+ return isLoggedIn !== undefined ? (
+ children
+ ) : (
+
+ )
+}
diff --git a/src/frontend/src/features/auth/index.ts b/src/frontend/src/features/auth/index.ts
index d298a6cb..0b533fea 100644
--- a/src/frontend/src/features/auth/index.ts
+++ b/src/frontend/src/features/auth/index.ts
@@ -1,3 +1,4 @@
export { useUser } from './api/useUser'
export { authUrl } from './utils/authUrl'
export { logoutUrl } from './utils/logoutUrl'
+export { RenderIfUserFetched } from './components/RenderIfUserFetched'
diff --git a/src/frontend/src/layout/LoadingScreen.tsx b/src/frontend/src/layout/LoadingScreen.tsx
index 40053ba8..2d58c9e4 100644
--- a/src/frontend/src/layout/LoadingScreen.tsx
+++ b/src/frontend/src/layout/LoadingScreen.tsx
@@ -3,14 +3,20 @@ import { useTranslation } from 'react-i18next'
import { BoxScreen } from './BoxScreen'
import { Screen } from './Screen'
-export const LoadingScreen = ({ asBox = false }: { asBox?: boolean }) => {
+export const LoadingScreen = ({
+ asBox = false,
+ renderTimeout = 500,
+}: {
+ asBox?: boolean
+ renderTimeout?: number
+}) => {
const { t } = useTranslation()
// show the loading screen only after a little while to prevent flash of texts
const [show, setShow] = useState(false)
useEffect(() => {
- const timeout = setTimeout(() => setShow(true), 500)
+ const timeout = setTimeout(() => setShow(true), renderTimeout)
return () => clearTimeout(timeout)
- }, [])
+ }, [renderTimeout])
if (!show) {
return null
}