Add remainder of the mailer mocks to the mailer flow

This commit is contained in:
Eli Ribble 2026-03-03 17:52:46 +00:00
parent c9eee95cbb
commit 0ff493cd53
No known key found for this signature in database
9 changed files with 1495 additions and 8 deletions

View file

@ -0,0 +1,250 @@
{{ template "rmo/layout/base.html" . }}
{{ define "title" }}Report Standing Water{{ end }}
{{ define "extraheader" }}
<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;
}
.success-icon {
font-size: 70px;
color: #198754;
margin-bottom: 20px;
display: block;
text-align: center;
}
.confirmation-title {
text-align: center;
margin-bottom: 30px;
}
.appointment-summary {
background-color: #e8f4f8;
border-left: 4px solid #0d6efd;
padding: 20px;
border-radius: 8px;
margin-bottom: 25px;
}
.appointment-details {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-top: 15px;
}
.appointment-detail {
flex: 1;
min-width: 150px;
padding: 10px;
background-color: #fff;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.detail-label {
font-size: 0.8rem;
text-transform: uppercase;
color: #6c757d;
font-weight: 600;
margin-bottom: 5px;
}
.detail-value {
font-weight: 600;
}
.contact-info {
background-color: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin-top: 25px;
margin-bottom: 25px;
}
.contact-method {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.contact-method i {
font-size: 1.2rem;
margin-right: 10px;
color: #0d6efd;
width: 25px;
text-align: center;
}
.tracking-link {
background-color: #e9f7ef;
border: 1px solid #d1e7dd;
border-left: 4px solid #198754;
padding: 15px;
border-radius: 8px;
margin-top: 20px;
display: flex;
justify-content: space-between;
align-items: center;
text-decoration: none;
color: inherit;
transition: all 0.2s;
}
.tracking-link:hover {
background-color: #d1e7dd;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.confirmation-number {
background-color: #f8f9fa;
padding: 10px 15px;
border-radius: 6px;
font-family: monospace;
font-size: 1.2rem;
font-weight: 600;
letter-spacing: 1px;
}
</style>
{{ end }}
{{ define "content" }}
<div class="page-container">
<!-- Logo -->
<div class="logo-area">
<img
src="https://placehold.co/200x50/e9ecef/adb5bd?text=County+Vector+Control"
alt="County Vector Control"
class="logo-placeholder"
/>
</div>
<!-- Main Content -->
<div class="content-card">
<span class="success-icon">
<i class="bi bi-check-circle-fill"></i>
</span>
<div class="confirmation-title">
<h1 class="h3">Thank You for Your Submission!</h1>
<p class="text-muted">
Your green pool report has been successfully submitted.
</p>
</div>
<!-- Appointment Summary -->
<div class="appointment-summary">
<h5><i class="bi bi-calendar-check me-2"></i>Appointment Confirmed</h5>
<p>Our inspector will visit your property at the scheduled time:</p>
<div class="appointment-details">
<div class="appointment-detail">
<div class="detail-label">Date</div>
<div class="detail-value">Thursday, June 22, 2023</div>
</div>
<div class="appointment-detail">
<div class="detail-label">Time</div>
<div class="detail-value">10:00 AM</div>
</div>
<div class="appointment-detail">
<div class="detail-label">Confirmation #</div>
<div class="detail-value">GP-23685</div>
</div>
</div>
</div>
<!-- What's Next Section -->
<div>
<h5 class="mb-3">What Happens Next?</h5>
<ul class="mb-4">
<li>
A confirmation email has been sent to the email address you
provided.
</li>
<li>
You'll receive a reminder notification 24 hours before your
scheduled appointment.
</li>
<li>
Our team will review your report and contact you by the next
business day if any additional information is needed.
</li>
<li>
During the scheduled visit, our inspector will assess the pool
condition and discuss treatment options if necessary.
</li>
</ul>
<p>
You can use the link below to track your report status and view the
photos you've submitted.
</p>
</div>
<!-- Tracking Link -->
<a href="#" class="tracking-link">
<div>
<strong>Track Your Report Status</strong>
<p class="mb-0 text-muted">View photos and check for updates</p>
</div>
<i class="bi bi-arrow-right"></i>
</a>
<!-- Contact Information -->
<div class="contact-info">
<h5 class="mb-3">Questions or Concerns?</h5>
<p>
If you have any questions about your report or need to change your
appointment, please contact us:
</p>
<div class="contact-method">
<i class="bi bi-telephone-fill"></i>
<div>
<strong>(555) 123-4567</strong>
<div class="small text-muted">Monday-Friday, 8:00 AM - 5:00 PM</div>
</div>
</div>
<div class="contact-method">
<i class="bi bi-envelope-fill"></i>
<div>
<strong>greenpool@vectorcontrol.county.gov</strong>
</div>
</div>
<p class="mt-3 mb-0 small">
Please include your confirmation number (GP-23685) in all
correspondence.
</p>
</div>
<!-- Print Option -->
<div class="d-flex justify-content-center mt-4">
<button
type="button"
class="btn btn-outline-secondary"
onclick="window.print()"
>
<i class="bi bi-printer me-2"></i> Print Confirmation
</button>
</div>
</div>
<!-- Help Text -->
<div class="text-center text-muted small">
<p>
Thank you for helping keep our community safe from mosquito-borne
diseases.
</p>
</div>
</div>
{{ end }}

View file

@ -0,0 +1,301 @@
{{ template "rmo/layout/base.html" . }}
{{ define "title" }}Report Standing Water{{ end }}
{{ define "extraheader" }}
<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;
}
</style>
{{ end }}
{{ define "content" }}
<div class="page-container">
<!-- Logo -->
<div class="logo-area">
<img
src="https://placehold.co/200x50/e9ecef/adb5bd?text=County+Vector+Control"
alt="County Vector Control"
class="logo-placeholder"
/>
</div>
<!-- Progress Bar -->
<div class="progress-container">
<div class="d-flex justify-content-between mb-1">
<span class="text-muted small">Upload Photos</span>
<span class="text-muted small">3 of 4</span>
</div>
<div class="progress">
<div
class="progress-bar"
role="progressbar"
style="width: 75%"
aria-valuenow="75"
aria-valuemin="0"
aria-valuemax="100"
></div>
</div>
</div>
<!-- Main Content -->
<div class="content-card">
<h1 class="h4 mb-3">Upload Current Pool Photos</h1>
<p>
Please provide current photos of your pool to help us assess its
condition.
</p>
<!-- Photo Tips Section -->
<div class="tips-section">
<h5><i class="bi bi-lightbulb me-2"></i>Photo Tips</h5>
<ul class="mb-0">
<li>
<strong>Take photos from as high an angle as possible</strong>
(second story window, deck, etc.)
</li>
<li>Try to capture the <strong>entire pool</strong> in your photo</li>
<li>Ensure photos are <strong>clear and well-lit</strong></li>
<li>
You can add <strong>multiple photos</strong> from different angles
</li>
</ul>
</div>
<!-- Photo Examples -->
<h5 class="mb-3">Photo Examples:</h5>
<div class="photo-example">
<div class="example-item">
<img
src="https://placehold.co/400x300/198754/ffffff?text=Good+Example"
alt="Good photo example"
class="example-img good-example"
/>
<div class="text-success">
<i class="bi bi-check-circle me-1"></i>Good: High angle, full view
</div>
</div>
<div class="example-item">
<img
src="https://placehold.co/400x300/dc3545/ffffff?text=Poor+Example"
alt="Poor photo example"
class="example-img poor-example"
/>
<div class="text-danger">
<i class="bi bi-x-circle me-1"></i>Poor: Ground level, partial view
</div>
</div>
</div>
<!-- Upload Area -->
<div class="upload-area">
<div class="upload-icon">
<i class="bi bi-camera"></i>
</div>
<h5>Add Pool Photos</h5>
<p class="text-muted">Take a new photo or upload from your device</p>
<div class="upload-options">
<button type="button" class="btn btn-primary">
<i class="bi bi-camera-fill me-2"></i> Take Photo
</button>
<button type="button" class="btn btn-outline-primary">
<i class="bi bi-image me-2"></i> Upload from Device
</button>
</div>
<input
type="file"
id="photo-upload"
accept="image/*"
multiple
style="display: none;"
/>
</div>
<!-- Already Uploaded Photos Section -->
<div>
<h5 class="mb-3">Uploaded Photos (2)</h5>
<div class="uploaded-photos">
<div class="uploaded-photo">
<img
src="https://placehold.co/300x300/76b5c5/ffffff?text=Pool+Photo+1"
alt="Uploaded pool photo"
/>
<button
type="button"
class="remove-photo"
aria-label="Remove photo"
>
<i class="bi bi-x"></i>
</button>
</div>
<div class="uploaded-photo">
<img
src="https://placehold.co/300x300/3e8e7e/ffffff?text=Pool+Photo+2"
alt="Uploaded pool photo"
/>
<button
type="button"
class="remove-photo"
aria-label="Remove photo"
>
<i class="bi bi-x"></i>
</button>
</div>
</div>
</div>
<!-- Information -->
<div class="alert alert-secondary mt-4">
<small
>You can add up to 5 photos to provide a complete view of your pool
area. We recommend taking photos from multiple angles.</small
>
</div>
<!-- Action Buttons -->
<div class="d-flex justify-content-between mt-4">
<a
href="{{ call .URL.RMO.Mailer.Evidence .C.PublicID }}"
class="btn btn-outline-secondary"
>
<i class="bi bi-arrow-left me-2"></i> Back
</a>
<a
href="{{ call .URL.RMO.Mailer.Schedule .C.PublicID }}"
class="btn btn-primary"
>
Next Step <i class="bi bi-arrow-right ms-2"></i>
</a>
</div>
</div>
<!-- Help Text -->
<div class="text-center text-muted small">
<p>
If you need assistance, please contact Vector Control at (555) 123-4567
</p>
</div>
</div>
{{ end }}

