Add map and photo upload to nuisance report page

This commit is contained in:
Eli Ribble 2026-01-24 19:55:09 +00:00
parent 03a97f30a8
commit ee1ee1e901
No known key found for this signature in database
4 changed files with 113 additions and 31 deletions

View file

@ -12,7 +12,7 @@ class MapLocator extends HTMLElement {
this.render();
// markers shown on the map. Should be none or 1, generally.
this._markers = null;
this._markers = [];
}
// Lifecycle: when element is added to the DOM
@ -34,9 +34,9 @@ class MapLocator extends HTMLElement {
const lng = Number(this.getAttribute('longitude') || -119.2);
const zoom = Number(this.getAttribute('zoom') || 15);
const mapElement = this.shadowRoot.querySelector("#map");
mapboxgl.accessToken = apiKey;
map = new mapboxgl.Map({
const mapElement = this.shadowRoot.querySelector("#map");
this._map = new mapboxgl.Map({
container: mapElement,
center: {
lat: lat,
@ -45,6 +45,7 @@ class MapLocator extends HTMLElement {
style: 'mapbox://styles/mapbox/streets-v12', // style URL
zoom: zoom,
});
/*
map.addControl(new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
@ -53,7 +54,9 @@ class MapLocator extends HTMLElement {
showUserHeading: true
}));
map.addControl(new mapboxgl.NavigationControl());
map.on("load", function() {
*/
this._map.on("load", () => {
console.log("map loaded");
this.dispatchEvent(new CustomEvent('load'), {
bubbles: true,
composed: true, // Allows event to cross shadow DOM boundary
@ -67,6 +70,7 @@ class MapLocator extends HTMLElement {
// Initial render of component
render() {
this.shadowRoot.innerHTML = `
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css' rel='stylesheet' />
<style>
.map-container {
background-color: #e9ecef;
@ -111,7 +115,7 @@ class MapLocator extends HTMLElement {
const marker = new mapboxgl.Marker({
color: "#FF0000",
draggable: true
}).setLngLat(coords).addTo(map);
}).setLngLat(coords).addTo(this._map);
marker.on('dragend', function(e) {
const markerDraggedEvent = new CustomEvent("markerdragend", {
detail: {

View file

@ -22,8 +22,9 @@ type ContentURL struct {
Nuisance string
}
type ContentMock struct {
District ContentDistrict
URL ContentURL
District ContentDistrict
MapboxToken string
URL ContentURL
}
func addMockRoutes(r chi.Router) {
@ -52,7 +53,8 @@ func renderMock(t *htmlpage.BuiltTemplate) func(http.ResponseWriter, *http.Reque
Name: "Delta MCD",
URLLogo: config.MakeURLNidus("/api/district/%s/logo", slug),
},
URL: makeContentURL(),
MapboxToken: config.MapboxToken,
URL: makeContentURL(),
},
)
}

View file

@ -2,7 +2,15 @@
{{define "title"}}Nuisance{{end}}
{{define "extraheader"}}
<script src='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.js'></script>
<script src="/static/js/address-display.js"></script>
<script src="/static/js/address-suggestion.js"></script>
<script src="/static/js/geocode.js"></script>
<script src="/static/js/location.js"></script>
<script src="/static/js/map-locator.js"></script>
{{template "photo-upload-header"}}
<script>
const MAPBOX_ACCESS_TOKEN = "{{.MapboxToken}}";
// Handle inspection type selection
function selectInspectionType(type) {
// Remove selected class from both cards
@ -41,6 +49,84 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
});
// Elements
const photoInput = document.getElementById('photos');
// Handle photo selection
photoInput.addEventListener('change', handlePhotoSelection);
// Handle drag and drop
const photoDropArea = document.getElementById('photoDropArea');
photoDropArea.addEventListener('dragover', function(e) {
e.preventDefault();
photoDropArea.style.backgroundColor = '#e9ecef';
});
photoDropArea.addEventListener('dragleave', function() {
photoDropArea.style.backgroundColor = '#f8f9fa';
});
photoDropArea.addEventListener('drop', function(e) {
e.preventDefault();
photoDropArea.style.backgroundColor = '#f8f9fa';
if (e.dataTransfer.files.length) {
handleFiles(e.dataTransfer.files);
}
});
const mapLocator = document.querySelector("map-locator");
mapLocator.addEventListener("load", (event) => {
getGeolocation({
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
}).then(position => {
mapLocator.jumpTo({
center: {
lng: position.coords.longitude,
lat: position.coords.latitude,
},
zoom: 14,
});
mapLocator.setMarker([
position.coords.longitude,
position.coords.latitude,
]);
geocodeReverse(MAPBOX_ACCESS_TOKEN, {
lat: position.coords.latitude,
lng: position.coords.longitude,
});
}).catch(error => {
console.log("location error", error);
})
})
//mapLocator.addEventListener("markerdragend",
let mapZoom = document.getElementById('map-zoom');
mapLocator.addEventListener("zoomend", function(e) {
mapZoom.value = e.target.getZoom();
});
mapLocator.addEventListener("markerdragend", (e) => {
const lngLat = marker.getLngLat();
//displaySelectedCoordinates(lngLat);
geocodeReverse(MAPBOX_ACCESS_TOKEN, lngLat);
});
const addressDisplay = document.querySelector("address-display");
const addressInput = document.querySelector("address-input");
addressInput.addEventListener("address-selected", (event) => {
const l = event.detail.location;
console.log("Address selected", l);
// Center map on selected address
mapSetMarker(l.geometry.coordinates);
mapJumpTo({
center: l.geometry.coordinates,
zoom: 14,
});
addressDisplay.show(l);
setLocationInputs(l);
});
});
</script>
<style>
@ -144,7 +230,6 @@ document.addEventListener('DOMContentLoaded', function() {
{{end}}
{{define "content"}}
<div class="container">
<!-- Page Title -->
<div class="row mb-4">
<div class="col-12">
<h2>Report Mosquito Nuisance</h2>
@ -152,7 +237,6 @@ document.addEventListener('DOMContentLoaded', function() {
</div>
</div>
<!-- Info Alert -->
<div class="row mb-4">
<div class="col-12">
<div class="alert alert-info" role="alert">
@ -168,32 +252,24 @@ document.addEventListener('DOMContentLoaded', function() {
<div class="form-section">
<div class="section-heading">
<i class="bi bi-geo-alt"></i>
<h3>Location & Contact Information</h3>
<h3>Nuisance Location Information</h3>
</div>
<div class="row mb-4">
<div class="col-md-12">
<label for="address" class="form-label">Your Address</label>
<input type="text" class="form-control" name="address" placeholder="Enter your street address">
<div class="col-md-6">
<div class="mb-3 position-relative">
<address-input
placeholder="Start typing an address (min 3 characters)"
api-key="{{ .MapboxToken }}">
</address-input>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="name" class="form-label">Your Name</label>
<input type="text" class="form-control" name="name">
</div>
<div class="col-md-6 mb-3">
<label for="phone" class="form-label">Phone Number</label>
<input type="tel" class="form-control" id="phone" name="phone">
</div>
<div class="col-md-12 mb-3">
<label for="email" class="form-label">Email Address</label>
<input type="email" class="form-control" id="email" name="email">
<div class="form-text">We'll use this to send you a confirmation and follow-up information.</div>
</div>
<div class="col-md-6">
<address-display></address-display>
</div>
</div>
<p class="small text-muted mb-2">You can also click on the map to mark the location precisely</p>
<map-locator api-key="{{ .MapboxToken }}"></map-locator>
<input type="hidden" id="map-zoom" name="map-zoom"/>
<!-- Mosquito Activity Section -->
<div class="form-section">
@ -386,6 +462,7 @@ document.addEventListener('DOMContentLoaded', function() {
<div class="col-md-12">
<label for="otherSources" class="form-label">Have you noticed any other potential mosquito breeding sources?</label>
<textarea class="form-control" id="otherSources" name="source-description" rows="2" placeholder="Describe any other potential breeding sites you've noticed..."></textarea>
{{template "photo-upload"}}
</div>
</div>
</div>

View file

@ -3,7 +3,6 @@
{{define "title"}}Green Pool{{end}}
{{define "extraheader"}}
<script src='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.css' rel='stylesheet' />
<script src="/static/js/address-display.js"></script>
<script src="/static/js/address-suggestion.js"></script>
<script src="/static/js/geocode.js"></script>