Files
bert.hausmans 845665c8be feat: per-subscriber Mailwizz sync button on admin list
Add POST route and form request to queue SyncSubscriberToMailwizz for one
subscriber when the page has Mailwizz configured. Include Dutch strings
and feature tests for auth and edge cases.

Made-with: Cursor
2026-04-05 13:45:30 +02:00

139 lines
9.8 KiB
PHP

@extends('layouts.admin')
@section('title', __('Subscribers') . ' — ' . $page->title)
@section('mobile_title', __('Subscribers'))
@section('content')
<div class="mx-auto max-w-7xl">
<div class="mb-8">
<a href="{{ route('admin.pages.index') }}" class="text-sm font-medium text-indigo-600 hover:text-indigo-500"> {{ __('Back to pages') }}</a>
<h1 class="mt-4 text-2xl font-semibold text-slate-900">{{ __('Subscribers') }}</h1>
<p class="mt-1 text-sm text-slate-600">{{ $page->title }}</p>
</div>
<div class="mb-6 flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
<form method="get" action="{{ route('admin.pages.subscribers.index', $page) }}" class="flex flex-1 flex-col gap-2 sm:max-w-md">
<label for="search" class="text-sm font-medium text-slate-700">{{ __('Search by name or email') }}</label>
<div class="flex gap-2">
<input type="search" name="search" id="search" value="{{ request('search') }}"
class="block w-full rounded-lg border-slate-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" placeholder="{{ __('Search…') }}" />
<button type="submit" class="rounded-lg bg-slate-800 px-4 py-2 text-sm font-semibold text-white hover:bg-slate-700">{{ __('Filter') }}</button>
</div>
@error('search')
<p class="text-sm text-red-600">{{ $message }}</p>
@enderror
</form>
<div class="flex flex-wrap items-center gap-2">
@if ($unsyncedMailwizzCount > 0)
<form method="post" action="{{ route('admin.pages.subscribers.queue-mailwizz-sync', $page) }}" class="inline"
onsubmit="return confirm(@js(__('Queue Mailwizz sync jobs for all :count not-yet-synced subscribers on this page? Duplicates are skipped if a job is already pending.', ['count' => $unsyncedMailwizzCount])));">
@csrf
<button type="submit" class="inline-flex items-center justify-center rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500">
{{ __('Queue Mailwizz sync') }} ({{ $unsyncedMailwizzCount }})
</button>
</form>
@endif
<a href="{{ route('admin.pages.subscribers.export', $page) }}{{ request()->filled('search') ? '?'.http_build_query(['search' => request('search')]) : '' }}"
class="inline-flex items-center justify-center rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-700 shadow-sm hover:bg-slate-50">
{{ __('Export CSV') }}
</a>
</div>
</div>
<div class="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-slate-200 text-left text-sm">
<thead class="bg-slate-50">
<tr>
<th class="px-4 py-3 font-semibold text-slate-700">{{ __('First name') }}</th>
<th class="px-4 py-3 font-semibold text-slate-700">{{ __('Last name') }}</th>
<th class="px-4 py-3 font-semibold text-slate-700">{{ __('Email') }}</th>
@if ($page->isPhoneFieldEnabledForSubscribers())
<th class="px-4 py-3 font-semibold text-slate-700">{{ __('Phone') }}</th>
@endif
<th class="px-4 py-3 font-semibold text-slate-700">{{ __('Kortingscode') }}</th>
<th class="px-4 py-3 font-semibold text-slate-700">{{ __('Registered at') }}</th>
<th class="px-4 py-3 font-semibold text-slate-700">{{ __('Mailwizz') }}</th>
<th class="w-px whitespace-nowrap px-4 py-3 font-semibold text-slate-700">{{ __('Actions') }}</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
@forelse ($subscribers as $subscriber)
<tr class="hover:bg-slate-50/80">
<td class="px-4 py-3 text-slate-900">{{ $subscriber->first_name }}</td>
<td class="px-4 py-3 text-slate-900">{{ $subscriber->last_name }}</td>
<td class="px-4 py-3 text-slate-600">{{ $subscriber->email }}</td>
@if ($page->isPhoneFieldEnabledForSubscribers())
<td class="px-4 py-3 text-slate-600">{{ $subscriber->phoneDisplay() ?? '—' }}</td>
@endif
<td class="px-4 py-3 font-mono text-xs text-slate-700">{{ $subscriber->coupon_code ?? '—' }}</td>
<td class="whitespace-nowrap px-4 py-3 text-slate-600">{{ $subscriber->created_at->timezone(config('app.timezone'))->format('Y-m-d H:i') }}</td>
<td class="px-4 py-3">
@if ($subscriber->synced_to_mailwizz)
<span class="inline-flex h-8 w-8 items-center justify-center rounded-full bg-emerald-100 text-emerald-700" title="{{ __('Synced') }}">
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
</span>
@else
<span class="inline-flex h-8 w-8 items-center justify-center rounded-full bg-slate-100 text-slate-500" title="{{ __('Not synced') }}">
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
</span>
@endif
</td>
<td class="whitespace-nowrap px-4 py-3 text-right">
@can('update', $page)
<div class="inline-flex flex-wrap items-center justify-end gap-1.5">
@if ($page->mailwizzConfig !== null)
<form
method="post"
action="{{ route('admin.pages.subscribers.sync-mailwizz', [$page, $subscriber]) }}"
class="inline"
onsubmit="return confirm(@js(__('Queue a Mailwizz sync for this subscriber? The tag and coupon code will be sent when the queue worker runs.')));"
>
@csrf
<button
type="submit"
class="rounded-lg border border-indigo-200 bg-white px-2.5 py-1 text-xs font-semibold text-indigo-700 hover:bg-indigo-50"
>
{{ __('Sync Mailwizz') }}
</button>
</form>
@endif
<form
method="post"
action="{{ route('admin.pages.subscribers.destroy', [$page, $subscriber]) }}"
class="inline"
onsubmit="return confirm(@js(__('Delete this subscriber? This cannot be undone.')));"
>
@csrf
@method('DELETE')
<button
type="submit"
class="rounded-lg border border-red-200 bg-white px-2.5 py-1 text-xs font-semibold text-red-700 hover:bg-red-50"
>
{{ __('Remove') }}
</button>
</form>
</div>
@endcan
</td>
</tr>
@empty
<tr>
<td colspan="{{ $page->isPhoneFieldEnabledForSubscribers() ? 8 : 7 }}" class="px-4 py-12 text-center text-slate-500">
{{ __('No subscribers match your criteria.') }}
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if ($subscribers->hasPages())
<div class="border-t border-slate-200 px-4 py-3">
{{ $subscribers->links() }}
</div>
@endif
</div>
</div>
@endsection