Deploy Ladill Hosting / deploy (push) Successful in 21s
Point show.blade.php at hosting.legacy.* routes and add the missing input-error component. Co-authored-by: Cursor <cursoragent@cursor.com>
425 lines
28 KiB
PHP
425 lines
28 KiB
PHP
<x-user-layout>
|
|
<x-slot name="title">Hosting — {{ $order->domain_name }}</x-slot>
|
|
|
|
@php
|
|
$statusColors = [
|
|
'active' => 'bg-emerald-50 text-emerald-700',
|
|
'pending' => 'bg-amber-50 text-amber-700',
|
|
'suspended' => 'bg-red-50 text-red-700',
|
|
'expired' => 'bg-gray-100 text-gray-600',
|
|
'cancelled' => 'bg-gray-100 text-gray-500',
|
|
'failed' => 'bg-red-50 text-red-700',
|
|
];
|
|
$statusBadge = $statusColors[$order->status] ?? 'bg-gray-100 text-gray-600';
|
|
$nameservers = collect((array) $order->nameservers)->filter()->values();
|
|
$renewalOptions = collect($renewalOptions ?? [])->values();
|
|
$initialRenewalMonths = (string) ($renewalOptions->first()['months'] ?? '12');
|
|
$backRoute = match ((string) $order->hosting_type) {
|
|
'multi_domain' => route('hosting.multi-domain'),
|
|
'wordpress' => route('hosting.wordpress'),
|
|
default => route('hosting.single-domain'),
|
|
};
|
|
@endphp
|
|
|
|
<div class="space-y-6" x-data="{
|
|
passwordModal: false,
|
|
password: '',
|
|
passwordConfirmation: '',
|
|
submittingPassword: false,
|
|
passwordError: '',
|
|
passwordSuccess: '',
|
|
|
|
openPasswordModal() {
|
|
this.passwordModal = true;
|
|
this.password = '';
|
|
this.passwordConfirmation = '';
|
|
this.passwordError = '';
|
|
this.passwordSuccess = '';
|
|
this.submittingPassword = false;
|
|
},
|
|
|
|
async resetPassword() {
|
|
if (!this.password || this.password !== this.passwordConfirmation) {
|
|
this.passwordError = 'Passwords do not match.';
|
|
return;
|
|
}
|
|
|
|
this.submittingPassword = true;
|
|
this.passwordError = '';
|
|
this.passwordSuccess = '';
|
|
|
|
try {
|
|
const res = await fetch('{{ route('hosting.legacy.reset-panel-password', $order) }}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
},
|
|
body: JSON.stringify({ password: this.password }),
|
|
});
|
|
const data = await res.json();
|
|
if (!res.ok) {
|
|
this.passwordError = data.message || Object.values(data.errors || {}).flat().join(' ') || 'Could not update the password.';
|
|
return;
|
|
}
|
|
this.passwordSuccess = data.message || 'Password updated successfully.';
|
|
this.password = '';
|
|
this.passwordConfirmation = '';
|
|
} catch (e) {
|
|
this.passwordError = 'Network error. Please try again.';
|
|
} finally {
|
|
this.submittingPassword = false;
|
|
}
|
|
},
|
|
}">
|
|
{{-- Page Header --}}
|
|
<div>
|
|
<a href="{{ $backRoute }}" class="inline-flex items-center gap-1 text-sm text-gray-400 hover:text-gray-600">
|
|
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/></svg>
|
|
Hosting
|
|
</a>
|
|
<div class="mt-2 flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
|
<div>
|
|
<div class="flex items-center gap-2">
|
|
<h1 class="text-2xl font-semibold tracking-tight text-gray-900">{{ $order->domain_name }}</h1>
|
|
<span class="inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium {{ $statusBadge }}">{{ ucfirst($order->status) }}</span>
|
|
</div>
|
|
<p class="mt-1 text-sm text-gray-500">
|
|
@if ($order->rc_order_id)
|
|
Order #{{ $order->rc_order_id }}
|
|
@else
|
|
Local order #{{ $order->id }}
|
|
@endif
|
|
@if ($order->plan_name) · {{ $order->plan_name }} @endif
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
@if ($order->cpanel_url)
|
|
<a href="{{ $order->cpanel_url }}" target="_blank" rel="noopener"
|
|
class="inline-flex items-center gap-1.5 rounded-lg bg-gray-900 px-3.5 py-2 text-sm font-medium text-white shadow-sm transition hover:bg-gray-800">
|
|
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/></svg>
|
|
Open cPanel
|
|
</a>
|
|
@endif
|
|
@if ($order->rc_order_id)
|
|
<button @click="openPasswordModal()" type="button"
|
|
class="inline-flex items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-3.5 py-2 text-sm font-medium text-gray-700 shadow-sm transition hover:bg-gray-50">
|
|
Set Password
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Quick Stats --}}
|
|
<div class="grid grid-cols-2 gap-4 sm:grid-cols-4">
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4">
|
|
<p class="text-xs font-medium text-gray-500">Status</p>
|
|
<p class="mt-1 text-lg font-semibold {{ str_contains($statusBadge, 'emerald') ? 'text-emerald-600' : (str_contains($statusBadge, 'amber') ? 'text-amber-600' : (str_contains($statusBadge, 'red') ? 'text-red-600' : 'text-gray-900')) }}">{{ ucfirst($order->status) }}</p>
|
|
</div>
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4">
|
|
<p class="text-xs font-medium text-gray-500">IP Address</p>
|
|
<p class="mt-1 font-mono text-lg font-semibold text-gray-900">{{ $order->ip_address ?: '—' }}</p>
|
|
</div>
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4">
|
|
<p class="text-xs font-medium text-gray-500">Plan</p>
|
|
<p class="mt-1 text-lg font-semibold text-gray-900">{{ $order->plan_name ?: '—' }}</p>
|
|
</div>
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4">
|
|
<p class="text-xs font-medium text-gray-500">Expires</p>
|
|
<p class="mt-1 text-lg font-semibold text-gray-900">{{ $order->expires_at ? $order->expires_at->format('M d, Y') : '—' }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Details + Renew --}}
|
|
<div class="grid gap-6 lg:grid-cols-[minmax(0,1.2fr)_minmax(280px,0.8fr)]">
|
|
{{-- Details Card --}}
|
|
<div class="rounded-lg border border-gray-200 bg-white p-5">
|
|
<h2 class="text-sm font-semibold text-gray-900">Hosting Details</h2>
|
|
<dl class="mt-4 grid gap-3 sm:grid-cols-2">
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Domain</dt>
|
|
<dd class="mt-1 text-sm font-medium text-gray-900">{{ $order->domain_name }}</dd>
|
|
</div>
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Hosting Type</dt>
|
|
<dd class="mt-1 text-sm font-medium text-gray-900">{{ str_replace('_', ' ', ucfirst($order->hosting_type)) }}</dd>
|
|
</div>
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">cPanel Username</dt>
|
|
<dd class="mt-1 font-mono text-sm font-medium text-gray-900">{{ $order->cpanel_username ?: '—' }}</dd>
|
|
</div>
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Access Status</dt>
|
|
<dd class="mt-1 text-sm font-medium text-gray-900">{{ $order->cpanel_url ? 'Ready' : 'Waiting for provisioning' }}</dd>
|
|
</div>
|
|
@if ($order->website_url)
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Website URL</dt>
|
|
<dd class="mt-1 break-all text-sm font-medium text-gray-900">{{ $order->website_url }}</dd>
|
|
</div>
|
|
@endif
|
|
@if ($order->direct_url)
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Direct URL</dt>
|
|
<dd class="mt-1 break-all text-sm font-medium text-gray-900">{{ $order->direct_url }}</dd>
|
|
</div>
|
|
@endif
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Disk Space</dt>
|
|
<dd class="mt-1 text-sm font-medium text-gray-900">{{ $order->disk_space_mb ? number_format($order->disk_space_mb) . ' MB' : '—' }}</dd>
|
|
</div>
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Bandwidth</dt>
|
|
<dd class="mt-1 text-sm font-medium text-gray-900">{{ $order->bandwidth_mb ? number_format($order->bandwidth_mb) . ' MB' : '—' }}</dd>
|
|
</div>
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Provisioned At</dt>
|
|
<dd class="mt-1 text-sm font-medium text-gray-900">{{ $order->provisioned_at ? $order->provisioned_at->format('M d, Y H:i') : '—' }}</dd>
|
|
</div>
|
|
<div class="rounded-md bg-gray-50 px-3 py-3">
|
|
<dt class="text-xs font-medium text-gray-400">Last Updated</dt>
|
|
<dd class="mt-1 text-sm font-medium text-gray-900">{{ $order->updated_at->format('M d, Y H:i') }}</dd>
|
|
</div>
|
|
@if ($order->cpanel_url)
|
|
<div class="rounded-md bg-gray-50 px-3 py-3 sm:col-span-2">
|
|
<dt class="text-xs font-medium text-gray-400">Console URL</dt>
|
|
<dd class="mt-1 break-all text-sm font-medium text-gray-900">{{ $order->cpanel_url }}</dd>
|
|
</div>
|
|
@endif
|
|
</dl>
|
|
</div>
|
|
|
|
{{-- Sidebar --}}
|
|
<div class="space-y-6">
|
|
{{-- Control Panel Access --}}
|
|
<div class="overflow-hidden rounded-xl border border-gray-200 bg-white">
|
|
<div class="flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-slate-50 to-white px-5 py-4">
|
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg {{ $order->cpanel_url ? 'bg-emerald-100' : 'bg-amber-100' }}">
|
|
<svg class="h-5 w-5 {{ $order->cpanel_url ? 'text-emerald-600' : 'text-amber-600' }}" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 0 1-3-3m3 3a3 3 0 1 0 0 6h13.5a3 3 0 1 0 0-6m-16.5-3a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3m-19.5 0a4.5 4.5 0 0 1 .9-2.7L5.737 5.1a3.375 3.375 0 0 1 2.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 0 1 .9 2.7m0 0a3 3 0 0 1-3 3m0 3h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Zm-3 6h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Z"/></svg>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-gray-900">Control Panel</h3>
|
|
<p class="text-xs text-gray-500">{{ $order->cpanel_url ? 'Ready to access' : 'Waiting for provisioning' }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="divide-y divide-gray-100">
|
|
<div class="flex items-center justify-between px-5 py-3">
|
|
<span class="text-sm text-gray-500">Username</span>
|
|
<span class="font-mono text-sm font-medium text-gray-900">{{ $order->cpanel_username ?: '—' }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between px-5 py-3">
|
|
<span class="text-sm text-gray-500">Panel URL</span>
|
|
<span class="max-w-[180px] truncate text-sm font-medium text-gray-900" title="{{ $order->cpanel_url ?: 'Pending' }}">{{ $order->cpanel_url ? parse_url($order->cpanel_url, PHP_URL_HOST) : 'Pending' }}</span>
|
|
</div>
|
|
@if ($order->direct_url)
|
|
<div class="flex items-center justify-between px-5 py-3">
|
|
<span class="text-sm text-gray-500">Direct URL</span>
|
|
<span class="max-w-[180px] truncate text-sm font-medium text-gray-900" title="{{ $order->direct_url }}">{{ parse_url($order->direct_url, PHP_URL_HOST) }}</span>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@if ($order->cpanel_url)
|
|
<div class="border-t border-gray-100 bg-gray-50 px-5 py-3">
|
|
<a href="{{ $order->cpanel_url }}" target="_blank" rel="noopener"
|
|
class="inline-flex w-full items-center justify-center gap-2 rounded-lg bg-gray-900 px-4 py-2.5 text-sm font-medium text-white transition hover:bg-gray-800">
|
|
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"/></svg>
|
|
Open Control Panel
|
|
</a>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Nameservers --}}
|
|
<div class="overflow-hidden rounded-xl border border-gray-200 bg-white">
|
|
<div class="flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-slate-50 to-white px-5 py-4">
|
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-blue-100 text-blue-600">
|
|
@include('components.icons.domain-globe', ['class' => 'h-5 w-5'])
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-gray-900">Nameservers</h3>
|
|
<p class="text-xs text-gray-500">Point your domain to this hosting</p>
|
|
</div>
|
|
</div>
|
|
@if ($nameservers->isNotEmpty())
|
|
<div class="divide-y divide-gray-100">
|
|
@foreach ($nameservers as $index => $nameserver)
|
|
<div class="flex items-center justify-between px-5 py-3">
|
|
<span class="text-sm text-gray-500">NS{{ $index + 1 }}</span>
|
|
<span class="font-mono text-sm font-medium text-gray-900">{{ $nameserver }}</span>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@else
|
|
<div class="px-5 py-4 text-center">
|
|
<p class="text-sm text-gray-500">Nameservers will appear once provisioning is complete.</p>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Server Details --}}
|
|
@if ($order->ip_address || $order->website_url)
|
|
<div class="overflow-hidden rounded-xl border border-gray-200 bg-white">
|
|
<div class="flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-slate-50 to-white px-5 py-4">
|
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-purple-100">
|
|
<svg class="h-5 w-5 text-purple-600" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 0 1-3-3m3 3a3 3 0 1 0 0 6h13.5a3 3 0 1 0 0-6m-16.5-3a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3m-19.5 0a4.5 4.5 0 0 1 .9-2.7L5.737 5.1a3.375 3.375 0 0 1 2.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 0 1 .9 2.7m0 0a3 3 0 0 1-3 3m0 3h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Zm-3 6h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Z"/></svg>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-gray-900">Server Details</h3>
|
|
<p class="text-xs text-gray-500">For DNS and manual configuration</p>
|
|
</div>
|
|
</div>
|
|
<div class="divide-y divide-gray-100">
|
|
@if ($order->ip_address)
|
|
<div class="flex items-center justify-between px-5 py-3">
|
|
<span class="text-sm text-gray-500">Server IP</span>
|
|
<span class="font-mono text-sm font-medium text-gray-900">{{ $order->ip_address }}</span>
|
|
</div>
|
|
@endif
|
|
@if ($order->website_url)
|
|
<div class="flex items-center justify-between px-5 py-3">
|
|
<span class="text-sm text-gray-500">Primary Domain</span>
|
|
<span class="max-w-[180px] truncate text-sm font-medium text-gray-900" title="{{ $order->website_url }}">{{ $order->website_url }}</span>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Renew Card --}}
|
|
@if (($order->isActive() || ($order->expires_at && $order->expires_at->diffInDays(now()) < 30)) && $renewalOptions->isNotEmpty())
|
|
<div class="rounded-lg border border-gray-200 bg-white p-5" x-data="{
|
|
renewing: false,
|
|
months: @js($initialRenewalMonths),
|
|
error: '',
|
|
success: '',
|
|
|
|
async renew() {
|
|
this.renewing = true;
|
|
this.error = '';
|
|
this.success = '';
|
|
try {
|
|
const res = await fetch('{{ route('hosting.legacy.renew', $order) }}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
},
|
|
body: JSON.stringify({ months: this.months }),
|
|
});
|
|
const data = await res.json();
|
|
if (!res.ok) {
|
|
this.error = data.message || 'Renewal failed.';
|
|
return;
|
|
}
|
|
this.success = 'Hosting renewed successfully!';
|
|
setTimeout(() => window.location.reload(), 1500);
|
|
} catch (e) {
|
|
this.error = 'Network error. Please try again.';
|
|
} finally {
|
|
this.renewing = false;
|
|
}
|
|
}
|
|
}">
|
|
<h2 class="text-sm font-semibold text-gray-900">Renew Hosting</h2>
|
|
<p class="mt-1 text-sm text-gray-500">Extend your hosting before it expires.</p>
|
|
|
|
<div class="mt-4 space-y-3">
|
|
<div>
|
|
<label class="mb-1 block text-sm font-medium text-gray-700">Duration</label>
|
|
<select x-model="months" class="w-full rounded-lg border-gray-200 bg-white px-3 py-2 text-sm shadow-sm focus:border-gray-400 focus:ring-0">
|
|
@foreach ($renewalOptions as $option)
|
|
<option value="{{ $option['months'] }}">
|
|
{{ $option['label'] }}
|
|
@if (! empty($option['total']))
|
|
- {{ $option['total'] }}
|
|
@endif
|
|
</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
@if ($renewalOptions->contains(fn (array $option) => ! empty($option['monthly'])))
|
|
<p class="text-xs text-gray-500">
|
|
Renewal options are based on the current pricing for this plan.
|
|
</p>
|
|
@endif
|
|
<button @click="renew()" type="button" :disabled="renewing"
|
|
class="inline-flex w-full items-center justify-center gap-2 rounded-lg bg-gray-900 px-3.5 py-2 text-sm font-medium text-white shadow-sm transition hover:bg-gray-800 disabled:opacity-50">
|
|
<template x-if="renewing">
|
|
<svg class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
|
|
</template>
|
|
Renew Hosting
|
|
</button>
|
|
</div>
|
|
|
|
<template x-if="error">
|
|
<p class="mt-3 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700" x-text="error"></p>
|
|
</template>
|
|
<template x-if="success">
|
|
<p class="mt-3 rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-700" x-text="success"></p>
|
|
</template>
|
|
</div>
|
|
@endif
|
|
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Password Modal --}}
|
|
<template x-teleport="body">
|
|
<div x-show="passwordModal" x-cloak class="fixed inset-0 z-50 overflow-y-auto sm:flex sm:items-center sm:justify-center sm:p-4" @keydown.escape.window="passwordModal = false">
|
|
<div x-show="passwordModal" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
|
|
x-transition:leave="transition ease-in duration-150" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
|
|
class="fixed inset-0 bg-gray-900/50 backdrop-blur-sm hidden sm:block" @click="passwordModal = false"></div>
|
|
|
|
<div x-show="passwordModal" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 scale-95" x-transition:enter-end="opacity-100 scale-100"
|
|
x-transition:leave="transition ease-in duration-150" x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-95"
|
|
class="relative min-h-full sm:min-h-0 w-full sm:max-w-lg sm:rounded-lg sm:border sm:border-gray-200 bg-white shadow-xl" @click.stop>
|
|
|
|
<div class="flex items-center justify-between border-b border-gray-100 px-5 py-4">
|
|
<h3 class="text-sm font-semibold text-gray-900">Set cPanel Password</h3>
|
|
<button @click="passwordModal = false" type="button" class="rounded-md p-1 text-gray-400 transition hover:bg-gray-100 hover:text-gray-600">
|
|
<svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/></svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="space-y-4 p-5">
|
|
<p class="text-sm text-gray-500">Choose a new hosting panel password. It must be 9 to 16 characters and include uppercase, lowercase, a number, and a special character.</p>
|
|
|
|
<div>
|
|
<label class="mb-1 block text-sm font-medium text-gray-700">New Password</label>
|
|
<input x-model="password" type="password" class="w-full rounded-lg border-gray-200 bg-white px-3 py-2 text-sm shadow-sm focus:border-gray-400 focus:ring-0">
|
|
</div>
|
|
|
|
<div>
|
|
<label class="mb-1 block text-sm font-medium text-gray-700">Confirm Password</label>
|
|
<input x-model="passwordConfirmation" type="password" class="w-full rounded-lg border-gray-200 bg-white px-3 py-2 text-sm shadow-sm focus:border-gray-400 focus:ring-0"
|
|
@keydown.enter.prevent="resetPassword()">
|
|
</div>
|
|
|
|
<template x-if="passwordError">
|
|
<p class="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700" x-text="passwordError"></p>
|
|
</template>
|
|
|
|
<template x-if="passwordSuccess">
|
|
<p class="rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-700" x-text="passwordSuccess"></p>
|
|
</template>
|
|
|
|
<div class="flex items-center justify-end gap-3 pt-1">
|
|
<button @click="passwordModal = false" type="button" class="rounded-lg border border-gray-200 px-3.5 py-2 text-sm font-medium text-gray-700 transition hover:bg-gray-50">Close</button>
|
|
<button @click="resetPassword()" type="button" :disabled="submittingPassword || !password || !passwordConfirmation"
|
|
class="inline-flex items-center gap-2 rounded-lg bg-gray-900 px-3.5 py-2 text-sm font-medium text-white shadow-sm transition hover:bg-gray-800 disabled:opacity-50">
|
|
<template x-if="submittingPassword">
|
|
<svg class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
|
|
</template>
|
|
Update Password
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</x-user-layout>
|