mirror of
https://github.com/R0m1k3/Regisflow.git
synced 2026-10-22 14:48:19 +02:00
Restore camera functionality and update new sales form component
Refactors CameraModal.tsx to restore camera functionality, updates NewSaleForm to NewSaleFormMultiProduct in FireworksApp.tsx. 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/PgD91fN
This commit is contained in:
1 parent
d1f3fced74
commit
e38d967015
2 files changed
+54
-86
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useRef, useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Camera, X } from 'lucide-react';
|
import { Camera, X } from 'lucide-react';
|
||||||
@@ -7,108 +7,76 @@ import { PhotoType } from '@/types/sale';
|
|||||||
interface CameraModalProps {
|
interface CameraModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
photoType: PhotoType | null;
|
photoType: PhotoType | null;
|
||||||
|
videoRef: React.RefObject<HTMLVideoElement>;
|
||||||
|
canvasRef: React.RefObject<HTMLCanvasElement>;
|
||||||
|
isCapturing: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onPhotoTaken: (photoData: string) => void;
|
onCapture: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CameraModal({
|
export default function CameraModal({
|
||||||
isOpen,
|
isOpen,
|
||||||
photoType,
|
photoType,
|
||||||
|
videoRef,
|
||||||
|
canvasRef,
|
||||||
|
isCapturing,
|
||||||
onClose,
|
onClose,
|
||||||
onPhotoTaken
|
onCapture
|
||||||
}: CameraModalProps) {
|
}: CameraModalProps) {
|
||||||
const videoRef = useRef<HTMLVideoElement>(null);
|
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
||||||
const [stream, setStream] = useState<MediaStream | null>(null);
|
|
||||||
const [isCapturing, setIsCapturing] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen && videoRef.current) {
|
||||||
startCamera();
|
const video = videoRef.current;
|
||||||
} else {
|
console.log('CameraModal useEffect - video element ready');
|
||||||
stopCamera();
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
const handleLoadedMetadata = () => {
|
||||||
stopCamera();
|
console.log('CameraModal: Video metadata loaded, dimensions:', video.videoWidth, 'x', video.videoHeight);
|
||||||
};
|
};
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
const startCamera = async () => {
|
const handleCanPlay = () => {
|
||||||
try {
|
console.log('CameraModal: Video can play, readyState:', video.readyState);
|
||||||
const mediaStream = await navigator.mediaDevices.getUserMedia({
|
};
|
||||||
video: {
|
|
||||||
facingMode: 'environment',
|
const handleError = (error: Event) => {
|
||||||
width: { ideal: 1280 },
|
console.error('CameraModal: Video error event:', error);
|
||||||
height: { ideal: 720 }
|
};
|
||||||
|
|
||||||
|
const handlePlay = () => {
|
||||||
|
console.log('CameraModal: Video started playing');
|
||||||
|
};
|
||||||
|
|
||||||
|
video.addEventListener('loadedmetadata', handleLoadedMetadata);
|
||||||
|
video.addEventListener('canplay', handleCanPlay);
|
||||||
|
video.addEventListener('error', handleError);
|
||||||
|
video.addEventListener('play', handlePlay);
|
||||||
|
|
||||||
|
// Forcer le play avec gestion d'erreur
|
||||||
|
const startPlayback = async () => {
|
||||||
|
try {
|
||||||
|
await video.play();
|
||||||
|
console.log('CameraModal: Video play() successful');
|
||||||
|
} catch (playError) {
|
||||||
|
console.error('CameraModal: Video play() failed:', playError);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
if (videoRef.current) {
|
startPlayback();
|
||||||
videoRef.current.srcObject = mediaStream;
|
|
||||||
setStream(mediaStream);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error accessing camera:', error);
|
|
||||||
// Fallback: try without specific constraints
|
|
||||||
try {
|
|
||||||
const mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
||||||
video: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (videoRef.current) {
|
return () => {
|
||||||
videoRef.current.srcObject = mediaStream;
|
video.removeEventListener('loadedmetadata', handleLoadedMetadata);
|
||||||
setStream(mediaStream);
|
video.removeEventListener('canplay', handleCanPlay);
|
||||||
}
|
video.removeEventListener('error', handleError);
|
||||||
} catch (fallbackError) {
|
video.removeEventListener('play', handlePlay);
|
||||||
console.error('Fallback camera access failed:', fallbackError);
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}, [isOpen, videoRef]);
|
||||||
|
|
||||||
const stopCamera = () => {
|
|
||||||
if (stream) {
|
|
||||||
stream.getTracks().forEach(track => track.stop());
|
|
||||||
setStream(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const capturePhoto = () => {
|
|
||||||
if (!videoRef.current || !canvasRef.current) return;
|
|
||||||
|
|
||||||
setIsCapturing(true);
|
|
||||||
const video = videoRef.current;
|
|
||||||
const canvas = canvasRef.current;
|
|
||||||
const context = canvas.getContext('2d');
|
|
||||||
|
|
||||||
if (!context) return;
|
|
||||||
|
|
||||||
// Set canvas dimensions to match video
|
|
||||||
canvas.width = video.videoWidth;
|
|
||||||
canvas.height = video.videoHeight;
|
|
||||||
|
|
||||||
// Draw video frame to canvas
|
|
||||||
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
||||||
|
|
||||||
// Convert to data URL
|
|
||||||
const photoData = canvas.toDataURL('image/jpeg', 0.8);
|
|
||||||
|
|
||||||
onPhotoTaken(photoData);
|
|
||||||
setIsCapturing(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
stopCamera();
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={isOpen} onOpenChange={handleClose}>
|
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||||
<DialogContent className="max-w-lg w-full mx-auto">
|
<DialogContent className="max-w-lg w-full mx-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="flex items-center justify-between">
|
<DialogTitle className="flex items-center justify-between">
|
||||||
<span>Capturer photo {photoType}</span>
|
<span>Capturer photo {photoType}</span>
|
||||||
<Button variant="ghost" size="sm" onClick={handleClose}>
|
<Button variant="ghost" size="sm" onClick={onClose}>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
@@ -131,14 +99,14 @@ export default function CameraModal({
|
|||||||
|
|
||||||
<div className="flex justify-center gap-4">
|
<div className="flex justify-center gap-4">
|
||||||
<Button
|
<Button
|
||||||
onClick={capturePhoto}
|
onClick={onCapture}
|
||||||
disabled={isCapturing}
|
disabled={isCapturing}
|
||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<Camera className="h-4 w-4" />
|
<Camera className="h-4 w-4" />
|
||||||
{isCapturing ? 'Capture...' : 'Prendre la photo'}
|
{isCapturing ? 'Capture...' : 'Prendre la photo'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outline" onClick={handleClose}>
|
<Button variant="outline" onClick={onClose}>
|
||||||
Annuler
|
Annuler
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState } from 'react';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { Shield, Flame, Plus, History } from 'lucide-react';
|
import { Shield, Flame, Plus, History } from 'lucide-react';
|
||||||
import NewSaleForm from './NewSaleForm';
|
import NewSaleFormMultiProduct from './NewSaleFormMultiProduct';
|
||||||
import SalesHistory from './SalesHistory';
|
import SalesHistory from './SalesHistory';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { useStoreContext } from '@/hooks/useStoreContext';
|
import { useStoreContext } from '@/hooks/useStoreContext';
|
||||||
@@ -68,7 +68,7 @@ export default function FireworksApp() {
|
|||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent value="nouvelle-vente">
|
<TabsContent value="nouvelle-vente">
|
||||||
<NewSaleForm />
|
<NewSaleFormMultiProduct />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="historique">
|
<TabsContent value="historique">
|
||||||
|
|||||||
Reference in new issue
Block a user