mirror of
https://github.com/donpat1to/Schichtenplaner.git
synced 2025-12-01 06:55:45 +01:00
changing repo structure
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// frontend/src/App.tsx - KORRIGIERT MIT LAYOUT
|
||||
// frontend/src/App.tsx - UPDATED WITH FOOTER LINKS
|
||||
import React from 'react';
|
||||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
||||
@@ -16,6 +16,15 @@ import Settings from './pages/Settings/Settings';
|
||||
import Help from './pages/Help/Help';
|
||||
import Setup from './pages/Setup/Setup';
|
||||
|
||||
// Footer Link Pages
|
||||
import Contact from '../../premium/frontendPRO/src/componentsPRO/FooterLinksPro/Contact/Contact';
|
||||
import FAQ from './components/Layout/FooterLinks/FAQ/FAQ';
|
||||
import Privacy from '../../premium/frontendPRO/src/componentsPRO/FooterLinksPro/Privacy/Privacy';
|
||||
import Imprint from '../../premium/frontendPRO/src/componentsPRO/FooterLinksPro/Imprint/Imprint';
|
||||
import Terms from '../../premium/frontendPRO/src/componentsPRO/FooterLinksPro/Terms/Terms';
|
||||
import About from './components/Layout/FooterLinks/About/About';
|
||||
import Features from './components/Layout/FooterLinks/Features/Features';
|
||||
|
||||
// Protected Route Component
|
||||
const ProtectedRoute: React.FC<{ children: React.ReactNode; roles?: string[] }> = ({
|
||||
children,
|
||||
@@ -49,6 +58,22 @@ const ProtectedRoute: React.FC<{ children: React.ReactNode; roles?: string[] }>
|
||||
return <Layout>{children}</Layout>;
|
||||
};
|
||||
|
||||
// Public Route Component (without Layout for footer pages)
|
||||
const PublicRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const { user, loading } = useAuth();
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ textAlign: 'center', padding: '40px' }}>
|
||||
<div>⏳ Lade Anwendung...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// If user is logged in, show with layout, otherwise without
|
||||
return user ? <Layout>{children}</Layout> : <>{children}</>;
|
||||
};
|
||||
|
||||
// Main App Content
|
||||
const AppContent: React.FC = () => {
|
||||
const { loading, needsSetup, user } = useAuth();
|
||||
@@ -80,6 +105,7 @@ const AppContent: React.FC = () => {
|
||||
console.log('✅ Showing protected routes for user:', user.email);
|
||||
return (
|
||||
<Routes>
|
||||
{/* Protected Routes (require login) */}
|
||||
<Route path="/" element={
|
||||
<ProtectedRoute>
|
||||
<Dashboard />
|
||||
@@ -120,7 +146,48 @@ const AppContent: React.FC = () => {
|
||||
<Help />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
|
||||
{/* Public Footer Link Pages (accessible without login, but show layout if logged in) */}
|
||||
<Route path="/contact" element={
|
||||
<PublicRoute>
|
||||
<Contact />
|
||||
</PublicRoute>
|
||||
} />
|
||||
<Route path="/faq" element={
|
||||
<PublicRoute>
|
||||
<FAQ />
|
||||
</PublicRoute>
|
||||
} />
|
||||
<Route path="/privacy" element={
|
||||
<PublicRoute>
|
||||
<Privacy />
|
||||
</PublicRoute>
|
||||
} />
|
||||
<Route path="/imprint" element={
|
||||
<PublicRoute>
|
||||
<Imprint />
|
||||
</PublicRoute>
|
||||
} />
|
||||
<Route path="/terms" element={
|
||||
<PublicRoute>
|
||||
<Terms />
|
||||
</PublicRoute>
|
||||
} />
|
||||
<Route path="/about" element={
|
||||
<PublicRoute>
|
||||
<About />
|
||||
</PublicRoute>
|
||||
} />
|
||||
<Route path="/features" element={
|
||||
<PublicRoute>
|
||||
<Features />
|
||||
</PublicRoute>
|
||||
} />
|
||||
|
||||
{/* Auth Routes */}
|
||||
<Route path="/login" element={<Login />} />
|
||||
|
||||
{/* Catch-all Route */}
|
||||
<Route path="*" element={
|
||||
<ProtectedRoute>
|
||||
<Dashboard />
|
||||
|
||||
76
frontend/src/components/Layout/FooterLinks/About/About.tsx
Normal file
76
frontend/src/components/Layout/FooterLinks/About/About.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
// frontend/src/pages/About/About.tsx
|
||||
import React from 'react';
|
||||
|
||||
const About: React.FC = () => {
|
||||
return (
|
||||
<div style={{ padding: '40px 20px', maxWidth: '800px', margin: '0 auto' }}>
|
||||
<h1>👨💻 Über uns</h1>
|
||||
|
||||
<div style={{
|
||||
backgroundColor: 'white',
|
||||
borderRadius: '12px',
|
||||
padding: '30px',
|
||||
marginTop: '20px',
|
||||
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
|
||||
border: '1px solid #e0e0e0',
|
||||
lineHeight: 1.6
|
||||
}}>
|
||||
<h2 style={{ color: '#2c3e50' }}>Unser Team</h2>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', marginTop: '20px', padding: '20px', backgroundColor: '#f8f9fa', borderRadius: '8px' }}>
|
||||
<div style={{ marginRight: '20px' }}>
|
||||
<div style={{
|
||||
width: '80px',
|
||||
height: '80px',
|
||||
backgroundColor: '#3498db',
|
||||
borderRadius: '50%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: 'white',
|
||||
fontSize: '2rem',
|
||||
fontWeight: 'bold'
|
||||
}}>
|
||||
P
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style={{ color: '#2c3e50', margin: '0 0 5px 0' }}>Patrick</h3>
|
||||
<p style={{ color: '#6c757d', margin: '0 0 10px 0' }}>
|
||||
Full-Stack Developer & Projektleiter
|
||||
</p>
|
||||
<p style={{ margin: 0, fontSize: '0.9rem' }}>
|
||||
GitHub: <a href="https://github.com/donpat1to" style={{ color: '#3498db' }}>donpat1to</a><br/>
|
||||
E-Mail: <a href="mailto:dev.patrick@inca-vikingo.de" style={{ color: '#3498db' }}>dev.patrick@inca-vikingo.de</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 style={{ color: '#3498db', marginTop: '30px' }}>🚀 Unsere Mission</h3>
|
||||
<p>
|
||||
Wir entwickeln intelligente Lösungen für die Personalplanung,
|
||||
die Zeit sparen und faire Schichtverteilung gewährleisten.
|
||||
</p>
|
||||
|
||||
<h3 style={{ color: '#3498db', marginTop: '25px' }}>💻 Technologie</h3>
|
||||
<p>
|
||||
Unser Stack umfasst moderne Technologien:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Frontend: React, TypeScript</li>
|
||||
<li>Backend: Node.js, Express</li>
|
||||
<li>Optimierung: Google OR-Tools CP-SAT</li>
|
||||
<li>Datenbank: SQLite/PostgreSQL</li>
|
||||
</ul>
|
||||
|
||||
<h3 style={{ color: '#3498db', marginTop: '25px' }}>📈 Entwicklung</h3>
|
||||
<p>
|
||||
Schichtenplaner wird kontinuierlich weiterentwickelt und
|
||||
basiert auf Feedback unserer Nutzer.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default About;
|
||||
103
frontend/src/components/Layout/FooterLinks/FAQ/FAQ.tsx
Normal file
103
frontend/src/components/Layout/FooterLinks/FAQ/FAQ.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
// frontend/src/pages/FAQ/FAQ.tsx
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const FAQ: React.FC = () => {
|
||||
const [openItems, setOpenItems] = useState<number[]>([]);
|
||||
|
||||
const toggleItem = (index: number) => {
|
||||
setOpenItems(prev =>
|
||||
prev.includes(index)
|
||||
? prev.filter(i => i !== index)
|
||||
: [...prev, index]
|
||||
);
|
||||
};
|
||||
|
||||
const faqItems = [
|
||||
{
|
||||
question: "Wie funktioniert der Scheduling-Algorithmus?",
|
||||
answer: "Unser System verwendet Google's OR-Tools CP-SAT Solver, um optimale Schichtzuweisungen basierend auf Verfügbarkeiten, Vertragstypen und Geschäftsregeln zu berechnen."
|
||||
},
|
||||
{
|
||||
question: "Was bedeuten die Verfügbarkeits-Level 1, 2 und 3?",
|
||||
answer: "Level 1: Bevorzugt (Mitarbeiter möchte diese Schicht), Level 2: Verfügbar (kann arbeiten), Level 3: Nicht verfügbar (kann nicht arbeiten)."
|
||||
},
|
||||
{
|
||||
question: "Wie werden Vertragstypen berücksichtigt?",
|
||||
answer: "Kleine Verträge: 1 Schicht pro Woche, Große Verträge: 2 Schichten pro Woche. Das System weist genau diese Anzahl zu."
|
||||
},
|
||||
{
|
||||
question: "Kann ich manuelle Anpassungen vornehmen?",
|
||||
answer: "Ja, nach dem automatischen Scheduling können Sie Zuordnungen manuell anpassen und optimieren."
|
||||
},
|
||||
{
|
||||
question: "Was passiert bei unterbesetzten Schichten?",
|
||||
answer: "Das System zeigt eine Warnung an und versucht, alternative Lösungen zu finden. In kritischen Fällen müssen manuelle Anpassungen vorgenommen werden."
|
||||
},
|
||||
{
|
||||
question: "Wie lange dauert die Planungserstellung?",
|
||||
answer: "Typischerweise 30-105 Sekunden, abhängig von der Anzahl der Mitarbeiter und Schichten."
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ padding: '40px 20px', maxWidth: '800px', margin: '0 auto' }}>
|
||||
<h1>❓ Häufige Fragen (FAQ)</h1>
|
||||
|
||||
<div style={{
|
||||
backgroundColor: 'white',
|
||||
borderRadius: '12px',
|
||||
marginTop: '20px',
|
||||
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
|
||||
border: '1px solid #e0e0e0'
|
||||
}}>
|
||||
{faqItems.map((item, index) => (
|
||||
<div key={index} style={{
|
||||
borderBottom: index < faqItems.length - 1 ? '1px solid #e0e0e0' : 'none',
|
||||
padding: '20px 30px'
|
||||
}}>
|
||||
<div
|
||||
onClick={() => toggleItem(index)}
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<h3 style={{
|
||||
color: '#2c3e50',
|
||||
margin: 0,
|
||||
fontSize: '1.1rem'
|
||||
}}>
|
||||
{item.question}
|
||||
</h3>
|
||||
<span style={{
|
||||
fontSize: '1.5rem',
|
||||
color: '#3498db',
|
||||
transform: openItems.includes(index) ? 'rotate(45deg)' : 'rotate(0)',
|
||||
transition: 'transform 0.2s ease'
|
||||
}}>
|
||||
+
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{openItems.includes(index) && (
|
||||
<div style={{
|
||||
marginTop: '15px',
|
||||
padding: '15px',
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRadius: '8px',
|
||||
color: '#6c757d',
|
||||
lineHeight: 1.6
|
||||
}}>
|
||||
{item.answer}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FAQ;
|
||||
111
frontend/src/components/Layout/FooterLinks/Features/Features.tsx
Normal file
111
frontend/src/components/Layout/FooterLinks/Features/Features.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
// frontend/src/pages/Features/Features.tsx
|
||||
import React from 'react';
|
||||
|
||||
const Features: React.FC = () => {
|
||||
const features = [
|
||||
{
|
||||
icon: "🤖",
|
||||
title: "Automatisches Scheduling",
|
||||
description: "Intelligenter Algorithmus erstellt optimale Schichtpläne basierend auf Verfügbarkeiten und Regeln"
|
||||
},
|
||||
{
|
||||
icon: "⚡",
|
||||
title: "Schnelle Berechnung",
|
||||
description: "Google OR-Tools CP-SAT Solver findet Lösungen in 30-105 Sekunden"
|
||||
},
|
||||
{
|
||||
icon: "👥",
|
||||
title: "Flexible Regelkonfiguration",
|
||||
description: "Anpassbare Geschäftsregeln für Trainee-Betreuung, Alleinarbeit, Vertragstypen"
|
||||
},
|
||||
{
|
||||
icon: "📊",
|
||||
title: "Echtzeit-Validierung",
|
||||
description: "Automatische Erkennung von Regelverletzungen und Konflikten"
|
||||
},
|
||||
{
|
||||
icon: "🔒",
|
||||
title: "Lokale Datenspeicherung",
|
||||
description: "Alle Daten bleiben in Ihrer Infrastruktur - volle Kontrolle und Datenschutz"
|
||||
},
|
||||
{
|
||||
icon: "🎯",
|
||||
title: "Präferenz-basiert",
|
||||
description: "Berücksichtigt Mitarbeiterwünsche für höhere Zufriedenheit"
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ padding: '40px 20px', maxWidth: '1000px', margin: '0 auto' }}>
|
||||
<h1>✨ Funktionen</h1>
|
||||
|
||||
<div style={{
|
||||
backgroundColor: 'white',
|
||||
borderRadius: '12px',
|
||||
padding: '30px',
|
||||
marginTop: '20px',
|
||||
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
|
||||
border: '1px solid #e0e0e0'
|
||||
}}>
|
||||
<h2 style={{ color: '#2c3e50', textAlign: 'center', marginBottom: '40px' }}>
|
||||
Alles, was Sie für die perfekte Schichtplanung benötigen
|
||||
</h2>
|
||||
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
|
||||
gap: '30px'
|
||||
}}>
|
||||
{features.map((feature, index) => (
|
||||
<div key={index} style={{
|
||||
padding: '25px',
|
||||
backgroundColor: '#f8f9fa',
|
||||
borderRadius: '12px',
|
||||
border: '2px solid #e9ecef',
|
||||
textAlign: 'center',
|
||||
transition: 'transform 0.2s ease, box-shadow 0.2s ease'
|
||||
}}>
|
||||
<div style={{
|
||||
fontSize: '3rem',
|
||||
marginBottom: '15px'
|
||||
}}>
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 style={{
|
||||
color: '#2c3e50',
|
||||
margin: '0 0 15px 0'
|
||||
}}>
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p style={{
|
||||
color: '#6c757d',
|
||||
margin: 0,
|
||||
lineHeight: 1.5
|
||||
}}>
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
marginTop: '40px',
|
||||
padding: '25px',
|
||||
backgroundColor: '#e8f4fd',
|
||||
borderRadius: '12px',
|
||||
border: '2px solid #b8d4f0',
|
||||
textAlign: 'center'
|
||||
}}>
|
||||
<h3 style={{ color: '#2980b9', margin: '0 0 15px 0' }}>
|
||||
🚀 Starter Sie durch
|
||||
</h3>
|
||||
<p style={{ color: '#2c3e50', margin: 0 }}>
|
||||
Erstellen Sie Ihren ersten optimierten Schichtplan in wenigen Minuten.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Features;
|
||||
Reference in New Issue
Block a user