Commit 9454aa03 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Replace emoji with icons; scope schedule builder by branch and sport

Icons
- No emoji anywhere in the UI. Extracted the sidebar's inline SVG map into
  a single <x-ui.icon name="..."> component and added the icons the pricing
  work needed, so there is one source instead of a per-view copy. Discount
  recipes now carry icon NAMES, not glyphs.

Schedule builder
- Facilities are scoped to the selected branch. The screen listed every
  branch's facilities, which is how someone books the wrong building. A
  ?facility_id= carried over from another branch (bookmark, back button) is
  now dropped instead of silently overriding the branch scope.
- Groups are scoped to the facility's branch AND to the sports that facility
  hosts, so a football court no longer offers swimming groups. That link did
  not exist, so this adds a facility_activities pivot. A facility that
  declares no activities still hosts anything, so nothing breaks for academies
  that have not filled it in.

Facility grid
- Removed the arbitrary ceilings (rows/columns capped at 10, lanes at 20).
  Physical space is not limited to a number we picked.
- New facilities never got a layout, which is why the grid silently failed to
  appear on them. FacilityService::create now seeds one, the migration
  backfills every existing facility that has none, and the default is a 1x1
  grid — "one whole space, not subdivided yet" — rather than inventing a
  subdivision nobody asked for.
- Grid size is editable straight from facility settings, with a live preview
  of the cells being described. Shrinking onto a segment that holds a
  confirmed future reservation is refused rather than silently dropping
  someone's booking.