View file

@ -0,0 +1,284 @@
{{ template "rmo/layout/base.html" . }}
{{ define "title" }}Report Standing Water{{ end }}
{{ define "extraheader" }}
<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;
}
</style>
{{ end }}
{{ define "content" }}
<div class="page-container">
<!-- Logo -->
<div class="logo-area">
<img
src="https://placehold.co/200x50/e9ecef/adb5bd?text=County+Vector+Control"
alt="County Vector Control"
class="logo-placeholder"
/>
</div>
<!-- Progress Bar -->
<div class="progress-container">
<div class="d-flex justify-content-between mb-1">
<span class="text-muted small">Evidence</span>
<span class="text-muted small">2 of 4</span>
</div>
<div class="progress">
<div
class="progress-bar"
role="progressbar"
style="width: 50%"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
></div>
</div>
</div>
<!-- Main Content -->
<div class="content-card">
<h1 class="h4 mb-4">Evidence of Potential Breeding Site</h1>
<!-- Aerial Photos -->
<div class="data-section">
<div class="section-title">
<i class="bi bi-camera-fill"></i> Aerial Surveillance Photos
</div>
<p class="small text-muted mb-2">
These photos were taken during routine aerial surveillance of the
area.
</p>
<div class="photo-gallery">
<div class="photo-item">
<img
src="https://placehold.co/200x150/76b5c5/ffffff?text=Aerial+Photo+1"
alt="Aerial photo of property"
/>
</div>
<div class="photo-item">
<img
src="https://placehold.co/200x150/3e8e7e/ffffff?text=Aerial+Photo+2"
alt="Aerial photo of property"
/>
</div>
<div class="photo-item">
<img
src="https://placehold.co/200x150/7accc8/ffffff?text=Aerial+Photo+3"
alt="Aerial photo of property"
/>
</div>
</div>
</div>
<!-- Historical Inspections -->
<div class="data-section">
<div class="section-title">
<i class="bi bi-clipboard-check-fill"></i> Historical Inspection Data
</div>
<div class="table-container">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Date</th>
<th>Inspector</th>
<th>Findings</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mar 15, 2023</td>
<td>J. Martinez</td>
<td>Pool water stagnant, green</td>
<td>Treatment applied, owner notified</td>
</tr>
<tr>
<td>Nov 02, 2022</td>
<td>L. Johnson</td>
<td>Pool water clear, maintained</td>
<td>No action needed</td>
</tr>
<tr>
<td>Aug 18, 2022</td>
<td>S. Williams</td>
<td>Minor algae formation</td>
<td>Owner provided maintenance resources</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Mosquito Trap Data -->
<div class="data-section">
<div class="section-title">
<i class="bi bi-bug-fill"></i> Mosquito Trap Count Data
</div>
<div class="table-container">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Date Collected</th>
<th>Count</th>
<th>Distance</th>
<th>Level</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jun 12, 2023</td>
<td>42</td>
<td>0.3 miles</td>
<td class="trap-high">High</td>
</tr>
<tr>
<td>Jun 05, 2023</td>
<td>36</td>
<td>0.3 miles</td>
<td class="trap-high">High</td>
</tr>
<tr>
<td>May 29, 2023</td>
<td>28</td>
<td>0.3 miles</td>
<td class="trap-medium">Medium</td>
</tr>
<tr>
<td>May 22, 2023</td>
<td>15</td>
<td>0.3 miles</td>
<td class="trap-low">Low</td>
</tr>
<tr>
<td>May 15, 2023</td>
<td>12</td>
<td>0.3 miles</td>
<td class="trap-low">Low</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Public Health Information -->
<div class="alert alert-info">
<h5><i class="bi bi-info-circle me-2"></i>Why This Matters</h5>
<p>
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.
</p>
<p>
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.
</p>
<p class="mb-0">
<strong>We need your help</strong> to ensure we maintain public health
by keeping mosquito counts low in your neighborhood. Your cooperation
makes a significant difference in community safety.
</p>
</div>
<!-- Action Button -->
<div class="d-grid gap-2 mt-4">
<a
href="{{ call .URL.RMO.Mailer.Contribute .C.PublicID }}"
class="btn btn-primary btn-lg"
>
<i class="bi bi-arrow-right-circle me-2"></i> Next Step: Upload
Current Photos
</a>
</div>
</div>
<!-- Help Text -->
<div class="text-center text-muted small">
<p>
If you need assistance, please contact Vector Control at (555) 123-4567
</p>
</div>
</div>
{{ end }}

