Commit 0618b998 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Add branch switcher in topbar with session-based branch scoping

- BranchSwitcher component in topbar: select branch or "all branches"
- UsesBranchScope trait: all components read active branch from session
- Dashboard/Reports: filter by selected branch, show all when "all"
- Receptionist wizards: use session branch instead of user->branch_id
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 4e5b3052
...@@ -13,29 +13,34 @@ ...@@ -13,29 +13,34 @@
class ReportService class ReportService
{ {
public function financialSummary(string $from, string $to): array public function financialSummary(string $from, string $to, ?int $branchId = null): array
{ {
return [ return [
'total_invoiced' => Invoice::whereBetween('created_at', [$from, $to])->sum('total_amount'), 'total_invoiced' => Invoice::whereBetween('created_at', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('total_amount'),
'total_collected' => Payment::where('status', 'confirmed') 'total_collected' => Payment::where('status', 'confirmed')
->whereBetween('created_at', [$from, $to])->sum('amount'), ->whereBetween('created_at', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('amount'),
'total_outstanding' => Invoice::whereIn('status', ['sent', 'partially_paid', 'overdue']) 'total_outstanding' => Invoice::whereIn('status', ['sent', 'partially_paid', 'overdue'])
->sum('due_amount'), ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('due_amount'),
'pos_revenue' => POSTransaction::whereBetween('processed_at', [$from, $to]) 'pos_revenue' => POSTransaction::whereBetween('processed_at', [$from, $to])
->sum('total_amount'), ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('total_amount'),
'payment_methods' => Payment::where('status', 'confirmed') 'payment_methods' => Payment::where('status', 'confirmed')
->whereBetween('created_at', [$from, $to]) ->whereBetween('created_at', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->select('method', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count')) ->select('method', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count'))
->groupBy('method') ->groupBy('method')
->get()->toArray(), ->get()->toArray(),
]; ];
} }
public function attendanceReport(string $from, string $to, ?int $groupId = null): array public function attendanceReport(string $from, string $to, ?int $groupId = null, ?int $branchId = null): array
{ {
$query = AttendanceRecord::whereBetween('created_at', [$from, $to]); $query = AttendanceRecord::whereBetween('created_at', [$from, $to]);
if ($groupId) { if ($groupId) {
$query->whereHas('session', fn ($q) => $q->where('training_group_id', $groupId)); $query->whereHas('session', fn ($q) => $q->where('training_group_id', $groupId));
} elseif ($branchId) {
$query->whereHas('session.group', fn ($q) => $q->where('branch_id', $branchId));
} }
$total = (clone $query)->count(); $total = (clone $query)->count();
...@@ -53,16 +58,20 @@ public function attendanceReport(string $from, string $to, ?int $groupId = null) ...@@ -53,16 +58,20 @@ public function attendanceReport(string $from, string $to, ?int $groupId = null)
]; ];
} }
public function enrollmentReport(string $from, string $to): array public function enrollmentReport(string $from, string $to, ?int $branchId = null): array
{ {
return [ return [
'new_enrollments' => Enrollment::whereBetween('enrollment_date', [$from, $to])->count(), 'new_enrollments' => Enrollment::whereBetween('enrollment_date', [$from, $to])
->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))->count(),
'by_status' => Enrollment::whereBetween('enrollment_date', [$from, $to]) 'by_status' => Enrollment::whereBetween('enrollment_date', [$from, $to])
->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))
->select('status', DB::raw('COUNT(*) as count')) ->select('status', DB::raw('COUNT(*) as count'))
->groupBy('status') ->groupBy('status')
->pluck('count', 'status')->toArray(), ->pluck('count', 'status')->toArray(),
'active_participants' => Participant::where('status', 'active')->count(), 'active_participants' => Participant::where('status', 'active')
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->count(),
'by_membership_type' => Participant::where('status', 'active') 'by_membership_type' => Participant::where('status', 'active')
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->whereNotNull('membership_type') ->whereNotNull('membership_type')
->select('membership_type', DB::raw('COUNT(*) as count')) ->select('membership_type', DB::raw('COUNT(*) as count'))
->groupBy('membership_type') ->groupBy('membership_type')
...@@ -74,6 +83,7 @@ public function participantList(array $filters = []): \Illuminate\Support\Collec ...@@ -74,6 +83,7 @@ public function participantList(array $filters = []): \Illuminate\Support\Collec
{ {
$query = Participant::with(['person', 'enrollments.group']) $query = Participant::with(['person', 'enrollments.group'])
->when($filters['status'] ?? null, fn ($q, $s) => $q->where('status', $s)) ->when($filters['status'] ?? null, fn ($q, $s) => $q->where('status', $s))
->when($filters['branch_id'] ?? null, fn ($q, $b) => $q->where('branch_id', $b))
->when($filters['group_id'] ?? null, fn ($q, $g) => $q->whereHas( ->when($filters['group_id'] ?? null, fn ($q, $g) => $q->whereHas(
'enrollments', 'enrollments',
fn ($eq) => $eq->where('training_group_id', $g)->where('status', 'active') fn ($eq) => $eq->where('training_group_id', $g)->where('status', 'active')
......
<?php
namespace App\Domain\Shared\Traits;
use App\Domain\Identity\Models\Branch;
trait UsesBranchScope
{
public function getActiveBranchId(): ?int
{
return session('active_branch_id', auth()->user()->branch_id);
}
public function getActiveBranchIdOrFail(): int
{
$id = $this->getActiveBranchId();
if (!$id) {
$id = Branch::where('is_active', true)->first()?->id;
if ($id) {
session(['active_branch_id' => $id]);
}
}
return $id;
}
public function isAllBranches(): bool
{
return session('active_branch_id') === null && !session()->has('active_branch_id');
}
}
<?php
namespace App\Livewire;
use App\Domain\Identity\Models\Branch;
use Livewire\Component;
class BranchSwitcher extends Component
{
public ?int $activeBranchId = null;
public function mount(): void
{
$this->activeBranchId = session('active_branch_id', auth()->user()->branch_id);
if (!$this->activeBranchId) {
$first = Branch::where('is_active', true)->first();
if ($first) {
$this->activeBranchId = $first->id;
session(['active_branch_id' => $first->id]);
}
}
}
public function updatedActiveBranchId($value): void
{
if ($value === 'all') {
session(['active_branch_id' => null]);
$this->activeBranchId = null;
} else {
$branchId = (int) $value;
session(['active_branch_id' => $branchId]);
$this->activeBranchId = $branchId;
}
$this->dispatch('branch-switched', branchId: $this->activeBranchId);
$this->redirect(request()->header('Referer', '/'), navigate: true);
}
public function render()
{
return view('livewire.branch-switcher', [
'branches' => Branch::where('is_active', true)->get(['id', 'name_ar', 'code']),
]);
}
}
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
use App\Domain\Inventory\Models\Product; use App\Domain\Inventory\Models\Product;
use App\Domain\Participant\Models\Participant; use App\Domain\Participant\Models\Participant;
use App\Domain\POS\Models\POSTransaction; use App\Domain\POS\Models\POSTransaction;
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\TrainingSession; use App\Domain\Training\Models\TrainingSession;
...@@ -21,32 +22,42 @@ ...@@ -21,32 +22,42 @@
#[Title('لوحة التحكم')] #[Title('لوحة التحكم')]
class Dashboard extends Component class Dashboard extends Component
{ {
use UsesBranchScope;
public function render() public function render()
{ {
$today = now()->toDateString(); $today = now()->toDateString();
$thisMonth = now()->startOfMonth()->toDateString(); $thisMonth = now()->startOfMonth()->toDateString();
$branchId = $this->getActiveBranchId();
// Key metrics
$stats = [ $stats = [
'active_participants' => Participant::where('status', 'active')->count(), 'active_participants' => Participant::where('status', 'active')
'active_enrollments' => Enrollment::where('status', 'active')->count(), ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->count(),
'active_groups' => TrainingGroup::whereIn('status', ['active', 'full'])->count(), 'active_enrollments' => Enrollment::where('status', 'active')
'today_sessions' => TrainingSession::where('session_date', $today)->count(), ->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))->count(),
'active_groups' => TrainingGroup::whereIn('status', ['active', 'full'])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->count(),
'today_sessions' => TrainingSession::where('session_date', $today)
->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))->count(),
]; ];
// Financial summary (this month)
$financial = [ $financial = [
'revenue_this_month' => Payment::where('status', 'confirmed') 'revenue_this_month' => Payment::where('status', 'confirmed')
->whereDate('created_at', '>=', $thisMonth)->sum('amount'), ->whereDate('created_at', '>=', $thisMonth)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('amount'),
'outstanding_invoices' => Invoice::whereIn('status', [ 'outstanding_invoices' => Invoice::whereIn('status', [
InvoiceStatus::Sent, InvoiceStatus::PartiallyPaid, InvoiceStatus::Overdue, InvoiceStatus::Sent, InvoiceStatus::PartiallyPaid, InvoiceStatus::Overdue,
])->sum('due_amount'), ])->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('due_amount'),
'pos_today' => POSTransaction::whereDate('processed_at', $today)->sum('total_amount'), 'pos_today' => POSTransaction::whereDate('processed_at', $today)
'pos_today_count' => POSTransaction::whereDate('processed_at', $today)->count(), ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('total_amount'),
'pos_today_count' => POSTransaction::whereDate('processed_at', $today)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->count(),
]; ];
// Attendance today $todaySessions = TrainingSession::where('session_date', $today)
$todaySessions = TrainingSession::where('session_date', $today)->pluck('id'); ->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))
->pluck('id');
$attendance = [ $attendance = [
'expected' => AttendanceRecord::whereIn('training_session_id', $todaySessions)->count(), 'expected' => AttendanceRecord::whereIn('training_session_id', $todaySessions)->count(),
'present' => AttendanceRecord::whereIn('training_session_id', $todaySessions) 'present' => AttendanceRecord::whereIn('training_session_id', $todaySessions)
...@@ -58,23 +69,23 @@ public function render() ...@@ -58,23 +69,23 @@ public function render()
? round(($attendance['present'] / $attendance['expected']) * 100, 0) ? round(($attendance['present'] / $attendance['expected']) * 100, 0)
: 0; : 0;
// Low stock alerts
$lowStockCount = Product::where('track_inventory', true) $lowStockCount = Product::where('track_inventory', true)
->where('is_active', true) ->where('is_active', true)
->whereNotNull('min_stock_level') ->whereNotNull('min_stock_level')
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->whereHas('inventoryLevels', function ($q) { ->whereHas('inventoryLevels', function ($q) {
$q->whereRaw('quantity_on_hand < (SELECT min_stock_level FROM products WHERE products.id = inventory_levels.product_id)'); $q->whereRaw('quantity_on_hand < (SELECT min_stock_level FROM products WHERE products.id = inventory_levels.product_id)');
})->count(); })->count();
// Groups near capacity
$nearFullGroups = TrainingGroup::where('status', 'active') $nearFullGroups = TrainingGroup::where('status', 'active')
->whereRaw('current_count >= max_capacity * 0.9') ->whereRaw('current_count >= max_capacity * 0.9')
->where('max_capacity', '>', 0) ->where('max_capacity', '>', 0)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->count(); ->count();
// Recent enrollments (last 7 days)
$recentEnrollments = Enrollment::where('status', 'active') $recentEnrollments = Enrollment::where('status', 'active')
->where('created_at', '>=', now()->subDays(7)) ->where('created_at', '>=', now()->subDays(7))
->when($branchId, fn ($q) => $q->whereHas('group', fn ($g) => $g->where('branch_id', $branchId)))
->count(); ->count();
return view('livewire.dashboard', [ return view('livewire.dashboard', [
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
use App\Domain\Financial\Services\PaymentService; use App\Domain\Financial\Services\PaymentService;
use App\Domain\Participant\Models\Participant; use App\Domain\Participant\Models\Participant;
use App\Domain\Shared\Exceptions\DomainException; use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Traits\UsesBranchScope;
use Livewire\Attributes\Layout; use Livewire\Attributes\Layout;
use Livewire\Attributes\Title; use Livewire\Attributes\Title;
use Livewire\Component; use Livewire\Component;
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
#[Title('تحصيل مدفوعات')] #[Title('تحصيل مدفوعات')]
class CollectPaymentWizard extends Component class CollectPaymentWizard extends Component
{ {
use UsesBranchScope;
public ?int $branchId = null; public ?int $branchId = null;
public int $currentStep = 1; public int $currentStep = 1;
...@@ -41,13 +44,7 @@ class CollectPaymentWizard extends Component ...@@ -41,13 +44,7 @@ class CollectPaymentWizard extends Component
public function mount(): void public function mount(): void
{ {
$this->authorize('invoices.create'); $this->authorize('invoices.create');
$this->branchId = $this->getActiveBranchIdOrFail();
$user = auth()->user();
$this->branchId = $user->branch_id;
if (!$this->branchId) {
$this->branchId = \App\Domain\Identity\Models\Branch::where('is_active', true)->first()?->id;
}
} }
public function rules(): array public function rules(): array
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
use App\Domain\Participant\Models\Participant; use App\Domain\Participant\Models\Participant;
use App\Domain\Shared\Exceptions\DomainException; use App\Domain\Shared\Exceptions\DomainException;
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;
use App\Domain\Training\Models\TrainingProgram; use App\Domain\Training\Models\TrainingProgram;
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
#[Title('تسجيل في برنامج')] #[Title('تسجيل في برنامج')]
class EnrollExistingWizard extends Component class EnrollExistingWizard extends Component
{ {
use UsesBranchScope;
public ?int $branchId = null; public ?int $branchId = null;
public int $currentStep = 1; public int $currentStep = 1;
...@@ -39,13 +42,7 @@ class EnrollExistingWizard extends Component ...@@ -39,13 +42,7 @@ class EnrollExistingWizard extends Component
public function mount(): void public function mount(): void
{ {
$this->authorize('enrollments.create'); $this->authorize('enrollments.create');
$this->branchId = $this->getActiveBranchIdOrFail();
$user = auth()->user();
$this->branchId = $user->branch_id;
if (!$this->branchId) {
$this->branchId = \App\Domain\Identity\Models\Branch::where('is_active', true)->first()?->id;
}
} }
public function rules(): array public function rules(): array
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
use App\Domain\Financial\Enums\PaymentMethod; use App\Domain\Financial\Enums\PaymentMethod;
use App\Domain\Participant\Services\ParticipantService; use App\Domain\Participant\Services\ParticipantService;
use App\Domain\Shared\Exceptions\DomainException; use App\Domain\Shared\Exceptions\DomainException;
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;
use Livewire\Attributes\Layout; use Livewire\Attributes\Layout;
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
#[Title('تسجيل جديد')] #[Title('تسجيل جديد')]
class NewRegistrationWizard extends Component class NewRegistrationWizard extends Component
{ {
use UsesBranchScope;
public ?int $branchId = null; public ?int $branchId = null;
public int $currentStep = 1; public int $currentStep = 1;
...@@ -51,13 +54,7 @@ class NewRegistrationWizard extends Component ...@@ -51,13 +54,7 @@ class NewRegistrationWizard extends Component
public function mount(): void public function mount(): void
{ {
$this->authorize('participants.create'); $this->authorize('participants.create');
$this->branchId = $this->getActiveBranchIdOrFail();
$user = auth()->user();
$this->branchId = $user->branch_id;
if (!$this->branchId) {
$this->branchId = \App\Domain\Identity\Models\Branch::where('is_active', true)->first()?->id;
}
} }
public function rules(): array public function rules(): array
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
use App\Domain\Financial\Models\Payment; use App\Domain\Financial\Models\Payment;
use App\Domain\Participant\Models\Participant; use App\Domain\Participant\Models\Participant;
use App\Domain\Training\Models\TrainingSession; use App\Domain\Training\Models\TrainingSession;
use App\Domain\Shared\Traits\UsesBranchScope;
use Livewire\Attributes\Layout; use Livewire\Attributes\Layout;
use Livewire\Attributes\Title; use Livewire\Attributes\Title;
use Livewire\Component; use Livewire\Component;
...@@ -15,24 +16,16 @@ ...@@ -15,24 +16,16 @@
#[Title('مكتب الاستقبال')] #[Title('مكتب الاستقبال')]
class ReceptionistDashboard extends Component class ReceptionistDashboard extends Component
{ {
use UsesBranchScope;
public ?int $branchId = null; public ?int $branchId = null;
public string $branchName = ''; public string $branchName = '';
public function mount(): void public function mount(): void
{ {
$this->authorize('participants.list'); $this->authorize('participants.list');
$this->branchId = $this->getActiveBranchIdOrFail();
$user = auth()->user(); $this->branchName = \App\Domain\Identity\Models\Branch::find($this->branchId)?->name_ar ?? '';
$this->branchId = $user->branch_id;
if (!$this->branchId) {
$firstBranch = \App\Domain\Identity\Models\Branch::where('is_active', true)->first();
$this->branchId = $firstBranch?->id;
}
$this->branchName = $this->branchId
? (\App\Domain\Identity\Models\Branch::find($this->branchId)?->name_ar ?? '')
: '';
} }
public function render() public function render()
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace App\Livewire\Reports; namespace App\Livewire\Reports;
use App\Domain\Shared\Services\ReportService; use App\Domain\Shared\Services\ReportService;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\TrainingGroup; use App\Domain\Training\Models\TrainingGroup;
use Livewire\Attributes\Layout; use Livewire\Attributes\Layout;
use Livewire\Attributes\Title; use Livewire\Attributes\Title;
...@@ -13,6 +14,8 @@ ...@@ -13,6 +14,8 @@
#[Title('التقارير')] #[Title('التقارير')]
class ReportsPage extends Component class ReportsPage extends Component
{ {
use UsesBranchScope;
#[Url] #[Url]
public string $reportType = 'financial'; public string $reportType = 'financial';
...@@ -38,16 +41,19 @@ public function setReportType(string $type): void ...@@ -38,16 +41,19 @@ public function setReportType(string $type): void
public function render(ReportService $reportService) public function render(ReportService $reportService)
{ {
$branchId = $this->getActiveBranchId();
$reportData = match ($this->reportType) { $reportData = match ($this->reportType) {
'financial' => $reportService->financialSummary($this->dateFrom, $this->dateTo), 'financial' => $reportService->financialSummary($this->dateFrom, $this->dateTo, $branchId),
'attendance' => $reportService->attendanceReport($this->dateFrom, $this->dateTo, $this->groupId), 'attendance' => $reportService->attendanceReport($this->dateFrom, $this->dateTo, $this->groupId, $branchId),
'enrollment' => $reportService->enrollmentReport($this->dateFrom, $this->dateTo), 'enrollment' => $reportService->enrollmentReport($this->dateFrom, $this->dateTo, $branchId),
default => [], default => [],
}; };
return view('livewire.reports.reports-page', [ return view('livewire.reports.reports-page', [
'reportData' => $reportData, 'reportData' => $reportData,
'groups' => TrainingGroup::orderBy('name_ar')->get(), 'groups' => TrainingGroup::orderBy('name_ar')
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->get(),
]); ]);
} }
} }
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
<!-- Right side --> <!-- Right side -->
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<!-- Branch Switcher -->
@livewire('branch-switcher')
<!-- Notifications bell (placeholder) --> <!-- Notifications bell (placeholder) -->
<button class="relative text-gray-500 hover:text-gray-700"> <button class="relative text-gray-500 hover:text-gray-700">
<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="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></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="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>
......
<div class="relative">
<select wire:model.live="activeBranchId"
class="appearance-none bg-gray-50 border border-gray-200 rounded-lg px-3 py-1.5 pe-8 text-sm font-medium text-gray-700 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 cursor-pointer">
<option value="all">{{ __('كل الفروع') }}</option>
@foreach($branches as $branch)
<option value="{{ $branch->id }}">{{ $branch->name_ar }}</option>
@endforeach
</select>
<div class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-2.5">
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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>
</div>
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