Commit 0504e7d1 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Add phone-or-email login, Egyptian NID decoder, proration engine, and receptionist wizard overhaul

- AuthService: accepts email or phone for login (identifier-based lookup)
- Login UI: updated to text input with Arabic labels
- EgyptianNidDecoder: decodes 14-digit NID → birth date, gender, governorate
- ProrationResult DTO + ProrationService: mid-month enrollment fee proration (x/30 of remaining days based on configurable renewal day)
- EnrollmentSettingsSeeder: seeds enrollment.allow_proration and enrollment.renewal_day per academy
- NewRegistrationWizard: rewritten — player-first flow, NID auto-decode locks birth/gender/governorate, foreign player toggle, guardian name deduced from player name, phone-only guardian, super admin price override, proration display
- EnrollmentService: applies proration to invoice creation
- EnrollExistingWizard: adds proratedProgramFee computed property, review step shows original vs prorated fee
- Migration: adds governorate column to people table
Co-Authored-By: 's avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent 20184e77
...@@ -12,9 +12,11 @@ class AuthService ...@@ -12,9 +12,11 @@ class AuthService
private const MAX_FAILED_ATTEMPTS = 5; private const MAX_FAILED_ATTEMPTS = 5;
private const LOCKOUT_MINUTES = 30; private const LOCKOUT_MINUTES = 30;
public function attempt(string $email, string $password, string $ip, ?string $userAgent = null): AuthResult public function attempt(string $identifier, string $password, string $ip, ?string $userAgent = null): AuthResult
{ {
$user = User::where('email', $email)->first(); $user = filter_var($identifier, FILTER_VALIDATE_EMAIL)
? User::where('email', $identifier)->first()
: User::where('phone', $identifier)->first();
if (!$user) { if (!$user) {
return new AuthResult(success: false, reason: 'invalid_credentials'); return new AuthResult(success: false, reason: 'invalid_credentials');
......
<?php
namespace App\Domain\Identity\Services;
use Carbon\Carbon;
class EgyptianNidDecoder
{
// Governorate codes → Arabic name
private const GOVERNORATES = [
'01' => 'القاهرة',
'02' => 'الإسكندرية',
'03' => 'بور سعيد',
'04' => 'السويس',
'11' => 'دمياط',
'12' => 'الدقهلية',
'13' => 'الشرقية',
'14' => 'القليوبية',
'15' => 'كفر الشيخ',
'16' => 'الغربية',
'17' => 'المنوفية',
'18' => 'البحيرة',
'19' => 'الإسماعيلية',
'21' => 'الجيزة',
'22' => 'بني سويف',
'23' => 'الفيوم',
'24' => 'المنيا',
'25' => 'أسيوط',
'26' => 'سوهاج',
'27' => 'قنا',
'28' => 'أسوان',
'29' => 'الأقصر',
'31' => 'البحر الأحمر',
'32' => 'الوادي الجديد',
'33' => 'مطروح',
'34' => 'شمال سيناء',
'35' => 'جنوب سيناء',
'88' => 'أجنبي مقيم',
];
public function decode(string $nid): array
{
$nid = preg_replace('/\D/', '', $nid);
if (strlen($nid) !== 14) {
return ['valid' => false];
}
$century = $nid[0];
if (!in_array($century, ['2', '3'])) {
return ['valid' => false];
}
$year = ($century === '2' ? '19' : '20') . substr($nid, 1, 2);
$month = substr($nid, 3, 2);
$day = substr($nid, 5, 2);
try {
$birthDate = Carbon::createFromDate((int)$year, (int)$month, (int)$day);
if ($birthDate->isFuture()) {
return ['valid' => false];
}
} catch (\Throwable) {
return ['valid' => false];
}
$govCode = substr($nid, 7, 2);
$governorate = self::GOVERNORATES[$govCode] ?? null;
// Last digit before check digit (position 12, 0-indexed) determines gender
// Odd = male, even = female
$genderDigit = (int) $nid[12];
$gender = ($genderDigit % 2 !== 0) ? 'male' : 'female';
return [
'valid' => true,
'birth_date' => $birthDate->toDateString(),
'gender' => $gender,
'governorate_ar' => $governorate,
'governorate_code' => $govCode,
];
}
}
<?php
namespace App\Domain\Shared\DTOs;
readonly class ProrationResult
{
public function __construct(
public bool $applied,
public int $originalAmount,
public int $proratedAmount,
public int $remainingDays,
public int $renewalDay,
public string $description,
) {}
}
<?php
namespace App\Domain\Shared\Services;
use App\Domain\Shared\DTOs\ProrationResult;
use Carbon\Carbon;
class ProrationService
{
public function __construct(
private readonly SettingsService $settings,
) {}
public function isEnabled(): bool
{
return (bool) $this->settings->get('enrollment.allow_proration', false);
}
public function renewalDay(): int
{
return (int) $this->settings->get('enrollment.renewal_day', 1);
}
/**
* Calculate prorated fee for a mid-month enrollment.
* If today is on or before the renewal day, no proration applies (full price).
*/
public function calculate(int $baseAmount, ?Carbon $enrollmentDate = null): ProrationResult
{
$today = $enrollmentDate ?? now();
$renewalDay = $this->renewalDay();
$currentDay = (int) $today->day;
// No proration if enrolling on or before the renewal day
if ($currentDay <= $renewalDay) {
return new ProrationResult(
applied: false,
originalAmount: $baseAmount,
proratedAmount: $baseAmount,
remainingDays: 30,
renewalDay: $renewalDay,
description: '',
);
}
// Days remaining until next renewal: renewal_day + 30 - today
$remainingDays = $renewalDay + 30 - $currentDay;
$remainingDays = max(1, $remainingDays);
$proratedAmount = (int) ceil($baseAmount * $remainingDays / 30);
$description = "متناسب: {$remainingDays} من 30 يوم";
return new ProrationResult(
applied: true,
originalAmount: $baseAmount,
proratedAmount: $proratedAmount,
remainingDays: $remainingDays,
renewalDay: $renewalDay,
description: $description,
);
}
}
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
use App\Domain\Participant\Models\Participant; use App\Domain\Participant\Models\Participant;
use App\Domain\Pricing\Services\PricingService; use App\Domain\Pricing\Services\PricingService;
use App\Domain\Shared\Exceptions\DomainException; use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Services\ProrationService;
use App\Domain\Shared\Services\SettingsService; use App\Domain\Shared\Services\SettingsService;
use App\Domain\Attendance\Services\AttendanceGenerationService; use App\Domain\Attendance\Services\AttendanceGenerationService;
use App\Domain\Training\Enums\RenewalPolicy; use App\Domain\Training\Enums\RenewalPolicy;
...@@ -28,6 +29,7 @@ public function __construct( ...@@ -28,6 +29,7 @@ public function __construct(
private readonly PricingService $pricingService, private readonly PricingService $pricingService,
private readonly InvoiceService $invoiceService, private readonly InvoiceService $invoiceService,
private readonly SettingsService $settings, private readonly SettingsService $settings,
private readonly ProrationService $prorationService,
) {} ) {}
public function enroll(Participant $participant, TrainingGroup $group, User $actor, ?array $options = []): Enrollment public function enroll(Participant $participant, TrainingGroup $group, User $actor, ?array $options = []): Enrollment
...@@ -385,13 +387,22 @@ private function createEnrollmentInvoice(Enrollment $enrollment, Participant $pa ...@@ -385,13 +387,22 @@ private function createEnrollmentInvoice(Enrollment $enrollment, Participant $pa
return; return;
} }
// Apply proration if enabled
$proration = $this->prorationService->calculate($priceResult->finalAmount);
$finalAmount = $proration->proratedAmount;
$lineDescription = "اشتراك: {$program->name_ar}";
if ($proration->applied) {
$lineDescription .= " ({$proration->description})";
}
$invoice = $this->invoiceService->create([ $invoice = $this->invoiceService->create([
'academy_id' => $enrollment->academy_id ?? $group->academy_id, 'academy_id' => $enrollment->academy_id ?? $group->academy_id,
'branch_id' => $group->branch_id, 'branch_id' => $group->branch_id,
'billable_type' => $participant->getMorphClass(), 'billable_type' => $participant->getMorphClass(),
'billable_id' => $participant->id, 'billable_id' => $participant->id,
'number' => $this->invoiceService->generateNumber($group->academy_id), 'number' => $this->invoiceService->generateNumber($group->academy_id),
'total_amount' => $priceResult->finalAmount, 'total_amount' => $finalAmount,
'subtotal_amount' => $priceResult->baseAmount, 'subtotal_amount' => $priceResult->baseAmount,
'discount_amount' => $priceResult->totalDiscount, 'discount_amount' => $priceResult->totalDiscount,
'tax_amount' => 0, 'tax_amount' => 0,
...@@ -399,10 +410,10 @@ private function createEnrollmentInvoice(Enrollment $enrollment, Participant $pa ...@@ -399,10 +410,10 @@ private function createEnrollmentInvoice(Enrollment $enrollment, Participant $pa
'contact_name' => $participant->person?->name_ar ?? $participant->person?->name, 'contact_name' => $participant->person?->name_ar ?? $participant->person?->name,
], [ ], [
[ [
'description' => "اشتراك: {$program->name_ar}", 'description' => $lineDescription,
'quantity' => 1, 'quantity' => 1,
'unit_price' => $priceResult->baseAmount, 'unit_price' => $finalAmount,
'discount_amount' => $priceResult->totalDiscount, 'discount_amount' => 0,
'tax_amount' => 0, 'tax_amount' => 0,
], ],
], $actor); ], $actor);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#[Title('تسجيل الدخول')] #[Title('تسجيل الدخول')]
class Login extends Component class Login extends Component
{ {
public string $email = ''; public string $identifier = '';
public string $password = ''; public string $password = '';
public bool $remember = false; public bool $remember = false;
public ?string $errorMessage = null; public ?string $errorMessage = null;
...@@ -21,7 +21,7 @@ class Login extends Component ...@@ -21,7 +21,7 @@ class Login extends Component
public function rules(): array public function rules(): array
{ {
return [ return [
'email' => 'required|email', 'identifier' => 'required|string|min:3',
'password' => 'required|min:6', 'password' => 'required|min:6',
]; ];
} }
...@@ -29,8 +29,8 @@ public function rules(): array ...@@ -29,8 +29,8 @@ public function rules(): array
public function messages(): array public function messages(): array
{ {
return [ return [
'email.required' => 'البريد الإلكتروني مطلوب', 'identifier.required' => 'البريد الإلكتروني أو رقم الهاتف مطلوب',
'email.email' => 'صيغة البريد الإلكتروني غير صحيحة', 'identifier.min' => 'يجب أن يكون الإدخال 3 أحرف على الأقل',
'password.required' => 'كلمة المرور مطلوبة', 'password.required' => 'كلمة المرور مطلوبة',
'password.min' => 'كلمة المرور يجب أن تكون 6 أحرف على الأقل', 'password.min' => 'كلمة المرور يجب أن تكون 6 أحرف على الأقل',
]; ];
...@@ -42,7 +42,7 @@ public function login(AuthService $authService): void ...@@ -42,7 +42,7 @@ public function login(AuthService $authService): void
$this->errorMessage = null; $this->errorMessage = null;
$result = $authService->attempt( $result = $authService->attempt(
email: $this->email, identifier: $this->identifier,
password: $this->password, password: $this->password,
ip: request()->ip(), ip: request()->ip(),
userAgent: request()->userAgent(), userAgent: request()->userAgent(),
...@@ -54,7 +54,7 @@ public function login(AuthService $authService): void ...@@ -54,7 +54,7 @@ public function login(AuthService $authService): void
} elseif ($result->reason === 'inactive') { } elseif ($result->reason === 'inactive') {
$this->errorMessage = 'الحساب غير نشط. تواصل مع الإدارة.'; $this->errorMessage = 'الحساب غير نشط. تواصل مع الإدارة.';
} else { } else {
$this->errorMessage = 'البريد الإلكتروني أو كلمة المرور غير صحيحة'; $this->errorMessage = 'بيانات الدخول غير صحيحة';
} }
return; return;
} }
......
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
use App\Domain\Participant\Models\Participant; use App\Domain\Participant\Models\Participant;
use App\Domain\Pricing\Models\BasePrice; use App\Domain\Pricing\Models\BasePrice;
use App\Domain\Shared\DTOs\ProrationResult;
use App\Domain\Shared\Exceptions\DomainException; use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Services\ProrationService;
use App\Domain\Shared\Traits\UsesBranchScope; use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\Activity; use App\Domain\Training\Models\Activity;
use App\Domain\Training\Models\Enrollment; use App\Domain\Training\Models\Enrollment;
...@@ -161,6 +163,24 @@ public function selectedProgramFee(): int ...@@ -161,6 +163,24 @@ public function selectedProgramFee(): int
return $price?->amount ?? 0; return $price?->amount ?? 0;
} }
#[Computed]
public function proratedProgramFee(): ProrationResult
{
$baseFee = $this->selectedProgramFee;
$service = app(ProrationService::class);
if (!$service->isEnabled() || $baseFee === 0) {
return new ProrationResult(
applied: false,
originalAmount: $baseFee,
proratedAmount: $baseFee,
remainingDays: 30,
renewalDay: $service->renewalDay(),
description: '',
);
}
return $service->calculate($baseFee);
}
public function render() public function render()
{ {
$searchResults = collect(); $searchResults = collect();
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use App\Domain\Identity\Models\Guardian; use App\Domain\Identity\Models\Guardian;
use App\Domain\Identity\Models\Person; use App\Domain\Identity\Models\Person;
use App\Domain\Identity\Models\Role; use App\Domain\Identity\Models\Role;
use App\Domain\Identity\Services\EgyptianNidDecoder;
use App\Domain\Identity\Services\PersonService; use App\Domain\Identity\Services\PersonService;
use App\Domain\Inventory\Models\Kit; use App\Domain\Inventory\Models\Kit;
use App\Domain\Inventory\Models\Product; use App\Domain\Inventory\Models\Product;
...@@ -16,8 +17,10 @@ ...@@ -16,8 +17,10 @@
use App\Domain\Participant\Services\DuplicateDetectionService; use App\Domain\Participant\Services\DuplicateDetectionService;
use App\Domain\Participant\Services\ParticipantService; use App\Domain\Participant\Services\ParticipantService;
use App\Domain\Pricing\Models\BasePrice; use App\Domain\Pricing\Models\BasePrice;
use App\Domain\Shared\DTOs\ProrationResult;
use App\Domain\Shared\Exceptions\DomainException; use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Services\PlatformFeeService; use App\Domain\Shared\Services\PlatformFeeService;
use App\Domain\Shared\Services\ProrationService;
use App\Domain\Shared\Traits\UsesBranchScope; use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\Activity; use App\Domain\Training\Models\Activity;
use App\Domain\Training\Models\TrainingProgram; use App\Domain\Training\Models\TrainingProgram;
...@@ -42,20 +45,7 @@ class NewRegistrationWizard extends Component ...@@ -42,20 +45,7 @@ class NewRegistrationWizard extends Component
public int $currentStep = 1; public int $currentStep = 1;
public int $totalSteps = 7; public int $totalSteps = 7;
// Step 1: Guardian info // Step 1: Participant (the actual player/child) — FIRST now
public string $guardian_name_ar = '';
public string $guardian_name = '';
public string $guardian_phone = '';
public string $guardian_national_id = '';
public string $guardian_relation = 'father';
// Step 2: Parent Account
public bool $createParentAccount = true;
public string $parentEmail = '';
public string $parentPassword = '';
public bool $sendParentCredentials = true;
// Step 3: Participant (the actual player/child)
public string $participant_name_ar = ''; public string $participant_name_ar = '';
public string $participant_name = ''; public string $participant_name = '';
public ?string $participant_date_of_birth = null; public ?string $participant_date_of_birth = null;
...@@ -65,6 +55,21 @@ class NewRegistrationWizard extends Component ...@@ -65,6 +55,21 @@ class NewRegistrationWizard extends Component
public string $participant_medical_notes = ''; public string $participant_medical_notes = '';
public string $membership_type = 'non_member'; public string $membership_type = 'non_member';
public string $membership_id = ''; public string $membership_id = '';
public string $participant_governorate = '';
public bool $participant_is_foreign = false;
public bool $participant_nid_decoded = false;
// Step 2: Guardian info
public string $guardian_name_ar = '';
public string $guardian_name = '';
public string $guardian_phone = '';
public string $guardian_relation = 'father';
// Step 3: Parent Account
public bool $createParentAccount = true;
public string $parentEmail = '';
public string $parentPassword = '';
public bool $sendParentCredentials = true;
// Step 4: Program selection // Step 4: Program selection
public ?int $selected_activity_id = null; public ?int $selected_activity_id = null;
...@@ -74,6 +79,11 @@ class NewRegistrationWizard extends Component ...@@ -74,6 +79,11 @@ class NewRegistrationWizard extends Component
public bool $pay_now = false; public bool $pay_now = false;
public string $payment_method = 'cash'; public string $payment_method = 'cash';
// Super-admin price override
public bool $priceOverrideEnabled = false;
public string $priceOverrideInput = '';
public string $priceOverrideReason = '';
// Guardian search (existing parent) // Guardian search (existing parent)
public bool $searchExistingGuardian = false; public bool $searchExistingGuardian = false;
public string $guardianSearchQuery = ''; public string $guardianSearchQuery = '';
...@@ -148,6 +158,69 @@ private function runPreflightChecks(): void ...@@ -148,6 +158,69 @@ private function runPreflightChecks(): void
$this->systemErrors = $errors; $this->systemErrors = $errors;
} }
// --- NID decode hooks ---
public function updatedParticipantNationalId(): void
{
if ($this->participant_is_foreign) {
return;
}
$nid = trim($this->participant_national_id);
if (strlen($nid) !== 14) {
$this->participant_nid_decoded = false;
return;
}
$result = app(EgyptianNidDecoder::class)->decode($nid);
if (!$result['valid']) {
$this->participant_nid_decoded = false;
return;
}
$this->participant_date_of_birth = $result['birth_date'];
$this->participant_gender = $result['gender'];
$this->participant_governorate = $result['governorate_ar'] ?? '';
$this->participant_nid_decoded = true;
}
public function updatedParticipantIsForeign(): void
{
if ($this->participant_is_foreign) {
// Unlock fields when switching to foreign
$this->participant_nid_decoded = false;
} else {
// Re-decode if NID already filled
$this->updatedParticipantNationalId();
}
}
// --- Guardian name auto-fill from player name ---
public function updatedParticipantNameAr(): void
{
$this->autoFillGuardianName();
}
private function autoFillGuardianName(): void
{
if (empty($this->participant_name_ar) || $this->guardianSelected) {
return;
}
$parts = array_values(array_filter(explode(' ', trim($this->participant_name_ar))));
// Father name = words[1] + words[2] (the two words after the player's first name)
if (count($parts) >= 3) {
$this->guardian_name_ar = implode(' ', array_slice($parts, 1, 2));
} elseif (count($parts) === 2) {
$this->guardian_name_ar = $parts[1];
}
}
// --- Step navigation ---
public function nextStep(): void public function nextStep(): void
{ {
$rules = $this->rulesForStep($this->currentStep); $rules = $this->rulesForStep($this->currentStep);
...@@ -156,14 +229,14 @@ public function nextStep(): void ...@@ -156,14 +229,14 @@ public function nextStep(): void
$this->validate($rules, $this->messages()); $this->validate($rules, $this->messages());
} }
// Duplicate check on step 1 — if duplicates found, stay on step 1 // Duplicate check on step 2 (guardian) — if duplicates found, stay on step 2
if ($this->currentStep === 1 && !$this->duplicateCheckDone) { if ($this->currentStep === 2 && !$this->duplicateCheckDone) {
$this->checkDuplicates(); $this->checkDuplicates();
return; return;
} }
// Pre-fill parent email from guardian person data when moving to step 2 // Pre-fill parent email from guardian person data when moving to step 3
if ($this->currentStep === 1 && $this->duplicateCheckDone && empty($this->parentEmail)) { if ($this->currentStep === 2 && $this->duplicateCheckDone && empty($this->parentEmail)) {
if ($this->useExistingPersonId) { if ($this->useExistingPersonId) {
$existingPerson = Person::find($this->useExistingPersonId); $existingPerson = Person::find($this->useExistingPersonId);
if ($existingPerson && $existingPerson->email) { if ($existingPerson && $existingPerson->email) {
...@@ -188,25 +261,24 @@ private function rulesForStep(int $step): array ...@@ -188,25 +261,24 @@ private function rulesForStep(int $step): array
{ {
return match ($step) { return match ($step) {
1 => [ 1 => [
'guardian_name_ar' => 'required|string|max:255',
'guardian_phone' => 'required|string|max:20',
'guardian_national_id' => 'nullable|string|max:14',
'guardian_relation' => 'required|in:father,mother,brother,sister,uncle,aunt,grandfather,grandmother,guardian,other',
],
2 => $this->createParentAccount ? [
'parentEmail' => 'required|email|max:255|unique:users,email',
'parentPassword' => 'required|string|min:6|max:100',
] : [],
3 => [
'participant_name_ar' => 'required|string|max:255', 'participant_name_ar' => 'required|string|max:255',
'participant_date_of_birth' => 'required|date|before:today', 'participant_date_of_birth' => 'required|date|before:today',
'participant_gender' => 'required|in:male,female', 'participant_gender' => 'required|in:male,female',
'participant_phone' => 'nullable|string|max:20', 'participant_phone' => 'nullable|string|max:20',
'participant_national_id' => 'nullable|string|max:14', 'participant_national_id' => 'nullable|string|max:' . ($this->participant_is_foreign ? '30' : '14'),
'participant_medical_notes' => 'nullable|string|max:1000', 'participant_medical_notes' => 'nullable|string|max:1000',
'membership_type' => 'required|in:member,non_member', 'membership_type' => 'required|in:member,non_member',
'membership_id' => 'required_if:membership_type,member|nullable|string|max:50', 'membership_id' => 'required_if:membership_type,member|nullable|string|max:50',
], ],
2 => [
'guardian_name_ar' => 'required|string|max:255',
'guardian_phone' => 'required|string|max:20',
'guardian_relation' => 'required|in:father,mother,brother,sister,uncle,aunt,grandfather,grandmother,guardian,other',
],
3 => $this->createParentAccount ? [
'parentEmail' => 'required|email|max:255|unique:users,email',
'parentPassword' => 'required|string|min:6|max:100',
] : [],
4 => [ 4 => [
'selected_activity_id' => 'required|exists:activities,id', 'selected_activity_id' => 'required|exists:activities,id',
'selected_program_id' => 'required|exists:training_programs,id', 'selected_program_id' => 'required|exists:training_programs,id',
...@@ -221,6 +293,14 @@ private function rulesForStep(int $step): array ...@@ -221,6 +293,14 @@ private function rulesForStep(int $step): array
public function messages(): array public function messages(): array
{ {
return [ return [
'participant_name_ar.required' => 'اسم المشترك مطلوب',
'participant_date_of_birth.required' => 'تاريخ الميلاد مطلوب',
'participant_date_of_birth.before' => 'تاريخ الميلاد يجب أن يكون في الماضي',
'participant_gender.required' => 'الجنس مطلوب',
'participant_gender.in' => 'الجنس غير صالح',
'membership_type.required' => 'نوع العضوية مطلوب',
'membership_type.in' => 'نوع العضوية غير صالح',
'membership_id.required_if' => 'رقم عضوية النادي مطلوب للأعضاء',
'guardian_name_ar.required' => 'اسم ولي الأمر مطلوب', 'guardian_name_ar.required' => 'اسم ولي الأمر مطلوب',
'guardian_phone.required' => 'رقم الهاتف مطلوب', 'guardian_phone.required' => 'رقم الهاتف مطلوب',
'guardian_relation.required' => 'صلة القرابة مطلوبة', 'guardian_relation.required' => 'صلة القرابة مطلوبة',
...@@ -230,18 +310,10 @@ public function messages(): array ...@@ -230,18 +310,10 @@ public function messages(): array
'parentEmail.unique' => 'البريد الإلكتروني مستخدم بالفعل', 'parentEmail.unique' => 'البريد الإلكتروني مستخدم بالفعل',
'parentPassword.required' => 'كلمة المرور مطلوبة', 'parentPassword.required' => 'كلمة المرور مطلوبة',
'parentPassword.min' => 'كلمة المرور يجب أن تكون 6 أحرف على الأقل', 'parentPassword.min' => 'كلمة المرور يجب أن تكون 6 أحرف على الأقل',
'participant_name_ar.required' => 'اسم المشترك مطلوب',
'participant_date_of_birth.required' => 'تاريخ الميلاد مطلوب',
'participant_date_of_birth.before' => 'تاريخ الميلاد يجب أن يكون في الماضي',
'participant_gender.required' => 'الجنس مطلوب',
'participant_gender.in' => 'الجنس غير صالح',
'selected_activity_id.required' => 'يرجى اختيار النشاط', 'selected_activity_id.required' => 'يرجى اختيار النشاط',
'selected_activity_id.exists' => 'النشاط المختار غير موجود', 'selected_activity_id.exists' => 'النشاط المختار غير موجود',
'selected_program_id.required' => 'يرجى اختيار البرنامج', 'selected_program_id.required' => 'يرجى اختيار البرنامج',
'selected_program_id.exists' => 'البرنامج المختار غير موجود', 'selected_program_id.exists' => 'البرنامج المختار غير موجود',
'membership_type.required' => 'نوع العضوية مطلوب',
'membership_type.in' => 'نوع العضوية غير صالح',
'membership_id.required_if' => 'رقم عضوية النادي مطلوب للأعضاء',
'payment_method.required_if' => 'يرجى اختيار طريقة الدفع', 'payment_method.required_if' => 'يرجى اختيار طريقة الدفع',
'payment_method.in' => 'طريقة الدفع غير صالحة', 'payment_method.in' => 'طريقة الدفع غير صالحة',
]; ];
...@@ -325,7 +397,6 @@ public function selectExistingGuardian(int $guardianId): void ...@@ -325,7 +397,6 @@ public function selectExistingGuardian(int $guardianId): void
$this->guardian_name_ar = $guardian->person->name_ar ?? ''; $this->guardian_name_ar = $guardian->person->name_ar ?? '';
$this->guardian_name = $guardian->person->name ?? ''; $this->guardian_name = $guardian->person->name ?? '';
$this->guardian_phone = $guardian->person->phone ?? ''; $this->guardian_phone = $guardian->person->phone ?? '';
$this->guardian_national_id = $guardian->person->national_id ?? '';
$this->guardian_relation = $guardian->relation_type ?? 'father'; $this->guardian_relation = $guardian->relation_type ?? 'father';
$this->guardianSelected = true; $this->guardianSelected = true;
$this->guardianSearchResults = []; $this->guardianSearchResults = [];
...@@ -337,7 +408,6 @@ public function clearSelectedGuardian(): void ...@@ -337,7 +408,6 @@ public function clearSelectedGuardian(): void
$this->guardian_name_ar = ''; $this->guardian_name_ar = '';
$this->guardian_name = ''; $this->guardian_name = '';
$this->guardian_phone = ''; $this->guardian_phone = '';
$this->guardian_national_id = '';
$this->guardian_relation = 'father'; $this->guardian_relation = 'father';
$this->guardianSelected = false; $this->guardianSelected = false;
$this->searchExistingGuardian = false; $this->searchExistingGuardian = false;
...@@ -383,6 +453,27 @@ public function updatedSelectedActivityId(): void ...@@ -383,6 +453,27 @@ public function updatedSelectedActivityId(): void
$this->selected_program_id = null; $this->selected_program_id = null;
} }
// --- Price override (super admin only) ---
public function updatedPriceOverrideEnabled(): void
{
if (!$this->priceOverrideEnabled) {
$this->priceOverrideInput = '';
$this->priceOverrideReason = '';
}
}
// Returns the effective total in piasters, respecting override
#[Computed]
public function effectiveTotal(): int
{
if ($this->priceOverrideEnabled && $this->priceOverrideInput !== '') {
$overridePiasters = (int) round((float) $this->priceOverrideInput * 100);
return max(0, $overridePiasters);
}
return $this->totalWithFee;
}
// --- Hot-buy methods --- // --- Hot-buy methods ---
#[Computed] #[Computed]
...@@ -477,6 +568,71 @@ public function hotbuyTotal(): int ...@@ -477,6 +568,71 @@ public function hotbuyTotal(): int
return collect($this->hotbuyCart)->sum(fn ($item) => $item['price'] * $item['quantity']); return collect($this->hotbuyCart)->sum(fn ($item) => $item['price'] * $item['quantity']);
} }
// --- Proration ---
#[Computed]
public function proratedProgramFee(): ProrationResult
{
$baseFee = $this->selectedProgramFee;
$service = app(ProrationService::class);
if (!$service->isEnabled() || $baseFee === 0) {
return new ProrationResult(
applied: false,
originalAmount: $baseFee,
proratedAmount: $baseFee,
remainingDays: 30,
renewalDay: $service->renewalDay(),
description: '',
);
}
return $service->calculate($baseFee);
}
#[Computed]
public function selectedProgram(): ?TrainingProgram
{
if (!$this->selected_program_id) {
return null;
}
return TrainingProgram::with('activity')->find($this->selected_program_id);
}
#[Computed]
public function selectedProgramFee(): int
{
if (!$this->selected_program_id) {
return 0;
}
$program = TrainingProgram::find($this->selected_program_id);
return $program ? $this->resolveProgramFee($program) : 0;
}
#[Computed]
public function platformFee(): int
{
$service = app(PlatformFeeService::class);
if (!$service->customerPays()) {
return 0;
}
$subtotal = $this->proratedProgramFee->proratedAmount + $this->hotbuyTotal;
return $service->calculate($subtotal);
}
#[Computed]
public function totalWithFee(): int
{
return $this->proratedProgramFee->proratedAmount + $this->hotbuyTotal + $this->platformFee;
}
#[Computed]
public function invoiceForPrint(): ?Invoice
{
if (!$this->invoiceId) {
return null;
}
return Invoice::with('items')->find($this->invoiceId);
}
public function confirm(): void public function confirm(): void
{ {
try { try {
...@@ -498,7 +654,6 @@ public function confirm(): void ...@@ -498,7 +654,6 @@ public function confirm(): void
'name_ar' => $this->guardian_name_ar, 'name_ar' => $this->guardian_name_ar,
'name' => $this->guardian_name ?: $this->guardian_name_ar, 'name' => $this->guardian_name ?: $this->guardian_name_ar,
'phone' => $this->guardian_phone, 'phone' => $this->guardian_phone,
'national_id' => $this->guardian_national_id ?: null,
], $actor); ], $actor);
} }
} }
...@@ -521,7 +676,6 @@ public function confirm(): void ...@@ -521,7 +676,6 @@ public function confirm(): void
->where('academy_id', app('current_academy')->id) ->where('academy_id', app('current_academy')->id)
->first(); ->first();
// Only create if no existing user is already linked
if (!$guardian->user_id) { if (!$guardian->user_id) {
$parentUser = User::create([ $parentUser = User::create([
'academy_id' => app('current_academy')->id, 'academy_id' => app('current_academy')->id,
...@@ -538,7 +692,6 @@ public function confirm(): void ...@@ -538,7 +692,6 @@ public function confirm(): void
$guardian->update(['user_id' => $parentUser->id]); $guardian->update(['user_id' => $parentUser->id]);
$guardianPerson->update(['user_id' => $parentUser->id]); $guardianPerson->update(['user_id' => $parentUser->id]);
// Attach the parent role via pivot if role exists
if ($parentRole) { if ($parentRole) {
$parentUser->roles()->attach($parentRole->id, [ $parentUser->roles()->attach($parentRole->id, [
'assigned_by' => $actor->id, 'assigned_by' => $actor->id,
...@@ -556,6 +709,7 @@ public function confirm(): void ...@@ -556,6 +709,7 @@ public function confirm(): void
'gender' => $this->participant_gender, 'gender' => $this->participant_gender,
'phone' => $this->participant_phone ?: null, 'phone' => $this->participant_phone ?: null,
'national_id' => $this->participant_national_id ?: null, 'national_id' => $this->participant_national_id ?: null,
'governorate' => $this->participant_governorate ?: null,
'medical_notes' => $this->participant_medical_notes ?: null, 'medical_notes' => $this->participant_medical_notes ?: null,
], $actor); ], $actor);
...@@ -588,25 +742,49 @@ public function confirm(): void ...@@ -588,25 +742,49 @@ public function confirm(): void
$actor $actor
); );
// 7. Look up the price for this program + calculate platform fee + hot-buy // 7. Resolve program fee with optional proration, hot-buy, platform fee
$feeAmount = $this->resolveProgramFee($program); $prorationResult = $this->proratedProgramFee;
$programFee = $prorationResult->proratedAmount;
$hotbuyTotal = $this->hotbuyTotal; $hotbuyTotal = $this->hotbuyTotal;
$subtotal = $feeAmount + $hotbuyTotal; $subtotal = $programFee + $hotbuyTotal;
$platformFeeService = app(PlatformFeeService::class); $platformFeeService = app(PlatformFeeService::class);
$customerPays = $platformFeeService->customerPays(); $customerPays = $platformFeeService->customerPays();
$serviceFee = $customerPays ? $platformFeeService->calculate($subtotal) : 0; $serviceFee = $customerPays ? $platformFeeService->calculate($subtotal) : 0;
$totalWithFee = $subtotal + $serviceFee; $computedTotal = $subtotal + $serviceFee;
// Super-admin override
$finalTotal = $computedTotal;
if ($this->priceOverrideEnabled && $this->priceOverrideInput !== '' && $actor->is_super_admin) {
$overrideAmount = (int) round((float) $this->priceOverrideInput * 100);
$finalTotal = max(0, $overrideAmount);
// Audit the override
\Log::channel('audit')->info('super_admin_price_override', [
'actor_id' => $actor->id,
'actor_name' => $actor->name,
'participant_name' => $this->participant_name_ar,
'program' => $program->name_ar,
'original_piasters' => $computedTotal,
'override_piasters' => $finalTotal,
'reason' => $this->priceOverrideReason,
]);
}
// 8. Create invoice if there's a fee or hot-buy items // 8. Create invoice if there's a fee or hot-buy items
$invoice = null; $invoice = null;
if ($subtotal > 0) { if ($subtotal > 0 || $finalTotal !== $computedTotal) {
$invoiceItems = []; $invoiceItems = [];
if ($feeAmount > 0) { if ($programFee > 0) {
$description = $program->name_ar;
if ($prorationResult->applied) {
$description .= ' (' . $prorationResult->description . ')';
}
$invoiceItems[] = [ $invoiceItems[] = [
'description' => $program->name_ar, 'description' => $description,
'quantity' => 1, 'quantity' => 1,
'unit_price' => $feeAmount, 'unit_price' => $programFee,
'discount_amount' => 0, 'discount_amount' => 0,
'tax_amount' => 0, 'tax_amount' => 0,
]; ];
...@@ -622,6 +800,12 @@ public function confirm(): void ...@@ -622,6 +800,12 @@ public function confirm(): void
]; ];
} }
// If override changed total, reflect as a discount line
$discountAmount = 0;
if ($this->priceOverrideEnabled && $actor->is_super_admin && $finalTotal < $computedTotal) {
$discountAmount = $computedTotal - $finalTotal;
}
$invoice = $invoiceService->create([ $invoice = $invoiceService->create([
'academy_id' => app('current_academy')->id, 'academy_id' => app('current_academy')->id,
'number' => $invoiceService->generateNumber(app('current_academy')->id), 'number' => $invoiceService->generateNumber(app('current_academy')->id),
...@@ -631,20 +815,17 @@ public function confirm(): void ...@@ -631,20 +815,17 @@ public function confirm(): void
'contact_name' => $this->guardian_name_ar, 'contact_name' => $this->guardian_name_ar,
'contact_phone' => $this->guardian_phone, 'contact_phone' => $this->guardian_phone,
'subtotal_amount' => $subtotal, 'subtotal_amount' => $subtotal,
'discount_amount' => 0, 'discount_amount' => $discountAmount,
'tax_amount' => 0, 'tax_amount' => 0,
'service_fee_amount' => $serviceFee, 'service_fee_amount' => $serviceFee,
'total_amount' => $totalWithFee, 'total_amount' => $finalTotal,
'currency' => 'EGP', 'currency' => 'EGP',
'issue_date' => now()->toDateString(), 'issue_date' => now()->toDateString(),
'due_date' => now()->addDays(7)->toDateString(), 'due_date' => now()->addDays(7)->toDateString(),
'notes' => 'اشتراك: ' . $program->name_ar, 'notes' => 'اشتراك: ' . $program->name_ar,
], $invoiceItems, $actor); ], $invoiceItems, $actor);
// Send the invoice (mark as sent)
$invoice->update(['status' => 'sent']); $invoice->update(['status' => 'sent']);
// Link enrollment to invoice
$enrollment->update(['invoice_id' => $invoice->id]); $enrollment->update(['invoice_id' => $invoice->id]);
$this->invoice_amount = $invoice->total_amount; $this->invoice_amount = $invoice->total_amount;
...@@ -700,7 +881,6 @@ private function resolveProgramFee(TrainingProgram $program): int ...@@ -700,7 +881,6 @@ private function resolveProgramFee(TrainingProgram $program): int
->where(fn ($q) => $q->whereNull('effective_to')->orWhere('effective_to', '>=', now())) ->where(fn ($q) => $q->whereNull('effective_to')->orWhere('effective_to', '>=', now()))
->forBranch($this->branchId); ->forBranch($this->branchId);
// Try membership-specific price first
$specificPrice = (clone $query) $specificPrice = (clone $query)
->whereJsonContains('metadata->membership_type', $this->membership_type) ->whereJsonContains('metadata->membership_type', $this->membership_type)
->orderByDesc('priority') ->orderByDesc('priority')
...@@ -710,7 +890,6 @@ private function resolveProgramFee(TrainingProgram $program): int ...@@ -710,7 +890,6 @@ private function resolveProgramFee(TrainingProgram $program): int
return $specificPrice->amount; return $specificPrice->amount;
} }
// Fall back to generic price (no membership_type in metadata)
$genericPrice = $query $genericPrice = $query
->where(fn ($q) => $q ->where(fn ($q) => $q
->whereNull('metadata->membership_type') ->whereNull('metadata->membership_type')
...@@ -723,53 +902,6 @@ private function resolveProgramFee(TrainingProgram $program): int ...@@ -723,53 +902,6 @@ private function resolveProgramFee(TrainingProgram $program): int
return $genericPrice?->amount ?? 0; return $genericPrice?->amount ?? 0;
} }
#[Computed]
public function selectedProgram(): ?TrainingProgram
{
if (!$this->selected_program_id) {
return null;
}
return TrainingProgram::with('activity')->find($this->selected_program_id);
}
#[Computed]
public function selectedProgramFee(): int
{
if (!$this->selected_program_id) {
return 0;
}
$program = TrainingProgram::find($this->selected_program_id);
return $program ? $this->resolveProgramFee($program) : 0;
}
#[Computed]
public function platformFee(): int
{
$service = app(PlatformFeeService::class);
if (!$service->customerPays()) {
return 0;
}
$subtotal = $this->selectedProgramFee + $this->hotbuyTotal;
return $service->calculate($subtotal);
}
#[Computed]
public function totalWithFee(): int
{
return $this->selectedProgramFee + $this->hotbuyTotal + $this->platformFee;
}
#[Computed]
public function invoiceForPrint(): ?Invoice
{
if (!$this->invoiceId) {
return null;
}
return Invoice::with('items')->find($this->invoiceId);
}
public function render() public function render()
{ {
$activities = Activity::where('is_active', true)->orderBy('name_ar')->get(); $activities = Activity::where('is_active', true)->orderBy('name_ar')->get();
...@@ -788,6 +920,7 @@ public function render() ...@@ -788,6 +920,7 @@ public function render()
return view('livewire.receptionist.new-registration-wizard', [ return view('livewire.receptionist.new-registration-wizard', [
'activities' => $activities, 'activities' => $activities,
'programs' => $programs, 'programs' => $programs,
'isSuperAdmin' => auth()->user()?->is_super_admin ?? false,
'relationOptions' => [ 'relationOptions' => [
'father' => 'أب', 'father' => 'أب',
'mother' => 'أم', 'mother' => 'أم',
......
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('people', function (Blueprint $table) {
$table->string('governorate', 100)->nullable()->after('national_id');
});
}
public function down(): void
{
Schema::table('people', function (Blueprint $table) {
$table->dropColumn('governorate');
});
}
};
...@@ -54,6 +54,7 @@ public function run(): void ...@@ -54,6 +54,7 @@ public function run(): void
$this->call(RolesAndPermissionsSeeder::class); $this->call(RolesAndPermissionsSeeder::class);
$this->call(PermissionSeeder::class); $this->call(PermissionSeeder::class);
$this->call(PaymentNotificationTemplateSeeder::class); $this->call(PaymentNotificationTemplateSeeder::class);
$this->call(EnrollmentSettingsSeeder::class);
// Assign academy_owner role + super_admin // Assign academy_owner role + super_admin
$ownerRole = Role::where('academy_id', $academy->id) $ownerRole = Role::where('academy_id', $academy->id)
......
<?php
namespace Database\Seeders;
use App\Domain\Shared\Models\SystemSetting;
use App\Domain\Identity\Models\Organization;
use Illuminate\Database\Seeder;
class EnrollmentSettingsSeeder extends Seeder
{
public function run(): void
{
$academies = Organization::all();
$defaults = [
[
'group' => 'enrollment',
'key' => 'enrollment.allow_proration',
'value' => '0',
'type' => 'boolean',
'label_ar' => 'تفعيل الدفع الجزئي (تناسبي)',
'description_ar' => 'عند تفعيله، يدفع المشترك الذي يلتحق في منتصف الشهر نسبة الأيام المتبقية فقط',
],
[
'group' => 'enrollment',
'key' => 'enrollment.renewal_day',
'value' => '1',
'type' => 'integer',
'label_ar' => 'يوم التجديد الشهري',
'description_ar' => 'اليوم من كل شهر الذي يُعتبر موعد تجديد الاشتراك (1-28)',
],
];
foreach ($academies as $academy) {
foreach ($defaults as $setting) {
SystemSetting::firstOrCreate(
['academy_id' => $academy->id, 'key' => $setting['key']],
array_merge($setting, ['academy_id' => $academy->id]),
);
}
}
}
}
...@@ -22,14 +22,14 @@ ...@@ -22,14 +22,14 @@
@endif @endif
<form wire:submit="login"> <form wire:submit="login">
<!-- Email --> <!-- Identifier (email or phone) -->
<div class="mb-4"> <div class="mb-4">
<label for="email" class="block text-sm font-medium text-gray-700 mb-1">{{ __('البريد الإلكتروني') }}</label> <label for="identifier" class="block text-sm font-medium text-gray-700 mb-1">{{ __('البريد الإلكتروني أو رقم الهاتف') }}</label>
<input type="email" id="email" wire:model="email" <input type="text" id="identifier" wire:model="identifier"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:border-transparent text-sm sm:text-base @error('email') border-red-500 @enderror" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:border-transparent text-sm sm:text-base @error('identifier') border-red-500 @enderror"
style="--tw-ring-color: var(--brand-primary, #2563eb);" style="--tw-ring-color: var(--brand-primary, #2563eb);"
placeholder="admin@example.com" dir="ltr" required autofocus inputmode="email" autocomplete="email"> placeholder="{{ __('admin@example.com أو 01012345678') }}" dir="ltr" required autofocus autocomplete="username">
@error('email') @error('identifier')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p> <p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror @enderror
</div> </div>
......
...@@ -272,9 +272,16 @@ class="inline-flex items-center gap-2 px-6 py-3 min-h-16 bg-emerald-600 text-whi ...@@ -272,9 +272,16 @@ class="inline-flex items-center gap-2 px-6 py-3 min-h-16 bg-emerald-600 text-whi
<span class="font-medium text-gray-800 ms-1">{{ $program->activity?->name_ar }}</span> <span class="font-medium text-gray-800 ms-1">{{ $program->activity?->name_ar }}</span>
</div> </div>
@if($this->selectedProgramFee > 0) @if($this->selectedProgramFee > 0)
<div> @php $proration = $this->proratedProgramFee; @endphp
<div class="col-span-2">
<span class="text-gray-500">{{ __('الرسوم') }}:</span> <span class="text-gray-500">{{ __('الرسوم') }}:</span>
<span class="font-bold text-green-700 ms-1" dir="ltr">{{ number_format($this->selectedProgramFee / 100, 2) }} {{ __('ج.م') }}</span> @if($proration->applied)
<span class="line-through text-gray-400 ms-1" dir="ltr">{{ number_format($proration->originalAmount / 100, 2) }} {{ __('ج.م') }}</span>
<span class="font-bold text-green-700 ms-2" dir="ltr">{{ number_format($proration->proratedAmount / 100, 2) }} {{ __('ج.م') }}</span>
<span class="text-xs text-blue-600 ms-1">({{ $proration->description }})</span>
@else
<span class="font-bold text-green-700 ms-1" dir="ltr">{{ number_format($proration->proratedAmount / 100, 2) }} {{ __('ج.م') }}</span>
@endif
</div> </div>
@endif @endif
@endif @endif
...@@ -284,6 +291,7 @@ class="inline-flex items-center gap-2 px-6 py-3 min-h-16 bg-emerald-600 text-whi ...@@ -284,6 +291,7 @@ class="inline-flex items-center gap-2 px-6 py-3 min-h-16 bg-emerald-600 text-whi
{{-- Payment Option --}} {{-- Payment Option --}}
@if($program && $this->selectedProgramFee > 0) @if($program && $this->selectedProgramFee > 0)
@php $proration = $this->proratedProgramFee; @endphp
<div class="border-t border-gray-200 pt-6"> <div class="border-t border-gray-200 pt-6">
<div class="flex items-center gap-4 mb-4"> <div class="flex items-center gap-4 mb-4">
<label class="relative cursor-pointer" dir="ltr"> <label class="relative cursor-pointer" dir="ltr">
......
<div> <div>
{{-- Header — compact on mobile --}} {{-- Header --}}
<div class="flex items-center justify-between mb-4 sm:mb-6 print:hidden"> <div class="flex items-center justify-between mb-4 sm:mb-6 print:hidden">
<div class="min-w-0"> <div class="min-w-0">
<h1 class="text-lg sm:text-2xl font-bold text-gray-800 truncate">{{ __('تسجيل جديد') }}</h1> <h1 class="text-lg sm:text-2xl font-bold text-gray-800 truncate">{{ __('تسجيل جديد') }}</h1>
...@@ -22,7 +22,7 @@ class="inline-flex items-center justify-center w-10 h-10 sm:w-auto sm:h-auto sm: ...@@ -22,7 +22,7 @@ class="inline-flex items-center justify-center w-10 h-10 sm:w-auto sm:h-auto sm:
</div> </div>
@endif @endif
{{-- System Pre-flight Errors — Block Wizard --}} {{-- System Pre-flight Errors --}}
@if(!empty($systemErrors)) @if(!empty($systemErrors))
<div class="bg-white rounded-xl shadow-sm border border-red-300 p-8 text-center"> <div class="bg-white rounded-xl shadow-sm border border-red-300 p-8 text-center">
<div class="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div class="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4">
...@@ -31,7 +31,6 @@ class="inline-flex items-center justify-center w-10 h-10 sm:w-auto sm:h-auto sm: ...@@ -31,7 +31,6 @@ class="inline-flex items-center justify-center w-10 h-10 sm:w-auto sm:h-auto sm:
</svg> </svg>
</div> </div>
<h2 class="text-xl font-bold text-gray-800 mb-2">{{ __('لا يمكن بدء التسجيل') }}</h2> <h2 class="text-xl font-bold text-gray-800 mb-2">{{ __('لا يمكن بدء التسجيل') }}</h2>
<p class="text-gray-500 text-sm mb-6">{{ __('يجب إصلاح المشاكل التالية قبل استخدام معالج التسجيل:') }}</p>
<ul class="text-start text-sm space-y-3 max-w-md mx-auto"> <ul class="text-start text-sm space-y-3 max-w-md mx-auto">
@foreach($systemErrors as $error) @foreach($systemErrors as $error)
<li class="flex items-start gap-3 p-3 bg-red-50 rounded-lg border border-red-100"> <li class="flex items-start gap-3 p-3 bg-red-50 rounded-lg border border-red-100">
...@@ -55,9 +54,9 @@ class="inline-flex items-center gap-2 px-6 py-3 bg-gray-100 text-gray-700 rounde ...@@ -55,9 +54,9 @@ class="inline-flex items-center gap-2 px-6 py-3 bg-gray-100 text-gray-700 rounde
@if($currentStep < 7) @if($currentStep < 7)
@php @php
$steps = [ $steps = [
1 => 'بيانات ولي الأمر', 1 => 'بيانات اللاعب',
2 => 'حساب ولي الأمر', 2 => 'بيانات ولي الأمر',
3 => 'بيانات المشترك', 3 => 'حساب ولي الأمر',
4 => 'اختيار البرنامج', 4 => 'اختيار البرنامج',
5 => 'مراجعة وتأكيد', 5 => 'مراجعة وتأكيد',
6 => 'الدفع', 6 => 'الدفع',
...@@ -113,17 +112,205 @@ class="flex items-center gap-2 {{ $num < $currentStep ? 'cursor-pointer' : 'curs ...@@ -113,17 +112,205 @@ class="flex items-center gap-2 {{ $num < $currentStep ? 'cursor-pointer' : 'curs
{{-- Step Content --}} {{-- Step Content --}}
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 sm:p-6 pb-28 sm:pb-6"> <div class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 sm:p-6 pb-28 sm:pb-6">
{{-- Step 1: Guardian Info --}}
{{-- ===================== STEP 1: PLAYER DATA ===================== --}}
@if($currentStep === 1) @if($currentStep === 1)
<div> <div>
<h2 class="text-lg font-semibold text-gray-800 mb-4">{{ __('بيانات ولي الأمر') }}</h2> <h2 class="text-lg font-semibold text-gray-800 mb-1">{{ __('بيانات اللاعب') }}</h2>
<p class="text-sm text-gray-500 mb-5">{{ __('أدخل الرقم القومي لملء البيانات تلقائياً') }}</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-5">
{{-- Name (Arabic) --}}
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الاسم بالعربية') }} <span class="text-red-500">*</span></label>
<input type="text" wire:model.live.debounce.400ms="participant_name_ar"
class="w-full px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="{{ __('الاسم رباعي') }}">
@error('participant_name_ar') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- NID + Foreign toggle --}}
<div class="sm:col-span-2">
<div class="flex items-center justify-between mb-1">
<label class="block text-sm font-medium text-gray-700">{{ __('الرقم القومي') }}</label>
{{-- Foreign toggle --}}
<label class="flex items-center gap-2 cursor-pointer select-none">
<span class="text-xs text-gray-500">{{ __('أجنبي') }}</span>
<div class="relative" dir="ltr">
<input type="checkbox" wire:model.live="participant_is_foreign" class="peer sr-only">
<div class="w-10 h-6 rounded-full bg-gray-300 peer-checked:bg-amber-500 transition-colors
after:content-[''] after:absolute after:top-1 after:left-1 after:w-4 after:h-4
after:bg-white after:rounded-full after:transition-all peer-checked:after:translate-x-4"></div>
</div>
</label>
</div>
<div class="relative">
<input type="text" wire:model.live="participant_national_id" dir="ltr"
class="w-full px-4 py-3 min-h-[52px] border rounded-lg focus:ring-2 focus:border-blue-500 text-lg font-mono
{{ $participant_nid_decoded ? 'border-green-400 bg-green-50 focus:ring-green-400' : 'border-gray-300 focus:ring-blue-500' }}
{{ $participant_is_foreign ? 'opacity-60' : '' }}"
placeholder="{{ $participant_is_foreign ? __('رقم جواز السفر (اختياري)') : '00000000000000' }}"
maxlength="{{ $participant_is_foreign ? '30' : '14' }}">
@if($participant_nid_decoded)
<div class="absolute inset-y-0 end-3 flex items-center pointer-events-none">
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
</div>
@endif
</div>
@if($participant_nid_decoded)
<p class="mt-1 text-xs text-green-600 flex items-center gap-1">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
{{ __('تم استخراج البيانات من الرقم القومي') }}
</p>
@endif
@error('participant_national_id') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- Date of Birth (locked when NID decoded) --}}
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
{{ __('تاريخ الميلاد') }} <span class="text-red-500">*</span>
@if($participant_nid_decoded)
<span class="inline-flex items-center gap-1 text-xs text-green-600 ms-1 font-normal">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/></svg>
{{ __('مقفل') }}
</span>
@endif
</label>
<input type="date" wire:model="participant_date_of_birth" dir="ltr"
@if($participant_nid_decoded) readonly @endif
class="w-full px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg
{{ $participant_nid_decoded ? 'bg-gray-50 text-gray-500 cursor-not-allowed' : '' }}">
@error('participant_date_of_birth') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- Gender (locked when NID decoded) --}}
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
{{ __('الجنس') }} <span class="text-red-500">*</span>
@if($participant_nid_decoded)
<span class="inline-flex items-center gap-1 text-xs text-green-600 ms-1 font-normal">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/></svg>
{{ __('مقفل') }}
</span>
@endif
</label>
<div class="grid grid-cols-2 gap-3 {{ $participant_nid_decoded ? 'pointer-events-none opacity-70' : '' }}">
<label class="relative cursor-pointer">
<input type="radio" wire:model="participant_gender" value="male" class="peer sr-only" @if($participant_nid_decoded) disabled @endif>
<div class="px-4 py-3 min-h-[52px] flex items-center justify-center border border-gray-300 rounded-lg text-center text-base font-medium transition-all
peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700 hover:border-gray-400">
{{ __('ذكر') }}
</div>
</label>
<label class="relative cursor-pointer">
<input type="radio" wire:model="participant_gender" value="female" class="peer sr-only" @if($participant_nid_decoded) disabled @endif>
<div class="px-4 py-3 min-h-[52px] flex items-center justify-center border border-gray-300 rounded-lg text-center text-base font-medium transition-all
peer-checked:border-pink-500 peer-checked:bg-pink-50 peer-checked:text-pink-700 hover:border-gray-400">
{{ __('أنثى') }}
</div>
</label>
</div>
@error('participant_gender') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- Governorate (locked when NID decoded) --}}
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
{{ __('المحافظة') }}
@if($participant_nid_decoded)
<span class="inline-flex items-center gap-1 text-xs text-green-600 ms-1 font-normal">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/></svg>
{{ __('مقفل') }}
</span>
@endif
</label>
<input type="text" wire:model="participant_governorate"
@if($participant_nid_decoded) readonly @endif
class="w-full px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg
{{ $participant_nid_decoded ? 'bg-gray-50 text-gray-500 cursor-not-allowed' : '' }}"
placeholder="{{ __('المحافظة') }}">
</div>
{{-- Phone (optional) --}}
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('رقم الهاتف (اختياري)') }}</label>
<input type="tel" wire:model="participant_phone" dir="ltr"
class="w-full px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="01xxxxxxxxx">
@error('participant_phone') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- Membership Type --}}
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('نوع العضوية') }} <span class="text-red-500">*</span></label>
<div class="grid grid-cols-2 gap-3">
<label class="relative cursor-pointer">
<input type="radio" wire:model.live="membership_type" value="non_member" class="peer sr-only">
<div class="px-4 py-3 min-h-[52px] flex items-center justify-center border border-gray-300 rounded-lg text-center text-base font-medium transition-all
peer-checked:border-amber-500 peer-checked:bg-amber-50 peer-checked:text-amber-700 hover:border-gray-400">
{{ __('غير عضو') }}
</div>
</label>
<label class="relative cursor-pointer">
<input type="radio" wire:model.live="membership_type" value="member" class="peer sr-only">
<div class="px-4 py-3 min-h-[52px] flex items-center justify-center border border-gray-300 rounded-lg text-center text-base font-medium transition-all
peer-checked:border-green-500 peer-checked:bg-green-50 peer-checked:text-green-700 hover:border-gray-400">
{{ __('عضو نادي') }}
</div>
</label>
</div>
@error('membership_type') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
@if($membership_type === 'member')
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('رقم عضوية النادي') }} <span class="text-red-500">*</span></label>
<input type="text" wire:model="membership_id" dir="ltr"
class="w-full px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500 text-lg"
placeholder="{{ __('أدخل رقم العضوية') }}">
@error('membership_id') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
@endif
{{-- Medical notes --}}
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('ملاحظات طبية (اختياري)') }}</label>
<textarea wire:model="participant_medical_notes" rows="2"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
placeholder="{{ __('حساسية، أدوية، إصابات سابقة...') }}"></textarea>
@error('participant_medical_notes') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
</div>
<div class="fixed bottom-0 start-0 end-0 bg-white border-t border-gray-200 p-4 safe-bottom sm:static sm:border-0 sm:p-0 sm:mt-8 flex justify-end z-30">
<button wire:click="nextStep" wire:loading.attr="disabled"
class="w-full sm:w-auto inline-flex items-center justify-center gap-2 px-6 py-3.5 sm:py-3 bg-blue-600 text-white rounded-xl sm:rounded-lg hover:bg-blue-700 text-base font-medium transition-colors disabled:opacity-50">
<span wire:loading.remove wire:target="nextStep">{{ __('التالي') }}</span>
<span wire:loading wire:target="nextStep">{{ __('جارٍ...') }}</span>
<svg class="w-5 h-5 rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
</svg>
</button>
</div>
</div>
@endif
{{-- ===================== STEP 2: GUARDIAN ===================== --}}
@if($currentStep === 2)
<div>
<h2 class="text-lg font-semibold text-gray-800 mb-1">{{ __('بيانات ولي الأمر') }}</h2>
<p class="text-sm text-gray-500 mb-5">{{ __('الهاتف هو وسيلة التواصل الرئيسية') }}</p>
{{-- Toggle: search existing or new --}} {{-- Toggle: search existing or new --}}
@if(!$guardianSelected) @if(!$guardianSelected)
<div class="flex gap-3 mb-6"> <div class="flex gap-3 mb-6">
<button wire:click="$set('searchExistingGuardian', false)" type="button" <button wire:click="$set('searchExistingGuardian', false)" type="button"
class="flex-1 px-4 py-3 text-sm font-medium rounded-lg border transition-colors {{ !$searchExistingGuardian ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-300 text-gray-600 hover:border-gray-400' }}"> class="flex-1 px-4 py-3 text-sm font-medium rounded-lg border transition-colors {{ !$searchExistingGuardian ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-300 text-gray-600 hover:border-gray-400' }}">
{{ __('تسجيل ولي أمر جديد') }} {{ __('ولي أمر جديد') }}
</button> </button>
<button wire:click="$set('searchExistingGuardian', true)" type="button" <button wire:click="$set('searchExistingGuardian', true)" type="button"
class="flex-1 px-4 py-3 text-sm font-medium rounded-lg border transition-colors {{ $searchExistingGuardian ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-300 text-gray-600 hover:border-gray-400' }}"> class="flex-1 px-4 py-3 text-sm font-medium rounded-lg border transition-colors {{ $searchExistingGuardian ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-300 text-gray-600 hover:border-gray-400' }}">
...@@ -137,8 +324,7 @@ class="flex-1 px-4 py-3 text-sm font-medium rounded-lg border transition-colors ...@@ -137,8 +324,7 @@ class="flex-1 px-4 py-3 text-sm font-medium rounded-lg border transition-colors
<div class="mb-6"> <div class="mb-6">
<input type="text" wire:model.live.debounce.300ms="guardianSearchQuery" <input type="text" wire:model.live.debounce.300ms="guardianSearchQuery"
placeholder="{{ __('ابحث بالاسم أو رقم الهاتف...') }}" placeholder="{{ __('ابحث بالاسم أو رقم الهاتف...') }}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"> class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 text-lg">
@if(!empty($guardianSearchResults)) @if(!empty($guardianSearchResults))
<div class="mt-3 space-y-2 max-h-60 overflow-y-auto"> <div class="mt-3 space-y-2 max-h-60 overflow-y-auto">
@foreach($guardianSearchResults as $result) @foreach($guardianSearchResults as $result)
...@@ -149,7 +335,7 @@ class="w-full flex items-center justify-between p-3 bg-gray-50 rounded-lg border ...@@ -149,7 +335,7 @@ class="w-full flex items-center justify-between p-3 bg-gray-50 rounded-lg border
<div class="flex items-center gap-3 text-sm text-gray-500 mt-0.5"> <div class="flex items-center gap-3 text-sm text-gray-500 mt-0.5">
<span dir="ltr">{{ $result['phone'] }}</span> <span dir="ltr">{{ $result['phone'] }}</span>
@if($result['children_count'] > 0) @if($result['children_count'] > 0)
<span class="px-2 py-0.5 bg-blue-100 text-blue-700 rounded text-xs">{{ $result['children_count'] }} {{ __('أبناء مسجلين') }}</span> <span class="px-2 py-0.5 bg-blue-100 text-blue-700 rounded text-xs">{{ $result['children_count'] }} {{ __('أبناء') }}</span>
@endif @endif
</div> </div>
</div> </div>
...@@ -165,8 +351,7 @@ class="w-full flex items-center justify-between p-3 bg-gray-50 rounded-lg border ...@@ -165,8 +351,7 @@ class="w-full flex items-center justify-between p-3 bg-gray-50 rounded-lg border
{{-- Selected guardian display --}} {{-- Selected guardian display --}}
@if($guardianSelected) @if($guardianSelected)
<div class="mb-6 p-4 bg-green-50 border border-green-200 rounded-xl"> <div class="mb-6 p-4 bg-green-50 border border-green-200 rounded-xl flex items-center justify-between">
<div class="flex items-center justify-between">
<div> <div>
<p class="font-semibold text-green-800">{{ $guardian_name_ar }}</p> <p class="font-semibold text-green-800">{{ $guardian_name_ar }}</p>
<p class="text-sm text-green-600" dir="ltr">{{ $guardian_phone }}</p> <p class="text-sm text-green-600" dir="ltr">{{ $guardian_phone }}</p>
...@@ -175,52 +360,44 @@ class="w-full flex items-center justify-between p-3 bg-gray-50 rounded-lg border ...@@ -175,52 +360,44 @@ class="w-full flex items-center justify-between p-3 bg-gray-50 rounded-lg border
{{ __('تغيير') }} {{ __('تغيير') }}
</button> </button>
</div> </div>
</div>
@endif @endif
{{-- Guardian form (new or show data) --}} {{-- Guardian form --}}
@if(!$searchExistingGuardian || $guardianSelected) @if(!$searchExistingGuardian || $guardianSelected)
<div class="grid grid-cols-1 sm:grid-cols-2 gap-5 {{ $guardianSelected ? 'opacity-60 pointer-events-none' : '' }}"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-5 {{ $guardianSelected ? 'opacity-60 pointer-events-none' : '' }}">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الاسم بالعربية') }} <span class="text-red-500">*</span></label> {{-- Name (auto-filled hint) --}}
<div class="sm:col-span-2">
<div class="flex items-center justify-between mb-1">
<label class="block text-sm font-medium text-gray-700">{{ __('اسم ولي الأمر') }} <span class="text-red-500">*</span></label>
@if($guardian_name_ar && $participant_name_ar)
<span class="text-xs text-blue-500">{{ __('مأخوذ من اسم اللاعب — يمكنك التعديل') }}</span>
@endif
</div>
<input type="text" wire:model="guardian_name_ar" <input type="text" wire:model="guardian_name_ar"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg" class="w-full px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="{{ __('اسم ولي الأمر') }}"> placeholder="{{ __('اسم ولي الأمر') }}">
@error('guardian_name_ar') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror @error('guardian_name_ar') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div> </div>
<div> {{-- Phone (required) --}}
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الاسم بالإنجليزية') }}</label>
<input type="text" wire:model="guardian_name" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="Guardian name">
</div>
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('رقم الهاتف') }} <span class="text-red-500">*</span></label> <label class="block text-sm font-medium text-gray-700 mb-1">{{ __('رقم الهاتف') }} <span class="text-red-500">*</span></label>
<input type="tel" wire:model="guardian_phone" dir="ltr" <input type="tel" wire:model="guardian_phone" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg" class="w-full px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="01xxxxxxxxx"> placeholder="01xxxxxxxxx">
@error('guardian_phone') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror @error('guardian_phone') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div> </div>
{{-- Relation --}}
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الرقم القومي') }}</label>
<input type="text" wire:model="guardian_national_id" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="00000000000000" maxlength="14">
@error('guardian_national_id') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('صلة القرابة') }} <span class="text-red-500">*</span></label> <label class="block text-sm font-medium text-gray-700 mb-1">{{ __('صلة القرابة') }} <span class="text-red-500">*</span></label>
<div class="grid grid-cols-3 sm:grid-cols-5 gap-3"> <div class="grid grid-cols-3 sm:grid-cols-5 gap-2">
@foreach($relationOptions as $value => $label) @foreach($relationOptions as $value => $label)
<label class="relative cursor-pointer"> <label class="relative cursor-pointer">
<input type="radio" wire:model="guardian_relation" value="{{ $value }}" class="peer sr-only"> <input type="radio" wire:model="guardian_relation" value="{{ $value }}" class="peer sr-only">
<div class="px-4 py-3 min-h-16 flex items-center justify-center border border-gray-300 rounded-lg text-center text-sm font-medium transition-all <div class="px-2 py-2.5 flex items-center justify-center border border-gray-300 rounded-lg text-center text-sm font-medium transition-all
peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700 peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700 hover:border-gray-400">
hover:border-gray-400">
{{ __($label) }} {{ __($label) }}
</div> </div>
</label> </label>
...@@ -240,10 +417,9 @@ class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 ...@@ -240,10 +417,9 @@ class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2
</svg> </svg>
<div> <div>
<h3 class="text-base font-bold text-amber-800">{{ __('تنبيه: تم العثور على سجلات مشابهة') }}</h3> <h3 class="text-base font-bold text-amber-800">{{ __('تنبيه: تم العثور على سجلات مشابهة') }}</h3>
<p class="text-sm text-amber-700 mt-1">{{ __('قد يكون ولي الأمر مسجلاً بالفعل. يرجى التحقق من السجلات التالية:') }}</p> <p class="text-sm text-amber-700 mt-1">{{ __('قد يكون ولي الأمر مسجلاً بالفعل:') }}</p>
</div> </div>
</div> </div>
<div class="space-y-3"> <div class="space-y-3">
@foreach($potentialDuplicates as $duplicate) @foreach($potentialDuplicates as $duplicate)
<div class="flex items-center justify-between p-3 bg-white rounded-lg border border-amber-200"> <div class="flex items-center justify-between p-3 bg-white rounded-lg border border-amber-200">
...@@ -254,35 +430,37 @@ class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 ...@@ -254,35 +430,37 @@ class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2
<span dir="ltr">{{ $duplicate['phone'] }}</span> <span dir="ltr">{{ $duplicate['phone'] }}</span>
@endif @endif
@if($duplicate['has_participant']) @if($duplicate['has_participant'])
<span class="inline-flex items-center gap-1 px-2 py-0.5 bg-blue-100 text-blue-700 rounded text-xs font-medium"> <span class="px-2 py-0.5 bg-blue-100 text-blue-700 rounded text-xs font-medium">{{ $duplicate['participant_number'] }}</span>
{{ __('مشترك') }}: {{ $duplicate['participant_number'] }}
</span>
@endif @endif
<span class="inline-flex items-center gap-1 px-2 py-0.5 bg-gray-100 text-gray-600 rounded text-xs"> <span class="px-2 py-0.5 bg-gray-100 text-gray-600 rounded text-xs">{{ $duplicate['confidence'] }}%</span>
{{ __('تطابق') }}: {{ $duplicate['confidence'] }}%
</span>
</div> </div>
</div> </div>
<button wire:click="useExistingPerson({{ $duplicate['person_id'] }})" <button wire:click="useExistingPerson({{ $duplicate['person_id'] }})"
class="px-4 py-2 text-sm font-medium text-blue-700 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 transition-colors whitespace-nowrap"> class="px-4 py-2 text-sm font-medium text-blue-700 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 transition-colors whitespace-nowrap">
{{ __('استخدام هذا السجل') }} {{ __('استخدام') }}
</button> </button>
</div> </div>
@endforeach @endforeach
</div> </div>
<div class="mt-4 flex justify-end"> <div class="mt-4 flex justify-end">
<button wire:click="proceedDespiteDuplicates" <button wire:click="proceedDespiteDuplicates"
class="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-amber-700 bg-amber-100 border border-amber-300 rounded-lg hover:bg-amber-200 transition-colors"> class="px-4 py-2 text-sm font-medium text-amber-700 bg-amber-100 border border-amber-300 rounded-lg hover:bg-amber-200 transition-colors">
{{ __('تجاهل والمتابعة كتسجيل جديد') }} {{ __('تجاهل والمتابعة كجديد') }}
</button> </button>
</div> </div>
</div> </div>
@endif @endif
<div class="fixed bottom-0 start-0 end-0 bg-white border-t border-gray-200 p-4 safe-bottom sm:static sm:border-0 sm:p-0 sm:mt-8 flex justify-end z-30"> <div class="fixed bottom-0 start-0 end-0 bg-white border-t border-gray-200 p-4 safe-bottom sm:static sm:border-0 sm:p-0 sm:mt-8 flex justify-between gap-3 z-30">
<button wire:click="previousStep"
class="inline-flex items-center justify-center gap-2 px-5 py-3.5 sm:py-3 text-gray-600 bg-gray-100 rounded-xl sm:rounded-lg hover:bg-gray-200 text-base font-medium transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
</svg>
{{ __('السابق') }}
</button>
<button wire:click="nextStep" wire:loading.attr="disabled" <button wire:click="nextStep" wire:loading.attr="disabled"
class="w-full sm:w-auto inline-flex items-center justify-center gap-2 px-6 py-3.5 sm:py-3 bg-blue-600 text-white rounded-xl sm:rounded-lg hover:bg-blue-700 text-base font-medium transition-colors disabled:opacity-50"> class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py-3.5 sm:py-3 bg-blue-600 text-white rounded-xl sm:rounded-lg hover:bg-blue-700 text-base font-medium transition-colors disabled:opacity-50">
<span wire:loading.remove wire:target="nextStep">{{ __('التالي') }}</span> <span wire:loading.remove wire:target="nextStep">{{ __('التالي') }}</span>
<span wire:loading wire:target="nextStep">{{ __('جارٍ...') }}</span> <span wire:loading wire:target="nextStep">{{ __('جارٍ...') }}</span>
<svg class="w-5 h-5 rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5 rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24">
...@@ -293,215 +471,55 @@ class="w-full sm:w-auto inline-flex items-center justify-center gap-2 px-6 py-3. ...@@ -293,215 +471,55 @@ class="w-full sm:w-auto inline-flex items-center justify-center gap-2 px-6 py-3.
</div> </div>
@endif @endif
{{-- Step 2: Parent Account --}} {{-- ===================== STEP 3: PARENT ACCOUNT ===================== --}}
@if($currentStep === 2) @if($currentStep === 3)
<div> <div>
<h2 class="text-lg font-semibold text-gray-800 mb-2">{{ __('حساب ولي الأمر') }}</h2> <h2 class="text-lg font-semibold text-gray-800 mb-2">{{ __('حساب ولي الأمر') }}</h2>
<p class="text-sm text-gray-500 mb-6">{{ __('إنشاء حساب لولي الأمر لمتابعة ابنه') }}</p> <p class="text-sm text-gray-500 mb-6">{{ __('إنشاء حساب لمتابعة الاشتراك والحضور') }}</p>
{{-- Toggle: Enable Parent Portal --}}
<div class="flex items-center gap-4 mb-6 p-4 bg-blue-50 border border-blue-200 rounded-xl"> <div class="flex items-center gap-4 mb-6 p-4 bg-blue-50 border border-blue-200 rounded-xl">
<label class="relative cursor-pointer shrink-0" dir="ltr"> <label class="relative cursor-pointer shrink-0" dir="ltr">
<input type="checkbox" wire:model.live="createParentAccount" class="peer sr-only"> <input type="checkbox" wire:model.live="createParentAccount" class="peer sr-only">
<div class="w-14 h-8 rounded-full bg-gray-300 peer-checked:bg-blue-600 transition-colors after:content-[''] after:absolute after:top-1 after:left-1 after:w-6 after:h-6 after:bg-white after:rounded-full after:transition-all peer-checked:after:translate-x-6"></div> <div class="w-14 h-8 rounded-full bg-gray-300 peer-checked:bg-blue-600 transition-colors after:content-[''] after:absolute after:top-1 after:left-1 after:w-6 after:h-6 after:bg-white after:rounded-full after:transition-all peer-checked:after:translate-x-6"></div>
</label> </label>
<div> <div>
<span class="text-base font-medium text-gray-800">{{ __('تفعيل الوصول لبوابة أولياء الأمور') }}</span> <span class="text-base font-medium text-gray-800">{{ __('تفعيل بوابة أولياء الأمور') }}</span>
<p class="text-xs text-gray-500 mt-0.5">{{ __('سيتمكن ولي الأمر من متابعة الحضور والتقييمات والمصروفات') }}</p> <p class="text-xs text-gray-500 mt-0.5">{{ __('يمكنك إنشاؤه لاحقاً إذا لم يكن هناك بريد إلكتروني الآن') }}</p>
</div> </div>
</div> </div>
@if($createParentAccount) @if($createParentAccount)
<div class="space-y-5"> <div class="space-y-5">
{{-- Email --}}
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('البريد الإلكتروني') }} <span class="text-red-500">*</span></label> <label class="block text-sm font-medium text-gray-700 mb-1">{{ __('البريد الإلكتروني') }} <span class="text-red-500">*</span></label>
<input type="email" wire:model="parentEmail" dir="ltr" <input type="email" wire:model="parentEmail" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg" class="w-full px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="parent@example.com"> placeholder="parent@example.com">
@error('parentEmail') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror @error('parentEmail') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div> </div>
{{-- Password --}}
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('كلمة المرور') }} <span class="text-red-500">*</span></label> <label class="block text-sm font-medium text-gray-700 mb-1">{{ __('كلمة المرور') }} <span class="text-red-500">*</span></label>
<div class="flex gap-3"> <div class="flex gap-3">
<input type="text" wire:model="parentPassword" dir="ltr" <input type="text" wire:model="parentPassword" dir="ltr"
class="flex-1 px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg font-mono" class="flex-1 px-4 py-3 min-h-[52px] border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg font-mono"
placeholder="{{ __('كلمة المرور') }}"> placeholder="{{ __('كلمة المرور') }}">
<button type="button" wire:click="generateParentPassword" <button type="button" wire:click="generateParentPassword"
class="inline-flex items-center gap-2 px-4 py-3 bg-gray-100 text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-200 transition-colors whitespace-nowrap text-sm font-medium"> class="inline-flex items-center gap-2 px-4 py-3 bg-gray-100 text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-200 transition-colors whitespace-nowrap text-sm font-medium">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg> </svg>
{{ __('توليد عشوائي') }} {{ __('توليد') }}
</button> </button>
</div> </div>
@error('parentPassword') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror @error('parentPassword') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div> </div>
{{-- Send credentials checkbox --}}
<label class="flex items-center gap-3 p-4 bg-gray-50 border border-gray-200 rounded-xl cursor-pointer hover:bg-gray-100 transition-colors">
<input type="checkbox" wire:model="sendParentCredentials"
class="w-5 h-5 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
<div>
<span class="text-sm font-medium text-gray-700">{{ __('إرسال بيانات الدخول بالبريد الإلكتروني') }}</span>
<p class="text-xs text-gray-500 mt-0.5">{{ __('سيتم إرسال البريد وكلمة المرور للعنوان المحدد') }}</p>
</div>
</label>
{{-- Info note --}}
<div class="p-3 bg-green-50 border border-green-200 rounded-lg">
<div class="flex items-start gap-2">
<svg class="w-5 h-5 text-green-600 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<p class="text-sm text-green-700">{{ __('سيتمكن ولي الأمر من متابعة الحضور والتقييمات والمصروفات من بوابة أولياء الأمور') }}</p>
</div>
</div>
</div> </div>
@else @else
{{-- Toggle OFF note --}} <div class="p-4 bg-amber-50 border border-amber-200 rounded-xl text-sm text-amber-700">
<div class="p-4 bg-amber-50 border border-amber-200 rounded-xl"> {{ __('يمكنك إنشاء الحساب لاحقاً من إدارة المستخدمين') }}
<div class="flex items-start gap-3">
<svg class="w-5 h-5 text-amber-600 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<p class="text-sm text-amber-700">{{ __('يمكنك إنشاء الحساب لاحقاً من إدارة المستخدمين') }}</p>
</div>
</div>
@endif
<div class="fixed bottom-0 start-0 end-0 bg-white border-t border-gray-200 p-4 safe-bottom sm:static sm:border-0 sm:p-0 sm:mt-8 flex justify-between gap-3 z-30">
<button wire:click="previousStep"
class="inline-flex items-center justify-center gap-2 px-5 py-3.5 sm:py-3 text-gray-600 bg-gray-100 rounded-xl sm:rounded-lg hover:bg-gray-200 text-base font-medium transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
</svg>
{{ __('السابق') }}
</button>
<button wire:click="nextStep" wire:loading.attr="disabled"
class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py-3.5 sm:py-3 bg-blue-600 text-white rounded-xl sm:rounded-lg hover:bg-blue-700 text-base font-medium transition-colors disabled:opacity-50">
<span wire:loading.remove wire:target="nextStep">{{ __('التالي') }}</span>
<span wire:loading wire:target="nextStep">{{ __('جارٍ...') }}</span>
<svg class="w-5 h-5 rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
</svg>
</button>
</div>
</div>
@endif
{{-- Step 3: Participant Info --}}
@if($currentStep === 3)
<div>
<h2 class="text-lg font-semibold text-gray-800 mb-6">{{ __('بيانات المشترك (اللاعب)') }}</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-5">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الاسم بالعربية') }} <span class="text-red-500">*</span></label>
<input type="text" wire:model="participant_name_ar"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="{{ __('اسم اللاعب / المشترك') }}">
@error('participant_name_ar') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الاسم بالإنجليزية') }}</label>
<input type="text" wire:model="participant_name" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="Player / participant name">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('تاريخ الميلاد') }} <span class="text-red-500">*</span></label>
<input type="date" wire:model="participant_date_of_birth" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg">
@error('participant_date_of_birth') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الجنس') }} <span class="text-red-500">*</span></label>
<div class="grid grid-cols-2 gap-3">
<label class="relative cursor-pointer">
<input type="radio" wire:model="participant_gender" value="male" class="peer sr-only">
<div class="px-4 py-3 min-h-16 flex items-center justify-center border border-gray-300 rounded-lg text-center text-base font-medium transition-all
peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700
hover:border-gray-400">
{{ __('ذكر') }}
</div>
</label>
<label class="relative cursor-pointer">
<input type="radio" wire:model="participant_gender" value="female" class="peer sr-only">
<div class="px-4 py-3 min-h-16 flex items-center justify-center border border-gray-300 rounded-lg text-center text-base font-medium transition-all
peer-checked:border-pink-500 peer-checked:bg-pink-50 peer-checked:text-pink-700
hover:border-gray-400">
{{ __('أنثى') }}
</div>
</label>
</div>
@error('participant_gender') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('رقم هاتف المشترك') }}</label>
<input type="tel" wire:model="participant_phone" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="01xxxxxxxxx">
@error('participant_phone') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الرقم القومي للمشترك') }}</label>
<input type="text" wire:model="participant_national_id" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="00000000000000" maxlength="14">
@error('participant_national_id') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- Membership Type --}}
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('نوع العضوية') }} <span class="text-red-500">*</span></label>
<div class="grid grid-cols-2 gap-3">
<label class="relative cursor-pointer">
<input type="radio" wire:model.live="membership_type" value="non_member" class="peer sr-only">
<div class="px-4 py-3 min-h-16 flex items-center justify-center border border-gray-300 rounded-lg text-center text-base font-medium transition-all
peer-checked:border-amber-500 peer-checked:bg-amber-50 peer-checked:text-amber-700
hover:border-gray-400">
{{ __('غير عضو') }}
</div>
</label>
<label class="relative cursor-pointer">
<input type="radio" wire:model.live="membership_type" value="member" class="peer sr-only">
<div class="px-4 py-3 min-h-16 flex items-center justify-center border border-gray-300 rounded-lg text-center text-base font-medium transition-all
peer-checked:border-green-500 peer-checked:bg-green-50 peer-checked:text-green-700
hover:border-gray-400">
{{ __('عضو نادي') }}
</div>
</label>
</div>
@error('membership_type') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- Membership ID (only for members) --}}
@if($membership_type === 'member')
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('رقم عضوية النادي') }} <span class="text-red-500">*</span></label>
<input type="text" wire:model="membership_id" dir="ltr"
class="w-full px-4 py-3 min-h-16 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500 text-lg"
placeholder="{{ __('أدخل رقم العضوية') }}">
@error('membership_id') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div> </div>
@endif @endif
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('ملاحظات طبية') }}</label>
<textarea wire:model="participant_medical_notes" rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="{{ __('أي ملاحظات طبية مهمة (حساسية، أدوية، إصابات سابقة)') }}"></textarea>
@error('participant_medical_notes') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
</div>
<div class="fixed bottom-0 start-0 end-0 bg-white border-t border-gray-200 p-4 safe-bottom sm:static sm:border-0 sm:p-0 sm:mt-8 flex justify-between gap-3 z-30"> <div class="fixed bottom-0 start-0 end-0 bg-white border-t border-gray-200 p-4 safe-bottom sm:static sm:border-0 sm:p-0 sm:mt-8 flex justify-between gap-3 z-30">
<button wire:click="previousStep" <button wire:click="previousStep"
class="inline-flex items-center justify-center gap-2 px-5 py-3.5 sm:py-3 text-gray-600 bg-gray-100 rounded-xl sm:rounded-lg hover:bg-gray-200 text-base font-medium transition-colors"> class="inline-flex items-center justify-center gap-2 px-5 py-3.5 sm:py-3 text-gray-600 bg-gray-100 rounded-xl sm:rounded-lg hover:bg-gray-200 text-base font-medium transition-colors">
...@@ -522,22 +540,19 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py ...@@ -522,22 +540,19 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py
</div> </div>
@endif @endif
{{-- Step 4: Program Selection --}} {{-- ===================== STEP 4: PROGRAM SELECTION ===================== --}}
@if($currentStep === 4) @if($currentStep === 4)
<div> <div>
<h2 class="text-lg font-semibold text-gray-800 mb-6">{{ __('اختيار البرنامج') }}</h2> <h2 class="text-lg font-semibold text-gray-800 mb-6">{{ __('اختيار البرنامج') }}</h2>
{{-- Activity Selection --}}
<div class="mb-6"> <div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-3">{{ __('اختر النشاط') }}</label> <label class="block text-sm font-medium text-gray-700 mb-3">{{ __('اختر النشاط') }}</label>
{{-- Mobile: horizontal scrollable pills --}}
<div class="flex gap-2.5 overflow-x-auto pb-2 -mx-4 px-4 sm:mx-0 sm:px-0 sm:flex-wrap sm:overflow-visible scrollbar-hide"> <div class="flex gap-2.5 overflow-x-auto pb-2 -mx-4 px-4 sm:mx-0 sm:px-0 sm:flex-wrap sm:overflow-visible scrollbar-hide">
@foreach($activities as $activity) @foreach($activities as $activity)
<label class="relative cursor-pointer shrink-0 sm:shrink"> <label class="relative cursor-pointer shrink-0 sm:shrink">
<input type="radio" wire:model.live="selected_activity_id" value="{{ $activity->id }}" class="peer sr-only"> <input type="radio" wire:model.live="selected_activity_id" value="{{ $activity->id }}" class="peer sr-only">
<div class="px-5 py-3 sm:p-4 sm:min-h-16 flex items-center justify-center border border-gray-300 rounded-full sm:rounded-xl text-center font-medium transition-all whitespace-nowrap <div class="px-5 py-3 sm:p-4 sm:min-h-[52px] flex items-center justify-center border border-gray-300 rounded-full sm:rounded-xl text-center font-medium transition-all whitespace-nowrap
peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700 peer-checked:shadow-sm peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700 peer-checked:shadow-sm hover:border-gray-400">
hover:border-gray-400">
{{ $activity->name_ar }} {{ $activity->name_ar }}
</div> </div>
</label> </label>
...@@ -546,15 +561,11 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py ...@@ -546,15 +561,11 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py
@error('selected_activity_id') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror @error('selected_activity_id') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div> </div>
{{-- Program Selection --}}
@if($selected_activity_id) @if($selected_activity_id)
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-3">{{ __('اختر البرنامج') }}</label> <label class="block text-sm font-medium text-gray-700 mb-3">{{ __('اختر البرنامج') }}</label>
@if($programs->isEmpty()) @if($programs->isEmpty())
<div class="text-center py-8 text-gray-500"> <div class="text-center py-8 text-gray-500">
<svg class="w-12 h-12 mx-auto text-gray-300 mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
</svg>
<p>{{ __('لا يوجد برامج متاحة لهذا النشاط') }}</p> <p>{{ __('لا يوجد برامج متاحة لهذا النشاط') }}</p>
</div> </div>
@else @else
...@@ -562,15 +573,11 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py ...@@ -562,15 +573,11 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py
@foreach($programs as $program) @foreach($programs as $program)
<label class="relative cursor-pointer"> <label class="relative cursor-pointer">
<input type="radio" wire:model="selected_program_id" value="{{ $program->id }}" class="peer sr-only"> <input type="radio" wire:model="selected_program_id" value="{{ $program->id }}" class="peer sr-only">
<div class="p-5 min-h-16 border border-gray-300 rounded-xl transition-all <div class="p-5 border border-gray-300 rounded-xl transition-all
peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:shadow-sm peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:shadow-sm hover:border-gray-400">
hover:border-gray-400">
<h4 class="font-bold text-gray-800">{{ $program->name_ar }}</h4> <h4 class="font-bold text-gray-800">{{ $program->name_ar }}</h4>
@if($program->name)
<p class="text-xs text-gray-500 mt-0.5" dir="ltr">{{ $program->name }}</p>
@endif
@if($program->description) @if($program->description)
<p class="text-sm text-gray-600 mt-2">{{ Str::limit($program->description, 80) }}</p> <p class="text-sm text-gray-600 mt-1">{{ Str::limit($program->description, 80) }}</p>
@endif @endif
</div> </div>
</label> </label>
...@@ -601,169 +608,95 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py ...@@ -601,169 +608,95 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py
</div> </div>
@endif @endif
{{-- Step 5: Review --}} {{-- ===================== STEP 5: REVIEW ===================== --}}
@if($currentStep === 5) @if($currentStep === 5)
<div> <div>
<h2 class="text-lg font-semibold text-gray-800 mb-6">{{ __('مراجعة وتأكيد') }}</h2> <h2 class="text-lg font-semibold text-gray-800 mb-6">{{ __('مراجعة وتأكيد') }}</h2>
<div class="space-y-4"> <div class="space-y-4">
{{-- Guardian Summary --}}
{{-- Player Summary --}}
<div class="p-4 bg-gray-50 rounded-xl border border-gray-200"> <div class="p-4 bg-gray-50 rounded-xl border border-gray-200">
<div class="flex items-center justify-between mb-3"> <div class="flex items-center justify-between mb-3">
<h3 class="font-semibold text-gray-700">{{ __('ولي الأمر') }}</h3> <h3 class="font-semibold text-gray-700">{{ __('اللاعب') }}</h3>
<button wire:click="goToStep(1)" class="text-sm text-blue-600 hover:text-blue-800">{{ __('تعديل') }}</button> <button wire:click="goToStep(1)" class="text-sm text-blue-600 hover:text-blue-800">{{ __('تعديل') }}</button>
</div> </div>
<div class="grid grid-cols-2 gap-3 text-sm"> <div class="grid grid-cols-2 gap-3 text-sm">
<div> <div><span class="text-gray-500">{{ __('الاسم') }}:</span> <span class="font-medium text-gray-800 ms-1">{{ $participant_name_ar }}</span></div>
<span class="text-gray-500">{{ __('الاسم') }}:</span> <div><span class="text-gray-500">{{ __('تاريخ الميلاد') }}:</span> <span class="font-medium text-gray-800 ms-1" dir="ltr">{{ $participant_date_of_birth }}</span></div>
<span class="font-medium text-gray-800 ms-1">{{ $guardian_name_ar }}</span> <div><span class="text-gray-500">{{ __('الجنس') }}:</span> <span class="font-medium text-gray-800 ms-1">{{ $participant_gender === 'male' ? __('ذكر') : __('أنثى') }}</span></div>
</div> @if($participant_governorate)
<div> <div><span class="text-gray-500">{{ __('المحافظة') }}:</span> <span class="font-medium text-gray-800 ms-1">{{ $participant_governorate }}</span></div>
<span class="text-gray-500">{{ __('الهاتف') }}:</span>
<span class="font-medium text-gray-800 ms-1" dir="ltr">{{ $guardian_phone }}</span>
</div>
<div>
<span class="text-gray-500">{{ __('صلة القرابة') }}:</span>
<span class="font-medium text-gray-800 ms-1">{{ __($relationOptions[$guardian_relation] ?? $guardian_relation) }}</span>
</div>
@if($guardian_national_id)
<div>
<span class="text-gray-500">{{ __('الرقم القومي') }}:</span>
<span class="font-medium text-gray-800 ms-1" dir="ltr">{{ $guardian_national_id }}</span>
</div>
@endif @endif
</div>
</div>
{{-- Parent Account Summary --}}
<div class="p-4 {{ $createParentAccount ? 'bg-blue-50 border-blue-200' : 'bg-gray-50 border-gray-200' }} rounded-xl border">
<div class="flex items-center justify-between mb-3">
<h3 class="font-semibold text-gray-700">{{ __('حساب ولي الأمر') }}</h3>
<button wire:click="goToStep(2)" class="text-sm text-blue-600 hover:text-blue-800">{{ __('تعديل') }}</button>
</div>
<div class="text-sm">
@if($createParentAccount)
<div class="grid grid-cols-2 gap-3">
<div>
<span class="text-gray-500">{{ __('البريد الإلكتروني') }}:</span>
<span class="font-medium text-gray-800 ms-1" dir="ltr">{{ $parentEmail }}</span>
</div>
<div> <div>
<span class="text-gray-500">{{ __('الحالة') }}:</span> <span class="text-gray-500">{{ __('العضوية') }}:</span>
<span class="inline-flex items-center gap-1 ms-1 px-2 py-0.5 bg-green-100 text-green-700 rounded text-xs font-medium"> <span class="font-medium ms-1 {{ $membership_type === 'member' ? 'text-green-700' : 'text-amber-700' }}">
{{ __('سيتم إنشاء الحساب') }} {{ $membership_type === 'member' ? __('عضو') : __('غير عضو') }}
</span> </span>
</div> </div>
@if($sendParentCredentials)
<div class="col-span-2">
<span class="text-gray-500">{{ __('الإرسال') }}:</span>
<span class="font-medium text-gray-800 ms-1">{{ __('سيتم إرسال بيانات الدخول بالبريد') }}</span>
</div>
@endif
</div>
@else
<p class="text-gray-500">{{ __('لن يتم إنشاء حساب — يمكن إنشاؤه لاحقاً') }}</p>
@endif
</div> </div>
</div> </div>
{{-- Participant Summary --}} {{-- Guardian Summary --}}
<div class="p-4 bg-gray-50 rounded-xl border border-gray-200"> <div class="p-4 bg-gray-50 rounded-xl border border-gray-200">
<div class="flex items-center justify-between mb-3"> <div class="flex items-center justify-between mb-3">
<h3 class="font-semibold text-gray-700">{{ __('المشترك (اللاعب)') }}</h3> <h3 class="font-semibold text-gray-700">{{ __('ولي الأمر') }}</h3>
<button wire:click="goToStep(3)" class="text-sm text-blue-600 hover:text-blue-800">{{ __('تعديل') }}</button> <button wire:click="goToStep(2)" class="text-sm text-blue-600 hover:text-blue-800">{{ __('تعديل') }}</button>
</div> </div>
<div class="grid grid-cols-2 gap-3 text-sm"> <div class="grid grid-cols-2 gap-3 text-sm">
<div> <div><span class="text-gray-500">{{ __('الاسم') }}:</span> <span class="font-medium text-gray-800 ms-1">{{ $guardian_name_ar }}</span></div>
<span class="text-gray-500">{{ __('الاسم') }}:</span> <div><span class="text-gray-500">{{ __('الهاتف') }}:</span> <span class="font-medium text-gray-800 ms-1" dir="ltr">{{ $guardian_phone }}</span></div>
<span class="font-medium text-gray-800 ms-1">{{ $participant_name_ar }}</span> <div><span class="text-gray-500">{{ __('الصلة') }}:</span> <span class="font-medium text-gray-800 ms-1">{{ __($relationOptions[$guardian_relation] ?? $guardian_relation) }}</span></div>
</div>
<div>
<span class="text-gray-500">{{ __('تاريخ الميلاد') }}:</span>
<span class="font-medium text-gray-800 ms-1" dir="ltr">{{ $participant_date_of_birth }}</span>
</div>
<div>
<span class="text-gray-500">{{ __('الجنس') }}:</span>
<span class="font-medium text-gray-800 ms-1">{{ $participant_gender === 'male' ? __('ذكر') : __('أنثى') }}</span>
</div>
@if($participant_phone)
<div>
<span class="text-gray-500">{{ __('الهاتف') }}:</span>
<span class="font-medium text-gray-800 ms-1" dir="ltr">{{ $participant_phone }}</span>
</div>
@endif
@if($participant_national_id)
<div>
<span class="text-gray-500">{{ __('الرقم القومي') }}:</span>
<span class="font-medium text-gray-800 ms-1" dir="ltr">{{ $participant_national_id }}</span>
</div>
@endif
<div>
<span class="text-gray-500">{{ __('العضوية') }}:</span>
<span class="font-medium ms-1 {{ $membership_type === 'member' ? 'text-green-700' : 'text-amber-700' }}">
{{ $membership_type === 'member' ? __('عضو نادي') : __('غير عضو') }}
</span>
@if($membership_type === 'member' && $membership_id)
<span class="text-gray-500 ms-1">({{ $membership_id }})</span>
@endif
</div>
@if($participant_medical_notes)
<div class="col-span-2">
<span class="text-gray-500">{{ __('ملاحظات طبية') }}:</span>
<span class="font-medium text-gray-800 ms-1">{{ $participant_medical_notes }}</span>
</div>
@endif
</div> </div>
</div> </div>
{{-- Program Summary --}} {{-- Program Summary + Fee --}}
<div class="p-4 bg-gray-50 rounded-xl border border-gray-200"> <div class="p-4 bg-gray-50 rounded-xl border border-gray-200">
<div class="flex items-center justify-between mb-3"> <div class="flex items-center justify-between mb-3">
<h3 class="font-semibold text-gray-700">{{ __('البرنامج') }}</h3> <h3 class="font-semibold text-gray-700">{{ __('البرنامج') }}</h3>
<button wire:click="goToStep(4)" class="text-sm text-blue-600 hover:text-blue-800">{{ __('تعديل') }}</button> <button wire:click="goToStep(4)" class="text-sm text-blue-600 hover:text-blue-800">{{ __('تعديل') }}</button>
</div> </div>
@if($this->selectedProgram) @if($this->selectedProgram)
<div class="text-sm"> <p class="text-sm font-medium text-gray-800">{{ $this->selectedProgram->name_ar }}</p>
<p class="font-medium text-gray-800">{{ $this->selectedProgram->name_ar }}</p>
@if($this->selectedProgram->activity) @if($this->selectedProgram->activity)
<p class="text-gray-500 mt-1">{{ __('النشاط') }}: {{ $this->selectedProgram->activity->name_ar }}</p> <p class="text-xs text-gray-500 mt-1">{{ $this->selectedProgram->activity->name_ar }}</p>
@endif @endif
@if($this->selectedProgramFee > 0) @if($this->selectedProgramFee > 0)
<div class="mt-3 space-y-1 text-sm"> <div class="mt-3 space-y-1 text-sm border-t border-gray-200 pt-3">
@if($this->proratedProgramFee->applied)
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-gray-500">{{ __('رسوم البرنامج') }}:</span> <span class="text-gray-500">{{ __('السعر الأصلي') }}:</span>
<span class="font-medium text-gray-800" dir="ltr">{{ number_format($this->selectedProgramFee / 100, 2) }} {{ __('ج.م') }}</span> <span class="text-gray-400 line-through" dir="ltr">{{ number_format($this->proratedProgramFee->originalAmount / 100, 2) }} {{ __('ج.م') }}</span>
</div> </div>
<div class="flex items-center justify-between">
<span class="text-blue-600 font-medium">{{ __('رسوم البرنامج') }} <span class="text-xs font-normal">({{ $this->proratedProgramFee->description }})</span>:</span>
<span class="font-medium text-blue-700" dir="ltr">{{ number_format($this->proratedProgramFee->proratedAmount / 100, 2) }} {{ __('ج.م') }}</span>
</div> </div>
@else @else
<p class="mt-2 text-gray-500">{{ __('بدون رسوم') }}</p> <div class="flex items-center justify-between">
<span class="text-gray-500">{{ __('رسوم البرنامج') }}:</span>
<span class="font-medium text-gray-800" dir="ltr">{{ number_format($this->selectedProgramFee / 100, 2) }} {{ __('ج.م') }}</span>
</div>
@endif @endif
</div> </div>
@endif @endif
@endif
</div> </div>
{{-- Hot-Buy: Quick product/kit sale --}} {{-- Hot-Buy: Quick product/kit sale --}}
<div class="p-4 bg-amber-50 rounded-xl border border-amber-200" x-data="{ showSearch: false }"> <div class="p-4 bg-amber-50 rounded-xl border border-amber-200" x-data="{ showSearch: false }">
<div class="flex items-center justify-between mb-3"> <div class="flex items-center justify-between mb-3">
<h3 class="font-semibold text-gray-700 flex items-center gap-2"> <h3 class="font-semibold text-gray-700">{{ __('بيع سريع (اختياري)') }}</h3>
<svg class="w-5 h-5 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"/>
</svg>
{{ __('بيع سريع (اختياري)') }}
</h3>
<button type="button" @click="showSearch = !showSearch" <button type="button" @click="showSearch = !showSearch"
class="text-sm text-amber-700 hover:text-amber-900 font-medium"> class="text-sm text-amber-700 hover:text-amber-900 font-medium">
<span x-show="!showSearch">{{ __('إضافة منتج') }}</span> <span x-show="!showSearch">{{ __('إضافة منتج') }}</span>
<span x-show="showSearch" x-cloak>{{ __('إغلاق') }}</span> <span x-show="showSearch" x-cloak>{{ __('إغلاق') }}</span>
</button> </button>
</div> </div>
{{-- Search --}}
<div x-show="showSearch" x-cloak x-transition class="mb-3"> <div x-show="showSearch" x-cloak x-transition class="mb-3">
<input type="text" wire:model.live.debounce.300ms="hotbuy_search" <input type="text" wire:model.live.debounce.300ms="hotbuy_search"
class="w-full px-4 py-3 border border-amber-300 rounded-lg focus:ring-2 focus:ring-amber-500 focus:border-amber-500 text-sm" class="w-full px-4 py-3 border border-amber-300 rounded-lg focus:ring-2 focus:ring-amber-500 focus:border-amber-500 text-sm"
placeholder="{{ __('ابحث بالاسم أو الكود أو الباركود...') }}"> placeholder="{{ __('ابحث بالاسم أو الكود...') }}">
@if(count($this->hotbuyResults) > 0) @if(count($this->hotbuyResults) > 0)
<div class="mt-2 bg-white border border-gray-200 rounded-lg shadow-lg max-h-48 overflow-y-auto"> <div class="mt-2 bg-white border border-gray-200 rounded-lg shadow-lg max-h-48 overflow-y-auto">
@foreach($this->hotbuyResults as $result) @foreach($this->hotbuyResults as $result)
...@@ -771,10 +704,7 @@ class="w-full px-4 py-3 border border-amber-300 rounded-lg focus:ring-2 focus:ri ...@@ -771,10 +704,7 @@ class="w-full px-4 py-3 border border-amber-300 rounded-lg focus:ring-2 focus:ri
class="w-full flex items-center justify-between px-4 py-3 text-start hover:bg-amber-50 border-b border-gray-100 last:border-0 transition-colors"> class="w-full flex items-center justify-between px-4 py-3 text-start hover:bg-amber-50 border-b border-gray-100 last:border-0 transition-colors">
<div> <div>
<p class="text-sm font-medium text-gray-800">{{ $result['name_ar'] }}</p> <p class="text-sm font-medium text-gray-800">{{ $result['name_ar'] }}</p>
<p class="text-xs text-gray-500"> <p class="text-xs text-gray-500">{{ $result['type'] === 'kit' ? __('طقم') : __('منتج') }}@if($result['sku']) — {{ $result['sku'] }}@endif</p>
{{ $result['type'] === 'kit' ? __('طقم') : __('منتج') }}
@if($result['sku']) — {{ $result['sku'] }} @endif
</p>
</div> </div>
<span class="text-sm font-bold text-green-700" dir="ltr">{{ number_format($result['price'] / 100, 2) }} {{ __('ج.م') }}</span> <span class="text-sm font-bold text-green-700" dir="ltr">{{ number_format($result['price'] / 100, 2) }} {{ __('ج.م') }}</span>
</button> </button>
...@@ -784,8 +714,6 @@ class="w-full flex items-center justify-between px-4 py-3 text-start hover:bg-am ...@@ -784,8 +714,6 @@ class="w-full flex items-center justify-between px-4 py-3 text-start hover:bg-am
<p class="mt-2 text-xs text-gray-500 text-center">{{ __('لا توجد نتائج') }}</p> <p class="mt-2 text-xs text-gray-500 text-center">{{ __('لا توجد نتائج') }}</p>
@endif @endif
</div> </div>
{{-- Cart items --}}
@if(count($hotbuyCart) > 0) @if(count($hotbuyCart) > 0)
<div class="space-y-2"> <div class="space-y-2">
@foreach($hotbuyCart as $key => $cartItem) @foreach($hotbuyCart as $key => $cartItem)
...@@ -811,18 +739,18 @@ class="w-8 h-8 rounded-full bg-red-100 text-red-600 flex items-center justify-ce ...@@ -811,18 +739,18 @@ class="w-8 h-8 rounded-full bg-red-100 text-red-600 flex items-center justify-ce
@endforeach @endforeach
</div> </div>
@else @else
<p class="text-xs text-gray-500">{{ __('يمكنك إضافة منتجات أو طقم (يونيفورم، كرة، إلخ) على نفس الفاتورة') }}</p> <p class="text-xs text-gray-500">{{ __('يمكنك إضافة منتجات أو طقم على نفس الفاتورة') }}</p>
@endif @endif
</div> </div>
{{-- Grand Total Summary --}} {{-- Grand Total --}}
@if($this->selectedProgramFee > 0 || $this->hotbuyTotal > 0) @if($this->totalWithFee > 0)
<div class="p-4 bg-green-50 rounded-xl border border-green-200"> <div class="p-4 bg-green-50 rounded-xl border border-green-200">
<div class="space-y-1.5 text-sm"> <div class="space-y-1.5 text-sm">
@if($this->selectedProgramFee > 0) @if($this->proratedProgramFee->proratedAmount > 0)
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-gray-600">{{ __('رسوم البرنامج') }}</span> <span class="text-gray-600">{{ __('رسوم البرنامج') }}</span>
<span class="font-medium text-gray-800" dir="ltr">{{ number_format($this->selectedProgramFee / 100, 2) }} {{ __('ج.م') }}</span> <span class="font-medium text-gray-800" dir="ltr">{{ number_format($this->proratedProgramFee->proratedAmount / 100, 2) }} {{ __('ج.م') }}</span>
</div> </div>
@endif @endif
@if($this->hotbuyTotal > 0) @if($this->hotbuyTotal > 0)
...@@ -839,7 +767,45 @@ class="w-8 h-8 rounded-full bg-red-100 text-red-600 flex items-center justify-ce ...@@ -839,7 +767,45 @@ class="w-8 h-8 rounded-full bg-red-100 text-red-600 flex items-center justify-ce
@endif @endif
<div class="flex items-center justify-between pt-2 border-t border-green-200"> <div class="flex items-center justify-between pt-2 border-t border-green-200">
<span class="font-bold text-gray-800">{{ __('الإجمالي') }}</span> <span class="font-bold text-gray-800">{{ __('الإجمالي') }}</span>
<span class="font-bold text-green-700 text-lg" dir="ltr">{{ number_format($this->totalWithFee / 100, 2) }} {{ __('ج.م') }}</span> <span class="font-bold text-green-700 text-lg" dir="ltr">{{ number_format($this->effectiveTotal / 100, 2) }} {{ __('ج.م') }}</span>
</div>
</div>
</div>
@endif
{{-- Super Admin Price Override --}}
@if($isSuperAdmin)
<div class="border border-dashed border-red-300 rounded-xl overflow-hidden" x-data="{ open: @entangle('priceOverrideEnabled') }">
<button type="button" @click="open = !open; $wire.set('priceOverrideEnabled', open)"
class="w-full flex items-center justify-between p-4 text-start hover:bg-red-50 transition-colors">
<div class="flex items-center gap-2">
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/>
</svg>
<span class="text-sm font-semibold text-red-700">{{ __('تجاوز السعر (مدير النظام فقط)') }}</span>
</div>
<svg class="w-4 h-4 text-red-400 transition-transform" :class="open ? 'rotate-180' : ''" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</button>
<div x-show="open" x-cloak x-transition class="p-4 pt-0 space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('المبلغ المخصص (ج.م)') }}</label>
<input type="number" wire:model.live="priceOverrideInput" dir="ltr" step="0.01" min="0"
class="w-full max-w-xs px-4 py-3 border border-red-300 rounded-lg focus:ring-2 focus:ring-red-400 focus:border-red-400 text-lg font-mono"
placeholder="0.00">
@if($priceOverrideInput !== '' && $this->effectiveTotal !== $this->totalWithFee)
<p class="mt-1 text-xs text-red-600">
{{ __('بدلاً من') }} {{ number_format($this->totalWithFee / 100, 2) }} {{ __('ج.م') }}
({{ $this->effectiveTotal < $this->totalWithFee ? '-' : '+' }}{{ number_format(abs($this->effectiveTotal - $this->totalWithFee) / 100, 2) }} {{ __('ج.م') }})
</p>
@endif
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('سبب التعديل (اختياري)') }}</label>
<input type="text" wire:model="priceOverrideReason"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-400 text-sm"
placeholder="{{ __('مثال: خصم خاص، اتفاقية، إلخ') }}">
</div> </div>
</div> </div>
</div> </div>
...@@ -866,46 +832,30 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py ...@@ -866,46 +832,30 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py
</div> </div>
@endif @endif
{{-- Step 6: Payment --}} {{-- ===================== STEP 6: PAYMENT ===================== --}}
@if($currentStep === 6) @if($currentStep === 6)
<div> <div>
<h2 class="text-lg font-semibold text-gray-800 mb-6">{{ __('الدفع') }}</h2> <h2 class="text-lg font-semibold text-gray-800 mb-6">{{ __('الدفع') }}</h2>
@if($this->totalWithFee > 0) @if($this->effectiveTotal > 0)
<div class="p-4 bg-blue-50 border border-blue-200 rounded-xl mb-6 space-y-2"> <div class="p-4 bg-blue-50 border border-blue-200 rounded-xl mb-6">
@if($this->selectedProgramFee > 0) <div class="flex items-center justify-between pt-2">
<div class="flex items-center justify-between text-sm">
<span class="text-blue-600">{{ __('رسوم البرنامج') }}</span>
<span class="font-medium text-blue-700" dir="ltr">{{ number_format($this->selectedProgramFee / 100, 2) }} {{ __('ج.م') }}</span>
</div>
@endif
@if($this->hotbuyTotal > 0)
<div class="flex items-center justify-between text-sm">
<span class="text-blue-600">{{ __('منتجات إضافية') }} ({{ count($hotbuyCart) }})</span>
<span class="font-medium text-blue-700" dir="ltr">{{ number_format($this->hotbuyTotal / 100, 2) }} {{ __('ج.م') }}</span>
</div>
@endif
@if($this->platformFee > 0)
<div class="flex items-center justify-between text-sm">
<span class="text-blue-600">{{ __('رسوم الخدمة') }}</span>
<span class="font-medium text-blue-700" dir="ltr">{{ number_format($this->platformFee / 100, 2) }} {{ __('ج.م') }}</span>
</div>
@endif
<div class="flex items-center justify-between pt-2 border-t border-blue-200">
<span class="text-blue-700 font-semibold">{{ __('الإجمالي المطلوب') }}</span> <span class="text-blue-700 font-semibold">{{ __('الإجمالي المطلوب') }}</span>
<span class="text-xl font-bold text-blue-800" dir="ltr"> <span class="text-xl font-bold text-blue-800" dir="ltr">
{{ number_format($this->totalWithFee / 100, 2) }} {{ __('ج.م') }} {{ number_format($this->effectiveTotal / 100, 2) }} {{ __('ج.م') }}
</span> </span>
</div> </div>
@if($priceOverrideEnabled && $isSuperAdmin && $this->effectiveTotal !== $this->totalWithFee)
<p class="text-xs text-red-600 mt-1 text-end">{{ __('سعر مُعدَّل من المدير') }}</p>
@endif
</div> </div>
@else @else
<div class="p-4 bg-gray-50 border border-gray-200 rounded-xl mb-6"> <div class="p-4 bg-gray-50 border border-gray-200 rounded-xl mb-6">
<p class="text-gray-600 text-sm">{{ __('لا يوجد سعر محدد لهذا البرنامج حالياً — سيتم التسجيل بدون فاتورة.') }}</p> <p class="text-gray-600 text-sm">{{ __('لا يوجد سعر محدد — سيتم التسجيل بدون فاتورة.') }}</p>
</div> </div>
@endif @endif
<div class="space-y-6"> <div class="space-y-6">
{{-- Pay now toggle --}}
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<label class="relative cursor-pointer" dir="ltr"> <label class="relative cursor-pointer" dir="ltr">
<input type="checkbox" wire:model.live="pay_now" class="peer sr-only"> <input type="checkbox" wire:model.live="pay_now" class="peer sr-only">
...@@ -915,40 +865,30 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py ...@@ -915,40 +865,30 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-6 py
</div> </div>
@if($pay_now) @if($pay_now)
{{-- Payment Method --}}
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-3">{{ __('طريقة الدفع') }}</label> <label class="block text-sm font-medium text-gray-700 mb-3">{{ __('طريقة الدفع') }}</label>
<div class="grid grid-cols-3 gap-3"> <div class="grid grid-cols-3 gap-3">
<label class="relative cursor-pointer"> <label class="relative cursor-pointer">
<input type="radio" wire:model="payment_method" value="cash" class="peer sr-only"> <input type="radio" wire:model="payment_method" value="cash" class="peer sr-only">
<div class="p-4 min-h-16 flex flex-col items-center justify-center gap-2 border border-gray-300 rounded-xl transition-all <div class="p-4 min-h-[64px] flex flex-col items-center justify-center gap-2 border border-gray-300 rounded-xl transition-all
peer-checked:border-green-500 peer-checked:bg-green-50 peer-checked:text-green-700 peer-checked:border-green-500 peer-checked:bg-green-50 peer-checked:text-green-700 hover:border-gray-400">
hover:border-gray-400"> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z"/></svg>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z"/>
</svg>
<span class="text-sm font-medium">{{ __('نقدي') }}</span> <span class="text-sm font-medium">{{ __('نقدي') }}</span>
</div> </div>
</label> </label>
<label class="relative cursor-pointer"> <label class="relative cursor-pointer">
<input type="radio" wire:model="payment_method" value="card" class="peer sr-only"> <input type="radio" wire:model="payment_method" value="card" class="peer sr-only">
<div class="p-4 min-h-16 flex flex-col items-center justify-center gap-2 border border-gray-300 rounded-xl transition-all <div class="p-4 min-h-[64px] flex flex-col items-center justify-center gap-2 border border-gray-300 rounded-xl transition-all
peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700 peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700 hover:border-gray-400">
hover:border-gray-400"> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"/></svg>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"/>
</svg>
<span class="text-sm font-medium">{{ __('بطاقة') }}</span> <span class="text-sm font-medium">{{ __('بطاقة') }}</span>
</div> </div>
</label> </label>
<label class="relative cursor-pointer"> <label class="relative cursor-pointer">
<input type="radio" wire:model="payment_method" value="wallet" class="peer sr-only"> <input type="radio" wire:model="payment_method" value="wallet" class="peer sr-only">
<div class="p-4 min-h-16 flex flex-col items-center justify-center gap-2 border border-gray-300 rounded-xl transition-all <div class="p-4 min-h-[64px] flex flex-col items-center justify-center gap-2 border border-gray-300 rounded-xl transition-all
peer-checked:border-purple-500 peer-checked:bg-purple-50 peer-checked:text-purple-700 peer-checked:border-purple-500 peer-checked:bg-purple-50 peer-checked:text-purple-700 hover:border-gray-400">
hover:border-gray-400"> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M3 6h18M3 14h18M3 18h18"/></svg>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M3 6h18M3 14h18M3 18h18"/>
</svg>
<span class="text-sm font-medium">{{ __('محفظة') }}</span> <span class="text-sm font-medium">{{ __('محفظة') }}</span>
</div> </div>
</label> </label>
...@@ -985,10 +925,9 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -985,10 +925,9 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
</div> </div>
@endif @endif
{{-- Step 7: Success + Printable Invoice --}} {{-- ===================== STEP 7: SUCCESS ===================== --}}
@if($currentStep === 7) @if($currentStep === 7)
<div> <div>
{{-- Success Banner --}}
<div class="text-center py-6 mb-6"> <div class="text-center py-6 mb-6">
<div class="w-16 h-16 mx-auto bg-green-100 rounded-full flex items-center justify-center mb-4"> <div class="w-16 h-16 mx-auto bg-green-100 rounded-full flex items-center justify-center mb-4">
<svg class="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
...@@ -1002,7 +941,6 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -1002,7 +941,6 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
@endif @endif
</div> </div>
{{-- Printable Invoice --}}
@if($this->invoiceForPrint) @if($this->invoiceForPrint)
@php @php
$inv = $this->invoiceForPrint; $inv = $this->invoiceForPrint;
...@@ -1013,7 +951,6 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -1013,7 +951,6 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
$receiptFooter = $branding->get('branding.receipt_footer_text', ''); $receiptFooter = $branding->get('branding.receipt_footer_text', '');
@endphp @endphp
<div id="printable-invoice" class="bg-white border border-gray-300 rounded-xl p-4 sm:p-6 max-w-2xl mx-auto print:border-0 print:shadow-none print:rounded-none print:p-0 print:max-w-full"> <div id="printable-invoice" class="bg-white border border-gray-300 rounded-xl p-4 sm:p-6 max-w-2xl mx-auto print:border-0 print:shadow-none print:rounded-none print:p-0 print:max-w-full">
{{-- Invoice Header with Branding --}}
<div class="flex items-start justify-between border-b border-gray-200 pb-4 mb-4"> <div class="flex items-start justify-between border-b border-gray-200 pb-4 mb-4">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
@if($brandLogo) @if($brandLogo)
...@@ -1023,31 +960,21 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -1023,31 +960,21 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
<h3 class="text-base sm:text-lg font-bold text-gray-800">{{ $academyName }}</h3> <h3 class="text-base sm:text-lg font-bold text-gray-800">{{ $academyName }}</h3>
@if($branch) @if($branch)
<p class="text-xs text-gray-500">{{ $branch->name_ar }}</p> <p class="text-xs text-gray-500">{{ $branch->name_ar }}</p>
@if($branch->address)
<p class="text-xs text-gray-400">{{ $branch->address }}</p>
@endif
@if($branch->phone)
<p class="text-xs text-gray-400" dir="ltr">{{ $branch->phone }}</p>
@endif
@endif @endif
</div> </div>
</div> </div>
<div class="text-end text-sm"> <div class="text-end text-sm">
<p class="font-bold text-gray-700">{{ __('فاتورة') }}</p> <p class="font-bold text-gray-700">{{ __('فاتورة') }}</p>
<p class="text-gray-500 mt-1 font-mono" dir="ltr">#{{ $inv->number }}</p> <p class="text-gray-500 mt-1 font-mono" dir="ltr">#{{ $inv->number }}</p>
<p class="text-gray-500 mt-1">{{ __('التاريخ') }}: {{ $inv->issue_date?->format('Y/m/d') ?? now()->format('Y/m/d') }}</p> <p class="text-gray-500 mt-1">{{ $inv->issue_date?->format('Y/m/d') ?? now()->format('Y/m/d') }}</p>
<p class="text-gray-500">{{ __('الاستحقاق') }}: {{ $inv->due_date?->format('Y/m/d') ?? now()->addDays(7)->format('Y/m/d') }}</p>
</div> </div>
</div> </div>
{{-- Customer Info --}}
<div class="grid grid-cols-2 gap-4 text-sm mb-6"> <div class="grid grid-cols-2 gap-4 text-sm mb-6">
<div> <div>
<p class="text-gray-500 text-xs mb-1">{{ __('المشترك') }}</p> <p class="text-gray-500 text-xs mb-1">{{ __('المشترك') }}</p>
<p class="font-semibold text-gray-800">{{ $participant_name_ar }}</p> <p class="font-semibold text-gray-800">{{ $participant_name_ar }}</p>
@if($participant_number) @if($participant_number)<p class="text-gray-500" dir="ltr">{{ $participant_number }}</p>@endif
<p class="text-gray-500" dir="ltr">{{ $participant_number }}</p>
@endif
</div> </div>
<div class="text-end"> <div class="text-end">
<p class="text-gray-500 text-xs mb-1">{{ __('ولي الأمر') }}</p> <p class="text-gray-500 text-xs mb-1">{{ __('ولي الأمر') }}</p>
...@@ -1056,14 +983,12 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -1056,14 +983,12 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
</div> </div>
</div> </div>
{{-- Items Table --}}
<table class="w-full text-sm mb-4"> <table class="w-full text-sm mb-4">
<thead> <thead>
<tr class="border-b border-gray-200"> <tr class="border-b border-gray-200">
<th class="text-start py-2 font-medium text-gray-600">{{ __('البند') }}</th> <th class="text-start py-2 font-medium text-gray-600">{{ __('البند') }}</th>
<th class="text-center py-2 font-medium text-gray-600 w-16">{{ __('الكمية') }}</th> <th class="text-center py-2 font-medium text-gray-600 w-16">{{ __('الكمية') }}</th>
<th class="text-end py-2 font-medium text-gray-600 w-28">{{ __('السعر') }}</th> <th class="text-end py-2 font-medium text-gray-600 w-28">{{ __('الإجمالي') }}</th>
<th class="text-end py-2 font-medium text-gray-600 w-28">{{ __('المجموع') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -1071,35 +996,23 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -1071,35 +996,23 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
<tr class="border-b border-gray-100"> <tr class="border-b border-gray-100">
<td class="py-3">{{ $item->description }}</td> <td class="py-3">{{ $item->description }}</td>
<td class="py-3 text-center">{{ $item->quantity }}</td> <td class="py-3 text-center">{{ $item->quantity }}</td>
<td class="py-3 text-end" dir="ltr">{{ number_format($item->unit_price / 100, 2) }}</td>
<td class="py-3 text-end" dir="ltr">{{ number_format($item->total_amount / 100, 2) }}</td> <td class="py-3 text-end" dir="ltr">{{ number_format($item->total_amount / 100, 2) }}</td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
{{-- Totals --}}
<div class="border-t border-gray-200 pt-3 space-y-2 text-sm max-w-xs ms-auto"> <div class="border-t border-gray-200 pt-3 space-y-2 text-sm max-w-xs ms-auto">
<div class="flex justify-between">
<span class="text-gray-500">{{ __('المجموع الفرعي') }}</span>
<span class="font-medium" dir="ltr">{{ number_format($inv->subtotal_amount / 100, 2) }} {{ __('ج.م') }}</span>
</div>
@if($inv->discount_amount > 0) @if($inv->discount_amount > 0)
<div class="flex justify-between text-green-600"> <div class="flex justify-between text-green-600">
<span>{{ __('الخصم') }}</span> <span>{{ __('خصم') }}</span>
<span dir="ltr">-{{ number_format($inv->discount_amount / 100, 2) }}</span> <span dir="ltr">-{{ number_format($inv->discount_amount / 100, 2) }}</span>
</div> </div>
@endif @endif
@if($inv->service_fee_amount > 0) @if($inv->service_fee_amount > 0)
<div class="flex justify-between"> <div class="flex justify-between">
<span class="text-gray-500">{{ __('رسوم الخدمة') }}</span> <span class="text-gray-500">{{ __('رسوم الخدمة') }}</span>
<span class="font-medium" dir="ltr">{{ number_format($inv->service_fee_amount / 100, 2) }} {{ __('ج.م') }}</span> <span dir="ltr">{{ number_format($inv->service_fee_amount / 100, 2) }} {{ __('ج.م') }}</span>
</div>
@endif
@if($inv->tax_amount > 0)
<div class="flex justify-between">
<span class="text-gray-500">{{ __('الضريبة') }}</span>
<span class="font-medium" dir="ltr">{{ number_format($inv->tax_amount / 100, 2) }}</span>
</div> </div>
@endif @endif
<div class="flex justify-between pt-2 border-t border-gray-300 text-base"> <div class="flex justify-between pt-2 border-t border-gray-300 text-base">
...@@ -1123,13 +1036,10 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -1123,13 +1036,10 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
@endif @endif
</div> </div>
{{-- Payment status badge --}}
<div class="mt-4 text-center"> <div class="mt-4 text-center">
@if($payment_recorded) @if($payment_recorded)
<span class="inline-flex items-center gap-1 px-4 py-2 bg-green-100 text-green-800 rounded-full text-sm font-bold"> <span class="inline-flex items-center gap-1 px-4 py-2 bg-green-100 text-green-800 rounded-full text-sm font-bold">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
{{ __('تم الدفع') }} {{ __('تم الدفع') }}
</span> </span>
@else @else
...@@ -1139,7 +1049,6 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -1139,7 +1049,6 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
@endif @endif
</div> </div>
{{-- Footer from branding settings --}}
@if($receiptFooter) @if($receiptFooter)
<div class="mt-4 pt-3 border-t border-gray-200 text-center text-xs text-gray-500"> <div class="mt-4 pt-3 border-t border-gray-200 text-center text-xs text-gray-500">
{{ $receiptFooter }} {{ $receiptFooter }}
...@@ -1147,48 +1056,38 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py ...@@ -1147,48 +1056,38 @@ class="flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-8 py
@endif @endif
</div> </div>
{{-- Actions --}}
<div class="flex flex-col sm:flex-row items-stretch sm:items-center justify-center gap-3 mt-6 print:hidden"> <div class="flex flex-col sm:flex-row items-stretch sm:items-center justify-center gap-3 mt-6 print:hidden">
<a href="{{ route('invoices.print', $invoice_uuid) }}" target="_blank" <a href="{{ route('invoices.print', $invoice_uuid) }}" target="_blank"
class="inline-flex items-center justify-center gap-2 px-6 py-3 min-h-[48px] bg-gray-800 text-white rounded-lg hover:bg-gray-900 active:bg-gray-950 text-base font-medium transition-colors"> class="inline-flex items-center justify-center gap-2 px-6 py-3 min-h-[48px] bg-gray-800 text-white rounded-lg hover:bg-gray-900 text-base font-medium transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"/></svg>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"/>
</svg>
{{ __('طباعة الفاتورة') }} {{ __('طباعة الفاتورة') }}
</a> </a>
<a href="{{ route('receptionist.new-registration') }}" wire:navigate <a href="{{ route('receptionist.new-registration') }}" wire:navigate
class="inline-flex items-center justify-center gap-2 px-6 py-3 min-h-[48px] bg-blue-600 text-white rounded-lg hover:bg-blue-700 active:bg-blue-800 text-base font-medium transition-colors"> class="inline-flex items-center justify-center gap-2 px-6 py-3 min-h-[48px] bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-base font-medium transition-colors">
{{ __('تسجيل آخر') }} {{ __('تسجيل آخر') }}
</a> </a>
<a href="{{ route('receptionist.dashboard') }}" wire:navigate <a href="{{ route('receptionist.dashboard') }}" wire:navigate
class="inline-flex items-center justify-center gap-2 px-6 py-3 min-h-[48px] bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 active:bg-gray-300 text-base font-medium transition-colors"> class="inline-flex items-center justify-center gap-2 px-6 py-3 min-h-[48px] bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 text-base font-medium transition-colors">
{{ __('العودة للاستقبال') }} {{ __('العودة للاستقبال') }}
</a> </a>
</div> </div>
{{-- Navigation Links --}}
<div class="flex items-center justify-center gap-3 mt-4 print:hidden"> <div class="flex items-center justify-center gap-3 mt-4 print:hidden">
@if($participant_uuid) @if($participant_uuid)
<a href="{{ route('participants.show', $participant_uuid) }}" wire:navigate <a href="{{ route('participants.show', $participant_uuid) }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2.5 min-h-[44px] border border-blue-300 rounded-lg text-sm font-medium text-blue-700 hover:bg-blue-50 active:bg-blue-100 transition-colors"> class="inline-flex items-center gap-2 px-4 py-2.5 min-h-[44px] border border-blue-300 rounded-lg text-sm font-medium text-blue-700 hover:bg-blue-50 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
{{ __('عرض المشترك') }} {{ __('عرض المشترك') }}
</a> </a>
@endif @endif
@if($invoice_uuid) @if($invoice_uuid)
<a href="{{ route('invoices.show', $invoice_uuid) }}" wire:navigate <a href="{{ route('invoices.show', $invoice_uuid) }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2.5 min-h-[44px] border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-colors"> class="inline-flex items-center gap-2 px-4 py-2.5 min-h-[44px] border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
{{ __('عرض الفاتورة') }} {{ __('عرض الفاتورة') }}
</a> </a>
@endif @endif
</div> </div>
@else @else
{{-- No invoice (free program) --}}
<div class="flex items-center justify-center gap-4 mt-6"> <div class="flex items-center justify-center gap-4 mt-6">
<a href="{{ route('receptionist.new-registration') }}" wire:navigate <a href="{{ route('receptionist.new-registration') }}" wire:navigate
class="inline-flex items-center gap-2 px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-base font-medium transition-colors"> class="inline-flex items-center gap-2 px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-base font-medium transition-colors">
...@@ -1199,15 +1098,10 @@ class="inline-flex items-center gap-2 px-6 py-3 bg-gray-100 text-gray-700 rounde ...@@ -1199,15 +1098,10 @@ class="inline-flex items-center gap-2 px-6 py-3 bg-gray-100 text-gray-700 rounde
{{ __('العودة للاستقبال') }} {{ __('العودة للاستقبال') }}
</a> </a>
</div> </div>
{{-- Navigation Links --}}
@if($participant_uuid) @if($participant_uuid)
<div class="flex items-center justify-center gap-3 mt-4"> <div class="flex items-center justify-center gap-3 mt-4">
<a href="{{ route('participants.show', $participant_uuid) }}" wire:navigate <a href="{{ route('participants.show', $participant_uuid) }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2.5 min-h-[44px] border border-blue-300 rounded-lg text-sm font-medium text-blue-700 hover:bg-blue-50 active:bg-blue-100 transition-colors"> class="inline-flex items-center gap-2 px-4 py-2.5 min-h-[44px] border border-blue-300 rounded-lg text-sm font-medium text-blue-700 hover:bg-blue-50 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
{{ __('عرض المشترك') }} {{ __('عرض المشترك') }}
</a> </a>
</div> </div>
...@@ -1215,6 +1109,7 @@ class="inline-flex items-center gap-2 px-4 py-2.5 min-h-[44px] border border-blu ...@@ -1215,6 +1109,7 @@ class="inline-flex items-center gap-2 px-4 py-2.5 min-h-[44px] border border-blu
@endif @endif
</div> </div>
@endif @endif
</div> </div>
@endif {{-- end systemErrors else block --}} @endif {{-- end systemErrors else block --}}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment