libra/resources/views/livewire/client/dashboard.blade.php

245 lines
12 KiB
PHP

<?php
use App\Models\TimelineUpdate;
use Livewire\Volt\Component;
new class extends Component {
public function with(): array
{
$user = auth()->user();
return [
'upcomingConsultation' => $user->consultations()
->approved()
->where('booking_date', '>=', today())
->orderBy('booking_date')
->orderBy('booking_time')
->first(),
'activeTimelinesCount' => $user->timelines()->active()->count(),
'latestTimeline' => $user->timelines()->active()->latest()->first(),
'recentUpdates' => TimelineUpdate::whereHas('timeline', fn ($q) => $q->where('user_id', $user->id))
->latest()
->take(3)
->with('timeline')
->get(),
'pendingBookingsCount' => $user->consultations()->pending()->count(),
'canBookToday' => ! $user->consultations()
->whereDate('booking_date', today())
->whereIn('status', ['pending', 'approved'])
->exists(),
];
}
}; ?>
<div class="space-y-6 p-6">
{{-- Welcome Section --}}
<div class="rounded-lg border border-zinc-200 bg-[#0A1F44] p-6 text-white dark:border-zinc-700">
<flux:heading size="xl" class="text-white">
{{ __('client.dashboard.welcome', ['name' => auth()->user()->full_name]) }}
</flux:heading>
<flux:text class="mt-1 text-zinc-300">
{{ now()->locale(app()->getLocale())->translatedFormat(app()->getLocale() === 'ar' ? 'l، j F Y' : 'l, F j, Y') }}
</flux:text>
</div>
{{-- Widgets Grid --}}
<div class="grid gap-6 md:grid-cols-2">
{{-- Upcoming Consultation Widget --}}
<div class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<flux:heading size="lg" class="mb-4">
{{ __('client.dashboard.upcoming_consultation') }}
</flux:heading>
@if ($upcomingConsultation)
<div class="space-y-3">
<div class="flex items-center gap-2">
<flux:icon name="calendar" class="h-5 w-5 text-zinc-500" />
<flux:text>
@if (app()->getLocale() === 'ar')
{{ $upcomingConsultation->booking_date->format('d/m/Y') }}
@else
{{ $upcomingConsultation->booking_date->format('m/d/Y') }}
@endif
</flux:text>
</div>
<div class="flex items-center gap-2">
<flux:icon name="clock" class="h-5 w-5 text-zinc-500" />
<flux:text>
{{ \Carbon\Carbon::parse($upcomingConsultation->booking_time)->format('g:i A') }}
</flux:text>
</div>
<div class="flex flex-wrap gap-2">
@if ($upcomingConsultation->consultation_type->value === 'free')
<flux:badge color="green">{{ $upcomingConsultation->consultation_type->label() }}</flux:badge>
@else
<flux:badge color="yellow">{{ $upcomingConsultation->consultation_type->label() }}</flux:badge>
@endif
<flux:badge color="sky">{{ $upcomingConsultation->status->label() }}</flux:badge>
</div>
<div class="pt-2">
<flux:button
variant="ghost"
size="sm"
:href="route('client.consultations.index')"
wire:navigate
>
{{ __('client.dashboard.view_details') }}
</flux:button>
</div>
</div>
@else
<div class="text-center py-4">
<flux:icon name="calendar-days" class="mx-auto h-12 w-12 text-zinc-300" />
<flux:text class="mt-2 text-zinc-500">{{ __('client.dashboard.no_upcoming') }}</flux:text>
<div class="mt-4">
<flux:button
variant="primary"
size="sm"
:href="route('client.consultations.book')"
wire:navigate
>
{{ __('client.dashboard.book_first') }}
</flux:button>
</div>
</div>
@endif
</div>
{{-- Active Cases Widget --}}
<div class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<flux:heading size="lg" class="mb-4">
{{ __('client.dashboard.active_cases') }}
</flux:heading>
@if ($activeTimelinesCount > 0)
<div class="space-y-3">
<div class="flex items-center gap-2">
<span class="text-3xl font-bold text-[#D4AF37]">{{ $activeTimelinesCount }}</span>
<flux:text class="text-zinc-500">{{ trans_choice('client.dashboard.cases_count', $activeTimelinesCount) }}</flux:text>
</div>
@if ($latestTimeline)
@php
$latestUpdate = $latestTimeline->updates()->reorder()->latest()->first();
@endphp
@if ($latestUpdate)
<div class="rounded-lg bg-zinc-50 p-3 dark:bg-zinc-800">
<flux:text size="sm" class="text-zinc-600 dark:text-zinc-400">
{{ __('client.dashboard.latest_update') }}:
</flux:text>
<flux:text class="mt-1">
{{ Str::limit($latestUpdate->update_text, 100) }}
</flux:text>
</div>
@endif
@endif
<div class="pt-2">
<flux:button
variant="ghost"
size="sm"
:href="route('client.timelines.index')"
wire:navigate
>
{{ __('client.dashboard.view_all_cases') }}
</flux:button>
</div>
</div>
@else
<div class="text-center py-4">
<flux:icon name="folder-open" class="mx-auto h-12 w-12 text-zinc-300" />
<flux:text class="mt-2 text-zinc-500">{{ __('client.dashboard.no_cases') }}</flux:text>
</div>
@endif
</div>
{{-- Recent Updates Widget --}}
<div class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<flux:heading size="lg" class="mb-4">
{{ __('client.dashboard.recent_updates') }}
</flux:heading>
@if ($recentUpdates->isNotEmpty())
<div class="space-y-3">
@foreach ($recentUpdates as $update)
<div class="border-b border-zinc-100 pb-3 last:border-0 last:pb-0 dark:border-zinc-800">
<div class="flex items-start justify-between gap-2">
<div class="flex-1">
<flux:text size="sm" class="font-medium">
{{ $update->timeline->case_name }}
</flux:text>
<flux:text size="sm" class="text-zinc-500">
{{ $update->created_at->locale(app()->getLocale())->diffForHumans() }}
</flux:text>
<flux:text class="mt-1">
{{ Str::limit($update->update_text, 80) }}
</flux:text>
</div>
<flux:button
variant="ghost"
size="xs"
:href="route('client.timelines.show', $update->timeline)"
wire:navigate
icon="arrow-right"
/>
</div>
</div>
@endforeach
</div>
@else
<div class="text-center py-4">
<flux:icon name="bell-slash" class="mx-auto h-12 w-12 text-zinc-300" />
<flux:text class="mt-2 text-zinc-500">{{ __('client.dashboard.no_updates') }}</flux:text>
</div>
@endif
</div>
{{-- Booking Status Widget --}}
<div class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<flux:heading size="lg" class="mb-4">
{{ __('client.dashboard.booking_status') }}
</flux:heading>
<div class="space-y-4">
@if ($pendingBookingsCount > 0)
<div class="flex items-center gap-2">
<flux:icon name="clock" class="h-5 w-5 text-amber-500" />
<flux:text>
{{ trans_choice('client.dashboard.pending_bookings', $pendingBookingsCount, ['count' => $pendingBookingsCount]) }}
</flux:text>
</div>
@endif
<div class="rounded-lg p-3 {{ $canBookToday ? 'bg-green-50 dark:bg-green-900/20' : 'bg-amber-50 dark:bg-amber-900/20' }}">
@if ($canBookToday)
<div class="flex items-center gap-2">
<flux:icon name="check-circle" class="h-5 w-5 text-green-600" />
<flux:text class="text-green-700 dark:text-green-400">
{{ __('client.dashboard.can_book') }}
</flux:text>
</div>
@else
<div class="flex items-center gap-2">
<flux:icon name="information-circle" class="h-5 w-5 text-amber-600" />
<flux:text class="text-amber-700 dark:text-amber-400">
{{ __('client.dashboard.cannot_book') }}
</flux:text>
</div>
@endif
</div>
<div class="pt-2">
<flux:button
variant="primary"
:href="route('client.consultations.book')"
wire:navigate
:disabled="!$canBookToday"
class="w-full justify-center"
>
{{ __('client.dashboard.book_consultation') }}
</flux:button>
</div>
</div>
</div>
</div>
</div>