Fix admin login and CORS issues

- Update CORS configuration to allow frontend on port 3005
- Fix auth service to map email field to username for backend compatibility
- Add loading state handling in AdminLayout
- Add error boundary to dashboard route
- Fix unused parameter warning in login function

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-06 22:23:14 +02:00
parent 28632e8970
commit 3470120a0d
6 changed files with 34 additions and 13 deletions
+1 -1
View File
@@ -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
}));
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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() {
<Routes>
<Route path="login" element={<AdminLoginPage />} />
<Route element={<AdminLayout />}>
<Route path="dashboard" element={<AdminDashboard />} />
<Route path="dashboard" element={<ErrorBoundary><AdminDashboard /></ErrorBoundary>} />
<Route path="events" element={<EventsListPage />} />
<Route path="events/new" element={<CreateEventPage />} />
<Route path="events/:id" element={<EventDetailsPage />} />
+12 -1
View File
@@ -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 (
<div className="min-h-screen bg-neutral-50 flex items-center justify-center">
<div className="text-center">
<div className="w-16 h-16 border-4 border-primary-600 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
<p className="text-neutral-600">Loading...</p>
</div>
</div>
);
}
if (!isAuthenticated) {
return <Navigate to="/admin/login" replace />;
}
+12 -6
View File
@@ -35,15 +35,21 @@ export const AdminAuthProvider: React.FC<AdminAuthProviderProps> = ({ 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);
+5 -1
View File
@@ -4,7 +4,11 @@ import type { LoginResponse, GalleryAuthResponse } from '../types';
export const authService = {
// Admin authentication
async adminLogin(credentials: { email: string; password: string }): Promise<LoginResponse> {
const response = await api.post<LoginResponse>('/api/auth/admin/login', credentials);
// Backend expects 'username' field, but we accept email
const response = await api.post<LoginResponse>('/api/auth/admin/login', {
username: credentials.email,
password: credentials.password
});
setAuthToken(response.data.token, true);
return response.data;