Add all files
This commit is contained in:
37
themes/lucentui/views/services/cancel.blade.php
Normal file
37
themes/lucentui/views/services/cancel.blade.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<div class="flex flex-col gap-6 p-4">
|
||||
<p class="text-color-base text-lg font-medium">
|
||||
{{ __('services.cancel_are_you_sure') }}
|
||||
</p>
|
||||
|
||||
<div class="bg-background-tertiary border border-neutral/50 p-5 rounded-lg shadow-sm">
|
||||
<x-form.select name="type" label="{{ __('services.cancel_type') }}" required wire:model.live="type">
|
||||
<option value="end_of_period">{{ __('services.cancel_end_of_period') }}</option>
|
||||
<option value="immediate">{{ __('services.cancel_immediate') }}</option>
|
||||
</x-form.select>
|
||||
</div>
|
||||
|
||||
<div class="bg-background-tertiary border border-neutral/50 p-5 rounded-lg shadow-sm">
|
||||
<x-form.textarea name="reason" label="{{ __('services.cancel_reason') }}" required wire:model="reason"
|
||||
rows="4"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<template x-if="$wire.type === 'immediate'">
|
||||
<div class="bg-red-700 text-white p-5 rounded-lg shadow-md flex items-center gap-3 animate-fade-in-up border border-red-500">
|
||||
<x-ri-skull-fill class="size-8 flex-shrink-0" />
|
||||
<div>
|
||||
<h3 class="text-xl font-bold mb-1">Hey!</h3>
|
||||
<p class="text-base font-medium">
|
||||
{{ __('services.cancel_immediate_warning') }}<br>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="flex justify-end mt-4">
|
||||
<x-button.danger wire:confirm="{{ __('Are you sure?') }}" wire:click="cancelService" class="px-6 py-3 text-base font-semibold">
|
||||
<span wire:loading.remove wire:target="cancelService">{{ __('services.cancel_are_you_sure') }}</span>
|
||||
<x-loading target="cancelService" class="ml-2" />
|
||||
</x-button.danger>
|
||||
</div>
|
||||
</div>
|
||||
113
themes/lucentui/views/services/index.blade.php
Normal file
113
themes/lucentui/views/services/index.blade.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<div class="container mx-auto px-4 py-8 sm:px-6 lg:px-8">
|
||||
|
||||
<h1 class="text-3xl lg:text-4xl font-extrabold text-color-base mt-4 mb-8">
|
||||
{{ __('navigation.services') }}
|
||||
</h1>
|
||||
|
||||
{{-- Status Overview --}}
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-12 bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/50 p-2 rounded-xl">
|
||||
<div class="bg-success/10 border border-success/50 rounded-xl p-4 text-center">
|
||||
<div class="flex items-center justify-center mb-2">
|
||||
<x-ri-checkbox-circle-fill class="size-6 text-success mr-2" />
|
||||
<span class="text-2xl font-bold text-success">{{ $services->where('status', 'active')->count() }}</span>
|
||||
</div>
|
||||
<p class="text-sm font-medium text-success">{{ __('Active') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-warning/10 border border-warning/50 rounded-xl p-4 text-center">
|
||||
<div class="flex items-center justify-center mb-2">
|
||||
<x-ri-error-warning-fill class="size-6 text-warning mr-2" />
|
||||
<span class="text-2xl font-bold text-warning">{{ $services->where('status', 'pending')->count() }}</span>
|
||||
</div>
|
||||
<p class="text-sm font-medium text-warning">{{ __('Pending') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-error/10 border border-error/50 rounded-xl p-4 text-center">
|
||||
<div class="flex items-center justify-center mb-2">
|
||||
<x-ri-forbid-fill class="size-6 text-red-500 mr-2" />
|
||||
<span class="text-2xl font-bold text-red-500">{{ $services->where('status', 'suspended')->count() }}</span>
|
||||
</div>
|
||||
<p class="text-sm font-medium text-red-500">{{ __('Suspended') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-inactive/10 border border-inactive/50 rounded-xl p-4 text-center">
|
||||
<div class="flex items-center justify-center mb-2">
|
||||
<x-ri-close-circle-fill class="size-6 text-inactive mr-2" />
|
||||
<span class="text-2xl font-bold text-inactive">{{ $services->where('status', 'cancelled')->count() }}</span>
|
||||
</div>
|
||||
<p class="text-sm font-medium text-inactive">{{ __('Cancelled') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-3 md:gap-5 ">
|
||||
@forelse ($services as $service)
|
||||
<a href="{{ route('services.show', $service) }}" wire:navigate class="block">
|
||||
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 hover:bg-secondary/25 border border-neutral/50 p-6 rounded-xl shadow-lg
|
||||
transition-all duration-300 hover:scale-[1.02] hover:shadow-xl hover:border-primary/50
|
||||
flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
|
||||
|
||||
<div class="flex items-start md:items-center gap-4 flex-grow">
|
||||
<div class="bg-primary/10 p-3 rounded-full flex-shrink-0 shadow-sm">
|
||||
<x-ri-instance-line class="size-6 text-primary" />
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<span class="text-xl font-bold text-color-base leading-tight">{{ $service->product->name }}</span>
|
||||
@if(optional($service->product->server)->extension === 'Proxmox' && $service->proxmoxServer && $service->proxmoxServer->hostname)
|
||||
<span class="text-sm text-color-muted">({{ $service->proxmoxServer->hostname }})</span>
|
||||
@endif
|
||||
</div>
|
||||
<p class="text-color-muted text-sm mt-1">
|
||||
<strong>{{ __('services.services') }}:</strong> {{ $service->product->category->name }}
|
||||
@if(in_array($service->plan->type, ['recurring']))
|
||||
- {{ __('services.every_period', [
|
||||
'period' => $service->plan->billing_period > 1 ? $service->plan->billing_period : '',
|
||||
'unit' => trans_choice(__('services.billing_cycles.' . $service->plan->billing_unit), $service->plan->billing_period)
|
||||
]) }}
|
||||
@else
|
||||
- {{ __('One time Payment') }}
|
||||
@endif
|
||||
</p>
|
||||
@if($service->expires_at)
|
||||
<p class="text-xs mt-1">
|
||||
<span class="text-primary"><strong>{{ __('Due at') }}:</strong></span> <span class="text-primary/75">{{ $service->expires_at->format('d M Y') }}</span>
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3 flex-shrink-0 mt-3 md:mt-0">
|
||||
<div class="text-sm font-semibold px-3 py-1 rounded-full flex items-center gap-1.5
|
||||
@if ($service->status == 'active') text-success bg-success/20
|
||||
@elseif($service->status == 'suspended') text-red-500 bg-red-500/20
|
||||
@elseif($service->status == 'cancelled') text-inactive bg-inactive/20
|
||||
@else text-warning bg-warning/20
|
||||
@endif">
|
||||
@if ($service->status == 'active')
|
||||
<x-ri-checkbox-circle-fill class="size-4" />
|
||||
{{ __('Active') }}
|
||||
@elseif($service->status == 'suspended')
|
||||
<x-ri-forbid-fill class="size-4" />
|
||||
{{ __('Suspended') }}
|
||||
@elseif($service->status == 'cancelled')
|
||||
<x-ri-close-circle-fill class="size-4" />
|
||||
{{ __('Canceled') }}
|
||||
@elseif($service->status == 'pending')
|
||||
<x-ri-error-warning-fill class="size-4" />
|
||||
{{ __('Pending') }}
|
||||
@endif
|
||||
</div>
|
||||
<x-ri-arrow-right-s-line class="size-6 text-color-muted group-hover:text-primary transition-colors duration-200" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@empty
|
||||
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 rounded-xl shadow-lg p-6 lg:p-8 border border-neutral/50 text-center">
|
||||
<x-ri-inbox-line class="size-16 text-color-muted mx-auto mb-4 opacity-60" />
|
||||
<h3 class="text-xl font-bold text-color-base mb-2">No services yet.</h3>
|
||||
</div>
|
||||
@endforelse
|
||||
|
||||
{{ $services->links() }}
|
||||
</div>
|
||||
</div>
|
||||
207
themes/lucentui/views/services/show.blade.php
Normal file
207
themes/lucentui/views/services/show.blade.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<div class="container mx-auto px-4 py-8 sm:px-6 lg:px-8">
|
||||
@if($invoice = $service->invoices()->where('status', 'pending')->first())
|
||||
<div class="w-full mb-4">
|
||||
<div class="bg-gradient-to-r from-warning/20 to-warning/10 border border-warning/30 rounded-2xl p-4 backdrop-blur-sm">
|
||||
<p class="font-medium text-warning flex items-center gap-2">
|
||||
<x-ri-error-warning-fill class="size-5" />
|
||||
{{ __('services.outstanding_invoice') }}
|
||||
<a href="{{ route('invoices.show', $invoice)}}"
|
||||
class="underline hover:text-warning/80 underline-offset-2 transition-colors duration-200">{{ __('services.view_and_pay') }}</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Main Service Container -->
|
||||
<div class="relative overflow-hidden bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/30 rounded-xl shadow-2xl backdrop-blur-sm mt-4 mb-8">
|
||||
|
||||
<!-- Decorative Elements -->
|
||||
<div class="absolute top-0 right-0 w-96 h-96 bg-gradient-to-bl from-primary/10 via-primary/5 to-transparent rounded-full blur-3xl opacity-60"></div>
|
||||
<div class="absolute -bottom-24 -left-24 w-72 h-72 bg-gradient-to-tr from-primary/8 via-primary/4 to-transparent rounded-full blur-2xl opacity-40"></div>
|
||||
|
||||
<!-- Content Layer -->
|
||||
<div class="relative z-10 p-8 lg:p-12">
|
||||
|
||||
<!-- Header Section -->
|
||||
<div class="flex flex-col lg:flex-row justify-between items-start lg:items-center mb-12">
|
||||
<div class="mb-6 lg:mb-0">
|
||||
<h1 class="text-4xl lg:text-4xl font-black text-color-base leading-tight mb-2 bg-gradient-to-r from-color-base via-color-base to-primary bg-clip-text flex items-center">
|
||||
<x-ri-box-3-fill class="size-10 mr-4 text-primary" />
|
||||
{{ __('services.services') }}
|
||||
|
||||
</h1>
|
||||
<div class="w-24 h-1 bg-gradient-to-r from-primary to-primary/60 rounded-full ml-14"></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<!-- Status Badge -->
|
||||
@if ($service->status == 'active')
|
||||
<div class="flex items-center gap-3 px-6 py-3 bg-gradient-to-r from-success/20 to-success/10 border border-success/30 rounded-2xl backdrop-blur-sm">
|
||||
<x-ri-checkbox-circle-fill class="size-6 text-success" />
|
||||
<span class="text-success font-bold text-lg">{{ __('services.statuses.' . $service->status) }}</span>
|
||||
</div>
|
||||
@elseif($service->status == 'suspended')
|
||||
<div class="flex items-center gap-3 px-6 py-3 bg-gradient-to-r from-warning/20 to-warning/10 border border-warning/30 rounded-2xl backdrop-blur-sm">
|
||||
<x-ri-forbid-fill class="size-6 text-warning" />
|
||||
<span class="text-warning font-bold text-lg">{{ __('services.statuses.' . $service->status) }}</span>
|
||||
</div>
|
||||
@elseif($service->status == 'cancelled')
|
||||
<div class="flex items-center gap-3 px-6 py-3 bg-gradient-to-r from-inactive/20 to-inactive/10 border border-inactive/30 rounded-2xl backdrop-blur-sm">
|
||||
<x-ri-close-circle-fill class="size-6 text-inactive" />
|
||||
<span class="text-inactive font-bold text-lg">{{ __('services.statuses.' . $service->status) }}</span>
|
||||
</div>
|
||||
@elseif($service->status == 'pending')
|
||||
<div class="flex items-center gap-3 px-6 py-3 bg-gradient-to-r from-warning/20 to-warning/10 border border-warning/30 rounded-2xl backdrop-blur-sm">
|
||||
<x-ri-error-warning-fill class="size-6 text-warning" />
|
||||
<span class="text-warning font-bold text-lg">{{ __('services.statuses.' . $service->status) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Details Grid -->
|
||||
<div class="grid grid-cols-1 xl:grid-cols-2 gap-8 mb-12">
|
||||
|
||||
<!-- Product Details Card -->
|
||||
<div class="bg-gradient-to-br from-background/50 to-background/20 border border-neutral/20 rounded-2xl p-6 backdrop-blur-sm hover:shadow-lg transition-all duration-300">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<x-ri-information-line class="size-6 text-primary" />
|
||||
<h3 class="uppercase font-black text-color-base text-sm tracking-wider">{{ __('services.product_details') }}</h3>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between py-3 px-4 bg-background/50 rounded-xl">
|
||||
<span class="text-color-muted text-sm font-medium">{{ __('services.name') }}</span>
|
||||
<span class="font-bold text-color-base">{{ $service->product->name }}</span>
|
||||
</div>
|
||||
@if(isset($proxmoxServer) && $proxmoxServer)
|
||||
<div class="flex items-center justify-between py-3 px-4 bg-background/50 rounded-xl">
|
||||
<span class="text-color-muted text-sm font-medium">Hostname</span>
|
||||
<span class="font-bold text-color-base">{{ $proxmoxServer->hostname }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex items-center justify-between py-3 px-4 bg-background/50 rounded-xl">
|
||||
<span class="text-color-muted text-sm font-medium">{{ __('services.price') }}</span>
|
||||
<span class="font-bold text-success text-lg">{{ $service->formattedPrice }}</span>
|
||||
</div>
|
||||
@if($service->plan->type == 'recurring')
|
||||
<div class="flex items-center justify-between py-3 px-4 bg-background/50 rounded-xl">
|
||||
<span class="text-color-muted text-sm font-medium">{{ __('services.billing_cycle') }}</span>
|
||||
<span class="font-bold text-color-base">
|
||||
{{ __('services.every_period', [
|
||||
'period' => $service->plan->billing_period > 1 ? $service->plan->billing_period : '',
|
||||
'unit' => trans_choice(__('services.billing_cycles.' . $service->plan->billing_unit), $service->plan->billing_period)
|
||||
]) }}
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($service->expires_at)
|
||||
<div class="flex items-center justify-between py-3 px-4 bg-background/50 rounded-xl">
|
||||
<span class="text-color-muted text-sm font-medium">Due At</span>
|
||||
<span class="font-bold text-color-base">{{ $service->expires_at->format('d M Y') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex items-center justify-between py-3 px-4 bg-background/50 rounded-xl">
|
||||
<span class="text-color-muted text-sm font-medium">{{ __('services.status') }}</span>
|
||||
<span class="font-bold @if ($service->status == 'active') text-success @elseif($service->status == 'cancelled') text-inactive @else text-warning @endif">
|
||||
{{ __('services.statuses.' . $service->status) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Card -->
|
||||
@if($service->cancellable || $service->upgradable || count($buttons) > 0)
|
||||
<div class="bg-gradient-to-br from-background/50 to-background/20 border border-neutral/20 rounded-2xl p-6 backdrop-blur-sm hover:shadow-lg transition-all duration-300">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<x-ri-flashlight-fill class="size-6 text-primary" />
|
||||
<h3 class="uppercase font-black text-color-base text-sm tracking-wider">{{ __('services.actions') }}</h3>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
@if($service->upgradable)
|
||||
<a href="{{ route('services.upgrade', $service->id) }}" class="block">
|
||||
<button class="group w-full flex items-center justify-center gap-3 px-6 py-4 bg-gradient-to-r from-primary to-primary/80 text-white font-semibold rounded-2xl transition-all duration-300 transform hover:scale-105 hover:shadow-xl">
|
||||
<x-ri-upload-cloud-2-line class="size-5 transition-transform group-hover:scale-110" />
|
||||
<span>{{ __('services.upgrade') }}</span>
|
||||
</button>
|
||||
</a>
|
||||
@endif
|
||||
@if($service->upgrade()->where('status', 'pending')->exists())
|
||||
<button class="group w-full flex items-center justify-center gap-3 px-6 py-4 bg-gradient-to-r from-warning/80 to-warning/60 text-white font-semibold rounded-2xl transition-all duration-300 transform hover:scale-105 hover:shadow-xl"
|
||||
@click="Alpine.store('notifications').addNotification([{message: '{{ __('services.upgrade_pending') }}', type: 'error'}])">
|
||||
<x-ri-upload-cloud-2-line class="size-5 transition-transform group-hover:scale-110" />
|
||||
<span>{{ __('services.upgrade') }}</span>
|
||||
</button>
|
||||
@endif
|
||||
@if($service->cancellable)
|
||||
<button class="group w-full flex items-center justify-center gap-3 px-6 py-4 bg-gradient-to-r from-error to-error/80 text-white font-semibold rounded-2xl transition-all duration-300 transform hover:scale-105 hover:shadow-xl" wire:click="$set('showCancel', true)">
|
||||
<x-ri-spam-line class="size-5 transition-transform group-hover:scale-110" />
|
||||
<span wire:loading.remove wire:target="$set('showCancel', true)">{{ __('services.cancel') }}</span>
|
||||
<x-loading target="$set('showCancel', true)" class="ml-2" />
|
||||
</button>
|
||||
@endif
|
||||
|
||||
@if(($service->upgradable || $service->cancellable) && count($buttons) > 0)
|
||||
<div class="border-t border-neutral/20 my-4"></div>
|
||||
@endif
|
||||
|
||||
@foreach ($buttons as $button)
|
||||
@if (isset($button['function']))
|
||||
<button class="group w-full flex items-center justify-center gap-3 px-6 py-3 bg-gradient-to-r from-background to-background/80 border border-neutral/30 text-color-base font-semibold rounded-2xl transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:bg-background-secondary" wire:click="goto('{{ $button['function'] }}')">
|
||||
<x-ri-link-m class="size-5 transition-transform group-hover:scale-110" />
|
||||
{{ $button['label'] }}
|
||||
</button>
|
||||
@else
|
||||
<a href="{{ $button['url'] }}" class="block">
|
||||
<button class="group w-full flex items-center justify-center gap-3 px-6 py-3 bg-gradient-to-r from-background to-background/80 border border-neutral/30 text-color-base font-semibold rounded-2xl transition-all duration-300 transform hover:scale-105 hover:shadow-lg hover:bg-background-secondary">
|
||||
<x-ri-link-m class="size-5 transition-transform group-hover:scale-110" />
|
||||
{{ $button['label'] }}
|
||||
</button>
|
||||
</a>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($showCancel)
|
||||
<x-modal open="true"
|
||||
title="{{ __('services.cancellation', ['service' => $service->product->name]) }}"
|
||||
width="max-w-3xl">
|
||||
<livewire:services.cancel :service="$service" />
|
||||
<x-slot name="closeTrigger">
|
||||
<div class="flex gap-4">
|
||||
<button wire:click="$set('showCancel', false)" @click="open = false"
|
||||
class="text-color-muted hover:text-color-base transition-colors duration-200 p-2 rounded-full focus:outline-none focus:ring-2 focus:ring-primary/50">
|
||||
<x-ri-close-fill class="size-7" />
|
||||
</button>
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-modal>
|
||||
@endif
|
||||
|
||||
@if (count($views) > 0)
|
||||
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/30 p-6 md:p-8 rounded-xl shadow-lg mt-6 relative overflow-hidden">
|
||||
<div class="absolute bottom-0 right-0 w-24 h-24 bg-warning/10 rounded-full mix-blend-multiply filter blur-xl opacity-70 animate-blob animation-delay-4000"></div>
|
||||
<div class="absolute bottom-0 left-0 w-24 h-24 bg-info/10 rounded-full mix-blend-multiply filter blur-xl opacity-70 animate-blob animation-delay-6000"></div>
|
||||
|
||||
@if (count($views) > 1)
|
||||
<div class="flex w-full mb-4 border-b border-neutral/50 overflow-x-auto scrollbar-hide relative z-10">
|
||||
@foreach ($views as $view)
|
||||
<button wire:click="changeView('{{ $view['name'] }}')"
|
||||
class="flex-shrink-0 px-6 py-3 -mb-px text-lg font-semibold transition-colors duration-200 whitespace-nowrap
|
||||
{{ $view['name'] == $currentView ? 'border-b-2 border-primary text-primary-light' : 'text-color-muted hover:text-color-base hover:border-neutral-focus' }}">
|
||||
{{ $view['label'] }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<x-loading target="changeView" class="!fill-primary mx-auto my-8 size-10" />
|
||||
<div wire:loading.remove wire:target="changeView" class="relative z-10">
|
||||
{!! $extensionView !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
226
themes/lucentui/views/services/upgrade.blade.php
Normal file
226
themes/lucentui/views/services/upgrade.blade.php
Normal file
@@ -0,0 +1,226 @@
|
||||
<div class="mx-auto container mt-8 mb-12 p-6 sm:px-6 lg:px-8">
|
||||
<!-- Title Section -->
|
||||
<div class="text-center sm:text-left mb-8">
|
||||
<h1 class="text-3xl lg:text-4xl font-bold text-color-base leading-tight flex items-center gap-2">
|
||||
{{ __('services.upgrade_service', ['service' => $service->product->name]) }}
|
||||
</h1>
|
||||
<h2 class="text-lg font-semibold mt-2">
|
||||
@if($step == 1)
|
||||
{{ __('services.upgrade_choose_product') }}
|
||||
@else
|
||||
{{ __('services.upgrade_choose_config') }}
|
||||
@endif
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-4 gap-8 lg:gap-12 items-start">
|
||||
<div class="flex flex-col gap-6 w-full col-span-3">
|
||||
|
||||
@if($step == 1)
|
||||
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/50 rounded-2xl shadow-lg overflow-hidden animate-fade-in-up" style="animation-delay: 0.1s;">
|
||||
<div class="p-6 lg:p-8">
|
||||
<div class="flex items-center gap-4 mb-6">
|
||||
<div class="bg-primary/10 text-primary p-3 rounded-full shadow-md">
|
||||
<x-ri-price-tag-3-fill class="size-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-xl font-bold text-color-base">
|
||||
{{ __('services.upgrade_choose_product') }}
|
||||
</h2>
|
||||
<p class="text-color-muted text-sm">Select your new plan or keep your current one</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<input type="radio" name="upgrade" value="{{ $service->product->id }}" wire:model.live="upgrade"
|
||||
class="hidden peer" id="product-{{ $service->product->id }}">
|
||||
<label for="product-{{ $service->product->id }}"
|
||||
class="flex flex-col cursor-pointer bg-background-tertiary/30 hover:bg-background-tertiary/50 border border-neutral/30 peer-checked:border-primary peer-checked:bg-primary/5 peer-checked:ring-2 peer-checked:ring-primary p-6 rounded-xl transition-all duration-300 h-full">
|
||||
|
||||
@if ($service->product->image)
|
||||
<div class="relative overflow-hidden rounded-lg bg-gradient-to-br from-primary/10 to-primary/5 p-2 mb-4">
|
||||
<img src="{{ Storage::url($service->product->image) }}" alt="{{ $service->product->name }}" class="rounded-lg w-full object-cover object-center h-auto max-h-48">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="rounded-full border border-background inline-flex items-center justify-center gap-2 align-middle bg-primary/60 w-fit px-3 py-1 mb-4">
|
||||
<p class="text-sm font-medium text-color-base">{{ __('services.current_plan') }}</p>
|
||||
</div>
|
||||
|
||||
<h3 class="text-lg font-bold text-color-base mb-2">{{ $service->product->name }}</h3>
|
||||
|
||||
|
||||
<div class="flex justify-between items-center p-3 bg-background-tertiary/30 rounded-lg mt-auto">
|
||||
<span class="text-sm text-color-muted">Current Price</span>
|
||||
<span class="text-lg font-semibold text-color-base">
|
||||
{{ $service->product->price(null, $service->plan->billing_period, $service->plan->billing_unit, $service->currency_code) }}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@foreach ($service->productUpgrades() as $product)
|
||||
<div>
|
||||
<input type="radio" name="upgrade" value="{{ $product->id }}" wire:model.live="upgrade"
|
||||
class="hidden peer" id="product-{{ $product->id }}">
|
||||
<label for="product-{{ $product->id }}"
|
||||
class="flex flex-col cursor-pointer bg-background-tertiary/30 hover:bg-background-tertiary/50 border border-neutral/50 peer-checked:border-secondary peer-checked:bg-secondary/5 peer-checked:ring-2 peer-checked:ring-secondary p-6 rounded-xl transition-all duration-300 h-full">
|
||||
|
||||
@if ($product->image)
|
||||
<div class="relative overflow-hidden rounded-lg bg-gradient-to-br from-primary/10 to-primary/5 p-2 mb-4">
|
||||
<img src="{{ Storage::url($product->image) }}" alt="{{ $product->name }}" class="rounded-lg w-full object-cover object-center h-auto max-h-48">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($upgrade == $product->id)
|
||||
<div class="rounded-full border border-background inline-flex items-center justify-center gap-2 align-middle bg-primary w-fit px-3 py-1 mb-4 animate-fade-in-up" style="animation-delay: 0.1s;">
|
||||
<p class="text-sm font-medium text-color-base">{{ __('services.new_plan') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<h3 class="text-lg font-bold text-color-base mb-2">{{ $product->name }}</h3>
|
||||
|
||||
|
||||
<div class="flex justify-between items-center p-3 bg-background-tertiary/30 rounded-lg mt-auto">
|
||||
<span class="text-sm text-color-muted">New Price</span>
|
||||
<span class="text-lg font-semibold text-color-base">
|
||||
{{ $product->price(null, $service->plan->billing_period, $service->plan->billing_unit, $service->currency_code) }}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/50 rounded-2xl shadow-lg overflow-hidden animate-fade-in-up" style="animation-delay: 0.2s;">
|
||||
<div class="p-6 lg:p-8">
|
||||
<div class="flex items-center gap-4 mb-6">
|
||||
<div class="bg-primary/10 text-primary p-3 rounded-full shadow-md">
|
||||
<x-ri-settings-3-fill class="size-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-xl font-bold text-color-base">
|
||||
{{ __('services.upgrade_choose_config') }}
|
||||
</h2>
|
||||
<p class="text-color-muted text-sm">Customize your upgrade options</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6">
|
||||
@foreach ($upgradeProduct->upgradableConfigOptions as $configOption)
|
||||
@php
|
||||
$showPriceTag = $configOption->children->filter(fn ($value) => !$value->price(billing_period: $service->plan->billing_period, billing_unit: $service->plan->billing_unit)->is_free)->count() > 0;
|
||||
@endphp
|
||||
|
||||
<x-form.configoption :config="$configOption" :name="'configOptions.' . $configOption->id" :showPriceTag="$showPriceTag" :plan="$service->plan">
|
||||
@if ($configOption->type == 'select')
|
||||
<select wire:model.live="configOptions.{{ $configOption->id }}"
|
||||
id="config-{{ $configOption->id }}"
|
||||
name="configOptions[{{ $configOption->id }}]"
|
||||
class="w-full text-color-base bg-background-tertiary/50 border border-neutral/50 focus:border-primary focus:ring-primary focus:ring-2 focus:ring-primary/20 rounded-xl px-4 py-3">
|
||||
@foreach ($configOption->children as $configOptionValue)
|
||||
<option value="{{ $configOptionValue->id }}">
|
||||
{{ $configOptionValue->name }}
|
||||
{{ ($showPriceTag && $configOptionValue->price(billing_period: $service->plan->billing_period, billing_unit: $service->plan->billing_unit)->available) ? ' - ' . $configOptionValue->price(billing_period: $service->billing_period, billing_unit: $service->billing_unit) : '' }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@elseif($configOption->type == 'radio')
|
||||
<div class="space-y-3">
|
||||
@foreach ($configOption->children as $configOptionValue)
|
||||
<label for="config-{{ $configOptionValue->id }}"
|
||||
class="flex items-center gap-3 cursor-pointer text-color-base p-3 rounded-lg border border-transparent hover:bg-background-tertiary/20">
|
||||
<input type="radio"
|
||||
id="config-{{ $configOptionValue->id }}"
|
||||
name="configOptions[{{ $configOption->id }}]"
|
||||
wire:model.live="configOptions.{{ $configOption->id }}"
|
||||
value="{{ $configOptionValue->id }}"
|
||||
class="form-radio text-primary focus:ring-primary focus:ring-2 focus:ring-primary/20 size-4">
|
||||
<span class="flex-grow">
|
||||
{{ $configOptionValue->name }}
|
||||
@if($showPriceTag && $configOptionValue->price(billing_period: $service->billing_period, billing_unit: $service->billing_unit)->available)
|
||||
<span class="text-color-muted text-sm ml-2">
|
||||
({{ $configOptionValue->price(billing_period: $service->billing_period, billing_unit: $service->billing_unit) }})
|
||||
</span>
|
||||
@endif
|
||||
</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</x-form.configoption>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-6 w-full col-span-3 md:col-span-1 sticky top-8 md:top-20">
|
||||
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral/50 rounded-2xl shadow-lg overflow-hidden animate-fade-in-up" style="animation-delay: 0.3s;">
|
||||
<div class="p-6 lg:p-8">
|
||||
<div class="flex items-center gap-4 mb-6 pb-4 border-b border-neutral/50">
|
||||
<div class="bg-primary/10 text-primary p-3 rounded-full shadow-md">
|
||||
<x-ri-arrow-up-circle-fill class="size-6" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-xl font-bold text-color-base">
|
||||
{{ __('services.upgrade_summary') }}
|
||||
</h2>
|
||||
<p class="text-color-muted text-xs">Review your upgrade details</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4 mb-6">
|
||||
<div class="flex justify-between items-center p-3 bg-background-tertiary/30 rounded-lg border border-neutral/30">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-archive-fill class="size-4 text-color-muted" />
|
||||
<span class="text-sm text-color-muted">{{ __('services.current_plan') }}</span>
|
||||
</div>
|
||||
<span class="text-sm font-medium text-color-base">{{ $service->product->name }}</span>
|
||||
</div>
|
||||
|
||||
@if($upgrade != $service->product->id)
|
||||
<div class="flex justify-between items-center p-3 bg-primary/10 rounded-lg border border-primary/20">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-star-fill class="size-4 text-primary" />
|
||||
<span class="text-sm text-primary font-medium">{{ __('services.new_plan') }}</span>
|
||||
</div>
|
||||
<span class="text-sm font-medium text-primary">{{ $upgradeProduct ? $upgradeProduct->name : __('general.select_plan') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex-col justify-between items-center p-4 bg-gradient-to-r from-primary/10 to-primary/5 rounded-xl">
|
||||
<div class="flex items-center gap-2">
|
||||
<x-ri-money-dollar-circle-fill class="size-5 text-primary" />
|
||||
<span class="text-lg font-semibold text-color-base">{{ __('services.total_today') }}</span>
|
||||
</div>
|
||||
<span class="text-2xl font-bold text-primary">{{ $this->totalToday() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<button wire:click="{{ ($upgradeProduct->upgradableConfigOptions()->count() > 0 && $step == 1) ? 'nextStep' : 'doUpgrade' }}"
|
||||
wire:loading.attr="disabled"
|
||||
class="group/btn w-full inline-flex items-center justify-center gap-3 bg-primary hover:bg-primary/90 text-white px-6 py-4 rounded-xl font-semibold text-lg transition-all duration-300 hover:shadow-lg hover:shadow-primary/30 disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
<span wire:loading.remove>
|
||||
@if($upgradeProduct && $upgradeProduct->upgradableConfigOptions()->count() > 0 && $step == 1)
|
||||
{{ __('services.next_step') }}
|
||||
@else
|
||||
{{ __('services.upgrade') }}
|
||||
@endif
|
||||
</span>
|
||||
<span wire:loading>Processing...</span>
|
||||
<x-ri-arrow-right-fill class="size-5 transform transition-transform duration-300 group-hover/btn:translate-x-1" wire:loading.remove />
|
||||
<x-ri-loader-4-fill class="size-5 animate-spin" wire:loading />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
31
themes/lucentui/views/services/widget.blade.php
Normal file
31
themes/lucentui/views/services/widget.blade.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<div class="space-y-4">
|
||||
@foreach ($services as $service)
|
||||
<a href="{{ route('services.show', $service) }}" wire:navigate>
|
||||
<div class="bg-gradient-to-br from-background-secondary/50 to-background-secondary/30 border border-neutral p-4 rounded-lg mb-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-secondary/10 p-2 rounded-full">
|
||||
<x-ri-instance-line class="size-5 text-secondary" />
|
||||
</div>
|
||||
<span class="font-medium">{{ $service->product->name }}</span>
|
||||
</div>
|
||||
<div class="size-5 rounded-full p-0.5
|
||||
@if ($service->status == 'active') text-success bg-success/20
|
||||
@elseif($service->status == 'suspended') text-inactive bg-inactive/20
|
||||
@else text-warning bg-warning/20
|
||||
@endif"
|
||||
@if ($service->status == 'active')
|
||||
<x-ri-checkbox-circle-fill />
|
||||
@elseif($service->status == 'suspended')
|
||||
<x-ri-forbid-fill />
|
||||
@elseif($service->status == 'pending')
|
||||
<x-ri-error-warning-fill />
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-base text-sm"><strong>Product(s):</strong> {{ $service->product->category->name }} - Every {{ $service->plan->billing_period > 1 ? $service->plan->billing_period : '' }}
|
||||
{{ Str::plural($service->plan->billing_unit, $service->plan->billing_period) }}</p>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
Reference in New Issue
Block a user