datakeen-session-react 1.1.140-dev.77 → 1.1.140-dev.79

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.
Files changed (37) hide show
  1. package/dist/cjs/components/nfc-scan/NfcScanNode.js +89 -0
  2. package/dist/cjs/components/nfc-scan/NfcScanNode.js.map +1 -0
  3. package/dist/cjs/components/nfc-scan/NfcSuccessAnimation.js +40 -0
  4. package/dist/cjs/components/nfc-scan/NfcSuccessAnimation.js.map +1 -0
  5. package/dist/cjs/components/session/DocumentCheck.js +89 -35
  6. package/dist/cjs/components/session/DocumentCheck.js.map +1 -1
  7. package/dist/cjs/hooks/useNfcSseStatus.js +46 -0
  8. package/dist/cjs/hooks/useNfcSseStatus.js.map +1 -0
  9. package/dist/cjs/hooks/useUserInputForm.js +8 -2
  10. package/dist/cjs/hooks/useUserInputForm.js.map +1 -1
  11. package/dist/cjs/i18n/en.json.js +10 -1
  12. package/dist/cjs/i18n/en.json.js.map +1 -1
  13. package/dist/cjs/i18n/fr.json.js +10 -1
  14. package/dist/cjs/i18n/fr.json.js.map +1 -1
  15. package/dist/cjs/index.css.js +1 -1
  16. package/dist/cjs/services/api.js +1 -0
  17. package/dist/cjs/services/api.js.map +1 -1
  18. package/dist/cjs/types/session.js.map +1 -1
  19. package/dist/esm/components/nfc-scan/NfcScanNode.js +85 -0
  20. package/dist/esm/components/nfc-scan/NfcScanNode.js.map +1 -0
  21. package/dist/esm/components/nfc-scan/NfcSuccessAnimation.js +36 -0
  22. package/dist/esm/components/nfc-scan/NfcSuccessAnimation.js.map +1 -0
  23. package/dist/esm/components/session/DocumentCheck.js +89 -35
  24. package/dist/esm/components/session/DocumentCheck.js.map +1 -1
  25. package/dist/esm/hooks/useNfcSseStatus.js +44 -0
  26. package/dist/esm/hooks/useNfcSseStatus.js.map +1 -0
  27. package/dist/esm/hooks/useUserInputForm.js +8 -2
  28. package/dist/esm/hooks/useUserInputForm.js.map +1 -1
  29. package/dist/esm/i18n/en.json.js +10 -2
  30. package/dist/esm/i18n/en.json.js.map +1 -1
  31. package/dist/esm/i18n/fr.json.js +10 -2
  32. package/dist/esm/i18n/fr.json.js.map +1 -1
  33. package/dist/esm/index.css.js +1 -1
  34. package/dist/esm/services/api.js +1 -1
  35. package/dist/esm/services/api.js.map +1 -1
  36. package/dist/esm/types/session.js.map +1 -1
  37. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sources":["../../../../src/services/api.ts"],"sourcesContent":["import axios, { AxiosError } from \"axios\";\nimport type {\n AxiosInstance,\n AxiosResponse,\n InternalAxiosRequestConfig,\n AxiosRequestConfig,\n} from \"axios\";\nimport { API_BASE_URL } from \"../config/env\";\n\n// Types pour window global\ndeclare global {\n interface Window {\n VITE_API_BASE_URL?: string;\n }\n}\n\n// Helpers\nconst normalizeBaseURL = (url: string | undefined | null): string => {\n const DEFAULT_BASE_URL = \"https://dev2.datakeen.co/backend\";\n if (!url) {\n return DEFAULT_BASE_URL;\n }\n\n const trimmed = url.trim();\n if (!trimmed) {\n return DEFAULT_BASE_URL;\n }\n\n try {\n const parsed = new URL(trimmed);\n const cleanedPath = parsed.pathname.replace(/\\/+$/, \"\");\n const hasBackendSegment = /\\/backend(\\/|$)/.test(cleanedPath);\n const normalizedPath = hasBackendSegment\n ? cleanedPath.replace(/\\/backend(\\/*.*)?$/, \"/backend\")\n : `${cleanedPath}/backend`;\n\n const finalPath = normalizedPath.startsWith(\"/\")\n ? normalizedPath\n : `/${normalizedPath}`;\n\n const normalized = `${parsed.origin}${finalPath}`.replace(/\\/+$/, \"\");\n return normalized;\n } catch {\n const withoutTrailingSlash = trimmed.replace(/\\/+$/, \"\");\n if (/\\/backend(\\/|$)/.test(withoutTrailingSlash)) {\n return withoutTrailingSlash.replace(/\\/backend(\\/*.*)?$/, \"/backend\");\n }\n return `${withoutTrailingSlash}/backend`;\n }\n};\n\n// Configuration globale pour l'URL de base\nlet globalBaseURL: string | null = null;\n\n// Fonction pour définir l'URL de base globalement\nexport const configureApiBaseURL = (baseURL: string): void => {\n const normalizedBaseURL = normalizeBaseURL(baseURL);\n globalBaseURL = normalizedBaseURL;\n // Mettre à jour l'instance existante si elle existe\n if (apiService) {\n apiService.updateBaseURL(normalizedBaseURL);\n }\n};\n\n// Fonction pour récupérer l'URL de base dynamiquement\nconst getBaseURL = (): string => {\n // Priorité 1: URL configurée dynamiquement\n if (globalBaseURL) {\n return globalBaseURL;\n }\n\n // Priorité 2: Variable d'environnement du projet hôte (si disponible via window)\n if (typeof window !== \"undefined\" && window.VITE_API_BASE_URL) {\n return normalizeBaseURL(window.VITE_API_BASE_URL);\n }\n\n // Priorité 3: Variable d'environnement du SDK via wrapper\n if (API_BASE_URL) {\n return normalizeBaseURL(API_BASE_URL);\n }\n\n // Priorité 4: URL par défaut (dev2 pour développement)\n return normalizeBaseURL(\"https://dev2.datakeen.co/backend\");\n};\n\n// Types pour la configuration de l'API\nexport interface ApiConfig {\n baseURL: string;\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n headers?: Record<string, string>;\n}\n\n// Types pour les réponses\nexport interface ApiResponse<T = any> {\n data: T;\n message?: string;\n success: boolean;\n status: number;\n}\n\nexport interface ApiError {\n message: string;\n status?: number;\n code?: string;\n details?: any;\n}\n\nexport class ApiService {\n private client: AxiosInstance;\n private config: ApiConfig;\n\n constructor(config: ApiConfig) {\n this.config = config;\n\n this.client = axios.create({\n baseURL: config.baseURL,\n timeout: config.timeout || 30000,\n headers: {\n Accept: \"application/json\",\n ...config.headers,\n },\n });\n\n this.setupInterceptors();\n }\n\n private setupInterceptors(): void {\n // Intercepteur de requête\n this.client.interceptors.request.use(\n (config: InternalAxiosRequestConfig) => {\n return config;\n },\n (error: AxiosError) => {\n return Promise.reject(this.handleError(error));\n }\n );\n\n // Intercepteur de réponse pour gérer les erreurs\n this.client.interceptors.response.use(\n (response: AxiosResponse) => {\n return response;\n },\n (error: AxiosError) => {\n return Promise.reject(this.handleError(error));\n }\n );\n }\n\n private handleError(error: AxiosError): ApiError {\n let apiError: ApiError = {\n message: \"Une erreur inattendue s'est produite\",\n status: 500,\n };\n\n if (error.response) {\n // Erreur de réponse du serveur\n const { status, data } = error.response;\n apiError = {\n message: (data as any)?.message || `Erreur ${status}`,\n status,\n code: (data as any)?.code,\n details: data,\n };\n } else if (error.code === \"ECONNABORTED\") {\n // Timeout\n apiError = {\n message: \"Délai d'attente dépassé\",\n code: \"TIMEOUT_ERROR\",\n };\n } else if (error.request) {\n // Erreur réseau - Log plus de détails pour debug\n console.error(\"❌ Network error details:\", {\n message: error.message,\n code: error.code,\n config: {\n url: error.config?.url,\n method: error.config?.method,\n baseURL: error.config?.baseURL,\n timeout: error.config?.timeout,\n },\n });\n \n // Vérifier si c'est une erreur CORS\n if (error.message.includes(\"Network Error\") || error.message.includes(\"CORS\")) {\n apiError = {\n message: \"Erreur CORS ou serveur inaccessible. Vérifiez que le serveur backend est démarré et autorise les requêtes depuis votre domaine.\",\n code: \"CORS_OR_NETWORK_ERROR\",\n };\n } else {\n apiError = {\n message: \"Erreur de connexion réseau\",\n code: \"NETWORK_ERROR\",\n };\n }\n }\n\n console.error(\"❌ API Error:\", apiError);\n return apiError;\n }\n\n // Plus de retryRequest, shouldRetry, ni delay : chaque appel Axios ne sera fait qu'une seule fois\n\n // Méthodes publiques pour les requêtes HTTP\n async get<T = any>(\n url: string,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.get<T>(url, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n async post<T = any>(\n url: string,\n data?: any,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.post<T>(url, data, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n async put<T = any>(\n url: string,\n data?: any,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.put<T>(url, data, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n async patch<T = any>(\n url: string,\n data?: any,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.patch<T>(url, data, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n async delete<T = any>(\n url: string,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.delete<T>(url, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n // Méthodes utilitaires\n setDefaultHeader(key: string, value: string): void {\n this.client.defaults.headers.common[key] = value;\n }\n\n removeDefaultHeader(key: string): void {\n delete this.client.defaults.headers.common[key];\n }\n\n // Méthode pour créer une nouvelle instance avec une configuration différente\n createInstance(config: Partial<ApiConfig>): ApiService {\n return new ApiService({ ...this.config, ...config });\n }\n\n // Accès à l'instance Axios pour des cas spéciaux\n getRawClient(): AxiosInstance {\n return this.client;\n }\n\n // Méthode pour mettre à jour dynamiquement l'URL de base\n updateBaseURL(baseURL: string): void {\n this.config.baseURL = baseURL;\n this.client.defaults.baseURL = baseURL;\n }\n}\n\n// In test environment, mock axios to avoid real HTTP requests\nif (\n typeof process !== \"undefined\" &&\n process.env &&\n process.env.NODE_ENV === \"test\"\n) {\n // @ts-ignore\n global.axios = {\n create: () => ({\n get: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n post: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n put: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n patch: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n delete: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n defaults: { headers: { common: {} } },\n interceptors: {\n request: { use: jest.fn() },\n response: { use: jest.fn() },\n },\n }),\n };\n}\n\n// Factory pour créer une instance\nexport const createApiService = (config: ApiConfig): ApiService => {\n return new ApiService(config);\n};\n\n// Instance par défaut (à configurer selon vos besoins)\nexport const apiService = createApiService({\n baseURL: getBaseURL(),\n timeout: 30000,\n});\n\nexport { normalizeBaseURL };\n"],"names":["API_BASE_URL","__assign"],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sources":["../../../../src/services/api.ts"],"sourcesContent":["import axios, { AxiosError } from \"axios\";\nimport type {\n AxiosInstance,\n AxiosResponse,\n InternalAxiosRequestConfig,\n AxiosRequestConfig,\n} from \"axios\";\nimport { API_BASE_URL } from \"../config/env\";\n\n// Types pour window global\ndeclare global {\n interface Window {\n VITE_API_BASE_URL?: string;\n }\n}\n\n// Helpers\nconst normalizeBaseURL = (url: string | undefined | null): string => {\n const DEFAULT_BASE_URL = \"https://dev2.datakeen.co/backend\";\n if (!url) {\n return DEFAULT_BASE_URL;\n }\n\n const trimmed = url.trim();\n if (!trimmed) {\n return DEFAULT_BASE_URL;\n }\n\n try {\n const parsed = new URL(trimmed);\n const cleanedPath = parsed.pathname.replace(/\\/+$/, \"\");\n const hasBackendSegment = /\\/backend(\\/|$)/.test(cleanedPath);\n const normalizedPath = hasBackendSegment\n ? cleanedPath.replace(/\\/backend(\\/*.*)?$/, \"/backend\")\n : `${cleanedPath}/backend`;\n\n const finalPath = normalizedPath.startsWith(\"/\")\n ? normalizedPath\n : `/${normalizedPath}`;\n\n const normalized = `${parsed.origin}${finalPath}`.replace(/\\/+$/, \"\");\n return normalized;\n } catch {\n const withoutTrailingSlash = trimmed.replace(/\\/+$/, \"\");\n if (/\\/backend(\\/|$)/.test(withoutTrailingSlash)) {\n return withoutTrailingSlash.replace(/\\/backend(\\/*.*)?$/, \"/backend\");\n }\n return `${withoutTrailingSlash}/backend`;\n }\n};\n\n// Configuration globale pour l'URL de base\nlet globalBaseURL: string | null = null;\n\n// Fonction pour définir l'URL de base globalement\nexport const configureApiBaseURL = (baseURL: string): void => {\n const normalizedBaseURL = normalizeBaseURL(baseURL);\n globalBaseURL = normalizedBaseURL;\n // Mettre à jour l'instance existante si elle existe\n if (apiService) {\n apiService.updateBaseURL(normalizedBaseURL);\n }\n};\n\n// Fonction pour récupérer l'URL de base dynamiquement\nexport const getBaseURL = (): string => {\n // Priorité 1: URL configurée dynamiquement\n if (globalBaseURL) {\n return globalBaseURL;\n }\n\n // Priorité 2: Variable d'environnement du projet hôte (si disponible via window)\n if (typeof window !== \"undefined\" && window.VITE_API_BASE_URL) {\n return normalizeBaseURL(window.VITE_API_BASE_URL);\n }\n\n // Priorité 3: Variable d'environnement du SDK via wrapper\n if (API_BASE_URL) {\n return normalizeBaseURL(API_BASE_URL);\n }\n\n // Priorité 4: URL par défaut (dev2 pour développement)\n return normalizeBaseURL(\"https://dev2.datakeen.co/backend\");\n};\n\n// Types pour la configuration de l'API\nexport interface ApiConfig {\n baseURL: string;\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n headers?: Record<string, string>;\n}\n\n// Types pour les réponses\nexport interface ApiResponse<T = any> {\n data: T;\n message?: string;\n success: boolean;\n status: number;\n}\n\nexport interface ApiError {\n message: string;\n status?: number;\n code?: string;\n details?: any;\n}\n\nexport class ApiService {\n private client: AxiosInstance;\n private config: ApiConfig;\n\n constructor(config: ApiConfig) {\n this.config = config;\n\n this.client = axios.create({\n baseURL: config.baseURL,\n timeout: config.timeout || 30000,\n headers: {\n Accept: \"application/json\",\n ...config.headers,\n },\n });\n\n this.setupInterceptors();\n }\n\n private setupInterceptors(): void {\n // Intercepteur de requête\n this.client.interceptors.request.use(\n (config: InternalAxiosRequestConfig) => {\n return config;\n },\n (error: AxiosError) => {\n return Promise.reject(this.handleError(error));\n }\n );\n\n // Intercepteur de réponse pour gérer les erreurs\n this.client.interceptors.response.use(\n (response: AxiosResponse) => {\n return response;\n },\n (error: AxiosError) => {\n return Promise.reject(this.handleError(error));\n }\n );\n }\n\n private handleError(error: AxiosError): ApiError {\n let apiError: ApiError = {\n message: \"Une erreur inattendue s'est produite\",\n status: 500,\n };\n\n if (error.response) {\n // Erreur de réponse du serveur\n const { status, data } = error.response;\n apiError = {\n message: (data as any)?.message || `Erreur ${status}`,\n status,\n code: (data as any)?.code,\n details: data,\n };\n } else if (error.code === \"ECONNABORTED\") {\n // Timeout\n apiError = {\n message: \"Délai d'attente dépassé\",\n code: \"TIMEOUT_ERROR\",\n };\n } else if (error.request) {\n // Erreur réseau - Log plus de détails pour debug\n console.error(\"❌ Network error details:\", {\n message: error.message,\n code: error.code,\n config: {\n url: error.config?.url,\n method: error.config?.method,\n baseURL: error.config?.baseURL,\n timeout: error.config?.timeout,\n },\n });\n \n // Vérifier si c'est une erreur CORS\n if (error.message.includes(\"Network Error\") || error.message.includes(\"CORS\")) {\n apiError = {\n message: \"Erreur CORS ou serveur inaccessible. Vérifiez que le serveur backend est démarré et autorise les requêtes depuis votre domaine.\",\n code: \"CORS_OR_NETWORK_ERROR\",\n };\n } else {\n apiError = {\n message: \"Erreur de connexion réseau\",\n code: \"NETWORK_ERROR\",\n };\n }\n }\n\n console.error(\"❌ API Error:\", apiError);\n return apiError;\n }\n\n // Plus de retryRequest, shouldRetry, ni delay : chaque appel Axios ne sera fait qu'une seule fois\n\n // Méthodes publiques pour les requêtes HTTP\n async get<T = any>(\n url: string,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.get<T>(url, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n async post<T = any>(\n url: string,\n data?: any,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.post<T>(url, data, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n async put<T = any>(\n url: string,\n data?: any,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.put<T>(url, data, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n async patch<T = any>(\n url: string,\n data?: any,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.patch<T>(url, data, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n async delete<T = any>(\n url: string,\n config?: AxiosRequestConfig\n ): Promise<ApiResponse<T>> {\n const response = await this.client.delete<T>(url, config);\n return {\n data: response.data,\n success: true,\n status: response.status,\n };\n }\n\n // Méthodes utilitaires\n setDefaultHeader(key: string, value: string): void {\n this.client.defaults.headers.common[key] = value;\n }\n\n removeDefaultHeader(key: string): void {\n delete this.client.defaults.headers.common[key];\n }\n\n // Méthode pour créer une nouvelle instance avec une configuration différente\n createInstance(config: Partial<ApiConfig>): ApiService {\n return new ApiService({ ...this.config, ...config });\n }\n\n // Accès à l'instance Axios pour des cas spéciaux\n getRawClient(): AxiosInstance {\n return this.client;\n }\n\n // Méthode pour mettre à jour dynamiquement l'URL de base\n updateBaseURL(baseURL: string): void {\n this.config.baseURL = baseURL;\n this.client.defaults.baseURL = baseURL;\n }\n}\n\n// In test environment, mock axios to avoid real HTTP requests\nif (\n typeof process !== \"undefined\" &&\n process.env &&\n process.env.NODE_ENV === \"test\"\n) {\n // @ts-ignore\n global.axios = {\n create: () => ({\n get: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n post: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n put: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n patch: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n delete: jest.fn(() =>\n Promise.resolve({ data: {}, status: 200, success: true })\n ),\n defaults: { headers: { common: {} } },\n interceptors: {\n request: { use: jest.fn() },\n response: { use: jest.fn() },\n },\n }),\n };\n}\n\n// Factory pour créer une instance\nexport const createApiService = (config: ApiConfig): ApiService => {\n return new ApiService(config);\n};\n\n// Instance par défaut (à configurer selon vos besoins)\nexport const apiService = createApiService({\n baseURL: getBaseURL(),\n timeout: 30000,\n});\n\nexport { normalizeBaseURL };\n"],"names":["API_BASE_URL","__assign"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sources":["../../../../src/types/session.ts"],"sourcesContent":["import type React from \"react\";\n\nexport interface SessionConfig {\n selfie?: boolean;\n requireMobile?: boolean;\n}\n\nexport interface DatakeenSessionProps {\n sessionId: string;\n sessionConfig?: SessionConfig;\n apiBaseUrl?: string; // Optional API base URL for dynamic environment configuration\n}\n\nexport interface UseSessionReturn {\n SessionComponent: React.ReactElement;\n}\n\nexport type stepObject = {\n setStep: (step: number) => void;\n goBack: () => void;\n goToNextStep: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n step: number;\n canGoBack: boolean;\n};\n\nexport interface ProcessingStep {\n title: string;\n subtitle: string;\n hasError?: boolean;\n}\n\nexport type ConditionTokenType = \"variable\" | \"control\" | \"operator\" | \"input\";\n\nexport interface ConditionToken {\n type: ConditionTokenType;\n value: string;\n label?: string;\n sourceNodeId?: string;\n}\n\n/**\n * Type for custom field value types\n */\nexport type CustomFieldValueType =\n | \"text\"\n | \"enum\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"email\"\n | \"address\"\n | \"list\";\n\n/**\n * Display formats supported for date fields (top-level and list columns).\n */\nexport type DateDisplayFormat = \"dd/mm/yyyy\" | \"mm/dd/yyyy\" | \"yyyy-mm-dd\";\n\nexport const DEFAULT_DATE_DISPLAY_FORMAT: DateDisplayFormat = \"dd/mm/yyyy\";\n\n/**\n * Column definition for a list-type custom field\n */\nexport interface ListColumn {\n label: string;\n type: \"text\" | \"enum\" | \"date\" | \"email\";\n options?: string[]; // required when type === 'enum'\n placeholder?: string; // text/email/date — shown to the end user\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n}\n\n/**\n * Interface for custom field definition\n */\nexport interface CustomField {\n id: string;\n label: string;\n placeholder?: string;\n description?: string;\n valueType: CustomFieldValueType;\n enumOptions?: string[];\n listColumns?: ListColumn[]; // for list type: column definitions\n minRows?: number; // for list type: minimum rows expected\n required?: boolean;\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n lockedFromApi?: boolean;\n userInputKey?: string;\n}\n\n/**\n * Interface for session template node\n */\nexport interface SessionTemplateNode {\n id: string;\n type: string;\n title: string;\n description: string;\n informationType?:\n | \"identity\"\n | \"identity-legal\"\n | \"contact\"\n | \"address\"\n | \"nationality\"\n | \"custom\";\n position: {\n x: number;\n y: number;\n };\n options: unknown[];\n selectedOptions: string[];\n requiredDocumentType?: string;\n isRequired: boolean;\n order: number;\n optionalFields?: string[];\n requiredFields?: string[];\n pageTitle?: string;\n pageDescription?: string;\n // Properties for document-collection node type\n allowedDocumentTypes?: Array<{\n id: string;\n name: string;\n /**\n * Optional side information coming from the template.\n * When provided and equals to two (\"two\", 2, \"double\", \"recto-verso\"),\n * consumers should allow uploading two sides (front/back).\n */\n side?: string | number;\n }>;\n allowedAddingMethods?: string[];\n introductionPage?: {\n title?: string;\n description?: string;\n };\n documentSelection?: {\n title?: string;\n description?: string;\n };\n // Start node specific properties\n welcomeTitle?: string;\n welcomeSubtitle?: string;\n welcomeDescription?: string;\n welcomeImage?: string;\n qrCodeTitle?: string;\n qrCodeDescription?: string;\n showLegacyCGU?: boolean; // default: true — rétrocompatibilité\n\n // Legal consent node specific properties\n consentDescription?: string;\n consentDescription2?: string;\n cguUrl?: string;\n privacyPolicyUrl?: string;\n checkboxText?: string;\n // Identity control specific properties\n automaticPhotoCapture?: boolean;\n acceptedCountries?: AcceptedCountry[];\n // End node specific properties\n callbackURL?: string | null;\n // Condition node specific properties\n conditionExpression?: string;\n conditionTokens?: ConditionToken[];\n conditionFalseErrorMessage?: string;\n conditionMaxRetries?: number;\n conditionMaxRetryAction?: \"end-journey\" | \"force-true\";\n conditionFalseMode?: \"retry\" | \"loop\";\n\n // External verification specific properties\n targetApi?: \"INSEE\";\n referenceNodeId?: string;\n referenceNodeType?:\n | \"information-input\"\n | \"document-collection\"\n | \"identity-control\";\n referenceField?: \"siren\" | \"siret\";\n referenceVariable?: string;\n // Custom form fields (for information-input with type 'custom')\n customFields?: CustomField[];\n\n // Electronic signature specific properties\n templateId?: string;\n external_id?: string;\n fieldMappings?: Array<{\n sourceFieldId: string;\n label: string;\n docusealType: string;\n readonly: boolean;\n role?: string;\n sourceNodeId?: string;\n }>;\n /** If set, the generated PDF from this upstream pdf-generation node will be used as the document to sign */\n sourcePdfNodeId?: string;\n\n // PDF generation node specific properties\n // Note: htmlTemplate is intentionally NOT included — it is server-side only and never sent to the client\n pdfMode?: \"upload\" | \"html-template\";\n sourceNodeIds?: string[];\n\n // retry properties\n allowResubmission: boolean;\n maxResubmissionAttempts?: number;\n}\n\n/**\n * Interface for accepted countries\n */\nexport interface AcceptedCountry {\n code: string;\n documents: {\n passport: string[];\n idCard: string[];\n driverLicense: string[];\n residencePermit: string[];\n pinkDriverLicense: string[];\n };\n}\n\n/**\n * Interface for session template edge\n */\nexport interface SessionTemplateEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n conditionValue?: string;\n}\n\n/**\n * Interface for platform information\n */\nexport interface PlatformInfo {\n mobile: boolean;\n desktop: boolean;\n backoffice: boolean;\n}\n\n/**\n * Interface for session template\n */\nexport interface SessionTemplate {\n id: string;\n name: string;\n description: string;\n version: string;\n languages: string[];\n nodes: SessionTemplateNode[];\n edges: SessionTemplateEdge[];\n groupId: string;\n userId: string | null;\n created_at: string;\n updated_at: string;\n platforms?: PlatformInfo;\n logo?: string;\n showQRCode?: boolean;\n buttonBgColor?: string;\n buttonTextColor?: string;\n}\n\n/**\n * Interface for session data\n */\nexport interface SessionData {\n id: string;\n userId: string | null;\n token: string;\n templateId: string;\n templateKey: string;\n expireTime: number;\n status: string;\n result: Record<string, unknown>;\n landingPage: unknown;\n withSelfie: boolean | null;\n groupId: string | null;\n userInput: Record<string, unknown>;\n contactInfo?: {\n email: string;\n phoneNumber: string;\n };\n callbackURL?: string | null;\n webhookURL: string;\n analysisTemplateId: string | null;\n userAgent: unknown[];\n mobile: boolean;\n analysisId: string | null;\n currentStep?: number;\n createdAt: string;\n updatedAt: string;\n auditTrail: unknown[];\n user: unknown | null;\n analysis: unknown[];\n documents: unknown[];\n template: SessionTemplate;\n retryCounts?: Record<string, number>; // nodeId -> retry count\n}\n\nexport interface ClientInfo {\n ip?: string;\n location?: string;\n device: string;\n browser: string;\n os: string;\n}\n"],"names":[],"mappings":";;AA8DO,IAAM,2BAA2B,GAAsB;;;;"}
