Website (14 monoliths split): - compliance/page.tsx (1,519 → 9), docs/audit (1,262 → 20) - quality (1,231 → 16), alerts (1,203 → 10), docs (1,202 → 11) - i18n.ts (1,173 → 8 language files) - unity-bridge (1,094 → 12), backlog (1,087 → 6) - training (1,066 → 8), rag (1,063 → 8) - Deleted index_original.ts (4,899 LOC dead backup) Studio-v2 (5 monoliths split): - meet/page.tsx (1,481 → 9), messages (1,166 → 9) - AlertsB2BContext.tsx (1,165 → 5 modules) - alerts-b2b/page.tsx (1,019 → 6), korrektur/archiv (1,001 → 6) All existing imports preserved. Zero new TypeScript errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68 lines
2.8 KiB
TypeScript
68 lines
2.8 KiB
TypeScript
'use client'
|
|
|
|
import type { AlertItem } from './types'
|
|
import { formatTimeAgo, getScoreBadge, getDecisionBadge } from './useAlertsData'
|
|
|
|
interface InboxTabProps {
|
|
inboxFilter: string
|
|
setInboxFilter: (filter: string) => void
|
|
filteredAlerts: AlertItem[]
|
|
}
|
|
|
|
export default function InboxTab({ inboxFilter, setInboxFilter, filteredAlerts }: InboxTabProps) {
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* Filters */}
|
|
<div className="flex gap-2 flex-wrap">
|
|
{['all', 'new', 'keep', 'review'].map((filter) => (
|
|
<button
|
|
key={filter}
|
|
onClick={() => setInboxFilter(filter)}
|
|
className={`px-4 py-2 rounded-full text-sm font-medium transition-colors ${
|
|
inboxFilter === filter
|
|
? 'bg-primary-600 text-white'
|
|
: 'bg-slate-100 text-slate-600 hover:bg-slate-200'
|
|
}`}
|
|
>
|
|
{filter === 'all' && 'Alle'}
|
|
{filter === 'new' && 'Neu'}
|
|
{filter === 'keep' && 'Relevant'}
|
|
{filter === 'review' && 'Pruefung'}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Alerts Table */}
|
|
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
|
<table className="w-full">
|
|
<thead className="bg-slate-50 border-b border-slate-200">
|
|
<tr>
|
|
<th className="text-left p-4 text-xs font-semibold text-slate-500 uppercase">Alert</th>
|
|
<th className="text-left p-4 text-xs font-semibold text-slate-500 uppercase">Topic</th>
|
|
<th className="text-left p-4 text-xs font-semibold text-slate-500 uppercase">Score</th>
|
|
<th className="text-left p-4 text-xs font-semibold text-slate-500 uppercase">Decision</th>
|
|
<th className="text-left p-4 text-xs font-semibold text-slate-500 uppercase">Zeit</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-slate-100">
|
|
{filteredAlerts.map((alert) => (
|
|
<tr key={alert.id} className="hover:bg-slate-50">
|
|
<td className="p-4">
|
|
<a href={alert.url} target="_blank" rel="noopener noreferrer" className="font-medium text-slate-900 hover:text-primary-600">
|
|
{alert.title}
|
|
</a>
|
|
<p className="text-sm text-slate-500 truncate max-w-md">{alert.snippet}</p>
|
|
</td>
|
|
<td className="p-4 text-sm text-slate-600">{alert.topic_name}</td>
|
|
<td className="p-4">{getScoreBadge(alert.relevance_score)}</td>
|
|
<td className="p-4">{getDecisionBadge(alert.relevance_decision)}</td>
|
|
<td className="p-4 text-sm text-slate-500">{formatTimeAgo(alert.fetched_at)}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|