deckhearth/src/components/DebugInfo.tsx
Randall Stillwell 331911cd2b Add debug component to troubleshoot scanner issues
🔧 Debug Component:
- Add DebugInfo component to Scanner page
- Tests camera support and permissions
- Tests API connectivity and token validation
- Shows detailed error information
- Helps diagnose both collection API and camera issues

This will help identify:
 Why collections API fails in browser but works in curl
 Why camera UI doesn't appear after starting camera
 Token/authentication issues
 Browser permissions and support
2025-07-22 08:27:11 -05:00

144 lines
No EOL
4.1 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { useAuth } from '../contexts/AuthContext';
const DebugInfo: React.FC = () => {
const { user } = useAuth();
const [debugInfo, setDebugInfo] = useState<any>(null);
const [cameraSupported, setCameraSupported] = useState<boolean | null>(null);
useEffect(() => {
// Check camera support
setCameraSupported(
navigator.mediaDevices &&
navigator.mediaDevices.getUserMedia &&
typeof navigator.mediaDevices.getUserMedia === 'function'
);
// Test API connectivity
testAPIs();
}, [user]);
const testAPIs = async () => {
const token = localStorage.getItem('token');
const results: any = {
token: token ? `${token.substring(0, 20)}...` : 'No token',
tokenLength: token?.length || 0,
user: user ? {
id: user.id,
username: user.username,
roles: user.roles
} : 'Not logged in'
};
try {
// Test collections API
const collectionsResponse = await fetch('/api/collections', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
results.collectionsAPI = {
status: collectionsResponse.status,
ok: collectionsResponse.ok,
data: collectionsResponse.ok ? await collectionsResponse.json() : await collectionsResponse.text()
};
} catch (error: any) {
results.collectionsAPI = {
error: error.message
};
}
setDebugInfo(results);
};
const testCamera = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'environment' }
});
setDebugInfo((prev: any) => ({
...prev,
cameraTest: '✅ Camera access successful',
cameraStream: {
active: stream.active,
tracks: stream.getVideoTracks().length
}
}));
// Stop the test stream
stream.getTracks().forEach(track => track.stop());
} catch (error: any) {
setDebugInfo((prev: any) => ({
...prev,
cameraTest: `❌ Camera error: ${error.message}`,
cameraError: error.name
}));
}
};
if (!debugInfo) return <div>Loading debug info...</div>;
return (
<div className="bg-gray-100 border border-gray-300 rounded-lg p-4 mb-6">
<h3 className="font-bold text-gray-900 mb-3">🔧 Debug Information</h3>
<div className="space-y-3 text-sm">
<div>
<strong>Camera Support:</strong> {cameraSupported ? '✅ Supported' : '❌ Not supported'}
</div>
<div>
<strong>User:</strong> {JSON.stringify(debugInfo.user, null, 2)}
</div>
<div>
<strong>Token:</strong> {debugInfo.token} (Length: {debugInfo.tokenLength})
</div>
<div>
<strong>Collections API:</strong>
<pre className="mt-1 bg-white p-2 rounded text-xs overflow-x-auto">
{JSON.stringify(debugInfo.collectionsAPI, null, 2)}
</pre>
</div>
{debugInfo.cameraTest && (
<div>
<strong>Camera Test:</strong> {debugInfo.cameraTest}
{debugInfo.cameraStream && (
<div className="ml-4 text-xs">
Active: {debugInfo.cameraStream.active ? 'Yes' : 'No'},
Tracks: {debugInfo.cameraStream.tracks}
</div>
)}
{debugInfo.cameraError && (
<div className="ml-4 text-xs text-red-600">
Error Type: {debugInfo.cameraError}
</div>
)}
</div>
)}
</div>
<div className="mt-4 space-x-2">
<button
onClick={testCamera}
className="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded text-sm"
>
Test Camera
</button>
<button
onClick={testAPIs}
className="bg-green-600 hover:bg-green-700 text-white px-3 py-1 rounded text-sm"
>
Refresh API Test
</button>
</div>
</div>
);
};
export default DebugInfo;