Testing Alpha
This commit is contained in:
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" />
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" />
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" />
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<p>Module Management</p>
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<p>Plugins</p>
|
||||
</div>
|
83
resources/views/livewire/navbar/vuexy-quicklinks.blade.php
Normal file
83
resources/views/livewire/navbar/vuexy-quicklinks.blade.php
Normal file
@ -0,0 +1,83 @@
|
||||
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown">
|
||||
<a class="nav-link btn btn-text-secondary btn-icon rounded-pill btn-icon dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
|
||||
<i class='ti ti-layout-grid-add ti-md'></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end p-0">
|
||||
<div class="dropdown-menu-header border-bottom">
|
||||
<div class="dropdown-header d-flex align-items-center py-3">
|
||||
<h6 class="mb-0 me-auto">Atajos</h6>
|
||||
@if($isRouteAllowed)
|
||||
@if($vuexyQuickLinks['current_page_in_list'])
|
||||
<button
|
||||
wire:click="remove('{{ Route::currentRouteName() }}')"
|
||||
type="button"
|
||||
class="btn btn-text-secondary rounded-pill btn-icon dropdown-shortcuts-remove"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Remover atajo">
|
||||
<i class="ti ti-trash text-heading"></i>
|
||||
</button>
|
||||
@else
|
||||
@if($vuexyQuickLinks['totalLinks'] < config('koneko.admin.vuexy.maxQuickLinks', 8))
|
||||
<button
|
||||
wire:click="add('{{ Route::currentRouteName() }}')"
|
||||
type="button"
|
||||
class="btn btn-text-secondary rounded-pill btn-icon dropdown-shortcuts-add"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Agregar atajo">
|
||||
<i class="ti ti-plus text-heading"></i>
|
||||
</button>
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-shortcuts-list scrollable-container">
|
||||
@foreach ($vuexyQuickLinks['rows'] as $quickLinksRow)
|
||||
<div class="row row-bordered overflow-visible g-0">
|
||||
@foreach ($quickLinksRow as $key => $quickLink)
|
||||
<div class="dropdown-shortcuts-item col @if ($quickLink['route'] === $currentRouteId) active @endif">
|
||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i class="ti ti-{{ $quickLink['icon'] }} ti-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="{{ $quickLink['url'] }}" class="stretched-link">{{ $quickLink['title'] }}</a>
|
||||
<small>{{ $quickLink['subtitle'] }}</small>
|
||||
</div>
|
||||
@if ($key == 0 && !isset($quickLinksRow[1]))
|
||||
<div class="dropdown-shortcuts-item col"></div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.addEventListener('refresh-tooltips', () => {
|
||||
initVuexyTooltips();
|
||||
|
||||
setTimeout(() => {
|
||||
window.Helpers.initNavbarDropdownScrollbar();
|
||||
}, 1);
|
||||
});
|
||||
|
||||
function initVuexyTooltips() {
|
||||
// Limpia tooltips previos
|
||||
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||
|
||||
tooltipTriggerList.forEach(el => {
|
||||
const tooltip = bootstrap.Tooltip.getInstance(el);
|
||||
|
||||
if (tooltip) {
|
||||
tooltip.dispose(); // elimina instancia previa
|
||||
}
|
||||
});
|
||||
|
||||
// Vuelve a inicializar
|
||||
tooltipTriggerList.forEach(el => {
|
||||
new bootstrap.Tooltip(el);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,207 @@
|
||||
@php
|
||||
/**
|
||||
* Vista Blade para mostrar los accesos rápidos.
|
||||
* Compatible con Vuexy Admin y modo oscuro.
|
||||
*/
|
||||
@endphp
|
||||
|
||||
<div class="space-y-8">
|
||||
<!-- 🔍 Campo de búsqueda -->
|
||||
<x-vuexy-admin::form.input
|
||||
id="quick_acces_search"
|
||||
placeholder="Buscar acceso rápido..."
|
||||
suffixIcon="ti ti-search"
|
||||
class="form-control-lg"
|
||||
mb0
|
||||
autocomplete="off"
|
||||
role="search"
|
||||
aria-label="Buscar acceso rápido"
|
||||
/>
|
||||
@if($components)
|
||||
<div class="col-12 overflow-hidden mt-2">
|
||||
<div id="quick-access-scroll">
|
||||
<ul class="nav mb-1" id="quick-access-tabs">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link active" data-component-filter="all">Todos</button>
|
||||
</li>
|
||||
@foreach($components as $component)
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-component-filter="{{ $component['namespace'] }}">
|
||||
{{ \Str::headline($component['label']) }}
|
||||
</button>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@foreach ($menuCards as $category)
|
||||
@if(!empty($category['cards']) || config('vuexy.debug.menu.show_all_hidden', false))
|
||||
<div class="quick-access-category">
|
||||
<!-- Título de categoría con icono -->
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="{{ $category['icon'] }} text-2xl text-primary"></i>
|
||||
<h5 class="mb-0 ms-2 text-dark dark:text-white search-term">{{ $category['title'] }}</h5>
|
||||
</div>
|
||||
<!-- Descripción de categoría -->
|
||||
@if (!empty($category['description']))
|
||||
<p class="text-muted">
|
||||
{{ $category['description'] }}
|
||||
</p>
|
||||
@endif
|
||||
<!-- Grid de accesos rápidos en formato de Cards -->
|
||||
@if (!empty($category['cards']))
|
||||
<div class="row row-cols-2 row-cols-md-4 row-cols-lg-5 g-4">
|
||||
@foreach ($category['cards'] as $item)
|
||||
<div class="col quick-access-card" data-component="{{ $item['component'] ?? 'unknown' }}">
|
||||
<a href="{{ $item['url'] }}" class="text-decoration-none">
|
||||
<div class="card border-0 shadow-sm hover:shadow-lg transition-all duration-300">
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center text-center p-4">
|
||||
<!-- Ícono -->
|
||||
<i class="{{ $item['icon'] }} text-3xl text-primary mt-1 mb-3"></i>
|
||||
|
||||
<!-- Título -->
|
||||
<h6 class="mb-0 text-dark dark:text-light fw-semibold search-term">
|
||||
{{ $item['title'] }}
|
||||
@if(config('koneko.admin.menu.debug.show_broken_routers') && $item['url'] == "javascript:;")
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="xs mr-1">❌</span>
|
||||
Sin URL valida
|
||||
</p>
|
||||
@endif
|
||||
@if(config('koneko.admin.menu.debug.show_disallowed_links') && $item['disallowed_link'])
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="text-sm mr-1">🔒</span>
|
||||
Sin permisos
|
||||
</p>
|
||||
@endif
|
||||
@if(config('koneko.admin.menu.debug.show_hidden_items') && $item['hidden_item'])
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="text-sm mr-1">🚧</span>
|
||||
Vista forzada
|
||||
</p>
|
||||
@endif
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-muted fst-italic">
|
||||
No hay accesos rápidos en esta categoría.
|
||||
</p>
|
||||
@endif
|
||||
<div class="pb-6"></div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const quickAccessScroll = document.getElementById('quick-access-scroll');
|
||||
const searchInput = document.getElementById('quick_acces_search');
|
||||
const categories = document.querySelectorAll('.quick-access-category');
|
||||
const tabButtons = document.querySelectorAll('#quick-access-tabs button');
|
||||
const normalize = str => str?.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||
|
||||
const highlightMatch = (element, term) => {
|
||||
const text = element.dataset.originalText || element.textContent;
|
||||
|
||||
element.dataset.originalText = text; // Save original
|
||||
|
||||
if (!term) {
|
||||
element.innerHTML = text;
|
||||
return;
|
||||
}
|
||||
|
||||
const regex = new RegExp(`(${term})`, 'gi');
|
||||
|
||||
element.innerHTML = text.replace(regex, '<mark>$1</mark>');
|
||||
};
|
||||
|
||||
let currentComponentFilter = 'all';
|
||||
|
||||
|
||||
// PerfectScroll
|
||||
if (quickAccessScroll) {
|
||||
new PerfectScrollbar(quickAccessScroll, {
|
||||
suppressScrollY: true,
|
||||
wheelPropagation: false
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Buscador
|
||||
searchInput.focus();
|
||||
searchInput.addEventListener('input', applyFilters);
|
||||
|
||||
|
||||
// Tabs
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', function () {
|
||||
currentComponentFilter = this.dataset.componentFilter;
|
||||
|
||||
tabButtons.forEach(b => b.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
|
||||
applyFilters();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Método de filtrado
|
||||
function applyFilters() {
|
||||
const searchTerm = normalize(searchInput.value.trim());
|
||||
const isSearchEmpty = searchTerm === '';
|
||||
|
||||
categories.forEach(category => {
|
||||
let categoryMatch = false;
|
||||
const categoryTitleEl = category.querySelector('.search-term');
|
||||
const categoryTitle = normalize(categoryTitleEl?.textContent);
|
||||
const categoryMatches = categoryTitle.includes(searchTerm);
|
||||
|
||||
highlightMatch(categoryTitleEl, searchTerm);
|
||||
|
||||
const cards = category.querySelectorAll('.quick-access-card');
|
||||
let visibleCards = 0;
|
||||
|
||||
cards.forEach(card => {
|
||||
const titleEl = card.querySelector('.search-term');
|
||||
const titleText = normalize(titleEl?.textContent);
|
||||
const cardComponent = card.dataset.component;
|
||||
|
||||
const matchesComponent = currentComponentFilter === 'all' || cardComponent === currentComponentFilter;
|
||||
const matchesSearch = isSearchEmpty || titleText.includes(searchTerm) || categoryMatches;
|
||||
|
||||
const match = matchesComponent && matchesSearch;
|
||||
|
||||
highlightMatch(titleEl, searchTerm);
|
||||
|
||||
if (match) {
|
||||
card.classList.remove('quick-hidden');
|
||||
card.style.display = 'block';
|
||||
requestAnimationFrame(() => {
|
||||
card.classList.add('quick-showing');
|
||||
});
|
||||
visibleCards++;
|
||||
} else {
|
||||
card.classList.remove('quick-showing');
|
||||
card.classList.add('quick-hidden');
|
||||
setTimeout(() => {
|
||||
card.style.display = 'none';
|
||||
}, 400);
|
||||
}
|
||||
});
|
||||
|
||||
const showCategory = visibleCards > 0;
|
||||
|
||||
category.classList.toggle('quick-hidden', !showCategory);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,155 @@
|
||||
@php
|
||||
/**
|
||||
* Vista Blade para mostrar los accesos rápidos.
|
||||
* Compatible con Vuexy Admin y modo oscuro.
|
||||
*/
|
||||
@endphp
|
||||
|
||||
<div class="space-y-8">
|
||||
<!-- 🔍 Campo de búsqueda -->
|
||||
<x-vuexy-admin::form.input
|
||||
id="quick_acces_search"
|
||||
placeholder="Buscar acceso rápido..."
|
||||
suffixIcon="ti ti-search"
|
||||
class="form-control-lg"
|
||||
mb0
|
||||
autocomplete="off"
|
||||
role="search"
|
||||
aria-label="Buscar acceso rápido"
|
||||
/>
|
||||
@if($components)
|
||||
<div class="col-12 overflow-hidden mt-2">
|
||||
<div id="quick-access-scroll">
|
||||
<ul class="nav mb-1" id="quick-access-tabs">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link active" data-component-filter="all">Todos</button>
|
||||
</li>
|
||||
@foreach($components as $component)
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-component-filter="{{ $component['tag'] }}">
|
||||
{{ $component['label'] }}
|
||||
</button>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@foreach ($groups as $group)
|
||||
@if(!empty($group['cards']))
|
||||
<div class="quick-access-group">
|
||||
<!-- Título de categoría con icono -->
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="{{ $group['icon'] }} text-2xl text-primary"></i>
|
||||
<h5 class="mb-0 ms-2 text-dark dark:text-white search-term">{{ $group['label'] }}</h5>
|
||||
</div>
|
||||
<!-- Descripción de categoría -->
|
||||
@if (!empty($group['description']))
|
||||
<p class="text-muted">
|
||||
{{ $group['description'] }}
|
||||
</p>
|
||||
@endif
|
||||
<!-- Grid de accesos rápidos en formato de Cards -->
|
||||
<div class="row row-cols-2 row-cols-md-4 row-cols-lg-5 g-4">
|
||||
@foreach ($group['cards'] as $item)
|
||||
<div class="col quick-access-card" data-component="{{ $item['component'] ?? 'unknown' }}">
|
||||
<a href="{{ $item['url'] }}" class="text-decoration-none">
|
||||
<div class="card border-0 shadow-sm hover:shadow-lg transition-all duration-300">
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center text-center p-4">
|
||||
<i class="{{ $item['icon'] }} text-3xl text-primary mt-1 mb-3"></i>
|
||||
<h6 class="mb-0 text-dark dark:text-light fw-semibold search-term">
|
||||
{{ $item['title'] }}
|
||||
@if(config('koneko.admin.menu.debug.show_broken_routers') && $item['url'] == "javascript:;")
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="xs mr-1">❌</span> Sin URL válida
|
||||
</p>
|
||||
@endif
|
||||
@if(config('koneko.admin.menu.debug.show_disallowed_links') && $item['disallowed_link'])
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="text-sm mr-1">🔒</span> Sin permisos
|
||||
</p>
|
||||
@endif
|
||||
@if(config('koneko.admin.menu.debug.show_hidden_items') && $item['hidden_item'])
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="text-sm mr-1">🚧</span> Vista forzada
|
||||
</p>
|
||||
@endif
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="pb-6"></div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const searchInput = document.getElementById('quick_acces_search');
|
||||
const categories = document.querySelectorAll('.quick-access-group');
|
||||
const tabButtons = document.querySelectorAll('#quick-access-tabs button');
|
||||
const normalize = str => str?.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||
|
||||
const highlightMatch = (element, term) => {
|
||||
const text = element.dataset.originalText || element.textContent;
|
||||
element.dataset.originalText = text;
|
||||
element.innerHTML = term ? text.replace(new RegExp(`(${term})`, 'gi'), '<mark>$1</mark>') : text;
|
||||
};
|
||||
|
||||
let currentComponentFilter = 'all';
|
||||
|
||||
searchInput.focus();
|
||||
searchInput.addEventListener('input', applyFilters);
|
||||
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', function () {
|
||||
currentComponentFilter = this.dataset.componentFilter;
|
||||
tabButtons.forEach(b => b.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
applyFilters();
|
||||
});
|
||||
});
|
||||
|
||||
function applyFilters() {
|
||||
const searchTerm = normalize(searchInput.value.trim());
|
||||
const isSearchEmpty = searchTerm === '';
|
||||
|
||||
categories.forEach(group => {
|
||||
const groupTitleEl = group.querySelector('.search-term');
|
||||
const groupTitle = normalize(groupTitleEl?.textContent);
|
||||
const groupMatches = groupTitle.includes(searchTerm);
|
||||
|
||||
highlightMatch(groupTitleEl, searchTerm);
|
||||
|
||||
const cards = group.querySelectorAll('.quick-access-card');
|
||||
|
||||
let visibleCards = 0;
|
||||
|
||||
cards.forEach(card => {
|
||||
const titleEl = card.querySelector('.search-term');
|
||||
const titleText = normalize(titleEl?.textContent);
|
||||
const cardComponent = card.dataset.component;
|
||||
|
||||
const matchesComponent = currentComponentFilter === 'all' || cardComponent === currentComponentFilter;
|
||||
const matchesSearch = isSearchEmpty || titleText.includes(searchTerm) || groupMatches;
|
||||
|
||||
const match = matchesComponent && matchesSearch;
|
||||
|
||||
highlightMatch(titleEl, searchTerm);
|
||||
|
||||
card.classList.toggle('quick-hidden', !match);
|
||||
card.style.display = match ? 'block' : 'none';
|
||||
if (match) visibleCards++;
|
||||
});
|
||||
|
||||
group.classList.toggle('quick-hidden', visibleCards === 0);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -1,7 +0,0 @@
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable">
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-offcanvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
@ -9,7 +9,7 @@
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="key" label="Clave del parámetro" required icon="ti ti-key" placeholder="Ej: ui.theme" />
|
||||
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="category" label="Categoría"
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="module" label="Categoría"
|
||||
:options="[
|
||||
'general' => 'General',
|
||||
'ui' => 'Interfaz',
|
@ -0,0 +1,9 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable">
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-offcanvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
||||
</div>
|
@ -2,9 +2,9 @@
|
||||
changeSmtpSettings: @entangle('change_smtp_settings'),
|
||||
saveButtonDisabled: @entangle('save_button_disabled'),
|
||||
}">
|
||||
<form id="sendmail-settings-card">
|
||||
<form id="smtp-settings-card">
|
||||
<div class="card mb-6">
|
||||
<h5 class="card-header">Servidor saliente de correo electrónico</h5>
|
||||
<h5 class="card-header">Servidor de correo saliente</h5>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
45
resources/views/livewire/settings/users/form.blade.php
Normal file
45
resources/views/livewire/settings/users/form.blade.php
Normal file
@ -0,0 +1,45 @@
|
||||
<div>
|
||||
<x-vuexy-admin::form id="{{ $formId }}" :mode="$mode" wireSubmit="onSubmit" actionPosition="both">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.form-buttons :mode="$mode" :label="$singularName" />
|
||||
</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="name" label="Nombre de usuario" />
|
||||
</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::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="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
</div>
|
||||
</x-vuexy-admin::form>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const initializeUserForm = (mode) => {
|
||||
|
||||
}
|
||||
|
||||
// Evento para inicializar el formulario
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.addEventListener('on-failed-validation-user', (event) => {
|
||||
setTimeout(() => {
|
||||
initializeUserForm('{{ $mode }}');
|
||||
}, 10);
|
||||
});
|
||||
|
||||
initializeUserForm('{{ $mode }}');
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,93 @@
|
||||
<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 --}}
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre(s)" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="last_name" label="Apellidos" />
|
||||
{{-- Correos electrónicos --}}
|
||||
<x-vuexy-admin::form.input type="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
|
||||
{{-- Imágen de perfil --}}
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Imágen de perfil</label>
|
||||
@if ($upload_profile_photo && in_array($upload_profile_photo->getMimeType(), ['image/jpeg', 'image/png', 'image/webp']))
|
||||
<div class="text-center mb-2">
|
||||
<img src="{{ $upload_profile_photo->temporaryUrl() }}" alt="Vista previa" class="img-thumbnail mx-auto" style="max-height: 300px;">
|
||||
</div>
|
||||
@endif
|
||||
<x-vuexy-admin::form.input type="file" :uid="$uniqueId" model="upload_profile_photo" accept="image/*" />
|
||||
</div>
|
||||
|
||||
{{-- Contraseña --}}
|
||||
<x-vuexy-admin::form.input-password :uid="$uniqueId" model="password" icon="ti ti-lock" />
|
||||
|
||||
{{-- Roles --}}
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="roles" label="Roles" multiple :options="$rolesOptions" class="select2 form-select" />
|
||||
<hr>
|
||||
</x-vuexy-admin::form>
|
||||
</x-vuexy-admin::offcanvas.basic>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const uniqueId = '{{ $uniqueId }}';
|
||||
const offcanvasId = '{{ $offcanvasId }}';
|
||||
const tagName = '{{ Str::kebab($tagName) }}';
|
||||
const myOffcanvas = document.getElementById(offcanvasId);
|
||||
|
||||
// Asegúrate de no agregar múltiples veces el listener
|
||||
const hideAndReopen = () => {
|
||||
let myOffcanvas = document.getElementById(offcanvasId);
|
||||
let offcanvasInstance = bootstrap.Offcanvas.getOrCreateInstance(myOffcanvas);
|
||||
|
||||
const onHidden = () => {
|
||||
myOffcanvas.removeEventListener('hidden.bs.offcanvas', onHidden);
|
||||
offcanvasInstance.show();
|
||||
};
|
||||
|
||||
myOffcanvas.addEventListener('hidden.bs.offcanvas', onHidden);
|
||||
offcanvasInstance.hide();
|
||||
};
|
||||
|
||||
// Inizar Select2
|
||||
const initializeSelect2 = () => {
|
||||
let rolesSelect = document.getElementById(`roles_${uniqueId}`),
|
||||
myOffcanvas = document.getElementById(offcanvasId);
|
||||
|
||||
$(rolesSelect)
|
||||
.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
placeholder: 'Selecciona los roles',
|
||||
dropdownParent: myOffcanvas
|
||||
})
|
||||
.on('select2:clear', () => {
|
||||
@this.roles = [];
|
||||
})
|
||||
.on('select2:select', (e) => {
|
||||
@this.roles.push(e.params.data.id);
|
||||
});
|
||||
};
|
||||
|
||||
// Inicializar el formulario
|
||||
const initializeUserForm = () => {
|
||||
setTimeout(initializeSelect2, 10);
|
||||
};
|
||||
|
||||
|
||||
// Evento para inicializar el formulario cuando se abre el offcanvas
|
||||
myOffcanvas.addEventListener('show.bs.offcanvas', function () {
|
||||
initializeUserForm();
|
||||
attachPasswordToggles();
|
||||
});
|
||||
|
||||
|
||||
// Evento para recargar el formulario
|
||||
Livewire.on('refresh-user-form', hideAndReopen);
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -42,7 +42,7 @@
|
||||
<i class="ti ti-user pr-2"></i> Cuenta de usuario
|
||||
</button>
|
||||
</li>
|
||||
@if (($is_customer) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_customer) && $this->tipo_persona != Koneko\VuexyAdmin\Models\User::TIPO_RFC_PUBLICO)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" @click="setActiveTabPan('accesos')" :class="{ 'active': activeTabPan === 'accesos' }" class="nav-link waves-effect" role="tab" data-bs-toggle="tab" data-bs-target="#navs-left-accesos" aria-controls="navs-left-accesos">
|
||||
<i class="ti ti-key pr-2"></i> Accesos
|
||||
@ -56,21 +56,21 @@
|
||||
</button>
|
||||
</li>
|
||||
@endif
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != Koneko\VuexyAdmin\Models\User::TIPO_RFC_PUBLICO)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" @click="setActiveTabPan('direcciones')" :class="{ 'active': activeTabPan === 'direcciones' }" class="nav-link waves-effect" role="tab" data-bs-toggle="tab" data-bs-target="#navs-left-direcciones" aria-controls="navs-left-direcciones">
|
||||
<i class="ti ti-map-pin pr-2"></i> Direcciones
|
||||
</button>
|
||||
</li>
|
||||
@endif
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != Koneko\VuexyAdmin\Models\User::TIPO_RFC_PUBLICO)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" @click="setActiveTabPan('contacto')" :class="{ 'active': activeTabPan === 'contacto' }" class="nav-link waves-effect" role="tab" data-bs-toggle="tab" data-bs-target="#navs-left-contacto" aria-controls="navs-left-contacto">
|
||||
<i class="ti ti-address-book pr-2"></i> Contacto
|
||||
</button>
|
||||
</li>
|
||||
@endif
|
||||
@if (($is_customer || $is_provider) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_customer || $is_provider) && $this->tipo_persona != Koneko\VuexyAdmin\Models\User::TIPO_RFC_PUBLICO)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" @click="setActiveTabPan('cuentas-bancarias')" :class="{ 'active': activeTabPan === 'cuentas-bancarias' }" class="nav-link waves-effect" role="tab" data-bs-toggle="tab" data-bs-target="#navs-left-cuentas-bancarias" aria-controls="navs-left-cuentas-bancarias">
|
||||
<i class="ti ti-credit-card pr-2"></i> Cuentas bancarias
|
@ -0,0 +1,15 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" >
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-offcanvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
window.userRoleStyles = {!! $userRoleStyles !!};
|
||||
</script>
|
||||
@endpush
|
@ -1,5 +1,8 @@
|
||||
<div x-data>
|
||||
<div id="interface-settings-card" class="form-custom-listener mb-4">
|
||||
<div id="vuexy-interface-index-card" class="form-custom-listener mb-4">
|
||||
{{-- Notificaciones --}}
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{-- Tema --}}
|
||||
@ -59,11 +62,32 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-end">
|
||||
<x-vuexy-admin::button.basic wire:click="save" disabled variant="primary" icon="ti ti-check" label="Aplicar cambios" class="btn-save mb-2 mx-2" size="sm" waves />
|
||||
<x-vuexy-admin::button.basic wire:click="resetForm" disabled variant="secondary" icon="ti ti-rotate-2" label="Cancelar" class="btn-cancel mb-2 mx-2" size="sm" waves />
|
||||
<x-vuexy-admin::button.basic wire:click="loadForm" disabled variant="secondary" icon="ti ti-rotate-2" label="Cancelar" class="btn-cancel mb-2 mx-2" size="sm" waves />
|
||||
</div>
|
||||
<div class="col-lg-12 text-end">
|
||||
<x-vuexy-admin::button.basic wire:click="clearCustomConfig" variant="success" icon="ti ti-adjustments-cog" label="Restaurar valores predeterminados" class="btn-reset mb-2 mx-2" size="sm" waves />
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notificaciones --}}
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
Livewire.on('refreshAndNotify', event => {
|
||||
const notification = {
|
||||
type: event.type || 'success',
|
||||
message: event.message || 'Configuraciones guardadas exitosamente.',
|
||||
target: event.target || '#vuexy-interface-index-card .notification-container',
|
||||
delay: event.delay || 6000
|
||||
};
|
||||
|
||||
// Guardar notificación en localStorage
|
||||
localStorage.setItem('vuexy_notification', JSON.stringify(notification));
|
||||
|
||||
// Refrescar la página
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div id="app-description-settings-card" class="form-custom-listener mb-4">
|
||||
<div id="app-description-card-card" class="form-custom-listener mb-4">
|
||||
<x-vuexy-admin::card.basic title="Datos de la aplicación" class="mb-4">
|
||||
<x-vuexy-admin::form.input
|
||||
label="Titulo de la aplicación"
|
||||
@ -31,7 +31,7 @@
|
||||
icon="ti ti-rotate-2"
|
||||
label="Cancelar"
|
||||
disabled
|
||||
wire:click="resetForm"
|
||||
wire:click="loadForm"
|
||||
class="btn-cancel"
|
||||
waves />
|
||||
</div>
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div id="app-favicon-settings-card" class="mb-4">
|
||||
<div id="app-favicon-card-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Favicon" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
@ -73,7 +73,7 @@
|
||||
size="sm"
|
||||
icon="ti ti-rotate-2"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
wire:click="loadForm"
|
||||
:disabled="$upload_image_favicon === null"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div id="logo-on-dark-bg-settings-card" class="mb-4">
|
||||
<div id="logo-on-dark-bg-card-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Logotipo sobre fondo oscuro" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
@ -29,7 +29,7 @@
|
||||
icon="ti ti-rotate-2"
|
||||
disabled="{{ $upload_image_logo_dark === null }}"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
wire:click="loadForm"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
||||
</div>
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div id="logo-on-light-bg-settings-card" class="mb-4">
|
||||
<div id="logo-on-light-bg-card-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Logotipo sobre fondo claro" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
@ -29,7 +29,7 @@
|
||||
icon="ti ti-rotate-2"
|
||||
disabled="{{ $upload_image_logo === null }}"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
wire:click="loadForm"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
||||
</div>
|
61
resources/views/livewire/user/viewer/index.blade.php
Normal file
61
resources/views/livewire/user/viewer/index.blade.php
Normal file
@ -0,0 +1,61 @@
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<!-- Banner y Header -->
|
||||
<x-vuexy-admin::user.details.banner-profile-header
|
||||
:banner-url="$user?->banner_url"
|
||||
:avatar-url="$user?->profile_photo_url"
|
||||
:name="$user?->name"
|
||||
:position="$user?->position"
|
||||
:location="$user?->location"
|
||||
:joined="$user?->joined_at?->format('F Y')"
|
||||
button-label="Connected"
|
||||
button-icon="ti ti-user-check"
|
||||
/>
|
||||
|
||||
<!-- Tabs -->
|
||||
<x-vuexy-admin::user.details.tabs :tabs="$tabs" />
|
||||
|
||||
<!-- Contenido Principal -->
|
||||
<div class="row">
|
||||
<!-- Columna Izquierda -->
|
||||
<div class="col-xl-4 col-lg-5 col-md-5">
|
||||
<x-vuexy-admin::user.details.about :user="$user" class="mb-6" />
|
||||
@php /*
|
||||
<x-vuexy-admin::user.details.overview :stats="$stats" />
|
||||
*/ @endphp
|
||||
</div>
|
||||
|
||||
<!-- Columna Derecha -->
|
||||
<div class="col-xl-8 col-lg-7 col-md-7">
|
||||
<x-vuexy-admin::user.details.permissions :user="$user" />
|
||||
|
||||
@php /*
|
||||
<x-vuexy-admin::user.details.timeline :items="$timeline" class="mb-6" />
|
||||
*/ @endphp
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-xl-6">
|
||||
@php /*
|
||||
<x-vuexy-admin::user.details.connections :connections="$connections" />
|
||||
*/ @endphp
|
||||
</div>
|
||||
<div class="col-lg-12 col-xl-6">
|
||||
|
||||
@php /*
|
||||
<x-vuexy-admin::user.details.teams :teams="$teams" />
|
||||
*/ @endphp
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
|
||||
tooltipTriggerList.forEach(function (tooltipTriggerEl) {
|
||||
new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -1,165 +0,0 @@
|
||||
<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
|
@ -1,7 +0,0 @@
|
||||
<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-offcanvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
@ -1,39 +0,0 @@
|
||||
<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 --}}
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre(s)" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="last_name" label="Apellidos" />
|
||||
{{-- Correos electrónicos --}}
|
||||
<x-vuexy-admin::form.input type="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
|
||||
{{-- Contraseña --}}
|
||||
<x-vuexy-admin::form.input type="password" :uid="$uniqueId" model="password" label="Contraseña" icon="ti ti-lock" autocomplete="new-password" />
|
||||
|
||||
|
||||
<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
|
@ -1,53 +0,0 @@
|
||||
@php
|
||||
/**
|
||||
* Vista Blade para mostrar los accesos rápidos.
|
||||
* Compatible con Vuexy Admin y modo oscuro.
|
||||
*/
|
||||
@endphp
|
||||
|
||||
<div class="p-6 space-y-8">
|
||||
@foreach ($quickAccessItems as $category)
|
||||
<div class="mb-8">
|
||||
<!-- Título de categoría con icono -->
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="{{ $category['icon'] }} text-3xl text-primary"></i>
|
||||
<h5 class="mb-0 ms-2 text-dark dark:text-white">{{ $category['title'] }}</h5>
|
||||
</div>
|
||||
|
||||
<!-- Descripción de categoría -->
|
||||
@if (!empty($category['description']))
|
||||
<p class="text-muted">
|
||||
{{ $category['description'] }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<!-- Grid de accesos rápidos en formato de Cards -->
|
||||
@if (!empty($category['submenu']))
|
||||
<div class="row row-cols-2 row-cols-md-4 row-cols-lg-5 g-4">
|
||||
@foreach ($category['submenu'] as $item)
|
||||
<div class="col">
|
||||
<a href="{{ $item['url'] }}" class="text-decoration-none">
|
||||
<div class="card border-0 shadow-sm hover:shadow-lg transition-all duration-300">
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center text-center p-4">
|
||||
|
||||
<!-- Ícono -->
|
||||
<i class="{{ $item['icon'] }} text-4xl text-primary mb-2"></i>
|
||||
|
||||
<!-- Título -->
|
||||
<h6 class="mb-0 text-dark dark:text-light fw-semibold">
|
||||
{{ $item['title'] }}
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-muted fst-italic">
|
||||
No hay accesos rápidos en esta categoría.
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
Reference in New Issue
Block a user