Files
AdsPreview/frontend/src/App.js
Johannes 501dc92119 feat: UI improvements and responsive design enhancements
- Fix dark mode overscroll areas with proper background colors
- Add mobile responsiveness for project logos in header
- Improve viewport handling with interactive-widget support
- Update app title to proper case 'AdsPreview'
- Add mobile-friendly padding adjustments for tabs and headers
- Update .gitignore to exclude .code-workspace files
- Enhance CSS with anticon color overrides and mobile breakpoints
2025-09-09 18:45:39 +02:00

167 lines
6.1 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import LoginPage from './pages/LoginPage';
import { ConfigProvider, theme, Spin, Alert, Layout, App as AntApp, Tabs } from 'antd';
import { LoadingOutlined } from '@ant-design/icons';
import { getCurrentUser } from './services/api';
import UserMenu from './components/UserMenu';
import AdminDashboard from './pages/AdminDashboard';
import ClientProjects from './pages/ClientProjects';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import ProjectDetail from './pages/ProjectDetail';
import SmartProjectRoute from './components/SmartProjectRoute';
function App() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [darkMode, setDarkMode] = useState(() => {
const stored = localStorage.getItem('darkMode');
return stored === 'true';
});
// Set initial background colors immediately on component mount
useEffect(() => {
const htmlElement = document.documentElement;
const bodyElement = document.body;
// Set initial colors based on current darkMode state
const bgColor = darkMode ? '#181818' : '#f5f5f5';
htmlElement.style.backgroundColor = bgColor;
bodyElement.style.backgroundColor = bgColor;
if (darkMode) {
htmlElement.classList.add('dark-mode');
} else {
htmlElement.classList.remove('dark-mode');
}
}, []); // Run only once on mount
// Update HTML class and background color when darkMode changes
useEffect(() => {
const htmlElement = document.documentElement;
const bodyElement = document.body;
if (darkMode) {
htmlElement.classList.add('dark-mode');
// Set dark mode background colors to prevent white overscroll areas
htmlElement.style.backgroundColor = '#181818';
bodyElement.style.backgroundColor = '#181818';
} else {
htmlElement.classList.remove('dark-mode');
// Set light mode background colors
htmlElement.style.backgroundColor = '#ebebeb';
bodyElement.style.backgroundColor = '#f5f5f5';
}
}, [darkMode]);
useEffect(() => {
const token = localStorage.getItem('jwt');
if (token && !user) {
getCurrentUser().then(res => {
if (res.success) {
setUser(res.user);
} else {
setError(res.error?.message || 'Fehler beim Laden der Userdaten');
localStorage.removeItem('jwt');
}
}).catch(() => setError('Serverfehler')).finally(() => setLoading(false));
} else {
setLoading(false);
}
}, [user]);
if (!user) {
return (
<ConfigProvider theme={{ algorithm: darkMode ? theme.darkAlgorithm : theme.defaultAlgorithm }}>
<AntApp>
{loading ? (
<Spin indicator={<LoadingOutlined spin />} size="large" tip="Lade Preview..." fullscreen />
) : (
<>
{error && <Alert type="error" message={error} showIcon style={{ margin: 16 }} />}
<LoginPage onLogin={() => setUser(null)} />
</>
)}
</AntApp>
</ConfigProvider>
);
}
const handleLogout = () => {
// Entferne alle ads-overview-Caches beim Logout
Object.keys(localStorage).forEach(key => {
if (key.startsWith('ads-overview-')) {
localStorage.removeItem(key);
}
});
localStorage.removeItem('jwt');
setUser(null);
};
const handleToggleDarkMode = () => {
setDarkMode((prev) => {
localStorage.setItem('darkMode', !prev);
return !prev;
});
};
return (
<ConfigProvider
theme={{
token: {
colorPrimary: '#c792ff',
colorText: darkMode ? '#fff' : '#000',
colorBgBase: darkMode ? '#181818' : '#f5f5f5',
colorBgContainer: darkMode ? '#1f1f1f' : '#fff',
colorBorder: darkMode ? '#404040' : '#d9d9d9',
borderRadius: 4,
lineWidth: 0
},
components: {
Button: {
defaultBg: darkMode ? '#c792ff' : '#c792ff',
defaultHoverBg: darkMode ? '#edff5f' : '#edff5f',
defaultHoverColor: darkMode ? '#001f1e' : '#001f1e',
},
Tabs: {
itemColor: darkMode ? '#fff' : '#fff',
background: darkMode ? '#1f1f1f' : '#001f1e',
},
},
algorithm: darkMode ? theme.darkAlgorithm : theme.defaultAlgorithm
}}
>
<AntApp>
<Router>
<Layout style={{ minHeight: '100dvh' }}>
<Layout.Content style={{ padding: 0 }}>
<Routes>
{user.role === 'admin' ? (
<>
<Route path="/" element={<AdminDashboard user={user} darkMode={darkMode} onLogout={handleLogout} onToggleDarkMode={handleToggleDarkMode} />} />
{/* Smart URL Resolution für Admin-Zugriff auf Client-URLs - MUSS VOR der 3-Parameter Route stehen */}
<Route path=":project/:tab?" element={<SmartProjectRoute user={user} darkMode={darkMode} onLogout={handleLogout} onToggleDarkMode={handleToggleDarkMode} />} />
<Route path=":client/:project/:tab?" element={<ProjectDetail user={user} darkMode={darkMode} onLogout={handleLogout} onToggleDarkMode={handleToggleDarkMode} />} />
<Route path="*" element={<Navigate to="/" replace />} />
</>
) : (
<>
<Route path="/" element={<ClientProjects user={user} darkMode={darkMode} onLogout={handleLogout} onToggleDarkMode={handleToggleDarkMode} />} />
<Route path="/login" element={<LoginPage onLogin={() => setUser(null)} />} />
<Route path=":project/:tab?" element={<ProjectDetail user={user} darkMode={darkMode} onLogout={handleLogout} onToggleDarkMode={handleToggleDarkMode} />} />
{/* Catch-All-Route für nicht gefundene Pfade */}
<Route path="*" element={<Navigate to="/" replace />} />
</>
)}
</Routes>
</Layout.Content>
</Layout>
</Router>
</AntApp>
</ConfigProvider>
);
}
export default App;