- Sports and starting grid are both settable at creation time too.
Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
parent b3f127c8
......@@ -98,6 +98,26 @@ public function reservations(): HasMany
return $this->hasMany(SpaceReservation::class);
}
/**
* Sports this facility can host. Empty = hosts anything (the default for
* facilities created before the link existed).
*/
public function activities(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
{
return $this->belongsToMany(
\App\Domain\Training\Models\Activity::class,
'facility_activities',
'facility_id',
'activity_id'
)->withTimestamps();
}
/** Facilities belonging to one branch. */
public function scopeForBranch($query, ?int $branchId)
{
return $branchId ? $query->where('branch_id', $branchId) : $query;
}
public function scopeActive($query)
{
return $query->where('status', FacilityStatus::Active);
......
......@@ -19,13 +19,36 @@ class FacilityService
'unavailable' => ['active'],
];
public function create(array $data, User $creator): Facility
public function __construct(private SpaceLayoutService $layouts) {}
/**
* @param array $data Facility attributes
* @param User $creator
* @param array $activityIds Sports this facility can host (empty = any)
* @param array $grid ['rows' => n, 'columns' => n] for the starting layout
*/
public function create(array $data, User $creator, array $activityIds = [], array $grid = []): Facility
{
return DB::transaction(function () use ($data, $creator) {
return Facility::create([
return DB::transaction(function () use ($data, $creator, $activityIds, $grid) {
$facility = Facility::create([
...$data,
'created_by' => $creator->id,
]);
if ($activityIds) {
$facility->activities()->sync($activityIds);
}
// Every facility gets a layout on day one. Without one the schedule
// grid renders empty and the facility looks broken rather than new.
$this->layouts->createDefaultLayout(
$facility,
$creator,
max(1, (int) ($grid['rows'] ?? 1)),
max(1, (int) ($grid['columns'] ?? 1)),
);
return $facility->fresh();
});
}
......
......@@ -2,7 +2,9 @@
namespace App\Domain\Facility\Services;
use App\Domain\Facility\Models\Facility;
use App\Domain\Facility\Models\SpaceLayout;
use App\Domain\Facility\Models\SpaceReservation;
use App\Domain\Facility\Models\SpaceSegment;
use App\Domain\Shared\Exceptions\DomainException;
use App\Models\User;
......@@ -32,6 +34,82 @@ public function create(array $data, User $creator): SpaceLayout
/**
* Update a layout. Regenerates segments if type/config changed.
*/
/**
* The starting layout for a new facility.
*
* Defaults to a single 1x1 cell — "the whole facility, not subdivided yet" —
* which is honest and keeps the schedule grid from rendering empty. The
* academy resizes it in facility settings whenever they are ready.
*/
public function createDefaultLayout(
Facility $facility,
User $creator,
int $rows = 1,
int $columns = 1
): SpaceLayout {
return $this->create([
'academy_id' => $facility->academy_id,
'facility_id' => $facility->id,
'name' => 'Default layout',
'name_ar' => 'التقسيم الافتراضي',
'layout_type' => 'grid',
'layout_config' => ['rows' => max(1, $rows), 'columns' => max(1, $columns)],
'is_recurring' => true,
'start_time' => $facility->operating_start ?: '00:00',
'end_time' => $facility->operating_end ?: '23:59',
'metadata' => ['auto_created' => true],
], $creator);
}
/**
* Resize a grid layout in place, regenerating its segments.
*
* Segments currently held by a confirmed reservation are protected — a
* shrink that would orphan a booking is refused rather than silently
* dropping someone's slot.
*/
public function resizeGrid(SpaceLayout $layout, int $rows, int $columns): SpaceLayout
{
$rows = max(1, $rows);
$columns = max(1, $columns);
$keptCodes = [];
for ($r = 1; $r <= $rows; $r++) {
for ($c = 1; $c <= $columns; $c++) {
$keptCodes[] = "R{$r}C{$c}";
}
}
$droppedIds = $layout->segments()
->whereNotIn('code', $keptCodes)
->pluck('id');
if ($droppedIds->isNotEmpty()) {
$inUse = SpaceReservation::where('status', 'confirmed')
->where('facility_id', $layout->facility_id)
->whereDate('reservation_date', '>=', now()->toDateString())
->get()
->filter(function ($reservation) use ($droppedIds) {
$segments = is_array($reservation->segment_ids)
? $reservation->segment_ids
: json_decode($reservation->segment_ids ?? '[]', true);
return ! empty(array_intersect($droppedIds->all(), $segments ?? []));
});
if ($inUse->isNotEmpty()) {
throw new DomainException(
'لا يمكن تصغير التقسيم: توجد حجوزات مؤكدة على الأجزاء التي ستُحذف'
);
}
}
return $this->update($layout, [
'layout_type' => 'grid',
'layout_config' => ['rows' => $rows, 'columns' => $columns],
]);
}
public function update(SpaceLayout $layout, array $data): SpaceLayout
{
return DB::transaction(function () use ($layout, $data) {
......
......@@ -5,6 +5,7 @@
/**
* The twelve discounts a sports academy actually gives.
*
* Icons are icon NAMES resolved by <x-ui.icon>, never emoji.
* A recipe pre-fills the builder — rule type, conditions, adjustment, stacking,
* pin — so authoring a sibling discount is "change two numbers", not five steps
* of database columns. Recipes are templates, not rows: once created the rule is
......@@ -14,7 +15,7 @@
{
public const RECIPES = [
'sibling' => [
'icon' => '👨‍👩‍👧',
'icon' => 'user-group',
'name_ar' => 'خصم الإخوة',
'hint_ar' => 'الابن الثاني فأكثر',
'rule_type' => 'sibling_order',
......@@ -25,7 +26,7 @@
'is_pinned' => true,
],
'early_bird' => [
'icon' => '🐦',
'icon' => 'clock',
'name_ar' => 'الحجز المبكر',
'hint_ar' => 'قبل بداية الموسم',
'rule_type' => 'enrollment_timing',
......@@ -36,7 +37,7 @@
'is_pinned' => true,
],
'scholarship' => [
'icon' => '🎓',
'icon' => 'academic-cap',
'name_ar' => 'منحة دراسية',
'hint_ar' => 'حسب التصنيف',
'rule_type' => 'classification',
......@@ -47,7 +48,7 @@
'is_pinned' => false,
],
'extra_program' => [
'icon' => '🏃',
'icon' => 'squares-plus',
'name_ar' => 'برنامج إضافي',
'hint_ar' => 'من البرنامج الثاني',
'rule_type' => 'enrollment_volume',
......@@ -58,7 +59,7 @@
'is_pinned' => true,
],
'morning_slot' => [
'icon' => '🌅',
'icon' => 'sun',
'name_ar' => 'مواعيد الصباح',
'hint_ar' => 'قبل الساعة ٣',
'rule_type' => 'day_time',
......@@ -69,7 +70,7 @@
'is_pinned' => false,
],
'annual' => [
'icon' => '📅',
'icon' => 'calendar-days',
'name_ar' => 'اشتراك سنوي',
'hint_ar' => 'دفعة واحدة',
'rule_type' => 'membership_duration',
......@@ -80,7 +81,7 @@
'is_pinned' => false,
],
'staff_child' => [
'icon' => '👔',
'icon' => 'briefcase',
'name_ar' => 'أبناء العاملين',
'hint_ar' => 'يُجمع مع غيره',
'rule_type' => 'classification',
......@@ -91,7 +92,7 @@
'is_pinned' => false,
],
'loyalty' => [
'icon' => '',
'icon' => 'shield-check',
'name_ar' => 'عضو قديم',
'hint_ar' => 'بعد ١٢ شهر',
'rule_type' => 'loyalty',
......@@ -102,7 +103,7 @@
'is_pinned' => false,
],
'season_end' => [
'icon' => '🏁',
'icon' => 'flag',
'name_ar' => 'نهاية الموسم',
'hint_ar' => 'شهور محددة',
'rule_type' => 'seasonal',
......@@ -113,7 +114,7 @@
'is_pinned' => false,
],
'birthday' => [
'icon' => '🎂',
'icon' => 'cake',
'name_ar' => 'عرض عيد الميلاد',
'hint_ar' => 'شهر الميلاد',
'rule_type' => 'seasonal',
......@@ -124,7 +125,7 @@
'is_pinned' => false,
],
'juniors' => [
'icon' => '🧒',
'icon' => 'user',
'name_ar' => 'خصم البراعم',
'hint_ar' => 'أقل من ٧ سنوات',
'rule_type' => 'age',
......@@ -135,7 +136,7 @@
'is_pinned' => false,
],
'manual' => [
'icon' => '',
'icon' => 'hand-raised',
'name_ar' => 'خصم استثنائي',
'hint_ar' => 'يدوي باعتماد',
'rule_type' => 'custom',
......
......@@ -50,6 +50,13 @@ public function mount(): void
$this->branches = Branch::orderBy('name_ar')->get(['id', 'name_ar'])->toArray();
}
/** Sports this facility can host (empty = any). */
public array $activityIds = [];
/** Starting grid. 1x1 means "one whole space, not subdivided yet". */
public int $gridRows = 1;
public int $gridColumns = 1;
public function getStepLabels(): array
{
return [
......@@ -150,7 +157,12 @@ public function confirm(): void
'status' => 'active',
];
app(FacilityService::class)->create($data, auth()->user());
app(FacilityService::class)->create(
$data,
auth()->user(),
$this->activityIds,
['rows' => $this->gridRows, 'columns' => $this->gridColumns],
);
$this->completed = true;
session()->flash('success', 'تم إنشاء المنشأة بنجاح');
......@@ -161,6 +173,10 @@ public function confirm(): void
public function render()
{
return view('livewire.facilities.create-facility-wizard');
return view('livewire.facilities.create-facility-wizard', [
'activities' => \App\Domain\Training\Models\Activity::where('is_active', true)
->orderBy('name_ar')
->get(['id', 'name_ar']),
]);
}
}
......@@ -42,6 +42,14 @@ class FacilityForm extends Component
public ?string $latitude = null;
public ?string $longitude = null;
public int $sort_order = 0;
/** Sports this facility hosts. Empty = any sport (no filtering). */
public array $activityIds = [];
/** Live grid size, edited straight from facility settings. */
public int $gridRows = 1;
public int $gridColumns = 1;
public ?string $gridError = null;
public string $branch_id = '';
public function mount(?Facility $facility = null): void
......@@ -75,6 +83,13 @@ public function mount(?Facility $facility = null): void
$this->longitude = $facility->longitude;
$this->sort_order = $facility->sort_order;
$this->branch_id = (string) $facility->branch_id;
$this->activityIds = $facility->activities()->pluck('activities.id')->all();
$layout = $facility->activeLayout;
$config = $layout?->layout_config ?? [];
$this->gridRows = (int) ($config['rows'] ?? 1);
$this->gridColumns = (int) ($config['columns'] ?? 1);
}
}
......@@ -173,9 +188,16 @@ public function save(FacilityService $service): void
if ($this->editing) {
$service->update($this->facility, $data);
$this->facility->activities()->sync($this->activityIds);
$this->syncGrid();
session()->flash('success', __('تم تحديث المنشأة بنجاح'));
} else {
$service->create($data, auth()->user());
$service->create(
$data,
auth()->user(),
$this->activityIds,
['rows' => $this->gridRows, 'columns' => $this->gridColumns],
);
session()->flash('success', __('تم إنشاء المنشأة بنجاح'));
}
......@@ -185,10 +207,49 @@ public function save(FacilityService $service): void
}
}
/**
* Apply the grid size typed in facility settings.
*
* A facility with no layout gets one rather than staying grid-less — that
* silent gap is why new facilities showed an empty schedule.
*/
private function syncGrid(): void
{
$this->gridError = null;
$layouts = app(\App\Domain\Facility\Services\SpaceLayoutService::class);
$rows = max(1, $this->gridRows);
$columns = max(1, $this->gridColumns);
try {
$layout = $this->facility->activeLayout;
if (! $layout) {
$layouts->createDefaultLayout($this->facility, auth()->user(), $rows, $columns);
return;
}
$config = $layout->layout_config ?? [];
if ((int) ($config['rows'] ?? 0) === $rows && (int) ($config['columns'] ?? 0) === $columns) {
return;
}
$layouts->resizeGrid($layout, $rows, $columns);
} catch (DomainException $e) {
// Shrinking onto a booked segment is refused; keep the rest of the save.
$this->gridError = $e->getMessage();
session()->flash('warning', $e->getMessage());
}
}
public function render()
{
return view('livewire.facilities.facility-form', [
'branches' => Branch::orderBy('name_ar')->get(['id', 'name_ar']),
'activities' => \App\Domain\Training\Models\Activity::where('is_active', true)
->orderBy('name_ar')
->get(['id', 'name_ar']),
'typeOptions' => collect(FacilityType::cases())->mapWithKeys(fn ($t) => [$t->value => $t->label()]),
'statusOptions' => collect(FacilityStatus::cases())->mapWithKeys(fn ($s) => [$s->value => $s->label()]),
]);
......
......@@ -9,6 +9,7 @@
use App\Domain\HR\Services\TrainerWorkloadService;
use App\Domain\Scheduling\Services\ScheduleConflictService;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\TrainingSchedule;
use App\Models\User;
use Illuminate\Support\Carbon;
......@@ -22,6 +23,8 @@
#[Title('جدولة المنشآت')]
class VisualScheduleBuilder extends Component
{
use UsesBranchScope;
#[Url]
public string $facility_id = '';
......@@ -58,11 +61,30 @@ public function mount(): void
if (!$this->selectedDay) {
$this->selectedDay = now()->toDateString();
}
// A ?facility_id= carried over from another branch (bookmark, back
// button, shared link) must not survive the branch scope.
if ($this->facility_id) {
$branchId = $this->getActiveBranchId();
$belongs = Facility::where('id', $this->facility_id)
->forBranch($branchId)
->exists();
if (! $belongs) {
$this->facility_id = '';
}
}
}
public function render()
{
$facilities = Facility::active()->with('branch')->orderBy('name_ar')->get();
// Only this branch's facilities. Showing every branch's courts on a
// branch-scoped screen is how a receptionist books the wrong building.
$facilities = Facility::active()
->forBranch($this->getActiveBranchId())
->with('branch')
->orderBy('name_ar')
->get();
$facility = $this->facility_id ? Facility::with('activeLayout')->find($this->facility_id) : null;
......@@ -930,9 +952,29 @@ private function resolveLayout(?Facility $facility): ?SpaceLayout
->first();
}
/**
* Groups offerable in the selected facility.
*
* Scoped two ways: the facility's branch, and the sports that facility can
* host. A football court must not list swimming groups. A facility that
* declares no activities hosts anything, so nothing breaks for academies
* that have not filled the link in yet.
*/
private function getAvailableGroups(): array
{
$facility = $this->facility_id
? Facility::with('activities:id')->find($this->facility_id)
: null;
$branchId = $facility?->branch_id ?? $this->getActiveBranchId();
$activityIds = $facility ? $facility->activities->pluck('id')->all() : [];
return TrainingGroup::whereIn('status', ['active', 'forming', 'full'])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->when($activityIds, fn ($q) => $q->whereHas(
'program',
fn ($p) => $p->whereIn('activity_id', $activityIds)
))
->with(['program', 'headTrainer'])
->withCount(['schedules as active_schedules_count' => fn ($q) => $q->where('is_active', true)])
->orderBy('name_ar')
......
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
/**
* 1. facility_activities — which sports a facility can host.
*
* Without this the schedule builder offered every group in the academy for
* every facility, so a football court listed swimming groups.
* A facility with NO rows declared hosts anything (existing behaviour), so
* this is additive and nothing breaks until an academy opts in.
*
* 2. A default layout for every facility that has none — the reason the grid
* silently failed to appear on newly created facilities.
*/
return new class extends Migration
{
public function up(): void
{
Schema::create('facility_activities', function (Blueprint $table) {
$table->id();
$table->foreignId('academy_id')->constrained('academies');
$table->foreignId('facility_id')->constrained('facilities')->cascadeOnDelete();
$table->foreignId('activity_id')->constrained('activities')->cascadeOnDelete();
$table->timestamps();
$table->unique(['facility_id', 'activity_id'], 'facility_activities_unique');
$table->index(['academy_id', 'activity_id']);
});
$this->backfillDefaultLayouts();
}
/**
* Every facility needs at least one layout or the schedule grid renders empty.
* A 1x1 grid ("the whole facility") is the honest default — it says the space
* is not subdivided yet, rather than inventing a subdivision nobody asked for.
*/
private function backfillDefaultLayouts(): void
{
$facilities = DB::table('facilities')
->whereNull('deleted_at')
->whereNotExists(function ($q) {
$q->selectRaw('1')->from('space_layouts')
->whereColumn('space_layouts.facility_id', 'facilities.id');
})
->get(['id', 'academy_id', 'created_by', 'operating_start', 'operating_end']);
foreach ($facilities as $facility) {
$layoutId = DB::table('space_layouts')->insertGetId([
'uuid' => (string) Str::uuid(),
'academy_id' => $facility->academy_id,
'facility_id' => $facility->id,
'name' => 'Default layout',
'name_ar' => 'التقسيم الافتراضي',
'layout_type' => 'grid',
'layout_config' => json_encode(['rows' => 1, 'columns' => 1]),
'is_recurring' => true,
'effective_day_of_week' => null,
'effective_date' => null,
'start_time' => $facility->operating_start ?: '00:00:00',
'end_time' => $facility->operating_end ?: '23:59:00',
'is_active' => true,
'sort_order' => 0,
'metadata' => json_encode(['auto_created' => true]),
'created_by' => $facility->created_by,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('space_segments')->insert([
'uuid' => (string) Str::uuid(),
'space_layout_id' => $layoutId,
'code' => 'R1C1',
'name' => 'Whole facility',
'name_ar' => 'المنشأة كاملة',
'row_index' => 1,
'col_index' => 1,
'sort_order' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
}
}
public function down(): void
{
Schema::dropIfExists('facility_activities');
// Only remove layouts this migration created.
$ids = DB::table('space_layouts')->where('metadata->auto_created', true)->pluck('id');
DB::table('space_segments')->whereIn('space_layout_id', $ids)->delete();
DB::table('space_layouts')->whereIn('id', $ids)->delete();
}
};
......@@ -117,48 +117,6 @@
]],
];
$icons = [
'home' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>',
'users' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>',
'user-group' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"/>',
'bolt' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>',
'academic-cap' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222"/>',
'calendar' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>',
'calendar-days' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z"/>',
'clipboard-check' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>',
'document-text' => '<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"/>',
'document' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>',
'banknotes' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.25 18.75a60.07 60.07 0 0115.797 2.101c.727.198 1.453-.342 1.453-1.096V18.75M3.75 4.5v.75A.75.75 0 013 6h-.75m0 0v-.375c0-.621.504-1.125 1.125-1.125H20.25M2.25 6v9m18-10.5v.75c0 .414.336.75.75.75h.75m-1.5-1.5h.375c.621 0 1.125.504 1.125 1.125v9.75c0 .621-.504 1.125-1.125 1.125h-.375m1.5-1.5H21a.75.75 0 00-.75.75v.75m0 0H3.75m0 0h-.375a1.125 1.125 0 01-1.125-1.125V15m1.5 1.5v-.75A.75.75 0 003 15h-.75M15 10.5a3 3 0 11-6 0 3 3 0 016 0zm3 0h.008v.008H18V10.5zm-12 0h.008v.008H6V10.5z"/>',
'building-library' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 21v-8.25M15.75 21v-8.25M8.25 21v-8.25M3 9l9-6 9 6m-1.5 12V10.332A48.36 48.36 0 0012 9.75c-2.551 0-5.056.2-7.5.582V21M3 21h18M12 6.75h.008v.008H12V6.75z"/>',
'wallet' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a2.25 2.25 0 00-2.25-2.25H15a3 3 0 110 6h3.75A2.25 2.25 0 0021 13.5V12zm0 0V9.75a2.25 2.25 0 00-2.25-2.25h-13.5A2.25 2.25 0 003 9.75v10.5A2.25 2.25 0 005.25 22.5h13.5A2.25 2.25 0 0021 20.25V12zM3 9.75V7.5A2.25 2.25 0 015.25 5.25h13.5A2.25 2.25 0 0121 7.5v2.25"/>',
'credit-card' => '<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"/>',
'calculator' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.75 15.75V18m-7.5-6.75h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V13.5zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V18zm2.498-6.75h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V13.5zm0 2.25h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V18zm2.504-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V18zm2.498-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zM8.25 6h7.5v2.25h-7.5V6zM12 2.25c-1.892 0-3.758.11-5.593.322C5.307 2.7 4.5 3.65 4.5 4.757V19.5a2.25 2.25 0 002.25 2.25h10.5a2.25 2.25 0 002.25-2.25V4.757c0-1.108-.806-2.057-1.907-2.185A48.507 48.507 0 0012 2.25z"/>',
'shopping-cart' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 100 4 2 2 0 000-4z"/>',
'clock' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>',
'tag' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"/>',
'adjustments-horizontal' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.5 6h9.75M10.5 6a1.5 1.5 0 11-3 0m3 0a1.5 1.5 0 10-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-9.75 0h9.75"/>',
'gift' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v13m0-13V6a4 4 0 00-4-4 4 4 0 004 4zm0 0V6a4 4 0 014-4 4 4 0 01-4 4zm-8 4h16m-16 0v8a2 2 0 002 2h12a2 2 0 002-2v-8m-16 0h16"/>',
'cube' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"/>',
'building-storefront' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.5 21v-7.5a.75.75 0 01.75-.75h3a.75.75 0 01.75.75V21m-4.5 0H2.36m11.14 0H18m0 0h3.64m-1.39 0V9.349m-16.5 11.65V9.35m0 0a3.001 3.001 0 003.75-.615A2.993 2.993 0 009.75 9.75c.896 0 1.7-.393 2.25-1.016a2.993 2.993 0 002.25 1.016c.896 0 1.7-.393 2.25-1.016a3.001 3.001 0 003.75.614m-16.5 0a3.004 3.004 0 01-.621-4.72L4.318 3.44A1.5 1.5 0 015.378 3h13.243a1.5 1.5 0 011.06.44l1.19 1.189a3 3 0 01-.621 4.72m-13.5 8.65h3.75a.75.75 0 00.75-.75V13.5a.75.75 0 00-.75-.75H6.75a.75.75 0 00-.75.75v3.75c0 .415.336.75.75.75z"/>',
'truck' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.25 18.75a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m3 0h6m-9 0H3.375a1.125 1.125 0 01-1.125-1.125V14.25m17.25 4.5a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m3 0h1.125c.621 0 1.129-.504 1.09-1.124a17.902 17.902 0 00-3.213-9.193 2.056 2.056 0 00-1.58-.86H14.25M16.5 18.75h-2.25m0-11.177v-.958c0-.568-.422-1.048-.987-1.106a48.554 48.554 0 00-10.026 0 1.106 1.106 0 00-.987 1.106v7.635m12-6.677v6.677m0 4.5v-4.5m0 0h-12"/>',
'clipboard-document-list' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15a2.25 2.25 0 012.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25zM6.75 12h.008v.008H6.75V12zm0 3h.008v.008H6.75V15zm0 3h.008v.008H6.75V18z"/>',
'building-office' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.75 21h16.5M4.5 3h15M5.25 3v18m13.5-18v18M9 6.75h1.5m-1.5 3h1.5m-1.5 3h1.5m3-6H15m-1.5 3H15m-1.5 3H15M9 21v-3.375c0-.621.504-1.125 1.125-1.125h3.75c.621 0 1.125.504 1.125 1.125V21"/>',
'check-badge' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12.75L11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 01-1.043 3.296 3.745 3.745 0 01-3.296 1.043A3.745 3.745 0 0112 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 01-3.296-1.043 3.746 3.746 0 01-1.043-3.296A3.745 3.745 0 013 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 011.043-3.296 3.746 3.746 0 013.296-1.043A3.746 3.746 0 0112 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 013.296 1.043 3.746 3.746 0 011.043 3.296A3.745 3.745 0 0121 12z"/>',
'chart-bar' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>',
'shield-check' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>',
'eye' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>',
'cog-6-tooth' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>',
'reception' => '<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"/>',
'swatch' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.098 19.902a3.75 3.75 0 005.304 0l6.401-6.402M6.75 21A3.75 3.75 0 013 17.25V4.125C3 3.504 3.504 3 4.125 3h5.25c.621 0 1.125.504 1.125 1.125v4.072M6.75 21a3.75 3.75 0 003.75-3.75V8.197M6.75 21h13.125c.621 0 1.125-.504 1.125-1.125v-5.25c0-.621-.504-1.125-1.125-1.125h-4.072M10.5 8.197l2.88-2.88c.438-.439 1.15-.439 1.59 0l3.712 3.713c.44.44.44 1.152 0 1.59l-2.879 2.88M6.75 17.25h.008v.008H6.75v-.008z"/>',
'grid' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"/>',
'chat' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/>',
'user' => '<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"/>',
'receipt-percent' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 14l6-6m-5.5.5h.01m4.99 5h.01M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16l3.5-2 3.5 2 3.5-2 3.5 2zM10 8.5a.5.5 0 11-1 0 .5.5 0 011 0zm5 5a.5.5 0 11-1 0 .5.5 0 011 0z"/>',
'photo' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M3.75 21h16.5A2.25 2.25 0 0022.5 18.75V5.25A2.25 2.25 0 0020.25 3H3.75A2.25 2.25 0 001.5 5.25v13.5A2.25 2.25 0 003.75 21zm14.25-9.75a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0z"/>',
'arrow-trending-up' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.25 18L9 11.25l4.306 4.307a11.95 11.95 0 015.814-5.519l2.74-1.22m0 0l-5.94-2.28m5.94 2.28l-2.28 5.941"/>',
'briefcase' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7H4a2 2 0 00-2 2v10a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2zM16 7V5a2 2 0 00-2-2h-4a2 2 0 00-2 2v2"/>',
];
$permissionService = app(\App\Domain\Identity\Services\PermissionService::class);
$currentUser = auth()->user();
......@@ -208,7 +166,7 @@ class="fixed top-0 start-0 h-screen w-64 flex flex-col z-40 overflow-hidden tran
<a href="{{ route($item['route']) }}"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-150 hover:bg-white/10 active:bg-white/20 active:scale-[0.97]"
style="{{ request()->routeIs($item['route'] . '*') ? 'background-color: var(--brand-sidebar-active, #2563eb); color: #fff;' : 'color: var(--brand-sidebar-text, #e2e8f0);' }}">
<svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">{!! $icons[$item['icon']] ?? '' !!}</svg>
<x-ui.icon :name="$item['icon']" class="w-5 h-5 shrink-0" />
<span>{{ $item['label'] }}</span>
</a>
@endif
......@@ -236,7 +194,7 @@ class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transi
<a href="{{ route($child['route']) }}"
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]"
style="{{ request()->routeIs(Str::before($child['route'], '.index') . '.*') ? 'background-color: var(--brand-sidebar-active, #2563eb); color: #fff;' : 'color: var(--brand-sidebar-text, #e2e8f0);' }}">
<svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">{!! $icons[$child['icon']] ?? '' !!}</svg>
<x-ui.icon :name="$child['icon']" class="w-5 h-5 shrink-0" />
<span>{{ $child['label'] }}</span>
</a>
@endforeach
......
......@@ -37,12 +37,12 @@
class="inline-flex items-center gap-1.5 px-3 py-2 rounded-lg border-2 text-sm font-bold transition-colors
{{ $isOn ? 'bg-emerald-100 border-emerald-600 text-emerald-800'
: 'bg-white border-gray-300 text-gray-700 hover:border-emerald-400' }}">
@if($pin['icon'])<span>{{ $pin['icon'] }}</span>@endif
@if($pin['icon'])<x-ui.icon :name="$pin['icon']" class="w-4 h-4" />@endif
<span>{{ $pin['name'] }}</span>
@if($pin['value_label'])
<span dir="ltr" class="tabular-nums">{{ $pin['value_label'] }}</span>
@endif
@if($isOn)<span class="opacity-60">✕</span>@endif
@if($isOn)<x-ui.icon name="x-mark" class="w-3.5 h-3.5 opacity-60" />@endif
</button>
@endforeach
</div>
......@@ -53,8 +53,12 @@ class="inline-flex items-center gap-1.5 px-3 py-2 rounded-lg border-2 text-sm fo
class="w-full flex items-center justify-between gap-2 px-3 py-2.5 bg-white
border-2 border-emerald-500 rounded-lg text-sm font-semibold text-gray-700
focus:outline-none focus:ring-2 focus:ring-emerald-500">
<span>🔍 {{ __('اختر خصم...') }}</span>
<span class="text-emerald-600 text-xs" x-text="open ? '▴' : '▾'"></span>
<span class="inline-flex items-center gap-1.5">
<x-ui.icon name="magnifying-glass" class="w-4 h-4 text-gray-400" />
{{ __('اختر خصم...') }}
</span>
<x-ui.icon name="chevron-down" class="w-4 h-4 text-emerald-600 transition-transform"
x-bind:class="open && 'rotate-180'" />
</button>
<div x-show="open" x-cloak @click.outside="open = false" x-transition
......@@ -91,8 +95,14 @@ class="w-full flex items-center justify-between gap-3 px-3 py-2 text-sm text-sta
: ($isOn ? 'bg-emerald-50 text-emerald-800 font-bold'
: ($approval ? 'text-amber-700 hover:bg-amber-50' : 'text-gray-700 hover:bg-gray-50')) }}">
<span class="flex items-center gap-1.5">
@if($isOn)<span>✓</span>@elseif($approval)<span>⚠</span>@elseif($blocked)<span>✕</span>@endif
@if($row['icon'])<span>{{ $row['icon'] }}</span>@endif
@if($isOn)
<x-ui.icon name="check" class="w-4 h-4" />
@elseif($approval)
<x-ui.icon name="exclamation-triangle" class="w-4 h-4" />
@elseif($blocked)
<x-ui.icon name="no-symbol" class="w-4 h-4" />
@endif
@if($row['icon'])<x-ui.icon :name="$row['icon']" class="w-4 h-4" />@endif
<span>{{ $row['name'] }}</span>
</span>
<span dir="ltr" class="tabular-nums text-xs whitespace-nowrap">
......@@ -114,7 +124,8 @@ class="w-full flex items-center justify-between gap-3 px-3 py-2 text-sm text-sta
<div class="border-t border-gray-100 bg-gray-50 p-3">
<button type="button" @click="manual = !manual"
class="text-sm font-bold text-amber-700 hover:text-amber-800">
✋ {{ __('خصم استثنائي') }}
<x-ui.icon name="hand-raised" class="w-4 h-4 inline-block align-text-bottom" />
{{ __('خصم استثنائي') }}
<span class="text-xs font-normal text-gray-500">
({{ __('حتى') }} {{ $manualCap }}%)
</span>
......@@ -159,7 +170,9 @@ class="w-full px-3 py-1.5 border border-gray-300 rounded-lg text-sm focus:ring-2
@endif
@if($canRemove)
<button type="button" wire:click="removeDiscount({{ $row['rule_id'] }})"
class="opacity-60 hover:opacity-100" title="{{ __('إلغاء') }}">✕</button>
class="opacity-60 hover:opacity-100" title="{{ __('إلغاء') }}">
<x-ui.icon name="x-mark" class="w-3.5 h-3.5" />
</button>
@endif
</span>
@endforeach
......
{{--
The single icon source for the app. Outline set, 24x24, currentColor.
We use icons, never emoji pass a name, not a glyph.
--}}
@props(['name', 'class' => 'w-5 h-5'])
@php
$icons = [
'home' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>',
'users' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>',
'user-group' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"/>',
'bolt' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>',
'academic-cap' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222"/>',
'calendar' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>',
'calendar-days' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z"/>',
'clipboard-check' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>',
'document-text' => '<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"/>',
'document' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>',
'banknotes' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.25 18.75a60.07 60.07 0 0115.797 2.101c.727.198 1.453-.342 1.453-1.096V18.75M3.75 4.5v.75A.75.75 0 013 6h-.75m0 0v-.375c0-.621.504-1.125 1.125-1.125H20.25M2.25 6v9m18-10.5v.75c0 .414.336.75.75.75h.75m-1.5-1.5h.375c.621 0 1.125.504 1.125 1.125v9.75c0 .621-.504 1.125-1.125 1.125h-.375m1.5-1.5H21a.75.75 0 00-.75.75v.75m0 0H3.75m0 0h-.375a1.125 1.125 0 01-1.125-1.125V15m1.5 1.5v-.75A.75.75 0 003 15h-.75M15 10.5a3 3 0 11-6 0 3 3 0 016 0zm3 0h.008v.008H18V10.5zm-12 0h.008v.008H6V10.5z"/>',
'building-library' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 21v-8.25M15.75 21v-8.25M8.25 21v-8.25M3 9l9-6 9 6m-1.5 12V10.332A48.36 48.36 0 0012 9.75c-2.551 0-5.056.2-7.5.582V21M3 21h18M12 6.75h.008v.008H12V6.75z"/>',
'wallet' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a2.25 2.25 0 00-2.25-2.25H15a3 3 0 110 6h3.75A2.25 2.25 0 0021 13.5V12zm0 0V9.75a2.25 2.25 0 00-2.25-2.25h-13.5A2.25 2.25 0 003 9.75v10.5A2.25 2.25 0 005.25 22.5h13.5A2.25 2.25 0 0021 20.25V12zM3 9.75V7.5A2.25 2.25 0 015.25 5.25h13.5A2.25 2.25 0 0121 7.5v2.25"/>',
'credit-card' => '<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"/>',
'calculator' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.75 15.75V18m-7.5-6.75h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V13.5zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V18zm2.498-6.75h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V13.5zm0 2.25h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V18zm2.504-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V18zm2.498-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zM8.25 6h7.5v2.25h-7.5V6zM12 2.25c-1.892 0-3.758.11-5.593.322C5.307 2.7 4.5 3.65 4.5 4.757V19.5a2.25 2.25 0 002.25 2.25h10.5a2.25 2.25 0 002.25-2.25V4.757c0-1.108-.806-2.057-1.907-2.185A48.507 48.507 0 0012 2.25z"/>',
'shopping-cart' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 100 4 2 2 0 000-4z"/>',
'clock' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>',
'tag' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"/>',
'adjustments-horizontal' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.5 6h9.75M10.5 6a1.5 1.5 0 11-3 0m3 0a1.5 1.5 0 10-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-9.75 0h9.75"/>',
'gift' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v13m0-13V6a4 4 0 00-4-4 4 4 0 004 4zm0 0V6a4 4 0 014-4 4 4 0 01-4 4zm-8 4h16m-16 0v8a2 2 0 002 2h12a2 2 0 002-2v-8m-16 0h16"/>',
'cube' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"/>',
'building-storefront' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.5 21v-7.5a.75.75 0 01.75-.75h3a.75.75 0 01.75.75V21m-4.5 0H2.36m11.14 0H18m0 0h3.64m-1.39 0V9.349m-16.5 11.65V9.35m0 0a3.001 3.001 0 003.75-.615A2.993 2.993 0 009.75 9.75c.896 0 1.7-.393 2.25-1.016a2.993 2.993 0 002.25 1.016c.896 0 1.7-.393 2.25-1.016a3.001 3.001 0 003.75.614m-16.5 0a3.004 3.004 0 01-.621-4.72L4.318 3.44A1.5 1.5 0 015.378 3h13.243a1.5 1.5 0 011.06.44l1.19 1.189a3 3 0 01-.621 4.72m-13.5 8.65h3.75a.75.75 0 00.75-.75V13.5a.75.75 0 00-.75-.75H6.75a.75.75 0 00-.75.75v3.75c0 .415.336.75.75.75z"/>',
'truck' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.25 18.75a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m3 0h6m-9 0H3.375a1.125 1.125 0 01-1.125-1.125V14.25m17.25 4.5a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m3 0h1.125c.621 0 1.129-.504 1.09-1.124a17.902 17.902 0 00-3.213-9.193 2.056 2.056 0 00-1.58-.86H14.25M16.5 18.75h-2.25m0-11.177v-.958c0-.568-.422-1.048-.987-1.106a48.554 48.554 0 00-10.026 0 1.106 1.106 0 00-.987 1.106v7.635m12-6.677v6.677m0 4.5v-4.5m0 0h-12"/>',
'clipboard-document-list' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15a2.25 2.25 0 012.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25zM6.75 12h.008v.008H6.75V12zm0 3h.008v.008H6.75V15zm0 3h.008v.008H6.75V18z"/>',
'building-office' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.75 21h16.5M4.5 3h15M5.25 3v18m13.5-18v18M9 6.75h1.5m-1.5 3h1.5m-1.5 3h1.5m3-6H15m-1.5 3H15m-1.5 3H15M9 21v-3.375c0-.621.504-1.125 1.125-1.125h3.75c.621 0 1.125.504 1.125 1.125V21"/>',
'check-badge' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12.75L11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 01-1.043 3.296 3.745 3.745 0 01-3.296 1.043A3.745 3.745 0 0112 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 01-3.296-1.043 3.746 3.746 0 01-1.043-3.296A3.745 3.745 0 013 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 011.043-3.296 3.746 3.746 0 013.296-1.043A3.746 3.746 0 0112 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 013.296 1.043 3.746 3.746 0 011.043 3.296A3.745 3.745 0 0121 12z"/>',
'chart-bar' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>',
'shield-check' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>',
'eye' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>',
'cog-6-tooth' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>',
'reception' => '<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"/>',
'swatch' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.098 19.902a3.75 3.75 0 005.304 0l6.401-6.402M6.75 21A3.75 3.75 0 013 17.25V4.125C3 3.504 3.504 3 4.125 3h5.25c.621 0 1.125.504 1.125 1.125v4.072M6.75 21a3.75 3.75 0 003.75-3.75V8.197M6.75 21h13.125c.621 0 1.125-.504 1.125-1.125v-5.25c0-.621-.504-1.125-1.125-1.125h-4.072M10.5 8.197l2.88-2.88c.438-.439 1.15-.439 1.59 0l3.712 3.713c.44.44.44 1.152 0 1.59l-2.879 2.88M6.75 17.25h.008v.008H6.75v-.008z"/>',
'grid' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"/>',
'chat' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/>',
'user' => '<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"/>',
'receipt-percent' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 14l6-6m-5.5.5h.01m4.99 5h.01M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16l3.5-2 3.5 2 3.5-2 3.5 2zM10 8.5a.5.5 0 11-1 0 .5.5 0 011 0zm5 5a.5.5 0 11-1 0 .5.5 0 011 0z"/>',
'photo' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M3.75 21h16.5A2.25 2.25 0 0022.5 18.75V5.25A2.25 2.25 0 0020.25 3H3.75A2.25 2.25 0 001.5 5.25v13.5A2.25 2.25 0 003.75 21zm14.25-9.75a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0z"/>',
'arrow-trending-up' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.25 18L9 11.25l4.306 4.307a11.95 11.95 0 015.814-5.519l2.74-1.22m0 0l-5.94-2.28m5.94 2.28l-2.28 5.941"/>',
'briefcase' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7H4a2 2 0 00-2 2v10a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2zM16 7V5a2 2 0 00-2-2h-4a2 2 0 00-2 2v2"/>',
'magnifying-glass' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"/>',
'check' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.5 12.75l6 6 9-13.5"/>',
'x-mark' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>',
'chevron-down' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.5 8.25l-7.5 7.5-7.5-7.5"/>',
'chevron-up' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.5 15.75l7.5-7.5 7.5 7.5"/>',
'exclamation-triangle' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"/>',
'sun' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"/>',
'cake' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8.25v-1.5m0 1.5c-1.355 0-2.697.056-4.024.166C6.845 8.51 6 9.473 6 10.608v2.513m6-4.871c1.355 0 2.697.056 4.024.166C17.155 8.51 18 9.473 18 10.608v2.513M15 8.25v-1.5m-6 1.5v-1.5m12 9.75l-1.5.75a3.354 3.354 0 01-3 0 3.354 3.354 0 00-3 0 3.354 3.354 0 01-3 0 3.354 3.354 0 00-3 0 3.354 3.354 0 01-3 0L3 16.5m15-3.379a48.474 48.474 0 00-6-.371c-2.032 0-4.034.126-6 .371m12 0c.39.049.777.102 1.163.16 1.07.16 1.837 1.094 1.837 2.175v5.169c0 .621-.504 1.125-1.125 1.125H4.125A1.125 1.125 0 013 20.625v-5.169c0-1.081.768-2.015 1.837-2.175A48.111 48.111 0 016 13.121"/>',
'hand-raised' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.05 4.575a1.575 1.575 0 10-3.15 0v3m3.15-3v-1.5a1.575 1.575 0 013.15 0v1.5m-3.15 0l.075 5.925m3.075.75V4.575m0 0a1.575 1.575 0 013.15 0V15M6.9 7.575a1.575 1.575 0 10-3.15 0v8.175a6.75 6.75 0 006.75 6.75h2.018a5.25 5.25 0 003.712-1.538l1.732-1.732a5.25 5.25 0 001.538-3.712l.003-2.024a.668.668 0 01.198-.471 1.575 1.575 0 10-2.228-2.228 3.818 3.818 0 00-1.12 2.687M6.9 7.575V12"/>',
'flag' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3v1.5M3 21v-6m0 0l2.77-.693a9 9 0 016.208.682l.108.054a9 9 0 006.086.71l3.114-.732a48.524 48.524 0 01-.005-10.499l-3.11.732a9 9 0 01-6.085-.711l-.108-.054a9 9 0 00-6.208-.682L3 4.5M3 15V4.5"/>',
'squares-plus' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.5 16.875h3.375m0 0h3.375m-3.375 0V13.5m0 3.375v3.375M6 10.5h2.25a2.25 2.25 0 002.25-2.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v2.25A2.25 2.25 0 006 10.5zm0 9.75h2.25A2.25 2.25 0 0010.5 18v-2.25a2.25 2.25 0 00-2.25-2.25H6a2.25 2.25 0 00-2.25 2.25V18A2.25 2.25 0 006 20.25zm9.75-9.75H18a2.25 2.25 0 002.25-2.25V6A2.25 2.25 0 0018 3.75h-2.25A2.25 2.25 0 0013.5 6v2.25a2.25 2.25 0 002.25 2.25z"/>',
'ticket' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16.5 6v.75m0 3v.75m0 3v.75m0 3V18m-9-5.25h5.25M7.5 15h3M3.375 5.25c-.621 0-1.125.504-1.125 1.125v3.026a2.999 2.999 0 010 5.198v3.026c0 .621.504 1.125 1.125 1.125h17.25c.621 0 1.125-.504 1.125-1.125v-3.026a2.999 2.999 0 010-5.198V6.375c0-.621-.504-1.125-1.125-1.125H3.375z"/>',
'plus' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.5v15m7.5-7.5h-15"/>',
'minus' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14"/>',
'no-symbol' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"/>',
];
@endphp
@if(isset($icons[$name]))
<svg {{ $attributes->merge(['class' => $class]) }} fill="none" stroke="currentColor"
viewBox="0 0 24 24" aria-hidden="true" focusable="false">{!! $icons[$name] !!}</svg>
@endif
......@@ -197,6 +197,55 @@ class="w-5 h-5 rounded border-gray-300 text-blue-600 focus:ring-blue-500">
</div>
</div>
</div>
{{-- Sports hosted + starting grid --}}
<div class="mt-6 pt-6 border-t border-gray-200 space-y-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('الرياضات في هذه المنشأة') }}</label>
<p class="text-xs text-gray-500 mb-3">
{{ __('تُصفّي المجموعات المعروضة عند الجدولة — اتركها فارغة لعرض كل الرياضات') }}
</p>
<div class="flex flex-wrap gap-2">
@foreach($activities as $activity)
<label class="cursor-pointer">
<input type="checkbox" value="{{ $activity->id }}" wire:model="activityIds" class="peer sr-only">
<span class="inline-block px-3 py-1.5 rounded-full border-2 text-sm font-medium
border-gray-200 text-gray-600
peer-checked:border-emerald-500 peer-checked:bg-emerald-50 peer-checked:text-emerald-700">
{{ $activity->name_ar }}
</span>
</label>
@endforeach
@if($activities->isEmpty())
<p class="text-sm text-gray-400">{{ __('لا توجد أنشطة معرّفة بعد') }}</p>
@endif
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('تقسيم المساحة') }}</label>
<p class="text-xs text-gray-500 mb-3">
{{ __('اتركها 1×1 إذا كانت المنشأة مساحة واحدة — يمكن تغييرها لاحقاً من إعدادات المنشأة') }}
</p>
<div class="grid grid-cols-2 sm:grid-cols-3 gap-4">
<div>
<label class="block text-xs text-gray-500 mb-1">{{ __('صفوف') }}</label>
<input type="number" wire:model.live="gridRows" min="1" dir="ltr"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500">
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">{{ __('أعمدة') }}</label>
<input type="number" wire:model.live="gridColumns" min="1" dir="ltr"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500">
</div>
<div class="flex items-end">
<p class="text-sm text-gray-600 pb-2">
{{ max(1, (int) $gridRows) * max(1, (int) $gridColumns) }} {{ __('قطعة') }}
</p>
</div>
</div>
</div>
</div>
@endif
{{-- Step 3: Operating Hours --}}
......
......@@ -232,6 +232,96 @@ class="w-full text-sm px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2
</div>
</div>
{{-- Sports hosted here --}}
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 sm:p-6">
<div class="flex items-start gap-2 mb-1">
<x-ui.icon name="bolt" class="w-5 h-5 text-blue-600 shrink-0 mt-0.5" />
<div>
<h2 class="text-base font-bold text-gray-800">{{ __('الرياضات في هذه المنشأة') }}</h2>
<p class="text-xs text-gray-500">
{{ __('تُستخدم لتصفية المجموعات في جدولة المنشآت — اتركها فارغة لعرض كل الرياضات') }}
</p>
</div>
</div>
<div class="flex flex-wrap gap-2 mt-4">
@foreach($activities as $activity)
<label class="cursor-pointer">
<input type="checkbox" value="{{ $activity->id }}" wire:model="activityIds" class="peer sr-only">
<span class="inline-block px-3 py-1.5 rounded-full border-2 text-sm font-medium
border-gray-200 text-gray-600
peer-checked:border-blue-500 peer-checked:bg-blue-50 peer-checked:text-blue-700">
{{ $activity->name_ar }}
</span>
</label>
@endforeach
@if($activities->isEmpty())
<p class="text-sm text-gray-400">{{ __('لا توجد أنشطة معرّفة بعد') }}</p>
@endif
</div>
</div>
{{-- Grid size --}}
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 sm:p-6">
<div class="flex items-start gap-2 mb-1">
<x-ui.icon name="grid" class="w-5 h-5 text-blue-600 shrink-0 mt-0.5" />
<div>
<h2 class="text-base font-bold text-gray-800">{{ __('تقسيم المساحة') }}</h2>
<p class="text-xs text-gray-500">
{{ __('عدد الصفوف والأعمدة التي تُقسم بها المنشأة فعلياً — بدون حد أقصى') }}
</p>
</div>
</div>
<div class="grid grid-cols-2 sm:grid-cols-3 gap-4 mt-4">
<div>
<label for="gridRows" class="block text-sm font-medium text-gray-700 mb-1">{{ __('عدد الصفوف') }}</label>
<input type="number" id="gridRows" wire:model.live="gridRows" min="1" dir="ltr"
class="w-full text-sm px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label for="gridColumns" class="block text-sm font-medium text-gray-700 mb-1">{{ __('عدد الأعمدة') }}</label>
<input type="number" id="gridColumns" wire:model.live="gridColumns" min="1" dir="ltr"
class="w-full text-sm px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div class="flex items-end">
<p class="text-sm text-gray-600 pb-2.5">
{{ __('الناتج') }}:
<span class="font-bold text-gray-900">{{ max(1, (int) $gridRows) * max(1, (int) $gridColumns) }}</span>
{{ __('قطعة') }}
</p>
</div>
</div>
{{-- Live preview of the grid being described --}}
@php
$pr = min(max(1, (int) $gridRows), 12);
$pc = min(max(1, (int) $gridColumns), 12);
@endphp
<div class="mt-4">
<div class="inline-grid gap-1 p-2 bg-gray-50 border border-gray-200 rounded-lg"
style="grid-template-columns: repeat({{ $pc }}, minmax(0, 1fr));">
@for($r = 1; $r <= $pr; $r++)
@for($c = 1; $c <= $pc; $c++)
<div class="w-9 h-9 rounded bg-white border border-blue-200 flex items-center justify-center
text-[10px] text-blue-700 font-medium" dir="ltr">R{{ $r }}C{{ $c }}</div>
@endfor
@endfor
</div>
@if($pr < (int) $gridRows || $pc < (int) $gridColumns)
<p class="text-xs text-gray-500 mt-2">
{{ __('المعاينة تعرض أول 12×12 فقط — سيتم إنشاء كل القطع عند الحفظ') }}
</p>
@endif
</div>
@if($gridError)
<div class="mt-3 p-3 bg-amber-50 border border-amber-200 rounded-lg text-sm text-amber-800">
{{ $gridError }}
</div>
@endif
</div>
{{-- Actions --}}
<div class="flex flex-col-reverse sm:flex-row items-stretch sm:items-center justify-end gap-3">
<a href="{{ route('facilities.list') }}" wire:navigate
......
......@@ -64,18 +64,18 @@ class="w-full sm:w-auto px-4 py-2.5 bg-blue-600 text-white font-medium rounded-x
<div class="grid grid-cols-2 gap-3 sm:gap-4 p-4 bg-gray-50 rounded-xl">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('عدد الصفوف') }}</label>
<input type="number" wire:model="grid_rows" min="1" max="10" dir="ltr" class="w-full border-gray-300 rounded-lg py-2.5">
<input type="number" wire:model.live="grid_rows" min="1" dir="ltr" class="w-full border-gray-300 rounded-lg py-2.5">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('عدد الأعمدة') }}</label>
<input type="number" wire:model="grid_columns" min="1" max="10" dir="ltr" class="w-full border-gray-300 rounded-lg py-2.5">
<input type="number" wire:model.live="grid_columns" min="1" dir="ltr" class="w-full border-gray-300 rounded-lg py-2.5">
</div>
<p class="col-span-2 text-xs text-gray-500">{{ __('سيتم إنشاء') }} {{ $grid_rows * $grid_columns }} {{ __('قطعة') }}</p>
</div>
@elseif($layout_type === 'lanes')
<div class="p-4 bg-gray-50 rounded-xl">
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('عدد الحارات') }}</label>
<input type="number" wire:model="lane_count" min="1" max="20" dir="ltr" class="w-32 border-gray-300 rounded-lg py-2.5">
<input type="number" wire:model.live="lane_count" min="1" dir="ltr" class="w-32 border-gray-300 rounded-lg py-2.5">
</div>
@elseif($layout_type === 'zones' || $layout_type === 'custom')
<div class="p-4 bg-gray-50 rounded-xl space-y-3">
......
......@@ -47,7 +47,7 @@ class="px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-5
<button type="button" wire:click="chooseRecipe('{{ $key }}')"
class="p-4 rounded-xl border-2 border-gray-200 hover:border-emerald-500 hover:bg-emerald-50
text-center transition-colors focus:outline-none focus:ring-2 focus:ring-emerald-500">
<div class="text-2xl leading-9">{{ $recipe['icon'] }}</div>
<x-ui.icon :name="$recipe['icon']" class="w-7 h-7 mx-auto mb-1.5 text-emerald-600" />
<div class="text-sm font-bold text-gray-800">{{ $recipe['name_ar'] }}</div>
<div class="text-xs text-gray-400 mt-0.5">{{ $recipe['hint_ar'] }}</div>
</button>
......@@ -228,11 +228,13 @@ class="px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-5
@if($audience)
<div class="mb-4 p-3 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-800 font-semibold">
👥 {{ __('تنطبق على') }} {{ $audience['matched'] }}
<x-ui.icon name="users" class="w-4 h-4 inline-block align-text-bottom" />
{{ __('تنطبق على') }} {{ $audience['matched'] }}
{{ __('مشترك من') }} {{ $audience['total'] }}
@if($audience['total'] > 0 && $audience['matched'] === $audience['total'])
<div class="text-xs font-normal text-blue-700 mt-1">
⚠ {{ __('تنطبق على الجميع — تأكد أن هذا مقصود') }}
<x-ui.icon name="exclamation-triangle" class="w-3.5 h-3.5 inline-block align-text-bottom" />
{{ __('تنطبق على الجميع — تأكد أن هذا مقصود') }}
</div>
@endif
</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