From 7cbbc86ee4e66923918b5c4d0b627e2f98f0be68 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Wed, 28 May 2025 23:10:54 -0400 Subject: [PATCH] Refactored the header --- src/app/layout.tsx | 31 +++++++++++------------ src/app/nodes/[clientId]/page.tsx | 35 +++++++++++--------------- src/app/page.tsx | 5 +--- src/components/AppContent.tsx | 10 ++------ src/components/Header.tsx | 39 ++++++++++++++++++++++++++++ src/context/HeaderContext.tsx | 42 +++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 48 deletions(-) create mode 100644 src/components/Header.tsx create mode 100644 src/context/HeaderContext.tsx diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d2773a3..6dd7391 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -4,7 +4,8 @@ import { Geist, Geist_Mono } from "next/font/google"; import { Toaster } from '@/components/ui/sonner'; import { ThemeProvider } from '@/components/ThemeProvider'; import { AuthProvider } from '@/context/AuthContext'; -import { ThemeToggle } from '@/components/ThemeToggle'; // Import ThemeToggle +import { HeaderProvider } from '@/context/HeaderContext'; // Import HeaderProvider +import Header from '@/components/Header'; import "./globals.css"; const geistSans = Geist({ @@ -39,22 +40,20 @@ export default function RootLayout({ disableTransitionOnChange > - {/* ThemeToggle placed in a fixed position */} -
{/* Add these classes for positioning */} - -
- - {children} -
-
-
- © 2025 Logan Cusano. All rights reserved. + {/* Wrap with HeaderProvider */} +
{/* Header component now consumes HeaderContext */} + {children} +
-
+ +
diff --git a/src/app/nodes/[clientId]/page.tsx b/src/app/nodes/[clientId]/page.tsx index 1df2208..ada8594 100644 --- a/src/app/nodes/[clientId]/page.tsx +++ b/src/app/nodes/[clientId]/page.tsx @@ -1,30 +1,37 @@ // app/nodes/[clientId]/page.tsx "use client"; -import React from 'react'; +import React, { useEffect } from 'react'; // Import useEffect import { useParams, useRouter } from 'next/navigation'; import { useAuth } from '@/context/AuthContext'; +import { useHeader } from '@/context/HeaderContext'; // Import useHeader import IndividualClientPage from '@/components/IndividualClientPage'; import LoginPage from '@/components/LoginPage'; import { UserRoles } from '@/types'; -import { Button } from '@/components/ui/button'; const ClientDetailPage: React.FC = () => { const router = useRouter(); - const params = useParams(); // params can be null or an object with string | string[] values - + const params = useParams(); const { user, loading, token, hasPermission, logout } = useAuth(); + const { setHeaderConfig } = useHeader(); + + // Use useEffect to set header configuration on mount and clean up on unmount + useEffect(() => { + setHeaderConfig({ showBackButton: true }); + + return () => { + setHeaderConfig({ showBackButton: false }); + }; + }, [setHeaderConfig]); // Dependency array: ensure effect runs if setHeaderConfig changes (unlikely) + if (loading) { return
Loading Authentication...
; } - // Safely extract clientId, handling the case where params might be null or clientId might be undefined - const clientId = params?.clientId; // Use optional chaining + const clientId = params?.clientId; if (!clientId) { - // This covers cases where params is null, or clientId property is missing/undefined - // or if the URL param isn't properly captured. return (
Client ID not found in URL. @@ -32,15 +39,11 @@ const ClientDetailPage: React.FC = () => { ); } - // Ensure clientIdentifier is a string (use the first element if it's an array) const clientIdentifier = Array.isArray(clientId) ? clientId[0] : clientId; if (!user || !token || !hasPermission(UserRoles.MOD)) { return (
-
-

Radio App Admin

-
{!user ? ( @@ -56,14 +59,6 @@ const ClientDetailPage: React.FC = () => { return (
-
-

Radio App Admin

-
- Logged in as: {user.username} ({user.role}) - - -
-
diff --git a/src/app/page.tsx b/src/app/page.tsx index 120b3f6..8845792 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,12 +1,9 @@ "use client"; import React from 'react'; -import { AuthProvider } from '@/context/AuthContext'; import AppContent from '@/components/AppContent'; export default function App() { return ( - - - + ); } \ No newline at end of file diff --git a/src/components/AppContent.tsx b/src/components/AppContent.tsx index 5c2998d..3234544 100644 --- a/src/components/AppContent.tsx +++ b/src/components/AppContent.tsx @@ -2,7 +2,7 @@ "use client"; import React, { useState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; -import { useAuth } from '@/context/AuthContext'; // Correct path to useAuth +import { useAuth } from '@/context/AuthContext'; import LoginPage from '@/components/LoginPage'; import BotsManagement from '@/components/BotsManagement'; import SystemsManagement from '@/components/SystemsManagement'; @@ -45,13 +45,7 @@ const AppContent: React.FC = () => { // If loading is false, and we have a user with MOD permission and a token, render the main app content return (
-
-

Radio App Admin

-
- Logged in as: {user.username} ({user.role}) - -
-
+ {/* Header is now in layout.tsx */}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx new file mode 100644 index 0000000..5f0500e --- /dev/null +++ b/src/components/Header.tsx @@ -0,0 +1,39 @@ +// components/Header.tsx +"use client"; +import React from 'react'; +import { useRouter } from 'next/navigation'; +import { Button } from '@/components/ui/button'; +import { useAuth } from '@/context/AuthContext'; +import { useHeader } from '@/context/HeaderContext'; // Import useHeader hook +import { ThemeToggle } from '@/components/ThemeToggle'; + +const Header: React.FC = () => { + const router = useRouter(); + const { user, logout } = useAuth(); + const { config } = useHeader(); // Consume the header config from context + + const handleLogoutAndRedirect = () => { + logout(); + router.push('/'); + }; + + return ( +
+
+ {config.showBackButton && ( // Use config from context + + )} +

Radio App Admin

+
+
+ {user && Logged in as: {user.username} ({user.role})} + {user && } + +
+
+ ); +}; + +export default Header; \ No newline at end of file diff --git a/src/context/HeaderContext.tsx b/src/context/HeaderContext.tsx new file mode 100644 index 0000000..c725464 --- /dev/null +++ b/src/context/HeaderContext.tsx @@ -0,0 +1,42 @@ +// context/HeaderContext.tsx +"use client"; + +import React, { createContext, useContext, useState, ReactNode, useCallback } from 'react'; + +interface HeaderConfig { + showBackButton: boolean; + // Add other configurable items here, e.g., title, custom elements +} + +interface HeaderContextType { + config: HeaderConfig; + setHeaderConfig: (newConfig: Partial) => void; +} + +const defaultHeaderConfig: HeaderConfig = { + showBackButton: false, +}; + +const HeaderContext = createContext(undefined); + +export const HeaderProvider: React.FC<{ children: ReactNode }> = ({ children }) => { + const [config, setConfig] = useState(defaultHeaderConfig); + + const setHeaderConfig = useCallback((newConfig: Partial) => { + setConfig(prevConfig => ({ ...prevConfig, ...newConfig })); + }, []); + + return ( + + {children} + + ); +}; + +export const useHeader = () => { + const context = useContext(HeaderContext); + if (context === undefined) { + throw new Error('useHeader must be used within a HeaderProvider'); + } + return context; +}; \ No newline at end of file