datakeen-session-react 1.1.140-rc.80 → 1.1.140-rc.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/nfc-scan/NfcFallbackSurvey.js +6 -2
- package/dist/cjs/components/nfc-scan/NfcFallbackSurvey.js.map +1 -1
- package/dist/cjs/components/nfc-scan/NfcScanNode.js +44 -4
- package/dist/cjs/components/nfc-scan/NfcScanNode.js.map +1 -1
- package/dist/cjs/components/session/DocumentCheck.js +72 -12
- package/dist/cjs/components/session/DocumentCheck.js.map +1 -1
- package/dist/cjs/hooks/useNfcSseStatus.js +8 -9
- package/dist/cjs/hooks/useNfcSseStatus.js.map +1 -1
- package/dist/cjs/i18n/en.json.js +6 -0
- package/dist/cjs/i18n/en.json.js.map +1 -1
- package/dist/cjs/i18n/fr.json.js +6 -0
- package/dist/cjs/i18n/fr.json.js.map +1 -1
- package/dist/cjs/index.css.js +1 -1
- package/dist/cjs/services/sessionService.js +16 -0
- package/dist/cjs/services/sessionService.js.map +1 -1
- package/dist/esm/components/nfc-scan/NfcFallbackSurvey.js +6 -2
- package/dist/esm/components/nfc-scan/NfcFallbackSurvey.js.map +1 -1
- package/dist/esm/components/nfc-scan/NfcScanNode.js +45 -5
- package/dist/esm/components/nfc-scan/NfcScanNode.js.map +1 -1
- package/dist/esm/components/session/DocumentCheck.js +72 -12
- package/dist/esm/components/session/DocumentCheck.js.map +1 -1
- package/dist/esm/hooks/useNfcSseStatus.js +8 -9
- package/dist/esm/hooks/useNfcSseStatus.js.map +1 -1
- package/dist/esm/i18n/en.json.js +6 -0
- package/dist/esm/i18n/en.json.js.map +1 -1
- package/dist/esm/i18n/fr.json.js +6 -0
- package/dist/esm/i18n/fr.json.js.map +1 -1
- package/dist/esm/index.css.js +1 -1
- package/dist/esm/services/sessionService.js +16 -1
- package/dist/esm/services/sessionService.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import { __awaiter, __generator } from '../../node_modules/tslib/tslib.es6.js';
|
|
2
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { useRef, useState, useMemo, useEffect } from 'react';
|
|
4
4
|
import QRCode from 'qrcode';
|
|
5
5
|
import { useI18n } from '../../hooks/useI18n.js';
|
|
6
6
|
import { useNfcSseStatus } from '../../hooks/useNfcSseStatus.js';
|
|
7
7
|
import { getBaseURL } from '../../services/api.js';
|
|
8
|
+
import { resetNfcScan } from '../../services/sessionService.js';
|
|
8
9
|
import { isMobileDevice } from '../../utils/isMobileDevice.js';
|
|
9
10
|
import MobilePageLayout from '../ui/MobilePageLayout.js';
|
|
10
11
|
import Button from '../ui/Button.js';
|
|
12
|
+
import PageActions from '../ui/PageActions.js';
|
|
11
13
|
import Title from '../ui/Title.js';
|
|
12
14
|
import Subtitle from '../ui/Subtitle.js';
|
|
13
15
|
import NfcSuccessAnimation from './NfcSuccessAnimation.js';
|
|
14
16
|
|
|
15
17
|
var NfcScanStep = function (_a) {
|
|
16
|
-
var sessionId = _a.sessionId, nodeId = _a.nodeId, stepObject = _a.stepObject, template = _a.template, pageTitle = _a.pageTitle, pageDescription = _a.pageDescription, onBack = _a.onBack;
|
|
18
|
+
var sessionId = _a.sessionId, nodeId = _a.nodeId, stepObject = _a.stepObject, template = _a.template, pageTitle = _a.pageTitle, pageDescription = _a.pageDescription, onBack = _a.onBack, onContinueWithoutChip = _a.onContinueWithoutChip;
|
|
17
19
|
var t = useI18n().t;
|
|
18
20
|
var canvasRef = useRef(null);
|
|
19
21
|
var _b = useState(null), qrError = _b[0], setQrError = _b[1];
|
|
22
|
+
var _c = useState(null), resetError = _c[0], setResetError = _c[1];
|
|
23
|
+
var _d = useState(false), isResetting = _d[0], setIsResetting = _d[1];
|
|
20
24
|
// Sur mobile, on ouvre directement l'app de scan au lieu d'afficher un QR code inutile.
|
|
21
25
|
var isMobile = useMemo(function () { return isMobileDevice(); }, []);
|
|
22
26
|
var nfcUrl = useMemo(function () {
|
|
@@ -94,10 +98,46 @@ var NfcScanStep = function (_a) {
|
|
|
94
98
|
}); };
|
|
95
99
|
generate();
|
|
96
100
|
}, [nfcUrl, status, t, isMobile]);
|
|
97
|
-
|
|
101
|
+
var handleBack = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
102
|
+
return __generator(this, function (_b) {
|
|
103
|
+
switch (_b.label) {
|
|
104
|
+
case 0:
|
|
105
|
+
if (!onBack)
|
|
106
|
+
return [2 /*return*/];
|
|
107
|
+
if (status !== "failed") {
|
|
108
|
+
onBack();
|
|
109
|
+
return [2 /*return*/];
|
|
110
|
+
}
|
|
111
|
+
setResetError(null);
|
|
112
|
+
setIsResetting(true);
|
|
113
|
+
_b.label = 1;
|
|
114
|
+
case 1:
|
|
115
|
+
_b.trys.push([1, 3, 4, 5]);
|
|
116
|
+
return [4 /*yield*/, resetNfcScan(sessionId)];
|
|
117
|
+
case 2:
|
|
118
|
+
_b.sent();
|
|
119
|
+
onBack();
|
|
120
|
+
return [3 /*break*/, 5];
|
|
121
|
+
case 3:
|
|
122
|
+
_b.sent();
|
|
123
|
+
setResetError(t("nfc_scan.reset_failed", "Impossible de réinitialiser le scan NFC. Veuillez réessayer."));
|
|
124
|
+
return [3 /*break*/, 5];
|
|
125
|
+
case 4:
|
|
126
|
+
setIsResetting(false);
|
|
127
|
+
return [7 /*endfinally*/];
|
|
128
|
+
case 5: return [2 /*return*/];
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}); };
|
|
132
|
+
// Footer : sur l'échec définitif ('failed'), les actions dédiées (revenir au choix / poursuivre
|
|
133
|
+
// sans puce) sont rendues via PageActions, comme les autres écrans NFC (NfcChipGate). Sinon, un
|
|
134
|
+
// simple "Retour" tant que le scan n'a pas commencé/abouti.
|
|
98
135
|
var canGoBack = !!onBack && (status === "pending" || status === "opened");
|
|
99
|
-
var footer = canGoBack ? (jsx(Button, { variant: "secondary", onClick: onBack, children: t("common.back", "Retour") })) : null;
|
|
100
|
-
return (jsx(MobilePageLayout, { footer: footer, children: jsx("div", { className: "px-4 py-6 pt-11 md:px-8 md:py-8", children: jsxs("div", { className: "w-full max-w-md mx-auto space-y-6", children: [jsxs("div", { className: "text-center space-y-4 mt-16 md:mt-20", children: [jsx(Title, { className: "text-xl md:text-2xl lg:text-3xl", children: title }), jsx(Subtitle, { className: "text-sm md:text-base text-gray-600 leading-relaxed whitespace-pre-line", children: subtitle })] }), jsx("div", { className: "flex-1 flex justify-center items-center", children: status === "success" ? (jsx(NfcSuccessAnimation, {})) : status === "completed" ? (jsxs("div", { className: "flex flex-col items-center gap-4 p-8", children: [jsx("div", { className: "animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full" }), jsx("p", { className: "text-sm text-gray-600", children: t("nfc_scan.verifying", "Vérification en cours…") })] })) : status === "
|
|
136
|
+
var footer = status === "failed" ? (jsx(PageActions, { primary: onBack ? (jsx(Button, { onClick: function () { return void handleBack(); }, disabled: isResetting, children: t("nfc_scan.failed_back_to_selection", "Revenir au choix du document") })) : null, secondary: onContinueWithoutChip ? (jsx(Button, { variant: "secondary", onClick: onContinueWithoutChip, children: t("nfc_scan.failed_continue_without_chip", "Poursuivre sans puce") })) : null })) : canGoBack ? (jsx(Button, { variant: "secondary", onClick: onBack, children: t("common.back", "Retour") })) : null;
|
|
137
|
+
return (jsx(MobilePageLayout, { footer: footer, children: jsx("div", { className: "px-4 py-6 pt-11 md:px-8 md:py-8", children: jsxs("div", { className: "w-full max-w-md mx-auto space-y-6", children: [jsxs("div", { className: "text-center space-y-4 mt-16 md:mt-20", children: [jsx(Title, { className: "text-xl md:text-2xl lg:text-3xl", children: title }), jsx(Subtitle, { className: "text-sm md:text-base text-gray-600 leading-relaxed whitespace-pre-line", children: subtitle })] }), jsx("div", { className: "flex-1 flex flex-col justify-center items-center gap-4", children: status === "success" ? (jsx(NfcSuccessAnimation, {})) : status === "completed" ? (jsxs("div", { className: "flex flex-col items-center gap-4 p-8", children: [jsx("div", { className: "animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full" }), jsx("p", { className: "text-sm text-gray-600", children: t("nfc_scan.verifying", "Vérification en cours…") })] })) : status === "failed" ? (jsxs("div", { className: "flex flex-col items-center gap-2 p-8 text-center", children: [jsx("p", { className: "text-base font-semibold text-red-600", children: t("nfc_scan.failed_title", "Le scan n'a pas pu être vérifié") }), jsx("p", { className: "text-sm text-gray-600 leading-relaxed", children: t("nfc_scan.failed_description", "Après plusieurs tentatives, la lecture de votre document n'a pas pu être validée.") }), resetError && (jsx("p", { className: "text-sm text-red-600", role: "alert", children: resetError }))] })) : (
|
|
138
|
+
// Contenu principal QR/mobile — reste monté pour "pending" ET "opened", pour ne
|
|
139
|
+
// jamais démonter le canvas déjà généré.
|
|
140
|
+
jsxs(Fragment, { children: [qrError ? (jsx("div", { className: "text-red-500 text-center p-4", children: qrError })) : isMobile ? (jsxs("div", { className: "flex flex-col items-center gap-4 p-8 text-center", children: [jsx("div", { className: "animate-spin w-10 h-10 border-2 border-gray-300 border-t-blue-500 rounded-full" }), jsx("p", { className: "text-sm text-gray-600", children: t("nfc_scan.opening_app", "Ouverture de l'application…") }), jsx("a", { href: nfcUrl, className: "text-sm font-medium text-blue-600 underline", children: t("nfc_scan.open_app_link", "Ouvrir l'application") })] })) : (jsx("div", { className: "bg-white p-4 rounded-lg shadow-lg border-2 border-gray-200", children: jsx("canvas", { ref: canvasRef }) })), status === "opened" && (jsxs("div", { className: "text-center space-y-1", children: [jsx("p", { className: "text-sm font-semibold", style: { color: "var(--uni-secondary-color, #0a9983)" }, children: t("nfc_scan.qr_opened_title", "QR code scanné") }), jsx("p", { className: "text-xs text-gray-500 leading-relaxed", children: t("nfc_scan.qr_opened_description", "L'expérience NFC est ouverte sur votre smartphone. Continuez le scan sur votre téléphone.") }), jsxs("div", { className: "flex items-center justify-center gap-2 text-xs text-gray-500 pt-1", children: [jsx("span", { className: "h-2 w-2 rounded-full animate-pulse", style: { backgroundColor: "var(--uni-primary-color, #11e5c5)" } }), t("nfc_scan.waiting_completion", "En attente de la lecture NFC")] })] }))] })) })] }) }) }));
|
|
101
141
|
};
|
|
102
142
|
|
|
103
143
|
export { NfcScanStep as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NfcScanNode.js","sources":["../../../../../src/components/nfc-scan/NfcScanNode.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport QRCode from \"qrcode\";\nimport type { SessionTemplate, stepObject } from \"../../types/session\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport { useNfcSseStatus } from \"../../hooks/useNfcSseStatus\";\nimport { getBaseURL } from \"../../services/api\";\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 NfcSuccessAnimation from \"./NfcSuccessAnimation\";\n\ninterface NfcScanStepProps {\n sessionId: string;\n nodeId: string;\n stepObject: stepObject;\n template?: SessionTemplate;\n pageTitle?: string;\n pageDescription?: string;\n /** Retour vers la sélection du document (pour corriger un mauvais choix). */\n onBack?: () => void;\n}\n\nconst NfcScanStep: React.FC<NfcScanStepProps> = ({\n sessionId,\n nodeId,\n stepObject,\n template,\n pageTitle,\n pageDescription,\n onBack,\n}) => {\n const { t } = useI18n();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const [qrError, setQrError] = useState<string | null>(null);\n // Sur mobile, on ouvre directement l'app de scan au lieu d'afficher un QR code inutile.\n const isMobile = useMemo(() => isMobileDevice(), []);\n\n const nfcUrl = useMemo(() => {\n const origin = typeof window !== \"undefined\" ? window.location.origin : \"\";\n return `${origin}/scan/${sessionId}`;\n }, [sessionId]);\n\n const apiBaseUrl = useMemo(() => getBaseURL(), []);\n\n const { status } = useNfcSseStatus({\n sessionId,\n apiBaseUrl,\n onCompleted: () => {\n if (template) {\n stepObject.goToNextStep(nodeId, template);\n } else {\n stepObject.setStep(stepObject.step + 1);\n }\n },\n });\n\n const title =\n pageTitle || t(\"nfc_scan.page_title\", \"Scan NFC de votre document\");\n const subtitle =\n pageDescription ||\n t(\n \"nfc_scan.page_description\",\n \"Scannez le QR code ci-dessous avec votre smartphone pour lire la puce électronique de votre document d'identité.\"\n );\n\n // Sur mobile : ouvrir directement l'application de scan (pas de QR à se scanner soi-même).\n // Une seule fois, tant que le scan n'a pas progressé. Le SSE reste actif pour faire avancer\n // le parcours quand la lecture est terminée.\n const hasRedirectedRef = useRef(false);\n useEffect(() => {\n if (!isMobile || status !== \"pending\" || hasRedirectedRef.current) return;\n hasRedirectedRef.current = true;\n window.location.assign(nfcUrl);\n }, [isMobile, status, nfcUrl]);\n\n useEffect(() => {\n if (isMobile) return; // pas de QR sur mobile (redirection directe)\n if (status !== \"pending\") return;\n\n const generate = async () => {\n if (!canvasRef.current) return;\n setQrError(null);\n\n try {\n const dataUrl = await QRCode.toDataURL(nfcUrl, {\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 }, [nfcUrl, status, t, isMobile]);\n\n // Bouton retour : seulement tant que le scan n'a pas commencé/abouti, et si un handler est fourni.\n const canGoBack = !!onBack && (status === \"pending\" || status === \"opened\");\n const footer = canGoBack ? (\n <Button variant=\"secondary\" onClick={onBack}>\n {t(\"common.back\", \"Retour\")}\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 {status === \"success\" ? (\n <NfcSuccessAnimation />\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(\"nfc_scan.verifying\", \"Vérification en cours…\")}\n </p>\n </div>\n ) : status === \"opened\" ? (\n <div className=\"w-full max-w-sm rounded-2xl border border-emerald-200 bg-emerald-50 p-6 text-center shadow-sm\">\n <div className=\"mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-full bg-emerald-500 text-white shadow-md shadow-emerald-200\">\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n className=\"h-7 w-7\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </div>\n <p className=\"text-base font-semibold text-gray-900\">\n {t(\"nfc_scan.qr_opened_title\", \"QR code scanné\")}\n </p>\n <p className=\"mt-2 text-sm leading-relaxed text-gray-600\">\n {t(\n \"nfc_scan.qr_opened_description\",\n \"L'expérience NFC est ouverte sur votre smartphone. Continuez le scan sur votre téléphone.\"\n )}\n </p>\n <div className=\"mt-5 flex items-center justify-center gap-2 text-xs font-medium text-emerald-700\">\n <span className=\"h-2 w-2 animate-pulse rounded-full bg-emerald-500\" />\n {t(\"nfc_scan.waiting_completion\", \"En attente de la lecture NFC\")}\n </div>\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(\"nfc_scan.opening_app\", \"Ouverture de l'application…\")}\n </p>\n <a\n href={nfcUrl}\n className=\"text-sm font-medium text-blue-600 underline\"\n >\n {t(\"nfc_scan.open_app_link\", \"Ouvrir l'application\")}\n </a>\n </div>\n ) : (\n <div className=\"bg-white p-4 rounded-lg shadow-lg border-2 border-gray-200\">\n <canvas ref={canvasRef} />\n </div>\n )}\n </div>\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default NfcScanStep;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NfcScanNode.js","sources":["../../../../../src/components/nfc-scan/NfcScanNode.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport QRCode from \"qrcode\";\nimport type { SessionTemplate, stepObject } from \"../../types/session\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport { useNfcSseStatus } from \"../../hooks/useNfcSseStatus\";\nimport { getBaseURL } from \"../../services/api\";\nimport { resetNfcScan } from \"../../services/sessionService\";\nimport { isMobileDevice } from \"../../utils/isMobileDevice\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport Button from \"../ui/Button\";\nimport PageActions from \"../ui/PageActions\";\nimport Title from \"../ui/Title\";\nimport Subtitle from \"../ui/Subtitle\";\nimport NfcSuccessAnimation from \"./NfcSuccessAnimation\";\n\ninterface NfcScanStepProps {\n sessionId: string;\n nodeId: string;\n stepObject: stepObject;\n template?: SessionTemplate;\n pageTitle?: string;\n pageDescription?: string;\n /** Retour vers la sélection du document (pour corriger un mauvais choix). */\n onBack?: () => void;\n /**\n * Fallback \"poursuivre sans puce\" proposé sur l'échec définitif (nfcStatus 'failed'). Ouvre le\n * questionnaire de raison côté web (NfcFallbackSurvey) ; la reprise (photo/API ou saut de nœud)\n * est décidée par l'orchestrateur selon nfcMode. Absent = bouton masqué.\n */\n onContinueWithoutChip?: () => void;\n}\n\nconst NfcScanStep: React.FC<NfcScanStepProps> = ({\n sessionId,\n nodeId,\n stepObject,\n template,\n pageTitle,\n pageDescription,\n onBack,\n onContinueWithoutChip,\n}) => {\n const { t } = useI18n();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const [qrError, setQrError] = useState<string | null>(null);\n const [resetError, setResetError] = useState<string | null>(null);\n const [isResetting, setIsResetting] = useState(false);\n // Sur mobile, on ouvre directement l'app de scan au lieu d'afficher un QR code inutile.\n const isMobile = useMemo(() => isMobileDevice(), []);\n\n const nfcUrl = useMemo(() => {\n const origin = typeof window !== \"undefined\" ? window.location.origin : \"\";\n return `${origin}/scan/${sessionId}`;\n }, [sessionId]);\n\n const apiBaseUrl = useMemo(() => getBaseURL(), []);\n\n const { status } = useNfcSseStatus({\n sessionId,\n apiBaseUrl,\n onCompleted: () => {\n if (template) {\n stepObject.goToNextStep(nodeId, template);\n } else {\n stepObject.setStep(stepObject.step + 1);\n }\n },\n });\n\n const title =\n pageTitle || t(\"nfc_scan.page_title\", \"Scan NFC de votre document\");\n const subtitle =\n pageDescription ||\n t(\n \"nfc_scan.page_description\",\n \"Scannez le QR code ci-dessous avec votre smartphone pour lire la puce électronique de votre document d'identité.\"\n );\n\n // Sur mobile : ouvrir directement l'application de scan (pas de QR à se scanner soi-même).\n // Une seule fois, tant que le scan n'a pas progressé. Le SSE reste actif pour faire avancer\n // le parcours quand la lecture est terminée.\n const hasRedirectedRef = useRef(false);\n useEffect(() => {\n if (!isMobile || status !== \"pending\" || hasRedirectedRef.current) return;\n hasRedirectedRef.current = true;\n window.location.assign(nfcUrl);\n }, [isMobile, status, nfcUrl]);\n\n useEffect(() => {\n if (isMobile) return; // pas de QR sur mobile (redirection directe)\n if (status !== \"pending\") return;\n\n const generate = async () => {\n if (!canvasRef.current) return;\n setQrError(null);\n\n try {\n const dataUrl = await QRCode.toDataURL(nfcUrl, {\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 }, [nfcUrl, status, t, isMobile]);\n\n const handleBack = async () => {\n if (!onBack) return;\n\n if (status !== \"failed\") {\n onBack();\n return;\n }\n\n setResetError(null);\n setIsResetting(true);\n try {\n await resetNfcScan(sessionId);\n onBack();\n } catch {\n setResetError(\n t(\n \"nfc_scan.reset_failed\",\n \"Impossible de réinitialiser le scan NFC. Veuillez réessayer.\",\n ),\n );\n } finally {\n setIsResetting(false);\n }\n };\n\n // Footer : sur l'échec définitif ('failed'), les actions dédiées (revenir au choix / poursuivre\n // sans puce) sont rendues via PageActions, comme les autres écrans NFC (NfcChipGate). Sinon, un\n // simple \"Retour\" tant que le scan n'a pas commencé/abouti.\n const canGoBack = !!onBack && (status === \"pending\" || status === \"opened\");\n const footer =\n status === \"failed\" ? (\n <PageActions\n primary={\n onBack ? (\n <Button onClick={() => void handleBack()} disabled={isResetting}>\n {t(\"nfc_scan.failed_back_to_selection\", \"Revenir au choix du document\")}\n </Button>\n ) : null\n }\n secondary={\n onContinueWithoutChip ? (\n <Button variant=\"secondary\" onClick={onContinueWithoutChip}>\n {t(\"nfc_scan.failed_continue_without_chip\", \"Poursuivre sans puce\")}\n </Button>\n ) : null\n }\n />\n ) : canGoBack ? (\n <Button variant=\"secondary\" onClick={onBack}>\n {t(\"common.back\", \"Retour\")}\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 flex-col justify-center items-center gap-4\">\n {status === \"success\" ? (\n <NfcSuccessAnimation />\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(\"nfc_scan.verifying\", \"Vérification en cours…\")}\n </p>\n </div>\n ) : status === \"failed\" ? (\n <div className=\"flex flex-col items-center gap-2 p-8 text-center\">\n <p className=\"text-base font-semibold text-red-600\">\n {t(\"nfc_scan.failed_title\", \"Le scan n'a pas pu être vérifié\")}\n </p>\n <p className=\"text-sm text-gray-600 leading-relaxed\">\n {t(\n \"nfc_scan.failed_description\",\n \"Après plusieurs tentatives, la lecture de votre document n'a pas pu être validée.\"\n )}\n </p>\n {resetError && (\n <p className=\"text-sm text-red-600\" role=\"alert\">\n {resetError}\n </p>\n )}\n </div>\n ) : (\n // Contenu principal QR/mobile — reste monté pour \"pending\" ET \"opened\", pour ne\n // jamais démonter le canvas déjà généré.\n <>\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(\"nfc_scan.opening_app\", \"Ouverture de l'application…\")}\n </p>\n <a\n href={nfcUrl}\n className=\"text-sm font-medium text-blue-600 underline\"\n >\n {t(\"nfc_scan.open_app_link\", \"Ouvrir l'application\")}\n </a>\n </div>\n ) : (\n <div className=\"bg-white p-4 rounded-lg shadow-lg border-2 border-gray-200\">\n <canvas ref={canvasRef} />\n </div>\n )}\n\n {status === \"opened\" && (\n <div className=\"text-center space-y-1\">\n <p\n className=\"text-sm font-semibold\"\n style={{ color: \"var(--uni-secondary-color, #0a9983)\" }}\n >\n {t(\"nfc_scan.qr_opened_title\", \"QR code scanné\")}\n </p>\n <p className=\"text-xs text-gray-500 leading-relaxed\">\n {t(\n \"nfc_scan.qr_opened_description\",\n \"L'expérience NFC est ouverte sur votre smartphone. Continuez le scan sur votre téléphone.\"\n )}\n </p>\n <div className=\"flex items-center justify-center gap-2 text-xs text-gray-500 pt-1\">\n <span\n className=\"h-2 w-2 rounded-full animate-pulse\"\n style={{ backgroundColor: \"var(--uni-primary-color, #11e5c5)\" }}\n />\n {t(\"nfc_scan.waiting_completion\", \"En attente de la lecture NFC\")}\n </div>\n </div>\n )}\n </>\n )}\n </div>\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default NfcScanStep;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
|
|
@@ -71,7 +71,7 @@ var normalizeNfcMode = function (mode) {
|
|
|
71
71
|
*/
|
|
72
72
|
var DocumentCheck = function (_a) {
|
|
73
73
|
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
74
|
-
var stepObject = _a.stepObject, sessionId = _a.sessionId, node = _a.node
|
|
74
|
+
var stepObject = _a.stepObject, sessionId = _a.sessionId, node = _a.node, documentTypeId = _a.documentTypeId, acceptedCountries = _a.acceptedCountries, _p = _a.isMobileCapture, isMobileCapture = _p === void 0 ? false : _p, allowedAddingMethods = _a.allowedAddingMethods, template = _a.template, setUserInput = _a.setUserInput;
|
|
75
75
|
var t = useI18n().t;
|
|
76
76
|
var session = getSession().session;
|
|
77
77
|
var _q = useState(), documentTemplates = _q[0], setDocumentTemplates = _q[1];
|
|
@@ -138,21 +138,61 @@ var DocumentCheck = function (_a) {
|
|
|
138
138
|
setRetryCount(sessionRetryCount);
|
|
139
139
|
}
|
|
140
140
|
}, [session, node.id]);
|
|
141
|
-
// Restauration après refresh
|
|
142
|
-
//
|
|
143
|
-
//
|
|
141
|
+
// Restauration après refresh / déchargement de l'onglet : `docStep` est en mémoire et serait perdu
|
|
142
|
+
// au rechargement. On s'appuie sur `session.nfcStatus` (persisté et exposé par le backend) pour
|
|
143
|
+
// remettre l'utilisateur au bon endroit du nœud NFC au lieu de repartir au début (gate -1).
|
|
144
|
+
//
|
|
145
|
+
// En parcours full mobile, l'ouverture de l'app de scan peut décharger l'onglet ; au retour, le
|
|
146
|
+
// composant remonte. Sans cette restauration, l'utilisateur retombait sur le choix pays/document.
|
|
144
147
|
var hasRestoredNfcStep = useRef(false);
|
|
145
148
|
useEffect(function () {
|
|
149
|
+
var _a, _b;
|
|
146
150
|
if (hasRestoredNfcStep.current)
|
|
147
151
|
return;
|
|
148
152
|
if (node.nfcEnabled !== true)
|
|
149
153
|
return;
|
|
150
154
|
var status = session === null || session === void 0 ? void 0 : session.nfcStatus;
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
// 'pending' (ou absent) → rien à restaurer : le scan n'a pas démarré, l'effet de reset affiche
|
|
156
|
+
// le gate -1 (écran d'entrée normal).
|
|
157
|
+
if (status !== "opened" && status !== "failed" && status !== "completed" && status !== "skipped") {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// À partir d'ici on prend la décision une seule fois (idempotence, y compris si l'effet se
|
|
161
|
+
// re-déclenche) : on pose le flag AVANT toute navigation.
|
|
162
|
+
hasRestoredNfcStep.current = true;
|
|
163
|
+
if (status === "opened" || status === "failed") {
|
|
164
|
+
// Scan en cours, ou échoué (définitivement, ou en attente d'une nouvelle tentative) :
|
|
165
|
+
// rester sur l'écran de scan / d'échec (docStep 7) avec ses actions.
|
|
153
166
|
setDocStep(7);
|
|
167
|
+
return;
|
|
154
168
|
}
|
|
155
|
-
|
|
169
|
+
if (status === "completed") {
|
|
170
|
+
// Scan réussi avant le déchargement : le nœud NFC est terminé → passer à l'étape suivante
|
|
171
|
+
// (y compris en mode nfcOrPhoto — le NFC réussi suffit à valider le document).
|
|
172
|
+
if (template) {
|
|
173
|
+
stepObject.goToNextStep(node.id, template);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
stepObject.setStep(stepObject.step + 1);
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// status === "skipped" : l'utilisateur a poursuivi sans puce avant le déchargement.
|
|
181
|
+
// Reproduit le routage de handleNfcFallback selon le mode :
|
|
182
|
+
// - nfcOrPhoto → reprendre le flux photo/API du même nœud (intro/pays)
|
|
183
|
+
// - nfcOnly → sauter le nœud (étape suivante)
|
|
184
|
+
if (normalizeNfcMode(node.nfcMode) === "nfcOrPhoto") {
|
|
185
|
+
var hasIntroduction = ((_a = node.introductionPage) === null || _a === void 0 ? void 0 : _a.title) !== undefined ||
|
|
186
|
+
((_b = node.introductionPage) === null || _b === void 0 ? void 0 : _b.description) !== undefined;
|
|
187
|
+
setDocStep(hasIntroduction ? 0 : 1);
|
|
188
|
+
}
|
|
189
|
+
else if (template) {
|
|
190
|
+
stepObject.goToNextStep(node.id, template);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
stepObject.setStep(stepObject.step + 1);
|
|
194
|
+
}
|
|
195
|
+
}, [session, node, template, stepObject]);
|
|
156
196
|
// Check retry limits on mount/reload - if retries exhausted, show error page immediately
|
|
157
197
|
useEffect(function () {
|
|
158
198
|
// Special case: if allowResubmission is false and retryCount > 0, show error immediately
|
|
@@ -268,8 +308,18 @@ var DocumentCheck = function (_a) {
|
|
|
268
308
|
if (docStep === 6) {
|
|
269
309
|
return;
|
|
270
310
|
}
|
|
271
|
-
// En NFC, on affiche d'abord l'écran de confirmation de la puce (gate -1)
|
|
311
|
+
// En NFC, on affiche d'abord l'écran de confirmation de la puce (gate -1).
|
|
312
|
+
// MAIS si un scan est déjà engagé/terminé/sauté côté backend (reload / retour après
|
|
313
|
+
// déchargement de l'onglet), on ne force PAS le gate : on laisse l'effet de restauration
|
|
314
|
+
// ci-dessus décider (sinon il l'écraserait et l'utilisateur repartirait au début du nœud).
|
|
272
315
|
if (node.nfcEnabled === true) {
|
|
316
|
+
var nfcStatus = session === null || session === void 0 ? void 0 : session.nfcStatus;
|
|
317
|
+
if (nfcStatus === "opened" ||
|
|
318
|
+
nfcStatus === "failed" ||
|
|
319
|
+
nfcStatus === "completed" ||
|
|
320
|
+
nfcStatus === "skipped") {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
273
323
|
setDocStep(-1);
|
|
274
324
|
return;
|
|
275
325
|
}
|
|
@@ -280,7 +330,9 @@ var DocumentCheck = function (_a) {
|
|
|
280
330
|
else {
|
|
281
331
|
setDocStep(0);
|
|
282
332
|
}
|
|
283
|
-
|
|
333
|
+
// `session` (nfcStatus) est requis : au chargement asynchrone de la session après un reload,
|
|
334
|
+
// cet effet doit se ré-évaluer pour ne pas forcer le gate -1 alors qu'un scan est déjà engagé.
|
|
335
|
+
}, [documentTypeId, sessionId, isMobileCapture, session, node.nfcEnabled]);
|
|
284
336
|
var handleCountrySelect = function (countryId) {
|
|
285
337
|
console.debug("[DocumentCheck] handleCountrySelect - countryId:", countryId);
|
|
286
338
|
setUserInput(function (prev) { return (__assign(__assign({}, prev), { countryCode: countryId.toUpperCase() })); });
|
|
@@ -648,7 +700,7 @@ var DocumentCheck = function (_a) {
|
|
|
648
700
|
? undefined
|
|
649
701
|
: ((_o = node.documentSelection) === null || _o === void 0 ? void 0 : _o.description) ||
|
|
650
702
|
t("jdi.document_selection.description"), nfcEnabled: node.nfcEnabled === true }));
|
|
651
|
-
case 3:
|
|
703
|
+
case 3: {
|
|
652
704
|
if (!selectedDocumentType) {
|
|
653
705
|
console.error("DocumentCheck: selectedDocumentType is null for step 3!");
|
|
654
706
|
return (jsxs("div", { className: "flex flex-col items-center justify-center h-full p-4 text-center", children: [jsx("div", { className: "text-red-500 text-4xl mb-4", children: "\u26A0\uFE0F" }), jsx("h2", { className: "text-xl font-bold text-red-600 mb-2", children: t("document_check.selection_error.title", "Erreur de sélection") }), jsx("p", { className: "text-gray-600 mb-4", children: t("document_check.selection_error.description", "Aucun type de document sélectionné. Veuillez revenir à l'étape précédente.") }), jsx(ButtonDesktop, { className: "px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition-colors", type: "back", onClick: function () { return setDocStep(2); }, children: t("document_check.selection_error.back", "Retour à la sélection") })] }));
|
|
@@ -700,6 +752,8 @@ var DocumentCheck = function (_a) {
|
|
|
700
752
|
}
|
|
701
753
|
}, initialFront: errorCode === "2.5" ? fileUploaded === null || fileUploaded === void 0 ? void 0 : fileUploaded.front : null, initialBack: errorCode === "2.5" ? fileUploaded === null || fileUploaded === void 0 ? void 0 : fileUploaded.back : null, sessionId: sessionId }));
|
|
702
754
|
}
|
|
755
|
+
}
|
|
756
|
+
// fall-through volontaire vers case 4 (comportement existant conservé)
|
|
703
757
|
case 4:
|
|
704
758
|
return (jsx(JDIProcessing, { documentType: (selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.id) || documentTypeId, onProcessingComplete: handleProcessingComplete, fileUploaded: fileUploaded, documentTypeId: documentTypeId, retryCount: retryCount, documentTemplateId: selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.documentTemplateId, nodeId: node.id }));
|
|
705
759
|
case 5:
|
|
@@ -712,12 +766,18 @@ var DocumentCheck = function (_a) {
|
|
|
712
766
|
}
|
|
713
767
|
return (jsx(NfcScanStep, { sessionId: sessionId, nodeId: node.id, stepObject: stepObject, template: template, onBack: function () {
|
|
714
768
|
var _a, _b;
|
|
715
|
-
// Retour vers la sélection du document (corriger un mauvais choix
|
|
716
|
-
// NfcScanStep ferme le SSE via le cleanup du hook (pas d'appel backend
|
|
769
|
+
// Retour vers la sélection du document (corriger un mauvais choix, ou après échec NFC).
|
|
770
|
+
// Le démontage de NfcScanStep ferme le SSE via le cleanup du hook (pas d'appel backend).
|
|
717
771
|
var hasIntroduction = ((_a = node.introductionPage) === null || _a === void 0 ? void 0 : _a.title) !== undefined ||
|
|
718
772
|
((_b = node.introductionPage) === null || _b === void 0 ? void 0 : _b.description) !== undefined;
|
|
719
773
|
hasRestoredNfcStep.current = true; // ne pas re-restaurer l'étape QR après ce retour
|
|
720
774
|
setDocStep(hasIntroduction ? 0 : 1);
|
|
775
|
+
}, onContinueWithoutChip: function () {
|
|
776
|
+
// "Poursuivre sans puce" après échec définitif : ouvre le questionnaire de raison
|
|
777
|
+
// (docStep -2 → NfcFallbackSurvey → handleNfcFallback). handleNfcFallback applique
|
|
778
|
+
// ensuite la reprise selon nfcMode (nfcOrPhoto → photo/API ; nfcOnly → nœud suivant).
|
|
779
|
+
hasRestoredNfcStep.current = true;
|
|
780
|
+
setDocStep(-2);
|
|
721
781
|
} }));
|
|
722
782
|
default:
|
|
723
783
|
console.error("Invalid docStep: ".concat(docStep));
|