diff --git a/arcgis.go b/arcgis.go
index f77d1c1a..6afc19e2 100644
--- a/arcgis.go
+++ b/arcgis.go
@@ -358,6 +358,7 @@ func periodicallyExportFieldseeker(ctx context.Context, org *models.Organization
if err != nil {
return fmt.Errorf("Failed to export Fieldseeker data: %v", err)
}
+ slog.Info("Completed exporting data, waiting 15 minutes to go agoin.")
pollTicker = time.NewTicker(15 * time.Minute)
}
}
@@ -400,7 +401,9 @@ func exportFieldseekerData(ctx context.Context, org *models.Organization, oauth
RecordsUnchanged: omit.From(int32(stats.Unchanged)),
}
err = org.InsertFieldseekerSyncs(ctx, PGInstance.BobDB, &setter)
- //err = user.InsertUserOauthTokens(ctx, PGInstance.BobDB, &setter)
+ if err != nil {
+ return fmt.Errorf("Failed to insert sync: %v", err)
+ }
return nil
}
diff --git a/endpoint.go b/endpoint.go
index 263bedd9..fa930581 100644
--- a/endpoint.go
+++ b/endpoint.go
@@ -182,6 +182,50 @@ func getRoot(w http.ResponseWriter, r *http.Request) {
respondError(w, "Failed to render root", err, http.StatusInternalServerError)
}
}
+
+func getServiceRequest(w http.ResponseWriter, r *http.Request) {
+ err := htmlServiceRequest(w)
+ if err != nil {
+ respondError(w, "Failed to generate service request page", err, http.StatusInternalServerError)
+ }
+}
+
+func getServiceRequestDetail(w http.ResponseWriter, r *http.Request) {
+ code := chi.URLParam(r, "code")
+ err := htmlServiceRequestDetail(w, code)
+ if err != nil {
+ respondError(w, "Failed to generate service request page", err, http.StatusInternalServerError)
+ }
+}
+
+func getServiceRequestLocation(w http.ResponseWriter, r *http.Request) {
+ err := htmlServiceRequestLocation(w)
+ if err != nil {
+ respondError(w, "Failed to generate service request location page", err, http.StatusInternalServerError)
+ }
+}
+
+func getServiceRequestMosquito(w http.ResponseWriter, r *http.Request) {
+ err := htmlServiceRequestMosquito(w)
+ if err != nil {
+ respondError(w, "Failed to generate service request mosquito page", err, http.StatusInternalServerError)
+ }
+}
+
+func getServiceRequestPool(w http.ResponseWriter, r *http.Request) {
+ err := htmlServiceRequestPool(w)
+ if err != nil {
+ respondError(w, "Failed to generate service request pool page", err, http.StatusInternalServerError)
+ }
+}
+
+func getServiceRequestUpdates(w http.ResponseWriter, r *http.Request) {
+ err := htmlServiceRequestUpdates(w)
+ if err != nil {
+ respondError(w, "Failed to generate service request updates page", err, http.StatusInternalServerError)
+ }
+}
+
func getSignup(w http.ResponseWriter, r *http.Request) {
err := htmlSignup(w, r.URL.Path)
if err != nil {
diff --git a/html.go b/html.go
index eb0e57d7..a6c26b0a 100644
--- a/html.go
+++ b/html.go
@@ -18,17 +18,23 @@ import (
)
var (
- dashboard = newBuiltTemplate("dashboard", "authenticated")
- oauthPrompt = newBuiltTemplate("oauth-prompt", "authenticated")
- report = newBuiltTemplate("report", "base")
- reportConfirmation = newBuiltTemplate("report-confirmation", "base")
- reportContribute = newBuiltTemplate("report-contribute", "base")
- reportDetail = newBuiltTemplate("report-detail", "base")
- reportEvidence = newBuiltTemplate("report-evidence", "base")
- reportSchedule = newBuiltTemplate("report-schedule", "base")
- reportUpdate = newBuiltTemplate("report-update", "base")
- signin = newBuiltTemplate("signin", "base")
- signup = newBuiltTemplate("signup", "base")
+ dashboard = newBuiltTemplate("dashboard", "authenticated")
+ oauthPrompt = newBuiltTemplate("oauth-prompt", "authenticated")
+ report = newBuiltTemplate("report", "base")
+ reportConfirmation = newBuiltTemplate("report-confirmation", "base")
+ reportContribute = newBuiltTemplate("report-contribute", "base")
+ reportDetail = newBuiltTemplate("report-detail", "base")
+ reportEvidence = newBuiltTemplate("report-evidence", "base")
+ reportSchedule = newBuiltTemplate("report-schedule", "base")
+ reportUpdate = newBuiltTemplate("report-update", "base")
+ serviceRequest = newBuiltTemplate("service-request", "base")
+ serviceRequestDetail = newBuiltTemplate("service-request-detail", "base")
+ serviceRequestLocation = newBuiltTemplate("service-request-location", "base")
+ serviceRequestMosquito = newBuiltTemplate("service-request-mosquito", "base")
+ serviceRequestPool = newBuiltTemplate("service-request-pool", "base")
+ serviceRequestUpdates = newBuiltTemplate("service-request-updates", "base")
+ signin = newBuiltTemplate("signin", "base")
+ signup = newBuiltTemplate("signup", "base")
)
var components = [...]string{"header"}
@@ -52,7 +58,7 @@ type ContentDashboard struct {
CountInspections int
CountMosquitoSources int
CountServiceRequests int
- LastSync string
+ LastSync time.Time
Org string
RecentRequests []ServiceRequestSummary
User User
@@ -109,13 +115,12 @@ func htmlDashboard(ctx context.Context, w io.Writer, user *models.User) error {
if err != nil {
return fmt.Errorf("Failed to get org: %v", err)
}
- var syncString string
+ var lastSync time.Time
sync, err := org.FieldseekerSyncs(sm.OrderBy("created")).One(ctx, PGInstance.BobDB)
if err != nil {
- //return fmt.Errorf("Failed to get sync: %v", err)
- syncString = "never"
+ return fmt.Errorf("Failed to get sync: %v", err)
} else {
- syncString = sync.Created.String()
+ lastSync = sync.Created
}
inspectionCount, err := org.FSMosquitoinspections().Count(ctx, PGInstance.BobDB)
if err != nil {
@@ -146,7 +151,7 @@ func htmlDashboard(ctx context.Context, w io.Writer, user *models.User) error {
CountInspections: int(inspectionCount),
CountMosquitoSources: int(sourceCount),
CountServiceRequests: int(serviceCount),
- LastSync: syncString,
+ LastSync: lastSync,
Org: org.Name.MustGet(),
RecentRequests: requests,
User: User{
@@ -226,6 +231,36 @@ func htmlReportUpdate(w io.Writer, code string) error {
return reportUpdate.ExecuteTemplate(w, data)
}
+func htmlServiceRequest(w io.Writer) error {
+ data := ContentPlaceholder{}
+ return serviceRequest.ExecuteTemplate(w, data)
+}
+
+func htmlServiceRequestDetail(w io.Writer, code string) error {
+ data := ContentPlaceholder{}
+ return serviceRequestDetail.ExecuteTemplate(w, data)
+}
+
+func htmlServiceRequestLocation(w io.Writer) error {
+ data := ContentPlaceholder{}
+ return serviceRequestLocation.ExecuteTemplate(w, data)
+}
+
+func htmlServiceRequestMosquito(w io.Writer) error {
+ data := ContentPlaceholder{}
+ return serviceRequestMosquito.ExecuteTemplate(w, data)
+}
+
+func htmlServiceRequestPool(w io.Writer) error {
+ data := ContentPlaceholder{}
+ return serviceRequestPool.ExecuteTemplate(w, data)
+}
+
+func htmlServiceRequestUpdates(w io.Writer) error {
+ data := ContentPlaceholder{}
+ return serviceRequestUpdates.ExecuteTemplate(w, data)
+}
+
func htmlSignin(w io.Writer, errorCode string) error {
data := ContentSignin{
InvalidCredentials: errorCode == "invalid-credentials",
@@ -311,6 +346,7 @@ func timeSince(t time.Time) string {
diff := now.Sub(t)
hours := diff.Hours()
+ slog.Info("time since", slog.String("t", t.String()), slog.Float64("hours", hours))
if hours < 1 {
minutes := diff.Minutes()
return fmt.Sprintf("%d minutes ago", int(minutes))
diff --git a/main.go b/main.go
index ebe69626..939fcadd 100644
--- a/main.go
+++ b/main.go
@@ -71,6 +71,12 @@ func main() {
r.Get("/report/{code}/evidence", getReportEvidence)
r.Get("/report/{code}/schedule", getReportSchedule)
r.Get("/report/{code}/update", getReportUpdate)
+ r.Get("/service-request", getServiceRequest)
+ r.Get("/service-request/{code}", getServiceRequestDetail)
+ r.Get("/service-request-location", getServiceRequestLocation)
+ r.Get("/service-request-mosquito", getServiceRequestMosquito)
+ r.Get("/service-request-pool", getServiceRequestPool)
+ r.Get("/service-request-updates", getServiceRequestUpdates)
r.Post("/signin", postSignin)
r.Get("/signup", getSignup)
r.Post("/signup", postSignup)
diff --git a/templates/base.html b/templates/base.html
index b71d267f..b60842b0 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -3,8 +3,14 @@
+
{{template "title" .}} - Nidus Sync
+
+
+
diff --git a/templates/dashboard.html b/templates/dashboard.html
index eb848191..58d5fa7b 100644
--- a/templates/dashboard.html
+++ b/templates/dashboard.html
@@ -69,7 +69,7 @@ body {
- Last updated: {{ .LastSync }}
+ Last updated: {{ .LastSync | timeSince }}
Refresh Data
@@ -85,7 +85,7 @@ body {
Last Data Refresh
- {{ .LastSync }}
+ {{ .LastSync | timeSince }}
Last sync: 12:45 PM
diff --git a/templates/empty.html b/templates/empty.html
new file mode 100644
index 00000000..dde29a29
--- /dev/null
+++ b/templates/empty.html
@@ -0,0 +1,7 @@
+{{template "base.html" .}}
+
+{{define "title"}}Dash{{end}}
+{{define "style"}}
+{{end}}
+{{define "content"}}
+{{end}}
diff --git a/templates/service-request-detail.html b/templates/service-request-detail.html
new file mode 100644
index 00000000..732a42ba
--- /dev/null
+++ b/templates/service-request-detail.html
@@ -0,0 +1,316 @@
+{{template "base.html" .}}
+
+{{define "title"}}Dash{{end}}
+{{define "style"}}
+.district-logo {
+ max-height: 80px;
+ width: auto;
+}
+.map-container {
+ height: 300px;
+ background-color: #e9ecef;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 5px;
+ border: 1px solid #dee2e6;
+}
+.progress-tracker {
+ display: flex;
+ justify-content: space-between;
+ margin: 20px 0;
+ position: relative;
+}
+.progress-tracker::before {
+ content: '';
+ position: absolute;
+ top: 25px;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ background-color: #dee2e6;
+ z-index: 1;
+}
+.progress-step {
+ position: relative;
+ z-index: 2;
+ text-align: center;
+ width: 60px;
+}
+.progress-icon {
+ height: 50px;
+ width: 50px;
+ background-color: #fff;
+ border-radius: 50%;
+ border: 2px solid #dee2e6;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 8px;
+}
+.progress-icon.active {
+ border-color: #0d6efd;
+ background-color: #0d6efd;
+ color: white;
+}
+.progress-icon.completed {
+ border-color: #198754;
+ background-color: #198754;
+ color: white;
+}
+.progress-label {
+ font-size: 0.8rem;
+ font-weight: 500;
+}
+.type-badge {
+ display: flex;
+ align-items: center;
+ font-size: 1.1rem;
+}
+.type-badge i {
+ margin-right: 8px;
+}
+.coordinates {
+ font-size: 0.85rem;
+ color: #6c757d;
+}
+.note-item {
+ border-left: 3px solid #0d6efd;
+ padding: 10px 15px;
+ background-color: rgba(13, 110, 253, 0.05);
+ margin-bottom: 10px;
+}
+.note-date {
+ font-size: 0.8rem;
+ color: #6c757d;
+ margin-bottom: 2px;
+}
+{{end}}
+{{define "content"}}
+
+
+
+
+
+
[District Name]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Report #MMD-2023-12345
+
+
+
+ Green Pool
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Map of Report Location
+
+
+
+
+
+
Address
+
123 Mosquito Ave, Lakeside, CA 92040
+
+ 32.8573° N, 116.9222° W
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Report Source
+
Phone Call
+
+
+
Report Date
+
October 15, 2023 at 2:45 PM
+
+
+
+
+
Description
+
I noticed my neighbor's backyard pool has turned green and there's nobody living in the house currently. I'm concerned it might be breeding mosquitoes as I've noticed more of them in my yard recently. The house seems to be vacant for about 3 months now.
+
+
+
+
+
Pool Status
+
Stagnant/Green
+
+
+
Scheduled Appointment
+
October 20, 2023, 9:00 AM - 11:00 AM
+
+
+
+
+
Contact Information
+
+
+
Reported By: John Smith
+
Phone: (555) 123-4567
+
+
+
Email: john.smith@example.com
+
Preferred Contact: Phone
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Added by System on Oct 15, 2023, 2:45 PM
+
Report created via phone call to district office.
+
+
+
Added by Sarah Johnson (Office Staff) on Oct 16, 2023, 9:30 AM
+
Verified location information. Property appears to be vacant according to county records. Left voicemail with property management company listed in county database.
+
+
+
Added by Mike Davis (Technician) on Oct 18, 2023, 11:15 AM
+
Scheduled inspection for Oct 20. Will need access to backyard. Contacted reporter to confirm they'll be available to provide access information on day of service.
+
+
+
+
+
+
+
+
+
+
+
+
Next Steps
+
Technician scheduled to inspect the property on October 20, 2023, between 9:00 AM - 11:00 AM. If access to the property is not possible, treatment may be conducted from outside the property or additional follow-up may be required.
+
Note: You will receive a notification when the status of this report changes.
+
+
+
+
+
+
+
+
+
+
+
+
Do you have additional information about this report? Add it below to update the technician.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
© 2023 [District Name] Mosquito Management District
+
+
+
Contact: (555) 123-4567 | info@mosquitodistrict.gov
+
+
+
+
+{{end}}
diff --git a/templates/service-request-location.html b/templates/service-request-location.html
new file mode 100644
index 00000000..42be3f7f
--- /dev/null
+++ b/templates/service-request-location.html
@@ -0,0 +1,365 @@
+{{template "base.html" .}}
+
+{{define "title"}}Dash{{end}}
+{{define "style"}}
+.district-logo {
+ max-height: 80px;
+ width: auto;
+}
+.map-container {
+ height: 400px;
+ background-color: #e9ecef;
+ border-radius: 5px;
+ border: 1px solid #dee2e6;
+ position: relative;
+}
+.map-placeholder {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ flex-direction: column;
+}
+.map-overlay {
+ position: absolute;
+ bottom: 20px;
+ right: 20px;
+ background-color: rgba(255, 255, 255, 0.9);
+ padding: 10px;
+ border-radius: 5px;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
+ max-width: 250px;
+}
+.map-controls {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+}
+.map-control-btn {
+ width: 40px;
+ height: 40px;
+ background-color: white;
+ border: 1px solid #dee2e6;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.2rem;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+}
+.report-type-icon {
+ font-size: 1.2rem;
+}
+.days-ago {
+ font-size: 0.85rem;
+ color: #6c757d;
+}
+.status-badge {
+ font-size: 0.85rem;
+ font-weight: normal;
+ padding: 6px 10px;
+}
+.report-row:hover {
+ background-color: rgba(13, 110, 253, 0.05);
+ cursor: pointer;
+}
+.instruction-card {
+ border-left: 4px solid #0d6efd;
+}
+{{end}}
+{{define "content"}}
+
+
+
+
+
+
[District Name]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Lookup Reports by Location
+
Find reports and mosquito activity in your area
+
+
+
+
+
+
+
+
+
How to use this tool
+
You can either enter an address in the search box or navigate the map by dragging and zooming to find reports in your area. The table below will update automatically to show reports within the current map view.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Enter an address or location
+
+
+
+
+
+
+
+
+ Search radius
+
+ 0.5 miles
+ 1 mile
+ 2 miles
+ 5 miles
+
+
+
+
+
+ Currently showing reports within 1 mile of map center
+
+
+
+
+
+
+
+
+
+
+
Interactive Map Area
+
The map will display here and allow you to navigate the area
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Current View
+
Lakeside, CA
+
32.857° N, 116.922° W
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type
+ Location
+ Submitted
+ Status
+ Report ID
+
+
+
+
+
+
+
+
+
+ Green Pool
+
+ 123 Mosquito Ave
+
+ Oct 15, 2023
+ 5 days ago
+
+
+ Scheduled
+
+
+ MMD-2023-12345
+
+
+
+
+
+
+
+
+
+ Mosquito Nuisance
+
+ 456 Lake Dr
+
+ Oct 12, 2023
+ 8 days ago
+
+
+ Complete
+
+
+ MMD-2023-12341
+
+
+
+
+
+
+
+
+
+ Fish Request
+
+ 789 Creek Rd
+
+ Oct 18, 2023
+ 2 days ago
+
+
+ Acknowledged
+
+
+ MMD-2023-12350
+
+
+
+
+
+
+
+
+
+ Mosquito Nuisance
+
+ 101 Pond Ln
+
+ Sep 25, 2023
+ 25 days ago
+
+
+ Complete
+
+
+ MMD-2023-12289
+
+
+
+
+
+
+
+
+
+ Green Pool
+
+ 202 Highland Ave
+
+ Oct 19, 2023
+ 1 day ago
+
+
+ Submitted
+
+
+ MMD-2023-12356
+
+
+
+
+
+
+
+
+
+ Green Pool
+
+ 303 Marsh Way
+
+ Aug 15, 2023
+ 2 months ago
+
+
+ Complete
+
+
+ MMD-2023-12056
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
© 2023 [District Name] Mosquito Management District
+
+
+
Contact: (555) 123-4567 | info@mosquitodistrict.gov
+
+
+
+
+{{end}}
diff --git a/templates/service-request-mosquito.html b/templates/service-request-mosquito.html
new file mode 100644
index 00000000..1e8eeddc
--- /dev/null
+++ b/templates/service-request-mosquito.html
@@ -0,0 +1,539 @@
+{{template "base.html" .}}
+
+{{define "title"}}Dash{{end}}
+{{define "script"}}
+// Handle inspection type selection
+function selectInspectionType(type) {
+ // Remove selected class from both cards
+ document.getElementById('propertyInspection').classList.remove('selected');
+ document.getElementById('neighborhoodInspection').classList.remove('selected');
+
+ // Add selected class to chosen card
+ if (type === 'property') {
+ document.getElementById('propertyInspection').classList.add('selected');
+ document.getElementById('inspectionTypeProperty').checked = true;
+ document.getElementById('schedulingSection').style.display = 'block';
+ } else {
+ document.getElementById('neighborhoodInspection').classList.add('selected');
+ document.getElementById('inspectionTypeNeighborhood').checked = true;
+ document.getElementById('schedulingSection').style.display = 'none';
+ }
+}
+
+// Check for source identification
+document.addEventListener('DOMContentLoaded', function() {
+ const sourceCheckboxes = [
+ document.getElementById('sourceStagnantWater'),
+ document.getElementById('sourceContainers'),
+ document.getElementById('sourceGutters')
+ ];
+
+ const sourceAlert = document.getElementById('sourceFoundAlert');
+
+ sourceCheckboxes.forEach(checkbox => {
+ checkbox.addEventListener('change', function() {
+ // If any source is checked, show the alert
+ if (sourceCheckboxes.some(cb => cb.checked)) {
+ sourceAlert.style.display = 'block';
+ } else {
+ sourceAlert.style.display = 'none';
+ }
+ });
+ });
+});
+{{end}}
+{{define "style"}}
+.district-logo {
+ max-height: 80px;
+ width: auto;
+}
+.form-section {
+ margin-bottom: 2.5rem;
+ padding-bottom: 2rem;
+ border-bottom: 1px solid #dee2e6;
+}
+.form-section:last-child {
+ border-bottom: none;
+ margin-bottom: 1rem;
+ padding-bottom: 0;
+}
+.section-heading {
+ margin-bottom: 1.5rem;
+ display: flex;
+ align-items: center;
+}
+.section-heading i {
+ margin-right: 10px;
+ font-size: 1.5rem;
+ color: #0d6efd;
+}
+.optional-label {
+ font-size: 0.875rem;
+ color: #6c757d;
+ font-weight: normal;
+ margin-left: 8px;
+}
+.submit-container {
+ background-color: #f8f9fa;
+ padding: 20px;
+ border-radius: 5px;
+ margin-top: 2rem;
+}
+.source-card {
+ height: 100%;
+ transition: transform 0.3s;
+}
+.source-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+}
+.source-icon {
+ font-size: 2rem;
+ margin-bottom: 1rem;
+ color: #0d6efd;
+}
+.time-of-day-btn {
+ width: 100%;
+ margin-bottom: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 15px 0;
+}
+.time-of-day-icon {
+ font-size: 1.5rem;
+ margin-bottom: 8px;
+}
+.time-label {
+ font-size: 0.9rem;
+}
+.severity-item {
+ text-align: center;
+ padding: 10px;
+}
+.severity-scale {
+ display: flex;
+ justify-content: space-between;
+ margin: 20px 0;
+}
+.btn-check:checked + .btn.time-of-day-btn {
+ background-color: #0d6efd;
+ color: white;
+}
+.inspection-type-card {
+ cursor: pointer;
+ border: 1px solid #dee2e6;
+ padding: 20px;
+ border-radius: 5px;
+ height: 100%;
+ transition: all 0.3s;
+}
+.inspection-type-card.selected {
+ border-color: #0d6efd;
+ background-color: rgba(13, 110, 253, 0.05);
+}
+.inspection-type-card:hover {
+ border-color: #0d6efd;
+}
+.card-highlight {
+ border-left: 4px solid #0d6efd;
+ background-color: #f8f9fa;
+}
+{{end}}
+{{define "content"}}
+
+
+
+
+
+
[District Name]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Report Mosquito Nuisance
+
Help us identify mosquito activity in your area
+
+
+
+
+
+
+
+
About Mosquito Control
+
While we don't spray for adult mosquitoes based on individual requests, your reports help us identify and eliminate breeding sources. Adult mosquito control is based on trap counts and disease testing. Your detailed information helps us prioritize our work and locate potential breeding sites.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Thank you for reporting this mosquito issue.
+
After submission, you'll receive a confirmation with a report ID and further information.
+
+
+
+ Submit Report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
© 2023 [District Name] Mosquito Management District
+
+
+
Contact: (555) 123-4567 | info@mosquitodistrict.gov
+
+
+
+
+{{end}}
diff --git a/templates/service-request-pool.html b/templates/service-request-pool.html
new file mode 100644
index 00000000..00603199
--- /dev/null
+++ b/templates/service-request-pool.html
@@ -0,0 +1,522 @@
+{{template "base.html" .}}
+
+{{define "title"}}Dash{{end}}
+{{define "script"}}
+document.addEventListener('DOMContentLoaded', function() {
+ const photoUpload = document.getElementById('photoUpload');
+ const imagePreview = document.getElementById('imagePreview');
+ const dropArea = document.getElementById('dropArea');
+
+ // Handle file selection
+ photoUpload.addEventListener('change', handleFileSelect);
+
+ // Handle drag and drop
+ dropArea.addEventListener('dragover', function(e) {
+ e.preventDefault();
+ dropArea.style.backgroundColor = '#e9ecef';
+ });
+
+ dropArea.addEventListener('dragleave', function() {
+ dropArea.style.backgroundColor = '#f8f9fa';
+ });
+
+ dropArea.addEventListener('drop', function(e) {
+ e.preventDefault();
+ dropArea.style.backgroundColor = '#f8f9fa';
+
+ if (e.dataTransfer.files.length) {
+ handleFiles(e.dataTransfer.files);
+ }
+ });
+
+ function handleFileSelect(e) {
+ const files = e.target.files;
+ handleFiles(files);
+ }
+
+ function handleFiles(files) {
+ const maxFiles = 5;
+ const currentFiles = imagePreview.querySelectorAll('.preview-item').length;
+
+ for (let i = 0; i < files.length && currentFiles + i < maxFiles; i++) {
+ const file = files[i];
+
+ if (!file.type.match('image.*')) {
+ continue;
+ }
+
+ const reader = new FileReader();
+
+ reader.onload = (function(theFile) {
+ return function(e) {
+ const previewItem = document.createElement('div');
+ previewItem.className = 'preview-item';
+
+ const img = document.createElement('img');
+ img.src = e.target.result;
+
+ const removeBtn = document.createElement('div');
+ removeBtn.className = 'preview-remove';
+ removeBtn.innerHTML = 'x';
+ removeBtn.addEventListener('click', function() {
+ imagePreview.removeChild(previewItem);
+ });
+
+ previewItem.appendChild(img);
+ previewItem.appendChild(removeBtn);
+ imagePreview.appendChild(previewItem);
+ };
+ })(file);
+
+ reader.readAsDataURL(file);
+ }
+
+ photoUpload.value = '';
+ }
+});
+{{end}}
+{{define "style"}}
+ .district-logo {
+ max-height: 80px;
+ width: auto;
+ }
+ .map-container {
+ height: 300px;
+ background-color: #e9ecef;
+ border-radius: 5px;
+ border: 1px solid #dee2e6;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-top: 10px;
+ }
+ .file-upload-container {
+ border: 2px dashed #dee2e6;
+ border-radius: 5px;
+ padding: 20px;
+ text-align: center;
+ background-color: #f8f9fa;
+ transition: background-color 0.3s;
+ }
+ .file-upload-container:hover {
+ background-color: #e9ecef;
+ cursor: pointer;
+ }
+ .image-preview {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-top: 15px;
+ }
+ .preview-item {
+ width: 100px;
+ height: 100px;
+ border-radius: 5px;
+ overflow: hidden;
+ position: relative;
+ }
+ .preview-item img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+ .preview-remove {
+ position: absolute;
+ top: 5px;
+ right: 5px;
+ background-color: rgba(0,0,0,0.5);
+ color: white;
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 10px;
+ cursor: pointer;
+ }
+ .form-section {
+ margin-bottom: 2.5rem;
+ padding-bottom: 2rem;
+ border-bottom: 1px solid #dee2e6;
+ }
+ .form-section:last-child {
+ border-bottom: none;
+ margin-bottom: 1rem;
+ padding-bottom: 0;
+ }
+ .section-heading {
+ margin-bottom: 1.5rem;
+ display: flex;
+ align-items: center;
+ }
+ .section-heading i {
+ margin-right: 10px;
+ font-size: 1.5rem;
+ color: #0d6efd;
+ }
+ .optional-label {
+ font-size: 0.875rem;
+ color: #6c757d;
+ font-weight: normal;
+ margin-left: 8px;
+ }
+ .submit-container {
+ background-color: #f8f9fa;
+ padding: 20px;
+ border-radius: 5px;
+ margin-top: 2rem;
+ }
+{{end}}
+{{define "content"}}
+
+
+
+
+
+
[District Name]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Report a Green Pool or Mosquito Source
+
Help us locate and treat potential mosquito breeding sources in your area
+
+
+
+
+
+
+
+
All fields are optional
+
We appreciate any information you can provide. The more details you share, the better we can address the issue. Photos and location information are especially helpful.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Thank you for helping us keep our community safe from mosquito-borne illnesses.
+
After submission, you will receive a confirmation with a report ID for tracking purposes.
+
+
+
+ Submit Report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Mosquito Larvae (Wigglers)
+
Mosquito larvae, often called "wigglers," are:
+
+ Small, worm-like aquatic organisms
+ Usually 1/4 to 1/2 inch long
+ Move with a wiggling motion in water
+ Hang upside-down at the water surface to breathe
+ Visible to the naked eye in standing water
+
+
+
+
Mosquito Pupae (Tumblers)
+
Mosquito pupae, often called "tumblers," are:
+
+ Comma-shaped organisms
+ Typically darker than larvae
+ Move with a tumbling motion when disturbed
+ Rest at the water surface
+ The stage just before adult mosquitoes emerge
+
+
+
+
When looking for mosquito larvae and pupae, check standing water sources like:
+
+ Swimming pools
+ Bird baths
+ Buckets or containers
+ Drainage ditches
+ Plant saucers
+ Rain gutters
+
+
If you see small creatures moving in standing water, there's a good chance they're mosquito larvae or pupae.
+
+
+
+
+
+
+
+
+
+
+
+
+
© 2023 [District Name] Mosquito Management District
+
+
+
Contact: (555) 123-4567 | info@mosquitodistrict.gov
+
+
+
+
+
+{{end}}
diff --git a/templates/service-request-updates.html b/templates/service-request-updates.html
new file mode 100644
index 00000000..7356b82a
--- /dev/null
+++ b/templates/service-request-updates.html
@@ -0,0 +1,160 @@
+{{template "base.html" .}}
+
+{{define "title"}}Dash{{end}}
+{{define "style"}}
+.option-card {
+ transition: transform 0.3s;
+ height: 100%;
+}
+.option-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 10px 20px rgba(0,0,0,0.1);
+}
+.district-logo {
+ max-height: 80px;
+ width: auto;
+}
+.divider {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.divider-line {
+ border-left: 1px solid #dee2e6;
+ height: 80%;
+}
+@media (max-width: 767.98px) {
+ .divider-line {
+ border-left: none;
+ border-top: 1px solid #dee2e6;
+ width: 80%;
+ height: auto;
+ margin: 2rem 0;
+ }
+}
+{{end}}
+{{define "content"}}
+
+
+
+
+
+
[District Name]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Check Status or Follow-up
+
+
+
+
+
+
+
+
+
+ Choose one of the following options to check on mosquito activity or follow up on a previous report.
+
+
+
+
+
+
+
+
+
+
+
Look up by Report ID
+
+ If you have a report ID from a previous request, enter it below to view the details and current status.
+
+
+
+
+
Report ID
+
+
Example: MMD-2023-12345
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Look up by Location
+
+ Don't have a report ID? You can check mosquito activity and reports in your area by providing your location information.
+
+
+ This option will guide you through selecting your location to find relevant information about mosquito activity near you.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
© 2023 [District Name] Mosquito Management District
+
+
+
Contact: (555) 123-4567 | info@mosquitodistrict.gov
+
+
+
+
+{{end}}
diff --git a/templates/service-request.html b/templates/service-request.html
new file mode 100644
index 00000000..139fe4cc
--- /dev/null
+++ b/templates/service-request.html
@@ -0,0 +1,121 @@
+{{template "base.html" .}}
+
+{{define "title"}}Dash{{end}}
+{{define "style"}}
+.service-card {
+ transition: transform 0.3s;
+ height: 100%;
+}
+.service-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 10px 20px rgba(0,0,0,0.1);
+}
+.district-logo {
+ max-height: 80px;
+ width: auto;
+}
+{{end}}
+{{define "content"}}
+
+
+
+
+
+
[District Name]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Welcome to Our Mosquito Management Services
+
+ We are dedicated to protecting public health and improving quality of life by reducing
+ mosquito populations and the diseases they can carry. Our district provides comprehensive
+ mosquito surveillance, control, and education services to our community.
+
+
+
+
+
+
+
+
+
+
How Can We Help You Today?
+
+
+
+
+
+
+
Follow-up or Check Status
+
Check on a previous request or view current mosquito activity in your area.
+
Get Updates
+
+
+
+
+
+
+
+
+
+
Report a Green Pool
+
Report stagnant water sources like abandoned pools that may breed mosquitoes.
+
Report Source
+
+
+
+
+
+
+
+
+
+
Report Mosquito Nuisance
+
Report areas with high adult mosquito activity causing discomfort or concern.
+
Report Problem
+
+
+
+
+
+
+
+
+
+
+
+
+
+
© 2023 [District Name] Mosquito Management District
+
+
+
Contact: (555) 123-4567 | info@mosquitodistrict.gov
+
+
+
+
+{{end}}