fix(vision): hide detection overlay when auto-detection disabled

Add ENABLE_AUTO_DETECTION flag to ObserverVisionFeed.tsx to hide the
useless detection overlay that always showed "---" and "0%" since
auto-detection is globally disabled. This matches the pattern already
used in DockedVisionFeed.tsx.

Also includes minor formatting fixes from Biome.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2026-01-01 20:37:37 -06:00
parent 8a454158b5
commit 995cb60086
3 changed files with 86 additions and 61 deletions

View File

@@ -614,7 +614,11 @@ export function AbacusVisionBridge({
</div>
{/* Camera feed - HERO ELEMENT */}
<div ref={cameraFeedContainerRef} data-element="camera-feed-container" className={css({ position: 'relative' })}>
<div
ref={cameraFeedContainerRef}
data-element="camera-feed-container"
className={css({ position: 'relative' })}
>
{cameraSource === 'local' ? (
<>
<VisionCameraFeed
@@ -759,7 +763,9 @@ export function AbacusVisionBridge({
borderRadius: 'md',
cursor: 'pointer',
fontSize: 'md',
_hover: { bg: vision.isTorchOn ? 'yellow.500' : 'rgba(255, 255, 255, 0.25)' },
_hover: {
bg: vision.isTorchOn ? 'yellow.500' : 'rgba(255, 255, 255, 0.25)',
},
})}
title={vision.isTorchOn ? 'Turn off flash' : 'Turn on flash'}
>
@@ -988,7 +994,9 @@ export function AbacusVisionBridge({
borderRadius: 'md',
cursor: 'pointer',
fontSize: 'md',
_hover: { bg: remoteIsTorchOn ? 'yellow.500' : 'rgba(255, 255, 255, 0.25)' },
_hover: {
bg: remoteIsTorchOn ? 'yellow.500' : 'rgba(255, 255, 255, 0.25)',
},
})}
title={remoteIsTorchOn ? 'Turn off flash' : 'Turn on flash'}
>
@@ -1144,8 +1152,8 @@ export function AbacusVisionBridge({
<span className={css({ fontSize: 'sm', fontWeight: 'medium' })}>Crop</span>
<span className={css({ color: 'gray.400', fontSize: 'sm' })}>·</span>
{/* Status summary */}
{((cameraSource === 'local' && vision.isCalibrated) ||
(cameraSource === 'phone' && remoteCalibration)) ? (
{(cameraSource === 'local' && vision.isCalibrated) ||
(cameraSource === 'phone' && remoteCalibration) ? (
<span className={css({ color: 'blue.300', fontSize: 'sm' })}>Manual</span>
) : (
<span
@@ -1310,7 +1318,9 @@ export function AbacusVisionBridge({
handleRemoteStartCalibration()
}
}}
disabled={cameraSource === 'local' ? !vision.videoStream : !remoteIsPhoneConnected}
disabled={
cameraSource === 'local' ? !vision.videoStream : !remoteIsPhoneConnected
}
className={css({
px: 3,
py: 1.5,

View File

@@ -3,6 +3,12 @@
import type { ObservedVisionFrame } from '@/hooks/useSessionObserver'
import { css } from '../../../styled-system/css'
/**
* Feature flag to control auto-detection display
* When false, hides the detection overlay since auto-detection is disabled globally
*/
const ENABLE_AUTO_DETECTION = false
interface ObserverVisionFeedProps {
/** The latest vision frame from the observed student */
frame: ObservedVisionFrame
@@ -45,62 +51,64 @@ export function ObserverVisionFeed({ frame }: ObserverVisionFeedProps) {
})}
/>
{/* Detection overlay */}
<div
data-element="detection-overlay"
className={css({
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
p: 2,
bg: 'rgba(0, 0, 0, 0.7)',
backdropFilter: 'blur(4px)',
})}
>
{/* Detected value */}
<div className={css({ display: 'flex', alignItems: 'center', gap: 2 })}>
<span
className={css({
fontSize: 'lg',
fontWeight: 'bold',
color: 'white',
fontFamily: 'mono',
})}
>
{frame.detectedValue !== null ? frame.detectedValue : '---'}
</span>
{frame.detectedValue !== null && (
<span className={css({ fontSize: 'xs', color: 'gray.400' })}>
{Math.round(frame.confidence * 100)}%
{/* Detection overlay - only shown when auto-detection is enabled */}
{ENABLE_AUTO_DETECTION && (
<div
data-element="detection-overlay"
className={css({
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
p: 2,
bg: 'rgba(0, 0, 0, 0.7)',
backdropFilter: 'blur(4px)',
})}
>
{/* Detected value */}
<div className={css({ display: 'flex', alignItems: 'center', gap: 2 })}>
<span
className={css({
fontSize: 'lg',
fontWeight: 'bold',
color: 'white',
fontFamily: 'mono',
})}
>
{frame.detectedValue !== null ? frame.detectedValue : '---'}
</span>
)}
</div>
{frame.detectedValue !== null && (
<span className={css({ fontSize: 'xs', color: 'gray.400' })}>
{Math.round(frame.confidence * 100)}%
</span>
)}
</div>
{/* Live indicator */}
<div className={css({ display: 'flex', alignItems: 'center', gap: 1 })}>
<div
className={css({
w: '8px',
h: '8px',
borderRadius: 'full',
bg: isStale ? 'gray.500' : 'green.500',
animation: isStale ? 'none' : 'pulse 2s infinite',
})}
/>
<span
className={css({
fontSize: 'xs',
color: isStale ? 'gray.500' : 'green.400',
})}
>
{isStale ? 'Stale' : 'Live'}
</span>
{/* Live indicator */}
<div className={css({ display: 'flex', alignItems: 'center', gap: 1 })}>
<div
className={css({
w: '8px',
h: '8px',
borderRadius: 'full',
bg: isStale ? 'gray.500' : 'green.500',
animation: isStale ? 'none' : 'pulse 2s infinite',
})}
/>
<span
className={css({
fontSize: 'xs',
color: isStale ? 'gray.500' : 'green.400',
})}
>
{isStale ? 'Stale' : 'Live'}
</span>
</div>
</div>
</div>
)}
{/* Vision mode badge */}
<div

View File

@@ -32,8 +32,15 @@ export function RemoteCameraQRCode({
existingSessionId,
compact = false,
}: RemoteCameraQRCodeProps) {
const { session, isCreating, error, createSession, setExistingSession, clearSession, getPhoneUrl } =
useRemoteCameraSession()
const {
session,
isCreating,
error,
createSession,
setExistingSession,
clearSession,
getPhoneUrl,
} = useRemoteCameraSession()
// Ref to track if we've already initiated session creation
// This prevents React 18 Strict Mode from creating duplicate sessions