View file

@ -127,13 +127,13 @@
<!-- Action Buttons -->
<div class="action-buttons">
<a
href="{{ call .URL.RMO.Evidence .C.PublicID }}"
href="{{ call .URL.RMO.Mailer.Evidence .C.PublicID }}"
class="btn btn-success flex-grow-1"
>
<i class="bi bi-check-circle me-2"></i> Correct
</a>
<a
href="{{ call .URL.RMO.UpdateLocation .C.PublicID }}"
href="{{ call .URL.RMO.Mailer.Update .C.PublicID }}"
class="btn btn-outline-primary flex-grow-1"
>
<i class="bi bi-geo-alt me-2"></i> Update Location

View file

@ -0,0 +1,347 @@
{{ template "rmo/layout/base.html" . }}
{{ define "title" }}Report Standing Water{{ end }}
{{ define "extraheader" }}
<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;
}
.calendar-section {
margin-bottom: 30px;
}
.dates-container {
display: flex;
overflow-x: auto;
gap: 10px;
padding-bottom: 10px;
margin-bottom: 20px;
}
.date-card {
min-width: 110px;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 10px;
text-align: center;
cursor: pointer;
transition: all 0.2s;
}
.date-card:hover {
border-color: #0d6efd;
background-color: #f8f9fa;
}
.date-card.selected {
border-color: #0d6efd;
background-color: #e6f2ff;
box-shadow: 0 0 0 1px #0d6efd;
}
.date-card .month {
font-size: 0.8rem;
text-transform: uppercase;
color: #6c757d;
font-weight: 600;
}
.date-card .day {
font-size: 1.5rem;
font-weight: 700;
line-height: 1.2;
}
.date-card .weekday {
font-size: 0.8rem;
color: #6c757d;
}
.time-slots {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 10px;
margin-bottom: 20px;
}
.time-slot {
border: 1px solid #dee2e6;
border-radius: 6px;
padding: 10px;
text-align: center;
cursor: pointer;
transition: all 0.2s;
}
.time-slot:hover {
border-color: #0d6efd;
background-color: #f8f9fa;
}
.time-slot.selected {
border-color: #0d6efd;
background-color: #e6f2ff;
box-shadow: 0 0 0 1px #0d6efd;
}
.time-slot.unavailable {
background-color: #f8f9fa;
color: #adb5bd;
cursor: not-allowed;
text-decoration: line-through;
}
.form-section {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #dee2e6;
}
.section-title {
margin-bottom: 20px;
display: flex;
align-items: center;
}
.section-title i {
margin-right: 10px;
color: #0d6efd;
}
.selected-date-time {
background-color: #e8f4f8;
border-left: 4px solid #0d6efd;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}
</style>
{{ end }}
{{ define "content" }}
<div class="page-container">
<!-- Logo -->
<div class="logo-area">
<img
src="https://placehold.co/200x50/e9ecef/adb5bd?text=County+Vector+Control"
alt="County Vector Control"
class="logo-placeholder"
/>
</div>
<!-- Progress Bar -->
<div class="progress-container">
<div class="d-flex justify-content-between mb-1">
<span class="text-muted small">Schedule Follow-up</span>
<span class="text-muted small">4 of 4</span>
</div>
<div class="progress">
<div
class="progress-bar"
role="progressbar"
style="width: 100%"
aria-valuenow="100"
aria-valuemin="0"
aria-valuemax="100"
></div>
</div>
</div>
<!-- Main Content -->
<div class="content-card">
<h1 class="h4 mb-3">Schedule a Follow-up Inspection</h1>
<p>
Please select a convenient date and time for our inspector to visit your
property.
</p>
<!-- Calendar Section -->
<div class="calendar-section">
<div class="section-title">
<i class="bi bi-calendar-date"></i>
<h5 class="mb-0">Select Date</h5>
</div>
<!-- Date Selection -->
<div class="dates-container">
<div class="date-card">
<div class="month">Jun</div>
<div class="day">20</div>
<div class="weekday">Tue</div>
</div>
<div class="date-card">
<div class="month">Jun</div>
<div class="day">21</div>
<div class="weekday">Wed</div>
</div>
<div class="date-card selected">
<div class="month">Jun</div>
<div class="day">22</div>
<div class="weekday">Thu</div>
</div>
<div class="date-card">
<div class="month">Jun</div>
<div class="day">23</div>
<div class="weekday">Fri</div>
</div>
<div class="date-card">
<div class="month">Jun</div>
<div class="day">26</div>
<div class="weekday">Mon</div>
</div>
<div class="date-card">
<div class="month">Jun</div>
<div class="day">27</div>
<div class="weekday">Tue</div>
</div>
<div class="date-card">
<div class="month">Jun</div>
<div class="day">28</div>
<div class="weekday">Wed</div>
</div>
<div class="date-card">
<div class="month">Jun</div>
<div class="day">29</div>
<div class="weekday">Thu</div>
</div>
<div class="date-card">
<div class="month">Jun</div>
<div class="day">30</div>
<div class="weekday">Fri</div>
</div>
<div class="date-card">
<div class="month">Jul</div>
<div class="day">03</div>
<div class="weekday">Mon</div>
</div>
</div>
<!-- Time Slot Selection -->
<div class="section-title">
<i class="bi bi-clock"></i>
<h5 class="mb-0">Select Time</h5>
</div>
<div class="time-slots">
<div class="time-slot unavailable">8:00 AM</div>
<div class="time-slot unavailable">9:00 AM</div>
<div class="time-slot selected">10:00 AM</div>
<div class="time-slot">11:00 AM</div>
<div class="time-slot">1:00 PM</div>
<div class="time-slot">2:00 PM</div>
<div class="time-slot">3:00 PM</div>
<div class="time-slot">4:00 PM</div>
</div>
<!-- Selected Date & Time Summary -->
<div class="selected-date-time">
<div class="d-flex justify-content-between align-items-center">
<strong>Selected Appointment:</strong>
<span>Thursday, June 22, 2023 at 10:00 AM</span>
</div>
</div>
</div>
<!-- Contact Information Form -->
<div class="form-section">
<div class="section-title">
<i class="bi bi-person-lines-fill"></i>
<h5 class="mb-0">Contact Information</h5>
</div>
<form>
<div class="row g-3">
<div class="col-md-6">
<label for="fullName" class="form-label">Full Name</label>
<input type="text" class="form-control" id="fullName" required />
</div>
<div class="col-md-6">
<label for="phone" class="form-label">Phone Number</label>
<input
type="tel"
class="form-control"
id="phone"
placeholder="(555) 555-5555"
required
/>
</div>
<div class="col-12">
<label for="email" class="form-label">Email Address</label>
<input type="email" class="form-control" id="email" required />
</div>
<div class="col-12">
<label for="notes" class="form-label"
>Additional Notes (Optional)</label
>
<textarea
class="form-control"
id="notes"
rows="3"
placeholder="Any special instructions or information for the inspector"
></textarea>
</div>
<div class="col-12">
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
id="reminders"
checked
/>
<label class="form-check-label" for="reminders">
Send me text reminders about my appointment
</label>
</div>
</div>
</div>
<!-- Information -->
<div class="alert alert-secondary mt-4">
<small
>Our inspector will need access to view your pool area. If you
won't be home during the appointment, please provide access
instructions in the notes.</small
>
</div>
<!-- Action Buttons -->
<div class="d-flex justify-content-between mt-4">
<a
href="{{ call .URL.RMO.Mailer.Contribute .C.PublicID }}"
class="btn btn-outline-secondary"
>
<i class="bi bi-arrow-left me-2"></i> Back
</a>
<a
href="{{ call .URL.RMO.Mailer.Confirm .C.PublicID }}"
class="btn btn-success"
>
<i class="bi bi-calendar-check me-2"></i> Confirm Appointment
</a>
</div>
</form>
</div>
</div>
<!-- Help Text -->
<div class="text-center text-muted small">
<p>
If you need assistance, please contact Vector Control at (555) 123-4567
</p>
</div>
</div>
{{ end }}

View file

@ -0,0 +1,228 @@
{{ template "rmo/layout/base.html" . }}
{{ define "title" }}Report Standing Water{{ end }}
{{ define "extraheader" }}
<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;
}
.map-container {
height: 350px;
background-color: #e9ecef;
border-radius: 10px;
margin-bottom: 25px;
position: relative;
overflow: hidden;
border: 1px solid #dee2e6;
}
.map-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-image: url("https://placehold.co/800x350/e9ecef/adb5bd?text=Interactive+Map");
background-size: cover;
background-position: center;
}
.map-pin {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -100%);
color: #dc3545;
font-size: 30px;
filter: drop-shadow(0px 2px 2px rgba(0, 0, 0, 0.3));
}
.map-instructions {
position: absolute;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 15px;
border-radius: 20px;
font-size: 14px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
max-width: 90%;
text-align: center;
}
.or-divider {
display: flex;
align-items: center;
margin: 25px 0;
color: #6c757d;
}
.or-divider::before,
.or-divider::after {
content: "";
flex: 1;
border-bottom: 1px solid #dee2e6;
}
.or-divider::before {
margin-right: 15px;
}
.or-divider::after {
margin-left: 15px;
}
.info-box {
background-color: #e8f4f8;
border-left: 4px solid #0d6efd;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}
.info-box p:last-child {
margin-bottom: 0;
}
.form-section {
margin-bottom: 25px;
}
</style>
{{ end }}
{{ define "content" }}
<div class="page-container">
<!-- Logo -->
<div class="logo-area">
<img
src="https://placehold.co/200x50/e9ecef/adb5bd?text=County+Vector+Control"
alt="County Vector Control"
class="logo-placeholder"
/>
</div>
<!-- Main Content -->
<div class="content-card">
<h1 class="h4 mb-4">Update Property Location</h1>
<!-- Information Box -->
<div class="info-box mb-4">
<h5>
<i class="bi bi-info-circle me-2"></i>Two Ways to Update Location
</h5>
<p>
You can update the property location by either clicking on the map or
entering an address below. Both methods will automatically update each
other.
</p>
</div>
<!-- Map Section -->
<div class="form-section">
<h5 class="mb-3">Option 1: Select Location on Map</h5>
<div class="map-container">
<div class="map-placeholder"></div>
<div class="map-pin">
<i class="bi bi-geo-alt-fill"></i>
</div>
<div class="map-instructions">
<i class="bi bi-hand-index me-2"></i> Click or tap anywhere on the
map to set the location
</div>
</div>
</div>
<!-- Divider -->
<div class="or-divider">OR</div>
<!-- Address Form -->
<div class="form-section">
<h5 class="mb-3">Option 2: Enter Address</h5>
<form>
<div class="mb-3">
<label for="streetAddress" class="form-label">Street Address</label>
<input
type="text"
class="form-control"
id="streetAddress"
placeholder="123 Main Street"
/>
</div>
<div class="row g-3">
<div class="col-md-6">
<label for="city" class="form-label">City</label>
<input
type="text"
class="form-control"
id="city"
placeholder="Riverside"
/>
</div>
<div class="col-md-3">
<label for="state" class="form-label">State</label>
<select class="form-select" id="state">
<option selected>CA</option>
<option>AZ</option>
<option>NV</option>
<option>OR</option>
<!-- Add more states as needed -->
</select>
</div>
<div class="col-md-3">
<label for="zipCode" class="form-label">ZIP Code</label>
<input
type="text"
class="form-control"
id="zipCode"
placeholder="92501"
/>
</div>
</div>
</form>
</div>
<!-- Current Coordinates Display -->
<div class="mb-4 p-3 bg-light rounded small text-muted">
<div class="d-flex justify-content-between">
<span>Current Coordinates:</span>
<span>33.9806° N, 117.3755° W</span>
</div>
</div>
<!-- Action Buttons -->
<div class="d-flex justify-content-between">
<a
class="btn btn-outline-secondary"
href="{{ call .URL.RMO.Mailer.Root .C.PublicID }}"
>
Nevermind
</a>
<button type="button" class="btn btn-primary" id="saveBtn">
<i class="bi bi-check-circle me-2"></i> Save Updates
</button>
</div>
</div>
<!-- Help Text -->
<div class="text-center text-muted small">
<p>
If you need assistance, please contact Vector Control at (555) 123-4567
</p>
</div>
</div>
{{ end }}

View file

@ -59,14 +59,32 @@ func newContentURLConfiguration() contentURLConfiguration {
}
type contentURLRMO struct {
Evidence urlWithParams
UpdateLocation urlWithParams
Mailer contentURLRMOMailer
}
func newContentURLRMO() contentURLRMO {
return contentURLRMO{
Evidence: makeURLWithParams(config.MakeURLReport, "/mailer/%s/evidence"),
UpdateLocation: makeURLWithParams(config.MakeURLReport, "/mailer/%s/update"),
Mailer: newContentURLRMOMailer(),
}
}
type contentURLRMOMailer struct {
Confirm urlWithParams
Contribute urlWithParams
Evidence urlWithParams
Root urlWithParams
Schedule urlWithParams
Update urlWithParams
}
func newContentURLRMOMailer() contentURLRMOMailer {
return contentURLRMOMailer{
Confirm: makeURLWithParams(config.MakeURLReport, "/mailer/%s/confirm"),
Contribute: makeURLWithParams(config.MakeURLReport, "/mailer/%s/contribute"),
Evidence: makeURLWithParams(config.MakeURLReport, "/mailer/%s/evidence"),
Root: makeURLWithParams(config.MakeURLReport, "/mailer/%s"),
Schedule: makeURLWithParams(config.MakeURLReport, "/mailer/%s/schedule"),
Update: makeURLWithParams(config.MakeURLReport, "/mailer/%s/update"),
}
}

View file

@ -60,10 +60,65 @@ func getMailer(ctx context.Context, r *http.Request) (*html.Response[contentMail
return nil, nhttp.NewErrorStatus(http.StatusNotFound, "No compliance report with that public ID")
}
return html.NewResponse(
"rmo/mailer.html", contentMailer{
"rmo/mailer/root.html", contentMailer{
Address: report,
PublicID: public_id,
},
), nil
}
func getMailerConfirm(ctx context.Context, r *http.Request) (*html.Response[contentMailer], *nhttp.ErrorWithStatus) {
public_id := chi.URLParam(r, "public_id")
if public_id == "" {
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "No 'public_id' in the url params")
}
return html.NewResponse(
"rmo/mailer/confirm.html", contentMailer{
PublicID: public_id,
},
), nil
}
func getMailerContribute(ctx context.Context, r *http.Request) (*html.Response[contentMailer], *nhttp.ErrorWithStatus) {
public_id := chi.URLParam(r, "public_id")
if public_id == "" {
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "No 'public_id' in the url params")
}
return html.NewResponse(
"rmo/mailer/contribute.html", contentMailer{
PublicID: public_id,
},
), nil
}
func getMailerEvidence(ctx context.Context, r *http.Request) (*html.Response[contentMailer], *nhttp.ErrorWithStatus) {
public_id := chi.URLParam(r, "public_id")
if public_id == "" {
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "No 'public_id' in the url params")
}
return html.NewResponse(
"rmo/mailer/evidence.html", contentMailer{
PublicID: public_id,
},
), nil
}
func getMailerSchedule(ctx context.Context, r *http.Request) (*html.Response[contentMailer], *nhttp.ErrorWithStatus) {
public_id := chi.URLParam(r, "public_id")
if public_id == "" {
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "No 'public_id' in the url params")
}
return html.NewResponse(
"rmo/mailer/schedule.html", contentMailer{
PublicID: public_id,
},
), nil
}
func getMailerUpdate(ctx context.Context, r *http.Request) (*html.Response[contentMailer], *nhttp.ErrorWithStatus) {
public_id := chi.URLParam(r, "public_id")
if public_id == "" {
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "No 'public_id' in the url params")
}
return html.NewResponse(
"rmo/mailer/update.html", contentMailer{
PublicID: public_id,
},
), nil
}

View file

@ -33,7 +33,11 @@ func Router() chi.Router {
r.Get("/email/unsubscribe/report/{report_id}", getEmailReportUnsubscribe)
r.Get("/image/{uuid}", getImageByUUID)
r.Get("/mailer/{public_id}", html.MakeGet(getMailer))
r.Route("/mock", addMockRoutes)
r.Get("/mailer/{public_id}/confirm", html.MakeGet(getMailerConfirm))
r.Get("/mailer/{public_id}/contribute", html.MakeGet(getMailerContribute))
r.Get("/mailer/{public_id}/evidence", html.MakeGet(getMailerEvidence))
r.Get("/mailer/{public_id}/schedule", html.MakeGet(getMailerSchedule))
r.Get("/mailer/{public_id}/update", html.MakeGet(getMailerUpdate))
r.Post("/register-notifications", postRegisterNotifications)
r.Get("/register-notifications-complete", getRegisterNotificationsComplete)
r.Get("/report/suggest", getReportSuggestion)