diff --git a/attached_assets/image_1752931100350.png b/attached_assets/image_1752931100350.png new file mode 100644 index 0000000..ed7632e Binary files /dev/null and b/attached_assets/image_1752931100350.png differ diff --git a/client/src/components/NewSaleFormMulti.tsx b/client/src/components/NewSaleFormMulti.tsx index 61fa43b..16148ba 100644 --- a/client/src/components/NewSaleFormMulti.tsx +++ b/client/src/components/NewSaleFormMulti.tsx @@ -137,7 +137,84 @@ export default function NewSaleFormMulti() { }; const handlePhotoCapture = async (photoType: PhotoType) => { - await startCamera(photoType); + console.log('=== PHOTO CAPTURE REQUESTED ==='); + console.log('Photo type:', photoType); + + // Vérifications préliminaires + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + toast({ + title: "Navigateur non compatible", + description: "Votre navigateur ne supporte pas la capture photo. Utilisez Chrome, Firefox ou Safari récent.", + variant: "destructive", + }); + return; + } + + // Vérifier si nous sommes en HTTPS (requis par certains navigateurs) + if (location.protocol !== 'https:' && location.hostname !== 'localhost') { + toast({ + title: "Connexion sécurisée requise", + description: "L'accès à la caméra nécessite une connexion HTTPS.", + variant: "destructive", + }); + return; + } + + try { + console.log('Attempting to start camera...'); + + // Afficher toast de démarrage + toast({ + title: "Démarrage de la caméra", + description: "Préparation de la caméra en cours...", + }); + + // Démarrer la caméra simple + await startCamera(photoType); + console.log('Simple camera started successfully'); + + } catch (error) { + console.error('Camera start failed:', error); + toast({ + title: "Erreur d'accès à la caméra", + description: error instanceof Error ? error.message : "Impossible d'accéder à la caméra", + variant: "destructive", + }); + } + }; + + const handleCapturePhoto = async () => { + if (!currentPhotoType) return; + + try { + console.log('Attempting to capture photo...'); + const photoData = await capturePhoto(); + console.log('Photo captured successfully, data length:', photoData.length); + + if (currentPhotoType === 'recto') { + form.setValue('photoRecto', photoData); + } else if (currentPhotoType === 'verso') { + form.setValue('photoVerso', photoData); + } else if (currentPhotoType === 'ticket') { + form.setValue('photoTicket', photoData); + } + + toast({ + title: "Photo capturée", + description: `Photo ${currentPhotoType} enregistrée avec succès`, + variant: "success", + }); + + stopCamera(); + + } catch (error) { + console.error('Photo capture failed:', error); + toast({ + title: "Erreur de capture", + description: error instanceof Error ? error.message : "Impossible de capturer la photo", + variant: "destructive", + }); + } }; const handleRemovePhoto = (photoType: PhotoType) => { @@ -188,7 +265,7 @@ export default function NewSaleFormMulti() { canvasRef={canvasRef} isCapturing={isCapturing} onClose={stopCamera} - onCapture={capturePhoto} + onCapture={handleCapturePhoto} />
diff --git a/client/src/hooks/useSimpleCamera.tsx b/client/src/hooks/useSimpleCamera.tsx index 6a15264..5f7df35 100644 --- a/client/src/hooks/useSimpleCamera.tsx +++ b/client/src/hooks/useSimpleCamera.tsx @@ -19,14 +19,49 @@ export function useSimpleCamera() { stream.getTracks().forEach(track => track.stop()); } - // Demander l'accès à la caméra - const mediaStream = await navigator.mediaDevices.getUserMedia({ - video: { - width: { ideal: 1280 }, - height: { ideal: 720 }, - facingMode: 'environment' + // Vérifier la disponibilité des médias + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + throw new Error('Votre navigateur ne supporte pas l\'accès à la caméra. Utilisez un navigateur moderne comme Chrome, Firefox ou Safari.'); + } + + let mediaStream: MediaStream; + + try { + // Essayer d'abord avec des contraintes avancées + mediaStream = await navigator.mediaDevices.getUserMedia({ + video: { + width: { ideal: 1280 }, + height: { ideal: 720 }, + facingMode: 'environment' + } + }); + } catch (constraintError) { + console.warn('Failed with advanced constraints, trying basic video:', constraintError); + + try { + // Fallback avec des contraintes basiques + mediaStream = await navigator.mediaDevices.getUserMedia({ + video: true + }); + } catch (basicError) { + console.error('Basic camera access failed:', basicError); + + // Gestion des erreurs spécifiques + if (basicError instanceof Error) { + if (basicError.name === 'NotAllowedError') { + throw new Error('Permission d\'accès à la caméra refusée. Veuillez autoriser l\'accès dans votre navigateur et actualiser la page.'); + } else if (basicError.name === 'NotFoundError') { + throw new Error('Aucune caméra trouvée sur cet appareil. Veuillez connecter une caméra ou utiliser l\'option d\'importation de fichier.'); + } else if (basicError.name === 'NotReadableError') { + throw new Error('Caméra déjà utilisée par une autre application. Fermez les autres applications utilisant la caméra.'); + } else if (basicError.name === 'OverconstrainedError') { + throw new Error('Contraintes de caméra non supportées par votre appareil.'); + } + } + + throw new Error('Erreur d\'accès à la caméra. Utilisez l\'option d\'importation de fichier comme alternative.'); } - }); + } console.log('Media stream obtained:', mediaStream); setStream(mediaStream); @@ -55,6 +90,9 @@ export function useSimpleCamera() { } catch (error) { console.error('Camera start failed:', error); + // Nettoyer l'état en cas d'erreur + setIsOpen(false); + setCurrentPhotoType(null); throw error; } }, [stream]);