diff --git a/frontend/src/app/(dashboard)/appointments/page.tsx b/frontend/src/app/(dashboard)/appointments/page.tsx
new file mode 100644
index 0000000..d638c9f
--- /dev/null
+++ b/frontend/src/app/(dashboard)/appointments/page.tsx
@@ -0,0 +1,10 @@
+export default function AppointmentsPage() {
+ return (
+
+
Appointments
+
+ Appointments module is coming soon.
+
+
+ );
+}
diff --git a/frontend/src/app/(dashboard)/lab/page.tsx b/frontend/src/app/(dashboard)/lab/page.tsx
new file mode 100644
index 0000000..42c2cab
--- /dev/null
+++ b/frontend/src/app/(dashboard)/lab/page.tsx
@@ -0,0 +1,10 @@
+export default function LabPage() {
+ return (
+
+
Lab Management
+
+ Lab management module is coming soon.
+
+
+ );
+}
diff --git a/frontend/src/app/(dashboard)/layout.tsx b/frontend/src/app/(dashboard)/layout.tsx
index be84b47..62735b2 100644
--- a/frontend/src/app/(dashboard)/layout.tsx
+++ b/frontend/src/app/(dashboard)/layout.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useEffect } from 'react';
+import { memo, useCallback, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useAuth } from '@/lib/hooks/useAuth';
import Sidebar from '@/components/ui/Sidebar';
@@ -10,6 +10,9 @@ import { LogOut } from 'lucide-react';
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
const { user, currentOrganization, isAuthReady, logout } = useAuth();
const router = useRouter();
+ const handleLogout = useCallback(() => {
+ void logout();
+ }, [logout]);
// ✅ AUTH GUARD (runs once per navigation group)
useEffect(() => {
@@ -48,21 +51,11 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
-
+
@@ -72,4 +65,32 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
);
-}
\ No newline at end of file
+}
+
+const DashboardHeader = memo(function DashboardHeader({
+ organizationName,
+ userName,
+ onLogout,
+}: {
+ organizationName: string;
+ userName: string;
+ onLogout: () => void;
+}) {
+ return (
+
+ );
+});
\ No newline at end of file
diff --git a/frontend/src/app/(dashboard)/reports/page.tsx b/frontend/src/app/(dashboard)/reports/page.tsx
new file mode 100644
index 0000000..0d53048
--- /dev/null
+++ b/frontend/src/app/(dashboard)/reports/page.tsx
@@ -0,0 +1,10 @@
+export default function ReportsPage() {
+ return (
+
+
Reports
+
+ Reports module is coming soon.
+
+
+ );
+}
diff --git a/frontend/src/app/(dashboard)/staff/page.tsx b/frontend/src/app/(dashboard)/staff/page.tsx
new file mode 100644
index 0000000..e7167d2
--- /dev/null
+++ b/frontend/src/app/(dashboard)/staff/page.tsx
@@ -0,0 +1,10 @@
+export default function StaffPage() {
+ return (
+
+
Staff Management
+
+ Staff management module is coming soon.
+
+
+ );
+}
diff --git a/frontend/src/components/ui/Sidebar.tsx b/frontend/src/components/ui/Sidebar.tsx
index 427539e..f3c59d3 100644
--- a/frontend/src/components/ui/Sidebar.tsx
+++ b/frontend/src/components/ui/Sidebar.tsx
@@ -1,6 +1,8 @@
'use client';
-import { usePathname, useRouter } from 'next/navigation';
+import Link from 'next/link';
+import { memo } from 'react';
+import { usePathname } from 'next/navigation';
import {
LayoutDashboard,
Users,
@@ -21,9 +23,8 @@ const menu = [
{ name: 'Reports', path: '/reports', icon: FileText },
];
-export default function Sidebar() {
+function Sidebar() {
const pathname = usePathname();
- const router = useRouter();
return (
);
-}
\ No newline at end of file
+}
+
+export default memo(Sidebar);
\ No newline at end of file
diff --git a/frontend/src/lib/hooks/useAuth.tsx b/frontend/src/lib/hooks/useAuth.tsx
index 1f80eda..a97d5b0 100644
--- a/frontend/src/lib/hooks/useAuth.tsx
+++ b/frontend/src/lib/hooks/useAuth.tsx
@@ -1,6 +1,6 @@
'use client';
-import React, { createContext, useContext, useEffect, useState } from 'react';
+import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import { authApi } from '@/lib/api/auth';
import { User, Organization } from '@/types';
@@ -37,11 +37,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const router = useRouter();
- useEffect(() => {
- checkAuth();
- }, []);
-
- const normalizeProfilePayload = (payload: any): { user: User | null; organizations: Organization[] } => {
+ const normalizeProfilePayload = useCallback((payload: any): { user: User | null; organizations: Organization[] } => {
const organizations = payload?.organizations || [];
if (payload?.user) {
@@ -60,9 +56,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}
return { user: null, organizations };
- };
+ }, []);
- const checkAuth = async () => {
+ const checkAuth = useCallback(async () => {
try {
setIsLoading(true);
@@ -103,10 +99,14 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
setIsLoading(false);
setIsAuthReady(true);
}
- };
+ }, [normalizeProfilePayload]);
+
+ useEffect(() => {
+ void checkAuth();
+ }, [checkAuth]);
// ✅ REGISTER
- const registerTrial = async (
+ const registerTrial = useCallback(async (
email: string,
password: string,
name: string,
@@ -147,10 +147,10 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
} finally {
setIsLoading(false);
}
- };
+ }, [router]);
// ✅ LOGIN
- const login = async (email: string, password: string) => {
+ const login = useCallback(async (email: string, password: string) => {
try {
setIsLoading(true);
setError(null);
@@ -178,17 +178,17 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
} finally {
setIsLoading(false);
}
- };
+ }, [router]);
- const logout = async () => {
+ const logout = useCallback(async () => {
localStorage.clear();
setUser(null);
setOrganizations([]);
setCurrentOrganization(null);
router.push('/');
- };
+ }, [router]);
- const selectOrganization = async (orgId: string) => {
+ const selectOrganization = useCallback(async (orgId: string) => {
try {
setIsLoading(true);
@@ -208,26 +208,41 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
} finally {
setIsLoading(false);
}
- };
+ }, [router]);
- const clearError = () => setError(null);
+ const clearError = useCallback(() => setError(null), []);
+
+ const contextValue = useMemo(
+ () => ({
+ user,
+ organizations,
+ currentOrganization,
+ isLoading,
+ isAuthReady,
+ error,
+ registerTrial,
+ login,
+ logout,
+ selectOrganization,
+ clearError,
+ }),
+ [
+ user,
+ organizations,
+ currentOrganization,
+ isLoading,
+ isAuthReady,
+ error,
+ registerTrial,
+ login,
+ logout,
+ selectOrganization,
+ clearError,
+ ],
+ );
return (
-
+
{children}
);