@swan-admin/swan-web-component 1.0.75 → 1.0.76

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/faceScan.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var e=require("react/jsx-runtime"),s=require("./Header-Ce4cmwL6.js"),l=require("./arrow-right-CC1_17IM.js"),n=require("./LoadingScreen-B5M1cok3.js");function i({resetScanState:n,loading:i,config:t}){return e.jsx("div",{className:"fixed top-[0] left-[0] z-[999] flex justify-center items-center w-full h-full",style:{background:t?.style?.base?.backgroundColor},children:e.jsxs("div",{className:"flex flex-col w-full items-center p-[1rem] rounded-lg ",children:[e.jsx(s.Header,{noTitle:!0,resolvedConfig:t}),e.jsxs("div",{className:"flex flex-col items-center w-full",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-800 ",style:{fontFamily:t?.style?.heading?.headingFontFamily||"SeriouslyNostalgic Fn",fontSize:t?.style?.heading?.headingFontSize||"32px",color:t?.style?.heading?.headingColor||"#000",fontWeight:t?.style?.heading?.headingFontWeight||"normal"},children:"Your Scan Failed"}),e.jsx("p",{className:"mb-[1.5rem]",style:{fontFamily:t?.style?.subheading?.subheadingFontFamily||"'Inter', sans-serif",fontSize:t?.style?.subheading?.subheadingFontSize||"14px",color:t?.style?.subheading?.subheadingColor||"#4b5563",fontWeight:t?.style?.subheading?.subheadingFontWeight||"normal"},children:"Please click below to reset your scan."}),e.jsx(s.SpecificButton,{disabled:i,className:"w-full h-[45px] shadow-[0px_1px_2px_0px_#00000040] text-[16px]",buttonText:"Reset Scan",postfixIcon:e.jsx(l.ArrowRight,{}),buttonFunc:()=>n?.(),resolvedConfig:t})]})]})})}require("react");exports.FaceScan=({userDetails:l,onComplete:t,onScanError:r,onRetry:o,config:a,isError:c,isSuccess:d})=>{const u=s.useLocalConfig(a);return c?e.jsx(i,{config:u}):d?e.jsx("div",{className:"fixed z-[9] w-full h-full",style:{background:u?.style?.base?.primaryColor},children:e.jsx(n.LoadingScreen,{url:u?.loader})}):void 0};
1
+ "use strict";var e=require("react/jsx-runtime"),s=require("./Header-BiYtGF6l.js"),n=require("./arrow-right-CC1_17IM.js"),i=require("./LoadingScreen-D7OUJo45.js");function l({resetScanState:i,loading:l,config:t}){return e.jsx("div",{id:"faceScanErrorSuccess",className:"fixed top-[0] left-[0] z-[999] flex justify-center items-center w-full h-full",style:{background:t?.style?.base?.backgroundColor},children:e.jsxs("div",{className:"flex flex-col w-full items-center p-[1rem] rounded-lg ",children:[e.jsx(s.Header,{noTitle:!0,resolvedConfig:t}),e.jsxs("div",{className:"flex flex-col items-center w-full",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-800 ",style:{fontFamily:t?.style?.heading?.headingFontFamily||"SeriouslyNostalgic Fn",fontSize:t?.style?.heading?.headingFontSize||"32px",color:t?.style?.heading?.headingColor||"#000",fontWeight:t?.style?.heading?.headingFontWeight||"normal"},children:"Your Scan Failed"}),e.jsx("p",{className:"mb-[1.5rem]",style:{fontFamily:t?.style?.subheading?.subheadingFontFamily||"'Inter', sans-serif",fontSize:t?.style?.subheading?.subheadingFontSize||"14px",color:t?.style?.subheading?.subheadingColor||"#4b5563",fontWeight:t?.style?.subheading?.subheadingFontWeight||"normal"},children:"Please click below to reset your scan."}),e.jsx(s.SpecificButton,{disabled:l,className:"w-full h-[45px] shadow-[0px_1px_2px_0px_#00000040] text-[16px]",buttonText:"Reset Scan",postfixIcon:e.jsx(n.ArrowRight,{}),buttonFunc:()=>i?.(),resolvedConfig:t})]})]})})}require("react");exports.FaceScan=({userDetails:n,onComplete:t,onScanError:r,onRetry:o,config:a,isError:c,isSuccess:d})=>{const u=s.useLocalConfig(a);return c?e.jsx(l,{config:u}):d?e.jsx("div",{className:"fixed z-[9] w-full h-full",style:{background:u?.style?.base?.primaryColor},children:e.jsx(i.LoadingScreen,{url:u?.loader})}):void 0};
2
2
  //# sourceMappingURL=faceScan.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"faceScan.js","sources":["../src/components/faceScan/FaceScanErrorScreen.tsx","../src/components/faceScan/FaceScan.tsx"],"sourcesContent":["import { ArrowRight } from \"lucide-react\";\nimport Header from \"../Header\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\n\nfunction FaceScanErrorScreen({ resetScanState, loading, config }: { resetScanState?: () => void; loading?: boolean; config?: any }) {\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\tYour Scan Failed\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\tPlease click below to reset your scan.\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=\"Reset Scan\"\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","\"use client\";\nimport { useEffect, useRef, useState, useCallback, useMemo } 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 SpecificButton from \"../../atoms/specificButton/SpecificButton\";\nimport LoadingScreen from \"../LoadingScreen\";\n\nexport const FaceScan: React.FC<FaceScanProps> = ({ userDetails, onComplete, onScanError, onRetry, config,isError,isSuccess }) => {\n\t// const webcamRef = useRef<HTMLVideoElement | null>(null);\n\t// const canvasRef = useRef<HTMLCanvasElement | null>(null);\n\t// const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n\t// const recordedBlobsRef = useRef<Blob[] | null>([]);\n\t// const streamRef = useRef<MediaStream | null>(null);\n\t// const [showLoader, setShowLoader] = useState(false);\n\t// const [modelReady, setModelReady] = useState(false);\n\t// const [isScanning, setIsScanning] = useState(false);\n\t// const [showGuideCard, setShowGuideCard] = useState(true);\n\t// const [videoLoading, setVideoLoading] = useState(false);\n\t// const [videoError, setVideoError] = useState(false);\n\t// const [hasError, setHasError] = useState(false);\n\t// const [faceScanId, setFaceScanId] = useState(generateUuid());\n\tconst resolvedConfig = useLocalConfig(config);\n\t// const { email, gender, deviceFocalLength, shopDomain, callbackUrl } = userDetails;\n\t// const supportedTypes = useMemo(() => videoTypes.filter((type) => MediaRecorder.isTypeSupported(type)), []);\n\n\t// const 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\t// const 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\t// const videoFile = new File(recordedBlobsRef.current, `${faceScanId}.webm`, {\n\t\t\t// \ttype: \"video/webm\",\n\t\t\t// });\n\t\t\t// const fileSize = videoFile.size;\n\t\t\t// const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);\n\t\t\t// const estimatedDuration = Math.round(fileSize / 10000);\n\t\t\t// const 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\t// const 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\t// handleScanTimeCapture({\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\t// const uploadStartTime = Date.now();\n\t\t\t// handleScanTimeCapture({\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\t// const 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\t// Capture portrait-normalized stream\n\t\t// const canvasStream = canvas.captureStream(30); // 30fps\n\t\t// const mediaRecorderOptions = supportedTypes.length > 0 ? { mimeType: supportedTypes[0] } : {};\n\t\t// let mediaRecorder;\n\n\t\t// try {\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\t// const { 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\t// const 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\t// const 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\t// const 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\t// const 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// \tonComplete?.(data);\n\t// };\n\n\t// Initialize webcam\n\t// useEffect(() => {\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\tconsole.log(\"Webcam initialized\");\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\n\t\t// Cleanup function\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\t// useEffect(() => {\n\t// \tif (!modelReady || !isScanning) return;\n\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\t// const getButtonText = () => {\n\t// \tif (isScanning) return \"Reset\";\n\t// \tif (!isModelLoaded) return \"Loading...\";\n\t// \treturn \"Start\";\n\t// };\n\n\t// console.log(\"Model ready:\", modelReady, \"Has error:\", hasError, \"Is scanning:\", isScanning, \"showLoader\", showLoader);\n\n\t// useEffect(() => {\n\t// \tsetScanStage(-1);\n\t// \tif (isError || isSuccess) return;\n\t// \tposthog.init(posthogPublicKey, { api_host: posthogPublicHost });\n\t// \tposthog.capture(\"$pageview\");\n\t// }, [isError, isSuccess]);\n\n\tif (isError) {\n\t\treturn <FaceScanErrorScreen config={resolvedConfig} />;\n\t}\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?.primaryColor }}>\n\t\t\t\t{/* <Asset genderType={gender} /> */}\n\t\t\t\t<LoadingScreen url={resolvedConfig?.loader} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// return (\n\t// \t<>\n\t// \t\t<audio id=\"audioElement\" crossOrigin=\"anonymous\" preload=\"auto\" style={{ position: \"absolute\", zIndex: -99999 }} src=\"\" />\n\n\t// \t\t{showLoader && !hasError && (\n\t// \t\t\t<div className=\"fixed z-[9] w-full h-full\" style={{ background: resolvedConfig?.style?.base?.primaryColor }}>\n\t// \t\t\t\t{/* <Asset genderType={gender} /> */}\n\t// \t\t\t\t<LoadingScreen url={resolvedConfig?.loader} />\n\t// \t\t\t</div>\n\t// \t\t)}\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 stage={scanStage} videoLoading={videoLoading} setVideoLoading={setVideoLoading} videoError={videoError} setVideoError={setVideoError} gender={gender} config={resolvedConfig}>\n\t\t// \t\t\t\t<div className=\"flex justify-center w-full p-[1rem]\">\n\t\t// \t\t\t\t\t<SpecificButton\n\t\t// \t\t\t\t\t\tdisabled={showLoader || !isModelLoaded}\n\t\t// \t\t\t\t\t\tclassName=\"!w-[60px] !h-[35px] !py-0 !px-0\"\n\t\t// \t\t\t\t\t\tbuttonText={getButtonText()}\n\t\t// \t\t\t\t\t\tpostfixIcon={isScanning ? <ArrowRight /> : \"\"}\n\t\t// \t\t\t\t\t\tbuttonFunc={isScanning ? resetScanState : startScan}\n\t\t// \t\t\t\t\t\tresolvedConfig={resolvedConfig}\n\t\t// \t\t\t\t\t/>\n\t\t// \t\t\t\t</div>\n\t\t// \t\t\t</FaceScanGuide>\n\t\t// \t\t</Drawer>\n\t\t// \t)}\n\t\t// </>\n\t// );\n};\n"],"names":["FaceScanErrorScreen","resetScanState","loading","config","_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","SpecificButton","disabled","buttonText","postfixIcon","ArrowRight","buttonFunc","userDetails","onComplete","onScanError","onRetry","isError","isSuccess","useLocalConfig","primaryColor","LoadingScreen","url","loader"],"mappings":"kKAIA,SAASA,GAAoBC,eAAEA,EAAcC,QAAEA,EAAOC,OAAEA,IACvD,OACCC,EAAAA,WAAKC,UAAU,kFAAkFC,MAAO,CAAEC,WAAYJ,GAAQG,OAAOE,MAAMC,iBAAiBC,SAC3JC,EAAAA,KAAA,MAAA,CAAKN,UAAU,0DAAyDK,SAAA,CACvEN,EAAAA,IAACQ,EAAAA,OAAM,CAACC,WAAQC,eAAgBX,IAChCQ,EAAAA,YAAKN,UAAU,oCAAmCK,SAAA,CACjDN,EAAAA,IAAA,KAAA,CACCC,UAAU,uCACVC,MAAO,CACNS,WAAYZ,GAAQG,OAAOU,SAASC,mBAAqB,wBACzDC,SAAUf,GAAQG,OAAOU,SAASG,iBAAmB,OACrDC,MAAOjB,GAAQG,OAAOU,SAASK,cAAgB,OAC/CC,WAAYnB,GAAQG,OAAOU,SAASO,mBAAqB,UACzDb,SAAA,qBAIFN,EAAAA,IAAA,IAAA,CACCC,UAAU,cACVC,MAAO,CACNS,WAAYZ,GAAQG,OAAOkB,YAAYC,sBAAwB,sBAC/DP,SAAUf,GAAQG,OAAOkB,YAAYE,oBAAsB,OAC3DN,MAAOjB,GAAQG,OAAOkB,YAAYG,iBAAmB,UACrDL,WAAYnB,GAAQG,OAAOkB,YAAYI,sBAAwB,UAC/DlB,SAAA,2CAIFN,EAAAA,IAACyB,EAAAA,eAAc,CACdC,SAAU5B,EACVG,UAAU,iEACV0B,WAAW,aACXC,YAAa5B,EAAAA,IAAC6B,EAAAA,WAAU,CAAA,GACxBC,WAAY,IAAMjC,MAClBa,eAAgBX,WAMtB,mCC3BiD,EAAGgC,cAAaC,aAAYC,cAAaC,UAASnC,SAAOoC,UAAQC,gBAcjH,MAAM1B,EAAiB2B,EAAAA,eAAetC,GA4UtC,OAAIoC,EACInC,EAAAA,IAACJ,EAAmB,CAACG,OAAQW,IAGjC0B,EAEFpC,EAAAA,IAAA,MAAA,CAAKC,UAAU,6BAA6BC,MAAO,CAAEC,WAAYO,GAAgBR,OAAOE,MAAMkC,cAAchC,SAE3GN,EAAAA,IAACuC,EAAAA,cAAa,CAACC,IAAK9B,GAAgB+B,gBAJvC"}
1
+ {"version":3,"file":"faceScan.js","sources":["../src/components/faceScan/FaceScanErrorScreen.tsx","../src/components/faceScan/FaceScan.tsx"],"sourcesContent":["import { ArrowRight } from \"lucide-react\";\nimport Header from \"../Header\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\n\nfunction FaceScanErrorScreen({ resetScanState, loading, config }: { resetScanState?: () => void; loading?: boolean; config?: any }) {\n\treturn (\n\t\t<div id=\"faceScanErrorSuccess\" 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\tYour Scan Failed\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\tPlease click below to reset your scan.\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=\"Reset Scan\"\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","\"use client\";\nimport { useEffect, useRef, useState, useCallback, useMemo } 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 SpecificButton from \"../../atoms/specificButton/SpecificButton\";\nimport LoadingScreen from \"../LoadingScreen\";\n\nexport const FaceScan: React.FC<FaceScanProps> = ({ userDetails, onComplete, onScanError, onRetry, config,isError,isSuccess }) => {\n\t// const webcamRef = useRef<HTMLVideoElement | null>(null);\n\t// const canvasRef = useRef<HTMLCanvasElement | null>(null);\n\t// const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n\t// const recordedBlobsRef = useRef<Blob[] | null>([]);\n\t// const streamRef = useRef<MediaStream | null>(null);\n\t// const [showLoader, setShowLoader] = useState(false);\n\t// const [modelReady, setModelReady] = useState(false);\n\t// const [isScanning, setIsScanning] = useState(false);\n\t// const [showGuideCard, setShowGuideCard] = useState(true);\n\t// const [videoLoading, setVideoLoading] = useState(false);\n\t// const [videoError, setVideoError] = useState(false);\n\t// const [hasError, setHasError] = useState(false);\n\t// const [faceScanId, setFaceScanId] = useState(generateUuid());\n\tconst resolvedConfig = useLocalConfig(config);\n\t// const { email, gender, deviceFocalLength, shopDomain, callbackUrl } = userDetails;\n\t// const supportedTypes = useMemo(() => videoTypes.filter((type) => MediaRecorder.isTypeSupported(type)), []);\n\n\t// const 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\t// const 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\t// const videoFile = new File(recordedBlobsRef.current, `${faceScanId}.webm`, {\n\t\t\t// \ttype: \"video/webm\",\n\t\t\t// });\n\t\t\t// const fileSize = videoFile.size;\n\t\t\t// const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);\n\t\t\t// const estimatedDuration = Math.round(fileSize / 10000);\n\t\t\t// const 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\t// const 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\t// handleScanTimeCapture({\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\t// const uploadStartTime = Date.now();\n\t\t\t// handleScanTimeCapture({\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\t// const 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\t// Capture portrait-normalized stream\n\t\t// const canvasStream = canvas.captureStream(30); // 30fps\n\t\t// const mediaRecorderOptions = supportedTypes.length > 0 ? { mimeType: supportedTypes[0] } : {};\n\t\t// let mediaRecorder;\n\n\t\t// try {\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\t// const { 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\t// const 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\t// const 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\t// const 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\t// const 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// \tonComplete?.(data);\n\t// };\n\n\t// Initialize webcam\n\t// useEffect(() => {\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\tconsole.log(\"Webcam initialized\");\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\n\t\t// Cleanup function\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\t// useEffect(() => {\n\t// \tif (!modelReady || !isScanning) return;\n\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\t// const getButtonText = () => {\n\t// \tif (isScanning) return \"Reset\";\n\t// \tif (!isModelLoaded) return \"Loading...\";\n\t// \treturn \"Start\";\n\t// };\n\n\t// console.log(\"Model ready:\", modelReady, \"Has error:\", hasError, \"Is scanning:\", isScanning, \"showLoader\", showLoader);\n\n\t// useEffect(() => {\n\t// \tsetScanStage(-1);\n\t// \tif (isError || isSuccess) return;\n\t// \tposthog.init(posthogPublicKey, { api_host: posthogPublicHost });\n\t// \tposthog.capture(\"$pageview\");\n\t// }, [isError, isSuccess]);\n\n\tif (isError) {\n\t\treturn <FaceScanErrorScreen config={resolvedConfig} />;\n\t}\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?.primaryColor }}>\n\t\t\t\t{/* <Asset genderType={gender} /> */}\n\t\t\t\t<LoadingScreen url={resolvedConfig?.loader} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// return (\n\t// \t<>\n\t// \t\t<audio id=\"audioElement\" crossOrigin=\"anonymous\" preload=\"auto\" style={{ position: \"absolute\", zIndex: -99999 }} src=\"\" />\n\n\t// \t\t{showLoader && !hasError && (\n\t// \t\t\t<div className=\"fixed z-[9] w-full h-full\" style={{ background: resolvedConfig?.style?.base?.primaryColor }}>\n\t// \t\t\t\t{/* <Asset genderType={gender} /> */}\n\t// \t\t\t\t<LoadingScreen url={resolvedConfig?.loader} />\n\t// \t\t\t</div>\n\t// \t\t)}\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 stage={scanStage} videoLoading={videoLoading} setVideoLoading={setVideoLoading} videoError={videoError} setVideoError={setVideoError} gender={gender} config={resolvedConfig}>\n\t\t// \t\t\t\t<div className=\"flex justify-center w-full p-[1rem]\">\n\t\t// \t\t\t\t\t<SpecificButton\n\t\t// \t\t\t\t\t\tdisabled={showLoader || !isModelLoaded}\n\t\t// \t\t\t\t\t\tclassName=\"!w-[60px] !h-[35px] !py-0 !px-0\"\n\t\t// \t\t\t\t\t\tbuttonText={getButtonText()}\n\t\t// \t\t\t\t\t\tpostfixIcon={isScanning ? <ArrowRight /> : \"\"}\n\t\t// \t\t\t\t\t\tbuttonFunc={isScanning ? resetScanState : startScan}\n\t\t// \t\t\t\t\t\tresolvedConfig={resolvedConfig}\n\t\t// \t\t\t\t\t/>\n\t\t// \t\t\t\t</div>\n\t\t// \t\t\t</FaceScanGuide>\n\t\t// \t\t</Drawer>\n\t\t// \t)}\n\t\t// </>\n\t// );\n};\n"],"names":["FaceScanErrorScreen","resetScanState","loading","config","_jsx","id","className","style","background","base","backgroundColor","children","_jsxs","Header","noTitle","resolvedConfig","fontFamily","heading","headingFontFamily","fontSize","headingFontSize","color","headingColor","fontWeight","headingFontWeight","subheading","subheadingFontFamily","subheadingFontSize","subheadingColor","subheadingFontWeight","SpecificButton","disabled","buttonText","postfixIcon","ArrowRight","buttonFunc","userDetails","onComplete","onScanError","onRetry","isError","isSuccess","useLocalConfig","primaryColor","LoadingScreen","url","loader"],"mappings":"kKAIA,SAASA,GAAoBC,eAAEA,EAAcC,QAAEA,EAAOC,OAAEA,IACvD,OACCC,EAAAA,WAAKC,GAAG,uBAAuBC,UAAU,kFAAkFC,MAAO,CAAEC,WAAYL,GAAQI,OAAOE,MAAMC,iBAAiBC,SACrLC,OAAA,MAAA,CAAKN,UAAU,oEACdF,EAAAA,IAACS,EAAAA,QAAOC,SAAO,EAACC,eAAgBZ,IAChCS,OAAA,MAAA,CAAKN,UAAU,oCAAmCK,SAAA,CACjDP,EAAAA,IAAA,KAAA,CACCE,UAAU,uCACVC,MAAO,CACNS,WAAYb,GAAQI,OAAOU,SAASC,mBAAqB,wBACzDC,SAAUhB,GAAQI,OAAOU,SAASG,iBAAmB,OACrDC,MAAOlB,GAAQI,OAAOU,SAASK,cAAgB,OAC/CC,WAAYpB,GAAQI,OAAOU,SAASO,mBAAqB,UACzDb,SAAA,qBAIFP,EAAAA,IAAA,IAAA,CACCE,UAAU,cACVC,MAAO,CACNS,WAAYb,GAAQI,OAAOkB,YAAYC,sBAAwB,sBAC/DP,SAAUhB,GAAQI,OAAOkB,YAAYE,oBAAsB,OAC3DN,MAAOlB,GAAQI,OAAOkB,YAAYG,iBAAmB,UACrDL,WAAYpB,GAAQI,OAAOkB,YAAYI,sBAAwB,UAC/DlB,SAAA,2CAIFP,EAAAA,IAAC0B,EAAAA,eAAc,CACdC,SAAU7B,EACVI,UAAU,iEACV0B,WAAW,aACXC,YAAa7B,EAAAA,IAAC8B,EAAAA,WAAU,CAAA,GACxBC,WAAY,IAAMlC,MAClBc,eAAgBZ,WAMtB,mCC3BiD,EAAGiC,cAAaC,aAAYC,cAAaC,UAASpC,SAAOqC,UAAQC,gBAcjH,MAAM1B,EAAiB2B,EAAAA,eAAevC,GA4UtC,OAAIqC,EACIpC,EAAAA,IAACJ,EAAmB,CAACG,OAAQY,IAGjC0B,EAEFrC,EAAAA,IAAA,MAAA,CAAKE,UAAU,6BAA6BC,MAAO,CAAEC,WAAYO,GAAgBR,OAAOE,MAAMkC,cAAchC,SAE3GP,EAAAA,IAACwC,EAAAA,cAAa,CAACC,IAAK9B,GAAgB+B,gBAJvC"}
package/dist/faceScan.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{jsx as e,jsxs as t}from"react/jsx-runtime";import{H as l,S as o,u as n}from"./Header-BeNeDIFA.js";import{A as s}from"./arrow-right-DXQbS3wL.js";import{L as i}from"./LoadingScreen-BAi9IQ7c.js";import"react";function a({resetScanState:n,loading:i,config:a}){return e("div",{className:"fixed top-[0] left-[0] z-[999] flex justify-center items-center w-full h-full",style:{background:a?.style?.base?.backgroundColor},children:t("div",{className:"flex flex-col w-full items-center p-[1rem] rounded-lg ",children:[e(l,{noTitle:!0,resolvedConfig:a}),t("div",{className:"flex flex-col items-center w-full",children:[e("h2",{className:"text-xl font-semibold text-gray-800 ",style:{fontFamily:a?.style?.heading?.headingFontFamily||"SeriouslyNostalgic Fn",fontSize:a?.style?.heading?.headingFontSize||"32px",color:a?.style?.heading?.headingColor||"#000",fontWeight:a?.style?.heading?.headingFontWeight||"normal"},children:"Your Scan Failed"}),e("p",{className:"mb-[1.5rem]",style:{fontFamily:a?.style?.subheading?.subheadingFontFamily||"'Inter', sans-serif",fontSize:a?.style?.subheading?.subheadingFontSize||"14px",color:a?.style?.subheading?.subheadingColor||"#4b5563",fontWeight:a?.style?.subheading?.subheadingFontWeight||"normal"},children:"Please click below to reset your scan."}),e(o,{disabled:i,className:"w-full h-[45px] shadow-[0px_1px_2px_0px_#00000040] text-[16px]",buttonText:"Reset Scan",postfixIcon:e(s,{}),buttonFunc:()=>n?.(),resolvedConfig:a})]})]})})}const r=({userDetails:t,onComplete:l,onScanError:o,onRetry:s,config:r,isError:c,isSuccess:d})=>{const f=n(r);return c?e(a,{config:f}):d?e("div",{className:"fixed z-[9] w-full h-full",style:{background:f?.style?.base?.primaryColor},children:e(i,{url:f?.loader})}):void 0};export{r as FaceScan};
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import{H as l,S as o,u as n}from"./Header-BhrDARhH.js";import{A as s}from"./arrow-right-DXQbS3wL.js";import{L as i}from"./LoadingScreen-BXF96hkf.js";import"react";function r({resetScanState:n,loading:i,config:r}){return e("div",{id:"faceScanErrorSuccess",className:"fixed top-[0] left-[0] z-[999] flex justify-center items-center w-full h-full",style:{background:r?.style?.base?.backgroundColor},children:t("div",{className:"flex flex-col w-full items-center p-[1rem] rounded-lg ",children:[e(l,{noTitle:!0,resolvedConfig:r}),t("div",{className:"flex flex-col items-center w-full",children:[e("h2",{className:"text-xl font-semibold text-gray-800 ",style:{fontFamily:r?.style?.heading?.headingFontFamily||"SeriouslyNostalgic Fn",fontSize:r?.style?.heading?.headingFontSize||"32px",color:r?.style?.heading?.headingColor||"#000",fontWeight:r?.style?.heading?.headingFontWeight||"normal"},children:"Your Scan Failed"}),e("p",{className:"mb-[1.5rem]",style:{fontFamily:r?.style?.subheading?.subheadingFontFamily||"'Inter', sans-serif",fontSize:r?.style?.subheading?.subheadingFontSize||"14px",color:r?.style?.subheading?.subheadingColor||"#4b5563",fontWeight:r?.style?.subheading?.subheadingFontWeight||"normal"},children:"Please click below to reset your scan."}),e(o,{disabled:i,className:"w-full h-[45px] shadow-[0px_1px_2px_0px_#00000040] text-[16px]",buttonText:"Reset Scan",postfixIcon:e(s,{}),buttonFunc:()=>n?.(),resolvedConfig:r})]})]})})}const a=({userDetails:t,onComplete:l,onScanError:o,onRetry:s,config:a,isError:c,isSuccess:d})=>{const f=n(a);return c?e(r,{config:f}):d?e("div",{className:"fixed z-[9] w-full h-full",style:{background:f?.style?.base?.primaryColor},children:e(i,{url:f?.loader})}):void 0};export{a as FaceScan};
2
2
  //# sourceMappingURL=faceScan.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"faceScan.mjs","sources":["../src/components/faceScan/FaceScanErrorScreen.tsx","../src/components/faceScan/FaceScan.tsx"],"sourcesContent":["import { ArrowRight } from \"lucide-react\";\nimport Header from \"../Header\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\n\nfunction FaceScanErrorScreen({ resetScanState, loading, config }: { resetScanState?: () => void; loading?: boolean; config?: any }) {\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\tYour Scan Failed\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\tPlease click below to reset your scan.\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=\"Reset Scan\"\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","\"use client\";\nimport { useEffect, useRef, useState, useCallback, useMemo } 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 SpecificButton from \"../../atoms/specificButton/SpecificButton\";\nimport LoadingScreen from \"../LoadingScreen\";\n\nexport const FaceScan: React.FC<FaceScanProps> = ({ userDetails, onComplete, onScanError, onRetry, config,isError,isSuccess }) => {\n\t// const webcamRef = useRef<HTMLVideoElement | null>(null);\n\t// const canvasRef = useRef<HTMLCanvasElement | null>(null);\n\t// const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n\t// const recordedBlobsRef = useRef<Blob[] | null>([]);\n\t// const streamRef = useRef<MediaStream | null>(null);\n\t// const [showLoader, setShowLoader] = useState(false);\n\t// const [modelReady, setModelReady] = useState(false);\n\t// const [isScanning, setIsScanning] = useState(false);\n\t// const [showGuideCard, setShowGuideCard] = useState(true);\n\t// const [videoLoading, setVideoLoading] = useState(false);\n\t// const [videoError, setVideoError] = useState(false);\n\t// const [hasError, setHasError] = useState(false);\n\t// const [faceScanId, setFaceScanId] = useState(generateUuid());\n\tconst resolvedConfig = useLocalConfig(config);\n\t// const { email, gender, deviceFocalLength, shopDomain, callbackUrl } = userDetails;\n\t// const supportedTypes = useMemo(() => videoTypes.filter((type) => MediaRecorder.isTypeSupported(type)), []);\n\n\t// const 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\t// const 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\t// const videoFile = new File(recordedBlobsRef.current, `${faceScanId}.webm`, {\n\t\t\t// \ttype: \"video/webm\",\n\t\t\t// });\n\t\t\t// const fileSize = videoFile.size;\n\t\t\t// const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);\n\t\t\t// const estimatedDuration = Math.round(fileSize / 10000);\n\t\t\t// const 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\t// const 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\t// handleScanTimeCapture({\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\t// const uploadStartTime = Date.now();\n\t\t\t// handleScanTimeCapture({\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\t// const 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\t// Capture portrait-normalized stream\n\t\t// const canvasStream = canvas.captureStream(30); // 30fps\n\t\t// const mediaRecorderOptions = supportedTypes.length > 0 ? { mimeType: supportedTypes[0] } : {};\n\t\t// let mediaRecorder;\n\n\t\t// try {\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\t// const { 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\t// const 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\t// const 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\t// const 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\t// const 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// \tonComplete?.(data);\n\t// };\n\n\t// Initialize webcam\n\t// useEffect(() => {\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\tconsole.log(\"Webcam initialized\");\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\n\t\t// Cleanup function\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\t// useEffect(() => {\n\t// \tif (!modelReady || !isScanning) return;\n\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\t// const getButtonText = () => {\n\t// \tif (isScanning) return \"Reset\";\n\t// \tif (!isModelLoaded) return \"Loading...\";\n\t// \treturn \"Start\";\n\t// };\n\n\t// console.log(\"Model ready:\", modelReady, \"Has error:\", hasError, \"Is scanning:\", isScanning, \"showLoader\", showLoader);\n\n\t// useEffect(() => {\n\t// \tsetScanStage(-1);\n\t// \tif (isError || isSuccess) return;\n\t// \tposthog.init(posthogPublicKey, { api_host: posthogPublicHost });\n\t// \tposthog.capture(\"$pageview\");\n\t// }, [isError, isSuccess]);\n\n\tif (isError) {\n\t\treturn <FaceScanErrorScreen config={resolvedConfig} />;\n\t}\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?.primaryColor }}>\n\t\t\t\t{/* <Asset genderType={gender} /> */}\n\t\t\t\t<LoadingScreen url={resolvedConfig?.loader} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// return (\n\t// \t<>\n\t// \t\t<audio id=\"audioElement\" crossOrigin=\"anonymous\" preload=\"auto\" style={{ position: \"absolute\", zIndex: -99999 }} src=\"\" />\n\n\t// \t\t{showLoader && !hasError && (\n\t// \t\t\t<div className=\"fixed z-[9] w-full h-full\" style={{ background: resolvedConfig?.style?.base?.primaryColor }}>\n\t// \t\t\t\t{/* <Asset genderType={gender} /> */}\n\t// \t\t\t\t<LoadingScreen url={resolvedConfig?.loader} />\n\t// \t\t\t</div>\n\t// \t\t)}\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 stage={scanStage} videoLoading={videoLoading} setVideoLoading={setVideoLoading} videoError={videoError} setVideoError={setVideoError} gender={gender} config={resolvedConfig}>\n\t\t// \t\t\t\t<div className=\"flex justify-center w-full p-[1rem]\">\n\t\t// \t\t\t\t\t<SpecificButton\n\t\t// \t\t\t\t\t\tdisabled={showLoader || !isModelLoaded}\n\t\t// \t\t\t\t\t\tclassName=\"!w-[60px] !h-[35px] !py-0 !px-0\"\n\t\t// \t\t\t\t\t\tbuttonText={getButtonText()}\n\t\t// \t\t\t\t\t\tpostfixIcon={isScanning ? <ArrowRight /> : \"\"}\n\t\t// \t\t\t\t\t\tbuttonFunc={isScanning ? resetScanState : startScan}\n\t\t// \t\t\t\t\t\tresolvedConfig={resolvedConfig}\n\t\t// \t\t\t\t\t/>\n\t\t// \t\t\t\t</div>\n\t\t// \t\t\t</FaceScanGuide>\n\t\t// \t\t</Drawer>\n\t\t// \t)}\n\t\t// </>\n\t// );\n};\n"],"names":["FaceScanErrorScreen","resetScanState","loading","config","_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","SpecificButton","disabled","buttonText","postfixIcon","ArrowRight","buttonFunc","FaceScan","userDetails","onComplete","onScanError","onRetry","isError","isSuccess","useLocalConfig","primaryColor","LoadingScreen","url","loader"],"mappings":"qNAIA,SAASA,GAAoBC,eAAEA,EAAcC,QAAEA,EAAOC,OAAEA,IACvD,OACCC,SAAKC,UAAU,kFAAkFC,MAAO,CAAEC,WAAYJ,GAAQG,OAAOE,MAAMC,iBAAiBC,SAC3JC,EAAA,MAAA,CAAKN,UAAU,0DAAyDK,SAAA,CACvEN,EAACQ,EAAM,CAACC,WAAQC,eAAgBX,IAChCQ,SAAKN,UAAU,oCAAmCK,SAAA,CACjDN,EAAA,KAAA,CACCC,UAAU,uCACVC,MAAO,CACNS,WAAYZ,GAAQG,OAAOU,SAASC,mBAAqB,wBACzDC,SAAUf,GAAQG,OAAOU,SAASG,iBAAmB,OACrDC,MAAOjB,GAAQG,OAAOU,SAASK,cAAgB,OAC/CC,WAAYnB,GAAQG,OAAOU,SAASO,mBAAqB,UACzDb,SAAA,qBAIFN,EAAA,IAAA,CACCC,UAAU,cACVC,MAAO,CACNS,WAAYZ,GAAQG,OAAOkB,YAAYC,sBAAwB,sBAC/DP,SAAUf,GAAQG,OAAOkB,YAAYE,oBAAsB,OAC3DN,MAAOjB,GAAQG,OAAOkB,YAAYG,iBAAmB,UACrDL,WAAYnB,GAAQG,OAAOkB,YAAYI,sBAAwB,UAC/DlB,SAAA,2CAIFN,EAACyB,EAAc,CACdC,SAAU5B,EACVG,UAAU,iEACV0B,WAAW,aACXC,YAAa5B,EAAC6B,EAAU,CAAA,GACxBC,WAAY,IAAMjC,MAClBa,eAAgBX,WAMtB,OC3BagC,EAAoC,EAAGC,cAAaC,aAAYC,cAAaC,UAASpC,SAAOqC,UAAQC,gBAcjH,MAAM3B,EAAiB4B,EAAevC,GA4UtC,OAAIqC,EACIpC,EAACJ,EAAmB,CAACG,OAAQW,IAGjC2B,EAEFrC,EAAA,MAAA,CAAKC,UAAU,6BAA6BC,MAAO,CAAEC,WAAYO,GAAgBR,OAAOE,MAAMmC,cAAcjC,SAE3GN,EAACwC,EAAa,CAACC,IAAK/B,GAAgBgC,gBAJvC"}
1
+ {"version":3,"file":"faceScan.mjs","sources":["../src/components/faceScan/FaceScanErrorScreen.tsx","../src/components/faceScan/FaceScan.tsx"],"sourcesContent":["import { ArrowRight } from \"lucide-react\";\nimport Header from \"../Header\";\nimport SpecificButton from \"../../atoms/specificButton/SpecificButton\";\n\nfunction FaceScanErrorScreen({ resetScanState, loading, config }: { resetScanState?: () => void; loading?: boolean; config?: any }) {\n\treturn (\n\t\t<div id=\"faceScanErrorSuccess\" 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\tYour Scan Failed\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\tPlease click below to reset your scan.\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=\"Reset Scan\"\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","\"use client\";\nimport { useEffect, useRef, useState, useCallback, useMemo } 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 SpecificButton from \"../../atoms/specificButton/SpecificButton\";\nimport LoadingScreen from \"../LoadingScreen\";\n\nexport const FaceScan: React.FC<FaceScanProps> = ({ userDetails, onComplete, onScanError, onRetry, config,isError,isSuccess }) => {\n\t// const webcamRef = useRef<HTMLVideoElement | null>(null);\n\t// const canvasRef = useRef<HTMLCanvasElement | null>(null);\n\t// const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n\t// const recordedBlobsRef = useRef<Blob[] | null>([]);\n\t// const streamRef = useRef<MediaStream | null>(null);\n\t// const [showLoader, setShowLoader] = useState(false);\n\t// const [modelReady, setModelReady] = useState(false);\n\t// const [isScanning, setIsScanning] = useState(false);\n\t// const [showGuideCard, setShowGuideCard] = useState(true);\n\t// const [videoLoading, setVideoLoading] = useState(false);\n\t// const [videoError, setVideoError] = useState(false);\n\t// const [hasError, setHasError] = useState(false);\n\t// const [faceScanId, setFaceScanId] = useState(generateUuid());\n\tconst resolvedConfig = useLocalConfig(config);\n\t// const { email, gender, deviceFocalLength, shopDomain, callbackUrl } = userDetails;\n\t// const supportedTypes = useMemo(() => videoTypes.filter((type) => MediaRecorder.isTypeSupported(type)), []);\n\n\t// const 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\t// const 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\t// const videoFile = new File(recordedBlobsRef.current, `${faceScanId}.webm`, {\n\t\t\t// \ttype: \"video/webm\",\n\t\t\t// });\n\t\t\t// const fileSize = videoFile.size;\n\t\t\t// const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);\n\t\t\t// const estimatedDuration = Math.round(fileSize / 10000);\n\t\t\t// const 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\t// const 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\t// handleScanTimeCapture({\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\t// const uploadStartTime = Date.now();\n\t\t\t// handleScanTimeCapture({\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\t// const 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\t// Capture portrait-normalized stream\n\t\t// const canvasStream = canvas.captureStream(30); // 30fps\n\t\t// const mediaRecorderOptions = supportedTypes.length > 0 ? { mimeType: supportedTypes[0] } : {};\n\t\t// let mediaRecorder;\n\n\t\t// try {\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\t// const { 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\t// const 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\t// const 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\t// const 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\t// const 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// \tonComplete?.(data);\n\t// };\n\n\t// Initialize webcam\n\t// useEffect(() => {\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\tconsole.log(\"Webcam initialized\");\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\n\t\t// Cleanup function\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\t// useEffect(() => {\n\t// \tif (!modelReady || !isScanning) return;\n\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\t// const getButtonText = () => {\n\t// \tif (isScanning) return \"Reset\";\n\t// \tif (!isModelLoaded) return \"Loading...\";\n\t// \treturn \"Start\";\n\t// };\n\n\t// console.log(\"Model ready:\", modelReady, \"Has error:\", hasError, \"Is scanning:\", isScanning, \"showLoader\", showLoader);\n\n\t// useEffect(() => {\n\t// \tsetScanStage(-1);\n\t// \tif (isError || isSuccess) return;\n\t// \tposthog.init(posthogPublicKey, { api_host: posthogPublicHost });\n\t// \tposthog.capture(\"$pageview\");\n\t// }, [isError, isSuccess]);\n\n\tif (isError) {\n\t\treturn <FaceScanErrorScreen config={resolvedConfig} />;\n\t}\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?.primaryColor }}>\n\t\t\t\t{/* <Asset genderType={gender} /> */}\n\t\t\t\t<LoadingScreen url={resolvedConfig?.loader} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// return (\n\t// \t<>\n\t// \t\t<audio id=\"audioElement\" crossOrigin=\"anonymous\" preload=\"auto\" style={{ position: \"absolute\", zIndex: -99999 }} src=\"\" />\n\n\t// \t\t{showLoader && !hasError && (\n\t// \t\t\t<div className=\"fixed z-[9] w-full h-full\" style={{ background: resolvedConfig?.style?.base?.primaryColor }}>\n\t// \t\t\t\t{/* <Asset genderType={gender} /> */}\n\t// \t\t\t\t<LoadingScreen url={resolvedConfig?.loader} />\n\t// \t\t\t</div>\n\t// \t\t)}\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 stage={scanStage} videoLoading={videoLoading} setVideoLoading={setVideoLoading} videoError={videoError} setVideoError={setVideoError} gender={gender} config={resolvedConfig}>\n\t\t// \t\t\t\t<div className=\"flex justify-center w-full p-[1rem]\">\n\t\t// \t\t\t\t\t<SpecificButton\n\t\t// \t\t\t\t\t\tdisabled={showLoader || !isModelLoaded}\n\t\t// \t\t\t\t\t\tclassName=\"!w-[60px] !h-[35px] !py-0 !px-0\"\n\t\t// \t\t\t\t\t\tbuttonText={getButtonText()}\n\t\t// \t\t\t\t\t\tpostfixIcon={isScanning ? <ArrowRight /> : \"\"}\n\t\t// \t\t\t\t\t\tbuttonFunc={isScanning ? resetScanState : startScan}\n\t\t// \t\t\t\t\t\tresolvedConfig={resolvedConfig}\n\t\t// \t\t\t\t\t/>\n\t\t// \t\t\t\t</div>\n\t\t// \t\t\t</FaceScanGuide>\n\t\t// \t\t</Drawer>\n\t\t// \t)}\n\t\t// </>\n\t// );\n};\n"],"names":["FaceScanErrorScreen","resetScanState","loading","config","_jsx","id","className","style","background","base","backgroundColor","children","_jsxs","Header","noTitle","resolvedConfig","fontFamily","heading","headingFontFamily","fontSize","headingFontSize","color","headingColor","fontWeight","headingFontWeight","subheading","subheadingFontFamily","subheadingFontSize","subheadingColor","subheadingFontWeight","SpecificButton","disabled","buttonText","postfixIcon","ArrowRight","buttonFunc","FaceScan","userDetails","onComplete","onScanError","onRetry","isError","isSuccess","useLocalConfig","primaryColor","LoadingScreen","url","loader"],"mappings":"qNAIA,SAASA,GAAoBC,eAAEA,EAAcC,QAAEA,EAAOC,OAAEA,IACvD,OACCC,SAAKC,GAAG,uBAAuBC,UAAU,kFAAkFC,MAAO,CAAEC,WAAYL,GAAQI,OAAOE,MAAMC,iBAAiBC,SACrLC,EAAA,MAAA,CAAKN,UAAU,oEACdF,EAACS,GAAOC,SAAO,EAACC,eAAgBZ,IAChCS,EAAA,MAAA,CAAKN,UAAU,oCAAmCK,SAAA,CACjDP,EAAA,KAAA,CACCE,UAAU,uCACVC,MAAO,CACNS,WAAYb,GAAQI,OAAOU,SAASC,mBAAqB,wBACzDC,SAAUhB,GAAQI,OAAOU,SAASG,iBAAmB,OACrDC,MAAOlB,GAAQI,OAAOU,SAASK,cAAgB,OAC/CC,WAAYpB,GAAQI,OAAOU,SAASO,mBAAqB,UACzDb,SAAA,qBAIFP,EAAA,IAAA,CACCE,UAAU,cACVC,MAAO,CACNS,WAAYb,GAAQI,OAAOkB,YAAYC,sBAAwB,sBAC/DP,SAAUhB,GAAQI,OAAOkB,YAAYE,oBAAsB,OAC3DN,MAAOlB,GAAQI,OAAOkB,YAAYG,iBAAmB,UACrDL,WAAYpB,GAAQI,OAAOkB,YAAYI,sBAAwB,UAC/DlB,SAAA,2CAIFP,EAAC0B,EAAc,CACdC,SAAU7B,EACVI,UAAU,iEACV0B,WAAW,aACXC,YAAa7B,EAAC8B,EAAU,CAAA,GACxBC,WAAY,IAAMlC,MAClBc,eAAgBZ,WAMtB,OC3BaiC,EAAoC,EAAGC,cAAaC,aAAYC,cAAaC,UAASrC,SAAOsC,UAAQC,gBAcjH,MAAM3B,EAAiB4B,EAAexC,GA4UtC,OAAIsC,EACIrC,EAACJ,EAAmB,CAACG,OAAQY,IAGjC2B,EAEFtC,EAAA,MAAA,CAAKE,UAAU,6BAA6BC,MAAO,CAAEC,WAAYO,GAAgBR,OAAOE,MAAMmC,cAAcjC,SAE3GP,EAACyC,EAAa,CAACC,IAAK/B,GAAgBgC,gBAJvC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var e=require("react/jsx-runtime"),o=require("react"),l=require("./Header-Ce4cmwL6.js"),n=require("./enums-BD0ckKV4.js"),a=require("./arrow-right-CC1_17IM.js");function t(e){var o=Object.create(null);return e&&Object.keys(e).forEach(function(l){if("default"!==l){var n=Object.getOwnPropertyDescriptor(e,l);Object.defineProperty(o,l,n.get?n:{enumerable:!0,get:function(){return e[l]}})}}),o.default=e,Object.freeze(o)}require("react-dom");var i=t(o);const d=(...e)=>e.filter(Boolean).join(" "),m=i.forwardRef(({className:o,resolvedConfig:l,type:n,...a},t)=>e.jsxs(e.Fragment,{children:[e.jsx("input",{type:n,className:`${o||""} customInput `+d("flex w-full px-[.75rem] h-[40px] text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed backdrop-blur-sm bg-btn font-medium pl-[1rem] pr-[2.5rem] focus:ring-1 focus:outline-none transition-all duration-200"),autoCapitalize:"off",autoCorrect:"off",ref:t,...a,style:{background:l?.style?.input?.inputBackgroundColor||"#F9FAFC",color:l?.style?.input?.inputTextColor||"#000",fontSize:l?.style?.input?.inputFontSize||"16px",fontWeight:l?.style?.input?.inputFontWeight||"400",border:`1px solid ${l?.style?.input?.inputBorderColor||"transparent"}`,fontFamily:l?.style?.base?.baseFontFamily||"Inter, sans-serif",borderRadius:l?.style?.input?.inputBorderRadius||"4px"}}),e.jsx("style",{children:`\n .customInput::placeholder {\n color: ${l?.style?.input?.inputPlaceholderColor||"#000"};\n font-weight: ${l?.style?.input?.inputFontWeight||"500"};\n opacity: 1;\n font-size: ${l?.style?.input?.inputFontSize||"14px"};\n }\n .customInput:focus-visible {\n box-shadow:0 0 0 2px white, 0 0 0 4px rgb(from currentColor r g b / 0.5);\n }\n \n `})]}));m.displayName="CustomInput";
1
+ "use strict";var e=require("react/jsx-runtime"),o=require("react"),l=require("./Header-BiYtGF6l.js"),n=require("./enums-BD0ckKV4.js"),a=require("./arrow-right-CC1_17IM.js");function t(e){var o=Object.create(null);return e&&Object.keys(e).forEach(function(l){if("default"!==l){var n=Object.getOwnPropertyDescriptor(e,l);Object.defineProperty(o,l,n.get?n:{enumerable:!0,get:function(){return e[l]}})}}),o.default=e,Object.freeze(o)}require("react-dom");var i=t(o);const d=(...e)=>e.filter(Boolean).join(" "),m=i.forwardRef(({className:o,resolvedConfig:l,type:n,...a},t)=>e.jsxs(e.Fragment,{children:[e.jsx("input",{type:n,className:`${o||""} customInput `+d("flex w-full px-[.75rem] h-[40px] text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed backdrop-blur-sm bg-btn font-medium pl-[1rem] pr-[2.5rem] focus:ring-1 focus:outline-none transition-all duration-200"),autoCapitalize:"off",autoCorrect:"off",ref:t,...a,style:{background:l?.style?.input?.inputBackgroundColor||"#F9FAFC",color:l?.style?.input?.inputTextColor||"#000",fontSize:l?.style?.input?.inputFontSize||"16px",fontWeight:l?.style?.input?.inputFontWeight||"400",border:`1px solid ${l?.style?.input?.inputBorderColor||"transparent"}`,fontFamily:l?.style?.base?.baseFontFamily||"Inter, sans-serif",borderRadius:l?.style?.input?.inputBorderRadius||"4px"}}),e.jsx("style",{children:`\n .customInput::placeholder {\n color: ${l?.style?.input?.inputPlaceholderColor||"#000"};\n font-weight: ${l?.style?.input?.inputFontWeight||"500"};\n opacity: 1;\n font-size: ${l?.style?.input?.inputFontSize||"14px"};\n }\n .customInput:focus-visible {\n box-shadow:0 0 0 2px white, 0 0 0 4px rgb(from currentColor r g b / 0.5);\n }\n \n `})]}));m.displayName="CustomInput";
2
2
  /**
3
3
  * @license lucide-react v0.553.0 - ISC
4
4
  *
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import{jsxs as e,Fragment as l,jsx as o}from"react/jsx-runtime";import*as n from"react";import a,{isValidElement as t,cloneElement as i,Children as d,useState as m,useCallback as _,useMemo as r,useEffect as c,createContext as s,useRef as h,useLayoutEffect as f,useId as g,useContext as u,useInsertionEffect as p,Fragment as y,createElement as v,forwardRef as P,Component as A}from"react";import{S as x,u as S,a as b,H as G,b as C,f as T,l as E,c as O,m as M,d as N,e as R,s as L,g as w,h as X,i as F,j as V,k as I,O as D,n as k,o as H}from"./Header-BeNeDIFA.js";import{h as U,i as B,s as K,w as j,T as W,u as Y,a as $,b as z,E as Z,c as Q,P as J,d as q,e as ee,f as le,g as oe,_ as ne,j as ae,k as te,l as ie,m as de,n as me,o as _e,p as re,q as ce,r as se,t as he,v as fe,x as ge,y as ue,z as pe,A as ye,B as ve,C as Pe,D as Ae,F as xe,G as Se,H as be,I as Ge,J as Ce,K as Te,L as Ee,M as Oe,N as Me,O as Ne,Q as Re,R as Le,S as we,U as Xe,V as Fe,W as Ve,X as Ie,Y as De,Z as ke,$ as He,a0 as Ue,a1 as Be,a2 as Ke,a3 as je,a4 as We,a5 as Ye,a6 as $e,a7 as ze,a8 as Ze,a9 as Qe,aa as Je,ab as qe}from"./enums-C7dttoT7.js";export{ac as PreferredLanguage}from"./enums-C7dttoT7.js";import{c as el,A as ll}from"./arrow-right-DXQbS3wL.js";import"react-dom";const ol=(...e)=>e.filter(Boolean).join(" "),nl=n.forwardRef(({className:n,resolvedConfig:a,type:t,...i},d)=>e(l,{children:[o("input",{type:t,className:`${n||""} customInput `+ol("flex w-full px-[.75rem] h-[40px] text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed backdrop-blur-sm bg-btn font-medium pl-[1rem] pr-[2.5rem] focus:ring-1 focus:outline-none transition-all duration-200"),autoCapitalize:"off",autoCorrect:"off",ref:d,...i,style:{background:a?.style?.input?.inputBackgroundColor||"#F9FAFC",color:a?.style?.input?.inputTextColor||"#000",fontSize:a?.style?.input?.inputFontSize||"16px",fontWeight:a?.style?.input?.inputFontWeight||"400",border:`1px solid ${a?.style?.input?.inputBorderColor||"transparent"}`,fontFamily:a?.style?.base?.baseFontFamily||"Inter, sans-serif",borderRadius:a?.style?.input?.inputBorderRadius||"4px"}}),o("style",{children:`\n .customInput::placeholder {\n color: ${a?.style?.input?.inputPlaceholderColor||"#000"};\n font-weight: ${a?.style?.input?.inputFontWeight||"500"};\n opacity: 1;\n font-size: ${a?.style?.input?.inputFontSize||"14px"};\n }\n .customInput:focus-visible {\n box-shadow:0 0 0 2px white, 0 0 0 4px rgb(from currentColor r g b / 0.5);\n }\n \n `})]}));nl.displayName="CustomInput";
1
+ import{jsxs as e,Fragment as l,jsx as o}from"react/jsx-runtime";import*as n from"react";import a,{isValidElement as t,cloneElement as i,Children as d,useState as m,useCallback as _,useMemo as r,useEffect as c,createContext as s,useRef as h,useLayoutEffect as f,useId as g,useContext as u,useInsertionEffect as p,Fragment as y,createElement as v,forwardRef as P,Component as A}from"react";import{S as x,u as S,a as b,H as G,b as C,f as T,l as E,c as O,m as M,d as N,e as R,s as L,g as w,h as X,i as F,j as V,k as I,O as D,n as k,o as H}from"./Header-BhrDARhH.js";import{h as U,i as B,s as K,w as j,T as W,u as Y,a as $,b as z,E as Z,c as Q,P as J,d as q,e as ee,f as le,g as oe,_ as ne,j as ae,k as te,l as ie,m as de,n as me,o as _e,p as re,q as ce,r as se,t as he,v as fe,x as ge,y as ue,z as pe,A as ye,B as ve,C as Pe,D as Ae,F as xe,G as Se,H as be,I as Ge,J as Ce,K as Te,L as Ee,M as Oe,N as Me,O as Ne,Q as Re,R as Le,S as we,U as Xe,V as Fe,W as Ve,X as Ie,Y as De,Z as ke,$ as He,a0 as Ue,a1 as Be,a2 as Ke,a3 as je,a4 as We,a5 as Ye,a6 as $e,a7 as ze,a8 as Ze,a9 as Qe,aa as Je,ab as qe}from"./enums-C7dttoT7.js";export{ac as PreferredLanguage}from"./enums-C7dttoT7.js";import{c as el,A as ll}from"./arrow-right-DXQbS3wL.js";import"react-dom";const ol=(...e)=>e.filter(Boolean).join(" "),nl=n.forwardRef(({className:n,resolvedConfig:a,type:t,...i},d)=>e(l,{children:[o("input",{type:t,className:`${n||""} customInput `+ol("flex w-full px-[.75rem] h-[40px] text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed backdrop-blur-sm bg-btn font-medium pl-[1rem] pr-[2.5rem] focus:ring-1 focus:outline-none transition-all duration-200"),autoCapitalize:"off",autoCorrect:"off",ref:d,...i,style:{background:a?.style?.input?.inputBackgroundColor||"#F9FAFC",color:a?.style?.input?.inputTextColor||"#000",fontSize:a?.style?.input?.inputFontSize||"16px",fontWeight:a?.style?.input?.inputFontWeight||"400",border:`1px solid ${a?.style?.input?.inputBorderColor||"transparent"}`,fontFamily:a?.style?.base?.baseFontFamily||"Inter, sans-serif",borderRadius:a?.style?.input?.inputBorderRadius||"4px"}}),o("style",{children:`\n .customInput::placeholder {\n color: ${a?.style?.input?.inputPlaceholderColor||"#000"};\n font-weight: ${a?.style?.input?.inputFontWeight||"500"};\n opacity: 1;\n font-size: ${a?.style?.input?.inputFontSize||"14px"};\n }\n .customInput:focus-visible {\n box-shadow:0 0 0 2px white, 0 0 0 4px rgb(from currentColor r g b / 0.5);\n }\n \n `})]}));nl.displayName="CustomInput";
2
2
  /**
3
3
  * @license lucide-react v0.553.0 - ISC
4
4
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swan-admin/swan-web-component",
3
- "version": "1.0.75",
3
+ "version": "1.0.76",
4
4
  "description": "Cross-framework Onboarding component (React + Angular compatible)",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",