diff --git a/src/App.tsx b/src/App.tsx
index aa34b4d..78d0d9e 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,13 +1,14 @@
import { createBrowserRouter, RouterProvider, Navigate, Outlet, useLocation } from "react-router-dom"
import { useState } from "react"
+import { Command } from "lucide-react"
import { ThemeProvider } from "./components/ThemeProvider"
import { LanguageProvider } from "./components/LanguageProvider"
import { Toaster } from "./components/ui/toaster"
import { Navbar } from "./components/Navbar"
import { Sidebar } from './components/Sidebar';
-import { AppProvider } from "./context/AppContext"
+import { AppProvider, useAppContext } from "./context/AppContext"
import { NotificationsProvider } from "./context/NotificationsContext"
-import { WorkspaceProvider } from "./context/WorkspaceContext"
+import { useWorkspace, WorkspaceProvider } from "./context/WorkspaceContext"
import Auth from "./pages/Auth"
import GoogleAuthCallback from "./pages/GoogleAuthCallback"
import Profile from "./pages/Profile"
@@ -39,6 +40,7 @@ import { SignupPasswordPage } from "./pages/auth/SignupPasswordPage"
import { ForgotPasswordMobilePage } from "./pages/auth/ForgotPasswordMobilePage"
import { ForgotPasswordOtpPage } from "./pages/auth/ForgotPasswordOtpPage"
import { ForgotPasswordPasswordPage } from "./pages/auth/ForgotPasswordPasswordPage"
+import { useTranslation } from "./hooks/useTranslation"
const MainLayout = () => {
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false)
@@ -94,12 +96,45 @@ const AuthLayout = () => (
)
+const ProtectedBootLoader = () => {
+ const { t } = useTranslation()
+
+ return (
+
+
+
+
+
+
+
+
{t.title || "Qlockify"}
+
{t.loading || "Loading..."}
+
+
+ )
+}
+
+const ProtectedAppGate = () => {
+ const { isLoadingUser } = useAppContext()
+ const { isLoading } = useWorkspace()
+
+ if (isLoadingUser || isLoading) {
+ return
+ }
+
+ return (
+
+
+
+ )
+}
+
const ProtectedAppLayout = () => (
-
-
-
+
)
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index 6e30383..737d084 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -5,12 +5,13 @@ import { Button } from "./ui/button"
import { SettingsMenu } from "./SettingsMenu"
import { FlaskConical, LogOut, User, Moon, Sun, Globe, Command, Menu, RefreshCcw } from "lucide-react"
import { useTheme } from "./ThemeProvider"
-import { logoutUser, getUserProfile } from "../api/users"
+import { logoutUser } from "../api/users"
import { WorkspaceSelector } from "./WorkspaceSelector"
import { toast } from "sonner"
import { NotificationBell } from "./notifications/NotificationBell"
-import { clearSessionTokens, getAccessToken, getRefreshToken, setDemoSessionMeta, setSessionTokens } from "../lib/session"
+import { clearSessionTokens, getRefreshToken, setDemoSessionMeta, setSessionTokens } from "../lib/session"
import { startDemo } from "../api/demo"
+import { useAppContext } from "../context/AppContext"
type NavbarProps = {
onOpenSidebar?: () => void
@@ -19,12 +20,12 @@ type NavbarProps = {
export function Navbar({ onOpenSidebar }: NavbarProps) {
const { t, lang, setLanguage } = useTranslation()
const { theme, setTheme } = useTheme()
+ const { user, isLoadingUser, setUser } = useAppContext()
const navigate = useNavigate()
const [showLogoutModal, setShowLogoutModal] = useState(false)
const [isDropdownOpen, setIsDropdownOpen] = useState(false)
const [isResettingDemo, setIsResettingDemo] = useState(false)
- const [user, setUser] = useState(null)
const dropdownRef = useRef(null)
@@ -40,33 +41,6 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
}).format(new Date(user.demo_expires_at))
: null
- useEffect(() => {
- const handleProfileUpdated = ((e: CustomEvent) => {
- if (e.detail) {
- setUser((prev: any) => (prev ? { ...prev, ...e.detail } : e.detail))
- }
- }) as EventListener
-
- window.addEventListener("profile_updated", handleProfileUpdated)
- return () => window.removeEventListener("profile_updated", handleProfileUpdated)
- }, [])
-
- useEffect(() => {
- const fetchUser = async () => {
- const token = getAccessToken()
- if (!token) return
-
- try {
- const userData = await getUserProfile()
- setUser(userData)
- } catch (error) {
- console.error("Failed to fetch user profile:", error)
- }
- }
-
- void fetchUser()
- }, [])
-
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
@@ -279,7 +253,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) {
)}
>
- ) : (
+ ) : isLoadingUser ? null : (
<>
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index f8ef1d9..84b87b6 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useState } from "react"
+import { useState } from "react"
import { NavLink, useNavigate } from "react-router-dom"
import {
Users,
@@ -28,9 +28,10 @@ import { canWorkspace, WORKSPACE_LOGS_VIEW } from "../lib/permissions"
import { WorkspaceSelector } from "./WorkspaceSelector"
import { SettingsMenu } from "./SettingsMenu"
import { Button } from "./ui/button"
-import { getUserProfile, logoutUser } from "../api/users"
-import { clearSessionTokens, getAccessToken, getRefreshToken, setDemoSessionMeta, setSessionTokens } from "../lib/session"
+import { logoutUser } from "../api/users"
+import { clearSessionTokens, getRefreshToken, setDemoSessionMeta, setSessionTokens } from "../lib/session"
import { startDemo } from "../api/demo"
+import { useAppContext } from "../context/AppContext"
type SidebarProps = {
mobileOpen?: boolean
@@ -41,7 +42,7 @@ export const Sidebar = ({ mobileOpen = false, onMobileClose }: SidebarProps) =>
const [isCollapsed, setIsCollapsed] = useState(false)
const [showLogoutModal, setShowLogoutModal] = useState(false)
const [isResettingDemo, setIsResettingDemo] = useState(false)
- const [user, setUser] = useState(null)
+ const { user, isLoadingUser, setUser } = useAppContext()
const navigate = useNavigate()
const { t, lang, setLanguage } = useTranslation()
@@ -67,33 +68,6 @@ export const Sidebar = ({ mobileOpen = false, onMobileClose }: SidebarProps) =>
? PanelLeftOpen
: PanelLeftClose
- useEffect(() => {
- const handleProfileUpdated = ((e: CustomEvent) => {
- if (e.detail) {
- setUser((prev: any) => (prev ? { ...prev, ...e.detail } : e.detail))
- }
- }) as EventListener
-
- window.addEventListener("profile_updated", handleProfileUpdated)
- return () => window.removeEventListener("profile_updated", handleProfileUpdated)
- }, [])
-
- useEffect(() => {
- const fetchUser = async () => {
- const token = getAccessToken()
- if (!token) return
-
- try {
- const userData = await getUserProfile()
- setUser(userData)
- } catch (error) {
- console.error("Failed to fetch user profile:", error)
- }
- }
-
- void fetchUser()
- }, [])
-
const handleLogout = async () => {
try {
const refreshToken = getRefreshToken()
@@ -245,7 +219,7 @@ export const Sidebar = ({ mobileOpen = false, onMobileClose }: SidebarProps) =>
}
const renderMobileFooterSection = () => {
- if (!user) {
+ if (!user && !isLoadingUser) {
return (