Commit de3ccd63 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Smart cascading filters, collapsible sidebar, wizard-only create entry

- Add cascading filters across all list pages (activity→program→group,
  program→trainer, direction→movement type)
- Make sidebar sections collapsible with auto-expand on active page
- Route all "Create" buttons to wizards instead of plain forms
- Fix low stock count mismatch between dashboard and product list
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent d74bc423
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
use App\Domain\Financial\Models\Payment; use App\Domain\Financial\Models\Payment;
use App\Domain\HR\Enums\PayslipStatus; use App\Domain\HR\Enums\PayslipStatus;
use App\Domain\HR\Models\Payslip; use App\Domain\HR\Models\Payslip;
use App\Domain\Inventory\Models\InventoryLevel; use App\Domain\Inventory\Models\Product;
use App\Domain\Participant\Models\Participant; use App\Domain\Participant\Models\Participant;
use App\Domain\Shared\Traits\UsesBranchScope; use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\TrainingSession; use App\Domain\Training\Models\TrainingSession;
...@@ -84,8 +84,11 @@ public function render() ...@@ -84,8 +84,11 @@ public function render()
$pendingDocuments = Document::where('status', DocumentStatus::Pending) $pendingDocuments = Document::where('status', DocumentStatus::Pending)
->count(); ->count();
$lowStockItems = InventoryLevel::whereHas('product', fn ($q) => $q->where('track_inventory', true)->where('is_active', true)->whereNotNull('min_stock_level')->where('min_stock_level', '>', 0)) $lowStockItems = Product::where('track_inventory', true)
->whereRaw('quantity_on_hand < (SELECT min_stock_level FROM products WHERE products.id = inventory_levels.product_id)') ->where('is_active', true)
->whereNotNull('min_stock_level')
->where('min_stock_level', '>', 0)
->whereHas('inventoryLevels', fn ($q) => $q->whereRaw('quantity_on_hand <= (SELECT min_stock_level FROM products WHERE products.id = inventory_levels.product_id)'))
->count(); ->count();
$expiringMedicalCerts = Document::where('document_type', DocumentType::MedicalCertificate) $expiringMedicalCerts = Document::where('document_type', DocumentType::MedicalCertificate)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
use App\Domain\Shared\Traits\UsesBranchScope; use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\Enrollment; use App\Domain\Training\Models\Enrollment;
use App\Domain\Training\Models\TrainingGroup; use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Services\EnrollmentService; use App\Domain\Training\Services\EnrollmentService;
use App\Domain\Shared\Exceptions\DomainException; use App\Domain\Shared\Exceptions\DomainException;
use App\Livewire\Concerns\AppliesRoleScope; use App\Livewire\Concerns\AppliesRoleScope;
...@@ -28,6 +29,9 @@ class EnrollmentList extends Component ...@@ -28,6 +29,9 @@ class EnrollmentList extends Component
#[Url] #[Url]
public string $status = ''; public string $status = '';
#[Url]
public string $programFilter = '';
public string $groupFilter = ''; public string $groupFilter = '';
public string $paymentFilter = ''; public string $paymentFilter = '';
...@@ -41,6 +45,12 @@ public function updatedStatus(): void ...@@ -41,6 +45,12 @@ public function updatedStatus(): void
$this->resetPage(); $this->resetPage();
} }
public function updatedProgramFilter(): void
{
$this->groupFilter = '';
$this->resetPage();
}
public function updatedGroupFilter(): void public function updatedGroupFilter(): void
{ {
$this->resetPage(); $this->resetPage();
...@@ -84,15 +94,22 @@ public function render() ...@@ -84,15 +94,22 @@ public function render()
}); });
}) })
->when($this->status, fn ($q) => $q->where('status', $this->status)) ->when($this->status, fn ($q) => $q->where('status', $this->status))
->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
->when($this->groupFilter, fn ($q) => $q->where('training_group_id', $this->groupFilter)) ->when($this->groupFilter, fn ($q) => $q->where('training_group_id', $this->groupFilter))
->when($this->paymentFilter, fn ($q) => $q->where('payment_status', $this->paymentFilter)) ->when($this->paymentFilter, fn ($q) => $q->where('payment_status', $this->paymentFilter))
->orderByDesc('enrollment_date'); ->orderByDesc('enrollment_date');
$this->applyRoleScope($query); $this->applyRoleScope($query);
$groups = TrainingGroup::whereIn('status', ['forming', 'active', 'full'])
->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
->orderBy('name_ar')
->get(['id', 'name_ar']);
return view('livewire.enrollments.enrollment-list', [ return view('livewire.enrollments.enrollment-list', [
'enrollments' => $query->paginate(20), 'enrollments' => $query->paginate(20),
'groups' => TrainingGroup::whereIn('status', ['forming', 'active', 'full'])->orderBy('name_ar')->get(['id', 'name_ar']), 'programs' => TrainingProgram::where('status', 'active')->orderBy('name_ar')->get(['id', 'name_ar']),
'groups' => $groups,
'statusOptions' => [ 'statusOptions' => [
'pending' => 'معلق', 'pending' => 'معلق',
'active' => 'نشط', 'active' => 'نشط',
......
...@@ -46,6 +46,7 @@ public function updatedGroupFilter(): void ...@@ -46,6 +46,7 @@ public function updatedGroupFilter(): void
public function updatedProgramFilter(): void public function updatedProgramFilter(): void
{ {
$this->groupFilter = '';
$this->resetPage(); $this->resetPage();
} }
...@@ -118,11 +119,14 @@ public function render() ...@@ -118,11 +119,14 @@ public function render()
->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter)) ->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
->orderBy('enrollment_date'); ->orderBy('enrollment_date');
$groups = TrainingGroup::whereIn('status', ['forming', 'active', 'full'])
->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
->orderBy('name_ar')
->get(['id', 'name_ar', 'current_count', 'max_capacity']);
return view('livewire.enrollments.waitlist-manager', [ return view('livewire.enrollments.waitlist-manager', [
'enrollments' => $query->paginate(20), 'enrollments' => $query->paginate(20),
'groups' => TrainingGroup::whereIn('status', ['forming', 'active', 'full']) 'groups' => $groups,
->orderBy('name_ar')
->get(['id', 'name_ar', 'current_count', 'max_capacity']),
'programs' => TrainingProgram::where('status', 'active') 'programs' => TrainingProgram::where('status', 'active')
->orderBy('name_ar') ->orderBy('name_ar')
->get(['id', 'name_ar']), ->get(['id', 'name_ar']),
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
use App\Domain\Training\Enums\EvaluationStatus; use App\Domain\Training\Enums\EvaluationStatus;
use App\Domain\Training\Models\Evaluation; use App\Domain\Training\Models\Evaluation;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram;
use App\Livewire\Concerns\AppliesRoleScope; use App\Livewire\Concerns\AppliesRoleScope;
use Livewire\Attributes\Layout; use Livewire\Attributes\Layout;
use Livewire\Attributes\Title; use Livewire\Attributes\Title;
...@@ -25,6 +27,9 @@ class EvaluationList extends Component ...@@ -25,6 +27,9 @@ class EvaluationList extends Component
#[Url] #[Url]
public string $status = ''; public string $status = '';
#[Url]
public string $programFilter = '';
#[Url] #[Url]
public string $groupId = ''; public string $groupId = '';
...@@ -43,6 +48,12 @@ public function updatedStatus(): void ...@@ -43,6 +48,12 @@ public function updatedStatus(): void
$this->resetPage(); $this->resetPage();
} }
public function updatedProgramFilter(): void
{
$this->groupId = '';
$this->resetPage();
}
public function updatedGroupId(): void public function updatedGroupId(): void
{ {
$this->resetPage(); $this->resetPage();
...@@ -51,18 +62,27 @@ public function updatedGroupId(): void ...@@ -51,18 +62,27 @@ public function updatedGroupId(): void
public function render() public function render()
{ {
$query = Evaluation::query() $query = Evaluation::query()
->with(['participant.person', 'group', 'evaluator']) ->with(['participant.person', 'group.program', 'evaluator'])
->when($this->search, fn ($q) => $q->whereHas('participant.person', fn ($pq) => $pq->where('name_ar', 'ilike', "%{$this->search}%"))) ->when($this->search, fn ($q) => $q->whereHas('participant.person', fn ($pq) => $pq->where('name_ar', 'ilike', "%{$this->search}%")))
->when($this->status, fn ($q) => $q->where('status', $this->status)) ->when($this->status, fn ($q) => $q->where('status', $this->status))
->when($this->programFilter, fn ($q) => $q->whereHas('group', fn ($gq) => $gq->where('training_program_id', $this->programFilter)))
->when($this->groupId, fn ($q) => $q->where('training_group_id', $this->groupId)) ->when($this->groupId, fn ($q) => $q->where('training_group_id', $this->groupId))
->orderByDesc('evaluation_date'); ->orderByDesc('evaluation_date');
$this->applyRoleScope($query); $this->applyRoleScope($query);
$groups = \App\Domain\Training\Models\TrainingGroup::orderBy('name_ar')->get(['id', 'name_ar']); $groups = TrainingGroup::query()
->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
->orderBy('name_ar')
->get(['id', 'name_ar']);
$programs = TrainingProgram::where('status', 'active')
->orderBy('name_ar')
->get(['id', 'name_ar']);
return view('livewire.evaluations.evaluation-list', [ return view('livewire.evaluations.evaluation-list', [
'evaluations' => $query->paginate(20), 'evaluations' => $query->paginate(20),
'programs' => $programs,
'groups' => $groups, 'groups' => $groups,
'statuses' => EvaluationStatus::cases(), 'statuses' => EvaluationStatus::cases(),
]); ]);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
use App\Domain\Shared\Traits\UsesBranchScope; use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Enums\GroupStatus; use App\Domain\Training\Enums\GroupStatus;
use App\Domain\Training\Models\Activity;
use App\Domain\Training\Models\TrainingGroup; use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram; use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Services\TrainingGroupService; use App\Domain\Training\Services\TrainingGroupService;
...@@ -30,6 +31,9 @@ class GroupList extends Component ...@@ -30,6 +31,9 @@ class GroupList extends Component
#[Url] #[Url]
public string $status = ''; public string $status = '';
#[Url]
public string $activityFilter = '';
#[Url] #[Url]
public string $programFilter = ''; public string $programFilter = '';
...@@ -49,6 +53,12 @@ public function updatedStatus(): void ...@@ -49,6 +53,12 @@ public function updatedStatus(): void
$this->resetPage(); $this->resetPage();
} }
public function updatedActivityFilter(): void
{
$this->programFilter = '';
$this->resetPage();
}
public function updatedProgramFilter(): void public function updatedProgramFilter(): void
{ {
$this->resetPage(); $this->resetPage();
...@@ -110,14 +120,21 @@ public function render() ...@@ -110,14 +120,21 @@ public function render()
->orWhere('code', 'ilike', "%{$this->search}%"); ->orWhere('code', 'ilike', "%{$this->search}%");
})) }))
->when($this->status, fn ($q) => $q->where('status', $this->status)) ->when($this->status, fn ($q) => $q->where('status', $this->status))
->when($this->activityFilter, fn ($q) => $q->whereHas('program', fn ($p) => $p->where('activity_id', $this->activityFilter)))
->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter)) ->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
->orderBy($this->sortBy, $this->sortDir); ->orderBy($this->sortBy, $this->sortDir);
$this->applyRoleScope($query); $this->applyRoleScope($query);
$programs = TrainingProgram::query()
->when($this->activityFilter, fn ($q) => $q->where('activity_id', $this->activityFilter))
->orderBy('name_ar')
->get(['id', 'name_ar']);
return view('livewire.groups.group-list', [ return view('livewire.groups.group-list', [
'groups' => $query->paginate(15), 'groups' => $query->paginate(15),
'programs' => TrainingProgram::orderBy('name_ar')->get(['id', 'name_ar']), 'activities' => Activity::where('is_active', true)->orderBy('name_ar')->get(['id', 'name_ar']),
'programs' => $programs,
'statusOptions' => [ 'statusOptions' => [
'forming' => 'قيد التشكيل', 'forming' => 'قيد التشكيل',
'active' => 'نشطة', 'active' => 'نشطة',
......
...@@ -59,6 +59,7 @@ public function updatedMovementType(): void ...@@ -59,6 +59,7 @@ public function updatedMovementType(): void
public function updatedDirection(): void public function updatedDirection(): void
{ {
$this->movementType = '';
$this->resetPage(); $this->resetPage();
} }
...@@ -99,27 +100,38 @@ public function render() ...@@ -99,27 +100,38 @@ public function render()
->when($this->warehouseFilter, fn ($q) => $q->where('inventory_movements.warehouse_id', $this->warehouseFilter)) ->when($this->warehouseFilter, fn ($q) => $q->where('inventory_movements.warehouse_id', $this->warehouseFilter))
->orderByDesc('inventory_movements.created_at'); ->orderByDesc('inventory_movements.created_at');
$allTypes = [
'purchase_received' => 'استلام مشتريات',
'sale' => 'بيع',
'transfer_out' => 'تحويل صادر',
'transfer_in' => 'تحويل وارد',
'return_to_stock' => 'مرتجع للمخزون',
'return_to_supplier' => 'مرتجع للمورد',
'adjustment_up' => 'تسوية بالزيادة',
'adjustment_down' => 'تسوية بالنقص',
'damage' => 'تلف',
'loss' => 'فقد',
'consumption' => 'استهلاك',
'kit_assembly' => 'تجميع طقم',
'kit_disassembly' => 'تفكيك طقم',
'initial_stock' => 'رصيد افتتاحي',
'count_adjustment_up' => 'تسوية جرد بالزيادة',
'count_adjustment_down' => 'تسوية جرد بالنقص',
];
$inTypes = ['purchase_received', 'transfer_in', 'return_to_stock', 'adjustment_up', 'kit_disassembly', 'initial_stock', 'count_adjustment_up'];
$outTypes = ['sale', 'transfer_out', 'return_to_supplier', 'adjustment_down', 'damage', 'loss', 'consumption', 'kit_assembly', 'count_adjustment_down'];
$movementTypeOptions = match ($this->direction) {
'in' => array_intersect_key($allTypes, array_flip($inTypes)),
'out' => array_intersect_key($allTypes, array_flip($outTypes)),
default => $allTypes,
};
return view('livewire.inventory.movement-list', [ return view('livewire.inventory.movement-list', [
'movements' => $query->paginate(25), 'movements' => $query->paginate(25),
'warehouses' => Warehouse::active()->orderBy('name_ar')->get(['id', 'name_ar']), 'warehouses' => Warehouse::active()->orderBy('name_ar')->get(['id', 'name_ar']),
'movementTypeOptions' => [ 'movementTypeOptions' => $movementTypeOptions,
'purchase_received' => 'استلام مشتريات',
'sale' => 'بيع',
'transfer_out' => 'تحويل صادر',
'transfer_in' => 'تحويل وارد',
'return_to_stock' => 'مرتجع للمخزون',
'return_to_supplier' => 'مرتجع للمورد',
'adjustment_up' => 'تسوية بالزيادة',
'adjustment_down' => 'تسوية بالنقص',
'damage' => 'تلف',
'loss' => 'فقد',
'consumption' => 'استهلاك',
'kit_assembly' => 'تجميع طقم',
'kit_disassembly' => 'تفكيك طقم',
'initial_stock' => 'رصيد افتتاحي',
'count_adjustment_up' => 'تسوية جرد بالزيادة',
'count_adjustment_down' => 'تسوية جرد بالنقص',
],
]); ]);
} }
} }
...@@ -86,9 +86,10 @@ public function render() ...@@ -86,9 +86,10 @@ public function render()
}) })
->when($this->stockFilter === 'low', function ($q) { ->when($this->stockFilter === 'low', function ($q) {
$q->where('track_inventory', true) $q->where('track_inventory', true)
->where('is_active', true)
->whereNotNull('min_stock_level') ->whereNotNull('min_stock_level')
->where('min_stock_level', '>', 0) ->where('min_stock_level', '>', 0)
->whereHas('inventoryLevels', fn ($il) => $il->whereRaw('quantity_on_hand < (SELECT min_stock_level FROM products WHERE products.id = inventory_levels.product_id)')); ->whereHas('inventoryLevels', fn ($il) => $il->whereRaw('quantity_on_hand <= (SELECT min_stock_level FROM products WHERE products.id = inventory_levels.product_id)'));
}) })
->orderByDesc('created_at'); ->orderByDesc('created_at');
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use App\Domain\Training\Services\TrainingProgramService; use App\Domain\Training\Services\TrainingProgramService;
use App\Domain\Shared\Exceptions\DomainException; use App\Domain\Shared\Exceptions\DomainException;
use App\Livewire\Concerns\AppliesRoleScope; use App\Livewire\Concerns\AppliesRoleScope;
use App\Models\User;
use Livewire\Attributes\Layout; use Livewire\Attributes\Layout;
use Livewire\Attributes\Title; use Livewire\Attributes\Title;
use Livewire\Attributes\Url; use Livewire\Attributes\Url;
...@@ -32,6 +33,9 @@ class ProgramList extends Component ...@@ -32,6 +33,9 @@ class ProgramList extends Component
#[Url] #[Url]
public string $activityFilter = ''; public string $activityFilter = '';
#[Url]
public string $trainerFilter = '';
#[Url] #[Url]
public string $sortBy = 'created_at'; public string $sortBy = 'created_at';
...@@ -49,6 +53,12 @@ public function updatedStatus(): void ...@@ -49,6 +53,12 @@ public function updatedStatus(): void
} }
public function updatedActivityFilter(): void public function updatedActivityFilter(): void
{
$this->trainerFilter = '';
$this->resetPage();
}
public function updatedTrainerFilter(): void
{ {
$this->resetPage(); $this->resetPage();
} }
...@@ -101,13 +111,26 @@ public function render() ...@@ -101,13 +111,26 @@ public function render()
})) }))
->when($this->status, fn ($q) => $q->where('status', $this->status)) ->when($this->status, fn ($q) => $q->where('status', $this->status))
->when($this->activityFilter, fn ($q) => $q->where('activity_id', $this->activityFilter)) ->when($this->activityFilter, fn ($q) => $q->where('activity_id', $this->activityFilter))
->when($this->trainerFilter, fn ($q) => $q->where('default_trainer_id', $this->trainerFilter))
->orderBy($this->sortBy, $this->sortDir); ->orderBy($this->sortBy, $this->sortDir);
$this->applyRoleScope($query); $this->applyRoleScope($query);
$trainers = User::query()
->select('id', 'name_ar', 'name')
->whereHas('roles', fn ($q) => $q->whereIn('slug', ['trainer', 'head_trainer']))
->when($this->activityFilter, fn ($q) => $q->whereIn('id',
TrainingProgram::where('activity_id', $this->activityFilter)
->whereNotNull('default_trainer_id')
->pluck('default_trainer_id')
))
->orderBy('name_ar')
->get();
return view('livewire.programs.program-list', [ return view('livewire.programs.program-list', [
'programs' => $query->paginate(15), 'programs' => $query->paginate(15),
'activities' => Activity::where('is_active', true)->orderBy('name_ar')->get(['id', 'name_ar']), 'activities' => Activity::where('is_active', true)->orderBy('name_ar')->get(['id', 'name_ar']),
'trainers' => $trainers,
'statusOptions' => [ 'statusOptions' => [
'draft' => 'مسودة', 'draft' => 'مسودة',
'active' => 'نشط', 'active' => 'نشط',
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace App\Livewire\Schedule; namespace App\Livewire\Schedule;
use App\Domain\Shared\Traits\UsesBranchScope; use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram; use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Models\TrainingSession; use App\Domain\Training\Models\TrainingSession;
use App\Models\User; use App\Models\User;
...@@ -47,6 +48,11 @@ public function nextWeek(): void ...@@ -47,6 +48,11 @@ public function nextWeek(): void
$this->weekStart = Carbon::parse($this->weekStart)->addWeek()->format('Y-m-d'); $this->weekStart = Carbon::parse($this->weekStart)->addWeek()->format('Y-m-d');
} }
public function updatedProgramFilter(): void
{
$this->trainerFilter = '';
}
public function goToToday(): void public function goToToday(): void
{ {
$today = Carbon::today(); $today = Carbon::today();
...@@ -118,10 +124,15 @@ public function render() ...@@ -118,10 +124,15 @@ public function render()
->orderBy('name_ar') ->orderBy('name_ar')
->get(); ->get();
// Trainers for filter // Trainers for filter — cascade from program
$trainers = User::query() $trainers = User::query()
->select('id', 'name_ar', 'name') ->select('id', 'name_ar', 'name')
->whereHas('roles', fn ($q) => $q->whereIn('slug', ['trainer', 'head_trainer'])) ->whereHas('roles', fn ($q) => $q->whereIn('slug', ['trainer', 'head_trainer']))
->when($this->programFilter, fn ($q) => $q->whereIn('id',
TrainingGroup::where('training_program_id', $this->programFilter)
->whereNotNull('head_trainer_id')
->pluck('head_trainer_id')
))
->orderBy('name_ar') ->orderBy('name_ar')
->get(); ->get();
......
...@@ -205,27 +205,35 @@ class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transi ...@@ -205,27 +205,35 @@ class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transi
</a> </a>
@endif @endif
{{-- Section with items --}} {{-- Section with items (collapsible) --}}
@elseif(isset($item['section'])) @elseif(isset($item['section']))
@php @php
$visibleItems = collect($item['items'])->filter(function ($child) use ($itemVisible) { $visibleItems = collect($item['items'])->filter(function ($child) use ($itemVisible) {
return $itemVisible($child); return $itemVisible($child);
}); });
$sectionActive = $visibleItems->contains(function ($child) {
return request()->routeIs(Str::before($child['route'], '.index') . '.*');
});
@endphp @endphp
@if($visibleItems->isNotEmpty()) @if($visibleItems->isNotEmpty())
<div class="pt-5 pb-1"> <div x-data="{ open: {{ $sectionActive ? 'true' : 'false' }} }" class="pt-3">
<p class="px-3 text-xs font-semibold uppercase tracking-wider" style="color: var(--brand-sidebar-text, #e2e8f0); opacity: 0.5;">{{ $item['section'] }}</p> <button @click="open = !open" class="w-full flex items-center justify-between px-3 py-1.5 rounded-lg hover:bg-white/5 transition-colors group">
</div> <p class="text-xs font-semibold uppercase tracking-wider" style="color: var(--brand-sidebar-text, #e2e8f0); opacity: 0.5;">{{ $item['section'] }}</p>
<svg class="w-3.5 h-3.5 transition-transform duration-200" :class="open ? 'rotate-180' : ''" fill="none" stroke="currentColor" viewBox="0 0 24 24" style="color: var(--brand-sidebar-text, #e2e8f0); opacity: 0.4;"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
</button>
@foreach($visibleItems as $child) <div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0 -translate-y-1" x-transition:enter-end="opacity-100 translate-y-0" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" class="mt-1 space-y-0.5">
<a href="{{ route($child['route']) }}" @foreach($visibleItems as $child)
class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-150 hover:bg-white/10 active:bg-white/20 active:scale-[0.97]" <a href="{{ route($child['route']) }}"
style="{{ request()->routeIs(Str::before($child['route'], '.index') . '.*') ? 'background-color: var(--brand-sidebar-active, #2563eb); color: #fff;' : 'color: var(--brand-sidebar-text, #e2e8f0);' }}"> class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-150 hover:bg-white/10 active:bg-white/20 active:scale-[0.97]"
<svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">{!! $icons[$child['icon']] ?? '' !!}</svg> style="{{ request()->routeIs(Str::before($child['route'], '.index') . '.*') ? 'background-color: var(--brand-sidebar-active, #2563eb); color: #fff;' : 'color: var(--brand-sidebar-text, #e2e8f0);' }}">
<span>{{ $child['label'] }}</span> <svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">{!! $icons[$child['icon']] ?? '' !!}</svg>
</a> <span>{{ $child['label'] }}</span>
@endforeach </a>
@endforeach
</div>
</div>
@endif @endif
@endif @endif
@endforeach @endforeach
......
...@@ -25,7 +25,7 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-l ...@@ -25,7 +25,7 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-l
{{-- Filters --}} {{-- Filters --}}
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4 mb-4"> <div class="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4 mb-4">
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-3"> <div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3">
<div class="col-span-2 md:col-span-1 lg:col-span-2"> <div class="col-span-2 md:col-span-1 lg:col-span-2">
<input type="text" wire:model.live.debounce.300ms="search" <input type="text" wire:model.live.debounce.300ms="search"
placeholder="{{ __('بحث بالاسم أو رقم المشترك...') }}" placeholder="{{ __('بحث بالاسم أو رقم المشترك...') }}"
...@@ -37,6 +37,12 @@ class="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 f ...@@ -37,6 +37,12 @@ class="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 f
<option value="{{ $value }}">{{ __($label) }}</option> <option value="{{ $value }}">{{ __($label) }}</option>
@endforeach @endforeach
</select> </select>
<select wire:model.live="programFilter" class="text-sm px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل البرامج') }}</option>
@foreach($programs as $program)
<option value="{{ $program->id }}">{{ $program->name_ar }}</option>
@endforeach
</select>
<select wire:model.live="groupFilter" class="text-sm px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> <select wire:model.live="groupFilter" class="text-sm px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل المجموعات') }}</option> <option value="">{{ __('كل المجموعات') }}</option>
@foreach($groups as $group) @foreach($groups as $group)
......
...@@ -29,18 +29,18 @@ class="inline-flex items-center gap-2 px-4 py-2 text-gray-600 bg-gray-100 rounde ...@@ -29,18 +29,18 @@ class="inline-flex items-center gap-2 px-4 py-2 text-gray-600 bg-gray-100 rounde
placeholder="{{ __('بحث بالاسم أو رقم المشترك...') }}" placeholder="{{ __('بحث بالاسم أو رقم المشترك...') }}"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500"> class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
</div> </div>
<select wire:model.live="groupFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
<option value="">{{ __('كل المجموعات') }}</option>
@foreach($groups as $group)
<option value="{{ $group->id }}">{{ $group->name_ar }} ({{ $group->current_count }}/{{ $group->max_capacity }})</option>
@endforeach
</select>
<select wire:model.live="programFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500"> <select wire:model.live="programFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
<option value="">{{ __('كل البرامج') }}</option> <option value="">{{ __('كل البرامج') }}</option>
@foreach($programs as $program) @foreach($programs as $program)
<option value="{{ $program->id }}">{{ $program->name_ar }}</option> <option value="{{ $program->id }}">{{ $program->name_ar }}</option>
@endforeach @endforeach
</select> </select>
<select wire:model.live="groupFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
<option value="">{{ __('كل المجموعات') }}</option>
@foreach($groups as $group)
<option value="{{ $group->id }}">{{ $group->name_ar }} ({{ $group->current_count }}/{{ $group->max_capacity }})</option>
@endforeach
</select>
</div> </div>
</div> </div>
......
...@@ -16,7 +16,7 @@ class="inline-flex items-center gap-2 px-4 py-2.5 bg-blue-600 text-white text-sm ...@@ -16,7 +16,7 @@ class="inline-flex items-center gap-2 px-4 py-2.5 bg-blue-600 text-white text-sm
<!-- Filters --> <!-- Filters -->
<div class="mb-6 p-4 bg-white border border-gray-200 rounded-lg"> <div class="mb-6 p-4 bg-white border border-gray-200 rounded-lg">
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3"> <div class="grid grid-cols-1 gap-4 sm:grid-cols-4">
<!-- Search --> <!-- Search -->
<div> <div>
<label for="search" class="block text-sm font-medium text-gray-700 mb-1">{{ __('بحث بالمشترك') }}</label> <label for="search" class="block text-sm font-medium text-gray-700 mb-1">{{ __('بحث بالمشترك') }}</label>
...@@ -42,6 +42,20 @@ class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:r ...@@ -42,6 +42,20 @@ class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:r
</select> </select>
</div> </div>
<!-- Program Filter -->
<div>
<label for="programFilter" class="block text-sm font-medium text-gray-700 mb-1">{{ __('البرنامج') }}</label>
<select
id="programFilter"
wire:model.live="programFilter"
class="w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 text-sm">
<option value="">{{ __('الكل') }}</option>
@foreach($programs as $program)
<option value="{{ $program->id }}">{{ $program->name_ar }}</option>
@endforeach
</select>
</div>
<!-- Group Filter --> <!-- Group Filter -->
<div> <div>
<label for="groupId" class="block text-sm font-medium text-gray-700 mb-1">{{ __('المجموعة') }}</label> <label for="groupId" class="block text-sm font-medium text-gray-700 mb-1">{{ __('المجموعة') }}</label>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('المنشآت') }}</h1> <h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('المنشآت') }}</h1>
@permission('facilities.create') @permission('facilities.create')
<a href="{{ route('facilities.create') }}" wire:navigate <a href="{{ route('facilities.wizard') }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium"> class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium">
<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="M12 4v16m8-8H4"/></svg> <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="M12 4v16m8-8H4"/></svg>
{{ __('إضافة منشأة') }} {{ __('إضافة منشأة') }}
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('المجموعات التدريبية') }}</h1> <h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('المجموعات التدريبية') }}</h1>
@can('groups.create') @can('groups.create')
<a href="{{ route('groups.create') }}" wire:navigate <a href="{{ route('groups.wizard') }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium"> class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium">
<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="M12 4v16m8-8H4"/></svg> <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="M12 4v16m8-8H4"/></svg>
{{ __('إنشاء مجموعة') }} {{ __('إنشاء مجموعة') }}
...@@ -19,16 +19,16 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-l ...@@ -19,16 +19,16 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-l
{{-- Filters --}} {{-- Filters --}}
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 mb-4"> <div class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 mb-4">
<div class="grid grid-cols-1 sm:grid-cols-4 gap-4"> <div class="grid grid-cols-1 sm:grid-cols-5 gap-4">
<div class="sm:col-span-2"> <div class="sm:col-span-2">
<input type="text" wire:model.live.debounce.300ms="search" <input type="text" wire:model.live.debounce.300ms="search"
placeholder="{{ __('بحث بالاسم أو الكود...') }}" placeholder="{{ __('بحث بالاسم أو الكود...') }}"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div> </div>
<select wire:model.live="status" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> <select wire:model.live="activityFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل الحالات') }}</option> <option value="">{{ __('كل الأنشطة') }}</option>
@foreach($statusOptions as $value => $label) @foreach($activities as $activity)
<option value="{{ $value }}">{{ __($label) }}</option> <option value="{{ $activity->id }}">{{ $activity->name_ar }}</option>
@endforeach @endforeach
</select> </select>
<select wire:model.live="programFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> <select wire:model.live="programFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
...@@ -37,6 +37,12 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:rin ...@@ -37,6 +37,12 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:rin
<option value="{{ $program->id }}">{{ $program->name_ar }}</option> <option value="{{ $program->id }}">{{ $program->name_ar }}</option>
@endforeach @endforeach
</select> </select>
<select wire:model.live="status" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل الحالات') }}</option>
@foreach($statusOptions as $value => $label)
<option value="{{ $value }}">{{ __($label) }}</option>
@endforeach
</select>
</div> </div>
</div> </div>
...@@ -125,7 +131,7 @@ class="text-red-600 hover:text-red-800 text-sm">{{ __('حذف') }}</button> ...@@ -125,7 +131,7 @@ class="text-red-600 hover:text-red-800 text-sm">{{ __('حذف') }}</button>
<td colspan="7" class="px-4 py-12 text-center"> <td colspan="7" class="px-4 py-12 text-center">
<p class="text-gray-500 text-sm">{{ __('لا توجد مجموعات') }}</p> <p class="text-gray-500 text-sm">{{ __('لا توجد مجموعات') }}</p>
@can('groups.create') @can('groups.create')
<a href="{{ route('groups.create') }}" wire:navigate class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium block">{{ __('إنشاء أول مجموعة') }}</a> <a href="{{ route('groups.wizard') }}" wire:navigate class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium block">{{ __('إنشاء أول مجموعة') }}</a>
@endcan @endcan
</td> </td>
</tr> </tr>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6"> <div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
<h1 class="text-2xl font-bold text-gray-900">{{ __('الموظفين') }}</h1> <h1 class="text-2xl font-bold text-gray-900">{{ __('الموظفين') }}</h1>
@can('employees.create') @can('employees.create')
<a href="{{ route('employees.create') }}" wire:navigate <a href="{{ route('employees.wizard') }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2.5 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 transition-colors"> class="inline-flex items-center gap-2 px-4 py-2.5 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 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="M12 4v16m8-8H4"/></svg> <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="M12 4v16m8-8H4"/></svg>
{{ __('إضافة موظف') }} {{ __('إضافة موظف') }}
......
...@@ -21,17 +21,17 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:rin ...@@ -21,17 +21,17 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:rin
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="{{ __('إلى تاريخ') }}"> placeholder="{{ __('إلى تاريخ') }}">
</div> </div>
<select wire:model.live="direction" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل الاتجاهات') }}</option>
<option value="in">{{ __('وارد') }}</option>
<option value="out">{{ __('صادر') }}</option>
</select>
<select wire:model.live="movementType" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> <select wire:model.live="movementType" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل الأنواع') }}</option> <option value="">{{ __('كل الأنواع') }}</option>
@foreach($movementTypeOptions as $value => $label) @foreach($movementTypeOptions as $value => $label)
<option value="{{ $value }}">{{ __($label) }}</option> <option value="{{ $value }}">{{ __($label) }}</option>
@endforeach @endforeach
</select> </select>
<select wire:model.live="direction" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل الاتجاهات') }}</option>
<option value="in">{{ __('وارد') }}</option>
<option value="out">{{ __('صادر') }}</option>
</select>
</div> </div>
<div class="mt-3"> <div class="mt-3">
<select wire:model.live="warehouseFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> <select wire:model.live="warehouseFilter" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('المنتجات') }}</h1> <h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('المنتجات') }}</h1>
@can('inventory.create') @can('inventory.create')
<a href="{{ route('inventory.products.create') }}" wire:navigate <a href="{{ route('inventory.products.wizard') }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium"> class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium">
<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="M12 4v16m8-8H4"/></svg> <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="M12 4v16m8-8H4"/></svg>
{{ __('إضافة منتج') }} {{ __('إضافة منتج') }}
...@@ -118,7 +118,7 @@ class="text-green-600 hover:text-green-800 text-sm">{{ __('تعديل') }}</a> ...@@ -118,7 +118,7 @@ class="text-green-600 hover:text-green-800 text-sm">{{ __('تعديل') }}</a>
</svg> </svg>
<p class="text-gray-500 text-sm">{{ __('لا توجد منتجات') }}</p> <p class="text-gray-500 text-sm">{{ __('لا توجد منتجات') }}</p>
@can('inventory.create') @can('inventory.create')
<a href="{{ route('inventory.products.create') }}" wire:navigate <a href="{{ route('inventory.products.wizard') }}" wire:navigate
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium"> class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium">
{{ __('إضافة أول منتج') }} {{ __('إضافة أول منتج') }}
</a> </a>
......
...@@ -8,7 +8,7 @@ class="inline-flex items-center gap-2 px-3 py-2 bg-green-600 text-white rounded- ...@@ -8,7 +8,7 @@ class="inline-flex items-center gap-2 px-3 py-2 bg-green-600 text-white rounded-
{{ __('تصدير CSV') }} {{ __('تصدير CSV') }}
</a> </a>
@can('invoices.create') @can('invoices.create')
<a href="{{ route('invoices.create') }}" wire:navigate <a href="{{ route('invoices.wizard') }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium"> class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium">
<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="M12 4v16m8-8H4"/></svg> <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="M12 4v16m8-8H4"/></svg>
{{ __('إنشاء فاتورة') }} {{ __('إنشاء فاتورة') }}
...@@ -127,7 +127,7 @@ class="text-blue-600 hover:text-blue-800 text-sm">{{ __('عرض') }}</a> ...@@ -127,7 +127,7 @@ class="text-blue-600 hover:text-blue-800 text-sm">{{ __('عرض') }}</a>
</svg> </svg>
<p class="text-gray-500 text-sm">{{ __('لا توجد فواتير') }}</p> <p class="text-gray-500 text-sm">{{ __('لا توجد فواتير') }}</p>
@can('invoices.create') @can('invoices.create')
<a href="{{ route('invoices.create') }}" wire:navigate <a href="{{ route('invoices.wizard') }}" wire:navigate
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium"> class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium">
{{ __('إنشاء أول فاتورة') }} {{ __('إنشاء أول فاتورة') }}
</a> </a>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4 sm:mb-6"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4 sm:mb-6">
<h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('قواعد التسعير') }}</h1> <h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('قواعد التسعير') }}</h1>
@can('pricing.create') @can('pricing.create')
<a href="{{ route('pricing.rules.create') }}" wire:navigate <a href="{{ route('pricing.rules.wizard') }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium"> class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium">
<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="M12 4v16m8-8H4"/></svg> <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="M12 4v16m8-8H4"/></svg>
<span class="hidden sm:inline">{{ __('إضافة قاعدة') }}</span> <span class="hidden sm:inline">{{ __('إضافة قاعدة') }}</span>
...@@ -120,7 +120,7 @@ class="text-blue-600 hover:text-blue-800 text-sm">{{ __('تعديل') }}</a> ...@@ -120,7 +120,7 @@ class="text-blue-600 hover:text-blue-800 text-sm">{{ __('تعديل') }}</a>
</svg> </svg>
<p class="text-gray-500 text-sm">{{ __('لا توجد قواعد تسعير') }}</p> <p class="text-gray-500 text-sm">{{ __('لا توجد قواعد تسعير') }}</p>
@can('pricing.create') @can('pricing.create')
<a href="{{ route('pricing.rules.create') }}" wire:navigate <a href="{{ route('pricing.rules.wizard') }}" wire:navigate
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium"> class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium">
{{ __('إضافة أول قاعدة') }} {{ __('إضافة أول قاعدة') }}
</a> </a>
...@@ -208,7 +208,7 @@ class="block text-center py-2 text-blue-600 hover:text-blue-800 text-sm font-med ...@@ -208,7 +208,7 @@ class="block text-center py-2 text-blue-600 hover:text-blue-800 text-sm font-med
</svg> </svg>
<p class="text-gray-500 text-sm">{{ __('لا توجد قواعد تسعير') }}</p> <p class="text-gray-500 text-sm">{{ __('لا توجد قواعد تسعير') }}</p>
@can('pricing.create') @can('pricing.create')
<a href="{{ route('pricing.rules.create') }}" wire:navigate <a href="{{ route('pricing.rules.wizard') }}" wire:navigate
class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium"> class="mt-2 text-blue-600 hover:text-blue-800 text-sm font-medium">
{{ __('إضافة أول قاعدة') }} {{ __('إضافة أول قاعدة') }}
</a> </a>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4 sm:mb-6"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4 sm:mb-6">
<h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('البرامج التدريبية') }}</h1> <h1 class="text-xl sm:text-2xl font-bold text-gray-800">{{ __('البرامج التدريبية') }}</h1>
@permission('programs.create') @permission('programs.create')
<a href="{{ route('programs.create') }}" wire:navigate <a href="{{ route('programs.wizard') }}" wire:navigate
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium"> class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium">
<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="M12 4v16m8-8H4"/></svg> <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="M12 4v16m8-8H4"/></svg>
<span class="hidden sm:inline">{{ __('إضافة برنامج') }}</span> <span class="hidden sm:inline">{{ __('إضافة برنامج') }}</span>
...@@ -24,7 +24,7 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-l ...@@ -24,7 +24,7 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-l
<!-- Filters --> <!-- Filters -->
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4 mb-4"> <div class="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4 mb-4">
<div class="grid grid-cols-2 md:grid-cols-3 gap-3"> <div class="grid grid-cols-2 md:grid-cols-4 gap-3">
<div class="col-span-2 md:col-span-1"> <div class="col-span-2 md:col-span-1">
<input type="text" wire:model.live.debounce.300ms="search" <input type="text" wire:model.live.debounce.300ms="search"
placeholder="{{ __('بحث بالاسم...') }}" placeholder="{{ __('بحث بالاسم...') }}"
...@@ -36,6 +36,12 @@ class="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 f ...@@ -36,6 +36,12 @@ class="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 f
<option value="{{ $activity->id }}">{{ $activity->name_ar }}</option> <option value="{{ $activity->id }}">{{ $activity->name_ar }}</option>
@endforeach @endforeach
</select> </select>
<select wire:model.live="trainerFilter" class="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل المدربين') }}</option>
@foreach($trainers as $trainer)
<option value="{{ $trainer->id }}">{{ $trainer->name_ar ?: $trainer->name }}</option>
@endforeach
</select>
<select wire:model.live="status" class="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> <select wire:model.live="status" class="px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">{{ __('كل الحالات') }}</option> <option value="">{{ __('كل الحالات') }}</option>
@foreach($statusOptions as $key => $label) @foreach($statusOptions as $key => $label)
......
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