diff --git a/app/Livewire/Billing.php b/app/Livewire/Billing.php index 57df6de..98caa46 100644 --- a/app/Livewire/Billing.php +++ b/app/Livewire/Billing.php @@ -68,6 +68,12 @@ class Billing extends Component $this->dispatch('notify', message: __('billing.purchased')); } + #[\Livewire\Attributes\On('order-removed')] + public function orderRemoved(): void + { + $this->dispatch('notify', message: __('billing.cart.removed')); + } + public function render() { $customer = $this->customer(); diff --git a/app/Livewire/ConfirmRemoveOrder.php b/app/Livewire/ConfirmRemoveOrder.php new file mode 100644 index 0000000..e541214 --- /dev/null +++ b/app/Livewire/ConfirmRemoveOrder.php @@ -0,0 +1,73 @@ +order($uuid); + abort_if($order === null, 404); + + $this->uuid = $uuid; + $this->label = $order->label(); + $this->amountCents = $order->amount_cents; + } + + public function remove(): void + { + $order = $this->order($this->uuid); + + // Gone or already paid for: say so instead of pretending it worked. + if ($order === null) { + $this->dispatch('notify', message: __('billing.cart.gone')); + $this->closeModal(); + + return; + } + + $order->delete(); + + $this->dispatch('order-removed'); + $this->closeModal(); + } + + /** @return Order|null the customer's own, still-pending order */ + private function order(string $uuid): ?Order + { + $customer = $this->customer(); + if ($customer === null) { + return null; + } + + return Order::query() + ->where('customer_id', $customer->id) + ->where('uuid', $uuid) + ->where('status', 'pending') + ->first(); + } + + public function render() + { + return view('livewire.confirm-remove-order'); + } +} diff --git a/app/Models/Order.php b/app/Models/Order.php index d972a9c..5cb03a8 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -25,6 +25,30 @@ class Order extends Model implements ProvisioningSubject return ['amount_cents' => 'integer']; } + /** + * What this order actually buys, in words. + * + * Lives on the model rather than in the view: the cart, the invoice list and + * any future confirmation mail must not each invent their own wording for + * the same row. + */ + public function label(): string + { + return match ($this->type) { + 'upgrade' => __('billing.cart.upgrade', ['plan' => ucfirst($this->plan)]), + 'storage' => __('billing.cart.storage', ['gb' => (int) config('provisioning.storage_addon.gb', 100)]), + 'traffic' => __('billing.cart.traffic', ['gb' => (int) config('provisioning.traffic.addon.gb', 1000)]), + 'addon' => __('billing.addon.'.$this->addon_key.'.name'), + default => __('billing.cart.plan', ['plan' => ucfirst($this->plan)]), + }; + } + + /** Only a pending order is still the customer's to change. */ + public function isRemovable(): bool + { + return $this->status === 'pending'; + } + public function customer(): BelongsTo { return $this->belongsTo(Customer::class); diff --git a/lang/de/billing.php b/lang/de/billing.php index 3fed853..8ec321f 100644 --- a/lang/de/billing.php +++ b/lang/de/billing.php @@ -1,6 +1,23 @@ [ + 'title' => 'Vorgemerkte Käufe', + 'subtitle' => 'Wird nach Zahlung aktiviert', + 'added' => 'vorgemerkt am :when', + 'total' => 'Summe', + 'remove' => 'Entfernen', + 'removed' => 'Aus den vorgemerkten Käufen entfernt.', + 'gone' => 'Dieser Eintrag ist nicht mehr vorgemerkt.', + 'keep' => 'Behalten', + 'remove_title' => 'Eintrag entfernen?', + 'remove_body' => '„:item" wird aus den vorgemerkten Käufen genommen. Sie können es jederzeit erneut auswählen.', + 'remove_confirm' => 'Entfernen', + 'upgrade' => 'Wechsel auf Paket :plan', + 'storage' => ':gb GB Zusatzspeicher', + 'traffic' => ':gb GB Datenvolumen', + 'plan' => 'Paket :plan', + ], 'traffic_title' => 'Datenvolumen', 'traffic_body' => ':gb GB zusätzliches Volumen für diesen Monat, :price.', 'traffic_used' => ':used von :quota verbraucht', diff --git a/lang/en/billing.php b/lang/en/billing.php index 306295d..a4a1788 100644 --- a/lang/en/billing.php +++ b/lang/en/billing.php @@ -1,6 +1,23 @@ [ + 'title' => 'Pending purchases', + 'subtitle' => 'Activated once paid', + 'added' => 'added :when', + 'total' => 'Total', + 'remove' => 'Remove', + 'removed' => 'Removed from your pending purchases.', + 'gone' => 'That entry is no longer pending.', + 'keep' => 'Keep', + 'remove_title' => 'Remove this entry?', + 'remove_body' => '":item" will be taken out of your pending purchases. You can add it again at any time.', + 'remove_confirm' => 'Remove', + 'upgrade' => 'Change to the :plan plan', + 'storage' => ':gb GB extra storage', + 'traffic' => ':gb GB data transfer', + 'plan' => ':plan plan', + ], 'traffic_title' => 'Data transfer', 'traffic_body' => ':gb GB of extra volume for this month, :price.', 'traffic_used' => ':used of :quota used', diff --git a/resources/views/livewire/billing.blade.php b/resources/views/livewire/billing.blade.php index 3b3c86f..cb00d7a 100644 --- a/resources/views/livewire/billing.blade.php +++ b/resources/views/livewire/billing.blade.php @@ -34,10 +34,39 @@ + {{-- Cart: "5 purchases pending" told nobody what they had ordered, and + offered no way to change their mind. --}} @if ($pending->isNotEmpty()) -
{{ __('billing.pending_note', ['count' => $pending->count()]) }}
+{{ $order->label() }}
++ {{ __('billing.cart.added', ['when' => $order->created_at->isoFormat('LL')]) }} +
+{{ $eur($order->amount_cents) }}
+ +{{ __('billing.cart.remove_body', ['item' => $label]) }}
+