1
+ {"version":3,"file":"session.js","sources":["../../../../src/types/session.ts"],"sourcesContent":["import type React from \"react\";\n\nexport interface SessionConfig {\n selfie?: boolean;\n requireMobile?: boolean;\n}\n\nexport interface DatakeenSessionProps {\n sessionId: string;\n sessionConfig?: SessionConfig;\n apiBaseUrl?: string; // Optional API base URL for dynamic environment configuration\n}\n\nexport interface UseSessionReturn {\n SessionComponent: React.ReactElement;\n}\n\nexport type stepObject = {\n setStep: (step: number) => void;\n goBack: () => void;\n goToNextStep: (\n currentNodeId: string,\n template: SessionTemplate,\n handle?: string,\n ) => void;\n step: number;\n canGoBack: boolean;\n};\n\nexport interface ProcessingStep {\n title: string;\n subtitle: string;\n hasError?: boolean;\n}\n\nexport type ConditionTokenType = \"variable\" | \"control\" | \"operator\" | \"input\";\n\nexport interface ConditionToken {\n type: ConditionTokenType;\n value: string;\n label?: string;\n sourceNodeId?: string;\n}\n\n/**\n * Type for custom field value types\n */\nexport type CustomFieldValueType =\n | \"text\"\n | \"enum\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"email\"\n | \"address\"\n | \"list\";\n\n/**\n * Display formats supported for date fields (top-level and list columns).\n */\nexport type DateDisplayFormat = \"dd/mm/yyyy\" | \"mm/dd/yyyy\" | \"yyyy-mm-dd\";\n\nexport const DEFAULT_DATE_DISPLAY_FORMAT: DateDisplayFormat = \"dd/mm/yyyy\";\n\n/**\n * Column definition for a list-type custom field\n */\nexport interface ListColumn {\n label: string;\n type: \"text\" | \"enum\" | \"date\" | \"email\";\n options?: string[]; // required when type === 'enum'\n placeholder?: string; // text/email/date — shown to the end user\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n}\n\n/**\n * Interface for custom field definition\n */\nexport interface CustomField {\n id: string;\n label: string;\n placeholder?: string;\n description?: string;\n valueType: CustomFieldValueType;\n enumOptions?: string[];\n listColumns?: ListColumn[]; // for list type: column definitions\n minRows?: number; // for list type: minimum rows expected\n required?: boolean;\n regex?: string; // text — JS regex source (without slashes)\n regexErrorMessage?: string; // text — message displayed when regex fails\n dateFormat?: DateDisplayFormat; // date — display format expected\n lockedFromApi?: boolean;\n userInputKey?: string;\n}\n\n/**\n * Interface for session template node\n */\nexport interface SessionTemplateNode {\n id: string;\n type: string;\n title: string;\n description: string;\n informationType?:\n | \"identity\"\n | \"identity-legal\"\n | \"contact\"\n | \"address\"\n | \"nationality\"\n | \"custom\";\n position: {\n x: number;\n y: number;\n };\n options: unknown[];\n selectedOptions: string[];\n requiredDocumentType?: string;\n isRequired: boolean;\n order: number;\n optionalFields?: string[];\n requiredFields?: string[];\n pageTitle?: string;\n pageDescription?: string;\n // Properties for document-collection node type\n allowedDocumentTypes?: Array<{\n id: string;\n name: string;\n /**\n * Optional side information coming from the template.\n * When provided and equals to two (\"two\", 2, \"double\", \"recto-verso\"),\n * consumers should allow uploading two sides (front/back).\n */\n side?: string | number;\n }>;\n allowedAddingMethods?: string[];\n introductionPage?: {\n title?: string;\n description?: string;\n };\n documentSelection?: {\n title?: string;\n description?: string;\n };\n // Start node specific properties\n welcomeTitle?: string;\n welcomeSubtitle?: string;\n welcomeDescription?: string;\n welcomeImage?: string;\n qrCodeTitle?: string;\n qrCodeDescription?: string;\n showLegacyCGU?: boolean; // default: true — rétrocompatibilité\n\n // Legal consent node specific properties\n consentDescription?: string;\n consentDescription2?: string;\n cguUrl?: string;\n privacyPolicyUrl?: string;\n checkboxText?: string;\n // Identity control specific properties\n automaticPhotoCapture?: boolean;\n nfcEnabled?: boolean;\n nfcMode?: \"nfcOnly\" | \"nfcAndApi\";\n acceptedCountries?: AcceptedCountry[];\n // End node specific properties\n callbackURL?: string | null;\n // Condition node specific properties\n conditionExpression?: string;\n conditionTokens?: ConditionToken[];\n conditionFalseErrorMessage?: string;\n conditionMaxRetries?: number;\n conditionMaxRetryAction?: \"end-journey\" | \"force-true\";\n conditionFalseMode?: \"retry\" | \"loop\";\n\n // External verification specific properties\n targetApi?: \"INSEE\";\n referenceNodeId?: string;\n referenceNodeType?:\n | \"information-input\"\n | \"document-collection\"\n | \"identity-control\";\n referenceField?: \"siren\" | \"siret\";\n referenceVariable?: string;\n // Custom form fields (for information-input with type 'custom')\n customFields?: CustomField[];\n\n // Electronic signature specific properties\n templateId?: string;\n external_id?: string;\n fieldMappings?: Array<{\n sourceFieldId: string;\n label: string;\n docusealType: string;\n readonly: boolean;\n role?: string;\n sourceNodeId?: string;\n }>;\n /** If set, the generated PDF from this upstream pdf-generation node will be used as the document to sign */\n sourcePdfNodeId?: string;\n\n // PDF generation node specific properties\n // Note: htmlTemplate is intentionally NOT included — it is server-side only and never sent to the client\n pdfMode?: \"upload\" | \"html-template\";\n sourceNodeIds?: string[];\n\n // retry properties\n allowResubmission: boolean;\n maxResubmissionAttempts?: number;\n}\n\n/**\n * Interface for accepted countries\n */\nexport interface AcceptedCountry {\n code: string;\n documents: {\n passport: string[];\n idCard: string[];\n driverLicense: string[];\n residencePermit: string[];\n pinkDriverLicense: string[];\n };\n}\n\n/**\n * Interface for session template edge\n */\nexport interface SessionTemplateEdge {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n conditionValue?: string;\n}\n\n/**\n * Interface for platform information\n */\nexport interface PlatformInfo {\n mobile: boolean;\n desktop: boolean;\n backoffice: boolean;\n}\n\n/**\n * Interface for session template\n */\nexport interface SessionTemplate {\n id: string;\n name: string;\n description: string;\n version: string;\n languages: string[];\n nodes: SessionTemplateNode[];\n edges: SessionTemplateEdge[];\n groupId: string;\n userId: string | null;\n created_at: string;\n updated_at: string;\n platforms?: PlatformInfo;\n logo?: string;\n showQRCode?: boolean;\n buttonBgColor?: string;\n buttonTextColor?: string;\n}\n\n/**\n * Interface for session data\n */\nexport interface SessionData {\n id: string;\n userId: string | null;\n token: string;\n templateId: string;\n templateKey: string;\n expireTime: number;\n status: string;\n result: Record<string, unknown>;\n landingPage: unknown;\n withSelfie: boolean | null;\n groupId: string | null;\n userInput: Record<string, unknown>;\n contactInfo?: {\n email: string;\n phoneNumber: string;\n };\n callbackURL?: string | null;\n webhookURL: string;\n analysisTemplateId: string | null;\n userAgent: unknown[];\n mobile: boolean;\n analysisId: string | null;\n currentStep?: number;\n createdAt: string;\n updatedAt: string;\n auditTrail: unknown[];\n user: unknown | null;\n analysis: unknown[];\n documents: unknown[];\n template: SessionTemplate;\n retryCounts?: Record<string, number>; // nodeId -> retry count\n}\n\nexport interface ClientInfo {\n ip?: string;\n location?: string;\n device: string;\n browser: string;\n os: string;\n}\n"],"names":[],"mappings":";;AA8DO,IAAM,2BAA2B,GAAsB;;;;"}
@@ -0,0 +1,85 @@
1
+ import { __awaiter, __generator } from '../../node_modules/tslib/tslib.es6.js';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { useRef, useState, useMemo, useEffect } from 'react';
4
+ import QRCode from 'qrcode';
5
+ import { useI18n } from '../../hooks/useI18n.js';
6
+ import { useNfcSseStatus } from '../../hooks/useNfcSseStatus.js';
7
+ import { getBaseURL } from '../../services/api.js';
8
+ import MobilePageLayout from '../ui/MobilePageLayout.js';
9
+ import Title from '../ui/Title.js';
10
+ import Subtitle from '../ui/Subtitle.js';
11
+ import NfcSuccessAnimation from './NfcSuccessAnimation.js';
12
+
13
+ var NfcScanStep = function (_a) {
14
+ var sessionId = _a.sessionId, nodeId = _a.nodeId, stepObject = _a.stepObject, template = _a.template, pageTitle = _a.pageTitle, pageDescription = _a.pageDescription;
15
+ var t = useI18n().t;
16
+ var canvasRef = useRef(null);
17
+ var _b = useState(null), qrError = _b[0], setQrError = _b[1];
18
+ var nfcUrl = useMemo(function () {
19
+ var origin = typeof window !== "undefined" ? window.location.origin : "";
20
+ return "".concat(origin, "/scan/").concat(sessionId);
21
+ }, [sessionId]);
22
+ var apiBaseUrl = useMemo(function () { return getBaseURL(); }, []);
23
+ var status = useNfcSseStatus({
24
+ sessionId: sessionId,
25
+ apiBaseUrl: apiBaseUrl,
26
+ onCompleted: function () {
27
+ if (template) {
28
+ stepObject.goToNextStep(nodeId, template);
29
+ }
30
+ else {
31
+ stepObject.setStep(stepObject.step + 1);
32
+ }
33
+ },
34
+ }).status;
35
+ var title = pageTitle || t("nfc_scan.page_title", "Scan NFC de votre document");
36
+ var subtitle = pageDescription ||
37
+ t("nfc_scan.page_description", "Scannez le QR code ci-dessous avec votre iPhone pour lire la puce NFC de votre document d'identité.");
38
+ useEffect(function () {
39
+ if (status !== "pending")
40
+ return;
41
+ var generate = function () { return __awaiter(void 0, void 0, void 0, function () {
42
+ var dataUrl, canvas_1, ctx_1, img_1;
43
+ return __generator(this, function (_b) {
44
+ switch (_b.label) {
45
+ case 0:
46
+ if (!canvasRef.current)
47
+ return [2 /*return*/];
48
+ setQrError(null);
49
+ _b.label = 1;
50
+ case 1:
51
+ _b.trys.push([1, 3, , 4]);
52
+ return [4 /*yield*/, QRCode.toDataURL(nfcUrl, {
53
+ width: 256,
54
+ margin: 2,
55
+ color: { dark: "#000000", light: "#FFFFFF" },
56
+ })];
57
+ case 2:
58
+ dataUrl = _b.sent();
59
+ canvas_1 = canvasRef.current;
60
+ ctx_1 = canvas_1.getContext("2d");
61
+ if (ctx_1) {
62
+ img_1 = new Image();
63
+ img_1.onload = function () {
64
+ canvas_1.width = img_1.width;
65
+ canvas_1.height = img_1.height;
66
+ ctx_1.drawImage(img_1, 0, 0);
67
+ };
68
+ img_1.src = dataUrl;
69
+ }
70
+ return [3 /*break*/, 4];
71
+ case 3:
72
+ _b.sent();
73
+ setQrError(t("qr_code.generation_failed", "Erreur de génération du QR code"));
74
+ return [3 /*break*/, 4];
75
+ case 4: return [2 /*return*/];
76
+ }
77
+ });
78
+ }); };
79
+ generate();
80
+ }, [nfcUrl, status, t]);
81
+ return (jsx(MobilePageLayout, { footer: null, 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 === "opened" ? (jsxs("div", { className: "w-full max-w-sm rounded-2xl border border-emerald-200 bg-emerald-50 p-6 text-center shadow-sm", children: [jsx("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", children: jsx("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", className: "h-7 w-7", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M20 6 9 17l-5-5" }) }) }), jsx("p", { className: "text-base font-semibold text-gray-900", children: t("nfc_scan.qr_opened_title", "QR code scanné") }), jsx("p", { className: "mt-2 text-sm leading-relaxed text-gray-600", children: t("nfc_scan.qr_opened_description", "L'expérience NFC est ouverte sur l'iPhone. Continuez le scan sur le téléphone.") }), jsxs("div", { className: "mt-5 flex items-center justify-center gap-2 text-xs font-medium text-emerald-700", children: [jsx("span", { className: "h-2 w-2 animate-pulse rounded-full bg-emerald-500" }), t("nfc_scan.waiting_completion", "En attente de la lecture NFC")] })] })) : qrError ? (jsx("div", { className: "text-red-500 text-center p-4", children: qrError })) : (jsx("div", { className: "bg-white p-4 rounded-lg shadow-lg border-2 border-gray-200", children: jsx("canvas", { ref: canvasRef }) })) })] }) }) }));
82
+ };
83
+
84
+ export { NfcScanStep as default };
85
+ //# sourceMappingURL=NfcScanNode.js.map
@@ -0,0 +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 MobilePageLayout from \"../ui/MobilePageLayout\";\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}\n\nconst NfcScanStep: React.FC<NfcScanStepProps> = ({\n sessionId,\n nodeId,\n stepObject,\n template,\n pageTitle,\n pageDescription,\n}) => {\n const { t } = useI18n();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const [qrError, setQrError] = useState<string | null>(null);\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 iPhone pour lire la puce NFC de votre document d'identité.\"\n );\n\n useEffect(() => {\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]);\n\n return (\n <MobilePageLayout footer={null}>\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 l'iPhone. Continuez le scan sur le 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 ) : (\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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"}
@@ -0,0 +1,36 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import { useI18n } from '../../hooks/useI18n.js';
4
+
5
+ var NfcSuccessAnimation = function () {
6
+ var t = useI18n().t;
7
+ var _a = useState(false), visible = _a[0], setVisible = _a[1];
8
+ useEffect(function () {
9
+ // Déclenche l'animation au prochain frame pour permettre la transition CSS
10
+ var id = requestAnimationFrame(function () { return setVisible(true); });
11
+ return function () { return cancelAnimationFrame(id); };
12
+ }, []);
13
+ return (jsxs("div", { className: "flex flex-col items-center gap-6 p-8", style: {
14
+ opacity: visible ? 1 : 0,
15
+ transform: visible ? "scale(1)" : "scale(0.85)",
16
+ transition: "opacity 0.4s ease, transform 0.4s ease",
17
+ }, children: [jsxs("div", { style: { position: "relative", width: 72, height: 72, flexShrink: 0 }, children: [jsx("div", { style: {
18
+ position: "absolute",
19
+ inset: 0,
20
+ borderRadius: "50%",
21
+ backgroundColor: "var(--uni-primary-color, #11e5c5)",
22
+ transformOrigin: "center center",
23
+ animation: "nfc-pulse 1.6s ease-out infinite",
24
+ pointerEvents: "none",
25
+ } }), jsxs("svg", { width: 72, height: 72, viewBox: "0 0 72 72", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [jsx("circle", { cx: 36, cy: 36, r: 34, fill: "var(--uni-primary-color, #11e5c5)", style: {
26
+ opacity: visible ? 1 : 0,
27
+ transition: "opacity 0.3s ease 0.1s",
28
+ } }), jsx("polyline", { points: "20,37 30,47 52,25", stroke: "#ffffff", strokeWidth: 5, strokeLinecap: "round", strokeLinejoin: "round", fill: "none", style: {
29
+ strokeDasharray: 50,
30
+ strokeDashoffset: visible ? 0 : 50,
31
+ transition: "stroke-dashoffset 0.45s cubic-bezier(0.4, 0, 0.2, 1) 0.35s",
32
+ } })] })] }), jsxs("div", { className: "text-center space-y-1", children: [jsx("p", { className: "font-semibold text-base", style: { color: "var(--uni-secondary-color, #0a9983)" }, children: t("nfc_scan.success_title", "Documents validés") }), jsx("p", { className: "text-sm text-gray-500", children: t("nfc_scan.success_subtitle", "Lecture NFC confirmée avec succès") })] }), jsx("style", { children: "\n @keyframes nfc-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 " })] }));
33
+ };
34
+
35
+ export { NfcSuccessAnimation as default };
36
+ //# sourceMappingURL=NfcSuccessAnimation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NfcSuccessAnimation.js","sources":["../../../../../src/components/nfc-scan/NfcSuccessAnimation.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { useI18n } from \"../../hooks/useI18n\";\n\nconst NfcSuccessAnimation: React.FC = () => {\n const { t } = useI18n();\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n // Déclenche l'animation au prochain frame pour permettre la transition CSS\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 {/* Halo pulsant en arrière-plan */}\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: \"nfc-pulse 1.6s ease-out infinite\",\n pointerEvents: \"none\",\n }}\n />\n\n {/* Cercle + check SVG animé */}\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 {/* Cercle de fond rempli */}\n <circle\n cx={36}\n cy={36}\n r={34}\n fill=\"var(--uni-primary-color, #11e5c5)\"\n style={{\n opacity: visible ? 1 : 0,\n transition: \"opacity 0.3s ease 0.1s\",\n }}\n />\n {/* Trait du check — strokeDashoffset animé */}\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(\"nfc_scan.success_title\", \"Documents validés\")}\n </p>\n <p className=\"text-sm text-gray-500\">\n {t(\"nfc_scan.success_subtitle\", \"Lecture NFC confirmée avec succès\")}\n </p>\n </div>\n\n <style>{`\n @keyframes nfc-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 NfcSuccessAnimation;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
@@ -26,8 +26,15 @@ import { getAllDocumentTemplates, getDocumentTemplateId, getDocTypeKey } from '.
26
26
  import { blobToDataUrl, dataUrlToBlob, resizeAfterCapture } from '../../utils/imageProcessing.js';
27
27
  import { getNodeRetryCount, incrementNodeRetryCount } from '../../services/retryService.js';
28
28
  import { getSession } from '../../context/SessionContext.js';
29
+ import { updateSessionUserInput } from '../../services/sessionService.js';
30
+ import NfcScanStep from '../nfc-scan/NfcScanNode.js';
29
31
  import { EUROPEAN_COUNTRY_CODES } from '../../utils/europeanCountries.js';
30
32
 
33
+ var NFC_ELIGIBLE_DOCUMENT_TYPES = new Set([
34
+ "passport",
35
+ "idCard",
36
+ "residencePermit",
37
+ ]);
31
38
  /**
32
39
  * DocumentCheck component manages the multi-step document verification flow for a session.
33
40
  * It handles country and document type selection, document upload or photo capture, processing, and error/success handling.
@@ -106,10 +113,11 @@ var DocumentCheck = function (_a) {
106
113
  var _t = useState(null), fileUploaded = _t[0], setFileUploaded = _t[1];
107
114
  var _u = useState(null), analysisData = _u[0], setAnalysisData = _u[1];
108
115
  var _v = useState(null), errorCode = _v[0], setErrorCode = _v[1];
116
+ var _w = useState(null), nfcPreparationError = _w[0], setNfcPreparationError = _w[1];
109
117
  // Initialize retry count from session data
110
- var _w = useState(function () {
118
+ var _x = useState(function () {
111
119
  return getNodeRetryCount(session, node.id);
112
- }), retryCount = _w[0], setRetryCount = _w[1];
120
+ }), retryCount = _x[0], setRetryCount = _x[1];
113
121
  // Update retry count when session loads/changes
114
122
  useEffect(function () {
115
123
  if (session) {
@@ -149,10 +157,10 @@ var DocumentCheck = function (_a) {
149
157
  setDocStep(6);
150
158
  }
151
159
  }, [retryCount, node.allowResubmission, node.maxResubmissionAttempts]);
152
- var _x = useState({}), capturedImages = _x[0], setCapturedImages = _x[1];
153
- var _y = useState("before-recto"), currentPhotoStep = _y[0], setCurrentPhotoStep = _y[1];
154
- var _z = useState("photo"), videoFlowPhase = _z[0], setVideoFlowPhase = _z[1];
155
- var _0 = useDocumentContext(), selectedDocumentType = _0.selectedDocumentType, setSelectedDocumentType = _0.setSelectedDocumentType;
160
+ var _y = useState({}), capturedImages = _y[0], setCapturedImages = _y[1];
161
+ var _z = useState("before-recto"), currentPhotoStep = _z[0], setCurrentPhotoStep = _z[1];
162
+ var _0 = useState("photo"), videoFlowPhase = _0[0], setVideoFlowPhase = _0[1];
163
+ var _1 = useDocumentContext(), selectedDocumentType = _1.selectedDocumentType, setSelectedDocumentType = _1.setSelectedDocumentType;
156
164
  var finalAcceptedCountries = useMemo(function () {
157
165
  if (loadingTemplates)
158
166
  return acceptedCountries;
@@ -248,6 +256,7 @@ var DocumentCheck = function (_a) {
248
256
  setFileUploaded(null);
249
257
  setAnalysisData(null);
250
258
  setErrorCode(null);
259
+ setNfcPreparationError(null);
251
260
  // Reset retry count to 0 (will be synced to session)
252
261
  setRetryCount(0);
253
262
  setCapturedImages({});
@@ -333,35 +342,66 @@ var DocumentCheck = function (_a) {
333
342
  }
334
343
  handleProcessingComplete(success, undefined, analysisData);
335
344
  };
336
- var handleDocumentTypeSelect = function (documentId) {
337
- var documentLabel = t("documentTypes.".concat(documentId), documentId);
338
- logDocumentTypeSelected(sessionId, documentId, documentLabel);
339
- var documentTemplateID = loadingTemplates
340
- ? undefined
341
- : getDocumentTemplateId({
342
- acceptedCountries: finalAcceptedCountries,
343
- countryCode: selectedCountry,
344
- documentId: documentId,
345
- documentTemplates: documentTemplates,
346
- });
347
- // Find the selected document details
348
- var selectedDoc = {
349
- id: documentId,
350
- label: t("documentTypes.".concat(documentId)),
351
- hasTwoSides: documentId !== "passport" && documentId !== "pinkDriverLicense",
352
- documentTemplateId: documentTemplateID,
353
- };
354
- setSelectedDocumentType(selectedDoc);
355
- setFileUploaded(null);
356
- setAnalysisData(null);
357
- setErrorCode(null);
358
- // Don't reset retry count when selecting document type
359
- // Keep existing retry count for this node
360
- setCapturedImages({});
361
- setCurrentPhotoStep("before-recto");
362
- setVideoFlowPhase("photo");
363
- setDocStep(3);
364
- };
345
+ var handleDocumentTypeSelect = function (documentId) { return __awaiter(void 0, void 0, void 0, function () {
346
+ var documentLabel, documentTemplateID, selectedDoc, selectedCountryCode, selectedDocumentInput, nfcMode, error_2;
347
+ var _a;
348
+ return __generator(this, function (_b) {
349
+ switch (_b.label) {
350
+ case 0:
351
+ documentLabel = t("documentTypes.".concat(documentId), documentId);
352
+ logDocumentTypeSelected(sessionId, documentId, documentLabel);
353
+ documentTemplateID = loadingTemplates
354
+ ? undefined
355
+ : getDocumentTemplateId({
356
+ acceptedCountries: finalAcceptedCountries,
357
+ countryCode: selectedCountry,
358
+ documentId: documentId,
359
+ documentTemplates: documentTemplates,
360
+ });
361
+ selectedDoc = {
362
+ id: documentId,
363
+ label: t("documentTypes.".concat(documentId)),
364
+ hasTwoSides: documentId !== "passport" && documentId !== "pinkDriverLicense",
365
+ documentTemplateId: documentTemplateID,
366
+ };
367
+ selectedCountryCode = selectedCountry.toUpperCase();
368
+ selectedDocumentInput = {
369
+ countryCode: selectedCountryCode,
370
+ identityDocumentType: documentId,
371
+ identityDocumentTemplateId: documentTemplateID,
372
+ };
373
+ setSelectedDocumentType(selectedDoc);
374
+ setUserInput(function (prev) { return (__assign(__assign({}, prev), selectedDocumentInput)); });
375
+ setFileUploaded(null);
376
+ setAnalysisData(null);
377
+ setErrorCode(null);
378
+ setNfcPreparationError(null);
379
+ setCapturedImages({});
380
+ setCurrentPhotoStep("before-recto");
381
+ setVideoFlowPhase("photo");
382
+ if (!(node.nfcEnabled === true && NFC_ELIGIBLE_DOCUMENT_TYPES.has(documentId))) return [3 /*break*/, 5];
383
+ nfcMode = (_a = node.nfcMode) !== null && _a !== void 0 ? _a : "nfcOnly";
384
+ _b.label = 1;
385
+ case 1:
386
+ _b.trys.push([1, 3, , 4]);
387
+ return [4 /*yield*/, updateSessionUserInput(sessionId, selectedDocumentInput)];
388
+ case 2:
389
+ _b.sent();
390
+ return [3 /*break*/, 4];
391
+ case 3:
392
+ error_2 = _b.sent();
393
+ console.error("Failed to persist NFC document selection:", error_2);
394
+ setNfcPreparationError(t("nfc_scan.preparation_failed", "Impossible de préparer le scan NFC. Veuillez réessayer."));
395
+ return [3 /*break*/, 4];
396
+ case 4:
397
+ setDocStep(nfcMode === "nfcAndApi" ? 3 : 7);
398
+ return [2 /*return*/];
399
+ case 5:
400
+ setDocStep(3);
401
+ return [2 /*return*/];
402
+ }
403
+ });
404
+ }); };
365
405
  var handleDocumentUpload = function (files) {
366
406
  logDocumentLoaded(sessionId, "recto");
367
407
  if (files.back) {
@@ -380,6 +420,7 @@ var DocumentCheck = function (_a) {
380
420
  }
381
421
  };
382
422
  var handleProcessingComplete = function (success, _retryCount, apiAnalysisData) {
423
+ var _a;
383
424
  if (apiAnalysisData) {
384
425
  setAnalysisData(apiAnalysisData);
385
426
  // Extract and store the error code
@@ -389,6 +430,14 @@ var DocumentCheck = function (_a) {
389
430
  }
390
431
  }
391
432
  if (success) {
433
+ var shouldRunNfcAfterApi = node.nfcEnabled === true &&
434
+ ((_a = node.nfcMode) !== null && _a !== void 0 ? _a : "nfcOnly") === "nfcAndApi" &&
435
+ !!(selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.id) &&
436
+ NFC_ELIGIBLE_DOCUMENT_TYPES.has(selectedDocumentType.id);
437
+ if (shouldRunNfcAfterApi) {
438
+ setDocStep(7);
439
+ return;
440
+ }
392
441
  // Increment currentStep in database immediately after successful analysis
393
442
  // This prevents double analysis if the user refreshes the page
394
443
  if (template) {
@@ -554,6 +603,11 @@ var DocumentCheck = function (_a) {
554
603
  return (jsx(JDISuccess, { documentType: (selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.id) || documentTypeId, onContinue: handleSuccessContinue, errorCode: errorCode || undefined }));
555
604
  case 6:
556
605
  return (jsx(JDIError, { documentType: (selectedDocumentType === null || selectedDocumentType === void 0 ? void 0 : selectedDocumentType.id) || documentTypeId, onRetry: handleRetryFromError, onContinueAnyway: handleContinueAnyway, retryCount: retryCount, predictions: analysisData || undefined, errorCode: errorCode || undefined, allowResubmission: node.allowResubmission, maxResubmissionAttempts: node.maxResubmissionAttempts, isRetryAllowed: isRetryAllowed() }));
606
+ case 7:
607
+ if (nfcPreparationError) {
608
+ return (jsx(MobilePageLayout, { footer: jsx("div", { className: "w-full max-w-md mx-auto", children: jsx(ButtonDesktop, { type: "back", onClick: function () { return setDocStep(2); }, className: "w-full text-[#3C3C40] text-center font-poppins text-sm font-medium hover:underline py-2", children: t("buttons.back", "Retour") }) }), children: 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("nfc_scan.preparation_error_title", "Erreur de préparation NFC") }), jsx("p", { className: "text-gray-600 mb-4", children: nfcPreparationError })] }) }));
609
+ }
610
+ return (jsx(NfcScanStep, { sessionId: sessionId, nodeId: node.id, stepObject: stepObject, template: template }));
557
611
  default:
558
612
  console.error("Invalid docStep: ".concat(docStep));
559
613
  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.navigation_error.title", "Erreur de navigation") }), jsx("p", { className: "text-gray-600 mb-4", children: t("document_check.navigation_error.description", "Étape non valide. Veuillez recommencer.") }), jsx(ButtonDesktop, { className: "px-4 py-2 bg-primary text-white rounded hover:bg-primary-dark transition-colors", type: "back", onClick: function () { return setDocStep(0); }, children: t("document_check.navigation_error.back", "Retour au début") })] }));