complete story 11.3 with qa tests
This commit is contained in:
@@ -6,15 +6,20 @@
|
||||
|
||||
**معلومات العميل:**
|
||||
|
||||
@if($isGuest)
|
||||
- **نوع الحجز:** زائر (بدون حساب)
|
||||
@else
|
||||
@if($client->user_type === 'company')
|
||||
- **الشركة:** {{ $client->company_name }}
|
||||
- **الشخص المسؤول:** {{ $client->contact_person_name }}
|
||||
@else
|
||||
- **الاسم:** {{ $client->full_name }}
|
||||
@endif
|
||||
- **البريد الإلكتروني:** {{ $client->email }}
|
||||
- **الهاتف:** {{ $client->phone }}
|
||||
@endif
|
||||
- **الاسم:** {{ $clientName }}
|
||||
- **البريد الإلكتروني:** {{ $clientEmail }}
|
||||
- **الهاتف:** {{ $clientPhone ?? 'غير متوفر' }}
|
||||
@unless($isGuest)
|
||||
- **نوع العميل:** {{ $client->user_type === 'company' ? 'شركة' : 'فرد' }}
|
||||
@endunless
|
||||
|
||||
**تفاصيل الموعد:**
|
||||
|
||||
|
||||
@@ -5,15 +5,20 @@ A new consultation request has been submitted and requires your review.
|
||||
|
||||
**Client Information:**
|
||||
|
||||
@if($isGuest)
|
||||
- **Booking Type:** Guest (No Account)
|
||||
@else
|
||||
@if($client->user_type === 'company')
|
||||
- **Company:** {{ $client->company_name }}
|
||||
- **Contact Person:** {{ $client->contact_person_name }}
|
||||
@else
|
||||
- **Name:** {{ $client->full_name }}
|
||||
@endif
|
||||
- **Email:** {{ $client->email }}
|
||||
- **Phone:** {{ $client->phone }}
|
||||
@endif
|
||||
- **Name:** {{ $clientName }}
|
||||
- **Email:** {{ $clientEmail }}
|
||||
- **Phone:** {{ $clientPhone ?? 'Not provided' }}
|
||||
@unless($isGuest)
|
||||
- **Client Type:** {{ ucfirst($client->user_type) }}
|
||||
@endunless
|
||||
|
||||
**Appointment Details:**
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<x-mail::message>
|
||||
<div dir="rtl" style="text-align: right;">
|
||||
# تم تأكيد حجزك
|
||||
|
||||
عزيزي/عزيزتي {{ $guestName }}،
|
||||
|
||||
أخبار سارة! تمت الموافقة على طلب الاستشارة الخاص بك.
|
||||
|
||||
**التاريخ:** {{ $formattedDate }}
|
||||
|
||||
**الوقت:** {{ $formattedTime }}
|
||||
|
||||
**المدة:** 45 دقيقة
|
||||
|
||||
**النوع:** {{ $isPaid ? 'استشارة مدفوعة' : 'استشارة مجانية' }}
|
||||
|
||||
@if($isPaid && $paymentAmount)
|
||||
**المبلغ المستحق:** {{ number_format($paymentAmount, 2) }} شيكل
|
||||
|
||||
@if($paymentInstructions)
|
||||
**تعليمات الدفع:**
|
||||
{{ $paymentInstructions }}
|
||||
@endif
|
||||
@endif
|
||||
|
||||
مرفق بهذه الرسالة ملف دعوة تقويم (.ics). يمكنك إضافته إلى تطبيق التقويم الخاص بك.
|
||||
|
||||
نتطلع للقائك.
|
||||
|
||||
مع أطيب التحيات،<br>
|
||||
{{ config('app.name') }}
|
||||
</div>
|
||||
</x-mail::message>
|
||||
@@ -0,0 +1,31 @@
|
||||
<x-mail::message>
|
||||
# Your Booking Has Been Confirmed
|
||||
|
||||
Dear {{ $guestName }},
|
||||
|
||||
Great news! Your consultation request has been approved.
|
||||
|
||||
**Date:** {{ $formattedDate }}
|
||||
|
||||
**Time:** {{ $formattedTime }}
|
||||
|
||||
**Duration:** 45 minutes
|
||||
|
||||
**Type:** {{ $isPaid ? 'Paid Consultation' : 'Free Consultation' }}
|
||||
|
||||
@if($isPaid && $paymentAmount)
|
||||
**Amount Due:** {{ number_format($paymentAmount, 2) }} ILS
|
||||
|
||||
@if($paymentInstructions)
|
||||
**Payment Instructions:**
|
||||
{{ $paymentInstructions }}
|
||||
@endif
|
||||
@endif
|
||||
|
||||
A calendar invitation (.ics file) is attached to this email. You can add it to your calendar application.
|
||||
|
||||
We look forward to meeting with you.
|
||||
|
||||
Regards,<br>
|
||||
{{ config('app.name') }}
|
||||
</x-mail::message>
|
||||
@@ -0,0 +1,22 @@
|
||||
<x-mail::message>
|
||||
<div dir="rtl" style="text-align: right;">
|
||||
# تحديث الحجز
|
||||
|
||||
عزيزي/عزيزتي {{ $guestName }}،
|
||||
|
||||
نأسف لإبلاغك بأننا غير قادرين على استيعاب طلب الاستشارة الخاص بك في الوقت التالي:
|
||||
|
||||
**التاريخ المطلوب:** {{ $formattedDate }}
|
||||
|
||||
**الوقت المطلوب:** {{ $formattedTime }}
|
||||
|
||||
@if($hasReason)
|
||||
**السبب:** {{ $reason }}
|
||||
@endif
|
||||
|
||||
نعتذر عن أي إزعاج. لا تتردد في تقديم طلب حجز جديد لفترة زمنية مختلفة.
|
||||
|
||||
مع أطيب التحيات،<br>
|
||||
{{ config('app.name') }}
|
||||
</div>
|
||||
</x-mail::message>
|
||||
@@ -0,0 +1,20 @@
|
||||
<x-mail::message>
|
||||
# Booking Update
|
||||
|
||||
Dear {{ $guestName }},
|
||||
|
||||
We regret to inform you that we are unable to accommodate your consultation request for the following time:
|
||||
|
||||
**Requested Date:** {{ $formattedDate }}
|
||||
|
||||
**Requested Time:** {{ $formattedTime }}
|
||||
|
||||
@if($hasReason)
|
||||
**Reason:** {{ $reason }}
|
||||
@endif
|
||||
|
||||
We apologize for any inconvenience. Please feel free to submit a new booking request for a different time slot.
|
||||
|
||||
Regards,<br>
|
||||
{{ config('app.name') }}
|
||||
</x-mail::message>
|
||||
@@ -3,12 +3,15 @@
|
||||
use App\Enums\ConsultationStatus;
|
||||
use App\Enums\ConsultationType;
|
||||
use App\Enums\PaymentStatus;
|
||||
use App\Mail\GuestBookingApprovedMail;
|
||||
use App\Mail\GuestBookingRejectedMail;
|
||||
use App\Models\AdminLog;
|
||||
use App\Models\Consultation;
|
||||
use App\Notifications\BookingApproved;
|
||||
use App\Notifications\BookingRejected;
|
||||
use App\Services\CalendarService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Livewire\Volt\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
@@ -55,6 +58,7 @@ new class extends Component
|
||||
]);
|
||||
|
||||
// Generate calendar file and send notification
|
||||
$icsContent = null;
|
||||
try {
|
||||
$calendarService = app(CalendarService::class);
|
||||
$icsContent = $calendarService->generateIcs($consultation);
|
||||
@@ -63,10 +67,17 @@ new class extends Component
|
||||
'consultation_id' => $consultation->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
$icsContent = null;
|
||||
}
|
||||
|
||||
if ($consultation->user) {
|
||||
// Send appropriate notification/email based on guest/client
|
||||
if ($consultation->isGuest()) {
|
||||
Mail::to($consultation->guest_email)->queue(
|
||||
new GuestBookingApprovedMail(
|
||||
$consultation,
|
||||
app()->getLocale()
|
||||
)
|
||||
);
|
||||
} elseif ($consultation->user) {
|
||||
$consultation->user->notify(
|
||||
new BookingApproved($consultation, $icsContent ?? '', null)
|
||||
);
|
||||
@@ -106,8 +117,16 @@ new class extends Component
|
||||
'status' => ConsultationStatus::Rejected,
|
||||
]);
|
||||
|
||||
// Send rejection notification
|
||||
if ($consultation->user) {
|
||||
// Send appropriate notification/email based on guest/client
|
||||
if ($consultation->isGuest()) {
|
||||
Mail::to($consultation->guest_email)->queue(
|
||||
new GuestBookingRejectedMail(
|
||||
$consultation,
|
||||
app()->getLocale(),
|
||||
null
|
||||
)
|
||||
);
|
||||
} elseif ($consultation->user) {
|
||||
$consultation->user->notify(
|
||||
new BookingRejected($consultation, null)
|
||||
);
|
||||
@@ -191,8 +210,11 @@ new class extends Component
|
||||
<!-- Booking Info -->
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
@if($booking->isGuest())
|
||||
<flux:badge color="amber" size="sm">{{ __('admin.guest') }}</flux:badge>
|
||||
@endif
|
||||
<span class="font-semibold text-zinc-900 dark:text-zinc-100">
|
||||
{{ $booking->user?->full_name ?? __('common.unknown') }}
|
||||
{{ $booking->getClientName() }}
|
||||
</span>
|
||||
<flux:badge variant="warning" size="sm">
|
||||
{{ $booking->status->label() }}
|
||||
@@ -210,7 +232,9 @@ new class extends Component
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<flux:icon name="envelope" class="w-4 h-4" />
|
||||
{{ $booking->user?->email ?? '-' }}
|
||||
<a href="mailto:{{ $booking->getClientEmail() }}" class="hover:underline">
|
||||
{{ $booking->getClientEmail() }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<flux:icon name="document-text" class="w-4 h-4" />
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
use App\Enums\ConsultationStatus;
|
||||
use App\Enums\ConsultationType;
|
||||
use App\Enums\PaymentStatus;
|
||||
use App\Mail\GuestBookingApprovedMail;
|
||||
use App\Mail\GuestBookingRejectedMail;
|
||||
use App\Models\AdminLog;
|
||||
use App\Models\Consultation;
|
||||
use App\Notifications\BookingApproved;
|
||||
use App\Notifications\BookingRejected;
|
||||
use App\Services\CalendarService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Livewire\Volt\Component;
|
||||
|
||||
new class extends Component
|
||||
@@ -75,8 +78,16 @@ new class extends Component
|
||||
]);
|
||||
}
|
||||
|
||||
// Send notification with .ics attachment
|
||||
if ($this->consultation->user) {
|
||||
// Send appropriate notification/email based on guest/client
|
||||
if ($this->consultation->isGuest()) {
|
||||
Mail::to($this->consultation->guest_email)->queue(
|
||||
new GuestBookingApprovedMail(
|
||||
$this->consultation,
|
||||
app()->getLocale(),
|
||||
$this->paymentInstructions ?: null
|
||||
)
|
||||
);
|
||||
} elseif ($this->consultation->user) {
|
||||
$this->consultation->user->notify(
|
||||
new BookingApproved(
|
||||
$this->consultation,
|
||||
@@ -125,8 +136,16 @@ new class extends Component
|
||||
'status' => ConsultationStatus::Rejected,
|
||||
]);
|
||||
|
||||
// Send rejection notification
|
||||
if ($this->consultation->user) {
|
||||
// Send appropriate notification/email based on guest/client
|
||||
if ($this->consultation->isGuest()) {
|
||||
Mail::to($this->consultation->guest_email)->queue(
|
||||
new GuestBookingRejectedMail(
|
||||
$this->consultation,
|
||||
app()->getLocale(),
|
||||
$this->rejectionReason ?: null
|
||||
)
|
||||
);
|
||||
} elseif ($this->consultation->user) {
|
||||
$this->consultation->user->notify(
|
||||
new BookingRejected($this->consultation, $this->rejectionReason ?: null)
|
||||
);
|
||||
@@ -153,6 +172,11 @@ new class extends Component
|
||||
|
||||
public function with(): array
|
||||
{
|
||||
// Guest bookings don't have consultation history
|
||||
if ($this->consultation->isGuest()) {
|
||||
return ['consultationHistory' => collect()];
|
||||
}
|
||||
|
||||
return [
|
||||
'consultationHistory' => Consultation::query()
|
||||
->where('user_id', $this->consultation->user_id)
|
||||
@@ -185,35 +209,50 @@ new class extends Component
|
||||
</flux:callout>
|
||||
@endif
|
||||
|
||||
<!-- Client Information -->
|
||||
<!-- Client/Guest Information -->
|
||||
<div class="bg-white dark:bg-zinc-800 rounded-lg p-6 border border-zinc-200 dark:border-zinc-700 mb-6">
|
||||
<flux:heading size="lg" class="mb-4">{{ __('admin.client_information') }}</flux:heading>
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<flux:heading size="lg">{{ __('admin.client_information') }}</flux:heading>
|
||||
@if($consultation->isGuest())
|
||||
<flux:badge color="amber" size="sm">{{ __('admin.guest') }}</flux:badge>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p class="text-sm text-zinc-500 dark:text-zinc-400">{{ __('admin.client_name') }}</p>
|
||||
<p class="font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{{ $consultation->user?->full_name ?? __('common.unknown') }}
|
||||
{{ $consultation->getClientName() }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-zinc-500 dark:text-zinc-400">{{ __('admin.client_email') }}</p>
|
||||
<p class="font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{{ $consultation->user?->email ?? '-' }}
|
||||
<a href="mailto:{{ $consultation->getClientEmail() }}" class="text-primary hover:underline">
|
||||
{{ $consultation->getClientEmail() }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-zinc-500 dark:text-zinc-400">{{ __('admin.client_phone') }}</p>
|
||||
<p class="font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{{ $consultation->user?->phone ?? '-' }}
|
||||
@if($consultation->getClientPhone())
|
||||
<a href="tel:{{ $consultation->getClientPhone() }}" class="text-primary hover:underline">
|
||||
{{ $consultation->getClientPhone() }}
|
||||
</a>
|
||||
@else
|
||||
-
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
@unless($consultation->isGuest())
|
||||
<div>
|
||||
<p class="text-sm text-zinc-500 dark:text-zinc-400">{{ __('admin.client_type') }}</p>
|
||||
<p class="font-medium text-zinc-900 dark:text-zinc-100">
|
||||
{{ $consultation->user?->user_type?->value ?? '-' }}
|
||||
{{ ucfirst($consultation->user?->user_type?->value ?? '-') }}
|
||||
</p>
|
||||
</div>
|
||||
@endunless
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -312,7 +351,7 @@ new class extends Component
|
||||
|
||||
<!-- Client Info Summary -->
|
||||
<div class="bg-zinc-50 dark:bg-zinc-700 p-4 rounded-lg">
|
||||
<p><strong>{{ __('admin.client') }}:</strong> {{ $consultation->user?->full_name }}</p>
|
||||
<p><strong>{{ __('admin.client') }}:</strong> {{ $consultation->getClientName() }}</p>
|
||||
<p><strong>{{ __('admin.date') }}:</strong> {{ \Carbon\Carbon::parse($consultation->booking_date)->translatedFormat('l, d M Y') }}</p>
|
||||
<p><strong>{{ __('admin.time') }}:</strong> {{ \Carbon\Carbon::parse($consultation->booking_time)->format('g:i A') }}</p>
|
||||
</div>
|
||||
@@ -367,7 +406,7 @@ new class extends Component
|
||||
|
||||
<!-- Client Info Summary -->
|
||||
<div class="bg-zinc-50 dark:bg-zinc-700 p-4 rounded-lg">
|
||||
<p><strong>{{ __('admin.client') }}:</strong> {{ $consultation->user?->full_name }}</p>
|
||||
<p><strong>{{ __('admin.client') }}:</strong> {{ $consultation->getClientName() }}</p>
|
||||
<p><strong>{{ __('admin.date') }}:</strong> {{ \Carbon\Carbon::parse($consultation->booking_date)->translatedFormat('l, d M Y') }}</p>
|
||||
<p><strong>{{ __('admin.time') }}:</strong> {{ \Carbon\Carbon::parse($consultation->booking_time)->format('g:i A') }}</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user