- 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
167 lines
6.1 KiB
JavaScript
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;
|