first commit
This commit is contained in:
@ -0,0 +1,70 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="application-settings-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Información de aplicación</h5>
|
||||
<div class="fv-row mb-3">
|
||||
<label for="admin_app_name" class="form-label">
|
||||
Titulo de aplicación <span class="text-xs">(Nombre corto)</span>
|
||||
</label>
|
||||
<input type="text" id="admin_app_name" wire:model="admin_app_name" class="form-control" placeholder="Titulo de aplicación">
|
||||
@error('admin_app_name')
|
||||
<span class="text-danger">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="fv-row mb-6">
|
||||
<h5>Logotipo tema claro</h5>
|
||||
<div class="fv-row mb-4">
|
||||
<input type="file" wire:model="upload_image_logo" id="upload_image_logo" class="form-control" accept="image/*" />
|
||||
@error('upload_image_logo')
|
||||
<span class="text-danger">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mb-8 text-center align-items-center">
|
||||
<div class="justify-content-center align-items-center bg-slate-100 p-4">
|
||||
<img src="{{ $upload_image_logo ? $upload_image_logo->temporaryUrl() : asset('storage/' . $admin_image_logo) }}">
|
||||
</div>
|
||||
</div>
|
||||
<h5>Logotipo tema obscuro</h5>
|
||||
<div class="fv-row mb-4">
|
||||
<input type="file" wire:model="upload_image_logo_dark" id="upload_image_logo_dark" class="form-control" accept="image/*" />
|
||||
@error('upload_image_logo_dark')
|
||||
<span class="text-danger">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mb-3 text-center align-items-center">
|
||||
<div class="justify-content-center align-items-center bg-slate-800 p-4">
|
||||
<img src="{{ $upload_image_logo_dark ? $upload_image_logo_dark->temporaryUrl() : asset('storage/' . $admin_image_logo_dark) }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="save"
|
||||
class="btn btn-primary btn-save btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
:disabled="{{ $upload_image_logo === null && $upload_image_logo_dark === null ? 'true' : 'false' }}"
|
||||
data-loading-text="Guardando...">
|
||||
<i class="ti ti-device-floppy mr-2"></i>
|
||||
Guardar cambios
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="loadSettings"
|
||||
class="btn btn-secondary btn-cancel btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
:disabled="{{ $upload_image_logo === null && $upload_image_logo_dark === null ? 'true' : 'false' }}">
|
||||
<i class="ti ti-rotate-2 mr-2"></i>
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,105 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="general-settings-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Información de página web</h5>
|
||||
<div class="fv-row mb-3">
|
||||
<label for="admin_title" class="form-label">
|
||||
Titulo del sitio <span class="text-xs">(Nombre completo)</span>
|
||||
</label>
|
||||
<input type="text" id="admin_title" wire:model="admin_title" class="form-control"
|
||||
placeholder="Titulo del sitio">
|
||||
@error('admin_title')
|
||||
<span class="text-danger">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="fv-row mb-6">
|
||||
<label for="upload_image_favicon" class="form-label">
|
||||
Icono de página <span class="text-xs">(Favicon)</span>
|
||||
</label>
|
||||
<input type="file" wire:model="upload_image_favicon" id="upload_image_favicon" class="form-control"
|
||||
accept="image/*" />
|
||||
@error('upload_image_favicon')
|
||||
<span class="text-danger">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||
<div class="text-center flex flex-col items-center">
|
||||
<div class="mb-3 text-center d-flex flex-column align-items-center">
|
||||
<div class="image-wrapper-16x16 d-flex justify-content-center align-items-center">
|
||||
<img src="{{ $upload_image_favicon ? $upload_image_favicon->temporaryUrl() : asset('storage/' . $admin_favicon_16x16) }}">
|
||||
</div>
|
||||
<span class="text-muted mt-1">Navegadores web (16x16)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center flex flex-col items-center">
|
||||
<div class="mb-3 text-center d-flex flex-column align-items-center">
|
||||
<div class="image-wrapper-76x76 d-flex justify-content-center align-items-center">
|
||||
<img src="{{ $upload_image_favicon ? $upload_image_favicon->temporaryUrl() : asset('storage/' . $admin_favicon_76x76) }}">
|
||||
</div>
|
||||
<span class="text-muted mt-1">iPad sin Retina (76x76)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center flex flex-col items-center">
|
||||
<div class="mb-3 text-center d-flex flex-column align-items-center">
|
||||
<div class="image-wrapper-120x120 d-flex justify-content-center align-items-center">
|
||||
<img src="{{ $upload_image_favicon ? $upload_image_favicon->temporaryUrl() : asset('storage/' . $admin_favicon_120x120) }}">
|
||||
</div>
|
||||
<span class="text-muted mt-1">iPhone (120x120)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center flex flex-col items-center">
|
||||
<div class="mb-3 text-center d-flex flex-column align-items-center">
|
||||
<div class="image-wrapper-152x152 d-flex justify-content-center align-items-center">
|
||||
<img src="{{ $upload_image_favicon ? $upload_image_favicon->temporaryUrl() : asset('storage/' . $admin_favicon_152x152) }}">
|
||||
</div>
|
||||
<span class="text-muted mt-1">iPad (152x152)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center flex flex-col items-center">
|
||||
<div class="mb-3 text-center d-flex flex-column align-items-center">
|
||||
<div class="image-wrapper-180x180 d-flex justify-content-center align-items-center">
|
||||
<img src="{{ $upload_image_favicon ? $upload_image_favicon->temporaryUrl() : asset('storage/' . $admin_favicon_180x180) }}">
|
||||
</div>
|
||||
<span class="text-muted mt-1">iPhone con Retina HD (180x180)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center flex flex-col items-center">
|
||||
<div class="mb-3 text-center d-flex flex-column align-items-center">
|
||||
<div class="image-wrapper-192x192 d-flex justify-content-center align-items-center">
|
||||
<img src="{{ $upload_image_favicon ? $upload_image_favicon->temporaryUrl() : asset('storage/' . $admin_favicon_192x192) }}">
|
||||
</div>
|
||||
<span class="text-muted mt-1">Android y otros dispositivos móviles (192x192)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="save"
|
||||
class="btn btn-primary btn-save btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
{{ !$upload_image_favicon ? 'disabled' : '' }}
|
||||
data-loading-text="Guardando...">
|
||||
<i class="ti ti-device-floppy mr-2"></i>
|
||||
Guardar cambios
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="loadSettings"
|
||||
class="btn btn-secondary btn-cancel btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
{{ !$upload_image_favicon ? 'disabled' : '' }}>
|
||||
<i class="ti ti-rotate-2 mr-2"></i>
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,196 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="interface-settings-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Ajustes menú y barra superior</h5>
|
||||
|
||||
{{-- Diseño (Layout) --}}
|
||||
<div class="mb-4">
|
||||
<label for="vuexy_myLayout" class="form-label">Diseño</label>
|
||||
<select id="vuexy_myLayout" class="form-select" wire:model="vuexy_myLayout">
|
||||
<option value="vertical">Vertical</option>
|
||||
<option value="horizontal">Horizontal</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Campos exclusivos para diseño Horizontal --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'horizontal'" x-transition>
|
||||
<div class="mb-4">
|
||||
<label for="vuexy_headerType" class="form-label">Tipo de barra superior</label>
|
||||
<select id="vuexy_headerType" class="form-select" wire:model="vuexy_headerType">
|
||||
<option value="static">Estático</option>
|
||||
<option value="fixed">Fijo</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Campos exclusivos para diseño Vertical --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'vertical'" x-transition>
|
||||
<div class="mb-4">
|
||||
<label for="vuexy_navbarType" class="form-label">Tipo de barra de navegación</label>
|
||||
<select id="vuexy_navbarType" class="form-select" wire:model="vuexy_navbarType">
|
||||
<option value="sticky">Fija</option>
|
||||
<option value="static">Estática</option>
|
||||
<option value="hidden">Oculta</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div x-show="$wire.vuexy_hasCustomizer" x-transition>
|
||||
<div x-show="$wire.vuexy_myLayout === 'horizontal'" x-transition>
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
||||
wire:model='vuexy_showDropdownOnHover'
|
||||
parent_class='form-switch'>
|
||||
Mostrar desplegable al pasar el mouse
|
||||
</x-vuexy-admin::form.checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Campos exclusivos para diseño Vertical --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'vertical'" x-transition>
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
||||
wire:model='vuexy_menuFixed'
|
||||
parent_class='form-switch'>
|
||||
Menú fijo
|
||||
</x-vuexy-admin::form.checkbox>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
||||
wire:model='vuexy_menuCollapsed'
|
||||
parent_class='form-switch'>
|
||||
Menú colapsado
|
||||
</x-vuexy-admin::form.checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
{{-- Habilitar UI Customizer --}}
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
||||
wire:model='vuexy_hasCustomizer'
|
||||
parent_class='form-switch'>
|
||||
Habilitar personalizador de plantilla
|
||||
</x-vuexy-admin::form.checkbox>
|
||||
</div>
|
||||
|
||||
<div x-show="$wire.vuexy_hasCustomizer" x-transition>
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
||||
wire:model='vuexy_displayCustomizer'
|
||||
parent_class='form-switch'>
|
||||
Mostrar personalizador de plantilla
|
||||
</x-vuexy-admin::form.checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Máximo de Enlaces Rápidos --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'horizontal' || $wire.vuexy_navbarType !== 'hidden'" x-transition>
|
||||
<hr>
|
||||
<div class="mb-4">
|
||||
<label for="vuexy_maxQuickLinks" class="form-label">Máximo de enlaces rápidos</label>
|
||||
<input type="number" id="vuexy_maxQuickLinks" class="form-control" wire:model="vuexy_maxQuickLinks" min="2" max="20">
|
||||
<p class="text-muted">Selecciona un valor entre 2 y 20.</p>
|
||||
@error('vuexy_maxQuickLinks') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h5 class="card-title mt-6">Ajustes de tema</h5>
|
||||
|
||||
{{-- Tema --}}
|
||||
<div class="mb-4">
|
||||
<label for="vuexy_myTheme" class="form-label">Tema</label>
|
||||
<select id="vuexy_myTheme" class="form-select" wire:model="vuexy_myTheme">
|
||||
<option value="theme-default">Tema predeterminado</option>
|
||||
<option value="theme-bordered">Tema bordeado</option>
|
||||
<option value="theme-semi-dark">Tema semi-oscuro</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Estilo --}}
|
||||
<div class="mb-4">
|
||||
<label for="vuexy_myStyle" class="form-label">Estilo</label>
|
||||
<select id="vuexy_myStyle" class="form-select" wire:model="vuexy_myStyle">
|
||||
<option value="light">Claro</option>
|
||||
<option value="dark">Oscuro</option>
|
||||
<option value="system">Modo del sistema</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h5 class="card-title mt-6">Ajustes de diseño</h5>
|
||||
|
||||
{{-- Vista de Autenticación --}}
|
||||
<div class="mb-4">
|
||||
<label for="vuexy_authViewMode" class="form-label">Modo de vista de autenticación</label>
|
||||
<select id="vuexy_authViewMode" class="form-select" wire:model="vuexy_authViewMode">
|
||||
<option value="cover">Pantalla completa</option>
|
||||
<option value="basic">Básico</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Diseño del Contenido --}}
|
||||
<div class="mb-4">
|
||||
<label for="vuexy_contentLayout" class="form-label">Diseño del contenido</label>
|
||||
<select id="vuexy_contentLayout" class="form-select" wire:model="vuexy_contentLayout">
|
||||
<option value="compact">Compacto</option>
|
||||
<option value="wide">Ancho</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Pie de Página Fijo --}}
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
||||
wire:model='vuexy_footerFixed'
|
||||
parent_class='form-switch'>
|
||||
Pie de página fijo
|
||||
</x-vuexy-admin::form.checkbox>
|
||||
</div>
|
||||
|
||||
{{-- Botones --}}
|
||||
<div class="row mt-6">
|
||||
<div class="col-lg-12 text-end">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="save"
|
||||
disabled
|
||||
class="btn btn-primary btn-save btn-sm mt-2 mr-2 waves-effect waves-light">
|
||||
<i class="ti ti-device-floppy me-1"></i>
|
||||
Guardar cambios
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="loadSettings"
|
||||
disabled
|
||||
class="btn btn-secondary btn-cancel btn-sm mt-2 mr-2 waves-effect waves-light">
|
||||
<i class="ti ti-rotate-2 me-1"></i>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="clearCustomConfig"
|
||||
class="btn btn-success btn-reset btn-sm mt-2 mr-2 waves-effect waves-light">
|
||||
<i class="ti ti-adjustments-cog me-1"></i>
|
||||
Restaurar valores predeterminados
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,67 @@
|
||||
<div>
|
||||
<form id="mail-sender-response-settings-card">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Correo electrónicos de salida</h5>
|
||||
<div class="card-body">
|
||||
<div class="mb-3 fv-row">
|
||||
<label for="from_address" class="form-label">Correo electrónico</label>
|
||||
<input type="text" name="from_address" id="from_address" wire:model='from_address' class="form-control" placeholder="Correo electrónico">
|
||||
@error('from_address') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div class="mb-3 fv-row">
|
||||
<label for="from_name" class="form-label">Nombre</label>
|
||||
<input type="text" name="from_name" id="from_name" wire:model='from_name' class="form-control" placeholder="Nombre">
|
||||
@error('from_name') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<h5 class="mt-6">Correo electrónico de respuesta</h5>
|
||||
<div class="mb-3 fv-row">
|
||||
<label for="reply_to_method" class="form-label">Correo electrónico de respuesta</label>
|
||||
<x-vuexy-admin::form.select
|
||||
wire:model='reply_to_method'
|
||||
:options="$reply_email_options"
|
||||
placeholder="Selecciona el correo electrónico de respuesta" />
|
||||
@error('reply_to_method') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div class="email-custom-div">
|
||||
<div class="mb-3 fv-row">
|
||||
<label for="reply_to_email" class="form-label">Correo electrónico</label>
|
||||
<input type="text" name="reply_to_email" id="reply_to_email" wire:model='reply_to_email' class="form-control" placeholder="Correo electrónico">
|
||||
@error('reply_to_email') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div class="fv-row">
|
||||
<label for="reply_to_name" class="form-label">Nombre</label>
|
||||
<input type="text" name="reply_to_name" id="reply_to_name" wire:model='reply_to_name' class="form-control" placeholder="Nombre">
|
||||
@error('reply_to_name') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
<button
|
||||
type="submit"
|
||||
id="save_sender_response_button"
|
||||
class="btn btn-primary btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
disabled
|
||||
data-loading-text="Guardando...">
|
||||
<i class="ti ti-device-floppy mr-2"></i>
|
||||
Guardar cambios
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
id="cancel_sender_response_button"
|
||||
class="btn btn-secondary btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
wire:click="loadSettings"
|
||||
disabled>
|
||||
<i class="ti ti-rotate-2 mr-2"></i>
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -0,0 +1,86 @@
|
||||
<div x-data="{
|
||||
changeSmtpSettings: @entangle('change_smtp_settings'),
|
||||
saveButtonDisabled: @entangle('save_button_disabled'),
|
||||
}">
|
||||
<form id="mail-smtp-settings-card">
|
||||
<div class="card mb-6">
|
||||
<h5 class="card-header">Servidor saliente de correo electrónico</h5>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
||||
wire:model='change_smtp_settings'
|
||||
parent_class='form-switch'>
|
||||
Cambiar configuración
|
||||
</x-form.checkbox>
|
||||
</div>
|
||||
<div class="mb-3 fv-row">
|
||||
<label for="host" class="form-label">Servidor de correo saliente (SMTP)</label>
|
||||
<input type="text" name="host" id="host" wire:model='host' class="form-control" placeholder="Servidor de salida" :disabled="!changeSmtpSettings">
|
||||
@error('host') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div class="mb-3 fv-row">
|
||||
<label for="port" class="form-label">Puerto SMTP</label>
|
||||
<input type="number" name="port" id="port" wire:model='port' class="form-control" placeholder="Puerto SMTP" :disabled="!changeSmtpSettings">
|
||||
@error('port') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div class="mb-3 fv-row">
|
||||
<label for="encryption" class="form-label">Encriptación</label>
|
||||
<x-vuexy-admin::form.select
|
||||
wire:model='encryption'
|
||||
:options="$encryption_options"
|
||||
:disabled="!$change_smtp_settings"
|
||||
placeholder="Selecciona el método de encriptación" />
|
||||
@error('encryption') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3 fv-row">
|
||||
<label for="username" class="form-label">Usuario</label>
|
||||
<input type="text" name="username" id="username" wire:model='username' class="form-control" placeholder="Usuario" autocomplete="username" :disabled="!changeSmtpSettings">
|
||||
@error('username') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div class="fv-row">
|
||||
<label for="password" class="form-label">Contraseña</label>
|
||||
<input type="password" name="password" id="password" wire:model='password' class="form-control" placeholder="Contraseña" autocomplete="current-password" :disabled="!changeSmtpSettings">
|
||||
@error('password') <span class="text-danger">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
<button
|
||||
type="button"
|
||||
id="test_smtp_connection_button"
|
||||
class="btn btn-success btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
:disabled="!changeSmtpSettings"
|
||||
data-loading-text="Realizando prueba...">
|
||||
<i class="ti ti-flask mr-2"></i>
|
||||
Realizar una prueba
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
id="save_smtp_connection_button"
|
||||
class="btn btn-primary btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
:disabled="saveButtonDisabled"
|
||||
wire:click="save"
|
||||
data-loading-text="Guardando...">
|
||||
<i class="ti ti-device-floppy mr-2"></i>
|
||||
Guardar cambios
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
id="cancel_smtp_connection_button"
|
||||
class="btn btn-secondary btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
wire:click="loadSettings"
|
||||
:disabled="!changeSmtpSettings">
|
||||
<i class="ti ti-rotate-2 mr-2"></i>
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
204
resources/views/livewire/cache/cache-functions.blade.php
vendored
Normal file
204
resources/views/livewire/cache/cache-functions.blade.php
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
<div>
|
||||
<div id="cache-functions-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Resumen de Caché y Funcionalidades</h5>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tipo</th>
|
||||
<th>Estado</th>
|
||||
<th>Detalles</th>
|
||||
<th>Acción</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{-- Caché General --}}
|
||||
<tr>
|
||||
<td><strong>Caché general</strong></td>
|
||||
<td class="text-center">
|
||||
<span class="{{ is_numeric($cacheCounts['general']) && $cacheCounts['general'] > 0 ? 'text-success' : 'text-danger' }}">
|
||||
{{ is_numeric($cacheCounts['general']) ? $cacheCounts['general'] : 'Error' }}
|
||||
</span>
|
||||
</td>
|
||||
<td>Elementos almacenados</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-primary btn-sm my-2 mr-2"
|
||||
wire:click="clearLaravelCache"
|
||||
{{ !is_numeric($cacheCounts['general']) || !$cacheCounts['general'] ? 'disabled' : '' }}
|
||||
data-loading-text="Eliminando caché...">
|
||||
Elimina caché de aplicación
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{-- Configuración --}}
|
||||
<tr>
|
||||
<td><strong>Configuración</strong></td>
|
||||
<td class="text-center">
|
||||
<span class="{{ $cacheCounts['config'] ? 'text-success' : 'text-danger' }}">
|
||||
{{ $cacheCounts['config'] ? 'Habilitada' : 'No habilitada' }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ $cacheCounts['config'] ? 'Caché de configuración activa' : 'No se encontró caché de configuración' }}</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm my-2 mr-2"
|
||||
wire:click="clearConfigCache"
|
||||
{{ !$cacheCounts['config'] ? 'disabled' : '' }}
|
||||
data-loading-text="Eliminando caché...">
|
||||
Eliminar caché de configuración
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-success btn-config-cache btn-sm my-2 mr-2"
|
||||
data-loading-text="Generando caché...">
|
||||
Generar caché de configuración
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{-- Rutas --}}
|
||||
<tr>
|
||||
<td><strong>Rutas</strong></td>
|
||||
<td class="text-center">
|
||||
<span class="{{ $cacheCounts['routes'] ? 'text-success' : 'text-danger' }}">
|
||||
{{ $cacheCounts['routes'] ? 'Habilitada' : 'No habilitada' }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ $cacheCounts['routes'] ? 'Caché de rutas activa' : 'No se encontró caché de rutas' }}</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm my-2 mr-2"
|
||||
wire:click="clearRouteCache"
|
||||
{{ !$cacheCounts['routes'] ? 'disabled' : '' }}
|
||||
data-loading-text="Eliminando caché...">
|
||||
Eliminar caché de rutas
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-success btn-cache-routes btn-sm my-2 mr-2"
|
||||
data-loading-text="Generando caché...">
|
||||
Generar caché de rutas
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{-- Vistas --}}
|
||||
<tr>
|
||||
<td><strong>Vistas</strong></td>
|
||||
<td class="text-center">
|
||||
<span class="{{ $cacheCounts['views'] > 0 ? 'text-success' : 'text-danger' }}">
|
||||
{{ $cacheCounts['views'] }}
|
||||
</span>
|
||||
</td>
|
||||
<td>Vistas compiladas en el sistema</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm my-2 mr-2"
|
||||
wire:click="clearViewCache"
|
||||
{{ !$cacheCounts['views'] ? 'disabled' : '' }}
|
||||
data-loading-text="Eliminando caché...">
|
||||
Eliminar caché de vistas
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-success btn-sm my-2 mr-2"
|
||||
wire:click="cacheViews"
|
||||
data-loading-text="Generando caché...">
|
||||
Generar caché de vistas
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{-- Eventos --}}
|
||||
<tr>
|
||||
<td><strong>Eventos</strong></td>
|
||||
<td class="text-center">
|
||||
<span class="{{ $cacheCounts['events'] > 0 ? 'text-success' : 'text-danger' }}">
|
||||
{{ $cacheCounts['events'] ? 'Habilitada' : 'No habilitada' }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>{{ $cacheCounts['events'] ? 'Caché de eventos activa' : 'No se encontró caché de eventos' }}</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm my-2 mr-2"
|
||||
wire:click="clearEventCache"
|
||||
{{ !$cacheCounts['events'] ? 'disabled' : '' }}
|
||||
data-loading-text="Eliminando caché...">
|
||||
Eliminar caché de eventos
|
||||
</button>
|
||||
<button class="btn btn-success btn-sm my-2 mr-2"
|
||||
wire:click="cacheEvents"
|
||||
data-loading-text="Generando caché...">
|
||||
Generar caché de eventos
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{-- Optimización --}}
|
||||
<tr>
|
||||
<td><strong>Optimización</strong></td>
|
||||
<td class="text-center">N/A</td>
|
||||
<td>Eliminación de cacde de archivos optimizados, eventos, compilados, configuración, rutas y vistas.</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm my-2 mr-2"
|
||||
wire:click="optimizeClear"
|
||||
data-loading-text="Eliminando caché...">
|
||||
Elimina archivos optimizados
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{-- Resets de Autenticación --}}
|
||||
<tr>
|
||||
<td><strong>Roles y permisos</strong></td>
|
||||
<td class="text-center">N/A</td>
|
||||
<td>Gestión de roles y permisos (Spatie Permission)</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm my-2 mr-2"
|
||||
wire:click="resetPermissionCache"
|
||||
data-loading-text="Eliminando caché...">
|
||||
Eliminar caché de permisos
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{-- Tokens de restablecimiento --}}
|
||||
<tr>
|
||||
<td><strong>Tokens de restablecimiento</strong></td>
|
||||
<td class="text-center">N/A</td>
|
||||
<td>Eliminación de tokens de restablecimiento</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm my-2 mr-2"
|
||||
wire:click="clearResetTokens"
|
||||
data-loading-text="Eliminando caché...">
|
||||
Eliminar tokens de restablecimiento
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
<button
|
||||
class="btn btn-secondary btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
wire:click="reloadCacheStats"
|
||||
data-loading-text="Actualizando...">
|
||||
Actualizar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
105
resources/views/livewire/cache/cache-stats.blade.php
vendored
Normal file
105
resources/views/livewire/cache/cache-stats.blade.php
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="cache-stats-card">
|
||||
{{-- Form Card --}}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Gestión de Caché</h5>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Driver</strong></td>
|
||||
<td>{{ $cacheConfig['cache']['default'] }}</td>
|
||||
</tr>
|
||||
@if(in_array($cacheConfig['cache']['default'], ['database', 'memcached', 'redis']))
|
||||
<tr>
|
||||
<td><strong>Versión</strong></td>
|
||||
<td>
|
||||
@if($cacheConfig['cache']['default'] == 'database')
|
||||
{{ $cacheConfig['driver'][$cacheConfig['database']['default']]['version'] }}
|
||||
@else
|
||||
{{ $cacheConfig['driver'][$cacheConfig['cache']['default']]['version'] }}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Servidor</strong></td>
|
||||
<td>{{ $cacheConfig['cache']['host'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if(in_array($cacheConfig['cache']['default'], ['database', 'redis']))
|
||||
<tr>
|
||||
<td><strong>Base de datos</strong></td>
|
||||
<td>
|
||||
@if ($cacheConfig['cache']['default'] == 'database')
|
||||
{{ $cacheConfig['database']['connections'][$cacheConfig['database']['default']]['database'] }}
|
||||
@else
|
||||
{{ $cacheConfig['database']['redis']['cache']['database'] }}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if(in_array($cacheConfig['cache']['default'], ['database', 'memcached', 'redis']))
|
||||
<tr>
|
||||
<td><strong>Prefijo</strong></td>
|
||||
<td>{{ $cacheConfig['cache']['prefix'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if($cacheConfig['cache']['default'] == 'file')
|
||||
<tr>
|
||||
<td><strong>Ubicación de la Caché</strong></td>
|
||||
<td>{{ $cacheConfig['cache']['stores']['file']['path'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if($cacheConfig['cache']['default'] == 'database')
|
||||
<tr>
|
||||
<td><strong>Tabla de Caché</strong></td>
|
||||
<td>{{ $cacheConfig['cache']['stores']['database']['table'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
<tr>
|
||||
<td><strong>Cantidad de Elementos</strong></td>
|
||||
<td>{{ $cacheStats['item_count'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Espacio Utilizado</strong></td>
|
||||
<td>{{ $cacheStats['memory_usage'] }}</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
@if($cacheConfig['cache']['default'] != 'memcached')
|
||||
<button
|
||||
type="button"
|
||||
wire:click="clearCache"
|
||||
class="btn btn-danger btn-clear-cache btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
data-loading-text="Eliminando Caché...">
|
||||
Eliminar Caché
|
||||
</button>
|
||||
@endif
|
||||
<button
|
||||
type="button"
|
||||
wire:click="reloadCacheStats"
|
||||
class="btn btn-secondary btn-reload-cache-stats btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
data-loading-text="Actualizando...">
|
||||
Actualizar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
121
resources/views/livewire/cache/memcached-stats.blade.php
vendored
Normal file
121
resources/views/livewire/cache/memcached-stats.blade.php
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="memcached-stats-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Estadísticas de Memcached</h5>
|
||||
@foreach ($memcachedStats as $stat)
|
||||
<table class="table table-bordered table-sm mb-2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Versión de Memcached</strong></td>
|
||||
<td>{{ $stat['version'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Libevent</strong></td>
|
||||
<td>{{ $stat['libevent'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Servidor</strong></td>
|
||||
<td>{{ $stat['server'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Puerto TCP</strong></td>
|
||||
<td>{{ $stat['tcp_port'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Conexiones máximas</strong></td>
|
||||
<td>{{ $stat['max_connections'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Conexiones totales</strong></td>
|
||||
<td>{{ $stat['total_connections'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Conexiones rechazadas</strong></td>
|
||||
<td>{{ $stat['rejected_connections'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Memoria máxima</strong></td>
|
||||
<td>{{ number_format($stat['limit_maxbytes'] / 1024 / 1024, 2) }} MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Comandos GET ejecutados</strong></td>
|
||||
<td>{{ $stat['cmd_get'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Comandos SET ejecutados</strong></td>
|
||||
<td>{{ $stat['cmd_set'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>GET exitosos</strong></td>
|
||||
<td>{{ $stat['get_hits'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>GET fallidos</strong></td>
|
||||
<td>{{ $stat['get_misses'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Claves expulsadas</strong></td>
|
||||
<td>{{ $stat['evictions'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Megabytes leídos</strong></td>
|
||||
<td>{{ number_format($stat['bytes_read'] / 1024 / 1024, 2) }} MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Megabytes escritos</strong></td>
|
||||
<td>{{ number_format($stat['bytes_written'] / 1024 / 1024, 2) }} MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total de objetos</strong></td>
|
||||
<td>{{ $stat['total_items'] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="table table-bordered table-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Claves almacenadas</strong></td>
|
||||
<td>{{ $stat['curr_items'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Memoria usada</strong></td>
|
||||
<td>
|
||||
<span class="{{ ($stat['bytes'] / $stat['limit_maxbytes']) > 0.8 ? 'text-danger' : 'text-success' }}">
|
||||
{{ number_format($stat['bytes'] / 1024 / 1024, 2) }} MB
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Tiempo de actividad</strong></td>
|
||||
<td>{{ gmdate('H\h i\m s\s', $stat['uptime']) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
<button
|
||||
class="btn btn-danger btn-clear-cache btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
wire:click="clearCache"
|
||||
data-loading-text="Eliminando Caché de Memcached..."
|
||||
{{ $stat['curr_items']? '': 'disabled' }}>
|
||||
Eliminar Caché de Memcached
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-reload-cache-stats btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
wire:click="reloadCacheStats"
|
||||
data-loading-text="Actualizando...">
|
||||
Actualizar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
144
resources/views/livewire/cache/redis-stats.blade.php
vendored
Normal file
144
resources/views/livewire/cache/redis-stats.blade.php
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="redis-stats-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Estadísticas de Redis</h5>
|
||||
<div class="">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-sm mb-2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Versión de Redis</strong></td>
|
||||
<td>{{ $redisStats['redis_version'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Servidor</strong></td>
|
||||
<td>{{ $redisStats['server'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Puerto TCP</strong></td>
|
||||
<td>{{ $redisStats['tcp_port'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Clientes conectados</strong></td>
|
||||
<td>{{ $redisStats['connected_clients'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Clientes bloqueados</strong></td>
|
||||
<td>{{ $redisStats['blocked_clients'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Pico máximo de memoria utilizada</strong></td>
|
||||
<td>
|
||||
@if ($redisStats['maxmemory'] > 0)
|
||||
{{-- Usar maxmemory si está configurado --}}
|
||||
<span class="{{ ($redisStats['used_memory_peak'] / $redisStats['maxmemory']) > 0.8 ? 'text-warning' : 'text-success' }}">
|
||||
{{ $redisStats['used_memory_peak_human'] }}
|
||||
</span>
|
||||
@else
|
||||
{{-- Usar total_system_memory si maxmemory no está configurado --}}
|
||||
<span class="{{ ($redisStats['used_memory_peak'] / $redisStats['total_system_memory']) > 0.8 ? 'text-warning' : 'text-success' }}">
|
||||
{{ $redisStats['used_memory_peak_human'] }}
|
||||
</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Memoria total del sistema</strong></td>
|
||||
<td>{{ $redisStats['total_system_memory_human'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Límite máximo de memoria</strong></td>
|
||||
<td>
|
||||
@if ($redisStats['maxmemory'] > 0)
|
||||
{{ $redisStats['maxmemory_human'] }}
|
||||
@else
|
||||
<span class="text-info">Sin límite configurado</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total de conexiones recibidas</strong></td>
|
||||
<td>{{ $redisStats['total_connections_received'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Total de comandos procesados</strong></td>
|
||||
<td>{{ $redisStats['total_commands_processed'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Política de uso de memoria</strong></td>
|
||||
<td>{{ $redisStats['maxmemory_policy'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Rol del servidor</strong></td>
|
||||
<td>{{ $redisStats['role'] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="table table-bordered table-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Claves almacenadas</strong></td>
|
||||
<td>{{ $redisStats['keys'] }}</td>
|
||||
</tr>
|
||||
@isset ($redisStats['databases']['default']['database'])
|
||||
<tr>
|
||||
<td><strong>Base de datos general de Redis</strong></td>
|
||||
<td>{{ $redisStats['databases']['default']['database'] }}</td>
|
||||
</tr>
|
||||
@endisset
|
||||
@isset ($redisStats['databases']['cache']['database'])
|
||||
<tr>
|
||||
<td><strong>Base de datos de caché</strong></td>
|
||||
<td>{{ $redisStats['databases']['cache']['database'] }}</td>
|
||||
</tr>
|
||||
@endisset
|
||||
@isset ($redisStats['databases']['sessions']['database'])
|
||||
<tr>
|
||||
<td><strong>Base de datos de sesiones</strong></td>
|
||||
<td>{{ $redisStats['databases']['sessions']['database'] }}</td>
|
||||
</tr>
|
||||
@endisset
|
||||
<tr>
|
||||
<td><strong>Memoria usada</strong></td>
|
||||
<td>
|
||||
@if ($redisStats['maxmemory'] > 0)
|
||||
{{-- Usar maxmemory si está configurado --}}
|
||||
<span class="{{ ($redisStats['used_memory'] / $redisStats['maxmemory']) > 0.8 ? 'text-danger' : 'text-success' }}">
|
||||
{{ $redisStats['used_memory_human'] }}
|
||||
</span>
|
||||
@else
|
||||
{{-- Usar total_system_memory si maxmemory no está configurado --}}
|
||||
<span class="{{ ($redisStats['used_memory'] / $redisStats['total_system_memory']) > 0.8 ? 'text-danger' : 'text-success' }}">
|
||||
{{ $redisStats['used_memory_human'] }}
|
||||
</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Tiempo de actividad</strong></td>
|
||||
<td>{{ $redisStats['uptime'] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
<button
|
||||
class="btn btn-secondary btn-clear-cache btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
wire:click="reloadCacheStats"
|
||||
data-loading-text="Actualizando...">
|
||||
Actualizar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
121
resources/views/livewire/cache/session-stats.blade.php
vendored
Normal file
121
resources/views/livewire/cache/session-stats.blade.php
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="session-stats-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Configuraciones de Sesiones</h5>
|
||||
<div class="">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Driver</strong></td>
|
||||
<td>{{ $cacheConfig['session']['driver'] }}</td>
|
||||
</tr>
|
||||
@if(in_array($cacheConfig['session']['driver'], ['database', 'memcached', 'redis']))
|
||||
<tr>
|
||||
<td><strong>Versión</strong></td>
|
||||
<td>
|
||||
@if($cacheConfig['session']['driver'] == 'database')
|
||||
{{ $cacheConfig['driver'][$cacheConfig['database']['default']]['version'] }}
|
||||
@else
|
||||
{{ $cacheConfig['driver'][$cacheConfig['session']['driver']]['version'] }}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Servidor</strong></td>
|
||||
<td>{{ $cacheConfig['session']['host'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if(in_array($cacheConfig['session']['driver'], ['database', 'redis']))
|
||||
<tr>
|
||||
<td><strong>Base de datos</strong></td>
|
||||
<td>{{ $cacheConfig['session']['database'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
@if($cacheConfig['session']['driver'] == 'database')
|
||||
<tr>
|
||||
<td><strong>Tabla de sessiones</strong></td>
|
||||
<td>{{ $cacheConfig['session']['table'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
@if ($cacheConfig['session']['driver'] === 'file')
|
||||
<tr>
|
||||
<td><strong>Ubicación de las sesiones</strong></td>
|
||||
<td>{{ $cacheConfig['session']['files'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
<tr>
|
||||
<td><strong>Tiempo de vida (Minutos)</strong></td>
|
||||
<td>{{ $cacheConfig['session']['lifetime'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Encriptación habilitada</strong></td>
|
||||
<td>{{ $cacheConfig['session']['encrypt'] ? 'Sí' : 'No' }}</td>
|
||||
</tr>
|
||||
|
||||
{{-- Mostrar solo si el driver utiliza cookies --}}
|
||||
@if (in_array($cacheConfig['session']['driver'], ['cookie', 'database', 'redis']))
|
||||
<tr>
|
||||
<td><strong>Nombre de la cookie</strong></td>
|
||||
<td>{{ $cacheConfig['session']['cookie'] ?? 'No especificado' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Path de la Cookie</strong></td>
|
||||
<td>{{ $cacheConfig['session']['path'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Dominio de las sesiones</strong></td>
|
||||
<td>{{ $cacheConfig['session']['domain'] ?? 'No especificado' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Cookies seguras</strong></td>
|
||||
<td>{{ $cacheConfig['session']['secure'] ? 'Sí' : 'No' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Cookies solo HTTPS</strong></td>
|
||||
<td>{{ $cacheConfig['session']['http_only'] ? 'Sí' : 'No' }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
@if($cacheConfig['session']['driver'] != 'memcached')
|
||||
<tr>
|
||||
<td><strong>Sesiones</strong></td>
|
||||
<td>{{ $sessionStats['session_count'] }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if($cacheConfig['session']['driver'] != 'memcached')
|
||||
<div>
|
||||
{{-- Botones --}}
|
||||
<div class="row my-4">
|
||||
<div class="col-lg-12 text-end">
|
||||
@if($cacheConfig['cache']['default'] != 'memcached')
|
||||
<button
|
||||
class="btn btn-danger btn-clear-cache btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
wire:click="clearSessions"
|
||||
{{ $sessionStats['session_count']? '': 'disabled' }}
|
||||
data-loading-text="Eliminando Sesiones...">
|
||||
Eliminar Sesiones
|
||||
</button>
|
||||
@endif
|
||||
<button
|
||||
class="btn btn-secondary btn-reload-cache-stats btn-sm mt-2 mr-2 waves-effect waves-light"
|
||||
wire:click="reloadSessionStats"
|
||||
data-loading-text="Actualizando...">
|
||||
Actualizar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
152
resources/views/livewire/permissions/index.blade.php
Normal file
152
resources/views/livewire/permissions/index.blade.php
Normal file
@ -0,0 +1,152 @@
|
||||
<!-- Permission Table -->
|
||||
<div class="card">
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-permissions table border-top">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>Nombre</th>
|
||||
<th>Asignado a</th>
|
||||
<th>Creado</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!--/ Permission Table -->
|
||||
|
||||
|
||||
<?php
|
||||
/*
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
// Datatable
|
||||
var dt_permission = $('.datatables-permissions')
|
||||
.DataTable({
|
||||
ajax: '{{ url()->current() }}',
|
||||
columns: [
|
||||
// columns according to JSON
|
||||
{data: ''},
|
||||
{data: 'id'},
|
||||
{data: 'name'},
|
||||
{data: 'assigned_to'},
|
||||
{data: 'created_at'},
|
||||
//{data: ''}
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
// For Responsive
|
||||
className: 'control',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
responsivePriority: 2,
|
||||
targets: 0,
|
||||
render: function(data, type, full, meta) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 1,
|
||||
searchable: false,
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
// Name
|
||||
targets: 2,
|
||||
render: function(data, type, full, meta) {
|
||||
return "<span data-id=" + full.id + ">" + data + "</span><br>" +
|
||||
'<small>' + (typeof(full['sub_group']) == 'string'? full['sub_group']: '') + "</small>";
|
||||
}
|
||||
},
|
||||
{
|
||||
// assigned_to
|
||||
targets: 3,
|
||||
orderable: false,
|
||||
render: function(data, type, full, meta) {
|
||||
var $assignedTo = full['assigned_to'],
|
||||
$output = '',
|
||||
roleBadgeObj = <?= json_encode($rows_roles) ?>;
|
||||
|
||||
for (var i = 0; i < $assignedTo.length; i++) {
|
||||
var val = $assignedTo[i];
|
||||
|
||||
$output += roleBadgeObj[val];
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
},
|
||||
{
|
||||
// Created at
|
||||
targets: 4,
|
||||
orderable: false
|
||||
},
|
||||
],
|
||||
order: [
|
||||
[1, 'asc']
|
||||
],
|
||||
dom:
|
||||
'<"row mx-1"' +
|
||||
'<"col-sm-12 col-md-3" l>' +
|
||||
'<"col-sm-12 col-lg-9"<"dt-action-buttons d-flex align-items-center justify-content-lg-end justify-content-center flex-md-nowrap flex-wrap"<"me-1"f><"user_role mt-50 width-200 me-1">B>>' +
|
||||
'>t' +
|
||||
'<"row mx-2"' +
|
||||
'<"col-sm-12 col-md-6"i>' +
|
||||
'<"col-sm-12 col-md-6"p>' +
|
||||
'>',
|
||||
language: $.fn.dataTable.ext.datatable_spanish_default,
|
||||
// Buttons with Dropdown
|
||||
buttons: [],
|
||||
// For responsive popup
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.modal({
|
||||
header: function(row) {
|
||||
var data = row.data();
|
||||
|
||||
return 'Detalles del permiso';
|
||||
}
|
||||
}),
|
||||
type: 'column',
|
||||
renderer: function(api, rowIdx, columns) {
|
||||
var data = $.map(columns, function(col, i) {
|
||||
return col.title !== ''? // ? Do not show row in modal popup if title is blank (for check box)
|
||||
'<tr data-dt-row="' + col.rowIndex + '" data-dt-column="' + col.columnIndex + '">' +
|
||||
'<td>' + col.name + ':' + '</td> ' +
|
||||
'<td>' + col.data + '</td>' +
|
||||
'</tr>' :
|
||||
'';
|
||||
}).join('');
|
||||
|
||||
return data ? $('<table class="table table-striped"/><tbody />').append(data) : false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initComplete: function() {
|
||||
// Adding role filter once table initialized
|
||||
this.api()
|
||||
.columns(3)
|
||||
.every(function() {
|
||||
var column = this;
|
||||
|
||||
var select = $('{!! $roles_html_select !!}')
|
||||
.appendTo('.user_role')
|
||||
.on('change', function() {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
|
||||
column.search(val? val: '', true, false).draw();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
*/
|
||||
|
||||
?>
|
17
resources/views/livewire/permissions/permissions.blade.php
Normal file
17
resources/views/livewire/permissions/permissions.blade.php
Normal file
@ -0,0 +1,17 @@
|
||||
<div>
|
||||
<h2 class="text-xl font-bold">Gestión de Permisos</h2>
|
||||
|
||||
<div class="mb-4">
|
||||
<input type="text" wire:model="permissionName" placeholder="Nombre del permiso" class="border p-2">
|
||||
<button wire:click="createPermission" class="bg-blue-500 text-white px-4 py-2">Crear Permiso</button>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
@foreach($permissions as $permission)
|
||||
<li>
|
||||
{{ $permission->name }}
|
||||
<button wire:click="deletePermission({{ $permission->id }})" class="text-red-500">Eliminar</button>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
347
resources/views/livewire/roles/cards.blade.php
Normal file
347
resources/views/livewire/roles/cards.blade.php
Normal file
@ -0,0 +1,347 @@
|
||||
<div>
|
||||
<p class="mb-4">Un rol proporciona acceso a menús y funciones predefinidas para que, según el rol asignado por un administrador, el usuario tener acceso a lo que necesite.</p>
|
||||
|
||||
<!-- Role cards -->
|
||||
<div class="row g-4">
|
||||
@foreach($roles as $role)
|
||||
<div class="col-xl-4 col-lg-6 col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h6 class="fw-normal mb-2">Total {{ $role->users->count() }} usuario{{ $role->users->count() == 1? '': 's' }}</h6>
|
||||
<ul class="list-unstyled d-flex align-items-center avatar-group mb-0">
|
||||
@foreach($role->users->take(10) as $user)
|
||||
<li data-bs-toggle="tooltip"
|
||||
data-popup="tooltip-custom"
|
||||
data-bs-placement="top"
|
||||
title="{{ $user->name }}"
|
||||
class="avatar avatar-sm pull-up">
|
||||
<img class="rounded-circle" src="{{ asset($user->profile_photo_url) }}" alt="Avatar" />
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-end mt-1">
|
||||
<div class="role-heading">
|
||||
<h4 class="mb-1 role-name">{{ $role->name }}</h4>
|
||||
<span class="badge rounded-pill bg-label-{{ $role->style }}">Style: {{ $role->style }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a href="javascript:;" data-bs-toggle="modal" data-bs-target="#roleModal" wire:click="loadRoleData('view', {{ $role->id }})"
|
||||
class="text-body ms-2"
|
||||
data-bs-toggle="tooltip"
|
||||
data-popup="tooltip-custom"
|
||||
data-bs-placement="top"
|
||||
title="Ver rol">
|
||||
<i class="fa-regular fa-eye"></i>
|
||||
</a>
|
||||
@can('system.roles.edit')
|
||||
@if ($role->name != 'SuperAdmin' && $role->name != 'Admin')
|
||||
<a href="javascript:;" data-bs-toggle="modal" data-bs-target="#roleModal" wire:click="loadRoleData('edit', {{ $role->id }})"
|
||||
class="text-body ms-2"
|
||||
data-bs-toggle="tooltip"
|
||||
data-popup="tooltip-custom"
|
||||
data-bs-placement="top"
|
||||
title="Editar rol">
|
||||
<i class="fa-regular fa-pen-to-square"></i>
|
||||
</a>
|
||||
@endif
|
||||
@endcan
|
||||
@can('system.roles.create')
|
||||
<a href="javascript:;" data-bs-toggle="modal" data-bs-target="#roleModal" wire:click="loadRoleData('clone', {{ $role->id }})"
|
||||
class="text-body ms-2"
|
||||
data-bs-toggle="tooltip"
|
||||
data-popup="tooltip-custom"
|
||||
data-bs-placement="top"
|
||||
title="Crear una copia">
|
||||
<i class="fa-regular fa-copy"></i>
|
||||
</a>
|
||||
@endcan
|
||||
@can('system.roles.delete')
|
||||
@if ($role->name != 'SuperAdmin' && $role->name != 'Admin')
|
||||
<a href="javascript:;" data-bs-toggle="modal" data-bs-target="#roleDeleteModal" data-id="{{ $role->id }}"
|
||||
class="role-delete-modal text-body ms-2"
|
||||
data-bs-toggle="tooltip"
|
||||
data-popup="tooltip-custom"
|
||||
data-bs-placement="top"
|
||||
title="Eliminar">
|
||||
<i class="fa-regular fa-trash-can"></i>
|
||||
</a>
|
||||
@endif
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@can('system.roles.create')
|
||||
<div class="col-xl-4 col-lg-6 col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="row h-100">
|
||||
<div class="col-sm-5">
|
||||
<div class="d-flex align-items-end h-100 justify-content-center mt-sm-0 mt-3">
|
||||
<img src="{{ asset('vendor/vuexy-admin/img/illustrations/add-new-roles.png') }}" class="img-fluid mt-sm-4 mt-md-0" alt="add-new-roles" width="83">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-7">
|
||||
<div class="card-body text-sm-end text-center ps-sm-0">
|
||||
<button data-bs-target="#roleModal" data-bs-toggle="modal" class="btn btn-primary mb-2 text-nowrap add-new-role">
|
||||
<i class="fa-solid fa-plus me-1"></i> Nuevo rol
|
||||
</button>
|
||||
<p class="mb-0 mt-1">Agregar rol, si no existe</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endcan
|
||||
</div>
|
||||
<!--/ Role cards -->
|
||||
|
||||
<!-- Role Modals -->
|
||||
@include('vuexy-admin::roles._form_modal')
|
||||
@include('vuexy-admin::roles._delete_modal')
|
||||
<!-- / Role Modals -->
|
||||
<div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
// Función para obtener elementos del formulario
|
||||
const getFormElements = () => {
|
||||
const form = document.getElementById('roleForm');
|
||||
const formElements = form.querySelectorAll('input, select, textarea, button');
|
||||
|
||||
return {
|
||||
roleModal: document.getElementById('roleModal'),
|
||||
roleTitle: document.querySelector('.role-title'),
|
||||
form: form,
|
||||
inputId: document.querySelector('#roleForm input[name="id"]'),
|
||||
inputName: document.querySelector('#roleForm input[name="name"]'),
|
||||
formElements: formElements,
|
||||
addRoleButton: document.querySelector('.add-new-role'),
|
||||
selectAll: document.querySelector('#selectAll'),
|
||||
submitButton: document.querySelector('#roleForm button[type="submit"]'),
|
||||
deleteRoleButtons: document.querySelectorAll('.role-delete-modal'),
|
||||
deleteRoleModal: document.getElementById('roleDeleteModal'),
|
||||
deleteRoleForm: document.getElementById('deleteRoleForm'),
|
||||
deleteRoleText: document.querySelector('#roleDeleteModal .confirmation-text'),
|
||||
};
|
||||
};
|
||||
|
||||
// Función para habilitar o deshabilitar el formulario
|
||||
const habilitarForm = (enableForm = true) => {
|
||||
const { formElements, submitButton } = getFormElements();
|
||||
|
||||
formElements.forEach(element => {
|
||||
element.disabled = !enableForm;
|
||||
});
|
||||
|
||||
submitButton.disabled = !enableForm;
|
||||
}
|
||||
|
||||
// Función para resetear el formulario
|
||||
const resetForm = () => {
|
||||
const { roleTitle, form, submitButton } = getFormElements();
|
||||
|
||||
roleTitle.textContent = 'Agregar un nuevo rol';
|
||||
submitButton.textContent = 'Crear nuevo rol';
|
||||
|
||||
form.reset();
|
||||
|
||||
// Limpiar errores de validación
|
||||
form.querySelectorAll('.is-invalid').forEach(element => {
|
||||
element.classList.remove('is-invalid');
|
||||
});
|
||||
|
||||
// Restablecer mensajes de error
|
||||
form.querySelectorAll('.invalid-feedback').forEach(element => {
|
||||
element.textContent = '';
|
||||
});
|
||||
};
|
||||
|
||||
// Función para inicializar la validación del formulario
|
||||
const initializeFormValidation = (form) => {
|
||||
const { inputId, inputName } = getFormElements();
|
||||
|
||||
FormValidation.formValidation(form, {
|
||||
fields: {
|
||||
name: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'El nombre del rol es requerido'
|
||||
},
|
||||
// Agregar una regla personalizada para la validación AJAX
|
||||
remote: {
|
||||
url: '{{ route('admin.core.roles.check-unique-name') }}',
|
||||
data: function() {
|
||||
return {
|
||||
name: inputName.value,
|
||||
id: inputId.value,
|
||||
};
|
||||
},
|
||||
message: 'Este nombre de rol ya está en uso',
|
||||
method: 'GET'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
rowSelector: '.col-12'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus(),
|
||||
}
|
||||
})
|
||||
.on('core.form.valid', function(e) {
|
||||
Livewire.dispatch('saveRole');
|
||||
});
|
||||
};
|
||||
|
||||
// Función para agregar el listener a un botón de eliminación de rol
|
||||
const addDeleteRoleListener = (button) => {
|
||||
button.addEventListener('click', function() {
|
||||
const { deleteRoleText } = getFormElements();
|
||||
|
||||
var roleText = '¿Está seguro que desea eliminar el rol "' + button.closest('.card').querySelector('.role-name').innerHTML.trim() + '"?';
|
||||
|
||||
@this.deleteRoleId = this.dataset.id;
|
||||
deleteRoleText.textContent = roleText;
|
||||
});
|
||||
}
|
||||
|
||||
// Función para cambiar el estado de los checkboxes de permisos
|
||||
const setPermissionCheckboxState = (input, state) => {
|
||||
if(!input)
|
||||
return false;
|
||||
|
||||
let modelName = input.getAttribute('wire:model');
|
||||
|
||||
modelName = modelName.split('.').pop();
|
||||
|
||||
if(modelName)
|
||||
@this.permissionsInputs[modelName] = state;
|
||||
}
|
||||
|
||||
// Inicialización
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
Livewire.on('reloadForm', () => {
|
||||
setTimeout(() => {
|
||||
const { form, selectAll, deleteRoleForm } = getFormElements();
|
||||
|
||||
// Seleccionar/deseleccionar todos los checkboxes
|
||||
selectAll.addEventListener('change', e => {
|
||||
Object.keys(@this.permissionsInputs).forEach(key => {
|
||||
@this.permissionsInputs[key] = e.target.checked;
|
||||
});
|
||||
});
|
||||
|
||||
const checkboxList = document.querySelectorAll('#roleForm .permission-row input[type="checkbox"]');
|
||||
|
||||
checkboxList.forEach(checkbox => {
|
||||
checkbox.addEventListener('change', e => {
|
||||
let permissionType = e.target.dataset.type,
|
||||
permissionsRow = e.target.closest('.permission-row');
|
||||
|
||||
if (permissionType == 'view' && !e.target.checked) {
|
||||
let permissionCheckboxView = permissionsRow.querySelector('input[data-type="view"]'),
|
||||
permissionCheckboxCreate = permissionsRow.querySelector('input[data-type="create"]'),
|
||||
permissionCheckboxEdit = permissionsRow.querySelector('input[data-type="edit"]'),
|
||||
permissionCheckboxCancel = permissionsRow.querySelector('input[data-type="cancel"]'),
|
||||
permissionCheckboxDelete = permissionsRow.querySelector('input[data-type="delete"]');
|
||||
|
||||
if(permissionCheckboxView)
|
||||
setPermissionCheckboxState(permissionCheckboxView, false);
|
||||
|
||||
if(permissionCheckboxCreate)
|
||||
setPermissionCheckboxState(permissionCheckboxCreate, false);
|
||||
|
||||
if(permissionCheckboxEdit)
|
||||
setPermissionCheckboxState(permissionCheckboxEdit, false);
|
||||
|
||||
if(permissionCheckboxCancel)
|
||||
setPermissionCheckboxState(permissionCheckboxCancel, false);
|
||||
|
||||
if(permissionCheckboxDelete)
|
||||
setPermissionCheckboxState(permissionCheckboxDelete, false);
|
||||
}
|
||||
|
||||
if ((permissionType == 'create' || permissionType == 'edit' || permissionType == 'cancel' || permissionType == 'delete') && e.target.checked) {
|
||||
let permissionCheckboxView = permissionsRow.querySelector('input[data-type="view"]');
|
||||
|
||||
setPermissionCheckboxState(permissionCheckboxView, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Validación de formulario
|
||||
initializeFormValidation(form);
|
||||
|
||||
deleteRoleForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
Livewire.dispatch('deleteRole');
|
||||
});
|
||||
}, 1);
|
||||
});
|
||||
|
||||
Livewire.on('habilitarFormulario', () => {
|
||||
habilitarForm();
|
||||
})
|
||||
|
||||
Livewire.on('deshabilitarFormulario', () => {
|
||||
setTimeout(() => {
|
||||
habilitarForm(false);
|
||||
}, 1);
|
||||
})
|
||||
|
||||
Livewire.on('modalHide', () => {
|
||||
const { roleModal } = getFormElements();
|
||||
const modal = bootstrap.Modal.getInstance(roleModal);
|
||||
|
||||
modal.hide();
|
||||
});
|
||||
|
||||
Livewire.on('modalDeleteHide', () => {
|
||||
const { deleteRoleModal } = getFormElements();
|
||||
const modal = bootstrap.Modal.getInstance(deleteRoleModal);
|
||||
|
||||
modal.hide();
|
||||
});
|
||||
|
||||
Livewire.on('saveRole', () => {
|
||||
const { deleteRoleButtons } = getFormElements();
|
||||
|
||||
deleteRoleButtons.forEach(button => {
|
||||
addDeleteRoleListener(button);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
const { roleModal, addRoleButton, deleteRoleButtons } = getFormElements();
|
||||
|
||||
// Al agregar Rol
|
||||
addRoleButton.addEventListener('click', function() {
|
||||
const { form } = getFormElements();
|
||||
|
||||
resetForm();
|
||||
habilitarForm();
|
||||
});
|
||||
|
||||
// Al abrir el Modal Crear / Editar / Clonar
|
||||
roleModal.addEventListener('shown.bs.modal', function () {
|
||||
const { inputName } = getFormElements();
|
||||
|
||||
inputName.focus();
|
||||
});
|
||||
|
||||
// Eliminar
|
||||
deleteRoleButtons.forEach(button => {
|
||||
addDeleteRoleListener(button);
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@endsection
|
46
resources/views/livewire/roles/index.blade.php
Normal file
46
resources/views/livewire/roles/index.blade.php
Normal file
@ -0,0 +1,46 @@
|
||||
<div>
|
||||
<h2 class="text-xl font-bold">Gestión de Roles</h2>
|
||||
|
||||
<!-- Crear Nuevo Rol -->
|
||||
<div class="mb-4">
|
||||
<input type="text" wire:model="roleName" placeholder="Nombre del rol" class="border p-2">
|
||||
<button wire:click="createRole" class="bg-blue-500 text-white px-4 py-2">Crear Rol</button>
|
||||
</div>
|
||||
|
||||
<!-- Tabla de Roles -->
|
||||
<table class="table-auto w-full border">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($roles as $role)
|
||||
<tr>
|
||||
<td>{{ $role->name }}</td>
|
||||
<td>
|
||||
<button wire:click="selectRole({{ $role->id }})" class="text-blue-500">Editar</button>
|
||||
<button wire:click="deleteRole({{ $role->id }})" class="text-red-500">Eliminar</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{ $roles->links() }}
|
||||
|
||||
<!-- Editar Permisos del Rol -->
|
||||
@if($selectedRole)
|
||||
<div class="mt-4">
|
||||
<h3>Permisos para {{ $selectedRole->name }}</h3>
|
||||
@foreach($availablePermissions as $permission)
|
||||
<label>
|
||||
<input type="checkbox" wire:model="permissions" value="{{ $permission->id }}">
|
||||
{{ $permission->name }}
|
||||
</label>
|
||||
@endforeach
|
||||
<button wire:click="updateRolePermissions" class="bg-green-500 text-white px-4 py-2 mt-2">Actualizar</button>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
60
resources/views/livewire/users/count.blade.php
Normal file
60
resources/views/livewire/users/count.blade.php
Normal file
@ -0,0 +1,60 @@
|
||||
<div class="row g-4 mb-4 text-right">
|
||||
<div class="col-sm-6 col-xl-3"></div>
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between">
|
||||
<div class="content-left">
|
||||
<div class="d-flex align-items-center my-2">
|
||||
<h3 class="mb-0 mx-4">{{ $enabled }}</h3>
|
||||
</div>
|
||||
<p class="mb-0">Usuarios activos</p>
|
||||
</div>
|
||||
<div class="avatar">
|
||||
<span class="avatar-initial rounded bg-label-success">
|
||||
<i class="ti ti-user-plus ti-sm"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between">
|
||||
<div class="content-left">
|
||||
<div class="d-flex align-items-center my-2">
|
||||
<h3 class="mb-0 mx-4">{{ $disabled }}</h3>
|
||||
</div>
|
||||
<p class="mb-0">Usuarios suspendidos</p>
|
||||
</div>
|
||||
<div class="avatar">
|
||||
<span class="avatar-initial rounded bg-label-warning">
|
||||
<i class="ti ti-user-check ti-sm"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between">
|
||||
<div class="content-left">
|
||||
<div class="d-flex align-items-center my-2">
|
||||
<h3 class="mb-0 mx-4">{{ $total }}</h3>
|
||||
</div>
|
||||
<p class="mb-0">Total de usuarios</p>
|
||||
</div>
|
||||
<div class="avatar">
|
||||
<span class="avatar-initial rounded bg-label-primary">
|
||||
<i class="ti ti-user ti-sm"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
165
resources/views/livewire/users/form.blade.php
Normal file
165
resources/views/livewire/users/form.blade.php
Normal file
@ -0,0 +1,165 @@
|
||||
<div>
|
||||
<x-vuexy-admin::form id="{{ $formId }}" :mode="$mode" wireSubmit="onSubmit" actionPosition="both">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.offcanvas-buttons :mode="$mode" :tagName="$tagName" />
|
||||
</x-slot>
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
{{-- Identificación --}}
|
||||
<x-vuexy-admin::card.basic title="Identificación">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="code" label="Identificador único" icon="ti ti-tag" placeholder="UID code" autofocus autocomplete="off" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre de la sucursal" autocomplete="organization" />
|
||||
<x-vuexy-admin::form.textarea :uid="$uniqueId" model="description" label="Descripción" placeholder="Descripción de la sucursal" :autosize=true />
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Series de facturación --}}
|
||||
<x-vuexy-admin::card.basic title="Series de facturación">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="serie_ingresos" label="Serie para Ingresos" inline=true :labelCol=6 :inputCol=6 maxlength="5" autocomplete="off" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="serie_egresos" label="Serie para Egresos" inline=true :labelCol=6 :inputCol=6 maxlength="5" autocomplete="off" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="serie_pagos" label="Serie para Pagos" inline=true :labelCol=6 :inputCol=6 maxlength="5" autocomplete="off" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Configuraciones --}}
|
||||
<x-vuexy-admin::card.basic title="Configuraciones">
|
||||
<x-vuexy-admin::form.checkbox uid="random" model="status" label="Habilitar sucursal" switch="true" />
|
||||
<x-vuexy-admin::form.checkbox uid="random" model="show_on_website" label="Mostrar en sitio web" switch="true" />
|
||||
<x-vuexy-admin::form.checkbox uid="random" model="enable_ecommerce" label="eCommerce habilitado en sitio Web" switch="true" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
{{-- Información de contacto --}}
|
||||
<x-vuexy-admin::card.basic title="Información de contacto">
|
||||
<x-vuexy-admin::form.input type="tel" :uid="$uniqueId" model="tel" label="Teléfono" icon="ti ti-phone" phoneMode="national" />
|
||||
<x-vuexy-admin::form.input type="tel" :uid="$uniqueId" model="tel2" label="Teléfono alternativo" icon="ti ti-phone" phoneMode="both" />
|
||||
<x-vuexy-admin::form.input type="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="manager_id" label="Gerente" :options="$manager_id_options" placeholder="Selecciona el gerente" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Información fiscal --}}
|
||||
<x-vuexy-admin::card.basic title="Información fiscal">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="rfc" label="RFC" autocomplete="off" pattern="^[A-Z&Ñ]{3,4}[0-9]{6}[A-Z0-9]{3}$" maxlength="13" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="nombre_fiscal" label="Nombre fiscal" autocomplete="organization" />
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="c_regimen_fiscal" label="Régimen fiscal" :options="$c_regimen_fiscal_options" placeholder="Selecciona el régimen fiscal" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="domicilio_fiscal" label="Domicilio fiscal" autocomplete="address-line1" maxlength="100" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
{{-- Dirección --}}
|
||||
<x-vuexy-contacts::card.address :uid="$uniqueId" :paisOptions="$c_pais_options" :estadoOptions="$c_estado_options" :localidadOptions="$c_localidad_options" :municipioOptions="$c_municipio_options" :coloniaOptions="$c_colonia_options"/>
|
||||
|
||||
{{-- Ubicación --}}
|
||||
<x-vuexy-contacts::card.location :uid="$uniqueId" />
|
||||
</div>
|
||||
</div>
|
||||
</x-vuexy-admin::form>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const initializeStoreForm = (mode) => {
|
||||
const initializeContactInformation = () => {
|
||||
let $manager_id = $("#manager_id_{{ $uniqueId }}");
|
||||
|
||||
$manager_id
|
||||
.select2({
|
||||
language: "es",
|
||||
placeholder: "Selecciona el gerente",
|
||||
allowClear: true,
|
||||
width: "100%"
|
||||
})
|
||||
.on('select2:select select2:clear', function (e) {
|
||||
@this.manager_id = e.params?.data?.id || null;
|
||||
});
|
||||
}
|
||||
|
||||
const initializeFiscalInformation = () => {
|
||||
let $c_regimen_fiscal = $("#c_regimen_fiscal_{{ $uniqueId }}");
|
||||
|
||||
$c_regimen_fiscal
|
||||
.select2({
|
||||
language: "es",
|
||||
placeholder: "Selecciona el regimen fiscal",
|
||||
allowClear: true,
|
||||
width: "100%"
|
||||
})
|
||||
.on('select2:select select2:clear', function (e) {
|
||||
@this.c_regimen_fiscal = e.params?.data?.id || null;
|
||||
});
|
||||
}
|
||||
|
||||
const initializeLocationIQ = () => {
|
||||
//
|
||||
}
|
||||
|
||||
const initializeAddressFormHandler = () => {
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
|
||||
// Definición de selectores AddressFormHandler
|
||||
formSelectors = {
|
||||
c_pais: '#c_pais_{{ $uniqueId }}',
|
||||
c_estado: '#c_estado_{{ $uniqueId }}',
|
||||
c_localidad: '#c_localidad_{{ $uniqueId }}',
|
||||
c_municipio: '#c_municipio_{{ $uniqueId }}',
|
||||
c_colonia: '#c_colonia_{{ $uniqueId }}',
|
||||
c_codigo_postal: '#c_codigo_postal_{{ $uniqueId }}',
|
||||
direccion: '#direccion_{{ $uniqueId }}',
|
||||
notification: '#{{ $formId }} .address-notification'
|
||||
};
|
||||
|
||||
// Definición de rutas AJAX Componente AddressFormHandler
|
||||
const ajaxRoutes = {
|
||||
codigo_postal: "{{ route('admin.core.sat.get.ajax', 'codigo_postal') }}",
|
||||
localidad: "{{ route('admin.core.sat.get.ajax', 'localidad') }}",
|
||||
estado: "{{ route('admin.core.sat.get.ajax', 'estado') }}",
|
||||
municipio: "{{ route('admin.core.sat.get.ajax', 'municipio') }}",
|
||||
colonia: "{{ route('admin.core.sat.get.ajax', 'colonia') }}"
|
||||
};
|
||||
|
||||
// Inicializamos el handler de la información de la dirección
|
||||
new AddressFormHandler(formSelectors, ajaxRoutes, @this, csrfToken);
|
||||
}
|
||||
|
||||
const initializeLocationCard = (mode) => {
|
||||
const locationInputs = {
|
||||
search: '#location_search_{{ $uniqueId }}',
|
||||
btnSearch: '#btn_search_{{ $uniqueId }}',
|
||||
lat: '#lat_{{ $uniqueId }}',
|
||||
lng: '#lng_{{ $uniqueId }}',
|
||||
btnClear: '#{{ $formId }} .btn-clear-coords',
|
||||
mapId: 'locationMap_{{ $uniqueId }}',
|
||||
}
|
||||
|
||||
leafletMap = LeafletMapHelper.initializeMap(locationInputs, mode, @this);
|
||||
}
|
||||
|
||||
|
||||
// Inicializamos Tarjeta de Información de contacto
|
||||
initializeContactInformation();
|
||||
|
||||
// Inicializamos Tarjeta de Información fiscal
|
||||
initializeFiscalInformation();
|
||||
|
||||
// Inicializamos Tarjeta de Dirección
|
||||
initializeAddressFormHandler();
|
||||
|
||||
// Inicializamos Tarjeta de Ubicación
|
||||
initializeLocationCard(mode);
|
||||
|
||||
// Deshabilitamos el formulario si estamos eliminando
|
||||
if (mode === 'delete') {
|
||||
window.disableStoreForm('#{{ $formId }}');
|
||||
}
|
||||
}
|
||||
|
||||
// Evento para inicializar el formulario
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.addEventListener('on-failed-validation-store', (event) => {
|
||||
setTimeout(() => {
|
||||
initializeStoreForm('{{ $mode }}');
|
||||
}, 10);
|
||||
});
|
||||
|
||||
initializeStoreForm('{{ $mode }}');
|
||||
});
|
||||
</script>
|
||||
@endpush
|
704
resources/views/livewire/users/index.blade.copy.php
Normal file
704
resources/views/livewire/users/index.blade.copy.php
Normal file
@ -0,0 +1,704 @@
|
||||
<div>
|
||||
<div class="users-index alert-errors">{!! $indexAlert !!}</div>
|
||||
|
||||
<!-- Users List Table -->
|
||||
<div class="card" wire:ignore>
|
||||
<div class="card-datatable table-responsive">
|
||||
<table class="datatables-users table">
|
||||
<thead class="border-top">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Id</th>
|
||||
<th>Usuario</th>
|
||||
<th>Roles</th>
|
||||
<th>Estatus</th>
|
||||
<th>Creado</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Offcanvas to add new user -->
|
||||
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasUser" aria-labelledby="offcanvasLabel">
|
||||
<div class="offcanvas-header border-bottom">
|
||||
<h5 id="offcanvasLabel" class="offcanvas-title">{{ $modalTitle }}</h5>
|
||||
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body mx-0 flex-grow-0 p-6 h-100">
|
||||
<form class="pt-0" id="userForm" autocomplete='off'>
|
||||
<input type="hidden" name="id" wire:model='userId' />
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nombre completo</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text"><i class="ti ti-user"></i></span>
|
||||
<input type="text" name="name" wire:model='name' id="name" class="form-control" placeholder="Pepe Pecas" />
|
||||
</div>
|
||||
<div class="error-message"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Correo electrónico</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text"><i class="ti ti-mail"></i></span>
|
||||
<input type="text" name="email" wire:model='email' id="email" class="form-control" placeholder="picapapas@mail.com" />
|
||||
</div>
|
||||
<div class="error-message"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Contraseña</label>
|
||||
<div class="input-group input-group-merge form-password-toggle">
|
||||
<span class="input-group-text"><i class="ti ti-key"></i></span>
|
||||
<input type="password" name="password" wire:model='password' class="form-control form-control-merge" id="password" placeholder="············" />
|
||||
<span class="input-group-text cursor-pointer"><i class="ti ti-eye"></i></span>
|
||||
</div>
|
||||
<div class="error-message"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="roles" class="form-label">Roles del usuario</label>
|
||||
<x-vuexy-admin::form.select
|
||||
id="roles"
|
||||
name="roles[]"
|
||||
wire:model='roles'
|
||||
:options="$roles_options"
|
||||
multiple
|
||||
class="select2 form-select" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Estatus</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text"><i class="ti ti-alert-triangle"></i></span>
|
||||
<x-vuexy-admin::form.select
|
||||
id="status"
|
||||
name="status"
|
||||
wire:model='status'
|
||||
:options="$status_options"
|
||||
class="form-select" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="photo" class="form-label">Imagen de perfil</label>
|
||||
<div class="image-wrapper mb-1">
|
||||
<img id="user-image" class="max-w-full" src="{{ $src_photo }}" alt="">
|
||||
</div>
|
||||
<input type="file" name="photo" id="photo" class='form-control' accept='image/*' />
|
||||
</div>
|
||||
|
||||
<div class="alert-errors"></div>
|
||||
|
||||
<button type="submit" class="btn btn-primary me-3 data-submit">{{ $btnSubmitTxt }}</button>
|
||||
<button type="reset" class="btn btn-label-danger" data-bs-dismiss="offcanvas">Cancelar</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete User Modal -->
|
||||
<div class="modal fade" id="deleteUserModal" tabindex="-1" aria-hidden="true" wire:ignore>
|
||||
<div class="modal-dialog modal-dialog-centered modal-simple">
|
||||
<div class="modal-content p-3 p-md-5">
|
||||
<div class="modal-body">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<div class="text-center mb-4">
|
||||
<h3 class="mb-2">Eliminar usuario</h3>
|
||||
<p class="text-muted">El proceso de eliminación es definitivo e irreversible</p>
|
||||
</div>
|
||||
<form class="row g-3">
|
||||
<div class="col-12">
|
||||
<p class="name text-center font-bold"></p>
|
||||
</div>
|
||||
<div class="col-12 text-center">
|
||||
<button type="submit" class="btn btn-primary me-sm-3 me-1 btn-submit">Eliminar usuario</button>
|
||||
<button type="reset" class="btn btn-secondary btn-reset" data-bs-dismiss="modal" aria-label="Close">Cancelar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--/ Delete User Modal -->
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
update_route = '{{ route('admin.core.users.update-ajax', '0~0') }}',
|
||||
show_route = '{{ route('admin.core.users.show', '0~0') }}',
|
||||
destroy_route = '{{ route('admin.core.users.destroy', '0~0') }}';
|
||||
|
||||
var statusObj = <?= json_encode($statuses) ?>,
|
||||
$usersIndexAlert = $('.users-index.alert-errors'),
|
||||
$dt_user_table = $('.datatables-users'),
|
||||
dt_user;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 8
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val();
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form) {
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
|
||||
var url = $(form.id).val() ?
|
||||
update_route.replace('0~0', $(form.id).val()) :
|
||||
store_route;
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
|
||||
//@this.call('refreshUserCount');
|
||||
|
||||
dt_user.ajax.reload();
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
// Add User
|
||||
add_user = () => {
|
||||
let $offcanvasUser = $('#offcanvasUser');
|
||||
|
||||
$('.offcanvas-title', $offcanvasUser).html('Crear usuario nuevo');
|
||||
$('.btn-submit', $offcanvasUser).html('Crear usuario');
|
||||
|
||||
if ($('input[name=id]', $offcanvasUser).val()){
|
||||
document.getElementById('userForm').reset();
|
||||
|
||||
$('input[name=id]', $offcanvasUser).val('');
|
||||
|
||||
$('#roles').trigger('change');
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('.alert-errors', $offcanvasUser).html('');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Livewire.on('openModal', () => {
|
||||
setTimeout(() =>{
|
||||
offcanvasUser.show();
|
||||
|
||||
load_js_form();
|
||||
|
||||
dt_user.ajax.reload();
|
||||
}, 1)
|
||||
});
|
||||
|
||||
Livewire.on('afterDelete', () => {
|
||||
setTimeout(() =>{
|
||||
var modalElement = document.getElementById('deleteUserModal'),
|
||||
modalDelete = bootstrap.Modal.getInstance(modalElement);
|
||||
|
||||
modalDelete.hide();
|
||||
|
||||
load_js_form();
|
||||
|
||||
dt_user.ajax.reload();
|
||||
}, 1)
|
||||
});
|
||||
|
||||
|
||||
// (jquery)
|
||||
$(function () {
|
||||
let borderColor, bodyBg, headingColor;
|
||||
|
||||
if (isDarkStyle) {
|
||||
borderColor = config.colors_dark.borderColor;
|
||||
bodyBg = config.colors_dark.bodyBg;
|
||||
headingColor = config.colors_dark.headingColor;
|
||||
} else {
|
||||
borderColor = config.colors.borderColor;
|
||||
bodyBg = config.colors.bodyBg;
|
||||
headingColor = config.colors.headingColor;
|
||||
}
|
||||
|
||||
// Users datatable
|
||||
dt_user = $dt_user_table.DataTable({
|
||||
ajax: '{{ url()->current() }}',
|
||||
columns: [
|
||||
// columns according to JSON
|
||||
{ data: 'id' },
|
||||
{ data: 'id' },
|
||||
{ data: 'name' },
|
||||
{ data: 'roles' },
|
||||
{ data: 'status' },
|
||||
{ data: 'created_at' },
|
||||
{ data: 'action' }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
// For Responsive
|
||||
className: 'control',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
responsivePriority: 2,
|
||||
targets: 0,
|
||||
render: function (data, type, full, meta) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
// User name and email
|
||||
targets: 2,
|
||||
responsivePriority: 3,
|
||||
render: function (data, type, full, meta) {
|
||||
var $name = full['name'],
|
||||
$email = full['email'],
|
||||
$image = full['avatar'];
|
||||
|
||||
if ($image) {
|
||||
// For Avatar image
|
||||
var $output =
|
||||
'<img src="' + $image + '" alt="Avatar" class="rounded-circle">';
|
||||
} else {
|
||||
// For Avatar badge
|
||||
var $name = full['full_name'],
|
||||
$initials = $name.match(/\b\w/g) || [];
|
||||
$initials = (($initials.shift() || '') + ($initials.pop() || '')).toUpperCase();
|
||||
$output = '<span class="avatar-initial rounded-circle>' + $initials + '</span>';
|
||||
}
|
||||
|
||||
// Creates full output for row
|
||||
var $row_output =
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">' +
|
||||
'<div class="avatar-wrapper">' +
|
||||
'<div class="avatar avatar-sm me-4">' + $output + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="d-flex flex-column">' +
|
||||
'<a href="' + show_route.replace('0~0', full['id']) + '" class="text-heading text-truncate"><span class="fw-medium">' + $name + '</span></a>' +
|
||||
'<small>' + $email + '</small>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
return $row_output;
|
||||
}
|
||||
},
|
||||
{
|
||||
// User Role
|
||||
targets: 3,
|
||||
render: function(data, type, full, meta) {
|
||||
var $assignedTo = full['roles'],
|
||||
$output = '',
|
||||
roleBadgeObj = <?= json_encode($rows_roles) ?>;
|
||||
|
||||
for (var i = 0; i < $assignedTo.length; i++) {
|
||||
var val = $assignedTo[i];
|
||||
|
||||
$output += roleBadgeObj[val];
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
},
|
||||
{
|
||||
// User Status
|
||||
targets: 4,
|
||||
render: function (data, type, full, meta) {
|
||||
var $status = full['status'];
|
||||
|
||||
return ('<span class="badge rounded-pill ' + statusObj[$status].class + '" text-capitalized>' + statusObj[$status].title + '</span>');
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
// Created
|
||||
targets: 5,
|
||||
render: function (data, type, full, meta) {
|
||||
return full['created_at'];
|
||||
}
|
||||
},
|
||||
{
|
||||
// Actions
|
||||
targets: -1,
|
||||
title: 'Acciones',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return ('<div class="d-flex align-items-center">' +
|
||||
'<a href="' + show_route.replace('0~0', full['id']) + '" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill"><i class="ti ti-eye ti-md"></i></a>' +
|
||||
'<a href="javascript:;"" wire:click.prevent="edit(' + full['id'] + ')" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill"><i class="ti ti-edit ti-md"></i></a>' +
|
||||
@can('system.users.destroy')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>' +
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">' +
|
||||
'<a href="javascript:;" class="dropdown-item delete-record">Eliminar</a>' +
|
||||
'</div>' +
|
||||
@endcan
|
||||
'</div>');
|
||||
}
|
||||
}
|
||||
],
|
||||
order: [[2, 'desc']],
|
||||
dom:
|
||||
'<"row"' +
|
||||
'<"col-md-2"<"ms-n2"l>>' +
|
||||
'<"col-md-10"<"dt-action-buttons text-xl-end text-lg-start text-md-end text-start d-flex align-items-center justify-content-end flex-md-row flex-column mb-6 mb-md-0 mt-n6 mt-md-0"<"user_role dataTables_filter">fB>>' +
|
||||
'>t' +
|
||||
'<"row"' +
|
||||
'<"col-sm-12 col-md-6"i>' +
|
||||
'<"col-sm-12 col-md-6"p>' +
|
||||
'>',
|
||||
language: $.fn.dataTable.ext.datatable_spanish_default,
|
||||
// Buttons with Dropdown
|
||||
buttons: [
|
||||
{
|
||||
extend: 'collection',
|
||||
className: 'btn btn-label-secondary dropdown-toggle mx-4 waves-effect waves-light',
|
||||
text: '<i class="ti ti-upload me-2 ti-xs"></i>Exportar',
|
||||
buttons: [
|
||||
{
|
||||
extend: 'print',
|
||||
text: '<i class="ti ti-printer me-2" ></i>Imprimir',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be print
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
},
|
||||
customize: function (win) {
|
||||
//customize print view for dark
|
||||
$(win.document.body)
|
||||
.css('color', headingColor)
|
||||
.css('border-color', borderColor)
|
||||
.css('background-color', bodyBg);
|
||||
$(win.document.body)
|
||||
.find('table')
|
||||
.addClass('compact')
|
||||
.css('color', 'inherit')
|
||||
.css('border-color', 'inherit')
|
||||
.css('background-color', 'inherit');
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'csv',
|
||||
text: '<i class="ti ti-file-text me-2" ></i>Csv',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'excel',
|
||||
text: '<i class="ti ti-file-spreadsheet me-2"></i>Excel',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/*
|
||||
{
|
||||
extend: 'pdf',
|
||||
text: '<i class="ti ti-file-code-2 me-2"></i>Pdf',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
*/
|
||||
{
|
||||
extend: 'copy',
|
||||
text: '<i class="ti ti-copy me-2" ></i>Copiar',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@can('system.users.create') {
|
||||
text: '<i class="ti ti-plus me-0 me-sm-1 ti-xs"></i><span class="d-none d-sm-inline-block">Nuevo usuario</span>',
|
||||
className: 'add-new btn btn-primary waves-effect waves-light',
|
||||
attr: {
|
||||
'onclick': 'add_user()',
|
||||
'data-bs-toggle': 'offcanvas',
|
||||
'data-bs-target': '#offcanvasUser'
|
||||
}
|
||||
}
|
||||
@endcan
|
||||
],
|
||||
// For responsive popup
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.modal({
|
||||
header: function (row) {
|
||||
var data = row.data();
|
||||
return 'Details of ' + data['full_name'];
|
||||
}
|
||||
}),
|
||||
type: 'column',
|
||||
renderer: function (api, rowIdx, columns) {
|
||||
var data = $.map(columns, function (col, i) {
|
||||
return col.title !== '' // ? Do not show row in modal popup if title is blank (for check box)
|
||||
? '<tr data-dt-row="' + col.rowIndex + '" data-dt-column="' + col.columnIndex + '">' +
|
||||
'<td>' + col.title + ':' + '</td> ' +
|
||||
'<td>' + col.data + '</td>' +
|
||||
'</tr>'
|
||||
: '';
|
||||
}).join('');
|
||||
|
||||
return data ? $('<table class="table"/><tbody />').append(data) : false;
|
||||
}
|
||||
}
|
||||
},
|
||||
initComplete: function () {
|
||||
this.api()
|
||||
.columns(3)
|
||||
.every(function () {
|
||||
var column = this,
|
||||
select = $('{!! $roles_html_select !!}')
|
||||
.appendTo('.user_role')
|
||||
.on('change', function() {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
|
||||
column.search(val? val: '', true, false).draw();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Delete Record
|
||||
$('.datatables-users tbody')
|
||||
.on('click', '.delete-record', function () {
|
||||
var tr = $(this).closest('tr'),
|
||||
data = dt_user.row(tr).data();
|
||||
|
||||
$('#deleteUserModal').modal('show');
|
||||
$('#deleteUserModal .name').html(data.id + ': ' + data.name);
|
||||
|
||||
$('#deleteUserModal').data('userId', data.id);
|
||||
});
|
||||
|
||||
|
||||
// Attach the event listener to the submit button
|
||||
$('#deleteUserModal .btn-submit')
|
||||
.on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
@this.call('delete', $('#deleteUserModal').data('userId'));
|
||||
});
|
||||
|
||||
|
||||
// Filter form control to default size
|
||||
// ? setTimeout used for multilingual table initialization
|
||||
setTimeout(() => {
|
||||
$('.dataTables_filter .form-control').removeClass('form-control-sm');
|
||||
$('.dataTables_length .form-select').removeClass('form-select-sm');
|
||||
}, 300);
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@endpush
|
7
resources/views/livewire/users/index.blade.php
Normal file
7
resources/views/livewire/users/index.blade.php
Normal file
@ -0,0 +1,7 @@
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" :routes="$routes" >
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-off-canvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
52
resources/views/livewire/users/offcanvas-form.blade.php
Normal file
52
resources/views/livewire/users/offcanvas-form.blade.php
Normal file
@ -0,0 +1,52 @@
|
||||
<div>
|
||||
<x-vuexy-admin::offcanvas.basic :id="$offcanvasId" :tag-name="$tagName">
|
||||
<x-vuexy-admin::form :uid="$uniqueId" :id="$formId" :mode="$mode" wireSubmit="onSubmit">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.offcanvas-buttons :mode="$mode" :tagName="$tagName" />
|
||||
</x-slot>
|
||||
{{-- Usuario --}}
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="code" label="Código de usuario" icon="ti ti-tag" parent-class="col-md-8" autocomplete="off" />
|
||||
</div>
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre(s)" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="last_name" label="Apellidos" />
|
||||
<hr>
|
||||
|
||||
{{-- Teléfonos y Correos --}}
|
||||
<x-vuexy-admin::form.input type="tel" :uid="$uniqueId" model="tel" label="Teléfono" icon="ti ti-phone" phoneMode="both" />
|
||||
<x-vuexy-admin::form.input type="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
<hr>
|
||||
|
||||
|
||||
<x-vuexy-admin::form.textarea :uid="$uniqueId" model="notes" label="Notas / Observaciones" />
|
||||
<hr>
|
||||
|
||||
{{-- Estado del Centro de Trabajo --}}
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_partner" label="Es socio" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_employee" label="Es empleado" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_prospect" label="Es prospecto" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_customer" label="Es cliente" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_provider" label="Es proveedor" switch />
|
||||
<hr>
|
||||
|
||||
</x-vuexy-admin::form>
|
||||
</x-vuexy-admin::offcanvas.basic>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
// Evento para inicializar el formulario cuando se carga la página
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const initializeUserForm = () => {
|
||||
|
||||
};
|
||||
|
||||
var myOffcanvas = document.getElementById('{{ $offcanvasId }}');
|
||||
|
||||
myOffcanvas.addEventListener('show.bs.offcanvas', function () {
|
||||
initializeUserForm();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@endpush
|
1685
resources/views/livewire/users/show.blade.php
Normal file
1685
resources/views/livewire/users/show.blade.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user