feat: add manual photo proof capture, consensus voting, and anti-sabotage camera verification engine
This commit is contained in:
+158
@@ -724,6 +724,21 @@
|
||||
<input type="text" id="report-notes" class="search-input" style="padding: 12px;" placeholder="e.g. Northbound lanes, black solar panel on pole">
|
||||
</div>
|
||||
|
||||
<!-- Optional Photo Proof in Report Modal -->
|
||||
<div class="form-group" style="margin-bottom: 16px;">
|
||||
<label class="control-label" style="display:block; margin-bottom: 6px;">Physical Hardware Photo Proof (Recommended)</label>
|
||||
<div class="photo-proof-upload-zone" id="report-photo-zone">
|
||||
<button type="button" id="btn-report-add-photo" class="btn-secondary" style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px;">
|
||||
<span>📸</span>
|
||||
<span id="report-photo-btn-text">Snap Camera on Pole (+100 pts)</span>
|
||||
</button>
|
||||
<div id="report-photo-preview-box" class="photo-preview-box hidden" style="margin-top: 10px; position: relative;">
|
||||
<img id="report-photo-preview-img" src="" alt="Camera preview" style="width: 100%; max-height: 180px; object-fit: cover; border-radius: var(--radius-md); border: 1px solid var(--accent-cyan);">
|
||||
<button type="button" id="btn-report-remove-photo" style="position: absolute; top: 6px; right: 6px; background: rgba(0,0,0,0.7); color: #fff; border: none; border-radius: 50%; width: 26px; height: 26px; cursor: pointer;">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 24px;">
|
||||
<div>
|
||||
<label class="control-label" for="report-lat" style="display:block; margin-bottom: 6px;">Latitude</label>
|
||||
@@ -742,6 +757,149 @@
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- ========================================================================
|
||||
MODAL 4: SURVEILLANCE ZONE HARDWARE PROOF & COMMUNITY VOTING (<dialog>)
|
||||
======================================================================== -->
|
||||
<dialog id="camera-detail-modal" class="agency-dialog hardware-proof-dialog" aria-labelledby="cam-detail-title">
|
||||
<div class="modal-header">
|
||||
<div class="modal-header-titles">
|
||||
<div class="cam-verification-badge" id="cam-detail-verify-badge">
|
||||
<span class="badge-dot dot-clear"></span>
|
||||
<span id="cam-detail-verify-text">CHECKING VERIFICATION...</span>
|
||||
</div>
|
||||
<h2 id="cam-detail-title" class="modal-agency-name" style="margin-top: 6px;">Flock Camera Location</h2>
|
||||
<div class="modal-agency-meta" id="cam-detail-meta">Managing Agency & Hardware Registry</div>
|
||||
</div>
|
||||
<button id="cam-detail-close-btn" class="close-modal-btn" aria-label="Close modal">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Hardware Photo Proof Area -->
|
||||
<div class="proof-photo-container" id="cam-proof-container">
|
||||
<!-- Populated dynamically via JS: either real driver photo or upload prompt -->
|
||||
</div>
|
||||
|
||||
<!-- Hardware Specifications Grid -->
|
||||
<div class="modal-section" style="margin-top: 20px;">
|
||||
<h3 class="modal-section-title">Hardware Telemetry & Location</h3>
|
||||
<div class="proof-specs-grid">
|
||||
<div class="proof-spec-card">
|
||||
<span class="spec-label">INSTALLATION TYPE</span>
|
||||
<span class="spec-val" id="spec-mount-type">Solar Pole Mount</span>
|
||||
</div>
|
||||
<div class="proof-spec-card">
|
||||
<span class="spec-label">MANAGING ENTITY</span>
|
||||
<span class="spec-val" id="spec-agency">Local Law Enforcement</span>
|
||||
</div>
|
||||
<div class="proof-spec-card">
|
||||
<span class="spec-label">EST. 30-DAY LOGS</span>
|
||||
<span class="spec-val" id="spec-captures">300,000+ Reads</span>
|
||||
</div>
|
||||
<div class="proof-spec-card">
|
||||
<span class="spec-label">COORDINATES</span>
|
||||
<span class="spec-val" id="spec-coords">34.6019, -118.1484</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Community Consensus & Anti-Sabotage Rule Banner -->
|
||||
<div class="proof-consensus-banner">
|
||||
<div class="consensus-icon">🛡️</div>
|
||||
<div class="consensus-text">
|
||||
<strong>Democratic Checks & Balances Active</strong>
|
||||
<p>Flock cameras are permanent municipal installations. To prevent law enforcement or bad actors from deleting active surveillance zones, locations are protected by community consensus.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Voting & Action Bar -->
|
||||
<div class="proof-actions-row">
|
||||
<button id="btn-vote-confirm-cam" class="btn-proof-action btn-confirm-vote" title="Confirm camera is still bolted to pole">
|
||||
<span class="btn-icon">👍</span>
|
||||
<span id="btn-vote-confirm-text">Confirm Active (1)</span>
|
||||
</button>
|
||||
|
||||
<button id="btn-proof-add-photo" class="btn-proof-action btn-add-photo" title="Snap or upload a photo of the camera on the pole">
|
||||
<span class="btn-icon">📸</span>
|
||||
<span id="btn-proof-photo-text">Add Photo Proof</span>
|
||||
</button>
|
||||
|
||||
<button id="btn-proof-contest" class="btn-proof-action btn-contest-vote" title="Report camera removed or inaccurate">
|
||||
<span class="btn-icon">⚠️</span>
|
||||
<span>Contest</span>
|
||||
</button>
|
||||
|
||||
<a id="btn-proof-navigate" href="#" target="_blank" rel="noopener noreferrer" class="btn-proof-action btn-nav-maps" title="Open navigation in Apple/Google Maps">
|
||||
<span class="btn-icon">🧭</span>
|
||||
<span>Maps ↗</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Public Transparency Portal Link -->
|
||||
<div id="proof-portal-link-box" style="margin-top: 16px; text-align: center;">
|
||||
<button id="btn-proof-open-portal" class="btn-secondary" style="width: 100%; padding: 12px;">
|
||||
Inspect Official Transparency Portal & Policy Records ↗
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- ========================================================================
|
||||
MODAL 5: CONTEST CAMERA / REPORT REMOVAL MODAL (<dialog>)
|
||||
======================================================================== -->
|
||||
<dialog id="contest-modal" class="agency-dialog" aria-labelledby="contest-modal-title">
|
||||
<div class="modal-header">
|
||||
<div class="modal-header-titles">
|
||||
<h2 id="contest-modal-title" class="modal-agency-name">Contest Camera Location</h2>
|
||||
<div class="modal-agency-meta">Community Checks & Balances to Prevent Misinformation</div>
|
||||
</div>
|
||||
<button id="contest-close-btn" class="close-modal-btn" aria-label="Close modal">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="contest-form">
|
||||
<div class="form-group" style="margin-bottom: 16px;">
|
||||
<label class="control-label" for="contest-reason" style="display:block; margin-bottom: 6px;">Reason for Contesting</label>
|
||||
<select id="contest-reason" class="select-custom" style="width: 100%;">
|
||||
<option value="Camera / Solar Panel physically removed from pole">Camera / Solar Panel physically removed from pole</option>
|
||||
<option value="Not a Flock ALPR (Standard CCTV / traffic light sensor)">Not a Flock ALPR (Standard CCTV / traffic sensor)</option>
|
||||
<option value="Incorrect intersection or misplaced GPS pin">Incorrect intersection or misplaced GPS pin</option>
|
||||
<option value="Spam or fraudulent pin">Spam or fraudulent pin</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 16px;">
|
||||
<label class="control-label" for="contest-notes" style="display:block; margin-bottom: 6px;">Observations / Verification Notes</label>
|
||||
<textarea id="contest-notes" class="search-input" style="padding: 12px; height: 80px; resize: vertical;" placeholder="Describe why this pin is inaccurate or what was found on the pole..." required></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 20px;">
|
||||
<label class="control-label" style="display:block; margin-bottom: 6px;">Photo Proof of Empty Pole (Optional)</label>
|
||||
<button type="button" id="btn-contest-add-photo" class="btn-secondary" style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px;">
|
||||
<span>📷</span>
|
||||
<span id="contest-photo-btn-text">Snap Empty Pole</span>
|
||||
</button>
|
||||
<div id="contest-photo-preview-box" class="photo-preview-box hidden" style="margin-top: 10px; position: relative;">
|
||||
<img id="contest-photo-preview-img" src="" alt="Contest photo" style="width: 100%; max-height: 160px; object-fit: cover; border-radius: var(--radius-md); border: 1px solid var(--accent-amber);">
|
||||
<button type="button" id="btn-contest-remove-photo" style="position: absolute; top: 6px; right: 6px; background: rgba(0,0,0,0.7); color: #fff; border: none; border-radius: 50%; width: 26px; height: 26px; cursor: pointer;">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="proof-consensus-banner" style="margin-bottom: 20px;">
|
||||
<div class="consensus-icon">⚖️</div>
|
||||
<div class="consensus-text">
|
||||
<strong>Consensus Safeguard:</strong>
|
||||
<p>A single report does not delete a verified camera. Once 3 trusted scouts flag a location or photo proof of an empty pole is verified, the camera is archived.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-open-flock" style="width: 100%; justify-content: center; cursor: pointer; border: none; background: linear-gradient(135deg, #f59e0b, #d97706);">
|
||||
Submit Contest Report
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- Hidden Native Camera / File Input for Mobile Evidence Snapping -->
|
||||
<input type="file" id="camera-photo-file-input" accept="image/*" capture="environment" style="display: none;">
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div id="toast-container" class="toast-container" aria-live="assertive"></div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user