@extends('layouts.dashboard') @section('content') @php /** @var array $rows @var array $pager @var string $filter @var array $statuses @var array $counts */ $filter = $filter ?? ''; $statuses = $statuses ?? []; $counts = $counts ?? []; $tabs = array_merge(['' => t_raw('common.all')], array_combine($statuses, array_map(static fn ($s) => status_label('campaign', $s), $statuses))); $statusPill = static function (string $s): string { return match ($s) { 'active', 'approved' => 'qm-pill-green', 'pending' => 'qm-pill-amber', 'rejected', 'expired' => 'qm-pill-red', 'paused' => 'qm-pill-grey', default => 'qm-pill-grey', }; }; // Past-tense label for a logged moderation action, so the audit note reads as // something that already happened ("Approved by ...") rather than a command. $decidedVerb = static function (string $action): string { return match ($action) { 'approve' => t('admin.campaigns.decided_approved'), 'reject' => t('admin.campaigns.decided_rejected'), 'mark_paid' => t('admin.campaigns.decided_marked_paid'), 'edit' => t('admin.campaigns.decided_edited'), default => ucfirst(str_replace('_', ' ', $action)), }; }; @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp
@php // Page primary action → top-bar subheader slot (leaves the table card header for the // title + any table-scoped utility). ob_start captures the button HTML for the layout slot. ob_start(); @endphp {{ t_raw('admin.campaigns.new_house_title') }} @php \App\Support\View::slot('subhead', ob_get_clean()); @endphp

{{ t_raw('admin.campaigns.list_heading') }}

@if (!empty($counts['pending'])){{ t_raw('admin.comments.pending_badge', [':count' => (int) $counts['pending']]) }}@endif
@php /* The same status tabs the other moderation queues (reviews, comments) wear. */ @endphp
@php /* Period is a start-end date range, not a single Date.parse-able cell, so that carries no data-sort. */ @endphp @if ($rows) @foreach ($rows as $c) @php /* The moderation trail belongs to the decision it explains, so the note, who decided and when ride under the status pill, not in Actions. */ @endphp @endforeach @else @partial('table-empty', ['colspan' => 9, 'icon' => 'fa-bullhorn', 'msg' => t('admin.campaigns.empty')]) @endif
{{ t_raw('admin.campaigns.col_campaign') }}{{ t_raw('common.restaurant') }}{{ t_raw('admin.campaigns.col_placement') }}{{ t_raw('admin.campaigns.col_target') }}{{ t_raw('common.period') }}{{ t_raw('common.price') }}{{ t_raw('common.status') }}{{ t_raw('admin.campaigns.col_payment') }}{{ t_raw('common.actions') }}
{!! media_thumb($c['image'] ?? '', 'assets/client/covers/shop-1.png', 44, 'qm-tbl-thumb') !!}
{{ $c['headline'] }} {{ t_raw(($c['source'] ?? 'vendor') === 'house' ? 'admin.campaigns.source_house' : 'admin.campaigns.source_vendor') }}
{!! restaurant_brandmark(['logo' => $c['logo'] ?? '', 'name' => $c['restaurant_name'] ?? '', 'cuisine_slug' => $c['cuisine_slug'] ?? ''], 'md') !!}
{{ $c['restaurant_name'] }} {{ $c['owner_email'] ?? '' }}
{{ status_label('ad_placement', $c['placement']) }} @php $targetType = (string) ($c['target_type'] ?? 'none'); echo ($targetType === 'none' || empty($c['target_slug'])) ? dash() : status_label('ad_target_type', $targetType) . ': ' . e($c['target_slug']); @endphp @if (!empty($c['starts_at'])) {!! fmt_day($c['starts_at']) !!} – {!! fmt_day($c['ends_at'] ?? null) !!} @else {{ t_raw('admin.campaigns.months_suffix', [':n' => (int) $c['months']]) }} @endif {{ money($c['price']) }} {{ status_label('campaign', $c['status']) }} @if (!empty($c['admin_note']))
{{ $c['admin_note'] }}
@endif @if (!empty($c['decided_at']))
{!! $decidedVerb((string) $c['decided_action']) !!} @if (!empty($c['decided_by_name']) || !empty($c['decided_by_email'])) {{ t_raw('admin.campaigns.decided_by_prefix') }} {{ (string) ($c['decided_by_name'] ?: $c['decided_by_email']) }}@endif
@endif
{{ status_label('payment', $c['payment_status']) }}
@if (($c['source'] ?? 'vendor') === 'house')
@csrf
@elseif ($c['status'] === 'pending') @php /* Approve/Reject as the standard circular row actions; the rejection reason moves into the shared styled dialog (one per page), exactly as restaurant suspensions collect theirs. */ @endphp
@csrf
@endif @php /* A placement is bought outright, so the only thing left to do to a paid one is give the money back — which also stops it running. House ads cost nothing and have nothing to return. */ @endphp @if (($c['source'] ?? 'vendor') !== 'house' && ($c['payment_status'] ?? '') === 'paid' && (float) ($c['price'] ?? 0) > 0)
@csrf
@endif
@partial('table-toolbar', ['pager' => $pager, 'base' => '/admin/campaigns'])
@partial('campaign-reject-reason')
@php /* /.qm-d2 */ @endphp @endsection