Snapshot of main at 9f39a6e1e (2026-11-02)

This commit is contained in:
Ronald Huynen committed 2026-11-02 10:41:47 +01:00
commit 6ccf1792d7
2580 files changed
+1040202

No files matched your search

@@ -0,0 +1,275 @@
{{-- Mailing Report Modal Partial --}}
@php
$statusColors = [
'draft' => 'bg-gray-100 text-gray-800',
'scheduled' => 'bg-yellow-100 text-yellow-800',
'sending' => 'bg-blue-100 text-blue-800',
'sent' => 'bg-green-100 text-green-800',
'aborted' => 'bg-red-100 text-red-800',
'cancelled' => 'bg-red-100 text-red-800',
];
$statusColor = $statusColors[$mailing->status] ?? 'bg-gray-100 text-gray-800';
@endphp
{{-- Header --}}
<div class="flex items-center justify-between mb-4">
<div>
<h3 class="text-base font-semibold text-theme-primary">{{ $mailing->title }}</h3>
<p class="text-xs text-theme-secondary mt-0.5">{{ $mailing->id }}</p>
@if($mailing->sent_at || $mailing->scheduled_at)
<p class="text-xs text-theme-secondary mt-0.5">
@if($mailing->sent_at)
{{ __('Sent') }}: {{ $mailing->sent_at->format('d M Y H:i') }}
@else
{{ __('Scheduled') }}: {{ $mailing->scheduled_at->format('d M Y H:i') }}
@endif
</p>
@endif
@if($mailing->sending_started_at)
@php
$endTime = $mailing->sent_at ?? now();
$durationSeconds = (int) $mailing->sending_started_at->diffInSeconds($endTime, true);
$durationHours = intdiv($durationSeconds, 3600);
$durationMinutes = intdiv($durationSeconds % 3600, 60);
$durationSecs = $durationSeconds % 60;
$durationStr = $durationHours > 0
? sprintf('%dh %dm %ds', $durationHours, $durationMinutes, $durationSecs)
: ($durationMinutes > 0
? sprintf('%dm %ds', $durationMinutes, $durationSecs)
: sprintf('%ds', $durationSecs));
@endphp
<p class="text-xs text-theme-secondary mt-0.5">
{{ __('Started sending') }}: {{ $mailing->sending_started_at->format('d M Y H:i') }}
</p>
<p class="text-xs text-theme-secondary mt-0.5">
{{ $mailing->sent_at ? __('Duration') : __('Running for') }}: {{ $durationStr }}
</p>
@endif
</div>
<span class="inline-flex px-2.5 py-0.5 text-xs font-medium rounded-full {{ $statusColor }}">
{{ __(ucfirst($mailing->status)) }}
</span>
</div>
<div class="space-y-4">
{{-- Block 1: Estimated Recipients --}}
<div class="p-3 bg-theme-surface rounded-lg border border-theme-border">
<p class="text-sm font-medium text-theme-primary mb-3">{{ __('Recipients by Language & Content') }}</p>
@php
$rowsByLocaleLocation = $mailing->getRecipientCountsByLocaleAndLocation();
$fallbackLocale = $mailing->fallback_locale ?? '';
@endphp
@if(count($rowsByLocaleLocation) > 0)
<table class="w-full text-xs" style="border-collapse: collapse;">
<thead>
<tr class="text-theme-secondary font-medium">
<th style="text-align: left; padding: 0 8px 4px 0; font-weight: 500;">{{ __('Language') }}</th>
<th style="text-align: left; padding: 0 8px 4px 8px; font-weight: 500;">{{ __('Posts') }}</th>
<th style="text-align: left; padding: 0 8px 4px 8px; font-weight: 500; white-space: nowrap;">{{ __('Location') }}</th>
<th style="text-align: right; padding: 0 0.5rem 4px 8px; font-weight: 500;">{{ __('Recipients') }}</th>
</tr>
</thead>
<tbody>
@php
$prevLocale = null;
$fallbackLanguageName = \App\Models\Language::where('lang_code', $fallbackLocale)->value('name') ?? strtoupper($fallbackLocale);
@endphp
@foreach($rowsByLocaleLocation as $row)
@php
$isFirstForLocale = $row['locale'] !== $prevLocale;
$prevLocale = $row['locale'];
$language = $isFirstForLocale ? \App\Models\Language::where('lang_code', $row['locale'])->first() : null;
$flag = $language ? $language->flag : '🏳️';
$languageName = $language ? $language->name : strtoupper($row['locale']);
$nativePosts = $row['content_blocks'] - ($row['fallback_posts'] ?? 0);
$fallbackPosts = $row['fallback_posts'] ?? 0;
$missingPosts = $row['missing_posts'] ?? 0;
@endphp
<tr>
<td style="padding: 2px 8px 2px 0; white-space: nowrap;">
@if($isFirstForLocale)
<span style="display: inline-flex; align-items: center; gap: 6px;">
<span>{{ $flag }}</span>
<span class="font-medium text-theme-primary">{{ $languageName }}</span>
</span>
@endif
</td>
<td style="padding: 2px 8px;">
@if($isFirstForLocale)
<span style="display: inline-flex; align-items: center; gap: 4px;">
@if($nativePosts > 0)
<span class="font-medium rounded bg-green-100 text-green-800" style="padding: 2px 6px; white-space: nowrap;">
{{ $nativePosts }} {{ __('native') }}
</span>
@endif
@if($fallbackPosts > 0)
<span class="font-medium rounded bg-amber-100 text-amber-800" style="padding: 2px 6px; white-space: nowrap;">
{{ $fallbackPosts }} {{ __('fallback in') }} {{ $fallbackLanguageName }}
</span>
@endif
@if($missingPosts > 0)
<span class="font-medium rounded bg-theme-danger-light text-theme-danger-dark" style="padding: 2px 6px; white-space: nowrap;">
{{ $missingPosts }} {{ __('skipped') }}
</span>
@endif
@if($nativePosts === 0 && $fallbackPosts === 0)
<span class="font-medium rounded bg-theme-danger-light text-theme-danger-dark" style="padding: 2px 6px; white-space: nowrap;">
{{ __('No content') }}
</span>
@endif
</span>
@endif
</td>
<td class="text-theme-secondary" style="padding: 2px 8px; white-space: nowrap;">
{{ $row['location'] ?: __('Unknown') }}
</td>
<td class="text-theme-secondary" style="padding: 2px 0.5rem 2px 8px; text-align: right;">
{{ number_format($row['count']) }}
</td>
</tr>
@endforeach
</tbody>
</table>
@php
$totalEstimated = collect($rowsByLocaleLocation)->sum('count');
$suppressedCount = $mailing->getSuppressedRecipientsCount();
@endphp
<div class="mt-3 pt-2 border-t border-theme-border space-y-1">
<div class="flex justify-between text-xs">
<span class="font-medium text-theme-primary">{{ __('Total recipients:') }}</span>
<span class="text-theme-secondary" style="padding-right: 0.5rem;">{{ number_format($totalEstimated) }}</span>
</div>
@if($suppressedCount > 0)
<div class="flex justify-between text-xs">
<span class="text-theme-secondary">{{ __('Skipped (hard bounce):') }}</span>
<span class="font-medium text-gray-700" style="padding-right: 0.5rem;">{{ number_format($suppressedCount) }}</span>
</div>
@endif
</div>
@else
<p class="text-xs text-theme-secondary">{{ __('No recipients found for this mailing type.') }}</p>
@endif
</div>
{{-- Block 2: Send Results (only shown once sending has started) --}}
@if(in_array($mailing->status, ['sending', 'sent', 'aborted']))
@php
$bounceStats = $this->getReportBounceStats();
$recipientsCount = $mailing->recipients_count ?: 1;
$processedCount = $mailing->sent_count + $mailing->failed_count + $mailing->skipped_count + $mailing->aborted_count;
$progressPct = min(100, round($processedCount / $recipientsCount * 100));
@endphp
<div class="p-3 bg-theme-surface rounded-lg border border-theme-border">
<p class="text-sm font-medium text-theme-primary mb-3">{{ __('Send Results') }}</p>
{{-- Progress bar (while sending) --}}
@if($mailing->status === 'sending')
<div class="mb-4">
<div class="flex justify-between text-xs text-theme-secondary mb-1">
<span>{{ __('Progress') }}</span>
<span>{{ number_format($processedCount) }} / {{ number_format($mailing->recipients_count) }}</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-theme-brand h-2 rounded-full transition-all" style="width: {{ $progressPct }}%"></div>
</div>
</div>
@endif
{{-- Results table --}}
<table class="w-full text-xs" style="border-collapse: collapse;">
<tbody>
<tr>
<td style="padding: 3px 8px 3px 0; white-space: nowrap;" class="text-theme-secondary">{{ __('Successfully sent') }}</td>
<td style="padding: 3px 0 3px 8px; text-align: right; padding-right: 0.5rem;" class="text-theme-secondary">
{{ number_format($mailing->sent_count) }}
</td>
</tr>
<tr>
<td style="padding: 3px 8px 3px 0; white-space: nowrap;" class="text-theme-secondary">{{ __('Failed (delivery error)') }}</td>
<td style="padding: 3px 0 3px 8px; text-align: right; padding-right: 0.5rem;">
@if($mailing->failed_count > 0)
<span class="font-medium rounded bg-theme-danger-light text-theme-danger-dark" style="padding: 2px 6px;">
{{ number_format($mailing->failed_count) }}
</span>
@else
<span class="text-theme-secondary">0</span>
@endif
</td>
</tr>
@if($mailing->skipped_count > 0)
<tr>
<td style="padding: 3px 8px 3px 0; white-space: nowrap;" class="text-theme-secondary">
{{ __('Skipped (hard bounce)') }}
</td>
<td style="padding: 3px 0 3px 8px; text-align: right; padding-right: 0.5rem;">
<span class="font-medium rounded bg-gray-100 text-gray-700" style="padding: 2px 6px;">
{{ number_format($mailing->skipped_count) }}
</span>
</td>
</tr>
@endif
@if($mailing->aborted_count > 0)
<tr>
<td style="padding: 3px 8px 3px 0; white-space: nowrap;" class="text-theme-secondary">{{ __('Not sent (aborted)') }}</td>
<td style="padding: 3px 0 3px 8px; text-align: right; padding-right: 0.5rem;">
<span class="font-medium rounded bg-red-100 text-red-800" style="padding: 2px 6px;">
{{ number_format($mailing->aborted_count) }}
</span>
</td>
</tr>
@endif
@if($bounceStats['hard'] > 0)
<tr>
<td style="padding: 3px 8px 3px 0; white-space: nowrap;" class="text-theme-secondary">{{ __('Bounced (hard)') }}</td>
<td style="padding: 3px 0 3px 8px; text-align: right; padding-right: 0.5rem;">
<span class="font-medium rounded bg-red-100 text-red-800" style="padding: 2px 6px;">
{{ number_format($bounceStats['hard']) }}
</span>
</td>
</tr>
@endif
@if($bounceStats['soft'] > 0)
<tr>
<td style="padding: 3px 8px 3px 0; white-space: nowrap;" class="text-theme-secondary">{{ __('Bounced (soft)') }}</td>
<td style="padding: 3px 0 3px 8px; text-align: right; padding-right: 0.5rem;">
<span class="font-medium rounded bg-amber-100 text-amber-800" style="padding: 2px 6px;">
{{ number_format($bounceStats['soft']) }}
</span>
</td>
</tr>
@endif
@if($bounceStats['complaint'] > 0)
<tr>
<td style="padding: 3px 8px 3px 0; white-space: nowrap;" class="text-theme-secondary">{{ __('Complaints') }}</td>
<td style="padding: 3px 0 3px 8px; text-align: right; padding-right: 0.5rem;">
<span class="font-medium rounded bg-orange-100 text-orange-800" style="padding: 2px 6px;">
{{ number_format($bounceStats['complaint']) }}
</span>
</td>
</tr>
@endif
</tbody>
</table>
{{-- Totals --}}
<div class="mt-3 pt-2 border-t border-theme-border space-y-1">
<div class="flex justify-between text-xs">
<span class="font-medium text-theme-primary">{{ __('Total sent to:') }}</span>
<span class="text-theme-secondary" style="padding-right: 0.5rem;">{{ number_format($mailing->recipients_count) }}</span>
</div>
@if($mailing->sent_count > 0 && $mailing->recipients_count > 0)
<div class="flex justify-between text-xs">
<span class="text-theme-secondary">{{ __('Success rate') }}</span>
<span class="text-theme-secondary" style="padding-right: 0.5rem;">{{ round($mailing->sent_count / $mailing->recipients_count * 100, 1) }}%</span>
</div>
@endif
</div>
</div>
@endif
</div>