@rsuci/shared-form-components 1.0.78 → 1.0.80
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 +3 -2
- package/dist/components/form-renderer/FormRenderer.d.ts.map +1 -1
- package/dist/components/form-renderer/FormRenderer.js +36 -4
- package/dist/components/wrappers/ImageUpload.d.ts.map +1 -1
- package/dist/components/wrappers/ImageUpload.js +25 -6
- package/dist/components/wrappers/PhotoCapture.d.ts.map +1 -1
- package/dist/components/wrappers/PhotoCapture.js +25 -6
- 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;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,
|
|
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,CA+XzC,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -63,10 +63,11 @@ const IdDocInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
}, [stream]);
|
|
66
|
-
// Mettre à jour les données
|
|
66
|
+
// Mettre à jour les données (sérialiser en JSON string comme DatePicker le fait pour les dates)
|
|
67
67
|
const updateData = (updates) => {
|
|
68
68
|
const newData = { ...currentData, ...updates };
|
|
69
|
-
|
|
69
|
+
const serializedValue = VariableValueConverter.serialize(newData, variable.typeCode);
|
|
70
|
+
onChange(serializedValue);
|
|
70
71
|
};
|
|
71
72
|
// Gérer la sélection de fichier
|
|
72
73
|
const handleFileSelect = async (event) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/form-renderer/FormRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EAIf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAsBlF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,UAAU,EAAE,iBAAiB,CAAC;IAC9B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAClD,oCAAoC;IACpC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,iCAAiC;IACjC,SAAS,EAAE,qBAAqB,CAAC;IACjC,wBAAwB;IACxB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,wCAAwC;IACxC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iCAAiC;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"FormRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/form-renderer/FormRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EAIf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAsBlF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,UAAU,EAAE,iBAAiB,CAAC;IAC9B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAClD,oCAAoC;IACpC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,iCAAiC;IACjC,SAAS,EAAE,qBAAqB,CAAC;IACjC,wBAAwB;IACxB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,wCAAwC;IACxC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,iCAAiC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iCAAiC;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AA0wBD;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAgBpD,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -29,6 +29,18 @@ const FormRendererInner = () => {
|
|
|
29
29
|
const { formulaire, enquete, config, callbacks, services, geographicComponents, navigation, validation, instances, responses, updateResponse, hasUnsavedChanges, isSubmitting, effectiveDisabled, currentGroup, currentInstance, groupesWithInstances } = context;
|
|
30
30
|
const { mode, features } = config;
|
|
31
31
|
const labels = config.labels || {};
|
|
32
|
+
// Map de fallback: variableCode → réponse (même stratégie que interpolateVariableLabel)
|
|
33
|
+
// Permet de trouver les réponses dont la clé utilise un suffixe _N (ex: S1_01_1)
|
|
34
|
+
// alors que le rendu cherche par code simple (ex: S1_01)
|
|
35
|
+
const responsesByVariableCode = useMemo(() => {
|
|
36
|
+
const map = new Map();
|
|
37
|
+
Object.values(responses).forEach((response) => {
|
|
38
|
+
if (response?.variableCode && !map.has(response.variableCode)) {
|
|
39
|
+
map.set(response.variableCode, response);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return map;
|
|
43
|
+
}, [responses]);
|
|
32
44
|
// État local pour les modals et actions
|
|
33
45
|
const [showCancelModal, setShowCancelModal] = useState(false);
|
|
34
46
|
const [showValidationModal, setShowValidationModal] = useState(false);
|
|
@@ -118,9 +130,17 @@ const FormRendererInner = () => {
|
|
|
118
130
|
}, [currentGroup, getFilteredVariables, isVariableVisible]);
|
|
119
131
|
// Handler pour le changement de variable
|
|
120
132
|
const handleVariableChange = useCallback((variable, value) => {
|
|
121
|
-
|
|
133
|
+
let numeroMembre = currentGroup?.estMultiple
|
|
122
134
|
? currentInstance?.numeroInstance
|
|
123
135
|
: undefined;
|
|
136
|
+
// Pour les groupes non-multiples, préserver le numeroMembre existant du backend
|
|
137
|
+
// afin que la sauvegarde utilise la même clé que le chargement
|
|
138
|
+
if (numeroMembre === undefined) {
|
|
139
|
+
const existingResponse = responsesByVariableCode.get(variable.code);
|
|
140
|
+
if (existingResponse?.numeroMembre) {
|
|
141
|
+
numeroMembre = existingResponse.numeroMembre;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
124
144
|
updateResponse(variable.code, value, variable, numeroMembre);
|
|
125
145
|
// Mettre à jour le contexte du ConditionEngine immédiatement avec la nouvelle valeur
|
|
126
146
|
// avant de lancer la validation (sinon le contexte est en retard d'un cycle React)
|
|
@@ -143,7 +163,7 @@ const FormRendererInner = () => {
|
|
|
143
163
|
// Réévaluer les validations des variables dépendantes
|
|
144
164
|
const groupes = groupesWithInstances.length > 0 ? groupesWithInstances : formulaire?.groupes || [];
|
|
145
165
|
revalidateDependents(variable.code, groupes, numeroMembre);
|
|
146
|
-
}, [currentGroup, currentInstance, updateResponse, conditionEngine, validateConditionVariable, revalidateDependents, groupesWithInstances, formulaire?.groupes]);
|
|
166
|
+
}, [currentGroup, currentInstance, updateResponse, conditionEngine, validateConditionVariable, revalidateDependents, groupesWithInstances, formulaire?.groupes, responsesByVariableCode]);
|
|
147
167
|
// Handler pour remplir le formulaire depuis les données d'une enquête sélectionnée
|
|
148
168
|
const handleFillFormFromEnquete = useCallback((enqueteData) => {
|
|
149
169
|
if (!enqueteData?.reponses)
|
|
@@ -364,7 +384,15 @@ const FormRendererInner = () => {
|
|
|
364
384
|
const responseKey = currentGroup?.estMultiple && currentInstance?.numeroInstance
|
|
365
385
|
? `${variable.code}_${currentInstance.numeroInstance}`
|
|
366
386
|
: variable.code;
|
|
367
|
-
|
|
387
|
+
let currentValue = responses[responseKey]?.valeur;
|
|
388
|
+
// Fallback: si pas trouvé par clé directe, chercher par variableCode
|
|
389
|
+
// (gère les groupes non-multiples où le backend stocke avec numero_membre)
|
|
390
|
+
if (currentValue === undefined) {
|
|
391
|
+
const fallbackResponse = responsesByVariableCode.get(variable.code);
|
|
392
|
+
if (fallbackResponse) {
|
|
393
|
+
currentValue = fallbackResponse.valeur;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
368
396
|
// Debug log pour tracer le flux de données géographiques
|
|
369
397
|
if (['DISTRICT', 'REGION', 'DEPARTEMENT', 'SOUSPREFECTURE', 'QUARTIER'].includes(variable.typeCode)) {
|
|
370
398
|
console.log('[FormRenderer] Variable géographique:', {
|
|
@@ -381,7 +409,11 @@ const FormRendererInner = () => {
|
|
|
381
409
|
const rosterVariables = (variable.typeCode === 'ROSTERCHECK' || variable.typeCode === 'ROSTERLIST')
|
|
382
410
|
? variable.rosterVariables
|
|
383
411
|
: undefined;
|
|
384
|
-
return (_jsx(VariableRenderer, { variable: variable, value: currentValue, onChange: (value) => handleVariableChange(variable, value), disabled: effectiveDisabled, numeroMembre: currentGroup?.estMultiple
|
|
412
|
+
return (_jsx(VariableRenderer, { variable: variable, value: currentValue, onChange: (value) => handleVariableChange(variable, value), disabled: effectiveDisabled, numeroMembre: currentGroup?.estMultiple
|
|
413
|
+
? currentInstance?.numeroInstance
|
|
414
|
+
: responsesByVariableCode.get(variable.code)?.numeroMembre, conditionValidationError: getConditionErrorForVariable(variable.code, currentGroup?.estMultiple
|
|
415
|
+
? currentInstance?.numeroInstance
|
|
416
|
+
: responsesByVariableCode.get(variable.code)?.numeroMembre), services: services, geographicComponents: geographicComponents, formulaireVariables: formulaire.variables, allResponses: responses, reponses: responses, interpolateVariableLabel: interpolateVariableLabel, rosterVariables: rosterVariables, RosterCheckInput: RosterCheckInput, RosterListInput: RosterListInput, onFillFormFromEnquete: handleFillFormFromEnquete }, variable.id));
|
|
385
417
|
}) }), currentGroup?.estMultiple && currentGroup.instances && (_jsx("div", { className: "mt-6 pt-6 border-t", children: _jsx(GroupeInstanceTabs, { groupe: currentGroup, currentInstanceIndex: navigation.navigationState.instanceIndex, responses: responses, onInstanceChange: handleInstanceChange, onInstanceAdded: handleInstanceAdded, onInstanceRemoved: handleInstanceRemoved, disabled: effectiveDisabled }) }))] })] }), _jsx("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200 p-4", children: _jsxs("div", { className: "flex flex-wrap justify-between items-center gap-2", children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs("button", { type: "button", onClick: handlePrevious, disabled: navigation.isFirstGroup || (!isConsultationMode && effectiveDisabled), className: `flex items-center px-4 py-2 rounded-lg font-medium transition-colors ${!navigation.isFirstGroup && (isConsultationMode || !effectiveDisabled)
|
|
386
418
|
? 'bg-orange-500 text-white hover:bg-orange-600'
|
|
387
419
|
: 'bg-gray-100 text-gray-400 cursor-not-allowed'}`, children: [_jsx("svg", { className: "h-4 w-4 mr-2", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }), _jsx("span", { className: "hidden sm:inline", children: labels.previousButton || 'Précédent' }), _jsx("span", { className: "sm:hidden", children: "Pr\u00E9c." })] }), mode === 'admin' && features?.saveDraft && callbacks.onSaveDraft && (_jsx("button", { type: "button", onClick: handleSaveDraft, disabled: effectiveDisabled || isSavingDraft || isSubmitting || isSubmittingForm, className: `flex items-center px-4 py-2 rounded-lg font-medium transition-colors ${!effectiveDisabled && !isSavingDraft && !isSubmitting && !isSubmittingForm
|
|
@@ -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;AAKnD,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,CA4G3C,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,eAAe,WAAW,CAAC"}
|
|
@@ -7,14 +7,30 @@ const ImageUpload = ({ variable, value, onChange, error, disabled }) => {
|
|
|
7
7
|
const [preview, setPreview] = useState(null);
|
|
8
8
|
const fileInputRef = React.useRef(null);
|
|
9
9
|
useEffect(() => {
|
|
10
|
-
if (value
|
|
11
|
-
|
|
10
|
+
if (value) {
|
|
11
|
+
// Gérer les deux formats : objet ou string JSON
|
|
12
|
+
let fileData = value;
|
|
13
|
+
if (typeof value === 'string') {
|
|
14
|
+
try {
|
|
15
|
+
fileData = JSON.parse(value);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
fileData = null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (fileData && typeof fileData === 'object' && fileData.imageData) {
|
|
22
|
+
setPreview(fileData.imageData);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
setPreview(null);
|
|
26
|
+
if (fileInputRef.current)
|
|
27
|
+
fileInputRef.current.value = '';
|
|
28
|
+
}
|
|
12
29
|
}
|
|
13
30
|
else {
|
|
14
31
|
setPreview(null);
|
|
15
|
-
if (fileInputRef.current)
|
|
32
|
+
if (fileInputRef.current)
|
|
16
33
|
fileInputRef.current.value = '';
|
|
17
|
-
}
|
|
18
34
|
}
|
|
19
35
|
}, [value]);
|
|
20
36
|
const handleFileSelect = async (event) => {
|
|
@@ -37,14 +53,17 @@ const ImageUpload = ({ variable, value, onChange, error, disabled }) => {
|
|
|
37
53
|
}
|
|
38
54
|
// Convertir en base64
|
|
39
55
|
const imageData = await VariableValueConverter.fileToBase64(file);
|
|
40
|
-
|
|
56
|
+
// Sérialiser en JSON string avant d'émettre (comme DatePicker le fait pour les dates)
|
|
57
|
+
const fileData = {
|
|
41
58
|
imageData,
|
|
42
59
|
name: file.name,
|
|
43
60
|
size: file.size,
|
|
44
61
|
type: file.type,
|
|
45
62
|
timestamp: new Date(),
|
|
46
63
|
source: 'upload'
|
|
47
|
-
}
|
|
64
|
+
};
|
|
65
|
+
const serializedValue = VariableValueConverter.serialize(fileData, variable.typeCode);
|
|
66
|
+
onChange(serializedValue);
|
|
48
67
|
};
|
|
49
68
|
return (_jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "text-sm text-gray-600 mb-2", children: "\uD83D\uDCC1 Upload d'image uniquement" }), _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", onChange: handleFileSelect, disabled: disabled, className: `w-full px-3 py-2 border border-dashed rounded-lg focus:ring-2 focus:ring-green-500 focus:border-transparent text-gray-900 ${error ? 'border-red-500' : 'border-gray-300'} ${disabled ? 'bg-gray-100 cursor-not-allowed text-gray-500' : 'bg-white cursor-pointer hover:border-green-500'}` }), preview && (_jsxs("div", { className: "relative", children: [_jsx("img", { src: preview, alt: "Aper\u00E7u", className: "w-full max-w-xs mx-auto rounded-lg shadow-md" }), _jsx("button", { type: "button", onClick: () => {
|
|
50
69
|
onChange(null);
|
|
@@ -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;AAKnD,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,CAkQ7C,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,eAAe,YAAY,CAAC"}
|
|
@@ -12,14 +12,30 @@ const PhotoCapture = ({ variable, value, onChange, error, disabled }) => {
|
|
|
12
12
|
const videoRef = React.useRef(null);
|
|
13
13
|
const canvasRef = React.useRef(null);
|
|
14
14
|
useEffect(() => {
|
|
15
|
-
if (value
|
|
16
|
-
|
|
15
|
+
if (value) {
|
|
16
|
+
// Gérer les deux formats : objet ou string JSON
|
|
17
|
+
let fileData = value;
|
|
18
|
+
if (typeof value === 'string') {
|
|
19
|
+
try {
|
|
20
|
+
fileData = JSON.parse(value);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
fileData = null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (fileData && typeof fileData === 'object' && fileData.imageData) {
|
|
27
|
+
setPreview(fileData.imageData);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
setPreview(null);
|
|
31
|
+
if (fileInputRef.current)
|
|
32
|
+
fileInputRef.current.value = '';
|
|
33
|
+
}
|
|
17
34
|
}
|
|
18
35
|
else {
|
|
19
36
|
setPreview(null);
|
|
20
|
-
if (fileInputRef.current)
|
|
37
|
+
if (fileInputRef.current)
|
|
21
38
|
fileInputRef.current.value = '';
|
|
22
|
-
}
|
|
23
39
|
}
|
|
24
40
|
}, [value]);
|
|
25
41
|
// Nettoyer le stream quand le composant est démonté
|
|
@@ -53,14 +69,17 @@ const PhotoCapture = ({ variable, value, onChange, error, disabled }) => {
|
|
|
53
69
|
}
|
|
54
70
|
// Convertir en base64
|
|
55
71
|
const imageData = await VariableValueConverter.fileToBase64(file);
|
|
56
|
-
|
|
72
|
+
// Sérialiser en JSON string avant d'émettre (comme DatePicker le fait pour les dates)
|
|
73
|
+
const fileData = {
|
|
57
74
|
imageData,
|
|
58
75
|
name: file.name,
|
|
59
76
|
size: file.size,
|
|
60
77
|
type: file.type,
|
|
61
78
|
timestamp: new Date(),
|
|
62
79
|
source: captureMode === 'camera' ? 'camera' : 'upload'
|
|
63
|
-
}
|
|
80
|
+
};
|
|
81
|
+
const serializedValue = VariableValueConverter.serialize(fileData, variable.typeCode);
|
|
82
|
+
onChange(serializedValue);
|
|
64
83
|
};
|
|
65
84
|
const startCamera = async () => {
|
|
66
85
|
if (disabled)
|
package/package.json
CHANGED