feat(portal): bind the cloud card to the real instance (plan/seats/domain/quota) so the maintenance badge matches it
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/portal-design
parent
ac3b3a4e11
commit
d05932105d
|
|
@ -18,28 +18,39 @@ class Cloud extends Component
|
|||
$locale = app()->getLocale();
|
||||
$growth = [180, 188, 195, 199, 204, 210, 214, 219, 223, 228, 231, 235];
|
||||
|
||||
// Maintenance affecting THE DISPLAYED instance's host — scoped to that one
|
||||
// instance so a customer with several instances never sees another
|
||||
// instance's window on this card.
|
||||
// The card is built from the customer's real service instance, so the
|
||||
// maintenance badge below can be scoped to exactly that instance's host.
|
||||
$customer = $this->customer();
|
||||
$shown = $customer?->instances()
|
||||
->whereIn('status', ['active', 'provisioning', 'cancellation_scheduled'])
|
||||
->latest('id')->first();
|
||||
$maintenance = MaintenanceWindow::forInstance($shown)->first();
|
||||
|
||||
$plans = (array) config('provisioning.plans');
|
||||
$planKey = $shown->plan ?? 'team';
|
||||
$plan = $plans[$planKey] ?? [];
|
||||
$quota = (int) ($shown->quota_gb ?? ($plan['quota_gb'] ?? 500));
|
||||
// Usage metering is not wired yet — show the fixture curve until it is.
|
||||
$used = min($growth[count($growth) - 1], $quota);
|
||||
$domain = $shown?->custom_domain
|
||||
?: ($shown?->subdomain ? $shown->subdomain.'.'.config('provisioning.dns.zone', 'clupilot.com') : 'cloud.example.com');
|
||||
|
||||
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]),
|
||||
'name' => $customer ? __('cloud.instance_name', ['name' => $customer->name]) : __('cloud.title'),
|
||||
'domain' => $domain,
|
||||
'status' => $shown->status ?? 'active',
|
||||
'plan' => __('cloud.plan_line', [
|
||||
'plan' => 'CluPilot Cloud '.__('billing.plan.'.$planKey),
|
||||
'price' => (int) round(($plan['price_cents'] ?? 0) / 100),
|
||||
]),
|
||||
'location' => __('cloud.datacenter'),
|
||||
'version' => 'Nextcloud 31.0.4',
|
||||
'php' => 'PHP 8.3 · MariaDB 11.4',
|
||||
'storageUsed' => 235,
|
||||
'storageQuota' => 500,
|
||||
'seats' => __('billing.seats_count', ['count' => 25]),
|
||||
'performance' => __('billing.perf.enhanced'),
|
||||
'storageUsed' => $used,
|
||||
'storageQuota' => $quota,
|
||||
'seats' => __('billing.seats_count', ['count' => $plan['seats'] ?? 0]),
|
||||
'performance' => __('billing.perf.'.($plan['performance'] ?? 'standard')),
|
||||
],
|
||||
'storageChart' => [
|
||||
'type' => 'line',
|
||||
|
|
@ -64,7 +75,7 @@ class Cloud extends Component
|
|||
'plugins' => ['legend' => ['display' => false]],
|
||||
],
|
||||
],
|
||||
'storageLabel' => Number::format(235, locale: $locale).' / '.Number::format(500, locale: $locale).' GB',
|
||||
'storageLabel' => Number::format($used, locale: $locale).' / '.Number::format($quota, locale: $locale).' GB',
|
||||
'maintenance' => $maintenance,
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ return [
|
|||
'current' => 'aktuell',
|
||||
'runtime' => 'Laufzeit',
|
||||
'seats' => 'Benutzer',
|
||||
'instance_name' => 'Cloud der :name',
|
||||
'maintenance_planned' => 'Wartung geplant',
|
||||
'maintenance_active' => 'Wartung läuft',
|
||||
'maintenance_window' => 'Zeitraum: :start bis :end.',
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ return [
|
|||
'current' => 'up to date',
|
||||
'runtime' => 'Runtime',
|
||||
'seats' => 'Users',
|
||||
'instance_name' => ':name cloud',
|
||||
'maintenance_planned' => 'Maintenance planned',
|
||||
'maintenance_active' => 'Maintenance in progress',
|
||||
'maintenance_window' => 'Window: :start to :end.',
|
||||
|
|
|
|||
|
|
@ -15,3 +15,19 @@ it('renders portal tabs for authenticated users', function (string $tab) {
|
|||
->assertOk()
|
||||
->assertSee('CluPilot');
|
||||
})->with($tabs);
|
||||
|
||||
it('binds the cloud card to the real instance', function () {
|
||||
$user = \App\Models\User::factory()->create(['email' => 'c@cloud.test']);
|
||||
$customer = \App\Models\Customer::factory()->create(['email' => 'c@cloud.test', 'user_id' => $user->id, 'name' => 'Acme AG']);
|
||||
$host = \App\Models\Host::factory()->active()->create();
|
||||
\App\Models\Instance::factory()->create([
|
||||
'customer_id' => $customer->id, 'host_id' => $host->id, 'status' => 'active',
|
||||
'plan' => 'business', 'subdomain' => 'acme-ag', 'quota_gb' => 1000,
|
||||
]);
|
||||
|
||||
$this->actingAs($user)->get(route('cloud'))
|
||||
->assertOk()
|
||||
->assertSee('acme-ag.'.config('provisioning.dns.zone')) // real subdomain, not a fixture
|
||||
->assertSee(__('billing.plan.business'))
|
||||
->assertSee(__('billing.perf.high'));
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue