datakeen-session-react 1.1.140-rc.75 → 1.1.140-rc.76

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.
@@ -15,6 +15,7 @@ var PageActions = require('../ui/PageActions.js');
15
15
  var MobilePageLayout = require('../ui/MobilePageLayout.js');
16
16
  var useI18n = require('../../hooks/useI18n.js');
17
17
  var sessionService = require('../../services/sessionService.js');
18
+ var renderInlineMarkdown = require('../../utils/renderInlineMarkdown.js');
18
19
 
19
20
  function _interopNamespaceDefault(e) {
20
21
  var n = Object.create(null);
@@ -87,25 +88,19 @@ var LegalConsentNode = function (_a) {
87
88
  });
88
89
  }); };
89
90
  var pageTitle = node.pageTitle || t("LEGAL_CONSENT.default_title");
91
+ // Description unique au format Markdown (liens [libellé](url), gras).
90
92
  var description = node.consentDescription;
91
- var description2 = node.consentDescription2;
93
+ // Rétrocompat : on n'affiche consentDescription2 que pour les anciens nœuds
94
+ // qui n'ont pas de consentDescription (sinon doublon, le texte étant fusionné).
95
+ var description2 = description ? undefined : node.consentDescription2;
92
96
  var checkboxLabel = node.checkboxText || t("LEGAL_CONSENT.default_checkbox");
93
- // Use Datakeen default URLs when fields are left empty
94
- var cguUrl = node.cguUrl || t("LEGAL_CONSENT.default_cgu_url");
95
- var privacyUrl = node.privacyPolicyUrl || t("LEGAL_CONSENT.default_privacy_url");
96
- // Build description text with optional hyperlinks
97
- var renderDescription = function (text, url) {
98
- if (!url || !text)
99
- return jsxRuntime.jsx("p", { children: text });
100
- return (jsxRuntime.jsxs("p", { children: [text, " ", jsxRuntime.jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "underline text-blue-600 hover:text-blue-800", children: url })] }));
101
- };
102
97
  return (jsxRuntime.jsx(MobilePageLayout.default, { session: session, footer: jsxRuntime.jsxs("div", { className: "w-full space-y-4", children: [(error || submitError) && (jsxRuntime.jsx("div", { className: "bg-red-50 border border-red-200 rounded-lg p-3", children: jsxRuntime.jsx(Body.default, { className: "text-red-600 text-sm text-center", children: submitError
103
98
  ? submitError
104
99
  : t("LEGAL_CONSENT.error.required") }) })), jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 bg-gray-50 rounded-lg", children: [jsxRuntime.jsx(CheckboxPrimitive__namespace.Root, { id: "legal-consent-checkbox-".concat(node.id), checked: checked, onCheckedChange: function (value) { return handleCheckboxChange(!!value); }, className: "mt-1 h-5 w-5 shrink-0 rounded border bg-white transition-colors\n data-[state=checked]:bg-[var(--dk-btn-bg)] data-[state=checked]:border-[var(--dk-btn-bg)]\n ".concat(error
105
100
  ? "border-red-500"
106
101
  : "border-gray-300 hover:border-gray-400", "\n "), children: jsxRuntime.jsx(CheckboxPrimitive__namespace.Indicator, { className: "flex items-center justify-center text-white", children: jsxRuntime.jsx(reactIcons.CheckIcon, { className: "h-4 w-4" }) }) }), jsxRuntime.jsx(Label__namespace.Root, { htmlFor: "legal-consent-checkbox-".concat(node.id), className: "cursor-pointer", children: jsxRuntime.jsx(Body.default, { className: "text-left text-sm leading-relaxed ".concat(error ? "text-red-600" : "text-gray-700"), children: checkboxLabel }) })] }), jsxRuntime.jsx(PageActions.default, { primary: jsxRuntime.jsx(Button.default, { onClick: handleContinue, disabled: (isRequired && !checked) || isSubmitting, children: isSubmitting
107
102
  ? t("LEGAL_CONSENT.button.loading")
108
- : t("LEGAL_CONSENT.button.continue") }) })] }), children: jsxRuntime.jsx("div", { className: "px-4 py-8 md:px-8 flex flex-col", children: jsxRuntime.jsxs("div", { className: "w-full max-w-2xl mx-auto space-y-6", children: [jsxRuntime.jsx("div", { className: "text-center", children: jsxRuntime.jsx(Title.default, { className: "text-xl md:text-2xl lg:text-3xl mb-6", children: pageTitle }) }), (description || description2) && (jsxRuntime.jsx("div", { className: "bg-gray-50 rounded-lg p-4 md:p-6", children: jsxRuntime.jsxs(Body.default, { className: "text-left text-sm md:text-base leading-relaxed space-y-4", children: [description && renderDescription(description, cguUrl), description2 && renderDescription(description2, privacyUrl)] }) }))] }) }) }));
103
+ : t("LEGAL_CONSENT.button.continue") }) })] }), children: jsxRuntime.jsx("div", { className: "px-4 py-8 md:px-8 flex flex-col", children: jsxRuntime.jsxs("div", { className: "w-full max-w-2xl mx-auto space-y-6", children: [jsxRuntime.jsx("div", { className: "text-center", children: jsxRuntime.jsx(Title.default, { className: "text-xl md:text-2xl lg:text-3xl mb-6", children: pageTitle }) }), (description || description2) && (jsxRuntime.jsx("div", { className: "bg-gray-50 rounded-lg p-4 md:p-6", children: jsxRuntime.jsxs(Body.default, { className: "text-left text-sm md:text-base leading-relaxed space-y-4", children: [description && renderInlineMarkdown.renderInlineMarkdown(description), description2 && renderInlineMarkdown.renderInlineMarkdown(description2)] }) }))] }) }) }));
109
104
  };
110
105
 
111
106
  exports.default = LegalConsentNode;
