Files
AFC-Demo/resources/views/livewire/transaction-review.blade.php
T

573 lines
33 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
use App\Models\Transaction;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Volt\Component;
use Livewire\WithPagination;
new #[Layout('components.layouts.app'), Title('Transaktionsprüfung')] class extends Component {
use WithPagination;
public string $search = '';
public string $status = 'all';
public ?int $selectedTransactionId = null;
protected int $perPage = 12;
protected $queryString = [
'search' => ['except' => ''],
'status' => ['except' => 'all'],
'page' => ['except' => 1],
];
public function mount(): void
{
$this->selectedTransactionId = Transaction::query()
->orderByDesc('risk_score')
->orderByDesc('executed_at')
->value('id');
}
public function selectTransaction(int $transactionId): void
{
$this->selectedTransactionId = $transactionId;
}
public function updatingSearch(): void
{
$this->resetPage();
}
public function updatedSearch(): void
{
$this->refreshSelection();
}
public function updatingStatus(): void
{
$this->resetPage();
}
public function updatedStatus(): void
{
$this->refreshSelection();
}
public function updatedPage(): void
{
$this->refreshSelection();
}
protected function refreshSelection(): void
{
$first = $this->filteredQuery()
->orderByDesc('requires_review')
->orderByDesc('risk_score')
->orderByDesc('executed_at')
->forPage($this->getPage(), $this->perPage)
->first();
$this->selectedTransactionId = $first?->id;
}
#[Computed]
public function statusOptions(): array
{
return [
'all' => 'Alle Prüfaufträge',
Transaction::STATUS_TRUE_POSITIVE => 'Bestätigte Treffer',
Transaction::STATUS_FALSE_POSITIVE => 'Fehlalarme',
Transaction::STATUS_CLEARED => 'Freigegebene Vorgänge',
];
}
#[Computed]
public function transactions(): LengthAwarePaginator
{
return $this->filteredQuery()
->with('company')
->orderByDesc('requires_review')
->orderByDesc('risk_score')
->orderByDesc('executed_at')
->paginate($this->perPage);
}
#[Computed]
public function metrics(): array
{
$baseQuery = $this->filteredQuery();
/** @var Collection<int, array{count:int, amount:float}> $grouped */
$grouped = (clone $baseQuery)
->selectRaw('status, COUNT(*) AS total, COALESCE(SUM(amount), 0) AS volume')
->groupBy('status')
->get()
->mapWithKeys(fn($row) => [
$row->status => [
'count' => (int) $row->total,
'amount' => (float) $row->volume,
],
]);
return [
'by_status' => $grouped->toArray(),
'total' => [
'count' => $grouped->sum('count'),
'amount' => $grouped->sum('amount'),
],
];
}
#[Computed]
public function selectedTransaction(): ?Transaction
{
$transaction = $this->transactions->firstWhere('id', $this->selectedTransactionId);
if (! $transaction && $this->selectedTransactionId) {
$transaction = Transaction::query()
->with('company')
->find($this->selectedTransactionId);
}
return $transaction ?? $this->transactions->first();
}
protected function filteredQuery(): Builder
{
$search = trim($this->search);
return Transaction::query()
->when($this->status !== 'all', fn(Builder $query) => $query->where('status', $this->status))
->when($search !== '', function (Builder $query) use ($search) {
$like = '%' . $search . '%';
$query->where(function (Builder $inner) use ($like) {
$inner->where('reference', 'like', $like)
->orWhere('counterparty', 'like', $like)
->orWhereHas('company', function (Builder $company) use ($like) {
$company->where('name', 'like', $like)
->orWhere('legal_name', 'like', $like)
->orWhere('ticker', 'like', $like);
});
});
});
}
}; ?>
@php
/** @var \Illuminate\Contracts\Pagination\LengthAwarePaginator $transactions */
$transactions = $this->transactions;
/** @var \App\Models\Transaction|null $selected */
$selected = $this->selectedTransaction;
$metrics = $this->metrics;
$byStatus = collect($metrics['by_status']);
$resolveMetrics = static fn (string $status): array => $byStatus->get($status, ['count' => 0, 'amount' => 0.0]);
$formatAmount = static fn (float $value): string => number_format($value, 2, ',', '.') . ' €';
$confirmed = $resolveMetrics(Transaction::STATUS_TRUE_POSITIVE);
$falseAlarm = $resolveMetrics(Transaction::STATUS_FALSE_POSITIVE);
$cleared = $resolveMetrics(Transaction::STATUS_CLEARED);
$total = $metrics['total'];
$statusStyles = [
Transaction::STATUS_TRUE_POSITIVE => 'bg-gradient-to-r from-rose-500/25 via-rose-500/10 to-rose-400/25 text-rose-700 dark:text-rose-200 border border-rose-500/30 shadow-[0_0_25px_-14px_rgba(244,63,94,0.85)]',
Transaction::STATUS_FALSE_POSITIVE => 'bg-gradient-to-r from-amber-400/25 via-amber-400/10 to-amber-300/25 text-amber-700 dark:text-amber-200 border border-amber-400/30 shadow-[0_0_25px_-14px_rgba(251,191,36,0.85)]',
Transaction::STATUS_CLEARED => 'bg-gradient-to-r from-emerald-400/25 via-emerald-400/10 to-emerald-300/25 text-emerald-700 dark:text-emerald-200 border border-emerald-400/30 shadow-[0_0_25px_-14px_rgba(52,211,153,0.85)]',
];
$statusCopy = [
Transaction::STATUS_TRUE_POSITIVE => 'Sofortige Sonderprüfung einleiten und Ermittlungsakte anlegen.',
Transaction::STATUS_FALSE_POSITIVE => 'Anomalie begründen, Dokumentation ergänzen und Alarm schließen.',
Transaction::STATUS_CLEARED => 'Review-Ergebnis dokumentieren und Kontrollnachweis archivieren.',
];
$statusSummaryPhrases = [
Transaction::STATUS_TRUE_POSITIVE => [
'Verdachtsindikatoren bestätigen Treffer.',
'Risikotreiber stehen weiter auf Rot.',
'Sofortmaßnahmen priorisieren und dokumentieren.',
'Ermittlungsteam unverzüglich koordinieren.',
'Audit-Trail aktuell halten und teilen.',
],
Transaction::STATUS_FALSE_POSITIVE => [
'Alarm widerlegt, Dokumentation abschließen.',
'Risikoschwelle fällt unter interne Limits.',
'Regelwerk für Fehlalarm analysieren.',
'Stakeholder über Entwarnung informieren.',
'Kontrollnachweis im Archiv sichern.',
],
Transaction::STATUS_CLEARED => [
'Keine Auffälligkeiten, Vorgang freigegeben.',
'Monitoringdaten bestätigen Referenzverhalten.',
'Freigabe mit Vier-Augen-Prinzip dokumentieren.',
'Compliance-Team über Abschluss informieren.',
'Revisionsunterlagen vollständig archivieren.',
],
];
$statusSummary = array_map(
static fn (array $phrases): string => $phrases[0] ?? 'Status gemäß aktuellem Prüfpfad.',
$statusSummaryPhrases
);
$statusSummaryBanner = [
Transaction::STATUS_TRUE_POSITIVE => [
'classes' => 'border border-rose-400/60 bg-gradient-to-r from-rose-500/20 via-rose-500/10 to-rose-400/20 text-rose-900 shadow-[0_30px_70px_-50px_rgba(244,63,94,0.75)] dark:border-rose-500/50 dark:from-rose-500/20 dark:via-rose-500/10 dark:to-rose-400/20 dark:text-rose-100',
],
Transaction::STATUS_FALSE_POSITIVE => [
'classes' => 'border border-amber-400/60 bg-gradient-to-r from-amber-400/20 via-amber-400/10 to-amber-300/20 text-amber-900 shadow-[0_30px_70px_-50px_rgba(245,158,11,0.65)] dark:border-amber-400/50 dark:from-amber-400/20 dark:via-amber-400/10 dark:to-amber-300/20 dark:text-amber-100',
],
Transaction::STATUS_CLEARED => [
'classes' => 'border border-emerald-400/60 bg-gradient-to-r from-emerald-400/20 via-emerald-400/10 to-emerald-300/20 text-emerald-900 shadow-[0_30px_70px_-50px_rgba(16,185,129,0.65)] dark:border-emerald-400/50 dark:from-emerald-400/20 dark:via-emerald-400/10 dark:to-emerald-300/20 dark:text-emerald-100',
],
];
$statusLegend = [
Transaction::STATUS_TRUE_POSITIVE => [
'title' => 'Gruppe mit hohem Risikoscore Scorewert > 66',
'description' => 'Wenn man draufklickt, werden alles diese Fälle angezeigt',
'accent' => 'text-rose-500 dark:text-rose-300',
],
Transaction::STATUS_FALSE_POSITIVE => [
'title' => 'Gruppe mit mittlerem Risikoscore Scorewert 33- 65',
'description' => 'Wenn man draufklickt, werden alles diese Fälle angezeigt',
'accent' => 'text-amber-500 dark:text-amber-200',
],
Transaction::STATUS_CLEARED => [
'title' => 'Gruppe mit niedrigem Risikoscore Scorewert < 33', 'description'=> 'Wenn man draufklickt, werden alles diese Fälle angezeigt',
'accent' => 'text-emerald-500 dark:text-emerald-300',
],
];
$riskExplanation = 'Der Risikowert (0100) fasst Monitoring-Regeln, KYC-Risiken, Negativmeldungen sowie Verhaltens- und Geodaten zu einer Priorität zusammen. Werte über 80 kennzeichnen Sofortmaßnahmen, 5079 markieren erhöhte Aufmerksamkeit, alles darunter gilt als Routineprüfung.';
@endphp
<div class="flex flex-col gap-6">
<div class="relative overflow-hidden rounded-3xl border border-slate-200/60 bg-slate-950/95 p-8 text-white shadow-[0_30px_80px_-45px_rgba(15,23,42,0.9)] dark:border-slate-800/60">
<span class="pointer-events-none absolute -left-24 top-1/2 aspect-square w-72 -translate-y-1/2 rounded-full bg-sky-500/15 blur-3xl"></span>
<span class="pointer-events-none absolute -right-16 -top-16 aspect-square w-64 rounded-full bg-indigo-500/15 blur-3xl"></span>
<div class="relative flex flex-wrap items-end justify-between gap-6">
<div class="max-w-xl space-y-3">
<p class="inline-flex items-center gap-2 rounded-full border border-white/25 bg-white/10 px-3 py-1 text-xs font-semibold uppercase tracking-[0.18em] text-slate-200 shadow-sm">
Anti Financial Crime - Cases
</p>
<h1 class="text-2xl font-semibold tracking-tight sm:text-3xl">Übersicht Verdachtsfälle nach Automatisierung- und Risikoscore</h1>
</div>
<div class="grid grid-cols-2 gap-4 text-sm sm:text-base md:grid-cols-4">
<div class="rounded-2xl border border-white/10 bg-white/10 p-4 text-center backdrop-blur-sm shadow-lg shadow-slate-900/30">
<p class="text-xs font-medium uppercase tracking-wide text-slate-200">Gesamtfälle</p>
<p class="text-2xl font-semibold text-white">{{ $total['count'] }}</p>
<p class="mt-1 text-xs text-slate-300">Volumen: {{ $formatAmount($total['amount']) }}</p>
</div>
<div class="rounded-2xl border border-rose-400/40 bg-rose-500/15 p-4 text-center backdrop-blur-sm shadow-lg shadow-rose-900/40">
<p class="text-xs font-medium uppercase tracking-wide text-rose-50">Bestätigte Treffer</p>
<p class="text-2xl font-semibold text-rose-100">{{ $confirmed['count'] }}</p>
<p class="mt-1 text-xs text-rose-100/80">Volumen: {{ $formatAmount($confirmed['amount']) }}</p>
</div>
<div class="rounded-2xl border border-amber-400/40 bg-amber-400/15 p-4 text-center backdrop-blur-sm shadow-lg shadow-amber-900/30">
<p class="text-xs font-medium uppercase tracking-wide text-amber-50">Fehlalarme</p>
<p class="text-2xl font-semibold text-amber-100">{{ $falseAlarm['count'] }}</p>
<p class="mt-1 text-xs text-amber-100/80">Volumen: {{ $formatAmount($falseAlarm['amount']) }}</p>
</div>
<div class="rounded-2xl border border-emerald-400/40 bg-emerald-400/15 p-4 text-center backdrop-blur-sm shadow-lg shadow-emerald-900/30">
<p class="text-xs font-medium uppercase tracking-wide text-emerald-50">Freigegeben</p>
<p class="text-2xl font-semibold text-emerald-100">{{ $cleared['count'] }}</p>
<p class="mt-1 text-xs text-emerald-100/80">Volumen: {{ $formatAmount($cleared['amount']) }}</p>
</div>
</div>
</div>
</div>
<div class="grid gap-4 rounded-3xl border border-zinc-200/60 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90 md:grid-cols-3">
@foreach ($statusLegend as $key => $legend)
<div class="flex flex-col gap-3 rounded-2xl border border-zinc-100/60 bg-slate-50/80 p-4 shadow-sm transition hover:-translate-y-0.5 hover:shadow-md dark:border-zinc-700/60 dark:bg-zinc-800/70">
<div class="flex items-center gap-2">
<span class="inline-flex h-2.5 w-2.5 rounded-full bg-gradient-to-r @class([
'from-rose-500 to-rose-400' => $key === Transaction::STATUS_TRUE_POSITIVE,
'from-amber-400 to-amber-300' => $key === Transaction::STATUS_FALSE_POSITIVE,
'from-emerald-400 to-emerald-300' => $key === Transaction::STATUS_CLEARED,
])"></span>
<p class="text-xl font-semibold {{ $legend['accent'] }}">{{ $legend['title'] }}</p>
</div>
<p class="text-sm leading-relaxed text-zinc-600 dark:text-zinc-300">
{{ $legend['description'] }}
</p>
</div>
@endforeach
</div>
<div class="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
<div class="space-y-1">
<h2 class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">Aktive Prüfwarteschlange</h2>
<p class="text-sm text-zinc-500 dark:text-zinc-400">
Alle untenstehenden Meldungen benötigen eine finale Analystenentscheidung.
</p>
</div>
<div class="flex w-full flex-col gap-3 sm:w-auto sm:flex-row sm:items-center">
<flux:select wire:model.live="status" class="w-full sm:w-56">
@foreach ($this->statusOptions as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</flux:select>
<flux:input
wire:model.live.debounce.400ms="search"
type="search"
placeholder="Unternehmen, Gegenpartei oder Referenz suchen …"
class="w-full sm:w-80"
icon="magnifying-glass" />
</div>
</div>
<div class="grid gap-6 lg:grid-cols-[minmax(0,2.1fr)_minmax(0,1fr)]">
<div class="overflow-hidden rounded-3xl border border-zinc-200/70 bg-white/95 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<div class="hidden border-b border-zinc-200/70 bg-zinc-50/80 px-6 py-3 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:border-zinc-700/60 dark:bg-zinc-900/70 dark:text-zinc-400 sm:grid sm:grid-cols-[1.6fr_1fr_0.7fr]">
<span>Unternehmen &amp; Gegenpartei</span>
<span>Transaktionstyp &amp; Referenznummer</span>
<span class="text-right">Betrag</span>
</div>
<div class="divide-y divide-zinc-200/60 dark:divide-zinc-700/70">
@forelse ($transactions as $transaction)
@php
$selectedState = $transaction->id === $this->selectedTransactionId;
$buttonClasses = [
'flex w-full flex-col gap-3 px-4 py-4 text-left transition duration-200 sm:grid sm:grid-cols-[1.6fr_1fr_0.7fr]',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-400/70',
];
if ($selectedState) {
$buttonClasses[] = 'border-s-4 border-indigo-500/80 bg-indigo-500/10 shadow-lg shadow-indigo-500/20 ring-2 ring-indigo-400/70 ring-offset-2 ring-offset-white dark:bg-indigo-500/20 dark:ring-offset-zinc-900 scale-[1.01]';
} else {
$buttonClasses[] = 'border-s-4 border-transparent hover:-translate-y-0.5 hover:border-indigo-400/70 hover:bg-zinc-50/70 hover:shadow-lg hover:shadow-zinc-900/20 dark:hover:bg-zinc-800/60';
}
@endphp
<button
wire:click="selectTransaction({{ $transaction->id }})"
type="button"
class="{{ implode(' ', $buttonClasses) }}"
aria-pressed="{{ $selectedState ? 'true' : 'false' }}">
<div class="space-y-2">
<div class="flex items-start justify-between gap-3">
<div>
<p class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $transaction->company->legal_name }}</p>
<p class="text-xs uppercase tracking-wide text-zinc-400">{{ $transaction->company->name }} &middot; {{ $transaction->company->sector }}</p>
</div>
<span class="inline-flex items-center gap-1 rounded-full px-3 py-1 text-xs font-semibold {{ $statusStyles[$transaction->status] ?? 'bg-zinc-500/10 text-zinc-600 dark:text-zinc-300 border border-zinc-500/20' }}">
{{ $transaction->statusLabel() }}
</span>
</div>
<div class="flex flex-wrap items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400">
<span class="font-medium text-zinc-700 dark:text-zinc-200">{{ $transaction->counterparty }}</span>
<span>•</span>
<span>{{ $transaction->counterparty_country }}</span>
<span>•</span>
<span>{{ $transaction->executed_at?->format('d.m.Y H:i') }}</span>
</div>
</div>
<div class="space-y-2">
<p class="text-sm font-medium text-zinc-700 dark:text-zinc-200">{{ $transaction->channel }}</p>
<p class="font-mono text-xs text-zinc-400">{{ $transaction->reference }}</p>
</div>
<div class="flex flex-col items-end justify-between gap-2">
<p class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{{ number_format($transaction->amount, 2, ',', '.') }} {{ $transaction->currency }}
</p>
<div class="flex flex-wrap items-center gap-2 text-xs text-zinc-500 dark:text-zinc-400">
<!-- <flux:tooltip :content="$riskExplanation" position="top">
<span class="inline-flex items-center gap-1 rounded-md bg-slate-100/60 px-2 py-1 font-semibold text-slate-700 dark:bg-slate-900/60 dark:text-slate-200">
Risiko {{ $transaction->risk_score }}
<span aria-hidden="true" class="inline-flex h-3.5 w-3.5 items-center justify-center rounded-full border border-slate-400/60 text-[0.55rem] font-semibold text-slate-600 dark:border-slate-500/60 dark:text-slate-300">
i
</span>
</span>
</flux:tooltip>
<span>{{ $statusCopy[$transaction->status] ?? '' }}</span> -->
</div>
</div>
</button>
@empty
<div class="px-6 py-16 text-center text-sm text-zinc-500 dark:text-zinc-400">
Keine Transaktionen für die aktuellen Filterkriterien gefunden. Bitte Seed-Daten neu laden oder Filter anpassen.
</div>
@endforelse
</div>
@if ($transactions->hasPages())
<div class="flex items-center justify-between gap-3 border-t border-zinc-200/70 bg-zinc-50/70 px-4 py-3 text-sm text-zinc-500 dark:border-zinc-700/60 dark:bg-zinc-900/70 dark:text-zinc-300">
<button
wire:click="previousPage"
wire:loading.attr="disabled"
@disabled($transactions->onFirstPage())
class="inline-flex items-center gap-2 rounded-full border border-zinc-300/70 bg-white/70 px-4 py-1.5 font-medium text-zinc-700 transition hover:bg-white dark:border-zinc-600/70 dark:bg-zinc-800/80 dark:text-zinc-200 dark:hover:bg-zinc-800/60"
>
Zurück
</button>
<span class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
Seite {{ $transactions->currentPage() }} von {{ $transactions->lastPage() }}
</span>
<button
wire:click="nextPage"
wire:loading.attr="disabled"
@disabled(! $transactions->hasMorePages())
class="inline-flex items-center gap-2 rounded-full border border-zinc-300/70 bg-white/70 px-4 py-1.5 font-medium text-zinc-700 transition hover:bg-white dark:border-zinc-600/70 dark:bg-zinc-800/80 dark:text-zinc-200 dark:hover:bg-zinc-800/60"
>
Weiter
</button>
</div>
@endif
</div>
<div class="space-y-4">
@if ($selected)
@php
$summaryStyles = $statusSummaryBanner[$selected->status] ?? [
'classes' => 'border border-zinc-300/70 bg-zinc-100/80 text-zinc-700 dark:border-zinc-600/60 dark:bg-zinc-800/60 dark:text-zinc-200',
];
$summaryText = implode(' ', $statusSummaryPhrases[$selected->status] ?? ['Status gemäß aktuellem Prüfpfad.']);
@endphp
<div class="rounded-3xl px-6 py-5 text-sm leading-relaxed shadow-sm backdrop-blur {{ $summaryStyles['classes'] }}">
<div class="flex items-center justify-between gap-3">
<span class="text-xs font-semibold uppercase tracking-wide">Analyseergebnisse Summary</span>
<flux:link
:href="route('company.transactions', ['company' => $selected->company_id, 'transaction' => $selected->id])"
wire:navigate
class="inline-flex items-center gap-2 rounded-full border border-indigo-200/70 bg-indigo-500/10 px-4 py-1.5 text-xs font-semibold text-indigo-600 transition hover:bg-indigo-500/20 dark:border-indigo-500/40 dark:bg-indigo-500/10 dark:text-indigo-200">
{{ __('Fallansicht maximieren') }}
<flux:icon name="arrow-top-right-on-square" class="h-4 w-4" />
</flux:link>
</div>
<p class="mt-3 text-base font-medium leading-relaxed">
{{ $summaryText }}
</p>
</div>
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<div class="flex flex-wrap items-start justify-between gap-4">
<div>
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">{{ $selected->company->legal_name }}</h3>
<p class="text-sm text-zinc-500 dark:text-zinc-400">{{ $selected->company->summary }}</p>
</div>
<div class="flex flex-col items-end gap-2">
<span class="inline-flex items-center rounded-full bg-slate-900/90 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-white dark:bg-slate-200/20">
Prüfung erforderlich
</span>
@php($detailStatusStyle = $statusStyles[$selected->status] ?? 'bg-zinc-500/10 text-zinc-600 border border-zinc-500/20')
<span class="inline-flex items-center gap-2 rounded-full px-3 py-1 text-xs font-semibold {{ $detailStatusStyle }}">
Status: {{ $selected->statusLabel() }}
</span>
<span class="text-3xl font-semibold text-slate-900 dark:text-white">
{{ number_format($selected->amount, 2, ',', '.') }} {{ $selected->currency }}
</span>
<div class="flex items-center gap-2 text-xs text-zinc-500 dark:text-zinc-400">
<flux:tooltip :content="$riskExplanation" position="top">
<span class="inline-flex items-center gap-1 rounded-md bg-slate-900/10 px-2 py-1 font-semibold text-slate-700 dark:bg-slate-200/10 dark:text-slate-200">
Risikoscore {{ $selected->risk_score }}
<span aria-hidden="true" class="inline-flex h-3.5 w-3.5 items-center justify-center rounded-full border border-slate-500/60 text-[0.55rem] font-semibold text-slate-600 dark:border-slate-400/60 dark:text-slate-200">
i
</span>
</span>
</flux:tooltip>
<span>{{ $selected->executed_at?->format('d.m.Y, H:i') }}</span>
</div>
</div>
</div>
<dl class="mt-6 grid grid-cols-1 gap-4 text-sm text-zinc-600 dark:text-zinc-300">
<!-- <div class="rounded-2xl bg-zinc-50/80 p-4 dark:bg-zinc-800/80">
<dt class="text-xs uppercase tracking-wide text-zinc-400">Statusbegründung</dt>
<dd class="mt-1 font-medium text-zinc-900 dark:text-zinc-100">
{{ $statusSummary[$selected->status] ?? 'Status gemäß aktuellem Prüfpfad.' }}
</dd>
</div> -->
<div class="rounded-2xl bg-zinc-50/80 p-4 dark:bg-zinc-800/80">
<dt class="text-xs uppercase tracking-wide text-zinc-400">Gegenpartei</dt>
<dd class="mt-1 font-medium text-zinc-900 dark:text-zinc-100">{{ $selected->counterparty }}</dd>
<dd class="text-xs text-zinc-500">{{ $selected->counterparty_country }}</dd>
</div>
<div class="rounded-2xl bg-zinc-50/80 p-4 dark:bg-zinc-800/80">
<dt class="text-xs uppercase tracking-wide text-zinc-400">Transaktionstyp &amp; Referenznummer</dt>
<dd class="mt-1 font-medium text-zinc-900 dark:text-zinc-100">{{ $selected->channel }}</dd>
<dd class="font-mono text-xs text-zinc-500">{{ $selected->reference }}</dd>
</div>
<!-- <div class="rounded-2xl bg-zinc-50/80 p-4 dark:bg-zinc-800/80">
<dt class="text-xs uppercase tracking-wide text-zinc-400">Flagging-Engine</dt>
<dd class="mt-1 font-medium text-zinc-900 dark:text-zinc-100">{{ $selected->flagged_by }}</dd>
<dd class="text-xs text-zinc-500">{{ $selected->flagged_reason }}</dd>
</div> -->
</dl>
@if (! empty($selected->signals))
<div class="mt-6 space-y-2">
<h4 class="text-xs font-semibold uppercase tracking-wide text-zinc-400">Detektionssignale aus dem AML-Vorsystem</h4>
<div class="flex flex-wrap gap-2">
@foreach ($selected->signals as $signal)
<span class="inline-flex items-center gap-2 rounded-full border border-slate-300/70 bg-slate-100/60 px-3 py-1 text-xs font-medium text-slate-700 dark:border-slate-600 dark:bg-slate-800/60 dark:text-slate-200">
<span class="h-1.5 w-1.5 rounded-full bg-emerald-500"></span>
{{ data_get($signal, 'type') }} &middot; {{ data_get($signal, 'value') }}
</span>
@endforeach
</div>
</div>
@endif
<!-- <div class="mt-6 rounded-2xl border border-indigo-200/60 bg-indigo-500/10 p-4 text-sm text-indigo-900 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-100">
<p class="font-medium">Empfohlene Maßnahme</p>
<p class="mt-1 text-sm leading-relaxed">
{{ $statusCopy[$selected->status] ?? 'Review abschließen und vollständigen Audit-Trail dokumentieren.' }}
</p>
</div> -->
<div class="mt-4 flex justify-end">
<flux:link
:href="route('company.transactions', ['company' => $selected->company_id, 'transaction' => $selected->id])"
wire:navigate
class="inline-flex items-center gap-2 rounded-full border border-indigo-200/70 bg-indigo-500/10 px-4 py-1.5 text-xs font-semibold text-indigo-600 transition hover:bg-indigo-500/20 dark:border-indigo-500/40 dark:bg-indigo-500/10 dark:text-indigo-200">
{{ __('Fallansicht maximieren') }}
<flux:icon name="arrow-top-right-on-square" class="h-4 w-4" />
</flux:link>
</div>
</div>
<div class="rounded-3xl border border-zinc-200/60 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h4 class="text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Kerndaten Unternehmen</h4>
<ul class="mt-4 space-y-3 text-sm text-zinc-600 dark:text-zinc-300">
<li class="flex items-center justify-between">
<span>Rechtlicher Name</span>
<span class="font-medium text-zinc-900 dark:text-zinc-100">{{ $selected->company->legal_name }}</span>
</li>
<li class="flex items-center justify-between">
<span>Ticker</span>
<span class="font-medium text-zinc-900 dark:text-zinc-100">{{ $selected->company->ticker }}</span>
</li>
<li class="flex items-center justify-between">
<span>Sektor</span>
<span class="font-medium text-zinc-900 dark:text-zinc-100">{{ $selected->company->sector }}</span>
</li>
<li class="flex items-center justify-between">
<span>Hauptsitz</span>
<span class="font-medium text-zinc-900 dark:text-zinc-100">{{ $selected->company->headquarters }}</span>
</li>
<li class="flex items-center justify-between">
<span>Land</span>
<span class="font-medium text-zinc-900 dark:text-zinc-100">{{ $selected->company->country }}</span>
</li>
<!-- <li class="flex items-center justify-between">
<span>KYC-Risikostufe</span>
<span class="inline-flex items-center rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold uppercase tracking-wide text-slate-700 dark:bg-slate-800 dark:text-slate-200">
{{ Str::title($selected->company->kyc_risk_level) }}
</span>
</li> -->
</ul>
</div>
@else
<div class="rounded-3xl border border-dashed border-zinc-300/70 bg-white/80 p-6 text-center text-sm text-zinc-500 shadow-sm dark:border-zinc-600/50 dark:bg-zinc-900/60 dark:text-zinc-300">
Wählen Sie links einen Alarm aus, um den vollständigen Prüfkontext einzusehen.
</div>
@endif
</div>
</div>
</div>