454 lines
29 KiB
PHP
454 lines
29 KiB
PHP
@php
|
||
$money = fn (?int $cents, string $currency = 'EUR') => $cents === null
|
||
? '—'
|
||
: Number::currency($cents / 100, in: $currency, locale: app()->getLocale());
|
||
$date = fn ($value) => $value === null ? '—' : $value->local()->isoFormat('D. MMM YYYY');
|
||
@endphp
|
||
|
||
<div class="mx-auto max-w-[1120px] space-y-6">
|
||
{{-- ── Who, at a glance ─────────────────────────────────────────────────
|
||
The four things somebody on the phone needs before they say anything:
|
||
who it is, whether the account is live, what they are on, and whether
|
||
the machine is running. --}}
|
||
<div class="animate-rise">
|
||
<a href="{{ route('admin.customers') }}" wire:navigate class="text-xs font-semibold text-muted hover:text-ink">
|
||
‹ {{ __('customer_detail.back') }}
|
||
</a>
|
||
<div class="mt-1 flex flex-wrap items-center gap-x-4 gap-y-2">
|
||
<h1 class="text-2xl font-bold tracking-tight text-ink">{{ $customer->name }}</h1>
|
||
<x-ui.badge :status="$customer->status === 'active' ? 'active' : 'warning'">
|
||
{{ __('admin.status.'.$customer->status) }}
|
||
</x-ui.badge>
|
||
@if ($subscription)
|
||
<x-ui.badge status="provisioning">{{ __('billing.plan.'.$subscription->plan) }}</x-ui.badge>
|
||
@endif
|
||
<a href="mailto:{{ $customer->email }}" class="ml-auto font-mono text-sm text-muted hover:text-ink">{{ $customer->email }}</a>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── The tabs ─────────────────────────────────────────────────────────
|
||
Four different questions, and stacking them made a page nobody read to
|
||
the bottom. Writing is last, because it is what you do after reading.
|
||
The choice is in the query string, so a reload, a bookmark and the back
|
||
button all land where the operator was. --}}
|
||
<div class="flex flex-wrap items-center gap-x-1 gap-y-2 border-b border-line animate-rise [animation-delay:40ms]" role="tablist">
|
||
@foreach ($tabs as $name)
|
||
<button type="button" role="tab" wire:click="$set('tab', '{{ $name }}')"
|
||
aria-selected="{{ $tab === $name ? 'true' : 'false' }}"
|
||
@class([
|
||
'flex items-center gap-2 whitespace-nowrap border-b-2 px-4 py-2.5 text-sm font-medium transition-colors -mb-px',
|
||
'border-accent-active text-ink' => $tab === $name,
|
||
'border-transparent text-muted hover:text-ink' => $tab !== $name,
|
||
])>
|
||
<x-ui.icon :name="['overview' => 'users', 'package' => 'box', 'billing' => 'receipt', 'messages' => 'mail', 'compose' => 'send'][$name] ?? 'settings'"
|
||
class="size-4" />{{ __('customer_detail.tab.'.$name) }}
|
||
@if ($name === 'messages' && $openRequests > 0)
|
||
<span class="rounded-pill bg-warning-bg px-1.5 text-[10px] font-semibold text-warning">{{ $openRequests }}</span>
|
||
@endif
|
||
</button>
|
||
@endforeach
|
||
</div>
|
||
|
||
{{-- ══ Stammdaten ═══════════════════════════════════════════════════════ --}}
|
||
@if ($tab === 'overview')
|
||
<div class="grid gap-5 lg:grid-cols-2 lg:items-start">
|
||
{{-- `editing` is local: fetching the modal is a round trip, and a
|
||
click with nothing to show for it reads as a click that missed. --}}
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise"
|
||
x-data="{ editing: false }"
|
||
x-on:modal-opened.window="editing = false"
|
||
x-on:modalclosed.window="editing = false">
|
||
<div class="flex flex-wrap items-center gap-3">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.identity') }}</h2>
|
||
{{-- R20: editing happens in a modal, never in the row. --}}
|
||
<x-ui.button variant="secondary" size="sm" class="ml-auto"
|
||
x-bind:disabled="editing"
|
||
x-on:click="editing = true; setTimeout(() => editing = false, 6000); $dispatch('openModal', { component: 'admin.edit-customer', arguments: { uuid: '{{ $customer->uuid }}' } })">
|
||
<x-ui.icon name="pencil" class="size-4" x-show="!editing" />
|
||
<x-ui.icon name="refresh" class="size-4 animate-spin" x-show="editing" x-cloak />
|
||
{{ __('customer_detail.edit') }}
|
||
</x-ui.button>
|
||
</div>
|
||
<dl class="mt-4 space-y-3 text-sm">
|
||
@foreach ([
|
||
__('customer_detail.company') => $customer->name,
|
||
__('customer_detail.contact') => $customer->contact_name ?: '—',
|
||
__('customer_detail.email') => $customer->email,
|
||
__('customer_detail.phone') => $customer->phone ?: '—',
|
||
__('customer_detail.since') => $date($customer->created_at),
|
||
__('customer_detail.locale') => strtoupper((string) ($customer->locale ?: '—')),
|
||
] as $term => $value)
|
||
<div class="flex justify-between gap-4 border-b border-line pb-3 last:border-0 last:pb-0">
|
||
<dt class="text-muted">{{ $term }}</dt>
|
||
<dd class="text-right font-medium text-ink">{{ $value }}</dd>
|
||
</div>
|
||
@endforeach
|
||
</dl>
|
||
</div>
|
||
|
||
<div class="space-y-5">
|
||
{{-- Whose money it is, in the tax sense. Consumer or business is
|
||
not cosmetic: it decides whether a withdrawal right exists
|
||
at all, and "nobody asked" is treated as consumer. --}}
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise [animation-delay:60ms]">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.tax') }}</h2>
|
||
<dl class="mt-4 space-y-3 text-sm">
|
||
<div class="flex justify-between gap-4">
|
||
<dt class="text-muted">{{ __('customer_detail.type') }}</dt>
|
||
<dd class="text-right font-medium text-ink">
|
||
@if ($customer->hasRecordedType())
|
||
{{ __('customer_detail.type_'.$customer->customer_type) }}
|
||
@else
|
||
<span class="text-warning">{{ __('customer_detail.type_unknown') }}</span>
|
||
@endif
|
||
</dd>
|
||
</div>
|
||
<div class="flex justify-between gap-4">
|
||
<dt class="text-muted">{{ __('customer_detail.vat_id') }}</dt>
|
||
<dd class="text-right font-mono text-ink">
|
||
{{ $customer->vat_id ?: '—' }}
|
||
@if ($customer->vat_id && $customer->hasVerifiedVatId())
|
||
<x-ui.badge status="active" class="ml-1">{{ __('customer_detail.verified') }}</x-ui.badge>
|
||
@elseif ($customer->vat_id)
|
||
<x-ui.badge status="warning" class="ml-1">{{ __('customer_detail.unverified') }}</x-ui.badge>
|
||
@endif
|
||
</dd>
|
||
</div>
|
||
<div class="flex justify-between gap-4">
|
||
<dt class="text-muted">{{ __('customer_detail.stripe') }}</dt>
|
||
<dd class="text-right font-mono text-xs text-muted">{{ $customer->stripe_customer_id ?: '—' }}</dd>
|
||
</div>
|
||
</dl>
|
||
</div>
|
||
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise [animation-delay:120ms]">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.address') }}</h2>
|
||
<p class="mt-3 whitespace-pre-line text-sm leading-relaxed text-body">
|
||
{{ $customer->billing_address ?: __('customer_detail.no_address') }}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
{{-- ══ Paket & Maschine ═════════════════════════════════════════════════ --}}
|
||
@if ($tab === 'package')
|
||
@if ($subscription === null)
|
||
<x-ui.alert variant="info">{{ __('customer_detail.no_contract') }}</x-ui.alert>
|
||
@else
|
||
<div class="grid gap-5 lg:grid-cols-2 lg:items-start">
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise">
|
||
<div class="flex flex-wrap items-center gap-3">
|
||
<h2 class="font-semibold text-ink">{{ __('billing.plan.'.$subscription->plan) }}</h2>
|
||
<x-ui.badge :status="$subscription->status === 'active' ? 'active' : 'warning'">
|
||
{{ $subscription->status }}
|
||
</x-ui.badge>
|
||
</div>
|
||
|
||
{{-- The contract's OWN frozen figures, not today's catalogue:
|
||
this is what the customer is owed, and a price rise does
|
||
not reach back into it. --}}
|
||
<dl class="mt-4 space-y-3 text-sm">
|
||
@foreach ([
|
||
__('customer_detail.price') => $money($subscription->price_cents, $subscription->currency).' '.__('customer_detail.net_per', ['term' => __('customer_detail.term_'.$subscription->term)]),
|
||
__('customer_detail.quota') => $subscription->quota_gb.' GB',
|
||
__('customer_detail.traffic') => $subscription->traffic_gb.' GB',
|
||
__('customer_detail.seats') => $subscription->seats,
|
||
__('customer_detail.started') => $date($subscription->started_at),
|
||
__('customer_detail.period_end') => $date($subscription->current_period_end),
|
||
] as $term => $value)
|
||
<div class="flex justify-between gap-4 border-b border-line pb-3 last:border-0 last:pb-0">
|
||
<dt class="text-muted">{{ $term }}</dt>
|
||
<dd class="text-right font-medium text-ink">{{ $value }}</dd>
|
||
</div>
|
||
@endforeach
|
||
</dl>
|
||
|
||
@if ($subscription->cancelled_at)
|
||
<x-ui.alert variant="warning" class="mt-4">
|
||
{{ __('customer_detail.cancelled', ['date' => $date($subscription->cancelled_at)]) }}
|
||
</x-ui.alert>
|
||
@endif
|
||
</div>
|
||
|
||
<div class="space-y-5">
|
||
@if ($subscription->addons->isNotEmpty())
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise [animation-delay:60ms]">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.addons') }}</h2>
|
||
<ul class="mt-3 divide-y divide-line text-sm">
|
||
@foreach ($subscription->addons as $addon)
|
||
{{-- addon_key and price_cents are the column
|
||
names; the price is the one it was
|
||
BOOKED at, which is what the customer
|
||
agreed to and what the row freezes. --}}
|
||
<li class="flex flex-wrap items-baseline justify-between gap-3 py-2.5">
|
||
<span class="text-body">
|
||
{{ __('billing.addon.'.$addon->addon_key.'.name') }}
|
||
@if ($addon->cancels_at)
|
||
<span class="text-xs text-warning">
|
||
{{ __('customer_detail.addon_until', ['date' => $date($addon->cancels_at)]) }}
|
||
</span>
|
||
@endif
|
||
</span>
|
||
<span class="font-mono tabular-nums text-ink">
|
||
{{ $addon->quantity > 1 ? $addon->quantity.' × ' : '' }}{{ $money($addon->price_cents, $subscription->currency) }}
|
||
</span>
|
||
</li>
|
||
@endforeach
|
||
</ul>
|
||
</div>
|
||
@endif
|
||
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise [animation-delay:120ms]">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.machine') }}</h2>
|
||
@if ($instance === null)
|
||
<p class="mt-3 text-sm text-muted">{{ __('customer_detail.no_instance') }}</p>
|
||
@else
|
||
<dl class="mt-4 space-y-3 text-sm">
|
||
@foreach ([
|
||
__('customer_detail.address_web') => $instance->subdomain ?: '—',
|
||
__('customer_detail.instance_status') => __('admin.status.'.$instance->status),
|
||
__('customer_detail.host') => $instance->host?->name ?? '—',
|
||
__('customer_detail.datacenter') => $instance->host?->datacenter ?? '—',
|
||
__('customer_detail.disk') => $instance->disk_gb.' GB',
|
||
] as $term => $value)
|
||
<div class="flex justify-between gap-4 border-b border-line pb-3 last:border-0 last:pb-0">
|
||
<dt class="text-muted">{{ $term }}</dt>
|
||
<dd class="text-right font-mono text-ink">{{ $value }}</dd>
|
||
</div>
|
||
@endforeach
|
||
</dl>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
@endif
|
||
|
||
{{-- ══ Zahlungen ════════════════════════════════════════════════════════ --}}
|
||
@if ($tab === 'billing')
|
||
<div class="space-y-5">
|
||
<div class="overflow-hidden rounded-lg border border-line bg-surface shadow-xs animate-rise">
|
||
<div class="flex flex-wrap items-center gap-3 border-b border-line px-6 py-4">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.invoices') }}</h2>
|
||
<x-ui.button :href="route('admin.invoices.new', ['customer' => $customer->uuid])"
|
||
variant="secondary" size="sm" class="ml-auto" wire:navigate>
|
||
<x-ui.icon name="receipt" class="size-4" />{{ __('customer_detail.write_invoice') }}
|
||
</x-ui.button>
|
||
</div>
|
||
|
||
@if ($invoices->isEmpty())
|
||
<p class="p-8 text-center text-sm text-muted">{{ __('customer_detail.no_invoices') }}</p>
|
||
@else
|
||
<table class="w-full text-sm">
|
||
<thead>
|
||
<tr class="border-b border-line bg-surface-2 text-left text-xs font-semibold text-muted">
|
||
<th class="px-6 py-3 font-semibold">{{ __('customer_detail.number') }}</th>
|
||
<th class="px-6 py-3 font-semibold">{{ __('customer_detail.issued') }}</th>
|
||
<th class="px-6 py-3 text-right font-semibold">{{ __('customer_detail.net') }}</th>
|
||
<th class="px-6 py-3 text-right font-semibold">{{ __('customer_detail.gross') }}</th>
|
||
<th class="px-6 py-3"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@foreach ($invoices as $invoice)
|
||
<tr class="border-b border-line last:border-0">
|
||
<td class="px-6 py-3 font-mono text-ink">{{ $invoice->number }}</td>
|
||
<td class="px-6 py-3 text-muted">{{ $date($invoice->issued_on) }}</td>
|
||
<td class="px-6 py-3 text-right font-mono tabular-nums text-body">{{ $money($invoice->net_cents, $invoice->currency) }}</td>
|
||
<td class="px-6 py-3 text-right font-mono tabular-nums font-semibold text-ink">{{ $money($invoice->gross_cents, $invoice->currency) }}</td>
|
||
<td class="px-6 py-3 text-right">
|
||
<a href="{{ route('admin.invoices.pdf', $invoice->uuid) }}"
|
||
class="text-xs font-semibold text-accent-text hover:underline">PDF</a>
|
||
</td>
|
||
</tr>
|
||
@endforeach
|
||
</tbody>
|
||
</table>
|
||
@endif
|
||
</div>
|
||
|
||
{{-- What they actually bought, as opposed to what was invoiced. The
|
||
two answer different questions: an order is a purchase, an
|
||
invoice is a document about one. --}}
|
||
<div class="overflow-hidden rounded-lg border border-line bg-surface shadow-xs animate-rise [animation-delay:60ms]">
|
||
<h2 class="border-b border-line px-6 py-4 font-semibold text-ink">{{ __('customer_detail.orders') }}</h2>
|
||
|
||
@if ($orders->isEmpty())
|
||
<p class="p-8 text-center text-sm text-muted">{{ __('customer_detail.no_orders') }}</p>
|
||
@else
|
||
<ul class="divide-y divide-line">
|
||
@foreach ($orders as $order)
|
||
<li class="flex flex-wrap items-baseline gap-x-4 gap-y-1 px-6 py-3 text-sm">
|
||
<span class="font-medium text-ink">{{ $order->label() }}</span>
|
||
<x-ui.badge :status="$order->status === 'paid' ? 'active' : 'warning'">{{ $order->status }}</x-ui.badge>
|
||
<span class="font-mono text-xs text-muted">{{ $date($order->created_at) }}</span>
|
||
<span class="ml-auto font-mono tabular-nums text-ink">{{ $money($order->amount_cents, $order->currency) }}</span>
|
||
</li>
|
||
@endforeach
|
||
</ul>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
{{-- ══ Nachrichten ══════════════════════════════════════════════════════ --}}
|
||
@if ($tab === 'messages')
|
||
<div class="space-y-5">
|
||
{{-- What they asked through the portal --}}
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.requests') }}</h2>
|
||
|
||
@if ($requests->isEmpty())
|
||
<p class="mt-3 text-sm text-muted">{{ __('customer_detail.no_requests') }}</p>
|
||
@else
|
||
<ul class="mt-3 divide-y divide-line">
|
||
@foreach ($requests as $request)
|
||
<li class="py-4">
|
||
<div class="flex flex-wrap items-baseline gap-x-3 gap-y-1">
|
||
<span class="font-medium text-ink">{{ $request->subject }}</span>
|
||
<x-ui.badge :status="$request->isOpen() ? 'warning' : 'active'">
|
||
{{ __('support.status_'.$request->status) }}
|
||
</x-ui.badge>
|
||
<span class="ml-auto text-xs text-muted">{{ $request->created_at->local()->isoFormat('D. MMM YYYY, HH:mm') }}</span>
|
||
</div>
|
||
<p class="mt-2 whitespace-pre-line text-sm leading-relaxed text-body">{{ $request->body }}</p>
|
||
@if ($request->isOpen())
|
||
<x-ui.button wire:click="answer('{{ $request->uuid }}')" variant="secondary" size="sm" class="mt-3">
|
||
{{ __('customer_detail.answer') }}
|
||
</x-ui.button>
|
||
@endif
|
||
</li>
|
||
@endforeach
|
||
</ul>
|
||
@endif
|
||
</div>
|
||
|
||
{{-- What they wrote by mail --}}
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise [animation-delay:60ms]">
|
||
<div class="flex flex-wrap items-center gap-3">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.inbound') }}</h2>
|
||
<a href="{{ route('admin.inbox') }}" class="ml-auto text-xs font-semibold text-accent-text hover:underline">
|
||
{{ __('customer_detail.to_inbox') }} ›
|
||
</a>
|
||
</div>
|
||
|
||
@if ($inbound->isEmpty())
|
||
<p class="mt-3 text-sm text-muted">{{ __('customer_detail.no_inbound') }}</p>
|
||
@else
|
||
<ul class="mt-3 divide-y divide-line">
|
||
@foreach ($inbound as $mail)
|
||
<li class="py-3">
|
||
<div class="flex flex-wrap items-baseline gap-x-3 gap-y-1 text-sm">
|
||
<span class="font-medium text-ink">{{ $mail->subject ?: __('inbox.no_subject') }}</span>
|
||
@if ($mail->hasAttachments())
|
||
<x-ui.badge status="warning">{{ __('inbox.attachments') }}: {{ count($mail->attachments) }}</x-ui.badge>
|
||
@endif
|
||
<span class="ml-auto font-mono text-xs text-muted">{{ $mail->received_at->local()->isoFormat('D. MMM YYYY, HH:mm') }}</span>
|
||
</div>
|
||
<p class="mt-1.5 whitespace-pre-line text-xs leading-relaxed text-body">{{ $mail->body }}</p>
|
||
</li>
|
||
@endforeach
|
||
</ul>
|
||
@endif
|
||
</div>
|
||
|
||
{{-- What we sent --}}
|
||
<div class="rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise [animation-delay:120ms]">
|
||
<div class="flex flex-wrap items-center gap-3">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_detail.mails') }}</h2>
|
||
<a href="{{ route('admin.mail-log') }}" class="ml-auto text-xs font-semibold text-accent-text hover:underline">
|
||
{{ __('customer_detail.all_mails') }} ›
|
||
</a>
|
||
</div>
|
||
|
||
@if ($mails->isEmpty())
|
||
<p class="mt-3 text-sm text-muted">{{ __('customer_detail.no_mails') }}</p>
|
||
@else
|
||
<ul class="mt-3 divide-y divide-line">
|
||
@foreach ($mails as $mail)
|
||
<li class="py-3">
|
||
<div class="flex flex-wrap items-baseline gap-x-3 gap-y-1 text-sm">
|
||
<span class="font-medium text-ink">{{ $mail->subject }}</span>
|
||
@if ($mail->from_operator)
|
||
<x-ui.badge status="provisioning">{{ __('customer_detail.by_hand') }}</x-ui.badge>
|
||
@endif
|
||
<span class="ml-auto font-mono text-xs text-muted">
|
||
{{ $mail->sent_at->local()->isoFormat('D. MMM YYYY, HH:mm') }}
|
||
</span>
|
||
</div>
|
||
@if ($mail->body)
|
||
<p class="mt-1.5 whitespace-pre-line text-xs leading-relaxed text-muted">{{ $mail->body }}</p>
|
||
@else
|
||
<p class="mt-1 font-mono text-xs text-faint">{{ $mail->kind() }}</p>
|
||
@endif
|
||
</li>
|
||
@endforeach
|
||
</ul>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
{{-- ══ Schreiben ════════════════════════════════════════════════════════ --}}
|
||
@if ($tab === 'compose')
|
||
<div class="grid gap-5 lg:grid-cols-[1fr_300px] lg:items-start">
|
||
<div class="space-y-4 rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise">
|
||
<div class="flex flex-wrap items-center gap-3">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_message.title') }}</h2>
|
||
@if ($answering)
|
||
<x-ui.badge status="provisioning">{{ __('customer_message.answering') }}</x-ui.badge>
|
||
<button type="button" wire:click="cancelAnswer" class="text-xs font-semibold text-muted hover:text-ink">
|
||
{{ __('customer_message.cancel_answer') }}
|
||
</button>
|
||
@endif
|
||
</div>
|
||
|
||
<form wire:submit="send" class="space-y-4">
|
||
<x-ui.input name="subject" wire:model="subject" :label="__('customer_message.subject')" />
|
||
<div>
|
||
<label for="body" class="block text-sm font-medium text-body">{{ __('customer_message.body') }}</label>
|
||
<textarea id="body" rows="12" wire:model="body"
|
||
class="mt-1.5 block w-full rounded border border-line bg-surface px-3.5 py-2.5 text-sm text-ink placeholder:text-faint"
|
||
placeholder="{{ __('customer_message.body_hint') }}"></textarea>
|
||
@error('body')<p class="mt-1.5 text-xs text-danger">{{ $message }}</p>@enderror
|
||
</div>
|
||
<div class="flex flex-wrap items-center gap-3">
|
||
<x-ui.button type="submit" variant="primary" wire:loading.attr="disabled" wire:target="send">
|
||
<x-ui.icon name="send" class="size-4" />{{ __('customer_message.send') }}
|
||
</x-ui.button>
|
||
<p class="text-xs text-muted">{{ __('customer_message.note', ['email' => $customer->email]) }}</p>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
{{-- The templates. Inserted with this customer's own details already
|
||
in them; the last two sentences stay the operator's to write. --}}
|
||
<div class="space-y-3 rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise [animation-delay:60ms] lg:sticky lg:top-6">
|
||
<div class="flex flex-wrap items-center gap-2">
|
||
<h2 class="font-semibold text-ink">{{ __('customer_message.templates') }}</h2>
|
||
<a href="{{ route('admin.templates') }}" class="ml-auto text-xs font-semibold text-accent-text hover:underline">
|
||
{{ __('customer_message.manage_templates') }} ›
|
||
</a>
|
||
</div>
|
||
|
||
@if ($templates->isEmpty())
|
||
<p class="text-xs leading-relaxed text-muted">{{ __('customer_message.no_templates') }}</p>
|
||
@else
|
||
<p class="text-xs leading-relaxed text-muted">{{ __('customer_message.templates_note') }}</p>
|
||
<ul class="space-y-1.5">
|
||
@foreach ($templates as $template)
|
||
<li>
|
||
<button type="button" wire:click="useTemplate('{{ $template->uuid }}')"
|
||
class="w-full rounded-md border border-line bg-surface-2 px-3 py-2 text-left text-sm text-body transition-colors hover:border-accent-border hover:text-ink">
|
||
{{ $template->name }}
|
||
</button>
|
||
</li>
|
||
@endforeach
|
||
</ul>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
@endif
|
||
</div>
|