import { useState } from 'react'; import { useForm, useFieldArray } from 'react-hook-form'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { useToast } from '@/hooks/use-toast'; import { useAuth } from '@/hooks/useAuth'; import { useStoreContext } from '@/hooks/useStoreContext'; 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, Plus, Minus } from 'lucide-react'; import SimpleCameraModal from '@/components/SimpleCameraModal'; import type { PhotoType, FormData } from '@/types/sale'; export default function NewSaleFormMulti() { const { toast } = useToast(); const queryClient = useQueryClient(); const { user } = useAuth(); const { selectedStoreId } = useStoreContext(); const [isSubmitting, setIsSubmitting] = useState(false); // Camera functionality const { isOpen: isCameraOpen, currentPhotoType, isCapturing, videoRef, canvasRef, startCamera, capturePhoto, stopCamera } = useSimpleCamera(); const form = useForm({ defaultValues: { vendeur: '', products: [ { typeArticle: '', categorie: '', quantite: '', gencode: '', } ], nom: '', prenom: '', dateNaissance: '', lieuNaissance: '', modePaiement: 'Espèce', typeIdentite: '', numeroIdentite: '', autoriteDelivrance: '', dateDelivrance: '', photoRecto: '', photoVerso: '', photoTicket: '', } }); const { fields, append, remove } = useFieldArray({ control: form.control, name: "products" }); const createSaleMutation = useMutation({ mutationFn: async (saleData: any) => { const dataToSend = { ...saleData, ...(user?.role === 'admin' && selectedStoreId && { storeId: selectedStoreId }) }; const response = await apiRequest('/api/sales', { method: 'POST', body: JSON.stringify(dataToSend), }); return response.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/sales'], exact: false }); toast({ title: "Vente enregistrée", description: "La vente a été enregistrée avec succès", variant: "success", }); form.reset(); }, onError: (error: any) => { const errorMessage = error.message || 'Erreur lors de la création de la vente'; toast({ title: "Erreur", description: errorMessage, variant: "destructive", }); }, }); const onSubmit = async (data: FormData) => { console.log('Form data:', data); setIsSubmitting(true); try { // Validation des champs requis const missingFields = validateRequiredFields(data); if (missingFields.length > 0) { toast({ title: "Champs obligatoires manquants", description: `Veuillez remplir : ${missingFields.join(', ')}`, variant: "destructive", }); setIsSubmitting(false); return; } // Validation EAN-13 pour tous les produits const invalidBarcodes = data.products.filter(product => !validateEAN13(product.gencode)); if (invalidBarcodes.length > 0) { toast({ title: "Code-barres invalide", description: "Certains codes EAN-13 ne sont pas valides", variant: "destructive", }); setIsSubmitting(false); return; } await createSaleMutation.mutateAsync(data); } catch (error) { console.error('Submit error:', error); } finally { setIsSubmitting(false); } }; const handlePhotoCapture = async (photoType: PhotoType) => { await startCamera(photoType); }; const handleRemovePhoto = (photoType: PhotoType) => { const field = photoType === 'recto' ? 'photoRecto' : photoType === 'verso' ? 'photoVerso' : 'photoTicket'; form.setValue(field, ''); }; const handleFileUpload = (photoType: PhotoType, event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { const result = e.target?.result as string; const field = photoType === 'recto' ? 'photoRecto' : photoType === 'verso' ? 'photoVerso' : 'photoTicket'; form.setValue(field, result); }; reader.readAsDataURL(file); } }; const addProduct = () => { append({ typeArticle: '', categorie: '', quantite: '', gencode: '', }); }; const removeProduct = (index: number) => { if (fields.length > 1) { remove(index); } }; const getAvailableCategories = (typeArticle: string) => { return typeArticle ? ARTICLE_CATEGORY_MAPPING[typeArticle as keyof typeof ARTICLE_CATEGORY_MAPPING] || [] : []; }; return (
{/* Section Vendeur */}

Informations vendeur

( Nom du vendeur * )} />
{/* Section Produits */}

Produits

{fields.map((field, index) => (

Produit {index + 1}

{fields.length > 1 && ( )}
( Type d'article * )} /> ( Catégorie * )} /> ( Quantité * )} /> ( Code EAN-13 * )} />
))}
{/* Section Client */}

Informations client

( Nom * )} /> ( Prénom * )} /> ( Date de naissance * )} /> ( Lieu de naissance * )} /> ( Mode de paiement * )} />
{/* Section Identité */}

Pièce d'identité

( Type de pièce d'identité * )} /> ( Numéro de pièce d'identité * )} /> ( Autorité de délivrance )} /> ( Date de délivrance * )} />
{/* Photos */}

Photos de la pièce d'identité

{/* Photo Recto */}
{form.watch('photoRecto') && ( )}
{form.watch('photoRecto') && (
✓ Photo recto capturée
)}
{/* Photo Verso */}
{form.watch('photoVerso') && ( )}
{form.watch('photoVerso') && (
✓ Photo verso capturée
)}
{/* Photo Ticket */}
{form.watch('photoTicket') && ( )}
{form.watch('photoTicket') && (
✓ Photo ticket capturée
)}
{/* Boutons d'action */}
); }