659659 margin-bottom : 24px ;
660660 }
661661
662+ .btn-scan {
663+ display : inline-flex;
664+ align-items : center;
665+ gap : 8px ;
666+ padding : 6px 14px ;
667+ border-radius : 6px ;
668+ font-family : var (--mono );
669+ font-size : 0.68rem ;
670+ margin-bottom : 24px ;
671+ margin-left : 10px ;
672+ background : rgba (255 , 69 , 0 , 0.1 );
673+ border : 1px solid rgba (255 , 69 , 0 , 0.4 );
674+ color : var (--fire );
675+ cursor : pointer;
676+ transition : all 0.2s ;
677+ }
678+ .btn-scan : hover {
679+ background : rgba (255 , 69 , 0 , 0.2 );
680+ }
681+
662682 .selected-tpl .none {
663683 background : rgba (255 , 255 , 255 , 0.02 );
664684 border : 1px solid var (--border );
@@ -1186,7 +1206,10 @@ <h1 class="hero-h1">REPORT<br /><span class="outline">ONCE.</span></h1>
11861206 </ div >
11871207
11881208 < div class ="form-area ">
1189- < div class ="selected-tpl none " id ="tplBadge "> ← Select a template from the sidebar</ div >
1209+ < div style ="display:flex; ">
1210+ < div class ="selected-tpl none " id ="tplBadge "> ← Select a template from the sidebar</ div >
1211+ < button id ="btnScan " class ="btn-scan " style ="display:none; " onclick ="scanTemplate() "> 👁️ AI Layout Scan</ button >
1212+ </ div >
11901213 < div class ="field-label ">
11911214 < span > Incident Description < span class ="req "> *</ span > </ span >
11921215 < span class ="char-count " id ="charCount "> 0 chars</ span >
@@ -1204,6 +1227,14 @@ <h1 class="hero-h1">REPORT<br /><span class="outline">ONCE.</span></h1>
12041227 < input class ="input-field " id ="incidentIdInput " type ="text "
12051228 placeholder ="Incident ID (Optional - To append to an existing Data Lake record) " style ="margin-bottom:14px; "
12061229 oninput ="updateFillBtn() " />
1230+
1231+ < div class ="upload-zone " id ="photoZone " style ="margin-bottom:14px; padding: 15px; ">
1232+ < input type ="file " id ="photoInput " accept ="image/* " capture ="environment " onchange ="onPhotoChosen(this) " />
1233+ < span class ="upload-zone-icon " style ="font-size: 1.5rem; margin-bottom: 5px; "> 📸</ span >
1234+ < div class ="upload-zone-text "> < b > Add Scene Photo</ b > < br /> (AI will dynamically analyze details into lake)</ div >
1235+ < div class ="file-chosen " id ="photoChosen "> </ div >
1236+ </ div >
1237+
12071238 < textarea id ="incidentText "
12081239 placeholder ="Officer Hernandez responding to a structure fire at 742 Evergreen Terrace. Two occupants evacuated safely. Minor smoke inhalation treated on scene by EMS. Unit 7 on scene 14:32, cleared 16:45. Handed off to Deputy Martinez... "
12091240 oninput ="onTextInput(this) "> </ textarea >
@@ -1314,6 +1345,10 @@ <h1 class="hero-h1">REPORT<br /><span class="outline">ONCE.</span></h1>
13141345 const b = document . getElementById ( 'tplBadge' ) ;
13151346 b . className = 'selected-tpl set' ; b . textContent = `\ud83d\udccb ${ name } ` ;
13161347 document . getElementById ( 'step2' ) . classList . add ( 'done' ) ;
1348+ document . getElementById ( 'btnScan' ) . style . display = 'inline-flex' ;
1349+ document . getElementById ( 'btnScan' ) . textContent = '👁️ AI Layout Scan' ;
1350+ document . getElementById ( 'btnScan' ) . style . color = 'var(--fire)' ;
1351+ document . getElementById ( 'btnScan' ) . style . borderColor = 'rgba(255, 69, 0, 0.4)' ;
13171352 updateFillBtn ( ) ;
13181353 }
13191354
@@ -1325,6 +1360,7 @@ <h1 class="hero-h1">REPORT<br /><span class="outline">ONCE.</span></h1>
13251360 const b = document . getElementById ( 'tplBadge' ) ;
13261361 if ( count === 0 ) { b . className = 'selected-tpl none' ; b . textContent = '\u2190 Check multiple templates for batch fill' ; }
13271362 else { b . className = 'selected-tpl set' ; b . textContent = `\ud83d\udccb ${ count } template${ count > 1 ? 's' : '' } selected for batch` ; }
1363+ document . getElementById ( 'btnScan' ) . style . display = 'none' ;
13281364 if ( count > 0 ) document . getElementById ( 'step2' ) . classList . add ( 'done' ) ;
13291365 updateFillBtn ( ) ; loadTemplates ( ) ;
13301366 }
@@ -1351,6 +1387,63 @@ <h1 class="hero-h1">REPORT<br /><span class="outline">ONCE.</span></h1>
13511387 }
13521388 } ) ;
13531389
1390+ async function scanTemplate ( ) {
1391+ if ( ! selectedTplId ) return ;
1392+ const btn = document . getElementById ( 'btnScan' ) ;
1393+ btn . disabled = true ;
1394+ btn . textContent = 'Scanning...' ;
1395+ try {
1396+ const r = await fetch ( `${ API } /templates/${ selectedTplId } /scan` , { method : 'POST' } ) ;
1397+ const data = await r . json ( ) ;
1398+ if ( r . ok || data . status === 'already_scanned' ) {
1399+ btn . textContent = '✓ Scanned' ;
1400+ btn . style . color = 'var(--green)' ;
1401+ btn . style . borderColor = 'var(--green)' ;
1402+ } else {
1403+ btn . textContent = '✗ Scan Failed' ;
1404+ }
1405+ } catch {
1406+ btn . textContent = '✗ Scan Failed' ;
1407+ }
1408+ btn . disabled = false ;
1409+ }
1410+
1411+ async function onPhotoChosen ( input ) {
1412+ if ( input . files . length > 0 ) {
1413+ const file = input . files [ 0 ] ;
1414+ const ch = document . getElementById ( 'photoChosen' ) ;
1415+ ch . textContent = '⏳ Analyzing scene details...' ;
1416+ ch . style . display = 'block' ;
1417+ ch . style . color = 'var(--ember)' ;
1418+
1419+ let incidentId = document . getElementById ( 'incidentIdInput' ) . value . trim ( ) ;
1420+ if ( ! incidentId ) {
1421+ const d = new Date ( ) ;
1422+ incidentId = `INC-${ d . getFullYear ( ) } -${ String ( d . getMonth ( ) + 1 ) . padStart ( 2 , '0' ) } ${ String ( d . getDate ( ) ) . padStart ( 2 , '0' ) } -${ String ( d . getHours ( ) ) . padStart ( 2 , '0' ) } ${ String ( d . getMinutes ( ) ) . padStart ( 2 , '0' ) } ` ;
1423+ document . getElementById ( 'incidentIdInput' ) . value = incidentId ;
1424+ }
1425+
1426+ const fd = new FormData ( ) ;
1427+ fd . append ( 'file' , file ) ;
1428+
1429+ try {
1430+ const r = await fetch ( `${ API } /incidents/${ incidentId } /scene-photo` , { method : 'POST' , body : fd } ) ;
1431+ const data = await r . json ( ) ;
1432+ if ( r . ok || r . status === 200 ) {
1433+ ch . textContent = '✓ Scene visually analyzed & logged to Data Lake!' ;
1434+ ch . style . color = 'var(--green)' ;
1435+ updateFillBtn ( ) ;
1436+ } else {
1437+ ch . textContent = '✗ Analysis failed' ;
1438+ ch . style . color = 'var(--red)' ;
1439+ }
1440+ } catch {
1441+ ch . textContent = '✗ Analysis failed' ;
1442+ ch . style . color = 'var(--red)' ;
1443+ }
1444+ }
1445+ }
1446+
13541447 async function saveTemplate ( ) {
13551448 const file = document . getElementById ( 'pdfInput' ) . files [ 0 ] ;
13561449 const name = document . getElementById ( 'tplName' ) . value . trim ( ) || file ?. name . replace ( '.pdf' , '' ) || 'Untitled' ;
0 commit comments