Compare commits
2 Commits
d4b70b7477
...
7da2939c55
| Author | SHA1 | Date |
|---|---|---|
|
|
7da2939c55 | |
|
|
8479fc30f8 |
|
|
@ -14,6 +14,7 @@ return [
|
|||
'terms_first' => 'Bitte oben die AGB annehmen.',
|
||||
'term_monthly' => 'Monatlich',
|
||||
'term_yearly' => 'Jährlich',
|
||||
'free_months_taken' => '{1} 1 Monat gratis enthalten|[2,*] :count Monate gratis enthalten',
|
||||
'free_months_hint' => '{1} 1 Monat gratis bei Jahreszahlung|[2,*] :count Monate gratis bei Jahreszahlung',
|
||||
'yearly_total' => ':total jährlich',
|
||||
'instead_of' => 'statt :amount',
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ return [
|
|||
'terms_first' => 'Please accept the terms above.',
|
||||
'term_monthly' => 'Monthly',
|
||||
'term_yearly' => 'Yearly',
|
||||
'free_months_taken' => '{1} 1 month free included|[2,*] :count months free included',
|
||||
'free_months_hint' => '{1} 1 month free when paying yearly|[2,*] :count months free when paying yearly',
|
||||
'yearly_total' => ':total per year',
|
||||
'instead_of' => 'instead of :amount',
|
||||
|
|
|
|||
|
|
@ -520,6 +520,15 @@
|
|||
charge. The saving is named next to the switch: "jährlich" on its
|
||||
own gives nobody a reason to look. --}}
|
||||
<div x-data="{ term: 'monthly' }" class="mt-12">
|
||||
{{-- The saving above the switch, and always present: hidden on the
|
||||
yearly view it re-centred the row every time somebody changed
|
||||
their mind. One line, two wordings. --}}
|
||||
@if ($bestFreeMonths > 0)
|
||||
<p class="mb-3 text-center text-sm font-semibold text-success">
|
||||
<span x-show="term !== 'yearly'">{{ $bestFreeMonths === 1 ? '1 Monat gratis' : $bestFreeMonths.' Monate gratis' }} bei Jahreszahlung</span>
|
||||
<span x-show="term === 'yearly'" x-cloak>{{ $bestFreeMonths === 1 ? '1 Monat gratis' : $bestFreeMonths.' Monate gratis' }} — in jedem Jahrespreis enthalten</span>
|
||||
</p>
|
||||
@endif
|
||||
<div class="flex flex-wrap items-center justify-center gap-3">
|
||||
{{-- text-bg on the active option, not a colour that does not
|
||||
exist: `text-on-ink` is not in the palette (the ink pairing
|
||||
|
|
@ -537,11 +546,6 @@
|
|||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@if ($bestFreeMonths > 0)
|
||||
<span class="text-sm font-semibold text-success-text" x-show="term !== 'yearly'">
|
||||
{{ $bestFreeMonths === 1 ? '1 Monat gratis' : $bestFreeMonths.' Monate gratis' }} bei Jahreszahlung
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Stretched, not items-start: the cards carry different numbers of
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@
|
|||
radius less its own padding. A rounded-md option — Tailwind's
|
||||
untokenised 6px — read as a different component sitting
|
||||
inside this one. --}}
|
||||
{{-- Above the switch, and ALWAYS present. It hung underneath
|
||||
and was hidden on the yearly view, so choosing a term moved
|
||||
the buttons that choose it. One line, two wordings: an offer
|
||||
while it is an offer, a statement once it is taken. --}}
|
||||
@if ($bestFreeMonths > 0)
|
||||
<span class="text-xs font-semibold text-success">
|
||||
<span x-show="term !== 'yearly'">{{ trans_choice('order.free_months_hint', $bestFreeMonths, ['count' => $bestFreeMonths]) }}</span>
|
||||
<span x-show="term === 'yearly'" x-cloak>{{ trans_choice('order.free_months_taken', $bestFreeMonths, ['count' => $bestFreeMonths]) }}</span>
|
||||
</span>
|
||||
@endif
|
||||
<div class="inline-flex rounded-lg border border-line bg-surface p-1 shadow-xs" role="group">
|
||||
@foreach (['monthly', 'yearly'] as $option)
|
||||
<button type="button" x-on:click="term = '{{ $option }}'"
|
||||
|
|
@ -56,11 +66,6 @@
|
|||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@if ($bestFreeMonths > 0)
|
||||
<span class="text-xs font-semibold text-success" x-show="term !== 'yearly'">
|
||||
{{ trans_choice('order.free_months_hint', $bestFreeMonths, ['count' => $bestFreeMonths]) }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</header>
|
||||
|
|
@ -163,8 +168,14 @@
|
|||
The term travels in the address, so the checkout shows
|
||||
what was being looked at — and a reload of that page
|
||||
still shows it. --}}
|
||||
{{-- The whole address from route(), with the term swapped
|
||||
into it — not route() plus "?term=". Both parameters are
|
||||
query parameters here, so appending a second "?" built
|
||||
`?plan=team?term=monthly`, and the package arrived as
|
||||
the string "team?term=monthly": every click landed on
|
||||
"this package is not on sale". --}}
|
||||
<a href="{{ route('checkout', ['plan' => $plan['key'], 'term' => 'monthly']) }}"
|
||||
x-bind:href="'{{ route('checkout', ['plan' => $plan['key']]) }}?term=' + term"
|
||||
x-bind:href="'{{ route('checkout', ['plan' => $plan['key'], 'term' => '__TERM__']) }}'.replace('__TERM__', term)"
|
||||
@class([
|
||||
'mt-6 inline-flex w-full items-center justify-center gap-2 rounded px-4 py-2.5 text-sm font-semibold transition-colors',
|
||||
'bg-ink text-bg hover:bg-accent-text' => $plan['recommended'],
|
||||
|
|
|
|||
|
|
@ -76,10 +76,36 @@ it('lets a customer pick the term on the order page', function () {
|
|||
|
||||
// Both figures rendered, one shown: switching costs no round trip.
|
||||
expect($page)->toContain("term = 'yearly'")
|
||||
->and($page)->toContain(__('order.term_yearly'))
|
||||
// And the choice travels to the checkout page in the address, so a
|
||||
// reload there still shows what was chosen.
|
||||
->and($page)->toContain("?term=' + term");
|
||||
->and($page)->toContain(__('order.term_yearly'));
|
||||
});
|
||||
|
||||
it('links to the checkout with one query string, not two question marks', function () {
|
||||
// Both parameters are query parameters, so route() + '?term=' built
|
||||
// `?plan=team?term=monthly` and the package arrived as the whole string
|
||||
// "team?term=monthly". Every click landed on "this package is not on sale",
|
||||
// and nothing in the page or the log said why.
|
||||
$page = $this->actingAs(termBuyer())->get(route('order'))->assertOk()->getContent();
|
||||
|
||||
preg_match_all('/href="([^"]*checkout[^"]*)"/', $page, $plain);
|
||||
preg_match_all('/x-bind:href="\x27([^\x27]*)\x27/', $page, $bound);
|
||||
|
||||
expect($plain[1])->not->toBeEmpty()
|
||||
->and($bound[1])->not->toBeEmpty();
|
||||
|
||||
foreach (array_merge($plain[1], $bound[1]) as $href) {
|
||||
expect(substr_count($href, '?'))->toBe(1, $href);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps the saving above the switch, where it cannot move the buttons', function () {
|
||||
// It hung underneath and was hidden on the yearly view, so choosing a term
|
||||
// moved the very buttons that choose it.
|
||||
$page = Illuminate\Support\Facades\File::get(resource_path('views/livewire/order.blade.php'));
|
||||
|
||||
expect(strpos($page, "order.free_months_hint"))->toBeLessThan(strpos($page, "order.term_'.\$option"))
|
||||
// And it is always there: one line, two wordings, no appearing and
|
||||
// disappearing.
|
||||
->and($page)->toContain('order.free_months_taken');
|
||||
});
|
||||
|
||||
it('carries the chosen term into the checkout page and its form', function () {
|
||||
|
|
|
|||
Loading…
Reference in New Issue