getLocale(); $growth = [180, 188, 195, 199, 204, 210, 214, 219, 223, 228, 231, 235]; // 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(); // The instance carries what was actually provisioned, and the contract // what was bought. Neither is the catalogue, which only describes what // we would sell someone new — never what this customer already has. $contract = $shown?->subscription; $planKey = $shown?->plan ?? 'team'; $quota = (int) ($shown?->quota_gb ?? $contract?->quota_gb ?? 500); // Usage metering is not wired yet — scale the illustrative curve into the // instance's quota so the chart and the "x / y GB" label never disagree. $curveMax = max($growth); if ($curveMax > $quota) { $growth = array_map(fn ($v) => (int) round($v / $curveMax * $quota), $growth); } $used = $growth[count($growth) - 1]; // address() rather than `custom_domain ?: subdomain`: a domain whose // DNS proof has not been read is not this instance's address, and // printing it here would tell a customer to visit a hostname that does // not resolve to them. $domain = $shown?->subdomain ? $shown->address(ProvisioningSettings::dnsZone()) : 'cloud.example.com'; return view('livewire.cloud', [ 'instance' => [ 'name' => $customer ? __('cloud.instance_name', ['name' => $customer->name]) : __('cloud.title'), 'domain' => $domain, 'status' => $shown->status ?? 'active', // A granted package shows without a price at all — not "free", // not struck through — so a later conversion to paid does not // read as a negotiation. 'plan' => $contract?->isGranted() ? __('cloud.plan_line_granted', ['plan' => 'CluPilot Cloud '.__('billing.plan.'.$planKey)]) : __('cloud.plan_line', [ 'plan' => 'CluPilot Cloud '.__('billing.plan.'.$planKey), // The line ends in "/mo", so a yearly contract has to be // divided down before it goes in. 'price' => (int) round(($contract?->monthlyPriceCents() ?? 0) / 100), ]), 'location' => __('cloud.datacenter'), 'storageUsed' => $used, 'storageQuota' => $quota, 'seats' => __('billing.seats_count', ['count' => $contract?->seats ?? 0]), 'performance' => __('billing.perf.'.($contract?->performance ?? 'standard')), ], '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($used, locale: $locale).' / '.Number::format($quota, locale: $locale).' GB', 'maintenance' => $maintenance, // A plan change writes the new CPU and memory into the VM's // configuration and a running guest only takes them at its next cold // boot. Nobody restarts somebody's cloud as a side effect of a // purchase, so the customer is told instead — otherwise they are // paying for cores they cannot see and have no way of finding out. 'restartPending' => $shown?->restartIsPending() ?? false, ]); } }