Files
star-cloud/resources/views/admin/permission/roles.blade.php
sky121113 d2cefe3f39
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 1m4s
[FEAT] 完善全站多語系支援、角色權限篩選優化及 UI 元件重構
- [DOCS] 補齊 en, ja, zh_TW 語系檔翻譯並完善驗證錯誤訊息 (validation.php)
- [FEAT] 角色權限頁面新增「所屬單位」篩選功能 (僅限系統管理員)
- [STYLE] 優化角色列表顯示,將「類型」變更為具體「所屬單位」名稱
- [STYLE] 修正角色頁面工具列佈局,搜尋框置前並修正下拉箭頭顯示
- [REFACTOR] 統一全站刪除確認視窗,導入新版 <x-delete-confirm-modal /> 組件
- [REFACTOR] 優化 PermissionController 查詢效能 (Eager Loading)
- [FIX] 修正 RoleSeeder 角色命名與資料庫同步邏輯
2026-03-20 13:41:51 +08:00

349 lines
31 KiB
PHP

@extends('layouts.admin')
@php
$routeName = request()->route()->getName();
$baseRoute = str_contains($routeName, 'sub-account-roles') ? 'admin.data-config.sub-account-roles' : 'admin.permission.roles';
@endphp
@section('content')
<div class="space-y-6" x-data="{
showModal: {{ $errors->any() ? 'true' : 'false' }},
isEdit: {{ (old('_method') == 'PUT' || request()->has('edit')) ? 'true' : 'false' }},
roleId: '{{ old('roleId', '') }}',
roleName: '{{ old('name', '') }}',
rolePermissions: @js(old('permissions', [])),
currentUserRoleIds: @js($currentUserRoleIds ?? []),
isSystem: {{ old('is_system', '0') }},
modalTitle: '{{ $errors->any() && old('_method') == 'PUT' ? __('Edit Role') : ($errors->any() ? __('Create Role') : __('Create Role')) }}',
openModal(edit = false, id = '', name = '', permissions = [], isSys = false) {
this.isEdit = edit;
this.roleId = id;
this.roleName = name;
this.rolePermissions = Array.isArray(permissions) ? permissions : (typeof permissions === 'string' ? JSON.parse(permissions) : []);
this.isSystem = isSys;
this.modalTitle = edit ? '{{ __('Edit Role') }}' : '{{ __('Create Role') }}';
this.showModal = true;
},
isWarningModalOpen: false,
deleteWarningMsg: '',
triggerDeleteWarning(msg) {
this.deleteWarningMsg = msg;
this.isWarningModalOpen = true;
},
isDeleteConfirmOpen: false,
deleteFormAction: '',
confirmDelete(action) {
this.deleteFormAction = action;
this.isDeleteConfirmOpen = true;
}
}">
<!-- Header -->
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
<div>
<h1 class="text-3xl font-black text-slate-800 dark:text-white font-display tracking-tight">{{ $title }}</h1>
<p class="text-sm font-bold text-slate-500 dark:text-slate-400 mt-1 uppercase tracking-widest">{{ __('Define and manage security roles and permissions.') }}</p>
</div>
<button @click="openModal()" class="btn-luxury-primary text-sm">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
<span>{{ __('Add Role') }}</span>
</button>
</div>
<!-- Roles Content (Integrated Card) -->
<div class="luxury-card rounded-3xl p-8 animate-luxury-in">
<!-- Toolbar -->
<div class="flex flex-col md:flex-row md:items-center justify-between gap-6 mb-10">
<form action="{{ route($baseRoute) }}" method="GET" class="flex flex-col md:flex-row md:items-center gap-4">
<div class="relative group">
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none z-10">
<svg class="h-4 w-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
</span>
<input type="text" name="search" value="{{ request('search') }}" class="py-2.5 pl-12 pr-6 block w-full md:w-80 luxury-input" placeholder="{{ __('Search roles...') }}">
</div>
@if(auth()->user()->isSystemAdmin())
<div class="relative">
<select name="company_id" onchange="this.form.submit()" class="py-2.5 pl-4 pr-10 block w-full md:w-60 luxury-input">
<option value="">{{ __('All Affiliations') }}</option>
<option value="system" {{ request('company_id') === 'system' ? 'selected' : '' }}>{{ __('System Level') }}</option>
@foreach($companies as $company)
<option value="{{ $company->id }}" {{ request('company_id') == $company->id ? 'selected' : '' }}>{{ $company->name }}</option>
@endforeach
</select>
</div>
@endif
<input type="hidden" name="per_page" value="{{ request('per_page', 10) }}">
</form>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-separate border-spacing-y-0">
<thead>
<tr class="bg-slate-50/50 dark:bg-slate-900/10">
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Role Name') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Affiliation') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Permissions') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Users') }}</th>
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-right">{{ __('Actions') }}</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-50 dark:divide-slate-800/80">
@forelse($roles as $role)
<tr class="group hover:bg-slate-50/80 dark:hover:bg-slate-800/40 transition-all duration-300">
<td class="px-6 py-6">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-2xl bg-slate-100 dark:bg-slate-800 flex items-center justify-center text-slate-400 border border-slate-200 dark:border-slate-700 group-hover:bg-cyan-500 group-hover:text-white transition-all duration-300">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" 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" /></svg>
</div>
<span class="text-base font-extrabold text-slate-800 dark:text-slate-100 group-hover:text-cyan-600 dark:group-hover:text-cyan-400 transition-colors">{{ $role->name }}</span>
@if($role->is_system)
<span class="p-1.5 bg-cyan-50 dark:bg-cyan-900/30 text-cyan-600 dark:text-cyan-400 rounded-lg tooltip" title="{{ __('System Role') }}">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
</span>
@endif
</div>
</td>
<td class="px-6 py-6">
@if($role->is_system)
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 border border-slate-200 dark:border-slate-800 uppercase tracking-wider">
{{ __('System Level') }}
</span>
@else
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border border-emerald-500/20 tracking-wider">
{{ $role->company->name ?? __('Company Level') }}
</span>
@endif
</td>
<td class="px-6 py-6">
<div class="flex flex-wrap gap-1 max-w-xs">
@forelse($role->permissions->take(6) as $permission)
<span class="px-2 py-0.5 text-xs bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 rounded border border-slate-200 dark:border-slate-700 uppercase font-bold tracking-widest">{{ __(str_replace('menu.', '', $permission->name)) }}</span>
@empty
<span class="text-xs font-bold text-slate-500 dark:text-slate-400 tracking-widest">{{ __('No permissions') }}</span>
@endforelse
@if($role->permissions->count() > 6)
<span class="px-2 py-0.5 text-xs bg-slate-100 dark:bg-slate-800 text-slate-500 dark:text-slate-400 rounded border border-slate-200 dark:border-slate-700 uppercase font-bold tracking-widest">+{{ $role->permissions->count() - 6 }}</span>
@endif
</div>
</td>
<td class="px-6 py-6 text-center">
<span class="text-sm font-extrabold text-slate-700 dark:text-slate-300">{{ $role->users()->count() }}</span>
</td>
<td class="px-6 py-6 text-right">
<div class="flex items-center justify-end gap-2">
<button @click="openModal(true, @js($role->id), @js($role->name), @js($role->permissions->pluck('name')), {{ $role->is_system ? 'true' : 'false' }})" class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 transition-all border border-transparent hover:border-cyan-500/20 tooltip" title="{{ __('Edit') }}">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"/></svg>
</button>
@if($role->name !== 'super-admin' && (auth()->user()->isSystemAdmin() || !$role->is_system))
<form action="{{ route($baseRoute . '.destroy', $role->id) }}" method="POST" @submit.prevent="if({{ $role->users()->count() }} > 0) { triggerDeleteWarning('{{ __('Cannot delete role with active users.') }}'); return; } confirmDelete('{{ route($baseRoute . '.destroy', $role->id) }}')" class="inline text-slate-400">
@csrf
@method('DELETE')
<button type="submit" class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-rose-500 hover:bg-rose-500/5 transition-all border border-transparent hover:border-rose-500/20 tooltip" title="{{ __('Delete') }}">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" x2="10" y1="11" y2="17"/><line x1="14" x2="14" y1="11" y2="17"/></svg>
</button>
</form>
@endif
</div>
</td>
</tr>
@empty
<tr>
<td colspan="5" class="px-6 py-20 text-center">
<div class="flex flex-col items-center justify-center gap-4 text-slate-400">
<svg xmlns="http://www.w3.org/2000/svg" class="w-16 h-16 opacity-20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M12 8v8"/><path d="M8 12h8"/></svg>
<p class="text-lg font-bold">{{ __('No roles found.') }}</p>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="mt-8 border-t border-slate-100 dark:border-slate-800 pt-6">
{{ $roles->links('vendor.pagination.luxury') }}
</div>
</div>
<!-- Modal -->
<template x-if="showModal">
<div class="fixed inset-0 z-[60] flex items-center justify-center p-4">
<div @click="showModal = false" class="absolute inset-0 bg-slate-900/60 backdrop-blur-sm transition-opacity"></div>
<div class="relative w-full max-w-3xl bg-white dark:bg-slate-900 rounded-3xl shadow-2xl overflow-hidden animate-luxury-in">
<div class="flex items-center justify-between p-8 border-b border-slate-100 dark:border-slate-800">
<div>
<h3 class="text-2xl font-black text-slate-800 dark:text-white" x-text="modalTitle"></h3>
<p class="text-sm font-bold text-slate-400 mt-1" x-text="isEdit ? '{{ __('Update existing role and permissions.') }}' : '{{ __('Create a new role and assign permissions.') }}'"></p>
</div>
<button @click="showModal = false" class="p-2 rounded-xl hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-all">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
</div>
<form :action="isEdit ? '{{ route($baseRoute) }}/' + roleId : '{{ route($baseRoute . '.store') }}'" method="POST">
@csrf
<template x-if="isEdit"><input type="hidden" name="_method" value="PUT"></template>
<input type="hidden" name="roleId" x-model="roleId">
<div class="p-8 max-h-[65vh] overflow-y-auto custom-scrollbar">
<!-- Warning for editing own role -->
<template x-if="isEdit && (currentUserRoleIds || []).map(String).includes(String(roleId))">
<div class="mb-8 p-5 bg-amber-500/10 border border-amber-500/20 text-amber-600 dark:text-amber-400 rounded-2xl font-bold flex items-start gap-4 animate-luxury-in">
<div class="size-10 bg-amber-500/20 rounded-xl flex items-center justify-center flex-shrink-0">
<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.5" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/></svg>
</div>
<div class="text-sm">
<p class="text-base font-black leading-tight">{{ __('Warning: You are editing your own role!') }}</p>
<p class="font-bold mt-1 opacity-90 leading-relaxed">{{ __('Modifying your own administrative permissions may result in losing access to certain system functions.') }}</p>
</div>
</div>
</template>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- Left: Basic Info -->
<div class="space-y-6">
<div class="space-y-2">
<label class="text-xs font-black text-slate-400 uppercase tracking-widest pl-1">{{ __('Role Name') }}</label>
<input type="text" name="name" x-model="roleName" required class="luxury-input w-full @error('name') border-rose-500 @enderror" placeholder="{{ __('Enter role name') }}" :disabled="isEdit && roleName === 'super-admin'">
@error('name')
<p class="text-[11px] text-rose-500 font-bold mt-1.5 px-1 flex items-center gap-1.5 animate-luxury-in">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
{{ $message }}
</p>
@enderror
<template x-if="isEdit && roleName === 'super-admin'">
<p class="text-[10px] text-amber-500 font-bold mt-1 px-1 flex items-center gap-1.5">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
{{ __('The Super Admin role name cannot be modified.') }}
</p>
</template>
</div>
@if(auth()->user()->isSystemAdmin())
<div class="space-y-4">
<label class="text-xs font-black text-slate-400 uppercase tracking-widest pl-1">{{ __('Affiliation') }}</label>
<div class="flex flex-col gap-2">
<label class="flex items-center gap-3 p-3 rounded-xl hover:bg-slate-50 dark:hover:bg-slate-800/50 cursor-pointer transition-all border border-slate-200 dark:border-slate-800 group has-[:checked]:border-cyan-500/50 has-[:checked]:bg-cyan-500/5">
<input type="radio" name="is_system" value="1" x-model="isSystem" class="w-4 h-4 text-cyan-500 bg-transparent border-slate-300 focus:ring-cyan-500" :disabled="isEdit && roleName === 'super-admin'">
<span class="text-sm font-bold text-slate-700 dark:text-slate-200 group-hover:text-cyan-600 dark:group-hover:text-cyan-400">{{ __('System Level') }}</span>
</label>
<label class="flex items-center gap-3 p-3 rounded-xl hover:bg-slate-50 dark:hover:bg-slate-800/50 cursor-pointer transition-all border border-slate-200 dark:border-slate-800 group has-[:checked]:border-cyan-500/50 has-[:checked]:bg-cyan-500/5">
<input type="radio" name="is_system" value="0" x-model="isSystem" class="w-4 h-4 text-cyan-500 bg-transparent border-slate-300 focus:ring-cyan-500" :disabled="isEdit && roleName === 'super-admin'">
<span class="text-sm font-bold text-slate-700 dark:text-slate-200 group-hover:text-cyan-600 dark:group-hover:text-cyan-400">{{ __('Company Level') }}</span>
</label>
</div>
</div>
@endif
</div>
<!-- Right: Permissions -->
<div class="space-y-6">
<label class="text-xs font-black text-slate-400 uppercase tracking-widest pl-1">{{ __('Menu Permissions') }}</label>
<div class="luxury-card border-slate-100 dark:border-slate-800 p-4 rounded-2xl grid grid-cols-1 gap-3">
@php
$icon_map = [
'members' => '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',
'machines' => 'M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 01-2 2v4a2 2 0 012 2h14a2 2 0 012-2v-4a2 2 0 01-2-2m-2-4h.01M17 16h.01',
'app' => 'M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z',
'warehouses' => 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10',
'sales' => 'M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z',
'analysis' => 'M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z',
'audit' => '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',
'data-config' => '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.065 2.572c1.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.572 1.065c-.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.065-2.572c-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',
'remote' => 'M5.636 18.364a9 9 0 010-12.728m12.728 0a9 9 0 010 12.728m-9.9-2.829a5 5 0 010-7.07m7.072 0a5 5 0 010 7.07M21 12a9 9 0 11-18 0 9 9 0 0118 0z',
'line' => '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',
'reservation' => 'M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z',
'special-permission' => 'M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z',
'basic-settings' => '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.065 2.572c1.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.572 1.065c-.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.065-2.572c-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',
'permissions' => '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',
];
@endphp
@foreach($all_permissions->get('menu', []) as $permission)
@php
$pure_name = str_replace('menu.', '', $permission->name);
$is_restricted = in_array($permission->name, ['menu.basic-settings', 'menu.permissions']);
@endphp
<label class="flex items-center gap-3 p-3 rounded-xl hover:bg-slate-50 dark:hover:bg-slate-800/50 cursor-pointer transition-all border border-transparent hover:border-slate-200 dark:hover:border-slate-700 group"
@if($is_restricted) x-show="isSystem == '1'" x-transition @endif>
<div class="relative flex items-center">
<input type="checkbox" name="permissions[]" value="{{ $permission->name }}"
x-model="rolePermissions"
class="peer w-5 h-5 rounded-lg border-2 border-slate-200 dark:border-slate-700 text-cyan-500 focus:ring-cyan-500 focus:ring-offset-0 bg-transparent transition-all checked:border-cyan-500">
<svg class="absolute w-3.5 h-3.5 text-white opacity-0 peer-checked:opacity-100 left-0.5 pointer-events-none transition-opacity" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
</div>
<div class="flex items-center gap-2.5">
<div class="w-7 h-7 rounded-lg flex items-center justify-center bg-slate-50 dark:bg-slate-800 text-slate-400 group-hover:bg-cyan-500 group-hover:text-white transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="{{ $icon_map[$pure_name] ?? 'M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z' }}" /></svg>
</div>
<span class="text-sm font-bold text-slate-600 dark:text-slate-300 group-hover:text-slate-900 dark:group-hover:text-white tracking-wide transition-colors">{{ __($pure_name) }}</span>
</div>
</label>
@endforeach
</div>
</div>
</div>
</div>
<div class="p-8 bg-slate-50 dark:bg-slate-800/50 border-t border-slate-100 dark:border-slate-800 flex items-center justify-end gap-4">
<button type="button" @click="showModal = false" class="btn-luxury-ghost px-8 py-3 rounded-2xl font-black text-xs uppercase tracking-widest">{{ __('Cancel') }}</button>
<button type="submit" class="btn-luxury-primary px-10 py-3 rounded-2xl font-black text-xs uppercase tracking-widest shadow-xl shadow-cyan-500/20">{{ __('Save Changes') }}</button>
</div>
</form>
</div>
</div>
</template>
<!-- Global Delete Warning Modal -->
<div x-show="isWarningModalOpen" class="fixed inset-0 z-[200] overflow-y-auto" x-cloak>
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div x-show="isWarningModalOpen" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-200" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0" class="fixed inset-0 transition-opacity bg-slate-900/60 backdrop-blur-sm"
@click="isWarningModalOpen = false"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen">&#8203;</span>
<div x-show="isWarningModalOpen" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100" x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white dark:bg-slate-900 rounded-3xl shadow-2xl sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-8 border border-slate-100 dark:border-slate-800">
<div class="sm:flex sm:items-start">
<div class="flex items-center justify-center flex-shrink-0 w-12 h-12 mx-auto bg-rose-100 dark:bg-rose-500/10 rounded-2xl sm:mx-0 sm:h-12 sm:w-12 text-rose-600 dark:text-rose-400">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" 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" />
</svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-6 sm:text-left">
<h3 class="text-xl font-black text-slate-800 dark:text-white leading-6 tracking-tight outfit-font">
{{ __('Cannot Delete Role') }}
</h3>
<div class="mt-4">
<p class="text-sm font-bold text-slate-500 dark:text-slate-400 leading-relaxed" x-text="deleteWarningMsg"></p>
</div>
</div>
</div>
<div class="mt-8 sm:mt-10 sm:flex sm:flex-row-reverse">
<button type="button" @click="isWarningModalOpen = false"
class="inline-flex justify-center w-full px-8 py-3 text-sm font-black text-white transition-all bg-slate-800 dark:bg-slate-700 rounded-xl hover:bg-slate-900 dark:hover:bg-slate-600 sm:w-auto tracking-widest uppercase">
{{ __('Got it') }}
</button>
</div>
</div>
</div>
</div>
<!-- Global Delete Confirm Modal -->
<x-delete-confirm-modal :message="__('Are you sure you want to delete this role? This action cannot be undone.')" />
</div>
@endsection