datakeen-session-react 1.1.192 → 1.1.194-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.gitlab-ci.yml +9 -3
  2. package/dist/cjs/components/document-collection/DocumentProcessing.js +18 -2
  3. package/dist/cjs/components/document-collection/DocumentProcessing.js.map +1 -1
  4. package/dist/cjs/components/id-check/BeforePhoto.js +1 -1
  5. package/dist/cjs/components/id-check/BeforePhoto.js.map +1 -1
  6. package/dist/cjs/components/id-check/CameraMask.js +8 -6
  7. package/dist/cjs/components/id-check/CameraMask.js.map +1 -1
  8. package/dist/cjs/components/id-check/Photo.js +28 -8
  9. package/dist/cjs/components/id-check/Photo.js.map +1 -1
  10. package/dist/cjs/components/jdi/JDIProcessing.js +17 -2
  11. package/dist/cjs/components/jdi/JDIProcessing.js.map +1 -1
  12. package/dist/cjs/i18n/en.json.js +16 -14
  13. package/dist/cjs/i18n/en.json.js.map +1 -1
  14. package/dist/cjs/i18n/es.json.js +1208 -0
  15. package/dist/cjs/i18n/es.json.js.map +1 -0
  16. package/dist/cjs/i18n/fr.json.js +8 -6
  17. package/dist/cjs/i18n/fr.json.js.map +1 -1
  18. package/dist/cjs/i18n/index.js +5 -1
  19. package/dist/cjs/i18n/index.js.map +1 -1
  20. package/dist/cjs/index.css.js +1 -1
  21. package/dist/cjs/types/session.js.map +1 -1
  22. package/dist/cjs/utils/analysisErrors.js +18 -0
  23. package/dist/cjs/utils/analysisErrors.js.map +1 -1
  24. package/dist/cjs/utils/languageFlags.js +6 -0
  25. package/dist/cjs/utils/languageFlags.js.map +1 -1
  26. package/dist/esm/components/document-collection/DocumentProcessing.js +19 -3
  27. package/dist/esm/components/document-collection/DocumentProcessing.js.map +1 -1
  28. package/dist/esm/components/id-check/BeforePhoto.js +1 -1
  29. package/dist/esm/components/id-check/BeforePhoto.js.map +1 -1
  30. package/dist/esm/components/id-check/CameraMask.js +8 -6
  31. package/dist/esm/components/id-check/CameraMask.js.map +1 -1
  32. package/dist/esm/components/id-check/Photo.js +28 -8
  33. package/dist/esm/components/id-check/Photo.js.map +1 -1
  34. package/dist/esm/components/jdi/JDIProcessing.js +18 -3
  35. package/dist/esm/components/jdi/JDIProcessing.js.map +1 -1
  36. package/dist/esm/i18n/en.json.js +16 -14
  37. package/dist/esm/i18n/en.json.js.map +1 -1
  38. package/dist/esm/i18n/es.json.js +1167 -0
  39. package/dist/esm/i18n/es.json.js.map +1 -0
  40. package/dist/esm/i18n/fr.json.js +8 -6
  41. package/dist/esm/i18n/fr.json.js.map +1 -1
  42. package/dist/esm/i18n/index.js +5 -1
  43. package/dist/esm/i18n/index.js.map +1 -1
  44. package/dist/esm/index.css.js +1 -1
  45. package/dist/esm/types/session.js.map +1 -1
  46. package/dist/esm/utils/analysisErrors.js +17 -1
  47. package/dist/esm/utils/analysisErrors.js.map +1 -1
  48. package/dist/esm/utils/languageFlags.js +6 -0
  49. package/dist/esm/utils/languageFlags.js.map +1 -1
  50. package/docs/JOURNEY_NODE_BUILDER.md +10 -0
  51. package/package.json +1 -1
package/.gitlab-ci.yml CHANGED
@@ -132,9 +132,11 @@ publish:main:
132
132
  - git config user.email "ci@datakeen.io"
133
133
  - git config user.name "Datakeen CI"
134
134
  - git remote set-url origin https://${CI_PUSH_USER}:${CI_PUSH_TOKEN}@gitlab.datakeen.co/datakeenteam/teamfullstack/client-sessions-react-sdk.git
135
+ - git fetch origin "$CI_COMMIT_BRANCH"
136
+ - git checkout -B "$CI_COMMIT_BRANCH" "origin/$CI_COMMIT_BRANCH"
135
137
  - 'npm version patch -m "chore(release): %s"'
136
138
  - export TARGET_TAG="v$(node -p "require('./package.json').version")"
137
- - git push -o ci.skip origin HEAD:main
139
+ - git push -o ci.skip origin "$CI_COMMIT_BRANCH"
138
140
  - git push -o ci.skip origin --tags
139
141
  - git remote add relay "https://oauth2:${RELAY_API_TOKEN}@gitlab.com/datakeen-ci-relay/npm-publish-relay.git" 2>/dev/null || git remote set-url relay "https://oauth2:${RELAY_API_TOKEN}@gitlab.com/datakeen-ci-relay/npm-publish-relay.git"
140
142
  - git checkout --orphan "relay-snapshot-${CI_JOB_ID}"
@@ -185,9 +187,11 @@ publish:staging:
185
187
  - git config user.email "ci@datakeen.io"
186
188
  - git config user.name "Datakeen CI"
187
189
  - git remote set-url origin https://${CI_PUSH_USER}:${CI_PUSH_TOKEN}@gitlab.datakeen.co/datakeenteam/teamfullstack/client-sessions-react-sdk.git
190
+ - git fetch origin "$CI_COMMIT_BRANCH"
191
+ - git checkout -B "$CI_COMMIT_BRANCH" "origin/$CI_COMMIT_BRANCH"
188
192
  - 'npm version prerelease --preid=rc -m "chore(release): %s"'
189
193
  - export TARGET_TAG="v$(node -p "require('./package.json').version")"
190
- - git push -o ci.skip origin HEAD:staging
194
+ - git push -o ci.skip origin "$CI_COMMIT_BRANCH"
191
195
  - git push -o ci.skip origin --tags
192
196
  - git remote add relay "https://oauth2:${RELAY_API_TOKEN}@gitlab.com/datakeen-ci-relay/npm-publish-relay.git" 2>/dev/null || git remote set-url relay "https://oauth2:${RELAY_API_TOKEN}@gitlab.com/datakeen-ci-relay/npm-publish-relay.git"
193
197
  - git checkout --orphan "relay-snapshot-${CI_JOB_ID}"
@@ -238,9 +242,11 @@ publish:dev:
238
242
  - git config user.email "ci@datakeen.io"
239
243
  - git config user.name "Datakeen CI"
240
244
  - git remote set-url origin https://${CI_PUSH_USER}:${CI_PUSH_TOKEN}@gitlab.datakeen.co/datakeenteam/teamfullstack/client-sessions-react-sdk.git
245
+ - git fetch origin "$CI_COMMIT_BRANCH"
246
+ - git checkout -B "$CI_COMMIT_BRANCH" "origin/$CI_COMMIT_BRANCH"
241
247
  - 'npm version prerelease --preid=dev -m "chore(release): %s"'
242
248
  - export TARGET_TAG="v$(node -p "require('./package.json').version")"
243
- - git push -o ci.skip origin HEAD:dev
249
+ - git push -o ci.skip origin "$CI_COMMIT_BRANCH"
244
250
  - git push -o ci.skip origin --tags
245
251
  - git remote add relay "https://oauth2:${RELAY_API_TOKEN}@gitlab.com/datakeen-ci-relay/npm-publish-relay.git" 2>/dev/null || git remote set-url relay "https://oauth2:${RELAY_API_TOKEN}@gitlab.com/datakeen-ci-relay/npm-publish-relay.git"
246
252
  - git checkout --orphan "relay-snapshot-${CI_JOB_ID}"
