feat(admin): Weeztix setup wizard, integration status badges
- Summary view when Weeztix is configured; edits only via 3-step wizard - Step 1: reuse or replace OAuth client ID/secret; callback URL shown - Step 2: OAuth connect (resume wizard after callback when started from wizard) - Step 3: coupon, prefix, usage; finishing exits wizard - PreregistrationPage: mailwizz/weeztix integration status helpers - Pages index: Integrations column with MW/WZ badges; edit page: status cards Made-with: Cursor
This commit is contained in:
@@ -28,7 +28,7 @@ class PageController extends Controller
|
|||||||
{
|
{
|
||||||
$query = PreregistrationPage::query()
|
$query = PreregistrationPage::query()
|
||||||
->withCount('subscribers')
|
->withCount('subscribers')
|
||||||
->with('weeztixConfig')
|
->with(['weeztixConfig', 'mailwizzConfig'])
|
||||||
->orderByDesc('start_date');
|
->orderByDesc('start_date');
|
||||||
|
|
||||||
if (! $request->user()?->isSuperadmin()) {
|
if (! $request->user()?->isSuperadmin()) {
|
||||||
@@ -86,7 +86,11 @@ class PageController extends Controller
|
|||||||
|
|
||||||
public function edit(PreregistrationPage $page): View
|
public function edit(PreregistrationPage $page): View
|
||||||
{
|
{
|
||||||
$page->load(['blocks' => fn ($q) => $q->orderBy('sort_order')]);
|
$page->load([
|
||||||
|
'blocks' => fn ($q) => $q->orderBy('sort_order'),
|
||||||
|
'mailwizzConfig',
|
||||||
|
'weeztixConfig',
|
||||||
|
]);
|
||||||
|
|
||||||
return view('admin.pages.edit', compact('page'));
|
return view('admin.pages.edit', compact('page'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,34 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Http\Requests\Admin\UpdateWeeztixConfigRequest;
|
use App\Http\Requests\Admin\UpdateWeeztixConfigRequest;
|
||||||
use App\Models\PreregistrationPage;
|
use App\Models\PreregistrationPage;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
class WeeztixController extends Controller
|
class WeeztixController extends Controller
|
||||||
{
|
{
|
||||||
public function edit(PreregistrationPage $page): View
|
public function edit(Request $request, PreregistrationPage $page): View
|
||||||
{
|
{
|
||||||
$this->authorize('update', $page);
|
$this->authorize('update', $page);
|
||||||
|
|
||||||
$page->load('weeztixConfig');
|
$page->load('weeztixConfig');
|
||||||
|
|
||||||
return view('admin.weeztix.edit', compact('page'));
|
$showWizard = $page->weeztixConfig === null || $request->boolean('wizard');
|
||||||
|
$wizardStep = $showWizard ? min(3, max(1, (int) $request->query('step', 1))) : 1;
|
||||||
|
if ($showWizard && $page->weeztixConfig === null && $wizardStep !== 1) {
|
||||||
|
return redirect()
|
||||||
|
->route('admin.pages.weeztix.edit', ['page' => $page, 'wizard' => 1, 'step' => 1]);
|
||||||
|
}
|
||||||
|
$hasStoredCredentials = $page->weeztixConfig !== null
|
||||||
|
&& is_string($page->weeztixConfig->client_id)
|
||||||
|
&& $page->weeztixConfig->client_id !== '';
|
||||||
|
|
||||||
|
return view('admin.weeztix.edit', compact(
|
||||||
|
'page',
|
||||||
|
'showWizard',
|
||||||
|
'wizardStep',
|
||||||
|
'hasStoredCredentials'
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(UpdateWeeztixConfigRequest $request, PreregistrationPage $page): RedirectResponse
|
public function update(UpdateWeeztixConfigRequest $request, PreregistrationPage $page): RedirectResponse
|
||||||
@@ -41,8 +57,26 @@ class WeeztixController extends Controller
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$page->load('weeztixConfig');
|
||||||
|
|
||||||
|
if ($request->boolean('wizard')) {
|
||||||
|
if ($request->boolean('wizard_coupon_save')) {
|
||||||
|
return redirect()
|
||||||
|
->route('admin.pages.weeztix.edit', ['page' => $page])
|
||||||
|
->with('status', __('Weeztix-configuratie opgeslagen.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('admin.pages.weeztix.edit', [
|
||||||
|
'page' => $page,
|
||||||
|
'wizard' => 1,
|
||||||
|
'step' => 2,
|
||||||
|
])
|
||||||
|
->with('status', __('Weeztix-configuratie opgeslagen.'));
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('admin.pages.weeztix.edit', $page)
|
->route('admin.pages.weeztix.edit', ['page' => $page])
|
||||||
->with('status', __('Weeztix-configuratie opgeslagen.'));
|
->with('status', __('Weeztix-configuratie opgeslagen.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use RuntimeException;
|
|||||||
|
|
||||||
class WeeztixOAuthController extends Controller
|
class WeeztixOAuthController extends Controller
|
||||||
{
|
{
|
||||||
public function redirect(PreregistrationPage $page): RedirectResponse
|
public function redirect(Request $request, PreregistrationPage $page): RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('update', $page);
|
$this->authorize('update', $page);
|
||||||
|
|
||||||
@@ -38,6 +38,7 @@ class WeeztixOAuthController extends Controller
|
|||||||
session([
|
session([
|
||||||
'weeztix_oauth_state' => $state,
|
'weeztix_oauth_state' => $state,
|
||||||
'weeztix_page_id' => $page->id,
|
'weeztix_page_id' => $page->id,
|
||||||
|
'weeztix_oauth_resume_wizard' => $request->boolean('wizard'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$redirectUri = $config->redirect_uri;
|
$redirectUri = $config->redirect_uri;
|
||||||
@@ -90,7 +91,7 @@ class WeeztixOAuthController extends Controller
|
|||||||
|
|
||||||
$config = $page->weeztixConfig;
|
$config = $page->weeztixConfig;
|
||||||
if ($config === null) {
|
if ($config === null) {
|
||||||
session()->forget(['weeztix_oauth_state', 'weeztix_page_id']);
|
$this->forgetOauthSession();
|
||||||
|
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('admin.pages.weeztix.edit', $page)
|
->route('admin.pages.weeztix.edit', $page)
|
||||||
@@ -110,30 +111,52 @@ class WeeztixOAuthController extends Controller
|
|||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
session()->forget(['weeztix_oauth_state', 'weeztix_page_id']);
|
$resumeWizard = $this->forgetOauthSession();
|
||||||
|
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('admin.pages.weeztix.edit', $page)
|
->route('admin.pages.weeztix.edit', $this->weeztixEditParams($page, $resumeWizard, 2))
|
||||||
->with('error', __('Verbinden met Weeztix is mislukt. Controleer je gegevens en probeer opnieuw.'));
|
->with('error', __('Verbinden met Weeztix is mislukt. Controleer je gegevens en probeer opnieuw.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
session()->forget(['weeztix_oauth_state', 'weeztix_page_id']);
|
$resumeWizard = $this->forgetOauthSession();
|
||||||
|
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('admin.pages.weeztix.edit', $page)
|
->route('admin.pages.weeztix.edit', $this->weeztixEditParams($page, $resumeWizard, 3))
|
||||||
->with('status', __('Succesvol verbonden met Weeztix.'));
|
->with('status', __('Succesvol verbonden met Weeztix.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{page: PreregistrationPage, wizard?: int, step?: int}
|
||||||
|
*/
|
||||||
|
private function weeztixEditParams(PreregistrationPage $page, bool $resumeWizard, int $step): array
|
||||||
|
{
|
||||||
|
$params = ['page' => $page];
|
||||||
|
if ($resumeWizard) {
|
||||||
|
$params['wizard'] = 1;
|
||||||
|
$params['step'] = $step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function forgetOauthSession(): bool
|
||||||
|
{
|
||||||
|
$resumeWizard = (bool) session()->pull('weeztix_oauth_resume_wizard', false);
|
||||||
|
session()->forget(['weeztix_oauth_state', 'weeztix_page_id']);
|
||||||
|
|
||||||
|
return $resumeWizard;
|
||||||
|
}
|
||||||
|
|
||||||
private function redirectToWeeztixEditWithSessionPage(string $message): RedirectResponse
|
private function redirectToWeeztixEditWithSessionPage(string $message): RedirectResponse
|
||||||
{
|
{
|
||||||
$pageId = session('weeztix_page_id');
|
$pageId = session('weeztix_page_id');
|
||||||
session()->forget(['weeztix_oauth_state', 'weeztix_page_id']);
|
$resumeWizard = $this->forgetOauthSession();
|
||||||
|
|
||||||
if (is_int($pageId) || is_numeric($pageId)) {
|
if (is_int($pageId) || is_numeric($pageId)) {
|
||||||
$page = PreregistrationPage::query()->find((int) $pageId);
|
$page = PreregistrationPage::query()->find((int) $pageId);
|
||||||
if ($page !== null) {
|
if ($page !== null) {
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('admin.pages.weeztix.edit', $page)
|
->route('admin.pages.weeztix.edit', $this->weeztixEditParams($page, $resumeWizard, 2))
|
||||||
->with('error', $message);
|
->with('error', $message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,4 +204,56 @@ class PreregistrationPage extends Model
|
|||||||
|
|
||||||
return 'active';
|
return 'active';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mailwizz setup depth for admin UI (API key + list + email field = ready to sync).
|
||||||
|
*
|
||||||
|
* @return 'none'|'partial'|'ready'
|
||||||
|
*/
|
||||||
|
public function mailwizzIntegrationStatus(): string
|
||||||
|
{
|
||||||
|
$c = $this->mailwizzConfig;
|
||||||
|
if ($c === null) {
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $c->api_key;
|
||||||
|
if (! is_string($key) || $key === '') {
|
||||||
|
return 'partial';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_string($c->list_uid) || $c->list_uid === '' || ! is_string($c->field_email) || $c->field_email === '') {
|
||||||
|
return 'partial';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'ready';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weeztix setup depth for admin UI.
|
||||||
|
*
|
||||||
|
* @return 'none'|'credentials'|'connected'|'ready'
|
||||||
|
*/
|
||||||
|
public function weeztixIntegrationStatus(): string
|
||||||
|
{
|
||||||
|
$c = $this->weeztixConfig;
|
||||||
|
if ($c === null) {
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
$hasClient = is_string($c->client_id) && $c->client_id !== '';
|
||||||
|
if (! $hasClient) {
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $c->is_connected) {
|
||||||
|
return 'credentials';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_string($c->coupon_guid) || $c->coupon_guid === '') {
|
||||||
|
return 'connected';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'ready';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
resources/views/admin/pages/_integration_badges.blade.php
Normal file
55
resources/views/admin/pages/_integration_badges.blade.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
@php
|
||||||
|
$only = $only ?? null;
|
||||||
|
$integrationBadgeClass = $integrationBadgeClass ?? '';
|
||||||
|
if (! in_array($only, [null, 'mailwizz', 'weeztix'], true)) {
|
||||||
|
$only = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mailwizz = $page->mailwizzIntegrationStatus();
|
||||||
|
$weeztix = $page->weeztixIntegrationStatus();
|
||||||
|
|
||||||
|
$mailwizzClasses = match ($mailwizz) {
|
||||||
|
'ready' => 'border-emerald-200 bg-emerald-50 text-emerald-900',
|
||||||
|
'partial' => 'border-amber-200 bg-amber-50 text-amber-950',
|
||||||
|
default => 'border-slate-200 bg-slate-50 text-slate-600',
|
||||||
|
};
|
||||||
|
$mailwizzLabel = match ($mailwizz) {
|
||||||
|
'ready' => __('Ready'),
|
||||||
|
'partial' => __('Incomplete'),
|
||||||
|
default => __('Off'),
|
||||||
|
};
|
||||||
|
|
||||||
|
$weeztixClasses = match ($weeztix) {
|
||||||
|
'ready' => 'border-emerald-200 bg-emerald-50 text-emerald-900',
|
||||||
|
'connected' => 'border-sky-200 bg-sky-50 text-sky-950',
|
||||||
|
'credentials' => 'border-amber-200 bg-amber-50 text-amber-950',
|
||||||
|
default => 'border-slate-200 bg-slate-50 text-slate-600',
|
||||||
|
};
|
||||||
|
$weeztixLabel = match ($weeztix) {
|
||||||
|
'ready' => __('Ready'),
|
||||||
|
'connected' => __('Connected'),
|
||||||
|
'credentials' => __('OAuth only'),
|
||||||
|
default => __('Off'),
|
||||||
|
};
|
||||||
|
|
||||||
|
$showMailwizz = $only === null || $only === 'mailwizz';
|
||||||
|
$showWeeztix = $only === null || $only === 'weeztix';
|
||||||
|
@endphp
|
||||||
|
<div class="flex flex-wrap items-center gap-1.5 {{ $integrationBadgeClass }}">
|
||||||
|
@if ($showMailwizz)
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium {{ $mailwizzClasses }}"
|
||||||
|
title="{{ __('Mailwizz: :state', ['state' => $mailwizzLabel]) }}"
|
||||||
|
>
|
||||||
|
{{ __('MW') }} · {{ $mailwizzLabel }}
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
@if ($showWeeztix)
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium {{ $weeztixClasses }}"
|
||||||
|
title="{{ __('Weeztix: :state', ['state' => $weeztixLabel]) }}"
|
||||||
|
>
|
||||||
|
{{ __('WZ') }} · {{ $weeztixLabel }}
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
@@ -13,10 +13,30 @@
|
|||||||
{{ __('Public URL') }}: <a href="{{ route('public.page', ['publicPage' => $page]) }}" class="text-indigo-600 hover:underline" target="_blank" rel="noopener">{{ url('/r/'.$page->slug) }}</a>
|
{{ __('Public URL') }}: <a href="{{ route('public.page', ['publicPage' => $page]) }}" class="text-indigo-600 hover:underline" target="_blank" rel="noopener">{{ url('/r/'.$page->slug) }}</a>
|
||||||
</p>
|
</p>
|
||||||
@can('update', $page)
|
@can('update', $page)
|
||||||
<p class="mt-3 flex flex-wrap gap-x-4 gap-y-1">
|
<div class="mt-6 grid gap-4 sm:grid-cols-2">
|
||||||
<a href="{{ route('admin.pages.mailwizz.edit', $page) }}" class="text-sm font-medium text-indigo-600 hover:text-indigo-500">{{ __('Mailwizz integration') }} →</a>
|
<a
|
||||||
<a href="{{ route('admin.pages.weeztix.edit', $page) }}" class="text-sm font-medium text-indigo-600 hover:text-indigo-500">{{ __('Weeztix integration') }} →</a>
|
href="{{ route('admin.pages.mailwizz.edit', $page) }}"
|
||||||
</p>
|
class="group flex flex-col rounded-xl border border-slate-200 bg-white p-4 shadow-sm transition hover:border-indigo-200 hover:shadow-md"
|
||||||
|
>
|
||||||
|
<div class="flex items-start justify-between gap-3">
|
||||||
|
<h2 class="text-sm font-semibold text-slate-900">{{ __('Mailwizz') }}</h2>
|
||||||
|
@include('admin.pages._integration_badges', ['page' => $page, 'only' => 'mailwizz', 'integrationBadgeClass' => 'justify-end'])
|
||||||
|
</div>
|
||||||
|
<p class="mt-2 flex-1 text-xs text-slate-600">{{ __('Sync subscribers to your Mailwizz list and map fields.') }}</p>
|
||||||
|
<span class="mt-3 text-sm font-medium text-indigo-600 group-hover:text-indigo-500">{{ __('Open Mailwizz') }} →</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="{{ route('admin.pages.weeztix.edit', $page) }}"
|
||||||
|
class="group flex flex-col rounded-xl border border-slate-200 bg-white p-4 shadow-sm transition hover:border-indigo-200 hover:shadow-md"
|
||||||
|
>
|
||||||
|
<div class="flex items-start justify-between gap-3">
|
||||||
|
<h2 class="text-sm font-semibold text-slate-900">{{ __('Weeztix') }}</h2>
|
||||||
|
@include('admin.pages._integration_badges', ['page' => $page, 'only' => 'weeztix', 'integrationBadgeClass' => 'justify-end'])
|
||||||
|
</div>
|
||||||
|
<p class="mt-2 flex-1 text-xs text-slate-600">{{ __('Issue unique discount codes via Weeztix when visitors sign up.') }}</p>
|
||||||
|
<span class="mt-3 text-sm font-medium text-indigo-600 group-hover:text-indigo-500">{{ __('Open Weeztix') }} →</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
@endcan
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
<th scope="col" class="px-4 py-3 font-semibold text-slate-700">{{ __('Start') }}</th>
|
<th scope="col" class="px-4 py-3 font-semibold text-slate-700">{{ __('Start') }}</th>
|
||||||
<th scope="col" class="px-4 py-3 font-semibold text-slate-700">{{ __('End') }}</th>
|
<th scope="col" class="px-4 py-3 font-semibold text-slate-700">{{ __('End') }}</th>
|
||||||
<th scope="col" class="px-4 py-3 font-semibold text-slate-700">{{ __('Subscribers') }}</th>
|
<th scope="col" class="px-4 py-3 font-semibold text-slate-700">{{ __('Subscribers') }}</th>
|
||||||
|
<th scope="col" class="px-4 py-3 font-semibold text-slate-700">{{ __('Integrations') }}</th>
|
||||||
<th scope="col" class="px-4 py-3 text-right font-semibold text-slate-700">{{ __('Actions') }}</th>
|
<th scope="col" class="px-4 py-3 text-right font-semibold text-slate-700">{{ __('Actions') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -64,6 +65,9 @@
|
|||||||
<td class="whitespace-nowrap px-4 py-3 text-slate-600">{{ $page->start_date->timezone(config('app.timezone'))->format('Y-m-d H:i') }}</td>
|
<td class="whitespace-nowrap px-4 py-3 text-slate-600">{{ $page->start_date->timezone(config('app.timezone'))->format('Y-m-d H:i') }}</td>
|
||||||
<td class="whitespace-nowrap px-4 py-3 text-slate-600">{{ $page->end_date->timezone(config('app.timezone'))->format('Y-m-d H:i') }}</td>
|
<td class="whitespace-nowrap px-4 py-3 text-slate-600">{{ $page->end_date->timezone(config('app.timezone'))->format('Y-m-d H:i') }}</td>
|
||||||
<td class="whitespace-nowrap px-4 py-3 tabular-nums text-slate-600">{{ number_format($page->subscribers_count) }}</td>
|
<td class="whitespace-nowrap px-4 py-3 tabular-nums text-slate-600">{{ number_format($page->subscribers_count) }}</td>
|
||||||
|
<td class="px-4 py-3">
|
||||||
|
@include('admin.pages._integration_badges', ['page' => $page])
|
||||||
|
</td>
|
||||||
<td class="whitespace-nowrap px-4 py-3 text-right">
|
<td class="whitespace-nowrap px-4 py-3 text-right">
|
||||||
<div class="flex flex-wrap items-center justify-end gap-2">
|
<div class="flex flex-wrap items-center justify-end gap-2">
|
||||||
@can('update', $page)
|
@can('update', $page)
|
||||||
@@ -77,9 +81,6 @@
|
|||||||
@endcan
|
@endcan
|
||||||
@can('update', $page)
|
@can('update', $page)
|
||||||
<a href="{{ route('admin.pages.weeztix.edit', $page) }}" class="text-indigo-600 hover:text-indigo-500">{{ __('Weeztix') }}</a>
|
<a href="{{ route('admin.pages.weeztix.edit', $page) }}" class="text-indigo-600 hover:text-indigo-500">{{ __('Weeztix') }}</a>
|
||||||
@if ($page->weeztixConfig?->is_connected)
|
|
||||||
<span class="text-xs font-medium text-emerald-600" title="{{ __('Weeztix verbonden') }}">●</span>
|
|
||||||
@endif
|
|
||||||
@endcan
|
@endcan
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -103,7 +104,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="{{ auth()->user()->isSuperadmin() ? 7 : 6 }}" class="px-4 py-12 text-center text-slate-500">
|
<td colspan="{{ auth()->user()->isSuperadmin() ? 8 : 7 }}" class="px-4 py-12 text-center text-slate-500">
|
||||||
{{ __('No pages yet.') }}
|
{{ __('No pages yet.') }}
|
||||||
@can('create', \App\Models\PreregistrationPage::class)
|
@can('create', \App\Models\PreregistrationPage::class)
|
||||||
<a href="{{ route('admin.pages.create') }}" class="font-medium text-indigo-600 hover:text-indigo-500">{{ __('Create one') }}</a>
|
<a href="{{ route('admin.pages.create') }}" class="font-medium text-indigo-600 hover:text-indigo-500">{{ __('Create one') }}</a>
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
'usage_count' => $wz->usage_count,
|
'usage_count' => $wz->usage_count,
|
||||||
]
|
]
|
||||||
: null;
|
: null;
|
||||||
|
$credentialsEdit = ! $hasStoredCredentials || request()->query('credentials') === 'edit';
|
||||||
|
$oauthUrl = route('admin.pages.weeztix.oauth.redirect', ['page' => $page, 'wizard' => 1]);
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
@extends('layouts.admin')
|
@extends('layouts.admin')
|
||||||
@@ -18,25 +20,7 @@
|
|||||||
@section('mobile_title', __('Weeztix'))
|
@section('mobile_title', __('Weeztix'))
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div
|
<div class="mx-auto max-w-3xl">
|
||||||
class="mx-auto max-w-3xl"
|
|
||||||
x-data="weeztixSetup(@js([
|
|
||||||
'pageId' => $page->id,
|
|
||||||
'couponsUrl' => route('admin.weeztix.coupons'),
|
|
||||||
'csrf' => csrf_token(),
|
|
||||||
'isConnected' => $wz?->is_connected ?? false,
|
|
||||||
'tokenExpiresAt' => $wz?->token_expires_at instanceof Carbon ? $wz->token_expires_at->timezone(config('app.timezone'))->format('Y-m-d H:i') : null,
|
|
||||||
'callbackUrl' => route('admin.weeztix.callback', absolute: true),
|
|
||||||
'existing' => $existing,
|
|
||||||
'strings' => [
|
|
||||||
'genericError' => __('Er ging iets mis. Probeer het opnieuw.'),
|
|
||||||
'loadCouponsError' => __('Kon kortingsbonnen niet laden.'),
|
|
||||||
'refreshCoupons' => __('Vernieuwen'),
|
|
||||||
'refreshCouponsBusy' => __('Bezig…'),
|
|
||||||
'refreshCouponsTitle' => __('Couponlijst opnieuw ophalen van Weeztix'),
|
|
||||||
],
|
|
||||||
]))"
|
|
||||||
>
|
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<a href="{{ route('admin.pages.edit', $page) }}" class="text-sm font-medium text-indigo-600 hover:text-indigo-500">← {{ __('Terug naar pagina') }}</a>
|
<a href="{{ route('admin.pages.edit', $page) }}" class="text-sm font-medium text-indigo-600 hover:text-indigo-500">← {{ __('Terug naar pagina') }}</a>
|
||||||
<h1 class="mt-4 text-2xl font-semibold text-slate-900">{{ __('Weeztix') }}</h1>
|
<h1 class="mt-4 text-2xl font-semibold text-slate-900">{{ __('Weeztix') }}</h1>
|
||||||
@@ -56,183 +40,304 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if ($wz !== null && $wz->is_connected && ($wz->company_guid === null || $wz->company_guid === ''))
|
@if (! $showWizard && $wz !== null)
|
||||||
<div class="mb-8 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-950">
|
{{-- Summary (read-only): change only via wizard --}}
|
||||||
<p class="font-medium">{{ __('Bedrijf nog niet vastgelegd') }}</p>
|
@if ($wz->is_connected && ($wz->company_guid === null || $wz->company_guid === ''))
|
||||||
<p class="mt-1 text-amber-900">{{ __('Verbind opnieuw met Weeztix zodat het juiste bedrijf automatisch wordt gekoppeld.') }}</p>
|
<div class="mb-6 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-950">
|
||||||
</div>
|
<p class="font-medium">{{ __('Bedrijf nog niet vastgelegd') }}</p>
|
||||||
@endif
|
<p class="mt-1 text-amber-900">{{ __('Start de wizard en verbind opnieuw met Weeztix zodat het bedrijf automatisch wordt gekoppeld.') }}</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
@if ($wz !== null && $wz->is_connected)
|
<div class="mb-6 flex flex-wrap items-center gap-3">
|
||||||
<div class="mb-8 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-900">
|
<a
|
||||||
<p class="font-medium">{{ __('Verbonden met Weeztix') }}</p>
|
href="{{ route('admin.pages.weeztix.edit', ['page' => $page, 'wizard' => 1, 'step' => 1]) }}"
|
||||||
@if ($wz->token_expires_at)
|
class="inline-flex rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500"
|
||||||
<p class="mt-1 text-emerald-800">
|
>
|
||||||
{{ __('Huidig toegangstoken tot:') }}
|
{{ __('Instellingen wijzigen (wizard)') }}
|
||||||
<span class="font-mono text-xs">{{ $wz->token_expires_at->timezone(config('app.timezone'))->format('Y-m-d H:i') }}</span>
|
</a>
|
||||||
</p>
|
<form action="{{ route('admin.pages.weeztix.destroy', $page) }}" method="post" class="inline"
|
||||||
<p class="mt-2 text-emerald-800/90">
|
onsubmit="return confirm(@js(__('Weeztix-integratie voor deze pagina verwijderen? Opgeslagen tokens worden gewist.')));">
|
||||||
{{ __('Het toegangstoken wordt automatisch vernieuwd bij API-gebruik (o.a. kortingscodes), zolang de refresh-token geldig is. Je hoeft niet opnieuw te verbinden.') }}
|
|
||||||
</p>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@elseif ($wz !== null && ! $wz->is_connected)
|
|
||||||
<div class="mb-8 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-950">
|
|
||||||
<p class="font-medium">{{ __('Niet verbonden') }}</p>
|
|
||||||
<p class="mt-1 text-amber-900">{{ __('Je moet opnieuw verbinden om kortingscodes aan te maken. Gebruik de knop “Verbind met Weeztix”.') }}</p>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if ($wz !== null)
|
|
||||||
<form action="{{ route('admin.pages.weeztix.destroy', $page) }}" method="post" class="mb-8"
|
|
||||||
onsubmit="return confirm(@js(__('Weeztix-integratie voor deze pagina verwijderen? Opgeslagen tokens worden gewist.')));">
|
|
||||||
@csrf
|
|
||||||
@method('DELETE')
|
|
||||||
<button type="submit" class="text-sm font-semibold text-red-700 underline hover:text-red-800">
|
|
||||||
{{ __('Weeztix loskoppelen') }}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<div class="rounded-xl border border-slate-200 bg-white p-6 shadow-sm sm:p-8">
|
|
||||||
<div x-show="errorMessage !== ''" x-cloak class="mb-6 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800" x-text="errorMessage"></div>
|
|
||||||
|
|
||||||
<section class="space-y-4 border-b border-slate-100 pb-8">
|
|
||||||
<h2 class="text-lg font-semibold text-slate-900">{{ __('Stap 1: OAuth-gegevens') }}</h2>
|
|
||||||
<p class="text-sm leading-relaxed text-slate-600">
|
|
||||||
{{ __('Maak eerst een OAuth-client in het Weeztix-dashboard en stel de redirect-URI exact in op:') }}
|
|
||||||
</p>
|
|
||||||
<p class="rounded-lg bg-slate-50 px-3 py-2 font-mono text-xs text-slate-800 break-all" x-text="callbackUrl"></p>
|
|
||||||
<p class="text-sm text-slate-600">
|
|
||||||
{{ __('Maak daarna een korting (coupon) in Weeztix; die kies je hierna in stap 2.') }}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<form method="post" action="{{ route('admin.pages.weeztix.update', $page) }}" class="space-y-4">
|
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('DELETE')
|
||||||
<div>
|
<button type="submit" class="rounded-lg border border-red-200 bg-white px-4 py-2.5 text-sm font-semibold text-red-700 shadow-sm hover:bg-red-50">
|
||||||
<label for="weeztix_client_id" class="block text-sm font-medium text-slate-700">{{ __('Client ID') }}</label>
|
{{ __('Weeztix loskoppelen') }}
|
||||||
<input
|
|
||||||
id="weeztix_client_id"
|
|
||||||
name="client_id"
|
|
||||||
type="text"
|
|
||||||
autocomplete="off"
|
|
||||||
value="{{ old('client_id') }}"
|
|
||||||
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
|
||||||
placeholder="{{ $wz !== null ? __('Laat leeg om ongewijzigd te laten') : '' }}"
|
|
||||||
@if ($wz === null) required @endif
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="weeztix_client_secret" class="block text-sm font-medium text-slate-700">{{ __('Client secret') }}</label>
|
|
||||||
<input
|
|
||||||
id="weeztix_client_secret"
|
|
||||||
name="client_secret"
|
|
||||||
type="password"
|
|
||||||
autocomplete="off"
|
|
||||||
value=""
|
|
||||||
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
|
||||||
placeholder="{{ $wz !== null ? __('Laat leeg om ongewijzigd te laten') : '' }}"
|
|
||||||
@if ($wz === null) required @endif
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
@if ($wz !== null)
|
|
||||||
<p class="text-xs text-slate-500">
|
|
||||||
{{ __('Client ID en secret zijn opgeslagen maar worden niet opnieuw getoond. Laat de velden leeg om ze te behouden; vul ze alleen in als je ze wilt wijzigen.') }}
|
|
||||||
</p>
|
|
||||||
@endif
|
|
||||||
<button type="submit" class="rounded-lg bg-slate-800 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-slate-700">
|
|
||||||
{{ __('Gegevens opslaan') }}
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rounded-xl border border-slate-200 bg-white p-6 shadow-sm sm:p-8">
|
||||||
|
<h2 class="text-lg font-semibold text-slate-900">{{ __('Huidige configuratie') }}</h2>
|
||||||
|
<p class="mt-1 text-sm text-slate-600">{{ __('OAuth-gegevens zijn opgeslagen maar worden om veiligheidsredenen niet getoond.') }}</p>
|
||||||
|
|
||||||
|
<dl class="mt-6 space-y-4 border-t border-slate-100 pt-6 text-sm">
|
||||||
|
<div class="flex flex-col gap-1 sm:flex-row sm:justify-between">
|
||||||
|
<dt class="font-medium text-slate-700">{{ __('Verbinding') }}</dt>
|
||||||
|
<dd>
|
||||||
|
@if ($wz->is_connected)
|
||||||
|
<span class="inline-flex rounded-full bg-emerald-100 px-2.5 py-0.5 text-xs font-medium text-emerald-800">{{ __('Verbonden') }}</span>
|
||||||
|
@else
|
||||||
|
<span class="inline-flex rounded-full bg-amber-100 px-2.5 py-0.5 text-xs font-medium text-amber-900">{{ __('Niet verbonden') }}</span>
|
||||||
|
@endif
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
@if ($wz->is_connected && $wz->token_expires_at)
|
||||||
|
<div class="flex flex-col gap-1 sm:flex-row sm:justify-between">
|
||||||
|
<dt class="font-medium text-slate-700">{{ __('Toegangstoken tot') }}</dt>
|
||||||
|
<dd class="font-mono text-xs text-slate-800">{{ $wz->token_expires_at->timezone(config('app.timezone'))->format('Y-m-d H:i') }}</dd>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="flex flex-col gap-1 sm:flex-row sm:justify-between">
|
||||||
|
<dt class="font-medium text-slate-700">{{ __('Callback-URL (in Weeztix-dashboard)') }}</dt>
|
||||||
|
<dd class="break-all font-mono text-xs text-slate-600">{{ route('admin.weeztix.callback', absolute: true) }}</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1 sm:flex-row sm:justify-between">
|
||||||
|
<dt class="font-medium text-slate-700">{{ __('Coupon') }}</dt>
|
||||||
|
<dd class="text-slate-800">{{ $wz->coupon_name ?: ($wz->coupon_guid ? $wz->coupon_guid : '—') }}</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1 sm:flex-row sm:justify-between">
|
||||||
|
<dt class="font-medium text-slate-700">{{ __('Codevoorvoegsel') }}</dt>
|
||||||
|
<dd class="font-mono text-slate-800">{{ $wz->code_prefix ?? '—' }}</dd>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1 sm:flex-row sm:justify-between">
|
||||||
|
<dt class="font-medium text-slate-700">{{ __('Gebruik per code') }}</dt>
|
||||||
|
<dd class="text-slate-800">{{ (int) ($wz->usage_count ?? 1) }}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
{{-- Wizard --}}
|
||||||
|
<div class="mb-6 flex flex-wrap items-center justify-between gap-3">
|
||||||
@if ($wz !== null)
|
@if ($wz !== null)
|
||||||
<div class="pt-2">
|
<a href="{{ route('admin.pages.weeztix.edit', ['page' => $page]) }}" class="text-sm font-medium text-slate-600 hover:text-slate-900">
|
||||||
<a
|
{{ __('Annuleren en terug naar overzicht') }}
|
||||||
href="{{ route('admin.pages.weeztix.oauth.redirect', $page) }}"
|
</a>
|
||||||
class="inline-flex rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500"
|
@endif
|
||||||
>
|
</div>
|
||||||
{{ __('Verbind met Weeztix') }}
|
|
||||||
</a>
|
<div class="mb-8 flex flex-wrap items-center gap-2" aria-label="{{ __('Wizardstappen') }}">
|
||||||
|
@foreach ([1 => __('OAuth'), 2 => __('Verbinden'), 3 => __('Coupon')] as $num => $label)
|
||||||
|
@php
|
||||||
|
$active = $wizardStep === $num;
|
||||||
|
$done = $wizardStep > $num;
|
||||||
|
@endphp
|
||||||
|
<span class="inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs font-medium
|
||||||
|
{{ $active ? 'border-indigo-500 bg-indigo-50 text-indigo-900' : '' }}
|
||||||
|
{{ $done ? 'border-emerald-200 bg-emerald-50 text-emerald-900' : '' }}
|
||||||
|
{{ ! $active && ! $done ? 'border-slate-200 bg-slate-50 text-slate-500' : '' }}">
|
||||||
|
<span class="tabular-nums">{{ $num }}</span>
|
||||||
|
{{ $label }}
|
||||||
|
</span>
|
||||||
|
@if ($num < 3)
|
||||||
|
<span class="text-slate-300" aria-hidden="true">→</span>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rounded-xl border border-slate-200 bg-white p-6 shadow-sm sm:p-8 space-y-10">
|
||||||
|
@if ($wizardStep === 1)
|
||||||
|
<section class="space-y-4" aria-labelledby="wz-wizard-step1">
|
||||||
|
<h2 id="wz-wizard-step1" class="text-lg font-semibold text-slate-900">{{ __('Stap 1: OAuth-client') }}</h2>
|
||||||
|
|
||||||
|
@if ($hasStoredCredentials && ! $credentialsEdit)
|
||||||
|
<p class="text-sm text-slate-600">{{ __('Wil je Client ID, client secret of de callback-URI in Weeztix wijzigen? De callback-URL van deze applicatie is hieronder; die moet exact overeenkomen in het Weeztix-dashboard.') }}</p>
|
||||||
|
<p class="rounded-lg bg-slate-50 px-3 py-2 font-mono text-xs text-slate-800 break-all">{{ route('admin.weeztix.callback', absolute: true) }}</p>
|
||||||
|
<div class="flex flex-wrap gap-3 pt-2">
|
||||||
|
<a
|
||||||
|
href="{{ route('admin.pages.weeztix.edit', ['page' => $page, 'wizard' => 1, 'step' => 2]) }}"
|
||||||
|
class="inline-flex rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500"
|
||||||
|
>
|
||||||
|
{{ __('Nee, huidige gegevens behouden') }}
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="{{ route('admin.pages.weeztix.edit', ['page' => $page, 'wizard' => 1, 'step' => 1, 'credentials' => 'edit']) }}"
|
||||||
|
class="inline-flex rounded-lg border border-slate-300 bg-white px-4 py-2.5 text-sm font-semibold text-slate-800 shadow-sm hover:bg-slate-50"
|
||||||
|
>
|
||||||
|
{{ __('Ja, Client ID en secret wijzigen') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<p class="text-sm text-slate-600">{{ __('Vul de OAuth-client uit het Weeztix-dashboard in. Zet de redirect-URI exact op de onderstaande URL.') }}</p>
|
||||||
|
<p class="rounded-lg bg-slate-50 px-3 py-2 font-mono text-xs text-slate-800 break-all">{{ route('admin.weeztix.callback', absolute: true) }}</p>
|
||||||
|
|
||||||
|
<form method="post" action="{{ route('admin.pages.weeztix.update', $page) }}" class="space-y-4 pt-2">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
<input type="hidden" name="wizard" value="1">
|
||||||
|
<input type="hidden" name="wizard_credential_save" value="1">
|
||||||
|
<div>
|
||||||
|
<label for="weeztix_client_id" class="block text-sm font-medium text-slate-700">{{ __('Client ID') }}</label>
|
||||||
|
<input
|
||||||
|
id="weeztix_client_id"
|
||||||
|
name="client_id"
|
||||||
|
type="text"
|
||||||
|
autocomplete="off"
|
||||||
|
value="{{ old('client_id') }}"
|
||||||
|
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
||||||
|
placeholder="{{ $wz !== null ? __('Laat leeg om ongewijzigd te laten') : '' }}"
|
||||||
|
@if ($wz === null) required @endif
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="weeztix_client_secret" class="block text-sm font-medium text-slate-700">{{ __('Client secret') }}</label>
|
||||||
|
<input
|
||||||
|
id="weeztix_client_secret"
|
||||||
|
name="client_secret"
|
||||||
|
type="password"
|
||||||
|
autocomplete="off"
|
||||||
|
value=""
|
||||||
|
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
||||||
|
placeholder="{{ $wz !== null ? __('Laat leeg om ongewijzigd te laten') : '' }}"
|
||||||
|
@if ($wz === null) required @endif
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
@if ($wz !== null)
|
||||||
|
<p class="text-xs text-slate-500">
|
||||||
|
{{ __('Laat velden leeg om opgeslagen waarden te behouden.') }}
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
<button type="submit" class="rounded-lg bg-slate-800 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-slate-700">
|
||||||
|
{{ __('Opslaan en verder naar verbinden') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
@endif
|
||||||
|
</section>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if ($wizardStep === 2)
|
||||||
|
<section class="space-y-4" aria-labelledby="wz-wizard-step2">
|
||||||
|
<h2 id="wz-wizard-step2" class="text-lg font-semibold text-slate-900">{{ __('Stap 2: Verbinden met Weeztix') }}</h2>
|
||||||
|
<p class="text-sm text-slate-600">{{ __('Log in bij Weeztix en keur de toegang goed. Daarna ga je automatisch verder naar de coupon.') }}</p>
|
||||||
|
<p class="rounded-lg bg-slate-50 px-3 py-2 font-mono text-xs text-slate-800 break-all">{{ route('admin.weeztix.callback', absolute: true) }}</p>
|
||||||
|
|
||||||
|
@if ($wz !== null && $wz->is_connected)
|
||||||
|
<div class="rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-900">
|
||||||
|
{{ __('Je bent al verbonden. Ga door naar de coupon.') }}
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href="{{ route('admin.pages.weeztix.edit', ['page' => $page, 'wizard' => 1, 'step' => 3]) }}"
|
||||||
|
class="inline-flex rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500"
|
||||||
|
>
|
||||||
|
{{ __('Naar stap 3: coupon') }}
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<a
|
||||||
|
href="{{ $oauthUrl }}"
|
||||||
|
class="inline-flex rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500"
|
||||||
|
>
|
||||||
|
{{ __('Verbind met Weeztix') }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<p class="pt-4">
|
||||||
|
<a href="{{ route('admin.pages.weeztix.edit', ['page' => $page, 'wizard' => 1, 'step' => 1]) }}" class="text-sm font-medium text-slate-600 hover:text-slate-900">{{ __('← Terug naar stap 1') }}</a>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if ($wizardStep === 3)
|
||||||
|
<div
|
||||||
|
x-data="weeztixSetup(@js([
|
||||||
|
'pageId' => $page->id,
|
||||||
|
'couponsUrl' => route('admin.weeztix.coupons'),
|
||||||
|
'csrf' => csrf_token(),
|
||||||
|
'isConnected' => $wz?->is_connected ?? false,
|
||||||
|
'callbackUrl' => route('admin.weeztix.callback', absolute: true),
|
||||||
|
'existing' => $existing,
|
||||||
|
'strings' => [
|
||||||
|
'genericError' => __('Er ging iets mis. Probeer het opnieuw.'),
|
||||||
|
'loadCouponsError' => __('Kon kortingsbonnen niet laden.'),
|
||||||
|
'refreshCoupons' => __('Vernieuwen'),
|
||||||
|
'refreshCouponsBusy' => __('Bezig…'),
|
||||||
|
'refreshCouponsTitle' => __('Couponlijst opnieuw ophalen van Weeztix'),
|
||||||
|
],
|
||||||
|
]))"
|
||||||
|
>
|
||||||
|
<div x-show="errorMessage !== ''" x-cloak class="mb-6 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800" x-text="errorMessage"></div>
|
||||||
|
|
||||||
|
<section class="space-y-4" aria-labelledby="wz-wizard-step3">
|
||||||
|
<h2 id="wz-wizard-step3" class="text-lg font-semibold text-slate-900">{{ __('Stap 3: Coupon en codes') }}</h2>
|
||||||
|
<p class="text-sm text-slate-600">{{ __('Kies een bestaande coupon in Weeztix en stel het voorvoegsel en aantal gebruiken per code in.') }}</p>
|
||||||
|
|
||||||
|
<form method="post" action="{{ route('admin.pages.weeztix.update', $page) }}" class="space-y-4">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
<input type="hidden" name="wizard" value="1">
|
||||||
|
<input type="hidden" name="wizard_coupon_save" value="1">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex flex-wrap items-end justify-between gap-2">
|
||||||
|
<label for="weeztix_coupon" class="block text-sm font-medium text-slate-700">{{ __('Coupon (kortingssjabloon)') }}</label>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
x-show="isConnected"
|
||||||
|
x-cloak
|
||||||
|
@click="refreshCoupons()"
|
||||||
|
:disabled="couponsRefreshing"
|
||||||
|
:aria-busy="couponsRefreshing"
|
||||||
|
:title="strings.refreshCouponsTitle"
|
||||||
|
class="shrink-0 rounded-md border border-slate-300 bg-white px-2.5 py-1 text-xs font-medium text-slate-700 shadow-sm hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
|
>
|
||||||
|
<span x-show="!couponsRefreshing" x-text="strings.refreshCoupons"></span>
|
||||||
|
<span x-show="couponsRefreshing" x-cloak x-text="strings.refreshCouponsBusy"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<select
|
||||||
|
id="weeztix_coupon"
|
||||||
|
name="coupon_guid"
|
||||||
|
x-model="couponGuid"
|
||||||
|
@change="syncCouponName()"
|
||||||
|
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
|
<option value="">{{ __('Selecteer een coupon…') }}</option>
|
||||||
|
<template x-for="c in coupons" :key="c.guid">
|
||||||
|
<option :value="c.guid" x-text="c.name"></option>
|
||||||
|
</template>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" name="coupon_name" :value="couponName">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
|
<div>
|
||||||
|
<label for="weeztix_code_prefix" class="block text-sm font-medium text-slate-700">{{ __('Codevoorvoegsel') }}</label>
|
||||||
|
<input
|
||||||
|
id="weeztix_code_prefix"
|
||||||
|
name="code_prefix"
|
||||||
|
type="text"
|
||||||
|
maxlength="32"
|
||||||
|
x-model="codePrefix"
|
||||||
|
value="{{ old('code_prefix', $wz->code_prefix ?? 'PREREG') }}"
|
||||||
|
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="weeztix_usage_count" class="block text-sm font-medium text-slate-700">{{ __('Gebruik per code') }}</label>
|
||||||
|
<input
|
||||||
|
id="weeztix_usage_count"
|
||||||
|
name="usage_count"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="99999"
|
||||||
|
x-model.number="usageCount"
|
||||||
|
value="{{ old('usage_count', $wz->usage_count ?? 1) }}"
|
||||||
|
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap gap-3 pt-2">
|
||||||
|
<button type="submit" class="rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500">
|
||||||
|
{{ __('Opslaan en wizard afronden') }}
|
||||||
|
</button>
|
||||||
|
<a href="{{ route('admin.pages.weeztix.edit', ['page' => $page, 'wizard' => 1, 'step' => 2]) }}" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-4 py-2.5 text-sm font-semibold text-slate-700 shadow-sm hover:bg-slate-50">
|
||||||
|
{{ __('Terug naar stap 2') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</section>
|
</div>
|
||||||
|
@endif
|
||||||
@if ($wz !== null)
|
|
||||||
<section class="space-y-4 pt-8">
|
|
||||||
<h2 class="text-lg font-semibold text-slate-900">{{ __('Stap 2: Kortingsbon') }}</h2>
|
|
||||||
<p class="text-sm text-slate-600">{{ __('Na een geslaagde verbinding kies je een bestaande coupon uit Weeztix. Het bedrijf volgt uit je Weeztix-login en wordt automatisch opgeslagen.') }}</p>
|
|
||||||
|
|
||||||
<form method="post" action="{{ route('admin.pages.weeztix.update', $page) }}" class="space-y-4">
|
|
||||||
@csrf
|
|
||||||
@method('PUT')
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="flex flex-wrap items-end justify-between gap-2">
|
|
||||||
<label for="weeztix_coupon" class="block text-sm font-medium text-slate-700">{{ __('Coupon (kortingssjabloon)') }}</label>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
x-show="isConnected"
|
|
||||||
x-cloak
|
|
||||||
@click="refreshCoupons()"
|
|
||||||
:disabled="couponsRefreshing"
|
|
||||||
:aria-busy="couponsRefreshing"
|
|
||||||
:title="strings.refreshCouponsTitle"
|
|
||||||
class="shrink-0 rounded-md border border-slate-300 bg-white px-2.5 py-1 text-xs font-medium text-slate-700 shadow-sm hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50"
|
|
||||||
>
|
|
||||||
<span x-show="!couponsRefreshing" x-text="strings.refreshCoupons"></span>
|
|
||||||
<span x-show="couponsRefreshing" x-cloak x-text="strings.refreshCouponsBusy"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<select
|
|
||||||
id="weeztix_coupon"
|
|
||||||
name="coupon_guid"
|
|
||||||
x-model="couponGuid"
|
|
||||||
@change="syncCouponName()"
|
|
||||||
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
|
||||||
>
|
|
||||||
<option value="">{{ __('Selecteer een coupon…') }}</option>
|
|
||||||
<template x-for="c in coupons" :key="c.guid">
|
|
||||||
<option :value="c.guid" x-text="c.name"></option>
|
|
||||||
</template>
|
|
||||||
</select>
|
|
||||||
<input type="hidden" name="coupon_name" :value="couponName">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
||||||
<div>
|
|
||||||
<label for="weeztix_code_prefix" class="block text-sm font-medium text-slate-700">{{ __('Codevoorvoegsel') }}</label>
|
|
||||||
<input
|
|
||||||
id="weeztix_code_prefix"
|
|
||||||
name="code_prefix"
|
|
||||||
type="text"
|
|
||||||
maxlength="32"
|
|
||||||
x-model="codePrefix"
|
|
||||||
value="{{ old('code_prefix', $wz->code_prefix ?? 'PREREG') }}"
|
|
||||||
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="weeztix_usage_count" class="block text-sm font-medium text-slate-700">{{ __('Gebruik per code') }}</label>
|
|
||||||
<input
|
|
||||||
id="weeztix_usage_count"
|
|
||||||
name="usage_count"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="99999"
|
|
||||||
x-model.number="usageCount"
|
|
||||||
value="{{ old('usage_count', $wz->usage_count ?? 1) }}"
|
|
||||||
class="mt-1 block w-full rounded-lg border border-slate-300 px-3 py-2 text-slate-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit" class="rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500">
|
|
||||||
{{ __('Configuratie opslaan') }}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
Reference in New Issue
Block a user