Latest Version

This commit is contained in:
MarcWieland
2026-08-05 18:51:37 +02:00
parent de3bce8dcc
commit 3600036833
29 changed files with 3932 additions and 849 deletions
+808
View File
@@ -0,0 +1,808 @@
import React, { useState, useEffect } from 'react';
import {
Wrench,
Lock,
CheckCircle2,
AlertTriangle,
Clock,
Calendar,
FileText,
Package,
Send,
Sparkles,
ArrowRight,
LogOut,
ChevronRight,
ShieldCheck,
Check
} from 'lucide-react';
import { portalService, PortalProjectDetails } from '../services/portalService';
interface CustomerPortalViewProps {
initialCode?: string;
initialPin?: string;
}
export const CustomerPortalView: React.FC<CustomerPortalViewProps> = ({ initialCode, initialPin }) => {
const [accessCode, setAccessCode] = useState(initialCode || '');
const [accessPin, setAccessPin] = useState(initialPin || '');
const [isLoading, setIsLoading] = useState(false);
const [errorMsg, setErrorMsg] = useState<string | null>(null);
const [projectData, setProjectData] = useState<PortalProjectDetails | null>(null);
const [activeSubTab, setActiveSubTab] = useState<'progress' | 'booking' | 'parts' | 'docs'>('progress');
// Booking Form State
const [selectedDate, setSelectedDate] = useState('2026-08-11');
const [selectedSlot, setSelectedSlot] = useState('10:00 - 11:30 Uhr');
const [bookingNote, setBookingNote] = useState('');
const [bookingSuccess, setBookingSuccess] = useState(false);
const [isSubmittingBooking, setIsSubmittingBooking] = useState(false);
useEffect(() => {
if (initialCode && initialPin) {
handleLogin(initialCode, initialPin);
}
}, [initialCode, initialPin]);
const handleLogin = async (codeToUse?: string, pinToUse?: string) => {
const code = codeToUse || accessCode;
const pin = pinToUse || accessPin;
if (!code.trim() || !pin.trim()) {
setErrorMsg('Bitte gib den Projekt-Code und die PIN ein.');
return;
}
setIsLoading(true);
setErrorMsg(null);
const details = await portalService.verifyPortalAccess(code, pin);
setIsLoading(false);
if (details) {
setProjectData(details);
} else {
setErrorMsg('Ungültige Projekt-ID oder PIN. Bitte überprüfe deine Eingabe.');
}
};
const handleDemoLogin = (type: 'on_track' | 'delay') => {
const code = type === 'on_track' ? 'PRJ-8392' : 'PRJ-DELAY';
const pin = '749201';
setAccessCode(code);
setAccessPin(pin);
handleLogin(code, pin);
};
const handleBookAppointment = async (e: React.FormEvent) => {
e.preventDefault();
if (!projectData) return;
setIsSubmittingBooking(true);
await portalService.bookAppointmentSlot(
projectData.order.id,
projectData.customer.id,
selectedDate,
selectedSlot,
bookingNote
);
setIsSubmittingBooking(false);
setBookingSuccess(true);
// Refresh project details to show new changelog
const updated = await portalService.verifyPortalAccess(projectData.order.accessCode!, projectData.order.accessPin!);
if (updated) setProjectData(updated);
setTimeout(() => setBookingSuccess(false), 4000);
};
// Render Login Screen if not logged into a project
if (!projectData) {
return (
<div style={{
minHeight: '100vh',
backgroundColor: '#0f172a',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '24px',
color: '#f8fafc',
fontFamily: 'system-ui, -apple-system, sans-serif'
}}>
<div style={{
width: '100%',
maxWidth: '460px',
backgroundColor: '#1e293b',
borderRadius: '16px',
border: '1px solid #334155',
boxShadow: '0 25px 50px -12px rgba(0,0,0,0.5)',
padding: '36px 32px'
}}>
{/* Header */}
<div style={{ textAlign: 'center', marginBottom: '28px' }}>
<div style={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: '56px',
height: '56px',
borderRadius: '14px',
backgroundColor: 'rgba(2, 132, 199, 0.15)',
border: '1px solid rgba(2, 132, 199, 0.3)',
marginBottom: '16px'
}}>
<Wrench size={30} color="#38bdf8" />
</div>
<h2 style={{ margin: 0, fontSize: '1.45rem', fontWeight: 800 }}>Kundenportal</h2>
<p style={{ margin: '6px 0 0 0', fontSize: '0.88rem', color: '#94a3b8' }}>
Echtzeit-Projektstatus & Terminbuchung
</p>
</div>
{errorMsg && (
<div style={{
backgroundColor: 'rgba(239, 68, 68, 0.15)',
border: '1px solid rgba(239, 68, 68, 0.4)',
color: '#fca5a5',
padding: '12px 14px',
borderRadius: '10px',
fontSize: '0.85rem',
marginBottom: '20px'
}}>
{errorMsg}
</div>
)}
<form onSubmit={(e) => { e.preventDefault(); handleLogin(); }} style={{ display: 'flex', flexDirection: 'column', gap: '18px' }}>
<div>
<label style={{ display: 'block', fontSize: '0.83rem', fontWeight: 600, color: '#cbd5e1', marginBottom: '6px' }}>
Projekt-Code / Zugangs-ID
</label>
<div style={{ position: 'relative' }}>
<Lock size={18} color="#64748b" style={{ position: 'absolute', left: '14px', top: '50%', transform: 'translateY(-50%)' }} />
<input
type="text"
placeholder="z.B. PRJ-8392"
value={accessCode}
onChange={(e) => setAccessCode(e.target.value)}
style={{
width: '100%',
padding: '12px 14px 12px 42px',
backgroundColor: '#0f172a',
border: '1px solid #334155',
borderRadius: '10px',
color: '#ffffff',
fontSize: '0.95rem',
boxSizing: 'border-box',
outline: 'none',
fontWeight: 600
}}
/>
</div>
</div>
<div>
<label style={{ display: 'block', fontSize: '0.83rem', fontWeight: 600, color: '#cbd5e1', marginBottom: '6px' }}>
Sicherheits-PIN
</label>
<div style={{ position: 'relative' }}>
<ShieldCheck size={18} color="#64748b" style={{ position: 'absolute', left: '14px', top: '50%', transform: 'translateY(-50%)' }} />
<input
type="password"
placeholder="z.B. 749201"
value={accessPin}
onChange={(e) => setAccessPin(e.target.value)}
style={{
width: '100%',
padding: '12px 14px 12px 42px',
backgroundColor: '#0f172a',
border: '1px solid #334155',
borderRadius: '10px',
color: '#ffffff',
fontSize: '0.95rem',
boxSizing: 'border-box',
outline: 'none',
letterSpacing: '2px',
fontWeight: 600
}}
/>
</div>
</div>
<button
type="submit"
disabled={isLoading}
className="btn-primary-cta"
style={{
width: '100%',
padding: '13px',
fontSize: '0.95rem',
justifyContent: 'center',
marginTop: '6px'
}}
>
<span>{isLoading ? 'Prüfe Zugangsdaten...' : 'Projekt-Status Einsehen'}</span>
<ArrowRight size={18} />
</button>
</form>
{/* Quick Demo Section */}
<div style={{
marginTop: '28px',
paddingTop: '20px',
borderTop: '1px solid #334155',
textAlign: 'center'
}}>
<div style={{ fontSize: '0.78rem', color: '#64748b', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: '12px' }}>
Quick Demo-Zugänge zum Testen
</div>
<div style={{ display: 'flex', gap: '10px' }}>
<button
type="button"
onClick={() => handleDemoLogin('on_track')}
style={{
flex: 1,
padding: '9px 10px',
borderRadius: '8px',
backgroundColor: 'rgba(34, 197, 94, 0.12)',
border: '1px solid rgba(34, 197, 94, 0.3)',
color: '#4ade80',
fontSize: '0.78rem',
fontWeight: 600,
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '6px'
}}
>
<CheckCircle2 size={14} />
<span>🟢 Demo (On Track)</span>
</button>
<button
type="button"
onClick={() => handleDemoLogin('delay')}
style={{
flex: 1,
padding: '9px 10px',
borderRadius: '8px',
backgroundColor: 'rgba(245, 158, 11, 0.12)',
border: '1px solid rgba(245, 158, 11, 0.3)',
color: '#fbbf24',
fontSize: '0.78rem',
fontWeight: 600,
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '6px'
}}
>
<AlertTriangle size={14} />
<span>🟠 Demo (Verzögerung)</span>
</button>
</div>
</div>
</div>
</div>
);
}
// Active Project Dashboard View
const { order, customer, changelogs, attachments, installedParts } = projectData;
const isDelay = order.healthStatus === 'delay' || order.healthStatus === 'critical';
return (
<div style={{
minHeight: '100vh',
backgroundColor: 'var(--bg-app, #0f172a)',
color: 'var(--text-primary, #f8fafc)',
padding: '24px 16px',
boxSizing: 'border-box'
}}>
<div style={{ maxWidth: '960px', margin: '0 auto', display: 'flex', flexDirection: 'column', gap: '20px' }}>
{/* Top Navbar */}
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '14px 20px',
backgroundColor: 'var(--bg-card, #1e293b)',
borderRadius: '14px',
border: '1px solid var(--border-color, #334155)'
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<div style={{
width: '38px',
height: '38px',
borderRadius: '10px',
backgroundColor: '#0284c7',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#ffffff'
}}>
<Wrench size={20} />
</div>
<div>
<div style={{ fontSize: '1rem', fontWeight: 800 }}>Handwerksfreund Kundenportal</div>
<div style={{ fontSize: '0.78rem', color: 'var(--text-muted, #94a3b8)' }}>
Projekt-Code: <strong style={{ color: '#38bdf8' }}>{order.accessCode}</strong>
</div>
</div>
</div>
<button
onClick={() => setProjectData(null)}
style={{
padding: '8px 14px',
borderRadius: '8px',
backgroundColor: 'rgba(239, 68, 68, 0.1)',
border: '1px solid rgba(239, 68, 68, 0.3)',
color: '#fca5a5',
fontSize: '0.82rem',
fontWeight: 600,
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '6px'
}}
>
<LogOut size={16} />
<span>Abmelden</span>
</button>
</div>
{/* Health Status Banner */}
<div style={{
padding: '24px',
borderRadius: '16px',
background: isDelay
? 'linear-gradient(135deg, rgba(245, 158, 11, 0.2) 0%, rgba(217, 119, 6, 0.1) 100%)'
: 'linear-gradient(135deg, rgba(34, 197, 94, 0.2) 0%, rgba(16, 185, 129, 0.1) 100%)',
border: isDelay
? '1.5px solid rgba(245, 158, 11, 0.5)'
: '1.5px solid rgba(34, 197, 94, 0.5)',
display: 'flex',
flexDirection: 'column',
gap: '16px'
}}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: '12px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<div style={{
width: '46px',
height: '46px',
borderRadius: '12px',
backgroundColor: isDelay ? '#f59e0b' : '#22c55e',
color: '#ffffff',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: isDelay ? '0 0 15px rgba(245, 158, 11, 0.4)' : '0 0 15px rgba(34, 197, 94, 0.4)'
}}>
{isDelay ? <AlertTriangle size={26} /> : <CheckCircle2 size={26} />}
</div>
<div>
<div style={{
fontSize: '0.78rem',
fontWeight: 700,
textTransform: 'uppercase',
letterSpacing: '1px',
color: isDelay ? '#fbbf24' : '#4ade80'
}}>
PROJEKT-STATUS STATUS-CHECK
</div>
<h2 style={{ margin: 0, fontSize: '1.35rem', fontWeight: 800, color: 'var(--text-primary, #ffffff)' }}>
{isDelay ? 'Verzögerung im Ablauf (Delay)' : '🟢 Projekt ist voll im Zeitplan (On Track)'}
</h2>
</div>
</div>
<div style={{
backgroundColor: 'rgba(15, 23, 42, 0.6)',
padding: '8px 16px',
borderRadius: '10px',
border: '1px solid rgba(255,255,255,0.1)',
display: 'flex',
alignItems: 'center',
gap: '8px',
fontSize: '0.85rem'
}}>
<Calendar size={16} color="#38bdf8" />
<span>Voraussichtliche Fertigstellung: <strong style={{ color: '#38bdf8' }}>{order.expectedCompletionDate || '12.08.2026'}</strong></span>
</div>
</div>
{/* Delay Explanation Notice */}
{isDelay && order.delayReason && (
<div style={{
backgroundColor: 'rgba(15, 23, 42, 0.7)',
padding: '14px 16px',
borderRadius: '10px',
fontSize: '0.9rem',
color: '#fef08a',
lineHeight: '1.5',
borderLeft: '4px solid #f59e0b'
}}>
<strong>Transparenz-Hinweis von deinem Handwerker:</strong> {order.delayReason}
</div>
)}
{/* Visual Progress Bar */}
<div>
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: '0.88rem', fontWeight: 700, marginBottom: '8px' }}>
<span>Gesamter Baufortschritt</span>
<span style={{ color: '#38bdf8' }}>{order.progressPercent || 75}% Abgeschlossen</span>
</div>
<div style={{
width: '100%',
height: '14px',
backgroundColor: 'rgba(15, 23, 42, 0.6)',
borderRadius: '20px',
overflow: 'hidden',
padding: '2px',
boxSizing: 'border-box',
border: '1px solid rgba(255,255,255,0.1)'
}}>
<div style={{
width: `${order.progressPercent || 75}%`,
height: '100%',
borderRadius: '20px',
background: isDelay
? 'linear-gradient(90deg, #f59e0b 0%, #d97706 100%)'
: 'linear-gradient(90deg, #0284c7 0%, #38bdf8 100%)',
transition: 'width 0.8s ease'
}} />
</div>
</div>
</div>
{/* Navigation Tabs */}
<div style={{ display: 'flex', gap: '8px', borderBottom: '1px solid var(--border-color, #334155)', paddingBottom: '4px' }}>
<button
onClick={() => setActiveSubTab('progress')}
style={{
padding: '10px 18px',
borderRadius: '10px',
fontSize: '0.88rem',
fontWeight: 700,
border: 'none',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '8px',
backgroundColor: activeSubTab === 'progress' ? '#0284c7' : 'transparent',
color: activeSubTab === 'progress' ? '#ffffff' : 'var(--text-muted, #94a3b8)'
}}
>
<Clock size={18} />
<span>Bau-Verlauf & Updates</span>
</button>
<button
onClick={() => setActiveSubTab('booking')}
style={{
padding: '10px 18px',
borderRadius: '10px',
fontSize: '0.88rem',
fontWeight: 700,
border: 'none',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '8px',
backgroundColor: activeSubTab === 'booking' ? '#ea580c' : 'transparent',
color: '#ffffff'
}}
>
<Calendar size={18} />
<span>Online-Termin buchen</span>
</button>
<button
onClick={() => setActiveSubTab('parts')}
style={{
padding: '10px 18px',
borderRadius: '10px',
fontSize: '0.88rem',
fontWeight: 700,
border: 'none',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '8px',
backgroundColor: activeSubTab === 'parts' ? '#0284c7' : 'transparent',
color: activeSubTab === 'parts' ? '#ffffff' : 'var(--text-muted, #94a3b8)'
}}
>
<Package size={18} />
<span>Geräte ({installedParts.length})</span>
</button>
<button
onClick={() => setActiveSubTab('docs')}
style={{
padding: '10px 18px',
borderRadius: '10px',
fontSize: '0.88rem',
fontWeight: 700,
border: 'none',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '8px',
backgroundColor: activeSubTab === 'docs' ? '#0284c7' : 'transparent',
color: activeSubTab === 'docs' ? '#ffffff' : 'var(--text-muted, #94a3b8)'
}}
>
<FileText size={18} />
<span>Dokumente ({attachments.length})</span>
</button>
</div>
{/* TAB 1: Bau-Verlauf & Updates */}
{activeSubTab === 'progress' && (
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
<h3 style={{ margin: '0 0 4px 0', fontSize: '1.1rem', fontWeight: 700 }}>Projekt-Changelog & Handwerker-Updates</h3>
{changelogs.length === 0 ? (
<div style={{ padding: '24px', textAlign: 'center', color: '#94a3b8', backgroundColor: 'var(--bg-card, #1e293b)', borderRadius: '12px' }}>
Noch keine Einträge vorhanden.
</div>
) : (
changelogs.map((item) => (
<div key={item.id} style={{
backgroundColor: 'var(--bg-card, #1e293b)',
border: '1px solid var(--border-color, #334155)',
borderRadius: '12px',
padding: '16px 20px',
display: 'flex',
flexDirection: 'column',
gap: '8px'
}}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<span style={{ fontSize: '0.85rem', fontWeight: 700, color: '#38bdf8' }}>
{item.authorName}
</span>
<span style={{ fontSize: '0.78rem', color: 'var(--text-muted, #94a3b8)' }}>
{new Date(item.createdAt).toLocaleString('de-DE')}
</span>
</div>
<p style={{ margin: 0, fontSize: '0.92rem', lineHeight: '1.5' }}>{item.note}</p>
</div>
))
)}
</div>
)}
{/* TAB 2: Online-Terminbuchung */}
{activeSubTab === 'booking' && (
<div style={{
backgroundColor: 'var(--bg-card, #1e293b)',
border: '1px solid var(--border-color, #334155)',
borderRadius: '16px',
padding: '24px'
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '16px' }}>
<div style={{
width: '40px',
height: '40px',
borderRadius: '10px',
backgroundColor: 'rgba(234, 88, 12, 0.15)',
border: '1px solid rgba(234, 88, 12, 0.3)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#ea580c'
}}>
<Calendar size={22} />
</div>
<div>
<h3 style={{ margin: 0, fontSize: '1.15rem', fontWeight: 800 }}>Termin online vereinbaren</h3>
<p style={{ margin: 0, fontSize: '0.82rem', color: 'var(--text-muted, #94a3b8)' }}>Wähle ein freies Zeitfenster für deine Wartung oder Abnahme</p>
</div>
</div>
{bookingSuccess && (
<div style={{
backgroundColor: 'rgba(34, 197, 94, 0.15)',
border: '1px solid rgba(34, 197, 94, 0.4)',
color: '#4ade80',
padding: '14px',
borderRadius: '10px',
fontSize: '0.9rem',
fontWeight: 600,
display: 'flex',
alignItems: 'center',
gap: '10px',
marginBottom: '20px'
}}>
<Check size={20} />
<span>Vielen Dank! Dein Termin wurde erfolgreich gebucht. Unser Team hat die Benachrichtigung erhalten.</span>
</div>
)}
<form onSubmit={handleBookAppointment} style={{ display: 'flex', flexDirection: 'column', gap: '18px' }}>
<div>
<label style={{ display: 'block', fontSize: '0.83rem', fontWeight: 600, color: '#cbd5e1', marginBottom: '6px' }}>
Wunschdatum
</label>
<input
type="date"
value={selectedDate}
onChange={(e) => setSelectedDate(e.target.value)}
style={{
width: '100%',
padding: '10px 14px',
backgroundColor: '#0f172a',
border: '1px solid #334155',
borderRadius: '8px',
color: '#ffffff',
fontSize: '0.9rem',
boxSizing: 'border-box'
}}
/>
</div>
<div>
<label style={{ display: 'block', fontSize: '0.83rem', fontWeight: 600, color: '#cbd5e1', marginBottom: '6px' }}>
Verfügbares Zeitfenster wählen
</label>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: '10px' }}>
{['08:30 - 10:00 Uhr', '10:00 - 11:30 Uhr', '13:00 - 14:30 Uhr', '15:00 - 16:30 Uhr'].map((slot) => (
<button
key={slot}
type="button"
onClick={() => setSelectedSlot(slot)}
style={{
padding: '12px',
borderRadius: '10px',
border: selectedSlot === slot ? '2px solid #ea580c' : '1px solid #334155',
backgroundColor: selectedSlot === slot ? 'rgba(234, 88, 12, 0.15)' : '#0f172a',
color: selectedSlot === slot ? '#ffffff' : '#94a3b8',
fontWeight: selectedSlot === slot ? 700 : 500,
cursor: 'pointer',
textAlign: 'center'
}}
>
{slot}
</button>
))}
</div>
</div>
<div>
<label style={{ display: 'block', fontSize: '0.83rem', fontWeight: 600, color: '#cbd5e1', marginBottom: '6px' }}>
Anmerkung / Notiz (optional)
</label>
<textarea
rows={3}
placeholder="z.B. Schlüssel liegt unter der Fußmatte..."
value={bookingNote}
onChange={(e) => setBookingNote(e.target.value)}
style={{
width: '100%',
padding: '10px 14px',
backgroundColor: '#0f172a',
border: '1px solid #334155',
borderRadius: '8px',
color: '#ffffff',
fontSize: '0.9rem',
boxSizing: 'border-box'
}}
/>
</div>
<button
type="submit"
disabled={isSubmittingBooking}
className="btn-primary-cta"
style={{ padding: '12px 20px', alignSelf: 'flex-start' }}
>
<Send size={18} />
<span>{isSubmittingBooking ? 'Bucht Termin...' : 'Termin Verbindlich Buchen'}</span>
</button>
</form>
</div>
)}
{/* TAB 3: Verbaute Geräte */}
{activeSubTab === 'parts' && (
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
<h3 style={{ margin: '0 0 4px 0', fontSize: '1.1rem', fontWeight: 700 }}>Installierte Geräte & Komponenten</h3>
{installedParts.map((part) => (
<div key={part.id} style={{
backgroundColor: 'var(--bg-card, #1e293b)',
border: '1px solid var(--border-color, #334155)',
borderRadius: '12px',
padding: '16px 20px',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<Package size={24} color="#38bdf8" />
<div>
<div style={{ fontSize: '0.95rem', fontWeight: 700 }}>{part.name}</div>
<div style={{ fontSize: '0.8rem', color: 'var(--text-muted, #94a3b8)' }}>
Hersteller: {part.manufacturer} | Kategorie: {part.category}
</div>
</div>
</div>
<div style={{
backgroundColor: '#0f172a',
padding: '4px 10px',
borderRadius: '8px',
fontSize: '0.78rem',
fontFamily: 'monospace',
color: '#94a3b8',
border: '1px solid #334155'
}}>
SN: {part.serialNumber || 'Keine SN'}
</div>
</div>
))}
</div>
)}
{/* TAB 4: Dokumente */}
{activeSubTab === 'docs' && (
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
<h3 style={{ margin: '0 0 4px 0', fontSize: '1.1rem', fontWeight: 700 }}>Dokumente & Vor-Ort-Fotos</h3>
{attachments.length === 0 ? (
<div style={{ padding: '24px', textAlign: 'center', color: '#94a3b8', backgroundColor: 'var(--bg-card, #1e293b)', borderRadius: '12px' }}>
Noch keine Dokumente freigegeben.
</div>
) : (
attachments.map((doc) => (
<div key={doc.id} style={{
backgroundColor: 'var(--bg-card, #1e293b)',
border: '1px solid var(--border-color, #334155)',
borderRadius: '12px',
padding: '16px 20px',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<FileText size={24} color="#ea580c" />
<div>
<div style={{ fontSize: '0.95rem', fontWeight: 700 }}>{doc.title}</div>
<div style={{ fontSize: '0.78rem', color: 'var(--text-muted, #94a3b8)' }}>
Kategorie: {doc.category}
</div>
</div>
</div>
<a
href={doc.filePath}
target="_blank"
rel="noreferrer"
style={{
padding: '6px 14px',
borderRadius: '8px',
backgroundColor: '#0284c7',
color: '#ffffff',
textDecoration: 'none',
fontSize: '0.8rem',
fontWeight: 600
}}
>
Ansehen
</a>
</div>
))
)}
</div>
)}
</div>
</div>
);
};