@@ -135,7 +135,7 @@ var DocumentProcessing = React.memo(function (_a) {
135
135
  return;
136
136
  }
137
137
  var processFiles = function () { return tslib_es6.__awaiter(void 0, void 0, void 0, function () {
138
- var _loop_1, i, error_1, isUploadNotConfirmed;
138
+ var _loop_1, i, error_1, isUploadNotConfirmed, isQuotaExceeded, apiError;
139
139
  return tslib_es6.__generator(this, function (_a) {
140
140
  switch (_a.label) {
141
141
  case 0:
@@ -213,10 +213,26 @@ var DocumentProcessing = React.memo(function (_a) {
213
213
  });
214
214
  });
215
215
  isUploadNotConfirmed = analysisErrors.isS3UploadNotConfirmedError(error_1);
216
+ isQuotaExceeded = analysisErrors.isQuotaExceededError(error_1);
217
+ apiError = error_1;
216
218
  setAnalysisResult({
217
219
  success: false,
218
220
  data: null,
219
- canRetry: isUploadNotConfirmed,
221
+ // Propage le code/message QUOTA_EXCEEDED pour que DocumentError
222
+ // puisse afficher un message dédié via `user_guidance.<code>` au
223
+ // lieu de rester muet sur la cause (limité au cas quota : les
224
+ // autres erreurs gardent leur comportement existant).
225
+ predictions: isQuotaExceeded
226
+ ? [
227
+ {
228
+ code: analysisErrors.QUOTA_EXCEEDED_CODE,
229
+ codeName: analysisErrors.QUOTA_EXCEEDED_CODE,
230
+ codeDescription: (apiError === null || apiError === void 0 ? void 0 : apiError.message) || "",
231
+ type: "document",
232
+ },
233
+ ]
234
+ : undefined,
235
+ canRetry: isUploadNotConfirmed || isQuotaExceeded,
220
236
  blockContinue: isUploadNotConfirmed,
221
237
  });
222
238
  setIsComplete(true);
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentProcessing.js","sources":["../../../../../src/components/document-collection/DocumentProcessing.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useMemo, useCallback, memo } from \"react\";\nimport Title from \"../ui/Title\";\nimport Subtitle from \"../ui/Subtitle\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport {\n analyzeFiles,\n type AnalyzeFilesOptions,\n} from \"../../services/analysis\";\nimport { getActiveSessionId } from \"../../services/sessionMemoryStore\";\nimport type { onUploadFiles } from \"../../types/uploadFiles\";\nimport type {\n DocumentProcessingProps,\n ProcessingStep,\n ProcessingResult,\n} from \"./types\";\nimport type { Prediction } from \"../../utils/apiAnalysis\";\nimport { isS3UploadNotConfirmedError } from \"../../utils/analysisErrors\";\n\n// Localized processing steps generator\nconst getProcessingSteps = (t: any): ProcessingStep[] => [\n {\n title: t(\n \"processing.steps.document_reception.title\",\n \"Réception du document\",\n ),\n subtitle: t(\n \"processing.steps.document_reception.subtitle\",\n \"Téléchargement et vérification du format\",\n ),\n hasError: false,\n },\n {\n title: t(\n \"processing.steps.quality_analysis.title\",\n \"Analyse de la qualité\",\n ),\n subtitle: t(\n \"processing.steps.quality_analysis.subtitle\",\n \"Contrôle de la netteté et de l'éclairage\",\n ),\n hasError: false,\n },\n {\n title: t(\n \"processing.steps.data_extraction.title\",\n \"Extraction des données\",\n ),\n subtitle: t(\n \"processing.steps.data_extraction.subtitle\",\n \"Lecture des informations du document\",\n ),\n hasError: false,\n },\n {\n title: t(\n \"processing.steps.final_verification.title\",\n \"Vérification finale\",\n ),\n subtitle: t(\n \"processing.steps.final_verification.subtitle\",\n \"Validation des données extraites\",\n ),\n hasError: false,\n },\n];\n\nconst DocumentProcessing = memo(\n ({\n onProcessingComplete,\n documentType,\n documentTypeLabel,\n nodeId,\n fileUploaded,\n documentTypeId,\n retryCount = 0,\n config,\n customAnalysisFunction,\n }: DocumentProcessingProps) => {\n const inferRequiresTwoSides = useCallback(\n (type?: string): boolean | undefined => {\n if (!type) {\n return undefined;\n }\n\n const normalized = type.trim().toLowerCase();\n if (!normalized) {\n return undefined;\n }\n\n if (normalized.includes(\"passport\")) {\n return false;\n }\n\n if (\n normalized.includes(\"idcard\") ||\n normalized.includes(\"identity\") ||\n normalized.includes(\"driver\") ||\n normalized.includes(\"licenc\") ||\n normalized.includes(\"residence\")\n ) {\n return true;\n }\n\n return undefined;\n },\n [],\n );\n\n const { t, translateDocumentType } = useI18n();\n\n const [isProcessing, setIsProcessing] = useState(false);\n const [currentStep, setCurrentStep] = useState(0);\n const [processingSteps, setProcessingSteps] = useState<ProcessingStep[]>(\n () => config?.steps || getProcessingSteps(t),\n );\n const [isComplete, setIsComplete] = useState(false);\n const [analysisResult, setAnalysisResult] =\n useState<ProcessingResult | null>(null);\n\n const processingStartedRef = useRef(false);\n const processedFilesRef = useRef<string | null>(null);\n\n // Create stable key for uploaded files\n const filesKey = useMemo(() => {\n if (!fileUploaded) return null;\n\n // Handle onUploadFiles structure\n return `${fileUploaded.front?.substring(0, 50) || \"no-front\"}-${\n fileUploaded.back?.substring(0, 50) || \"no-back\"\n }`;\n }, [fileUploaded]);\n\n // Stable callback for completion\n const stableOnProcessingComplete = useCallback(\n (\n success: boolean,\n retryCount?: number,\n analysisData?: Prediction[] | null,\n blockContinue?: boolean,\n ) => {\n console.log(\"[DocumentProcessing] Stable callback for completion:\", success, retryCount);\n if (blockContinue === true) {\n onProcessingComplete(success, retryCount, analysisData, true);\n } else {\n onProcessingComplete(success, retryCount, analysisData);\n }\n },\n [onProcessingComplete],\n );\n\n // Default analysis function\n const defaultAnalysisFunction = useCallback(\n async (\n sessionId: string,\n files: onUploadFiles,\n docTypeId: string,\n options?: AnalyzeFilesOptions,\n ): Promise<ProcessingResult> => {\n const response = await analyzeFiles(\n sessionId,\n nodeId,\n files,\n docTypeId,\n {\n ...options,\n save: options?.save ?? false, // don't save to session yet\n incrementAnalysis: options?.incrementAnalysis ?? false, // don't auto-progress session\n },\n );\n\n // When polling is enabled, response is AnalysisStatusResponse\n // which has code, codeName, codeDescription directly on the object\n const extractedCode = response?.code || String(response?.status);\n const codeName = response?.codeName;\n const codeDescription = response?.codeDescription;\n\n // Construct predictions array from the response\n const predictions = [];\n if (extractedCode && codeName) {\n predictions.push({\n code: extractedCode,\n codeName: codeName,\n codeDescription: codeDescription || \"\",\n type: \"document\", // default type\n });\n }\n\n // Determine success based on code\n // Code 8.x (specimen) is blocking — treated as failure\n const isSuccess = [\"1.\", \"4.\", \"5.\", \"6.\", \"9.\"].some((prefix) =>\n extractedCode.startsWith(prefix),\n );\n\n return {\n success: isSuccess,\n code: extractedCode,\n data: response,\n predictions: predictions,\n };\n },\n [nodeId],\n );\n\n // Main processing effect\n useEffect(() => {\n // Prevent multiple calls\n if (\n !fileUploaded ||\n !filesKey ||\n isProcessing ||\n processingStartedRef.current\n ) {\n return;\n }\n\n const sessionId = getActiveSessionId();\n if (!sessionId) {\n stableOnProcessingComplete(false);\n return;\n }\n\n // Check if we already processed these same files\n if (processedFilesRef.current === filesKey) {\n return;\n }\n\n const processFiles = async () => {\n try {\n // Mark processing start\n setIsProcessing(true);\n processingStartedRef.current = true;\n processedFilesRef.current = filesKey;\n\n // Animate through steps with real API call at the end\n for (let i = 0; i < processingSteps.length; i++) {\n setCurrentStep(i);\n\n if (i < processingSteps.length - 1) {\n // Delay between steps (except last one)\n await new Promise((resolve) => setTimeout(resolve, 800));\n } else {\n // Last step: real API call\n const analysisFunction =\n customAnalysisFunction || defaultAnalysisFunction;\n const inferredTwoSides = inferRequiresTwoSides(\n typeof config?.documentType === \"string\"\n ? config.documentType\n : documentType,\n );\n\n const analysisOptions: AnalyzeFilesOptions = {\n documentTypeKey: documentType,\n requiresTwoSides:\n typeof inferredTwoSides === \"boolean\"\n ? inferredTwoSides\n : Boolean(fileUploaded.back),\n };\n\n const result = await analysisFunction(\n sessionId,\n fileUploaded,\n documentTypeId,\n analysisOptions,\n );\n\n setAnalysisResult(result);\n\n // Mark current step according to result\n setProcessingSteps((prev) =>\n prev.map((step, index) =>\n index === i ? { ...step, hasError: !result.success } : step,\n ),\n );\n\n // Small delay to see result\n await new Promise((resolve) => setTimeout(resolve, 500));\n }\n }\n\n setCurrentStep(processingSteps.length);\n setIsComplete(true);\n } catch (error) {\n console.error(\"Processing error:\", error);\n\n // Mark current step as error\n setProcessingSteps((prev) =>\n prev.map((step, index) =>\n index === currentStep ? { ...step, hasError: true } : step,\n ),\n );\n\n const isUploadNotConfirmed = isS3UploadNotConfirmedError(error);\n setAnalysisResult({\n success: false,\n data: null,\n canRetry: isUploadNotConfirmed,\n blockContinue: isUploadNotConfirmed,\n });\n setIsComplete(true);\n } finally {\n setIsProcessing(false);\n }\n };\n\n processFiles();\n }, [\n fileUploaded,\n filesKey,\n documentTypeId,\n documentType,\n config?.documentType,\n isProcessing,\n stableOnProcessingComplete,\n processingSteps.length,\n currentStep,\n customAnalysisFunction,\n defaultAnalysisFunction,\n inferRequiresTwoSides,\n ]);\n\n // Auto-complete when analysis is done\n useEffect(() => {\n if (isComplete && analysisResult) {\n setTimeout(() => {\n stableOnProcessingComplete(\n analysisResult.success,\n retryCount,\n analysisResult.predictions || null,\n analysisResult.blockContinue,\n );\n }, 1000);\n }\n }, [isComplete, analysisResult, stableOnProcessingComplete, retryCount]);\n\n return (\n <div className=\"flex flex-col justify-between h-full w-full\">\n {/* Main content area */}\n <div className=\"flex-1 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 {/* Header */}\n <div className=\"text-center space-y-4\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl\">\n {config?.processingTitle ||\n t(\"processing.title\", \"Analyse en cours\")}\n </Title>\n <Subtitle className=\"text-sm text-gray-600 leading-relaxed\">\n {config?.processingSubtitle ||\n t(\"processing.subtitle\", {\n documentType: t(\n \"documentTypes.\" + documentType,\n \"document\",\n ),\n defaultValue: `Nous analysons votre ${t(\"documentTypes.\" + documentType, \"document\")}. Cela peut prendre quelques instants.`,\n })}\n </Subtitle>\n </div>\n\n {/* Processing steps with status indicators */}\n <div className=\"w-full flex justify-center\">\n <div className=\"space-y-5\">\n {processingSteps.map((step, index: number) => (\n <div key={index} className=\"flex items-start\">\n {/* Status indicator */}\n <div className=\"mr-4 mt-1 flex-shrink-0\">\n {index < currentStep ? (\n step.hasError ? (\n // Error indicator - Red X\n <div className=\"flex items-center justify-center w-6 h-6 rounded-full bg-red-500 text-white text-xs\">\n ✕\n </div>\n ) : (\n // Success indicator - Green checkmark\n <div className=\"flex items-center justify-center w-6 h-6 rounded-full bg-[#11E5C5] text-white text-xs\">\n ✓\n </div>\n )\n ) : index === currentStep ? (\n // Loading spinner only for the current step\n <div className=\"w-6 h-6 rounded-full border-2 border-t-[#11E5C5] border-r-[#11E5C5] border-b-[#11E5C5] border-l-transparent animate-spin\"></div>\n ) : (\n // Empty circle for future steps\n <div className=\"w-6 h-6 rounded-full border-2 border-gray-300\"></div>\n )}\n </div>\n\n {/* Step content */}\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium text-[#3C3C40] text-sm\">\n {step.title}\n </p>\n <p className=\"text-xs text-gray-500 mt-1\">\n {step.subtitle}\n </p>\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n },\n);\n\nDocumentProcessing.displayName = \"DocumentProcessing\";\n\nexport default DocumentProcessing;\nexport type { DocumentProcessingProps };\n"],"names":["memo","useCallback","useI18n","useState","useRef","useMemo","__awaiter","analyzeFiles","__assign","useEffect","getActiveSessionId","isS3UploadNotConfirmedError","_jsx","_jsxs","Title","Subtitle"],"mappings":"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"}
1
+ {"version":3,"file":"DocumentProcessing.js","sources":["../../../../../src/components/document-collection/DocumentProcessing.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useMemo, useCallback, memo } from \"react\";\nimport Title from \"../ui/Title\";\nimport Subtitle from \"../ui/Subtitle\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport {\n analyzeFiles,\n type AnalyzeFilesOptions,\n} from \"../../services/analysis\";\nimport { getActiveSessionId } from \"../../services/sessionMemoryStore\";\nimport type { onUploadFiles } from \"../../types/uploadFiles\";\nimport type {\n DocumentProcessingProps,\n ProcessingStep,\n ProcessingResult,\n} from \"./types\";\nimport type { Prediction } from \"../../utils/apiAnalysis\";\nimport {\n isS3UploadNotConfirmedError,\n isQuotaExceededError,\n QUOTA_EXCEEDED_CODE,\n} from \"../../utils/analysisErrors\";\n\n// Localized processing steps generator\nconst getProcessingSteps = (t: any): ProcessingStep[] => [\n {\n title: t(\n \"processing.steps.document_reception.title\",\n \"Réception du document\",\n ),\n subtitle: t(\n \"processing.steps.document_reception.subtitle\",\n \"Téléchargement et vérification du format\",\n ),\n hasError: false,\n },\n {\n title: t(\n \"processing.steps.quality_analysis.title\",\n \"Analyse de la qualité\",\n ),\n subtitle: t(\n \"processing.steps.quality_analysis.subtitle\",\n \"Contrôle de la netteté et de l'éclairage\",\n ),\n hasError: false,\n },\n {\n title: t(\n \"processing.steps.data_extraction.title\",\n \"Extraction des données\",\n ),\n subtitle: t(\n \"processing.steps.data_extraction.subtitle\",\n \"Lecture des informations du document\",\n ),\n hasError: false,\n },\n {\n title: t(\n \"processing.steps.final_verification.title\",\n \"Vérification finale\",\n ),\n subtitle: t(\n \"processing.steps.final_verification.subtitle\",\n \"Validation des données extraites\",\n ),\n hasError: false,\n },\n];\n\nconst DocumentProcessing = memo(\n ({\n onProcessingComplete,\n documentType,\n documentTypeLabel,\n nodeId,\n fileUploaded,\n documentTypeId,\n retryCount = 0,\n config,\n customAnalysisFunction,\n }: DocumentProcessingProps) => {\n const inferRequiresTwoSides = useCallback(\n (type?: string): boolean | undefined => {\n if (!type) {\n return undefined;\n }\n\n const normalized = type.trim().toLowerCase();\n if (!normalized) {\n return undefined;\n }\n\n if (normalized.includes(\"passport\")) {\n return false;\n }\n\n if (\n normalized.includes(\"idcard\") ||\n normalized.includes(\"identity\") ||\n normalized.includes(\"driver\") ||\n normalized.includes(\"licenc\") ||\n normalized.includes(\"residence\")\n ) {\n return true;\n }\n\n return undefined;\n },\n [],\n );\n\n const { t, translateDocumentType } = useI18n();\n\n const [isProcessing, setIsProcessing] = useState(false);\n const [currentStep, setCurrentStep] = useState(0);\n const [processingSteps, setProcessingSteps] = useState<ProcessingStep[]>(\n () => config?.steps || getProcessingSteps(t),\n );\n const [isComplete, setIsComplete] = useState(false);\n const [analysisResult, setAnalysisResult] =\n useState<ProcessingResult | null>(null);\n\n const processingStartedRef = useRef(false);\n const processedFilesRef = useRef<string | null>(null);\n\n // Create stable key for uploaded files\n const filesKey = useMemo(() => {\n if (!fileUploaded) return null;\n\n // Handle onUploadFiles structure\n return `${fileUploaded.front?.substring(0, 50) || \"no-front\"}-${\n fileUploaded.back?.substring(0, 50) || \"no-back\"\n }`;\n }, [fileUploaded]);\n\n // Stable callback for completion\n const stableOnProcessingComplete = useCallback(\n (\n success: boolean,\n retryCount?: number,\n analysisData?: Prediction[] | null,\n blockContinue?: boolean,\n ) => {\n console.log(\"[DocumentProcessing] Stable callback for completion:\", success, retryCount);\n if (blockContinue === true) {\n onProcessingComplete(success, retryCount, analysisData, true);\n } else {\n onProcessingComplete(success, retryCount, analysisData);\n }\n },\n [onProcessingComplete],\n );\n\n // Default analysis function\n const defaultAnalysisFunction = useCallback(\n async (\n sessionId: string,\n files: onUploadFiles,\n docTypeId: string,\n options?: AnalyzeFilesOptions,\n ): Promise<ProcessingResult> => {\n const response = await analyzeFiles(\n sessionId,\n nodeId,\n files,\n docTypeId,\n {\n ...options,\n save: options?.save ?? false, // don't save to session yet\n incrementAnalysis: options?.incrementAnalysis ?? false, // don't auto-progress session\n },\n );\n\n // When polling is enabled, response is AnalysisStatusResponse\n // which has code, codeName, codeDescription directly on the object\n const extractedCode = response?.code || String(response?.status);\n const codeName = response?.codeName;\n const codeDescription = response?.codeDescription;\n\n // Construct predictions array from the response\n const predictions = [];\n if (extractedCode && codeName) {\n predictions.push({\n code: extractedCode,\n codeName: codeName,\n codeDescription: codeDescription || \"\",\n type: \"document\", // default type\n });\n }\n\n // Determine success based on code\n // Code 8.x (specimen) is blocking — treated as failure\n const isSuccess = [\"1.\", \"4.\", \"5.\", \"6.\", \"9.\"].some((prefix) =>\n extractedCode.startsWith(prefix),\n );\n\n return {\n success: isSuccess,\n code: extractedCode,\n data: response,\n predictions: predictions,\n };\n },\n [nodeId],\n );\n\n // Main processing effect\n useEffect(() => {\n // Prevent multiple calls\n if (\n !fileUploaded ||\n !filesKey ||\n isProcessing ||\n processingStartedRef.current\n ) {\n return;\n }\n\n const sessionId = getActiveSessionId();\n if (!sessionId) {\n stableOnProcessingComplete(false);\n return;\n }\n\n // Check if we already processed these same files\n if (processedFilesRef.current === filesKey) {\n return;\n }\n\n const processFiles = async () => {\n try {\n // Mark processing start\n setIsProcessing(true);\n processingStartedRef.current = true;\n processedFilesRef.current = filesKey;\n\n // Animate through steps with real API call at the end\n for (let i = 0; i < processingSteps.length; i++) {\n setCurrentStep(i);\n\n if (i < processingSteps.length - 1) {\n // Delay between steps (except last one)\n await new Promise((resolve) => setTimeout(resolve, 800));\n } else {\n // Last step: real API call\n const analysisFunction =\n customAnalysisFunction || defaultAnalysisFunction;\n const inferredTwoSides = inferRequiresTwoSides(\n typeof config?.documentType === \"string\"\n ? config.documentType\n : documentType,\n );\n\n const analysisOptions: AnalyzeFilesOptions = {\n documentTypeKey: documentType,\n requiresTwoSides:\n typeof inferredTwoSides === \"boolean\"\n ? inferredTwoSides\n : Boolean(fileUploaded.back),\n };\n\n const result = await analysisFunction(\n sessionId,\n fileUploaded,\n documentTypeId,\n analysisOptions,\n );\n\n setAnalysisResult(result);\n\n // Mark current step according to result\n setProcessingSteps((prev) =>\n prev.map((step, index) =>\n index === i ? { ...step, hasError: !result.success } : step,\n ),\n );\n\n // Small delay to see result\n await new Promise((resolve) => setTimeout(resolve, 500));\n }\n }\n\n setCurrentStep(processingSteps.length);\n setIsComplete(true);\n } catch (error) {\n console.error(\"Processing error:\", error);\n\n // Mark current step as error\n setProcessingSteps((prev) =>\n prev.map((step, index) =>\n index === currentStep ? { ...step, hasError: true } : step,\n ),\n );\n\n const isUploadNotConfirmed = isS3UploadNotConfirmedError(error);\n const isQuotaExceeded = isQuotaExceededError(error);\n const apiError = error as { code?: string; message?: string };\n setAnalysisResult({\n success: false,\n data: null,\n // Propage le code/message QUOTA_EXCEEDED pour que DocumentError\n // puisse afficher un message dédié via `user_guidance.<code>` au\n // lieu de rester muet sur la cause (limité au cas quota : les\n // autres erreurs gardent leur comportement existant).\n predictions: isQuotaExceeded\n ? [\n {\n code: QUOTA_EXCEEDED_CODE,\n codeName: QUOTA_EXCEEDED_CODE,\n codeDescription: apiError?.message || \"\",\n type: \"document\",\n },\n ]\n : undefined,\n canRetry: isUploadNotConfirmed || isQuotaExceeded,\n blockContinue: isUploadNotConfirmed,\n });\n setIsComplete(true);\n } finally {\n setIsProcessing(false);\n }\n };\n\n processFiles();\n }, [\n fileUploaded,\n filesKey,\n documentTypeId,\n documentType,\n config?.documentType,\n isProcessing,\n stableOnProcessingComplete,\n processingSteps.length,\n currentStep,\n customAnalysisFunction,\n defaultAnalysisFunction,\n inferRequiresTwoSides,\n ]);\n\n // Auto-complete when analysis is done\n useEffect(() => {\n if (isComplete && analysisResult) {\n setTimeout(() => {\n stableOnProcessingComplete(\n analysisResult.success,\n retryCount,\n analysisResult.predictions || null,\n analysisResult.blockContinue,\n );\n }, 1000);\n }\n }, [isComplete, analysisResult, stableOnProcessingComplete, retryCount]);\n\n return (\n <div className=\"flex flex-col justify-between h-full w-full\">\n {/* Main content area */}\n <div className=\"flex-1 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 {/* Header */}\n <div className=\"text-center space-y-4\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl\">\n {config?.processingTitle ||\n t(\"processing.title\", \"Analyse en cours\")}\n </Title>\n <Subtitle className=\"text-sm text-gray-600 leading-relaxed\">\n {config?.processingSubtitle ||\n t(\"processing.subtitle\", {\n documentType: t(\n \"documentTypes.\" + documentType,\n \"document\",\n ),\n defaultValue: `Nous analysons votre ${t(\"documentTypes.\" + documentType, \"document\")}. Cela peut prendre quelques instants.`,\n })}\n </Subtitle>\n </div>\n\n {/* Processing steps with status indicators */}\n <div className=\"w-full flex justify-center\">\n <div className=\"space-y-5\">\n {processingSteps.map((step, index: number) => (\n <div key={index} className=\"flex items-start\">\n {/* Status indicator */}\n <div className=\"mr-4 mt-1 flex-shrink-0\">\n {index < currentStep ? (\n step.hasError ? (\n // Error indicator - Red X\n <div className=\"flex items-center justify-center w-6 h-6 rounded-full bg-red-500 text-white text-xs\">\n ✕\n </div>\n ) : (\n // Success indicator - Green checkmark\n <div className=\"flex items-center justify-center w-6 h-6 rounded-full bg-[#11E5C5] text-white text-xs\">\n ✓\n </div>\n )\n ) : index === currentStep ? (\n // Loading spinner only for the current step\n <div className=\"w-6 h-6 rounded-full border-2 border-t-[#11E5C5] border-r-[#11E5C5] border-b-[#11E5C5] border-l-transparent animate-spin\"></div>\n ) : (\n // Empty circle for future steps\n <div className=\"w-6 h-6 rounded-full border-2 border-gray-300\"></div>\n )}\n </div>\n\n {/* Step content */}\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium text-[#3C3C40] text-sm\">\n {step.title}\n </p>\n <p className=\"text-xs text-gray-500 mt-1\">\n {step.subtitle}\n </p>\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n },\n);\n\nDocumentProcessing.displayName = \"DocumentProcessing\";\n\nexport default DocumentProcessing;\nexport type { DocumentProcessingProps };\n"],"names":["memo","useCallback","useI18n","useState","useRef","useMemo","__awaiter","analyzeFiles","__assign","useEffect","getActiveSessionId","isS3UploadNotConfirmedError","isQuotaExceededError","QUOTA_EXCEEDED_CODE","_jsx","_jsxs","Title","Subtitle"],"mappings":"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"}
@@ -23,7 +23,7 @@ var BeforePhoto = function (_a) {
23
23
  };
24
24
  return (jsxRuntime.jsx(MobilePageLayout.default, { footer: jsxRuntime.jsx(PageActions.default, { primary: jsxRuntime.jsx(Button.default, { onClick: goOnNextStep, children: t("id_check.before.button_ready", "Je suis prêt.e") }), secondary: onBack ? (jsxRuntime.jsx(Button.default, { variant: "secondary", onClick: onBack, children: t("buttons.back") })) : undefined }), children: jsxRuntime.jsx("div", { className: "px-4 py-6 pt-11 md:px-8 md:py-8", children: jsxRuntime.jsxs("div", { className: "w-full max-w-md mx-auto space-y-6", children: [jsxRuntime.jsxs("div", { className: "text-center space-y-4", children: [jsxRuntime.jsx(Title.default, { className: "text-xl md:text-2xl lg:text-3xl", children: isSingleSided
25
25
  ? t("id_check.before.title_single_sided", "Tenez votre document face à la caméra")
26
- : t("id_check.before.title_front", "Tenez le recto de votre document") }), jsxRuntime.jsx(Subtitle.default, { className: "text-sm text-gray-600 leading-relaxed", children: t("id_check.before.subtitle_front", "Afin de vérifier votre document, nous allons vous demander de le tenir face à la caméra") })] }), jsxRuntime.jsx("div", { className: "flex justify-center", children: jsxRuntime.jsx("img", { src: isSingleSided ? beforePassport.default : beforePhoto.default, alt: t("id_check.before.alt_front", "Avant de prendre la photo"), className: "max-w-full h-auto object-contain max-h-[30vh]" }) })] }) }) }));
26
+ : t("id_check.before.title_front", "Recto de votre document") }), jsxRuntime.jsx(Subtitle.default, { className: "text-sm text-gray-600 leading-relaxed", children: t("id_check.before.subtitle_front", "Vous pouvez le tenir face à la caméra ou le poser à plat sur une surface stable, comme vous préférez.") })] }), jsxRuntime.jsx("div", { className: "flex justify-center", children: jsxRuntime.jsx("img", { src: isSingleSided ? beforePassport.default : beforePhoto.default, alt: t("id_check.before.alt_front", "Avant de prendre la photo"), className: "max-w-full h-auto object-contain max-h-[30vh]" }) })] }) }) }));
27
27
  };
