diff --git a/client/src/components/NewSaleForm.tsx b/client/src/components/NewSaleForm.tsx
index a851d62..4485bbe 100644
--- a/client/src/components/NewSaleForm.tsx
+++ b/client/src/components/NewSaleForm.tsx
@@ -35,6 +35,7 @@ interface FormData {
dateDelivrance: string;
photoRecto?: string;
photoVerso?: string;
+ photoTicket?: string;
}
export default function NewSaleForm() {
@@ -75,6 +76,7 @@ export default function NewSaleForm() {
dateDelivrance: '',
photoRecto: '',
photoVerso: '',
+ photoTicket: '',
}
});
@@ -119,6 +121,7 @@ export default function NewSaleForm() {
dateDelivrance: '',
photoRecto: '',
photoVerso: '',
+ photoTicket: '',
});
},
onError: (error: any) => {
@@ -235,7 +238,13 @@ export default function NewSaleForm() {
const photoData = await capturePhoto();
console.log('Photo captured successfully, data length:', photoData.length);
- form.setValue(currentPhotoType === 'recto' ? 'photoRecto' : 'photoVerso', photoData);
+ 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",
@@ -255,7 +264,13 @@ export default function NewSaleForm() {
};
const handleRemovePhoto = (photoType: PhotoType) => {
- form.setValue(photoType === 'recto' ? 'photoRecto' : 'photoVerso', '');
+ if (photoType === 'recto') {
+ form.setValue('photoRecto', '');
+ } else if (photoType === 'verso') {
+ form.setValue('photoVerso', '');
+ } else if (photoType === 'ticket') {
+ form.setValue('photoTicket', '');
+ }
toast({
title: "Photo supprimée",
description: `Photo ${photoType} supprimée`,
@@ -288,7 +303,13 @@ export default function NewSaleForm() {
const reader = new FileReader();
reader.onload = (e) => {
const result = e.target?.result as string;
- form.setValue(photoType === 'recto' ? 'photoRecto' : 'photoVerso', result);
+ if (photoType === 'recto') {
+ form.setValue('photoRecto', result);
+ } else if (photoType === 'verso') {
+ form.setValue('photoVerso', result);
+ } else if (photoType === 'ticket') {
+ form.setValue('photoTicket', result);
+ }
toast({
title: "Photo ajoutée",
description: `Photo ${photoType} ajoutée avec succès`,
@@ -715,6 +736,63 @@ export default function NewSaleForm() {
+
+ {/* Photo Ticket de caisse */}
+
+
+
Photo du ticket de caisse
+
+
+
+
+ {form.watch('photoTicket') ? (
+
+
})
+
+
+ ) : (
+
+
+
+ handleFileUpload('ticket', e)}
+ className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
+ />
+
+
+
+ )}
+
+
{/* Boutons d'action */}
diff --git a/client/src/components/SaleDetailsModal.tsx b/client/src/components/SaleDetailsModal.tsx
index b4320ba..182d752 100644
--- a/client/src/components/SaleDetailsModal.tsx
+++ b/client/src/components/SaleDetailsModal.tsx
@@ -87,49 +87,77 @@ export default function SaleDetailsModal({ isOpen, sale, onClose }: SaleDetailsM
{/* Photos */}
-
-
Photos de la Pièce d'Identité
-
-
-
Photo Recto:
- {sale.photoRecto ? (
-
-

+ {(sale.photoRecto || sale.photoVerso || sale.photoTicket) && (
+
+
Photos
+
+ {/* Photos de la pièce d'identité */}
+ {(sale.photoRecto || sale.photoVerso) && (
+
+
Pièce d'identité
+
+
+
Photo Recto:
+ {sale.photoRecto ? (
+
+

+
+
+ ) : (
+
Aucune photo
+ )}
+
+
+
Photo Verso:
+ {sale.photoVerso ? (
+
+

+
+
+ ) : (
+
Aucune photo
+ )}
+
+
+
+ )}
+
+ {/* Photo du ticket de caisse */}
+ {sale.photoTicket && (
+
+
Ticket de caisse
+
+
- ) : (
-
Aucune photo
- )}
-
-
-
Photo Verso:
- {sale.photoVerso ? (
-
-

-
-
- ) : (
-
Aucune photo
- )}
-
+
+ )}
-
+ )}
{/* System Information */}
diff --git a/client/src/types/sale.ts b/client/src/types/sale.ts
index 0a5c7ea..3160bf0 100644
--- a/client/src/types/sale.ts
+++ b/client/src/types/sale.ts
@@ -27,6 +27,7 @@ export interface Sale {
// Photos
photoRecto?: string;
photoVerso?: string;
+ photoTicket?: string;
}
export interface FormData {
@@ -46,9 +47,10 @@ export interface FormData {
dateDelivrance: string;
photoRecto?: string;
photoVerso?: string;
+ photoTicket?: string;
}
-export type PhotoType = 'recto' | 'verso';
+export type PhotoType = 'recto' | 'verso' | 'ticket';
export interface BackupData {
timestamp: string;
diff --git a/replit.md b/replit.md
index 771bdfb..89d5e0b 100644
--- a/replit.md
+++ b/replit.md
@@ -264,6 +264,10 @@ Preferred communication style: Simple, everyday language.
- ✅ Comprehensive error handling with specific messages for different failure types
- ✅ HTTPS requirement detection for secure camera access
- ✅ Multiple capture methods: camera → file upload for maximum compatibility
+- ✅ Added receipt/ticket photo capture as third photo type alongside identity documents
+- ✅ PayloadTooLargeError resolved by increasing server limit to 10MB for photo uploads
+- ✅ Complete photo management system with separate sections for identity and receipt photos
+- ✅ Enhanced SaleDetailsModal with organized photo display and download functionality
### Production Deployment System (January 11, 2025)
- ✅ Complete production deployment configuration with Docker Compose
diff --git a/shared/schema.ts b/shared/schema.ts
index f749a44..0f2947b 100644
--- a/shared/schema.ts
+++ b/shared/schema.ts
@@ -83,6 +83,7 @@ export const sales = pgTable("sales", {
// Photos
photoRecto: text("photo_recto"),
photoVerso: text("photo_verso"),
+ photoTicket: text("photo_ticket"),
});
// Relations