Add: PDF-Viewer inline + Team-Fortschritt auf Übersicht-Tab

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 12:36:12 +02:00
parent 50bbfc6b22
commit 54114b5b9f

View File

@@ -372,6 +372,45 @@ export default function OffboardingDetailPage() {
))} ))}
</div> </div>
{/* Team-Fortschritt */}
<div style={{ gridColumn: '1 / -1', background: 'var(--bg-secondary)', border: '1px solid var(--border-color)', borderRadius: 12, padding: 18 }}>
<div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.5px', marginBottom: 14 }}>👥 Checklisten-Fortschritt nach Team</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
{['it', 'hr', 'buchhaltung'].map(team => {
const teamProcs = processes.filter(p => p.responsible_team === team);
if (!teamProcs.length) return null;
const done = teamProcs.filter(p => !!checklist[`proc_${p.id}`]).length;
const pctT = Math.round(done / teamProcs.length * 100);
const tc = TEAM_COLORS[team];
const isMyTeam = userTeam === team;
return (
<div key={team} style={{ border: `1px solid ${isMyTeam ? tc : 'var(--border-color)'}`, borderLeft: `3px solid ${tc}`, borderRadius: 8, padding: '12px 14px', background: isMyTeam ? `${tc}0a` : 'transparent' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
<span style={{ fontSize: 16 }}>{TEAM_ICONS[team]}</span>
<span style={{ fontWeight: 600, fontSize: 13, color: tc }}>{TEAM_LABELS[team]}</span>
{isMyTeam && <span style={{ fontSize: 10, background: `${tc}20`, color: tc, borderRadius: 4, padding: '1px 6px', fontWeight: 700, marginLeft: 'auto' }}>Dein Team</span>}
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6 }}>
<span style={{ fontSize: 12, color: 'var(--text-muted)' }}>{done} / {teamProcs.length} erledigt</span>
<span style={{ fontSize: 12, fontWeight: 700, color: pctT === 100 ? '#10b981' : 'var(--text-primary)' }}>{pctT}%</span>
</div>
<div style={{ height: 6, background: 'var(--border-color)', borderRadius: 3, overflow: 'hidden' }}>
<div style={{ height: '100%', width: `${pctT}%`, background: pctT === 100 ? '#10b981' : tc, borderRadius: 3, transition: 'width .3s' }} />
</div>
{pctT < 100 && (
<div style={{ marginTop: 8, fontSize: 11, color: '#f59e0b' }}>
{teamProcs.length - done} Aufgabe{teamProcs.length - done !== 1 ? 'n' : ''} offen
</div>
)}
{pctT === 100 && (
<div style={{ marginTop: 8, fontSize: 11, color: '#10b981' }}> Vollständig abgehakt</div>
)}
</div>
);
})}
</div>
</div>
{/* Allgemeine Infos */} {/* Allgemeine Infos */}
<div style={{ background: 'var(--bg-secondary)', border: '1px solid var(--border-color)', borderRadius: 12, padding: 18 }}> <div style={{ background: 'var(--bg-secondary)', border: '1px solid var(--border-color)', borderRadius: 12, padding: 18 }}>
<div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.5px', marginBottom: 12 }}>📋 Allgemeine Infos</div> <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.5px', marginBottom: 12 }}>📋 Allgemeine Infos</div>
@@ -489,25 +528,31 @@ export default function OffboardingDetailPage() {
)} )}
</div> </div>
<div style={{ background: 'var(--bg-secondary)', border: '1px solid var(--border-color)', borderRadius: 12, padding: 20 }}> <div style={{ background: 'var(--bg-secondary)', border: '1px solid var(--border-color)', borderRadius: 12, padding: 20 }}>
<div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-muted)', marginBottom: 16, textTransform: 'uppercase', letterSpacing: '.5px' }}>📄 PDF-Dokument</div> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
{protocol.pdf_path ? ( <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '.5px' }}>📄 PDF-Dokument</div>
<div> {protocol.pdf_file_path && (
<div style={{ fontSize: 13, color: 'var(--text-primary)', marginBottom: 14 }}>PDF vorhanden</div>
<div style={{ display: 'flex', gap: 8 }}> <div style={{ display: 'flex', gap: 8 }}>
<a href={offboardingService.downloadPdf(protocol.pdf_path)} target="_blank" rel="noreferrer" <a href={offboardingService.downloadPdf(protocol.pdf_file_path)} target="_blank" rel="noreferrer"
style={{ background: 'var(--cereda-primary)', border: 'none', borderRadius: 8, color: '#fff', padding: '7px 16px', fontSize: 13, textDecoration: 'none', fontWeight: 600 }}> style={{ background: 'var(--cereda-primary)', border: 'none', borderRadius: 6, color: '#fff', padding: '5px 12px', fontSize: 12, textDecoration: 'none', fontWeight: 600 }}>
📥 Download 📥 Download
</a> </a>
{canAct && ( {canAct && (
<button onClick={regeneratePdf} <button onClick={regeneratePdf}
style={{ background: 'var(--bg-tertiary)', border: '1px solid var(--border-color)', borderRadius: 8, color: 'var(--text-primary)', padding: '7px 14px', fontSize: 13, cursor: 'pointer' }}> style={{ background: 'var(--bg-tertiary)', border: '1px solid var(--border-color)', borderRadius: 6, color: 'var(--text-primary)', padding: '5px 12px', fontSize: 12, cursor: 'pointer' }}>
🔄 Neu erstellen 🔄 Neu
</button> </button>
)} )}
</div> </div>
</div> )}
</div>
{protocol.pdf_file_path ? (
<iframe
src={offboardingService.downloadPdf(protocol.pdf_file_path)}
title="Offboarding PDF"
style={{ width: '100%', height: 600, border: 'none', borderRadius: 8, background: '#fff' }}
/>
) : ( ) : (
<div style={{ textAlign: 'center', padding: '24px 0', color: 'var(--text-muted)' }}> <div style={{ textAlign: 'center', padding: '32px 0', color: 'var(--text-muted)' }}>
<div style={{ fontSize: 36, marginBottom: 10 }}>📄</div> <div style={{ fontSize: 36, marginBottom: 10 }}>📄</div>
<div style={{ fontSize: 13, marginBottom: 14 }}>Noch kein PDF generiert</div> <div style={{ fontSize: 13, marginBottom: 14 }}>Noch kein PDF generiert</div>
{canAct && ( {canAct && (