AudioCortesia / components /DeviceScanner.tsx
Lukeetah's picture
Upload 7 files
8fcabb2 verified
import React, { useCallback } from 'react';
import type { BluetoothDevice, Action } from '../types.ts';
import { DeviceStatus } from '../types.ts';
import { DeviceCard } from './DeviceCard.tsx';
import { ScanIcon } from './icons.tsx';
interface DeviceScannerProps {
devices: BluetoothDevice[];
onScan: () => void;
dispatch: React.Dispatch<Action>;
isScanning: boolean;
}
export const DeviceScanner: React.FC<DeviceScannerProps> = ({ devices, onScan, dispatch, isScanning }) => {
const handleConnect = useCallback((id: string) => {
dispatch({ type: 'UPDATE_STATUS', payload: { id, status: DeviceStatus.Connecting } });
setTimeout(() => {
const randomLatency = Math.floor(Math.random() * 50) + 5;
dispatch({ type: 'UPDATE_STATUS', payload: { id, status: DeviceStatus.Connected, latency: randomLatency } });
}, 1500);
}, [dispatch]);
return (
<div className="bg-slate-800/50 rounded-lg p-6 shadow-lg h-full flex flex-col">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-semibold text-white">Available Devices</h2>
<button
onClick={onScan}
disabled={isScanning}
className="flex items-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:bg-slate-600 disabled:cursor-not-allowed transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-slate-900"
aria-label={isScanning ? 'Scanning for devices' : 'Scan for new devices'}
>
{isScanning ? (
<svg className="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
) : (
<ScanIcon className="h-5 w-5" />
)}
<span>{isScanning ? 'Scanning...' : 'Scan'}</span>
</button>
</div>
<div className="flex-grow overflow-y-auto pr-2 -mr-2 space-y-3">
{isScanning && devices.length === 0 && (
<div className="text-center py-10 text-slate-400">
<p>Searching for nearby devices...</p>
</div>
)}
{!isScanning && devices.length === 0 && (
<div className="text-center py-10 text-slate-400">
<p>No devices found. Try scanning again.</p>
</div>
)}
{devices.map(device => (
<DeviceCard key={device.id} device={device} onConnect={handleConnect} />
))}
</div>
</div>
);
};