28
28
 
29
29
  exports.default = BeforePhoto;
@@ -1 +1 @@
1
- {"version":3,"file":"BeforePhoto.js","sources":["../../../../../src/components/id-check/BeforePhoto.tsx"],"sourcesContent":["import { beforePhotoIcon, beforePassportIcon } from \"../../assets\";\nimport Button from \"../ui/Button\";\nimport PageActions from \"../ui/PageActions\";\nimport Subtitle from \"../ui/Subtitle\";\nimport Title from \"../ui/Title\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport { useI18n } from \"../../hooks/useI18n\";\n\ninterface BeforePhotoProps {\n setStep: (step: number) => void;\n isSingleSided?: boolean;\n onBack?: () => void;\n}\n\nconst BeforePhoto = ({ setStep, isSingleSided = false, onBack }: BeforePhotoProps) => {\n const { t } = useI18n();\n\n const goOnNextStep = () => {\n setStep(1);\n };\n\n return (\n <MobilePageLayout\n footer={\n <PageActions\n primary={\n <Button onClick={goOnNextStep}>\n {t(\"id_check.before.button_ready\", \"Je suis prêt.e\")}\n </Button>\n }\n secondary={\n onBack ? (\n <Button variant=\"secondary\" onClick={onBack}>\n {t(\"buttons.back\")}\n </Button>\n ) : undefined\n }\n />\n }\n >\n <div className=\"px-4 py-6 pt-11 md:px-8 md:py-8\">\n <div className=\"w-full max-w-md mx-auto space-y-6\">\n {/* Header */}\n <div className=\"text-center space-y-4\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl\">\n {isSingleSided\n ? t(\"id_check.before.title_single_sided\", \"Tenez votre document face à la caméra\")\n : t(\"id_check.before.title_front\", \"Tenez le recto de votre document\")\n }\n </Title>\n <Subtitle className=\"text-sm text-gray-600 leading-relaxed\">\n {t(\n \"id_check.before.subtitle_front\",\n \"Afin de vérifier votre document, nous allons vous demander de le tenir face à la caméra\"\n )}\n </Subtitle>\n </div>\n\n {/* Illustration */}\n <div className=\"flex justify-center\">\n <img\n src={isSingleSided ? beforePassportIcon : beforePhotoIcon}\n alt={t(\"id_check.before.alt_front\", \"Avant de prendre la photo\")}\n className=\"max-w-full h-auto object-contain max-h-[30vh]\"\n />\n </div>\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default BeforePhoto;\n"],"names":["useI18n","_jsx","MobilePageLayout","PageActions","Button","_jsxs","Title","Subtitle","beforePassportIcon","beforePhotoIcon"],"mappings":";;;;;;;;;;;;;;;;;AAcA,IAAM,WAAW,GAAG,UAAC,EAA4D,EAAA;QAA1D,OAAO,GAAA,EAAA,CAAA,OAAA,EAAE,EAAA,GAAA,EAAA,CAAA,aAAqB,EAArB,aAAa,mBAAG,KAAK,GAAA,EAAA,EAAE,MAAM,GAAA,EAAA,CAAA,MAAA;AACnD,IAAA,IAAA,CAAC,GAAKA,eAAO,EAAE,EAAd;AAET,IAAA,IAAM,YAAY,GAAG,YAAA;QACnB,OAAO,CAAC,CAAC,CAAC;AACZ,IAAA,CAAC;AAED,IAAA,QACEC,cAAA,CAACC,wBAAgB,EAAA,EACf,MAAM,EACJD,cAAA,CAACE,mBAAW,EAAA,EACV,OAAO,EACLF,cAAA,CAACG,cAAM,EAAA,EAAC,OAAO,EAAE,YAAY,EAAA,QAAA,EAC1B,CAAC,CAAC,8BAA8B,EAAE,gBAAgB,CAAC,EAAA,CAC7C,EAEX,SAAS,EACP,MAAM,IACJH,eAACG,cAAM,EAAA,EAAC,OAAO,EAAC,WAAW,EAAC,OAAO,EAAE,MAAM,EAAA,QAAA,EACxC,CAAC,CAAC,cAAc,CAAC,EAAA,CACX,IACP,SAAS,EAAA,CAEf,EAAA,QAAA,EAGJH,wBAAK,SAAS,EAAC,iCAAiC,EAAA,QAAA,EAC9CI,yBAAK,SAAS,EAAC,mCAAmC,EAAA,QAAA,EAAA,CAEhDA,yBAAK,SAAS,EAAC,uBAAuB,EAAA,QAAA,EAAA,CACpCJ,eAACK,aAAK,EAAA,EAAC,SAAS,EAAC,iCAAiC,YAC/C;AACC,sCAAE,CAAC,CAAC,oCAAoC,EAAE,uCAAuC;AACjF,sCAAE,CAAC,CAAC,6BAA6B,EAAE,kCAAkC,CAAC,EAAA,CAElE,EACRL,cAAA,CAACM,gBAAQ,EAAA,EAAC,SAAS,EAAC,uCAAuC,EAAA,QAAA,EACxD,CAAC,CACA,gCAAgC,EAChC,yFAAyF,CAC1F,EAAA,CACQ,CAAA,EAAA,CACP,EAGNN,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,qBAAqB,EAAA,QAAA,EAClCA,cAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,aAAa,GAAGO,sBAAkB,GAAGC,mBAAe,EACzD,GAAG,EAAE,CAAC,CAAC,2BAA2B,EAAE,2BAA2B,CAAC,EAChE,SAAS,EAAC,+CAA+C,EAAA,CACzD,EAAA,CACE,CAAA,EAAA,CACF,EAAA,CACF,EAAA,CACW;AAEvB;;;;"}
1
+ {"version":3,"file":"BeforePhoto.js","sources":["../../../../../src/components/id-check/BeforePhoto.tsx"],"sourcesContent":["import { beforePhotoIcon, beforePassportIcon } from \"../../assets\";\nimport Button from \"../ui/Button\";\nimport PageActions from \"../ui/PageActions\";\nimport Subtitle from \"../ui/Subtitle\";\nimport Title from \"../ui/Title\";\nimport MobilePageLayout from \"../ui/MobilePageLayout\";\nimport { useI18n } from \"../../hooks/useI18n\";\n\ninterface BeforePhotoProps {\n setStep: (step: number) => void;\n isSingleSided?: boolean;\n onBack?: () => void;\n}\n\nconst BeforePhoto = ({ setStep, isSingleSided = false, onBack }: BeforePhotoProps) => {\n const { t } = useI18n();\n\n const goOnNextStep = () => {\n setStep(1);\n };\n\n return (\n <MobilePageLayout\n footer={\n <PageActions\n primary={\n <Button onClick={goOnNextStep}>\n {t(\"id_check.before.button_ready\", \"Je suis prêt.e\")}\n </Button>\n }\n secondary={\n onBack ? (\n <Button variant=\"secondary\" onClick={onBack}>\n {t(\"buttons.back\")}\n </Button>\n ) : undefined\n }\n />\n }\n >\n <div className=\"px-4 py-6 pt-11 md:px-8 md:py-8\">\n <div className=\"w-full max-w-md mx-auto space-y-6\">\n {/* Header */}\n <div className=\"text-center space-y-4\">\n <Title className=\"text-xl md:text-2xl lg:text-3xl\">\n {isSingleSided\n ? t(\"id_check.before.title_single_sided\", \"Tenez votre document face à la caméra\")\n : t(\"id_check.before.title_front\", \"Recto de votre document\")\n }\n </Title>\n <Subtitle className=\"text-sm text-gray-600 leading-relaxed\">\n {t(\n \"id_check.before.subtitle_front\",\n \"Vous pouvez le tenir face à la caméra ou le poser à plat sur une surface stable, comme vous préférez.\"\n )}\n </Subtitle>\n </div>\n\n {/* Illustration */}\n <div className=\"flex justify-center\">\n <img\n src={isSingleSided ? beforePassportIcon : beforePhotoIcon}\n alt={t(\"id_check.before.alt_front\", \"Avant de prendre la photo\")}\n className=\"max-w-full h-auto object-contain max-h-[30vh]\"\n />\n </div>\n </div>\n </div>\n </MobilePageLayout>\n );\n};\n\nexport default BeforePhoto;\n"],"names":["useI18n","_jsx","MobilePageLayout","PageActions","Button","_jsxs","Title","Subtitle","beforePassportIcon","beforePhotoIcon"],"mappings":";;;;;;;;;;;;;;;;;AAcA,IAAM,WAAW,GAAG,UAAC,EAA4D,EAAA;QAA1D,OAAO,GAAA,EAAA,CAAA,OAAA,EAAE,EAAA,GAAA,EAAA,CAAA,aAAqB,EAArB,aAAa,mBAAG,KAAK,GAAA,EAAA,EAAE,MAAM,GAAA,EAAA,CAAA,MAAA;AACnD,IAAA,IAAA,CAAC,GAAKA,eAAO,EAAE,EAAd;AAET,IAAA,IAAM,YAAY,GAAG,YAAA;QACnB,OAAO,CAAC,CAAC,CAAC;AACZ,IAAA,CAAC;AAED,IAAA,QACEC,cAAA,CAACC,wBAAgB,EAAA,EACf,MAAM,EACJD,cAAA,CAACE,mBAAW,EAAA,EACV,OAAO,EACLF,cAAA,CAACG,cAAM,EAAA,EAAC,OAAO,EAAE,YAAY,EAAA,QAAA,EAC1B,CAAC,CAAC,8BAA8B,EAAE,gBAAgB,CAAC,EAAA,CAC7C,EAEX,SAAS,EACP,MAAM,IACJH,eAACG,cAAM,EAAA,EAAC,OAAO,EAAC,WAAW,EAAC,OAAO,EAAE,MAAM,EAAA,QAAA,EACxC,CAAC,CAAC,cAAc,CAAC,EAAA,CACX,IACP,SAAS,EAAA,CAEf,EAAA,QAAA,EAGJH,wBAAK,SAAS,EAAC,iCAAiC,EAAA,QAAA,EAC9CI,yBAAK,SAAS,EAAC,mCAAmC,EAAA,QAAA,EAAA,CAEhDA,yBAAK,SAAS,EAAC,uBAAuB,EAAA,QAAA,EAAA,CACpCJ,eAACK,aAAK,EAAA,EAAC,SAAS,EAAC,iCAAiC,YAC/C;AACC,sCAAE,CAAC,CAAC,oCAAoC,EAAE,uCAAuC;AACjF,sCAAE,CAAC,CAAC,6BAA6B,EAAE,yBAAyB,CAAC,EAAA,CAEzD,EACRL,cAAA,CAACM,gBAAQ,EAAA,EAAC,SAAS,EAAC,uCAAuC,EAAA,QAAA,EACxD,CAAC,CACA,gCAAgC,EAChC,uGAAuG,CACxG,EAAA,CACQ,CAAA,EAAA,CACP,EAGNN,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,qBAAqB,EAAA,QAAA,EAClCA,cAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,aAAa,GAAGO,sBAAkB,GAAGC,mBAAe,EACzD,GAAG,EAAE,CAAC,CAAC,2BAA2B,EAAE,2BAA2B,CAAC,EAChE,SAAS,EAAC,+CAA+C,EAAA,CACzD,EAAA,CACE,CAAA,EAAA,CACF,EAAA,CACF,EAAA,CACW;AAEvB;;;;"}
@@ -8,9 +8,9 @@ var useI18n = require('../../hooks/useI18n.js');
8
8
 
