@rsuci/shared-form-components 1.0.2 → 1.0.4
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/VariableRenderer.d.ts.map +1 -1
- package/dist/components/VariableRenderer.js +2 -2
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/inputs/GeographicCascadeInput.d.ts +1 -0
- package/dist/components/inputs/GeographicCascadeInput.d.ts.map +1 -1
- package/dist/components/inputs/GeographicCascadeInput.js +42 -27
- package/dist/components/inputs/SearchableSelect.d.ts +28 -0
- package/dist/components/inputs/SearchableSelect.d.ts.map +1 -0
- package/dist/components/inputs/SearchableSelect.js +71 -0
- package/dist/components/inputs/SelectInput.d.ts +1 -1
- package/dist/components/inputs/SelectInput.d.ts.map +1 -1
- package/dist/components/inputs/SelectInput.js +24 -19
- package/dist/components/selectors/EnqueteInput.d.ts +4 -3
- package/dist/components/selectors/EnqueteInput.d.ts.map +1 -1
- package/dist/components/selectors/EnqueteInput.js +52 -13
- package/dist/components/selectors/MenageInput.d.ts +4 -3
- package/dist/components/selectors/MenageInput.d.ts.map +1 -1
- package/dist/components/selectors/MenageInput.js +52 -13
- package/dist/utils/variableDependencyResolver.d.ts +3 -2
- package/dist/utils/variableDependencyResolver.d.ts.map +1 -1
- package/dist/utils/variableDependencyResolver.js +5 -3
- package/package.json +1 -1
- package/.gitattributes +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VariableRenderer.d.ts","sourceRoot":"","sources":["../../src/components/VariableRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AA2BxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC1F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,MAAM,WAAW,qBAAqB;IACpC,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;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC9D,qBAAqB,CAAC,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjE,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC3C,eAAe,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAG/B,gBAAgB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC9D,eAAe,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC7D,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAGvH,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,oBAAoB,CAAC,EAAE,GAAG,CAAC;CAC5B;AAGD,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAQvD,CAAC;AAGF,QAAA,MAAM,mBAAmB,GACvB,UAAU,MAAM,EAChB,mBAAmB,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,EAC7D,kBAAkB,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,KAC3D,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAgD3C,CAAC;AAGF,QAAA,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"VariableRenderer.d.ts","sourceRoot":"","sources":["../../src/components/VariableRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AA2BxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC1F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,MAAM,WAAW,qBAAqB;IACpC,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;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC9D,qBAAqB,CAAC,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjE,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC3C,eAAe,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAG/B,gBAAgB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC9D,eAAe,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC7D,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAGvH,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,oBAAoB,CAAC,EAAE,GAAG,CAAC;CAC5B;AAGD,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAQvD,CAAC;AAGF,QAAA,MAAM,mBAAmB,GACvB,UAAU,MAAM,EAChB,mBAAmB,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,EAC7D,kBAAkB,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,KAC3D,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAgD3C,CAAC;AAGF,QAAA,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAmGrD,CAAC;AAEF,eAAe,gBAAgB,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -53,7 +53,7 @@ const getVariableRenderer = (typeCode, RosterCheckInput, RosterListInput) => {
|
|
|
53
53
|
return renderers[typeCode] || StringInput;
|
|
54
54
|
};
|
|
55
55
|
// Composant principal VariableRenderer
|
|
56
|
-
const VariableRenderer = ({ variable, value, onChange, onBlur, error, disabled, numeroMembre, valeurMin, onFillFormFromMenage, onFillFormFromEnquete, formulaireVariables, rosterVariables, allResponses = {}, RosterCheckInput, RosterListInput, interpolateVariableLabel, reponses = {} }) => {
|
|
56
|
+
const VariableRenderer = ({ variable, value, onChange, onBlur, error, disabled, numeroMembre, valeurMin, onFillFormFromMenage, onFillFormFromEnquete, formulaireVariables, rosterVariables, allResponses = {}, RosterCheckInput, RosterListInput, interpolateVariableLabel, reponses = {}, services }) => {
|
|
57
57
|
const RendererComponent = getVariableRenderer(variable.typeCode, RosterCheckInput, RosterListInput);
|
|
58
58
|
// Interpoler le libellé avec les valeurs des autres variables (si fonction fournie)
|
|
59
59
|
const interpolatedDesignation = interpolateVariableLabel
|
|
@@ -77,7 +77,7 @@ const VariableRenderer = ({ variable, value, onChange, onBlur, error, disabled,
|
|
|
77
77
|
length: Array.isArray(rosterVariables) ? rosterVariables.length : 'N/A'
|
|
78
78
|
});
|
|
79
79
|
return null;
|
|
80
|
-
})(), _jsx(RendererComponent, { variable: variable, value: value, onChange: onChange, onBlur: onBlur, error: error, disabled: disabled, numeroMembre: numeroMembre, valeurMin: valeurMin, onFillFormFromMenage: onFillFormFromMenage, onFillFormFromEnquete: onFillFormFromEnquete, formulaireVariables: formulaireVariables, rosterVariables: rosterVariables, allResponses: allResponses, reponses: reponses })] }), variable.proprietes?.helpText && (_jsx("p", { className: "text-xs text-gray-500", children: variable.proprietes.helpText })), 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 })] }))] }));
|
|
80
|
+
})(), _jsx(RendererComponent, { variable: variable, value: value, onChange: onChange, onBlur: onBlur, error: error, disabled: disabled, numeroMembre: numeroMembre, valeurMin: valeurMin, onFillFormFromMenage: onFillFormFromMenage, onFillFormFromEnquete: onFillFormFromEnquete, formulaireVariables: formulaireVariables, rosterVariables: rosterVariables, allResponses: allResponses, reponses: reponses, services: services })] }), variable.proprietes?.helpText && (_jsx("p", { className: "text-xs text-gray-500", children: variable.proprietes.helpText })), 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 })] }))] }));
|
|
81
81
|
};
|
|
82
82
|
export default VariableRenderer;
|
|
83
83
|
export { getVariableRenderer, GeographicFallback };
|
|
@@ -9,6 +9,7 @@ export { default as DepartementInput } from './geographic/DepartementInput';
|
|
|
9
9
|
export { default as SousPrefectureInput } from './geographic/SousPrefectureInput';
|
|
10
10
|
export { default as QuartierInput } from './geographic/QuartierInput';
|
|
11
11
|
export { default as VillageInput } from './geographic/VillageInput';
|
|
12
|
+
export { default as SearchableSelect } from './inputs/SearchableSelect';
|
|
12
13
|
export { default as GeographicCascadeInput } from './inputs/GeographicCascadeInput';
|
|
13
14
|
export { default as StringInput } from './inputs/StringInput';
|
|
14
15
|
export { default as NumberInput } from './inputs/NumberInput';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAI3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAG9D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGnE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAI3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAG9D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGnE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/components/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export { default as SousPrefectureInput } from './geographic/SousPrefectureInput
|
|
|
14
14
|
export { default as QuartierInput } from './geographic/QuartierInput';
|
|
15
15
|
export { default as VillageInput } from './geographic/VillageInput';
|
|
16
16
|
// Input Components
|
|
17
|
+
export { default as SearchableSelect } from './inputs/SearchableSelect';
|
|
17
18
|
export { default as GeographicCascadeInput } from './inputs/GeographicCascadeInput';
|
|
18
19
|
export { default as StringInput } from './inputs/StringInput';
|
|
19
20
|
export { default as NumberInput } from './inputs/NumberInput';
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Composant unifié pour la sélection géographique en cascade
|
|
3
3
|
* S'adapte automatiquement selon le type de variable (DISTRICT, REGION, DEPARTEMENT, etc.)
|
|
4
4
|
* Gère la cascade via le champ variable.valeur (ex: "${G_01}")
|
|
5
|
+
* Utilise SearchableSelect pour une meilleure UX avec recherche intégrée
|
|
5
6
|
*/
|
|
6
7
|
import React from 'react';
|
|
7
8
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GeographicCascadeInput.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/GeographicCascadeInput.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"GeographicCascadeInput.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/GeographicCascadeInput.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAUhE;;GAEG;AACH,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAWD,UAAU,2BAA2B;IACnC,QAAQ,EAAE,GAAG,CAAC;IACd,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAoLxE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -3,19 +3,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
* Composant unifié pour la sélection géographique en cascade
|
|
4
4
|
* S'adapte automatiquement selon le type de variable (DISTRICT, REGION, DEPARTEMENT, etc.)
|
|
5
5
|
* Gère la cascade via le champ variable.valeur (ex: "${G_01}")
|
|
6
|
+
* Utilise SearchableSelect pour une meilleure UX avec recherche intégrée
|
|
6
7
|
*/
|
|
7
8
|
import { useEffect, useState, useCallback } from 'react';
|
|
9
|
+
import SearchableSelect from './SearchableSelect';
|
|
8
10
|
import { resolveParentValue, getApiEndpoint, getParentLabel, requiresParent } from '../../utils/variableDependencyResolver';
|
|
9
11
|
export const GeographicCascadeInput = ({ variable, value, onChange, reponses, disabled = false, required = false, className = '' }) => {
|
|
10
12
|
const [items, setItems] = useState([]);
|
|
11
13
|
const [loading, setLoading] = useState(false);
|
|
12
14
|
const [error, setError] = useState(null);
|
|
13
15
|
// 1. Déterminer si ce type nécessite un parent
|
|
14
|
-
const needsParent = requiresParent(variable.
|
|
16
|
+
const needsParent = requiresParent(variable.typeCode);
|
|
15
17
|
// 2. Résoudre la valeur du parent depuis les réponses
|
|
16
18
|
const parentValue = resolveParentValue(variable, reponses);
|
|
17
|
-
// 3.
|
|
18
|
-
const
|
|
19
|
+
// 3. Pour DISTRICT, déterminer le code pays (depuis variable.valeur ou défaut 'CIV')
|
|
20
|
+
const countryCode = variable.typeCode === 'DISTRICT'
|
|
21
|
+
? (variable.valeur || 'CIV')
|
|
22
|
+
: undefined;
|
|
23
|
+
// 4. Déterminer l'endpoint API à appeler
|
|
24
|
+
const apiEndpoint = getApiEndpoint(variable.typeCode, parentValue, countryCode);
|
|
19
25
|
// 4. Fonction pour charger les données
|
|
20
26
|
const fetchData = useCallback(async () => {
|
|
21
27
|
// Si un parent est requis mais absent, ne rien charger
|
|
@@ -49,8 +55,8 @@ export const GeographicCascadeInput = ({ variable, value, onChange, reponses, di
|
|
|
49
55
|
}
|
|
50
56
|
}
|
|
51
57
|
catch (err) {
|
|
52
|
-
console.error(`Error fetching ${variable.
|
|
53
|
-
setError(`Erreur de chargement des ${variable.
|
|
58
|
+
console.error(`Error fetching ${variable.typeCode}:`, err);
|
|
59
|
+
setError(`Erreur de chargement des ${variable.designation?.toLowerCase() || 'données'}`);
|
|
54
60
|
setItems([]);
|
|
55
61
|
}
|
|
56
62
|
finally {
|
|
@@ -71,22 +77,18 @@ export const GeographicCascadeInput = ({ variable, value, onChange, reponses, di
|
|
|
71
77
|
}
|
|
72
78
|
}, [parentValue, needsParent, value]);
|
|
73
79
|
// 7. Gérer le changement de valeur
|
|
74
|
-
const handleChange = (
|
|
75
|
-
|
|
76
|
-
if (!selectedId || selectedId === '') {
|
|
80
|
+
const handleChange = (option) => {
|
|
81
|
+
if (!option) {
|
|
77
82
|
onChange(null);
|
|
78
83
|
return;
|
|
79
84
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// Stocker l'objet complet SelectDto
|
|
88
|
-
onChange(selected);
|
|
89
|
-
}
|
|
85
|
+
// Convertir SelectOption vers SelectDto
|
|
86
|
+
const selectDto = {
|
|
87
|
+
id: typeof option.id === 'string' ? parseInt(option.id, 10) : option.id,
|
|
88
|
+
code: option.code || '',
|
|
89
|
+
designation: option.designation
|
|
90
|
+
};
|
|
91
|
+
onChange(selectDto);
|
|
90
92
|
};
|
|
91
93
|
// 8. Déterminer si le champ est désactivé
|
|
92
94
|
const isDisabled = disabled || loading || (needsParent && !parentValue);
|
|
@@ -94,19 +96,32 @@ export const GeographicCascadeInput = ({ variable, value, onChange, reponses, di
|
|
|
94
96
|
const getPlaceholder = () => {
|
|
95
97
|
if (loading)
|
|
96
98
|
return 'Chargement...';
|
|
97
|
-
if (error)
|
|
98
|
-
return error;
|
|
99
99
|
if (needsParent && !parentValue) {
|
|
100
|
-
return `Sélectionnez d'abord ${getParentLabel(variable.
|
|
100
|
+
return `Sélectionnez d'abord ${getParentLabel(variable.typeCode)}`;
|
|
101
101
|
}
|
|
102
102
|
if (items.length === 0 && !loading) {
|
|
103
|
-
return `Aucun(e) ${variable.
|
|
103
|
+
return `Aucun(e) ${variable.designation?.toLowerCase() || 'élément'} disponible`;
|
|
104
104
|
}
|
|
105
|
-
return `Sélectionner ${variable.
|
|
105
|
+
return `Sélectionner ${variable.designation || 'un élément'}...`;
|
|
106
106
|
};
|
|
107
|
-
// 10.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
// 10. Convertir les items en SelectOption pour SearchableSelect
|
|
108
|
+
const options = items.map(item => ({
|
|
109
|
+
id: item.id,
|
|
110
|
+
code: item.code,
|
|
111
|
+
designation: item.designation
|
|
112
|
+
}));
|
|
113
|
+
// 11. Convertir la valeur actuelle en SelectOption
|
|
114
|
+
const currentValue = value ? {
|
|
115
|
+
id: value.id,
|
|
116
|
+
code: value.code,
|
|
117
|
+
designation: value.designation
|
|
118
|
+
} : null;
|
|
119
|
+
// 12. Rendu du composant
|
|
120
|
+
return (_jsxs("div", { className: "w-full", children: [_jsx(SearchableSelect, { options: options, value: currentValue, onChange: handleChange, placeholder: getPlaceholder(), searchPlaceholder: "Rechercher...", disabled: isDisabled, required: required, loading: loading, error: error || undefined, className: className, noOptionsMessage: needsParent && !parentValue
|
|
121
|
+
? `Veuillez d'abord sélectionner ${getParentLabel(variable.typeCode)}`
|
|
122
|
+
: `Aucun(e) ${variable.designation?.toLowerCase() || 'élément'} disponible`, formatOptionLabel: (option) => {
|
|
123
|
+
// Formater le label avec le code si disponible
|
|
124
|
+
return option.code ? `${option.code} ${option.designation}` : option.designation;
|
|
125
|
+
} }), needsParent && !parentValue && !loading && !error && (_jsxs("p", { className: "mt-1 text-sm text-gray-500 flex items-center", children: [_jsx("svg", { className: "w-4 h-4 mr-1", fill: "currentColor", viewBox: "0 0 20 20", children: _jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" }) }), "Veuillez d'abord s\u00E9lectionner ", getParentLabel(variable.typeCode)] })), loading && (_jsxs("p", { className: "mt-1 text-sm text-blue-600 flex items-center", children: [_jsxs("svg", { className: "animate-spin h-4 w-4 mr-1", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }), "Chargement des donn\u00E9es..."] }))] }));
|
|
111
126
|
};
|
|
112
127
|
export default GeographicCascadeInput;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composant de sélection avec recherche intégrée
|
|
3
|
+
* Inspiré du design de production avec champ de filtre
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
export interface SelectOption {
|
|
7
|
+
id: number | string;
|
|
8
|
+
code?: string;
|
|
9
|
+
designation: string;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
12
|
+
interface SearchableSelectProps {
|
|
13
|
+
options: SelectOption[];
|
|
14
|
+
value?: SelectOption | null;
|
|
15
|
+
onChange: (option: SelectOption | null) => void;
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
searchPlaceholder?: string;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
required?: boolean;
|
|
20
|
+
loading?: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
className?: string;
|
|
23
|
+
noOptionsMessage?: string;
|
|
24
|
+
formatOptionLabel?: (option: SelectOption) => string;
|
|
25
|
+
}
|
|
26
|
+
export declare const SearchableSelect: React.FC<SearchableSelectProps>;
|
|
27
|
+
export default SearchableSelect;
|
|
28
|
+
//# sourceMappingURL=SearchableSelect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchableSelect.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/SearchableSelect.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAsC,MAAM,OAAO,CAAC;AAE3D,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,MAAM,CAAC;CACtD;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA+L5D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Composant de sélection avec recherche intégrée
|
|
4
|
+
* Inspiré du design de production avec champ de filtre
|
|
5
|
+
*/
|
|
6
|
+
import { useState, useRef, useEffect } from 'react';
|
|
7
|
+
export const SearchableSelect = ({ options, value, onChange, placeholder = 'Sélectionner...', searchPlaceholder = 'Rechercher...', disabled = false, required = false, loading = false, error, className = '', noOptionsMessage = 'Aucune option disponible', formatOptionLabel }) => {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
10
|
+
const dropdownRef = useRef(null);
|
|
11
|
+
const searchInputRef = useRef(null);
|
|
12
|
+
// Fermer le dropdown quand on clique à l'extérieur
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const handleClickOutside = (event) => {
|
|
15
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
16
|
+
setIsOpen(false);
|
|
17
|
+
setSearchTerm('');
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
21
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
22
|
+
}, []);
|
|
23
|
+
// Focus sur le champ de recherche quand le dropdown s'ouvre
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (isOpen && searchInputRef.current) {
|
|
26
|
+
searchInputRef.current.focus();
|
|
27
|
+
}
|
|
28
|
+
}, [isOpen]);
|
|
29
|
+
// Filtrer les options selon le terme de recherche
|
|
30
|
+
const filteredOptions = options.filter(option => {
|
|
31
|
+
const label = formatOptionLabel ? formatOptionLabel(option) : option.designation;
|
|
32
|
+
const searchLower = searchTerm.toLowerCase();
|
|
33
|
+
return (label.toLowerCase().includes(searchLower) ||
|
|
34
|
+
(option.code && option.code.toLowerCase().includes(searchLower)));
|
|
35
|
+
});
|
|
36
|
+
// Gérer la sélection d'une option
|
|
37
|
+
const handleSelect = (option) => {
|
|
38
|
+
onChange(option);
|
|
39
|
+
setIsOpen(false);
|
|
40
|
+
setSearchTerm('');
|
|
41
|
+
};
|
|
42
|
+
// Gérer l'ouverture/fermeture du dropdown
|
|
43
|
+
const toggleDropdown = () => {
|
|
44
|
+
if (!disabled && !loading) {
|
|
45
|
+
setIsOpen(!isOpen);
|
|
46
|
+
if (!isOpen) {
|
|
47
|
+
setSearchTerm('');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
// Formater le label d'une option
|
|
52
|
+
const getOptionLabel = (option) => {
|
|
53
|
+
if (formatOptionLabel) {
|
|
54
|
+
return formatOptionLabel(option);
|
|
55
|
+
}
|
|
56
|
+
return option.code ? `${option.code} ${option.designation}` : option.designation;
|
|
57
|
+
};
|
|
58
|
+
// Obtenir le label de la valeur sélectionnée
|
|
59
|
+
const getSelectedLabel = () => {
|
|
60
|
+
if (!value)
|
|
61
|
+
return placeholder;
|
|
62
|
+
return getOptionLabel(value);
|
|
63
|
+
};
|
|
64
|
+
return (_jsxs("div", { className: `relative w-full ${className}`, ref: dropdownRef, children: [_jsx("button", { type: "button", onClick: toggleDropdown, disabled: disabled || loading, className: `w-full px-3 py-2 text-left border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors ${error ? 'border-red-300 bg-red-50' : 'border-gray-300'} ${disabled || loading
|
|
65
|
+
? 'bg-gray-100 cursor-not-allowed text-gray-500'
|
|
66
|
+
: 'bg-white text-gray-900 hover:border-gray-400'} ${isOpen ? 'ring-2 ring-blue-500 border-transparent' : ''}`, children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: value ? 'text-gray-900' : 'text-gray-500', children: loading ? 'Chargement...' : getSelectedLabel() }), _jsx("svg", { className: `w-5 h-5 text-gray-400 transition-transform ${isOpen ? 'transform rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })] }) }), isOpen && !disabled && !loading && (_jsxs("div", { className: "absolute z-50 w-full mt-1 bg-white border border-gray-300 rounded-lg shadow-lg max-h-80 overflow-hidden", children: [_jsx("div", { className: "p-2 border-b border-gray-200 bg-gray-50", children: _jsxs("div", { className: "relative", children: [_jsx("svg", { className: "absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), _jsx("input", { ref: searchInputRef, type: "text", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), placeholder: searchPlaceholder, className: "w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm" })] }) }), _jsx("div", { className: "overflow-y-auto max-h-60", children: filteredOptions.length === 0 ? (_jsx("div", { className: "px-4 py-3 text-sm text-gray-500 text-center", children: searchTerm ? `Aucun résultat pour "${searchTerm}"` : noOptionsMessage })) : (_jsx("ul", { className: "py-1", children: filteredOptions.map((option) => {
|
|
67
|
+
const isSelected = value?.id === option.id;
|
|
68
|
+
return (_jsx("li", { children: _jsx("button", { type: "button", onClick: () => handleSelect(option), className: `w-full px-4 py-2 text-left text-sm hover:bg-blue-50 transition-colors ${isSelected ? 'bg-blue-100 text-blue-900 font-medium' : 'text-gray-900'}`, children: getOptionLabel(option) }) }, option.id));
|
|
69
|
+
}) })) })] })), error && (_jsxs("p", { className: "mt-1 text-sm text-red-600 flex items-center", children: [_jsx("svg", { className: "w-4 h-4 mr-1", fill: "currentColor", viewBox: "0 0 20 20", children: _jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }), error] })), required && !value && (_jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Ce champ est obligatoire" }))] }));
|
|
70
|
+
};
|
|
71
|
+
export default SearchableSelect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectInput.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/SelectInput.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,
|
|
1
|
+
{"version":3,"file":"SelectInput.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/SelectInput.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIxE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,kBAAkB,GAAG;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IACrD,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;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAuF3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Composant SelectInput - Liste de sélection avec recherche
|
|
2
|
+
* Composant SelectInput - Liste de sélection avec recherche intégrée
|
|
3
3
|
* RSU v2 - Moteur de Rendu des Formulaires d'Enquête
|
|
4
4
|
*/
|
|
5
5
|
'use client';
|
|
6
6
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { useState } from 'react';
|
|
8
7
|
import { VariableValueConverter } from '../../lib/utils/variableValueConverter';
|
|
8
|
+
import SearchableSelect from './SearchableSelect';
|
|
9
9
|
const SelectInput = ({ variable, value, onChange, onBlur, error, disabled }) => {
|
|
10
|
-
const [searchTerm, setSearchTerm] = useState('');
|
|
11
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
12
|
-
const itemsPerPage = 10;
|
|
13
10
|
// Récupérer les options depuis la propriété valeur OU valeurDefaut (format: "Code1#Designation1|Code2#Designation2")
|
|
14
11
|
const optionsSource = variable.proprietes?.valeur || variable.valeurDefaut;
|
|
15
12
|
const allOptions = optionsSource && typeof optionsSource === 'string'
|
|
@@ -18,22 +15,30 @@ const SelectInput = ({ variable, value, onChange, onBlur, error, disabled }) =>
|
|
|
18
15
|
code: opt.value.toString(),
|
|
19
16
|
designation: opt.label
|
|
20
17
|
}));
|
|
21
|
-
// Filtrage par recherche
|
|
22
|
-
const filteredOptions = allOptions.filter(option => option.designation.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
23
|
-
option.code.toLowerCase().includes(searchTerm.toLowerCase()));
|
|
24
|
-
// Pagination
|
|
25
|
-
const totalPages = Math.ceil(filteredOptions.length / itemsPerPage);
|
|
26
|
-
const startIndex = (currentPage - 1) * itemsPerPage;
|
|
27
|
-
const paginatedOptions = filteredOptions.slice(startIndex, startIndex + itemsPerPage);
|
|
28
18
|
const selectedValue = value || '';
|
|
29
|
-
// Affichage radio pour peu d'options
|
|
30
|
-
if (allOptions.length <= 5
|
|
19
|
+
// Affichage radio pour peu d'options (≤5)
|
|
20
|
+
if (allOptions.length <= 5) {
|
|
31
21
|
return (_jsx("div", { className: "space-y-2", children: allOptions.map((option) => (_jsxs("label", { className: "flex items-center space-x-2 cursor-pointer", children: [_jsx("input", { type: "radio", name: variable.code, value: option.code, checked: selectedValue === option.code, onChange: (e) => onChange(e.target.value), onBlur: onBlur, disabled: disabled, className: `w-4 h-4 text-green-600 border-gray-300 focus:ring-green-500 ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}` }), _jsx("span", { className: `text-sm ${disabled ? 'text-gray-400' : 'text-gray-700'}`, children: option.designation })] }, option.code))) }));
|
|
32
22
|
}
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
// Convertir les options au format SelectOption pour SearchableSelect
|
|
24
|
+
const selectOptions = allOptions.map(opt => ({
|
|
25
|
+
id: opt.code,
|
|
26
|
+
code: opt.code,
|
|
27
|
+
designation: opt.designation
|
|
28
|
+
}));
|
|
29
|
+
// Trouver l'option sélectionnée
|
|
30
|
+
const selectedOption = selectOptions.find(opt => opt.code === selectedValue) || null;
|
|
31
|
+
// Gérer le changement de sélection
|
|
32
|
+
const handleChange = (option) => {
|
|
33
|
+
onChange(option?.code || '');
|
|
34
|
+
if (onBlur)
|
|
35
|
+
onBlur();
|
|
36
|
+
};
|
|
37
|
+
// Format d'affichage: "Code - Designation"
|
|
38
|
+
const formatOptionLabel = (option) => {
|
|
39
|
+
return `${option.code} - ${option.designation}`;
|
|
40
|
+
};
|
|
41
|
+
// Affichage avec SearchableSelect pour beaucoup d'options (>5)
|
|
42
|
+
return (_jsxs("div", { className: "space-y-2", children: [_jsx(SearchableSelect, { options: selectOptions, value: selectedOption, onChange: handleChange, placeholder: "S\u00E9lectionner...", searchPlaceholder: "Rechercher...", disabled: disabled, required: variable.estObligatoire, error: error, formatOptionLabel: formatOptionLabel, noOptionsMessage: "Aucune option trouv\u00E9e" }), selectedValue && selectedOption && (_jsx("div", { className: "p-2 bg-green-50 border border-green-200 rounded text-sm", children: _jsxs("span", { className: "text-green-800", children: ["S\u00E9lectionn\u00E9: ", selectedOption.designation] }) }))] }));
|
|
38
43
|
};
|
|
39
44
|
export default SelectInput;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
3
|
-
id: number;
|
|
4
|
-
}
|
|
2
|
+
import { EnqueteCompletDto } from '../../types/services';
|
|
5
3
|
export interface EnqueteInputProps {
|
|
6
4
|
variable: {
|
|
7
5
|
typeCode: string;
|
|
@@ -22,6 +20,9 @@ export interface EnqueteInputProps {
|
|
|
22
20
|
valeurMin?: number;
|
|
23
21
|
onFillFormFromEnquete?: (enqueteData: EnqueteCompletDto) => void;
|
|
24
22
|
formulaireVariables?: any[];
|
|
23
|
+
services?: {
|
|
24
|
+
fetchEnquetes?: (filter?: any) => Promise<EnqueteCompletDto[]>;
|
|
25
|
+
};
|
|
25
26
|
}
|
|
26
27
|
declare const EnqueteInput: React.FC<EnqueteInputProps>;
|
|
27
28
|
export { EnqueteInput };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnqueteInput.d.ts","sourceRoot":"","sources":["../../../src/components/selectors/EnqueteInput.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"EnqueteInput.d.ts","sourceRoot":"","sources":["../../../src/components/selectors/EnqueteInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,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,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;IACnB,qBAAqB,CAAC,EAAE,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjE,mBAAmB,CAAC,EAAE,GAAG,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE;QACT,aAAa,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;KAChE,CAAC;CACH;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmF7C,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,eAAe,YAAY,CAAC"}
|
|
@@ -1,21 +1,60 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import SearchableSelect from '../inputs/SearchableSelect';
|
|
5
|
+
const EnqueteInput = ({ variable, value, onChange, error, disabled, onFillFormFromEnquete, services }) => {
|
|
6
|
+
const [enquetes, setEnquetes] = useState([]);
|
|
7
|
+
const [loading, setLoading] = useState(false);
|
|
8
|
+
const [loadError, setLoadError] = useState(null);
|
|
9
|
+
// Charger les enquêtes au montage du composant
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const loadEnquetes = async () => {
|
|
12
|
+
if (!services?.fetchEnquetes) {
|
|
13
|
+
setLoadError('Service de chargement des enquêtes non disponible');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
setLoading(true);
|
|
17
|
+
setLoadError(null);
|
|
18
|
+
try {
|
|
19
|
+
const data = await services.fetchEnquetes();
|
|
20
|
+
setEnquetes(data);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
console.error('Erreur lors du chargement des enquêtes:', err);
|
|
24
|
+
setLoadError('Erreur lors du chargement des enquêtes');
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
setLoading(false);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
loadEnquetes();
|
|
31
|
+
}, [services]);
|
|
32
|
+
// Convertir les enquêtes en options pour SearchableSelect
|
|
33
|
+
const options = enquetes.map(enquete => ({
|
|
34
|
+
id: enquete.id,
|
|
35
|
+
code: enquete.numeroEnquete || enquete.id.toString(),
|
|
36
|
+
designation: `Enquête ${enquete.numeroEnquete || enquete.id}` + (enquete.formulaireId ? ` - Formulaire ${enquete.formulaireId}` : '')
|
|
37
|
+
}));
|
|
38
|
+
// Trouver l'enquête sélectionnée
|
|
39
|
+
const enqueteId = value ? parseInt(value) : null;
|
|
40
|
+
const selectedOption = enqueteId ? options.find(opt => opt.id === enqueteId) : null;
|
|
41
|
+
// Gérer le changement de sélection
|
|
42
|
+
const handleChange = (option) => {
|
|
43
|
+
const newEnqueteId = option?.id;
|
|
11
44
|
onChange(newEnqueteId?.toString() || null);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
45
|
+
// Si un callback de remplissage est fourni et qu'une enquête est sélectionnée
|
|
46
|
+
if (onFillFormFromEnquete && newEnqueteId) {
|
|
47
|
+
const enqueteData = enquetes.find(e => e.id === newEnqueteId);
|
|
48
|
+
if (enqueteData) {
|
|
49
|
+
onFillFormFromEnquete(enqueteData);
|
|
50
|
+
}
|
|
16
51
|
}
|
|
17
52
|
};
|
|
18
|
-
|
|
53
|
+
// Format d'affichage: "NumeroEnquete - Description"
|
|
54
|
+
const formatOptionLabel = (option) => {
|
|
55
|
+
return `${option.code} - ${option.designation}`;
|
|
56
|
+
};
|
|
57
|
+
return (_jsx(SearchableSelect, { options: options, value: selectedOption, onChange: handleChange, placeholder: "S\u00E9lectionner une enqu\u00EAte...", searchPlaceholder: "Rechercher une enqu\u00EAte...", disabled: disabled, required: variable.estObligatoire, loading: loading, error: loadError || error, formatOptionLabel: formatOptionLabel, noOptionsMessage: loading ? "Chargement..." : "Aucune enquête trouvée" }));
|
|
19
58
|
};
|
|
20
59
|
export { EnqueteInput };
|
|
21
60
|
export default EnqueteInput;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
3
|
-
id: number;
|
|
4
|
-
}
|
|
2
|
+
import { MenageCompletDto } from '../../types/services';
|
|
5
3
|
export interface MenageInputProps {
|
|
6
4
|
variable: {
|
|
7
5
|
typeCode: string;
|
|
@@ -22,6 +20,9 @@ export interface MenageInputProps {
|
|
|
22
20
|
valeurMin?: number;
|
|
23
21
|
onFillFormFromMenage?: (menageData: MenageCompletDto) => void;
|
|
24
22
|
formulaireVariables?: any[];
|
|
23
|
+
services?: {
|
|
24
|
+
fetchMenages?: () => Promise<MenageCompletDto[]>;
|
|
25
|
+
};
|
|
25
26
|
}
|
|
26
27
|
declare const MenageInput: React.FC<MenageInputProps>;
|
|
27
28
|
export { MenageInput };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MenageInput.d.ts","sourceRoot":"","sources":["../../../src/components/selectors/MenageInput.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"MenageInput.d.ts","sourceRoot":"","sources":["../../../src/components/selectors/MenageInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,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,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;IACnB,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC9D,mBAAmB,CAAC,EAAE,GAAG,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE;QACT,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;KAClD,CAAC;CACH;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAmF3C,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,eAAe,WAAW,CAAC"}
|
|
@@ -1,21 +1,60 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import SearchableSelect from '../inputs/SearchableSelect';
|
|
5
|
+
const MenageInput = ({ variable, value, onChange, error, disabled, onFillFormFromMenage, services }) => {
|
|
6
|
+
const [menages, setMenages] = useState([]);
|
|
7
|
+
const [loading, setLoading] = useState(false);
|
|
8
|
+
const [loadError, setLoadError] = useState(null);
|
|
9
|
+
// Charger les ménages au montage du composant
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const loadMenages = async () => {
|
|
12
|
+
if (!services?.fetchMenages) {
|
|
13
|
+
setLoadError('Service de chargement des ménages non disponible');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
setLoading(true);
|
|
17
|
+
setLoadError(null);
|
|
18
|
+
try {
|
|
19
|
+
const data = await services.fetchMenages();
|
|
20
|
+
setMenages(data);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
console.error('Erreur lors du chargement des ménages:', err);
|
|
24
|
+
setLoadError('Erreur lors du chargement des ménages');
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
setLoading(false);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
loadMenages();
|
|
31
|
+
}, [services]);
|
|
32
|
+
// Convertir les ménages en options pour SearchableSelect
|
|
33
|
+
const options = menages.map(menage => ({
|
|
34
|
+
id: menage.id,
|
|
35
|
+
code: menage.numeroMenage || menage.id.toString(),
|
|
36
|
+
designation: `${menage.nomChefMenage || ''} ${menage.prenomChefMenage || ''}`.trim() || `Ménage ${menage.id}`
|
|
37
|
+
}));
|
|
38
|
+
// Trouver le ménage sélectionné
|
|
39
|
+
const menageId = value ? parseInt(value) : null;
|
|
40
|
+
const selectedOption = menageId ? options.find(opt => opt.id === menageId) : null;
|
|
41
|
+
// Gérer le changement de sélection
|
|
42
|
+
const handleChange = (option) => {
|
|
43
|
+
const newMenageId = option?.id;
|
|
11
44
|
onChange(newMenageId?.toString() || null);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
45
|
+
// Si un callback de remplissage est fourni et qu'un ménage est sélectionné
|
|
46
|
+
if (onFillFormFromMenage && newMenageId) {
|
|
47
|
+
const menageData = menages.find(m => m.id === newMenageId);
|
|
48
|
+
if (menageData) {
|
|
49
|
+
onFillFormFromMenage(menageData);
|
|
50
|
+
}
|
|
16
51
|
}
|
|
17
52
|
};
|
|
18
|
-
|
|
53
|
+
// Format d'affichage: "NumeroMenage - Nom Prénom"
|
|
54
|
+
const formatOptionLabel = (option) => {
|
|
55
|
+
return `${option.code} - ${option.designation}`;
|
|
56
|
+
};
|
|
57
|
+
return (_jsx(SearchableSelect, { options: options, value: selectedOption, onChange: handleChange, placeholder: "S\u00E9lectionner un m\u00E9nage...", searchPlaceholder: "Rechercher un m\u00E9nage...", disabled: disabled, required: variable.estObligatoire, loading: loading, error: loadError || error, formatOptionLabel: formatOptionLabel, noOptionsMessage: loading ? "Chargement..." : "Aucun ménage trouvé" }));
|
|
19
58
|
};
|
|
20
59
|
export { MenageInput };
|
|
21
60
|
export default MenageInput;
|
|
@@ -30,14 +30,15 @@ export declare function resolveParentValue(variable: any, reponses: Record<strin
|
|
|
30
30
|
* Détermine l'endpoint API selon le type de variable et l'ID du parent
|
|
31
31
|
* @param variableType - Type de la variable (DISTRICT, REGION, DEPARTEMENT, etc.)
|
|
32
32
|
* @param parentId - ID du parent (optionnel)
|
|
33
|
+
* @param defaultCountryCode - Code pays par défaut pour DISTRICT (défaut: 'CIV')
|
|
33
34
|
* @returns Endpoint API ou null si invalide
|
|
34
35
|
*
|
|
35
36
|
* @example
|
|
36
|
-
* getApiEndpoint('DISTRICT') // Returns: '/api/v1/Districts/select'
|
|
37
|
+
* getApiEndpoint('DISTRICT') // Returns: '/api/v1/Districts/CIV/select'
|
|
37
38
|
* getApiEndpoint('REGION', 1) // Returns: '/api/v1/Regions/1/select'
|
|
38
39
|
* getApiEndpoint('REGION') // Returns: null (parent requis mais absent)
|
|
39
40
|
*/
|
|
40
|
-
export declare function getApiEndpoint(variableType: string, parentId?: number | null): string | null;
|
|
41
|
+
export declare function getApiEndpoint(variableType: string, parentId?: number | null, defaultCountryCode?: string): string | null;
|
|
41
42
|
/**
|
|
42
43
|
* Détermine le libellé du parent selon le type de variable
|
|
43
44
|
* @param variableType - Type de la variable
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"variableDependencyResolver.d.ts","sourceRoot":"","sources":["../../src/utils/variableDependencyResolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAMpF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,MAAM,GAAG,IAAI,CAiCf;AAED
|
|
1
|
+
{"version":3,"file":"variableDependencyResolver.d.ts","sourceRoot":"","sources":["../../src/utils/variableDependencyResolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAMpF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,MAAM,GAAG,IAAI,CAiCf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EACxB,kBAAkB,GAAE,MAAc,GACjC,MAAM,GAAG,IAAI,CA2Bf;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAa3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAW5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAY9D"}
|
|
@@ -64,18 +64,20 @@ export function resolveParentValue(variable, reponses) {
|
|
|
64
64
|
* Détermine l'endpoint API selon le type de variable et l'ID du parent
|
|
65
65
|
* @param variableType - Type de la variable (DISTRICT, REGION, DEPARTEMENT, etc.)
|
|
66
66
|
* @param parentId - ID du parent (optionnel)
|
|
67
|
+
* @param defaultCountryCode - Code pays par défaut pour DISTRICT (défaut: 'CIV')
|
|
67
68
|
* @returns Endpoint API ou null si invalide
|
|
68
69
|
*
|
|
69
70
|
* @example
|
|
70
|
-
* getApiEndpoint('DISTRICT') // Returns: '/api/v1/Districts/select'
|
|
71
|
+
* getApiEndpoint('DISTRICT') // Returns: '/api/v1/Districts/CIV/select'
|
|
71
72
|
* getApiEndpoint('REGION', 1) // Returns: '/api/v1/Regions/1/select'
|
|
72
73
|
* getApiEndpoint('REGION') // Returns: null (parent requis mais absent)
|
|
73
74
|
*/
|
|
74
|
-
export function getApiEndpoint(variableType, parentId) {
|
|
75
|
+
export function getApiEndpoint(variableType, parentId, defaultCountryCode = 'CIV') {
|
|
75
76
|
const type = variableType?.toUpperCase();
|
|
76
77
|
switch (type) {
|
|
77
78
|
case 'DISTRICT':
|
|
78
|
-
|
|
79
|
+
// Pour DISTRICT, utiliser le code pays (par défaut 'CIV')
|
|
80
|
+
return `/api/v1/Districts/${defaultCountryCode}/select`;
|
|
79
81
|
case 'REGION':
|
|
80
82
|
return parentId ? `/api/v1/Regions/${parentId}/select` : null;
|
|
81
83
|
case 'DEPARTEMENT':
|
package/package.json
CHANGED
package/.gitattributes
DELETED