Spaces:
Sleeping
Sleeping
| /** | |
| * Capture Form Component | |
| * Data entry form for capture details | |
| */ | |
| const CaptureFormComponent = { | |
| captureData: null, | |
| location: null, | |
| placeName: null, | |
| render() { | |
| const selectedSpecies = app.state.selectedSpecies || []; | |
| return ` | |
| <div class="nav"> | |
| <button class="nav-back" onclick="app.navigate('species-selector')">←</button> | |
| <h1>Detalles de Captura</h1> | |
| </div> | |
| <div class="content"> | |
| <div class="content"> | |
| <!-- Ubicación procesada en segundo plano --> | |
| <form id="capture-form" onsubmit="CaptureFormComponent.submit(event)"> | |
| <!-- Datos Simplificados --> | |
| <div class="card"> | |
| <h3>👤 Datos de Contacto</h3> | |
| <div class="form-group"> | |
| <label for="port">Puerto / Desembarcadero</label> | |
| <input type="text" id="port" name="port" placeholder="Ej: Las Terrenas, Bayahibe..." required> | |
| </div> | |
| <div class="form-group"> | |
| <label for="phone">Teléfono de Contacto</label> | |
| <input type="tel" id="phone" name="phone" placeholder="809-000-0000"> | |
| </div> | |
| <p style="font-size: 0.85rem; color: #666; margin-top: 10px;"> | |
| 🔒 Tus datos personales serán anonimizados. | |
| <a href="#" onclick="event.preventDefault(); app.navigate('info')" style="color: var(--primary-color); font-weight: 600;">Más información</a> | |
| </p> | |
| </div> | |
| <!-- Detalles de Captura por Especie --> | |
| <h3>🐟 Captura Específica</h3> | |
| ${selectedSpecies.map((speciesId, index) => { | |
| const speciesInfo = SpeciesSelectorComponent.allSpecies.find(s => s.id === speciesId) || {}; | |
| return ` | |
| <div class="card"> | |
| ${speciesId === 'otro' ? ` | |
| <div class="form-group"> | |
| <label for="custom-name-${index}">Nombre de la Especie</label> | |
| <input | |
| type="text" | |
| id="custom-name-${index}" | |
| placeholder="Ej: Pez León, Pulpo, etc." | |
| required | |
| > | |
| </div> | |
| ` : ` | |
| <h3>${speciesInfo.commonName || speciesId}</h3> | |
| `} | |
| <div class="form-group"> | |
| <label for="quantity-${index}">Cantidad</label> | |
| <input | |
| type="number" | |
| id="quantity-${index}" | |
| name="quantity-${index}" | |
| min="0.1" | |
| step="0.1" | |
| required | |
| > | |
| </div> | |
| <div class="form-group"> | |
| <label for="unit-${index}">Unidad</label> | |
| <select id="unit-${index}" name="unit-${index}" required> | |
| <option value="lbs">Libras (lbs)</option> | |
| <option value="units">Unidades</option> | |
| </select> | |
| </div> | |
| </div> | |
| `}).join('')} | |
| <div class="card"> | |
| <h3>📉 Otros Detalles</h3> | |
| <div class="form-group"> | |
| <label for="fishing-method">Método de Pesca (General)</label> | |
| <select id="fishing-method" name="fishing-method" required> | |
| <option value="">Seleccionar...</option> | |
| <option value="Línea de mano">Línea de mano</option> | |
| <option value="Nasa">Nasa</option> | |
| <option value="Red de enmalle">Red de enmalle</option> | |
| <option value="Palangre">Palangre</option> | |
| <option value="Buceo">Buceo</option> | |
| <option value="Otro">Otro</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="depth">Profundidad (Brazadas)</label> | |
| <input | |
| type="number" | |
| id="depth" | |
| name="depth" | |
| min="0" | |
| step="1" | |
| required | |
| > | |
| </div> | |
| </div> | |
| <button type="submit" class="btn-primary btn-full"> | |
| Guardar Registro de Pesca | |
| </button> | |
| </form> | |
| </div> | |
| `; | |
| }, | |
| async init() { | |
| console.log('Capturando ubicación en segundo plano...'); | |
| try { | |
| this.location = await geolocationService.getCurrentPosition(); | |
| console.log('Ubicación obtenida con éxito (silenciosa)'); | |
| } catch (error) { | |
| console.warn('Error capturando ubicación inicial:', error); | |
| } | |
| }, | |
| getSpeciesName(speciesId) { | |
| const species = SpeciesSelectorComponent.allSpecies.find(s => s.id === speciesId); | |
| return species ? species.commonName : speciesId; | |
| }, | |
| async submit(event) { | |
| event.preventDefault(); | |
| // Refresco silencioso de GPS al enviar | |
| try { | |
| this.location = await geolocationService.getCurrentPosition(); | |
| } catch (e) { | |
| console.warn('Refresh GPS falló, usando último valor conocido:', e); | |
| } | |
| if (!this.location) { | |
| alert('Asegúrate de permitir el acceso al GPS para continuar. Es necesario para el registro científico.'); | |
| return; | |
| } | |
| const selectedSpecies = app.state.selectedSpecies || []; | |
| const items = []; | |
| // Collect data for each species | |
| selectedSpecies.forEach((speciesId, index) => { | |
| const speciesInfo = SpeciesSelectorComponent.allSpecies.find(s => s.id === speciesId) || {}; | |
| const quantity = parseFloat(document.getElementById(`quantity-${index}`).value); | |
| const unit = document.getElementById(`unit-${index}`).value; | |
| const customNameInput = document.getElementById(`custom-name-${index}`); | |
| const customName = customNameInput ? customNameInput.value : null; | |
| items.push({ | |
| speciesId: speciesId, | |
| commonName: speciesId === 'otro' ? customName : speciesInfo.commonName, | |
| category: speciesInfo.category || 'Otros', | |
| quantity: quantity, | |
| unit: unit, | |
| customName: customName | |
| }); | |
| }); | |
| // Create capture object | |
| const capture = { | |
| id: this.generateUUID(), | |
| timestamp: new Date().toISOString(), | |
| latitude: this.location.latitude, | |
| longitude: this.location.longitude, | |
| placeName: this.placeName, | |
| species: selectedSpecies, | |
| items: items, | |
| fishingMethod: document.getElementById('fishing-method').value, | |
| depth: parseFloat(document.getElementById('depth').value), | |
| // Simplified fields | |
| port: document.getElementById('port').value, | |
| phone: document.getElementById('phone').value, | |
| totalWeight: items.reduce((sum, item) => sum + (item.unit === 'lbs' ? item.quantity : 0), 0), | |
| captureSource: 'device-gps', | |
| synced: 0 | |
| }; | |
| // Save to IndexedDB | |
| try { | |
| await dbService.addCapture(capture); | |
| // Store in app state for confirmation | |
| app.state.lastCapture = capture; | |
| // Navigate to confirmation | |
| app.navigate('confirmation'); | |
| // Trigger sync if online | |
| if (navigator.onLine) { | |
| syncService.syncNow(); | |
| } | |
| } catch (error) { | |
| console.error('Error saving capture:', error); | |
| alert('Error al guardar la captura. Por favor, intenta de nuevo.'); | |
| } | |
| }, | |
| generateUUID() { | |
| return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { | |
| const r = Math.random() * 16 | 0; | |
| const v = c === 'x' ? r : (r & 0x3 | 0x8); | |
| return v.toString(16); | |
| }); | |
| } | |
| }; | |