Merge pull request #6563 from menloresearch/feat/web-minor-ui-tweak-login
feat: tweak login UI
This commit is contained in:
parent
3f51c35229
commit
b322c7649b
@ -41,7 +41,7 @@ function DropdownMenuContent({
|
|||||||
data-slot="dropdown-menu-content"
|
data-slot="dropdown-menu-content"
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-main-view select-none text-main-view-fg border-main-view-fg/5 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
|
'bg-main-view select-none text-main-view-fg border-main-view-fg/5 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-[51] max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@ -229,7 +229,7 @@ function DropdownMenuSubContent({
|
|||||||
<DropdownMenuPrimitive.SubContent
|
<DropdownMenuPrimitive.SubContent
|
||||||
data-slot="dropdown-menu-sub-content"
|
data-slot="dropdown-menu-sub-content"
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-main-view text-main-view-fg border-main-view-fg/5 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
|
'bg-main-view text-main-view-fg border-main-view-fg/5 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-[51] min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@ -141,7 +141,7 @@ const LeftPanel = () => {
|
|||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('resize', handleResize)
|
window.removeEventListener('resize', handleResize)
|
||||||
}
|
}
|
||||||
}, [setLeftPanel])
|
}, [setLeftPanel, open])
|
||||||
|
|
||||||
const currentPath = useRouterState({
|
const currentPath = useRouterState({
|
||||||
select: (state) => state.location.pathname,
|
select: (state) => state.location.pathname,
|
||||||
@ -433,6 +433,7 @@ const LeftPanel = () => {
|
|||||||
if (menu.title === 'common:authentication') {
|
if (menu.title === 'common:authentication') {
|
||||||
return (
|
return (
|
||||||
<div key={menu.title}>
|
<div key={menu.title}>
|
||||||
|
<div className="mx-1 my-2 border-t border-left-panel-fg/5" />
|
||||||
{isAuthenticated ? (
|
{isAuthenticated ? (
|
||||||
<UserProfileMenu />
|
<UserProfileMenu />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* Shows available authentication providers in a dropdown menu
|
* Shows available authentication providers in a dropdown menu
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useState, useRef, useEffect } from 'react'
|
||||||
import { IconLogin, IconBrandGoogleFilled } from '@tabler/icons-react'
|
import { IconLogin, IconBrandGoogleFilled } from '@tabler/icons-react'
|
||||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||||
import { useAuth } from '@/hooks/useAuth'
|
import { useAuth } from '@/hooks/useAuth'
|
||||||
@ -15,14 +15,45 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu'
|
} from '@/components/ui/dropdown-menu'
|
||||||
|
import { useSmallScreen } from '@/hooks/useMediaQuery'
|
||||||
|
|
||||||
export const AuthLoginButton = () => {
|
export const AuthLoginButton = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { getAllProviders, loginWithProvider } = useAuth()
|
const { getAllProviders, loginWithProvider } = useAuth()
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [panelWidth, setPanelWidth] = useState<number>(192)
|
||||||
|
const dropdownRef = useRef<HTMLButtonElement>(null)
|
||||||
|
const isSmallScreen = useSmallScreen()
|
||||||
|
|
||||||
const enabledProviders = getAllProviders()
|
const enabledProviders = getAllProviders()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updateWidth = () => {
|
||||||
|
// Find the left panel element
|
||||||
|
const leftPanel = document.querySelector('aside[ref]') ||
|
||||||
|
document.querySelector('aside') ||
|
||||||
|
dropdownRef.current?.closest('aside')
|
||||||
|
if (leftPanel) {
|
||||||
|
setPanelWidth(leftPanel.getBoundingClientRect().width)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWidth()
|
||||||
|
window.addEventListener('resize', updateWidth)
|
||||||
|
|
||||||
|
// Also observe for panel resize
|
||||||
|
const observer = new ResizeObserver(updateWidth)
|
||||||
|
const leftPanel = document.querySelector('aside')
|
||||||
|
if (leftPanel) {
|
||||||
|
observer.observe(leftPanel)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', updateWidth)
|
||||||
|
observer.disconnect()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const handleProviderLogin = async (providerId: ProviderType) => {
|
const handleProviderLogin = async (providerId: ProviderType) => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
@ -52,6 +83,7 @@ export const AuthLoginButton = () => {
|
|||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<button
|
<button
|
||||||
|
ref={dropdownRef}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="flex items-center gap-1.5 cursor-pointer hover:bg-left-panel-fg/10 py-1 px-1 rounded w-full"
|
className="flex items-center gap-1.5 cursor-pointer hover:bg-left-panel-fg/10 py-1 px-1 rounded w-full"
|
||||||
>
|
>
|
||||||
@ -59,7 +91,12 @@ export const AuthLoginButton = () => {
|
|||||||
<span className="font-medium text-left-panel-fg/90">{t('common:login')}</span>
|
<span className="font-medium text-left-panel-fg/90">{t('common:login')}</span>
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="right" align="start" className="w-48">
|
<DropdownMenuContent
|
||||||
|
side="top"
|
||||||
|
align="end"
|
||||||
|
style={{ width: `${panelWidth}px` }}
|
||||||
|
alignOffset={isSmallScreen ? -4 : 0}
|
||||||
|
>
|
||||||
{enabledProviders.map((provider) => {
|
{enabledProviders.map((provider) => {
|
||||||
const IconComponent = getProviderIcon(provider.icon)
|
const IconComponent = getProviderIcon(provider.icon)
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* Dropdown menu with user profile and logout options
|
* Dropdown menu with user profile and logout options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useState, useRef, useEffect } from 'react'
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@ -13,16 +13,46 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu'
|
} from '@/components/ui/dropdown-menu'
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||||
import { Button } from '@/components/ui/button'
|
import { IconUser, IconLogout } from '@tabler/icons-react'
|
||||||
import { IconUser, IconLogout, IconChevronDown } from '@tabler/icons-react'
|
|
||||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||||
import { useAuth } from '@/hooks/useAuth'
|
import { useAuth } from '@/hooks/useAuth'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
|
import { useSmallScreen } from '@/hooks/useMediaQuery'
|
||||||
|
|
||||||
export const UserProfileMenu = () => {
|
export const UserProfileMenu = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { user, isLoading, logout } = useAuth()
|
const { user, isLoading, logout } = useAuth()
|
||||||
const [isLoggingOut, setIsLoggingOut] = useState(false)
|
const [isLoggingOut, setIsLoggingOut] = useState(false)
|
||||||
|
const [panelWidth, setPanelWidth] = useState<number>(192)
|
||||||
|
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||||
|
const isSmallScreen = useSmallScreen()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updateWidth = () => {
|
||||||
|
// Find the left panel element
|
||||||
|
const leftPanel = document.querySelector('aside[ref]') ||
|
||||||
|
document.querySelector('aside') ||
|
||||||
|
dropdownRef.current?.closest('aside')
|
||||||
|
if (leftPanel) {
|
||||||
|
setPanelWidth(leftPanel.getBoundingClientRect().width)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWidth()
|
||||||
|
window.addEventListener('resize', updateWidth)
|
||||||
|
|
||||||
|
// Also observe for panel resize
|
||||||
|
const observer = new ResizeObserver(updateWidth)
|
||||||
|
const leftPanel = document.querySelector('aside')
|
||||||
|
if (leftPanel) {
|
||||||
|
observer.observe(leftPanel)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', updateWidth)
|
||||||
|
observer.disconnect()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
if (isLoggingOut) return
|
if (isLoggingOut) return
|
||||||
@ -54,26 +84,24 @@ export const UserProfileMenu = () => {
|
|||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<div ref={dropdownRef} className="flex items-center gap-1.5 cursor-pointer hover:bg-left-panel-fg/10 py-1 px-1 rounded">
|
||||||
variant="link"
|
<Avatar className="h-[18px] w-[18px]">
|
||||||
size="sm"
|
|
||||||
className="w-full justify-between gap-2 px-2"
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Avatar className="h-6 w-6">
|
|
||||||
{user.picture && (
|
{user.picture && (
|
||||||
<AvatarImage src={user.picture} alt={user.name} />
|
<AvatarImage src={user.picture} alt={user.name} />
|
||||||
)}
|
)}
|
||||||
<AvatarFallback className="text-xs">
|
<AvatarFallback className="text-[10px]">
|
||||||
{getInitials(user.name)}
|
{getInitials(user.name)}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<span className="truncate text-sm">{user.name}</span>
|
<span className="font-medium text-left-panel-fg/90">{user.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<IconChevronDown size={14} className="text-muted-foreground" />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="right" align="start" className="w-56">
|
<DropdownMenuContent
|
||||||
|
side="top"
|
||||||
|
align="end"
|
||||||
|
style={{ width: `${panelWidth}px` }}
|
||||||
|
alignOffset={isSmallScreen ? -4 : 0}
|
||||||
|
>
|
||||||
<DropdownMenuLabel>
|
<DropdownMenuLabel>
|
||||||
<div className="flex flex-col space-y-1">
|
<div className="flex flex-col space-y-1">
|
||||||
<p className="text-sm font-medium leading-none">{user.name}</p>
|
<p className="text-sm font-medium leading-none">{user.name}</p>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useAppState } from './useAppState'
|
import { useAppState } from './useAppState'
|
||||||
import { useMessages } from './useMessages'
|
import { useMessages } from './useMessages'
|
||||||
import { useShallow } from 'zustand/react/shallow'
|
import { useShallow } from 'zustand/react/shallow'
|
||||||
@ -25,16 +25,16 @@ export const useThreadScrolling = (
|
|||||||
|
|
||||||
const showScrollToBottomBtn = !isAtBottom && hasScrollbar
|
const showScrollToBottomBtn = !isAtBottom && hasScrollbar
|
||||||
|
|
||||||
const scrollToBottom = (smooth = false) => {
|
const scrollToBottom = useCallback((smooth = false) => {
|
||||||
if (scrollContainerRef.current) {
|
if (scrollContainerRef.current) {
|
||||||
scrollContainerRef.current.scrollTo({
|
scrollContainerRef.current.scrollTo({
|
||||||
top: scrollContainerRef.current.scrollHeight,
|
top: scrollContainerRef.current.scrollHeight,
|
||||||
...(smooth ? { behavior: 'smooth' } : {}),
|
...(smooth ? { behavior: 'smooth' } : {}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
const handleScroll = (e: Event) => {
|
const handleScroll = useCallback((e: Event) => {
|
||||||
const target = e.target as HTMLDivElement
|
const target = e.target as HTMLDivElement
|
||||||
const { scrollTop, scrollHeight, clientHeight } = target
|
const { scrollTop, scrollHeight, clientHeight } = target
|
||||||
// Use a small tolerance to better detect when we're at the bottom
|
// Use a small tolerance to better detect when we're at the bottom
|
||||||
@ -53,17 +53,18 @@ export const useThreadScrolling = (
|
|||||||
setIsAtBottom(isBottom)
|
setIsAtBottom(isBottom)
|
||||||
setHasScrollbar(hasScroll)
|
setHasScrollbar(hasScroll)
|
||||||
lastScrollTopRef.current = scrollTop
|
lastScrollTopRef.current = scrollTop
|
||||||
}
|
}, [streamingContent])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scrollContainerRef.current) {
|
const scrollContainer = scrollContainerRef.current
|
||||||
scrollContainerRef.current.addEventListener('scroll', handleScroll)
|
if (scrollContainer) {
|
||||||
|
scrollContainer.addEventListener('scroll', handleScroll)
|
||||||
return () =>
|
return () =>
|
||||||
scrollContainerRef.current?.removeEventListener('scroll', handleScroll)
|
scrollContainer.removeEventListener('scroll', handleScroll)
|
||||||
}
|
}
|
||||||
}, [scrollContainerRef])
|
}, [handleScroll])
|
||||||
|
|
||||||
const checkScrollState = () => {
|
const checkScrollState = useCallback(() => {
|
||||||
const scrollContainer = scrollContainerRef.current
|
const scrollContainer = scrollContainerRef.current
|
||||||
if (!scrollContainer) return
|
if (!scrollContainer) return
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ export const useThreadScrolling = (
|
|||||||
|
|
||||||
setIsAtBottom(isBottom)
|
setIsAtBottom(isBottom)
|
||||||
setHasScrollbar(hasScroll)
|
setHasScrollbar(hasScroll)
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
// Single useEffect for all auto-scrolling logic
|
// Single useEffect for all auto-scrolling logic
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -120,7 +121,7 @@ export const useThreadScrolling = (
|
|||||||
const interval = setInterval(checkScrollState, 100)
|
const interval = setInterval(checkScrollState, 100)
|
||||||
return () => clearInterval(interval)
|
return () => clearInterval(interval)
|
||||||
}
|
}
|
||||||
}, [streamingContent])
|
}, [streamingContent, checkScrollState])
|
||||||
|
|
||||||
// Auto-scroll to bottom when component mounts or thread content changes
|
// Auto-scroll to bottom when component mounts or thread content changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -138,7 +139,7 @@ export const useThreadScrolling = (
|
|||||||
checkScrollState()
|
checkScrollState()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}, [])
|
}, [checkScrollState, scrollToBottom])
|
||||||
|
|
||||||
const handleDOMScroll = (e: Event) => {
|
const handleDOMScroll = (e: Event) => {
|
||||||
const target = e.target as HTMLDivElement
|
const target = e.target as HTMLDivElement
|
||||||
@ -182,7 +183,7 @@ export const useThreadScrolling = (
|
|||||||
userIntendedPositionRef.current = null
|
userIntendedPositionRef.current = null
|
||||||
wasStreamingRef.current = false
|
wasStreamingRef.current = false
|
||||||
checkScrollState()
|
checkScrollState()
|
||||||
}, [threadId])
|
}, [threadId, checkScrollState, scrollToBottom])
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({ showScrollToBottomBtn, scrollToBottom, setIsUserScrolling }),
|
() => ({ showScrollToBottomBtn, scrollToBottom, setIsUserScrolling }),
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* Initializes the auth service and sets up event listeners
|
* Initializes the auth service and sets up event listeners
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useEffect, useState, ReactNode } from 'react'
|
import { useCallback, useEffect, useState, ReactNode } from 'react'
|
||||||
import { PlatformFeature } from '@/lib/platform/types'
|
import { PlatformFeature } from '@/lib/platform/types'
|
||||||
import { PlatformFeatures } from '@/lib/platform/const'
|
import { PlatformFeatures } from '@/lib/platform/const'
|
||||||
import { initializeAuthStore, getAuthStore } from '@/hooks/useAuth'
|
import { initializeAuthStore, getAuthStore } from '@/hooks/useAuth'
|
||||||
@ -28,7 +28,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
PlatformFeatures[PlatformFeature.AUTHENTICATION]
|
PlatformFeatures[PlatformFeature.AUTHENTICATION]
|
||||||
|
|
||||||
// Fetch user data when user logs in
|
// Fetch user data when user logs in
|
||||||
const fetchUserData = async () => {
|
const fetchUserData = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const { setThreads } = useThreads.getState()
|
const { setThreads } = useThreads.getState()
|
||||||
const { setMessages } = useMessages.getState()
|
const { setMessages } = useMessages.getState()
|
||||||
@ -47,10 +47,10 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch user data:', error)
|
console.error('Failed to fetch user data:', error)
|
||||||
}
|
}
|
||||||
}
|
}, [serviceHub])
|
||||||
|
|
||||||
// Reset all app data when user logs out
|
// Reset all app data when user logs out
|
||||||
const resetAppData = () => {
|
const resetAppData = useCallback(() => {
|
||||||
// Clear all threads (including favorites)
|
// Clear all threads (including favorites)
|
||||||
const { clearAllThreads, setCurrentThreadId } = useThreads.getState()
|
const { clearAllThreads, setCurrentThreadId } = useThreads.getState()
|
||||||
clearAllThreads()
|
clearAllThreads()
|
||||||
@ -70,7 +70,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
|
|
||||||
// Navigate back to home to ensure clean state
|
// Navigate back to home to ensure clean state
|
||||||
navigate({ to: '/', replace: true })
|
navigate({ to: '/', replace: true })
|
||||||
}
|
}, [navigate])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isAuthenticationEnabled) {
|
if (!isAuthenticationEnabled) {
|
||||||
@ -139,7 +139,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
return () => {
|
return () => {
|
||||||
cleanupAuthListener()
|
cleanupAuthListener()
|
||||||
}
|
}
|
||||||
}, [isAuthenticationEnabled, isReady])
|
}, [isAuthenticationEnabled, isReady, fetchUserData, resetAppData])
|
||||||
|
|
||||||
return <>{isReady && children}</>
|
return <>{isReady && children}</>
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user