@@ -174,6 +174,10 @@ const gpsAccEl = document.getElementById("gpsAcc");
174174const distanceInfoEl = document . getElementById ( "distanceInfo" ) ; // Distance from last ping
175175const txPingsEl = document . getElementById ( "txPings" ) ; // TX log container
176176const coverageFrameEl = document . getElementById ( "coverageFrame" ) ;
177+
178+ // Track last connection status to avoid logging spam (declared here to avoid TDZ with setConnStatus call below)
179+ let lastConnStatusText = null ;
180+
177181setConnectButton ( false ) ;
178182setConnStatus ( "Disconnected" , STATUS_COLORS . error ) ;
179183
@@ -675,7 +679,7 @@ function cleanupAllTimers() {
675679}
676680
677681function enableControls ( connected ) {
678- connectBtn . disabled = false ;
682+ setConnectButtonDisabled ( false ) ;
679683 channelInfoEl . textContent = CHANNEL_NAME ;
680684 updateControlsForCooldown ( ) ;
681685
@@ -723,6 +727,22 @@ function scheduleCoverageRefresh(lat, lon, delayMs = 0) {
723727 coverageFrameEl . src = url ;
724728 } , delayMs ) ;
725729}
730+
731+ /**
732+ * Set Connect button visual disabled state
733+ * Updates opacity and cursor to indicate whether button is clickable
734+ * @param {boolean } disabled - Whether button should appear disabled
735+ */
736+ function setConnectButtonDisabled ( disabled ) {
737+ if ( ! connectBtn ) return ;
738+ connectBtn . disabled = disabled ;
739+ if ( disabled ) {
740+ connectBtn . classList . add ( "opacity-50" , "cursor-not-allowed" ) ;
741+ } else {
742+ connectBtn . classList . remove ( "opacity-50" , "cursor-not-allowed" ) ;
743+ }
744+ }
745+
726746function setConnectButton ( connected ) {
727747 if ( ! connectBtn ) return ;
728748 if ( connected ) {
@@ -759,9 +779,6 @@ function setConnectButton(connected) {
759779 * @param {string } text - Connection status text (one of the four states above)
760780 * @param {string } color - Status color class from STATUS_COLORS
761781 */
762- // Track last connection status to avoid logging spam
763- let lastConnStatusText = null ;
764-
765782function setConnStatus ( text , color ) {
766783 const connectionStatusEl = document . getElementById ( "connectionStatus" ) ;
767784 const statusIndicatorEl = document . getElementById ( "statusIndicator" ) ;
@@ -963,7 +980,7 @@ async function performAppLaunchZoneCheck() {
963980 debugLog ( "[GEO AUTH] [INIT] Performing app launch zone check" ) ;
964981
965982 // Disable Connect button initially
966- connectBtn . disabled = true ;
983+ setConnectButtonDisabled ( true ) ;
967984 debugLog ( "[GEO AUTH] [INIT] Connect button disabled during zone check" ) ;
968985
969986 // Show "Checking zone..." status
@@ -1023,7 +1040,7 @@ async function performAppLaunchZoneCheck() {
10231040
10241041 // Enable Connect button only if in valid zone
10251042 if ( result . success && result . in_zone ) {
1026- connectBtn . disabled = false ;
1043+ setConnectButtonDisabled ( false ) ;
10271044 debugLog ( "[GEO AUTH] [INIT] ✅ Connect button enabled (in valid zone)" ) ;
10281045
10291046 // Start 30s slot refresh timer (disconnected mode)
@@ -1047,14 +1064,14 @@ async function performAppLaunchZoneCheck() {
10471064 } , 30000 ) ; // 30 seconds
10481065 debugLog ( "[GEO AUTH] [INIT] Started 30s slot refresh timer" ) ;
10491066 } else {
1050- connectBtn . disabled = true ;
1067+ setConnectButtonDisabled ( true ) ;
10511068 debugLog ( "[GEO AUTH] [INIT] ❌ Connect button remains disabled (not in valid zone or check failed)" ) ;
10521069 }
10531070
10541071 } catch ( err ) {
10551072 debugError ( `[GEO AUTH] [INIT] Exception during app launch zone check: ${ err . message } ` ) ;
10561073 updateZoneStatusUI ( null , "error" ) ;
1057- connectBtn . disabled = true ;
1074+ setConnectButtonDisabled ( true ) ;
10581075 }
10591076}
10601077
@@ -5005,7 +5022,7 @@ async function connect() {
50055022 alert ( "Web Bluetooth not supported in this browser." ) ;
50065023 return ;
50075024 }
5008- connectBtn . disabled = true ;
5025+ setConnectButtonDisabled ( true ) ;
50095026
50105027 // Hide zone status to make room for device name/noise floor
50115028 zoneStatus . classList . add ( "hidden" ) ;
@@ -5043,7 +5060,7 @@ async function connect() {
50435060 // Keep "Connecting" status visible during the full connection process
50445061 // Don't show "Connected" until everything is complete
50455062 setConnectButton ( true ) ;
5046- connectBtn . disabled = false ;
5063+ setConnectButtonDisabled ( false ) ;
50475064 const selfInfo = await conn . getSelfInfo ( ) ;
50485065 debugLog ( `[BLE] Device info: ${ selfInfo ?. name || "[No device]" } ` ) ;
50495066
@@ -5360,7 +5377,7 @@ async function connect() {
53605377 debugError ( `[BLE] BLE connection failed: ${ e . message } ` , e ) ;
53615378 setConnStatus ( "Disconnected" , STATUS_COLORS . error ) ;
53625379 setDynamicStatus ( "Connection failed" , STATUS_COLORS . error ) ;
5363- connectBtn . disabled = false ;
5380+ setConnectButtonDisabled ( false ) ;
53645381 }
53655382}
53665383async function disconnect ( ) {
@@ -5370,7 +5387,7 @@ async function disconnect() {
53705387 return ;
53715388 }
53725389
5373- connectBtn . disabled = true ;
5390+ setConnectButtonDisabled ( true ) ;
53745391
53755392 // Set disconnectReason to "normal" if not already set (for user-initiated disconnects)
53765393 if ( state . disconnectReason === null || state . disconnectReason === undefined ) {
@@ -5470,7 +5487,7 @@ async function disconnect() {
54705487 state . disconnectReason = "ble_disconnect_error" ; // Mark specific disconnect reason
54715488 state . bleDisconnectErrorMessage = e . message || "Disconnect failed" ; // Store error message
54725489 } finally {
5473- connectBtn . disabled = false ;
5490+ setConnectButtonDisabled ( false ) ;
54745491 }
54755492}
54765493
@@ -5524,7 +5541,7 @@ function updateConnectButtonState() {
55245541
55255542 if ( ! isConnected ) {
55265543 // Only enable Connect if external antenna is selected
5527- connectBtn . disabled = ! externalAntennaSelected ;
5544+ setConnectButtonDisabled ( ! externalAntennaSelected ) ;
55285545
55295546 // Update dynamic status based on selection
55305547 if ( ! externalAntennaSelected ) {
0 commit comments