Files
breakpilot-compliance/admin-compliance/app/sdk/incidents/_components/CountdownTimer.tsx
Sharang Parnerkar 375b34a0d8 refactor(admin): split consent-management, control-library, incidents, training pages
Agent-completed splits committed after agents hit rate limits before
committing their work. All 4 pages now under 500 LOC:

- consent-management: 1303 -> 193 LOC (+ 7 _components, _hooks, _data, _types)
- control-library: 1210 -> 298 LOC (+ _components, _types)
- incidents: 1150 -> 373 LOC (+ _components)
- training: 1127 -> 366 LOC (+ _components)

Verification: next build clean (142 pages generated).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:52:45 +02:00

76 lines
2.7 KiB
TypeScript

'use client'
import React from 'react'
import {
Incident,
getHoursUntil72hDeadline,
is72hDeadlineExpired
} from '@/lib/sdk/incidents/types'
/**
* 72h-Countdown-Anzeige mit visueller Farbkodierung
* Gruen > 48h, Gelb > 24h, Orange > 12h, Rot < 12h oder abgelaufen
*/
export function CountdownTimer({ incident }: { incident: Incident }) {
const hoursRemaining = getHoursUntil72hDeadline(incident.detectedAt)
const expired = is72hDeadlineExpired(incident.detectedAt)
// Nicht relevant fuer abgeschlossene Vorfaelle
if (incident.status === 'closed') return null
// Bereits gemeldet
if (incident.authorityNotification && (incident.authorityNotification.status === 'submitted' || incident.authorityNotification.status === 'acknowledged')) {
return (
<span className="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium bg-green-100 text-green-700 rounded-full">
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
Gemeldet
</span>
)
}
// Keine Meldepflicht festgestellt
if (incident.riskAssessment && !incident.riskAssessment.notificationRequired) {
return (
<span className="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium bg-gray-100 text-gray-600 rounded-full">
Keine Meldepflicht
</span>
)
}
// Abgelaufen
if (expired) {
const overdueHours = Math.abs(hoursRemaining)
return (
<span className="inline-flex items-center gap-1 px-2 py-1 text-xs font-bold bg-red-100 text-red-700 rounded-full animate-pulse">
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{overdueHours.toFixed(0)}h ueberfaellig
</span>
)
}
// Farbkodierung: gruen > 48h, gelb > 24h, orange > 12h, rot < 12h
let colorClass: string
if (hoursRemaining > 48) {
colorClass = 'bg-green-100 text-green-700'
} else if (hoursRemaining > 24) {
colorClass = 'bg-yellow-100 text-yellow-700'
} else if (hoursRemaining > 12) {
colorClass = 'bg-orange-100 text-orange-700'
} else {
colorClass = 'bg-red-100 text-red-700'
}
return (
<span className={`inline-flex items-center gap-1 px-2 py-1 text-xs font-bold rounded-full ${colorClass}`}>
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{hoursRemaining.toFixed(0)}h verbleibend
</span>
)
}