prop/assets/js/locate_me_hook.ts
Graham McIntire 1f368f9b61 Convert all JavaScript to TypeScript with type annotations
- Rename all .js files to .ts in assets/js/
- Add interfaces for hook state, data structures, and event payloads
- Add type annotations to function parameters and return types
- Create type declarations for vendor deps (Leaflet, Chart.js, Phoenix, topbar)
- Update tsconfig.json for strict TypeScript checking
- Update esbuild entry point to app.ts
2026-04-11 16:59:28 -05:00

74 lines
2.1 KiB
TypeScript

interface CopyLinkHook extends ViewHook {
el: HTMLElement
}
export const CopyLink = {
mounted(this: CopyLinkHook): void {
this.el.addEventListener("click", () => {
navigator.clipboard.writeText(window.location.href).then(() => {
const orig = this.el.innerHTML
this.el.innerHTML = '<span class="text-success">Copied!</span>'
setTimeout(() => { this.el.innerHTML = orig }, 1500)
})
})
}
}
interface LocateMeHook extends ViewHook {
el: HTMLElement
watchId: number | null
lastSentAt: number
startWatching(): void
}
export const LocateMe = {
mounted(this: LocateMeHook): void {
this.watchId = null
this.lastSentAt = 0
this.el.addEventListener("click", () => this.startWatching())
// Also respond to server-pushed request (for source=gps URLs)
this.handleEvent("request_gps", () => this.startWatching())
},
destroyed(this: LocateMeHook): void {
if (this.watchId !== null) {
navigator.geolocation.clearWatch(this.watchId)
}
},
startWatching(this: LocateMeHook): void {
if (!navigator.geolocation) {
alert("Geolocation is not supported by this browser")
return
}
// Already watching — don't start another
if (this.watchId !== null) return
this.el.classList.add("loading", "loading-spinner")
this.watchId = navigator.geolocation.watchPosition(
(pos: GeolocationPosition) => {
const now = Date.now()
// Send immediately on first fix, then at most once per minute
if (this.lastSentAt === 0 || now - this.lastSentAt >= 60000) {
this.lastSentAt = now
this.el.classList.remove("loading", "loading-spinner")
this.pushEvent("gps_location", {
lat: pos.coords.latitude,
lon: pos.coords.longitude
})
}
},
(err: GeolocationPositionError) => {
this.el.classList.remove("loading", "loading-spinner")
navigator.geolocation.clearWatch(this.watchId!)
this.watchId = null
alert("Could not get location: " + err.message)
},
{ enableHighAccuracy: true, timeout: 10000 }
)
}
}