From 056b871c38ec0d4921b617caae501a732c3de41e Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Wed, 5 Nov 2025 21:51:23 +0000 Subject: [PATCH] Add pages for reviewing evidence and contributing evidence. --- endpoint.go | 17 +++ html.go | 18 +++ main.go | 2 + templates/report-contribute.html | 237 ++++++++++++++++++++++++++++++ templates/report-evidence.html | 241 +++++++++++++++++++++++++++++++ 5 files changed, 515 insertions(+) create mode 100644 templates/report-contribute.html create mode 100644 templates/report-evidence.html diff --git a/endpoint.go b/endpoint.go index 667a6b66..4b167e98 100644 --- a/endpoint.go +++ b/endpoint.go @@ -82,6 +82,15 @@ func getReport(w http.ResponseWriter, r *http.Request) { respondError(w, "Failed to generate report page", err, http.StatusInternalServerError) } } + +func getReportContribute(w http.ResponseWriter, r *http.Request) { + code := chi.URLParam(r, "code") + err := htmlReportContribute(w, code) + if err != nil { + respondError(w, "Failed to generate report page", err, http.StatusInternalServerError) + } +} + func getReportDetail(w http.ResponseWriter, r *http.Request) { code := chi.URLParam(r, "code") err := htmlReportDetail(w, code) @@ -90,6 +99,14 @@ func getReportDetail(w http.ResponseWriter, r *http.Request) { } } +func getReportEvidence(w http.ResponseWriter, r *http.Request) { + code := chi.URLParam(r, "code") + err := htmlReportEvidence(w, code) + if err != nil { + respondError(w, "Failed to generate report page", err, http.StatusInternalServerError) + } +} + func getRoot(w http.ResponseWriter, r *http.Request) { user, err := getAuthenticatedUser(r) if err != nil && !errors.Is(err, &NoCredentialsError{}) { diff --git a/html.go b/html.go index da715a22..c3173f2e 100644 --- a/html.go +++ b/html.go @@ -16,7 +16,9 @@ import ( var ( dashboard = newBuiltTemplate("dashboard", "authenticated") report = newBuiltTemplate("report", "base") + reportContribute = newBuiltTemplate("report-contribute", "base") reportDetail = newBuiltTemplate("report-detail", "base") + reportEvidence = newBuiltTemplate("report-evidence", "base") signin = newBuiltTemplate("signin", "base") signup = newBuiltTemplate("signup", "base") ) @@ -101,6 +103,14 @@ func htmlReport(w io.Writer) error { return report.ExecuteTemplate(w, data) } +func htmlReportContribute(w io.Writer, code string) error { + nextURL := BaseURL + "/report/" + code + "/schedule" + data := ContentReportDetail{ + NextURL: nextURL, + } + return reportContribute.ExecuteTemplate(w, data) +} + func htmlReportDetail(w io.Writer, code string) error { nextURL := BaseURL + "/report/" + code + "/evidence" data := ContentReportDetail{ @@ -109,6 +119,14 @@ func htmlReportDetail(w io.Writer, code string) error { return reportDetail.ExecuteTemplate(w, data) } +func htmlReportEvidence(w io.Writer, code string) error { + nextURL := BaseURL + "/report/" + code + "/contribute" + data := ContentReportDetail{ + NextURL: nextURL, + } + return reportEvidence.ExecuteTemplate(w, data) +} + func htmlSignin(w io.Writer, errorCode string) error { data := ContentSignin{ InvalidCredentials: errorCode == "invalid-credentials", diff --git a/main.go b/main.go index 755c2cb5..2f032556 100644 --- a/main.go +++ b/main.go @@ -61,6 +61,8 @@ func main() { r.Get("/qr-code/report/{code}", getQRCodeReport) r.Get("/report", getReport) r.Get("/report/{code}", getReportDetail) + r.Get("/report/{code}/contribute", getReportContribute) + r.Get("/report/{code}/evidence", getReportEvidence) r.Post("/signin", postSignin) r.Get("/signup", getSignup) r.Post("/signup", postSignup) diff --git a/templates/report-contribute.html b/templates/report-contribute.html new file mode 100644 index 00000000..363a868a --- /dev/null +++ b/templates/report-contribute.html @@ -0,0 +1,237 @@ +{{template "base.html" .}} + +{{define "title"}}Login{{end}} +{{define "style"}} + body { + background-color: #f8f9fa; + } + .page-container { + max-width: 800px; + margin: 0 auto; + padding: 20px; + } + .content-card { + background-color: white; + border-radius: 15px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + padding: 25px; + margin-bottom: 20px; + } + .logo-area { + text-align: center; + margin-bottom: 20px; + } + .logo-placeholder { + height: 50px; + max-width: 200px; + margin: 0 auto; + } + .progress-container { + margin: 30px 0 20px; + } + .progress { + height: 8px; + } + .upload-area { + border: 2px dashed #dee2e6; + border-radius: 10px; + padding: 30px; + text-align: center; + margin-bottom: 25px; + background-color: #f8f9fa; + transition: all 0.3s ease; + } + .upload-area:hover { + border-color: #0d6efd; + background-color: #f0f7ff; + } + .upload-icon { + font-size: 48px; + color: #6c757d; + margin-bottom: 15px; + } + .photo-example { + display: flex; + gap: 15px; + margin-bottom: 20px; + flex-wrap: wrap; + } + .example-item { + flex: 1; + min-width: 200px; + text-align: center; + } + .example-img { + width: 100%; + height: 150px; + object-fit: cover; + border-radius: 8px; + margin-bottom: 10px; + border: 2px solid #dee2e6; + } + .good-example { + border-color: #198754; + } + .poor-example { + border-color: #dc3545; + } + .upload-options { + display: flex; + gap: 10px; + margin-top: 20px; + flex-wrap: wrap; + } + .upload-options button { + flex: 1; + min-width: 150px; + } + .uploaded-photos { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 15px; + margin-top: 20px; + } + .uploaded-photo { + position: relative; + height: 150px; + border-radius: 8px; + overflow: hidden; + border: 2px solid #dee2e6; + } + .uploaded-photo img { + width: 100%; + height: 100%; + object-fit: cover; + } + .remove-photo { + position: absolute; + top: 5px; + right: 5px; + background-color: rgba(255, 255, 255, 0.8); + color: #dc3545; + border: none; + border-radius: 50%; + width: 30px; + height: 30px; + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; + } + .tips-section { + background-color: #e8f4f8; + border-left: 4px solid #0d6efd; + padding: 15px; + border-radius: 5px; + margin-bottom: 20px; + } +{{end}} +{{define "content"}} +
+ +
+ County Vector Control +
+ + +
+
+ Upload Photos + 3 of 4 +
+
+
+
+
+ + +
+

Upload Current Pool Photos

+

Please provide current photos of your pool to help us assess its condition.

+ + +
+
Photo Tips
+
    +
  • Take photos from as high an angle as possible (second story window, deck, etc.)
  • +
  • Try to capture the entire pool in your photo
  • +
  • Ensure photos are clear and well-lit
  • +
  • You can add multiple photos from different angles
  • +
+
+ + +
Photo Examples:
+
+
+ Good photo example +
Good: High angle, full view
+
+ +
+ Poor photo example +
Poor: Ground level, partial view
+
+
+ + +
+
+ +
+
Add Pool Photos
+

Take a new photo or upload from your device

+ +
+ + +
+ + +
+ + +
+
Uploaded Photos (2)
+
+
+ Uploaded pool photo + +
+
+ Uploaded pool photo + +
+
+
+ + +
+ You can add up to 5 photos to provide a complete view of your pool area. We recommend taking photos from multiple angles. +
+ + +
+ + + Next Step + +
+
+ + +
+

If you need assistance, please contact Vector Control at (555) 123-4567

+
+
+{{end}} diff --git a/templates/report-evidence.html b/templates/report-evidence.html new file mode 100644 index 00000000..72e54cf8 --- /dev/null +++ b/templates/report-evidence.html @@ -0,0 +1,241 @@ +{{template "base.html" .}} + +{{define "title"}}Login{{end}} +{{define "style"}} + body { + background-color: #f8f9fa; + } + .page-container { + max-width: 800px; + margin: 0 auto; + padding: 20px; + } + .content-card { + background-color: white; + border-radius: 15px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + padding: 25px; + margin-bottom: 20px; + } + .logo-area { + text-align: center; + margin-bottom: 20px; + } + .logo-placeholder { + height: 50px; + max-width: 200px; + margin: 0 auto; + } + .photo-gallery { + display: flex; + gap: 10px; + margin-bottom: 20px; + overflow-x: auto; + padding-bottom: 10px; + } + .photo-item { + min-width: 200px; + height: 150px; + border-radius: 8px; + overflow: hidden; + border: 2px solid #dee2e6; + } + .photo-item img { + width: 100%; + height: 100%; + object-fit: cover; + } + .data-section { + margin-bottom: 25px; + } + .section-title { + font-size: 1.1rem; + font-weight: 600; + margin-bottom: 10px; + color: #0d6efd; + display: flex; + align-items: center; + } + .section-title i { + margin-right: 8px; + } + .table-container { + overflow-x: auto; + margin-bottom: 15px; + } + .alert-info { + background-color: #e8f4f8; + border-color: #b8daff; + } + .progress-container { + margin: 30px 0 20px; + } + .progress { + height: 8px; + } + .trap-high { + color: #dc3545; + font-weight: bold; + } + .trap-medium { + color: #fd7e14; + font-weight: bold; + } + .trap-low { + color: #198754; + } +{{end}} +{{define "content"}} +
+ +
+ County Vector Control +
+ + +
+
+ Evidence + 2 of 4 +
+
+
+
+
+ + +
+

Evidence of Potential Breeding Site

+ + +
+
+ Aerial Surveillance Photos +
+

These photos were taken during routine aerial surveillance of the area.

+ + +
+ + +
+
+ Historical Inspection Data +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateInspectorFindingsAction
Mar 15, 2023J. MartinezPool water stagnant, greenTreatment applied, owner notified
Nov 02, 2022L. JohnsonPool water clear, maintainedNo action needed
Aug 18, 2022S. WilliamsMinor algae formationOwner provided maintenance resources
+
+
+ + +
+
+ Mosquito Trap Count Data +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Date CollectedCountDistanceLevel
Jun 12, 2023420.3 milesHigh
Jun 05, 2023360.3 milesHigh
May 29, 2023280.3 milesMedium
May 22, 2023150.3 milesLow
May 15, 2023120.3 milesLow
+
+
+ + +
+
Why This Matters
+

The data above shows mosquito activity in your area. Recent trap counts indicate elevated mosquito populations, which increases the risk of mosquito-borne diseases like West Nile virus.

+

Unmaintained swimming pools can produce thousands of mosquitoes each week. By addressing potential breeding sites, you're helping protect your family and neighbors from these health risks.

+

We need your help to ensure we maintain public health by keeping mosquito counts low in your neighborhood. Your cooperation makes a significant difference in community safety.

+
+ + + +
+ + +
+

If you need assistance, please contact Vector Control at (555) 123-4567

+
+
+{{end}}