diff --git a/backend/server.js b/backend/server.js index 11986e9..e57f0b1 100644 --- a/backend/server.js +++ b/backend/server.js @@ -21,7 +21,7 @@ const PORT = process.env.PORT || 3000; // Security middleware app.use(helmet()); app.use(cors({ - origin: process.env.FRONTEND_URL || 'http://localhost:3001', + origin: process.env.FRONTEND_URL || 'http://localhost:3005', credentials: true })); diff --git a/docker-compose.local.yml b/docker-compose.local.yml index 8f516a9..282fdcb 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -11,8 +11,8 @@ services: - NODE_ENV=development - PORT=3000 - JWT_SECRET=local-dev-secret-key-123 - - ADMIN_URL=http://localhost:3001 - - FRONTEND_URL=http://localhost:3000 + - ADMIN_URL=http://localhost:3005 + - FRONTEND_URL=http://localhost:3005 # Email - uses Mailhog - SMTP_HOST=mailhog - SMTP_PORT=1025 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index afcb942..73d527c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -20,7 +20,7 @@ import { BrandingPage } from './pages/admin'; import { AdminLayout } from './components/admin'; -import { PageErrorBoundary, OfflineIndicator, SkipLink } from './components/common'; +import { PageErrorBoundary, ErrorBoundary, OfflineIndicator, SkipLink } from './components/common'; // Create a client const queryClient = new QueryClient({ @@ -68,7 +68,7 @@ function App() { } /> }> - } /> + } /> } /> } /> } /> diff --git a/frontend/src/components/admin/AdminLayout.tsx b/frontend/src/components/admin/AdminLayout.tsx index 6971f4e..16a9039 100644 --- a/frontend/src/components/admin/AdminLayout.tsx +++ b/frontend/src/components/admin/AdminLayout.tsx @@ -6,9 +6,20 @@ import { AdminSidebar } from './AdminSidebar'; import { AdminHeader } from './AdminHeader'; export const AdminLayout: React.FC = () => { - const { isAuthenticated } = useAdminAuth(); + const { isAuthenticated, isLoading } = useAdminAuth(); const [sidebarOpen, setSidebarOpen] = useState(false); + if (isLoading) { + return ( +
+
+
+

Loading...

+
+
+ ); + } + if (!isAuthenticated) { return ; } diff --git a/frontend/src/contexts/AdminAuthContext.tsx b/frontend/src/contexts/AdminAuthContext.tsx index db11d79..3117109 100644 --- a/frontend/src/contexts/AdminAuthContext.tsx +++ b/frontend/src/contexts/AdminAuthContext.tsx @@ -35,15 +35,21 @@ export const AdminAuthProvider: React.FC = ({ children } useEffect(() => { // Check if user has a valid token on mount - const token = getAuthToken(true); - if (token) { - // TODO: Validate token with backend and get user info - setIsAuthenticated(true); - } - setIsLoading(false); + const checkAuth = async () => { + const token = getAuthToken(true); + if (token) { + // For now, just assume the token is valid + // TODO: Validate token with backend and get user info + setIsAuthenticated(true); + } + setIsLoading(false); + }; + + checkAuth(); }, []); const login = (_token: string, user: AdminUser) => { + // Token is already stored in cookie by authService setUser(user); setIsAuthenticated(true); setError(null); diff --git a/frontend/src/services/auth.service.ts b/frontend/src/services/auth.service.ts index 882b2bc..52bf2b0 100644 --- a/frontend/src/services/auth.service.ts +++ b/frontend/src/services/auth.service.ts @@ -4,7 +4,11 @@ import type { LoginResponse, GalleryAuthResponse } from '../types'; export const authService = { // Admin authentication async adminLogin(credentials: { email: string; password: string }): Promise { - const response = await api.post('/api/auth/admin/login', credentials); + // Backend expects 'username' field, but we accept email + const response = await api.post('/api/auth/admin/login', { + username: credentials.email, + password: credentials.password + }); setAuthToken(response.data.token, true); return response.data;