Plan: ein Streifen im Dashboard zeigt die Restfrist

Vom Betreiber gefordert, und der Ort stimmt: eine Mail sieben Tage vorher kann
im Postfach untergehen, die eigene Uebersicht oeffnet der Kunde ohnehin.

Er nennt, wie lange der ZUGANG noch steht — nicht, wann etwas geloescht wird.
Das ist die Frist, die den Kunden betrifft. Und er ist der natuerliche Platz
fuer die Export-Antwort: wer liest, dass die Zeit laeuft, will es sich im
selben Atemzug anders ueberlegen koennen.
claude/nice-moser-521659
nexxo 2026-08-04 07:57:21 +02:00
parent 34ef35518c
commit 82ace84d01
1 changed files with 127 additions and 1 deletions

View File

@ -414,6 +414,131 @@ it('laesst sie nach dem Laufzeitende nicht mehr aendern', function () {
---
## Task 5: Der Streifen im Dashboard, der die Frist zeigt
**Files:**
- Modify: `app/Livewire/Dashboard.php`
- Modify: `resources/views/livewire/dashboard.blade.php`
- Modify: `lang/{de,en}/dashboard.php`
- Test: `tests/Feature/Cancellation/DashboardCountdownTest.php`
**Vom Betreiber gefordert, und es ist der richtige Ort:** das Dashboard ist die
Seite, die ein Kunde ohnehin öffnet. Eine Mail sieben Tage vorher kann im
Postfach untergehen; ein Streifen über der eigenen Übersicht nicht.
Er zeigt, **wie lange der Zugang noch steht** — nicht, wann irgendetwas
gelöscht wird. Das ist die Frist, die den Kunden betrifft: ab dem Laufzeitende
kommt er nicht mehr an seine Cloud.
Und er ist der natürliche Platz für Aufgabe 4: wer hier liest, dass die Zeit
läuft, will im selben Atemzug seine Antwort zum Export ändern können.
- [ ] **Schritt 1: Die fehlschlagenden Prüfungen schreiben**
```php
<?php // tests/Feature/Cancellation/DashboardCountdownTest.php
use App\Livewire\Dashboard;
use Livewire\Livewire;
it('zeigt nach einer Kuendigung, wie lange der Zugang noch steht', function () {
[$user, $instance] = gekuendigteInstanz(endetIn: now()->addDays(12));
Livewire::actingAs($user)->test(Dashboard::class)
->assertSee(__('dashboard.ending.title'))
->assertSee($instance->service_ends_at->local()->isoFormat('LL'));
});
it('zeigt den Streifen nicht, solange nicht gekuendigt wurde', function () {
[$user] = laufendeInstanz();
Livewire::actingAs($user)->test(Dashboard::class)
->assertDontSee(__('dashboard.ending.title'));
});
it('zeigt ihn auch nach dem Laufzeitende nicht mehr', function () {
// Danach ist der Zugang zu, und ein Streifen, der eine Restzeit nennt,
// waere schlicht falsch. Was dann gilt, sagt die Seite an anderer Stelle.
[$user] = gekuendigteInstanz(endetIn: now()->subDay(), status: 'ended');
Livewire::actingAs($user)->test(Dashboard::class)
->assertDontSee(__('dashboard.ending.title'));
});
it('nennt keine Restzeit, die schon abgelaufen ist', function () {
// Der Fall zwischen den Stuehlen: das Laufzeitende ist vorbei, aber der
// stuendliche Lauf hat die Instanz noch nicht auf `ended` gestellt. Eine
// Zeile "noch -3 Stunden" ist die Sorte Fehler, die niemand meldet und
// jeder sieht.
[$user] = gekuendigteInstanz(endetIn: now()->subHours(3));
$html = Livewire::actingAs($user)->test(Dashboard::class)->html();
expect($html)->not->toContain('-'); // an der Restzeit, nicht im ganzen Dokument — siehe unten
});
it('traegt die Antwort zum Export und laesst sie aendern', function () {
[$user, $instance] = gekuendigteInstanz(endetIn: now()->addDays(12));
$instance->update(['export_wish' => false]);
Livewire::actingAs($user)->test(Dashboard::class)
->assertSee(__('dashboard.ending.export_no'))
->call('setExportWish', true);
expect($instance->fresh()->export_wish)->toBeTrue();
});
```
**Zur vierten Prüfung:** `not->toContain('-')` über das ganze Dokument trägt
nicht — ein Datum enthält Bindestriche, eine CSS-Klasse auch. Schreib sie so,
dass sie **die Restzeit** prüft und nicht die Seite: entweder gegen den Wert,
den die Komponente berechnet, oder gegen den Textbaustein mit eingesetzter
Zahl. Eine Zusicherung, die aus dem falschen Grund grün ist, ist keine.
- [ ] **Schritt 2: Laufen lassen, Fehlschlag bestätigen**
- [ ] **Schritt 3: Den Streifen bauen**
`Dashboard::render()` holt die Instanz bereits (Zeile 36 ff.) — von dort kommt
`service_ends_at`. Der Streifen erscheint, wenn `status === 'cancellation_scheduled'`
**und** das Ende in der Zukunft liegt.
Die Restzeit geht durch `->local()` (R19) und wird **abgerundet auf ganze Tage
genannt, solange mehr als ein Tag bleibt** — „noch 12 Tage" liest sich, „noch
11 Tage 7 Stunden" nicht. Am letzten Tag zählt er Stunden; das ist der Moment,
in dem die Zahl wirklich zählt.
Der Streifen benutzt dieselbe Warnfarbe wie der bestehende Zugangsdaten-Kasten
darüber (`border-warning-border bg-warning-bg text-warning`) und steht an
derselben Stelle im Fluss — nicht zwei verschiedene Sprachen für zwei
verschiedene Dringlichkeiten auf einer Seite.
Er nennt drei Dinge: das Datum, die Restzeit, und **was dann geschieht** — dass
der Zugang zur Cloud endet und ein Selbst-Herunterladen bis dahin möglich ist.
Dazu die Antwort zum Export mit einem Schalter, sie zu ändern (Aufgabe 4).
- [ ] **Schritt 4: Laufen lassen, grün**
- [ ] **Schritt 5: Ganze Suite**
- [ ] **Schritt 6: Festschreiben**
```bash
git commit -F- <<'MSG'
Ein Streifen im Dashboard sagt, wie lange der Zugang noch steht
Eine Mail sieben Tage vorher kann im Postfach untergehen; die eigene Uebersicht
oeffnet der Kunde ohnehin. Der Streifen nennt das Datum, die Restzeit und was
danach geschieht — dass der Zugang zur Cloud endet, nicht dass irgendetwas
geloescht wird. Das ist die Frist, die ihn betrifft.
Und er traegt die Antwort zum Export: wer liest, dass die Zeit laeuft, will es
sich im selben Atemzug anders ueberlegen koennen.
MSG
```
---
## Selbstdurchsicht
**Abdeckung von Teil A des Entwurfs**
@ -422,8 +547,9 @@ it('laesst sie nach dem Laufzeitende nicht mehr aendern', function () {
|---|---|
| Beim Kündigen wird gefragt | 2 |
| Drei Zustände, `null` ≠ „nein" | 1 |
| Antwort später änderbar | 4 |
| Antwort später änderbar | 4, 5 |
| Erinnerung vor dem Laufzeitende | 3 |
| Streifen im Dashboard mit der Restfrist | 5 |
| Kein Gast angefasst, kein Speicher gebraucht | alle |
**Was Teil A ausdrücklich NICHT tut**