@rsuci/shared-form-components 1.0.77 → 1.0.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/IdDocInput.d.ts.map +1 -1
- package/dist/components/IdDocInput.js +24 -27
- package/dist/components/inputs/DatePicker.d.ts.map +1 -1
- package/dist/components/inputs/DatePicker.js +8 -5
- package/dist/components/inputs/ListRadioInput.js +2 -2
- package/dist/components/wrappers/ImageUpload.d.ts.map +1 -1
- package/dist/components/wrappers/ImageUpload.js +9 -11
- package/dist/components/wrappers/PhotoCapture.d.ts.map +1 -1
- package/dist/components/wrappers/PhotoCapture.js +11 -16
- package/dist/lib/utils/variableValueConverter.d.ts +13 -1
- package/dist/lib/utils/variableValueConverter.d.ts.map +1 -1
- package/dist/lib/utils/variableValueConverter.js +118 -22
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdDocInput.d.ts","sourceRoot":"","sources":["../../src/components/IdDocInput.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"IdDocInput.d.ts","sourceRoot":"","sources":["../../src/components/IdDocInput.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKrE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAuBD,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA8XzC,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
10
|
import React, { useState, useEffect, useRef } from 'react';
|
|
11
11
|
import { AlertCircle, Camera, Upload, X, FileText, CreditCard } from 'lucide-react';
|
|
12
|
+
import { VariableValueConverter } from '../lib/utils/variableValueConverter';
|
|
12
13
|
// Types de documents d'identité supportés
|
|
13
14
|
const DOC_TYPES = [
|
|
14
15
|
{ code: 'CNI', label: 'Carte Nationale d\'Identité' },
|
|
@@ -44,10 +45,8 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
44
45
|
}, [value]);
|
|
45
46
|
// Mettre à jour l'aperçu quand la valeur change
|
|
46
47
|
useEffect(() => {
|
|
47
|
-
if (currentData.
|
|
48
|
-
|
|
49
|
-
reader.onload = (e) => setPreview(e.target?.result);
|
|
50
|
-
reader.readAsDataURL(currentData.file);
|
|
48
|
+
if (currentData.imageData) {
|
|
49
|
+
setPreview(currentData.imageData);
|
|
51
50
|
}
|
|
52
51
|
else {
|
|
53
52
|
setPreview(null);
|
|
@@ -55,7 +54,7 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
55
54
|
fileInputRef.current.value = '';
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
|
-
}, [currentData.
|
|
57
|
+
}, [currentData.imageData]);
|
|
59
58
|
// Nettoyer le stream quand le composant est démonté
|
|
60
59
|
useEffect(() => {
|
|
61
60
|
return () => {
|
|
@@ -67,21 +66,21 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
67
66
|
// Mettre à jour les données
|
|
68
67
|
const updateData = (updates) => {
|
|
69
68
|
const newData = { ...currentData, ...updates };
|
|
70
|
-
onChange(
|
|
69
|
+
onChange(newData);
|
|
71
70
|
};
|
|
72
71
|
// Gérer la sélection de fichier
|
|
73
|
-
const handleFileSelect = (event) => {
|
|
72
|
+
const handleFileSelect = async (event) => {
|
|
74
73
|
if (disabled)
|
|
75
74
|
return;
|
|
76
75
|
const file = event.target.files?.[0];
|
|
77
76
|
if (!file)
|
|
78
77
|
return;
|
|
79
|
-
processFile(file);
|
|
78
|
+
await processFile(file);
|
|
80
79
|
};
|
|
81
80
|
// Traiter le fichier sélectionné
|
|
82
|
-
const processFile = (file) => {
|
|
83
|
-
// Validation de la taille
|
|
84
|
-
const maxSize = variable.proprietes?.maxFileSize ||
|
|
81
|
+
const processFile = async (file) => {
|
|
82
|
+
// Validation de la taille (5MB)
|
|
83
|
+
const maxSize = variable.proprietes?.maxFileSize || 5 * 1024 * 1024;
|
|
85
84
|
if (file.size > maxSize) {
|
|
86
85
|
alert(`Fichier trop volumineux. Taille maximum: ${Math.round(maxSize / 1024 / 1024)}MB`);
|
|
87
86
|
return;
|
|
@@ -95,12 +94,13 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
95
94
|
alert(`Type de fichier non supporté. Types acceptés: ${acceptedTypes.join(', ')}`);
|
|
96
95
|
return;
|
|
97
96
|
}
|
|
98
|
-
//
|
|
97
|
+
// Convertir en base64
|
|
98
|
+
const imageData = await VariableValueConverter.fileToBase64(file);
|
|
99
99
|
updateData({
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
imageData,
|
|
101
|
+
name: file.name,
|
|
102
|
+
size: file.size,
|
|
103
|
+
type: file.type,
|
|
104
104
|
timestamp: new Date(),
|
|
105
105
|
source: captureMode === 'camera' ? 'camera' : 'upload'
|
|
106
106
|
});
|
|
@@ -113,7 +113,7 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
113
113
|
setIsCapturing(true);
|
|
114
114
|
const mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
115
115
|
video: {
|
|
116
|
-
facingMode: 'environment'
|
|
116
|
+
facingMode: 'environment'
|
|
117
117
|
}
|
|
118
118
|
});
|
|
119
119
|
setStream(mediaStream);
|
|
@@ -144,16 +144,13 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
144
144
|
const context = canvas.getContext('2d');
|
|
145
145
|
if (!context)
|
|
146
146
|
return;
|
|
147
|
-
// Définir les dimensions du canvas
|
|
148
147
|
canvas.width = video.videoWidth;
|
|
149
148
|
canvas.height = video.videoHeight;
|
|
150
|
-
// Dessiner l'image du video sur le canvas
|
|
151
149
|
context.drawImage(video, 0, 0);
|
|
152
|
-
|
|
153
|
-
canvas.toBlob((blob) => {
|
|
150
|
+
canvas.toBlob(async (blob) => {
|
|
154
151
|
if (blob) {
|
|
155
152
|
const file = new File([blob], `iddoc_${Date.now()}.jpg`, { type: 'image/jpeg' });
|
|
156
|
-
processFile(file);
|
|
153
|
+
await processFile(file);
|
|
157
154
|
stopCamera();
|
|
158
155
|
}
|
|
159
156
|
}, 'image/jpeg', 0.9);
|
|
@@ -161,10 +158,10 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
161
158
|
// Supprimer le document
|
|
162
159
|
const clearDocument = () => {
|
|
163
160
|
updateData({
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
161
|
+
imageData: undefined,
|
|
162
|
+
name: undefined,
|
|
163
|
+
size: undefined,
|
|
164
|
+
type: undefined,
|
|
168
165
|
timestamp: undefined,
|
|
169
166
|
source: undefined
|
|
170
167
|
});
|
|
@@ -183,6 +180,6 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
183
180
|
startCamera();
|
|
184
181
|
}, disabled: disabled, className: `flex items-center px-3 py-2 rounded-lg text-sm font-medium transition-colors ${captureMode === 'camera'
|
|
185
182
|
? 'bg-blue-600 text-white'
|
|
186
|
-
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'} ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`, children: [_jsx(Camera, { className: "w-4 h-4 mr-2" }), "Cam\u00E9ra"] })] }), captureMode === 'upload' && !preview && (_jsxs("div", { className: "relative", children: [_jsx("input", { ref: fileInputRef, type: "file", accept: "image/*,application/pdf", onChange: handleFileSelect, disabled: disabled, className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer" }), _jsxs("div", { className: `flex flex-col items-center justify-center p-6 border-2 border-dashed rounded-lg ${error ? 'border-red-500' : 'border-gray-300'} ${disabled ? 'bg-gray-100 cursor-not-allowed' : 'bg-white hover:border-green-500 cursor-pointer'}`, children: [_jsx(CreditCard, { className: "w-10 h-10 text-gray-400 mb-2" }), _jsx("span", { className: "text-sm text-gray-600", children: "Cliquez ou glissez-d\u00E9posez" }), _jsx("span", { className: "text-xs text-gray-400 mt-1", children: "JPG, PNG, PDF - Max
|
|
183
|
+
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'} ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`, children: [_jsx(Camera, { className: "w-4 h-4 mr-2" }), "Cam\u00E9ra"] })] }), captureMode === 'upload' && !preview && (_jsxs("div", { className: "relative", children: [_jsx("input", { ref: fileInputRef, type: "file", accept: "image/*,application/pdf", onChange: handleFileSelect, disabled: disabled, className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer" }), _jsxs("div", { className: `flex flex-col items-center justify-center p-6 border-2 border-dashed rounded-lg ${error ? 'border-red-500' : 'border-gray-300'} ${disabled ? 'bg-gray-100 cursor-not-allowed' : 'bg-white hover:border-green-500 cursor-pointer'}`, children: [_jsx(CreditCard, { className: "w-10 h-10 text-gray-400 mb-2" }), _jsx("span", { className: "text-sm text-gray-600", children: "Cliquez ou glissez-d\u00E9posez" }), _jsx("span", { className: "text-xs text-gray-400 mt-1", children: "JPG, PNG, PDF - Max 5MB" })] })] })), captureMode === 'camera' && (_jsxs("div", { className: "space-y-3", children: [isCapturing && (_jsxs("div", { className: "relative", children: [_jsx("video", { ref: videoRef, autoPlay: true, playsInline: true, className: "w-full max-w-md mx-auto rounded-lg border border-gray-300" }), _jsxs("div", { className: "flex justify-center space-x-2 mt-2", children: [_jsxs("button", { type: "button", onClick: capturePhoto, disabled: disabled, className: "flex items-center px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50", children: [_jsx(Camera, { className: "w-4 h-4 mr-2" }), "Capturer"] }), _jsxs("button", { type: "button", onClick: stopCamera, disabled: disabled, className: "flex items-center px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 focus:ring-2 focus:ring-red-500 focus:ring-offset-2 disabled:opacity-50", children: [_jsx(X, { className: "w-4 h-4 mr-2" }), "Arr\u00EAter"] })] })] })), !isCapturing && !preview && (_jsxs("button", { type: "button", onClick: startCamera, disabled: disabled, className: "w-full flex items-center justify-center px-4 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50", children: [_jsx(Camera, { className: "w-5 h-5 mr-2" }), "D\u00E9marrer la cam\u00E9ra"] }))] })), _jsx("canvas", { ref: canvasRef, style: { display: 'none' } }), preview && (_jsxs("div", { className: "relative", children: [currentData.type?.startsWith('image/') ? (_jsx("img", { src: preview, alt: "Aper\u00E7u du document", className: "w-full max-w-md mx-auto rounded-lg shadow-md border border-gray-200" })) : (_jsxs("div", { className: "flex items-center justify-center p-6 bg-gray-100 rounded-lg", children: [_jsx(FileText, { className: "w-10 h-10 text-gray-500 mr-3" }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-gray-700", children: currentData.name }), _jsx("p", { className: "text-xs text-gray-500", children: currentData.size ? `${Math.round(currentData.size / 1024)} KB` : '' })] })] })), _jsx("button", { type: "button", onClick: clearDocument, disabled: disabled, className: "absolute top-2 right-2 p-1 bg-red-500 text-white rounded-full hover:bg-red-600 focus:ring-2 focus:ring-red-500 focus:ring-offset-2 disabled:opacity-50", children: _jsx(X, { className: "w-4 h-4" }) })] })), currentData.name && (_jsxs("div", { className: "p-2 bg-green-50 border border-green-200 rounded text-sm", children: [_jsxs("div", { className: "flex items-center text-green-800", children: [_jsx(FileText, { className: "w-4 h-4 mr-2" }), _jsx("span", { className: "font-medium", children: currentData.name })] }), currentData.source && (_jsxs("p", { className: "text-xs text-green-600 mt-1", children: ["Source: ", currentData.source === 'camera' ? 'Caméra' : 'Upload'] }))] }))] }), error && (_jsxs("div", { className: "flex items-center space-x-1 text-red-600 text-sm", children: [_jsx(AlertCircle, { className: "h-4 w-4" }), _jsx("span", { children: error })] }))] }));
|
|
187
184
|
};
|
|
188
185
|
export default IdDocInput;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/DatePicker.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKxE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,kBAAkB,GAAG;QAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,CAAC;IAClE,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,
|
|
1
|
+
{"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/DatePicker.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKxE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,kBAAkB,GAAG;QAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,CAAC;IAClE,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAkEzC,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -24,16 +24,19 @@ const DatePicker = ({ variable, value, onChange, onBlur, error, disabled, isCons
|
|
|
24
24
|
};
|
|
25
25
|
// Conversion de la valeur string vers Date pour l'affichage
|
|
26
26
|
const parsedDate = VariableValueConverter.parse(value, variable.typeCode);
|
|
27
|
-
// Formatage pour l'input
|
|
27
|
+
// Formatage pour l'input HTML (qui exige YYYY-MM-DD / YYYY-MM-DDTHH:mm)
|
|
28
28
|
let inputValue = '';
|
|
29
29
|
if (parsedDate && !isNaN(parsedDate.getTime())) {
|
|
30
|
+
const y = parsedDate.getFullYear();
|
|
31
|
+
const m = (parsedDate.getMonth() + 1).toString().padStart(2, '0');
|
|
32
|
+
const d = parsedDate.getDate().toString().padStart(2, '0');
|
|
30
33
|
if (variable.typeCode === 'DATEHEURE') {
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
const hh = parsedDate.getHours().toString().padStart(2, '0');
|
|
35
|
+
const mm = parsedDate.getMinutes().toString().padStart(2, '0');
|
|
36
|
+
inputValue = `${y}-${m}-${d}T${hh}:${mm}`;
|
|
33
37
|
}
|
|
34
38
|
else {
|
|
35
|
-
|
|
36
|
-
inputValue = parsedDate.toISOString().split('T')[0];
|
|
39
|
+
inputValue = `${y}-${m}-${d}`;
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
const inputType = variable.typeCode === 'DATEHEURE' ? 'datetime-local' : 'date';
|
|
@@ -40,11 +40,11 @@ const ListRadioInput = ({ variable, value, onChange, onBlur, error, disabled, is
|
|
|
40
40
|
}, [value]);
|
|
41
41
|
const handleOptionChange = (code, selected) => {
|
|
42
42
|
const newData = { ...data, [code]: selected };
|
|
43
|
-
onChange(
|
|
43
|
+
onChange(newData);
|
|
44
44
|
};
|
|
45
45
|
const handleClear = (code) => {
|
|
46
46
|
const newData = { ...data, [code]: null };
|
|
47
|
-
onChange(
|
|
47
|
+
onChange(newData);
|
|
48
48
|
};
|
|
49
49
|
return (_jsxs("div", { className: "space-y-1", style: containerStyle, children: [_jsxs("div", { className: "flex items-center text-sm font-medium text-blue-600 mb-2 pl-1", children: [_jsx("span", { children: "Oui" }), _jsx("span", { className: "mx-2", children: "/" }), _jsx("span", { children: "Non" })] }), _jsx("div", { className: "space-y-1", children: options.map((option) => {
|
|
50
50
|
const optionValue = data[option.code] ?? null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageUpload.d.ts","sourceRoot":"","sources":["../../../src/components/wrappers/ImageUpload.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ImageUpload.d.ts","sourceRoot":"","sources":["../../../src/components/wrappers/ImageUpload.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE;YACX,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;YACzB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB,CAAC;KACH,CAAC;IACF,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAiG3C,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,eAAe,WAAW,CAAC"}
|
|
@@ -2,32 +2,29 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React, { useState, useEffect } from 'react';
|
|
4
4
|
import { AlertCircle } from 'lucide-react';
|
|
5
|
+
import { VariableValueConverter } from '../../lib/utils/variableValueConverter';
|
|
5
6
|
const ImageUpload = ({ variable, value, onChange, error, disabled }) => {
|
|
6
7
|
const [preview, setPreview] = useState(null);
|
|
7
8
|
const fileInputRef = React.useRef(null);
|
|
8
9
|
useEffect(() => {
|
|
9
|
-
if (value && typeof value === 'object' && value.
|
|
10
|
-
|
|
11
|
-
const reader = new FileReader();
|
|
12
|
-
reader.onload = (e) => setPreview(e.target?.result);
|
|
13
|
-
reader.readAsDataURL(file);
|
|
10
|
+
if (value && typeof value === 'object' && value.imageData) {
|
|
11
|
+
setPreview(value.imageData);
|
|
14
12
|
}
|
|
15
13
|
else {
|
|
16
14
|
setPreview(null);
|
|
17
|
-
// Réinitialiser l'input file quand la valeur est supprimée
|
|
18
15
|
if (fileInputRef.current) {
|
|
19
16
|
fileInputRef.current.value = '';
|
|
20
17
|
}
|
|
21
18
|
}
|
|
22
19
|
}, [value]);
|
|
23
|
-
const handleFileSelect = (event) => {
|
|
20
|
+
const handleFileSelect = async (event) => {
|
|
24
21
|
if (disabled)
|
|
25
22
|
return;
|
|
26
23
|
const file = event.target.files?.[0];
|
|
27
24
|
if (!file)
|
|
28
25
|
return;
|
|
29
|
-
// Validation de la taille
|
|
30
|
-
const maxSize = variable.proprietes?.maxFileSize || 5 * 1024 * 1024;
|
|
26
|
+
// Validation de la taille (5MB)
|
|
27
|
+
const maxSize = variable.proprietes?.maxFileSize || 5 * 1024 * 1024;
|
|
31
28
|
if (file.size > maxSize) {
|
|
32
29
|
alert(`Fichier trop volumineux. Taille maximum: ${Math.round(maxSize / 1024 / 1024)}MB`);
|
|
33
30
|
return;
|
|
@@ -38,9 +35,10 @@ const ImageUpload = ({ variable, value, onChange, error, disabled }) => {
|
|
|
38
35
|
alert(`Type de fichier non supporté. Types acceptés: ${acceptedTypes.join(', ')}`);
|
|
39
36
|
return;
|
|
40
37
|
}
|
|
41
|
-
//
|
|
38
|
+
// Convertir en base64
|
|
39
|
+
const imageData = await VariableValueConverter.fileToBase64(file);
|
|
42
40
|
onChange({
|
|
43
|
-
|
|
41
|
+
imageData,
|
|
44
42
|
name: file.name,
|
|
45
43
|
size: file.size,
|
|
46
44
|
type: file.type,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhotoCapture.d.ts","sourceRoot":"","sources":["../../../src/components/wrappers/PhotoCapture.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"PhotoCapture.d.ts","sourceRoot":"","sources":["../../../src/components/wrappers/PhotoCapture.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,UAAU,CAAC,EAAE;YACX,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;YACzB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB,CAAC;KACH,CAAC;IACF,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAuP7C,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,eAAe,YAAY,CAAC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import React, { useState, useEffect } from 'react';
|
|
4
4
|
import { AlertCircle } from 'lucide-react';
|
|
5
|
+
import { VariableValueConverter } from '../../lib/utils/variableValueConverter';
|
|
5
6
|
const PhotoCapture = ({ variable, value, onChange, error, disabled }) => {
|
|
6
7
|
const [preview, setPreview] = useState(null);
|
|
7
8
|
const [captureMode, setCaptureMode] = useState('upload');
|
|
@@ -11,15 +12,11 @@ const PhotoCapture = ({ variable, value, onChange, error, disabled }) => {
|
|
|
11
12
|
const videoRef = React.useRef(null);
|
|
12
13
|
const canvasRef = React.useRef(null);
|
|
13
14
|
useEffect(() => {
|
|
14
|
-
if (value && typeof value === 'object' && value.
|
|
15
|
-
|
|
16
|
-
const reader = new FileReader();
|
|
17
|
-
reader.onload = (e) => setPreview(e.target?.result);
|
|
18
|
-
reader.readAsDataURL(file);
|
|
15
|
+
if (value && typeof value === 'object' && value.imageData) {
|
|
16
|
+
setPreview(value.imageData);
|
|
19
17
|
}
|
|
20
18
|
else {
|
|
21
19
|
setPreview(null);
|
|
22
|
-
// Réinitialiser l'input file quand la valeur est supprimée
|
|
23
20
|
if (fileInputRef.current) {
|
|
24
21
|
fileInputRef.current.value = '';
|
|
25
22
|
}
|
|
@@ -41,9 +38,9 @@ const PhotoCapture = ({ variable, value, onChange, error, disabled }) => {
|
|
|
41
38
|
return;
|
|
42
39
|
processFile(file);
|
|
43
40
|
};
|
|
44
|
-
const processFile = (file) => {
|
|
45
|
-
// Validation de la taille
|
|
46
|
-
const maxSize = variable.proprietes?.maxFileSize || 5 * 1024 * 1024;
|
|
41
|
+
const processFile = async (file) => {
|
|
42
|
+
// Validation de la taille (5MB)
|
|
43
|
+
const maxSize = variable.proprietes?.maxFileSize || 5 * 1024 * 1024;
|
|
47
44
|
if (file.size > maxSize) {
|
|
48
45
|
alert(`Fichier trop volumineux. Taille maximum: ${Math.round(maxSize / 1024 / 1024)}MB`);
|
|
49
46
|
return;
|
|
@@ -54,9 +51,10 @@ const PhotoCapture = ({ variable, value, onChange, error, disabled }) => {
|
|
|
54
51
|
alert(`Type de fichier non supporté. Types acceptés: ${acceptedTypes.join(', ')}`);
|
|
55
52
|
return;
|
|
56
53
|
}
|
|
57
|
-
//
|
|
54
|
+
// Convertir en base64
|
|
55
|
+
const imageData = await VariableValueConverter.fileToBase64(file);
|
|
58
56
|
onChange({
|
|
59
|
-
|
|
57
|
+
imageData,
|
|
60
58
|
name: file.name,
|
|
61
59
|
size: file.size,
|
|
62
60
|
type: file.type,
|
|
@@ -100,16 +98,13 @@ const PhotoCapture = ({ variable, value, onChange, error, disabled }) => {
|
|
|
100
98
|
const context = canvas.getContext('2d');
|
|
101
99
|
if (!context)
|
|
102
100
|
return;
|
|
103
|
-
// Définir les dimensions du canvas
|
|
104
101
|
canvas.width = video.videoWidth;
|
|
105
102
|
canvas.height = video.videoHeight;
|
|
106
|
-
// Dessiner l'image du video sur le canvas
|
|
107
103
|
context.drawImage(video, 0, 0);
|
|
108
|
-
|
|
109
|
-
canvas.toBlob((blob) => {
|
|
104
|
+
canvas.toBlob(async (blob) => {
|
|
110
105
|
if (blob) {
|
|
111
106
|
const file = new File([blob], `photo_${Date.now()}.jpg`, { type: 'image/jpeg' });
|
|
112
|
-
processFile(file);
|
|
107
|
+
await processFile(file);
|
|
113
108
|
stopCamera();
|
|
114
109
|
}
|
|
115
110
|
}, 'image/jpeg', 0.8);
|
|
@@ -15,11 +15,14 @@ export interface GPSData {
|
|
|
15
15
|
timestamp: Date;
|
|
16
16
|
}
|
|
17
17
|
export interface FileData {
|
|
18
|
-
|
|
18
|
+
imageData: string;
|
|
19
19
|
name: string;
|
|
20
20
|
size: number;
|
|
21
21
|
type: string;
|
|
22
22
|
timestamp: Date;
|
|
23
|
+
source?: 'camera' | 'upload';
|
|
24
|
+
docType?: string;
|
|
25
|
+
docNumber?: string;
|
|
23
26
|
}
|
|
24
27
|
/**
|
|
25
28
|
* Classe utilitaire pour la conversion des valeurs de variables
|
|
@@ -41,6 +44,11 @@ export declare class VariableValueConverter {
|
|
|
41
44
|
private static parseGPS;
|
|
42
45
|
private static parseFile;
|
|
43
46
|
private static parseRSU;
|
|
47
|
+
/**
|
|
48
|
+
* Déséchappe itérativement une chaîne JSON multi-échappée jusqu'à obtenir un objet JSON propre.
|
|
49
|
+
* Équivalent frontend de ParseGeographicJsonObject du backend.
|
|
50
|
+
*/
|
|
51
|
+
private static unescapeToJsonObject;
|
|
44
52
|
private static parseDistrict;
|
|
45
53
|
private static parseGeographicData;
|
|
46
54
|
private static serializeNumeric;
|
|
@@ -49,6 +57,10 @@ export declare class VariableValueConverter {
|
|
|
49
57
|
private static serializeCheckboxValue;
|
|
50
58
|
private static serializeGPS;
|
|
51
59
|
private static serializeFile;
|
|
60
|
+
/**
|
|
61
|
+
* Convertit un objet File en data URL base64
|
|
62
|
+
*/
|
|
63
|
+
static fileToBase64(file: File): Promise<string>;
|
|
52
64
|
private static serializeRSU;
|
|
53
65
|
private static serializeDistrict;
|
|
54
66
|
private static serializeGeographicData;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"variableValueConverter.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/variableValueConverter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGlE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,
|
|
1
|
+
{"version":3,"file":"variableValueConverter.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/variableValueConverter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGlE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,sBAAsB;IAEjC;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,aAAa;IAuEjF;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM;IAiElE,OAAO,CAAC,MAAM,CAAC,YAAY;IAK3B,OAAO,CAAC,MAAM,CAAC,SAAS;IAexB,OAAO,CAAC,MAAM,CAAC,aAAa;IAqB5B,OAAO,CAAC,MAAM,CAAC,SAAS;IAQxB,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAIjC,OAAO,CAAC,MAAM,CAAC,QAAQ;IAcvB,OAAO,CAAC,MAAM,CAAC,SAAS;IAmBxB,OAAO,CAAC,MAAM,CAAC,QAAQ;IAKvB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAkDnC,OAAO,CAAC,MAAM,CAAC,aAAa;IA8B5B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAoElC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAI/B,OAAO,CAAC,MAAM,CAAC,aAAa;IAQ5B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAUhC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAIrC,OAAO,CAAC,MAAM,CAAC,YAAY;IAS3B,OAAO,CAAC,MAAM,CAAC,aAAa;IAc5B;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAShD,OAAO,CAAC,MAAM,CAAC,YAAY;IAK3B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAWhC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IA2DtC;;OAEG;IACH,MAAM,CAAC,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,UAAU,EAAE;IAuBpE;;OAEG;IACH,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE;;;;;IAUlD;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO;IA4ChE;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM;CAsC1E"}
|
|
@@ -46,6 +46,7 @@ export class VariableValueConverter {
|
|
|
46
46
|
return this.parseGPS(value);
|
|
47
47
|
case 'PHOTO':
|
|
48
48
|
case 'IMAGE':
|
|
49
|
+
case 'IDDOC':
|
|
49
50
|
return this.parseFile(value);
|
|
50
51
|
case 'RSU':
|
|
51
52
|
return this.parseRSU(value);
|
|
@@ -99,6 +100,7 @@ export class VariableValueConverter {
|
|
|
99
100
|
return this.serializeGPS(value);
|
|
100
101
|
case 'PHOTO':
|
|
101
102
|
case 'IMAGE':
|
|
103
|
+
case 'IDDOC':
|
|
102
104
|
return this.serializeFile(value);
|
|
103
105
|
case 'RSU':
|
|
104
106
|
return this.serializeRSU(value);
|
|
@@ -128,6 +130,13 @@ export class VariableValueConverter {
|
|
|
128
130
|
static parseDate(value) {
|
|
129
131
|
if (!value)
|
|
130
132
|
return null;
|
|
133
|
+
// Format DD/MM/YYYY
|
|
134
|
+
if (value.includes('/')) {
|
|
135
|
+
const [day, month, year] = value.split('/');
|
|
136
|
+
const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
|
|
137
|
+
return isNaN(date.getTime()) ? null : date;
|
|
138
|
+
}
|
|
139
|
+
// Fallback ISO (YYYY-MM-DD) pour rétrocompatibilité
|
|
131
140
|
const date = new Date(value);
|
|
132
141
|
return isNaN(date.getTime()) ? null : date;
|
|
133
142
|
}
|
|
@@ -179,12 +188,17 @@ export class VariableValueConverter {
|
|
|
179
188
|
static parseFile(value) {
|
|
180
189
|
try {
|
|
181
190
|
const parsed = JSON.parse(value);
|
|
191
|
+
if (!parsed || typeof parsed !== 'object')
|
|
192
|
+
return null;
|
|
182
193
|
return {
|
|
183
|
-
|
|
184
|
-
name: parsed.name,
|
|
185
|
-
size: parsed.size,
|
|
186
|
-
type: parsed.type,
|
|
187
|
-
timestamp: new Date(parsed.timestamp)
|
|
194
|
+
imageData: parsed.imageData || '',
|
|
195
|
+
name: parsed.name || '',
|
|
196
|
+
size: parsed.size || 0,
|
|
197
|
+
type: parsed.type || '',
|
|
198
|
+
timestamp: parsed.timestamp ? new Date(parsed.timestamp) : new Date(),
|
|
199
|
+
source: parsed.source,
|
|
200
|
+
docType: parsed.docType,
|
|
201
|
+
docNumber: parsed.docNumber
|
|
188
202
|
};
|
|
189
203
|
}
|
|
190
204
|
catch {
|
|
@@ -195,18 +209,71 @@ export class VariableValueConverter {
|
|
|
195
209
|
// RSU stocke directement l'ID comme string
|
|
196
210
|
return value || '';
|
|
197
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Déséchappe itérativement une chaîne JSON multi-échappée jusqu'à obtenir un objet JSON propre.
|
|
214
|
+
* Équivalent frontend de ParseGeographicJsonObject du backend.
|
|
215
|
+
*/
|
|
216
|
+
static unescapeToJsonObject(value) {
|
|
217
|
+
if (!value)
|
|
218
|
+
return null;
|
|
219
|
+
let current = value;
|
|
220
|
+
const maxIterations = 5;
|
|
221
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
222
|
+
// Si c'est déjà un objet JSON, tenter le parse
|
|
223
|
+
if (current.startsWith('{') && current.endsWith('}')) {
|
|
224
|
+
try {
|
|
225
|
+
return JSON.parse(current);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Si c'est une string JSON (commence par "), désérialiser un niveau
|
|
232
|
+
if (current.startsWith('"') && current.endsWith('"')) {
|
|
233
|
+
try {
|
|
234
|
+
const unescaped = JSON.parse(current);
|
|
235
|
+
if (typeof unescaped === 'string') {
|
|
236
|
+
current = unescaped;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
return unescaped;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Tenter de supprimer manuellement les guillemets et échappements
|
|
243
|
+
if (current.length >= 2) {
|
|
244
|
+
current = current.slice(1, -1).replace(/\\"/g, '"');
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
// Dernière tentative
|
|
253
|
+
if (current.startsWith('{') && current.endsWith('}')) {
|
|
254
|
+
try {
|
|
255
|
+
return JSON.parse(current);
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
198
263
|
static parseDistrict(value) {
|
|
199
264
|
if (!value)
|
|
200
265
|
return null;
|
|
201
266
|
try {
|
|
202
|
-
//
|
|
203
|
-
if (value.startsWith('{')) {
|
|
204
|
-
const parsed =
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
267
|
+
// Tenter le parsing avec support du multi-échappement
|
|
268
|
+
if (value.startsWith('{') || value.startsWith('"')) {
|
|
269
|
+
const parsed = this.unescapeToJsonObject(value);
|
|
270
|
+
if (parsed && typeof parsed === 'object') {
|
|
271
|
+
return {
|
|
272
|
+
id: parsed.id,
|
|
273
|
+
code: parsed.code,
|
|
274
|
+
designation: parsed.designation
|
|
275
|
+
};
|
|
276
|
+
}
|
|
210
277
|
}
|
|
211
278
|
// Sinon, c'est juste un ID - retourner un objet minimal
|
|
212
279
|
const id = parseInt(value, 10);
|
|
@@ -226,8 +293,12 @@ export class VariableValueConverter {
|
|
|
226
293
|
if (!value)
|
|
227
294
|
return null;
|
|
228
295
|
try {
|
|
229
|
-
// Parser le JSON stocké
|
|
230
|
-
const parsed =
|
|
296
|
+
// Parser le JSON stocké avec support du multi-échappement
|
|
297
|
+
const parsed = (value.startsWith('{') || value.startsWith('"'))
|
|
298
|
+
? this.unescapeToJsonObject(value)
|
|
299
|
+
: JSON.parse(value);
|
|
300
|
+
if (!parsed || typeof parsed !== 'object')
|
|
301
|
+
return null;
|
|
231
302
|
const result = {};
|
|
232
303
|
// Reconstruire l'objet GeographicData
|
|
233
304
|
if (parsed.district) {
|
|
@@ -285,12 +356,20 @@ export class VariableValueConverter {
|
|
|
285
356
|
static serializeDate(date) {
|
|
286
357
|
if (!date || isNaN(date.getTime()))
|
|
287
358
|
return '';
|
|
288
|
-
|
|
359
|
+
const d = date.getDate().toString().padStart(2, '0');
|
|
360
|
+
const m = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
361
|
+
const y = date.getFullYear();
|
|
362
|
+
return `${d}/${m}/${y}`;
|
|
289
363
|
}
|
|
290
364
|
static serializeDateTime(date) {
|
|
291
365
|
if (!date || isNaN(date.getTime()))
|
|
292
366
|
return '';
|
|
293
|
-
|
|
367
|
+
const d = date.getDate().toString().padStart(2, '0');
|
|
368
|
+
const m = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
369
|
+
const y = date.getFullYear();
|
|
370
|
+
const hh = date.getHours().toString().padStart(2, '0');
|
|
371
|
+
const mm = date.getMinutes().toString().padStart(2, '0');
|
|
372
|
+
return `${d}/${m}/${y} ${hh}:${mm}`;
|
|
294
373
|
}
|
|
295
374
|
static serializeCheckboxValue(values) {
|
|
296
375
|
return Array.isArray(values) ? values.filter(v => v).join('|') : '';
|
|
@@ -304,12 +383,29 @@ export class VariableValueConverter {
|
|
|
304
383
|
});
|
|
305
384
|
}
|
|
306
385
|
static serializeFile(fileData) {
|
|
307
|
-
|
|
386
|
+
const obj = {
|
|
387
|
+
imageData: fileData.imageData,
|
|
308
388
|
name: fileData.name,
|
|
309
389
|
size: fileData.size,
|
|
310
390
|
type: fileData.type,
|
|
311
|
-
timestamp: fileData.timestamp.toISOString()
|
|
312
|
-
|
|
391
|
+
timestamp: fileData.timestamp instanceof Date ? fileData.timestamp.toISOString() : fileData.timestamp,
|
|
392
|
+
source: fileData.source
|
|
393
|
+
};
|
|
394
|
+
if (fileData.docType)
|
|
395
|
+
obj.docType = fileData.docType;
|
|
396
|
+
if (fileData.docNumber)
|
|
397
|
+
obj.docNumber = fileData.docNumber;
|
|
398
|
+
return JSON.stringify(obj);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Convertit un objet File en data URL base64
|
|
402
|
+
*/
|
|
403
|
+
static fileToBase64(file) {
|
|
404
|
+
return new Promise((resolve, reject) => {
|
|
405
|
+
const reader = new FileReader();
|
|
406
|
+
reader.onload = () => resolve(reader.result);
|
|
407
|
+
reader.onerror = reject;
|
|
408
|
+
reader.readAsDataURL(file);
|
|
313
409
|
});
|
|
314
410
|
}
|
|
315
411
|
static serializeRSU(value) {
|
|
@@ -423,9 +519,9 @@ export class VariableValueConverter {
|
|
|
423
519
|
case 'NUMERIQUE':
|
|
424
520
|
return !isNaN(parseFloat(value));
|
|
425
521
|
case 'DATE':
|
|
426
|
-
return
|
|
522
|
+
return this.parseDate(value) !== null;
|
|
427
523
|
case 'DATEHEURE':
|
|
428
|
-
return
|
|
524
|
+
return this.parseDateTime(value) !== null;
|
|
429
525
|
case 'HOUR':
|
|
430
526
|
return /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/.test(value);
|
|
431
527
|
case 'PHONE':
|
package/package.json
CHANGED