Commit 6079ab5d authored by Mahmoud Aglan's avatar Mahmoud Aglan

Remove academy creation from setup wizard — academy comes from env vars

The academy identity is now established by the seeder (from ACADEMY_NAME_EN,
ACADEMY_NAME_AR env vars). The wizard no longer has an "Academy Profile" step.
It starts directly at Branches (step 1) and only configures operational data:
branches, activities, programs, facilities, groups, staff, settings.

This enforces one-academy-per-instance: the academy exists before the wizard
runs, and no user action can create or duplicate it.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 2f4c631c
......@@ -30,40 +30,30 @@
class SetupWizard extends Component
{
public int $currentStep = 1;
public int $totalSteps = 12;
// Step 1: Academy Profile
public string $academyName = '';
public string $academyNameAr = '';
public string $academyPhone = '';
public string $academyEmail = '';
public string $academyAddress = '';
public string $academyType = '';
public string $academyWebsite = '';
public string $socialWhatsapp = '';
// Step 2: Branches
public int $totalSteps = 11;
// Step 1: Branches
public array $branches = [];
// Step 3: Activities
// Step 2: Activities
public array $activities = [];
// Step 4: Programs
// Step 3: Programs
public array $programs = [];
// Step 5: Facilities + Grid
// Step 4: Facilities + Grid
public array $facilities = [];
// Step 6: Groups + Schedule
// Step 5: Groups + Schedule
public array $groups = [];
// Step 7: Participants
// Step 6: Participants
public array $participants = [];
// Step 8: Staff & Users
// Step 7: Staff & Users
public array $users = [];
// Step 9: Financial & Pricing
// Step 8: Financial & Pricing
public bool $taxEnabled = false;
public float $taxPercentage = 14;
public string $invoicePrefix = 'INV';
......@@ -76,7 +66,7 @@ class SetupWizard extends Component
public int $familyDiscountStartChild = 2;
public int $trialPeriodDays = 7;
// Step 10: Rules & Policies
// Step 9: Rules & Policies
public int $gracePeriodParticipant = 15;
public int $gracePeriodTrainer = 10;
public int $autoAbsentAfterHours = 2;
......@@ -90,7 +80,7 @@ class SetupWizard extends Component
public bool $emailEnabled = true;
public bool $smsEnabled = false;
// Step 11: General Settings
// Step 10: General Settings
public string $defaultCurrency = 'EGP';
public string $timezone = 'Africa/Cairo';
public string $weekStartsOn = '6';
......@@ -118,10 +108,6 @@ public function mount(): void
return;
}
// Pre-fill academy info
$this->academyName = $this->academy->name ?? '';
$this->academyNameAr = $this->academy->name_ar ?? '';
// Initialize with one empty branch
$this->addBranch();
}
......@@ -345,33 +331,14 @@ public function removeUser(int $index): void
protected function validateCurrentStep(): void
{
match ($this->currentStep) {
1 => $this->validate([
'academyNameAr' => 'required|string|min:3|max:255',
'academyName' => 'nullable|string|max:255',
'academyPhone' => 'required|string|max:20',
'academyEmail' => 'required|email|max:255',
'academyAddress' => 'nullable|string|max:500',
'academyType' => 'required|string|in:sports_club,fitness_center,educational_center,multi_sport,swimming_academy,martial_arts,other',
'academyWebsite' => 'nullable|url|max:255',
'socialWhatsapp' => 'nullable|string|max:20',
], [
'academyNameAr.required' => __('اسم الأكاديمية بالعربية مطلوب'),
'academyNameAr.min' => __('اسم الأكاديمية يجب أن يكون 3 أحرف على الأقل'),
'academyPhone.required' => __('رقم هاتف الأكاديمية مطلوب'),
'academyEmail.required' => __('البريد الإلكتروني للأكاديمية مطلوب'),
'academyEmail.email' => __('البريد الإلكتروني غير صالح'),
'academyType.required' => __('نوع الأكاديمية مطلوب'),
'academyType.in' => __('نوع الأكاديمية غير صالح'),
'academyWebsite.url' => __('رابط الموقع غير صالح'),
]),
2 => $this->validateBranches(),
3 => $this->validateActivities(),
4 => $this->validatePrograms(),
5 => $this->validateFacilities(),
6 => $this->validateGroups(),
7 => $this->validateParticipants(),
8 => $this->validateUsers(),
9 => $this->validate([
1 => $this->validateBranches(),
2 => $this->validateActivities(),
3 => $this->validatePrograms(),
4 => $this->validateFacilities(),
5 => $this->validateGroups(),
6 => $this->validateParticipants(),
7 => $this->validateUsers(),
8 => $this->validate([
'taxEnabled' => 'boolean',
'taxPercentage' => 'required|numeric|min:0|max:100',
'invoicePrefix' => 'required|string|max:10',
......@@ -400,7 +367,7 @@ protected function validateCurrentStep(): void
'familyDiscountStartChild.required' => __('ترتيب الطفل لبدء خصم العائلة مطلوب'),
'trialPeriodDays.required' => __('فترة التجربة مطلوبة'),
]),
10 => $this->validate([
9 => $this->validate([
'gracePeriodParticipant' => 'required|integer|min:0|max:60',
'gracePeriodTrainer' => 'required|integer|min:0|max:60',
'autoAbsentAfterHours' => 'required|integer|min:1|max:24',
......@@ -427,7 +394,7 @@ protected function validateCurrentStep(): void
'freezeMaxDays.required' => __('الحد الأقصى لأيام التجميد مطلوب'),
'freezeMaxDays.min' => __('الحد الأقصى لأيام التجميد يجب أن يكون يوم واحد على الأقل'),
]),
11 => $this->validate([
10 => $this->validate([
'defaultCurrency' => 'required|string|in:EGP,SAR,AED,USD',
'timezone' => 'required|string|timezone',
'weekStartsOn' => 'required|string|in:0,1,6',
......@@ -663,30 +630,13 @@ public function completeSetup(): void
$academyId = $this->academy->id;
$actor = auth()->user();
// Update academy profile
// Update academy currency/timezone from wizard settings
$this->academy->update([
'name' => $this->academyName ?: $this->academyNameAr,
'name_ar' => $this->academyNameAr,
'phone' => $this->academyPhone,
'email' => $this->academyEmail,
'currency' => $this->defaultCurrency,
'timezone' => $this->timezone,
'settings' => array_merge($this->academy->settings ?? [], [
'address' => $this->academyAddress,
'type' => $this->academyType,
'website' => $this->academyWebsite,
'whatsapp' => $this->socialWhatsapp,
]),
]);
// Save additional academy info as settings
$settingsService = app(SettingsService::class);
$settingsService->set('academy_phone', $this->academyPhone, 'general', 'string');
$settingsService->set('academy_email', $this->academyEmail, 'general', 'string');
$settingsService->set('academy_address', $this->academyAddress, 'general', 'string');
$settingsService->set('academy_type', $this->academyType, 'general', 'string');
$settingsService->set('academy_website', $this->academyWebsite, 'general', 'string');
$settingsService->set('social_whatsapp', $this->socialWhatsapp, 'general', 'string');
// Create branches
$createdBranches = [];
......@@ -1049,31 +999,17 @@ private function generateParticipantNumber(int $academyId, int $index): string
public function getStepLabels(): array
{
return [
1 => __('الأكاديمية'),
2 => __('الفروع'),
3 => __('الأنشطة'),
4 => __('البرامج'),
5 => __('المنشآت'),
6 => __('المجموعات'),
7 => __('المشتركين'),
8 => __('الطاقم'),
9 => __('المالية'),
10 => __('السياسات'),
11 => __('الإعدادات'),
12 => __('تم!'),
];
}
public function getAcademyTypes(): array
{
return [
'sports_club' => __('نادي رياضي'),
'fitness_center' => __('مركز لياقة'),
'educational_center' => __('مركز تعليمي'),
'multi_sport' => __('أكاديمية متعددة'),
'swimming_academy' => __('أكاديمية سباحة'),
'martial_arts' => __('فنون قتالية'),
'other' => __('أخرى'),
1 => __('الفروع'),
2 => __('الأنشطة'),
3 => __('البرامج'),
4 => __('المنشآت'),
5 => __('المجموعات'),
6 => __('المشتركين'),
7 => __('الطاقم'),
8 => __('المالية'),
9 => __('السياسات'),
10 => __('الإعدادات'),
11 => __('تم!'),
];
}
......
......@@ -54,77 +54,8 @@
{{-- ─── Step Content ─────────────────────────────────────────── --}}
<div class="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden">
{{-- ═══ Step 1: Academy Profile ═══ --}}
{{-- ═══ Step 1: Branches ═══ --}}
@if($currentStep === 1)
<div class="p-8">
<div class="text-center mb-8">
<div class="inline-flex items-center justify-center w-16 h-16 bg-blue-50 rounded-2xl mb-4">
<svg class="w-8 h-8 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"/>
</svg>
</div>
<h2 class="text-2xl font-bold text-gray-800">{{ __('بيانات الأكاديمية') }}</h2>
<p class="text-sm text-gray-500 mt-2">{{ __('أدخل البيانات الأساسية لأكاديميتك') }}</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6 max-w-3xl mx-auto">
<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="academyNameAr" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" placeholder="{{ __('مثال: أكاديمية النجوم الرياضية') }}">
@error('academyNameAr') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الاسم بالإنجليزية') }}</label>
<input type="text" wire:model="academyName" dir="ltr" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" placeholder="Stars Sports Academy">
@error('academyName') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<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="academyPhone" dir="ltr" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" placeholder="01012345678">
@error('academyPhone') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('البريد الإلكتروني') }} <span class="text-red-500">*</span></label>
<input type="email" wire:model="academyEmail" dir="ltr" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" placeholder="info@academy.com">
@error('academyEmail') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('العنوان') }}</label>
<input type="text" wire:model="academyAddress" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" placeholder="{{ __('المدينة، الحي، الشارع') }}">
@error('academyAddress') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('نوع الأكاديمية') }} <span class="text-red-500">*</span></label>
<select wire:model="academyType" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
<option value="">{{ __('اختر...') }}</option>
@foreach($this->getAcademyTypes() as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</select>
@error('academyType') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الموقع الإلكتروني') }}</label>
<input type="url" wire:model="academyWebsite" dir="ltr" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" placeholder="https://academy.com">
@error('academyWebsite') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('واتساب') }}</label>
<input type="text" wire:model="socialWhatsapp" dir="ltr" class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" placeholder="01012345678">
@error('socialWhatsapp') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
</div>
<div class="mt-6 max-w-3xl mx-auto">
<div class="bg-blue-50 border border-blue-100 rounded-lg p-3">
<p class="text-sm text-blue-700">{{ __('هذه البيانات ستظهر في الفواتير والإيصالات والمراسلات الرسمية') }}</p>
</div>
</div>
</div>
@endif
{{-- ═══ Step 2: Branches ═══ --}}
@if($currentStep === 2)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('الفروع') }}</h2>
......@@ -208,8 +139,8 @@ class="px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors">
</div>
@endif
{{-- ═══ Step 3: Activities ═══ --}}
@if($currentStep === 3)
{{-- ═══ Step 2: Activities ═══ --}}
@if($currentStep === 2)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('الأنشطة') }}</h2>
......@@ -256,8 +187,8 @@ class="px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors">
</div>
@endif
{{-- ═══ Step 4: Programs ═══ --}}
@if($currentStep === 4)
{{-- ═══ Step 3: Programs ═══ --}}
@if($currentStep === 3)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('البرامج التدريبية') }}</h2>
......@@ -347,8 +278,8 @@ class="px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors">
</div>
@endif
{{-- ═══ Step 5: Facilities ═══ --}}
@if($currentStep === 5)
{{-- ═══ Step 4: Facilities ═══ --}}
@if($currentStep === 4)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('المنشآت والملاعب') }}</h2>
......@@ -442,8 +373,8 @@ class="px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors">
</div>
@endif
{{-- ═══ Step 6: Groups + Schedule ═══ --}}
@if($currentStep === 6)
{{-- ═══ Step 5: Groups + Schedule ═══ --}}
@if($currentStep === 5)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('المجموعات والجدول') }}</h2>
......@@ -554,8 +485,8 @@ class="w-10 h-8 border rounded flex items-center justify-center text-xs font-mon
</div>
@endif
{{-- ═══ Step 7: Participants ═══ --}}
@if($currentStep === 7)
{{-- ═══ Step 6: Participants ═══ --}}
@if($currentStep === 6)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('المشتركين') }}</h2>
......@@ -674,8 +605,8 @@ class="w-10 h-8 border rounded flex items-center justify-center text-xs font-mon
</div>
@endif
{{-- ═══ Step 8: Staff & Users ═══ --}}
@if($currentStep === 8)
{{-- ═══ Step 7: Staff & Users ═══ --}}
@if($currentStep === 7)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('الطاقم والمستخدمين') }}</h2>
......@@ -743,8 +674,8 @@ class="w-10 h-8 border rounded flex items-center justify-center text-xs font-mon
</div>
@endif
{{-- ═══ Step 9: Financial & Pricing ═══ --}}
@if($currentStep === 9)
{{-- ═══ Step 8: Financial & Pricing ═══ --}}
@if($currentStep === 8)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('الإعدادات المالية والتسعير') }}</h2>
......@@ -851,8 +782,8 @@ class="w-10 h-8 border rounded flex items-center justify-center text-xs font-mon
</div>
@endif
{{-- ═══ Step 10: Rules & Policies ═══ --}}
@if($currentStep === 10)
{{-- ═══ Step 9: Rules & Policies ═══ --}}
@if($currentStep === 9)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('السياسات والقواعد') }}</h2>
......@@ -958,8 +889,8 @@ class="w-10 h-8 border rounded flex items-center justify-center text-xs font-mon
</div>
@endif
{{-- ═══ Step 11: General Settings ═══ --}}
@if($currentStep === 11)
{{-- ═══ Step 10: General Settings ═══ --}}
@if($currentStep === 10)
<div class="p-8">
<div class="mb-6">
<h2 class="text-xl font-bold text-gray-800">{{ __('الإعدادات العامة') }}</h2>
......@@ -1032,8 +963,8 @@ class="w-10 h-8 border rounded flex items-center justify-center text-xs font-mon
</div>
@endif
{{-- ═══ Step 12: Summary & Complete ═══ --}}
@if($currentStep === 12)
{{-- ═══ Step 11: Summary & Complete ═══ --}}
@if($currentStep === 11)
<div class="p-8">
<div class="text-center mb-8">
<div class="inline-flex items-center justify-center w-16 h-16 bg-green-50 rounded-2xl mb-4">
......@@ -1049,8 +980,8 @@ class="w-10 h-8 border rounded flex items-center justify-center text-xs font-mon
{{-- Academy --}}
<div class="bg-blue-50 rounded-xl p-4">
<h4 class="text-xs font-semibold text-blue-800 uppercase mb-2">{{ __('الأكاديمية') }}</h4>
<p class="text-sm font-medium text-gray-800">{{ $academyNameAr }}</p>
<p class="text-xs text-gray-500">{{ $this->getAcademyTypes()[$academyType] ?? $academyType }}</p>
<p class="text-sm font-medium text-gray-800">{{ $academy->name_ar }}</p>
<p class="text-xs text-gray-500">{{ $academy->name }}</p>
</div>
{{-- Branches --}}
......
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