feat: Implement the promoter event creation
Some checks failed
Ruby on Rails Test / rails-test (push) Failing after 1m50s

- Promoter can now create an event in draft mode
- Place is found based on address and long/lat are automatically
  deducted from it
- Slug is forged using the *slug* npm package instead of custom code
This commit is contained in:
kbe
2025-09-10 20:46:31 +02:00
parent 332827c6da
commit 10c93fff2f
19 changed files with 552 additions and 1661 deletions

View File

@@ -1,17 +1,18 @@
import { Controller } from "@hotwired/stimulus"
import slug from 'slug'
export default class extends Controller {
static targets = ["name", "slug", "latitude", "longitude", "address", "mapLinksContainer"]
static values = {
static values = {
geocodeDelay: { type: Number, default: 1500 } // Delay before auto-geocoding
}
connect() {
this.geocodeTimeout = null
// Initialize map links if we have an address and coordinates already exist
if (this.hasAddressTarget && this.addressTarget.value.trim() &&
this.hasLatitudeTarget && this.hasLongitudeTarget &&
if (this.hasAddressTarget && this.addressTarget.value.trim() &&
this.hasLatitudeTarget && this.hasLongitudeTarget &&
this.latitudeTarget.value && this.longitudeTarget.value) {
this.updateMapLinks()
}
@@ -26,14 +27,8 @@ export default class extends Controller {
// Generate slug from name
generateSlug() {
const name = this.nameTarget.value
const slug = name
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '') // Remove special characters
.replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/-+/g, '-') // Replace multiple hyphens with single
.replace(/^-|-$/g, '') // Remove leading/trailing hyphens
this.slugTarget.value = slug
this.slugTarget.value = slug(name)
}
// Handle address changes with debounced geocoding
@@ -44,7 +39,7 @@ export default class extends Controller {
}
const address = this.addressTarget.value.trim()
if (!address) {
this.clearCoordinates()
this.clearMapLinks()
@@ -76,27 +71,27 @@ export default class extends Controller {
const position = await this.getCurrentPositionPromise(options)
const lat = position.coords.latitude
const lng = position.coords.longitude
// Set coordinates first
this.latitudeTarget.value = lat.toFixed(6)
this.longitudeTarget.value = lng.toFixed(6)
// Then reverse geocode to get address
const address = await this.reverseGeocode(lat, lng)
if (address) {
this.addressTarget.value = address
this.showLocationSuccess("Position actuelle détectée et adresse mise à jour!")
} else {
this.showLocationSuccess("Position actuelle détectée!")
}
this.updateMapLinks()
} catch (error) {
this.hideLocationLoading()
let message = "Erreur lors de la récupération de la localisation."
switch(error.code) {
case error.PERMISSION_DENIED:
message = "L'accès à la localisation a été refusé."
@@ -108,7 +103,7 @@ export default class extends Controller {
message = "La demande de localisation a expiré."
break
}
this.showLocationError(message)
}
}
@@ -125,11 +120,11 @@ export default class extends Controller {
try {
const response = await fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json`)
const data = await response.json()
if (data && data.display_name) {
return data.display_name
}
return null
} catch (error) {
console.log("Reverse geocoding failed:", error)
@@ -145,7 +140,7 @@ export default class extends Controller {
}
// If we already have coordinates, just update map links
if (this.hasLatitudeTarget && this.hasLongitudeTarget &&
if (this.hasLatitudeTarget && this.hasLongitudeTarget &&
this.latitudeTarget.value && this.longitudeTarget.value) {
this.updateMapLinks()
this.showLocationSuccess("Liens de carte mis à jour!")
@@ -163,11 +158,11 @@ export default class extends Controller {
}
const address = this.addressTarget.value.trim()
try {
this.showLocationLoading()
const result = await this.performGeocode(address)
if (result) {
this.latitudeTarget.value = result.lat
this.longitudeTarget.value = result.lng
@@ -187,7 +182,7 @@ export default class extends Controller {
async geocodeAddressQuiet(address) {
try {
const result = await this.performGeocode(address)
if (result) {
this.latitudeTarget.value = result.lat
this.longitudeTarget.value = result.lng
@@ -207,7 +202,7 @@ export default class extends Controller {
const encodedAddress = encodeURIComponent(address)
const response = await fetch(`https://nominatim.openstreetmap.org/search?q=${encodedAddress}&format=json&limit=1`)
const data = await response.json()
if (data && data.length > 0) {
const result = data[0]
return {
@@ -215,7 +210,7 @@ export default class extends Controller {
lng: parseFloat(result.lon).toFixed(6)
}
}
return null
}
@@ -226,7 +221,7 @@ export default class extends Controller {
const lat = parseFloat(this.latitudeTarget.value)
const lng = parseFloat(this.longitudeTarget.value)
const address = this.hasAddressTarget ? this.addressTarget.value.trim() : ""
if (isNaN(lat) || isNaN(lng) || !address) {
this.clearMapLinks()
return
@@ -239,7 +234,7 @@ export default class extends Controller {
// Generate map links HTML
generateMapLinks(lat, lng, address) {
const encodedAddress = encodeURIComponent(address)
const providers = {
openstreetmap: {
name: "OpenStreetMap",
@@ -247,7 +242,7 @@ export default class extends Controller {
icon: "🗺️"
},
google: {
name: "Google Maps",
name: "Google Maps",
url: `https://www.google.com/maps/search/${encodedAddress}/@${lat},${lng},16z`,
icon: "🔍"
},
@@ -266,7 +261,7 @@ export default class extends Controller {
</div>
<div class="flex flex-wrap gap-2">
${Object.entries(providers).map(([key, provider]) => `
<a href="${provider.url}" target="_blank" rel="noopener"
<a href="${provider.url}" target="_blank" rel="noopener"
class="inline-flex items-center px-3 py-2 text-xs font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">
<span class="mr-2">${provider.icon}</span>
${provider.name}
@@ -327,7 +322,7 @@ export default class extends Controller {
showMessage(id, message, type) {
const colors = {
info: "bg-blue-50 border-blue-200 text-blue-800",
success: "bg-green-50 border-green-200 text-green-800",
success: "bg-green-50 border-green-200 text-green-800",
error: "bg-red-50 border-red-200 text-red-800",
warning: "bg-yellow-50 border-yellow-200 text-yellow-800"
}
@@ -372,4 +367,4 @@ export default class extends Controller {
this.hideMessage("location-error")
this.hideMessage("geocoding-warning")
}
}
}