@swan-admin/swan-web-component 1.0.86 → 1.0.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BodyScan-CP2sxAs_.js +2 -0
- package/dist/BodyScan-CP2sxAs_.js.map +1 -0
- package/dist/BodyScan-M3PbHzI8.js +2 -0
- package/dist/BodyScan-M3PbHzI8.js.map +1 -0
- package/dist/FaceScan-BmbbbsFP.js +2 -0
- package/dist/FaceScan-BmbbbsFP.js.map +1 -0
- package/dist/FaceScan-DVAAtG8v.js +2 -0
- package/dist/FaceScan-DVAAtG8v.js.map +1 -0
- package/dist/{LoadingScreen-DgDeiI0O.js → LoadingScreen-DCHEgS3u.js} +2 -2
- package/dist/LoadingScreen-DCHEgS3u.js.map +1 -0
- package/dist/{LoadingScreen-C__KGOn0.js → LoadingScreen-vewtx75y.js} +2 -2
- package/dist/LoadingScreen-vewtx75y.js.map +1 -0
- package/dist/bodyScan.d.ts +2 -2
- package/dist/bodyScan.js +1 -1
- package/dist/bodyScan.mjs +1 -1
- package/dist/faceScan.d.ts +2 -2
- package/dist/faceScan.js +1 -1
- package/dist/faceScan.mjs +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/{interfaces-K-OZcTWn.d.ts → interfaces-DUnjeJHY.d.ts} +1 -2
- package/package.json +1 -1
- package/dist/BodyScan-CD4TAtOe.js +0 -2
- package/dist/BodyScan-CD4TAtOe.js.map +0 -1
- package/dist/BodyScan-C_rKR94B.js +0 -2
- package/dist/BodyScan-C_rKR94B.js.map +0 -1
- package/dist/FaceScan-CMbTqaDD.js +0 -2
- package/dist/FaceScan-CMbTqaDD.js.map +0 -1
- package/dist/FaceScan-nLKzJkWU.js +0 -2
- package/dist/FaceScan-nLKzJkWU.js.map +0 -1
- package/dist/LoadingScreen-C__KGOn0.js.map +0 -1
- package/dist/LoadingScreen-DgDeiI0O.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaceScan-DVAAtG8v.js","sources":["../src/customHooks/useFaceScan.ts","../src/components/faceScan/FaceScanErrorScreen.tsx","../src/components/faceScan/FaceScanGuide.tsx","../src/components/faceScan/FaceScanStep.tsx","../src/components/faceScan/FaceScan.tsx"],"sourcesContent":["import {\n useState,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n RefObject,\n} from \"react\";\n// 1. Use TYPE-ONLY imports. These are erased at build time and won't crash SSR.\nimport type { PoseDetector } from \"@tensorflow-models/pose-detection\";\nimport type * as tf from \"@tensorflow/tfjs\";\n\nimport { posthog } from \"posthog-js\";\nimport speechService from \"../utils/service/speechService\";\nimport { videoConstraints, voiceOverAssetsPath } from \"../utils/constants\";\n\n/**\n * useFaceScan Hook with PostHog Analytics\n * Refactored for Zero-Config SSR/CSR Compatibility\n */\n\n// Debounce utility\nfunction debounce(fn: (...args: any) => void, delay: number) {\n let timer: number | NodeJS.Timeout;\n return (...args: any) => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => fn(...args), delay);\n };\n}\n\n// Global Singleton Cache (Preserves state across re-renders)\nlet preloadedDetector: PoseDetector | null = null;\nlet isPreloading = false;\n\n// 2. Async Preloader with Dynamic Imports\nexport const preloadDetector = async (): Promise<PoseDetector | null> => {\n // Guard: Never run on server\n if (typeof window === \"undefined\") return null;\n if (preloadedDetector) return preloadedDetector;\n if (isPreloading) {\n // Simple wait mechanism if already loading\n while (isPreloading) {\n await new Promise(r => setTimeout(r, 100));\n if (preloadedDetector) return preloadedDetector;\n }\n }\n\n isPreloading = true;\n\n try {\n // DYNAMIC IMPORTS: Only fetch these heavy bundles in the browser\n const [tf, poseDetection] = await Promise.all([\n import(\"@tensorflow/tfjs\"),\n import(\"@tensorflow-models/pose-detection\")\n ]);\n\n // Initialize Backend\n await tf.setBackend(\"webgl\");\n await tf.ready();\n\n const detector = await poseDetection.createDetector(\n poseDetection.SupportedModels.BlazePose,\n {\n runtime: \"tfjs\",\n modelType: \"full\",\n }\n );\n\n // Dummy video warmup (Performance Optimization)\n // This runs the model once on a blank canvas to \"wake up\" the GPU\n // so the first user frame detects instantly.\n const dummyCanvas = document.createElement(\"canvas\");\n dummyCanvas.width = videoConstraints.width;\n dummyCanvas.height = videoConstraints.height;\n const ctx = dummyCanvas.getContext(\"2d\");\n if (ctx) {\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, dummyCanvas.width, dummyCanvas.height);\n try {\n await detector.estimatePoses(dummyCanvas);\n } catch (e) {\n console.warn(\"Warmup frame failed (non-fatal):\", e);\n }\n }\n\n preloadedDetector = detector;\n return detector;\n } catch (err) {\n console.error(\"Failed to preload detector:\", err);\n return null;\n } finally {\n isPreloading = false;\n }\n};\n\ntype Point = [number, number, number];\n\nfunction useFaceScan({\n faceScanId,\n onValidPose,\n onScanComplete,\n onModelReady,\n onStartRecording,\n shopDomain,\n}: {\n faceScanId: string;\n onValidPose?: () => void;\n onScanComplete?: () => void;\n onModelReady?: () => void;\n onStartRecording: () => void;\n shopDomain: string;\n}) {\n const detectorRef = useRef<PoseDetector | null>(null);\n const [scanStage, setScanStage] = useState(0);\n const [consecutiveValid, setConsecutiveValid] = useState(0);\n const [isModelLoaded, setIsModelLoaded] = useState(false);\n const [isScanningActive, setIsScanningActive] = useState(false);\n \n const utteranceRef = useRef<SpeechSynthesisUtterance | null>(null);\n const scanStageRef = useRef(scanStage);\n const consecutiveValidRef = useRef(consecutiveValid);\n const validityBufferRef = useRef<boolean[]>([]);\n const lastSpokenMessageRef = useRef(\"\");\n const lastSpokenTimeRef = useRef(0);\n const voiceEnabledRef = useRef(false);\n \n const VALIDITY_BUFFER_LENGTH = 10;\n const CONSECUTIVE_VALID_LENGTH = 2;\n const TOTAL_STAGES = 4;\n const POSE_TRACKING_INTERVAL = 4000;\n const lastPoseTrackingTimeRef = useRef(0);\n\n // Safe iOS detection (SSR safe)\n const isIOS = typeof navigator !== 'undefined' && (\n /iPad|iPhone|iPod/.test(navigator.userAgent) ||\n (navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1)\n );\n\n const directionMessages = useMemo(\n () => [\n \"Face front\",\n \"Turn head fully left\",\n \"Turn head fully right\",\n \"Smile facing front\",\n ],\n []\n );\n\n const debouncedTrackPoseDetection = useMemo(\n () =>\n debounce((payload) => {\n posthog.capture(`${shopDomain}/face_scan_pose_detection`, payload);\n }, 4000),\n [shopDomain]\n );\n\n const trackPoseDetection = useCallback(\n (\n faceKeypoints: Point[],\n bodyKeypoints: Point[],\n stage: number,\n headValid: boolean,\n bodyInvalid: boolean,\n consecutiveValidCount: number\n ) => {\n const now = Date.now();\n if (now - lastPoseTrackingTimeRef.current < POSE_TRACKING_INTERVAL) {\n return;\n }\n\n lastPoseTrackingTimeRef.current = now;\n\n try {\n const nose = faceKeypoints[0] || [0, 0, 0];\n const leftEye = faceKeypoints[2] || [0, 0, 0];\n const rightEye = faceKeypoints[5] || [0, 0, 0];\n const leftMouth = faceKeypoints[9] || [0, 0, 0];\n const rightMouth = faceKeypoints[10] || [0, 0, 0];\n\n const faceKeypointScores = faceKeypoints\n .map((kp: Point) => kp[2])\n .filter((score: number) => score > 0);\n const avgFaceScore =\n faceKeypointScores.length > 0\n ? faceKeypointScores.reduce((a, b) => a + b, 0) /\n faceKeypointScores.length\n : 0;\n\n const bodyKeypointScores = bodyKeypoints\n .map((kp: Point) => kp[2])\n .filter((score: number) => score > 0);\n const avgBodyScore =\n bodyKeypointScores.length > 0\n ? bodyKeypointScores.reduce((a: number, b: number) => a + b, 0) /\n bodyKeypointScores.length\n : 0;\n\n const eyeDistance = Math.abs(leftEye[0] - rightEye[0]);\n const noseToRight = nose[0] - rightEye[0];\n const noseToLeft = leftEye[0] - nose[0];\n\n let expectedPosition = \"frontal\";\n if (stage === 1) expectedPosition = \"left\";\n else if (stage === 2) expectedPosition = \"right\";\n else if (stage === 3) expectedPosition = \"frontal_smile\";\n\n const payload = {\n faceScanId,\n stage,\n timestamp: new Date().toISOString(),\n data: JSON.stringify({\n headValid,\n bodyInvalid,\n consecutiveValid: consecutiveValidCount,\n avgFaceScore: parseFloat(avgFaceScore.toFixed(3)),\n avgBodyScore: parseFloat(avgBodyScore.toFixed(3)),\n faceKeypointsDetected: faceKeypointScores.length,\n bodyKeypointsDetected: bodyKeypointScores.length,\n eyeDistance: parseFloat(eyeDistance.toFixed(2)),\n noseToRightRatio: parseFloat((noseToRight / eyeDistance).toFixed(3)),\n noseToLeftRatio: parseFloat((noseToLeft / eyeDistance).toFixed(3)),\n noseScore: parseFloat(nose[2].toFixed(3)),\n leftEyeScore: parseFloat(leftEye[2].toFixed(3)),\n rightEyeScore: parseFloat(rightEye[2].toFixed(3)),\n leftMouthScore: parseFloat(leftMouth[2].toFixed(3)),\n rightMouthScore: parseFloat(rightMouth[2].toFixed(3)),\n expectedPosition,\n }),\n };\n debouncedTrackPoseDetection(payload);\n } catch (error) {\n console.warn(\"Failed to track pose detection:\", error);\n }\n },\n [faceScanId, debouncedTrackPoseDetection]\n );\n\n const enableVoiceCommands = () => {\n voiceEnabledRef.current = true;\n if (typeof window !== 'undefined' && isIOS && \"speechSynthesis\" in window) {\n const silentUtterance = new SpeechSynthesisUtterance(\"\");\n silentUtterance.volume = 0;\n speechSynthesis.speak(silentUtterance);\n }\n };\n\n const startScanSequence = () => {\n posthog.capture(`${shopDomain}/face_scan_detection_started`, {\n faceScanId,\n stage: scanStageRef.current,\n timestamp: new Date().toISOString(),\n stageName: directionMessages[scanStageRef.current],\n });\n\n setTimeout(() => {\n setIsScanningActive(true);\n }, 1500);\n };\n\n const isHeadInPosition = (stage: number, keypoints: Point[]) => {\n // ... logic unchanged ...\n const nose = 0;\n const leftEye = 2;\n const rightEye = 5;\n const leftMouth = 9;\n const rightMouth = 10;\n\n const minScore = 0.2;\n if (\n !keypoints[nose] || !keypoints[leftEye] || !keypoints[rightEye] ||\n keypoints[nose][2] < minScore ||\n keypoints[leftEye][2] < minScore ||\n keypoints[rightEye][2] < minScore\n ) {\n return false;\n }\n\n const eyesToMouthVerticalDistance =\n 0.5 * (keypoints[rightMouth][1] + keypoints[leftMouth][1]) -\n 0.5 * (keypoints[rightEye][1] + keypoints[leftEye][1]);\n\n const faceTiltedness =\n (0.5 * (keypoints[rightMouth][1] + keypoints[leftMouth][1]) -\n keypoints[nose][1]) /\n eyesToMouthVerticalDistance;\n\n const faceIsTilted = faceTiltedness > 0.7 || faceTiltedness < 0.3;\n\n const faceIsVertical =\n Math.abs(keypoints[leftEye][1] - keypoints[rightEye][1]) <\n 0.5 * eyesToMouthVerticalDistance &&\n Math.abs(keypoints[leftMouth][1] - keypoints[rightMouth][1]) <\n 0.5 * eyesToMouthVerticalDistance;\n\n const eyeDistance = keypoints[leftEye][0] - keypoints[rightEye][0];\n const noseToRight = keypoints[nose][0] - keypoints[rightEye][0];\n const noseToLeft = keypoints[leftEye][0] - keypoints[nose][0];\n\n const frontalFace =\n noseToRight > 0.4 * eyeDistance && noseToRight < 0.6 * eyeDistance;\n const fullLeft = noseToRight > 0.85 * eyeDistance;\n const fullRight = noseToLeft > 0.85 * eyeDistance;\n\n switch (stage) {\n case 0:\n return !faceIsTilted && faceIsVertical && frontalFace;\n case 1:\n return !faceIsTilted && faceIsVertical && fullLeft;\n case 2:\n return !faceIsTilted && faceIsVertical && fullRight;\n case 3:\n return !faceIsTilted && faceIsVertical && frontalFace;\n default:\n return false;\n }\n };\n\n const faceScanDetector = async (\n webcamRef: RefObject<HTMLVideoElement | null>,\n canvasRef: RefObject<HTMLCanvasElement | null>\n ) => {\n if (\n !detectorRef.current ||\n !webcamRef.current ||\n !isModelLoaded ||\n !isScanningActive\n )\n return;\n\n // Safety: ensure video is actually playing with data\n if (webcamRef.current.readyState < 2) return;\n\n try {\n const poses = await detectorRef.current.estimatePoses(webcamRef.current);\n if (poses.length > 0) {\n const faceKeypoints: Point[] = [];\n const bodyKeypoints: Point[] = [];\n poses[0].keypoints.forEach((landmark, idx) => {\n const score = landmark.score ?? 0;\n const point: Point = [landmark.x ?? -1, landmark.y ?? -1, score];\n if (idx <= 10) faceKeypoints.push(point);\n else bodyKeypoints.push(point);\n });\n\n // Optional drawing\n if (canvasRef?.current) {\n const ctx = canvasRef.current.getContext(\"2d\");\n const { width, height } = canvasRef.current;\n if (ctx) {\n ctx.clearRect(0, 0, width, height);\n\n const progress = Math.min(\n consecutiveValidRef.current / CONSECUTIVE_VALID_LENGTH,\n 1\n );\n const radius = height * 0.35;\n ctx.beginPath();\n ctx.strokeStyle = \"#00ff00\";\n ctx.lineWidth = 6;\n ctx.arc(\n width / 2,\n height / 2,\n radius + 10,\n -Math.PI / 2,\n -Math.PI / 2 + progress * 2 * Math.PI\n );\n ctx.stroke();\n }\n }\n\n const headValid = isHeadInPosition(scanStageRef.current, faceKeypoints);\n const bodyInvalid =\n bodyKeypoints.slice(2).filter((p) => p[2] > 0.7).length <= 2;\n\n validityBufferRef.current.push(headValid && bodyInvalid);\n if (validityBufferRef.current.length > VALIDITY_BUFFER_LENGTH) {\n validityBufferRef.current.shift();\n }\n\n const validCount = validityBufferRef.current.filter(Boolean).length;\n if (validCount >= 2) {\n const nextValid = consecutiveValidRef.current + 1;\n setConsecutiveValid(nextValid);\n } else {\n setConsecutiveValid(Math.max(0, consecutiveValidRef.current - 1));\n }\n\n if (consecutiveValidRef.current >= CONSECUTIVE_VALID_LENGTH) {\n onValidPose?.();\n\n const nextStage = scanStageRef.current + 1;\n setConsecutiveValid(0);\n validityBufferRef.current = [];\n setScanStage(nextStage);\n setIsScanningActive(false);\n\n (async () => {\n await speechService.playAudio(\n `${voiceOverAssetsPath}face-scan-vos/Sound-effect.mp3`\n );\n posthog.capture(\n `${shopDomain}/face_scan_detection_stage_completed`,\n {\n faceScanId,\n completedStage: scanStageRef.current,\n nextStage,\n timestamp: new Date().toISOString(),\n totalStages: TOTAL_STAGES,\n stageName: directionMessages[scanStageRef.current],\n }\n );\n \n if (nextStage === 1 && onStartRecording) {\n onStartRecording();\n }\n if (nextStage >= TOTAL_STAGES) {\n onScanComplete?.();\n } else {\n let nextSound = null;\n switch (nextStage) {\n case 1: nextSound = \"Left.mp3\"; break;\n case 2: nextSound = \"Right.mp3\"; break;\n case 3: nextSound = \"Smile.mp3\"; break;\n }\n if (nextSound) {\n await speechService.playAudio(\n `${voiceOverAssetsPath}face-scan-vos/${nextSound}`\n );\n }\n startScanSequence();\n }\n })();\n }\n\n trackPoseDetection(\n faceKeypoints,\n bodyKeypoints,\n scanStageRef.current,\n headValid,\n bodyInvalid,\n consecutiveValidRef.current\n );\n }\n } catch (err) {\n console.error(\"Pose detection error:\", err);\n }\n };\n\n const initializeModels = async () => {\n // 3. Browser Guard\n if (typeof window === 'undefined') return;\n\n try {\n console.log(\"Initializing Face Scan...\");\n // Calls our safe, dynamic preloader\n const detector = await preloadDetector();\n \n if (detector) {\n detectorRef.current = detector;\n console.log(\"Face scan model loaded successfully\");\n setIsModelLoaded(true);\n onModelReady?.();\n }\n } catch (err) {\n console.error(\"Error initializing face scan:\", err);\n }\n };\n\n const disposeModelAndTf = async () => {\n // Optional: We might NOT want to dispose if we want to keep the cache \n // for re-mounting. But if you must dispose:\n try {\n setIsModelLoaded(false);\n // NOTE: We generally don't dispose the detector if we want to reuse it \n // via the 'preloadedDetector' global variable.\n // If you dispose here, make sure to set 'preloadedDetector = null' too.\n /* if (detectorRef.current) {\n await detectorRef.current.dispose();\n detectorRef.current = null;\n preloadedDetector = null; // Clear global cache if disposing\n }\n */\n } catch (err) {\n console.error(\"Error disposing resources:\", err);\n } finally {\n // Reset state\n setScanStage(0);\n setConsecutiveValid(0);\n scanStageRef.current = 0;\n consecutiveValidRef.current = 0;\n validityBufferRef.current = [];\n }\n };\n\n const resetScan = () => {\n posthog.capture(`${shopDomain}/face_scan_reset`, {\n faceScanId,\n stage: scanStageRef.current,\n timestamp: new Date().toISOString(),\n stageName: directionMessages[scanStageRef.current],\n consecutiveValid: consecutiveValidRef.current,\n });\n\n setScanStage(0);\n setConsecutiveValid(0);\n setIsScanningActive(false);\n scanStageRef.current = 0;\n consecutiveValidRef.current = 0;\n validityBufferRef.current = [];\n lastSpokenMessageRef.current = \"\";\n lastSpokenTimeRef.current = 0;\n voiceEnabledRef.current = false;\n if (utteranceRef.current) {\n speechSynthesis.cancel();\n utteranceRef.current = null;\n }\n };\n\n useEffect(() => {\n initializeModels();\n return () => {\n disposeModelAndTf();\n };\n }, []);\n\n useEffect(() => {\n scanStageRef.current = scanStage;\n }, [scanStage]);\n\n useEffect(() => {\n consecutiveValidRef.current = consecutiveValid;\n }, [consecutiveValid]);\n\n return {\n faceScanDetector,\n scanStage,\n setScanStage,\n consecutiveValid,\n isModelLoaded,\n resetScan,\n enableVoiceCommands,\n startScanSequence,\n isScanningActive,\n };\n}\n\nexport default useFaceScan;","import { ArrowRight } from \"lucide-react\";\nimport Header from \"../Header\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\nimport { useContext } from \"react\";\nimport { LanguageKeys } from \"../../utils/languageKeys\";\nimport { LanguageContext } from \"../../utils/context/languageContext\";\nimport { Config } from \"../../types/interfaces\";\n\nfunction FaceScanErrorScreen({ resetScanState, loading, config }: { resetScanState?: () => void; loading?: boolean; config?: Config }) {\n\tconst { translate,preferredLanguage } = useContext(LanguageContext) || {};\nconsole.log(preferredLanguage,\"preferredLanguage\");\n\nconsole.log(translate?.(LanguageKeys.scanFailed),\"translate\");\n\n\n\treturn (\n\t\t<div className=\"fixed top-[0] left-[0] z-[999] flex justify-center items-center w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t<div className=\"flex flex-col w-full items-center p-[1rem] rounded-lg \">\n\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t<div className=\"flex flex-col items-center w-full\">\n\t\t\t\t\t<h2\n\t\t\t\t\t\tclassName=\"text-xl font-semibold text-gray-800 \"\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{translate?.(LanguageKeys.scanFailed)}\n\t\t\t\t\t</h2>\n\t\t\t\t\t<p\n\t\t\t\t\t\tclassName=\"mb-[1.5rem]\"\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\tcolor: config?.style?.subheading?.subheadingColor || \"#4b5563\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{translate?.(LanguageKeys.clickToResetScan)}\n\t\t\t\t\t</p>\n\t\t\t\t\t<SpecificButton\n\t\t\t\t\t\tdisabled={loading}\n\t\t\t\t\t\tclassName=\"w-full h-[45px] shadow-[0px_1px_2px_0px_#00000040] text-[16px]\"\n\t\t\t\t\t\tbuttonText={translate?.(LanguageKeys.resetScan)}\n\t\t\t\t\t\tpostfixIcon={<ArrowRight />}\n\t\t\t\t\t\tbuttonFunc={() => resetScanState?.()}\n\t\t\t\t\t\tresolvedConfig={config}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport default FaceScanErrorScreen;\n","import { FaceScanGuideProps } from \"../../types/interfaces\";\nimport Header from \"../Header\";\nimport { GenderType } from \"../../utils/enums\";\nimport { directionMessages, FACE_SCAN_HEADSHOT, glassesOffVideo, maleGlassesOffVideo } from \"../../utils/constants\";\nimport { LanguageContext } from \"../../utils/context/languageContext\";\nimport { useContext } from \"react\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\nimport { LanguageKeys } from \"../../utils/languageKeys\";\n\nfunction FaceScanGuide({ stage, videoLoading, setVideoLoading, videoError, setVideoError, gender, config, btnConfig }: FaceScanGuideProps) {\n\tconst { translate } = useContext(LanguageContext) || {};\n\n\n\n\tif (stage === -1) {\n\t\treturn (\n\t\t\t<div className=\"text-center p-[16px] w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t\t<div className=\"w-full\">\n\t\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t\t<h2\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{translate?.(LanguageKeys.faceVisible)}\n\t\t\t\t\t</h2>\n\t\t\t\t\t{videoLoading && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"mb-4 flex items-center justify-center\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\t\tcolor: config?.style?.subheading?.subheadingColor || \"#4b5563\",\n\t\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{translate?.(LanguageKeys.loadingVideo)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{videoError && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"mb-4 text-red-600\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tfontFamily: config?.style?.subheading?.subheadingFontFamily || \"'Inter', sans-serif\",\n\t\t\t\t\t\t\t\tfontSize: config?.style?.subheading?.subheadingFontSize || \"14px\",\n\t\t\t\t\t\t\t\tcolor: \"#ff0000\",\n\t\t\t\t\t\t\t\tfontWeight: config?.style?.subheading?.subheadingFontWeight || \"normal\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{translate?.(LanguageKeys.videoLoadFailed)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{!videoError && (\n\t\t\t\t\t\t<div className={` w-[100px] mx-auto`}>\n\t\t\t\t\t\t\t<video\n\t\t\t\t\t\t\t\tsrc={gender === GenderType.Male ? maleGlassesOffVideo : glassesOffVideo}\n\t\t\t\t\t\t\t\tautoPlay\n\t\t\t\t\t\t\t\tloop\n\t\t\t\t\t\t\t\tcontrols={false}\n\t\t\t\t\t\t\t\tmuted\n\t\t\t\t\t\t\t\tplaysInline\n\t\t\t\t\t\t\t\tclassName=\"h-full w-full object-contain border-none\"\n\t\t\t\t\t\t\t\tonCanPlay={() => setVideoLoading(false)}\n\t\t\t\t\t\t\t\tonLoadStart={() => setVideoLoading(true)}\n\t\t\t\t\t\t\t\tonError={() => setVideoError(true)}\n\t\t\t\t\t\t\t\taria-label=\"Instructional video: Please remove your glasses before starting the scan.\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex justify-center w-full p-[1rem]\">\n\t\t\t\t\t<SpecificButton\n\t\t\t\t\t\tdisabled={btnConfig.isDisabled}\n\t\t\t\t\t\tclassName=\"!w-[60px] !h-[35px] !py-0 !px-0\"\n\t\t\t\t\t\tbuttonText={translate?.(btnConfig.label)}\n\t\t\t\t\t\tpostfixIcon={btnConfig?.icon}\n\t\t\t\t\t\tbuttonFunc={btnConfig.onClick}\n\t\t\t\t\t\tresolvedConfig={config}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"text-center p-[16px] w-full h-full\" style={{ background: config?.style?.base?.backgroundColor }}>\n\t\t\t<div className=\"w-full\">\n\t\t\t\t<Header noTitle resolvedConfig={config} />\n\t\t\t\t<h3\n\t\t\t\t\tclassName=\"mb-[0.5rem]\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tfontFamily: config?.style?.heading?.headingFontFamily || \"SeriouslyNostalgic Fn\",\n\t\t\t\t\t\tfontSize: config?.style?.heading?.headingFontSize || \"32px\",\n\t\t\t\t\t\tcolor: config?.style?.heading?.headingColor || \"#000\",\n\t\t\t\t\t\tfontWeight: config?.style?.heading?.headingFontWeight || \"normal\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{translate?.(directionMessages[stage])}\n\t\t\t\t</h3>\n\t\t\t\t{/* <p>We'll guide you to take 6 selfies </p> */}\n\t\t\t\t<div className=\"max-w-[400px] justify-center gap-1 mx-auto flex items-center\">\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 0 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.forward : FACE_SCAN_HEADSHOT.female.forward} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 1 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.left : FACE_SCAN_HEADSHOT.female.left} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 2 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.right : FACE_SCAN_HEADSHOT.female.right} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={` w-[120px] overflow-hidden ${stage === 3 ? \"opacity-100\" : \"opacity-0 hidden\"} `}>\n\t\t\t\t\t\t<video className=\"h-full w-full object-contain border-none\" muted loop autoPlay playsInline>\n\t\t\t\t\t\t\t<source src={gender === GenderType.Male ? FACE_SCAN_HEADSHOT.male.smile : FACE_SCAN_HEADSHOT.female.smile} type=\"video/mp4\" />\n\t\t\t\t\t\t</video>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport default FaceScanGuide;\n","import React, { useContext, useEffect } from 'react'\nimport ParamsContext from '../../utils/context/paramsContext';\nimport FaceScanErrorScreen from './FaceScanErrorScreen';\nimport LoadingScreen from '../LoadingScreen';\nimport { videoConstraints } from '../../utils/constants';\nimport { Drawer } from '@mui/material';\nimport FaceScanGuide from './FaceScanGuide';\nimport { ArrowRight } from 'lucide-react';\nimport { LanguageContext } from '../../utils/context/languageContext';\nimport { useLocalConfig } from '../../config/useLocalConfig';\ninterface FaceScanStepProps {\n\twebcamRef: React.RefObject<HTMLVideoElement | null>;\n\tcanvasRef: React.RefObject<HTMLCanvasElement | null>;\n}\n\nconst FaceScanStep:React.FC<FaceScanStepProps> = ({webcamRef,canvasRef}) => {\n\n const {isError,isSuccess,showLoader,hasError,resetScanState,showGuideCard,scanStage,videoLoading,setVideoLoading,videoError,setVideoError,gender,getButtonText,isScanning,startScan,isModelLoaded,config} = useContext(ParamsContext)\n \tconst resolvedConfig = useLocalConfig(config);\n\n const { setPreferredLanguage } = useContext(LanguageContext) || {};\n \tuseEffect(() => {\t\t\n\t\tsetPreferredLanguage?.(resolvedConfig?.language);\n\t}, [resolvedConfig]);\n \tif (isError) {\n\t\treturn (<FaceScanErrorScreen config={resolvedConfig} />)\n }\n\tif (isSuccess) {\n\t\treturn (\n\t\t\t<div className=\"fixed z-[9] w-full h-full\" style={{ background: resolvedConfig?.style?.base?.backgroundColor }}>\n\t\t\t\t{/* <Asset genderType={gender} /> */}\n\t\t\t\t<LoadingScreen url={resolvedConfig?.loader} loaderType=\"black\" />\n\t\t\t</div>\n\n\t\t);\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<audio id=\"audioElement\" crossOrigin=\"anonymous\" preload=\"auto\" style={{ position: \"absolute\", zIndex: -99999 }} src={undefined} />\n\n\t\t\t{/* Error overlay */}\n\t\t\t{!showLoader && hasError && <FaceScanErrorScreen loading={showLoader} resetScanState={resetScanState} config={resolvedConfig} />}\n\n\t\t\t{/* Always show camera view */}\n\t\t\t<div className=\"h-full flex-col relative w-full flex justify-center items-center text-center rounded-t-[20px]\" style={{ background: resolvedConfig?.style?.base?.backgroundColor }}>\n\t\t\t\t<div className=\"flex-1 w-full max-w-md overflow-hidden\">\n\t\t\t\t\t<div className=\"w-full h-full\">\n\t\t\t\t\t\t<video\n\t\t\t\t\t\t\tref={webcamRef}\n\t\t\t\t\t\t\tautoPlay\n\t\t\t\t\t\t\tplaysInline\n\t\t\t\t\t\t\tmuted\n\t\t\t\t\t\t\twidth={videoConstraints.width}\n\t\t\t\t\t\t\theight={videoConstraints.height}\n\t\t\t\t\t\t\tclassName=\"w-full h-full object-cover fixed left-0 top-0 z-0\"\n\t\t\t\t\t\t\tstyle={{ transform: \"scaleX(-1)\" }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<canvas ref={canvasRef} width={videoConstraints.width} height={videoConstraints.height} style={{ transform: \"scaleX(-1)\", opacity: \"0\" }} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{/* Error overlay */}\n\t\t\t{!showLoader && hasError && <FaceScanErrorScreen loading={showLoader} resetScanState={resetScanState} config={resolvedConfig} />}\n\n\t\t\t{/* Scan guide drawer - only show when scanning */}\n\t\t\t{showGuideCard && !hasError && !showLoader && (\n\t\t\t\t<Drawer\n\t\t\t\t\topen\n\t\t\t\t\tclassName=\"face-scan-small camera-draw\"\n\t\t\t\t\tanchor=\"bottom\"\n\t\t\t\t\tonClose={(event, reason) => {\n\t\t\t\t\t\tif (reason === \"backdropClick\") {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t\thideBackdrop\n\t\t\t\t>\n\t\t\t\t\t<FaceScanGuide\n\t\t\t\t\t\tstage={scanStage}\n\t\t\t\t\t\tvideoLoading={videoLoading}\n\t\t\t\t\t\tsetVideoLoading={setVideoLoading}\n\t\t\t\t\t\tvideoError={videoError}\n\t\t\t\t\t\tsetVideoError={setVideoError}\n\t\t\t\t\t\tgender={gender}\n\t\t\t\t\t\tconfig={resolvedConfig}\n\t\t\t\t\t\tbtnConfig={{\n\t\t\t\t\t\t\tlabel: getButtonText(),\n\t\t\t\t\t\t\tonClick: isScanning ? resetScanState : startScan,\n\t\t\t\t\t\t\tisDisabled: showLoader || !isModelLoaded,\n\t\t\t\t\t\t\ticon: isScanning ? <ArrowRight /> : <></>,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</Drawer>\n\t\t\t)}\n\t\t</>\n\t);\n}\n\nexport default FaceScanStep","\"use client\";\nimport { useEffect, useRef, useState, useCallback, useContext } from \"react\";\nimport { ArrowRight } from \"lucide-react\";\nimport { Drawer } from \"@mui/material\";\nimport FaceScanGuide from \"./FaceScanGuide\";\nimport FaceScanErrorScreen from \"./FaceScanErrorScreen\";\nimport posthog from \"posthog-js\";\nimport { FaceScanProps } from \"../../types/interfaces\";\nimport { generateUuid, handleScanTimeCapture, handleWebSocketCapture } from \"../../utils/utils\";\nimport { useLocalConfig } from \"../../config/useLocalConfig\";\nimport { posthogPublicHost, posthogPublicKey, videoConstraints, videoTypes, voiceOverAssetsPath } from \"../../utils/constants\";\nimport swan from \"../../utils/service/swanService\";\nimport speechService from \"../../utils/service/speechService\";\nimport useFaceScan from \"../../customHooks/useFaceScan\";\nimport LoadingScreen from \"../LoadingScreen\";\nimport { LanguageKeys } from \"../../utils/languageKeys\";\nimport LanguageContextProvider, { LanguageContext } from \"../../utils/context/languageContext\";\nimport FaceScanStep from \"./FaceScanStep\";\nimport ParamsContext from \"../../utils/context/paramsContext\";\n\nexport const FaceScan: React.FC<FaceScanProps> = ({ userDetails, onScanSuccess, onScanError, onRetry, config, isError, isSuccess }) => {\n\t\n\tconst webcamRef = useRef<HTMLVideoElement | null>(null);\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst mediaRecorderRef = useRef<MediaRecorder | null>(null);\n\tconst recordedBlobsRef = useRef<Blob[] | null>([]);\n\tconst streamRef = useRef<MediaStream | null>(null);\n\tconst [showLoader, setShowLoader] = useState(false);\n\tconst [modelReady, setModelReady] = useState(false);\n\tconst [isScanning, setIsScanning] = useState(false);\n\tconst [showGuideCard, setShowGuideCard] = useState(true);\n\tconst [videoLoading, setVideoLoading] = useState(false);\n\tconst [videoError, setVideoError] = useState(false);\n\tconst [hasError, setHasError] = useState(false);\n\tconst [faceScanId, setFaceScanId] = useState(generateUuid());\n\tconst { email, gender, deviceFocalLength, shopDomain, callbackUrl } = userDetails;\n\tconst [supportedTypes, setSupportedTypes] = useState<string[]>([]);\n\t// const supportedTypes = useMemo(() => videoTypes.filter((type) => MediaRecorder.isTypeSupported(type)), []);\n\t\n\tconst stopRecording = useCallback(() => {\n\t\tconsole.log(\"Stopping recording...\");\n\t\tif (mediaRecorderRef.current && mediaRecorderRef.current.state === \"recording\") {\n\t\t\tmediaRecorderRef.current.stop();\n\t\t}\n\t\tmediaRecorderRef.current = null;\n\t}, []);\n\n\tconst uploadFinalVideo = async () => {\n\t\tsetShowLoader(true);\n\t\tconsole.log(\"upload final video\");\n\t\tif (recordedBlobsRef.current) {\n\t\t\tif (recordedBlobsRef.current.length === 0) {\n\t\t\t\tconsole.error(\"No video data recorded\");\n\t\t\t\tsetHasError(true);\n\t\t\t\tsetShowLoader(false);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst videoFile = new File(recordedBlobsRef.current, `${faceScanId}.webm`, {\n\t\t\t\ttype: \"video/webm\",\n\t\t\t});\n\t\t\tconst fileSize = videoFile.size;\n\t\t\tconst fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);\n\t\t\tconst estimatedDuration = Math.round(fileSize / 10000);\n\t\t\tconst videoData = {\n\t\t\t\tvideo_size_mb: parseFloat(fileSizeMB),\n\t\t\t\tvideo_size_bytes: fileSize,\n\t\t\t\tblob_count: recordedBlobsRef.current.length,\n\t\t\t\testimated_duration_seconds: estimatedDuration,\n\t\t\t};\n\n\t\t\tconst metaData = [\n\t\t\t\t{ gender: gender },\n\t\t\t\t{ face_scan_id: faceScanId },\n\t\t\t\t{\n\t\t\t\t\tfocal_length: `${deviceFocalLength}`,\n\t\t\t\t},\n\t\t\t\t{ customer_store_url: shopDomain },\n\t\t\t\t{ scan_type: \"face_scan\" },\n\t\t\t\t{ callback_url: callbackUrl },\n\t\t\t];\n\t\t\thandleScanTimeCapture({\n\t\t\t\teventName: `${shopDomain}/face_scan_meta_data`,\n\t\t\t\tfaceScanId,\n\t\t\t\temail,\n\t\t\t\tdata: JSON.stringify({ metaData, videoData }),\n\t\t\t});\n\n\t\t\tconst uploadStartTime = Date.now();\n\t\t\thandleScanTimeCapture({\n\t\t\t\teventName: `${shopDomain}/face_scan_upload_start`,\n\t\t\t\tfaceScanId,\n\t\t\t\temail,\n\t\t\t\tstartTime: uploadStartTime,\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\tconst res = await swan.fileUpload.faceScanFileUploader({\n\t\t\t\t\tfile: videoFile,\n\t\t\t\t\tobjectKey: faceScanId,\n\t\t\t\t\temail,\n\t\t\t\t\tarrayMetaData: metaData,\n\t\t\t\t\tcontentType: videoFile.type,\n\t\t\t\t});\n\n\t\t\t\tconst uploadEndTime = Date.now();\n\t\t\t\tconst uploadDuration = uploadEndTime - uploadStartTime;\n\n\t\t\t\thandleScanTimeCapture({\n\t\t\t\t\teventName: `${shopDomain}/face_scan_upload_complete`,\n\t\t\t\t\tfaceScanId,\n\t\t\t\t\temail,\n\t\t\t\t\tcompletionTime: uploadEndTime,\n\t\t\t\t\tuploadDuration,\n\t\t\t\t});\n\n\t\t\t\tconsole.log(\"✅ Upload successful\", res);\n\t\t\t\tswan.measurement.handlFaceScaneSocket({\n\t\t\t\t\tfaceScanId,\n\t\t\t\t\tonOpen: () => {\n\t\t\t\t\t\thandleWebSocketCapture({\n\t\t\t\t\t\t\teventName: `${shopDomain}/webSocket`,\n\t\t\t\t\t\t\tfaceScanID: faceScanId,\n\t\t\t\t\t\t\tconnection: \"open\",\n\t\t\t\t\t\t\ttype: \"faceScan_recommendation\",\n\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconsole.log(\"websocket connect open\");\n\t\t\t\t\t},\n\t\t\t\t\tonError: (err) => {\n\t\t\t\t\t\thandleWebSocketCapture({\n\t\t\t\t\t\t\teventName: `${shopDomain}/webSocket`,\n\t\t\t\t\t\t\tfaceScanID: faceScanId,\n\t\t\t\t\t\t\tconnection: \"error\",\n\t\t\t\t\t\t\ttype: \"faceScan_recommendation\",\n\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tonError(err);\n\t\t\t\t\t},\n\t\t\t\t\tonSuccess: (data) => {\n\t\t\t\t\t\thandleWebSocketCapture({\n\t\t\t\t\t\t\teventName: `${shopDomain}/webSocket`,\n\t\t\t\t\t\t\tfaceScanID: faceScanId,\n\t\t\t\t\t\t\tconnection: \"success\",\n\t\t\t\t\t\t\ttype: \"faceScan_recommendation\",\n\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tonSuccess(data);\n\t\t\t\t\t},\n\t\t\t\t\tonClose: () => {\n\t\t\t\t\t\tconsole.log(\"websocket connect close\");\n\t\t\t\t\t\thandleWebSocketCapture({\n\t\t\t\t\t\t\teventName: `${shopDomain}/webSocket`,\n\t\t\t\t\t\t\tfaceScanID: faceScanId,\n\t\t\t\t\t\t\tconnection: \"close\",\n\t\t\t\t\t\t\ttype: \"faceScan_recommendation\",\n\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tonError(error);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst startRecording = useCallback(() => {\n\t\tconsole.log(\"Starting recording for stages 1-3...\");\n\t\tconst stream = webcamRef.current?.srcObject as MediaStream | null;\n\t\tif (!stream) return;\n\n\t\t// Create a canvas to normalize orientation\n\t\tconst videoTrack = stream.getVideoTracks()[0];\n\t\tconst settings = videoTrack.getSettings();\n\t\tconst { width = videoConstraints.width, height = videoConstraints.height } = settings;\n\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\tconst ctx = canvas.getContext(\"2d\");\n\n\t\t// Always force portrait (swap width/height if landscape)\n\t\tif (width > height) {\n\t\t\tcanvas.width = height;\n\t\t\tcanvas.height = width;\n\t\t} else {\n\t\t\tcanvas.width = width;\n\t\t\tcanvas.height = height;\n\t\t}\n\n\t\tconst videoEl = document.createElement(\"video\");\n\t\tvideoEl.srcObject = stream;\n\t\tvideoEl.muted = true;\n\t\tvideoEl.playsInline = true;\n\t\tvideoEl.play();\n\n\t\t// Draw video frames onto canvas\n\t\tconst drawFrame = () => {\n\t\t\t// Rotate if camera gives landscape frames\n\t\t\tif (width > height) {\n\t\t\t\tctx?.save();\n\t\t\t\tctx?.translate(canvas.width, 0);\n\t\t\t\tctx?.rotate(Math.PI / 2);\n\t\t\t\tctx?.drawImage(videoEl, 0, 0, height, width);\n\t\t\t\tctx?.restore();\n\t\t\t} else {\n\t\t\t\tctx?.drawImage(videoEl, 0, 0, width, height);\n\t\t\t}\n\t\t\trequestAnimationFrame(drawFrame);\n\t\t};\n\t\tdrawFrame();\n\n\t\tconst canvasStream = canvas.captureStream(30); // 30fps\n\t\tconst mediaRecorderOptions = supportedTypes.length > 0 ? { mimeType: supportedTypes[0] } : {};\n\t\tlet mediaRecorder;\n\n\t\ttry {\n\t\t\tmediaRecorder = new MediaRecorder(canvasStream, mediaRecorderOptions);\n\t\t} catch (e) {\n\t\t\tconsole.error(\"MediaRecorder init failed:\", e);\n\t\t\tsetHasError(true);\n\t\t\tsetShowLoader(false);\n\t\t\treturn;\n\t\t}\n\n\t\trecordedBlobsRef.current = [];\n\t\tmediaRecorder.ondataavailable = (event) => {\n\t\t\tif (event?.data && event.data.size > 0 && recordedBlobsRef.current) {\n\t\t\t\trecordedBlobsRef.current.push(event.data);\n\t\t\t}\n\t\t};\n\t\tmediaRecorder.onstop = () => {\n\t\t\tconsole.log(\"Recording stopped, total blobs:\", recordedBlobsRef?.current?.length);\n\t\t\tuploadFinalVideo();\n\t\t};\n\n\t\tmediaRecorder.start(100); // 100ms chunks\n\t\tmediaRecorderRef.current = mediaRecorder;\n\t\tconsole.log(\"Recording started successfully (portrait normalized)\");\n\t}, [supportedTypes, uploadFinalVideo]);\n\n\tconst { faceScanDetector, scanStage, setScanStage, resetScan, isModelLoaded, startScanSequence } = useFaceScan({\n\t\tfaceScanId,\n\t\tshopDomain,\n\t\tonScanComplete: () => {\n\t\t\tstopRecording();\n\t\t},\n\t\tonModelReady: () => {\n\t\t\tsetModelReady(true);\n\t\t},\n\t\tonStartRecording: () => {\n\t\t\tconsole.log(\"Stage 0 completed - starting recording for stages 1-3\");\n\t\t\tstartRecording();\n\t\t},\n\t});\n\n\tconst startScan = useCallback(() => {\n\t\tif (!isModelLoaded) return;\n\t\tsetScanStage(0);\n\t\tspeechService.playAudio(`${voiceOverAssetsPath}face-scan-vos/Face-forward.mp3`);\n\t\tsetTimeout(() => {\n\t\t\tsetIsScanning(true);\n\t\t\tsetTimeout(() => {\n\t\t\t\tstartScanSequence();\n\t\t\t}, 200);\n\t\t}, 200);\n\t}, [setScanStage, setIsScanning, startScanSequence, isModelLoaded]);\n\n\tconst resetScanState = useCallback(() => {\n\t\tsetIsScanning(false);\n\t\tsetShowGuideCard(true);\n\t\tstopRecording();\n\t\tresetScan();\n\t\tonRetry?.();\n\t\trecordedBlobsRef.current = [];\n\t\tif (mediaRecorderRef.current) {\n\t\t\tmediaRecorderRef.current = null;\n\t\t}\n\t\tsetHasError(false);\n\t\tsetScanStage(-1);\n\t\tsetFaceScanId(generateUuid());\n\t\tif (webcamRef.current && streamRef.current) {\n\t\t\twebcamRef.current.srcObject = streamRef.current;\n\t\t\tconsole.log(\"Camera stream restored after reset\");\n\t\t}\n\t}, [setScanStage, setIsScanning, setShowGuideCard, stopRecording, resetScan, setFaceScanId]);\n\n\tconst onError = (data: any) => {\n\t\tconsole.log(data, \"ws error\");\n\t\tonScanError?.(data);\n\t\tsetHasError(true);\n\t\tsetShowLoader(false);\n\t\tsetShowGuideCard(false);\n\t\thandleScanTimeCapture({\n\t\t\teventName: `${shopDomain}/faceScan`,\n\t\t\tfaceScanId,\n\t\t\tstatus: \"failed\",\n\t\t\temail,\n\t\t\tdata: JSON.stringify(data),\n\t\t});\n\t};\n\n\tconst onSuccess = (data: any) => {\n\t\tconsole.log(data, \"ws success\");\n\t\tif (data && data?.resultType === \"intermediate\") {\n\t\t\thandleScanTimeCapture({\n\t\t\t\teventName: `${shopDomain}/faceScan_success/intermediate`,\n\t\t\t\tfaceScanId,\n\t\t\t\tstatus: \"success\",\n\t\t\t\temail,\n\t\t\t\tdata: JSON.stringify(data),\n\t\t\t});\n\t\t}\n\t\tonScanSuccess?.(data);\n\t};\n\n\tuseEffect(() => {\n\t\tif (isError || isSuccess) return;\n\t\tif (navigator.mediaDevices.getUserMedia) {\n\t\t\tnavigator.mediaDevices\n\t\t\t\t.getUserMedia({ video: videoConstraints })\n\t\t\t\t.then((stream) => {\n\t\t\t\t\tstreamRef.current = stream;\n\t\t\t\t\tif (webcamRef.current) {\n\t\t\t\t\t\twebcamRef.current.srcObject = stream;\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch((err) => console.error(\"Error accessing webcam:\", err));\n\t\t}\n\t\treturn () => {\n\t\t\tif (streamRef.current) {\n\t\t\t\tstreamRef.current.getTracks().forEach((track) => track.stop());\n\t\t\t}\n\t\t};\n\t}, [isError, isSuccess]);\n\n\t// Face detection interval - only run when scanning is active\n\tuseEffect(() => {\n\t\tif (!modelReady || !isScanning) return;\n\t\tconst intervalId = setInterval(() => {\n\t\t\tfaceScanDetector(webcamRef, canvasRef);\n\t\t}, 500);\n\n\t\t// eslint-disable-next-line consistent-return\n\t\treturn () => clearInterval(intervalId);\n\t}, [faceScanDetector, modelReady, isScanning]);\n\n\tconst getButtonText = () => {\n\t\tif (isScanning) return LanguageKeys.reset;\n\t\tif (!isModelLoaded) return LanguageKeys.loading;\n\t\treturn LanguageKeys.start;\n\t};\n\n\tconsole.log(\"Model ready:\", modelReady, \"Has error:\", hasError, \"Is scanning:\", isScanning, \"showLoader\", showLoader);\n\tuseEffect(() => {\n\t\tif (typeof MediaRecorder !== \"undefined\") {\n\t\t\tconst supported = videoTypes.filter((type) => MediaRecorder.isTypeSupported(type));\n\t\t\tsetSupportedTypes(supported);\n\t\t}\n\t}, []);\n\tuseEffect(() => {\n\t\tsetScanStage(-1);\n\t\tif (isError || isSuccess) return;\n\t}, [isError, isSuccess]);\n\n\tuseEffect(() => {\n\t\tposthog.init(posthogPublicKey, { api_host: posthogPublicHost });\n\t\tposthog.capture(\"$pageview\");\n\t}, []);\n\n return (\n\t\t<LanguageContextProvider>\n\t\t\t<ParamsContext.Provider value={{isError,isSuccess,showLoader,hasError,resetScanState,showGuideCard,scanStage,videoLoading,setVideoLoading,videoError,setVideoError,gender,getButtonText,isScanning,startScan,isModelLoaded,config}}>\n\t\t\t<FaceScanStep webcamRef={webcamRef} canvasRef={canvasRef}/>\n\t\t\t</ParamsContext.Provider>\n\t\t</LanguageContextProvider>\n\t )\n};\n"],"names":["preloadedDetector","isPreloading","useFaceScan","faceScanId","onValidPose","onScanComplete","onModelReady","onStartRecording","shopDomain","detectorRef","useRef","scanStage","setScanStage","useState","consecutiveValid","setConsecutiveValid","isModelLoaded","setIsModelLoaded","isScanningActive","setIsScanningActive","utteranceRef","scanStageRef","consecutiveValidRef","validityBufferRef","lastSpokenMessageRef","lastSpokenTimeRef","voiceEnabledRef","lastPoseTrackingTimeRef","isIOS","navigator","test","userAgent","platform","maxTouchPoints","directionMessages","useMemo","debouncedTrackPoseDetection","fn","delay","timer","args","clearTimeout","setTimeout","debounce","payload","posthog","capture","trackPoseDetection","useCallback","faceKeypoints","bodyKeypoints","stage","headValid","bodyInvalid","consecutiveValidCount","now","Date","current","nose","leftEye","rightEye","leftMouth","rightMouth","faceKeypointScores","map","kp","filter","score","avgFaceScore","length","reduce","a","b","bodyKeypointScores","avgBodyScore","eyeDistance","Math","abs","noseToRight","noseToLeft","expectedPosition","timestamp","toISOString","data","JSON","stringify","parseFloat","toFixed","faceKeypointsDetected","bodyKeypointsDetected","noseToRightRatio","noseToLeftRatio","noseScore","leftEyeScore","rightEyeScore","leftMouthScore","rightMouthScore","error","console","warn","startScanSequence","stageName","initializeModels","async","window","log","detector","Promise","r","tf","poseDetection","all","import","setBackend","ready","createDetector","SupportedModels","BlazePose","runtime","modelType","dummyCanvas","document","createElement","width","videoConstraints","height","ctx","getContext","fillStyle","fillRect","estimatePoses","e","err","preloadDetector","useEffect","disposeModelAndTf","faceScanDetector","webcamRef","canvasRef","readyState","poses","keypoints","forEach","landmark","idx","point","x","y","push","clearRect","progress","min","radius","beginPath","strokeStyle","lineWidth","arc","PI","stroke","eyesToMouthVerticalDistance","faceTiltedness","faceIsTilted","faceIsVertical","frontalFace","fullLeft","fullRight","isHeadInPosition","slice","p","shift","Boolean","nextValid","max","nextStage","speechService","playAudio","voiceOverAssetsPath","completedStage","totalStages","nextSound","resetScan","speechSynthesis","cancel","enableVoiceCommands","silentUtterance","SpeechSynthesisUtterance","volume","speak","FaceScanErrorScreen","resetScanState","loading","config","translate","preferredLanguage","useContext","LanguageContext","LanguageKeys","scanFailed","_jsx","className","style","background","base","backgroundColor","children","_jsxs","Header","noTitle","resolvedConfig","fontFamily","heading","headingFontFamily","fontSize","headingFontSize","color","headingColor","fontWeight","headingFontWeight","subheading","subheadingFontFamily","subheadingFontSize","subheadingColor","subheadingFontWeight","clickToResetScan","SpecificButton","disabled","buttonText","postfixIcon","ArrowRight","buttonFunc","FaceScanGuide","videoLoading","setVideoLoading","videoError","setVideoError","gender","btnConfig","faceVisible","loadingVideo","videoLoadFailed","src","GenderType","Male","maleGlassesOffVideo","glassesOffVideo","autoPlay","loop","controls","muted","playsInline","onCanPlay","onLoadStart","onError","isDisabled","label","icon","onClick","FACE_SCAN_HEADSHOT","male","forward","female","type","left","right","smile","FaceScanStep","isError","isSuccess","showLoader","hasError","showGuideCard","getButtonText","isScanning","startScan","ParamsContext","useLocalConfig","setPreferredLanguage","language","LoadingScreen","url","loader","loaderType","id","crossOrigin","preload","position","zIndex","undefined","ref","transform","opacity","Drawer","open","anchor","onClose","event","reason","hideBackdrop","_Fragment","FaceScan","userDetails","onScanSuccess","onScanError","onRetry","mediaRecorderRef","recordedBlobsRef","streamRef","setShowLoader","modelReady","setModelReady","setIsScanning","setShowGuideCard","setHasError","setFaceScanId","generateUuid","email","deviceFocalLength","callbackUrl","supportedTypes","setSupportedTypes","stopRecording","state","stop","uploadFinalVideo","videoFile","File","fileSize","size","fileSizeMB","estimatedDuration","round","videoData","video_size_mb","video_size_bytes","blob_count","estimated_duration_seconds","metaData","face_scan_id","focal_length","customer_store_url","scan_type","callback_url","handleScanTimeCapture","eventName","uploadStartTime","startTime","res","swan","fileUpload","faceScanFileUploader","file","objectKey","arrayMetaData","contentType","uploadEndTime","completionTime","uploadDuration","measurement","handlFaceScaneSocket","onOpen","handleWebSocketCapture","faceScanID","connection","onSuccess","startRecording","stream","srcObject","settings","getVideoTracks","getSettings","canvas","videoEl","play","drawFrame","save","rotate","drawImage","restore","requestAnimationFrame","canvasStream","captureStream","mediaRecorderOptions","mimeType","mediaRecorder","MediaRecorder","ondataavailable","onstop","start","status","resultType","mediaDevices","getUserMedia","video","then","catch","getTracks","track","intervalId","setInterval","clearInterval","supported","videoTypes","isTypeSupported","init","posthogPublicKey","api_host","posthogPublicHost","LanguageContextProvider","Provider","value","reset"],"mappings":"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"}
|