@@ -1 +1 @@
1
- {"version":3,"file":"LegalConsentNode.js","sources":["../../../../../src/components/legal-consent/LegalConsentNode.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport Body from \"../ui/Body\";\nimport Title from \"../ui/Title\";\nimport Button from \"../ui/Button\";\nimport PageActions from \"../ui/PageActions\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport { updateSessionUserInput } from \"../../services/sessionService\";\nimport type { SessionData, SessionTemplateNode, stepObject } from \"../../types/session\";\n\ninterface LegalConsentNodeProps {\n node: SessionTemplateNode;\n session: SessionData;\n sessionId: string;\n stepObject: stepObject;\n}\n\nconst LegalConsentNode = ({\n node,\n session,\n sessionId,\n stepObject,\n}: LegalConsentNodeProps) => {\n const { t } = useI18n();\n const [checked, setChecked] = useState(false);\n const [error, setError] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const isRequired = node.isRequired !== false; // true by default\n\n const handleCheckboxChange = (value: boolean) => {\n setChecked(value);\n setError(false);\n setSubmitError(null);\n };\n\n const handleContinue = async () => {\n if (isRequired && !checked) {\n setError(true);\n return;\n }\n\n setIsSubmitting(true);\n try {\n // Merge consent data with existing userInput (backend does full replacement)\n const existingUserInput = (session.userInput as Record<string, unknown>) ?? {};\n const merged = {\n ...existingUserInput,\n [node.id]: {\n accepted: checked,\n timestamp: new Date().toISOString(),\n },\n };\n await updateSessionUserInput(sessionId, merged);\n stepObject.goToNextStep(node.id, session.template);\n } catch (err) {\n console.error(t(\"LEGAL_CONSENT.error.console_update\"), err);\n setSubmitError(t(\"LEGAL_CONSENT.error.general\"));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const pageTitle = node.pageTitle || t(\"LEGAL_CONSENT.default_title\");\n const description = node.consentDescription;\n const description2 = node.consentDescription2;\n const checkboxLabel = node.checkboxText || t(\"LEGAL_CONSENT.default_checkbox\");\n\n // Use Datakeen default URLs when fields are left empty\n const cguUrl = node.cguUrl || t(\"LEGAL_CONSENT.default_cgu_url\");\n const privacyUrl = node.privacyPolicyUrl || t(\"LEGAL_CONSENT.default_privacy_url\");\n\n // Build description text with optional hyperlinks\n const renderDescription = (text: string, url?: string) => {\n if (!url || !text) return <p>{text}</p>;\n return (\n <p>\n {text}{\" \"}\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"underline text-blue-600 hover:text-blue-800\"\n >\n {url}\n </a>\n </p>\n );\n };\n\n return (\n <MobilePageLayout\n session={session}\n footer={\n <div className=\"w-full space-y-4\">\n {/* Error message */}\n {(error || submitError) && (\n <div className=\"bg-red-50 border border-red-200 rounded-lg p-3\">\n <Body className=\"text-red-600 text-sm text-center\">\n {submitError\n ? submitError\n : t(\"LEGAL_CONSENT.error.required\")}\n </Body>\n </div>\n )}\n\n {/* Consent checkbox */}\n <div className=\"flex items-start gap-3 p-3 bg-gray-50 rounded-lg\">\n <CheckboxPrimitive.Root\n id={`legal-consent-checkbox-${node.id}`}\n checked={checked}\n onCheckedChange={(value) => handleCheckboxChange(!!value)}\n className={`mt-1 h-5 w-5 shrink-0 rounded border bg-white transition-colors\n data-[state=checked]:bg-[var(--dk-btn-bg)] data-[state=checked]:border-[var(--dk-btn-bg)]\n ${error\n ? \"border-red-500\"\n : \"border-gray-300 hover:border-gray-400\"\n }\n `}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-white\">\n <CheckIcon className=\"h-4 w-4\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n\n <LabelPrimitive.Root\n htmlFor={`legal-consent-checkbox-${node.id}`}\n className=\"cursor-pointer\"\n >\n <Body\n className={`text-left text-sm leading-relaxed ${\n error ? \"text-red-600\" : \"text-gray-700\"\n }`}\n >\n {checkboxLabel}\n </Body>\n </LabelPrimitive.Root>\n </div>\n\n {/* Continue button */}\n <PageActions\n primary={\n <Button\n onClick={handleContinue}\n disabled={(isRequired && !checked) || isSubmitting}\n >\n {isSubmitting\n ? t(\"LEGAL_CONSENT.button.loading\")\n : t(\"LEGAL_CONSENT.button.continue\")}\n </Button>\n }\n />\n </div>\n }\n >\n <div className=\"px-4 py-8 md:px-8 flex flex-col\">\n <div className=\"w-full max-w-2xl mx-auto space-y-6\">\n <div className=\"text-center\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl mb-6\">\n {pageTitle}\n </Title>\n </div>\n\n {/* Consent content */}\n {(description || description2) && (\n <div className=\"bg-gray-50 rounded-lg p-4 md:p-6\">\n <Body className=\"text-left text-sm md:text-base leading-relaxed space-y-4\">\n {description && renderDescription(description, cguUrl)}\n {description2 && renderDescription(description2, privacyUrl)}\n </Body>\n </div>\n )}\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default LegalConsentNode;\n"],"names":["useI18n","useState","__awaiter","updateSessionUserInput","_jsx","_jsxs","MobilePageLayout","Body","CheckboxPrimitive","CheckIcon","LabelPrimitive","PageActions","Button","Title"],"mappings":"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"}
1
+ {"version":3,"file":"LegalConsentNode.js","sources":["../../../../../src/components/legal-consent/LegalConsentNode.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport Body from \"../ui/Body\";\nimport Title from \"../ui/Title\";\nimport Button from \"../ui/Button\";\nimport PageActions from \"../ui/PageActions\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport { updateSessionUserInput } from \"../../services/sessionService\";\nimport { renderInlineMarkdown } from \"../../utils/renderInlineMarkdown\";\nimport type { SessionData, SessionTemplateNode, stepObject } from \"../../types/session\";\n\ninterface LegalConsentNodeProps {\n node: SessionTemplateNode;\n session: SessionData;\n sessionId: string;\n stepObject: stepObject;\n}\n\nconst LegalConsentNode = ({\n node,\n session,\n sessionId,\n stepObject,\n}: LegalConsentNodeProps) => {\n const { t } = useI18n();\n const [checked, setChecked] = useState(false);\n const [error, setError] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const isRequired = node.isRequired !== false; // true by default\n\n const handleCheckboxChange = (value: boolean) => {\n setChecked(value);\n setError(false);\n setSubmitError(null);\n };\n\n const handleContinue = async () => {\n if (isRequired && !checked) {\n setError(true);\n return;\n }\n\n setIsSubmitting(true);\n try {\n // Merge consent data with existing userInput (backend does full replacement)\n const existingUserInput = (session.userInput as Record<string, unknown>) ?? {};\n const merged = {\n ...existingUserInput,\n [node.id]: {\n accepted: checked,\n timestamp: new Date().toISOString(),\n },\n };\n await updateSessionUserInput(sessionId, merged);\n stepObject.goToNextStep(node.id, session.template);\n } catch (err) {\n console.error(t(\"LEGAL_CONSENT.error.console_update\"), err);\n setSubmitError(t(\"LEGAL_CONSENT.error.general\"));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const pageTitle = node.pageTitle || t(\"LEGAL_CONSENT.default_title\");\n // Description unique au format Markdown (liens [libellé](url), gras).\n const description = node.consentDescription;\n // Rétrocompat : on n'affiche consentDescription2 que pour les anciens nœuds\n // qui n'ont pas de consentDescription (sinon doublon, le texte étant fusionné).\n const description2 = description ? undefined : node.consentDescription2;\n const checkboxLabel = node.checkboxText || t(\"LEGAL_CONSENT.default_checkbox\");\n\n return (\n <MobilePageLayout\n session={session}\n footer={\n <div className=\"w-full space-y-4\">\n {/* Error message */}\n {(error || submitError) && (\n <div className=\"bg-red-50 border border-red-200 rounded-lg p-3\">\n <Body className=\"text-red-600 text-sm text-center\">\n {submitError\n ? submitError\n : t(\"LEGAL_CONSENT.error.required\")}\n </Body>\n </div>\n )}\n\n {/* Consent checkbox */}\n <div className=\"flex items-start gap-3 p-3 bg-gray-50 rounded-lg\">\n <CheckboxPrimitive.Root\n id={`legal-consent-checkbox-${node.id}`}\n checked={checked}\n onCheckedChange={(value) => handleCheckboxChange(!!value)}\n className={`mt-1 h-5 w-5 shrink-0 rounded border bg-white transition-colors\n data-[state=checked]:bg-[var(--dk-btn-bg)] data-[state=checked]:border-[var(--dk-btn-bg)]\n ${error\n ? \"border-red-500\"\n : \"border-gray-300 hover:border-gray-400\"\n }\n `}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-white\">\n <CheckIcon className=\"h-4 w-4\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n\n <LabelPrimitive.Root\n htmlFor={`legal-consent-checkbox-${node.id}`}\n className=\"cursor-pointer\"\n >\n <Body\n className={`text-left text-sm leading-relaxed ${\n error ? \"text-red-600\" : \"text-gray-700\"\n }`}\n >\n {checkboxLabel}\n </Body>\n </LabelPrimitive.Root>\n </div>\n\n {/* Continue button */}\n <PageActions\n primary={\n <Button\n onClick={handleContinue}\n disabled={(isRequired && !checked) || isSubmitting}\n >\n {isSubmitting\n ? t(\"LEGAL_CONSENT.button.loading\")\n : t(\"LEGAL_CONSENT.button.continue\")}\n </Button>\n }\n />\n </div>\n }\n >\n <div className=\"px-4 py-8 md:px-8 flex flex-col\">\n <div className=\"w-full max-w-2xl mx-auto space-y-6\">\n <div className=\"text-center\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl mb-6\">\n {pageTitle}\n </Title>\n </div>\n\n {/* Consent content */}\n {(description || description2) && (\n <div className=\"bg-gray-50 rounded-lg p-4 md:p-6\">\n <Body className=\"text-left text-sm md:text-base leading-relaxed space-y-4\">\n {/* Descriptions au format Markdown : liens cliquables dans le texte. */}\n {description && renderInlineMarkdown(description)}\n {description2 && renderInlineMarkdown(description2)}\n </Body>\n </div>\n )}\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default LegalConsentNode;\n"],"names":["useI18n","useState","__awaiter","updateSessionUserInput","_jsx","MobilePageLayout","_jsxs","Body","CheckboxPrimitive","CheckIcon","LabelPrimitive","PageActions","Button","Title","renderInlineMarkdown"],"mappings":"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"}
@@ -335,6 +335,8 @@ var LEGAL_CONSENT = {
335
335
  default_checkbox: "I accept the terms and conditions.",
336
336
  default_cgu_url: "https://www.datakeen.co/conditions-generales-dutilisation/",
337
337
  default_privacy_url: "https://www.datakeen.co/regles-de-confidentialite/",
338
+ default_cgu_link_label: "terms of use",
339
+ default_privacy_link_label: "privacy policy",
338
340
  error: {
339
341
  required: "You must accept the terms to continue.",
340
342
  general: "An error occurred while updating the session. Please try again.",
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -335,6 +335,8 @@ var LEGAL_CONSENT = {
335
335
  default_checkbox: "J'accepte les conditions générales d'utilisation.",
336
336
  default_cgu_url: "https://www.datakeen.co/conditions-generales-dutilisation/",
337
337
  default_privacy_url: "https://www.datakeen.co/regles-de-confidentialite/",
338
+ default_cgu_link_label: "conditions générales d'utilisation",
339
+ default_privacy_link_label: "politique de confidentialité",
338
340
  error: {
339
341
  required: "Vous devez accepter les conditions pour continuer.",
340
342
  general: "Une erreur est survenue lors de la mise à jour de la session. Veuillez réessayer.",
@@ -1 +1 @@
1
- {"version":3,"file":"fr.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"fr.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sources":["../../../../src/types/session.ts"],"sourcesContent":["import type React from \"react\";\n\nexport interface SessionConfig {\n selfie?: boolean;\n requireMobile?: boolean;\n}\n\nexport interface DatakeenSessionProps {\n sessionId: string;\n sessionConfig?: SessionConfig;\n apiBaseUrl?: string; // Optional API base URL for dynamic environment configuration\n}\n\nexport interface UseSessionReturn {\n SessionComponent: React.ReactElement;\n}\n\nexport type stepObject = {\n setStep: (step: number, skipHistory?: boolean) => void;\n goBack: () => void;\n /** Retour arrière vers un nœud précis (ex: \"Corriger ma saisie\") :\n * tronque l'historique jusqu'à `targetStep` au lieu de l'empiler. */\n goBackToStep: (targetStep: number) => void;\n goToNextStep: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n step: number;\n canGoBack: boolean;\n};\n\nexport interface ProcessingStep {\n title: string;\n subtitle: string;\n hasError?: boolean;\n}\n\nexport type ConditionTokenType = \"variable\" | \"control\" | \"operator\" | \"input\";\n\nexport interface ConditionToken {\n type: ConditionTokenType;\n value: string;\n label?: string;\n sourceNodeId?: string;\n}\n\n/**\n * Type for custom field value types\n */\nexport type CustomFieldValueType =\n | \"text\"\n | \"enum\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"email\"\n | \"address\"\n | \"list\";\n\n/**\n * Display formats supported for date fields (top-level and list columns).\n */\nexport type DateDisplayFormat = \"dd/mm/yyyy\" | \"mm/dd/yyyy\" | \"yyyy-mm-dd\";\n\nexport const DEFAULT_DATE_DISPLAY_FORMAT: DateDisplayFormat = \"dd/mm/yyyy\";\n\n/**\n * Column definition for a list-type custom field\n */\nexport interface ListColumn {\n label: string;\n type: \"text\" | \"enum\" | \"date\" | \"email\";\n options?: string[]; // required when type === 'enum'\n placeholder?: string; // text/email/date — shown to the end user\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n}\n\n/**\n * Interface for custom field definition\n */\nexport interface CustomField {\n id: string;\n label: string;\n placeholder?: string;\n description?: string;\n valueType: CustomFieldValueType;\n enumOptions?: string[];\n listColumns?: ListColumn[]; // for list type: column definitions\n minRows?: number; // for list type: minimum rows expected\n required?: boolean;\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n lockedFromApi?: boolean;\n editableIfMissing?: boolean; // soft lock — éditable si la valeur API est absente\n userInputKey?: string;\n}\n\n/**\n * Interface for session template node\n */\nexport interface SessionTemplateNode {\n id: string;\n type: string;\n title: string;\n description: string;\n informationType?:\n | \"identity\"\n | \"identity-legal\"\n | \"contact\"\n | \"address\"\n | \"nationality\"\n | \"custom\";\n position: {\n x: number;\n y: number;\n };\n options: unknown[];\n selectedOptions: string[];\n requiredDocumentType?: string;\n isRequired: boolean;\n order: number;\n optionalFields?: string[];\n requiredFields?: string[];\n pageTitle?: string;\n pageDescription?: string;\n // Properties for document-collection node type\n allowedDocumentTypes?: Array<{\n id: string;\n name: string;\n /**\n * Optional side information coming from the template.\n * When provided and equals to two (\"two\", 2, \"double\", \"recto-verso\"),\n * consumers should allow uploading two sides (front/back).\n */\n side?: string | number;\n }>;\n allowedAddingMethods?: string[];\n introductionPage?: {\n title?: string;\n description?: string;\n };\n documentSelection?: {\n title?: string;\n description?: string;\n };\n // Start node specific properties\n welcomeTitle?: string;\n welcomeSubtitle?: string;\n welcomeDescription?: string;\n welcomeImage?: string;\n qrCodeTitle?: string;\n qrCodeDescription?: string;\n showLegacyCGU?: boolean; // default: true — rétrocompatibilité\n\n // Legal consent node specific properties\n consentDescription?: string;\n consentDescription2?: string;\n cguUrl?: string;\n privacyPolicyUrl?: string;\n checkboxText?: string;\n // Identity control specific properties\n automaticPhotoCapture?: boolean;\n nfcEnabled?: boolean;\n // \"nfcAndApi\" reste accepté pour rétrocompat (parcours legacy) ; à normaliser à la lecture.\n nfcMode?: \"nfcOnly\" | \"nfcOrPhoto\" | \"nfcAndApi\";\n acceptedCountries?: AcceptedCountry[];\n // End node specific properties\n callbackURL?: string | null;\n // Résultat forcé par le nœud `end` (configuré dans le builder). Sert au SDK à\n // afficher la variante « erreur conservée » de l'écran de fin quand la branche\n // fausse d'une condition pointe directement vers un end non_compliant.\n expectedResult?: string;\n // Condition node specific properties\n conditionExpression?: string;\n conditionTokens?: ConditionToken[];\n conditionFalseErrorMessage?: string;\n conditionMaxRetries?: number;\n conditionMaxRetryAction?: \"end-journey\" | \"force-true\";\n // Undefined is treated as \"loop\" by the SDK for legacy templates.\n conditionFalseMode?: \"retry\" | \"loop\";\n\n // External verification specific properties\n targetApi?: \"INSEE\";\n referenceNodeId?: string;\n referenceNodeType?:\n | \"information-input\"\n | \"document-collection\"\n | \"identity-control\";\n referenceField?: \"siren\" | \"siret\";\n referenceVariable?: string;\n // Custom form fields (for information-input with type 'custom')\n customFields?: CustomField[];\n\n // Electronic signature specific properties\n templateId?: string;\n external_id?: string;\n fieldMappings?: Array<{\n sourceFieldId: string;\n label: string;\n docusealType: string;\n readonly: boolean;\n role?: string;\n sourceNodeId?: string;\n }>;\n /** If set, the generated PDF from this upstream pdf-generation node will be used as the document to sign */\n sourcePdfNodeId?: string;\n\n // PDF generation node specific properties\n // Note: htmlTemplate is intentionally NOT included — it is server-side only and never sent to the client\n pdfMode?: \"upload\" | \"html-template\";\n sourceNodeIds?: string[];\n\n // retry properties\n allowResubmission: boolean;\n maxResubmissionAttempts?: number;\n}\n\n/**\n * Interface for accepted countries\n */\nexport interface AcceptedCountry {\n code: string;\n documents: {\n passport: string[];\n idCard: string[];\n driverLicense: string[];\n residencePermit: string[];\n pinkDriverLicense: string[];\n };\n}\n\n/**\n * Interface for session template edge\n */\nexport interface SessionTemplateEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n conditionValue?: string;\n}\n\n/**\n * Interface for platform information\n */\nexport interface PlatformInfo {\n mobile: boolean;\n desktop: boolean;\n backoffice: boolean;\n}\n\n/**\n * Interface for session template\n */\n/** Clé du catalogue d'icônes des écrans de fin (mappée vers lucide-react au rendu). */\nexport type EndScreenIcon =\n | \"thanks\"\n | \"send\"\n | \"mail\"\n | \"check\"\n | \"clock\"\n | \"shield\"\n | \"user\"\n | \"info\";\n\nexport interface EndScreenItem {\n icon: EndScreenIcon;\n text: string;\n}\n\nexport interface EndScreenCase {\n title?: string;\n items: EndScreenItem[];\n}\n\n/** Textes de fin personnalisés (config globale du journey). Vide → fallback standard. */\nexport interface EndScreenConfig {\n compliant?: EndScreenCase;\n nonCompliant?: EndScreenCase;\n}\n\nexport interface SessionTemplate {\n id: string;\n name: string;\n description: string;\n version: string;\n languages: string[];\n nodes: SessionTemplateNode[];\n edges: SessionTemplateEdge[];\n groupId: string;\n userId: string | null;\n created_at: string;\n updated_at: string;\n platforms?: PlatformInfo;\n logo?: string;\n showQRCode?: boolean;\n buttonBgColor?: string;\n buttonTextColor?: string;\n endScreenConfig?: EndScreenConfig;\n}\n\n/**\n * Interface for session data\n */\nexport interface SessionData {\n id: string;\n userId: string | null;\n token: string;\n templateId: string;\n templateKey: string;\n expireTime: number;\n status: string;\n result: Record<string, unknown>;\n landingPage: unknown;\n withSelfie: boolean | null;\n groupId: string | null;\n userInput: Record<string, unknown>;\n contactInfo?: {\n email: string;\n phoneNumber: string;\n };\n callbackURL?: string | null;\n webhookURL: string;\n analysisTemplateId: string | null;\n userAgent: unknown[];\n mobile: boolean;\n analysisId: string | null;\n currentStep?: number;\n nfcStatus?: \"pending\" | \"opened\" | \"completed\" | \"skipped\" | \"failed\";\n createdAt: string;\n updatedAt: string;\n auditTrail: unknown[];\n user: unknown | null;\n analysis: unknown[];\n documents: unknown[];\n template: SessionTemplate;\n retryCounts?: Record<string, number>; // nodeId -> retry count\n}\n\nexport interface ClientInfo {\n ip?: string;\n location?: string;\n device: string;\n browser: string;\n os: string;\n}\n"],"names":[],"mappings":";;AAiEO,IAAM,2BAA2B,GAAsB;;;;"}
1
+ {"version":3,"file":"session.js","sources":["../../../../src/types/session.ts"],"sourcesContent":["import type React from \"react\";\n\nexport interface SessionConfig {\n selfie?: boolean;\n requireMobile?: boolean;\n}\n\nexport interface DatakeenSessionProps {\n sessionId: string;\n sessionConfig?: SessionConfig;\n apiBaseUrl?: string; // Optional API base URL for dynamic environment configuration\n}\n\nexport interface UseSessionReturn {\n SessionComponent: React.ReactElement;\n}\n\nexport type stepObject = {\n setStep: (step: number, skipHistory?: boolean) => void;\n goBack: () => void;\n /** Retour arrière vers un nœud précis (ex: \"Corriger ma saisie\") :\n * tronque l'historique jusqu'à `targetStep` au lieu de l'empiler. */\n goBackToStep: (targetStep: number) => void;\n goToNextStep: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n step: number;\n canGoBack: boolean;\n};\n\nexport interface ProcessingStep {\n title: string;\n subtitle: string;\n hasError?: boolean;\n}\n\nexport type ConditionTokenType = \"variable\" | \"control\" | \"operator\" | \"input\";\n\nexport interface ConditionToken {\n type: ConditionTokenType;\n value: string;\n label?: string;\n sourceNodeId?: string;\n}\n\n/**\n * Type for custom field value types\n */\nexport type CustomFieldValueType =\n | \"text\"\n | \"enum\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"email\"\n | \"address\"\n | \"list\";\n\n/**\n * Display formats supported for date fields (top-level and list columns).\n */\nexport type DateDisplayFormat = \"dd/mm/yyyy\" | \"mm/dd/yyyy\" | \"yyyy-mm-dd\";\n\nexport const DEFAULT_DATE_DISPLAY_FORMAT: DateDisplayFormat = \"dd/mm/yyyy\";\n\n/**\n * Column definition for a list-type custom field\n */\nexport interface ListColumn {\n label: string;\n type: \"text\" | \"enum\" | \"date\" | \"email\";\n options?: string[]; // required when type === 'enum'\n placeholder?: string; // text/email/date — shown to the end user\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n}\n\n/**\n * Interface for custom field definition\n */\nexport interface CustomField {\n id: string;\n label: string;\n placeholder?: string;\n description?: string;\n valueType: CustomFieldValueType;\n enumOptions?: string[];\n listColumns?: ListColumn[]; // for list type: column definitions\n minRows?: number; // for list type: minimum rows expected\n required?: boolean;\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n lockedFromApi?: boolean;\n editableIfMissing?: boolean; // soft lock — éditable si la valeur API est absente\n userInputKey?: string;\n}\n\n/**\n * Interface for session template node\n */\nexport interface SessionTemplateNode {\n id: string;\n type: string;\n title: string;\n description: string;\n informationType?:\n | \"identity\"\n | \"identity-legal\"\n | \"contact\"\n | \"address\"\n | \"nationality\"\n | \"custom\";\n position: {\n x: number;\n y: number;\n };\n options: unknown[];\n selectedOptions: string[];\n requiredDocumentType?: string;\n isRequired: boolean;\n order: number;\n optionalFields?: string[];\n requiredFields?: string[];\n pageTitle?: string;\n pageDescription?: string;\n // Properties for document-collection node type\n allowedDocumentTypes?: Array<{\n id: string;\n name: string;\n /**\n * Optional side information coming from the template.\n * When provided and equals to two (\"two\", 2, \"double\", \"recto-verso\"),\n * consumers should allow uploading two sides (front/back).\n */\n side?: string | number;\n }>;\n allowedAddingMethods?: string[];\n introductionPage?: {\n title?: string;\n description?: string;\n };\n documentSelection?: {\n title?: string;\n description?: string;\n };\n // Start node specific properties\n welcomeTitle?: string;\n welcomeSubtitle?: string;\n welcomeDescription?: string;\n welcomeImage?: string;\n qrCodeTitle?: string;\n qrCodeDescription?: string;\n showLegacyCGU?: boolean; // default: true — rétrocompatibilité\n\n // Legal consent node specific properties\n consentDescription?: string;\n consentDescription2?: string;\n cguUrl?: string;\n privacyPolicyUrl?: string;\n cguLinkLabel?: string;\n privacyLinkLabel?: string;\n checkboxText?: string;\n // Identity control specific properties\n automaticPhotoCapture?: boolean;\n nfcEnabled?: boolean;\n // \"nfcAndApi\" reste accepté pour rétrocompat (parcours legacy) ; à normaliser à la lecture.\n nfcMode?: \"nfcOnly\" | \"nfcOrPhoto\" | \"nfcAndApi\";\n acceptedCountries?: AcceptedCountry[];\n // End node specific properties\n callbackURL?: string | null;\n // Résultat forcé par le nœud `end` (configuré dans le builder). Sert au SDK à\n // afficher la variante « erreur conservée » de l'écran de fin quand la branche\n // fausse d'une condition pointe directement vers un end non_compliant.\n expectedResult?: string;\n // Condition node specific properties\n conditionExpression?: string;\n conditionTokens?: ConditionToken[];\n conditionFalseErrorMessage?: string;\n conditionMaxRetries?: number;\n conditionMaxRetryAction?: \"end-journey\" | \"force-true\";\n // Undefined is treated as \"loop\" by the SDK for legacy templates.\n conditionFalseMode?: \"retry\" | \"loop\";\n\n // External verification specific properties\n targetApi?: \"INSEE\";\n referenceNodeId?: string;\n referenceNodeType?:\n | \"information-input\"\n | \"document-collection\"\n | \"identity-control\";\n referenceField?: \"siren\" | \"siret\";\n referenceVariable?: string;\n // Custom form fields (for information-input with type 'custom')\n customFields?: CustomField[];\n\n // Electronic signature specific properties\n templateId?: string;\n external_id?: string;\n fieldMappings?: Array<{\n sourceFieldId: string;\n label: string;\n docusealType: string;\n readonly: boolean;\n role?: string;\n sourceNodeId?: string;\n }>;\n /** If set, the generated PDF from this upstream pdf-generation node will be used as the document to sign */\n sourcePdfNodeId?: string;\n\n // PDF generation node specific properties\n // Note: htmlTemplate is intentionally NOT included — it is server-side only and never sent to the client\n pdfMode?: \"upload\" | \"html-template\";\n sourceNodeIds?: string[];\n\n // retry properties\n allowResubmission: boolean;\n maxResubmissionAttempts?: number;\n}\n\n/**\n * Interface for accepted countries\n */\nexport interface AcceptedCountry {\n code: string;\n documents: {\n passport: string[];\n idCard: string[];\n driverLicense: string[];\n residencePermit: string[];\n pinkDriverLicense: string[];\n };\n}\n\n/**\n * Interface for session template edge\n */\nexport interface SessionTemplateEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n conditionValue?: string;\n}\n\n/**\n * Interface for platform information\n */\nexport interface PlatformInfo {\n mobile: boolean;\n desktop: boolean;\n backoffice: boolean;\n}\n\n/**\n * Interface for session template\n */\n/** Clé du catalogue d'icônes des écrans de fin (mappée vers lucide-react au rendu). */\nexport type EndScreenIcon =\n | \"thanks\"\n | \"send\"\n | \"mail\"\n | \"check\"\n | \"clock\"\n | \"shield\"\n | \"user\"\n | \"info\";\n\nexport interface EndScreenItem {\n icon: EndScreenIcon;\n text: string;\n}\n\nexport interface EndScreenCase {\n title?: string;\n items: EndScreenItem[];\n}\n\n/** Textes de fin personnalisés (config globale du journey). Vide → fallback standard. */\nexport interface EndScreenConfig {\n compliant?: EndScreenCase;\n nonCompliant?: EndScreenCase;\n}\n\nexport interface SessionTemplate {\n id: string;\n name: string;\n description: string;\n version: string;\n languages: string[];\n nodes: SessionTemplateNode[];\n edges: SessionTemplateEdge[];\n groupId: string;\n userId: string | null;\n created_at: string;\n updated_at: string;\n platforms?: PlatformInfo;\n logo?: string;\n showQRCode?: boolean;\n buttonBgColor?: string;\n buttonTextColor?: string;\n endScreenConfig?: EndScreenConfig;\n}\n\n/**\n * Interface for session data\n */\nexport interface SessionData {\n id: string;\n userId: string | null;\n token: string;\n templateId: string;\n templateKey: string;\n expireTime: number;\n status: string;\n result: Record<string, unknown>;\n landingPage: unknown;\n withSelfie: boolean | null;\n groupId: string | null;\n userInput: Record<string, unknown>;\n contactInfo?: {\n email: string;\n phoneNumber: string;\n };\n callbackURL?: string | null;\n webhookURL: string;\n analysisTemplateId: string | null;\n userAgent: unknown[];\n mobile: boolean;\n analysisId: string | null;\n currentStep?: number;\n nfcStatus?: \"pending\" | \"opened\" | \"completed\" | \"skipped\" | \"failed\";\n createdAt: string;\n updatedAt: string;\n auditTrail: unknown[];\n user: unknown | null;\n analysis: unknown[];\n documents: unknown[];\n template: SessionTemplate;\n retryCounts?: Record<string, number>; // nodeId -> retry count\n}\n\nexport interface ClientInfo {\n ip?: string;\n location?: string;\n device: string;\n browser: string;\n os: string;\n}\n"],"names":[],"mappings":";;AAiEO,IAAM,2BAA2B,GAAsB;;;;"}
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+
5
+ /**
6
+ * Mini-renderer Markdown *inline* et sûr, pour les textes de consentement.
7
+ *
8
+ * Volontairement limité (pas de lib externe, SDK publié npm) :
9
+ * - liens `[libellé](url)` — uniquement http(s) et mailto, ouverts en nouvel onglet ;
10
+ * - gras `**texte**` ;
11
+ * - paragraphes (lignes vides) et sauts de ligne simples.
12
+ *
13
+ * Aucune injection de HTML brut : on ne produit que des éléments React, le texte
14
+ * reste du texte. Les URLs non http(s)/mailto sont rendues en texte (pas de lien).
15
+ */
16
+ var SAFE_URL = /^(https?:|mailto:)/i;
17
+ // Capture **gras** ou [libellé](url) ; le reste est du texte simple.
18
+ var INLINE_PATTERN = /(\*\*([^*]+)\*\*)|(\[([^\]]+)\]\(([^)\s]+)\))/g;
19
+ function renderInlineSegments(text, keyPrefix) {
20
+ var nodes = [];
21
+ var lastIndex = 0;
22
+ var match;
23
+ var i = 0;
24
+ INLINE_PATTERN.lastIndex = 0;
25
+ while ((match = INLINE_PATTERN.exec(text)) !== null) {
26
+ if (match.index > lastIndex) {
27
+ nodes.push(text.slice(lastIndex, match.index));
28
+ }
29
+ if (match[2] !== undefined) {
30
+ // **gras**
31
+ nodes.push(jsxRuntime.jsx("strong", { children: match[2] }, "".concat(keyPrefix, "-b-").concat(i)));
32
+ }
33
+ else if (match[4] !== undefined && match[5] !== undefined) {
34
+ // [libellé](url)
35
+ var label = match[4];
36
+ var url = match[5];
37
+ if (SAFE_URL.test(url)) {
38
+ nodes.push(jsxRuntime.jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "underline text-blue-600 hover:text-blue-800", children: label }, "".concat(keyPrefix, "-a-").concat(i)));
39
+ }
40
+ else {
41
+ // URL non sûre : on retombe sur le libellé en texte simple.
42
+ nodes.push(label);
43
+ }
44
+ }
45
+ lastIndex = INLINE_PATTERN.lastIndex;
46
+ i += 1;
47
+ }
48
+ if (lastIndex < text.length) {
49
+ nodes.push(text.slice(lastIndex));
50
+ }
51
+ return nodes;
52
+ }
53
+ /**
54
+ * Rend une chaîne markdown en paragraphes React. Les blocs séparés par une ligne
55
+ * vide deviennent des `<p>` ; les sauts de ligne simples deviennent des `<br/>`.
56
+ */
57
+ function renderInlineMarkdown(text) {
58
+ if (!text)
59
+ return null;
60
+ var blocks = text.split(/\n\s*\n/);
61
+ return blocks.map(function (block, blockIndex) {
62
+ var lines = block.split("\n");
63
+ var content = [];
64
+ lines.forEach(function (line, lineIndex) {
65
+ if (lineIndex > 0) {
66
+ content.push(jsxRuntime.jsx("br", {}, "br-".concat(blockIndex, "-").concat(lineIndex)));
67
+ }
68
+ content.push.apply(content, renderInlineSegments(line, "".concat(blockIndex, "-").concat(lineIndex)));
69
+ });
70
+ return jsxRuntime.jsx("p", { children: content }, "p-".concat(blockIndex));
71
+ });
72
+ }
73
+
74
+ exports.renderInlineMarkdown = renderInlineMarkdown;
75
+ //# sourceMappingURL=renderInlineMarkdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderInlineMarkdown.js","sources":["../../../../src/utils/renderInlineMarkdown.tsx"],"sourcesContent":["import React from \"react\";\n\n/**\n * Mini-renderer Markdown *inline* et sûr, pour les textes de consentement.\n *\n * Volontairement limité (pas de lib externe, SDK publié npm) :\n * - liens `[libellé](url)` — uniquement http(s) et mailto, ouverts en nouvel onglet ;\n * - gras `**texte**` ;\n * - paragraphes (lignes vides) et sauts de ligne simples.\n *\n * Aucune injection de HTML brut : on ne produit que des éléments React, le texte\n * reste du texte. Les URLs non http(s)/mailto sont rendues en texte (pas de lien).\n */\n\nconst SAFE_URL = /^(https?:|mailto:)/i;\n\n// Capture **gras** ou [libellé](url) ; le reste est du texte simple.\nconst INLINE_PATTERN = /(\\*\\*([^*]+)\\*\\*)|(\\[([^\\]]+)\\]\\(([^)\\s]+)\\))/g;\n\nfunction renderInlineSegments(text: string, keyPrefix: string): React.ReactNode[] {\n const nodes: React.ReactNode[] = [];\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n let i = 0;\n\n INLINE_PATTERN.lastIndex = 0;\n while ((match = INLINE_PATTERN.exec(text)) !== null) {\n if (match.index > lastIndex) {\n nodes.push(text.slice(lastIndex, match.index));\n }\n\n if (match[2] !== undefined) {\n // **gras**\n nodes.push(<strong key={`${keyPrefix}-b-${i}`}>{match[2]}</strong>);\n } else if (match[4] !== undefined && match[5] !== undefined) {\n // [libellé](url)\n const label = match[4];\n const url = match[5];\n if (SAFE_URL.test(url)) {\n nodes.push(\n <a\n key={`${keyPrefix}-a-${i}`}\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"underline text-blue-600 hover:text-blue-800\"\n >\n {label}\n </a>,\n );\n } else {\n // URL non sûre : on retombe sur le libellé en texte simple.\n nodes.push(label);\n }\n }\n\n lastIndex = INLINE_PATTERN.lastIndex;\n i += 1;\n }\n\n if (lastIndex < text.length) {\n nodes.push(text.slice(lastIndex));\n }\n\n return nodes;\n}\n\n/**\n * Rend une chaîne markdown en paragraphes React. Les blocs séparés par une ligne\n * vide deviennent des `<p>` ; les sauts de ligne simples deviennent des `<br/>`.\n */\nexport function renderInlineMarkdown(\n text: string | undefined,\n): React.ReactNode {\n if (!text) return null;\n\n const blocks = text.split(/\\n\\s*\\n/);\n\n return blocks.map((block, blockIndex) => {\n const lines = block.split(\"\\n\");\n const content: React.ReactNode[] = [];\n\n lines.forEach((line, lineIndex) => {\n if (lineIndex > 0) {\n content.push(<br key={`br-${blockIndex}-${lineIndex}`} />);\n }\n content.push(\n ...renderInlineSegments(line, `${blockIndex}-${lineIndex}`),\n );\n });\n\n return <p key={`p-${blockIndex}`}>{content}</p>;\n });\n}\n"],"names":["_jsx"],"mappings":"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"}
@@ -11,6 +11,7 @@ import PageActions from '../ui/PageActions.js';
11
11
  import MobilePageLayout from '../ui/MobilePageLayout.js';
