This commit is contained in:
2025-10-21 11:41:30 -06:00
parent ed2ef4e01b
commit b1b9e4a77c
49 changed files with 14632 additions and 1736 deletions

View File

@@ -0,0 +1,790 @@
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title> Nuevo Template Rápido</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
@media (min-width: 768px) { .content { margin-left: 250px; } }
@media (max-width: 767.98px) {
.content { margin-left: 0; }
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
border: none;
}
.btn-animated {
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.btn-animated:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.form-control:focus, .form-select:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
}
.emoji-picker {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 8px;
padding: 15px;
max-height: 250px;
overflow-y: auto;
border: 1px solid #dee2e6;
border-radius: 8px;
background: white;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.emoji-item {
padding: 10px;
text-align: center;
cursor: pointer;
border-radius: 6px;
transition: all 0.2s ease;
font-size: 20px;
border: 2px solid transparent;
display: flex;
align-items: center;
justify-content: center;
min-height: 40px;
}
.emoji-item:hover {
background-color: #e3f2fd;
border-color: #2196f3;
transform: scale(1.1);
}
.emoji-item.selected {
background-color: #1976d2;
color: white;
border-color: #0d47a1;
}
.preview-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 12px;
padding: 20px;
margin-top: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
.template-preview-item {
background: rgba(255,255,255,0.2);
border: 1px solid rgba(255,255,255,0.3);
color: white;
padding: 8px 14px;
border-radius: 25px;
font-size: 11px;
font-weight: 500;
margin: 3px;
display: inline-block;
backdrop-filter: blur(10px);
}
.section-header {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 15px 20px;
margin: -15px -15px 20px -15px;
border-radius: 8px 8px 0 0;
border-bottom: 1px solid #dee2e6;
}
.section-header h6 {
margin: 0;
color: #495057;
font-weight: 600;
}
.icon-preview {
font-size: 24px;
margin-right: 8px;
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background: rgba(255,255,255,0.1);
border-radius: 8px;
border: 1px solid rgba(255,255,255,0.2);
}
.form-label {
font-weight: 600;
color: #495057;
margin-bottom: 8px;
}
.choices__inner {
min-height: 42px !important;
border: 1px solid #ced4da !important;
border-radius: 6px !important;
}
.choices__inner:focus {
border-color: #0d6efd !important;
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25) !important;
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid rgba(255,255,255,.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.tips-section {
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
border-radius: 8px;
padding: 15px;
margin-top: 15px;
}
.tip-item {
display: flex;
align-items: center;
margin-bottom: 8px;
font-size: 13px;
color: #1565c0;
}
.tip-item:last-child {
margin-bottom: 0;
}
.tip-item i {
margin-right: 8px;
width: 16px;
}
</style>
</head>
<body>
<div class="content">
<div class="d-flex justify-content-between align-items-center mb-4">
<h4 class="mb-0"> Nuevo Template Rápido</h4>
<a href="/IMPORTADORES/templates_rapidos/lista" class="btn btn-secondary btn-animated">
<i class="fas fa-arrow-left me-1"></i>Volver a Lista
</a>
</div>
<div class="row">
<!-- Formulario Principal -->
<div class="col-lg-8">
<div class="card">
<div class="card-body p-4">
<form id="templateForm" action="/IMPORTADORES/templates_rapidos/guardar" method="POST">
<!-- Información Básica -->
<div class="section-header">
<h6 class="mb-0"><i class="fas fa-info-circle me-2"></i>Información Básica</h6>
</div>
<div class="row mb-4">
<div class="col-md-6">
<label for="nombre" class="form-label">Nombre del Template *</label>
<input id="nombre" name="nombre" type="text" class="form-control" required
placeholder="ej. Importación China" maxlength="100">
</div>
<div class="col-md-6">
<label for="icono" class="form-label">Icono</label>
<div class="input-group">
<span class="input-group-text" id="icon-display" style="font-size: 20px;">🏢</span>
<input id="icono" name="icono" type="text" class="form-control" value="🏢" readonly>
<button type="button" class="btn btn-outline-secondary dropdown-toggle"
data-bs-toggle="dropdown" aria-expanded="false">
<i class="fas fa-palette"></i>
</button>
<div class="dropdown-menu dropdown-menu-end p-0" style="width: 320px;">
<div class="p-2">
<h6 class="dropdown-header">🌍 Países</h6>
<div class="emoji-picker" style="max-height: 120px;">
<div class="emoji-item" data-emoji="🇨🇳">🇨🇳</div>
<div class="emoji-item" data-emoji="🇺🇸">🇺🇸</div>
<div class="emoji-item" data-emoji="🇪🇺">🇪🇺</div>
<div class="emoji-item" data-emoji="🇩🇪">🇩🇪</div>
<div class="emoji-item" data-emoji="🇯🇵">🇯🇵</div>
<div class="emoji-item" data-emoji="🇰🇷">🇰🇷</div>
<div class="emoji-item" data-emoji="🇮🇹">🇮🇹</div>
<div class="emoji-item" data-emoji="🇫🇷">🇫🇷</div>
<div class="emoji-item" data-emoji="🇨🇦">🇨🇦</div>
<div class="emoji-item" data-emoji="🇧🇷">🇧🇷</div>
<div class="emoji-item" data-emoji="🇮🇳">🇮🇳</div>
<div class="emoji-item" data-emoji="🇹🇼">🇹🇼</div>
</div>
<h6 class="dropdown-header mt-3">🏢 Empresas & Logística</h6>
<div class="emoji-picker" style="max-height: 120px;">
<div class="emoji-item" data-emoji="🏢">🏢</div>
<div class="emoji-item" data-emoji="🏭">🏭</div>
<div class="emoji-item" data-emoji="🏪">🏪</div>
<div class="emoji-item" data-emoji="🏬">🏬</div>
<div class="emoji-item" data-emoji="🚢">🚢</div>
<div class="emoji-item" data-emoji="✈️">✈️</div>
<div class="emoji-item" data-emoji="🚛">🚛</div>
<div class="emoji-item" data-emoji="🚚">🚚</div>
<div class="emoji-item" data-emoji="📦">📦</div>
<div class="emoji-item" data-emoji="📋">📋</div>
<div class="emoji-item" data-emoji="💼">💼</div>
<div class="emoji-item" data-emoji="📊">📊</div>
</div>
<h6 class="dropdown-header mt-3">⭐ Destacados</h6>
<div class="emoji-picker" style="max-height: 80px;">
<div class="emoji-item" data-emoji="⚡">⚡</div>
<div class="emoji-item" data-emoji="🔥">🔥</div>
<div class="emoji-item" data-emoji="⭐">⭐</div>
<div class="emoji-item" data-emoji="🎯">🎯</div>
<div class="emoji-item" data-emoji="🚀">🚀</div>
<div class="emoji-item" data-emoji="💎">💎</div>
<div class="emoji-item" data-emoji="🔧">🔧</div>
<div class="emoji-item" data-emoji="⚙️">⚙️</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-md-12">
<label for="descripcion" class="form-label">Descripción</label>
<textarea id="descripcion" name="descripcion" class="form-control" rows="2"
placeholder="Descripción breve del template (opcional)" maxlength="255"></textarea>
</div>
</div>
<!-- Configuración Principal -->
<div class="section-header">
<h6 class="mb-0"><i class="fas fa-cog me-2"></i>Configuración Principal</h6>
</div>
<div class="row mb-3">
<div class="col-md-3">
<label for="tipo_moneda" class="form-label">Moneda</label>
<select id="tipo_moneda" name="tipo_moneda" class="form-select searchable">
<option value="">-- Sin especificar --</option>
<option value="MXN">Peso Mexicano (MXN)</option>
<option value="USD">Dólar USD (USD)</option>
<option value="EUR">Euro (EUR)</option>
<option value="CNY">Yuan (CNY)</option>
<option value="GBP">Libra GBP (GBP)</option>
<option value="JPY">Yen (JPY)</option>
</select>
</div>
<div class="col-md-3">
<label for="incoterm" class="form-label">INCOTERM</label>
<select id="incoterm" name="incoterm" class="form-select searchable">
<option value="">-- Sin especificar --</option>
<?php foreach($incoterms as $inc): ?>
<option value="<?= htmlspecialchars($inc['INCOTERM']) ?>">
<?= htmlspecialchars($inc['INCOTERM'].' - '.$inc['DESCESPANOL']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label for="vinculacion" class="form-label">Vinculación</label>
<select id="vinculacion" name="vinculacion" class="form-select">
<option value="">-- Sin especificar --</option>
<option value="0">No existe</option>
<option value="1">Existe, no afecta</option>
<option value="2">Existe y afecta</option>
</select>
</div>
<div class="col-md-3">
<label for="tasa_preferencial" class="form-label">Tasa Preferencial</label>
<select id="tasa_preferencial" name="tasa_preferencial" class="form-select">
<option value="">-- Sin especificar --</option>
<option value="General">General</option>
<option value="TLC">TLC</option>
<option value="PROSEC">PROSEC</option>
<option value="ALADI">ALADI</option>
<option value="COMERCIALIZADORA">COMERCIALIZADORA</option>
</select>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label for="pais_proveedor" class="form-label">País Proveedor</label>
<select id="pais_proveedor" name="pais_proveedor" class="form-select searchable">
<option value="">-- Sin especificar --</option>
<?php foreach($paises as $p): ?>
<option value="<?= htmlspecialchars($p['id_pais']) ?>"><?= htmlspecialchars($p['nombre']) ?></option>
<?php endforeach; ?>
</select>
<input type="hidden" id="pais_proveedor_texto" name="pais_proveedor_texto">
</div>
<div class="col-md-6">
<label for="unidad_comercial_id" class="form-label">Unidad de Medida</label>
<select id="unidad_comercial_id" name="unidad_comercial_id" class="form-select searchable">
<option value="">-- Sin especificar --</option>
<?php foreach($unidades_medida as $um): ?>
<option value="<?= htmlspecialchars($um['id']) ?>"><?= htmlspecialchars($um['descripcion']) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<!-- Configuración Avanzada -->
<div class="section-header">
<h6 class="mb-0"><i class="fas fa-tools me-2"></i>Configuración Avanzada</h6>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label for="anexo22_apendice" class="form-label">Aduana</label>
<select id="anexo22_apendice" name="anexo22_apendice" class="form-select searchable">
<option value="">-- Sin especificar --</option>
<?php foreach($aduanas as $a): ?>
<option value="<?= htmlspecialchars($a['aduana_seccion']) ?>">
<?= htmlspecialchars($a['aduana_seccion'].' '.$a['nombre']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label for="patente" class="form-label">Patente Aduanal</label>
<select id="patente" name="patente" class="form-select searchable">
<option value="">-- Sin especificar --</option>
<?php foreach($patentes as $pt): ?>
<option value="<?= htmlspecialchars($pt['id_agente']) ?>">
<?= htmlspecialchars($pt['patente'].' - '.$pt['agente_aduanal']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<label for="transportista_id" class="form-label">Transportista</label>
<select id="transportista_id" name="transportista_id" class="form-select searchable">
<option value="">-- Sin especificar --</option>
<?php foreach($transportistas as $t): ?>
<option value="<?= htmlspecialchars($t['id_transportista']) ?>">
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label for="chofer_id" class="form-label">Chofer</label>
<select id="chofer_id" name="chofer_id" class="form-select searchable">
<option value="">-- Sin especificar --</option>
<?php foreach($choferes as $c): ?>
<option value="<?= htmlspecialchars($c['id_chofer']) ?>">
<?= htmlspecialchars($c['nombre']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<!-- Botones -->
<div class="text-end">
<button type="submit" class="btn btn-success btn-animated me-2">
<i class="fas fa-save me-1"></i>Guardar Template
</button>
<a href="/IMPORTADORES/templates_rapidos/lista" class="btn btn-secondary btn-animated">
<i class="fas fa-times me-1"></i>Cancelar
</a>
</div>
</form>
</div>
</div>
</div>
<!-- Vista Previa -->
<div class="col-lg-4">
<div class="card sticky-top" style="top: 20px;">
<div class="card-header bg-primary text-white">
<h6 class="mb-0"><i class="fas fa-eye me-2"></i>Vista Previa</h6>
</div>
<div class="card-body">
<div id="template-preview">
<div class="preview-card">
<div class="d-flex align-items-center mb-2">
<span id="preview-icono" class="fs-4 me-2">🏢</span>
<span id="preview-nombre" class="fw-bold">Nuevo Template</span>
</div>
<div id="preview-descripcion" class="small mb-3 opacity-75">
Descripción del template...
</div>
<div id="preview-config" class="d-flex flex-wrap">
<!-- Configuración se mostrará aquí dinámicamente -->
</div>
</div>
</div>
<div class="tips-section">
<h6 class="small text-primary mb-3 fw-bold">💡 Consejos para Templates Efectivos</h6>
<div class="tip-item">
<i class="fas fa-lightbulb text-warning"></i>
<span>Usa nombres descriptivos que identifiquen fácilmente el template</span>
</div>
<div class="tip-item">
<i class="fas fa-flag text-info"></i>
<span>Elige iconos de países o símbolos representativos</span>
</div>
<div class="tip-item">
<i class="fas fa-filter text-success"></i>
<span>Solo llena campos que sean comunes en todas las importaciones</span>
</div>
<div class="tip-item">
<i class="fas fa-clock text-danger"></i>
<span>Deja vacíos los campos que cambien frecuentemente</span>
</div>
<div class="tip-item">
<i class="fas fa-save text-primary"></i>
<span>Los templates te ahorrarán tiempo en futuras importaciones</span>
</div>
</div>
<!-- Botón adicional para resetear -->
<div class="d-grid mt-3">
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="resetForm()">
<i class="fas fa-refresh me-1"></i>Limpiar Formulario
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Variables globales
let choicesInstances = {};
// Inicializar cuando el DOM esté listo
document.addEventListener('DOMContentLoaded', function() {
initializeChoices();
initializeEmojiPicker();
initializePreview();
initializeValidation();
initializeDynamicUpdates();
});
// Inicializar Choices.js para selects con búsqueda
function initializeChoices() {
document.querySelectorAll('.searchable').forEach(element => {
choicesInstances[element.id] = new Choices(element, {
searchEnabled: true,
itemSelectText: '',
shouldSort: false,
searchPlaceholderValue: 'Buscar...',
noResultsText: 'No se encontraron resultados',
noChoicesText: 'No hay opciones disponibles'
});
});
}
// Inicializar selector de emojis
function initializeEmojiPicker() {
// Manejar clicks en emojis
document.addEventListener('click', function(e) {
if (e.target.classList.contains('emoji-item')) {
const emoji = e.target.getAttribute('data-emoji') || e.target.textContent;
selectEmoji(emoji);
// Cerrar dropdown
const dropdown = bootstrap.Dropdown.getInstance(document.querySelector('[data-bs-toggle="dropdown"]'));
if (dropdown) {
dropdown.hide();
}
}
});
// Mostrar emoji seleccionado visualmente
document.addEventListener('mouseenter', function(e) {
if (e.target.classList.contains('emoji-item')) {
// Quitar selección anterior
document.querySelectorAll('.emoji-item.selected').forEach(item => {
item.classList.remove('selected');
});
// Agregar efecto hover mejorado
e.target.style.transform = 'scale(1.2)';
e.target.style.background = 'linear-gradient(135deg, #4CAF50, #45a049)';
e.target.style.color = 'white';
e.target.style.borderRadius = '8px';
}
});
document.addEventListener('mouseleave', function(e) {
if (e.target.classList.contains('emoji-item')) {
e.target.style.transform = '';
e.target.style.background = '';
e.target.style.color = '';
e.target.style.borderRadius = '';
}
});
}
// Función para seleccionar emoji (mejorada)
function selectEmoji(emoji) {
const iconInput = document.getElementById('icono');
const iconDisplay = document.getElementById('icon-display');
// Actualizar valor e interfaz
iconInput.value = emoji;
iconDisplay.textContent = emoji;
// Efecto visual en el display
iconDisplay.style.transform = 'scale(1.3)';
iconDisplay.style.transition = 'transform 0.3s ease';
setTimeout(() => {
iconDisplay.style.transform = 'scale(1)';
}, 300);
updatePreview();
// Mostrar feedback visual
showToast('✅ Icono actualizado', 'success');
}
// Inicializar vista previa
function initializePreview() {
updatePreview();
// Eventos para actualizar vista previa en tiempo real
document.querySelectorAll('#templateForm input, #templateForm select, #templateForm textarea').forEach(element => {
element.addEventListener('input', debounce(updatePreview, 300));
element.addEventListener('change', updatePreview);
});
}
// Función para actualizar vista previa (mejorada)
function updatePreview() {
const nombre = document.getElementById('nombre').value.trim() || 'Nuevo Template';
const descripcion = document.getElementById('descripcion').value.trim() || 'Descripción del template...';
const icono = document.getElementById('icono').value;
// Actualizar elementos de vista previa con animación
const previewNombre = document.getElementById('preview-nombre');
const previewDescripcion = document.getElementById('preview-descripcion');
const previewIcono = document.getElementById('preview-icono');
if (previewNombre.textContent !== nombre) {
previewNombre.style.opacity = '0.5';
setTimeout(() => {
previewNombre.textContent = nombre;
previewNombre.style.opacity = '1';
}, 150);
}
if (previewDescripcion.textContent !== descripcion) {
previewDescripcion.style.opacity = '0.5';
setTimeout(() => {
previewDescripcion.textContent = descripcion;
previewDescripcion.style.opacity = '1';
}, 150);
}
previewIcono.textContent = icono;
// Actualizar configuración con más campos
const config = [];
const fields = [
{ id: 'tipo_moneda', label: '💰 Moneda' },
{ id: 'incoterm', label: '📋 INCOTERM', getValue: (el) => el.value ? el.options[el.selectedIndex].text.split(' - ')[0] : '' },
{ id: 'vinculacion', label: '🔗 Vinculación', map: {'0':'Sin Vinc.', '1':'No Afecta', '2':'Afecta'} },
{ id: 'tasa_preferencial', label: '📊 Tasa' },
{ id: 'pais_proveedor', label: '🌍 País', getValue: (el) => el.value ? el.options[el.selectedIndex].text : '' },
{ id: 'anexo22_apendice', label: '🏢 Aduana', getValue: (el) => el.value ? el.options[el.selectedIndex].text.split(' ')[0] : '' },
{ id: 'transportista_id', label: '🚛 Transportista', getValue: (el) => el.value ? el.options[el.selectedIndex].text.split(' - ')[0] : '' }
];
fields.forEach(field => {
const element = document.getElementById(field.id);
let value = '';
if (field.getValue) {
value = field.getValue(element);
} else {
value = element.value;
}
if (value) {
const displayValue = field.map && field.map[value] ? field.map[value] : value;
config.push(`<span class="template-preview-item">${field.label}: ${displayValue}</span>`);
}
});
const configContainer = document.getElementById('preview-config');
configContainer.style.opacity = '0.5';
setTimeout(() => {
configContainer.innerHTML = config.join('');
configContainer.style.opacity = '1';
}, 150);
}
// Inicializar actualizaciones dinámicas
function initializeDynamicUpdates() {
// Actualizar texto del país cuando cambie
const paisSelect = document.getElementById('pais_proveedor');
if (paisSelect && choicesInstances[paisSelect.id]) {
paisSelect.addEventListener('change', function() {
const selectedOption = this.options[this.selectedIndex];
document.getElementById('pais_proveedor_texto').value = selectedOption ? selectedOption.text : '';
updatePreview();
});
}
// Filtrar choferes según transportista seleccionado
const transportistaSelect = document.getElementById('transportista_id');
const choferSelect = document.getElementById('chofer_id');
if (transportistaSelect && choferSelect) {
transportistaSelect.addEventListener('change', function() {
const transportistaId = this.value;
const choferChoices = choicesInstances[choferSelect.id];
if (choferChoices) {
// Aquí podrías hacer una llamada AJAX para filtrar choferes
// Por ahora simplemente reseteamos la selección
choferChoices.setChoiceByValue('');
}
});
}
}
// Inicializar validación del formulario
function initializeValidation() {
const form = document.getElementById('templateForm');
form.addEventListener('submit', function(e) {
if (!validateForm()) {
e.preventDefault();
return false;
}
// Mostrar loading mejorado
Swal.fire({
title: 'Guardando template...',
html: '<div class="loading-spinner"></div><br>Por favor espera...',
allowOutsideClick: false,
allowEscapeKey: false,
showConfirmButton: false,
customClass: {
popup: 'swal2-noanimation'
}
});
});
// Validación en tiempo real del nombre
const nombreInput = document.getElementById('nombre');
nombreInput.addEventListener('input', function() {
validateField(this);
});
}
// Función de validación del formulario
function validateForm() {
const nombre = document.getElementById('nombre').value.trim();
if (!nombre) {
showErrorAlert('Campo requerido', 'El nombre del template es obligatorio');
document.getElementById('nombre').focus();
return false;
}
if (nombre.length > 100) {
showErrorAlert('Nombre muy largo', 'El nombre no puede exceder 100 caracteres');
document.getElementById('nombre').focus();
return false;
}
return true;
}
// Validar campo individual
function validateField(field) {
const value = field.value.trim();
if (field.id === 'nombre') {
if (value.length > 100) {
field.classList.add('is-invalid');
field.classList.remove('is-valid');
} else if (value.length > 0) {
field.classList.add('is-valid');
field.classList.remove('is-invalid');
} else {
field.classList.remove('is-valid', 'is-invalid');
}
}
}
// Funciones de utilidad
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
function showErrorAlert(title, text) {
Swal.fire({
icon: 'error',
title: title,
text: text,
confirmButtonColor: '#dc3545',
confirmButtonText: 'Entendido'
});
}
function showToast(message, type = 'info') {
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 2000,
timerProgressBar: true
});
Toast.fire({
icon: type,
title: message
});
}
// Función para resetear el formulario
function resetForm() {
document.getElementById('templateForm').reset();
// Resetear Choices.js
Object.values(choicesInstances).forEach(choice => {
choice.setChoiceByValue('');
});
// Resetear icono
document.getElementById('icono').value = '🏢';
document.getElementById('icon-display').textContent = '🏢';
updatePreview();
showToast('Formulario reiniciado', 'info');
}
</script>
</body>
</html>