mirror of
https://github.com/R0m1k3/Regisflow.git
synced 2026-10-24 15:48:17 +02:00
Improve camera support and photo capture, especially on tablets
Enhance camera functionalities with improved constraints, fallbacks, UI, and error handling within CameraModal and useCamera hook. Replit-Commit-Author: Agent Replit-Commit-Session-Id: dec54137-d5a2-4406-8ad4-5f2f9fb110bf Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0715008c-7244-40f4-befc-26c014852236/dcf949f8-2931-4556-aa3c-e4bf61346ee3.jpg
This commit is contained in:
1 parent
a589c8b770
commit
9b0a09614a
4 files changed
+82
-9
No files matched your search
@@ -32,7 +32,7 @@ export default function CameraModal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||||
<DialogContent className="max-w-md">
|
<DialogContent className="max-w-lg w-full mx-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
Photo {photoType ? photoType.charAt(0).toUpperCase() + photoType.slice(1) : ''}
|
Photo {photoType ? photoType.charAt(0).toUpperCase() + photoType.slice(1) : ''}
|
||||||
@@ -46,20 +46,33 @@ export default function CameraModal({
|
|||||||
autoPlay
|
autoPlay
|
||||||
playsInline
|
playsInline
|
||||||
muted
|
muted
|
||||||
className="w-full camera-preview"
|
className="w-full max-w-full h-auto camera-preview rounded-lg border"
|
||||||
|
style={{
|
||||||
|
aspectRatio: '16/9',
|
||||||
|
objectFit: 'cover',
|
||||||
|
maxHeight: '400px'
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<canvas ref={canvasRef} className="hidden" />
|
<canvas ref={canvasRef} className="hidden" />
|
||||||
|
|
||||||
|
{/* Overlay pour aider à cadrer la pièce d'identité */}
|
||||||
|
<div className="absolute inset-0 pointer-events-none">
|
||||||
|
<div className="absolute inset-4 border-2 border-white border-dashed rounded-lg opacity-50"></div>
|
||||||
|
<div className="absolute bottom-2 left-2 text-white text-sm bg-black bg-opacity-50 px-2 py-1 rounded">
|
||||||
|
Cadrez la pièce d'identité dans le rectangle
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end space-x-3">
|
<div className="flex justify-between space-x-3">
|
||||||
<Button variant="outline" onClick={onClose}>
|
<Button variant="outline" onClick={onClose} className="flex-1">
|
||||||
<X className="h-4 w-4 mr-2" />
|
<X className="h-4 w-4 mr-2" />
|
||||||
Fermer
|
Fermer
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={onCapture}
|
onClick={onCapture}
|
||||||
disabled={isCapturing}
|
disabled={isCapturing}
|
||||||
className="bg-primary hover:bg-primary/90"
|
className="bg-primary hover:bg-primary/90 flex-1"
|
||||||
>
|
>
|
||||||
<Camera className="h-4 w-4 mr-2" />
|
<Camera className="h-4 w-4 mr-2" />
|
||||||
{isCapturing ? 'Capture...' : 'Prendre la photo'}
|
{isCapturing ? 'Capture...' : 'Prendre la photo'}
|
||||||
|
|||||||
@@ -180,6 +180,16 @@ export default function NewSaleForm() {
|
|||||||
|
|
||||||
// Photo capture functions
|
// Photo capture functions
|
||||||
const handlePhotoCapture = async (photoType: PhotoType) => {
|
const handlePhotoCapture = async (photoType: PhotoType) => {
|
||||||
|
// Vérifier d'abord si les caméras sont supportées
|
||||||
|
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
||||||
|
toast({
|
||||||
|
title: "Caméra non supportée",
|
||||||
|
description: "Votre navigateur ne supporte pas l'accès aux caméras",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await startCamera(photoType);
|
await startCamera(photoType);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -12,9 +12,47 @@ export function useCamera() {
|
|||||||
|
|
||||||
const startCamera = useCallback(async (photoType: PhotoType) => {
|
const startCamera = useCallback(async (photoType: PhotoType) => {
|
||||||
try {
|
try {
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({
|
// Configuration avancée pour tablettes et appareils mobiles
|
||||||
video: { facingMode: 'environment' }
|
const constraints = {
|
||||||
});
|
video: {
|
||||||
|
facingMode: 'environment', // Caméra arrière par défaut
|
||||||
|
width: { ideal: 1280, max: 1920 }, // Résolution optimale
|
||||||
|
height: { ideal: 720, max: 1080 },
|
||||||
|
aspectRatio: { ideal: 16/9 },
|
||||||
|
frameRate: { ideal: 30 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let stream: MediaStream;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Essai avec caméra arrière
|
||||||
|
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||||
|
} catch (backCameraError) {
|
||||||
|
console.warn('Caméra arrière non disponible, essai avec caméra avant:', backCameraError);
|
||||||
|
|
||||||
|
// Fallback vers caméra avant si arrière non disponible
|
||||||
|
const frontConstraints = {
|
||||||
|
video: {
|
||||||
|
facingMode: 'user',
|
||||||
|
width: { ideal: 1280, max: 1920 },
|
||||||
|
height: { ideal: 720, max: 1080 },
|
||||||
|
aspectRatio: { ideal: 16/9 },
|
||||||
|
frameRate: { ideal: 30 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
stream = await navigator.mediaDevices.getUserMedia(frontConstraints);
|
||||||
|
} catch (frontCameraError) {
|
||||||
|
console.warn('Caméra avant non disponible, essai basique:', frontCameraError);
|
||||||
|
|
||||||
|
// Fallback minimal pour compatibilité maximale
|
||||||
|
stream = await navigator.mediaDevices.getUserMedia({
|
||||||
|
video: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
streamRef.current = stream;
|
streamRef.current = stream;
|
||||||
setCurrentPhotoType(photoType);
|
setCurrentPhotoType(photoType);
|
||||||
@@ -27,7 +65,7 @@ export function useCamera() {
|
|||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Camera error:', error);
|
console.error('Camera error:', error);
|
||||||
throw new Error('Impossible d\'accéder à la caméra');
|
throw new Error('Impossible d\'accéder à la caméra. Vérifiez les permissions et la disponibilité des caméras.');
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -248,6 +248,18 @@ Preferred communication style: Simple, everyday language.
|
|||||||
- ✅ Modern, crisp appearance with 4px border-radius for cards, inputs, and buttons
|
- ✅ Modern, crisp appearance with 4px border-radius for cards, inputs, and buttons
|
||||||
- ✅ White background for all input fields for better contrast and readability
|
- ✅ White background for all input fields for better contrast and readability
|
||||||
|
|
||||||
|
### Photo Capture System & Tablet Support (January 11, 2025)
|
||||||
|
- ✅ Restored complete photo capture functionality for identity documents (recto/verso)
|
||||||
|
- ✅ Added photo download capability from sales history modal with structured filenames
|
||||||
|
- ✅ Enhanced camera support for tablets with advanced constraint handling
|
||||||
|
- ✅ Multi-fallback camera system: environment → user → basic video for maximum compatibility
|
||||||
|
- ✅ Optimized video resolution for tablets (1280x720 ideal, up to 1920x1080)
|
||||||
|
- ✅ Added visual framing overlay to help users position identity documents correctly
|
||||||
|
- ✅ Improved CameraModal with better responsive design for tablet screens
|
||||||
|
- ✅ Enhanced error handling with device-specific camera availability checks
|
||||||
|
- ✅ Camera permission detection and clear error messages for troubleshooting
|
||||||
|
- ✅ Support for both front and rear cameras on tablets and mobile devices
|
||||||
|
|
||||||
### Docker Configuration & Cleanup (January 9, 2025)
|
### Docker Configuration & Cleanup (January 9, 2025)
|
||||||
- ✅ Complete Docker setup optimized for external PostgreSQL database
|
- ✅ Complete Docker setup optimized for external PostgreSQL database
|
||||||
- ✅ Docker Compose configuration with RegisFlow application only
|
- ✅ Docker Compose configuration with RegisFlow application only
|
||||||
|
|||||||
Reference in new issue
Block a user