9
9
  var COUNTDOWN_DURATION = 3; // seconds
10
10
  var CameraMask = function (_a) {
11
- var _b = _a.isPortrait, isPortrait = _b === void 0 ? false : _b, _c = _a.facingMode, facingMode = _c === void 0 ? "environment" : _c, _d = _a.isCountingDown, isCountingDown = _d === void 0 ? false : _d, _e = _a.countdown, countdown = _e === void 0 ? 0 : _e, _f = _a.maskType, maskType = _f === void 0 ? "id" : _f, onMaskRectChange = _a.onMaskRectChange;
12
- var _g = React.useState(null), videoOrientation = _g[0], setVideoOrientation = _g[1];
13
- useI18n.useI18n().t;
11
+ var _b = _a.isPortrait, isPortrait = _b === void 0 ? false : _b, _c = _a.facingMode, facingMode = _c === void 0 ? "environment" : _c, _d = _a.isCountingDown, isCountingDown = _d === void 0 ? false : _d, _e = _a.countdown, countdown = _e === void 0 ? 0 : _e, _f = _a.maskType, maskType = _f === void 0 ? "id" : _f, _g = _a.documentDetected, documentDetected = _g === void 0 ? false : _g, onMaskRectChange = _a.onMaskRectChange;
12
+ var _h = React.useState(null), videoOrientation = _h[0], setVideoOrientation = _h[1];
13
+ var t = useI18n.useI18n().t;
14
14
  var maskRef = React.useRef(null);
15
15
  // Détecter l'orientation réelle de la vidéo pour synchroniser avec Photo.tsx
16
16
  React.useEffect(function () {
@@ -78,10 +78,12 @@ var CameraMask = function (_a) {
78
78
  boxShadow: "0 0 0 9999px rgba(0, 0, 0, 0.75)",
79
79
  borderRadius: "8px",
80
80
  width: maskType === "document" ? (effectiveIsPortrait ? "85%" : "60%") : (effectiveIsPortrait ? "95%" : "85%"),
81
- }, "data-mask": maskType === "document" ? "document-frame" : "id-frame", ref: maskRef, children: [jsxRuntime.jsx("div", { className: "absolute inset-0", style: {
82
- border: "3px solid white",
81
+ }, "data-mask": maskType === "document" ? "document-frame" : "id-frame", ref: maskRef, children: [jsxRuntime.jsx("div", { "data-testid": "camera-mask-border", className: "absolute inset-0 transition-colors duration-300 ease-in-out", style: {
82
+ borderWidth: "3px",
83
+ borderColor: documentDetected ? "#11E5C5" : "#ffffff",
84
+ borderStyle: documentDetected ? "solid" : "dashed",
83
85
  borderRadius: "8px",
84
- } }), isCountingDown && (jsxRuntime.jsx("svg", { className: "absolute inset-0 w-full h-full", style: {
86
+ } }), documentDetected && (jsxRuntime.jsxs("div", { "data-testid": "document-detected-badge", className: "absolute -top-9 left-1/2 -translate-x-1/2 flex items-center gap-1 bg-[#11E5C5] text-white text-xs font-semibold px-2 py-1 rounded-full whitespace-nowrap", children: [jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2713" }), jsxRuntime.jsx("span", { children: t("id_check.camera.document_detected", "Document détecté") })] })), isCountingDown && (jsxRuntime.jsx("svg", { className: "absolute inset-0 w-full h-full", style: {
85
87
  borderRadius: "8px",
86
88
  }, children: jsxRuntime.jsx("rect", { x: "1.5", y: "1.5", width: "calc(100% - 3px)", height: "calc(100% - 3px)", fill: "none", stroke: "#11E5C5", strokeWidth: "3", strokeDasharray: "100", strokeDashoffset: 100 - progress * 100, pathLength: "100", rx: "6", ry: "6", style: {
87
89
  transition: "stroke-dashoffset 0.1s linear",
@@ -1 +1 @@
1
- {"version":3,"file":"CameraMask.js","sources":["../../../../../src/components/id-check/CameraMask.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport type { CameraFacingMode } from \"../../types/camera\";\n\ninterface CameraMaskProps {\n isDetecting: boolean;\n isPortrait?: boolean;\n facingMode?: CameraFacingMode;\n isCountingDown?: boolean;\n countdown?: number;\n maskType?: \"id\" | \"document\";\n onMaskRectChange?: (\n rect:\n | {\n left: number;\n top: number;\n width: number;\n height: number;\n }\n | null\n ) => void;\n}\n\nconst COUNTDOWN_DURATION = 3; // seconds\n\nconst CameraMask: React.FC<CameraMaskProps> = ({\n isPortrait = false,\n facingMode = \"environment\",\n isCountingDown = false,\n countdown = 0,\n maskType = \"id\",\n onMaskRectChange,\n}) => {\n const [videoOrientation, setVideoOrientation] = useState<boolean | null>(\n null\n );\n const { t } = useI18n();\n const maskRef = useRef<HTMLDivElement>(null);\n\n // Détecter l'orientation réelle de la vidéo pour synchroniser avec Photo.tsx\n useEffect(() => {\n const checkVideoOrientation = () => {\n const videoElement = document.querySelector(\"video\");\n if (\n videoElement &&\n videoElement.videoWidth > 0 &&\n videoElement.videoHeight > 0\n ) {\n const videoIsPortrait =\n videoElement.videoHeight > videoElement.videoWidth;\n setVideoOrientation(videoIsPortrait);\n }\n };\n\n // Vérifier immédiatement\n checkVideoOrientation();\n\n // Vérifier périodiquement en cas de changement\n const interval = setInterval(checkVideoOrientation, 1000);\n\n return () => clearInterval(interval);\n }, []);\n\n // Utiliser l'orientation de la vidéo si disponible, sinon fallback sur l'orientation de l'écran\n const effectiveIsPortrait =\n videoOrientation !== null ? videoOrientation : isPortrait;\n\n // Calculate the progress of the animation (0 to 1) over COUNTDOWN_DURATION seconds\n const progress = isCountingDown\n ? Math.min(1, (COUNTDOWN_DURATION - countdown) / COUNTDOWN_DURATION)\n : 0;\n\n useLayoutEffect(() => {\n if (!onMaskRectChange) {\n return;\n }\n\n const notify = () => {\n if (!maskRef.current) {\n onMaskRectChange(null);\n console.debug(\"[CameraMask] maskRef unavailable\");\n return;\n }\n\n const rect = maskRef.current.getBoundingClientRect();\n onMaskRectChange({\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n });\n console.debug(\"[CameraMask] mask rect updated\", {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n });\n };\n\n requestAnimationFrame(notify);\n\n const handleResize = () => requestAnimationFrame(notify);\n window.addEventListener(\"resize\", handleResize);\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\" && maskRef.current) {\n resizeObserver = new ResizeObserver(() => {\n requestAnimationFrame(notify);\n });\n resizeObserver.observe(maskRef.current);\n }\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n resizeObserver?.disconnect();\n };\n }, [onMaskRectChange, effectiveIsPortrait, facingMode]);\n\n return (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n <div\n className={`\n relative\n ${maskType === \"document\" ? \"aspect-[1/1.41]\" : \"aspect-3/2\"}\n ${facingMode === \"user\" ? \"transform scale-x-[-1]\" : \"\"}\n transition-all duration-300 ease-in-out\n `}\n style={{\n boxShadow: \"0 0 0 9999px rgba(0, 0, 0, 0.75)\",\n borderRadius: \"8px\",\n width: maskType === \"document\" ? (effectiveIsPortrait ? \"85%\" : \"60%\") : (effectiveIsPortrait ? \"95%\" : \"85%\"),\n }}\n data-mask={maskType === \"document\" ? \"document-frame\" : \"id-frame\"}\n ref={maskRef}\n >\n {/* Base white border */}\n <div\n className=\"absolute inset-0\"\n style={{\n border: \"3px solid white\",\n borderRadius: \"8px\",\n }}\n />\n\n {/* Animated blue border overlay */}\n {isCountingDown && (\n <svg\n className=\"absolute inset-0 w-full h-full\"\n style={{\n borderRadius: \"8px\",\n }}\n >\n <rect\n x=\"1.5\"\n y=\"1.5\"\n width={`calc(100% - 3px)`}\n height={`calc(100% - 3px)`}\n fill=\"none\"\n stroke=\"#11E5C5\"\n strokeWidth=\"3\"\n strokeDasharray=\"100\"\n strokeDashoffset={100 - progress * 100}\n pathLength=\"100\"\n rx=\"6\"\n ry=\"6\"\n style={{\n transition: \"stroke-dashoffset 0.1s linear\",\n }}\n />\n </svg>\n )}\n\n {/* Countdown display */}\n {isCountingDown && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"bg-black bg-opacity-50 text-white px-4 py-2 rounded-full text-lg font-bold\">\n {Math.ceil(countdown)}\n </div>\n </div>\n )}\n\n {/* Indicateur d'orientation pour debug */}\n {(typeof process !== \"undefined\" && process.env && process.env.NODE_ENV === \"development\") && (\n <div className=\"absolute -top-8 left-0 text-white text-xs bg-black bg-opacity-50 px-2 py-1 rounded\">\n {effectiveIsPortrait ? t(\"id_check.orientation.portrait\", \"Portrait\") : t(\"id_check.orientation.landscape\", \"Landscape\")}\n {videoOrientation !== null ? ` (${t(\"id_check.orientation.video_suffix\", \"Video\")})` : ` (${t(\"id_check.orientation.screen_suffix\", \"Screen\")})`}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default CameraMask;\n"],"names":["useState","useI18n","useRef","useEffect","useLayoutEffect","_jsx","_jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"CameraMask.js","sources":["../../../../../src/components/id-check/CameraMask.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport type { CameraFacingMode } from \"../../types/camera\";\n\ninterface CameraMaskProps {\n isDetecting: boolean;\n isPortrait?: boolean;\n facingMode?: CameraFacingMode;\n isCountingDown?: boolean;\n countdown?: number;\n maskType?: \"id\" | \"document\";\n documentDetected?: boolean;\n onMaskRectChange?: (\n rect:\n | {\n left: number;\n top: number;\n width: number;\n height: number;\n }\n | null\n ) => void;\n}\n\nconst COUNTDOWN_DURATION = 3; // seconds\n\nconst CameraMask: React.FC<CameraMaskProps> = ({\n isPortrait = false,\n facingMode = \"environment\",\n isCountingDown = false,\n countdown = 0,\n maskType = \"id\",\n documentDetected = false,\n onMaskRectChange,\n}) => {\n const [videoOrientation, setVideoOrientation] = useState<boolean | null>(\n null\n );\n const { t } = useI18n();\n const maskRef = useRef<HTMLDivElement>(null);\n\n // Détecter l'orientation réelle de la vidéo pour synchroniser avec Photo.tsx\n useEffect(() => {\n const checkVideoOrientation = () => {\n const videoElement = document.querySelector(\"video\");\n if (\n videoElement &&\n videoElement.videoWidth > 0 &&\n videoElement.videoHeight > 0\n ) {\n const videoIsPortrait =\n videoElement.videoHeight > videoElement.videoWidth;\n setVideoOrientation(videoIsPortrait);\n }\n };\n\n // Vérifier immédiatement\n checkVideoOrientation();\n\n // Vérifier périodiquement en cas de changement\n const interval = setInterval(checkVideoOrientation, 1000);\n\n return () => clearInterval(interval);\n }, []);\n\n // Utiliser l'orientation de la vidéo si disponible, sinon fallback sur l'orientation de l'écran\n const effectiveIsPortrait =\n videoOrientation !== null ? videoOrientation : isPortrait;\n\n // Calculate the progress of the animation (0 to 1) over COUNTDOWN_DURATION seconds\n const progress = isCountingDown\n ? Math.min(1, (COUNTDOWN_DURATION - countdown) / COUNTDOWN_DURATION)\n : 0;\n\n useLayoutEffect(() => {\n if (!onMaskRectChange) {\n return;\n }\n\n const notify = () => {\n if (!maskRef.current) {\n onMaskRectChange(null);\n console.debug(\"[CameraMask] maskRef unavailable\");\n return;\n }\n\n const rect = maskRef.current.getBoundingClientRect();\n onMaskRectChange({\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n });\n console.debug(\"[CameraMask] mask rect updated\", {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n });\n };\n\n requestAnimationFrame(notify);\n\n const handleResize = () => requestAnimationFrame(notify);\n window.addEventListener(\"resize\", handleResize);\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\" && maskRef.current) {\n resizeObserver = new ResizeObserver(() => {\n requestAnimationFrame(notify);\n });\n resizeObserver.observe(maskRef.current);\n }\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n resizeObserver?.disconnect();\n };\n }, [onMaskRectChange, effectiveIsPortrait, facingMode]);\n\n return (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n <div\n className={`\n relative\n ${maskType === \"document\" ? \"aspect-[1/1.41]\" : \"aspect-3/2\"}\n ${facingMode === \"user\" ? \"transform scale-x-[-1]\" : \"\"}\n transition-all duration-300 ease-in-out\n `}\n style={{\n boxShadow: \"0 0 0 9999px rgba(0, 0, 0, 0.75)\",\n borderRadius: \"8px\",\n width: maskType === \"document\" ? (effectiveIsPortrait ? \"85%\" : \"60%\") : (effectiveIsPortrait ? \"95%\" : \"85%\"),\n }}\n data-mask={maskType === \"document\" ? \"document-frame\" : \"id-frame\"}\n ref={maskRef}\n >\n {/* Base border - white dashed by default, green solid once a document is detected */}\n <div\n data-testid=\"camera-mask-border\"\n className=\"absolute inset-0 transition-colors duration-300 ease-in-out\"\n style={{\n borderWidth: \"3px\",\n borderColor: documentDetected ? \"#11E5C5\" : \"#ffffff\",\n borderStyle: documentDetected ? \"solid\" : \"dashed\",\n borderRadius: \"8px\",\n }}\n />\n\n {/* Document detected badge - icon + text, not color-only */}\n {documentDetected && (\n <div\n data-testid=\"document-detected-badge\"\n className=\"absolute -top-9 left-1/2 -translate-x-1/2 flex items-center gap-1 bg-[#11E5C5] text-white text-xs font-semibold px-2 py-1 rounded-full whitespace-nowrap\"\n >\n <span aria-hidden=\"true\">✓</span>\n <span>\n {t(\"id_check.camera.document_detected\", \"Document détecté\")}\n </span>\n </div>\n )}\n\n {/* Animated blue border overlay */}\n {isCountingDown && (\n <svg\n className=\"absolute inset-0 w-full h-full\"\n style={{\n borderRadius: \"8px\",\n }}\n >\n <rect\n x=\"1.5\"\n y=\"1.5\"\n width={`calc(100% - 3px)`}\n height={`calc(100% - 3px)`}\n fill=\"none\"\n stroke=\"#11E5C5\"\n strokeWidth=\"3\"\n strokeDasharray=\"100\"\n strokeDashoffset={100 - progress * 100}\n pathLength=\"100\"\n rx=\"6\"\n ry=\"6\"\n style={{\n transition: \"stroke-dashoffset 0.1s linear\",\n }}\n />\n </svg>\n )}\n\n {/* Countdown display */}\n {isCountingDown && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"bg-black bg-opacity-50 text-white px-4 py-2 rounded-full text-lg font-bold\">\n {Math.ceil(countdown)}\n </div>\n </div>\n )}\n\n {/* Indicateur d'orientation pour debug */}\n {(typeof process !== \"undefined\" && process.env && process.env.NODE_ENV === \"development\") && (\n <div className=\"absolute -top-8 left-0 text-white text-xs bg-black bg-opacity-50 px-2 py-1 rounded\">\n {effectiveIsPortrait ? t(\"id_check.orientation.portrait\", \"Portrait\") : t(\"id_check.orientation.landscape\", \"Landscape\")}\n {videoOrientation !== null ? ` (${t(\"id_check.orientation.video_suffix\", \"Video\")})` : ` (${t(\"id_check.orientation.screen_suffix\", \"Screen\")})`}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default CameraMask;\n"],"names":["useState","useI18n","useRef","useEffect","useLayoutEffect","_jsx","_jsxs"],"mappings":"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"}
@@ -23,13 +23,26 @@ var Photo = function (_a) {
23
23
  var _g = React.useState(window.matchMedia("(orientation: portrait)").matches), isPortrait = _g[0], setIsPortrait = _g[1];
24
24
  var _h = React.useState(false), isCountingDown = _h[0], setIsCountingDown = _h[1];
25
25
  var _j = React.useState(0), countdown = _j[0], setCountdown = _j[1];
26
- var _k = React.useState(false); _k[0]; var setDocumentDetected = _k[1];
26
+ var _k = React.useState(false), documentDetected = _k[0], setDocumentDetected = _k[1];
27
27
  var _l = React.useState(null), captureError = _l[0], setCaptureError = _l[1];
28
+ var _m = React.useState(false), showCaptureFlash = _m[0], setShowCaptureFlash = _m[1];
28
29
  var t = useI18n.useI18n().t;
29
- var _m = React.useState(null); _m[0]; var setLastCaptureMeta = _m[1];
30
- var _o = React.useState(null), maskRect = _o[0], setMaskRect = _o[1];
30
+ var _o = React.useState(null); _o[0]; var setLastCaptureMeta = _o[1];
31
+ var _p = React.useState(null), maskRect = _p[0], setMaskRect = _p[1];
31
32
  var countdownIntervalRef = React.useRef(null);
32
33
  var detectionHandlerRef = React.useRef(null);
34
+ var flashTimeoutRef = React.useRef(null);
35
+ var CAPTURE_FLASH_DURATION_MS = 300;
36
+ var triggerCaptureFeedback = React.useCallback(function () {
37
+ if (flashTimeoutRef.current) {
38
+ clearTimeout(flashTimeoutRef.current);
39
+ }
40
+ setShowCaptureFlash(true);
41
+ flashTimeoutRef.current = window.setTimeout(function () {
42
+ setShowCaptureFlash(false);
43
+ flashTimeoutRef.current = null;
44
+ }, CAPTURE_FLASH_DURATION_MS);
45
+ }, []);
33
46
  var CAPTURE_COUNTDOWN_SECONDS = 3;
34
47
  var clearCountdown = React.useCallback(function () {
35
48
  if (countdownIntervalRef.current) {
@@ -116,6 +129,7 @@ var Photo = function (_a) {
116
129
  }
117
130
  setCaptureError(null);
118
131
  setIsDetecting(false);
132
+ triggerCaptureFeedback();
119
133
  _a.label = 1;
120
134
  case 1:
121
135
  _a.trys.push([1, 3, , 4]);
@@ -146,7 +160,7 @@ var Photo = function (_a) {
146
160
  case 4: return [2 /*return*/];
147
161
  }
148
162
  });
149
- }); }, [facingMode, onCapture, stopDetection, maskRect, t]);
163
+ }); }, [facingMode, onCapture, stopDetection, maskRect, t, triggerCaptureFeedback]);
150
164
  var startCountdown = React.useCallback(function () {
151
165
  if (isCountingDown)
152
166
  return;
@@ -203,9 +217,11 @@ var Photo = function (_a) {
203
217
  return [2 /*return*/];
204
218
  if (result.success) {
205
219
  setLastCaptureMeta(null);
206
- if (automaticCapture) {
207
- setIsDetecting(true);
208
- }
220
+ // Detection also runs in manual mode: it only drives the visual
221
+ // feedback on the mask (documentDetected), it never starts the
222
+ // auto-capture countdown unless automaticCapture is true (see
223
+ // handleDetectionChange).
224
+ setIsDetecting(true);
209
225
  }
210
226
  else if (result.error) {
211
227
  setCameraError(result.error);
@@ -222,6 +238,10 @@ var Photo = function (_a) {
222
238
  stopDetection();
223
239
  cameraService.cameraService.stopCamera();
224
240
  setIsDetecting(false);
241
+ if (flashTimeoutRef.current) {
242
+ clearTimeout(flashTimeoutRef.current);
243
+ flashTimeoutRef.current = null;
244
+ }
225
245
  };
226
246
  }, [facingMode, clearCountdown, stopDetection]);
227
247
  React.useEffect(function () {
@@ -292,7 +312,7 @@ var Photo = function (_a) {
292
312
  zIndex: isMobile ? 50 : "auto",
293
313
  height: "100%",
294
314
  width: "100%",
295
- }, children: [jsxRuntime.jsx("div", { className: "flex-1 relative overflow-hidden bg-black", children: cameraError ? (jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full px-4 py-6", children: jsxRuntime.jsx(CameraError.default, { errorMessage: cameraError, onRetry: handleRetry }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("video", { ref: videoRef, autoPlay: true, playsInline: true, muted: true, className: "absolute inset-0 w-full h-full object-cover z-0 bg-black ".concat(facingMode === "user" ? "scale-x-[-1]" : "") }), jsxRuntime.jsx("div", { className: "absolute top-4 left-1/2 transform -translate-x-1/2 z-50", children: jsxRuntime.jsx("span", { className: "text-white z-50 text-sm font-semibold drop-shadow-lg", children: automaticCapture ? (jsxRuntime.jsx("span", { className: "animate-pulse", children: t("id_check.photo.mode_autocapture", "Autocapture activée") })) : (jsxRuntime.jsx("span", { className: "bg-orange-500 px-2 py-1 rounded hidden", children: t("id_check.photo.mode_manual", "Mode manuel") })) }) }), jsxRuntime.jsx(CameraMask.default, { isDetecting: isDetecting, isPortrait: isPortrait, facingMode: facingMode, isCountingDown: isCountingDown, countdown: countdown, maskType: maskType, onMaskRectChange: setMaskRect }), jsxRuntime.jsx("div", { className: "absolute bottom-20 left-0 right-0 z-20 pointer-events-none", children: jsxRuntime.jsx("div", { className: "text-center px-4", children: jsxRuntime.jsx("div", { className: "bg-black bg-opacity-60 text-white text-sm px-4 py-2 rounded-lg inline-block", children: t("id_check.photo.position_document", "Positionnez le document") }) }) }), jsxRuntime.jsx(OrientationToggle.default, { onCameraToggle: toggleCamera })] })) }), jsxRuntime.jsx("div", { className: "relative z-20 bg-black bg-opacity-80 p-4", children: jsxRuntime.jsxs("div", { className: "flex flex-col items-center space-y-4", children: [jsxRuntime.jsx("button", { onClick: handleManualCapture, className: "w-16 h-16 rounded-full border-4 border-white flex items-center justify-center transition-all bg-transparent hover:bg-white hover:bg-opacity-20 cursor-pointer", children: jsxRuntime.jsx("div", { className: "w-8 h-8 bg-white rounded-full" }) }), jsxRuntime.jsxs("div", { className: "text-white text-center text-sm", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-center space-x-2", children: [jsxRuntime.jsx("div", { className: "w-2 h-2 rounded-full ".concat(automaticCapture
315
+ }, children: [jsxRuntime.jsx("div", { className: "flex-1 relative overflow-hidden bg-black", children: cameraError ? (jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full px-4 py-6", children: jsxRuntime.jsx(CameraError.default, { errorMessage: cameraError, onRetry: handleRetry }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("video", { ref: videoRef, autoPlay: true, playsInline: true, muted: true, className: "absolute inset-0 w-full h-full object-cover z-0 bg-black ".concat(facingMode === "user" ? "scale-x-[-1]" : "") }), jsxRuntime.jsx("div", { className: "absolute top-4 left-1/2 transform -translate-x-1/2 z-50", children: jsxRuntime.jsx("span", { className: "text-white z-50 text-sm font-semibold drop-shadow-lg", children: automaticCapture ? (jsxRuntime.jsx("span", { className: "animate-pulse", children: t("id_check.photo.mode_autocapture", "Autocapture activée") })) : (jsxRuntime.jsx("span", { className: "bg-orange-500 px-2 py-1 rounded hidden", children: t("id_check.photo.mode_manual", "Mode manuel") })) }) }), jsxRuntime.jsx(CameraMask.default, { isDetecting: isDetecting, isPortrait: isPortrait, facingMode: facingMode, isCountingDown: isCountingDown, countdown: countdown, maskType: maskType, documentDetected: documentDetected, onMaskRectChange: setMaskRect }), jsxRuntime.jsx("div", { className: "absolute bottom-20 left-0 right-0 z-20 pointer-events-none", children: jsxRuntime.jsx("div", { className: "text-center px-4", children: jsxRuntime.jsx("div", { className: "bg-black bg-opacity-60 text-white text-sm px-4 py-2 rounded-lg inline-block", children: t("id_check.photo.position_document", "Posez le document à plat ou tenez-le dans le cadre") }) }) }), jsxRuntime.jsx(OrientationToggle.default, { onCameraToggle: toggleCamera }), showCaptureFlash && (jsxRuntime.jsx("div", { "data-testid": "capture-flash", className: "absolute inset-0 z-40 bg-white pointer-events-none animate-pulse" }))] })) }), jsxRuntime.jsx("div", { className: "relative z-20 bg-black bg-opacity-80 p-4", children: jsxRuntime.jsxs("div", { className: "flex flex-col items-center space-y-4", children: [jsxRuntime.jsx("button", { onClick: handleManualCapture, className: "w-16 h-16 rounded-full border-4 border-white flex items-center justify-center transition-all duration-150 bg-transparent hover:bg-white hover:bg-opacity-20 cursor-pointer ".concat(showCaptureFlash ? "scale-90 ring-4 ring-[#11E5C5]" : ""), children: jsxRuntime.jsx("div", { className: "w-8 h-8 bg-white rounded-full" }) }), jsxRuntime.jsxs("div", { className: "text-white text-center text-sm", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-center space-x-2", children: [jsxRuntime.jsx("div", { className: "w-2 h-2 rounded-full ".concat(automaticCapture
296
316
  ? "bg-[#11E5C5] animate-pulse"
297
317
  : "bg-orange-500") }), jsxRuntime.jsx("span", { children: automaticCapture
298
318
  ? t("id_check.photo.automatic_instruction", "Capture automatique active ou appuyez sur le bouton")
@@ -1 +1 @@
1
- {"version":3,"file":"Photo.js","sources":["../../../../../src/components/id-check/Photo.tsx"],"sourcesContent":["import { useRef, useState, useEffect, useCallback } from \"react\";\nimport type { CameraFacingMode } from \"../../types/camera\";\nimport {\n cameraService,\n type CaptureDocumentResult,\n} from \"../../services/cameraService\";\nimport {\n documentDetectionService,\n type DocumentDetectionResult,\n} from \"../../services/documentDetectionService\";\nimport CameraError from \"./CameraError\";\nimport CameraMask from \"./CameraMask\";\nimport OrientationToggle from \"./OrientationToggle\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport useIsMobile from \"../../hooks/useIsMobile\";\n\ninterface PhotoProps {\n onCapture: (image: string) => void;\n automaticCapture?: boolean; // Controls whether automatic capture is enabled\n maskType?: \"id\" | \"document\";\n}\n\nconst Photo: React.FC<PhotoProps> = ({\n onCapture,\n automaticCapture = false,\n maskType = \"id\",\n}) => {\n const isMobile = useIsMobile(768);\n const videoRef = useRef<HTMLVideoElement>(null);\n const [isDetecting, setIsDetecting] = useState(false);\n const [facingMode, setFacingMode] = useState<CameraFacingMode>(\"environment\");\n const [cameraError, setCameraError] = useState<string | null>(null);\n const [isPortrait, setIsPortrait] = useState(\n window.matchMedia(\"(orientation: portrait)\").matches\n );\n const [isCountingDown, setIsCountingDown] = useState(false);\n const [countdown, setCountdown] = useState(0);\n const [documentDetected, setDocumentDetected] = useState(false);\n const [captureError, setCaptureError] = useState<string | null>(null);\n const { t } = useI18n();\n const [lastCaptureMeta, setLastCaptureMeta] =\n useState<CaptureDocumentResult | null>(null);\n const [maskRect, setMaskRect] = useState<{\n left: number;\n top: number;\n width: number;\n height: number;\n } | null>(null);\n\n const countdownIntervalRef = useRef<number | null>(null);\n const detectionHandlerRef = useRef<{ stop: () => void } | null>(null);\n\n const CAPTURE_COUNTDOWN_SECONDS = 3;\n\n const clearCountdown = useCallback(() => {\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n setIsCountingDown(false);\n setCountdown(0);\n }, []);\n\n useEffect(() => {\n const handleOrientationChange = () => {\n setIsPortrait(window.matchMedia(\"(orientation: portrait)\").matches);\n };\n\n const mediaQuery = window.matchMedia(\"(orientation: portrait)\");\n mediaQuery.addEventListener(\"change\", handleOrientationChange);\n\n return () => {\n mediaQuery.removeEventListener(\"change\", handleOrientationChange);\n };\n }, []);\n\n const stopDetection = useCallback(() => {\n if (detectionHandlerRef.current) {\n detectionHandlerRef.current.stop();\n detectionHandlerRef.current = null;\n }\n documentDetectionService.stopDocumentDetection();\n }, []);\n\n const captureDocument = useCallback(async () => {\n if (!videoRef.current) {\n throw new Error(t(\"id_check.photo.errors.video_unavailable\", \"Le flux vidéo n'est pas disponible\"));\n }\n\n const video = videoRef.current;\n if (!video.videoWidth || !video.videoHeight) {\n throw new Error(\n t(\n \"id_check.photo.errors.video_dimensions_unavailable\",\n \"Dimensions vidéo indisponibles pour la capture\"\n )\n );\n }\n\n // Calculate crop area from mask if available\n let cropArea = null;\n if (maskRect) {\n const videoRect = video.getBoundingClientRect();\n\n // Calculate the actual displayed video dimensions accounting for object-fit: contain\n // Calculate the actual displayed video dimensions accounting for object-fit: cover\n const videoAspect = video.videoWidth / video.videoHeight;\n const displayAspect = videoRect.width / videoRect.height;\n\n let displayedWidth, displayedHeight, offsetX, offsetY;\n\n if (videoAspect > displayAspect) {\n // Video is wider than container - scaled to match height, sides cropped\n displayedHeight = videoRect.height;\n displayedWidth = videoRect.height * videoAspect;\n offsetY = 0;\n offsetX = (videoRect.width - displayedWidth) / 2;\n } else {\n // Video is taller than container - scaled to match width, top/bottom cropped\n displayedWidth = videoRect.width;\n displayedHeight = videoRect.width / videoAspect;\n offsetX = 0;\n offsetY = (videoRect.height - displayedHeight) / 2;\n }\n\n // Calculate the scale between actual displayed video and real video dimensions\n const scaleX = video.videoWidth / displayedWidth;\n const scaleY = video.videoHeight / displayedHeight;\n\n // Convert mask coordinates from screen space to video space\n // Account for video element offset and displayed video offset\n const cropX = (maskRect.left - videoRect.left - offsetX) * scaleX;\n const cropY = (maskRect.top - videoRect.top - offsetY) * scaleY;\n const cropWidth = maskRect.width * scaleX;\n const cropHeight = maskRect.height * scaleY;\n\n // Ensure crop area is within video bounds\n cropArea = {\n x: Math.max(0, Math.round(cropX)),\n y: Math.max(0, Math.round(cropY)),\n width: Math.min(video.videoWidth - Math.max(0, cropX), Math.round(cropWidth)),\n height: Math.min(video.videoHeight - Math.max(0, cropY), Math.round(cropHeight)),\n };\n\n console.debug(\"[Photo] Calculated crop area from mask\", {\n maskRect,\n videoRect: { left: videoRect.left, top: videoRect.top, width: videoRect.width, height: videoRect.height },\n videoDimensions: { width: video.videoWidth, height: video.videoHeight },\n displayedDimensions: { width: displayedWidth, height: displayedHeight },\n offset: { x: offsetX, y: offsetY },\n scale: { x: scaleX, y: scaleY },\n cropArea,\n });\n } else {\n console.debug(\"[Photo] No mask rect available, capturing full frame\");\n }\n\n setCaptureError(null);\n setIsDetecting(false);\n\n try {\n const result = await cameraService.captureDocument(video, cropArea, {\n facingMode,\n format: \"jpeg\",\n jpegQuality: 0.95,\n });\n\n setLastCaptureMeta(result);\n stopDetection();\n setDocumentDetected(false);\n\n console.debug(\"Document captured\", {\n method: result.method,\n analysis: result.analysis,\n source: result.sourceDimensions,\n crop: result.cropDimensions,\n });\n\n onCapture(result.dataUrl);\n } catch (error) {\n console.error(\"Document capture failed\", error);\n setCaptureError(t(\"id_check.photo.capture_failed\", \"La capture a échoué. Veuillez réessayer.\"));\n setIsDetecting(true);\n throw error;\n }\n }, [facingMode, onCapture, stopDetection, maskRect, t]);\n\n const startCountdown = useCallback(() => {\n if (isCountingDown) return;\n\n setIsCountingDown(true);\n setCountdown(CAPTURE_COUNTDOWN_SECONDS);\n\n let timeLeft = CAPTURE_COUNTDOWN_SECONDS;\n countdownIntervalRef.current = window.setInterval(() => {\n timeLeft = Math.max(0, timeLeft - 0.1);\n setCountdown(parseFloat(timeLeft.toFixed(1)));\n\n if (timeLeft <= 0.1) {\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n setIsCountingDown(false);\n\n captureDocument().catch(() => {\n // Error is handled inside captureDocument, but keep the promise chain quiet\n });\n }\n }, 100);\n }, [captureDocument, isCountingDown]);\n\n const handleDetectionChange = useCallback(\n (result: DocumentDetectionResult) => {\n setDocumentDetected(result.hasDocument);\n\n if (!automaticCapture) {\n return;\n }\n\n if (result.hasDocument) {\n startCountdown();\n } else {\n clearCountdown();\n }\n },\n [automaticCapture, clearCountdown, startCountdown]\n );\n\n const cancelCaptureTimer = useCallback(() => {\n clearCountdown();\n setDocumentDetected(false);\n }, [clearCountdown]);\n\n useEffect(() => {\n let isCancelled = false;\n\n const initCamera = async () => {\n setCameraError(null);\n const result = await cameraService.startCamera(videoRef.current, {\n facingMode,\n idealResolution: { width: 4096, height: 3072 },\n preferImageCapture: true,\n });\n\n if (isCancelled) return;\n\n if (result.success) {\n setLastCaptureMeta(null);\n if (automaticCapture) {\n setIsDetecting(true);\n }\n } else if (result.error) {\n setCameraError(result.error);\n setIsDetecting(false);\n }\n };\n\n initCamera();\n\n return () => {\n isCancelled = true;\n clearCountdown();\n stopDetection();\n cameraService.stopCamera();\n setIsDetecting(false);\n };\n }, [facingMode, clearCountdown, stopDetection]);\n\n useEffect(() => {\n if (!isDetecting || !videoRef.current) {\n return;\n }\n\n let cancelled = false;\n\n documentDetectionService\n .startDocumentDetection(videoRef.current, (result) => {\n if (!cancelled) {\n handleDetectionChange(result);\n }\n })\n .then((handler) => {\n if (!cancelled) {\n detectionHandlerRef.current = handler;\n }\n })\n .catch((error) => {\n console.error(\"[DocumentDetection] Unable to start automatic capture:\", error);\n if (!cancelled) {\n setIsDetecting(false);\n }\n });\n\n return () => {\n cancelled = true;\n if (detectionHandlerRef.current) {\n detectionHandlerRef.current.stop();\n detectionHandlerRef.current = null;\n }\n };\n }, [handleDetectionChange, isDetecting]);\n\n const toggleCamera = () => {\n setFacingMode((prev) => (prev === \"environment\" ? \"user\" : \"environment\"));\n cancelCaptureTimer();\n };\n\n const handleRetry = () => {\n setCameraError(null);\n cancelCaptureTimer();\n setCaptureError(null);\n setIsDetecting(false);\n stopDetection();\n cameraService.stopCamera();\n\n cameraService\n .startCamera(videoRef.current, {\n facingMode,\n idealResolution: { width: 4096, height: 3072 },\n preferImageCapture: true,\n })\n .then((result) => {\n if (result.success) {\n setIsDetecting(true);\n } else if (result.error) {\n setCameraError(result.error);\n }\n });\n };\n const handleManualCapture = () => {\n clearCountdown();\n captureDocument().catch(() => {\n // captureDocument already logs and sets error state\n });\n };\n\n return (\n <div\n className=\"flex flex-col\"\n style={{\n position: isMobile ? \"fixed\" : \"relative\",\n inset: isMobile ? 0 : \"auto\",\n zIndex: isMobile ? 50 : \"auto\",\n height: \"100%\",\n width: \"100%\",\n }}\n >\n {/* Camera content area */}\n <div className=\"flex-1 relative overflow-hidden bg-black\">\n {cameraError ? (\n <div className=\"flex items-center justify-center h-full px-4 py-6\">\n <CameraError errorMessage={cameraError} onRetry={handleRetry} />\n </div>\n ) : (\n <>\n {/* Livestream of the camera*/}\n <video\n ref={videoRef}\n autoPlay\n playsInline\n muted\n className={`absolute inset-0 w-full h-full object-cover z-0 bg-black ${facingMode === \"user\" ? \"scale-x-[-1]\" : \"\"\n }`}\n />\n {/* Capture mode indicator */}\n <div className=\"absolute top-4 left-1/2 transform -translate-x-1/2 z-50\">\n <span className=\"text-white z-50 text-sm font-semibold drop-shadow-lg\">\n {automaticCapture ? (\n <span className=\"animate-pulse\">{t(\"id_check.photo.mode_autocapture\", \"Autocapture activée\")}</span>\n ) : (\n <span className=\"bg-orange-500 px-2 py-1 rounded hidden\">{t(\"id_check.photo.mode_manual\", \"Mode manuel\")}</span>\n )}\n </span>\n </div>\n {/* Mask */}\n <CameraMask\n isDetecting={isDetecting}\n isPortrait={isPortrait}\n facingMode={facingMode}\n isCountingDown={isCountingDown}\n countdown={countdown}\n maskType={maskType}\n onMaskRectChange={setMaskRect}\n />\n {/* Manual capture instructions */}\n <div className=\"absolute bottom-20 left-0 right-0 z-20 pointer-events-none\">\n <div className=\"text-center px-4\">\n <div className=\"bg-black bg-opacity-60 text-white text-sm px-4 py-2 rounded-lg inline-block\">\n {t(\"id_check.photo.position_document\", \"Positionnez le document\")}\n </div>\n </div>\n </div>\n {/* Button to change orientation */}\n <OrientationToggle onCameraToggle={toggleCamera} />\n </>\n )}\n </div>\n\n {/* Controls at the bottom */}\n <div className=\"relative z-20 bg-black bg-opacity-80 p-4\">\n <div className=\"flex flex-col items-center space-y-4\">\n {/* Manual capture button - always available */}\n <button\n onClick={handleManualCapture}\n className={`w-16 h-16 rounded-full border-4 border-white flex items-center justify-center transition-all bg-transparent hover:bg-white hover:bg-opacity-20 cursor-pointer`}\n >\n <div className=\"w-8 h-8 bg-white rounded-full\"></div>\n </button>\n\n {/* Status message */}\n <div className=\"text-white text-center text-sm\">\n <div className=\"flex items-center justify-center space-x-2\">\n <div\n className={`w-2 h-2 rounded-full ${automaticCapture\n ? \"bg-[#11E5C5] animate-pulse\"\n : \"bg-orange-500\"\n }`}\n ></div>\n <span>\n {automaticCapture\n ? t(\n \"id_check.photo.automatic_instruction\",\n \"Capture automatique active ou appuyez sur le bouton\"\n )\n : t(\n \"id_check.photo.manual_instruction\",\n \"Appuyez sur le bouton pour capturer\"\n )}\n </span>\n </div>\n {captureError && (\n <p className=\"text-red-400 text-xs mt-2 text-center\">\n {captureError}\n </p>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default Photo;\n"],"names":["useIsMobile","useRef","useState","useI18n","useCallback","useEffect","documentDetectionService","__awaiter","cameraService","_jsxs","_jsx","CameraError","CameraMask","OrientationToggle"],"mappings":"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"}
1
+ {"version":3,"file":"Photo.js","sources":["../../../../../src/components/id-check/Photo.tsx"],"sourcesContent":["import { useRef, useState, useEffect, useCallback } from \"react\";\nimport type { CameraFacingMode } from \"../../types/camera\";\nimport {\n cameraService,\n type CaptureDocumentResult,\n} from \"../../services/cameraService\";\nimport {\n documentDetectionService,\n type DocumentDetectionResult,\n} from \"../../services/documentDetectionService\";\nimport CameraError from \"./CameraError\";\nimport CameraMask from \"./CameraMask\";\nimport OrientationToggle from \"./OrientationToggle\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport useIsMobile from \"../../hooks/useIsMobile\";\n\ninterface PhotoProps {\n onCapture: (image: string) => void;\n automaticCapture?: boolean; // Controls whether automatic capture is enabled\n maskType?: \"id\" | \"document\";\n}\n\nconst Photo: React.FC<PhotoProps> = ({\n onCapture,\n automaticCapture = false,\n maskType = \"id\",\n}) => {\n const isMobile = useIsMobile(768);\n const videoRef = useRef<HTMLVideoElement>(null);\n const [isDetecting, setIsDetecting] = useState(false);\n const [facingMode, setFacingMode] = useState<CameraFacingMode>(\"environment\");\n const [cameraError, setCameraError] = useState<string | null>(null);\n const [isPortrait, setIsPortrait] = useState(\n window.matchMedia(\"(orientation: portrait)\").matches\n );\n const [isCountingDown, setIsCountingDown] = useState(false);\n const [countdown, setCountdown] = useState(0);\n const [documentDetected, setDocumentDetected] = useState(false);\n const [captureError, setCaptureError] = useState<string | null>(null);\n const [showCaptureFlash, setShowCaptureFlash] = useState(false);\n const { t } = useI18n();\n const [lastCaptureMeta, setLastCaptureMeta] =\n useState<CaptureDocumentResult | null>(null);\n const [maskRect, setMaskRect] = useState<{\n left: number;\n top: number;\n width: number;\n height: number;\n } | null>(null);\n\n const countdownIntervalRef = useRef<number | null>(null);\n const detectionHandlerRef = useRef<{ stop: () => void } | null>(null);\n const flashTimeoutRef = useRef<number | null>(null);\n\n const CAPTURE_FLASH_DURATION_MS = 300;\n\n const triggerCaptureFeedback = useCallback(() => {\n if (flashTimeoutRef.current) {\n clearTimeout(flashTimeoutRef.current);\n }\n setShowCaptureFlash(true);\n flashTimeoutRef.current = window.setTimeout(() => {\n setShowCaptureFlash(false);\n flashTimeoutRef.current = null;\n }, CAPTURE_FLASH_DURATION_MS);\n }, []);\n\n const CAPTURE_COUNTDOWN_SECONDS = 3;\n\n const clearCountdown = useCallback(() => {\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n setIsCountingDown(false);\n setCountdown(0);\n }, []);\n\n useEffect(() => {\n const handleOrientationChange = () => {\n setIsPortrait(window.matchMedia(\"(orientation: portrait)\").matches);\n };\n\n const mediaQuery = window.matchMedia(\"(orientation: portrait)\");\n mediaQuery.addEventListener(\"change\", handleOrientationChange);\n\n return () => {\n mediaQuery.removeEventListener(\"change\", handleOrientationChange);\n };\n }, []);\n\n const stopDetection = useCallback(() => {\n if (detectionHandlerRef.current) {\n detectionHandlerRef.current.stop();\n detectionHandlerRef.current = null;\n }\n documentDetectionService.stopDocumentDetection();\n }, []);\n\n const captureDocument = useCallback(async () => {\n if (!videoRef.current) {\n throw new Error(t(\"id_check.photo.errors.video_unavailable\", \"Le flux vidéo n'est pas disponible\"));\n }\n\n const video = videoRef.current;\n if (!video.videoWidth || !video.videoHeight) {\n throw new Error(\n t(\n \"id_check.photo.errors.video_dimensions_unavailable\",\n \"Dimensions vidéo indisponibles pour la capture\"\n )\n );\n }\n\n // Calculate crop area from mask if available\n let cropArea = null;\n if (maskRect) {\n const videoRect = video.getBoundingClientRect();\n\n // Calculate the actual displayed video dimensions accounting for object-fit: contain\n // Calculate the actual displayed video dimensions accounting for object-fit: cover\n const videoAspect = video.videoWidth / video.videoHeight;\n const displayAspect = videoRect.width / videoRect.height;\n\n let displayedWidth, displayedHeight, offsetX, offsetY;\n\n if (videoAspect > displayAspect) {\n // Video is wider than container - scaled to match height, sides cropped\n displayedHeight = videoRect.height;\n displayedWidth = videoRect.height * videoAspect;\n offsetY = 0;\n offsetX = (videoRect.width - displayedWidth) / 2;\n } else {\n // Video is taller than container - scaled to match width, top/bottom cropped\n displayedWidth = videoRect.width;\n displayedHeight = videoRect.width / videoAspect;\n offsetX = 0;\n offsetY = (videoRect.height - displayedHeight) / 2;\n }\n\n // Calculate the scale between actual displayed video and real video dimensions\n const scaleX = video.videoWidth / displayedWidth;\n const scaleY = video.videoHeight / displayedHeight;\n\n // Convert mask coordinates from screen space to video space\n // Account for video element offset and displayed video offset\n const cropX = (maskRect.left - videoRect.left - offsetX) * scaleX;\n const cropY = (maskRect.top - videoRect.top - offsetY) * scaleY;\n const cropWidth = maskRect.width * scaleX;\n const cropHeight = maskRect.height * scaleY;\n\n // Ensure crop area is within video bounds\n cropArea = {\n x: Math.max(0, Math.round(cropX)),\n y: Math.max(0, Math.round(cropY)),\n width: Math.min(video.videoWidth - Math.max(0, cropX), Math.round(cropWidth)),\n height: Math.min(video.videoHeight - Math.max(0, cropY), Math.round(cropHeight)),\n };\n\n console.debug(\"[Photo] Calculated crop area from mask\", {\n maskRect,\n videoRect: { left: videoRect.left, top: videoRect.top, width: videoRect.width, height: videoRect.height },\n videoDimensions: { width: video.videoWidth, height: video.videoHeight },\n displayedDimensions: { width: displayedWidth, height: displayedHeight },\n offset: { x: offsetX, y: offsetY },\n scale: { x: scaleX, y: scaleY },\n cropArea,\n });\n } else {\n console.debug(\"[Photo] No mask rect available, capturing full frame\");\n }\n\n setCaptureError(null);\n setIsDetecting(false);\n triggerCaptureFeedback();\n\n try {\n const result = await cameraService.captureDocument(video, cropArea, {\n facingMode,\n format: \"jpeg\",\n jpegQuality: 0.95,\n });\n\n setLastCaptureMeta(result);\n stopDetection();\n setDocumentDetected(false);\n\n console.debug(\"Document captured\", {\n method: result.method,\n analysis: result.analysis,\n source: result.sourceDimensions,\n crop: result.cropDimensions,\n });\n\n onCapture(result.dataUrl);\n } catch (error) {\n console.error(\"Document capture failed\", error);\n setCaptureError(t(\"id_check.photo.capture_failed\", \"La capture a échoué. Veuillez réessayer.\"));\n setIsDetecting(true);\n throw error;\n }\n }, [facingMode, onCapture, stopDetection, maskRect, t, triggerCaptureFeedback]);\n\n const startCountdown = useCallback(() => {\n if (isCountingDown) return;\n\n setIsCountingDown(true);\n setCountdown(CAPTURE_COUNTDOWN_SECONDS);\n\n let timeLeft = CAPTURE_COUNTDOWN_SECONDS;\n countdownIntervalRef.current = window.setInterval(() => {\n timeLeft = Math.max(0, timeLeft - 0.1);\n setCountdown(parseFloat(timeLeft.toFixed(1)));\n\n if (timeLeft <= 0.1) {\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n setIsCountingDown(false);\n\n captureDocument().catch(() => {\n // Error is handled inside captureDocument, but keep the promise chain quiet\n });\n }\n }, 100);\n }, [captureDocument, isCountingDown]);\n\n const handleDetectionChange = useCallback(\n (result: DocumentDetectionResult) => {\n setDocumentDetected(result.hasDocument);\n\n if (!automaticCapture) {\n return;\n }\n\n if (result.hasDocument) {\n startCountdown();\n } else {\n clearCountdown();\n }\n },\n [automaticCapture, clearCountdown, startCountdown]\n );\n\n const cancelCaptureTimer = useCallback(() => {\n clearCountdown();\n setDocumentDetected(false);\n }, [clearCountdown]);\n\n useEffect(() => {\n let isCancelled = false;\n\n const initCamera = async () => {\n setCameraError(null);\n const result = await cameraService.startCamera(videoRef.current, {\n facingMode,\n idealResolution: { width: 4096, height: 3072 },\n preferImageCapture: true,\n });\n\n if (isCancelled) return;\n\n if (result.success) {\n setLastCaptureMeta(null);\n // Detection also runs in manual mode: it only drives the visual\n // feedback on the mask (documentDetected), it never starts the\n // auto-capture countdown unless automaticCapture is true (see\n // handleDetectionChange).\n setIsDetecting(true);\n } else if (result.error) {\n setCameraError(result.error);\n setIsDetecting(false);\n }\n };\n\n initCamera();\n\n return () => {\n isCancelled = true;\n clearCountdown();\n stopDetection();\n cameraService.stopCamera();\n setIsDetecting(false);\n if (flashTimeoutRef.current) {\n clearTimeout(flashTimeoutRef.current);\n flashTimeoutRef.current = null;\n }\n };\n }, [facingMode, clearCountdown, stopDetection]);\n\n useEffect(() => {\n if (!isDetecting || !videoRef.current) {\n return;\n }\n\n let cancelled = false;\n\n documentDetectionService\n .startDocumentDetection(videoRef.current, (result) => {\n if (!cancelled) {\n handleDetectionChange(result);\n }\n })\n .then((handler) => {\n if (!cancelled) {\n detectionHandlerRef.current = handler;\n }\n })\n .catch((error) => {\n console.error(\"[DocumentDetection] Unable to start automatic capture:\", error);\n if (!cancelled) {\n setIsDetecting(false);\n }\n });\n\n return () => {\n cancelled = true;\n if (detectionHandlerRef.current) {\n detectionHandlerRef.current.stop();\n detectionHandlerRef.current = null;\n }\n };\n }, [handleDetectionChange, isDetecting]);\n\n const toggleCamera = () => {\n setFacingMode((prev) => (prev === \"environment\" ? \"user\" : \"environment\"));\n cancelCaptureTimer();\n };\n\n const handleRetry = () => {\n setCameraError(null);\n cancelCaptureTimer();\n setCaptureError(null);\n setIsDetecting(false);\n stopDetection();\n cameraService.stopCamera();\n\n cameraService\n .startCamera(videoRef.current, {\n facingMode,\n idealResolution: { width: 4096, height: 3072 },\n preferImageCapture: true,\n })\n .then((result) => {\n if (result.success) {\n setIsDetecting(true);\n } else if (result.error) {\n setCameraError(result.error);\n }\n });\n };\n const handleManualCapture = () => {\n clearCountdown();\n captureDocument().catch(() => {\n // captureDocument already logs and sets error state\n });\n };\n\n return (\n <div\n className=\"flex flex-col\"\n style={{\n position: isMobile ? \"fixed\" : \"relative\",\n inset: isMobile ? 0 : \"auto\",\n zIndex: isMobile ? 50 : \"auto\",\n height: \"100%\",\n width: \"100%\",\n }}\n >\n {/* Camera content area */}\n <div className=\"flex-1 relative overflow-hidden bg-black\">\n {cameraError ? (\n <div className=\"flex items-center justify-center h-full px-4 py-6\">\n <CameraError errorMessage={cameraError} onRetry={handleRetry} />\n </div>\n ) : (\n <>\n {/* Livestream of the camera*/}\n <video\n ref={videoRef}\n autoPlay\n playsInline\n muted\n className={`absolute inset-0 w-full h-full object-cover z-0 bg-black ${facingMode === \"user\" ? \"scale-x-[-1]\" : \"\"\n }`}\n />\n {/* Capture mode indicator */}\n <div className=\"absolute top-4 left-1/2 transform -translate-x-1/2 z-50\">\n <span className=\"text-white z-50 text-sm font-semibold drop-shadow-lg\">\n {automaticCapture ? (\n <span className=\"animate-pulse\">{t(\"id_check.photo.mode_autocapture\", \"Autocapture activée\")}</span>\n ) : (\n <span className=\"bg-orange-500 px-2 py-1 rounded hidden\">{t(\"id_check.photo.mode_manual\", \"Mode manuel\")}</span>\n )}\n </span>\n </div>\n {/* Mask */}\n <CameraMask\n isDetecting={isDetecting}\n isPortrait={isPortrait}\n facingMode={facingMode}\n isCountingDown={isCountingDown}\n countdown={countdown}\n maskType={maskType}\n documentDetected={documentDetected}\n onMaskRectChange={setMaskRect}\n />\n {/* Manual capture instructions */}\n <div className=\"absolute bottom-20 left-0 right-0 z-20 pointer-events-none\">\n <div className=\"text-center px-4\">\n <div className=\"bg-black bg-opacity-60 text-white text-sm px-4 py-2 rounded-lg inline-block\">\n {t(\"id_check.photo.position_document\", \"Posez le document à plat ou tenez-le dans le cadre\")}\n </div>\n </div>\n </div>\n {/* Button to change orientation */}\n <OrientationToggle onCameraToggle={toggleCamera} />\n {/* Capture confirmation flash - fires for manual and auto capture alike */}\n {showCaptureFlash && (\n <div\n data-testid=\"capture-flash\"\n className=\"absolute inset-0 z-40 bg-white pointer-events-none animate-pulse\"\n />\n )}\n </>\n )}\n </div>\n\n {/* Controls at the bottom */}\n <div className=\"relative z-20 bg-black bg-opacity-80 p-4\">\n <div className=\"flex flex-col items-center space-y-4\">\n {/* Manual capture button - always available */}\n <button\n onClick={handleManualCapture}\n className={`w-16 h-16 rounded-full border-4 border-white flex items-center justify-center transition-all duration-150 bg-transparent hover:bg-white hover:bg-opacity-20 cursor-pointer ${showCaptureFlash ? \"scale-90 ring-4 ring-[#11E5C5]\" : \"\"\n }`}\n >\n <div className=\"w-8 h-8 bg-white rounded-full\"></div>\n </button>\n\n {/* Status message */}\n <div className=\"text-white text-center text-sm\">\n <div className=\"flex items-center justify-center space-x-2\">\n <div\n className={`w-2 h-2 rounded-full ${automaticCapture\n ? \"bg-[#11E5C5] animate-pulse\"\n : \"bg-orange-500\"\n }`}\n ></div>\n <span>\n {automaticCapture\n ? t(\n \"id_check.photo.automatic_instruction\",\n \"Capture automatique active ou appuyez sur le bouton\"\n )\n : t(\n \"id_check.photo.manual_instruction\",\n \"Appuyez sur le bouton pour capturer\"\n )}\n </span>\n </div>\n {captureError && (\n <p className=\"text-red-400 text-xs mt-2 text-center\">\n {captureError}\n </p>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default Photo;\n"],"names":["useIsMobile","useRef","useState","useI18n","useCallback","useEffect","documentDetectionService","__awaiter","cameraService","_jsxs","_jsx","CameraError","_Fragment","CameraMask","OrientationToggle"],"mappings":"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"}