12
12
  import { useI18n } from '../../hooks/useI18n.js';
13
13
  import { updateSessionUserInput } from '../../services/sessionService.js';
14
+ import { renderInlineMarkdown } from '../../utils/renderInlineMarkdown.js';
14
15
 
15
16
  var LegalConsentNode = function (_a) {
16
17
  var node = _a.node, session = _a.session, sessionId = _a.sessionId, stepObject = _a.stepObject;
@@ -63,25 +64,19 @@ var LegalConsentNode = function (_a) {
63
64
  });
64
65
  }); };
65
66
  var pageTitle = node.pageTitle || t("LEGAL_CONSENT.default_title");
67
+ // Description unique au format Markdown (liens [libellé](url), gras).
66
68
  var description = node.consentDescription;
67
- var description2 = node.consentDescription2;
69
+ // Rétrocompat : on n'affiche consentDescription2 que pour les anciens nœuds
70
+ // qui n'ont pas de consentDescription (sinon doublon, le texte étant fusionné).
71
+ var description2 = description ? undefined : node.consentDescription2;
68
72
  var checkboxLabel = node.checkboxText || t("LEGAL_CONSENT.default_checkbox");
69
- // Use Datakeen default URLs when fields are left empty
70
- var cguUrl = node.cguUrl || t("LEGAL_CONSENT.default_cgu_url");
71
- var privacyUrl = node.privacyPolicyUrl || t("LEGAL_CONSENT.default_privacy_url");
72
- // Build description text with optional hyperlinks
73
- var renderDescription = function (text, url) {
74
- if (!url || !text)
75
- return jsx("p", { children: text });
76
- return (jsxs("p", { children: [text, " ", jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "underline text-blue-600 hover:text-blue-800", children: url })] }));
77
- };
78
73
  return (jsx(MobilePageLayout, { session: session, footer: jsxs("div", { className: "w-full space-y-4", children: [(error || submitError) && (jsx("div", { className: "bg-red-50 border border-red-200 rounded-lg p-3", children: jsx(Body, { className: "text-red-600 text-sm text-center", children: submitError
79
74
  ? submitError
80
75
  : t("LEGAL_CONSENT.error.required") }) })), jsxs("div", { className: "flex items-start gap-3 p-3 bg-gray-50 rounded-lg", children: [jsx(CheckboxPrimitive.Root, { id: "legal-consent-checkbox-".concat(node.id), checked: checked, onCheckedChange: function (value) { return handleCheckboxChange(!!value); }, className: "mt-1 h-5 w-5 shrink-0 rounded border bg-white transition-colors\n data-[state=checked]:bg-[var(--dk-btn-bg)] data-[state=checked]:border-[var(--dk-btn-bg)]\n ".concat(error
81
76
  ? "border-red-500"
82
77
  : "border-gray-300 hover:border-gray-400", "\n "), children: jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-white", children: jsx(CheckIcon, { className: "h-4 w-4" }) }) }), jsx(Label.Root, { htmlFor: "legal-consent-checkbox-".concat(node.id), className: "cursor-pointer", children: jsx(Body, { className: "text-left text-sm leading-relaxed ".concat(error ? "text-red-600" : "text-gray-700"), children: checkboxLabel }) })] }), jsx(PageActions, { primary: jsx(Button, { onClick: handleContinue, disabled: (isRequired && !checked) || isSubmitting, children: isSubmitting
83
78
  ? t("LEGAL_CONSENT.button.loading")
84
- : t("LEGAL_CONSENT.button.continue") }) })] }), children: jsx("div", { className: "px-4 py-8 md:px-8 flex flex-col", children: jsxs("div", { className: "w-full max-w-2xl mx-auto space-y-6", children: [jsx("div", { className: "text-center", children: jsx(Title, { className: "text-xl md:text-2xl lg:text-3xl mb-6", children: pageTitle }) }), (description || description2) && (jsx("div", { className: "bg-gray-50 rounded-lg p-4 md:p-6", children: jsxs(Body, { className: "text-left text-sm md:text-base leading-relaxed space-y-4", children: [description && renderDescription(description, cguUrl), description2 && renderDescription(description2, privacyUrl)] }) }))] }) }) }));
79
+ : t("LEGAL_CONSENT.button.continue") }) })] }), children: jsx("div", { className: "px-4 py-8 md:px-8 flex flex-col", children: jsxs("div", { className: "w-full max-w-2xl mx-auto space-y-6", children: [jsx("div", { className: "text-center", children: jsx(Title, { className: "text-xl md:text-2xl lg:text-3xl mb-6", children: pageTitle }) }), (description || description2) && (jsx("div", { className: "bg-gray-50 rounded-lg p-4 md:p-6", children: jsxs(Body, { className: "text-left text-sm md:text-base leading-relaxed space-y-4", children: [description && renderInlineMarkdown(description), description2 && renderInlineMarkdown(description2)] }) }))] }) }) }));
85
80
  };
