dawarich/app/javascript/controllers/area_creation_v2_controller.js
Evgenii Burmakin 8934c29fce
0.36.2 (#2007)
* fix: move foreman to global gems to fix startup crash (#1971)

* Update exporting code to stream points data to file in batches to red… (#1980)

* Update exporting code to stream points data to file in batches to reduce memory usage

* Update changelog

* Update changelog

* Feature/maplibre frontend (#1953)

* Add a plan to use MapLibre GL JS for the frontend map rendering, replacing Leaflet

* Implement phase 1

* Phases 1-3 + part of 4

* Fix e2e tests

* Phase 6

* Implement fog of war

* Phase 7

* Next step: fix specs, phase 7 done

* Use our own map tiles

* Extract v2 map logic to separate manager classes

* Update settings panel on v2 map

* Update v2 e2e tests structure

* Reimplement location search in maps v2

* Update speed routes

* Implement visits and places creation in v2

* Fix last failing test

* Implement visits merging

* Fix a routes e2e test and simplify the routes layer styling.

* Extract js to modules from maps_v2_controller.js

* Implement area creation

* Fix spec problem

* Fix some e2e tests

* Implement live mode in v2 map

* Update icons and panel

* Extract some styles

* Remove unused file

* Start adding dark theme to popups on MapLibre maps

* Make popups respect dark theme

* Move v2 maps to maplibre namespace

* Update v2 references to maplibre

* Put place, area and visit info into side panel

* Update API to use safe settings config method

* Fix specs

* Fix method name to config in SafeSettings and update usages accordingly

* Add missing public files

* Add handling for real time points

* Fix remembering enabled/disabled layers of the v2 map

* Fix lots of e2e tests

* Add settings to select map version

* Use maps/v2 as main path for MapLibre maps

* Update routing

* Update live mode

* Update maplibre controller

* Update changelog

* Remove some console.log statements

---------

Co-authored-by: Robin Tuszik <mail@robin.gg>
2025-12-06 20:54:49 +01:00

161 lines
3.5 KiB
JavaScript

import { Controller } from '@hotwired/stimulus'
/**
* Area creation controller
* Handles the area creation modal and form submission
*/
export default class extends Controller {
static targets = [
'modal',
'form',
'nameInput',
'latitudeInput',
'longitudeInput',
'radiusInput',
'radiusDisplay',
'submitButton',
'submitSpinner',
'submitText'
]
static values = {
apiKey: String
}
connect() {
this.area = null
this.setupEventListeners()
console.log('[Area Creation V2] Controller connected')
}
/**
* Setup event listeners for area drawing
*/
setupEventListeners() {
document.addEventListener('area:drawn', (e) => {
this.open(e.detail.center, e.detail.radius)
})
}
/**
* Open the modal with area data
*/
open(center, radius) {
// Store area data
this.area = { center, radius }
// Update form fields
this.latitudeInputTarget.value = center[1]
this.longitudeInputTarget.value = center[0]
this.radiusInputTarget.value = Math.round(radius)
this.radiusDisplayTarget.textContent = Math.round(radius)
// Show modal
this.modalTarget.classList.add('modal-open')
this.nameInputTarget.focus()
}
/**
* Close the modal
*/
close() {
this.modalTarget.classList.remove('modal-open')
this.resetForm()
}
/**
* Submit the form
*/
async submit(event) {
event.preventDefault()
if (!this.area) {
console.error('No area data available')
return
}
const formData = new FormData(this.formTarget)
const name = formData.get('name')
const latitude = parseFloat(formData.get('latitude'))
const longitude = parseFloat(formData.get('longitude'))
const radius = parseFloat(formData.get('radius'))
if (!name || !latitude || !longitude || !radius) {
alert('Please fill in all required fields')
return
}
this.setLoading(true)
try {
const response = await fetch('/api/v1/areas', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKeyValue}`
},
body: JSON.stringify({
name,
latitude,
longitude,
radius
})
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.message || 'Failed to create area')
}
const area = await response.json()
// Close modal
this.close()
// Dispatch document event for area created
document.dispatchEvent(new CustomEvent('area:created', {
detail: { area }
}))
} catch (error) {
console.error('Error creating area:', error)
alert(`Error creating area: ${error.message}`)
} finally {
this.setLoading(false)
}
}
/**
* Set loading state
*/
setLoading(loading) {
this.submitButtonTarget.disabled = loading
if (loading) {
this.submitSpinnerTarget.classList.remove('hidden')
this.submitTextTarget.textContent = 'Creating...'
} else {
this.submitSpinnerTarget.classList.add('hidden')
this.submitTextTarget.textContent = 'Create Area'
}
}
/**
* Reset form
*/
resetForm() {
this.formTarget.reset()
this.area = null
this.radiusDisplayTarget.textContent = '0'
}
/**
* Show success message
*/
showSuccess(message) {
// Try to use the Toast component if available
if (window.Toast) {
window.Toast.show(message, 'success')
}
}
}