feat: integrar campos WhatsForm en formulario de visa
Reemplaza los 4 campos básicos del formulario de visa con 40+ campos del DS-160 organizados en 7 secciones (datos personales, patrocinador, historial migratorio, dirección, datos familiares, empleo, estudios). Agrega soporte para tipos heading (divisor de sección) y radio buttons. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1104,6 +1104,39 @@ select.form-control {
|
|||||||
padding-right: 2.5rem;
|
padding-right: 2.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-heading {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-accent);
|
||||||
|
margin-top: var(--space-lg);
|
||||||
|
margin-bottom: var(--space-md);
|
||||||
|
padding-bottom: var(--space-xs);
|
||||||
|
border-bottom: 1px solid rgba(192, 192, 192, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-radio-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--space-sm) var(--space-md);
|
||||||
|
padding-top: var(--space-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-radio-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
color: var(--color-gray-700);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-radio-label input[type="radio"] {
|
||||||
|
accent-color: var(--color-accent);
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.form-error {
|
.form-error {
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-xs);
|
||||||
color: var(--color-danger);
|
color: var(--color-danger);
|
||||||
|
|||||||
@@ -30,8 +30,9 @@ if (!$nombre || !$telefono || !isset($SERVICIOS[$servicio])) {
|
|||||||
// Collect service-specific fields
|
// Collect service-specific fields
|
||||||
$datosExtra = [];
|
$datosExtra = [];
|
||||||
foreach ($SERVICIOS[$servicio]['campos_formulario'] as $campo) {
|
foreach ($SERVICIOS[$servicio]['campos_formulario'] as $campo) {
|
||||||
|
if (empty($campo['name'])) continue; // Skip headings
|
||||||
$val = trim($_POST[$campo['name']] ?? '');
|
$val = trim($_POST[$campo['name']] ?? '');
|
||||||
if ($campo['required'] && !$val) {
|
if (!empty($campo['required']) && !$val) {
|
||||||
die('Por favor llene el campo: ' . htmlspecialchars($campo['label']));
|
die('Por favor llene el campo: ' . htmlspecialchars($campo['label']));
|
||||||
}
|
}
|
||||||
$datosExtra[$campo['label']] = $val;
|
$datosExtra[$campo['label']] = $val;
|
||||||
|
|||||||
@@ -20,9 +20,69 @@ $SERVICIOS = [
|
|||||||
'Acompañamiento el día de la cita',
|
'Acompañamiento el día de la cita',
|
||||||
],
|
],
|
||||||
'campos_formulario' => [
|
'campos_formulario' => [
|
||||||
|
// Tipo de trámite
|
||||||
['name' => 'tipo_visa', 'label' => 'Tipo de visa', 'type' => 'select', 'options' => ['Turista (B1/B2)', 'Estudiante (F1)', 'Trabajo (H1B)', 'Otro'], 'required' => true],
|
['name' => 'tipo_visa', 'label' => 'Tipo de visa', 'type' => 'select', 'options' => ['Turista (B1/B2)', 'Estudiante (F1)', 'Trabajo (H1B)', 'Otro'], 'required' => true],
|
||||||
['name' => 'primera_vez', 'label' => '¿Es primera vez o renovación?', 'type' => 'select', 'options' => ['Primera vez', 'Renovación'], 'required' => true],
|
['name' => 'primera_vez', 'label' => '¿Es primera vez o renovación?', 'type' => 'select', 'options' => ['Primera vez', 'Renovación'], 'required' => true],
|
||||||
['name' => 'pasaporte_vigente', 'label' => '¿Tiene pasaporte vigente?', 'type' => 'select', 'options' => ['Sí', 'No'], 'required' => true],
|
['name' => 'pasaporte_vigente', 'label' => '¿Tiene pasaporte vigente?', 'type' => 'select', 'options' => ['Sí', 'No'], 'required' => true],
|
||||||
|
|
||||||
|
// Datos personales
|
||||||
|
['type' => 'heading', 'label' => 'Datos personales'],
|
||||||
|
['name' => 'fecha_nacimiento', 'label' => 'Fecha de nacimiento', 'type' => 'date', 'required' => true],
|
||||||
|
['name' => 'lugar_nacimiento', 'label' => 'Lugar de nacimiento', 'type' => 'text', 'required' => true],
|
||||||
|
['name' => 'curp', 'label' => 'CURP', 'type' => 'text', 'required' => true],
|
||||||
|
['name' => 'estado_civil', 'label' => 'Estado civil', 'type' => 'radio', 'options' => ['Casado', 'Soltero', 'Viudo', 'Unión libre'], 'required' => false],
|
||||||
|
['name' => 'nombre_pareja', 'label' => 'Nombre completo de la pareja', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'lugar_fecha_nacimiento_pareja', 'label' => 'Lugar y fecha de nacimiento de la pareja', 'type' => 'text', 'required' => false],
|
||||||
|
|
||||||
|
// Patrocinador del viaje
|
||||||
|
['type' => 'heading', 'label' => 'Patrocinador del viaje'],
|
||||||
|
['name' => 'quien_paga_viaje', 'label' => '¿Quién paga el viaje?', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'nombre_patrocinador', 'label' => 'Nombre del patrocinador', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'parentesco_patrocinador', 'label' => 'Parentesco con el patrocinador', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'telefono_patrocinador', 'label' => 'Teléfono del patrocinador', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'email_patrocinador', 'label' => 'Email del patrocinador', 'type' => 'text', 'required' => false],
|
||||||
|
|
||||||
|
// Historial migratorio
|
||||||
|
['type' => 'heading', 'label' => 'Historial migratorio'],
|
||||||
|
['name' => 'ultimos_cruces', 'label' => 'Liste sus últimos 5 cruces a EE.UU. (fechas y motivo)', 'type' => 'textarea', 'required' => false],
|
||||||
|
['name' => 'visa_perdida_robada', 'label' => '¿Ha perdido o le han robado una visa?', 'type' => 'select', 'options' => ['Sí', 'No'], 'required' => false],
|
||||||
|
['name' => 'anio_perdida', 'label' => 'Año de la pérdida/robo', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'como_fue_perdida', 'label' => '¿Cómo fue la pérdida/robo?', 'type' => 'textarea', 'required' => false],
|
||||||
|
['name' => 'visa_negada', 'label' => '¿Le han negado una visa anteriormente?', 'type' => 'select', 'options' => ['Sí', 'No'], 'required' => false],
|
||||||
|
['name' => 'peticion_migracion', 'label' => '¿Tiene alguna petición de migración en proceso?', 'type' => 'select', 'options' => ['Sí', 'No'], 'required' => false],
|
||||||
|
|
||||||
|
// Dirección personal
|
||||||
|
['type' => 'heading', 'label' => 'Dirección personal'],
|
||||||
|
['name' => 'direccion', 'label' => 'Dirección completa', 'type' => 'text', 'required' => true],
|
||||||
|
|
||||||
|
// Datos familiares
|
||||||
|
['type' => 'heading', 'label' => 'Datos familiares'],
|
||||||
|
['name' => 'nombre_padre', 'label' => 'Nombre completo del padre', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'fecha_nacimiento_padre', 'label' => 'Fecha de nacimiento del padre', 'type' => 'date', 'required' => false],
|
||||||
|
['name' => 'nombre_madre', 'label' => 'Nombre completo de la madre', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'fecha_nacimiento_madre', 'label' => 'Fecha de nacimiento de la madre', 'type' => 'date', 'required' => false],
|
||||||
|
['name' => 'familiares_eeuu', 'label' => '¿Tiene familiares en EE.UU.?', 'type' => 'select', 'options' => ['Sí', 'No'], 'required' => false],
|
||||||
|
['name' => 'relacion_familiar', 'label' => 'Relación con el familiar', 'type' => 'select', 'options' => ['Padres', 'Hijos', 'Hermanos', 'Pareja'], 'required' => false],
|
||||||
|
['name' => 'status_migratorio_familiar', 'label' => 'Status migratorio del familiar', 'type' => 'select', 'options' => ['Residente legal', 'Ciudadano'], 'required' => false],
|
||||||
|
|
||||||
|
// Empleo (últimos 5 años)
|
||||||
|
['type' => 'heading', 'label' => 'Empleo (últimos 5 años)'],
|
||||||
|
['name' => 'nombre_empresa', 'label' => 'Nombre de la empresa', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'direccion_empresa', 'label' => 'Dirección de la empresa', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'telefono_empresa', 'label' => 'Teléfono de la empresa', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'puesto', 'label' => 'Puesto', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'fechas_trabajo', 'label' => 'Fechas de trabajo (inicio - fin)', 'type' => 'text', 'required' => false],
|
||||||
|
|
||||||
|
// Estudios
|
||||||
|
['type' => 'heading', 'label' => 'Estudios'],
|
||||||
|
['name' => 'nivel_estudios', 'label' => 'Nivel de estudios', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'nombre_escuela', 'label' => 'Nombre de la escuela', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'direccion_escuela', 'label' => 'Dirección de la escuela', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'telefono_escuela', 'label' => 'Teléfono de la escuela', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'curso_estudios', 'label' => 'Curso o carrera', 'type' => 'text', 'required' => false],
|
||||||
|
['name' => 'fechas_estudios', 'label' => 'Fechas de estudio (inicio - fin)', 'type' => 'text', 'required' => false],
|
||||||
|
|
||||||
|
// Final
|
||||||
['name' => 'comentarios', 'label' => 'Comentarios adicionales', 'type' => 'textarea', 'required' => false],
|
['name' => 'comentarios', 'label' => 'Comentarios adicionales', 'type' => 'textarea', 'required' => false],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
23
servicio.php
23
servicio.php
@@ -80,26 +80,39 @@ require_once __DIR__ . '/includes/header.php';
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php foreach ($servicio['campos_formulario'] as $campo): ?>
|
<?php foreach ($servicio['campos_formulario'] as $campo): ?>
|
||||||
|
<?php if ($campo['type'] === 'heading'): ?>
|
||||||
|
<h3 class="form-heading"><?= htmlspecialchars($campo['label']) ?></h3>
|
||||||
|
<?php else: ?>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="<?= htmlspecialchars($campo['name']) ?>">
|
<label for="<?= htmlspecialchars($campo['name']) ?>">
|
||||||
<?= htmlspecialchars($campo['label']) ?>
|
<?= htmlspecialchars($campo['label']) ?>
|
||||||
<?= $campo['required'] ? ' *' : '' ?>
|
<?= !empty($campo['required']) ? ' *' : '' ?>
|
||||||
</label>
|
</label>
|
||||||
<?php if ($campo['type'] === 'select'): ?>
|
<?php if ($campo['type'] === 'select'): ?>
|
||||||
<select id="<?= htmlspecialchars($campo['name']) ?>" name="<?= htmlspecialchars($campo['name']) ?>" class="form-control" <?= $campo['required'] ? 'required' : '' ?>>
|
<select id="<?= htmlspecialchars($campo['name']) ?>" name="<?= htmlspecialchars($campo['name']) ?>" class="form-control" <?= !empty($campo['required']) ? 'required' : '' ?>>
|
||||||
<option value="">Seleccione...</option>
|
<option value="">Seleccione...</option>
|
||||||
<?php foreach ($campo['options'] as $opt): ?>
|
<?php foreach ($campo['options'] as $opt): ?>
|
||||||
<option value="<?= htmlspecialchars($opt) ?>"><?= htmlspecialchars($opt) ?></option>
|
<option value="<?= htmlspecialchars($opt) ?>"><?= htmlspecialchars($opt) ?></option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
<?php elseif ($campo['type'] === 'radio'): ?>
|
||||||
|
<div class="form-radio-group">
|
||||||
|
<?php foreach ($campo['options'] as $opt): ?>
|
||||||
|
<label class="form-radio-label">
|
||||||
|
<input type="radio" name="<?= htmlspecialchars($campo['name']) ?>" value="<?= htmlspecialchars($opt) ?>" <?= !empty($campo['required']) ? 'required' : '' ?>>
|
||||||
|
<?= htmlspecialchars($opt) ?>
|
||||||
|
</label>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
<?php elseif ($campo['type'] === 'textarea'): ?>
|
<?php elseif ($campo['type'] === 'textarea'): ?>
|
||||||
<textarea id="<?= htmlspecialchars($campo['name']) ?>" name="<?= htmlspecialchars($campo['name']) ?>" class="form-control" rows="4" <?= $campo['required'] ? 'required' : '' ?> placeholder="Escribe aqui..."></textarea>
|
<textarea id="<?= htmlspecialchars($campo['name']) ?>" name="<?= htmlspecialchars($campo['name']) ?>" class="form-control" rows="4" <?= !empty($campo['required']) ? 'required' : '' ?> placeholder="Escribe aqui..."></textarea>
|
||||||
<?php elseif ($campo['type'] === 'date'): ?>
|
<?php elseif ($campo['type'] === 'date'): ?>
|
||||||
<input type="date" id="<?= htmlspecialchars($campo['name']) ?>" name="<?= htmlspecialchars($campo['name']) ?>" class="form-control" <?= $campo['required'] ? 'required' : '' ?>>
|
<input type="date" id="<?= htmlspecialchars($campo['name']) ?>" name="<?= htmlspecialchars($campo['name']) ?>" class="form-control" <?= !empty($campo['required']) ? 'required' : '' ?>>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<input type="text" id="<?= htmlspecialchars($campo['name']) ?>" name="<?= htmlspecialchars($campo['name']) ?>" class="form-control" <?= $campo['required'] ? 'required' : '' ?>>
|
<input type="text" id="<?= htmlspecialchars($campo['name']) ?>" name="<?= htmlspecialchars($campo['name']) ?>" class="form-control" <?= !empty($campo['required']) ? 'required' : '' ?>>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<button type="submit" class="btn btn--primary btn--block">
|
<button type="submit" class="btn btn--primary btn--block">
|
||||||
|
|||||||
Reference in New Issue
Block a user