86
81
 
87
82
  export { LegalConsentNode as default };
@@ -1 +1 @@
1
- {"version":3,"file":"LegalConsentNode.js","sources":["../../../../../src/components/legal-consent/LegalConsentNode.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport Body from \"../ui/Body\";\nimport Title from \"../ui/Title\";\nimport Button from \"../ui/Button\";\nimport PageActions from \"../ui/PageActions\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport { updateSessionUserInput } from \"../../services/sessionService\";\nimport type { SessionData, SessionTemplateNode, stepObject } from \"../../types/session\";\n\ninterface LegalConsentNodeProps {\n node: SessionTemplateNode;\n session: SessionData;\n sessionId: string;\n stepObject: stepObject;\n}\n\nconst LegalConsentNode = ({\n node,\n session,\n sessionId,\n stepObject,\n}: LegalConsentNodeProps) => {\n const { t } = useI18n();\n const [checked, setChecked] = useState(false);\n const [error, setError] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const isRequired = node.isRequired !== false; // true by default\n\n const handleCheckboxChange = (value: boolean) => {\n setChecked(value);\n setError(false);\n setSubmitError(null);\n };\n\n const handleContinue = async () => {\n if (isRequired && !checked) {\n setError(true);\n return;\n }\n\n setIsSubmitting(true);\n try {\n // Merge consent data with existing userInput (backend does full replacement)\n const existingUserInput = (session.userInput as Record<string, unknown>) ?? {};\n const merged = {\n ...existingUserInput,\n [node.id]: {\n accepted: checked,\n timestamp: new Date().toISOString(),\n },\n };\n await updateSessionUserInput(sessionId, merged);\n stepObject.goToNextStep(node.id, session.template);\n } catch (err) {\n console.error(t(\"LEGAL_CONSENT.error.console_update\"), err);\n setSubmitError(t(\"LEGAL_CONSENT.error.general\"));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const pageTitle = node.pageTitle || t(\"LEGAL_CONSENT.default_title\");\n const description = node.consentDescription;\n const description2 = node.consentDescription2;\n const checkboxLabel = node.checkboxText || t(\"LEGAL_CONSENT.default_checkbox\");\n\n // Use Datakeen default URLs when fields are left empty\n const cguUrl = node.cguUrl || t(\"LEGAL_CONSENT.default_cgu_url\");\n const privacyUrl = node.privacyPolicyUrl || t(\"LEGAL_CONSENT.default_privacy_url\");\n\n // Build description text with optional hyperlinks\n const renderDescription = (text: string, url?: string) => {\n if (!url || !text) return <p>{text}</p>;\n return (\n <p>\n {text}{\" \"}\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"underline text-blue-600 hover:text-blue-800\"\n >\n {url}\n </a>\n </p>\n );\n };\n\n return (\n <MobilePageLayout\n session={session}\n footer={\n <div className=\"w-full space-y-4\">\n {/* Error message */}\n {(error || submitError) && (\n <div className=\"bg-red-50 border border-red-200 rounded-lg p-3\">\n <Body className=\"text-red-600 text-sm text-center\">\n {submitError\n ? submitError\n : t(\"LEGAL_CONSENT.error.required\")}\n </Body>\n </div>\n )}\n\n {/* Consent checkbox */}\n <div className=\"flex items-start gap-3 p-3 bg-gray-50 rounded-lg\">\n <CheckboxPrimitive.Root\n id={`legal-consent-checkbox-${node.id}`}\n checked={checked}\n onCheckedChange={(value) => handleCheckboxChange(!!value)}\n className={`mt-1 h-5 w-5 shrink-0 rounded border bg-white transition-colors\n data-[state=checked]:bg-[var(--dk-btn-bg)] data-[state=checked]:border-[var(--dk-btn-bg)]\n ${error\n ? \"border-red-500\"\n : \"border-gray-300 hover:border-gray-400\"\n }\n `}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-white\">\n <CheckIcon className=\"h-4 w-4\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n\n <LabelPrimitive.Root\n htmlFor={`legal-consent-checkbox-${node.id}`}\n className=\"cursor-pointer\"\n >\n <Body\n className={`text-left text-sm leading-relaxed ${\n error ? \"text-red-600\" : \"text-gray-700\"\n }`}\n >\n {checkboxLabel}\n </Body>\n </LabelPrimitive.Root>\n </div>\n\n {/* Continue button */}\n <PageActions\n primary={\n <Button\n onClick={handleContinue}\n disabled={(isRequired && !checked) || isSubmitting}\n >\n {isSubmitting\n ? t(\"LEGAL_CONSENT.button.loading\")\n : t(\"LEGAL_CONSENT.button.continue\")}\n </Button>\n }\n />\n </div>\n }\n >\n <div className=\"px-4 py-8 md:px-8 flex flex-col\">\n <div className=\"w-full max-w-2xl mx-auto space-y-6\">\n <div className=\"text-center\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl mb-6\">\n {pageTitle}\n </Title>\n </div>\n\n {/* Consent content */}\n {(description || description2) && (\n <div className=\"bg-gray-50 rounded-lg p-4 md:p-6\">\n <Body className=\"text-left text-sm md:text-base leading-relaxed space-y-4\">\n {description && renderDescription(description, cguUrl)}\n {description2 && renderDescription(description2, privacyUrl)}\n </Body>\n </div>\n )}\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default LegalConsentNode;\n"],"names":["_jsx","_jsxs","LabelPrimitive"],"mappings":"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"}
1
+ {"version":3,"file":"LegalConsentNode.js","sources":["../../../../../src/components/legal-consent/LegalConsentNode.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport Body from \"../ui/Body\";\nimport Title from \"../ui/Title\";\nimport Button from \"../ui/Button\";\nimport PageActions from \"../ui/PageActions\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport { updateSessionUserInput } from \"../../services/sessionService\";\nimport { renderInlineMarkdown } from \"../../utils/renderInlineMarkdown\";\nimport type { SessionData, SessionTemplateNode, stepObject } from \"../../types/session\";\n\ninterface LegalConsentNodeProps {\n node: SessionTemplateNode;\n session: SessionData;\n sessionId: string;\n stepObject: stepObject;\n}\n\nconst LegalConsentNode = ({\n node,\n session,\n sessionId,\n stepObject,\n}: LegalConsentNodeProps) => {\n const { t } = useI18n();\n const [checked, setChecked] = useState(false);\n const [error, setError] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const isRequired = node.isRequired !== false; // true by default\n\n const handleCheckboxChange = (value: boolean) => {\n setChecked(value);\n setError(false);\n setSubmitError(null);\n };\n\n const handleContinue = async () => {\n if (isRequired && !checked) {\n setError(true);\n return;\n }\n\n setIsSubmitting(true);\n try {\n // Merge consent data with existing userInput (backend does full replacement)\n const existingUserInput = (session.userInput as Record<string, unknown>) ?? {};\n const merged = {\n ...existingUserInput,\n [node.id]: {\n accepted: checked,\n timestamp: new Date().toISOString(),\n },\n };\n await updateSessionUserInput(sessionId, merged);\n stepObject.goToNextStep(node.id, session.template);\n } catch (err) {\n console.error(t(\"LEGAL_CONSENT.error.console_update\"), err);\n setSubmitError(t(\"LEGAL_CONSENT.error.general\"));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const pageTitle = node.pageTitle || t(\"LEGAL_CONSENT.default_title\");\n // Description unique au format Markdown (liens [libellé](url), gras).\n const description = node.consentDescription;\n // Rétrocompat : on n'affiche consentDescription2 que pour les anciens nœuds\n // qui n'ont pas de consentDescription (sinon doublon, le texte étant fusionné).\n const description2 = description ? undefined : node.consentDescription2;\n const checkboxLabel = node.checkboxText || t(\"LEGAL_CONSENT.default_checkbox\");\n\n return (\n <MobilePageLayout\n session={session}\n footer={\n <div className=\"w-full space-y-4\">\n {/* Error message */}\n {(error || submitError) && (\n <div className=\"bg-red-50 border border-red-200 rounded-lg p-3\">\n <Body className=\"text-red-600 text-sm text-center\">\n {submitError\n ? submitError\n : t(\"LEGAL_CONSENT.error.required\")}\n </Body>\n </div>\n )}\n\n {/* Consent checkbox */}\n <div className=\"flex items-start gap-3 p-3 bg-gray-50 rounded-lg\">\n <CheckboxPrimitive.Root\n id={`legal-consent-checkbox-${node.id}`}\n checked={checked}\n onCheckedChange={(value) => handleCheckboxChange(!!value)}\n className={`mt-1 h-5 w-5 shrink-0 rounded border bg-white transition-colors\n data-[state=checked]:bg-[var(--dk-btn-bg)] data-[state=checked]:border-[var(--dk-btn-bg)]\n ${error\n ? \"border-red-500\"\n : \"border-gray-300 hover:border-gray-400\"\n }\n `}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-white\">\n <CheckIcon className=\"h-4 w-4\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n\n <LabelPrimitive.Root\n htmlFor={`legal-consent-checkbox-${node.id}`}\n className=\"cursor-pointer\"\n >\n <Body\n className={`text-left text-sm leading-relaxed ${\n error ? \"text-red-600\" : \"text-gray-700\"\n }`}\n >\n {checkboxLabel}\n </Body>\n </LabelPrimitive.Root>\n </div>\n\n {/* Continue button */}\n <PageActions\n primary={\n <Button\n onClick={handleContinue}\n disabled={(isRequired && !checked) || isSubmitting}\n >\n {isSubmitting\n ? t(\"LEGAL_CONSENT.button.loading\")\n : t(\"LEGAL_CONSENT.button.continue\")}\n </Button>\n }\n />\n </div>\n }\n >\n <div className=\"px-4 py-8 md:px-8 flex flex-col\">\n <div className=\"w-full max-w-2xl mx-auto space-y-6\">\n <div className=\"text-center\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl mb-6\">\n {pageTitle}\n </Title>\n </div>\n\n {/* Consent content */}\n {(description || description2) && (\n <div className=\"bg-gray-50 rounded-lg p-4 md:p-6\">\n <Body className=\"text-left text-sm md:text-base leading-relaxed space-y-4\">\n {/* Descriptions au format Markdown : liens cliquables dans le texte. */}\n {description && renderInlineMarkdown(description)}\n {description2 && renderInlineMarkdown(description2)}\n </Body>\n </div>\n )}\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default LegalConsentNode;\n"],"names":["_jsx","_jsxs","LabelPrimitive"],"mappings":"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"}
@@ -331,6 +331,8 @@ var LEGAL_CONSENT = {
331
331
  default_checkbox: "I accept the terms and conditions.",
332
332
  default_cgu_url: "https://www.datakeen.co/conditions-generales-dutilisation/",
333
333
  default_privacy_url: "https://www.datakeen.co/regles-de-confidentialite/",
334
+ default_cgu_link_label: "terms of use",
335
+ default_privacy_link_label: "privacy policy",
334
336
  error: {
335
337
  required: "You must accept the terms to continue.",
336
338
  general: "An error occurred while updating the session. Please try again.",
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -331,6 +331,8 @@ var LEGAL_CONSENT = {
331
331
  default_checkbox: "J'accepte les conditions générales d'utilisation.",
332
332
  default_cgu_url: "https://www.datakeen.co/conditions-generales-dutilisation/",
333
333
  default_privacy_url: "https://www.datakeen.co/regles-de-confidentialite/",
334
+ default_cgu_link_label: "conditions générales d'utilisation",
335
+ default_privacy_link_label: "politique de confidentialité",
334
336
  error: {
335
337
  required: "Vous devez accepter les conditions pour continuer.",
336
338
  general: "Une erreur est survenue lors de la mise à jour de la session. Veuillez réessayer.",
@@ -1 +1 @@
1
- {"version":3,"file":"fr.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"fr.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sources":["../../../../src/types/session.ts"],"sourcesContent":["import type React from \"react\";\n\nexport interface SessionConfig {\n selfie?: boolean;\n requireMobile?: boolean;\n}\n\nexport interface DatakeenSessionProps {\n sessionId: string;\n sessionConfig?: SessionConfig;\n apiBaseUrl?: string; // Optional API base URL for dynamic environment configuration\n}\n\nexport interface UseSessionReturn {\n SessionComponent: React.ReactElement;\n}\n\nexport type stepObject = {\n setStep: (step: number, skipHistory?: boolean) => void;\n goBack: () => void;\n /** Retour arrière vers un nœud précis (ex: \"Corriger ma saisie\") :\n * tronque l'historique jusqu'à `targetStep` au lieu de l'empiler. */\n goBackToStep: (targetStep: number) => void;\n goToNextStep: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n step: number;\n canGoBack: boolean;\n};\n\nexport interface ProcessingStep {\n title: string;\n subtitle: string;\n hasError?: boolean;\n}\n\nexport type ConditionTokenType = \"variable\" | \"control\" | \"operator\" | \"input\";\n\nexport interface ConditionToken {\n type: ConditionTokenType;\n value: string;\n label?: string;\n sourceNodeId?: string;\n}\n\n/**\n * Type for custom field value types\n */\nexport type CustomFieldValueType =\n | \"text\"\n | \"enum\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"email\"\n | \"address\"\n | \"list\";\n\n/**\n * Display formats supported for date fields (top-level and list columns).\n */\nexport type DateDisplayFormat = \"dd/mm/yyyy\" | \"mm/dd/yyyy\" | \"yyyy-mm-dd\";\n\nexport const DEFAULT_DATE_DISPLAY_FORMAT: DateDisplayFormat = \"dd/mm/yyyy\";\n\n/**\n * Column definition for a list-type custom field\n */\nexport interface ListColumn {\n label: string;\n type: \"text\" | \"enum\" | \"date\" | \"email\";\n options?: string[]; // required when type === 'enum'\n placeholder?: string; // text/email/date — shown to the end user\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n}\n\n/**\n * Interface for custom field definition\n */\nexport interface CustomField {\n id: string;\n label: string;\n placeholder?: string;\n description?: string;\n valueType: CustomFieldValueType;\n enumOptions?: string[];\n listColumns?: ListColumn[]; // for list type: column definitions\n minRows?: number; // for list type: minimum rows expected\n required?: boolean;\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n lockedFromApi?: boolean;\n editableIfMissing?: boolean; // soft lock — éditable si la valeur API est absente\n userInputKey?: string;\n}\n\n/**\n * Interface for session template node\n */\nexport interface SessionTemplateNode {\n id: string;\n type: string;\n title: string;\n description: string;\n informationType?:\n | \"identity\"\n | \"identity-legal\"\n | \"contact\"\n | \"address\"\n | \"nationality\"\n | \"custom\";\n position: {\n x: number;\n y: number;\n };\n options: unknown[];\n selectedOptions: string[];\n requiredDocumentType?: string;\n isRequired: boolean;\n order: number;\n optionalFields?: string[];\n requiredFields?: string[];\n pageTitle?: string;\n pageDescription?: string;\n // Properties for document-collection node type\n allowedDocumentTypes?: Array<{\n id: string;\n name: string;\n /**\n * Optional side information coming from the template.\n * When provided and equals to two (\"two\", 2, \"double\", \"recto-verso\"),\n * consumers should allow uploading two sides (front/back).\n */\n side?: string | number;\n }>;\n allowedAddingMethods?: string[];\n introductionPage?: {\n title?: string;\n description?: string;\n };\n documentSelection?: {\n title?: string;\n description?: string;\n };\n // Start node specific properties\n welcomeTitle?: string;\n welcomeSubtitle?: string;\n welcomeDescription?: string;\n welcomeImage?: string;\n qrCodeTitle?: string;\n qrCodeDescription?: string;\n showLegacyCGU?: boolean; // default: true — rétrocompatibilité\n\n // Legal consent node specific properties\n consentDescription?: string;\n consentDescription2?: string;\n cguUrl?: string;\n privacyPolicyUrl?: string;\n checkboxText?: string;\n // Identity control specific properties\n automaticPhotoCapture?: boolean;\n nfcEnabled?: boolean;\n // \"nfcAndApi\" reste accepté pour rétrocompat (parcours legacy) ; à normaliser à la lecture.\n nfcMode?: \"nfcOnly\" | \"nfcOrPhoto\" | \"nfcAndApi\";\n acceptedCountries?: AcceptedCountry[];\n // End node specific properties\n callbackURL?: string | null;\n // Résultat forcé par le nœud `end` (configuré dans le builder). Sert au SDK à\n // afficher la variante « erreur conservée » de l'écran de fin quand la branche\n // fausse d'une condition pointe directement vers un end non_compliant.\n expectedResult?: string;\n // Condition node specific properties\n conditionExpression?: string;\n conditionTokens?: ConditionToken[];\n conditionFalseErrorMessage?: string;\n conditionMaxRetries?: number;\n conditionMaxRetryAction?: \"end-journey\" | \"force-true\";\n // Undefined is treated as \"loop\" by the SDK for legacy templates.\n conditionFalseMode?: \"retry\" | \"loop\";\n\n // External verification specific properties\n targetApi?: \"INSEE\";\n referenceNodeId?: string;\n referenceNodeType?:\n | \"information-input\"\n | \"document-collection\"\n | \"identity-control\";\n referenceField?: \"siren\" | \"siret\";\n referenceVariable?: string;\n // Custom form fields (for information-input with type 'custom')\n customFields?: CustomField[];\n\n // Electronic signature specific properties\n templateId?: string;\n external_id?: string;\n fieldMappings?: Array<{\n sourceFieldId: string;\n label: string;\n docusealType: string;\n readonly: boolean;\n role?: string;\n sourceNodeId?: string;\n }>;\n /** If set, the generated PDF from this upstream pdf-generation node will be used as the document to sign */\n sourcePdfNodeId?: string;\n\n // PDF generation node specific properties\n // Note: htmlTemplate is intentionally NOT included — it is server-side only and never sent to the client\n pdfMode?: \"upload\" | \"html-template\";\n sourceNodeIds?: string[];\n\n // retry properties\n allowResubmission: boolean;\n maxResubmissionAttempts?: number;\n}\n\n/**\n * Interface for accepted countries\n */\nexport interface AcceptedCountry {\n code: string;\n documents: {\n passport: string[];\n idCard: string[];\n driverLicense: string[];\n residencePermit: string[];\n pinkDriverLicense: string[];\n };\n}\n\n/**\n * Interface for session template edge\n */\nexport interface SessionTemplateEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n conditionValue?: string;\n}\n\n/**\n * Interface for platform information\n */\nexport interface PlatformInfo {\n mobile: boolean;\n desktop: boolean;\n backoffice: boolean;\n}\n\n/**\n * Interface for session template\n */\n/** Clé du catalogue d'icônes des écrans de fin (mappée vers lucide-react au rendu). */\nexport type EndScreenIcon =\n | \"thanks\"\n | \"send\"\n | \"mail\"\n | \"check\"\n | \"clock\"\n | \"shield\"\n | \"user\"\n | \"info\";\n\nexport interface EndScreenItem {\n icon: EndScreenIcon;\n text: string;\n}\n\nexport interface EndScreenCase {\n title?: string;\n items: EndScreenItem[];\n}\n\n/** Textes de fin personnalisés (config globale du journey). Vide → fallback standard. */\nexport interface EndScreenConfig {\n compliant?: EndScreenCase;\n nonCompliant?: EndScreenCase;\n}\n\nexport interface SessionTemplate {\n id: string;\n name: string;\n description: string;\n version: string;\n languages: string[];\n nodes: SessionTemplateNode[];\n edges: SessionTemplateEdge[];\n groupId: string;\n userId: string | null;\n created_at: string;\n updated_at: string;\n platforms?: PlatformInfo;\n logo?: string;\n showQRCode?: boolean;\n buttonBgColor?: string;\n buttonTextColor?: string;\n endScreenConfig?: EndScreenConfig;\n}\n\n/**\n * Interface for session data\n */\nexport interface SessionData {\n id: string;\n userId: string | null;\n token: string;\n templateId: string;\n templateKey: string;\n expireTime: number;\n status: string;\n result: Record<string, unknown>;\n landingPage: unknown;\n withSelfie: boolean | null;\n groupId: string | null;\n userInput: Record<string, unknown>;\n contactInfo?: {\n email: string;\n phoneNumber: string;\n };\n callbackURL?: string | null;\n webhookURL: string;\n analysisTemplateId: string | null;\n userAgent: unknown[];\n mobile: boolean;\n analysisId: string | null;\n currentStep?: number;\n nfcStatus?: \"pending\" | \"opened\" | \"completed\" | \"skipped\" | \"failed\";\n createdAt: string;\n updatedAt: string;\n auditTrail: unknown[];\n user: unknown | null;\n analysis: unknown[];\n documents: unknown[];\n template: SessionTemplate;\n retryCounts?: Record<string, number>; // nodeId -> retry count\n}\n\nexport interface ClientInfo {\n ip?: string;\n location?: string;\n device: string;\n browser: string;\n os: string;\n}\n"],"names":[],"mappings":"AAiEO,IAAM,2BAA2B,GAAsB;;;;"}
1
+ {"version":3,"file":"session.js","sources":["../../../../src/types/session.ts"],"sourcesContent":["import type React from \"react\";\n\nexport interface SessionConfig {\n selfie?: boolean;\n requireMobile?: boolean;\n}\n\nexport interface DatakeenSessionProps {\n sessionId: string;\n sessionConfig?: SessionConfig;\n apiBaseUrl?: string; // Optional API base URL for dynamic environment configuration\n}\n\nexport interface UseSessionReturn {\n SessionComponent: React.ReactElement;\n}\n\nexport type stepObject = {\n setStep: (step: number, skipHistory?: boolean) => void;\n goBack: () => void;\n /** Retour arrière vers un nœud précis (ex: \"Corriger ma saisie\") :\n * tronque l'historique jusqu'à `targetStep` au lieu de l'empiler. */\n goBackToStep: (targetStep: number) => void;\n goToNextStep: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n step: number;\n canGoBack: boolean;\n};\n\nexport interface ProcessingStep {\n title: string;\n subtitle: string;\n hasError?: boolean;\n}\n\nexport type ConditionTokenType = \"variable\" | \"control\" | \"operator\" | \"input\";\n\nexport interface ConditionToken {\n type: ConditionTokenType;\n value: string;\n label?: string;\n sourceNodeId?: string;\n}\n\n/**\n * Type for custom field value types\n */\nexport type CustomFieldValueType =\n | \"text\"\n | \"enum\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"email\"\n | \"address\"\n | \"list\";\n\n/**\n * Display formats supported for date fields (top-level and list columns).\n */\nexport type DateDisplayFormat = \"dd/mm/yyyy\" | \"mm/dd/yyyy\" | \"yyyy-mm-dd\";\n\nexport const DEFAULT_DATE_DISPLAY_FORMAT: DateDisplayFormat = \"dd/mm/yyyy\";\n\n/**\n * Column definition for a list-type custom field\n */\nexport interface ListColumn {\n label: string;\n type: \"text\" | \"enum\" | \"date\" | \"email\";\n options?: string[]; // required when type === 'enum'\n placeholder?: string; // text/email/date — shown to the end user\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n}\n\n/**\n * Interface for custom field definition\n */\nexport interface CustomField {\n id: string;\n label: string;\n placeholder?: string;\n description?: string;\n valueType: CustomFieldValueType;\n enumOptions?: string[];\n listColumns?: ListColumn[]; // for list type: column definitions\n minRows?: number; // for list type: minimum rows expected\n required?: boolean;\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n lockedFromApi?: boolean;\n editableIfMissing?: boolean; // soft lock — éditable si la valeur API est absente\n userInputKey?: string;\n}\n\n/**\n * Interface for session template node\n */\nexport interface SessionTemplateNode {\n id: string;\n type: string;\n title: string;\n description: string;\n informationType?:\n | \"identity\"\n | \"identity-legal\"\n | \"contact\"\n | \"address\"\n | \"nationality\"\n | \"custom\";\n position: {\n x: number;\n y: number;\n };\n options: unknown[];\n selectedOptions: string[];\n requiredDocumentType?: string;\n isRequired: boolean;\n order: number;\n optionalFields?: string[];\n requiredFields?: string[];\n pageTitle?: string;\n pageDescription?: string;\n // Properties for document-collection node type\n allowedDocumentTypes?: Array<{\n id: string;\n name: string;\n /**\n * Optional side information coming from the template.\n * When provided and equals to two (\"two\", 2, \"double\", \"recto-verso\"),\n * consumers should allow uploading two sides (front/back).\n */\n side?: string | number;\n }>;\n allowedAddingMethods?: string[];\n introductionPage?: {\n title?: string;\n description?: string;\n };\n documentSelection?: {\n title?: string;\n description?: string;\n };\n // Start node specific properties\n welcomeTitle?: string;\n welcomeSubtitle?: string;\n welcomeDescription?: string;\n welcomeImage?: string;\n qrCodeTitle?: string;\n qrCodeDescription?: string;\n showLegacyCGU?: boolean; // default: true — rétrocompatibilité\n\n // Legal consent node specific properties\n consentDescription?: string;\n consentDescription2?: string;\n cguUrl?: string;\n privacyPolicyUrl?: string;\n cguLinkLabel?: string;\n privacyLinkLabel?: string;\n checkboxText?: string;\n // Identity control specific properties\n automaticPhotoCapture?: boolean;\n nfcEnabled?: boolean;\n // \"nfcAndApi\" reste accepté pour rétrocompat (parcours legacy) ; à normaliser à la lecture.\n nfcMode?: \"nfcOnly\" | \"nfcOrPhoto\" | \"nfcAndApi\";\n acceptedCountries?: AcceptedCountry[];\n // End node specific properties\n callbackURL?: string | null;\n // Résultat forcé par le nœud `end` (configuré dans le builder). Sert au SDK à\n // afficher la variante « erreur conservée » de l'écran de fin quand la branche\n // fausse d'une condition pointe directement vers un end non_compliant.\n expectedResult?: string;\n // Condition node specific properties\n conditionExpression?: string;\n conditionTokens?: ConditionToken[];\n conditionFalseErrorMessage?: string;\n conditionMaxRetries?: number;\n conditionMaxRetryAction?: \"end-journey\" | \"force-true\";\n // Undefined is treated as \"loop\" by the SDK for legacy templates.\n conditionFalseMode?: \"retry\" | \"loop\";\n\n // External verification specific properties\n targetApi?: \"INSEE\";\n referenceNodeId?: string;\n referenceNodeType?:\n | \"information-input\"\n | \"document-collection\"\n | \"identity-control\";\n referenceField?: \"siren\" | \"siret\";\n referenceVariable?: string;\n // Custom form fields (for information-input with type 'custom')\n customFields?: CustomField[];\n\n // Electronic signature specific properties\n templateId?: string;\n external_id?: string;\n fieldMappings?: Array<{\n sourceFieldId: string;\n label: string;\n docusealType: string;\n readonly: boolean;\n role?: string;\n sourceNodeId?: string;\n }>;\n /** If set, the generated PDF from this upstream pdf-generation node will be used as the document to sign */\n sourcePdfNodeId?: string;\n\n // PDF generation node specific properties\n // Note: htmlTemplate is intentionally NOT included — it is server-side only and never sent to the client\n pdfMode?: \"upload\" | \"html-template\";\n sourceNodeIds?: string[];\n\n // retry properties\n allowResubmission: boolean;\n maxResubmissionAttempts?: number;\n}\n\n/**\n * Interface for accepted countries\n */\nexport interface AcceptedCountry {\n code: string;\n documents: {\n passport: string[];\n idCard: string[];\n driverLicense: string[];\n residencePermit: string[];\n pinkDriverLicense: string[];\n };\n}\n\n/**\n * Interface for session template edge\n */\nexport interface SessionTemplateEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n conditionValue?: string;\n}\n\n/**\n * Interface for platform information\n */\nexport interface PlatformInfo {\n mobile: boolean;\n desktop: boolean;\n backoffice: boolean;\n}\n\n/**\n * Interface for session template\n */\n/** Clé du catalogue d'icônes des écrans de fin (mappée vers lucide-react au rendu). */\nexport type EndScreenIcon =\n | \"thanks\"\n | \"send\"\n | \"mail\"\n | \"check\"\n | \"clock\"\n | \"shield\"\n | \"user\"\n | \"info\";\n\nexport interface EndScreenItem {\n icon: EndScreenIcon;\n text: string;\n}\n\nexport interface EndScreenCase {\n title?: string;\n items: EndScreenItem[];\n}\n\n/** Textes de fin personnalisés (config globale du journey). Vide → fallback standard. */\nexport interface EndScreenConfig {\n compliant?: EndScreenCase;\n nonCompliant?: EndScreenCase;\n}\n\nexport interface SessionTemplate {\n id: string;\n name: string;\n description: string;\n version: string;\n languages: string[];\n nodes: SessionTemplateNode[];\n edges: SessionTemplateEdge[];\n groupId: string;\n userId: string | null;\n created_at: string;\n updated_at: string;\n platforms?: PlatformInfo;\n logo?: string;\n showQRCode?: boolean;\n buttonBgColor?: string;\n buttonTextColor?: string;\n endScreenConfig?: EndScreenConfig;\n}\n\n/**\n * Interface for session data\n */\nexport interface SessionData {\n id: string;\n userId: string | null;\n token: string;\n templateId: string;\n templateKey: string;\n expireTime: number;\n status: string;\n result: Record<string, unknown>;\n landingPage: unknown;\n withSelfie: boolean | null;\n groupId: string | null;\n userInput: Record<string, unknown>;\n contactInfo?: {\n email: string;\n phoneNumber: string;\n };\n callbackURL?: string | null;\n webhookURL: string;\n analysisTemplateId: string | null;\n userAgent: unknown[];\n mobile: boolean;\n analysisId: string | null;\n currentStep?: number;\n nfcStatus?: \"pending\" | \"opened\" | \"completed\" | \"skipped\" | \"failed\";\n createdAt: string;\n updatedAt: string;\n auditTrail: unknown[];\n user: unknown | null;\n analysis: unknown[];\n documents: unknown[];\n template: SessionTemplate;\n retryCounts?: Record<string, number>; // nodeId -> retry count\n}\n\nexport interface ClientInfo {\n ip?: string;\n location?: string;\n device: string;\n browser: string;\n os: string;\n}\n"],"names":[],"mappings":"AAiEO,IAAM,2BAA2B,GAAsB;;;;"}
@@ -0,0 +1,73 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * Mini-renderer Markdown *inline* et sûr, pour les textes de consentement.
5
+ *
6
+ * Volontairement limité (pas de lib externe, SDK publié npm) :
7
+ * - liens `[libellé](url)` — uniquement http(s) et mailto, ouverts en nouvel onglet ;
8
+ * - gras `**texte**` ;
9
+ * - paragraphes (lignes vides) et sauts de ligne simples.
10
+ *
11
+ * Aucune injection de HTML brut : on ne produit que des éléments React, le texte
12
+ * reste du texte. Les URLs non http(s)/mailto sont rendues en texte (pas de lien).
13
+ */
14
+ var SAFE_URL = /^(https?:|mailto:)/i;
15
+ // Capture **gras** ou [libellé](url) ; le reste est du texte simple.
16
+ var INLINE_PATTERN = /(\*\*([^*]+)\*\*)|(\[([^\]]+)\]\(([^)\s]+)\))/g;
17
+ function renderInlineSegments(text, keyPrefix) {
18
+ var nodes = [];
19
+ var lastIndex = 0;
20
+ var match;
21
+ var i = 0;
22
+ INLINE_PATTERN.lastIndex = 0;
23
+ while ((match = INLINE_PATTERN.exec(text)) !== null) {
24
+ if (match.index > lastIndex) {
25
+ nodes.push(text.slice(lastIndex, match.index));
26
+ }
27
+ if (match[2] !== undefined) {
28
+ // **gras**
29
+ nodes.push(jsx("strong", { children: match[2] }, "".concat(keyPrefix, "-b-").concat(i)));
30
+ }
31
+ else if (match[4] !== undefined && match[5] !== undefined) {
32
+ // [libellé](url)
33
+ var label = match[4];
34
+ var url = match[5];
35
+ if (SAFE_URL.test(url)) {
36
+ nodes.push(jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "underline text-blue-600 hover:text-blue-800", children: label }, "".concat(keyPrefix, "-a-").concat(i)));
37
+ }
38
+ else {
39
+ // URL non sûre : on retombe sur le libellé en texte simple.
40
+ nodes.push(label);
41
+ }
42
+ }
43
+ lastIndex = INLINE_PATTERN.lastIndex;
44
+ i += 1;
45
+ }
46
+ if (lastIndex < text.length) {
47
+ nodes.push(text.slice(lastIndex));
48
+ }
49
+ return nodes;
50
+ }
51
+ /**
52
+ * Rend une chaîne markdown en paragraphes React. Les blocs séparés par une ligne
53
+ * vide deviennent des `<p>` ; les sauts de ligne simples deviennent des `<br/>`.
54
+ */
55
+ function renderInlineMarkdown(text) {
56
+ if (!text)
57
+ return null;
58
+ var blocks = text.split(/\n\s*\n/);
59
+ return blocks.map(function (block, blockIndex) {
60
+ var lines = block.split("\n");
61
+ var content = [];
62
+ lines.forEach(function (line, lineIndex) {
63
+ if (lineIndex > 0) {
64
+ content.push(jsx("br", {}, "br-".concat(blockIndex, "-").concat(lineIndex)));
65
+ }
66
+ content.push.apply(content, renderInlineSegments(line, "".concat(blockIndex, "-").concat(lineIndex)));
67
+ });
68
+ return jsx("p", { children: content }, "p-".concat(blockIndex));
69
+ });
70
+ }
71
+
72
+ export { renderInlineMarkdown };
73
+ //# sourceMappingURL=renderInlineMarkdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderInlineMarkdown.js","sources":["../../../../src/utils/renderInlineMarkdown.tsx"],"sourcesContent":["import React from \"react\";\n\n/**\n * Mini-renderer Markdown *inline* et sûr, pour les textes de consentement.\n *\n * Volontairement limité (pas de lib externe, SDK publié npm) :\n * - liens `[libellé](url)` — uniquement http(s) et mailto, ouverts en nouvel onglet ;\n * - gras `**texte**` ;\n * - paragraphes (lignes vides) et sauts de ligne simples.\n *\n * Aucune injection de HTML brut : on ne produit que des éléments React, le texte\n * reste du texte. Les URLs non http(s)/mailto sont rendues en texte (pas de lien).\n */\n\nconst SAFE_URL = /^(https?:|mailto:)/i;\n\n// Capture **gras** ou [libellé](url) ; le reste est du texte simple.\nconst INLINE_PATTERN = /(\\*\\*([^*]+)\\*\\*)|(\\[([^\\]]+)\\]\\(([^)\\s]+)\\))/g;\n\nfunction renderInlineSegments(text: string, keyPrefix: string): React.ReactNode[] {\n const nodes: React.ReactNode[] = [];\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n let i = 0;\n\n INLINE_PATTERN.lastIndex = 0;\n while ((match = INLINE_PATTERN.exec(text)) !== null) {\n if (match.index > lastIndex) {\n nodes.push(text.slice(lastIndex, match.index));\n }\n\n if (match[2] !== undefined) {\n // **gras**\n nodes.push(<strong key={`${keyPrefix}-b-${i}`}>{match[2]}</strong>);\n } else if (match[4] !== undefined && match[5] !== undefined) {\n // [libellé](url)\n const label = match[4];\n const url = match[5];\n if (SAFE_URL.test(url)) {\n nodes.push(\n <a\n key={`${keyPrefix}-a-${i}`}\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"underline text-blue-600 hover:text-blue-800\"\n >\n {label}\n </a>,\n );\n } else {\n // URL non sûre : on retombe sur le libellé en texte simple.\n nodes.push(label);\n }\n }\n\n lastIndex = INLINE_PATTERN.lastIndex;\n i += 1;\n }\n\n if (lastIndex < text.length) {\n nodes.push(text.slice(lastIndex));\n }\n\n return nodes;\n}\n\n/**\n * Rend une chaîne markdown en paragraphes React. Les blocs séparés par une ligne\n * vide deviennent des `<p>` ; les sauts de ligne simples deviennent des `<br/>`.\n */\nexport function renderInlineMarkdown(\n text: string | undefined,\n): React.ReactNode {\n if (!text) return null;\n\n const blocks = text.split(/\\n\\s*\\n/);\n\n return blocks.map((block, blockIndex) => {\n const lines = block.split(\"\\n\");\n const content: React.ReactNode[] = [];\n\n lines.forEach((line, lineIndex) => {\n if (lineIndex > 0) {\n content.push(<br key={`br-${blockIndex}-${lineIndex}`} />);\n }\n content.push(\n ...renderInlineSegments(line, `${blockIndex}-${lineIndex}`),\n );\n });\n\n return <p key={`p-${blockIndex}`}>{content}</p>;\n });\n}\n"],"names":["_jsx"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datakeen-session-react",
3
- "version": "1.1.140-rc.75",
3
+ "version": "1.1.140-rc.76",
4
4
  "description": "React SDK component to manage and render Datakeen session experiences easily.",
5
5
  "publishConfig": {
6
6
  "access": "public",