diff --git a/app/Livewire/Backups.php b/app/Livewire/Backups.php new file mode 100644 index 0000000..4e4bc7c --- /dev/null +++ b/app/Livewire/Backups.php @@ -0,0 +1,55 @@ +getLocale(); + $gb = fn (float $v) => Number::format($v, precision: 1, locale: $locale).' GB'; + $date = fn (string $iso, string $fmt) => Carbon::parse($iso)->locale($locale)->isoFormat($fmt); + + // 14 days of backup sizes for the bar chart. + $sizes = [18.1, 18.1, 18.2, 18.2, 18.2, 18.3, 18.3, 18.3, 18.3, 18.4, 18.4, 18.3, 18.4, 18.4]; + + $rows = []; + foreach (range(0, 6) as $i) { + $rows[] = [ + 'when' => $date(Carbon::parse('2026-07-24')->subDays($i)->toDateString(), 'dd, D. MMMM').', 03:1'.($i % 3 + 1), + 'size' => $gb(18.4 - $i * 0.02), + 'status' => 'ok', + ]; + } + + return view('livewire.backups', [ + 'rows' => $rows, + 'lastTest' => $date('2026-07-01', 'LL'), + 'sizeChart' => [ + 'type' => 'bar', + 'data' => [ + 'labels' => array_map(fn ($i) => $date(Carbon::parse('2026-07-24')->subDays(13 - $i)->toDateString(), 'D.'), range(0, 13)), + 'datasets' => [[ + 'label' => 'GB', + 'data' => $sizes, + 'backgroundColor' => 'token:accent/0.85', + 'borderRadius' => 4, + ]], + ], + 'options' => [ + 'scales' => [ + 'x' => ['grid' => ['display' => false]], + 'y' => ['beginAtZero' => false, 'grid' => ['color' => 'token:border']], + ], + 'plugins' => ['legend' => ['display' => false]], + ], + ], + ]); + } +} diff --git a/app/Livewire/Cloud.php b/app/Livewire/Cloud.php new file mode 100644 index 0000000..a4976fc --- /dev/null +++ b/app/Livewire/Cloud.php @@ -0,0 +1,57 @@ +getLocale(); + $growth = [180, 188, 195, 199, 204, 210, 214, 219, 223, 228, 231, 235]; + + return view('livewire.cloud', [ + 'instance' => [ + 'name' => 'Cloud der Kanzlei Berger', + 'domain' => 'cloud.kanzlei-berger.at', + 'status' => 'active', + 'plan' => __('cloud.plan_line', ['plan' => 'CluPilot Cloud Team', 'price' => 179]), + 'location' => __('cloud.datacenter'), + 'version' => 'Nextcloud 31.0.4', + 'php' => 'PHP 8.3 · MariaDB 11.4', + 'storageUsed' => 235, + 'storageQuota' => 500, + 'ram' => '8 GB', + 'vcpu' => '4 vCPU', + ], + 'storageChart' => [ + 'type' => 'line', + 'data' => [ + 'labels' => ['', '', '', '', '', '', '', '', '', '', '', __('cloud.now')], + 'datasets' => [[ + 'label' => 'GB', + 'data' => $growth, + 'borderColor' => 'token:accent', + 'backgroundColor' => 'token:accent/0.10', + 'fill' => true, + 'tension' => 0.35, + 'pointRadius' => 0, + 'borderWidth' => 2, + ]], + ], + 'options' => [ + 'scales' => [ + 'x' => ['grid' => ['display' => false]], + 'y' => ['beginAtZero' => false, 'grid' => ['color' => 'token:border']], + ], + 'plugins' => ['legend' => ['display' => false]], + ], + ], + 'storageLabel' => Number::format(235, locale: $locale).' / '.Number::format(500, locale: $locale).' GB', + ]); + } +} diff --git a/app/Livewire/Invoices.php b/app/Livewire/Invoices.php new file mode 100644 index 0000000..0354bd6 --- /dev/null +++ b/app/Livewire/Invoices.php @@ -0,0 +1,55 @@ +getLocale(); + $eur = fn (float $v) => Number::currency($v, in: 'EUR', locale: $locale); + $date = fn (string $iso) => Carbon::parse($iso)->locale($locale)->isoFormat('LL'); + + $months = collect(['2026-03-01', '2026-04-01', '2026-05-01', '2026-06-01', '2026-07-01']) + ->map(fn ($m) => Carbon::parse($m)->locale($locale)->isoFormat('MMM'))->all(); + + $rows = [ + ['no' => 'CP-2026-0007', 'date' => $date('2026-07-01'), 'amount' => $eur(198), 'status' => 'paid'], + ['no' => 'CP-2026-0006', 'date' => $date('2026-06-01'), 'amount' => $eur(198), 'status' => 'paid'], + ['no' => 'CP-2026-0005', 'date' => $date('2026-05-01'), 'amount' => $eur(198), 'status' => 'paid'], + ['no' => 'CP-2026-0004', 'date' => $date('2026-04-01'), 'amount' => $eur(179), 'status' => 'paid'], + ['no' => 'CP-2026-0003', 'date' => $date('2026-03-15'), 'amount' => $eur(179), 'status' => 'paid'], + ]; + + return view('livewire.invoices', [ + 'rows' => $rows, + 'nextCharge' => $date('2026-08-01'), + 'nextAmount' => $eur(198), + 'spendChart' => [ + 'type' => 'bar', + 'data' => [ + 'labels' => $months, + 'datasets' => [[ + 'label' => 'EUR', + 'data' => [179, 179, 198, 198, 198], + 'backgroundColor' => 'token:accent/0.85', + 'borderRadius' => 4, + ]], + ], + 'options' => [ + 'scales' => [ + 'x' => ['grid' => ['display' => false]], + 'y' => ['beginAtZero' => true, 'grid' => ['color' => 'token:border']], + ], + 'plugins' => ['legend' => ['display' => false]], + ], + ], + ]); + } +} diff --git a/app/Livewire/Support.php b/app/Livewire/Support.php new file mode 100644 index 0000000..1652e16 --- /dev/null +++ b/app/Livewire/Support.php @@ -0,0 +1,30 @@ +getLocale(); + $date = fn (string $iso) => Carbon::parse($iso)->locale($locale)->isoFormat('LL'); + + return view('livewire.support', [ + 'tickets' => [ + ['subject' => __('support.ticket_migration'), 'ref' => '#4821', 'date' => $date('2026-07-22'), 'status' => 'open'], + ['subject' => __('support.ticket_training'), 'ref' => '#4790', 'date' => $date('2026-07-18'), 'status' => 'progress'], + ['subject' => __('support.ticket_smtp'), 'ref' => '#4712', 'date' => $date('2026-07-04'), 'status' => 'closed'], + ], + 'faqs' => [ + ['q' => __('support.faq_q1'), 'a' => __('support.faq_a1')], + ['q' => __('support.faq_q2'), 'a' => __('support.faq_a2')], + ['q' => __('support.faq_q3'), 'a' => __('support.faq_a3')], + ], + ]); + } +} diff --git a/app/Livewire/Users.php b/app/Livewire/Users.php new file mode 100644 index 0000000..67076be --- /dev/null +++ b/app/Livewire/Users.php @@ -0,0 +1,41 @@ + [ + ['name' => 'Dr. Sabine Berger', 'email' => 's.berger@kanzlei-berger.at', 'role' => __('users.role_admin'), 'group' => 'Partner', 'status' => 'active'], + ['name' => 'Michael Huber', 'email' => 'm.huber@kanzlei-berger.at', 'role' => __('users.role_member'), 'group' => 'Anwälte', 'status' => 'active'], + ['name' => 'Julia Wagner', 'email' => 'j.wagner@kanzlei-berger.at', 'role' => __('users.role_member'), 'group' => 'Anwälte', 'status' => 'active'], + ['name' => 'Thomas Bauer', 'email' => 't.bauer@kanzlei-berger.at', 'role' => __('users.role_member'), 'group' => 'Sekretariat', 'status' => 'active'], + ['name' => 'Lena Mayr', 'email' => 'l.mayr@kanzlei-berger.at', 'role' => __('users.role_member'), 'group' => 'Sekretariat', 'status' => 'active'], + ['name' => 'Paul Steiner', 'email' => 'p.steiner@kanzlei-berger.at', 'role' => __('users.role_member'), 'group' => 'Anwälte', 'status' => 'active'], + ['name' => 'Gast · Notariat Külz', 'email' => 'extern@notariat-kuelz.at', 'role' => __('users.role_guest'), 'group' => __('users.guests'), 'status' => 'guest'], + ['name' => 'Gast · Steuerberatung Reiss', 'email' => 'extern@stb-reiss.at', 'role' => __('users.role_guest'), 'group' => __('users.guests'), 'status' => 'guest'], + ], + 'groupsChart' => [ + 'type' => 'doughnut', + 'data' => [ + 'labels' => ['Partner', 'Anwälte', 'Sekretariat', __('users.guests')], + 'datasets' => [[ + 'data' => [1, 3, 2, 2], + 'backgroundColor' => ['token:accent', 'token:info', 'token:success-bright', 'token:surface-2'], + 'borderWidth' => 0, + ]], + ], + 'options' => [ + 'cutout' => '62%', + 'plugins' => ['legend' => ['position' => 'bottom', 'labels' => ['boxWidth' => 10, 'padding' => 12]]], + ], + ], + ]); + } +} diff --git a/lang/de/backups.php b/lang/de/backups.php new file mode 100644 index 0000000..473dfe1 --- /dev/null +++ b/lang/de/backups.php @@ -0,0 +1,15 @@ + 'Backups', + 'subtitle' => 'Automatische, verschlüsselte Sicherungen Ihrer Cloud.', + 'schedule' => 'täglich 03:00', + 'size_trend' => 'Backup-Größe (14 Tage)', + 'col_when' => 'Zeitpunkt', + 'col_size' => 'Größe', + 'col_status' => 'Status', + 'ok' => 'Erfolgreich', + 'restore' => 'Wiederherstellen', + 'note' => 'Clientseitig verschlüsselt, getrennt gelagert. Letzter Wiederherstellungstest: :date — erfolgreich.', + 'restore_toast' => 'Wiederherstellung: wir melden uns binnen 1 Std.', +]; diff --git a/lang/de/cloud.php b/lang/de/cloud.php new file mode 100644 index 0000000..0839f70 --- /dev/null +++ b/lang/de/cloud.php @@ -0,0 +1,24 @@ + 'Meine Cloud', + 'subtitle' => 'Details und Ressourcen Ihrer Instanz.', + 'plan_line' => ':plan · :price €/Monat', + 'datacenter' => 'EU · Rechenzentrum Falkenstein', + 'now' => 'jetzt', + 'open' => 'Cloud öffnen', + 'status_active' => 'Aktiv', + 'plan' => 'Paket', + 'location' => 'Serverstandort', + 'version' => 'Version', + 'current' => 'aktuell', + 'runtime' => 'Laufzeit', + 'resources' => 'Ressourcen', + 'storage' => 'Speicher', + 'storage_growth' => 'Speicherverlauf', + 'storage_growth_sub' => 'Belegter Speicher der letzten 12 Wochen.', + 'restart' => 'Neu starten', + 'snapshot' => 'Snapshot erstellen', + 'logs' => 'Protokolle', + 'action_toast' => 'Aktion im Prototyp nur angedeutet.', +]; diff --git a/lang/de/invoices.php b/lang/de/invoices.php new file mode 100644 index 0000000..5d53573 --- /dev/null +++ b/lang/de/invoices.php @@ -0,0 +1,16 @@ + 'Rechnungen', + 'subtitle' => 'Ihre Abrechnungen und kommende Zahlungen.', + 'col_no' => 'Nummer', + 'col_date' => 'Datum', + 'col_amount' => 'Betrag', + 'col_status' => 'Status', + 'paid' => 'Bezahlt', + 'pdf' => 'PDF', + 'next_charge' => 'Nächste Abbuchung', + 'on_date' => 'am :date', + 'spend' => 'Ausgaben (5 Monate)', + 'download_toast' => 'Rechnungs-PDF im Prototyp nur angedeutet.', +]; diff --git a/lang/de/support.php b/lang/de/support.php new file mode 100644 index 0000000..54938ac --- /dev/null +++ b/lang/de/support.php @@ -0,0 +1,27 @@ + 'Support', + 'subtitle' => 'Wir sind für Sie da — persönlich und schnell.', + 'new' => 'Anfrage stellen', + 'new_toast' => 'Support-Formular im Prototyp nur angedeutet.', + 'contact_hours' => 'Erreichbarkeit', + 'contact_hours_val' => 'Mo–Fr, 08–18 Uhr', + 'contact_email' => 'E-Mail', + 'contact_sla' => 'Reaktionszeit', + 'contact_sla_val' => 'Team-Paket · binnen 4 Std.', + 'tickets' => 'Ihre Anfragen', + 'status_open' => 'Offen', + 'status_progress' => 'In Bearbeitung', + 'status_closed' => 'Erledigt', + 'ticket_migration' => 'Datenübernahme aus Dropbox', + 'ticket_training' => 'Einschulungstermin Sekretariat', + 'ticket_smtp' => 'E-Mail-Versand einrichten', + 'faq' => 'Häufige Fragen', + 'faq_q1' => 'Wie stelle ich ein Backup wieder her?', + 'faq_a1' => 'Wählen Sie unter „Backups" den gewünschten Zeitpunkt und klicken Sie auf „Wiederherstellen". Wir bestätigen die Wiederherstellung binnen einer Stunde.', + 'faq_q2' => 'Kann ich weitere Benutzer hinzufügen?', + 'faq_a2' => 'Ja, bis zum Limit Ihres Pakets jederzeit unter „Benutzer". Zusätzliche Plätze buchen Sie mit einem Klick dazu.', + 'faq_q3' => 'Wo liegen meine Daten?', + 'faq_a3' => 'Ausschließlich in der EU, im Rechenzentrum Falkenstein — verschlüsselt und DSGVO-konform.', +]; diff --git a/lang/de/users.php b/lang/de/users.php new file mode 100644 index 0000000..cb7e5c6 --- /dev/null +++ b/lang/de/users.php @@ -0,0 +1,19 @@ + 'Benutzer', + 'subtitle' => ':count Benutzer · 3 Gruppen · 2 Gastzugänge', + 'add' => 'Benutzer hinzufügen', + 'col_name' => 'Name', + 'col_group' => 'Gruppe', + 'col_role' => 'Rolle', + 'col_status' => 'Status', + 'guest' => 'Gast', + 'active' => 'Aktiv', + 'guests' => 'Gäste', + 'by_group' => 'Nach Gruppe', + 'role_admin' => 'Administrator', + 'role_member' => 'Mitglied', + 'role_guest' => 'Gast', + 'action_toast' => 'Benutzerverwaltung im Prototyp nur angedeutet.', +]; diff --git a/lang/en/backups.php b/lang/en/backups.php new file mode 100644 index 0000000..11f2b2d --- /dev/null +++ b/lang/en/backups.php @@ -0,0 +1,15 @@ + 'Backups', + 'subtitle' => 'Automatic, encrypted backups of your cloud.', + 'schedule' => 'daily 03:00', + 'size_trend' => 'Backup size (14 days)', + 'col_when' => 'When', + 'col_size' => 'Size', + 'col_status' => 'Status', + 'ok' => 'Successful', + 'restore' => 'Restore', + 'note' => 'Client-side encrypted, stored separately. Last restore test: :date — successful.', + 'restore_toast' => 'Restore: we will get back to you within 1 hr.', +]; diff --git a/lang/en/cloud.php b/lang/en/cloud.php new file mode 100644 index 0000000..89e1f2a --- /dev/null +++ b/lang/en/cloud.php @@ -0,0 +1,24 @@ + 'My cloud', + 'subtitle' => 'Details and resources of your instance.', + 'plan_line' => ':plan · €:price/mo', + 'datacenter' => 'EU · Falkenstein data center', + 'now' => 'now', + 'open' => 'Open cloud', + 'status_active' => 'Active', + 'plan' => 'Plan', + 'location' => 'Server location', + 'version' => 'Version', + 'current' => 'up to date', + 'runtime' => 'Runtime', + 'resources' => 'Resources', + 'storage' => 'Storage', + 'storage_growth' => 'Storage over time', + 'storage_growth_sub' => 'Used storage over the last 12 weeks.', + 'restart' => 'Restart', + 'snapshot' => 'Create snapshot', + 'logs' => 'Logs', + 'action_toast' => 'Action is only indicated in this prototype.', +]; diff --git a/lang/en/invoices.php b/lang/en/invoices.php new file mode 100644 index 0000000..5b1056d --- /dev/null +++ b/lang/en/invoices.php @@ -0,0 +1,16 @@ + 'Invoices', + 'subtitle' => 'Your billing history and upcoming charges.', + 'col_no' => 'Number', + 'col_date' => 'Date', + 'col_amount' => 'Amount', + 'col_status' => 'Status', + 'paid' => 'Paid', + 'pdf' => 'PDF', + 'next_charge' => 'Next charge', + 'on_date' => 'on :date', + 'spend' => 'Spend (5 months)', + 'download_toast' => 'Invoice PDF is only indicated in this prototype.', +]; diff --git a/lang/en/support.php b/lang/en/support.php new file mode 100644 index 0000000..9c76129 --- /dev/null +++ b/lang/en/support.php @@ -0,0 +1,27 @@ + 'Support', + 'subtitle' => 'We are here for you — personal and fast.', + 'new' => 'New request', + 'new_toast' => 'Support form is only indicated in this prototype.', + 'contact_hours' => 'Availability', + 'contact_hours_val' => 'Mon–Fri, 8am–6pm', + 'contact_email' => 'Email', + 'contact_sla' => 'Response time', + 'contact_sla_val' => 'Team plan · within 4 hrs', + 'tickets' => 'Your requests', + 'status_open' => 'Open', + 'status_progress' => 'In progress', + 'status_closed' => 'Resolved', + 'ticket_migration' => 'Data import from Dropbox', + 'ticket_training' => 'Training session for the office', + 'ticket_smtp' => 'Set up email delivery', + 'faq' => 'Frequently asked questions', + 'faq_q1' => 'How do I restore a backup?', + 'faq_a1' => 'Under “Backups”, pick the point in time and click “Restore”. We confirm the restore within one hour.', + 'faq_q2' => 'Can I add more users?', + 'faq_a2' => 'Yes, any time under “Users” up to your plan limit. Add extra seats with one click.', + 'faq_q3' => 'Where is my data stored?', + 'faq_a3' => 'Exclusively in the EU, at the Falkenstein data center — encrypted and GDPR-compliant.', +]; diff --git a/lang/en/users.php b/lang/en/users.php new file mode 100644 index 0000000..8ce25e1 --- /dev/null +++ b/lang/en/users.php @@ -0,0 +1,19 @@ + 'Users', + 'subtitle' => ':count users · 3 groups · 2 guest accounts', + 'add' => 'Add user', + 'col_name' => 'Name', + 'col_group' => 'Group', + 'col_role' => 'Role', + 'col_status' => 'Status', + 'guest' => 'Guest', + 'active' => 'Active', + 'guests' => 'Guests', + 'by_group' => 'By group', + 'role_admin' => 'Administrator', + 'role_member' => 'Member', + 'role_guest' => 'Guest', + 'action_toast' => 'User management is only indicated in this prototype.', +]; diff --git a/resources/views/layouts/portal-app.blade.php b/resources/views/layouts/portal-app.blade.php index 07422b9..a76af55 100644 --- a/resources/views/layouts/portal-app.blade.php +++ b/resources/views/layouts/portal-app.blade.php @@ -22,30 +22,19 @@ diff --git a/resources/views/livewire/backups.blade.php b/resources/views/livewire/backups.blade.php new file mode 100644 index 0000000..076ee55 --- /dev/null +++ b/resources/views/livewire/backups.blade.php @@ -0,0 +1,46 @@ +
{{ __('backups.subtitle') }}
+| {{ __('backups.col_when') }} | +{{ __('backups.col_size') }} | +{{ __('backups.col_status') }} | ++ |
|---|---|---|---|
| {{ $r['when'] }} | +{{ $r['size'] }} | +
+
{{ __('cloud.subtitle') }}
+{{ $instance['name'] }}
+ {{ $instance['domain'] }} +{{ __('cloud.storage_growth_sub') }}
+{{ __('invoices.subtitle') }}
+| {{ __('invoices.col_no') }} | +{{ __('invoices.col_date') }} | +{{ __('invoices.col_amount') }} | +{{ __('invoices.col_status') }} | ++ |
|---|---|---|---|---|
| {{ $r['no'] }} | +{{ $r['date'] }} | +{{ $r['amount'] }} | +
{{ __('invoices.next_charge') }}
+{{ $nextAmount }}
+{{ __('invoices.on_date', ['date' => $nextCharge]) }}
+{{ __('support.subtitle') }}
+{{ $label }}
+{{ $val }}
+|
+ {{ $t['subject'] }} +{{ $t['ref'] }} · {{ $t['date'] }} + |
+
+ |
+
{{ __('users.subtitle', ['count' => count($people)]) }}
+| {{ __('users.col_name') }} | +{{ __('users.col_group') }} | +{{ __('users.col_role') }} | +{{ __('users.col_status') }} | +
|---|---|---|---|
|
+ {{ $p['name'] }} +{{ $p['email'] }} + |
+ {{ $p['group'] }} | +{{ $p['role'] }} | +