+ {{-- Stats --}}
+
+
+
+
+
+
+
+
{{ number_format($this->stats['total']) }}
+
Total Webhooks
+
+
+
+
+
+
+
+
+
+
+
{{ number_format($this->stats['active']) }}
+
Active
+
+
+
+
+
+
+
+
+
+
+
{{ number_format($this->stats['circuit_broken']) }}
+
Circuit Broken
+
+
+
+
+
+ {{-- Message --}}
+ @if($message)
+
+
+ {{ $message }}
+
+
+ @endif
+
+ {{-- Filters --}}
+
+
+
+
+
+
+
+
+
+ @foreach($this->workspaces as $workspace)
+
+ @endforeach
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ New Webhook
+
+
+
+
+ {{-- Webhooks Table --}}
+
+
+
+
+ Webhook
+ Workspace
+ Events
+ Status
+ Deliveries
+ Actions
+
+
+
+ @forelse($this->webhooks as $webhook)
+
+
+
+
{{ $webhook->name }}
+
+ {{ $webhook->url }}
+
+
+
+
+
+ {{ $webhook->workspace?->name ?? 'N/A' }}
+
+
+
+
+ @foreach($webhook->events as $event)
+ {{ $event }}
+ @endforeach
+
+
+
+
+ @if($webhook->isCircuitBroken())
+ Circuit Broken
+ @elseif($webhook->is_active)
+ Active
+ @else
+ Inactive
+ @endif
+
+ @if($webhook->last_delivery_status)
+
+
+ Last: {{ ucfirst($webhook->last_delivery_status->value) }}
+
+
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Edit
+
+
+
+
+ Send Test
+
+
+
+
+ View Deliveries
+
+
+
+
+ Regenerate Secret
+
+
+ @if($webhook->isCircuitBroken())
+
+
+ Reset Circuit Breaker
+
+ @endif
+
+
+
+
+ @if($webhook->is_active)
+
+ Disable
+ @else
+
+ Enable
+ @endif
+
+
+
+
+ Delete
+
+
+
+
+ @empty
+
+
+ No webhooks found. Create one to get started.
+
+
+ @endforelse
+
+
+
+
+ {{ $this->webhooks->links() }}
+
+
+
+ {{-- Create/Edit Modal --}}
+
+
+ {{ $editingId ? 'Edit Webhook' : 'Create Webhook' }}
+
+
+
+
+ @if(!$editingId)
+
+ Workspace
+
+
+ @foreach($this->workspaces as $workspace)
+
+ @endforeach
+
+
+
+ @endif
+
+
+ Name
+
+
+
+
+
+ URL
+
+
+ The endpoint that will receive webhook POST requests.
+
+
+
+ Events
+
+ @foreach($this->availableEvents as $eventKey => $eventInfo)
+
+ @endforeach
+
+
+
+
+
+ Max Retry Attempts
+
+ Number of times to retry failed deliveries (1-10).
+
+
+
+
+ Inactive webhooks will not receive any events.
+
+
+
+
+
+ Cancel
+
+ {{ $editingId ? 'Update' : 'Create' }}
+
+
+
+
+ {{-- Deliveries Modal --}}
+
+
+ Delivery History
+
+
+
+
+
+
+ Event
+ Status
+ HTTP
+ Attempts
+ Time
+
+
+
+
+ @forelse($this->recentDeliveries as $delivery)
+
+
+ {{ $delivery->getEventDisplayName() }}
+
+
+
+
+ {{ ucfirst($delivery->status->value) }}
+
+
+
+
+ {{ $delivery->http_status ?? '-' }}
+
+
+
+ {{ $delivery->attempts }}
+
+
+
+
+ {{ $delivery->created_at->diffForHumans() }}
+
+
+
+
+ @if($delivery->isFailed())
+
+ Retry
+
+ @endif
+
+
+ @empty
+
+
+ No deliveries yet.
+
+
+ @endforelse
+
+
+
+
+
+ Close
+
+
+
+ {{-- Secret Modal --}}
+
+
+ Webhook Secret
+
+
+
+
+ Save this secret now. It will not be shown again.
+
+
+
+ {{ $displaySecret }}
+
+
+
+ Use this secret to verify webhook signatures. The signature is sent in the
+ X-Signature header
+ and is a HMAC-SHA256 hash of the JSON payload.
+
+
+
+
+
+ I've saved the secret
+
+
+
+
diff --git a/src/View/Blade/admin/workspace-details.blade.php b/src/View/Blade/admin/workspace-details.blade.php
new file mode 100644
index 0000000..1c5bf09
--- /dev/null
+++ b/src/View/Blade/admin/workspace-details.blade.php
@@ -0,0 +1,696 @@
+
+ {{-- Header --}}
+
+
+
+
+ Workspaces
+
+
/
+
{{ $workspace->name }}
+
+
+
+
+
+
+
+
+
{{ $workspace->name }}
+
+ {{ $workspace->slug }}
+ @if($workspace->is_active)
+
+ Active
+
+ @else
+
+ Inactive
+
+ @endif
+
+
+
+
+
+ Hades Only
+
+
+
+
+ {{-- Action message --}}
+ @if($actionMessage)
+
+
+
+ {{ $actionMessage }}
+
+
+ @endif
+
+ {{-- Tabs --}}
+
+
+
+
+ {{-- Tab Content --}}
+
+ {{-- Overview Tab --}}
+ @if($activeTab === 'overview')
+
+ {{-- Quick Stats --}}
+
+ {{-- Owner Card --}}
+
+
Workspace Owner
+ @php $owner = $workspace->owner(); @endphp
+ @if($owner)
+
+
+
+
+
+
{{ $owner->name }}
+
{{ $owner->email }}
+
+
+ @else
+
No owner assigned
+ @endif
+
+
+ {{-- Packages Card --}}
+
+
Active Packages
+ @if($this->activePackages->count() > 0)
+
+ @foreach($this->activePackages as $wp)
+
+
+
+
+
+
+
{{ $wp->package?->name ?? 'Unknown' }}
+
{{ $wp->package?->code ?? '' }}
+
+
+
+
+ {{ ucfirst($wp->status) }}
+
+ @if($wp->expires_at)
+
Expires {{ $wp->expires_at->format('d M Y') }}
+ @endif
+
+
+ @endforeach
+
+ @else
+
No packages assigned
+ @endif
+
+
+ {{-- Boosts Card --}}
+
+
Active Boosts
+ @if($this->activeBoosts->count() > 0)
+
+ @foreach($this->activeBoosts as $boost)
+
+
+
+
+
+
+
{{ $boost->feature_code }}
+
{{ str_replace('_', ' ', $boost->boost_type) }}@if($boost->limit_value) · +{{ number_format($boost->limit_value) }}@endif
+
+
+
+
+ {{ ucfirst($boost->status) }}
+
+ @if($boost->expires_at)
+
Expires {{ $boost->expires_at->format('d M Y') }}
+ @else
+
Permanent
+ @endif
+
+
+ @endforeach
+
+ @else
+
No boosts active
+ @endif
+
+
+ {{-- Subscription Card --}}
+ @if($this->subscriptionInfo)
+
+
Subscription
+
+
+
+
+
+
+
{{ $this->subscriptionInfo['plan'] }}
+
Renews {{ $this->subscriptionInfo['current_period_end'] }}
+
+
+ @if($this->subscriptionInfo['amount'])
+
+
{{ $this->subscriptionInfo['currency'] }} {{ $this->subscriptionInfo['amount'] }}
+
/month
+
+ @endif
+
+
+ @endif
+
+
+ {{-- Sidebar Stats --}}
+
+
+
Quick Stats
+
+
+ Team Members
+ {{ $this->teamMembers->count() }}
+
+ @foreach(array_slice($this->resourceCounts, 0, 5) as $resource)
+
+ {{ $resource['label'] }}
+ {{ $resource['count'] }}
+
+ @endforeach
+
+
+
+ {{-- Workspace Info --}}
+
+
Details
+
+
+
Created
+
{{ $workspace->created_at->format('d M Y') }}
+
+
+
+ Domain
+
+
+
{{ $workspace->domain ?: 'Not set' }}
+
+ @if($workspace->wp_connector_enabled)
+
+
WP Connector
+
+ Connected
+
+
+ @endif
+
+
+
+
+ @endif
+
+ {{-- Team Tab --}}
+ @if($activeTab === 'team')
+
+
+
Team Members ({{ $this->teamMembers->count() }})
+
+
+ Add Member
+
+
+
+ @forelse($this->teamMembers as $member)
+
+
+
+
+
+
+
{{ $member->name }}
+
{{ $member->email }}
+
+
+
+
+ {{ ucfirst($member->pivot->role) }}
+
+ @if($member->pivot->role !== 'owner')
+
+
+
+
+ @endif
+
+
+ @empty
+
+ No team members found.
+
+ @endforelse
+
+
+ @endif
+
+ {{-- Entitlements Tab --}}
+ @if($activeTab === 'entitlements')
+
+ {{-- Stats Header --}}
+
+
+
Entitlement Overview
+
+
+
+ Add Package
+
+
+
+ Add Entitlement
+
+
+
+
+
+
{{ $this->entitlementStats['total'] }}
+
Total Features
+
+
+
{{ $this->entitlementStats['allowed'] }}
+
Allowed
+
+
+
{{ $this->entitlementStats['denied'] }}
+
Not Included
+
+
+
{{ $this->entitlementStats['near_limit'] }}
+
Near Limit
+
+
+
{{ $this->entitlementStats['packages'] }}
+
Packages
+
+
+
{{ $this->entitlementStats['boosts'] }}
+
Boosts
+
+
+
+
+ {{-- Active Boosts Section --}}
+ @if($this->activeBoosts->count() > 0)
+
+
+
+
+ Active Boosts ({{ $this->activeBoosts->count() }})
+
+
+
+ @foreach($this->activeBoosts as $boost)
+
+
+
+
+
+
+
{{ $boost->feature_code }}
+
+ {{ str_replace('_', ' ', $boost->boost_type) }}
+ @if($boost->limit_value)
+ · +{{ number_format($boost->limit_value) }}
+ @endif
+ @if($boost->expires_at)
+
+ · Expires {{ $boost->expires_at->format('d M Y') }}
+
+ @else
+ · Permanent
+ @endif
+
+
+
+
+
+ @endforeach
+
+
+ @endif
+
+ {{-- Resolved Entitlements by Category --}}
+ @forelse($this->resolvedEntitlements as $category => $features)
+
+
+
{{ $category ?: 'General' }}
+
+
+ @foreach($features as $entitlement)
+
+
+ {{-- Status indicator --}}
+
+
+
+
+
{{ $entitlement['name'] }}
+
{{ $entitlement['code'] }}
+
+
+
+
+ {{-- Type badge --}}
+
+ @if($entitlement['type'] === 'boolean')
+ Toggle
+ @elseif($entitlement['unlimited'])
+ Unlimited
+ @else
+ Limit
+ @endif
+
+
+ {{-- Usage info --}}
+ @if($entitlement['type'] !== 'boolean' && !$entitlement['unlimited'] && $entitlement['allowed'])
+
+
+ {{ number_format($entitlement['used'] ?? 0) }}
+ / {{ number_format($entitlement['limit']) }}
+
+ @if($entitlement['limit'] > 0)
+ @php $percent = $entitlement['percentage'] ?? 0; @endphp
+
+ @endif
+
+ @elseif($entitlement['unlimited'])
+
+
+
+ {{ number_format($entitlement['used'] ?? 0) }} used
+
+
+ @elseif(!$entitlement['allowed'])
+
+ Not included
+
+ @endif
+
+
+ @endforeach
+
+
+ @empty
+
+ No entitlements configured.
+
+ @endforelse
+
+ {{-- Packages Section --}}
+ @if($this->workspacePackages->count() > 0)
+
+
+
+
+ Assigned Packages ({{ $this->workspacePackages->count() }})
+
+
+
+ @foreach($this->workspacePackages as $wp)
+
+
+
+
+
+
+
{{ $wp->package?->name ?? 'Unknown' }}
+
+ {{ $wp->package?->code ?? '' }}
+ @if($wp->expires_at)
+
+ · Expires {{ $wp->expires_at->format('d M Y') }}
+
+ @endif
+
+
+
+
+
+ {{ ucfirst($wp->status) }}
+
+ @if($wp->status === 'active')
+
+ @elseif($wp->status === 'suspended')
+
+ @endif
+
+
+
+ @endforeach
+
+
+ @endif
+
+ @endif
+
+ {{-- Resources Tab --}}
+ @if($activeTab === 'resources')
+
+ @foreach($this->resourceCounts as $resource)
+
+
+
{{ number_format($resource['count']) }}
+
{{ $resource['label'] }}
+
+ @endforeach
+
+
+ @if(count($this->resourceCounts) === 0)
+
+ No resources configured for this workspace.
+
+ @endif
+ @endif
+
+ {{-- Activity Tab --}}
+ @if($activeTab === 'activity')
+
+
+
Recent Activity
+
+
+ @forelse($this->recentActivity as $activity)
+
+
+
+
+
+
{{ $activity['message'] }}
+ @if($activity['detail'])
+
{{ $activity['detail'] }}
+ @endif
+
{{ $activity['created_at']->diffForHumans() }}
+
+
+ @empty
+
+ No recent activity found.
+
+ @endforelse
+
+
+ @endif
+
+
+ {{-- Add Member Modal --}}
+
+ Add Team Member
+
+
+
+ Select user...
+ @foreach($this->availableUsers as $user)
+ {{ $user->name }} ({{ $user->email }})
+ @endforeach
+
+
+
+ Member
+ Admin
+ Owner
+
+
+
+ Cancel
+ Add Member
+
+
+
+
+ {{-- Edit Member Modal --}}
+
+ Edit Member Role
+
+
+
+ Member
+ Admin
+ Owner
+
+
+
+
+ Changing to Owner will transfer ownership from the current owner.
+
+
+
+
+ Cancel
+ Update Role
+
+
+
+
+ {{-- Edit Domain Modal --}}
+
+ Edit Domain
+
+
+
+
+
+
+ Enter the domain without the protocol (e.g., example.com not https://example.com).
+
+
+
+
+ Cancel
+ Save Domain
+
+
+
+
+ {{-- Add Package Modal --}}
+
+ Add Package
+
+
+
+ @foreach($this->allPackages as $package)
+
+ {{ $package->name }} ({{ $package->code }})
+
+ @endforeach
+
+
+
+
+ The package will be assigned immediately with no expiry date. You can modify or remove it later.
+
+
+
+
+ Cancel
+ Add Package
+
+
+
+
+ {{-- Add Entitlement Modal --}}
+
+ Add Entitlement
+
+
+
+ @foreach($this->allFeatures->groupBy('category') as $category => $features)
+ ── {{ ucfirst($category ?: 'General') }} ──
+ @foreach($features as $feature)
+
+ {{ $feature->name }} ({{ $feature->code }})
+
+ @endforeach
+ @endforeach
+
+
+
+ Enable (Toggle on)
+ Add Limit (Extra quota)
+ Unlimited
+
+
+ @if($entitlementType === 'add_limit')
+
+ @endif
+
+
+ Permanent
+ Expires on date
+
+
+ @if($entitlementDuration === 'duration')
+
+ @endif
+
+
+
+ This will create a boost that grants the selected feature directly to this workspace, independent of packages.
+
+
+
+
+ Cancel
+ Add Entitlement
+
+
+
+
diff --git a/src/View/Blade/admin/workspace-manager.blade.php b/src/View/Blade/admin/workspace-manager.blade.php
new file mode 100644
index 0000000..63bb9de
--- /dev/null
+++ b/src/View/Blade/admin/workspace-manager.blade.php
@@ -0,0 +1,417 @@
+
+ @if($status === 'success')
+
+
{{ __('tenant::tenant.deletion.cancelled.title') }}
+
{{ __('tenant::tenant.deletion.cancelled.message') }}
+
+ {{ __('tenant::tenant.deletion.cancelled.go_to_profile') }}
+
+ @elseif($status === 'invalid')
+
+
{{ __('tenant::tenant.deletion.cancel_invalid.title') }}
+
{{ __('tenant::tenant.deletion.cancel_invalid.message') }}
+
+ {{ __('tenant::tenant.deletion.return_home') }}
+
+ @else
+
+
{{ __('tenant::tenant.deletion.processing') }}
+ @endif
+
diff --git a/src/View/Blade/web/account/confirm-deletion.blade.php b/src/View/Blade/web/account/confirm-deletion.blade.php
new file mode 100644
index 0000000..25ec3d8
--- /dev/null
+++ b/src/View/Blade/web/account/confirm-deletion.blade.php
@@ -0,0 +1,220 @@
+
+ {{-- Invalid/Expired Token --}}
+ @if($step === 'invalid')
+
+
+
{{ __('tenant::tenant.deletion.invalid.title') }}
+
{{ __('tenant::tenant.deletion.invalid.message') }}
+
+ {{ __('tenant::tenant.deletion.return_home') }}
+
+
+ @endif
+
+ {{-- Step 1: Password Verification --}}
+ @if($step === 'verify')
+
+
+
{{ __('tenant::tenant.deletion.verify.title') }}
+
{{ __('tenant::tenant.deletion.verify.description', ['name' => $userName]) }}
+
+
+
+
+
+ {{ __('tenant::tenant.deletion.verify.changed_mind') }} {{ __('tenant::tenant.deletion.verify.cancel_link') }}
+
+ @endif
+
+ {{-- Step 2: Final Confirmation --}}
+ @if($step === 'confirm')
+
+
+
{{ __('tenant::tenant.deletion.confirm.title') }}
+
{!! __('tenant::tenant.deletion.confirm.warning') !!}
+
+
+
+
{{ __('tenant::tenant.deletion.confirm.will_delete') }}
+
+ -
+
+ {{ __('tenant::tenant.deletion.confirm.items.profile') }}
+
+ -
+
+ {{ __('tenant::tenant.deletion.confirm.items.workspaces') }}
+
+ -
+
+ {{ __('tenant::tenant.deletion.confirm.items.content') }}
+
+ -
+
+ {{ __('tenant::tenant.deletion.confirm.items.social') }}
+
+
+
+
+
+ @endif
+
+ {{-- Step 3: Deleting Animation --}}
+ @if($step === 'deleting')
+
+
+
+
{{ __('tenant::tenant.deletion.deleting.title') }}
+
+
+ @endif
+
+ {{-- Step 4: Goodbye with Typewriter Effect --}}
+ @if($step === 'goodbye')
+
+ @endif
+
diff --git a/src/View/Blade/web/workspace/home.blade.php b/src/View/Blade/web/workspace/home.blade.php
new file mode 100644
index 0000000..1186197
--- /dev/null
+++ b/src/View/Blade/web/workspace/home.blade.php
@@ -0,0 +1,156 @@
+@php
+ $appName = config('core.app.name', __('core::core.brand.name'));
+@endphp
+
+