System wird geladen...
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project Hub - Sektoren-Zentrale</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;600;800&display=swap');
:root {
--bg-main: #f1f5f9;
}
body {
font-family: 'Plus Jakarta Sans', sans-serif;
background-color: var(--bg-main);
color: #0f172a;
margin: 0;
padding: 0;
}
#loading-overlay {
background-color: #020617;
transition: opacity 0.5s ease;
}
.blur-md { filter: blur(24px); }
.hidden { display: none !important; }
.spinner {
border: 3px solid rgba(255, 255, 255, 0.1);
border-top: 3px solid #3b82f6;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
}
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
.project-card { cursor: pointer; transition: all 0.3s ease; }
.project-card:hover { transform: translateY(-4px); }
</style>
</head>
<body class="min-h-screen">
<!-- Lade-Bildschirm -->
<div id="loading-overlay" class="fixed inset-0 z-[100] flex items-center justify-center text-white">
<div class="text-center p-6">
<div class="spinner mx-auto mb-4"></div>
<p class="text-sm font-bold tracking-widest uppercase opacity-70">System wird geladen...</p>
<div id="init-error-container" class="mt-6 p-4 bg-red-900/30 border border-red-500/50 rounded-2xl hidden">
<p class="text-red-400 text-xs font-bold mb-2">KRITISCHER FEHLER</p>
<p id="init-error-msg" class="text-white text-[10px] font-medium"></p>
<button onclick="location.reload()" class="mt-4 text-[10px] bg-white/10 hover:bg-white/20 px-4 py-2 rounded-lg transition-all">Neu laden</button>
</div>
</div>
</div>
<!-- Login Bildschirm -->
<div id="login-screen" class="fixed inset-0 z-50 flex items-center justify-center bg-slate-950 px-4 hidden">
<div class="bg-white p-10 rounded-[3rem] shadow-2xl w-full max-w-md border border-white/20 relative z-10">
<div class="text-center mb-8">
<div class="bg-blue-600 w-16 h-16 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-xl">
<i data-lucide="shield-check" class="text-white w-8 h-8"></i>
</div>
<h1 class="text-3xl font-black text-slate-900 tracking-tighter mb-1 text-center">Project Hub</h1>
<p class="text-slate-400 font-bold text-[9px] tracking-[0.2em] uppercase text-center">Authentifizierung erforderlich</p>
</div>
<div class="space-y-4">
<div class="relative">
<input type="email" id="login-email" class="w-full pl-12 pr-4 py-4 bg-slate-50 border-2 border-slate-100 rounded-2xl outline-none focus:border-blue-500 transition-all font-bold" placeholder="E-Mail Adresse">
<i data-lucide="mail" class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-300 w-5 h-5"></i>
</div>
<div class="relative">
<input type="password" id="login-pw" class="w-full pl-12 pr-4 py-4 bg-slate-50 border-2 border-slate-100 rounded-2xl outline-none focus:border-blue-500 transition-all font-bold tracking-[0.2em]" placeholder="Passwort">
<i data-lucide="lock" class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-300 w-5 h-5"></i>
</div>
<p id="login-msg" class="hidden text-red-500 text-[11px] font-black text-center bg-red-50 py-3 rounded-xl border border-red-100"></p>
<button id="login-btn" onclick="window.handleLogin()" class="w-full bg-slate-900 hover:bg-black text-white font-black py-5 rounded-[1.5rem] transition-all shadow-xl flex items-center justify-center gap-3">
EINLOGGEN <i data-lucide="arrow-right" class="w-4 h-4 text-blue-400"></i>
</button>
</div>
</div>
</div>
<!-- Hauptanwendung -->
<div id="main-app" class="hidden">
<nav class="bg-white/80 backdrop-blur-xl border-b border-slate-200 sticky top-0 z-30">
<div class="max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="bg-blue-600 p-2 rounded-xl shadow-lg shadow-blue-500/20">
<i data-lucide="globe" class="text-white w-6 h-6"></i>
</div>
<span class="font-black text-xl tracking-tighter uppercase text-slate-900">Project<span class="text-blue-600">Hub</span></span>
</div>
<div class="flex items-center gap-6">
<div class="hidden md:flex flex-col items-end leading-none">
<span id="display-username" class="text-xs font-black text-slate-900 truncate max-w-[150px]">Nutzer</span>
<span class="text-[9px] font-black text-emerald-500 uppercase tracking-widest mt-1">Sicher verbunden</span>
</div>
<button onclick="window.handleLogout()" class="w-10 h-10 flex items-center justify-center bg-slate-50 text-slate-400 hover:text-red-500 rounded-xl border border-slate-100 transition-all">
<i data-lucide="log-out" class="w-4 h-4"></i>
</button>
</div>
</div>
</nav>
<main class="max-w-7xl mx-auto px-6 py-10">
<!-- Filter & Aktionen -->
<div class="bg-white p-4 rounded-[2.5rem] border border-slate-200 mb-12 flex flex-wrap gap-4 items-center justify-between shadow-sm">
<div class="flex flex-wrap gap-4 items-center">
<div class="flex items-center gap-2 px-4 py-2 bg-slate-50 rounded-xl border border-slate-100">
<i data-lucide="filter" class="w-3.5 h-3.5 text-blue-600"></i>
<span class="text-[10px] font-black text-slate-400 uppercase tracking-widest">Filter:</span>
</div>
<select id="filter-user" onchange="window.applyFilters()" class="bg-slate-50 border-2 border-slate-100 rounded-xl px-4 py-2.5 text-[10px] font-black outline-none focus:border-blue-500 transition-all cursor-pointer">
<option value="all">Alle Mitarbeiter</option>
</select>
<select id="filter-area" onchange="window.applyFilters()" class="bg-slate-50 border-2 border-slate-100 rounded-xl px-4 py-2.5 text-[10px] font-black outline-none focus:border-blue-500 transition-all cursor-pointer">
<option value="all">Alle Fachbereiche</option>
</select>
</div>
<button onclick="window.toggleModal('add-modal')" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-2xl text-[10px] font-black shadow-lg shadow-blue-500/20 flex items-center gap-2 active:scale-95 transition-all uppercase tracking-widest">
<i data-lucide="plus" class="w-4 h-4"></i> Mission Starten
</button>
</div>
<section class="mb-20">
<h2 class="text-2xl font-black text-slate-900 mb-8 flex items-center gap-3">
<span class="w-2 h-8 bg-blue-600 rounded-full"></span> Laufende Projekte
</h2>
<div id="active-projects" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8"></div>
</section>
<section class="opacity-40 grayscale border-t-2 border-dashed border-slate-200 pt-20">
<h2 class="text-2xl font-black text-slate-400 mb-8 flex items-center gap-3">
<i data-lucide="archive" class="w-6 h-6"></i> Archivierte Daten
</h2>
<div id="archive-projects" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8"></div>
</section>
</main>
</div>
<!-- Modal für Neues Projekt -->
<div id="add-modal" class="hidden fixed inset-0 z-50 bg-slate-950/90 backdrop-blur-md items-center justify-center p-4">
<div class="bg-white w-full max-w-2xl rounded-[3rem] shadow-2xl overflow-hidden max-h-[90vh] flex flex-col transform transition-all">
<div class="p-8 border-b border-slate-50 flex justify-between items-center bg-slate-50/50">
<div class="flex items-center gap-4">
<div class="bg-blue-600 p-3 rounded-2xl shadow-xl">
<i data-lucide="plus-circle" class="text-white w-6 h-6"></i>
</div>
<h2 class="text-2xl font-black text-slate-900 uppercase tracking-tighter">Mission anlegen</h2>
</div>
<button onclick="window.toggleModal('add-modal')" class="bg-white p-2 rounded-full shadow-sm border border-slate-100 text-slate-400 hover:text-slate-950 transition-all"><i data-lucide="x" class="w-6 h-6"></i></button>
</div>
<form onsubmit="window.handleCreateProject(event)" class="p-8 space-y-6 overflow-y-auto">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="space-y-1">
<label class="text-[10px] font-black text-slate-400 uppercase tracking-widest block ml-2">Bezeichnung</label>
<input name="name" required class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl outline-none focus:border-blue-500 font-bold" placeholder="z.B. Delta One">
</div>
<div class="space-y-1">
<label class="text-[10px] font-black text-slate-400 uppercase tracking-widest block ml-2">Fachbereich</label>
<select id="area-select" name="area" class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl outline-none focus:border-blue-500 font-bold cursor-pointer appearance-none"></select>
</div>
</div>
<div class="grid grid-cols-2 gap-6">
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Start</label><input type="date" name="startDate" required class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Abschluss</label><input type="date" name="endDate" required class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
</div>
<div class="grid grid-cols-2 gap-6">
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Budget (€)</label><input type="number" name="budget" required class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Abruf (€)</label><input type="number" name="money" class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
</div>
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Ziele & Beschreibung</label><textarea name="description" rows="3" class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-medium" placeholder="Parameter definieren..."></textarea></div>
<div class="p-5 bg-slate-900 rounded-3xl flex items-center justify-between cursor-pointer hover:bg-black transition-colors" onclick="const c = this.querySelector('input'); c.checked = !c.checked; window.togglePrivateFields(c, 'project-pw-field')">
<div class="flex items-center gap-3">
<div class="bg-blue-600/20 p-2 rounded-lg"><i data-lucide="shield-alert" class="text-blue-500 w-4 h-4"></i></div>
<span class="text-white text-[10px] font-black uppercase tracking-widest">Vertraulichkeitssperre</span>
</div>
<input type="checkbox" name="isPrivate" class="w-6 h-6 rounded-lg border-0 bg-slate-800 accent-blue-600" onclick="event.stopPropagation(); window.togglePrivateFields(this, 'project-pw-field')">
</div>
<div id="project-pw-field" class="hidden animate-in fade-in slide-in-from-top-4 duration-500">
<label class="text-[10px] font-black text-blue-500 uppercase block mb-3 ml-2">Sicherheitsschlüssel</label>
<input type="password" name="projectPassword" class="w-full p-4 bg-blue-50 border-2 border-blue-100 rounded-2xl font-black tracking-widest" placeholder="••••••••">
</div>
<div class="pt-4">
<button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-black py-5 rounded-[1.5rem] shadow-xl flex items-center justify-center gap-4 uppercase tracking-widest text-xs">Speichern <i data-lucide="save" class="w-5 h-5"></i></button>
</div>
</form>
</div>
</div>
<!-- Modal für Projektdetails & Bearbeiten -->
<div id="details-modal" class="hidden fixed inset-0 z-50 bg-slate-950/95 backdrop-blur-xl items-center justify-center p-4">
<div id="details-content-container" class="bg-white w-full max-w-3xl rounded-[3.5rem] shadow-2xl overflow-hidden max-h-[95vh] flex flex-col transform transition-all">
<!-- Inhalt wird dynamisch via JS gefüllt -->
</div>
</div>
<!-- JS Logik -->
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-app.js";
import { getFirestore, collection, addDoc, onSnapshot, doc, deleteDoc, updateDoc, serverTimestamp } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-firestore.js";
import { getAuth, signInWithEmailAndPassword, onAuthStateChanged, signOut } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-auth.js";
const firebaseConfig = {
apiKey: "AIzaSyBNAS4wsPMo_Sg4M5T9Zzi0HoTkwgz8-w8",
authDomain: "theapp-21711.firebaseapp.com",
projectId: "theapp-21711",
storageBucket: "theapp-21711.firebasestorage.app",
messagingSenderId: "113261889001",
appId: "1:113261889001:web:a78b931279e01e58b6b778"
};
const APP_ID = "theapp-21711";
let db, auth, projects = [], filterUser = "all", filterArea = "all";
const AREAS = [
"Militär (Drohnen)", "Militär (Infanterie)", "Militär (Logistik)", "Militär (Artillerie)", "Militär (Aufklärung)", "Militär (Marine)",
"Cyber-Abwehr", "KI-Kampfsysteme", "Luftraum-Überwachung", "Satelliten-Technik", "Elektronische Kampfführung", "Stealth-Technologie",
"Grenzschutz-Systeme", "Krisen-Kommunikation", "Taktische Analyse", "Spezial-Fahrzeuge", "Munitionsforschung", "Ballistik",
"Agrar-Technologie", "E-Mobility", "Smart City Lösungen", "Logistik (Global)", "Einzelhandel-KI", "Tourismus-Tech",
"Finanztechnologie (FinTech)", "Immobilien-Management", "Bildungstechnologie (EdTech)", "Lebensmittel-Sicherheit", "Automobilindustrie", "Schienenverkehr",
"Quanten-Computing", "KI-Grundlagenforschung", "Teilchenphysik", "Kernfusion", "Bio-Hacking", "Genomik", "Astrophysik", "Supraleiter", "Nanotechnologie", "Material-Entwicklung",
"Robotik (Medizin)", "Exoskelette", "Neurotechnologie", "Erneuerbare Energien", "Wasseraufbereitung", "Abfallwirtschaft", "Brückenbau", "Tunnelbohr-Technik", "Glasfaserausbau",
"5G/6G-Infrastruktur", "Katastrophenschutz", "Städteplanung", "Meeresreinigung", "Klimatechnologie", "Energie-Speichersysteme", "Gesundheitswesen", "Sozialmanagement",
"Öffentlicher Nahverkehr", "Kulturförderung", "E-Government", "Datenschutz-Systeme", "Rechtstechnologie (LawTech)", "Notfall-Medizin"
];
// System-Start
async function startSystem() {
try {
const app = initializeApp(firebaseConfig);
db = getFirestore(app);
auth = getAuth(app);
onAuthStateChanged(auth, (user) => {
const overlay = document.getElementById('loading-overlay');
if (overlay) overlay.style.opacity = '0';
setTimeout(() => overlay?.classList.add('hidden'), 500);
if (user) {
showApp();
loadProjects();
} else {
showLogin();
}
});
setupUI();
} catch (err) {
console.error("Firebase Init Fehler:", err);
const errBox = document.getElementById('init-error-container');
const errMsg = document.getElementById('init-error-msg');
if (errBox && errMsg) {
errMsg.innerText = err.message;
errBox.classList.remove('hidden');
}
}
}
function setupUI() {
const selects = ['area-select', 'filter-area'];
selects.forEach(id => {
const el = document.getElementById(id);
if (!el) return;
el.innerHTML = id === 'filter-area' ? '<option value="all">Alle Fachbereiche</option>' : '';
AREAS.sort().forEach(a => {
const o = document.createElement('option'); o.value = a; o.innerText = a; el.appendChild(o);
});
});
lucide.createIcons();
}
// Globale Handler
window.handleLogin = async () => {
const email = document.getElementById('login-email').value.trim();
const pw = document.getElementById('login-pw').value;
const errorEl = document.getElementById('login-msg');
const btn = document.getElementById('login-btn');
if (!email || !pw) return;
errorEl.classList.add('hidden');
btn.disabled = true; btn.innerText = "Verifizierung...";
try {
await signInWithEmailAndPassword(auth, email, pw);
} catch (err) {
errorEl.innerText = "Zugriff verweigert: " + err.message;
errorEl.classList.remove('hidden');
btn.disabled = false; btn.innerText = "SYSTEM BETRETEN";
}
};
window.handleLogout = () => signOut(auth).then(() => location.reload());
function showApp() {
document.getElementById('login-screen').classList.add('hidden');
document.getElementById('main-app').classList.remove('hidden');
document.getElementById('display-username').innerText = auth.currentUser.email;
lucide.createIcons();
}
function showLogin() {
document.getElementById('login-screen').classList.remove('hidden');
document.getElementById('main-app').classList.add('hidden');
lucide.createIcons();
}
function loadProjects() {
const q = collection(db, 'artifacts', APP_ID, 'public', 'data', 'projects');
onSnapshot(q, (snapshot) => {
projects = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
renderDashboard();
updateUserFilterDropdown();
}, (err) => {
console.error("Firestore Berechtigungsfehler:", err);
});
}
function renderDashboard() {
const activeList = document.getElementById('active-projects');
const archiveList = document.getElementById('archive-projects');
if(!activeList || !archiveList) return;
activeList.innerHTML = ''; archiveList.innerHTML = '';
const filtered = projects.filter(p => {
const userMatch = filterUser === "all" || p.creator === filterUser;
const areaMatch = filterArea === "all" || p.area === filterArea;
return userMatch && areaMatch;
}).sort((a,b) => new Date(a.endDate) - new Date(b.endDate));
filtered.forEach(p => {
const progress = calculateProgress(p.startDate, p.endDate);
const expired = isExpired(p.endDate);
const canDelete = p.creatorUid === auth.currentUser.uid;
const card = document.createElement('div');
card.className = "project-card bg-white border border-slate-200 rounded-[2rem] p-6 relative overflow-hidden shadow-sm";
card.onclick = () => window.openProjectDetails(p.id);
card.innerHTML = `
<div id="proj-container-${p.id}" class="relative">
${p.isPrivate ? `<div id="proj-lock-${p.id}" class="absolute inset-0 z-10 flex items-center justify-center bg-white/70 backdrop-blur-2xl cursor-pointer rounded-2xl" onclick="event.stopPropagation(); window.unlockProject('${p.id}')">
<div class="bg-slate-900 text-white px-5 py-2.5 rounded-xl flex items-center gap-2 shadow-2xl scale-95 hover:scale-100 transition-transform"><i data-lucide="lock" class="w-4 h-4 text-blue-400"></i><span class="text-[10px] font-black uppercase tracking-widest">Gesperrt</span></div>
</div>` : ''}
<div id="proj-content-${p.id}" class="${p.isPrivate ? 'filter blur-md select-none pointer-events-none' : ''}">
<div class="flex justify-between items-start mb-5">
<div class="flex-1 pr-4"><h3 class="text-lg font-black text-slate-900 leading-tight mb-2 truncate">${p.name}</h3><span class="text-[8px] bg-slate-950 text-white px-2 py-1 rounded-md font-black uppercase tracking-widest">${p.area}</span></div>
${canDelete ? `<button onclick="event.stopPropagation(); window.handleDeleteProject('${p.id}')" class="text-slate-300 hover:text-red-500 transition-all p-2 bg-slate-50 rounded-xl"><i data-lucide="trash-2" class="w-4 h-4"></i></button>` : ''}
</div>
<div class="space-y-4 mb-5">
<div class="flex justify-between items-center text-[9px] font-black text-slate-400 uppercase tracking-widest">
<div class="flex items-center gap-1.5"><i data-lucide="user" class="w-3 h-3 text-blue-500"></i> ${p.creator.split('@')[0]}</div>
<div class="flex items-center gap-1.5"><i data-lucide="calendar" class="w-3 h-3 text-slate-300"></i> ${new Date(p.endDate).toLocaleDateString('de-DE')}</div>
</div>
<div><div class="flex justify-between text-[9px] font-black text-slate-500 mb-1"><span>STATUS</span><span>${Math.round(progress)}%</span></div>
<div class="w-full bg-slate-100 h-2 rounded-full overflow-hidden p-0.5"><div class="bg-gradient-to-r from-blue-600 to-indigo-600 h-full rounded-full transition-all" style="width: ${progress}%"></div></div></div>
</div>
<div class="text-[10px] text-slate-500 font-medium leading-relaxed bg-white border border-slate-50 p-3 rounded-lg italic line-clamp-2">"${p.description || 'Keine Beschreibung.'}"</div>
</div>
</div>`;
if (expired) archiveList.appendChild(card); else activeList.appendChild(card);
});
lucide.createIcons();
}
// Utility Funktionen
function calculateProgress(s, e) {
const now = new Date(), start = new Date(s), end = new Date(e);
if (now < start) return 0; if (now > end) return 100;
return Math.min(100, Math.max(0, ((now - start) / (end - start)) * 100));
}
function isExpired(d) { return new Date().setHours(0,0,0,0) > new Date(d).setHours(0,0,0,0); }
window.toggleModal = (id) => { const m = document.getElementById(id); m?.classList.toggle('hidden'); m?.classList.toggle('flex'); };
window.togglePrivateFields = (cb, id) => document.getElementById(id)?.classList.toggle('hidden', !cb.checked);
window.applyFilters = () => { filterUser = document.getElementById('filter-user').value; filterArea = document.getElementById('filter-area').value; renderDashboard(); };
window.unlockProject = (id) => {
const p = projects.find(x => x.id === id);
const input = prompt("Sicherheitscode eingeben:");
if (input === p.projectPassword) {
document.getElementById(`proj-content-${id}`)?.classList.remove('filter', 'blur-md');
document.getElementById(`proj-lock-${id}`)?.remove();
} else if (input !== null) alert("Falscher Code.");
};
// --- Neu: Projektdetail & Edit Logik ---
window.openProjectDetails = (id) => {
const p = projects.find(x => x.id === id);
if (!p) return;
// Wenn privat und noch nicht entsperrt, erst entsperren (simuliert)
if (p.isPrivate && document.getElementById(`proj-lock-${id}`)) {
window.unlockProject(id);
return;
}
const container = document.getElementById('details-content-container');
const canEdit = p.creatorUid === auth.currentUser.uid;
container.innerHTML = `
<div class="p-8 border-b border-slate-50 flex justify-between items-center bg-slate-50/50">
<div class="flex items-center gap-4">
<div class="bg-blue-600 p-3 rounded-2xl shadow-xl"><i data-lucide="info" class="text-white w-6 h-6"></i></div>
<h2 class="text-2xl font-black text-slate-900 uppercase tracking-tighter">Projekt Übersicht</h2>
</div>
<button onclick="window.toggleModal('details-modal')" class="bg-white p-2 rounded-full shadow-sm border border-slate-100 text-slate-400 hover:text-slate-950 transition-all"><i data-lucide="x" class="w-6 h-6"></i></button>
</div>
<div id="project-details-body" class="p-10 space-y-8 overflow-y-auto">
<!-- Statische Ansicht -->
<div id="view-mode">
<div class="flex justify-between items-start mb-10">
<div class="space-y-4">
<h3 class="text-4xl font-black text-slate-900 leading-none">${p.name}</h3>
<div class="flex gap-2">
<span class="bg-slate-900 text-white px-3 py-1.5 rounded-lg text-[10px] font-black uppercase tracking-widest">${p.area}</span>
${p.isPrivate ? '<span class="bg-amber-100 text-amber-700 px-3 py-1.5 rounded-lg text-[10px] font-black uppercase tracking-widest">Vertraulich</span>' : ''}
</div>
</div>
<div class="text-right">
<p class="text-[11px] font-black text-slate-400 uppercase tracking-widest mb-1">Budgetierung</p>
<p class="text-2xl font-black text-blue-600">${p.budget.toLocaleString()} €</p>
<p class="text-xs font-bold text-slate-400">Genutzt: ${p.money.toLocaleString()} €</p>
</div>
</div>
<div class="grid grid-cols-2 gap-10 border-y border-slate-100 py-8 mb-8">
<div class="space-y-4">
<div>
<p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1">Verantwortlich</p>
<p class="text-sm font-bold text-slate-700">${p.creator}</p>
</div>
<div>
<p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1">Missionszeitraum</p>
<p class="text-sm font-bold text-slate-700">${new Date(p.startDate).toLocaleDateString()} - ${new Date(p.endDate).toLocaleDateString()}</p>
</div>
</div>
<div class="space-y-1">
<p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1">Fortschritt</p>
<div class="flex justify-between text-xs font-black text-blue-600 mb-2"><span>Status</span> <span>${Math.round(calculateProgress(p.startDate, p.endDate))}%</span></div>
<div class="w-full bg-slate-100 h-3 rounded-full overflow-hidden p-1 shadow-inner"><div class="bg-blue-600 h-full rounded-full" style="width: ${calculateProgress(p.startDate, p.endDate)}%"></div></div>
</div>
</div>
<div class="space-y-3">
<p class="text-[10px] font-black text-slate-400 uppercase tracking-widest">Detaillierte Mission & Ziele</p>
<div class="bg-slate-50 p-6 rounded-[2rem] text-slate-600 leading-relaxed font-medium italic">"${p.description || 'Keine Beschreibung vorhanden.'}"</div>
</div>
${canEdit ? `
<div class="pt-10 flex gap-4">
<button onclick="window.enterEditMode('${p.id}')" class="flex-1 bg-slate-900 text-white font-black py-5 rounded-2xl flex items-center justify-center gap-3 active:scale-95 transition-all uppercase tracking-widest text-xs"><i data-lucide="edit-3" class="w-4 h-4 text-blue-400"></i> Bearbeiten</button>
<button onclick="window.handleDeleteProject('${p.id}'); window.toggleModal('details-modal');" class="bg-red-50 text-red-600 font-black px-10 rounded-2xl border border-red-100 active:scale-95 transition-all uppercase tracking-widest text-xs">Löschen</button>
</div>
` : ''}
</div>
<!-- Editier Modus (Versteckt) -->
<div id="edit-mode" class="hidden">
<form onsubmit="window.handleUpdateProject(event, '${p.id}')" class="space-y-6">
<div class="grid grid-cols-2 gap-6">
<div class="space-y-1"><label class="text-[10px] font-black text-slate-400 uppercase tracking-widest block ml-2">Name</label><input name="name" value="${p.name}" required class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
<div class="space-y-1"><label class="text-[10px] font-black text-slate-400 uppercase tracking-widest block ml-2">Bereich</label><select name="area" id="edit-area-select" class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></select></div>
</div>
<div class="grid grid-cols-2 gap-6">
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Start</label><input type="date" name="startDate" value="${p.startDate}" required class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Ende</label><input type="date" name="endDate" value="${p.endDate}" required class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
</div>
<div class="grid grid-cols-2 gap-6">
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Budget (€)</label><input type="number" name="budget" value="${p.budget}" required class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Abruf (€)</label><input type="number" name="money" value="${p.money || 0}" class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-bold"></div>
</div>
<div><label class="text-[10px] font-black text-slate-400 uppercase block ml-2">Beschreibung</label><textarea name="description" rows="3" class="w-full p-4 bg-slate-50 border-2 border-slate-100 rounded-2xl font-medium">${p.description || ''}</textarea></div>
<div class="pt-4 flex gap-4">
<button type="submit" class="flex-1 bg-blue-600 text-white font-black py-5 rounded-2xl shadow-xl flex items-center justify-center gap-3 active:scale-95 transition-all uppercase tracking-widest text-xs">Änderungen speichern</button>
<button type="button" onclick="window.exitEditMode()" class="bg-slate-100 text-slate-500 font-black px-10 rounded-2xl active:scale-95 transition-all uppercase tracking-widest text-xs">Abbrechen</button>
</div>
</form>
</div>
</div>
`;
// Sektoren im Edit-Dropdown füllen
const select = document.getElementById('edit-area-select');
if(select) {
AREAS.sort().forEach(a => {
const o = document.createElement('option'); o.value = a; o.innerText = a;
if(a === p.area) o.selected = true;
select.appendChild(o);
});
}
window.toggleModal('details-modal');
lucide.createIcons();
};
window.enterEditMode = () => {
document.getElementById('view-mode').classList.add('hidden');
document.getElementById('edit-mode').classList.remove('hidden');
};
window.exitEditMode = () => {
document.getElementById('view-mode').classList.remove('hidden');
document.getElementById('edit-mode').classList.add('hidden');
};
window.handleUpdateProject = async (e, id) => {
e.preventDefault();
const fd = new FormData(e.target);
const updateData = {
name: fd.get('name'),
area: fd.get('area'),
startDate: fd.get('startDate'),
endDate: fd.get('endDate'),
budget: parseFloat(fd.get('budget')) || 0,
money: parseFloat(fd.get('money')) || 0,
description: fd.get('description'),
updatedAt: serverTimestamp()
};
try {
const projectRef = doc(db, 'artifacts', APP_ID, 'public', 'data', 'projects', id);
await updateDoc(projectRef, updateData);
window.toggleModal('details-modal');
} catch (err) {
alert("Fehler beim Aktualisieren: " + err.message);
}
};
window.handleCreateProject = async (e) => {
e.preventDefault();
const fd = new FormData(e.target);
const isPrivate = fd.get('isPrivate') === 'on';
const proj = {
name: fd.get('name'), creator: auth.currentUser.email, creatorUid: auth.currentUser.uid,
startDate: fd.get('startDate'), endDate: fd.get('endDate'), budget: parseFloat(fd.get('budget')) || 0,
money: parseFloat(fd.get('money')) || 0, description: fd.get('description'), area: fd.get('area'),
isPrivate, projectPassword: isPrivate ? fd.get('projectPassword') : null, createdAt: serverTimestamp()
};
try {
await addDoc(collection(db, 'artifacts', APP_ID, 'public', 'data', 'projects'), proj);
e.target.reset();
window.toggleModal('add-modal');
} catch (err) {
alert("Fehler beim Speichern: " + err.message);
}
};
window.handleDeleteProject = async (id) => {
if (confirm("Projekt dauerhaft löschen?")) {
try { await deleteDoc(doc(db, 'artifacts', APP_ID, 'public', 'data', 'projects', id)); }
catch (err) { alert("Löschen fehlgeschlagen."); }
}
};
function updateUserFilterDropdown() {
const s = document.getElementById('filter-user');
if(!s) return;
const cur = s.value;
const users = [...new Set(projects.map(p => p.creator))];
s.innerHTML = '<option value="all">Alle Mitarbeiter</option>';
users.sort().forEach(u => { const o = document.createElement('option'); o.value = o.innerText = u; s.appendChild(o); });
s.value = cur;
}
// Starten, sobald das DOM bereit ist
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', startSystem);
} else {
startSystem();
}
</script>
</body>
</html>