datakeen-session-react 1.1.140-dev.97 → 1.1.140-oid4vp-demo.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +37 -0
- package/dist/cjs/components/document-collection/DocumentCollection.js +132 -22
- package/dist/cjs/components/document-collection/DocumentCollection.js.map +1 -1
- package/dist/cjs/components/session/DocumentCheck.js +112 -15
- package/dist/cjs/components/session/DocumentCheck.js.map +1 -1
- package/dist/cjs/components/template/TemplateNodeRenderer.js +5 -1
- package/dist/cjs/components/template/TemplateNodeRenderer.js.map +1 -1
- package/dist/cjs/components/wallet/AgeControl.js +75 -0
- package/dist/cjs/components/wallet/AgeControl.js.map +1 -0
- package/dist/cjs/components/wallet/WalletProposal.js +27 -0
- package/dist/cjs/components/wallet/WalletProposal.js.map +1 -0
- package/dist/cjs/components/wallet/WalletSuccessAnimation.js +37 -0
- package/dist/cjs/components/wallet/WalletSuccessAnimation.js.map +1 -0
- package/dist/cjs/components/wallet/WalletVerificationStep.js +132 -0
- package/dist/cjs/components/wallet/WalletVerificationStep.js.map +1 -0
- package/dist/cjs/hooks/useWalletSseStatus.js +67 -0
- package/dist/cjs/hooks/useWalletSseStatus.js.map +1 -0
- package/dist/cjs/i18n/en.json.js +34 -1
- package/dist/cjs/i18n/en.json.js.map +1 -1
- package/dist/cjs/i18n/fr.json.js +34 -1
- package/dist/cjs/i18n/fr.json.js.map +1 -1
- package/dist/cjs/services/sessionService.js +57 -0
- package/dist/cjs/services/sessionService.js.map +1 -1
- package/dist/cjs/types/session.js.map +1 -1
- package/dist/esm/components/document-collection/DocumentCollection.js +132 -22
- package/dist/esm/components/document-collection/DocumentCollection.js.map +1 -1
- package/dist/esm/components/session/DocumentCheck.js +113 -16
- package/dist/esm/components/session/DocumentCheck.js.map +1 -1
- package/dist/esm/components/template/TemplateNodeRenderer.js +5 -1
- package/dist/esm/components/template/TemplateNodeRenderer.js.map +1 -1
- package/dist/esm/components/wallet/AgeControl.js +71 -0
- package/dist/esm/components/wallet/AgeControl.js.map +1 -0
- package/dist/esm/components/wallet/WalletProposal.js +23 -0
- package/dist/esm/components/wallet/WalletProposal.js.map +1 -0
- package/dist/esm/components/wallet/WalletSuccessAnimation.js +33 -0
- package/dist/esm/components/wallet/WalletSuccessAnimation.js.map +1 -0
- package/dist/esm/components/wallet/WalletVerificationStep.js +128 -0
- package/dist/esm/components/wallet/WalletVerificationStep.js.map +1 -0
- package/dist/esm/hooks/useWalletSseStatus.js +65 -0
- package/dist/esm/hooks/useWalletSseStatus.js.map +1 -0
- package/dist/esm/i18n/en.json.js +33 -2
- package/dist/esm/i18n/en.json.js.map +1 -1
- package/dist/esm/i18n/fr.json.js +33 -2
- package/dist/esm/i18n/fr.json.js.map +1 -1
- package/dist/esm/services/sessionService.js +55 -1
- package/dist/esm/services/sessionService.js.map +1 -1
- package/dist/esm/types/session.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateNodeRenderer.js","sources":["../../../../../src/components/template/TemplateNodeRenderer.tsx"],"sourcesContent":["import React, { useMemo } from \"react\";\nimport Selfie from \"../session/Selfie\";\nimport VideoWorkInProgress from \"../session/VideoWorkInProgress\";\nimport DocumentCheck, { NodeIdentityControl } from \"../session/DocumentCheck\";\nimport DocumentCollection, {\n DocumentTypeSide,\n NodeDocumentCollection,\n} from \"../document-collection/DocumentCollection\";\nimport EndFlow from \"../session/EndFlow\";\nimport LoadingState from \"../states/LoadingState\";\nimport JDDWorkInProgress from \"../jdi/JDDWorkInProgress\";\nimport { getOrderedJourneySteps, getRunPrefillData } from \"../../services/sessionService\";\nimport type { SessionData, stepObject } from \"../../types/session\";\nimport type { UserInput } from \"../../types/userInput\";\nimport type { ContactInfo } from \"../../types/contactInfo\";\nimport UserInputForm from \"../session/UserInputForm\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport ConditionNodeHandler from \"./ConditionNodeHandler\";\nimport SignatureElectronic from \"../signature-electronic/SignatureElectronic\";\nimport ExternalVerificationNodeHandler from \"./ExternalVerificationNodeHandler\";\nimport PdfGeneration from \"../session/PdfGeneration\";\nimport LegalConsentNode from \"../legal-consent/LegalConsentNode\";\n\ninterface TemplateNodeRendererProps {\n session: SessionData;\n sessionId: string;\n stepObject: stepObject;\n stepHistory: number[];\n templateIndex: number;\n onContinueOnPC: () => void;\n userInput: UserInput;\n setUserInput: React.Dispatch<React.SetStateAction<UserInput>>;\n contactInfo: ContactInfo;\n setContactInfo: React.Dispatch<React.SetStateAction<ContactInfo>>;\n isMobileTemplate: boolean;\n}\n\nconst TemplateNodeRenderer: React.FC<TemplateNodeRendererProps> = ({\n session,\n sessionId,\n stepObject,\n stepHistory,\n templateIndex,\n onContinueOnPC,\n userInput,\n setUserInput,\n contactInfo,\n setContactInfo,\n isMobileTemplate,\n}) => {\n const { t } = useI18n();\n\n if (!session?.template) {\n console.error(t(\"template.error.console_no_template\"));\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-red-500 text-4xl mb-4\">⚠️</div>\n <h2 className=\"text-xl font-bold text-red-600 mb-2\">\n {t(\"template.error.configuration\")}\n </h2>\n <p className=\"text-gray-600 mb-4\">{t(\"template.error.no_template\")}</p>\n </div>\n );\n }\n\n // Check if session is ended before rendering nodes\n if (session.status === \"ended\") {\n return (\n <EndFlow\n sessionId={sessionId}\n sessionStatus={session.status}\n callbackURL={session.callbackURL}\n compliantCase={session.template?.endScreenConfig?.compliant}\n nonCompliantCase={session.template?.endScreenConfig?.nonCompliant}\n />\n );\n }\n\n // Use getOrderedWorkflowSteps to get sorted and filtered nodes\n const templateNodes = useMemo(\n () => getOrderedJourneySteps(session.template),\n [session.template],\n );\n\n // Check if index is valid\n if (templateNodes.length === 0) {\n console.warn(\"No valid template nodes found after filtering\");\n return (\n <EndFlow\n sessionId={sessionId}\n sessionStatus={session?.status}\n callbackURL={session?.callbackURL}\n />\n );\n }\n\n if (templateIndex < 0 || templateIndex >= templateNodes.length) {\n console.warn(\n `Invalid template index: ${templateIndex}, max index: ${templateNodes.length - 1\n }`,\n );\n\n // If we're beyond the maximum index, it means we've completed all nodes\n if (templateIndex >= templateNodes.length) {\n return (\n <EndFlow\n sessionId={sessionId}\n sessionStatus={session?.status}\n callbackURL={session?.callbackURL}\n compliantCase={session?.template?.endScreenConfig?.compliant}\n nonCompliantCase={session?.template?.endScreenConfig?.nonCompliant}\n />\n );\n }\n\n // If index is negative, redirect to start\n if (templateIndex < 0) {\n setTimeout(() => stepObject.setStep(0), 0);\n return <LoadingState message={t(\"loading.step\")} subtitle=\"\" />;\n }\n }\n\n // At this point, we should have a valid node\n const node = templateNodes[templateIndex];\n if (!node) {\n console.error(\n `Node at index ${templateIndex} is undefined. Available nodes:`,\n templateNodes,\n );\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-red-500 text-4xl mb-4\">⚠️</div>\n <h2 className=\"text-xl font-bold text-red-600 mb-2\">\n {t(\"template.error.render\")}\n </h2>\n <p className=\"text-gray-600 mb-4\">\n {t(\"template.error.node_not_found\")}\n </p>\n <button\n className=\"px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition-colors\"\n onClick={() => stepObject.setStep(0)}\n >\n {t(\"template.buttons.restart\")}\n </button>\n </div>\n );\n }\n\n switch (node.type) {\n case \"end\":\n console.log(\"📄 Rendering EndFlow component\");\n return (\n <EndFlow\n sessionId={sessionId}\n sessionStatus={session?.status}\n callbackURL={session?.callbackURL}\n endNodeId={node.id}\n expectedResult={node.expectedResult}\n compliantCase={session?.template?.endScreenConfig?.compliant}\n nonCompliantCase={session?.template?.endScreenConfig?.nonCompliant}\n />\n );\n\n case \"information-input\": {\n // runIndex = nombre de fois que ce step a déjà été visité dans l'historique\n // (0 = premier passage, 1 = deuxième, …).\n // On compte les occurrences de (templateIndex + 1) dans stepHistory,\n // minus 1 car le step courant est déjà dans l'historique.\n const currentStep = templateIndex + 1;\n const visitCount = stepHistory.filter((s) => s === currentStep).length;\n const runIndex = Math.max(0, visitCount - 1);\n\n // Pré-remplissage multi-ENTITÉS : si _list présent, utiliser _list[runIndex]\n // (ou {} hors borne). L'énumération de plusieurs entités successives passe\n // exclusivement par _list (cf. docs/multi-runs.md).\n // Sans _list : on pré-remplit TOUJOURS depuis le userInput persisté — y compris\n // sur une ré-entrée (boucle condition de correction, retour arrière, bouton\n // \"Corriger ma saisie\"). Une ré-entrée sans _list = corriger les MÊMES données,\n // pas en saisir de nouvelles → on ne doit pas vider le formulaire.\n const hasList = Array.isArray(\n (session.userInput as Record<string, unknown>)?._list,\n );\n let initialUserInput: UserInput;\n if (hasList) {\n const prefill = getRunPrefillData(\n session.userInput as Record<string, unknown>,\n runIndex,\n );\n initialUserInput = (prefill ?? {}) as UserInput;\n } else {\n initialUserInput = userInput;\n }\n return (\n // key={node.id} : remonte le formulaire à chaque changement de nœud, pour\n // qu'il se ré-initialise depuis initialUserInput (comportement \"refresh sans\n // refresh\"). Évite la réutilisation d'instance qui laissait customFormData\n // périmé au retour arrière entre deux nœuds information-input.\n <UserInputForm\n key={node.id}\n stepObject={stepObject}\n node={node}\n template={session.template}\n setUserInput={setUserInput}\n initialUserInput={initialUserInput}\n contactInfo={contactInfo}\n setContactInfo={setContactInfo}\n sessionId={sessionId}\n />\n );\n }\n\n case \"document-collection\": {\n return (\n <DocumentCollection\n key={`doc-collection-${templateIndex}`}\n node={node as NodeDocumentCollection}\n stepObject={stepObject}\n sessionId={sessionId}\n template={session.template}\n onContinueOnPC={onContinueOnPC}\n allowedDocumentTypes={(node.allowedDocumentTypes || []).map(\n (docType: any) => ({\n ...docType,\n side:\n typeof docType.side === \"string\" ||\n typeof docType.side === \"number\"\n ? (docType.side as DocumentTypeSide)\n : undefined,\n }),\n )}\n allowedAddingMethods={node.allowedAddingMethods || [\"download\"]}\n introductionPage={node.introductionPage}\n documentSelection={node.documentSelection}\n allowResubmission={node.allowResubmission}\n maxResubmissionAttempts={node.maxResubmissionAttempts}\n />\n );\n }\n\n case \"document-selection\":\n case \"controle-jdi\": {\n if (!node.requiredDocumentType) {\n console.error(\n \"Missing requiredDocumentType in document-selection node:\",\n node,\n );\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-red-500 text-4xl mb-4\">⚠️</div>\n <h2 className=\"text-xl font-bold text-red-600 mb-2\">\n Erreur de configuration\n </h2>\n <p className=\"text-gray-600 mb-4\">\n Le type de document requis n'est pas spécifié dans le template.\n </p>\n <button\n className=\"px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition-colors\"\n onClick={() => stepObject.setStep(0)}\n >\n Recommencer\n </button>\n </div>\n );\n }\n\n // Determine if current device is mobile for capture method\n const isMobile =\n /Android|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i.test(\n navigator.userAgent,\n );\n\n return (\n <DocumentCheck\n key={`doc-check-${templateIndex}`}\n stepObject={stepObject}\n node={node as NodeIdentityControl}\n sessionId={sessionId}\n documentTypeId={node.requiredDocumentType}\n acceptedCountries={node.acceptedCountries}\n onContinueOnPC={onContinueOnPC}\n isMobileCapture={isMobileTemplate && isMobile}\n allowedAddingMethods={\n node.allowedAddingMethods || [\"download\", \"picture\"]\n }\n template={session.template}\n templateIndex={templateIndex}\n setUserInput={setUserInput}\n />\n );\n // }\n }\n\n case \"biometric-capture\":\n case \"selfie-capture\":\n return (\n <Selfie\n key={`selfie-${templateIndex}`}\n stepObject={stepObject}\n sessionId={sessionId}\n node={node}\n template={session.template}\n />\n );\n\n case \"signature-electronic\":\n return (\n <SignatureElectronic\n key={`signature-${templateIndex}`}\n sessionId={sessionId}\n stepObject={stepObject}\n node={node}\n session={session}\n title={node.title}\n description={node.description}\n // Always pass a stable node identifier so backend can resolve\n // either a static DocuSeal template OR a generated PDF source.\n external_id={node.templateId || node.external_id || node.id}\n fieldMappings={node.fieldMappings}\n userInput={userInput}\n contactInfo={contactInfo}\n />\n );\n\n case \"video-capture\":\n console.log(\"🎥 Rendering Video Work in Progress component\");\n return <VideoWorkInProgress onContinue={onContinueOnPC} />;\n\n case \"jdd\":\n console.log(\"🚧 Rendering JDD Work in Progress component\");\n return <JDDWorkInProgress onContinue={onContinueOnPC} />;\n\n case \"condition\":\n console.debug(\"🔀 Rendering Condition Node Handler component and well\");\n return (\n <ConditionNodeHandler\n node={node}\n session={session}\n templateNodes={templateNodes}\n stepObject={stepObject}\n userInput={userInput}\n contactInfo={contactInfo}\n />\n );\n\n case \"external-verification\":\n console.debug(\"🔍 Rendering External Verification Node Handler\");\n return (\n <ExternalVerificationNodeHandler\n node={node}\n session={session}\n userInput={userInput}\n setUserInput={setUserInput}\n onNext={() => stepObject.goToNextStep(node.id, session.template)}\n onPrevious={() => stepObject.goBack()}\n onNavigateToNode={(nodeId: string) => {\n const idx = templateNodes.findIndex((n: any) => n.id === nodeId);\n // idx est 0-based, les steps sont 1-based → idx + 1.\n // goBackToStep tronque l'historique pour que le nœud corrigé\n // redevienne runIndex 0 (formulaire pré-rempli).\n if (idx !== -1) stepObject.goBackToStep(idx + 1);\n else stepObject.goBack();\n }}\n />\n );\n\n case \"pdf-generation\":\n console.debug(\"📄 Rendering PDF Generation component\");\n return (\n <PdfGeneration\n key={`pdf-generation-${templateIndex}`}\n node={node}\n session={session}\n sessionId={sessionId}\n stepObject={stepObject}\n userInput={userInput}\n />\n );\n\n case \"legal-consent\":\n return (\n <LegalConsentNode\n node={node}\n session={session}\n sessionId={sessionId}\n stepObject={stepObject}\n />\n );\n\n case \"custom\":\n // For custom nodes, we provide a basic structure that can be extended\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-blue-500 text-4xl mb-4\">🔧</div>\n <h2 className=\"text-xl font-bold text-blue-600 mb-2\">\n Nœud personnalisé\n </h2>\n <p className=\"text-gray-600 mb-4\">\n Implémentation personnalisée requise pour: \"{node.title || node.id}\"\n </p>\n <div className=\"bg-blue-50 border border-blue-200 rounded p-3 text-left text-sm mb-4 max-w-md\">\n <p className=\"font-semibold text-blue-700 mb-2\">\n Configuration du nœud:\n </p>\n <pre className=\"text-xs overflow-auto max-h-32\">\n {JSON.stringify(\n {\n id: node.id,\n title: node.title,\n description: node.description,\n options: node.options,\n selectedOptions: node.selectedOptions,\n },\n null,\n 2,\n )}\n </pre>\n </div>\n <button\n className=\"px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors\"\n onClick={() => {\n console.log(\"Custom node action:\", node);\n stepObject.goToNextStep(node.id, session.template);\n }}\n >\n {t(\"template.buttons.continue\")}\n </button>\n </div>\n );\n\n default:\n console.warn(`❌ Type de nœud non supporté: ${node.type}`, node);\n console.log(\"❓ Available supported types:\", [\n \"end\",\n \"information-input\",\n \"document-collection\",\n \"document-selection\",\n \"document-upload\",\n \"controle-jdi\",\n \"selfie-capture\",\n \"video-capture\",\n \"country-selection\",\n \"identity-control\",\n \"jdd\",\n \"condition\",\n \"custom\",\n ]);\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-yellow-500 text-4xl mb-4\">⚠️</div>\n <h2 className=\"text-xl font-bold text-yellow-600 mb-2\">\n Étape non supportée\n </h2>\n <p className=\"text-gray-600 mb-4\">\n Le type d'étape \"{node.type}\" n'est pas pris en charge.\n </p>\n <div className=\"bg-gray-100 p-4 rounded mb-4 text-left text-xs overflow-auto max-h-32\">\n <pre>{JSON.stringify(node, null, 2)}</pre>\n </div>\n <button\n className=\"px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition-colors\"\n onClick={() => {\n stepObject.goToNextStep(node.id, session.template);\n }}\n >\n {t(\"template.buttons.continue\")}\n </button>\n </div>\n );\n }\n};\n\nexport default TemplateNodeRenderer;\n"],"names":["useI18n","_jsxs","_jsx","EndFlow","useMemo","getOrderedJourneySteps","LoadingState","getRunPrefillData","UserInputForm","DocumentCollection","__assign","DocumentCheck","Selfie","SignatureElectronic","VideoWorkInProgress","JDDWorkInProgress","ConditionNodeHandler","ExternalVerificationNodeHandler","PdfGeneration","LegalConsentNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TemplateNodeRenderer.js","sources":["../../../../../src/components/template/TemplateNodeRenderer.tsx"],"sourcesContent":["import React, { useMemo } from \"react\";\nimport Selfie from \"../session/Selfie\";\nimport VideoWorkInProgress from \"../session/VideoWorkInProgress\";\nimport DocumentCheck, { NodeIdentityControl } from \"../session/DocumentCheck\";\nimport DocumentCollection, {\n DocumentTypeSide,\n NodeDocumentCollection,\n} from \"../document-collection/DocumentCollection\";\nimport EndFlow from \"../session/EndFlow\";\nimport LoadingState from \"../states/LoadingState\";\nimport JDDWorkInProgress from \"../jdi/JDDWorkInProgress\";\nimport { getOrderedJourneySteps, getRunPrefillData } from \"../../services/sessionService\";\nimport type { SessionData, stepObject } from \"../../types/session\";\nimport type { UserInput } from \"../../types/userInput\";\nimport type { ContactInfo } from \"../../types/contactInfo\";\nimport UserInputForm from \"../session/UserInputForm\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport ConditionNodeHandler from \"./ConditionNodeHandler\";\nimport SignatureElectronic from \"../signature-electronic/SignatureElectronic\";\nimport ExternalVerificationNodeHandler from \"./ExternalVerificationNodeHandler\";\nimport PdfGeneration from \"../session/PdfGeneration\";\nimport LegalConsentNode from \"../legal-consent/LegalConsentNode\";\nimport AgeControl from \"../wallet/AgeControl\";\n\ninterface TemplateNodeRendererProps {\n session: SessionData;\n sessionId: string;\n stepObject: stepObject;\n stepHistory: number[];\n templateIndex: number;\n onContinueOnPC: () => void;\n userInput: UserInput;\n setUserInput: React.Dispatch<React.SetStateAction<UserInput>>;\n contactInfo: ContactInfo;\n setContactInfo: React.Dispatch<React.SetStateAction<ContactInfo>>;\n isMobileTemplate: boolean;\n}\n\nconst TemplateNodeRenderer: React.FC<TemplateNodeRendererProps> = ({\n session,\n sessionId,\n stepObject,\n stepHistory,\n templateIndex,\n onContinueOnPC,\n userInput,\n setUserInput,\n contactInfo,\n setContactInfo,\n isMobileTemplate,\n}) => {\n const { t } = useI18n();\n\n if (!session?.template) {\n console.error(t(\"template.error.console_no_template\"));\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-red-500 text-4xl mb-4\">⚠️</div>\n <h2 className=\"text-xl font-bold text-red-600 mb-2\">\n {t(\"template.error.configuration\")}\n </h2>\n <p className=\"text-gray-600 mb-4\">{t(\"template.error.no_template\")}</p>\n </div>\n );\n }\n\n // Check if session is ended before rendering nodes\n if (session.status === \"ended\") {\n return (\n <EndFlow\n sessionId={sessionId}\n sessionStatus={session.status}\n callbackURL={session.callbackURL}\n compliantCase={session.template?.endScreenConfig?.compliant}\n nonCompliantCase={session.template?.endScreenConfig?.nonCompliant}\n />\n );\n }\n\n // Use getOrderedWorkflowSteps to get sorted and filtered nodes\n const templateNodes = useMemo(\n () => getOrderedJourneySteps(session.template),\n [session.template],\n );\n\n // Check if index is valid\n if (templateNodes.length === 0) {\n console.warn(\"No valid template nodes found after filtering\");\n return (\n <EndFlow\n sessionId={sessionId}\n sessionStatus={session?.status}\n callbackURL={session?.callbackURL}\n />\n );\n }\n\n if (templateIndex < 0 || templateIndex >= templateNodes.length) {\n console.warn(\n `Invalid template index: ${templateIndex}, max index: ${templateNodes.length - 1\n }`,\n );\n\n // If we're beyond the maximum index, it means we've completed all nodes\n if (templateIndex >= templateNodes.length) {\n return (\n <EndFlow\n sessionId={sessionId}\n sessionStatus={session?.status}\n callbackURL={session?.callbackURL}\n compliantCase={session?.template?.endScreenConfig?.compliant}\n nonCompliantCase={session?.template?.endScreenConfig?.nonCompliant}\n />\n );\n }\n\n // If index is negative, redirect to start\n if (templateIndex < 0) {\n setTimeout(() => stepObject.setStep(0), 0);\n return <LoadingState message={t(\"loading.step\")} subtitle=\"\" />;\n }\n }\n\n // At this point, we should have a valid node\n const node = templateNodes[templateIndex];\n if (!node) {\n console.error(\n `Node at index ${templateIndex} is undefined. Available nodes:`,\n templateNodes,\n );\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-red-500 text-4xl mb-4\">⚠️</div>\n <h2 className=\"text-xl font-bold text-red-600 mb-2\">\n {t(\"template.error.render\")}\n </h2>\n <p className=\"text-gray-600 mb-4\">\n {t(\"template.error.node_not_found\")}\n </p>\n <button\n className=\"px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition-colors\"\n onClick={() => stepObject.setStep(0)}\n >\n {t(\"template.buttons.restart\")}\n </button>\n </div>\n );\n }\n\n switch (node.type) {\n case \"end\":\n console.log(\"📄 Rendering EndFlow component\");\n return (\n <EndFlow\n sessionId={sessionId}\n sessionStatus={session?.status}\n callbackURL={session?.callbackURL}\n endNodeId={node.id}\n expectedResult={node.expectedResult}\n compliantCase={session?.template?.endScreenConfig?.compliant}\n nonCompliantCase={session?.template?.endScreenConfig?.nonCompliant}\n />\n );\n\n case \"information-input\": {\n // runIndex = nombre de fois que ce step a déjà été visité dans l'historique\n // (0 = premier passage, 1 = deuxième, …).\n // On compte les occurrences de (templateIndex + 1) dans stepHistory,\n // minus 1 car le step courant est déjà dans l'historique.\n const currentStep = templateIndex + 1;\n const visitCount = stepHistory.filter((s) => s === currentStep).length;\n const runIndex = Math.max(0, visitCount - 1);\n\n // Pré-remplissage multi-ENTITÉS : si _list présent, utiliser _list[runIndex]\n // (ou {} hors borne). L'énumération de plusieurs entités successives passe\n // exclusivement par _list (cf. docs/multi-runs.md).\n // Sans _list : on pré-remplit TOUJOURS depuis le userInput persisté — y compris\n // sur une ré-entrée (boucle condition de correction, retour arrière, bouton\n // \"Corriger ma saisie\"). Une ré-entrée sans _list = corriger les MÊMES données,\n // pas en saisir de nouvelles → on ne doit pas vider le formulaire.\n const hasList = Array.isArray(\n (session.userInput as Record<string, unknown>)?._list,\n );\n let initialUserInput: UserInput;\n if (hasList) {\n const prefill = getRunPrefillData(\n session.userInput as Record<string, unknown>,\n runIndex,\n );\n initialUserInput = (prefill ?? {}) as UserInput;\n } else {\n initialUserInput = userInput;\n }\n return (\n // key={node.id} : remonte le formulaire à chaque changement de nœud, pour\n // qu'il se ré-initialise depuis initialUserInput (comportement \"refresh sans\n // refresh\"). Évite la réutilisation d'instance qui laissait customFormData\n // périmé au retour arrière entre deux nœuds information-input.\n <UserInputForm\n key={node.id}\n stepObject={stepObject}\n node={node}\n template={session.template}\n setUserInput={setUserInput}\n initialUserInput={initialUserInput}\n contactInfo={contactInfo}\n setContactInfo={setContactInfo}\n sessionId={sessionId}\n />\n );\n }\n\n case \"document-collection\": {\n return (\n <DocumentCollection\n key={`doc-collection-${templateIndex}`}\n node={node as NodeDocumentCollection}\n stepObject={stepObject}\n sessionId={sessionId}\n template={session.template}\n onContinueOnPC={onContinueOnPC}\n allowedDocumentTypes={(node.allowedDocumentTypes || []).map(\n (docType: any) => ({\n ...docType,\n side:\n typeof docType.side === \"string\" ||\n typeof docType.side === \"number\"\n ? (docType.side as DocumentTypeSide)\n : undefined,\n }),\n )}\n allowedAddingMethods={node.allowedAddingMethods || [\"download\"]}\n introductionPage={node.introductionPage}\n documentSelection={node.documentSelection}\n allowResubmission={node.allowResubmission}\n maxResubmissionAttempts={node.maxResubmissionAttempts}\n countryCode={userInput?.countryCode}\n />\n );\n }\n\n case \"document-selection\":\n case \"controle-jdi\": {\n if (!node.requiredDocumentType) {\n console.error(\n \"Missing requiredDocumentType in document-selection node:\",\n node,\n );\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-red-500 text-4xl mb-4\">⚠️</div>\n <h2 className=\"text-xl font-bold text-red-600 mb-2\">\n Erreur de configuration\n </h2>\n <p className=\"text-gray-600 mb-4\">\n Le type de document requis n'est pas spécifié dans le template.\n </p>\n <button\n className=\"px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition-colors\"\n onClick={() => stepObject.setStep(0)}\n >\n Recommencer\n </button>\n </div>\n );\n }\n\n // Determine if current device is mobile for capture method\n const isMobile =\n /Android|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i.test(\n navigator.userAgent,\n );\n\n return (\n <DocumentCheck\n key={`doc-check-${templateIndex}`}\n stepObject={stepObject}\n node={node as NodeIdentityControl}\n sessionId={sessionId}\n documentTypeId={node.requiredDocumentType}\n acceptedCountries={node.acceptedCountries}\n onContinueOnPC={onContinueOnPC}\n isMobileCapture={isMobileTemplate && isMobile}\n allowedAddingMethods={\n node.allowedAddingMethods || [\"download\", \"picture\"]\n }\n template={session.template}\n templateIndex={templateIndex}\n setUserInput={setUserInput}\n />\n );\n // }\n }\n\n case \"biometric-capture\":\n case \"selfie-capture\":\n return (\n <Selfie\n key={`selfie-${templateIndex}`}\n stepObject={stepObject}\n sessionId={sessionId}\n node={node}\n template={session.template}\n />\n );\n\n case \"signature-electronic\":\n return (\n <SignatureElectronic\n key={`signature-${templateIndex}`}\n sessionId={sessionId}\n stepObject={stepObject}\n node={node}\n session={session}\n title={node.title}\n description={node.description}\n // Always pass a stable node identifier so backend can resolve\n // either a static DocuSeal template OR a generated PDF source.\n external_id={node.templateId || node.external_id || node.id}\n fieldMappings={node.fieldMappings}\n userInput={userInput}\n contactInfo={contactInfo}\n />\n );\n\n case \"video-capture\":\n console.log(\"🎥 Rendering Video Work in Progress component\");\n return <VideoWorkInProgress onContinue={onContinueOnPC} />;\n\n case \"jdd\":\n console.log(\"🚧 Rendering JDD Work in Progress component\");\n return <JDDWorkInProgress onContinue={onContinueOnPC} />;\n\n case \"age-control\":\n return (\n <AgeControl\n key={`age-control-${templateIndex}`}\n sessionId={sessionId}\n node={node}\n stepObject={stepObject}\n template={session.template}\n countryCode={userInput?.countryCode}\n />\n );\n\n case \"condition\":\n console.debug(\"🔀 Rendering Condition Node Handler component and well\");\n return (\n <ConditionNodeHandler\n node={node}\n session={session}\n templateNodes={templateNodes}\n stepObject={stepObject}\n userInput={userInput}\n contactInfo={contactInfo}\n />\n );\n\n case \"external-verification\":\n console.debug(\"🔍 Rendering External Verification Node Handler\");\n return (\n <ExternalVerificationNodeHandler\n node={node}\n session={session}\n userInput={userInput}\n setUserInput={setUserInput}\n onNext={() => stepObject.goToNextStep(node.id, session.template)}\n onPrevious={() => stepObject.goBack()}\n onNavigateToNode={(nodeId: string) => {\n const idx = templateNodes.findIndex((n: any) => n.id === nodeId);\n // idx est 0-based, les steps sont 1-based → idx + 1.\n // goBackToStep tronque l'historique pour que le nœud corrigé\n // redevienne runIndex 0 (formulaire pré-rempli).\n if (idx !== -1) stepObject.goBackToStep(idx + 1);\n else stepObject.goBack();\n }}\n />\n );\n\n case \"pdf-generation\":\n console.debug(\"📄 Rendering PDF Generation component\");\n return (\n <PdfGeneration\n key={`pdf-generation-${templateIndex}`}\n node={node}\n session={session}\n sessionId={sessionId}\n stepObject={stepObject}\n userInput={userInput}\n />\n );\n\n case \"legal-consent\":\n return (\n <LegalConsentNode\n node={node}\n session={session}\n sessionId={sessionId}\n stepObject={stepObject}\n />\n );\n\n case \"custom\":\n // For custom nodes, we provide a basic structure that can be extended\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-blue-500 text-4xl mb-4\">🔧</div>\n <h2 className=\"text-xl font-bold text-blue-600 mb-2\">\n Nœud personnalisé\n </h2>\n <p className=\"text-gray-600 mb-4\">\n Implémentation personnalisée requise pour: \"{node.title || node.id}\"\n </p>\n <div className=\"bg-blue-50 border border-blue-200 rounded p-3 text-left text-sm mb-4 max-w-md\">\n <p className=\"font-semibold text-blue-700 mb-2\">\n Configuration du nœud:\n </p>\n <pre className=\"text-xs overflow-auto max-h-32\">\n {JSON.stringify(\n {\n id: node.id,\n title: node.title,\n description: node.description,\n options: node.options,\n selectedOptions: node.selectedOptions,\n },\n null,\n 2,\n )}\n </pre>\n </div>\n <button\n className=\"px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors\"\n onClick={() => {\n console.log(\"Custom node action:\", node);\n stepObject.goToNextStep(node.id, session.template);\n }}\n >\n {t(\"template.buttons.continue\")}\n </button>\n </div>\n );\n\n default:\n console.warn(`❌ Type de nœud non supporté: ${node.type}`, node);\n console.log(\"❓ Available supported types:\", [\n \"end\",\n \"information-input\",\n \"document-collection\",\n \"document-selection\",\n \"document-upload\",\n \"controle-jdi\",\n \"selfie-capture\",\n \"video-capture\",\n \"country-selection\",\n \"identity-control\",\n \"age-control\",\n \"jdd\",\n \"condition\",\n \"custom\",\n ]);\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-4 text-center\">\n <div className=\"text-yellow-500 text-4xl mb-4\">⚠️</div>\n <h2 className=\"text-xl font-bold text-yellow-600 mb-2\">\n Étape non supportée\n </h2>\n <p className=\"text-gray-600 mb-4\">\n Le type d'étape \"{node.type}\" n'est pas pris en charge.\n </p>\n <div className=\"bg-gray-100 p-4 rounded mb-4 text-left text-xs overflow-auto max-h-32\">\n <pre>{JSON.stringify(node, null, 2)}</pre>\n </div>\n <button\n className=\"px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition-colors\"\n onClick={() => {\n stepObject.goToNextStep(node.id, session.template);\n }}\n >\n {t(\"template.buttons.continue\")}\n </button>\n </div>\n );\n }\n};\n\nexport default TemplateNodeRenderer;\n"],"names":["useI18n","_jsxs","_jsx","EndFlow","useMemo","getOrderedJourneySteps","LoadingState","getRunPrefillData","UserInputForm","DocumentCollection","__assign","DocumentCheck","Selfie","SignatureElectronic","VideoWorkInProgress","JDDWorkInProgress","AgeControl","ConditionNodeHandler","ExternalVerificationNodeHandler","PdfGeneration","LegalConsentNode"],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var useI18n = require('../../hooks/useI18n.js');
|
|
8
|
+
var sessionService = require('../../services/sessionService.js');
|
|
9
|
+
var WalletProposal = require('./WalletProposal.js');
|
|
10
|
+
var WalletVerificationStep = require('./WalletVerificationStep.js');
|
|
11
|
+
var Button = require('../ui/Button.js');
|
|
12
|
+
var ButtonDesktop = require('../ui/ButtonDesktop.js');
|
|
13
|
+
var useIsMobile = require('../../hooks/useIsMobile.js');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Nœud de vérification d'âge par wallet (eu.europa.ec.av.1) — cf.
|
|
17
|
+
* docs/WALLET_OID4VP_IMPLEMENTATION_PLAN.md §5.5/§7. Contrairement à
|
|
18
|
+
* identity-control, ce nœud est intrinsèquement wallet-first : pas de bascule
|
|
19
|
+
* "walletEnabled", le wallet est tenté systématiquement s'il est disponible
|
|
20
|
+
* pour le pays connu, avec repli automatique et silencieux (§5.5 : "pas de
|
|
21
|
+
* refus explicite") sinon.
|
|
22
|
+
*
|
|
23
|
+
* L'estimation d'âge Unissey de repli n'existe pas encore comme flux dédié
|
|
24
|
+
* dans le SDK (aucun nœud de ce type n'était actif avant cette phase) — le
|
|
25
|
+
* repli affiche donc un écran "en construction" (même patron que
|
|
26
|
+
* JDDWorkInProgress) plutôt que d'improviser un flux non spécifié.
|
|
27
|
+
*/
|
|
28
|
+
var AgeControl = function (_a) {
|
|
29
|
+
var _b, _c, _d;
|
|
30
|
+
var sessionId = _a.sessionId, node = _a.node, stepObject = _a.stepObject, template = _a.template, countryCode = _a.countryCode;
|
|
31
|
+
var t = useI18n.useI18n().t;
|
|
32
|
+
var isMobile = useIsMobile.default();
|
|
33
|
+
var _e = React.useState("checking"), state = _e[0], setState = _e[1];
|
|
34
|
+
React.useEffect(function () {
|
|
35
|
+
var cancelled = false;
|
|
36
|
+
if (!countryCode) {
|
|
37
|
+
setState("fallback");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
sessionService.fetchWallets(countryCode, "age_verification")
|
|
41
|
+
.then(function (wallets) {
|
|
42
|
+
if (!cancelled)
|
|
43
|
+
setState(wallets.length > 0 ? "proposal" : "fallback");
|
|
44
|
+
})
|
|
45
|
+
.catch(function () {
|
|
46
|
+
if (!cancelled)
|
|
47
|
+
setState("fallback");
|
|
48
|
+
});
|
|
49
|
+
return function () {
|
|
50
|
+
cancelled = true;
|
|
51
|
+
};
|
|
52
|
+
}, [countryCode]);
|
|
53
|
+
var advance = function () {
|
|
54
|
+
if (template) {
|
|
55
|
+
stepObject.goToNextStep(node.id, template);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
stepObject.setStep(stepObject.step + 1);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
if (state === "checking") {
|
|
62
|
+
return (jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center h-full p-8", children: jsxRuntime.jsx("div", { className: "animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full" }) }));
|
|
63
|
+
}
|
|
64
|
+
if (state === "proposal") {
|
|
65
|
+
return (jsxRuntime.jsx(WalletProposal.default, { walletMode: "walletOrPhoto", onUseWallet: function () { return setState("verifying"); }, onDecline: function () { return setState("fallback"); } }));
|
|
66
|
+
}
|
|
67
|
+
if (state === "verifying") {
|
|
68
|
+
return (jsxRuntime.jsx(WalletVerificationStep.default, { sessionId: sessionId, nodeId: node.id, credentialType: "age_verification", walletMode: "walletOrPhoto", minimumAge: (_b = node.minimumAge) !== null && _b !== void 0 ? _b : 18, onCompleted: advance, onFailedOrDeclined: function () { return setState("fallback"); }, pageTitle: (_c = node.introductionPage) === null || _c === void 0 ? void 0 : _c.title, pageDescription: (_d = node.introductionPage) === null || _d === void 0 ? void 0 : _d.description }));
|
|
69
|
+
}
|
|
70
|
+
// fallback — wallet non disponible / décliné / échoué : repli silencieux
|
|
71
|
+
return (jsxRuntime.jsxs("div", { className: "flex flex-col justify-between h-full w-full", children: [jsxRuntime.jsx("div", { className: "flex-1 flex items-start justify-center md:items-center px-4 py-8", children: jsxRuntime.jsxs("div", { className: "w-full max-w-md mx-auto text-center space-y-6", children: [jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl font-bold text-gray-800 mb-4", children: t("age_control.fallback.title", "Vérification d'âge") }), jsxRuntime.jsx("p", { className: "text-gray-600 text-lg mb-6", children: t("age_control.fallback.subtitle", "Cette vérification sera complétée automatiquement à l'étape suivante.") })] }) }), jsxRuntime.jsx("div", { className: "flex-shrink-0 p-4 border-t border-gray-200 bg-white", children: isMobile ? (jsxRuntime.jsx("div", { className: "w-full", "data-cy": "age-control-continue", children: jsxRuntime.jsx(Button.default, { onClick: advance, className: "w-full py-3", children: t("age_control.fallback.continue", "Continuer") }) })) : (jsxRuntime.jsx("div", { className: "flex justify-end max-w-4xl mx-auto", "data-cy": "age-control-continue", children: jsxRuntime.jsx(ButtonDesktop.default, { onClick: advance, type: "continue", children: t("age_control.fallback.continue", "Continuer") }) })) })] }));
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
exports.default = AgeControl;
|
|
75
|
+
//# sourceMappingURL=AgeControl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgeControl.js","sources":["../../../../../src/components/wallet/AgeControl.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport type { SessionTemplate, stepObject } from \"../../types/session\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport { fetchWallets } from \"../../services/sessionService\";\nimport WalletProposal from \"./WalletProposal\";\nimport WalletVerificationStep from \"./WalletVerificationStep\";\nimport Button from \"../ui/Button\";\nimport ButtonDesktop from \"../ui/ButtonDesktop\";\nimport useIsMobile from \"../../hooks/useIsMobile\";\n\ninterface AgeControlNode {\n id: string;\n minimumAge?: number;\n introductionPage?: {\n title?: string;\n description?: string;\n };\n}\n\ninterface AgeControlProps {\n sessionId: string;\n node: AgeControlNode;\n stepObject: stepObject;\n template?: SessionTemplate;\n /** Pays de l'utilisateur, connu si un nœud identity-control précède ce nœud dans le parcours. */\n countryCode?: string;\n}\n\ntype AgeControlState = \"checking\" | \"proposal\" | \"verifying\" | \"fallback\";\n\n/**\n * Nœud de vérification d'âge par wallet (eu.europa.ec.av.1) — cf.\n * docs/WALLET_OID4VP_IMPLEMENTATION_PLAN.md §5.5/§7. Contrairement à\n * identity-control, ce nœud est intrinsèquement wallet-first : pas de bascule\n * \"walletEnabled\", le wallet est tenté systématiquement s'il est disponible\n * pour le pays connu, avec repli automatique et silencieux (§5.5 : \"pas de\n * refus explicite\") sinon.\n *\n * L'estimation d'âge Unissey de repli n'existe pas encore comme flux dédié\n * dans le SDK (aucun nœud de ce type n'était actif avant cette phase) — le\n * repli affiche donc un écran \"en construction\" (même patron que\n * JDDWorkInProgress) plutôt que d'improviser un flux non spécifié.\n */\nconst AgeControl: React.FC<AgeControlProps> = ({\n sessionId,\n node,\n stepObject,\n template,\n countryCode,\n}) => {\n const { t } = useI18n();\n const isMobile = useIsMobile();\n const [state, setState] = useState<AgeControlState>(\"checking\");\n\n useEffect(() => {\n let cancelled = false;\n if (!countryCode) {\n setState(\"fallback\");\n return;\n }\n fetchWallets(countryCode, \"age_verification\")\n .then((wallets) => {\n if (!cancelled) setState(wallets.length > 0 ? \"proposal\" : \"fallback\");\n })\n .catch(() => {\n if (!cancelled) setState(\"fallback\");\n });\n return () => {\n cancelled = true;\n };\n }, [countryCode]);\n\n const advance = () => {\n if (template) {\n stepObject.goToNextStep(node.id, template);\n } else {\n stepObject.setStep(stepObject.step + 1);\n }\n };\n\n if (state === \"checking\") {\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-8\">\n <div className=\"animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full\" />\n </div>\n );\n }\n\n if (state === \"proposal\") {\n return (\n <WalletProposal\n walletMode=\"walletOrPhoto\"\n onUseWallet={() => setState(\"verifying\")}\n onDecline={() => setState(\"fallback\")}\n />\n );\n }\n\n if (state === \"verifying\") {\n return (\n <WalletVerificationStep\n sessionId={sessionId}\n nodeId={node.id}\n credentialType=\"age_verification\"\n walletMode=\"walletOrPhoto\"\n minimumAge={node.minimumAge ?? 18}\n onCompleted={advance}\n onFailedOrDeclined={() => setState(\"fallback\")}\n pageTitle={node.introductionPage?.title}\n pageDescription={node.introductionPage?.description}\n />\n );\n }\n\n // fallback — wallet non disponible / décliné / échoué : repli silencieux\n return (\n <div className=\"flex flex-col justify-between h-full w-full\">\n <div className=\"flex-1 flex items-start justify-center md:items-center px-4 py-8\">\n <div className=\"w-full max-w-md mx-auto text-center space-y-6\">\n <h1 className=\"text-2xl md:text-3xl font-bold text-gray-800 mb-4\">\n {t(\"age_control.fallback.title\", \"Vérification d'âge\")}\n </h1>\n <p className=\"text-gray-600 text-lg mb-6\">\n {t(\n \"age_control.fallback.subtitle\",\n \"Cette vérification sera complétée automatiquement à l'étape suivante.\",\n )}\n </p>\n </div>\n </div>\n <div className=\"flex-shrink-0 p-4 border-t border-gray-200 bg-white\">\n {isMobile ? (\n <div className=\"w-full\" data-cy=\"age-control-continue\">\n <Button onClick={advance} className=\"w-full py-3\">\n {t(\"age_control.fallback.continue\", \"Continuer\")}\n </Button>\n </div>\n ) : (\n <div className=\"flex justify-end max-w-4xl mx-auto\" data-cy=\"age-control-continue\">\n <ButtonDesktop onClick={advance} type=\"continue\">\n {t(\"age_control.fallback.continue\", \"Continuer\")}\n </ButtonDesktop>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default AgeControl;\n"],"names":["useI18n","useIsMobile","useState","useEffect","fetchWallets","_jsx","WalletProposal","WalletVerificationStep","_jsxs","Button","ButtonDesktop"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var Title = require('../ui/Title.js');
|
|
7
|
+
var Subtitle = require('../ui/Subtitle.js');
|
|
8
|
+
var Button = require('../ui/Button.js');
|
|
9
|
+
var PageActions = require('../ui/PageActions.js');
|
|
10
|
+
var MobilePageLayout = require('../ui/MobilePageLayout.js');
|
|
11
|
+
var useI18n = require('../../hooks/useI18n.js');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Écran de proposition d'identification par wallet d'identité européen
|
|
15
|
+
* (OpenID4VP), affiché uniquement quand un wallet compatible existe pour le
|
|
16
|
+
* pays et le document choisis (cf. GET /backend/wallets). Modèle : NfcChipGate.
|
|
17
|
+
*/
|
|
18
|
+
var WalletProposal = function (_a) {
|
|
19
|
+
var onUseWallet = _a.onUseWallet, onDecline = _a.onDecline, walletMode = _a.walletMode;
|
|
20
|
+
var t = useI18n.useI18n().t;
|
|
21
|
+
return (jsxRuntime.jsx(MobilePageLayout.default, { footer: jsxRuntime.jsx(PageActions.default, { className: "flex-wrap justify-center!", primary: jsxRuntime.jsx(Button.default, { onClick: onUseWallet, children: t("wallet.proposal.use_wallet", "Utiliser mon wallet") }), secondary: jsxRuntime.jsx(Button.default, { variant: "secondary", onClick: onDecline, className: "whitespace-nowrap", children: walletMode === "walletOrPhoto"
|
|
22
|
+
? t("wallet.proposal.decline_photo", "Continuer avec une photo")
|
|
23
|
+
: t("wallet.proposal.decline_no_wallet", "Je n'ai pas de wallet") }) }), children: jsxRuntime.jsx("div", { className: "px-4 py-6 pt-11 md:px-8 md:py-8", children: jsxRuntime.jsx("div", { className: "w-full max-w-md mx-auto space-y-8 text-center", children: jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx(Title.default, { className: "text-xl md:text-2xl lg:text-3xl", children: t("wallet.proposal.title", "Identifiez-vous avec votre wallet d'identité") }), jsxRuntime.jsx(Subtitle.default, { className: "text-sm text-gray-600 leading-relaxed whitespace-pre-line", children: t("wallet.proposal.subtitle", "Un wallet d'identité européen est disponible pour ce document. Vous pouvez vous identifier en ligne, sans prendre de photo.") })] }) }) }) }));
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
exports.default = WalletProposal;
|
|
27
|
+
//# sourceMappingURL=WalletProposal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WalletProposal.js","sources":["../../../../../src/components/wallet/WalletProposal.tsx"],"sourcesContent":["import React from \"react\";\nimport Title from \"../ui/Title\";\nimport Subtitle from \"../ui/Subtitle\";\nimport Button from \"../ui/Button\";\nimport PageActions from \"../ui/PageActions\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport { useI18n } from \"../../hooks/useI18n\";\n\ninterface WalletProposalProps {\n /** L'utilisateur choisit de s'identifier par wallet → écran QR/deep-link */\n onUseWallet: () => void;\n /** L'utilisateur décline (photo si walletOrPhoto, saut du nœud si walletOnly) */\n onDecline: () => void;\n /** walletOnly : pas d'alternative photo, le libellé du bouton secondaire change */\n walletMode: \"walletOnly\" | \"walletOrPhoto\";\n}\n\n/**\n * Écran de proposition d'identification par wallet d'identité européen\n * (OpenID4VP), affiché uniquement quand un wallet compatible existe pour le\n * pays et le document choisis (cf. GET /backend/wallets). Modèle : NfcChipGate.\n */\nconst WalletProposal = ({ onUseWallet, onDecline, walletMode }: WalletProposalProps) => {\n const { t } = useI18n();\n\n return (\n <MobilePageLayout\n footer={\n <PageActions\n className=\"flex-wrap justify-center!\"\n primary={\n <Button onClick={onUseWallet}>\n {t(\"wallet.proposal.use_wallet\", \"Utiliser mon wallet\")}\n </Button>\n }\n secondary={\n <Button\n variant=\"secondary\"\n onClick={onDecline}\n className=\"whitespace-nowrap\"\n >\n {walletMode === \"walletOrPhoto\"\n ? t(\"wallet.proposal.decline_photo\", \"Continuer avec une photo\")\n : t(\"wallet.proposal.decline_no_wallet\", \"Je n'ai pas de wallet\")}\n </Button>\n }\n />\n }\n >\n <div className=\"px-4 py-6 pt-11 md:px-8 md:py-8\">\n <div className=\"w-full max-w-md mx-auto space-y-8 text-center\">\n <div className=\"space-y-4\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl\">\n {t(\n \"wallet.proposal.title\",\n \"Identifiez-vous avec votre wallet d'identité\",\n )}\n </Title>\n <Subtitle className=\"text-sm text-gray-600 leading-relaxed whitespace-pre-line\">\n {t(\n \"wallet.proposal.subtitle\",\n \"Un wallet d'identité européen est disponible pour ce document. Vous pouvez vous identifier en ligne, sans prendre de photo.\",\n )}\n </Subtitle>\n </div>\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default WalletProposal;\n"],"names":["useI18n","_jsx","MobilePageLayout","PageActions","Button","_jsxs","Title","Subtitle"],"mappings":";;;;;;;;;;;;AAiBA;;;;AAIG;AACH,IAAM,cAAc,GAAG,UAAC,EAA2D,EAAA;AAAzD,IAAA,IAAA,WAAW,iBAAA,EAAE,SAAS,GAAA,EAAA,CAAA,SAAA,EAAE,UAAU,GAAA,EAAA,CAAA,UAAA;AAClD,IAAA,IAAA,CAAC,GAAKA,eAAO,EAAE,EAAd;IAET,QACEC,eAACC,wBAAgB,EAAA,EACf,MAAM,EACJD,cAAA,CAACE,mBAAW,EAAA,EACV,SAAS,EAAC,2BAA2B,EACrC,OAAO,EACLF,cAAA,CAACG,cAAM,IAAC,OAAO,EAAE,WAAW,EAAA,QAAA,EACzB,CAAC,CAAC,4BAA4B,EAAE,qBAAqB,CAAC,EAAA,CAChD,EAEX,SAAS,EACPH,cAAA,CAACG,cAAM,EAAA,EACL,OAAO,EAAC,WAAW,EACnB,OAAO,EAAE,SAAS,EAClB,SAAS,EAAC,mBAAmB,EAAA,QAAA,EAE5B,UAAU,KAAK;AACd,sBAAE,CAAC,CAAC,+BAA+B,EAAE,0BAA0B;sBAC7D,CAAC,CAAC,mCAAmC,EAAE,uBAAuB,CAAC,EAAA,CAC5D,EAAA,CAEX,EAAA,QAAA,EAGJH,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,iCAAiC,EAAA,QAAA,EAC9CA,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,+CAA+C,EAAA,QAAA,EAC5DI,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,WAAW,EAAA,QAAA,EAAA,CACxBJ,cAAA,CAACK,aAAK,EAAA,EAAC,SAAS,EAAC,iCAAiC,EAAA,QAAA,EAC/C,CAAC,CACA,uBAAuB,EACvB,8CAA8C,CAC/C,EAAA,CACK,EACRL,cAAA,CAACM,gBAAQ,EAAA,EAAC,SAAS,EAAC,2DAA2D,EAAA,QAAA,EAC5E,CAAC,CACA,0BAA0B,EAC1B,6HAA6H,CAC9H,EAAA,CACQ,CAAA,EAAA,CACP,EAAA,CACF,EAAA,CACF,EAAA,CACW;AAEvB;;;;"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var useI18n = require('../../hooks/useI18n.js');
|
|
8
|
+
|
|
9
|
+
/** Même animation visuelle que NfcSuccessAnimation, avec un libellé adapté au wallet. */
|
|
10
|
+
var WalletSuccessAnimation = function () {
|
|
11
|
+
var t = useI18n.useI18n().t;
|
|
12
|
+
var _a = React.useState(false), visible = _a[0], setVisible = _a[1];
|
|
13
|
+
React.useEffect(function () {
|
|
14
|
+
var id = requestAnimationFrame(function () { return setVisible(true); });
|
|
15
|
+
return function () { return cancelAnimationFrame(id); };
|
|
16
|
+
}, []);
|
|
17
|
+
return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-6 p-8", style: {
|
|
18
|
+
opacity: visible ? 1 : 0,
|
|
19
|
+
transform: visible ? "scale(1)" : "scale(0.85)",
|
|
20
|
+
transition: "opacity 0.4s ease, transform 0.4s ease",
|
|
21
|
+
}, children: [jsxRuntime.jsxs("div", { style: { position: "relative", width: 72, height: 72, flexShrink: 0 }, children: [jsxRuntime.jsx("div", { style: {
|
|
22
|
+
position: "absolute",
|
|
23
|
+
inset: 0,
|
|
24
|
+
borderRadius: "50%",
|
|
25
|
+
backgroundColor: "var(--uni-primary-color, #11e5c5)",
|
|
26
|
+
transformOrigin: "center center",
|
|
27
|
+
animation: "wallet-pulse 1.6s ease-out infinite",
|
|
28
|
+
pointerEvents: "none",
|
|
29
|
+
} }), jsxRuntime.jsxs("svg", { width: 72, height: 72, viewBox: "0 0 72 72", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [jsxRuntime.jsx("circle", { cx: 36, cy: 36, r: 34, fill: "var(--uni-primary-color, #11e5c5)", style: { opacity: visible ? 1 : 0, transition: "opacity 0.3s ease 0.1s" } }), jsxRuntime.jsx("polyline", { points: "20,37 30,47 52,25", stroke: "#ffffff", strokeWidth: 5, strokeLinecap: "round", strokeLinejoin: "round", fill: "none", style: {
|
|
30
|
+
strokeDasharray: 50,
|
|
31
|
+
strokeDashoffset: visible ? 0 : 50,
|
|
32
|
+
transition: "stroke-dashoffset 0.45s cubic-bezier(0.4, 0, 0.2, 1) 0.35s",
|
|
33
|
+
} })] })] }), jsxRuntime.jsxs("div", { className: "text-center space-y-1", children: [jsxRuntime.jsx("p", { className: "font-semibold text-base", style: { color: "var(--uni-secondary-color, #0a9983)" }, children: t("wallet.verification.success_title", "Identité vérifiée") }), jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: t("wallet.verification.success_subtitle", "Vérification par wallet confirmée avec succès") })] }), jsxRuntime.jsx("style", { children: "\n @keyframes wallet-pulse {\n 0% { transform: scale(1); opacity: 0.25; }\n 70% { transform: scale(1.65); opacity: 0.05; }\n 100% { transform: scale(1.65); opacity: 0; }\n }\n " })] }));
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
exports.default = WalletSuccessAnimation;
|
|
37
|
+
//# sourceMappingURL=WalletSuccessAnimation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WalletSuccessAnimation.js","sources":["../../../../../src/components/wallet/WalletSuccessAnimation.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { useI18n } from \"../../hooks/useI18n\";\n\n/** Même animation visuelle que NfcSuccessAnimation, avec un libellé adapté au wallet. */\nconst WalletSuccessAnimation: React.FC = () => {\n const { t } = useI18n();\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n const id = requestAnimationFrame(() => setVisible(true));\n return () => cancelAnimationFrame(id);\n }, []);\n\n return (\n <div\n className=\"flex flex-col items-center gap-6 p-8\"\n style={{\n opacity: visible ? 1 : 0,\n transform: visible ? \"scale(1)\" : \"scale(0.85)\",\n transition: \"opacity 0.4s ease, transform 0.4s ease\",\n }}\n >\n <div style={{ position: \"relative\", width: 72, height: 72, flexShrink: 0 }}>\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n borderRadius: \"50%\",\n backgroundColor: \"var(--uni-primary-color, #11e5c5)\",\n transformOrigin: \"center center\",\n animation: \"wallet-pulse 1.6s ease-out infinite\",\n pointerEvents: \"none\",\n }}\n />\n <svg\n width={72}\n height={72}\n viewBox=\"0 0 72 72\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle\n cx={36}\n cy={36}\n r={34}\n fill=\"var(--uni-primary-color, #11e5c5)\"\n style={{ opacity: visible ? 1 : 0, transition: \"opacity 0.3s ease 0.1s\" }}\n />\n <polyline\n points=\"20,37 30,47 52,25\"\n stroke=\"#ffffff\"\n strokeWidth={5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n style={{\n strokeDasharray: 50,\n strokeDashoffset: visible ? 0 : 50,\n transition: \"stroke-dashoffset 0.45s cubic-bezier(0.4, 0, 0.2, 1) 0.35s\",\n }}\n />\n </svg>\n </div>\n\n <div className=\"text-center space-y-1\">\n <p\n className=\"font-semibold text-base\"\n style={{ color: \"var(--uni-secondary-color, #0a9983)\" }}\n >\n {t(\"wallet.verification.success_title\", \"Identité vérifiée\")}\n </p>\n <p className=\"text-sm text-gray-500\">\n {t(\"wallet.verification.success_subtitle\", \"Vérification par wallet confirmée avec succès\")}\n </p>\n </div>\n\n <style>{`\n @keyframes wallet-pulse {\n 0% { transform: scale(1); opacity: 0.25; }\n 70% { transform: scale(1.65); opacity: 0.05; }\n 100% { transform: scale(1.65); opacity: 0; }\n }\n `}</style>\n </div>\n );\n};\n\nexport default WalletSuccessAnimation;\n"],"names":["useI18n","useState","useEffect","_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var tslib_es6 = require('../../node_modules/tslib/tslib.es6.js');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var React = require('react');
|
|
8
|
+
var QRCode = require('qrcode');
|
|
9
|
+
var useI18n = require('../../hooks/useI18n.js');
|
|
10
|
+
var useWalletSseStatus = require('../../hooks/useWalletSseStatus.js');
|
|
11
|
+
var api = require('../../services/api.js');
|
|
12
|
+
var sessionService = require('../../services/sessionService.js');
|
|
13
|
+
var isMobileDevice = require('../../utils/isMobileDevice.js');
|
|
14
|
+
var MobilePageLayout = require('../ui/MobilePageLayout.js');
|
|
15
|
+
var Button = require('../ui/Button.js');
|
|
16
|
+
var Title = require('../ui/Title.js');
|
|
17
|
+
var Subtitle = require('../ui/Subtitle.js');
|
|
18
|
+
var WalletSuccessAnimation = require('./WalletSuccessAnimation.js');
|
|
19
|
+
|
|
20
|
+
var WalletVerificationStep = function (_a) {
|
|
21
|
+
var sessionId = _a.sessionId, nodeId = _a.nodeId, credentialType = _a.credentialType, walletMode = _a.walletMode, minimumAge = _a.minimumAge, onCompleted = _a.onCompleted, onFailedOrDeclined = _a.onFailedOrDeclined, pageTitle = _a.pageTitle, pageDescription = _a.pageDescription;
|
|
22
|
+
var t = useI18n.useI18n().t;
|
|
23
|
+
var canvasRef = React.useRef(null);
|
|
24
|
+
var _b = React.useState(null), qrError = _b[0], setQrError = _b[1];
|
|
25
|
+
var _c = React.useState(null), deepLink = _c[0], setDeepLink = _c[1];
|
|
26
|
+
var _d = React.useState(null), startError = _d[0], setStartError = _d[1];
|
|
27
|
+
var isMobile = React.useMemo(function () { return isMobileDevice.isMobileDevice(); }, []);
|
|
28
|
+
var apiBaseUrl = React.useMemo(function () { return api.getBaseURL(); }, []);
|
|
29
|
+
React.useEffect(function () {
|
|
30
|
+
var cancelled = false;
|
|
31
|
+
(function () { return tslib_es6.__awaiter(void 0, void 0, void 0, function () {
|
|
32
|
+
var result, error_1;
|
|
33
|
+
return tslib_es6.__generator(this, function (_a) {
|
|
34
|
+
switch (_a.label) {
|
|
35
|
+
case 0:
|
|
36
|
+
_a.trys.push([0, 2, , 3]);
|
|
37
|
+
return [4 /*yield*/, sessionService.startWalletVerification(sessionId, {
|
|
38
|
+
nodeId: nodeId,
|
|
39
|
+
credentialType: credentialType,
|
|
40
|
+
minimumAge: minimumAge,
|
|
41
|
+
})];
|
|
42
|
+
case 1:
|
|
43
|
+
result = _a.sent();
|
|
44
|
+
if (!cancelled)
|
|
45
|
+
setDeepLink(result.deepLink);
|
|
46
|
+
return [3 /*break*/, 3];
|
|
47
|
+
case 2:
|
|
48
|
+
error_1 = _a.sent();
|
|
49
|
+
console.error("Failed to start wallet verification:", error_1);
|
|
50
|
+
if (!cancelled) {
|
|
51
|
+
setStartError(t("wallet.verification.start_failed", "Impossible de démarrer la vérification par wallet."));
|
|
52
|
+
}
|
|
53
|
+
return [3 /*break*/, 3];
|
|
54
|
+
case 3: return [2 /*return*/];
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}); })();
|
|
58
|
+
return function () {
|
|
59
|
+
cancelled = true;
|
|
60
|
+
};
|
|
61
|
+
}, [sessionId, nodeId, credentialType, minimumAge, t]);
|
|
62
|
+
var status = useWalletSseStatus.useWalletSseStatus({
|
|
63
|
+
sessionId: sessionId,
|
|
64
|
+
apiBaseUrl: apiBaseUrl,
|
|
65
|
+
onCompleted: onCompleted,
|
|
66
|
+
}).status;
|
|
67
|
+
// Sur mobile : ouvrir directement l'app wallet via le deep-link openid4vp://,
|
|
68
|
+
// une seule fois, tant que la vérification n'a pas progressé.
|
|
69
|
+
var hasRedirectedRef = React.useRef(false);
|
|
70
|
+
React.useEffect(function () {
|
|
71
|
+
if (!isMobile || !deepLink || status !== "pending" || hasRedirectedRef.current)
|
|
72
|
+
return;
|
|
73
|
+
hasRedirectedRef.current = true;
|
|
74
|
+
window.location.assign(deepLink);
|
|
75
|
+
}, [isMobile, deepLink, status]);
|
|
76
|
+
React.useEffect(function () {
|
|
77
|
+
if (isMobile)
|
|
78
|
+
return; // pas de QR sur mobile (redirection directe)
|
|
79
|
+
if (!deepLink || status !== "pending")
|
|
80
|
+
return;
|
|
81
|
+
var generate = function () { return tslib_es6.__awaiter(void 0, void 0, void 0, function () {
|
|
82
|
+
var dataUrl, canvas_1, ctx_1, img_1;
|
|
83
|
+
return tslib_es6.__generator(this, function (_b) {
|
|
84
|
+
switch (_b.label) {
|
|
85
|
+
case 0:
|
|
86
|
+
if (!canvasRef.current)
|
|
87
|
+
return [2 /*return*/];
|
|
88
|
+
setQrError(null);
|
|
89
|
+
_b.label = 1;
|
|
90
|
+
case 1:
|
|
91
|
+
_b.trys.push([1, 3, , 4]);
|
|
92
|
+
return [4 /*yield*/, QRCode.toDataURL(deepLink, {
|
|
93
|
+
width: 256,
|
|
94
|
+
margin: 2,
|
|
95
|
+
color: { dark: "#000000", light: "#FFFFFF" },
|
|
96
|
+
})];
|
|
97
|
+
case 2:
|
|
98
|
+
dataUrl = _b.sent();
|
|
99
|
+
canvas_1 = canvasRef.current;
|
|
100
|
+
ctx_1 = canvas_1.getContext("2d");
|
|
101
|
+
if (ctx_1) {
|
|
102
|
+
img_1 = new Image();
|
|
103
|
+
img_1.onload = function () {
|
|
104
|
+
canvas_1.width = img_1.width;
|
|
105
|
+
canvas_1.height = img_1.height;
|
|
106
|
+
ctx_1.drawImage(img_1, 0, 0);
|
|
107
|
+
};
|
|
108
|
+
img_1.src = dataUrl;
|
|
109
|
+
}
|
|
110
|
+
return [3 /*break*/, 4];
|
|
111
|
+
case 3:
|
|
112
|
+
_b.sent();
|
|
113
|
+
setQrError(t("qr_code.generation_failed", "Erreur de génération du QR code"));
|
|
114
|
+
return [3 /*break*/, 4];
|
|
115
|
+
case 4: return [2 /*return*/];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}); };
|
|
119
|
+
generate();
|
|
120
|
+
}, [deepLink, status, t, isMobile]);
|
|
121
|
+
var title = pageTitle || t("wallet.verification.page_title", "Identification par wallet");
|
|
122
|
+
var subtitle = pageDescription ||
|
|
123
|
+
t("wallet.verification.page_description", "Scannez le QR code ci-dessous avec votre wallet d'identité pour vous identifier en ligne.");
|
|
124
|
+
var declineLabel = walletMode === "walletOrPhoto"
|
|
125
|
+
? t("wallet.verification.continue_with_photo", "Continuer avec une photo")
|
|
126
|
+
: t("wallet.verification.skip", "Passer");
|
|
127
|
+
var footer = status === "failed" || startError ? (jsxRuntime.jsx(Button.default, { onClick: onFailedOrDeclined, children: declineLabel })) : null;
|
|
128
|
+
return (jsxRuntime.jsx(MobilePageLayout.default, { footer: footer, children: jsxRuntime.jsx("div", { className: "px-4 py-6 pt-11 md:px-8 md:py-8", children: jsxRuntime.jsxs("div", { className: "w-full max-w-md mx-auto space-y-6", children: [jsxRuntime.jsxs("div", { className: "text-center space-y-4 mt-16 md:mt-20", children: [jsxRuntime.jsx(Title.default, { className: "text-xl md:text-2xl lg:text-3xl", children: title }), jsxRuntime.jsx(Subtitle.default, { className: "text-sm md:text-base text-gray-600 leading-relaxed whitespace-pre-line", children: subtitle })] }), jsxRuntime.jsx("div", { className: "flex-1 flex justify-center items-center", children: startError ? (jsxRuntime.jsx("div", { className: "text-red-500 text-center p-4", "data-cy": "wallet-start-error", children: startError })) : status === "success" ? (jsxRuntime.jsx(WalletSuccessAnimation.default, {})) : status === "completed" ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4 p-8", children: [jsxRuntime.jsx("div", { className: "animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: t("wallet.verification.verifying", "Vérification en cours…") })] })) : status === "failed" ? (jsxRuntime.jsx("div", { className: "w-full max-w-sm rounded-2xl border border-red-200 bg-red-50 p-6 text-center shadow-sm", "data-cy": "wallet-verification-failed", children: jsxRuntime.jsx("p", { className: "text-sm leading-relaxed text-red-700", children: t("wallet.verification.failed", "La vérification par wallet a échoué.") }) })) : qrError ? (jsxRuntime.jsx("div", { className: "text-red-500 text-center p-4", children: qrError })) : isMobile ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4 p-8 text-center", children: [jsxRuntime.jsx("div", { className: "animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: t("wallet.verification.opening_app", "Ouverture du wallet…") }), deepLink && (jsxRuntime.jsx("a", { href: deepLink, className: "text-sm font-medium text-blue-600 underline", children: t("wallet.verification.open_app_link", "Ouvrir mon wallet") }))] })) : deepLink ? (jsxRuntime.jsx("div", { className: "bg-white p-4 rounded-lg shadow-lg border-2 border-gray-200", "data-cy": "wallet-qr-code", children: jsxRuntime.jsx("canvas", { ref: canvasRef }) })) : (jsxRuntime.jsx("div", { className: "flex flex-col items-center gap-4 p-8", children: jsxRuntime.jsx("div", { className: "animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full" }) })) })] }) }) }));
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
exports.default = WalletVerificationStep;
|
|
132
|
+
//# sourceMappingURL=WalletVerificationStep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WalletVerificationStep.js","sources":["../../../../../src/components/wallet/WalletVerificationStep.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport QRCode from \"qrcode\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport { useWalletSseStatus } from \"../../hooks/useWalletSseStatus\";\nimport { getBaseURL } from \"../../services/api\";\nimport { startWalletVerification } from \"../../services/sessionService\";\nimport { isMobileDevice } from \"../../utils/isMobileDevice\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport Button from \"../ui/Button\";\nimport Title from \"../ui/Title\";\nimport Subtitle from \"../ui/Subtitle\";\nimport WalletSuccessAnimation from \"./WalletSuccessAnimation\";\n\nexport type WalletCredentialType =\n | \"pid\"\n | \"driving_license\"\n | \"vehicle_registration\"\n | \"age_verification\";\n\ninterface WalletVerificationStepProps {\n sessionId: string;\n nodeId: string;\n credentialType: WalletCredentialType;\n walletMode: \"walletOnly\" | \"walletOrPhoto\";\n minimumAge?: number;\n onCompleted: () => void;\n /** Échec de la vérification ou wallet non disponible — le parent décide de la\n * suite (fallback photo en walletOrPhoto, saut du nœud en walletOnly). */\n onFailedOrDeclined: () => void;\n pageTitle?: string;\n pageDescription?: string;\n}\n\nconst WalletVerificationStep: React.FC<WalletVerificationStepProps> = ({\n sessionId,\n nodeId,\n credentialType,\n walletMode,\n minimumAge,\n onCompleted,\n onFailedOrDeclined,\n pageTitle,\n pageDescription,\n}) => {\n const { t } = useI18n();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const [qrError, setQrError] = useState<string | null>(null);\n const [deepLink, setDeepLink] = useState<string | null>(null);\n const [startError, setStartError] = useState<string | null>(null);\n const isMobile = useMemo(() => isMobileDevice(), []);\n const apiBaseUrl = useMemo(() => getBaseURL(), []);\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const result = await startWalletVerification(sessionId, {\n nodeId,\n credentialType,\n minimumAge,\n });\n if (!cancelled) setDeepLink(result.deepLink);\n } catch (error) {\n console.error(\"Failed to start wallet verification:\", error);\n if (!cancelled) {\n setStartError(\n t(\n \"wallet.verification.start_failed\",\n \"Impossible de démarrer la vérification par wallet.\",\n ),\n );\n }\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [sessionId, nodeId, credentialType, minimumAge, t]);\n\n const { status } = useWalletSseStatus({\n sessionId,\n apiBaseUrl,\n onCompleted,\n });\n\n // Sur mobile : ouvrir directement l'app wallet via le deep-link openid4vp://,\n // une seule fois, tant que la vérification n'a pas progressé.\n const hasRedirectedRef = useRef(false);\n useEffect(() => {\n if (!isMobile || !deepLink || status !== \"pending\" || hasRedirectedRef.current) return;\n hasRedirectedRef.current = true;\n window.location.assign(deepLink);\n }, [isMobile, deepLink, status]);\n\n useEffect(() => {\n if (isMobile) return; // pas de QR sur mobile (redirection directe)\n if (!deepLink || status !== \"pending\") return;\n\n const generate = async () => {\n if (!canvasRef.current) return;\n setQrError(null);\n try {\n const dataUrl = await QRCode.toDataURL(deepLink, {\n width: 256,\n margin: 2,\n color: { dark: \"#000000\", light: \"#FFFFFF\" },\n });\n const canvas = canvasRef.current;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n const img = new Image();\n img.onload = () => {\n canvas.width = img.width;\n canvas.height = img.height;\n ctx.drawImage(img, 0, 0);\n };\n img.src = dataUrl;\n }\n } catch {\n setQrError(t(\"qr_code.generation_failed\", \"Erreur de génération du QR code\"));\n }\n };\n\n generate();\n }, [deepLink, status, t, isMobile]);\n\n const title = pageTitle || t(\"wallet.verification.page_title\", \"Identification par wallet\");\n const subtitle =\n pageDescription ||\n t(\n \"wallet.verification.page_description\",\n \"Scannez le QR code ci-dessous avec votre wallet d'identité pour vous identifier en ligne.\",\n );\n\n const declineLabel =\n walletMode === \"walletOrPhoto\"\n ? t(\"wallet.verification.continue_with_photo\", \"Continuer avec une photo\")\n : t(\"wallet.verification.skip\", \"Passer\");\n\n const footer =\n status === \"failed\" || startError ? (\n <Button onClick={onFailedOrDeclined}>\n {declineLabel}\n </Button>\n ) : null;\n\n return (\n <MobilePageLayout footer={footer}>\n <div className=\"px-4 py-6 pt-11 md:px-8 md:py-8\">\n <div className=\"w-full max-w-md mx-auto space-y-6\">\n <div className=\"text-center space-y-4 mt-16 md:mt-20\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl\">{title}</Title>\n <Subtitle className=\"text-sm md:text-base text-gray-600 leading-relaxed whitespace-pre-line\">\n {subtitle}\n </Subtitle>\n </div>\n\n <div className=\"flex-1 flex justify-center items-center\">\n {startError ? (\n <div className=\"text-red-500 text-center p-4\" data-cy=\"wallet-start-error\">\n {startError}\n </div>\n ) : status === \"success\" ? (\n <WalletSuccessAnimation />\n ) : status === \"completed\" ? (\n <div className=\"flex flex-col items-center gap-4 p-8\">\n <div className=\"animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full\" />\n <p className=\"text-sm text-gray-600\">\n {t(\"wallet.verification.verifying\", \"Vérification en cours…\")}\n </p>\n </div>\n ) : status === \"failed\" ? (\n <div\n className=\"w-full max-w-sm rounded-2xl border border-red-200 bg-red-50 p-6 text-center shadow-sm\"\n data-cy=\"wallet-verification-failed\"\n >\n <p className=\"text-sm leading-relaxed text-red-700\">\n {t(\n \"wallet.verification.failed\",\n \"La vérification par wallet a échoué.\",\n )}\n </p>\n </div>\n ) : qrError ? (\n <div className=\"text-red-500 text-center p-4\">{qrError}</div>\n ) : isMobile ? (\n <div className=\"flex flex-col items-center gap-4 p-8 text-center\">\n <div className=\"animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full\" />\n <p className=\"text-sm text-gray-600\">\n {t(\"wallet.verification.opening_app\", \"Ouverture du wallet…\")}\n </p>\n {deepLink && (\n <a href={deepLink} className=\"text-sm font-medium text-blue-600 underline\">\n {t(\"wallet.verification.open_app_link\", \"Ouvrir mon wallet\")}\n </a>\n )}\n </div>\n ) : deepLink ? (\n <div\n className=\"bg-white p-4 rounded-lg shadow-lg border-2 border-gray-200\"\n data-cy=\"wallet-qr-code\"\n >\n <canvas ref={canvasRef} />\n </div>\n ) : (\n <div className=\"flex flex-col items-center gap-4 p-8\">\n <div className=\"animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full\" />\n </div>\n )}\n </div>\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default WalletVerificationStep;\n"],"names":["useI18n","useRef","useState","useMemo","isMobileDevice","getBaseURL","useEffect","__awaiter","startWalletVerification","useWalletSseStatus","_jsx","Button","MobilePageLayout","_jsxs","Title","Subtitle","WalletSuccessAnimation"],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
|
|
5
|
+
var SUCCESS_DISPLAY_DURATION_MS = 2500;
|
|
6
|
+
/**
|
|
7
|
+
* Polls the wallet (OID4VP) verification status via SSE — symmetric to
|
|
8
|
+
* useNfcSseStatus. The backend learns about the wallet response by polling
|
|
9
|
+
* Oid4vpService.getStatus() internally (cf.
|
|
10
|
+
* docs/WALLET_OID4VP_IMPLEMENTATION_PLAN.md §5.2/§7), so from the SDK's point
|
|
11
|
+
* of view this is the same "connect once, react to status pushes" contract.
|
|
12
|
+
*/
|
|
13
|
+
function useWalletSseStatus(_a) {
|
|
14
|
+
var sessionId = _a.sessionId, apiBaseUrl = _a.apiBaseUrl, onCompleted = _a.onCompleted;
|
|
15
|
+
var _b = React.useState("pending"), status = _b[0], setStatus = _b[1];
|
|
16
|
+
var onCompletedRef = React.useRef(onCompleted);
|
|
17
|
+
onCompletedRef.current = onCompleted;
|
|
18
|
+
React.useEffect(function () {
|
|
19
|
+
if (!sessionId || !apiBaseUrl)
|
|
20
|
+
return;
|
|
21
|
+
var url = "".concat(apiBaseUrl, "/session/sdk/").concat(sessionId, "/wallet-status");
|
|
22
|
+
var source = new EventSource(url);
|
|
23
|
+
source.onmessage = function (event) {
|
|
24
|
+
try {
|
|
25
|
+
var data = JSON.parse(event.data);
|
|
26
|
+
if (data.status === "verified") {
|
|
27
|
+
source.close();
|
|
28
|
+
setStatus("success");
|
|
29
|
+
setTimeout(function () {
|
|
30
|
+
setStatus("completed");
|
|
31
|
+
onCompletedRef.current();
|
|
32
|
+
}, SUCCESS_DISPLAY_DURATION_MS);
|
|
33
|
+
}
|
|
34
|
+
else if (data.status === "failed" ||
|
|
35
|
+
data.status === "skipped" ||
|
|
36
|
+
data.status === "pending") {
|
|
37
|
+
setStatus(data.status);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (_a) {
|
|
41
|
+
// message malformé, on ignore
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
source.onerror = function () {
|
|
45
|
+
// EventSource reconnecte automatiquement — pas d'action requise
|
|
46
|
+
};
|
|
47
|
+
// Fermer le flux quand l'onglet/app se ferme ou passe en arrière-plan, sinon le SSE reste
|
|
48
|
+
// ouvert côté serveur (heartbeat + listener qui fuient). `pagehide` couvre la fermeture
|
|
49
|
+
// (plus fiable que `beforeunload` sur mobile) ; `visibilitychange` couvre le passage en fond.
|
|
50
|
+
var closeSource = function () { return source.close(); };
|
|
51
|
+
var closeOnHide = function () {
|
|
52
|
+
if (document.visibilityState === "hidden")
|
|
53
|
+
source.close();
|
|
54
|
+
};
|
|
55
|
+
window.addEventListener("pagehide", closeSource);
|
|
56
|
+
document.addEventListener("visibilitychange", closeOnHide);
|
|
57
|
+
return function () {
|
|
58
|
+
window.removeEventListener("pagehide", closeSource);
|
|
59
|
+
document.removeEventListener("visibilitychange", closeOnHide);
|
|
60
|
+
source.close();
|
|
61
|
+
};
|
|
62
|
+
}, [sessionId, apiBaseUrl]);
|
|
63
|
+
return { status: status };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
exports.useWalletSseStatus = useWalletSseStatus;
|
|
67
|
+
//# sourceMappingURL=useWalletSseStatus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWalletSseStatus.js","sources":["../../../../src/hooks/useWalletSseStatus.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\nexport type WalletStatus = \"pending\" | \"success\" | \"completed\" | \"failed\" | \"skipped\";\n\nconst SUCCESS_DISPLAY_DURATION_MS = 2500;\n\ninterface UseWalletSseStatusOptions {\n sessionId: string;\n apiBaseUrl: string;\n onCompleted: () => void;\n}\n\n/**\n * Polls the wallet (OID4VP) verification status via SSE — symmetric to\n * useNfcSseStatus. The backend learns about the wallet response by polling\n * Oid4vpService.getStatus() internally (cf.\n * docs/WALLET_OID4VP_IMPLEMENTATION_PLAN.md §5.2/§7), so from the SDK's point\n * of view this is the same \"connect once, react to status pushes\" contract.\n */\nexport function useWalletSseStatus({\n sessionId,\n apiBaseUrl,\n onCompleted,\n}: UseWalletSseStatusOptions) {\n const [status, setStatus] = useState<WalletStatus>(\"pending\");\n const onCompletedRef = useRef(onCompleted);\n onCompletedRef.current = onCompleted;\n\n useEffect(() => {\n if (!sessionId || !apiBaseUrl) return;\n\n const url = `${apiBaseUrl}/session/sdk/${sessionId}/wallet-status`;\n const source = new EventSource(url);\n\n source.onmessage = (event) => {\n try {\n const data = JSON.parse(event.data) as { status: string };\n if (data.status === \"verified\") {\n source.close();\n setStatus(\"success\");\n setTimeout(() => {\n setStatus(\"completed\");\n onCompletedRef.current();\n }, SUCCESS_DISPLAY_DURATION_MS);\n } else if (\n data.status === \"failed\" ||\n data.status === \"skipped\" ||\n data.status === \"pending\"\n ) {\n setStatus(data.status);\n }\n } catch {\n // message malformé, on ignore\n }\n };\n\n source.onerror = () => {\n // EventSource reconnecte automatiquement — pas d'action requise\n };\n\n // Fermer le flux quand l'onglet/app se ferme ou passe en arrière-plan, sinon le SSE reste\n // ouvert côté serveur (heartbeat + listener qui fuient). `pagehide` couvre la fermeture\n // (plus fiable que `beforeunload` sur mobile) ; `visibilitychange` couvre le passage en fond.\n const closeSource = () => source.close();\n const closeOnHide = () => {\n if (document.visibilityState === \"hidden\") source.close();\n };\n window.addEventListener(\"pagehide\", closeSource);\n document.addEventListener(\"visibilitychange\", closeOnHide);\n\n return () => {\n window.removeEventListener(\"pagehide\", closeSource);\n document.removeEventListener(\"visibilitychange\", closeOnHide);\n source.close();\n };\n }, [sessionId, apiBaseUrl]);\n\n return { status };\n}\n"],"names":["useState","useRef","useEffect"],"mappings":";;;;AAIA,IAAM,2BAA2B,GAAG,IAAI;AAQxC;;;;;;AAMG;AACG,SAAU,kBAAkB,CAAC,EAIP,EAAA;AAH1B,IAAA,IAAA,SAAS,eAAA,EACT,UAAU,GAAA,EAAA,CAAA,UAAA,EACV,WAAW,GAAA,EAAA,CAAA,WAAA;IAEL,IAAA,EAAA,GAAsBA,cAAQ,CAAe,SAAS,CAAC,EAAtD,MAAM,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,SAAS,GAAA,EAAA,CAAA,CAAA,CAAqC;AAC7D,IAAA,IAAM,cAAc,GAAGC,YAAM,CAAC,WAAW,CAAC;AAC1C,IAAA,cAAc,CAAC,OAAO,GAAG,WAAW;AAEpC,IAAAC,eAAS,CAAC,YAAA;AACR,QAAA,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU;YAAE;AAE/B,QAAA,IAAM,GAAG,GAAG,EAAA,CAAA,MAAA,CAAG,UAAU,EAAA,eAAA,CAAA,CAAA,MAAA,CAAgB,SAAS,mBAAgB;AAClE,QAAA,IAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC;AAEnC,QAAA,MAAM,CAAC,SAAS,GAAG,UAAC,KAAK,EAAA;AACvB,YAAA,IAAI;gBACF,IAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAuB;AACzD,gBAAA,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE;oBAC9B,MAAM,CAAC,KAAK,EAAE;oBACd,SAAS,CAAC,SAAS,CAAC;AACpB,oBAAA,UAAU,CAAC,YAAA;wBACT,SAAS,CAAC,WAAW,CAAC;wBACtB,cAAc,CAAC,OAAO,EAAE;oBAC1B,CAAC,EAAE,2BAA2B,CAAC;gBACjC;AAAO,qBAAA,IACL,IAAI,CAAC,MAAM,KAAK,QAAQ;oBACxB,IAAI,CAAC,MAAM,KAAK,SAAS;AACzB,oBAAA,IAAI,CAAC,MAAM,KAAK,SAAS,EACzB;AACA,oBAAA,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;gBACxB;YACF;AAAE,YAAA,OAAA,EAAA,EAAM;;YAER;AACF,QAAA,CAAC;QAED,MAAM,CAAC,OAAO,GAAG,YAAA;;AAEjB,QAAA,CAAC;;;;QAKD,IAAM,WAAW,GAAG,YAAA,EAAM,OAAA,MAAM,CAAC,KAAK,EAAE,CAAA,CAAd,CAAc;AACxC,QAAA,IAAM,WAAW,GAAG,YAAA;AAClB,YAAA,IAAI,QAAQ,CAAC,eAAe,KAAK,QAAQ;gBAAE,MAAM,CAAC,KAAK,EAAE;AAC3D,QAAA,CAAC;AACD,QAAA,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,WAAW,CAAC;AAChD,QAAA,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,WAAW,CAAC;QAE1D,OAAO,YAAA;AACL,YAAA,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,WAAW,CAAC;AACnD,YAAA,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,WAAW,CAAC;YAC7D,MAAM,CAAC,KAAK,EAAE;AAChB,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AAE3B,IAAA,OAAO,EAAE,MAAM,EAAA,MAAA,EAAE;AACnB;;;;"}
|