security: clean repository without media files and sensitive data
- Removed area/ directory with 816MB of media files - Removed sensitive FTP credentials from Git history - Implemented .env.upload system for secure deployments - Added comprehensive .gitignore for future protection This commit represents a clean slate with all sensitive data removed.
This commit is contained in:
132
frontend/src/App.js
Normal file
132
frontend/src/App.js
Normal file
@@ -0,0 +1,132 @@
|
||||
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';
|
||||
});
|
||||
|
||||
|
||||
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: '100vh' }}>
|
||||
{/* Kein globaler Header mehr, Header wird ggf. in einzelnen Seiten eingebunden */}
|
||||
<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;
|
||||
Reference in New Issue
Block a user