From 91caa16e7052480f09c99cdfc3f07fc75cfeab3d Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Sun, 5 Apr 2026 13:34:00 +0200 Subject: [PATCH] feat: Mailwizz overview vs wizard flow and wizard step guard Load Weeztix config for coupon mapping context, redirect incomplete configs to step one, and expand admin Mailwizz UI and tests. Made-with: Cursor --- .../Controllers/Admin/MailwizzController.php | 17 +- lang/nl.json | 1 + resources/views/admin/mailwizz/edit.blade.php | 536 +++++++++++------- tests/Feature/MailwizzConfigUiTest.php | 45 ++ 4 files changed, 385 insertions(+), 214 deletions(-) diff --git a/app/Http/Controllers/Admin/MailwizzController.php b/app/Http/Controllers/Admin/MailwizzController.php index 32a4f56..ce644ad 100644 --- a/app/Http/Controllers/Admin/MailwizzController.php +++ b/app/Http/Controllers/Admin/MailwizzController.php @@ -8,18 +8,29 @@ use App\Http\Controllers\Controller; use App\Http\Requests\Admin\UpdateMailwizzConfigRequest; use App\Models\PreregistrationPage; use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\View\View; class MailwizzController extends Controller { - public function edit(PreregistrationPage $page): View + public function edit(Request $request, PreregistrationPage $page): View|RedirectResponse { $this->authorize('update', $page); - $page->load('mailwizzConfig'); + $page->load(['mailwizzConfig', 'weeztixConfig']); - return view('admin.mailwizz.edit', compact('page')); + $config = $page->mailwizzConfig; + $showWizard = $config === null || $request->boolean('wizard'); + if ($showWizard && $config === null) { + $requestedStep = min(4, max(1, (int) $request->query('step', 1))); + if ($requestedStep !== 1) { + return redirect() + ->route('admin.pages.mailwizz.edit', ['page' => $page, 'wizard' => 1, 'step' => 1]); + } + } + + return view('admin.mailwizz.edit', compact('page', 'showWizard')); } public function update(UpdateMailwizzConfigRequest $request, PreregistrationPage $page): RedirectResponse diff --git a/lang/nl.json b/lang/nl.json index 33e95e3..5660fc7 100644 --- a/lang/nl.json +++ b/lang/nl.json @@ -14,6 +14,7 @@ "Sending…": "Bezig met verzenden…", "Something went wrong. Please try again.": "Er ging iets mis. Probeer het opnieuw.", "This pre-registration period has ended.": "Deze preregistratieperiode is afgelopen.", + "You will be redirected in :seconds s…": "Je wordt over :seconds seconden doorgestuurd…", "Visit ticket shop": "Ga naar de ticketshop", "Thank you for registering!": "Bedankt voor je registratie!", "You are already registered for this event.": "Je bent al geregistreerd voor dit evenement.", diff --git a/resources/views/admin/mailwizz/edit.blade.php b/resources/views/admin/mailwizz/edit.blade.php index a33a6b9..0799ed2 100644 --- a/resources/views/admin/mailwizz/edit.blade.php +++ b/resources/views/admin/mailwizz/edit.blade.php @@ -2,6 +2,7 @@ $config = $page->mailwizzConfig; $page->loadMissing('weeztixConfig'); $hasWeeztixForCouponMap = $page->weeztixConfig !== null && $page->weeztixConfig->is_connected; + $mailwizzStatus = $page->mailwizzIntegrationStatus(); $existing = $config !== null ? [ 'list_uid' => $config->list_uid, @@ -24,30 +25,15 @@ @section('mobile_title', __('Mailwizz')) @section('content') -
+
← {{ __('Back to page') }}

{{ __('Mailwizz') }}

{{ __('Page:') }} {{ $page->title }}

+ @include('admin.pages._save_flash') + @if ($errors->any()) @endif - @if ($config !== null) -
-

{{ __('Integration active') }}

-

- {{ __('List:') }} - {{ $config->list_name ?: $config->list_uid }} -

-
+

{{ __('Setup incomplete') }}

+

{{ __('Run the wizard again to finish Mailwizz (API key, list, and field mapping).') }}

+
+ @endif + +
+ + {{ __('Change settings (wizard)') }} + + @csrf @method('DELETE') -
- @endif -
- 1. {{ __('API key') }} - - 2. {{ __('List') }} - - 3. {{ __('Field mapping') }} - - 4. {{ __('Tag / source') }} -
+
+

{{ __('Current configuration') }}

+

{{ __('The API key is stored encrypted and is not shown here.') }}

-
-
+
+
+
{{ __('Connection') }}
+
+ @if ($mailwizzStatus === 'ready') + {{ __('Ready to sync') }} + @else + {{ __('Incomplete') }} + @endif +
+
+
+
{{ __('Mailing list') }}
+
{{ $config->list_name ?: '—' }}
+
+
+
{{ __('List UID') }}
+
{{ $config->list_uid ?: '—' }}
+
+
- {{-- Step 1 --}} -
-

- {{ __('First, create a mailing list in Mailwizz with the required custom fields. Add a custom field of type Checkbox List with an option value you will use to track this pre-registration source.') }} -

+

{{ __('Field mapping') }}

+

{{ __('Mailwizz custom fields are matched by tag.') }}

+
+
+
{{ __('Email') }}
+
{{ $config->field_email ?: '—' }}
+
+
+
{{ __('First name') }}
+
{{ $config->field_first_name ?: '—' }}
+
+
+
{{ __('Last name') }}
+
{{ $config->field_last_name ?: '—' }}
+
+ @if ($page->isPhoneFieldEnabledForSubscribers()) +
+
{{ __('Phone') }}
+
{{ filled($config->field_phone) ? $config->field_phone : '—' }}
+
+ @endif + @if ($hasWeeztixForCouponMap) +
+
{{ __('Kortingscode (Weeztix)') }}
+
{{ filled($config->field_coupon_code) ? $config->field_coupon_code : '—' }}
+
+ @endif +
+
{{ __('Tag / source (checkbox list)') }}
+
{{ filled($config->tag_field) ? $config->tag_field : '—' }}
+
+
+
{{ __('Source tag option') }}
+
{{ filled($config->tag_value) ? $config->tag_value : '—' }}
+
+
+
+ @else +
@if ($config !== null) -

- {{ __('Enter your API key and connect to load Mailwizz data (the same key as before is fine). If you clear the key field before saving, the previously stored key is kept.') }} -

+ @endif -
- - + -
- -
- - {{-- Step 2 --}} -
-
- - -
-
- - -
-
- - {{-- Step 3 --}} -
-

{{ __('Map each local field to the matching Mailwizz custom field (by tag).') }}

- -
- - -
-
- - -
-
- - -
-
- - -
-
- -

{{ __('Koppel aan een tekstveld in Mailwizz om de persoonlijke code in e-mails te tonen.') }}

- -
-
- - + 4 + {{ __('Tag / source') }} +
-

- {{ __('No checkbox list fields were returned for this list. Add one in Mailwizz, then run “Load fields” again from step 2.') }} -

-
- - -
-
+
+
- {{-- Step 4 --}} -
-

{{ __('Choose the checkbox option that marks subscribers from this pre-registration page.') }}

- -
- {{ __('Tag value') }} - -
-

- {{ __('This field has no options defined in Mailwizz. Add options to the checkbox list field, then reload fields.') }} -

- -
- @csrf - @method('PUT') - - - - - - - - - - - -
- -
-
+ + {{-- Step 2 --}} +
+

{{ __('Step 2: Mailing list') }}

+
+ + +
+
+ + +
+
+ + {{-- Step 3 --}} +
+

{{ __('Step 3: Field mapping') }}

+

{{ __('Map each local field to the matching Mailwizz custom field (by tag).') }}

+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +

{{ __('Koppel aan een tekstveld in Mailwizz om de persoonlijke code in e-mails te tonen.') }}

+ +
+
+ + +
+

+ {{ __('No checkbox list fields were returned for this list. Add one in Mailwizz, then run “Load fields” again from step 2.') }} +

+ +
+ + +
+
+ + {{-- Step 4 --}} +
+

{{ __('Step 4: Tag / source') }}

+

{{ __('Choose the checkbox option that marks subscribers from this pre-registration page.') }}

+ +
+ {{ __('Tag value') }} + +
+

+ {{ __('This field has no options defined in Mailwizz. Add options to the checkbox list field, then reload fields.') }} +

+ +
+ @csrf + @method('PUT') + + + + + + + + + + + +
+ + +
+
+
+
-
+ @endif
@endsection diff --git a/tests/Feature/MailwizzConfigUiTest.php b/tests/Feature/MailwizzConfigUiTest.php index 6dcbca6..7430cde 100644 --- a/tests/Feature/MailwizzConfigUiTest.php +++ b/tests/Feature/MailwizzConfigUiTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Tests\Feature; +use App\Models\MailwizzConfig; use App\Models\PreregistrationPage; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -36,6 +37,50 @@ class MailwizzConfigUiTest extends TestCase $response->assertForbidden(); } + public function test_connected_mailwizz_shows_overview_until_wizard_requested(): void + { + $user = User::factory()->create(['role' => 'user']); + $page = $this->makePageForUser($user); + MailwizzConfig::query()->create([ + 'preregistration_page_id' => $page->id, + 'api_key' => 'test-key', + 'list_uid' => 'list-uid-1', + 'list_name' => 'Main list', + 'field_email' => 'EMAIL', + 'field_first_name' => 'FNAME', + 'field_last_name' => 'LNAME', + 'field_phone' => null, + 'field_coupon_code' => null, + 'tag_field' => 'TAGS', + 'tag_value' => 'preregister-source', + ]); + + $overview = $this->actingAs($user)->get(route('admin.pages.mailwizz.edit', $page)); + $overview->assertOk(); + $overview->assertSee('Current configuration', escape: false); + $overview->assertSee('Change settings (wizard)', escape: false); + $overview->assertDontSee('Step 1: API key', escape: false); + + $wizard = $this->actingAs($user)->get(route('admin.pages.mailwizz.edit', [ + 'page' => $page, + 'wizard' => 1, + 'step' => 1, + ])); + $wizard->assertOk(); + $wizard->assertSee('Step 1: API key', escape: false); + $wizard->assertSee('Cancel and return to overview', escape: false); + } + + public function test_mailwizz_wizard_redirects_to_step_one_when_no_config_and_step_gt_one(): void + { + $user = User::factory()->create(['role' => 'user']); + $page = $this->makePageForUser($user); + + $this->actingAs($user) + ->get(route('admin.pages.mailwizz.edit', ['page' => $page, 'wizard' => 1, 'step' => 3])) + ->assertRedirect(route('admin.pages.mailwizz.edit', ['page' => $page, 'wizard' => 1, 'step' => 1])); + } + private function makePageForUser(User $user): PreregistrationPage { return PreregistrationPage::query()->create([