fix(camera): default to back camera, add flip button, fix settings crash on mobile

This commit is contained in:
Jacques committed 2026-01-22 21:19:51 +01:00
1 parent 5e50399457
commit be940cd54c
1 file changed
+32 -19
+32 -19
View File
@@ -4,7 +4,6 @@ import Webcam from 'react-webcam';
import { Camera, StopCircle, RefreshCw, CheckCircle, X, RotateCcw, Settings2, AlertCircle, Video } from 'lucide-react'; import { Camera, StopCircle, RefreshCw, CheckCircle, X, RotateCcw, Settings2, AlertCircle, Video } from 'lucide-react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
interface CameraRecorderProps { interface CameraRecorderProps {
onCapture: (file: File) => void; onCapture: (file: File) => void;
@@ -40,6 +39,7 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
// Devices & Settings // Devices & Settings
const [devices, setDevices] = useState<MediaDeviceInfo[]>([]); const [devices, setDevices] = useState<MediaDeviceInfo[]>([]);
const [selectedDeviceId, setSelectedDeviceId] = useState<string>(''); const [selectedDeviceId, setSelectedDeviceId] = useState<string>('');
const [facingMode, setFacingMode] = useState<"user" | "environment">("environment");
const [quality, setQuality] = useState<VideoQuality>('1080p'); const [quality, setQuality] = useState<VideoQuality>('1080p');
const [showSettings, setShowSettings] = useState(false); const [showSettings, setShowSettings] = useState(false);
const [cameraError, setCameraError] = useState<string | null>(null); const [cameraError, setCameraError] = useState<string | null>(null);
@@ -131,6 +131,11 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
setCameraError(msg); setCameraError(msg);
}, []); }, []);
const toggleCamera = () => {
setFacingMode(prev => prev === "user" ? "environment" : "user");
setSelectedDeviceId('');
};
// Review Mode // Review Mode
if (recordedBlob && previewUrl) { if (recordedBlob && previewUrl) {
return ( return (
@@ -153,7 +158,7 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
width: { ideal: config.width }, width: { ideal: config.width },
height: { ideal: config.height }, height: { ideal: config.height },
deviceId: selectedDeviceId ? { exact: selectedDeviceId } : undefined, deviceId: selectedDeviceId ? { exact: selectedDeviceId } : undefined,
facingMode: selectedDeviceId ? undefined : "user" facingMode: selectedDeviceId ? undefined : facingMode
}; };
return ( return (
@@ -173,10 +178,15 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
{formatTime(timer)} {formatTime(timer)}
</div> </div>
) : ( ) : (
<Button variant="outline" size="sm" onClick={() => setShowSettings(!showSettings)} className="bg-black/30 border-white/20 text-white backdrop-blur"> <div className="flex gap-2">
<Settings2 className="mr-2 h-4 w-4" /> <Button variant="outline" size="icon" onClick={toggleCamera} className="bg-black/30 border-white/20 text-white backdrop-blur">
<span className="hidden sm:inline">Réglages</span> <RefreshCw className="h-4 w-4" />
</Button> </Button>
<Button variant="outline" size="sm" onClick={() => setShowSettings(!showSettings)} className="bg-black/30 border-white/20 text-white backdrop-blur">
<Settings2 className="mr-2 h-4 w-4" />
<span className="hidden sm:inline">Réglages</span>
</Button>
</div>
)} )}
</div> </div>
<div className="w-10"></div> <div className="w-10"></div>
@@ -205,19 +215,22 @@ export function CameraRecorder({ onCapture, onCancel }: CameraRecorderProps) {
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<label className="text-sm font-medium text-white/70">Caméra</label> <label className="text-sm font-medium text-white/70 block mb-2">Caméra</label>
<Select value={selectedDeviceId} onValueChange={setSelectedDeviceId}> <Button variant="outline" className="w-full justify-start text-white border-white/20 hover:bg-white/10 mb-2" onClick={toggleCamera}>
<SelectTrigger className="w-full bg-white/5 border-white/10 text-white mt-1"> <RefreshCw className="mr-2 h-4 w-4" />
<SelectValue placeholder="Choisir..." /> Basculer Avant/Arrière
</SelectTrigger> </Button>
<SelectContent className="bg-[#2c2c2e] border-white/10 text-white"> <div className="space-y-1 max-h-32 overflow-y-auto">
{devices.map((device) => ( {devices.map((device, idx) => (
<SelectItem key={device.deviceId} value={device.deviceId}> <button
{device.label || `Caméra ${device.deviceId.slice(0, 5)}...`} key={device.deviceId || idx}
</SelectItem> onClick={() => setSelectedDeviceId(device.deviceId)}
))} className={`w-full text-left px-3 py-2 rounded text-sm truncate border transition-colors ${selectedDeviceId === device.deviceId ? 'bg-white text-black' : 'bg-transparent text-white border-white/20 hover:bg-white/10'}`}
</SelectContent> >
</Select> {device.label || `Caméra ${idx + 1}`}
</button>
))}
</div>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-white/70">Qualité</label> <label className="text-sm font-medium text-white/70">Qualité</label>