Prepare modules
This commit is contained in:
@ -106,7 +106,8 @@ class BootstrapTableManager {
|
||||
* Carga los formatters dinámicamente
|
||||
*/
|
||||
async loadFormatters() {
|
||||
const formattersModules = import.meta.glob('../../../../../**/resources/assets/js/bootstrap-table/*Formatters.js');
|
||||
//const formattersModules = import.meta.glob('../../../../../**/resources/assets/js/bootstrap-table/*Formatters.js');
|
||||
const formattersModules = import.meta.glob('/vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/*Formatters.js');
|
||||
|
||||
const formatterPromises = Object.entries(formattersModules).map(async ([path, importer]) => {
|
||||
const module = await importer();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { booleanStatusCatalog, statusIntBadgeBgCatalogCss, statusIntBadgeBgCatalog } from './globalConfig';
|
||||
import {routes} from '../../../../../laravel-vuexy-admin/resources/assets/js/bootstrap-table/globalConfig.js';
|
||||
import {routes} from '@vuexy-admin/bootstrap-table/globalConfig.js';
|
||||
|
||||
export const userActionFormatter = (value, row, index) => {
|
||||
if (!row.id) return '';
|
||||
|
@ -10,7 +10,7 @@
|
||||
// JS global variables
|
||||
window.config = {
|
||||
colors: {
|
||||
primary: '#7367f0',
|
||||
primary: '#155dfc',
|
||||
secondary: '#808390',
|
||||
success: '#28c76f',
|
||||
info: '#00bad1',
|
||||
@ -27,7 +27,7 @@ window.config = {
|
||||
borderColor: '#e6e6e8'
|
||||
},
|
||||
colors_label: {
|
||||
primary: '#7367f029',
|
||||
primary: '#155dfc29',
|
||||
secondary: '#a8aaae29',
|
||||
success: '#28c76f29',
|
||||
info: '#00cfe829',
|
||||
|
79
resources/assets/js/forms/disabledForm.js
Normal file
79
resources/assets/js/forms/disabledForm.js
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Previene interacción con el elemento.
|
||||
* @param {Event} event - El evento de clic.
|
||||
*/
|
||||
const preventInteraction = (event) => event.preventDefault();
|
||||
|
||||
/**
|
||||
* Habilita o deshabilita un select con Select2.
|
||||
* @param {HTMLElement} selectElement - El select afectado.
|
||||
* @param {boolean} disabled - Si debe ser deshabilitado.
|
||||
*/
|
||||
const toggleSelect2Disabled = (selectElement, disabled) => {
|
||||
selectElement.disabled = disabled;
|
||||
selectElement.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
};
|
||||
|
||||
/**
|
||||
* Aplica modo solo lectura a un select estándar o Select2.
|
||||
* @param {HTMLElement} select - El select a modificar.
|
||||
* @param {boolean} readonly - Si debe estar en modo solo lectura.
|
||||
*/
|
||||
const setSelectReadonly = (select, readonly) => {
|
||||
select.setAttribute('readonly-mode', readonly);
|
||||
select.style.pointerEvents = readonly ? 'none' : '';
|
||||
select.tabIndex = readonly ? -1 : '';
|
||||
|
||||
if (select.classList.contains('select2-hidden-accessible')) {
|
||||
toggleSelect2Disabled(select, readonly);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Aplica modo solo lectura a un checkbox o radio.
|
||||
* @param {HTMLElement} checkbox - El input a modificar.
|
||||
* @param {boolean} readonly - Si debe ser solo lectura.
|
||||
*/
|
||||
const setCheckboxReadonly = (checkbox, readonly) => {
|
||||
checkbox.setAttribute('readonly-mode', readonly);
|
||||
checkbox.style.pointerEvents = readonly ? 'none' : '';
|
||||
checkbox[readonly ? 'addEventListener' : 'removeEventListener']('click', preventInteraction);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deshabilita o pone en modo de solo lectura los campos del formulario.
|
||||
* @param {string} formSelector - Selector del formulario a deshabilitar.
|
||||
*/
|
||||
export default function disableForm(formSelector) {
|
||||
const form = document.querySelector(formSelector);
|
||||
if (!form) {
|
||||
console.warn(`Formulario no encontrado con el selector: ${formSelector}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const inputs = form.querySelectorAll('input, textarea, select');
|
||||
|
||||
inputs.forEach((el) => {
|
||||
if (!el.classList.contains('data-always-enabled')) {
|
||||
switch (el.tagName) {
|
||||
case 'SELECT':
|
||||
if (el.classList.contains('select2')) {
|
||||
toggleSelect2Disabled(el, true);
|
||||
} else {
|
||||
setSelectReadonly(el, true);
|
||||
}
|
||||
break;
|
||||
case 'INPUT':
|
||||
if (['checkbox', 'radio'].includes(el.type)) {
|
||||
setCheckboxReadonly(el, true);
|
||||
} else {
|
||||
el.readOnly = true;
|
||||
}
|
||||
break;
|
||||
case 'TEXTAREA':
|
||||
el.readOnly = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
@ -155,7 +155,19 @@ export default class FormCustomListener {
|
||||
this.setButtonLoadingState(saveButton, true); // Poner en estado de carga al botón anfitrión
|
||||
|
||||
// Enviar la solicitud de Livewire correspondiente al enviar el formulario
|
||||
Livewire.dispatch(this.config.dispatchOnSubmit);
|
||||
const componentEl = form.closest('[wire\\:id]');
|
||||
const componentId = componentEl?.getAttribute('wire:id');
|
||||
|
||||
if (componentId) {
|
||||
const component = Livewire.find(componentId);
|
||||
if (component) {
|
||||
component.call(this.config.dispatchOnSubmit);
|
||||
} else {
|
||||
console.warn('No se encontró el componente Livewire.');
|
||||
}
|
||||
} else {
|
||||
console.warn('No se pudo encontrar wire:id para ejecutar el método Livewire.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,7 +200,10 @@ export default class FormCustomListener {
|
||||
*/
|
||||
toggleButtonsState(buttons, isEnabled) {
|
||||
buttons.forEach(button => {
|
||||
if (button) button.disabled = !isEnabled;
|
||||
if (button){
|
||||
button.disabled = !isEnabled;
|
||||
button.classList.toggle('disabled', !isEnabled);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -217,24 +232,57 @@ export default class FormCustomListener {
|
||||
*/
|
||||
initializeValidation(form) {
|
||||
if (this.config.validationConfig) {
|
||||
this.formValidationInstance = FormValidation.formValidation(form, this.config.validationConfig).on(
|
||||
'core.form.valid',
|
||||
() => this.handleFormValid(form)
|
||||
);
|
||||
this.formValidationInstance = FormValidation.formValidation(
|
||||
form,
|
||||
this.config.validationConfig
|
||||
).on('core.form.valid', () => this.handleFormValid(form));
|
||||
|
||||
// Aplicamos el fix después de un pequeño delay
|
||||
setTimeout(() => {
|
||||
this.fixValidationMessagePosition(form);
|
||||
}, 100); // Lo suficiente para esperar a que FV inserte los mensajes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mueve los mensajes de error fuera del input-group para evitar romper el diseño
|
||||
*/
|
||||
fixValidationMessagePosition(form) {
|
||||
const groups = form.querySelectorAll('.input-group.has-validation');
|
||||
|
||||
groups.forEach(group => {
|
||||
const errorContainer = group.querySelector('.fv-plugins-message-container');
|
||||
|
||||
if (errorContainer) {
|
||||
// Evita duplicados
|
||||
if (errorContainer.classList.contains('moved')) return;
|
||||
|
||||
// Crear un contenedor si no existe
|
||||
let target = group.parentElement.querySelector('.fv-message');
|
||||
if (!target) {
|
||||
target = document.createElement('div');
|
||||
target.className = 'fv-message invalid-feedback';
|
||||
group.parentElement.appendChild(target);
|
||||
}
|
||||
|
||||
target.appendChild(errorContainer);
|
||||
errorContainer.classList.add('moved'); // Marcar como ya movido
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reloadValidation() {
|
||||
const form = document.querySelector(this.config.formSelector);
|
||||
|
||||
// Verificar si el formulario existe y si la validación está inicializada
|
||||
if (form && this.formValidationInstance) {
|
||||
try {
|
||||
// En lugar de destruir la validación, simplemente reiniciamos la validación.
|
||||
this.formValidationInstance.resetForm(); // Resetear el formulario, limpiando los errores
|
||||
setTimeout(() => {
|
||||
this.formValidationInstance.resetForm(); // Limpiar errores
|
||||
this.initializeValidation(form); // Reinicializar
|
||||
|
||||
// Reinicializar la validación con la configuración actual
|
||||
this.initializeValidation(form);
|
||||
// 🔁 Reconectar eventos de inputs y botones
|
||||
this.initFormEvents(form);
|
||||
}, 1);
|
||||
} catch (error) {
|
||||
console.error('Error al reiniciar la validación:', error);
|
||||
}
|
||||
@ -242,4 +290,5 @@ export default class FormCustomListener {
|
||||
console.warn('Formulario no encontrado o instancia de validación no disponible.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
10
resources/assets/js/forms/slugify.js
Normal file
10
resources/assets/js/forms/slugify.js
Normal file
@ -0,0 +1,10 @@
|
||||
window.createSlug = function(string) {
|
||||
return string
|
||||
.toLowerCase()
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/[^a-z0-9\s-]/g, '')
|
||||
.trim()
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/-+/g, '-');
|
||||
};
|
27
resources/assets/js/livewire/registerLivewireHookOnce.js
Normal file
27
resources/assets/js/livewire/registerLivewireHookOnce.js
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Registra un hook Livewire solo una vez por componente.
|
||||
* @param {string} hookName - Nombre del hook Livewire (por ejemplo, "morphed").
|
||||
* @param {string} componentName - Nombre exacto del componente Livewire.
|
||||
* @param {function} callback - Función que se ejecutará una vez por hook+componente.
|
||||
*/
|
||||
export default function registerLivewireHookOnce(hookName, componentName, callback) {
|
||||
if (!hookName || !componentName || typeof callback !== 'function') {
|
||||
console.warn('[registerLivewireHookOnce] Parámetros inválidos.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Clave única para este hook+componente
|
||||
const safeName = componentName.replace(/[^a-zA-Z0-9]/g, '_');
|
||||
const key = `__hook_${hookName}_${safeName}`;
|
||||
|
||||
if (!window[key]) {
|
||||
window[key] = true;
|
||||
|
||||
Livewire.hook(hookName, ({ component }) => {
|
||||
if (component.name === componentName) {
|
||||
// console.info(`[Livewire Hook Triggered] ${hookName} for ${component.name}`);
|
||||
callback(component);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
import './../../vendor/libs/leaflet/leaflet'
|
||||
|
||||
export const LeafletMapHelper = (() => {
|
||||
let mapInstance, markerInstance;
|
||||
|
||||
const DEFAULT_COORDS = [19.4326, -99.1332]; // Coordenadas de CDMX por defecto
|
||||
|
||||
// Valida coordenadas
|
||||
const isValidCoordinate = (lat, lng) => {
|
||||
return lat && !isNaN(lat) && lat >= -90 && lat <= 90 && lat !== 0 &&
|
||||
lng && !isNaN(lng) && lng >= -180 && lng <= 180 && lng !== 0;
|
||||
};
|
||||
|
||||
// Crea opciones del mapa según el modo
|
||||
const getMapOptions = (mode) => ({
|
||||
scrollWheelZoom: mode !== 'delete',
|
||||
dragging: mode !== 'delete',
|
||||
doubleClickZoom: mode !== 'delete',
|
||||
boxZoom: mode !== 'delete',
|
||||
keyboard: mode !== 'delete',
|
||||
zoomControl: mode !== 'delete',
|
||||
touchZoom: mode !== 'delete'
|
||||
});
|
||||
|
||||
// Destruir el mapa existente
|
||||
const destroyMap = () => {
|
||||
if (mapInstance) {
|
||||
mapInstance.off();
|
||||
mapInstance.remove();
|
||||
mapInstance = null;
|
||||
}
|
||||
removeMarker();
|
||||
};
|
||||
|
||||
// Crear marcador en el mapa
|
||||
const createMarker = (lat, lng, draggable = false, onDragEnd) => {
|
||||
if (isValidCoordinate(lat, lng)) {
|
||||
markerInstance = L.marker([lat, lng], { draggable }).addTo(mapInstance)
|
||||
.bindPopup('<b>Ubicación seleccionada</b>').openPopup();
|
||||
|
||||
if (draggable && onDragEnd) {
|
||||
markerInstance.on('dragend', (e) => {
|
||||
const { lat, lng } = e.target.getLatLng();
|
||||
onDragEnd(lat, lng);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Eliminar marcador
|
||||
const removeMarker = () => {
|
||||
if (markerInstance) {
|
||||
markerInstance.remove();
|
||||
markerInstance = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Actualizar coordenadas en formulario
|
||||
const updateCoordinates = (lat, lng, latSelector, lngSelector, livewireInstance) => {
|
||||
const latInput = document.querySelector(latSelector);
|
||||
const lngInput = document.querySelector(lngSelector);
|
||||
|
||||
if (!latInput || !lngInput) {
|
||||
console.warn(`⚠️ No se encontró el elemento del DOM para latitud (${latSelector}) o longitud (${lngSelector})`);
|
||||
return;
|
||||
}
|
||||
|
||||
latInput.value = lat ? lat.toFixed(6) : '';
|
||||
lngInput.value = lng ? lng.toFixed(6) : '';
|
||||
|
||||
if (livewireInstance) {
|
||||
livewireInstance.lat = lat ? lat.toFixed(6) : null;
|
||||
livewireInstance.lng = lng ? lng.toFixed(6) : null;
|
||||
}
|
||||
};
|
||||
|
||||
// Inicializar el mapa
|
||||
const initializeMap = (locationInputs, mode = 'create', livewireInstance = null) => {
|
||||
const mapElement = document.getElementById(locationInputs.mapId);
|
||||
|
||||
if (!mapElement) {
|
||||
console.error(`❌ No se encontró el contenedor del mapa con ID: ${locationInputs.mapId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let latElement = document.querySelector(locationInputs.lat);
|
||||
let lngElement = document.querySelector(locationInputs.lng);
|
||||
|
||||
if (!latElement || !lngElement) {
|
||||
console.error(`❌ No se encontraron los campos de latitud (${locationInputs.lat}) o longitud (${locationInputs.lng})`);
|
||||
return;
|
||||
}
|
||||
|
||||
let lat = parseFloat(latElement.value);
|
||||
let lng = parseFloat(lngElement.value);
|
||||
|
||||
const mapCoords = isValidCoordinate(lat, lng) ? [lat, lng] : DEFAULT_COORDS;
|
||||
const zoomLevel = isValidCoordinate(lat, lng) ? 16 : 13;
|
||||
|
||||
if (mapInstance) destroyMap();
|
||||
|
||||
mapInstance = L.map(locationInputs.mapId, getMapOptions(mode)).setView(mapCoords, zoomLevel);
|
||||
L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(mapInstance);
|
||||
|
||||
if (mode !== 'create') createMarker(lat, lng, mode === 'edit', (lat, lng) => updateCoordinates(lat, lng, locationInputs.lat, locationInputs.lng, livewireInstance));
|
||||
|
||||
if (mode !== 'delete') {
|
||||
mapInstance.on('click', (e) => {
|
||||
const { lat, lng } = e.latlng;
|
||||
removeMarker();
|
||||
createMarker(lat, lng, true, (lat, lng) => updateCoordinates(lat, lng, locationInputs.lat, locationInputs.lng, livewireInstance));
|
||||
updateCoordinates(lat, lng, locationInputs.lat, locationInputs.lng, livewireInstance);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
const btnClearElement = document.querySelector(locationInputs.btnClear);
|
||||
|
||||
if(!btnClearElement){
|
||||
console.error(`❌ No se encontró el botón de limpiar con ID: ${locationInputs.btnClear}`);return;
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
return {
|
||||
initializeMap,
|
||||
clearCoordinates: () => {
|
||||
removeMarker();
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
window.LeafletMapHelper = LeafletMapHelper;
|
@ -1,12 +0,0 @@
|
||||
export class LocationIQSearchHelper {
|
||||
constructor(apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
this.baseUrl = 'https://us1.locationiq.com/v1/search.php';
|
||||
}
|
||||
|
||||
async searchAddress(query) {
|
||||
const response = await fetch(`${this.baseUrl}?key=${this.apiKey}&q=${query}&format=json`);
|
||||
if (!response.ok) throw new Error('Error al buscar la dirección');
|
||||
return await response.json();
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ $grays: (
|
||||
// scss-docs-start color-variables
|
||||
$blue: #007bff !default;
|
||||
$indigo: #6610f2 !default;
|
||||
$purple: #7367f0 !default;
|
||||
$purple: #64748b !default;
|
||||
$pink: #e83e8c !default;
|
||||
$red: #ff4c51 !default;
|
||||
$orange: #fd7e14 !default;
|
||||
|
@ -35,7 +35,7 @@ $grays: (
|
||||
// scss-docs-start color-variables
|
||||
$blue: #007bff !default;
|
||||
$indigo: #6610f2 !default;
|
||||
$purple: #7367f0 !default;
|
||||
$purple: #64748b !default;
|
||||
$pink: #e83e8c !default;
|
||||
$red: #ff4c51 !default;
|
||||
$orange: #fd7e14 !default;
|
||||
|
2
resources/assets/vendor/scss/core-dark.scss
vendored
2
resources/assets/vendor/scss/core-dark.scss
vendored
@ -2,3 +2,5 @@
|
||||
@import 'bootstrap-extended-dark';
|
||||
@import 'components-dark';
|
||||
@import 'colors-dark';
|
||||
|
||||
$primary-color: #4a8c08;
|
||||
|
2
resources/assets/vendor/scss/core.scss
vendored
2
resources/assets/vendor/scss/core.scss
vendored
@ -2,3 +2,5 @@
|
||||
@import 'bootstrap-extended';
|
||||
@import 'components';
|
||||
@import 'colors';
|
||||
|
||||
$primary-color: #4a8c08;
|
||||
|
@ -4,7 +4,7 @@
|
||||
@import './_theme/pages';
|
||||
@import './_theme/_theme';
|
||||
|
||||
$primary-color: #7367f0;
|
||||
$primary-color: #155dfc;
|
||||
|
||||
body {
|
||||
background: $card-bg;
|
||||
|
@ -4,7 +4,7 @@
|
||||
@import './_theme/pages';
|
||||
@import './_theme/_theme';
|
||||
|
||||
$primary-color: #7367f0;
|
||||
$primary-color: #155dfc;
|
||||
$body-bg: #f8f7fa;
|
||||
|
||||
body {
|
||||
|
@ -4,7 +4,7 @@
|
||||
@import './_theme/pages';
|
||||
@import './_theme/_theme';
|
||||
|
||||
$primary-color: #7367f0;
|
||||
$primary-color: #155dfc;
|
||||
|
||||
body {
|
||||
background: $body-bg;
|
||||
|
@ -4,7 +4,7 @@
|
||||
@import './_theme/pages';
|
||||
@import './_theme/_theme';
|
||||
|
||||
$primary-color: #7367f0;
|
||||
$primary-color: #155dfc;
|
||||
$body-bg: #f8f7fa;
|
||||
|
||||
body {
|
||||
|
@ -4,7 +4,7 @@
|
||||
@import './_theme/pages';
|
||||
@import './_theme/_theme';
|
||||
|
||||
$primary-color: #7367f0;
|
||||
$primary-color: #155dfc;
|
||||
|
||||
body {
|
||||
background: $body-bg;
|
||||
|
@ -4,7 +4,7 @@
|
||||
@import './_theme/pages';
|
||||
@import './_theme/_theme';
|
||||
|
||||
$primary-color: #7367f0;
|
||||
$primary-color: #155dfc;
|
||||
$body-bg: #f8f7fa;
|
||||
|
||||
body {
|
||||
|
@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Deshabilita o pone en modo de solo lectura los campos del formulario.
|
||||
* @param {string} formSelector - Selector del formulario a deshabilitar.
|
||||
*/
|
||||
const disableStoreForm = (formSelector) => {
|
||||
const form = document.querySelector(formSelector);
|
||||
if (!form) {
|
||||
console.warn(`Formulario no encontrado con el selector: ${formSelector}`);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Habilita o deshabilita un select con Select2.
|
||||
* @param {HTMLElement} selectElement - El select afectado.
|
||||
* @param {boolean} disabled - Si debe ser deshabilitado.
|
||||
*/
|
||||
const toggleSelect2Disabled = (selectElement, disabled) => {
|
||||
selectElement.disabled = disabled;
|
||||
selectElement.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
};
|
||||
|
||||
/**
|
||||
* Aplica modo solo lectura a un select estándar o Select2.
|
||||
* @param {HTMLElement} select - El select a modificar.
|
||||
* @param {boolean} readonly - Si debe estar en modo solo lectura.
|
||||
*/
|
||||
const setSelectReadonly = (select, readonly) => {
|
||||
select.setAttribute('readonly-mode', readonly);
|
||||
select.style.pointerEvents = readonly ? 'none' : '';
|
||||
select.tabIndex = readonly ? -1 : '';
|
||||
|
||||
if (select.classList.contains('select2-hidden-accessible')) {
|
||||
toggleSelect2Disabled(select, readonly);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Aplica modo solo lectura a un checkbox o radio.
|
||||
* @param {HTMLElement} checkbox - El input a modificar.
|
||||
* @param {boolean} readonly - Si debe ser solo lectura.
|
||||
*/
|
||||
const setCheckboxReadonly = (checkbox, readonly) => {
|
||||
checkbox.setAttribute('readonly-mode', readonly);
|
||||
checkbox.style.pointerEvents = readonly ? 'none' : '';
|
||||
checkbox[readonly ? 'addEventListener' : 'removeEventListener']('click', preventInteraction);
|
||||
};
|
||||
|
||||
/**
|
||||
* Previene interacción con el elemento.
|
||||
* @param {Event} event - El evento de clic.
|
||||
*/
|
||||
const preventInteraction = (event) => event.preventDefault();
|
||||
|
||||
// Obtener todos los inputs del formulario
|
||||
const inputs = form.querySelectorAll('input, textarea, select');
|
||||
|
||||
inputs.forEach((el) => {
|
||||
if (!el.classList.contains('data-always-enabled')) {
|
||||
switch (el.tagName) {
|
||||
case 'SELECT':
|
||||
if (el.classList.contains('select2')) {
|
||||
toggleSelect2Disabled(el, true);
|
||||
} else {
|
||||
setSelectReadonly(el, true);
|
||||
}
|
||||
break;
|
||||
case 'INPUT':
|
||||
if (['checkbox', 'radio'].includes(el.type)) {
|
||||
setCheckboxReadonly(el, true);
|
||||
} else {
|
||||
el.readOnly = true;
|
||||
}
|
||||
break;
|
||||
case 'TEXTAREA':
|
||||
el.readOnly = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Hacer la función accesible globalmente
|
||||
window.disableStoreForm = disableStoreForm;
|
||||
|
@ -4,24 +4,3 @@ import FormCustomListener from '../../assets/js/forms/formCustomListener';
|
||||
new FormCustomListener({
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel', '.btn-reset'] // Selectores para botones
|
||||
});
|
||||
|
||||
Livewire.on('clearLocalStoregeTemplateCustomizer', event => {
|
||||
const _deleteCookie = name => {
|
||||
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
|
||||
};
|
||||
|
||||
const pattern = 'templateCustomizer-';
|
||||
|
||||
// Iterar sobre todas las claves en localStorage
|
||||
Object.keys(localStorage).forEach(key => {
|
||||
if (key.startsWith(pattern)) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
|
||||
_deleteCookie('admin-mode');
|
||||
_deleteCookie('admin-colorPref');
|
||||
_deleteCookie('colorPref');
|
||||
_deleteCookie('theme');
|
||||
_deleteCookie('direction');
|
||||
});
|
||||
|
@ -7,7 +7,7 @@ window.senderResponseForm = new SenderResponseForm();
|
||||
|
||||
Livewire.hook('morphed', ({ component }) => {
|
||||
switch (component.name) {
|
||||
case 'mail-smtp-settings':
|
||||
case 'sendmail-settings':
|
||||
if (window.smtpSettingsForm) {
|
||||
window.smtpSettingsForm.reload(); // Recarga el formulario sin destruir la instancia
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export default class SmtpSettingsForm {
|
||||
constructor(config = {}) {
|
||||
const defaultConfig = {
|
||||
formSmtpSettingsSelector: '#mail-smtp-settings-card',
|
||||
formSmtpSettingsSelector: '#sendmail-settings-card',
|
||||
changeSmtpSettingsId: 'change_smtp_settings',
|
||||
testSmtpConnectionButtonId: 'test_smtp_connection_button',
|
||||
saveSmtpConnectionButtonId: 'save_smtp_connection_button',
|
||||
|
@ -2,6 +2,10 @@
|
||||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
|
||||
[x-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.menu-horizontal-wrapper > .menu-inner > .menu-item:last-child {
|
||||
padding-right: 70px;
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ $authentication-1-inner-max-width: 460px !default;
|
||||
position: absolute;
|
||||
top: -35px;
|
||||
left: -45px;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='239' height='234' viewBox='0 0 239 234' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='88.5605' y='0.700195' width='149' height='149' rx='19.5' stroke='%237367F0' stroke-opacity='0.16'/%3E%3Crect x='0.621094' y='33.761' width='200' height='200' rx='10' fill='%237367F0' fill-opacity='0.08'/%3E%3C/svg%3E%0A");
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='239' height='234' viewBox='0 0 239 234' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='88.5605' y='0.700195' width='149' height='149' rx='19.5' stroke='%23155dfc' stroke-opacity='0.16'/%3E%3Crect x='0.621094' y='33.761' width='200' height='200' rx='10' fill='%23155dfc' fill-opacity='0.08'/%3E%3C/svg%3E%0A");
|
||||
}
|
||||
&:after {
|
||||
@include light.media-breakpoint-down(sm) {
|
||||
@ -98,7 +98,7 @@ $authentication-1-inner-max-width: 460px !default;
|
||||
z-index: -1;
|
||||
bottom: -30px;
|
||||
right: -56px;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='181' height='181' viewBox='0 0 181 181' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='1.30469' y='1.44312' width='178' height='178' rx='19' stroke='%237367F0' stroke-opacity='0.16' stroke-width='2' stroke-dasharray='8 8'/%3E%3Crect x='22.8047' y='22.9431' width='135' height='135' rx='10' fill='%237367F0' fill-opacity='0.08'/%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='181' height='181' viewBox='0 0 181 181' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='1.30469' y='1.44312' width='178' height='178' rx='19' stroke='%23155dfc' stroke-opacity='0.16' stroke-width='2' stroke-dasharray='8 8'/%3E%3Crect x='22.8047' y='22.9431' width='135' height='135' rx='10' fill='%23155dfc' fill-opacity='0.08'/%3E%3C/svg%3E");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Ajustes generales')
|
||||
|
||||
@push('page-script')
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/js/pages/admin-settings-scripts.js')
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- App Settings Card -->
|
||||
<div class="mb-4">
|
||||
@livewire('application-settings')
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<!-- General Settings Card -->
|
||||
<div class="mb-4">
|
||||
@livewire('general-settings')
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<!-- Interface Settings Card -->
|
||||
<div class="mb-4">
|
||||
@livewire('interface-settings')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@ -10,28 +10,28 @@
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="mb-6">
|
||||
@livewire('cache-stats')
|
||||
@livewire('vuexy-admin::cache-stats')
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
@livewire('session-stats')
|
||||
@livewire('vuexy-admin::session-stats')
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="mb-6">
|
||||
@livewire('cache-functions')
|
||||
@livewire('vuexy-admin::cache-functions')
|
||||
</div>
|
||||
<div class="row">
|
||||
@if($configCache['redisInUse'])
|
||||
<div class="col-md-6">
|
||||
<div class="mb-6">
|
||||
@livewire('redis-stats')
|
||||
@livewire('vuexy-admin::redis-stats')
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($configCache['memcachedInUse'])
|
||||
<div class="col-md-6">
|
||||
<div class="mb-6">
|
||||
@livewire('memcached-stats')
|
||||
@livewire('vuexy-admin::memcached-stats')
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
24
resources/views/components/alert/basic.blade.php
Normal file
24
resources/views/components/alert/basic.blade.php
Normal file
@ -0,0 +1,24 @@
|
||||
@props([
|
||||
'type' => 'primary', // Tipos: primary, secondary, success, danger, warning, info, dark
|
||||
'outline' => false,
|
||||
'dismissible' => false,
|
||||
'icon' => null,
|
||||
])
|
||||
|
||||
@php
|
||||
$alertClass = $outline ? "alert-outline-{$type}" : "alert-{$type}";
|
||||
@endphp
|
||||
|
||||
<div class="alert {{ $alertClass }} {{ $dismissible ? 'alert-dismissible' : '' }} d-flex align-items-center" role="alert">
|
||||
@if ($icon)
|
||||
<span class="alert-icon rounded me-2">
|
||||
<i class="{{ $icon }}"></i>
|
||||
</span>
|
||||
@endif
|
||||
<div>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
@if ($dismissible)
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
@endif
|
||||
</div>
|
@ -71,7 +71,7 @@
|
||||
@endphp
|
||||
|
||||
{{-- ============================ CHECKBOX CON INPUT GROUP ============================ --}}
|
||||
<div class="mb-4 {{ $parentClass }}">
|
||||
<div class="mb-4 {{ $parentClass }} fv-row">
|
||||
@if ($label)
|
||||
<label for="{{ $checkboxId }}" class="{{ $labelClass }}">{{ $label }}</label>
|
||||
@endif
|
||||
|
@ -74,7 +74,7 @@
|
||||
|
||||
@if ($switch)
|
||||
{{-- ============================ MODO SWITCH ============================ --}}
|
||||
<div class="{{ $alignClass }} {{ $inline ? 'd-inline-block' : '' }} {{ $parentClass }} {{ $mb0 ? '' : 'mb-2' }}">
|
||||
<div class="{{ $alignClass }} {{ $inline ? 'd-inline-block' : '' }} {{ $parentClass }} {{ $mb0 ? '' : 'mb-2' }} fv-row">
|
||||
<label class="switch {{ $switchTypeClass }} {{ $switchColorClass }} {{ $sizeClass }} {{ $labelClass }}">
|
||||
<input
|
||||
{{ $livewireModel ? "wire:model=$livewireModel" : '' }}
|
||||
@ -110,7 +110,7 @@
|
||||
|
||||
@else
|
||||
{{-- ============================ MODO CHECKBOX ============================ --}}
|
||||
<div class="form-check {{ $checkColorClass }} {{ $alignClass }} {{ $sizeClass }} {{ $inline ? 'form-check-inline' : '' }} {{ $parentClass }} {{ $mb0 ? '' : 'mb-4' }}">
|
||||
<div class="form-check {{ $checkColorClass }} {{ $alignClass }} {{ $sizeClass }} {{ $inline ? 'form-check-inline' : '' }} {{ $parentClass }} {{ $mb0 ? '' : 'mb-4' }} fv-row">
|
||||
<input
|
||||
{{ $livewireModel ? "wire:model=$livewireModel" : '' }}
|
||||
{{ $disabled ? 'disabled' : '' }}
|
||||
|
@ -24,7 +24,7 @@
|
||||
: ($image ? "<img src='{$image}' alt='{$title}' class='img-fluid rounded'>" : '');
|
||||
@endphp
|
||||
|
||||
<div class="mb-4 form-check custom-option custom-option-icon {{ $checked ? 'checked' : '' }}">
|
||||
<div class="mb-4 form-check custom-option custom-option-icon {{ $checked ? 'checked' : '' }} fv-row">
|
||||
<label class="form-check-label custom-option-content" for="{{ $inputId }}">
|
||||
<span class="custom-option-body">
|
||||
{!! $visualContent !!}
|
||||
|
@ -8,6 +8,8 @@
|
||||
'wireSubmit' => false, // Usar wire:submit.prevent
|
||||
'class' => '', // Clases adicionales para el formulario
|
||||
'actionPosition' => 'bottom', // Posición de acciones: top, bottom, both, none
|
||||
'whitOutId' => false, // Excluir el ID del formulario
|
||||
'whitOutMode' => false, // Excluir el modo del formulario
|
||||
])
|
||||
|
||||
@php
|
||||
@ -28,8 +30,12 @@
|
||||
@endphp
|
||||
|
||||
<form {{ $attributes->merge($formAttributes) }}>
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" type="hidden" model="id" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" type="hidden" model="mode" />
|
||||
@if (!$whitOutId)
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" type="hidden" model="id" />
|
||||
@endif
|
||||
@if (!$whitOutMode)
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" type="hidden" model="mode" />
|
||||
@endif
|
||||
@if ($mode !== 'delete' && in_array($actionPosition, ['top', 'both']))
|
||||
<div class="notification-container mb-4"></div>
|
||||
<div class="form-actions mb-4">
|
||||
|
@ -1,184 +0,0 @@
|
||||
@props([
|
||||
'uid' => uniqid(),
|
||||
|
||||
|
||||
'model' => '',
|
||||
|
||||
|
||||
'label' => '',
|
||||
'labelClass' => '',
|
||||
|
||||
|
||||
'class' => '',
|
||||
|
||||
'align' => 'start',
|
||||
'size' => '',
|
||||
'mb-0' => false,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'parentClass' => '',
|
||||
|
||||
|
||||
'prefix' => null,
|
||||
'suffix' => null,
|
||||
|
||||
'icon' => null,
|
||||
'clickableIcon' => null,
|
||||
|
||||
'inline' => false,
|
||||
|
||||
'labelCol' => 4,
|
||||
'inputCol' => 8,
|
||||
|
||||
'floatLabel' => false,
|
||||
'helperText' => '',
|
||||
|
||||
'attributes' => new \Illuminate\View\ComponentAttributeBag([]), // Atributos adicionales
|
||||
])
|
||||
|
||||
@php
|
||||
// Configuración dinámica de atributos y clases CSS
|
||||
$livewireModel = $attributes->get('wire:model', $model); // Permitir uso directo de wire:model en el atributo
|
||||
$name = $name ?: $livewireModel; // Si no se proporciona el nombre, toma el nombre del modelo
|
||||
$inputId = $id ?: ($uid ? $name . '_' . $uid : $name); // ID generado si no se proporciona uno
|
||||
|
||||
|
||||
// Obtener los atributos actuales en un array
|
||||
$attributesArray = array_merge([
|
||||
'type' => $type,
|
||||
'id' => $inputId,
|
||||
'name' => $name,
|
||||
]);
|
||||
|
||||
|
||||
// Agregar wire:model solo si existe
|
||||
if ($livewireModel) {
|
||||
$attributesArray['wire:model'] = $livewireModel;
|
||||
}
|
||||
|
||||
|
||||
$attributesArray = array_merge($attributesArray, $attributes->getAttributes());
|
||||
|
||||
|
||||
// Reconstruir el ComponentAttributeBag con los atributos modificados
|
||||
$inputAttributes = new \Illuminate\View\ComponentAttributeBag($attributesArray);
|
||||
|
||||
dump($inputAttributes);
|
||||
|
||||
|
||||
// Manejo de errores de validación
|
||||
$errorKey = $livewireModel ?: $name;
|
||||
$errorClass = $errors->has($errorKey) ? 'is-invalid' : '';
|
||||
|
||||
// Definir el tamaño del input basado en la clase seleccionada
|
||||
$sizeClass = $size === 'small' ? 'form-control-sm' : ($size === 'large' ? 'form-control-lg' : '');
|
||||
|
||||
// Alineación del texto
|
||||
$alignClass = match ($align) {
|
||||
'center' => 'text-center',
|
||||
'end' => 'text-end',
|
||||
default => ''
|
||||
};
|
||||
|
||||
// Clases combinadas para el input
|
||||
$fullClass = trim("form-control $sizeClass $alignClass $errorClass $class");
|
||||
|
||||
// Detectar si se necesita usar input-group
|
||||
$requiresInputGroup = $prefix || $suffix || $icon || $clickableIcon;
|
||||
@endphp
|
||||
|
||||
{{-- Input oculto sin estilos --}}
|
||||
@if($type === 'hidden')
|
||||
<input type="hidden" id="{{ $inputId }}" name="{{ $name }}" {{ $livewireModel ? "wire:model=$livewireModel" : '' }}
|
||||
/>
|
||||
@elseif($floatLabel)
|
||||
{{-- Input con etiqueta flotante --}}
|
||||
<div class="form-floating mb-4 {{ $parentClass }}">
|
||||
<input
|
||||
type="{{ $type }}"
|
||||
id="{{ $inputId }}"
|
||||
name="{{ $name }}"
|
||||
{{ $livewireModel ? "wire:model=$livewireModel" : '' }}
|
||||
class="{{ $fullClass }}"
|
||||
placeholder="{{ $placeholder ?: 'Ingrese ' . strtolower($label) }}"
|
||||
{{ $step ? "step=$step" : '' }}
|
||||
{{ $max ? "maxlength=$max" : '' }}
|
||||
{{ $min ? "minlength=$min" : '' }}
|
||||
{{ $pattern ? "pattern=$pattern" : '' }}
|
||||
{{ $disabled ? 'disabled' : '' }}
|
||||
{{ $multiple ? 'multiple' : '' }} />
|
||||
<label for="{{ $inputId }}">{{ $label }}</label>
|
||||
|
||||
@if ($helperText)
|
||||
<div class="form-text">{{ $helperText }}</div>
|
||||
@endif
|
||||
|
||||
@if ($errors->has($errorKey))
|
||||
<span class="text-danger">{{ $errors->first($errorKey) }}</span>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
{{-- Input con formato clásico --}}
|
||||
<div class="{{ $inline ? 'row' : '' }} {{ $parentClass }} fv-row mb-4">
|
||||
@isset($label)
|
||||
<label for="{{ $inputId }}" class="{{ $inline ? 'col-form-label col-md-' . $labelCol : 'form-label' }} {{ $labelClass }}">{{ $label }}</label>
|
||||
@endisset
|
||||
<div class="{{ $inline ? 'col-md-' . $inputCol : '' }}">
|
||||
@if ($requiresInputGroup)
|
||||
<div class="input-group input-group-merge">
|
||||
@if ($prefix)
|
||||
<span class="input-group-text">{{ $prefix }}</span>
|
||||
@endif
|
||||
@if ($icon)
|
||||
<span class="input-group-text"><i class="{{ $icon }}"></i></span>
|
||||
@endif
|
||||
<input
|
||||
type="{{ $type }}"
|
||||
id="{{ $inputId }}"
|
||||
name="{{ $name }}"
|
||||
{{ $livewireModel ? "wire:model=$livewireModel" : '' }}
|
||||
class="{{ $fullClass }}"
|
||||
placeholder="{{ $placeholder ?: 'Ingrese ' . strtolower($label) }}"
|
||||
{{ $step ? "step=$step" : '' }}
|
||||
{{ $max ? "maxlength=$max" : '' }}
|
||||
{{ $min ? "minlength=$min" : '' }}
|
||||
{{ $pattern ? "pattern=$pattern" : '' }}
|
||||
{{ $disabled ? 'disabled' : '' }}
|
||||
{{ $multiple ? 'multiple' : '' }} />
|
||||
@if ($suffix)
|
||||
<span class="input-group-text">{{ $suffix }}</span>
|
||||
@endif
|
||||
@if ($clickableIcon)
|
||||
<button type="button" class="input-group-text cursor-pointer">
|
||||
<i class="{{ $clickableIcon }}"></i>
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
{{-- Input sin prefijo o íconos --}}
|
||||
<input
|
||||
type="{{ $type }}"
|
||||
id="{{ $inputId }}"
|
||||
name="{{ $name }}"
|
||||
{{ $livewireModel ? "wire:model=$livewireModel" : '' }}
|
||||
class="{{ $fullClass }}"
|
||||
placeholder="{{ $placeholder ?: 'Ingrese ' . strtolower($label) }}"
|
||||
{{ $step ? "step=$step" : '' }}
|
||||
{{ $max ? "maxlength=$max" : '' }}
|
||||
{{ $min ? "minlength=$min" : '' }}
|
||||
{{ $pattern ? "pattern=$pattern" : '' }}
|
||||
{{ $disabled ? 'disabled' : '' }}
|
||||
{{ $multiple ? 'multiple' : '' }} />
|
||||
@endif
|
||||
@if ($helperText)
|
||||
<small class="form-text text-muted">{{ $helperText }}</small>
|
||||
@endif
|
||||
@if ($errors->has($errorKey))
|
||||
<span class="text-danger">{{ $errors->first($errorKey) }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
@ -16,13 +16,18 @@
|
||||
'mb0' => false, // Remover margen inferior
|
||||
'parentClass' => '',
|
||||
|
||||
// Elementos opcionales antes/después del input
|
||||
// Elementos de prefijo
|
||||
'prefix' => null,
|
||||
'suffix' => null,
|
||||
'prefixIcon' => null,
|
||||
'icon' => null, // Alias para prefixIcon
|
||||
'prefixClickable' => false,
|
||||
'prefixAction' => null,
|
||||
|
||||
// Íconos dentro del input
|
||||
'icon' => null,
|
||||
'clickableIcon' => null,
|
||||
// Elementos de sufijo
|
||||
'suffix' => null,
|
||||
'suffixIcon' => null,
|
||||
'suffixClickable' => false,
|
||||
'suffixAction' => null,
|
||||
|
||||
// Configuración especial
|
||||
'phoneMode' => false, // "national", "international", "both"
|
||||
@ -47,6 +52,9 @@
|
||||
$inputId = $attributes->get('id', $name . '_' . $uid);
|
||||
$type = $attributes->get('type', 'text');
|
||||
|
||||
// Manejar el alias de icon a prefixIcon
|
||||
$prefixIcon = $prefixIcon ?? $icon;
|
||||
|
||||
// **Definir formato de teléfono según `phoneMode`**
|
||||
if ($phoneMode) {
|
||||
$type = 'tel';
|
||||
@ -120,37 +128,68 @@
|
||||
'id' => $inputId,
|
||||
'name' => $name,
|
||||
])->class("form-control $sizeClass $alignClass $errorClass");
|
||||
|
||||
// Verificar si se necesita el input-group
|
||||
$hasAddons = $prefix || $prefixIcon || $suffix || $suffixIcon;
|
||||
@endphp
|
||||
|
||||
{{-- Estructura del Input --}}
|
||||
<div class="{{ $mb0 ? '' : 'mb-4' }} {{ $parentClass }}">
|
||||
<div class="{{ $mb0 ? '' : 'mb-4' }} {{ $parentClass }} fv-row">
|
||||
{{-- Etiqueta --}}
|
||||
@if ($label)
|
||||
<label for="{{ $inputId }}" class="form-label {{ $labelClass }}">{{ $label }}</label>
|
||||
@endif
|
||||
|
||||
{{-- Input con Prefijos, Sufijos o Íconos --}}
|
||||
@if ($prefix || $suffix || $icon || $clickableIcon)
|
||||
{{-- Input con Prefijos o Sufijos --}}
|
||||
@if ($hasAddons)
|
||||
<div class="input-group input-group-merge">
|
||||
@isset($prefix)
|
||||
<span class="input-group-text">{{ $prefix }}</span>
|
||||
@endisset
|
||||
|
||||
@isset($icon)
|
||||
<span class="input-group-text"><i class="{{ $icon }}"></i></span>
|
||||
@endisset
|
||||
{{-- Prefijo --}}
|
||||
@if ($prefix || $prefixIcon)
|
||||
@if ($prefixClickable)
|
||||
<button type="button" class="input-group-text cursor-pointer" {{ $prefixAction ? "wire:click=$prefixAction" : '' }}>
|
||||
@if ($prefixIcon)
|
||||
<i class="{{ $prefixIcon }}"></i>
|
||||
@endif
|
||||
@if ($prefix)
|
||||
{{ $prefix }}
|
||||
@endif
|
||||
</button>
|
||||
@else
|
||||
<span class="input-group-text">
|
||||
@if ($prefixIcon)
|
||||
<i class="{{ $prefixIcon }}"></i>
|
||||
@endif
|
||||
@if ($prefix)
|
||||
{{ $prefix }}
|
||||
@endif
|
||||
</span>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<input {!! $inputAttributes !!} {{ $livewireModel ? "wire:model=$livewireModel" : '' }} />
|
||||
|
||||
@isset($suffix)
|
||||
<span class="input-group-text">{{ $suffix }}</span>
|
||||
@endisset
|
||||
|
||||
@isset($clickableIcon)
|
||||
<button type="button" class="input-group-text cursor-pointer">
|
||||
<i class="{{ $clickableIcon }}"></i>
|
||||
</button>
|
||||
@endisset
|
||||
{{-- Sufijo --}}
|
||||
@if ($suffix || $suffixIcon)
|
||||
@if ($suffixClickable)
|
||||
<button type="button" class="input-group-text cursor-pointer" {{ $suffixAction ? "wire:click=$suffixAction" : '' }}>
|
||||
@if ($suffixIcon)
|
||||
<i class="{{ $suffixIcon }}"></i>
|
||||
@endif
|
||||
@if ($suffix)
|
||||
{{ $suffix }}
|
||||
@endif
|
||||
</button>
|
||||
@else
|
||||
<span class="input-group-text">
|
||||
@if ($suffixIcon)
|
||||
<i class="{{ $suffixIcon }}"></i>
|
||||
@endif
|
||||
@if ($suffix)
|
||||
{{ $suffix }}
|
||||
@endif
|
||||
</span>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
{{-- Input Simple --}}
|
||||
@ -166,4 +205,4 @@
|
||||
@if ($hasError)
|
||||
<span class="text-danger">{{ $errors->first($errorKey) }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
@ -72,7 +72,7 @@
|
||||
@endphp
|
||||
|
||||
{{-- ============================ RADIO BUTTON CON INPUT GROUP ============================ --}}
|
||||
<div class="{{ $mb0 ? '' : 'mb-4' }} {{ $parentClass }}">
|
||||
<div class="{{ $mb0 ? '' : 'mb-4' }} {{ $parentClass }} fv-row">
|
||||
@if ($label)
|
||||
<label for="{{ $radioId }}" class="{{ $labelClass }}">{{ $label }}</label>
|
||||
@endif
|
||||
@ -86,7 +86,7 @@
|
||||
type="radio"
|
||||
{{ $livewireRadio }}
|
||||
{{ $disabled ? 'disabled' : '' }}
|
||||
class="form-check-input mt-0"
|
||||
class="form-check-input fv-row mt-0"
|
||||
onchange="toggleRadioInputState('{{ $radioId }}', '{{ $textInputId }}', {{ $focusOnCheck ? 'true' : 'false' }}, {{ $disableOnOffRadio ? 'true' : 'false' }})"
|
||||
>
|
||||
</div>
|
||||
|
@ -72,7 +72,7 @@
|
||||
|
||||
@if ($switch)
|
||||
{{-- ============================ MODO SWITCH ============================ --}}
|
||||
<div class="{{ $alignClass }} {{ $inline ? 'd-inline-block' : '' }} {{ $parentClass }} {{ $mb0 ? '' : 'mb-4' }}">
|
||||
<div class="{{ $alignClass }} {{ $inline ? 'd-inline-block' : '' }} {{ $parentClass }} {{ $mb0 ? '' : 'mb-4' }} fv-row">
|
||||
<label class="switch {{ $switchTypeClass }} {{ $switchColorClass }} {{ $sizeClass }} {{ $labelClass }}">
|
||||
<input
|
||||
{{ $livewireModel ? "wire:model=$livewireModel" : '' }}
|
||||
@ -102,7 +102,7 @@
|
||||
|
||||
@else
|
||||
{{-- ============================ MODO RADIO ============================ --}}
|
||||
<div class="{{ $layoutClass }} {{ $radioColorClass }} {{ $alignClass }} {{ $sizeClass }} {{ $inline ? 'form-check-inline' : '' }} {{ $parentClass }} {{ $mb0 ? '' : 'mb-4' }}">
|
||||
<div class="{{ $layoutClass }} {{ $radioColorClass }} {{ $alignClass }} {{ $sizeClass }} {{ $inline ? 'form-check-inline' : '' }} {{ $parentClass }} {{ $mb0 ? '' : 'mb-4' }} fv-row">
|
||||
<input
|
||||
{{ $livewireModel ? "wire:model=$livewireModel" : '' }}
|
||||
{{ $disabled ? 'disabled' : '' }}
|
||||
|
@ -1,86 +0,0 @@
|
||||
@props([
|
||||
'uid' => uniqid(),
|
||||
'id' => '',
|
||||
'model' => '',
|
||||
'name' => '',
|
||||
'label' => '',
|
||||
'labelClass' => 'form-label',
|
||||
'placeholder' => '',
|
||||
'options' => [],
|
||||
'selected' => null,
|
||||
'class' => '',
|
||||
'parentClass' => '',
|
||||
'multiple' => false,
|
||||
'disabled' => false,
|
||||
'prefixLabel' => null,
|
||||
'suffixLabel' => null,
|
||||
'buttonBefore' => null,
|
||||
'buttonAfter' => null,
|
||||
'inline' => false, // Si es en línea
|
||||
'labelCol' => 2, // Columnas que ocupa el label (Bootstrap grid)
|
||||
'inputCol' => 10, // Columnas que ocupa el input (Bootstrap grid)
|
||||
'helperText' => '', // Texto de ayuda opcional
|
||||
'select2' => false, // Activar Select2 automáticamente
|
||||
])
|
||||
|
||||
@php
|
||||
$name = $name ?: $model;
|
||||
$inputId = $id ?: ($uid ? str_replace('.', '_', $name) . '_' . $uid : $name);
|
||||
$placeholder = $placeholder ?: 'Seleccione ' . strtolower($label);
|
||||
$errorClass = $errors->has($model) ? 'is-invalid' : '';
|
||||
$options = is_array($options) ? collect($options) : $options;
|
||||
$select2Class = $select2 ? 'select2' : ''; // Agrega la clase select2 si está habilitado
|
||||
@endphp
|
||||
|
||||
<div class="{{ $inline ? 'row' : 'mb-4' }} {{ $parentClass }} fv-row">
|
||||
@if($label != null)
|
||||
<label for="{{ $inputId }}" class="{{ $inline ? 'col-md-' . $labelCol : '' }} {{ $labelClass }}">{{ $label }}</label>
|
||||
@endif
|
||||
|
||||
<div class="{{ $inline ? 'col-md-' . $inputCol : '' }}">
|
||||
<div class="input-group {{ $prefixLabel || $suffixLabel || $buttonBefore || $buttonAfter ? 'input-group-merge' : '' }}">
|
||||
@if ($buttonBefore)
|
||||
<button class="btn btn-outline-primary waves-effect" type="button">{{ $buttonBefore }}</button>
|
||||
@endif
|
||||
|
||||
@if ($prefixLabel)
|
||||
<label class="input-group-text" for="{{ $inputId }}">{{ $prefixLabel }}</label>
|
||||
@endif
|
||||
|
||||
<select
|
||||
id="{{ $inputId }}"
|
||||
name="{{ $name }}"
|
||||
class="form-select {{ $errorClass }} {{ $class }} {{ $select2Class }}"
|
||||
{{ $multiple ? 'multiple' : '' }}
|
||||
{{ $disabled ? 'disabled' : '' }}
|
||||
{{ $model ? "wire:model=$model" : '' }}
|
||||
{{ $select2 ? 'data-live-search="true"' : '' }}
|
||||
>
|
||||
@if (!$multiple && $placeholder)
|
||||
<option value="">{{ $placeholder }}</option>
|
||||
@endif
|
||||
@foreach ($options as $key => $value)
|
||||
<option value="{{ $key }}" {{ (string) $key === (string) $selected ? 'selected' : '' }}>
|
||||
{{ $value }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
@if ($suffixLabel)
|
||||
<label class="input-group-text" for="{{ $inputId }}">{{ $suffixLabel }}</label>
|
||||
@endif
|
||||
|
||||
@if ($buttonAfter)
|
||||
<button class="btn btn-outline-primary waves-effect" type="button">{{ $buttonAfter }}</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if ($helperText)
|
||||
<div class="form-text">{{ $helperText }}</div>
|
||||
@endif
|
||||
|
||||
@if ($errors->has($model))
|
||||
<span class="text-danger">{{ $errors->first($model) }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
@ -88,7 +88,7 @@
|
||||
@endphp
|
||||
|
||||
{{-- ============================ TEXTAREA ============================ --}}
|
||||
<div class="{{ $mb0 ? '' : 'mb-4' }} {{ $parentClass }} {{ $alignClass }} {{ $floatingClass }}">
|
||||
<div class="{{ $mb0 ? '' : 'mb-4' }} {{ $parentClass }} {{ $alignClass }} {{ $floatingClass }} fv-row">
|
||||
@if (!$floating && $label)
|
||||
<label for="{{ $inputId }}" class="{{ $labelClass }}">{{ $label }}</label>
|
||||
@endif
|
||||
|
20
resources/views/general-settings/index.blade.php
Normal file
20
resources/views/general-settings/index.blade.php
Normal file
@ -0,0 +1,20 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Ajustes generales')
|
||||
|
||||
@push('page-script')
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/js/pages/admin-settings-scripts.js')
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-5">
|
||||
@livewire('vuexy-admin::app-description-settings')
|
||||
@livewire('vuexy-admin::app-favicon-settings')
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
@livewire('vuexy-admin::logo-on-light-bg-settings')
|
||||
@livewire('vuexy-admin::logo-on-dark-bg-settings')
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
22
resources/views/global-settings/index.blade.php
Normal file
22
resources/views/global-settings/index.blade.php
Normal file
@ -0,0 +1,22 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Configuraciones globales')
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@push('page-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js',
|
||||
])
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('vuexy-admin::global-settings-index')
|
||||
@livewire('vuexy-admin::global-setting-offcanvas-form')
|
||||
@endsection
|
11
resources/views/interface-settings/index.blade.php
Normal file
11
resources/views/interface-settings/index.blade.php
Normal file
@ -0,0 +1,11 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Ajustes de la interfaz')
|
||||
|
||||
@push('page-script')
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/js/pages/admin-settings-scripts.js')
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('vuexy-admin::interface-settings')
|
||||
@endsection
|
@ -181,7 +181,7 @@ $navbarDetached = ($navbarDetached ?? '');
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ route('admin.core.user-profile.index') }}">
|
||||
<i class="ti ti-user-cog me-2 ti-sm"></i>
|
||||
<span class="align-middle">Configuración de cuenta</span>
|
||||
<span class="align-middle">Cuenta de usuario</span>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
|
@ -1,70 +0,0 @@
|
||||
<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>
|
@ -1,105 +0,0 @@
|
||||
<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>
|
@ -1,196 +0,0 @@
|
||||
<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>
|
@ -1,67 +0,0 @@
|
||||
<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>
|
@ -198,7 +198,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="cache-stats-card">
|
||||
<div id="cache-stats-card" class="form-custom-listener mb-4">
|
||||
{{-- Form Card --}}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@ -99,7 +99,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="memcached-stats-card">
|
||||
<div id="memcached-stats-card" class="form-custom-listener mb-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Estadísticas de Memcached</h5>
|
||||
@ -115,7 +115,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="redis-stats-card">
|
||||
<div id="redis-stats-card" class="form-custom-listener mb-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Estadísticas de Redis</h5>
|
||||
@ -138,7 +138,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div class="form-custom-listener" id="session-stats-card">
|
||||
<div id="session-stats-card" class="form-custom-listener mb-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Configuraciones de Sesiones</h5>
|
||||
@ -114,7 +114,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
7
resources/views/livewire/global-settings/index.blade.php
Normal file
7
resources/views/livewire/global-settings/index.blade.php
Normal file
@ -0,0 +1,7 @@
|
||||
<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>
|
@ -0,0 +1,64 @@
|
||||
<div>
|
||||
<x-vuexy-admin::offcanvas.basic :id="$offcanvasId" :tag-name="$tagName">
|
||||
<x-vuexy-admin::form :id="$formId" :mode="$mode" wireSubmit="onSubmit">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.offcanvas-buttons :mode="$mode" :tagName="$tagName" />
|
||||
</x-slot>
|
||||
|
||||
{{-- Sección: Identificación --}}
|
||||
<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"
|
||||
:options="[
|
||||
'general' => 'General',
|
||||
'ui' => 'Interfaz',
|
||||
'mail' => 'Correo',
|
||||
'cfdi' => 'CFDI',
|
||||
]"
|
||||
placeholder="Selecciona una categoría"
|
||||
parentClass="col-md-6"
|
||||
/>
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="user_id" label="ID Usuario (Opcional)"
|
||||
type="number"
|
||||
parentClass="col-md-6"
|
||||
icon="ti ti-user"
|
||||
placeholder="ID del usuario asociado"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
{{-- Sección: Valores (solo llena uno) --}}
|
||||
<div class="alert" type="info" icon="ti ti-info-circle" class="mb-1">
|
||||
Puedes llenar **solo uno** de los valores siguientes según el tipo de configuración.
|
||||
</div>
|
||||
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="value_string" label="Valor (Texto Corto)" icon="ti ti-typography" placeholder="Ej: dark" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="value_integer" label="Valor (Entero)" type="number" icon="ti ti-hash" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="value_float" label="Valor (Decimal)" type="number" step="0.01" icon="ti ti-percentage" />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="value_boolean" label="Valor (Booleano)" />
|
||||
<x-vuexy-admin::form.textarea :uid="$uniqueId" model="value_text" label="Valor (Texto Largo)" placeholder="Valor largo o configuración avanzada en texto" rows="3" />
|
||||
|
||||
<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 initializeGlobalSettingsForm = () => {
|
||||
|
||||
};
|
||||
|
||||
var myOffcanvas = document.getElementById('{{ $offcanvasId }}');
|
||||
|
||||
myOffcanvas.addEventListener('show.bs.offcanvas', function () {
|
||||
initializeGlobalSettingsForm();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@endpush
|
@ -1,152 +1,7 @@
|
||||
<!-- 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>
|
||||
*/
|
||||
|
||||
?>
|
||||
<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>
|
||||
|
@ -0,0 +1,39 @@
|
||||
<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
|
@ -0,0 +1,95 @@
|
||||
<x-form-section submit="updateProfileInformation">
|
||||
<x-slot name="title">
|
||||
{{ __('Profile Information') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
{{ __('Update your account\'s profile information and email address.') }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="form">
|
||||
<!-- Profile Photo -->
|
||||
@if (Laravel\Jetstream\Jetstream::managesProfilePhotos())
|
||||
<div x-data="{photoName: null, photoPreview: null}" class="col-span-6 sm:col-span-4">
|
||||
<!-- Profile Photo File Input -->
|
||||
<input type="file" id="photo" class="hidden"
|
||||
wire:model.live="photo"
|
||||
x-ref="photo"
|
||||
x-on:change="
|
||||
photoName = $refs.photo.files[0].name;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
photoPreview = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL($refs.photo.files[0]);
|
||||
" />
|
||||
|
||||
<x-label for="photo" value="{{ __('Photo') }}" />
|
||||
|
||||
<!-- Current Profile Photo -->
|
||||
<div class="mt-2" x-show="! photoPreview">
|
||||
<img src="{{ $this->user->profile_photo_url }}" alt="{{ $this->user->name }}" class="rounded-full size-20 object-cover">
|
||||
</div>
|
||||
|
||||
<!-- New Profile Photo Preview -->
|
||||
<div class="mt-2" x-show="photoPreview" style="display: none;">
|
||||
<span class="block rounded-full size-20 bg-cover bg-no-repeat bg-center"
|
||||
x-bind:style="'background-image: url(\'' + photoPreview + '\');'">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<x-secondary-button class="mt-2 me-2" type="button" x-on:click.prevent="$refs.photo.click()">
|
||||
{{ __('Select A New Photo') }}
|
||||
</x-secondary-button>
|
||||
|
||||
@if ($this->user->profile_photo_path)
|
||||
<x-secondary-button type="button" class="mt-2" wire:click="deleteProfilePhoto">
|
||||
{{ __('Remove Photo') }}
|
||||
</x-secondary-button>
|
||||
@endif
|
||||
|
||||
<x-input-error for="photo" class="mt-2" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Name -->
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-label for="name" value="{{ __('Name') }}" />
|
||||
<x-input id="name" type="text" class="mt-1 block w-full" wire:model="state.name" required autocomplete="name" />
|
||||
<x-input-error for="name" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<x-label for="email" value="{{ __('Email') }}" />
|
||||
<x-input id="email" type="email" class="mt-1 block w-full" wire:model="state.email" required autocomplete="username" />
|
||||
<x-input-error for="email" class="mt-2" />
|
||||
|
||||
@if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::emailVerification()) && ! $this->user->hasVerifiedEmail())
|
||||
<p class="text-sm mt-2 dark:text-white">
|
||||
{{ __('Your email address is unverified.') }}
|
||||
|
||||
<button type="button" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800" wire:click.prevent="sendEmailVerification">
|
||||
{{ __('Click here to re-send the verification email.') }}
|
||||
</button>
|
||||
</p>
|
||||
|
||||
@if ($this->verificationLinkSent)
|
||||
<p class="mt-2 font-medium text-sm text-green-600 dark:text-green-400">
|
||||
{{ __('A new verification link has been sent to your email address.') }}
|
||||
</p>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="actions">
|
||||
<x-action-message class="me-3" on="saved">
|
||||
{{ __('Saved.') }}
|
||||
</x-action-message>
|
||||
|
||||
<x-button wire:loading.attr="disabled" wire:target="photo">
|
||||
{{ __('Save') }}
|
||||
</x-button>
|
||||
</x-slot>
|
||||
</x-form-section>
|
@ -1,704 +0,0 @@
|
||||
<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
|
@ -1,7 +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" />
|
||||
<x-vuexy-admin::button.index-offcanvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
||||
|
@ -5,28 +5,15 @@
|
||||
<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" />
|
||||
{{-- 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" />
|
||||
<hr>
|
||||
|
||||
{{-- Contraseña --}}
|
||||
<x-vuexy-admin::form.input type="password" :uid="$uniqueId" model="password" label="Contraseña" icon="ti ti-lock" autocomplete="new-password" />
|
||||
|
||||
|
||||
<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>
|
||||
|
@ -42,7 +42,7 @@
|
||||
<i class="ti ti-user pr-2"></i> Cuenta de usuario
|
||||
</button>
|
||||
</li>
|
||||
@if (($is_customer || $is_user) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_customer) && $this->tipo_persona != App\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,14 +56,14 @@
|
||||
</button>
|
||||
</li>
|
||||
@endif
|
||||
@if (($is_prospect || $is_customer || $is_provider || $is_user) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != App\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 || $is_user) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != App\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
|
||||
@ -158,14 +158,6 @@
|
||||
Es proveedor
|
||||
</x-checkbox-v>
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<x-checkbox-v value="{{ old('is_user', $is_user) }}"
|
||||
name='is_user'
|
||||
wire:model='is_user'
|
||||
parent_class='form-switch'>
|
||||
Es usuario
|
||||
</x-checkbox-v>
|
||||
</div>
|
||||
<div class="row pricelist-div mb-3">
|
||||
<div class="col-lg-12">
|
||||
<label for="pricelist_id" class="form-label">Lista de precios</label>
|
||||
@ -616,16 +608,13 @@
|
||||
@this.set('is_prospect', false, false);
|
||||
@this.set('is_customer', true, false);
|
||||
@this.set('is_provider', false, false);
|
||||
@this.set('is_user', false, false);
|
||||
@this.set('enable_credit', false, false);
|
||||
|
||||
$("#is_prospect").prop("disabled", true);
|
||||
$("#is_provider").prop("disabled", true);
|
||||
$("#is_user").prop("disabled", true);
|
||||
}else{
|
||||
$("#is_prospect").prop("disabled", false);
|
||||
$("#is_provider").prop("disabled", false);
|
||||
$("#is_user").prop("disabled", false);
|
||||
}
|
||||
|
||||
if (is_prospect || is_customer) {
|
||||
@ -1643,7 +1632,7 @@
|
||||
$(document).ready(function() {
|
||||
$("#pdf-dropzone")
|
||||
.dropzone({
|
||||
url: '{{ route('admin.crm.contacts.extraer-datos-pdf-constancia') }}',
|
||||
url: '{{ route('admin.crm.contacts.extract-data-pdf-certificate') }}',
|
||||
paramName: "file",
|
||||
maxFiles: 1,
|
||||
acceptedFiles: '.pdf',
|
||||
|
@ -0,0 +1,41 @@
|
||||
<div>
|
||||
<div id="app-description-settings-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"
|
||||
model="app_name"
|
||||
placeholder="Nombre corto" />
|
||||
<x-vuexy-admin::form.input
|
||||
label="Titulo del sitio"
|
||||
model="title"
|
||||
placeholder="Titulo del sitio" />
|
||||
<x-vuexy-admin::form.textarea
|
||||
label="Descripción del sitio"
|
||||
model="description"
|
||||
placeholder="Descripción del sitio" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-end">
|
||||
<x-vuexy-admin::button.basic
|
||||
variant="primary"
|
||||
size="sm"
|
||||
icon="ti ti-device-floppy"
|
||||
label="Guardar cambios"
|
||||
disabled
|
||||
wire:click="save"
|
||||
class="btn-save"
|
||||
waves />
|
||||
<x-vuexy-admin::button.basic
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
icon="ti ti-rotate-2"
|
||||
label="Cancelar"
|
||||
disabled
|
||||
wire:click="resetForm"
|
||||
class="btn-cancel"
|
||||
waves />
|
||||
</div>
|
||||
</div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,84 @@
|
||||
<div>
|
||||
<div id="app-favicon-settings-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Favicon" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
label="Icono de navegador"
|
||||
model="upload_image_favicon"
|
||||
accept="image/*" />
|
||||
<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>
|
||||
</x-vuexy-admin::card.basic>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-end">
|
||||
<x-vuexy-admin::button.basic
|
||||
variant="primary"
|
||||
size="sm"
|
||||
icon="ti ti-device-floppy"
|
||||
label="Guardar cambios"
|
||||
wire:click="save"
|
||||
:disabled="$upload_image_favicon === null"
|
||||
class="btn-save mt-2 mr-2"
|
||||
waves />
|
||||
<x-vuexy-admin::button.basic
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
icon="ti ti-rotate-2"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
:disabled="$upload_image_favicon === null"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
||||
</div>
|
||||
</div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
69
resources/views/livewire/vuexy/interface-settings.blade.php
Normal file
69
resources/views/livewire/vuexy/interface-settings.blade.php
Normal file
@ -0,0 +1,69 @@
|
||||
<div x-data>
|
||||
<div id="interface-settings-card" class="form-custom-listener mb-4">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{-- Tema --}}
|
||||
<x-vuexy-admin::card.basic title="Ajustes de tema" class="mb-6">
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="vuexy_myTheme" label="Tema" :options="['theme-default' => 'Tema predeterminado', 'theme-bordered' => 'Tema bordeado', 'theme-semi-dark' => 'Tema semi-oscuro']" />
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="vuexy_myStyle" label="Estilo" :options="['light' => 'Claro', 'dark' => 'Oscuro', 'system' => 'Modo del sistema']" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Diseño --}}
|
||||
<x-vuexy-admin::card.basic title="Ajustes de diseño" class="mb-6">
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="vuexy_authViewMode" label="Modo de vista de autenticación" :options="['cover' => 'Pantalla completa', 'basic' => 'Básico']" />
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="vuexy_contentLayout" label="Ancho predeterminado" :options="['compact' => 'Compacto', 'wide' => 'Ancho completo']" />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="vuexy_footerFixed" label="Fijar pie de página" switch />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{-- Ajustes de menú y barra superior --}}
|
||||
<x-vuexy-admin::card.basic title="Ajustes menú y barra superior" class="mb-6">
|
||||
{{-- Diseño (Layout) --}}
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="vuexy_myLayout" label="Diseño de menú" :options="['vertical' => 'Vertical', 'horizontal' => 'Horizontal']" />
|
||||
{{-- Horizontal layout --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'horizontal'" x-cloak x-transition>
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="vuexy_headerType" label="Tipo de barra superior" :options="['static' => 'Estático', 'fixed' => 'Fijo']" />
|
||||
</div>
|
||||
{{-- Vertical layout --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'vertical'" x-cloak x-transition>
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="vuexy_navbarType" label="Tipo de barra de navegación" :options="['sticky' => 'Fija', 'static' => 'Estática', 'hidden' => 'Oculta']" />
|
||||
</div>
|
||||
{{-- Personalizador activo --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'horizontal'" x-cloak x-transition>
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="vuexy_showDropdownOnHover" label="Mostrar desplegable al pasar el mouse" switch />
|
||||
</div>
|
||||
{{-- Opciones para diseño vertical --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'vertical'" x-cloak x-transition>
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="vuexy_menuFixed" label="Menú fijo" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="vuexy_menuCollapsed" label="Menú colapsado" switch />
|
||||
</div>
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Atajos --}}
|
||||
<div x-show="$wire.vuexy_myLayout === 'horizontal' || $wire.vuexy_navbarType !== 'hidden'" x-cloak x-transition>
|
||||
<x-vuexy-admin::card.basic title="Atajos" class="mb-6">
|
||||
<x-vuexy-admin::form.input type="number" :uid="$uniqueId" model="vuexy_maxQuickLinks" label="Máximo de enlaces rápidos" min="2" max="20" helperText="Selecciona un valor entre 2 y 20." />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
|
||||
{{-- Personalizador de plantilla --}}
|
||||
<x-vuexy-admin::card.basic title="Personalizador de plantilla" class="mb-6">
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="vuexy_hasCustomizer" label="Habilitar personalizador de plantilla" switch />
|
||||
<div x-show="$wire.vuexy_hasCustomizer" x-cloak x-transition>
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="vuexy_displayCustomizer" label="Mostrar personalizador de plantilla" switch />
|
||||
</div>
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Acciones --}}
|
||||
<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="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>
|
@ -0,0 +1,39 @@
|
||||
<div>
|
||||
<div id="logo-on-dark-bg-settings-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Logotipo sobre fondo oscuro" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
label="Logotipo sobre fondo oscuro"
|
||||
model="upload_image_logo_dark"
|
||||
accept="image/*" />
|
||||
<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>
|
||||
</x-vuexy-admin::card.basic>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-end">
|
||||
<x-vuexy-admin::button.basic
|
||||
variant="primary"
|
||||
size="sm"
|
||||
icon="ti ti-device-floppy"
|
||||
disabled="{{ $upload_image_logo_dark === null }}"
|
||||
label="Guardar cambios"
|
||||
wire:click="save"
|
||||
class="btn-save mt-2 mr-2"
|
||||
waves />
|
||||
<x-vuexy-admin::button.basic
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
icon="ti ti-rotate-2"
|
||||
disabled="{{ $upload_image_logo_dark === null }}"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
||||
</div>
|
||||
</div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,39 @@
|
||||
<div>
|
||||
<div id="logo-on-light-bg-settings-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Logotipo sobre fondo claro" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
label="Logotipo sobre fondo claro"
|
||||
model="upload_image_logo"
|
||||
accept="image/*" />
|
||||
<div class="mb-3 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>
|
||||
</x-vuexy-admin::card.basic>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-end">
|
||||
<x-vuexy-admin::button.basic
|
||||
variant="primary"
|
||||
size="sm"
|
||||
icon="ti ti-device-floppy"
|
||||
disabled="{{ $upload_image_logo === null }}"
|
||||
label="Guardar cambios"
|
||||
wire:click="save"
|
||||
class="btn-save mt-2 mr-2"
|
||||
waves />
|
||||
<x-vuexy-admin::button.basic
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
icon="ti ti-rotate-2"
|
||||
disabled="{{ $upload_image_logo === null }}"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
||||
</div>
|
||||
</div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
53
resources/views/livewire/vuexy/quick-access-widget.blade.php
Normal file
53
resources/views/livewire/vuexy/quick-access-widget.blade.php
Normal file
@ -0,0 +1,53 @@
|
||||
@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>
|
@ -2,7 +2,7 @@
|
||||
changeSmtpSettings: @entangle('change_smtp_settings'),
|
||||
saveButtonDisabled: @entangle('save_button_disabled'),
|
||||
}">
|
||||
<form id="mail-smtp-settings-card">
|
||||
<form id="sendmail-settings-card">
|
||||
<div class="card mb-6">
|
||||
<h5 class="card-header">Servidor saliente de correo electrónico</h5>
|
||||
<div class="card-body">
|
||||
@ -80,7 +80,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notifications --}}
|
||||
<div class="notification-container" wire:ignore></div>
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -1,7 +1,3 @@
|
||||
@php
|
||||
$configData = Helper::appClasses();
|
||||
@endphp
|
||||
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('content')
|
||||
|
@ -5,45 +5,5 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row">
|
||||
<h4>{{ $_admin['title'] }}</h4>
|
||||
<p>Para mayor información al respecto consulta la <a href="{{ config('koneko.documentation') }}" target="_blank" rel="noopener noreferrer">documentación</a>.</p>
|
||||
|
||||
@php
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
// Obtener el usuario autenticado
|
||||
$user = Auth::user();
|
||||
|
||||
echo '<pre>';
|
||||
if ($user) {
|
||||
// Imprimir información del usuario
|
||||
echo "Usuario: {$user->name}\n";
|
||||
echo "Email: {$user->email}\n\n";
|
||||
|
||||
// Obtener todos los roles del usuario
|
||||
$roles = $user->roles;
|
||||
|
||||
// Iterar sobre los roles del usuario
|
||||
foreach ($roles as $role) {
|
||||
echo "Rol: {$role->name}\n";
|
||||
|
||||
// Obtener todos los permisos del rol
|
||||
$permissions = $role->permissions;
|
||||
|
||||
// Imprimir los permisos del rol
|
||||
foreach ($permissions as $permission) {
|
||||
echo " - Permiso: {$permission->name}\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
echo "Usuario no autenticado\n";
|
||||
}
|
||||
echo '</pre>';
|
||||
@endphp
|
||||
|
||||
@livewire('vuexy-admin::quick-access-widget');
|
||||
@endsection
|
||||
|
@ -4,27 +4,26 @@
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/datatables-bs5/datatables.bootstrap5.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/datatables-responsive-bs5/responsive.bootstrap5.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/datatables-buttons-bs5/buttons.bootstrap5.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/@form-validation/form-validation.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('vendor-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/datatables-bs5/datatables-bootstrap5.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/@form-validation/popular.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/@form-validation/bootstrap5.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/@form-validation/auto-focus.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.js',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@push('page-script')
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/js/pages/roles-scripts.js/permissions-scripts.js')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js',
|
||||
])
|
||||
@endpush
|
||||
|
||||
|
||||
@section('content')
|
||||
@livewire('permissions-index')
|
||||
@livewire('vuexy-admin::permissions-index')
|
||||
@livewire('vuexy-admin::permission-offcanvas-form')
|
||||
@endsection
|
||||
|
@ -1,38 +1,33 @@
|
||||
@extends('layouts.vuexy.layoutMaster')
|
||||
|
||||
@php
|
||||
$breadcrumbs = [['link' => 'home', 'name' => 'Home'], ['link' => 'javascript:void(0)', 'name' => 'User'], ['name' => 'Profile']];
|
||||
@endphp
|
||||
|
||||
@section('title', 'Profile')
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Perfil de usuario')
|
||||
|
||||
@section('content')
|
||||
|
||||
@if (Laravel\Fortify\Features::canUpdateProfileInformation())
|
||||
<div class="mb-6">
|
||||
@livewire('profile.update-profile-information-form')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::updatePasswords()))
|
||||
<?php /*
|
||||
@if (Laravel\Fortify\Features::canUpdateProfileInformation())
|
||||
<div class="mb-6">
|
||||
@livewire('profile.update-password-form')
|
||||
@livewire('vuexy-admin::update-profile-information-form')
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if (Laravel\Fortify\Features::canManageTwoFactorAuthentication())
|
||||
<div class="mb-6">
|
||||
@livewire('profile.two-factor-authentication-form')
|
||||
</div>
|
||||
@endif
|
||||
@if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::updatePasswords()))
|
||||
<div class="mb-6">
|
||||
@livewire('profile.update-password-form')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="mb-6">
|
||||
@livewire('profile.logout-other-browser-sessions-form')
|
||||
</div>
|
||||
@if (Laravel\Fortify\Features::canManageTwoFactorAuthentication())
|
||||
<div class="mb-6">
|
||||
@livewire('profile.two-factor-authentication-form')
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (Laravel\Jetstream\Jetstream::hasAccountDeletionFeatures())
|
||||
@livewire('profile.delete-user-form')
|
||||
@endif
|
||||
<div class="mb-6">
|
||||
@livewire('profile.logout-other-browser-sessions-form')
|
||||
</div>
|
||||
|
||||
@if (Laravel\Jetstream\Jetstream::hasAccountDeletionFeatures())
|
||||
@livewire('profile.delete-user-form')
|
||||
@endif
|
||||
*/ ?>
|
||||
@endsection
|
||||
|
@ -17,5 +17,5 @@
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
@livewire('role-card')
|
||||
@livewire('vuexy-admin::roles-index')
|
||||
@endsection
|
||||
|
@ -24,12 +24,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="mb-4">
|
||||
@livewire('mail-smtp-settings')
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="mb-4">
|
||||
@livewire('mail-sender-response-settings')
|
||||
@livewire('vuexy-admin::sendmail-settings')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -24,6 +24,6 @@
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('user-index')
|
||||
@livewire('user-offcanvas-form')
|
||||
@livewire('vuexy-admin::users-index')
|
||||
@livewire('vuexy-admin::user-offcanvas-form')
|
||||
@endsection
|
||||
|
Reference in New Issue
Block a user