Buchungsseite: Verlauf mit Kauftyp, Erfolgsmeldungen grün

„Eingelöste Käufe" nennt jetzt Kauftyp und PM-Titel (z. B.
„Depublikation: <Titel>") über das neue kompakte shortLabel() am
SinglePurchaseType. Die Checkout-Erfolgsbanner (Buchung, Tarifwechsel,
vorgemerkter Wechsel) und die Extra-PM-Bestätigung nutzen das
etablierte grüne Success-Muster (ok-soft) statt Hub-Blau.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-08 11:25:24 +00:00
parent f6882b621a
commit fe8bd2b931
3 changed files with 40 additions and 10 deletions

View file

@ -21,6 +21,22 @@ enum SinglePurchaseType: string
};
}
/**
* Kompaktes Label für Listenzeilen, in denen der Kauftyp dem PM-Titel
* vorangestellt wird (z. B. „Depublikation: <Titel>" im Verlauf der
* Buchungs-Seite).
*/
public function shortLabel(): string
{
return match ($this) {
self::SinglePm => 'Einzel-Pressemitteilung',
self::ExtraPm => 'Extra-PM',
self::Boost => 'Boost',
self::ProofPdf => 'Veröffentlichungsnachweis',
self::Depublication => 'Depublikation',
};
}
/**
* Käufe, die zum Einreichen/Veröffentlichen einer PM berechtigen
* (relevant für das Submit-Gate und den Slot-Verbrauch).

View file

@ -325,8 +325,8 @@ new #[Layout('components.layouts.app'), Title('Buchungen & Add-ons')] class exte
@if ($checkoutResult === 'erfolg')
<div
class="px-4 py-3 rounded-[5px] border text-[13px] flex items-start gap-3
bg-[color:var(--color-hub-soft)] border-[color:var(--color-hub-soft-2)] text-[color:var(--color-ink-2)]">
<flux:icon.check-circle class="size-[16px] flex-shrink-0 mt-0.5 text-[color:var(--color-hub)]" />
bg-[color:var(--color-ok-soft)] border-[color:var(--color-ok)]/30 text-[color:var(--color-ink-2)]">
<flux:icon.check-circle class="size-[16px] flex-shrink-0 mt-0.5 text-[color:var(--color-gain-deep)]" />
<div class="flex-1">
<span
class="font-semibold text-[color:var(--color-ink)]">{{ __('Vielen Dank für Ihre Buchung!') }}</span>
@ -336,8 +336,8 @@ new #[Layout('components.layouts.app'), Title('Buchungen & Add-ons')] class exte
@elseif ($checkoutResult === 'wechsel')
<div
class="px-4 py-3 rounded-[5px] border text-[13px] flex items-start gap-3
bg-[color:var(--color-hub-soft)] border-[color:var(--color-hub-soft-2)] text-[color:var(--color-ink-2)]">
<flux:icon.check-circle class="size-[16px] flex-shrink-0 mt-0.5 text-[color:var(--color-hub)]" />
bg-[color:var(--color-ok-soft)] border-[color:var(--color-ok)]/30 text-[color:var(--color-ink-2)]">
<flux:icon.check-circle class="size-[16px] flex-shrink-0 mt-0.5 text-[color:var(--color-gain-deep)]" />
<div class="flex-1">
<span
class="font-semibold text-[color:var(--color-ink)]">{{ __('Ihr Tarifwechsel wurde durchgeführt!') }}</span>
@ -347,8 +347,8 @@ new #[Layout('components.layouts.app'), Title('Buchungen & Add-ons')] class exte
@elseif ($checkoutResult === 'wechsel-geplant')
<div
class="px-4 py-3 rounded-[5px] border text-[13px] flex items-start gap-3
bg-[color:var(--color-hub-soft)] border-[color:var(--color-hub-soft-2)] text-[color:var(--color-ink-2)]">
<flux:icon.check-circle class="size-[16px] flex-shrink-0 mt-0.5 text-[color:var(--color-hub)]" />
bg-[color:var(--color-ok-soft)] border-[color:var(--color-ok)]/30 text-[color:var(--color-ink-2)]">
<flux:icon.check-circle class="size-[16px] flex-shrink-0 mt-0.5 text-[color:var(--color-gain-deep)]" />
<div class="flex-1">
<span
class="font-semibold text-[color:var(--color-ink)]">{{ __('Ihr Tarifwechsel ist vorgemerkt!') }}</span>
@ -827,8 +827,8 @@ new #[Layout('components.layouts.app'), Title('Buchungen & Add-ons')] class exte
@if ($showExtraPm)
@if ($walletNotice)
<div class="px-4 py-3 rounded-[5px] border text-[13px] flex items-start gap-3
bg-[color:var(--color-hub-soft)] border-[color:var(--color-hub-soft-2)] text-[color:var(--color-ink-2)]">
<flux:icon.check-circle class="size-[16px] flex-shrink-0 mt-0.5 text-[color:var(--color-hub)]" />
bg-[color:var(--color-ok-soft)] border-[color:var(--color-ok)]/30 text-[color:var(--color-ink-2)]">
<flux:icon.check-circle class="size-[16px] flex-shrink-0 mt-0.5 text-[color:var(--color-gain-deep)]" />
<div class="flex-1">{{ $walletNotice }}</div>
</div>
@endif
@ -990,7 +990,7 @@ new #[Layout('components.layouts.app'), Title('Buchungen & Add-ons')] class exte
wire:key="consumed-purchase-{{ $purchase->id }}">
<div class="min-w-0">
<div class="text-[13px] font-semibold text-[color:var(--color-ink)] truncate">
{{ $purchase->pressRelease?->title ?? $purchase->type->label() }}
{{ $purchase->type->shortLabel() }}{{ $purchase->pressRelease ? ': ' . $purchase->pressRelease->title : '' }}
</div>
<div class="text-[11.5px] text-[color:var(--color-ink-3)]">
{{ __('eingelöst am :date', ['date' => $purchase->consumed_at?->format('d.m.Y')]) }}

View file

@ -1,10 +1,12 @@
<?php
use App\Enums\SinglePurchaseType;
use App\Enums\UserPaymentOptionStatus;
use App\Models\BillingAddress;
use App\Models\BookingConfirmation;
use App\Models\LegalDocument;
use App\Models\Plan;
use App\Models\PressRelease;
use App\Models\SinglePurchase;
use App\Models\User;
use App\Models\UserPaymentOption;
@ -158,11 +160,23 @@ test('open and consumed single purchases appear in the card and history', functi
SinglePurchase::factory()->paid()->create(['user_id' => $user->id]);
SinglePurchase::factory()->consumed()->create(['user_id' => $user->id]);
// Eingelöste Käufe nennen Kauftyp und PM-Titel (z. B. Depublikation).
$release = PressRelease::factory()->create([
'user_id' => $user->id,
'title' => 'Depublizierte Beispiel-Mitteilung',
]);
SinglePurchase::factory()->consumed()->create([
'user_id' => $user->id,
'type' => SinglePurchaseType::Depublication,
'press_release_id' => $release->id,
]);
$this->actingAs($user);
LivewireVolt::test('customer.bookings')
->assertSee('Einzel-Pressemitteilung verfügbar')
->assertSee('eingelöst am');
->assertSee('eingelöst am')
->assertSee('Depublikation: Depublizierte Beispiel-Mitteilung');
});
test('the billing portal redirects without an active subscription', function () {