From 5703a0086220168e3a62c4fdd724bb53036165e8 Mon Sep 17 00:00:00 2001 From: isaacclad Date: Sat, 6 Jun 2026 17:30:40 +0000 Subject: [PATCH] Show linked domains on cards and fix Email leftovers. Display hosted_sites on account cards, scope Afia and Settings to hosting, add hosting_settings for notifications, and remove mailbox UI from the hosting layout and account pages. Co-authored-by: Cursor --- .../Controllers/Hosting/AccountController.php | 182 +----------------- .../Controllers/Hosting/AfiaController.php | 77 +++++--- .../Hosting/HostingProductController.php | 2 +- app/Models/HostingAccount.php | 20 ++ app/Models/HostingSetting.php | 13 ++ app/Services/Afia/AfiaService.php | 39 +++- config/afia.php | 4 +- ...6_000001_create_hosting_settings_table.php | 24 +++ resources/js/app.js | 13 +- .../views/hosting/account/billing.blade.php | 36 +--- .../views/hosting/account/settings.blade.php | 67 +------ .../views/hosting/account/wallet.blade.php | 6 +- .../views/hosting/accounts-list.blade.php | 4 +- resources/views/hosting/dashboard.blade.php | 5 +- resources/views/hosting/type.blade.php | 2 +- resources/views/layouts/hosting.blade.php | 1 - resources/views/partials/afia.blade.php | 23 ++- routes/web.php | 4 - tests/Feature/AccountPagesTest.php | 9 +- 19 files changed, 202 insertions(+), 329 deletions(-) create mode 100644 app/Models/HostingSetting.php create mode 100644 database/migrations/2026_06_06_000001_create_hosting_settings_table.php diff --git a/app/Http/Controllers/Hosting/AccountController.php b/app/Http/Controllers/Hosting/AccountController.php index f6448a2..270858c 100644 --- a/app/Http/Controllers/Hosting/AccountController.php +++ b/app/Http/Controllers/Hosting/AccountController.php @@ -3,29 +3,22 @@ namespace App\Http\Controllers\Hosting; use App\Http\Controllers\Controller; -use App\Models\EmailSetting; -use App\Models\User; +use App\Models\HostingSetting; use App\Services\Billing\BillingClient; -use App\Services\Identity\IdentityClient; -use App\Services\Mailbox\MailboxClient; use App\Services\Payment\WalletPaymentService; -use App\Support\MailboxPricing; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\View\View; /** - * Account — Wallet, Billing, Settings. Money is read from the one platform - * UserWallet via the Billing API (tagged 'email'); funding is platform-level, so - * "Add funds" deep-links to the account portal. Settings are email-local prefs. + * Account — Wallet, Billing, Settings for Ladill Hosting. + * Money is read from the one platform UserWallet via the Billing API. */ class AccountController extends Controller { public function __construct( private WalletPaymentService $wallet, private BillingClient $billing, - private MailboxClient $mailboxes, - private IdentityClient $identity, ) {} private function topupUrl(): string @@ -33,7 +26,6 @@ class AccountController extends Controller return 'https://'.config('app.account_domain').'/wallet'; } - /** Wallet: balance + email spend summary + add-funds link. */ public function wallet(): View { $account = ladill_account(); @@ -47,34 +39,15 @@ class AccountController extends Controller ]); } - /** Billing: wallet snapshot + recurring paid-mailbox subscriptions. */ public function billing(): View { $account = ladill_account(); [$balanceMinor, $ledger] = $this->billingSnapshot($account?->public_id); - $paidMailboxes = []; - $monthlyTotalMinor = 0; - try { - foreach ($this->mailboxes->forUser((string) $account?->public_id) as $m) { - if (! ($m['is_paid'] ?? false)) { - continue; - } - $m['price_minor'] = MailboxPricing::priceMinorFor((int) ($m['quota_mb'] ?? 0)); - $m['quota_label'] = MailboxPricing::label((int) ($m['quota_mb'] ?? 0)); - $monthlyTotalMinor += $m['price_minor']; - $paidMailboxes[] = $m; - } - } catch (\Throwable $e) { - report($e); - } - return view('hosting.account.billing', [ 'balanceMinor' => $balanceMinor, 'spentMinor' => (int) ($ledger['spent_minor'] ?? 0), 'creditedMinor' => (int) ($ledger['credited_minor'] ?? 0), - 'paidMailboxes' => $paidMailboxes, - 'monthlyTotalMinor' => $monthlyTotalMinor, 'topupUrl' => $this->topupUrl(), ]); } @@ -82,169 +55,26 @@ class AccountController extends Controller public function settings(): View { $account = ladill_account(); - $settings = EmailSetting::firstOrNew(['user_id' => $account?->id]); - ['linkStatus' => $linkStatus, 'mailboxOptions' => $mailboxOptions, 'showMailboxLinkUi' => $showMailboxLinkUi] = $this->mailboxLinkContext($account); + $settings = HostingSetting::firstOrNew(['user_id' => $account?->id]); return view('hosting.account.settings', [ 'account' => $account, 'settings' => $settings, - 'linkStatus' => $linkStatus, - 'mailboxOptions' => $mailboxOptions, - 'showMailboxLinkUi' => $showMailboxLinkUi, ]); } - public function linkMailbox(Request $request): RedirectResponse - { - $account = ladill_account(); - - $data = $request->validate([ - 'mailbox_address' => ['required', 'email', 'max:255'], - ]); - - try { - $result = $this->identity->linkMailbox( - (string) $account->public_id, - $data['mailbox_address'], - ); - } catch (\Illuminate\Http\Client\RequestException $e) { - $message = (string) $e->response?->json('message', ''); - if ($message !== '') { - return redirect()->route('account.settings')->with('error', $message); - } - - report($e); - - return redirect()->route('account.settings')->with('error', 'Could not link mailbox. Try again in a moment, or contact support if this keeps happening.'); - } catch (\Throwable $e) { - report($e); - - return redirect()->route('account.settings')->with('error', 'Could not link mailbox. Try again in a moment, or contact support if this keeps happening.'); - } - - $request->session()->forget('mailbox_link_banner_dismissed'); - - $connectUrl = (string) ($result['webmail_connect_url'] ?? ''); - if ($connectUrl === '') { - $connectUrl = rtrim((string) config('services.ladill_webmail.url', 'https://mail.ladill.com'), '/').'/sso/connect'; - } - - return redirect()->away($connectUrl); - } - - public function unlinkMailbox(Request $request): RedirectResponse - { - $account = ladill_account(); - - try { - $this->identity->unlinkMailbox((string) $account->public_id); - } catch (\Illuminate\Http\Client\RequestException $e) { - $message = (string) $e->response?->json('message', ''); - if ($message !== '') { - return redirect()->route('account.settings')->with('error', $message); - } - - report($e); - - return redirect()->route('account.settings')->with('error', 'Could not unlink mailbox. Try again in a moment.'); - } catch (\Throwable $e) { - report($e); - - return redirect()->route('account.settings')->with('error', 'Could not unlink mailbox. Try again in a moment.'); - } - - $request->session()->forget('mailbox_link_banner_dismissed'); - - return redirect()->route('account.settings')->with('success', 'Mailbox unlinked from your Ladill account.'); - } - - /** @return array{linkStatus: array, mailboxOptions: array>, showMailboxLinkUi: bool} */ - private function mailboxLinkContext(?User $account): array - { - $linkStatus = ['show_reminder' => false]; - $mailboxOptions = []; - - if (! $account?->public_id) { - return [ - 'linkStatus' => $linkStatus, - 'mailboxOptions' => $mailboxOptions, - 'showMailboxLinkUi' => false, - ]; - } - - try { - $mailboxOptions = $this->mailboxes->forUser((string) $account->public_id); - } catch (\Throwable $e) { - report($e); - } - - try { - $linkStatus = $this->identity->mailboxLinkStatus((string) $account->public_id); - } catch (\Throwable $e) { - report($e); - $linkStatus = $this->localMailboxLinkStatus($account, $mailboxOptions); - } - - $showMailboxLinkUi = (bool) ($linkStatus['linked_mailbox'] ?? null) - || ($linkStatus['show_reminder'] ?? false) - || $this->localNeedsMailboxLink($account, $mailboxOptions, $linkStatus); - - return [ - 'linkStatus' => $linkStatus, - 'mailboxOptions' => $mailboxOptions, - 'showMailboxLinkUi' => $showMailboxLinkUi, - ]; - } - - /** @param array> $mailboxOptions */ - private function localNeedsMailboxLink(User $account, array $mailboxOptions, array $linkStatus): bool - { - if ($linkStatus['linked_mailbox'] ?? null) { - return false; - } - - $email = strtolower(trim($account->email ?? '')); - if ($email === '') { - return false; - } - - foreach ($mailboxOptions as $mailbox) { - if (strtolower((string) ($mailbox['address'] ?? '')) === $email) { - return false; - } - } - - return count($mailboxOptions) > 0; - } - - /** @param array> $mailboxOptions */ - /** @return array */ - private function localMailboxLinkStatus(User $account, array $mailboxOptions): array - { - $needsLink = $this->localNeedsMailboxLink($account, $mailboxOptions, []); - - return [ - 'show_reminder' => $needsLink, - 'stage' => count($mailboxOptions) > 0 ? 'needs_link' : 'needs_mailbox', - 'linked_mailbox' => null, - 'account_email' => $account->email, - ]; - } - public function updateSettings(Request $request): RedirectResponse { $account = ladill_account(); $data = $request->validate([ - 'default_quota_mb' => ['nullable', 'integer', 'min:256', 'max:153600'], 'notify_email' => ['nullable', 'email', 'max:255'], 'product_updates' => ['nullable', 'boolean'], ]); - EmailSetting::updateOrCreate( + HostingSetting::updateOrCreate( ['user_id' => $account->id], [ - 'default_quota_mb' => $data['default_quota_mb'] ?? null, 'notify_email' => $data['notify_email'] ?? null, 'product_updates' => $request->boolean('product_updates'), ], @@ -265,7 +95,7 @@ class AccountController extends Controller try { return [ $this->wallet->balanceMinor(ladill_account()), - $this->billing->serviceLedger($publicId, (string) config('billing.service', 'email')), + $this->billing->serviceLedger($publicId, (string) config('billing.service', 'hosting')), ]; } catch (\Throwable $e) { report($e); diff --git a/app/Http/Controllers/Hosting/AfiaController.php b/app/Http/Controllers/Hosting/AfiaController.php index be6ad3e..499e37d 100644 --- a/app/Http/Controllers/Hosting/AfiaController.php +++ b/app/Http/Controllers/Hosting/AfiaController.php @@ -3,17 +3,17 @@ namespace App\Http\Controllers\Hosting; use App\Http\Controllers\Controller; +use App\Models\CustomerHostingOrder; +use App\Models\HostedSite; +use App\Models\HostingAccount; +use App\Models\HostingAccountMember; +use App\Models\HostingProduct; use App\Services\Afia\AfiaService; use App\Services\Billing\BillingClient; -use App\Services\EmailDomain\EmailDomainClient; -use App\Services\Mailbox\MailboxClient; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -/** - * Ladill Email — Afia chat endpoint. Grounds the assistant in the user's live - * mailboxes/domains so answers are specific. - */ +/** Afia chat for Ladill Hosting — grounded in the user's live hosting accounts. */ class AfiaController extends Controller { public function chat(Request $request, AfiaService $afia): JsonResponse @@ -40,35 +40,60 @@ class AfiaController extends Controller return response()->json(['reply' => $reply]); } - /** @return array Live email context for grounding. */ + /** @return array */ private function context(): array { - $account = ladill_account(); + $user = auth()->user(); - if (! $account) { + if (! $user) { return ['signed_in' => 'no']; } - $pid = (string) $account->public_id; - $ctx = ['signed_in' => 'yes']; + $sharedTypes = [ + HostingProduct::TYPE_SINGLE_DOMAIN, + HostingProduct::TYPE_MULTI_DOMAIN, + HostingProduct::TYPE_WORDPRESS, + ]; - try { - $mailboxes = app(MailboxClient::class)->forUser($pid); - $ctx['mailboxes_total'] = count($mailboxes); - $ctx['mailboxes_paid'] = count(array_filter($mailboxes, fn ($m) => (bool) ($m['is_paid'] ?? false))); - } catch (\Throwable) { - } + $sharedAccountIds = HostingAccountMember::query() + ->where('user_id', $user->id) + ->pluck('hosting_account_id'); - try { - $domains = app(EmailDomainClient::class)->forUser($pid); - $ctx['domains_total'] = count($domains); - $ctx['domains_verified'] = count(array_filter($domains, fn ($d) => (bool) ($d['active'] ?? $d['verified'] ?? false))); - } catch (\Throwable) { - } + $accounts = HostingAccount::query() + ->where(function ($query) use ($user, $sharedAccountIds) { + $query->where('user_id', $user->id); + if ($sharedAccountIds->isNotEmpty()) { + $query->orWhereIn('id', $sharedAccountIds); + } + }) + ->whereHas('product', fn ($q) => $q->whereIn('type', $sharedTypes)) + ->with('sites') + ->get(); - try { - $ctx['wallet_balance_ghs'] = number_format(app(BillingClient::class)->balanceMinor($pid) / 100, 2); - } catch (\Throwable) { + $ctx = [ + 'signed_in' => 'yes', + 'hosting_accounts_total' => $accounts->count(), + 'hosting_accounts_active' => $accounts->where('status', HostingAccount::STATUS_ACTIVE)->count(), + 'linked_domains' => HostedSite::query() + ->whereIn('hosting_account_id', $accounts->pluck('id')) + ->count(), + 'pending_orders' => CustomerHostingOrder::query() + ->forUser($user->id) + ->whereIn('status', [ + CustomerHostingOrder::STATUS_PENDING_PAYMENT, + CustomerHostingOrder::STATUS_PENDING_APPROVAL, + CustomerHostingOrder::STATUS_APPROVED, + CustomerHostingOrder::STATUS_PROVISIONING, + ]) + ->count(), + ]; + + $account = ladill_account(); + if ($account?->public_id) { + try { + $ctx['wallet_balance_ghs'] = number_format(app(BillingClient::class)->balanceMinor((string) $account->public_id) / 100, 2); + } catch (\Throwable) { + } } return $ctx; diff --git a/app/Http/Controllers/Hosting/HostingProductController.php b/app/Http/Controllers/Hosting/HostingProductController.php index d4a26f7..747ebf1 100644 --- a/app/Http/Controllers/Hosting/HostingProductController.php +++ b/app/Http/Controllers/Hosting/HostingProductController.php @@ -76,7 +76,7 @@ class HostingProductController extends Controller } }) ->whereHas('product', fn ($q) => $q->ofType($type)) - ->with('product') + ->with(['product', 'sites']) ->latest() ->get(); diff --git a/app/Models/HostingAccount.php b/app/Models/HostingAccount.php index 4246efd..aef6767 100644 --- a/app/Models/HostingAccount.php +++ b/app/Models/HostingAccount.php @@ -135,6 +135,26 @@ class HostingAccount extends Model return $this->hasMany(HostedSite::class); } + /** Primary label for UI lists — prefers linked hosted_sites over primary_domain. */ + public function linkedDomainLabel(): ?string + { + if ($this->relationLoaded('sites') && $this->sites->isNotEmpty()) { + $domains = $this->sites->pluck('domain')->filter()->unique()->values(); + + if ($domains->count() === 1) { + return (string) $domains->first(); + } + + $preview = $domains->take(2)->implode(', '); + + return $domains->count() > 2 + ? "{$preview} +".($domains->count() - 2) + : $preview; + } + + return filled($this->primary_domain) ? (string) $this->primary_domain : null; + } + public function databases(): HasMany { return $this->hasMany(HostedDatabase::class); diff --git a/app/Models/HostingSetting.php b/app/Models/HostingSetting.php new file mode 100644 index 0000000..6c5ca74 --- /dev/null +++ b/app/Models/HostingSetting.php @@ -0,0 +1,13 @@ + 'boolean']; +} diff --git a/app/Services/Afia/AfiaService.php b/app/Services/Afia/AfiaService.php index a80ab82..c47ee1a 100644 --- a/app/Services/Afia/AfiaService.php +++ b/app/Services/Afia/AfiaService.php @@ -6,9 +6,9 @@ use Illuminate\Support\Facades\Http; use RuntimeException; /** - * Afia for Ladill Email — an AI assistant scoped to buying & managing mailboxes - * and email domains. Self-contained: builds an email-specific system prompt + - * the user's live context and calls the configured LLM (OpenAI or Anthropic). + * Afia — an AI assistant scoped to a Ladill product (hosting or email). + * Self-contained: builds a product-specific system prompt + live context + * and calls the configured LLM (OpenAI or Anthropic). */ class AfiaService { @@ -90,6 +90,39 @@ class AfiaService { $ctx = collect($context)->map(fn ($v, $k) => "- {$k}: {$v}")->implode("\n"); + return match ((string) config('afia.product', 'hosting')) { + 'email' => $this->emailSystemPrompt($ctx), + default => $this->hostingSystemPrompt($ctx), + }; + } + + private function hostingSystemPrompt(string $ctx): string + { + return << env('AFIA_PRODUCT', 'hosting'), 'enabled' => (bool) env('AFIA_ENABLED', true), 'provider' => env('AFIA_PROVIDER', 'openai'), // openai | anthropic 'model' => env('AFIA_MODEL', 'gpt-4o-mini'), diff --git a/database/migrations/2026_06_06_000001_create_hosting_settings_table.php b/database/migrations/2026_06_06_000001_create_hosting_settings_table.php new file mode 100644 index 0000000..271a7b6 --- /dev/null +++ b/database/migrations/2026_06_06_000001_create_hosting_settings_table.php @@ -0,0 +1,24 @@ +id(); + $table->foreignId('user_id')->unique()->constrained()->cascadeOnDelete(); + $table->string('notify_email')->nullable(); + $table->boolean('product_updates')->default(true); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('hosting_settings'); + } +}; diff --git a/resources/js/app.js b/resources/js/app.js index b38bd4c..2a66a04 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -5,21 +5,16 @@ import collapse from '@alpinejs/collapse'; Alpine.plugin(collapse); -// Afia — Ladill Email's AI assistant (slide-over chat). Opened via the topbar AI button -// which dispatches a window 'afia-open' event. +// Afia — Ladill in-app AI assistant (slide-over chat). Opened via the topbar AI button +// which dispatches a window 'afia-open' event. Greeting/suggestions are passed from Blade. Alpine.data('afia', (config = {}) => ({ open: false, input: '', loading: false, messages: [ - { role: 'assistant', text: "Hi, I'm Afia 👋 Ask me anything about email — setting up a domain, verifying DNS, creating mailboxes, IMAP/SMTP settings or billing…" }, - ], - suggestions: [ - 'How do I set up email for my domain?', - 'What DNS records do I need to verify?', - 'How do I create a mailbox?', - 'What are my IMAP and SMTP settings?', + { role: 'assistant', text: config.greeting || "Hi, I'm Afia 👋 How can I help?" }, ], + suggestions: config.suggestions || [], init() { window.addEventListener('afia-open', () => { this.open = true; diff --git a/resources/views/hosting/account/billing.blade.php b/resources/views/hosting/account/billing.blade.php index c0bbd70..8bdd60c 100644 --- a/resources/views/hosting/account/billing.blade.php +++ b/resources/views/hosting/account/billing.blade.php @@ -1,8 +1,10 @@ - +@extends('layouts.hosting') +@section('title', 'Billing — Ladill Hosting') +@section('content') @php $fmt = fn ($m) => 'GHS '.number_format($m / 100, 2); @endphp

Billing

-

Your Ladill wallet funds hosting and other Ladill apps.

+

Your Ladill wallet funds hosting renewals and upgrades.

@@ -20,31 +22,7 @@
-
-
-

Hosting subscriptions

- billed from wallet -
- @if(empty($paidMailboxes)) -

No active hosting subscriptions yet.

- @else -
    - @foreach($paidMailboxes as $m) -
  • -
    -

    {{ $m['address'] ?? '—' }}

    -

    {{ $m['quota_label'] }} · {{ ucfirst($m['status'] ?? 'active') }}

    -
    - {{ $fmt($m['price_minor']) }}/mo -
  • - @endforeach -
-
- Monthly total - {{ $fmt($monthlyTotalMinor) }} -
- @endif -
-

Keep your wallet funded to avoid hosting interruption.

+

Hosting plan renewals and upgrades are billed from your Ladill wallet. Manage individual accounts from the dashboard or account overview pages.

+

Keep your wallet funded to avoid hosting interruption.

-
+@endsection diff --git a/resources/views/hosting/account/settings.blade.php b/resources/views/hosting/account/settings.blade.php index 7616c8d..ac142d8 100644 --- a/resources/views/hosting/account/settings.blade.php +++ b/resources/views/hosting/account/settings.blade.php @@ -1,71 +1,16 @@ - -@php $emailApp = 'https://email.'.config('app.platform_domain'); @endphp +@extends('layouts.hosting') +@section('title', 'Settings — Ladill Hosting') +@section('content')

Settings

-

Hosting preferences and account mailbox linking.

- - @if($showMailboxLinkUi ?? (($linkStatus['linked_mailbox'] ?? null) || ($linkStatus['show_reminder'] ?? false))) -
-
- - @include('partials.ladill-pro-icon') - -
-

Link to mailbox

-

- Your Ladill account uses {{ $linkStatus['account_email'] ?? $account->email }}. - Link a mailbox so Ladill Mail opens with your Ladill sign-in. -

- - @if($linkStatus['linked_mailbox'] ?? null) -
- Linked mailbox: {{ $linkStatus['linked_mailbox'] }} -
-
- @csrf @method('DELETE') - -
- @elseif(($linkStatus['stage'] ?? '') === 'needs_domain') -

Add and verify an email domain first.

- - Go to Ladill Email - - - @elseif(($linkStatus['stage'] ?? '') === 'needs_mailbox') -

Create a mailbox on your verified domain first.

- - Create mailbox - - - @elseif(count($mailboxOptions) > 0) -
- @csrf @method('PUT') -
- - - @error('mailbox_address')

{{ $message }}

@enderror -
- -
- @endif -
-
-
- @endif +

Hosting notifications and preferences.

@csrf @method('PUT')

Notifications

+

Where we send hosting renewal reminders, suspension notices, and resource warnings.

Save settings
- +@endsection diff --git a/resources/views/hosting/account/wallet.blade.php b/resources/views/hosting/account/wallet.blade.php index 30ba58b..693950c 100644 --- a/resources/views/hosting/account/wallet.blade.php +++ b/resources/views/hosting/account/wallet.blade.php @@ -1,4 +1,6 @@ - +@extends('layouts.hosting') +@section('title', 'Wallet — Ladill Hosting') +@section('content') @php $fmt = fn ($m) => 'GHS '.number_format($m / 100, 2); @endphp

Wallet

@@ -22,4 +24,4 @@

Hosting renewals and upgrades are billed from this wallet.

- +@endsection diff --git a/resources/views/hosting/accounts-list.blade.php b/resources/views/hosting/accounts-list.blade.php index 71d9042..f7464aa 100644 --- a/resources/views/hosting/accounts-list.blade.php +++ b/resources/views/hosting/accounts-list.blade.php @@ -31,9 +31,11 @@

- {{ $account->primary_domain ?: $account->username }} + {{ $account->linkedDomainLabel() ?? $account->username }}

+ {{ $account->username }} + · {{ $account->product?->name ?? 'Hosting' }}
-

{{ $account->primary_domain ?: $account->username }}

+

{{ $account->linkedDomainLabel() ?? $account->username }}

- {{ $account->product?->name ?? 'Hosting' }} + {{ $account->username }} + · {{ $account->product?->name ?? 'Hosting' }} · {{ $account->sites->count() }} {{ Str::plural('domain', $account->sites->count()) }} @if ($account->expires_at) · Expires {{ $account->expires_at->format('d M Y') }} diff --git a/resources/views/hosting/type.blade.php b/resources/views/hosting/type.blade.php index cfd1c1d..4766915 100644 --- a/resources/views/hosting/type.blade.php +++ b/resources/views/hosting/type.blade.php @@ -124,7 +124,7 @@

Developer access

@endif - {{ filled($account->primary_domain) ? $account->primary_domain : '—' }} + {{ $account->linkedDomainLabel() ?? '—' }} {{ ucfirst($account->status) }} diff --git a/resources/views/layouts/hosting.blade.php b/resources/views/layouts/hosting.blade.php index 626e1ad..9853416 100644 --- a/resources/views/layouts/hosting.blade.php +++ b/resources/views/layouts/hosting.blade.php @@ -21,7 +21,6 @@ @include('partials.topbar')
@include('partials.flash') - @include('partials.mailbox-link-banner') @yield('content')
diff --git a/resources/views/partials/afia.blade.php b/resources/views/partials/afia.blade.php index b83e096..adc2c23 100644 --- a/resources/views/partials/afia.blade.php +++ b/resources/views/partials/afia.blade.php @@ -1,5 +1,20 @@ -{{-- Afia — Ladill Hosting AI assistant slide-over. Opened via $dispatch('afia-open'). --}} -
+@php + $afiaProduct = $afiaProduct ?? (request()->routeIs('email.*') ? 'email' : 'hosting'); + $afiaGreeting = $afiaProduct === 'email' + ? "Hi, I'm Afia 👋 Ask me anything about email — setting up a domain, verifying DNS, creating mailboxes, IMAP/SMTP settings or billing…" + : "Hi, I'm Afia 👋 Ask me anything about hosting — choosing a plan, linking a domain, using the control panel, SSL, or renewals…"; + $afiaSuggestions = $afiaProduct === 'email' + ? ['How do I set up email for my domain?', 'What DNS records do I need to verify?', 'How do I create a mailbox?', 'What are my IMAP and SMTP settings?'] + : ['How do I link a domain to my hosting?', 'How do I open the control panel?', 'How do I renew my hosting plan?', 'How do I install WordPress?']; + $afiaSubtitle = $afiaProduct === 'email' ? 'Email assistant' : 'Hosting assistant'; +@endphp +{{-- Afia — Ladill AI assistant slide-over. Opened via $dispatch('afia-open'). --}} +

Afia

-

Email assistant

+

{{ $afiaSubtitle }}

-
+