From 90e719368264688210abb4aebd285f388b4da7fa Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Sat, 19 Jul 2025 13:02:06 +0000 Subject: [PATCH] Improve camera functionality and integrate it into the product forms Refactors camera modal to use a custom hook for simplified photo capture logic across NewSaleForm and NewSaleFormMultiProduct components. Replit-Commit-Author: Agent Replit-Commit-Session-Id: c7151ec8-4e6b-4fcf-b628-65b094ac18fd Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0715008c-7244-40f4-befc-26c014852236/c7151ec8-4e6b-4fcf-b628-65b094ac18fd/URbRU29 --- client/src/components/NewSaleForm.tsx | 8 +- .../components/NewSaleFormMultiProduct.tsx | 134 ++++++++---------- 2 files changed, 61 insertions(+), 81 deletions(-) diff --git a/client/src/components/NewSaleForm.tsx b/client/src/components/NewSaleForm.tsx index ea6e8eb..60ce8ca 100644 --- a/client/src/components/NewSaleForm.tsx +++ b/client/src/components/NewSaleForm.tsx @@ -14,7 +14,7 @@ import { useSimpleCamera } from '@/hooks/useSimpleCamera'; import { apiRequest } from '@/lib/queryClient'; import { validateRequiredFields, validateEAN13, ARTICLE_CATEGORY_MAPPING, IDENTITY_TYPES, PAYMENT_METHODS } from '@/lib/validation'; import { Package, User, Users, Save, Calendar, BadgeCheck, Info, Camera, Upload, Trash2 } from 'lucide-react'; -import SimpleCameraModal from '@/components/SimpleCameraModal'; +import CameraModal from '@/components/CameraModal'; import type { PhotoType } from '@/types/sale'; interface Product { @@ -245,7 +245,7 @@ export default function NewSaleForm() { } }; - const handleTakePhoto = async () => { + const handleCapture = async () => { if (!currentPhotoType) return; try { @@ -833,14 +833,14 @@ export default function NewSaleForm() { {/* Camera Modal */} - ); diff --git a/client/src/components/NewSaleFormMultiProduct.tsx b/client/src/components/NewSaleFormMultiProduct.tsx index e4c0ca8..e903d78 100644 --- a/client/src/components/NewSaleFormMultiProduct.tsx +++ b/client/src/components/NewSaleFormMultiProduct.tsx @@ -11,8 +11,10 @@ import { useToast } from "@/hooks/use-toast"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@/lib/queryClient"; import { useStoreContext } from "@/hooks/useStoreContext"; -import { Package, User, Users, IdCard, Camera, Plus, Minus, Info, X } from "lucide-react"; +import { Package, User, Users, IdCard, Camera, Plus, Minus, Info } from "lucide-react"; import { validateEAN13, ARTICLE_CATEGORY_MAPPING, PAYMENT_METHODS, IDENTITY_TYPES } from "@/lib/validation"; +import CameraModal from "@/components/CameraModal"; +import { useSimpleCamera } from "@/hooks/useSimpleCamera"; // Types pour les photos type PhotoType = 'recto' | 'verso' | 'ticket'; @@ -50,9 +52,18 @@ export default function NewSaleFormMultiProduct() { const queryClient = useQueryClient(); const { selectedStoreId } = useStoreContext(); - // États pour les photos - const [currentPhotoType, setCurrentPhotoType] = useState(null); - const [isCameraOpen, setIsCameraOpen] = useState(false); + // Hook camera qui fonctionne + const { + isOpen: isCameraOpen, + currentPhotoType, + isCapturing, + videoRef, + canvasRef, + startCamera, + capturePhoto, + stopCamera + } = useSimpleCamera(); + const [isSubmitting, setIsSubmitting] = useState(false); // Formulaire avec valeurs par défaut @@ -183,28 +194,41 @@ export default function NewSaleFormMultiProduct() { } }; - // Gestion des photos - const handlePhotoCapture = (photoType: PhotoType) => { - setCurrentPhotoType(photoType); - setIsCameraOpen(true); + // Gestion des photos avec le hook qui fonctionne + const handlePhotoCapture = async (photoType: PhotoType) => { + try { + await startCamera(photoType); + } catch (error) { + console.error('Erreur ouverture caméra:', error); + toast({ + title: "Erreur caméra", + description: "Impossible d'accéder à la caméra. Vérifiez les autorisations.", + variant: "destructive", + }); + } }; - const handlePhotoTaken = (photoData: string) => { - if (currentPhotoType === 'recto') { - form.setValue('photoRecto', photoData); - } else if (currentPhotoType === 'verso') { - form.setValue('photoVerso', photoData); - } else if (currentPhotoType === 'ticket') { - form.setValue('photoTicket', photoData); + const handleCapture = async () => { + try { + const photoData = await capturePhoto(); + if (currentPhotoType) { + const fieldName = `photo${currentPhotoType.charAt(0).toUpperCase() + currentPhotoType.slice(1)}` as keyof FormData; + form.setValue(fieldName, photoData); + + toast({ + title: "Photo capturée", + description: `Photo ${currentPhotoType} enregistrée avec succès`, + }); + } + stopCamera(); + } catch (error) { + console.error('Erreur capture:', error); + toast({ + title: "Erreur capture", + description: "Impossible de capturer la photo", + variant: "destructive", + }); } - - toast({ - title: "Photo capturée", - description: `Photo ${currentPhotoType} enregistrée avec succès`, - }); - - setIsCameraOpen(false); - setCurrentPhotoType(null); }; const handleRemovePhoto = (photoType: PhotoType) => { @@ -667,60 +691,16 @@ export default function NewSaleFormMultiProduct() { - {/* Modal Camera */} - {isCameraOpen && ( -
-
-
-

- Capturer photo {currentPhotoType} -

- -
- -
-
-

- La capture photo sera bientôt disponible. -

- { - const file = e.target.files?.[0]; - if (file) { - const reader = new FileReader(); - reader.onload = (event) => { - const photoData = event.target?.result as string; - handlePhotoTaken(photoData); - }; - reader.readAsDataURL(file); - } - }} - className="hidden" - id="photo-upload" - /> - -
-
-
-
- )} + {/* Modal Camera qui fonctionne */} + ); } \ No newline at end of file