Files
MVE/views/templates_rapidos/crear.php
2025-10-21 11:41:30 -06:00

790 lines
31 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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>