diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index dab3a24..6e30383 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -3,13 +3,14 @@ import { useNavigate } from "react-router-dom" import { useTranslation } from "../hooks/useTranslation" import { Button } from "./ui/button" import { SettingsMenu } from "./SettingsMenu" -import { LogOut, User, Moon, Sun, Globe, Command, Menu } from "lucide-react" +import { FlaskConical, LogOut, User, Moon, Sun, Globe, Command, Menu, RefreshCcw } from "lucide-react" import { useTheme } from "./ThemeProvider" import { logoutUser, getUserProfile } from "../api/users" import { WorkspaceSelector } from "./WorkspaceSelector" import { toast } from "sonner" import { NotificationBell } from "./notifications/NotificationBell" -import { clearSessionTokens, getAccessToken, getRefreshToken } from "../lib/session" +import { clearSessionTokens, getAccessToken, getRefreshToken, setDemoSessionMeta, setSessionTokens } from "../lib/session" +import { startDemo } from "../api/demo" type NavbarProps = { onOpenSidebar?: () => void @@ -22,6 +23,7 @@ export function Navbar({ onOpenSidebar }: NavbarProps) { const [showLogoutModal, setShowLogoutModal] = useState(false) const [isDropdownOpen, setIsDropdownOpen] = useState(false) + const [isResettingDemo, setIsResettingDemo] = useState(false) const [user, setUser] = useState(null) const dropdownRef = useRef(null) @@ -30,6 +32,13 @@ export function Navbar({ onOpenSidebar }: NavbarProps) { const isDarkMode = theme === "dark" || (theme === "system" && document.documentElement.classList.contains("dark")) + const isDemoUser = Boolean(user?.is_demo) + const demoExpiryLabel = user?.demo_expires_at + ? new Intl.DateTimeFormat(isFa ? "fa-IR" : "en-US", { + dateStyle: "medium", + timeStyle: "short", + }).format(new Date(user.demo_expires_at)) + : null useEffect(() => { const handleProfileUpdated = ((e: CustomEvent) => { @@ -86,6 +95,23 @@ export function Navbar({ onOpenSidebar }: NavbarProps) { } } + const handleResetDemo = async () => { + if (isResettingDemo) return + setIsResettingDemo(true) + try { + const demo = await startDemo() + setSessionTokens(demo.access, demo.refresh) + setDemoSessionMeta(demo.expires_at) + toast.success(t.demo?.reset || "Fresh demo environment is ready.") + window.location.href = "/timesheet" + } catch (error) { + console.error("Demo reset failed:", error) + toast.error(t.demo?.startError || "Could not start the demo environment.") + } finally { + setIsResettingDemo(false) + } + } + const toggleTheme = () => { setTheme(isDarkMode ? "light" : "dark") } @@ -142,6 +168,12 @@ export function Navbar({ onOpenSidebar }: NavbarProps) { {/* Desktop navbar: keep the old controls here */}
{user && } + {isDemoUser && ( +
+ + {t.demo?.badge || "Demo environment"} +
+ )} {user ? ( <> @@ -178,8 +210,24 @@ export function Navbar({ onOpenSidebar }: NavbarProps) { ? `${user.first_name || ""} ${user.last_name || ""}`.trim() : user.email}

+ {isDemoUser && demoExpiryLabel && ( +

+ {(t.demo?.expiresAt || "Expires at")}: {demoExpiryLabel} +

+ )}
+ {isDemoUser && ( + + )} + + {isDemoUser && ( + + )} + + + )} {renderNavItems(false)} @@ -402,4 +478,4 @@ export const Sidebar = ({ mobileOpen = false, onMobileClose }: SidebarProps) => )} ) -} \ No newline at end of file +} diff --git a/src/context/AppContext.tsx b/src/context/AppContext.tsx index 88805cc..160136c 100644 --- a/src/context/AppContext.tsx +++ b/src/context/AppContext.tsx @@ -8,6 +8,8 @@ interface User { last_name: string; email?: string; profile_picture?: string | null; + is_demo?: boolean; + demo_expires_at?: string | null; } interface AppContextType {