@anker-in/campaign-ui 0.4.2 → 0.4.3-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/cjs/components/LiveChatWidget/components/ChatInput.js +1 -1
  2. package/dist/cjs/components/LiveChatWidget/components/ChatInput.js.map +2 -2
  3. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js +1 -1
  4. package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js.map +2 -2
  5. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
  6. package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js.map +2 -2
  7. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -1
  8. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +2 -2
  9. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
  10. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +2 -2
  11. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
  12. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js.map +2 -2
  13. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
  14. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +2 -2
  15. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +1 -1
  16. package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +2 -2
  17. package/dist/cjs/components/LiveChatWidget/utils/fetcher.js +1 -1
  18. package/dist/cjs/components/LiveChatWidget/utils/fetcher.js.map +3 -3
  19. package/dist/cjs/components/credits/modal/SubscribeModal.js +1 -1
  20. package/dist/cjs/components/credits/modal/SubscribeModal.js.map +3 -3
  21. package/dist/cjs/stories/LiveChatWidget.stories.js +2 -2
  22. package/dist/cjs/stories/LiveChatWidget.stories.js.map +2 -2
  23. package/dist/esm/components/LiveChatWidget/components/ChatInput.js +1 -1
  24. package/dist/esm/components/LiveChatWidget/components/ChatInput.js.map +2 -2
  25. package/dist/esm/components/LiveChatWidget/components/ChatMessage.js +2 -2
  26. package/dist/esm/components/LiveChatWidget/components/ChatMessage.js.map +2 -2
  27. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
  28. package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js.map +2 -2
  29. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -1
  30. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +2 -2
  31. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
  32. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +2 -2
  33. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
  34. package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js.map +2 -2
  35. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
  36. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +2 -2
  37. package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +1 -1
  38. package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +2 -2
  39. package/dist/esm/components/LiveChatWidget/utils/fetcher.js +1 -1
  40. package/dist/esm/components/LiveChatWidget/utils/fetcher.js.map +3 -3
  41. package/dist/esm/components/credits/modal/SubscribeModal.js +1 -1
  42. package/dist/esm/components/credits/modal/SubscribeModal.js.map +3 -3
  43. package/dist/esm/stories/LiveChatWidget.stories.js +1 -1
  44. package/dist/esm/stories/LiveChatWidget.stories.js.map +2 -2
  45. package/package.json +19 -19
  46. package/src/components/LiveChatWidget/components/ChatInput.tsx +2 -2
  47. package/src/components/LiveChatWidget/components/ChatMessage.tsx +1 -1
  48. package/src/components/LiveChatWidget/components/MessageContent/CartCard.tsx +7 -7
  49. package/src/components/LiveChatWidget/components/MessageContent/ProductCard.tsx +2 -2
  50. package/src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx +1 -1
  51. package/src/components/LiveChatWidget/components/MessageContent/ProductList.tsx +2 -2
  52. package/src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx +2 -2
  53. package/src/components/LiveChatWidget/components/MessageContent/ThinkingBlock.tsx +3 -3
  54. package/src/components/LiveChatWidget/utils/fetcher.ts +3 -12
  55. package/src/components/credits/modal/SubscribeModal.tsx +1 -3
  56. package/src/stories/LiveChatWidget.stories.tsx +2 -2
  57. package/dist/cjs/stories/CartCard.stories.d.ts +0 -33
  58. package/dist/cjs/stories/CartCard.stories.js +0 -21
  59. package/dist/cjs/stories/CartCard.stories.js.map +0 -7
  60. package/dist/esm/stories/CartCard.stories.d.ts +0 -33
  61. package/dist/esm/stories/CartCard.stories.js +0 -21
  62. package/dist/esm/stories/CartCard.stories.js.map +0 -7
@@ -1,2 +1,2 @@
1
- const u=async(n,t)=>{if(typeof window>"u")return console.warn("[LiveChat Fetcher] reCAPTCHA not available in non-browser environment"),!1;const r=window.grecaptcha?.enterprise?.execute??window.grecaptcha?.execute;if(!r)return console.warn("[LiveChat Fetcher] reCAPTCHA not loaded (neither enterprise nor standard v3)"),!1;try{return await r(t,{action:n})}catch(e){return console.error("[LiveChat Fetcher] reCAPTCHA execution failed:",e),!1}};async function f(n,t,r="X-Recaptcha-Token"){const e=await u(n,t);return e?{[r]:e}:{}}const T=async({url:n,method:t="POST",headers:r={},body:e,timeout:o=9e4,needRecaptcha:h=!1,recaptchaSitekey:c,recaptchaAction:g="",recaptchaHeaderKey:p="X-Recaptcha-Token"})=>{let s={};h&&(c?s=await f(g,c,p):console.warn("[LiveChat Fetcher] needRecaptcha=true but recaptchaSitekey is missing"));const d=e?JSON.stringify(e):void 0,l=new AbortController;let i;o&&(i=setTimeout(()=>l.abort(),o));try{const a=await fetch(n,{method:t,mode:"cors",headers:{"Content-Type":"application/json",...r,...s},signal:l.signal,...t!=="GET"&&d&&{body:d}});return i&&clearTimeout(i),a}catch(a){throw i&&clearTimeout(i),a}};export{T as fetcher};
1
+ const u=async(r,e)=>{if(typeof window>"u"||!window.grecaptcha?.enterprise?.execute)return console.warn("[LiveChat Fetcher] reCAPTCHA not loaded"),!1;try{return await window.grecaptcha.enterprise.execute(e,{action:r})}catch(t){return console.error("[LiveChat Fetcher] reCAPTCHA execution failed:",t),!1}};async function f(r,e,t="X-Recaptcha-Token"){const n=await u(r,e);return n?{[t]:n}:{}}const T=async({url:r,method:e="POST",headers:t={},body:n,timeout:o=9e4,needRecaptcha:l=!1,recaptchaSitekey:c,recaptchaAction:h="",recaptchaHeaderKey:p="X-Recaptcha-Token"})=>{let s={};l&&(c?s=await f(h,c,p):console.warn("[LiveChat Fetcher] needRecaptcha=true but recaptchaSitekey is missing"));const d=n?JSON.stringify(n):void 0,g=new AbortController;let i;o&&(i=setTimeout(()=>g.abort(),o));try{const a=await fetch(r,{method:e,mode:"cors",headers:{"Content-Type":"application/json",...t,...s},signal:g.signal,...e!=="GET"&&d&&{body:d}});return i&&clearTimeout(i),a}catch(a){throw i&&clearTimeout(i),a}};export{T as fetcher};
2
2
  //# sourceMappingURL=fetcher.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/components/LiveChatWidget/utils/fetcher.ts"],
4
- "sourcesContent": ["/**\n * LiveChat Fetcher\n * \u53C2\u7167 storefront \u7684\u5B9E\u73B0\uFF0C\u652F\u6301 reCAPTCHA\n */\n\n/**\n * \u6267\u884C Google reCAPTCHA \u9A8C\u8BC1\n * \u517C\u5BB9 Enterprise \u7248 (recaptcha/enterprise.js) \u548C\u6807\u51C6\u7248 v3 (recaptcha/api.js)\n * \u4F18\u5148\u4F7F\u7528 Enterprise \u7248\uFF0C\u56DE\u9000\u5230\u6807\u51C6\u7248\n */\nconst executeRecaptcha = async (action: string, sitekey: string): Promise<string | false> => {\n if (typeof window === 'undefined') {\n console.warn('[LiveChat Fetcher] reCAPTCHA not available in non-browser environment')\n return false\n }\n\n const executor = window.grecaptcha?.enterprise?.execute ?? window.grecaptcha?.execute\n\n if (!executor) {\n console.warn('[LiveChat Fetcher] reCAPTCHA not loaded (neither enterprise nor standard v3)')\n return false\n }\n\n try {\n const token = await executor(sitekey, { action })\n return token\n } catch (error) {\n console.error('[LiveChat Fetcher] reCAPTCHA execution failed:', error)\n return false\n }\n}\n\n/**\n * \u83B7\u53D6 reCAPTCHA headers\n */\nasync function getRecaptchaHeaders(\n action: string,\n sitekey: string,\n headerKey = 'X-Recaptcha-Token'\n): Promise<Record<string, string>> {\n const recaptchaToken = await executeRecaptcha(action, sitekey)\n if (!recaptchaToken) {\n return {}\n }\n return {\n [headerKey]: recaptchaToken,\n }\n}\n\n/**\n * Fetcher \u53C2\u6570\n */\nexport interface FetcherOptions {\n url: string\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'\n headers?: Record<string, string>\n body?: any\n timeout?: number\n needRecaptcha?: boolean\n recaptchaSitekey?: string\n recaptchaAction?: string\n recaptchaHeaderKey?: string\n}\n\n/**\n * Fetcher \u51FD\u6570\n * \u652F\u6301 reCAPTCHA \u548C\u81EA\u5B9A\u4E49 headers\n */\nexport const fetcher = async ({\n url,\n method = 'POST',\n headers = {},\n body,\n timeout = 90000,\n needRecaptcha = false,\n recaptchaSitekey,\n recaptchaAction = '',\n recaptchaHeaderKey = 'X-Recaptcha-Token',\n}: FetcherOptions): Promise<Response> => {\n // \u83B7\u53D6 reCAPTCHA headers\uFF08\u5982\u679C\u9700\u8981\uFF09\n let recaptchaHeaders: Record<string, string> = {}\n if (needRecaptcha) {\n if (!recaptchaSitekey) {\n console.warn('[LiveChat Fetcher] needRecaptcha=true but recaptchaSitekey is missing')\n } else {\n recaptchaHeaders = await getRecaptchaHeaders(recaptchaAction, recaptchaSitekey, recaptchaHeaderKey)\n }\n }\n\n // \u51C6\u5907\u8BF7\u6C42\u4F53\n const bodyData = body ? JSON.stringify(body) : undefined\n\n const controller = new AbortController()\n let timeoutTimer: NodeJS.Timeout | undefined\n if (timeout) {\n timeoutTimer = setTimeout(() => controller.abort(), timeout)\n }\n\n try {\n const response = await fetch(url, {\n method,\n mode: 'cors',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n ...recaptchaHeaders,\n },\n signal: controller.signal,\n ...(method !== 'GET' && bodyData && { body: bodyData }),\n })\n\n if (timeoutTimer) {\n clearTimeout(timeoutTimer)\n }\n\n return response\n } catch (error) {\n if (timeoutTimer) {\n clearTimeout(timeoutTimer)\n }\n throw error\n }\n}\n\n/**\n * \u6269\u5C55 Window \u63A5\u53E3\u4EE5\u652F\u6301 grecaptcha\n */\n declare global {\n interface Window {\n grecaptcha?: {\n execute: (sitekey: string, options: { action: string }) => Promise<string>\n ready: (callback: () => void) => void\n enterprise?: {\n execute: (sitekey: string, options: { action: string }) =>\n Promise<string>\n ready: (callback: () => void) => void\n }\n }\n }\n }\n"],
5
- "mappings": "AAUA,MAAMA,EAAmB,MAAOC,EAAgBC,IAA6C,CAC3F,GAAI,OAAO,OAAW,IACpB,eAAQ,KAAK,uEAAuE,EAC7E,GAGT,MAAMC,EAAW,OAAO,YAAY,YAAY,SAAW,OAAO,YAAY,QAE9E,GAAI,CAACA,EACH,eAAQ,KAAK,8EAA8E,EACpF,GAGT,GAAI,CAEF,OADc,MAAMA,EAASD,EAAS,CAAE,OAAAD,CAAO,CAAC,CAElD,OAASG,EAAO,CACd,eAAQ,MAAM,iDAAkDA,CAAK,EAC9D,EACT,CACF,EAKA,eAAeC,EACbJ,EACAC,EACAI,EAAY,oBACqB,CACjC,MAAMC,EAAiB,MAAMP,EAAiBC,EAAQC,CAAO,EAC7D,OAAKK,EAGE,CACL,CAACD,CAAS,EAAGC,CACf,EAJS,CAAC,CAKZ,CAqBO,MAAMC,EAAU,MAAO,CAC5B,IAAAC,EACA,OAAAC,EAAS,OACT,QAAAC,EAAU,CAAC,EACX,KAAAC,EACA,QAAAC,EAAU,IACV,cAAAC,EAAgB,GAChB,iBAAAC,EACA,gBAAAC,EAAkB,GAClB,mBAAAC,EAAqB,mBACvB,IAAyC,CAEvC,IAAIC,EAA2C,CAAC,EAC5CJ,IACGC,EAGHG,EAAmB,MAAMb,EAAoBW,EAAiBD,EAAkBE,CAAkB,EAFlG,QAAQ,KAAK,uEAAuE,GAOxF,MAAME,EAAWP,EAAO,KAAK,UAAUA,CAAI,EAAI,OAEzCQ,EAAa,IAAI,gBACvB,IAAIC,EACAR,IACFQ,EAAe,WAAW,IAAMD,EAAW,MAAM,EAAGP,CAAO,GAG7D,GAAI,CACF,MAAMS,EAAW,MAAM,MAAMb,EAAK,CAChC,OAAAC,EACA,KAAM,OACN,QAAS,CACP,eAAgB,mBAChB,GAAGC,EACH,GAAGO,CACL,EACA,OAAQE,EAAW,OACnB,GAAIV,IAAW,OAASS,GAAY,CAAE,KAAMA,CAAS,CACvD,CAAC,EAED,OAAIE,GACF,aAAaA,CAAY,EAGpBC,CACT,OAASlB,EAAO,CACd,MAAIiB,GACF,aAAaA,CAAY,EAErBjB,CACR,CACF",
6
- "names": ["executeRecaptcha", "action", "sitekey", "executor", "error", "getRecaptchaHeaders", "headerKey", "recaptchaToken", "fetcher", "url", "method", "headers", "body", "timeout", "needRecaptcha", "recaptchaSitekey", "recaptchaAction", "recaptchaHeaderKey", "recaptchaHeaders", "bodyData", "controller", "timeoutTimer", "response"]
4
+ "sourcesContent": ["/**\n * LiveChat Fetcher\n * \u53C2\u7167 storefront \u7684\u5B9E\u73B0\uFF0C\u652F\u6301 reCAPTCHA\n */\n\n/**\n * \u6267\u884C Google reCAPTCHA \u9A8C\u8BC1\n */\nconst executeRecaptcha = async (action: string, sitekey: string): Promise<string | false> => {\n if (typeof window === 'undefined' || !window.grecaptcha?.enterprise?.execute) {\n console.warn('[LiveChat Fetcher] reCAPTCHA not loaded')\n return false\n }\n\n try {\n const token = await window.grecaptcha.enterprise.execute(sitekey, { action })\n return token\n } catch (error) {\n console.error('[LiveChat Fetcher] reCAPTCHA execution failed:', error)\n return false\n }\n}\n\n/**\n * \u83B7\u53D6 reCAPTCHA headers\n */\nasync function getRecaptchaHeaders(\n action: string,\n sitekey: string,\n headerKey = 'X-Recaptcha-Token'\n): Promise<Record<string, string>> {\n const recaptchaToken = await executeRecaptcha(action, sitekey)\n if (!recaptchaToken) {\n return {}\n }\n return {\n [headerKey]: recaptchaToken,\n }\n}\n\n/**\n * Fetcher \u53C2\u6570\n */\nexport interface FetcherOptions {\n url: string\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'\n headers?: Record<string, string>\n body?: any\n timeout?: number\n needRecaptcha?: boolean\n recaptchaSitekey?: string\n recaptchaAction?: string\n recaptchaHeaderKey?: string\n}\n\n/**\n * Fetcher \u51FD\u6570\n * \u652F\u6301 reCAPTCHA \u548C\u81EA\u5B9A\u4E49 headers\n */\nexport const fetcher = async ({\n url,\n method = 'POST',\n headers = {},\n body,\n timeout = 90000,\n needRecaptcha = false,\n recaptchaSitekey,\n recaptchaAction = '',\n recaptchaHeaderKey = 'X-Recaptcha-Token',\n}: FetcherOptions): Promise<Response> => {\n // \u83B7\u53D6 reCAPTCHA headers\uFF08\u5982\u679C\u9700\u8981\uFF09\n let recaptchaHeaders: Record<string, string> = {}\n if (needRecaptcha) {\n if (!recaptchaSitekey) {\n console.warn('[LiveChat Fetcher] needRecaptcha=true but recaptchaSitekey is missing')\n } else {\n recaptchaHeaders = await getRecaptchaHeaders(recaptchaAction, recaptchaSitekey, recaptchaHeaderKey)\n }\n }\n\n // \u51C6\u5907\u8BF7\u6C42\u4F53\n const bodyData = body ? JSON.stringify(body) : undefined\n\n const controller = new AbortController()\n let timeoutTimer: NodeJS.Timeout | undefined\n if (timeout) {\n timeoutTimer = setTimeout(() => controller.abort(), timeout)\n }\n\n try {\n const response = await fetch(url, {\n method,\n mode: 'cors',\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n ...recaptchaHeaders,\n },\n signal: controller.signal,\n ...(method !== 'GET' && bodyData && { body: bodyData }),\n })\n\n if (timeoutTimer) {\n clearTimeout(timeoutTimer)\n }\n\n return response\n } catch (error) {\n if (timeoutTimer) {\n clearTimeout(timeoutTimer)\n }\n throw error\n }\n}\n\n/**\n * \u6269\u5C55 Window \u63A5\u53E3\u4EE5\u652F\u6301 grecaptcha\n */\n declare global {\n interface Window {\n grecaptcha?: {\n execute: (sitekey: string, options: { action: string }) => Promise<string>\n ready: (callback: () => void) => void\n enterprise?: {\n execute: (sitekey: string, options: { action: string }) =>\n Promise<string>\n ready: (callback: () => void) => void\n }\n }\n }\n }\n"],
5
+ "mappings": "AAQA,MAAMA,EAAmB,MAAOC,EAAgBC,IAA6C,CAC3F,GAAI,OAAO,OAAW,KAAe,CAAC,OAAO,YAAY,YAAY,QACnE,eAAQ,KAAK,yCAAyC,EAC/C,GAGT,GAAI,CAEF,OADc,MAAM,OAAO,WAAW,WAAW,QAAQA,EAAS,CAAE,OAAAD,CAAO,CAAC,CAE9E,OAASE,EAAO,CACd,eAAQ,MAAM,iDAAkDA,CAAK,EAC9D,EACT,CACF,EAKA,eAAeC,EACbH,EACAC,EACAG,EAAY,oBACqB,CACjC,MAAMC,EAAiB,MAAMN,EAAiBC,EAAQC,CAAO,EAC7D,OAAKI,EAGE,CACL,CAACD,CAAS,EAAGC,CACf,EAJS,CAAC,CAKZ,CAqBO,MAAMC,EAAU,MAAO,CAC5B,IAAAC,EACA,OAAAC,EAAS,OACT,QAAAC,EAAU,CAAC,EACX,KAAAC,EACA,QAAAC,EAAU,IACV,cAAAC,EAAgB,GAChB,iBAAAC,EACA,gBAAAC,EAAkB,GAClB,mBAAAC,EAAqB,mBACvB,IAAyC,CAEvC,IAAIC,EAA2C,CAAC,EAC5CJ,IACGC,EAGHG,EAAmB,MAAMb,EAAoBW,EAAiBD,EAAkBE,CAAkB,EAFlG,QAAQ,KAAK,uEAAuE,GAOxF,MAAME,EAAWP,EAAO,KAAK,UAAUA,CAAI,EAAI,OAEzCQ,EAAa,IAAI,gBACvB,IAAIC,EACAR,IACFQ,EAAe,WAAW,IAAMD,EAAW,MAAM,EAAGP,CAAO,GAG7D,GAAI,CACF,MAAMS,EAAW,MAAM,MAAMb,EAAK,CAChC,OAAAC,EACA,KAAM,OACN,QAAS,CACP,eAAgB,mBAChB,GAAGC,EACH,GAAGO,CACL,EACA,OAAQE,EAAW,OACnB,GAAIV,IAAW,OAASS,GAAY,CAAE,KAAMA,CAAS,CACvD,CAAC,EAED,OAAIE,GACF,aAAaA,CAAY,EAGpBC,CACT,OAASlB,EAAO,CACd,MAAIiB,GACF,aAAaA,CAAY,EAErBjB,CACR,CACF",
6
+ "names": ["executeRecaptcha", "action", "sitekey", "error", "getRecaptchaHeaders", "headerKey", "recaptchaToken", "fetcher", "url", "method", "headers", "body", "timeout", "needRecaptcha", "recaptchaSitekey", "recaptchaAction", "recaptchaHeaderKey", "recaptchaHeaders", "bodyData", "controller", "timeoutTimer", "response"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{jsx as t,jsxs as g}from"react/jsx-runtime";import{useCallback as T,useEffect as P,useState as l}from"react";import{useRouter as k}from"next/router";import{Button as A,Checkbox as D,Picture as I,Text as x}from"@anker-in/headless-ui";import{classNames as n,fetcher as L,gaTrack as b,useHeadlessContext as R}from"@anker-in/lib";import r from"js-cookie";import{parse as B}from"query-string";import F from"crypto-js/sha256";import{useCreditsContext as H}from"../context/provider";import{ROUNDED_BRANDS as q}from"../../../constants";import{emailValidate as O}from"../context/utils";import{CreditsModalContainer as U}from"./ModalContainer";const V=()=>{if(typeof window>"u")return{register_source:""};const{search:e,href:a}=window.location||{},o=B(e);return{fbuy_ref_code:r.get("fbuy_ref_code"),affiliate:r.get("affiliate"),ref:r.get("ref_ads"),inviter_code:o.ic||o.inviter_code||r.get("inviter_code"),register_source:o.redirect||r.get("reg_source")||a,deals_type:r.get("deal"),transfer_id:r.get("transfer_id")}};function ee({copy:e,onSuccess:a,...o}){const{brand:p}=R(),m=q.includes(p),{locale:h}=k(),[d,M]=l(!1),[s,v]=l(""),[_,i]=l(""),[C,y]=l(""),[w,N]=l(!1),{profile:c}=H(),S=T(u=>{i(""),v(u.target?.value?.trim())},[]),E=T(async()=>{if(i(""),!s)return i("Please fill in your email");if(!O(s))return i("Invalid email address");if(!d)return i("Please agree to the policy");N(!0);const{register_source:u}=V(),f=await L({locale:h,action:"subscribe",url:"/api/multipass/subscribe/subscribe_emails",method:"POST",body:{email:s,register_source:u,brand:p,deals_type:e.dealsType||"vip_subscribe"},headers:{},type:""});N(!1),f.errors?i(f.errors||f.statusText):(y(e.successTips||"Subscribed successfully!"),a&&a(),setTimeout(()=>{y("")},3e3),b({subscribe_hashed_email:s?F(s):""}),b({event:"ga4Event",event_name:"subscribe",event_parameters:{page_group:e.dealsType||"vip_subscribe",position:"pop_up"}}),b({event:"uaEvent",eventCategory:"subscribe",eventAction:e.dealsType||"vip_subscribe",eventLabel:"pop_up",nonInteraction:!1}))},[s,d,h,p,e.dealsType,e.successTips,a]);return P(()=>{c&&c?.email&&v(c?.email)},[c]),t(U,{className:"w-[540px] md:h-auto",scrollClassName:"mb-[40px] min-l:px-[48px] md:mb-[24px]",titleClassName:"h-[56px]",useAnimation:!0,animationClassName:"md:translate-y-[100vh]",...o,children:g("div",{className:"flex flex-col gap-[16px] text-center min-l:px-[16px]",children:[t("div",{children:t(x,{className:n("mb-[24px] text-[22px] font-bold"),html:e.title})}),e.desc&&t(x,{className:"mb-[8px] text-left text-[16px] font-semibold leading-[1.4] text-[#1F2021]",html:e.desc}),g("div",{className:n("relative flex h-[52px] w-full overflow-hidden rounded-[2px] md:grid md:h-auto md:grid-rows-1 md:gap-[16px]",!m&&"rounded-none"),children:[t("input",{className:n("h-full flex-1 rounded-l-[2px] border-[1px] border-[#d8d8d8] px-[14px] py-[17px] text-[16px] font-semibold leading-[1] outline-none placeholder:text-[#999] md:h-[52px] md:rounded-[2px]",!m&&"rounded-none"),placeholder:e.placeholder,value:s,onChange:S}),t(A,{variant:"primary",onClick:E,loading:w,className:n("legacy-headless-ui-primary-button !h-full !min-w-0 !rounded-l-none !rounded-r-[2px] !px-[40px] !py-[13px]",!m&&"rounded-none"),children:t(I,{source:"https://cdn.shopify.com/s/files/1/0512/8568/8505/files/icon_email.png?v=1697527383",className:"h-[24px] w-[24px]",alt:"email"})})]}),g("div",{className:"flex w-full",children:[t(D,{checked:d,onCheckedChange:()=>M(!d),required:!0,className:"border-[#1d1d1f]"}),t("label",{className:"text-left ml-2 text-[14px] font-semibold text-[#777] [&_a]:underline",dangerouslySetInnerHTML:{__html:e?.policy||""}})]}),t("div",{className:n("w-full text-left text-[16px] font-semibold",_&&"text-[#F84D4F]",C&&"text-[#52C41A]"),children:t(x,{html:C||_||""})})]})})}export{ee as CreditsSubscribeModal};
1
+ import{jsx as t,jsxs as g}from"react/jsx-runtime";import{useCallback as T,useEffect as P,useState as l}from"react";import{Button as k,Checkbox as A,Picture as D,Text as x}from"@anker-in/headless-ui";import{classNames as n,fetcher as I,gaTrack as b,useHeadlessContext as L}from"@anker-in/lib";import r from"js-cookie";import{parse as B}from"query-string";import F from"crypto-js/sha256";import{useCreditsContext as H}from"../context/provider";import{ROUNDED_BRANDS as R}from"../../../constants";import{emailValidate as q}from"../context/utils";import{CreditsModalContainer as O}from"./ModalContainer";const U=()=>{if(typeof window>"u")return{register_source:""};const{search:e,href:a}=window.location||{},o=B(e);return{fbuy_ref_code:r.get("fbuy_ref_code"),affiliate:r.get("affiliate"),ref:r.get("ref_ads"),inviter_code:o.ic||o.inviter_code||r.get("inviter_code"),register_source:o.redirect||r.get("reg_source")||a,deals_type:r.get("deal"),transfer_id:r.get("transfer_id")}};function $({copy:e,onSuccess:a,...o}){const{brand:p,locale:h}=L(),m=R.includes(p),[d,M]=l(!1),[s,v]=l(""),[_,i]=l(""),[C,y]=l(""),[w,N]=l(!1),{profile:c}=H(),S=T(u=>{i(""),v(u.target?.value?.trim())},[]),E=T(async()=>{if(i(""),!s)return i("Please fill in your email");if(!q(s))return i("Invalid email address");if(!d)return i("Please agree to the policy");N(!0);const{register_source:u}=U(),f=await I({locale:h,action:"subscribe",url:"/api/multipass/subscribe/subscribe_emails",method:"POST",body:{email:s,register_source:u,brand:p,deals_type:e.dealsType||"vip_subscribe"},headers:{},type:""});N(!1),f.errors?i(f.errors||f.statusText):(y(e.successTips||"Subscribed successfully!"),a&&a(),setTimeout(()=>{y("")},3e3),b({subscribe_hashed_email:s?F(s):""}),b({event:"ga4Event",event_name:"subscribe",event_parameters:{page_group:e.dealsType||"vip_subscribe",position:"pop_up"}}),b({event:"uaEvent",eventCategory:"subscribe",eventAction:e.dealsType||"vip_subscribe",eventLabel:"pop_up",nonInteraction:!1}))},[s,d,h,p,e.dealsType,e.successTips,a]);return P(()=>{c&&c?.email&&v(c?.email)},[c]),t(O,{className:"w-[540px] md:h-auto",scrollClassName:"mb-[40px] min-l:px-[48px] md:mb-[24px]",titleClassName:"h-[56px]",useAnimation:!0,animationClassName:"md:translate-y-[100vh]",...o,children:g("div",{className:"flex flex-col gap-[16px] text-center min-l:px-[16px]",children:[t("div",{children:t(x,{className:n("mb-[24px] text-[22px] font-bold"),html:e.title})}),e.desc&&t(x,{className:"mb-[8px] text-left text-[16px] font-semibold leading-[1.4] text-[#1F2021]",html:e.desc}),g("div",{className:n("relative flex h-[52px] w-full overflow-hidden rounded-[2px] md:grid md:h-auto md:grid-rows-1 md:gap-[16px]",!m&&"rounded-none"),children:[t("input",{className:n("h-full flex-1 rounded-l-[2px] border-[1px] border-[#d8d8d8] px-[14px] py-[17px] text-[16px] font-semibold leading-[1] outline-none placeholder:text-[#999] md:h-[52px] md:rounded-[2px]",!m&&"rounded-none"),placeholder:e.placeholder,value:s,onChange:S}),t(k,{variant:"primary",onClick:E,loading:w,className:n("legacy-headless-ui-primary-button !h-full !min-w-0 !rounded-l-none !rounded-r-[2px] !px-[40px] !py-[13px]",!m&&"rounded-none"),children:t(D,{source:"https://cdn.shopify.com/s/files/1/0512/8568/8505/files/icon_email.png?v=1697527383",className:"h-[24px] w-[24px]",alt:"email"})})]}),g("div",{className:"flex w-full",children:[t(A,{checked:d,onCheckedChange:()=>M(!d),required:!0,className:"border-[#1d1d1f]"}),t("label",{className:"text-left ml-2 text-[14px] font-semibold text-[#777] [&_a]:underline",dangerouslySetInnerHTML:{__html:e?.policy||""}})]}),t("div",{className:n("w-full text-left text-[16px] font-semibold",_&&"text-[#F84D4F]",C&&"text-[#52C41A]"),children:t(x,{html:C||_||""})})]})})}export{$ as CreditsSubscribeModal};
2
2
  //# sourceMappingURL=SubscribeModal.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/components/credits/modal/SubscribeModal.tsx"],
4
- "sourcesContent": ["import { useCallback, useEffect, useState } from 'react'\nimport { useRouter } from 'next/router'\nimport { Button, Checkbox, Picture, Text } from '@anker-in/headless-ui'\nimport { classNames, fetcher, gaTrack, useHeadlessContext } from '@anker-in/lib'\nimport Cookies from 'js-cookie'\nimport { parse } from 'query-string'\nimport sha256 from 'crypto-js/sha256'\nimport { useCreditsContext } from '../context/provider'\nimport { ROUNDED_BRANDS } from '../../../constants'\nimport { emailValidate } from '../context/utils'\nimport { CreditsModalContainer, type ModalContainerProps } from './ModalContainer'\n\nexport type CreditsSubscribeModalCopy = {\n title: string\n desc?: string\n placeholder: string\n policy?: string\n successTips?: string\n dealsType?: string\n}\n\ninterface CreditsSubscribeModalProps extends ModalContainerProps {\n copy: CreditsSubscribeModalCopy\n onSuccess?: () => void\n}\n\nconst getAdCookie = () => {\n if (typeof window === 'undefined') {\n return { register_source: '' }\n }\n const { search, href } = window.location || {}\n const query = parse(search)\n\n return {\n fbuy_ref_code: Cookies.get('fbuy_ref_code'),\n affiliate: Cookies.get('affiliate'),\n ref: Cookies.get('ref_ads'),\n inviter_code: query.ic || query.inviter_code || Cookies.get('inviter_code'),\n register_source: query.redirect || Cookies.get('reg_source') || href,\n deals_type: Cookies.get('deal'),\n transfer_id: Cookies.get('transfer_id'),\n }\n}\n\nexport function CreditsSubscribeModal({ copy, onSuccess, ...props }: CreditsSubscribeModalProps) {\n const { brand } = useHeadlessContext()\n const rounded = ROUNDED_BRANDS.includes(brand)\n const { locale } = useRouter()\n const [policy, setPolicy] = useState(false)\n const [email, setEmail] = useState('')\n const [errorMessage, setErrorMessage] = useState('')\n const [successMessage, setSuccessMessage] = useState('')\n const [loading, setLoading] = useState(false)\n const { profile } = useCreditsContext()\n\n const handleEmailChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setErrorMessage('')\n setEmail(event.target?.value?.trim())\n }, [])\n\n const handleSubmit = useCallback(async () => {\n setErrorMessage('')\n if (!email) {\n return setErrorMessage('Please fill in your email')\n }\n\n if (!emailValidate(email)) {\n return setErrorMessage('Invalid email address')\n }\n\n if (!policy) {\n return setErrorMessage('Please agree to the policy')\n }\n\n setLoading(true)\n const { register_source } = getAdCookie()\n\n const result = await fetcher({\n locale,\n action: 'subscribe',\n url: '/api/multipass/subscribe/subscribe_emails',\n method: 'POST',\n body: {\n email,\n register_source,\n brand,\n deals_type: copy.dealsType || 'vip_subscribe',\n },\n headers: {},\n type: '',\n })\n setLoading(false)\n\n if (!result.errors) {\n setSuccessMessage(copy.successTips || 'Subscribed successfully!')\n if (onSuccess) {\n onSuccess()\n }\n setTimeout(() => {\n setSuccessMessage('')\n }, 3000)\n gaTrack({\n subscribe_hashed_email: email ? sha256(email) : '',\n })\n gaTrack({\n event: 'ga4Event',\n event_name: 'subscribe',\n event_parameters: {\n page_group: copy.dealsType || 'vip_subscribe',\n position: 'pop_up',\n },\n })\n gaTrack({\n event: 'uaEvent',\n eventCategory: 'subscribe',\n eventAction: copy.dealsType || 'vip_subscribe',\n eventLabel: 'pop_up',\n nonInteraction: false,\n })\n } else {\n setErrorMessage(result.errors || result.statusText)\n }\n }, [email, policy, locale, brand, copy.dealsType, copy.successTips, onSuccess])\n\n useEffect(() => {\n if (profile && profile?.email) {\n setEmail(profile?.email)\n }\n }, [profile])\n\n return (\n <CreditsModalContainer\n className=\"w-[540px] md:h-auto\"\n scrollClassName=\"mb-[40px] min-l:px-[48px] md:mb-[24px]\"\n titleClassName=\"h-[56px]\"\n useAnimation\n animationClassName=\"md:translate-y-[100vh]\"\n {...props}\n >\n <div className=\"flex flex-col gap-[16px] text-center min-l:px-[16px]\">\n <div>\n <Text className={classNames('mb-[24px] text-[22px] font-bold')} html={copy.title}></Text>\n </div>\n {copy.desc && (\n <Text\n className=\"mb-[8px] text-left text-[16px] font-semibold leading-[1.4] text-[#1F2021]\"\n html={copy.desc}\n ></Text>\n )}\n <div\n className={classNames(\n 'relative flex h-[52px] w-full overflow-hidden rounded-[2px] md:grid md:h-auto md:grid-rows-1 md:gap-[16px]',\n !rounded && 'rounded-none'\n )}\n >\n <input\n className={classNames(\n 'h-full flex-1 rounded-l-[2px] border-[1px] border-[#d8d8d8] px-[14px] py-[17px] text-[16px] font-semibold leading-[1] outline-none placeholder:text-[#999] md:h-[52px] md:rounded-[2px]',\n !rounded && 'rounded-none'\n )}\n placeholder={copy.placeholder}\n value={email}\n onChange={handleEmailChange}\n />\n <Button\n variant=\"primary\"\n onClick={handleSubmit}\n loading={loading}\n className={classNames(\n 'legacy-headless-ui-primary-button !h-full !min-w-0 !rounded-l-none !rounded-r-[2px] !px-[40px] !py-[13px]',\n !rounded && 'rounded-none'\n )}\n >\n <Picture\n source=\"https://cdn.shopify.com/s/files/1/0512/8568/8505/files/icon_email.png?v=1697527383\"\n className=\"h-[24px] w-[24px]\"\n alt=\"email\"\n />\n </Button>\n </div>\n <div className=\"flex w-full\">\n <Checkbox checked={policy} onCheckedChange={() => setPolicy(!policy)} required className=\"border-[#1d1d1f]\" />\n <label\n className=\"text-left ml-2 text-[14px] font-semibold text-[#777] [&_a]:underline\"\n dangerouslySetInnerHTML={{\n __html: copy?.policy || '',\n }}\n />\n </div>\n <div\n className={classNames(\n 'w-full text-left text-[16px] font-semibold',\n errorMessage && 'text-[#F84D4F]',\n successMessage && 'text-[#52C41A]'\n )}\n >\n <Text html={successMessage || errorMessage || ''} />\n </div>\n </div>\n </CreditsModalContainer>\n )\n}\n"],
5
- "mappings": "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",
6
- "names": ["jsx", "jsxs", "useCallback", "useEffect", "useState", "useRouter", "Button", "Checkbox", "Picture", "Text", "classNames", "fetcher", "gaTrack", "useHeadlessContext", "Cookies", "parse", "sha256", "useCreditsContext", "ROUNDED_BRANDS", "emailValidate", "CreditsModalContainer", "getAdCookie", "search", "href", "query", "CreditsSubscribeModal", "copy", "onSuccess", "props", "brand", "rounded", "locale", "policy", "setPolicy", "email", "setEmail", "errorMessage", "setErrorMessage", "successMessage", "setSuccessMessage", "loading", "setLoading", "profile", "handleEmailChange", "event", "handleSubmit", "register_source", "result"]
4
+ "sourcesContent": ["import { useCallback, useEffect, useState } from 'react'\nimport { Button, Checkbox, Picture, Text } from '@anker-in/headless-ui'\nimport { classNames, fetcher, gaTrack, useHeadlessContext } from '@anker-in/lib'\nimport Cookies from 'js-cookie'\nimport { parse } from 'query-string'\nimport sha256 from 'crypto-js/sha256'\nimport { useCreditsContext } from '../context/provider'\nimport { ROUNDED_BRANDS } from '../../../constants'\nimport { emailValidate } from '../context/utils'\nimport { CreditsModalContainer, type ModalContainerProps } from './ModalContainer'\n\nexport type CreditsSubscribeModalCopy = {\n title: string\n desc?: string\n placeholder: string\n policy?: string\n successTips?: string\n dealsType?: string\n}\n\ninterface CreditsSubscribeModalProps extends ModalContainerProps {\n copy: CreditsSubscribeModalCopy\n onSuccess?: () => void\n}\n\nconst getAdCookie = () => {\n if (typeof window === 'undefined') {\n return { register_source: '' }\n }\n const { search, href } = window.location || {}\n const query = parse(search)\n\n return {\n fbuy_ref_code: Cookies.get('fbuy_ref_code'),\n affiliate: Cookies.get('affiliate'),\n ref: Cookies.get('ref_ads'),\n inviter_code: query.ic || query.inviter_code || Cookies.get('inviter_code'),\n register_source: query.redirect || Cookies.get('reg_source') || href,\n deals_type: Cookies.get('deal'),\n transfer_id: Cookies.get('transfer_id'),\n }\n}\n\nexport function CreditsSubscribeModal({ copy, onSuccess, ...props }: CreditsSubscribeModalProps) {\n const { brand, locale } = useHeadlessContext()\n const rounded = ROUNDED_BRANDS.includes(brand)\n const [policy, setPolicy] = useState(false)\n const [email, setEmail] = useState('')\n const [errorMessage, setErrorMessage] = useState('')\n const [successMessage, setSuccessMessage] = useState('')\n const [loading, setLoading] = useState(false)\n const { profile } = useCreditsContext()\n\n const handleEmailChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setErrorMessage('')\n setEmail(event.target?.value?.trim())\n }, [])\n\n const handleSubmit = useCallback(async () => {\n setErrorMessage('')\n if (!email) {\n return setErrorMessage('Please fill in your email')\n }\n\n if (!emailValidate(email)) {\n return setErrorMessage('Invalid email address')\n }\n\n if (!policy) {\n return setErrorMessage('Please agree to the policy')\n }\n\n setLoading(true)\n const { register_source } = getAdCookie()\n\n const result = await fetcher({\n locale,\n action: 'subscribe',\n url: '/api/multipass/subscribe/subscribe_emails',\n method: 'POST',\n body: {\n email,\n register_source,\n brand,\n deals_type: copy.dealsType || 'vip_subscribe',\n },\n headers: {},\n type: '',\n })\n setLoading(false)\n\n if (!result.errors) {\n setSuccessMessage(copy.successTips || 'Subscribed successfully!')\n if (onSuccess) {\n onSuccess()\n }\n setTimeout(() => {\n setSuccessMessage('')\n }, 3000)\n gaTrack({\n subscribe_hashed_email: email ? sha256(email) : '',\n })\n gaTrack({\n event: 'ga4Event',\n event_name: 'subscribe',\n event_parameters: {\n page_group: copy.dealsType || 'vip_subscribe',\n position: 'pop_up',\n },\n })\n gaTrack({\n event: 'uaEvent',\n eventCategory: 'subscribe',\n eventAction: copy.dealsType || 'vip_subscribe',\n eventLabel: 'pop_up',\n nonInteraction: false,\n })\n } else {\n setErrorMessage(result.errors || result.statusText)\n }\n }, [email, policy, locale, brand, copy.dealsType, copy.successTips, onSuccess])\n\n useEffect(() => {\n if (profile && profile?.email) {\n setEmail(profile?.email)\n }\n }, [profile])\n\n return (\n <CreditsModalContainer\n className=\"w-[540px] md:h-auto\"\n scrollClassName=\"mb-[40px] min-l:px-[48px] md:mb-[24px]\"\n titleClassName=\"h-[56px]\"\n useAnimation\n animationClassName=\"md:translate-y-[100vh]\"\n {...props}\n >\n <div className=\"flex flex-col gap-[16px] text-center min-l:px-[16px]\">\n <div>\n <Text className={classNames('mb-[24px] text-[22px] font-bold')} html={copy.title}></Text>\n </div>\n {copy.desc && (\n <Text\n className=\"mb-[8px] text-left text-[16px] font-semibold leading-[1.4] text-[#1F2021]\"\n html={copy.desc}\n ></Text>\n )}\n <div\n className={classNames(\n 'relative flex h-[52px] w-full overflow-hidden rounded-[2px] md:grid md:h-auto md:grid-rows-1 md:gap-[16px]',\n !rounded && 'rounded-none'\n )}\n >\n <input\n className={classNames(\n 'h-full flex-1 rounded-l-[2px] border-[1px] border-[#d8d8d8] px-[14px] py-[17px] text-[16px] font-semibold leading-[1] outline-none placeholder:text-[#999] md:h-[52px] md:rounded-[2px]',\n !rounded && 'rounded-none'\n )}\n placeholder={copy.placeholder}\n value={email}\n onChange={handleEmailChange}\n />\n <Button\n variant=\"primary\"\n onClick={handleSubmit}\n loading={loading}\n className={classNames(\n 'legacy-headless-ui-primary-button !h-full !min-w-0 !rounded-l-none !rounded-r-[2px] !px-[40px] !py-[13px]',\n !rounded && 'rounded-none'\n )}\n >\n <Picture\n source=\"https://cdn.shopify.com/s/files/1/0512/8568/8505/files/icon_email.png?v=1697527383\"\n className=\"h-[24px] w-[24px]\"\n alt=\"email\"\n />\n </Button>\n </div>\n <div className=\"flex w-full\">\n <Checkbox checked={policy} onCheckedChange={() => setPolicy(!policy)} required className=\"border-[#1d1d1f]\" />\n <label\n className=\"text-left ml-2 text-[14px] font-semibold text-[#777] [&_a]:underline\"\n dangerouslySetInnerHTML={{\n __html: copy?.policy || '',\n }}\n />\n </div>\n <div\n className={classNames(\n 'w-full text-left text-[16px] font-semibold',\n errorMessage && 'text-[#F84D4F]',\n successMessage && 'text-[#52C41A]'\n )}\n >\n <Text html={successMessage || errorMessage || ''} />\n </div>\n </div>\n </CreditsModalContainer>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["jsx", "jsxs", "useCallback", "useEffect", "useState", "Button", "Checkbox", "Picture", "Text", "classNames", "fetcher", "gaTrack", "useHeadlessContext", "Cookies", "parse", "sha256", "useCreditsContext", "ROUNDED_BRANDS", "emailValidate", "CreditsModalContainer", "getAdCookie", "search", "href", "query", "CreditsSubscribeModal", "copy", "onSuccess", "props", "brand", "locale", "rounded", "policy", "setPolicy", "email", "setEmail", "errorMessage", "setErrorMessage", "successMessage", "setSuccessMessage", "loading", "setLoading", "profile", "handleEmailChange", "event", "handleSubmit", "register_source", "result"]
7
7
  }
@@ -48,5 +48,5 @@ const customRenderers = {
48
48
  customRenderers={customRenderers}
49
49
  />
50
50
  \`\`\`
51
- `}}},tags:["autodocs"],argTypes:{apiBaseUrl:{control:"text",description:"API \u57FA\u7840 URL"},headers:{control:"object",description:"\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0",table:{defaultValue:{summary:"undefined"}}},recaptchaSitekey:{control:"text",description:"Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1",table:{defaultValue:{summary:"undefined"}}},recaptchaAction:{control:"text",description:"reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F",table:{defaultValue:{summary:'"activity"'}}},site:{control:"text",description:"Shopify \u5E97\u94FA URL"},channelCode:{control:"text",description:"\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053",table:{defaultValue:{summary:"undefined"}}},welcomeMessage:{control:"text",description:"\u6B22\u8FCE\u6D88\u606F",table:{defaultValue:{summary:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}}},logoUrl:{control:"text",description:"Logo URL"},position:{control:"object",description:"\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61",table:{defaultValue:{summary:'{ bottom: "1.5rem", right: "1.5rem" }'}}}},args:{apiBaseUrl:"http://172.16.38.183:3003",site:"www.eufy.com",loginUserId:"test_test",welcomeMessage:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}};var g=c;const m={args:{loginUserId:"test_test1",apiBaseUrl:"https://beta-api-v2-livechat.anker.com",site:"beta.soundcore.com",channelCode:"dtc",title:"eufy AI Assistant",cartId:"gid://shopify/Cart/hWNAAJweS9IkeRKib4LRy9PY?key=ff1f9b24e74b3f11f5574539e7cbbb2f",accessToken:"47b1aa2c0797043f9baba39388029d70",position:{bottom:"24px",right:"30px"},welcomeMessage:"",quickReplies:[{id:"1",label:"Product Info",value:"Tell me about your products",icon:"\u{1F4E6}"},{id:"2",label:"Track Order",value:"I want to track my order",icon:"\u{1F69A}"},{id:"3",label:"Support",value:"I need help with my device",icon:"\u{1F527}"},{id:"4",label:"Recommendations",value:"Recommend products for me",icon:"\u2B50"}],complianceConfig:{title:"Hi! I'm your eufy AI assistant.",content:"AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.",checkboxText:`By starting to use "Live Chat", you agree to Anker's <a href="https://www.anker.com/pages/privacy-policy" target="_blank" rel="noopener noreferrer" style="text-decoration: underline;">LIVE CHAT PRIVACY NOTICE</a>.`,agreeButtonText:"Agree"},recaptchaAction:"livechat",showNewSessionButton:!0,commonText:{learnMore:"Learn More",total:"Total"},customRenderers:{video:{render:t=>{const e=t;return r("div",{className:"w-full",children:[o("video",{src:e.url,controls:!0,className:"w-full rounded-lg",poster:e.poster,children:"Your browser does not support video playback"}),e.title&&o("p",{className:"mt-2 text-sm text-gray-600",children:e.title})]})}},image_gallery:{render:t=>{const a=t.images||[];return o("div",{className:"grid grid-cols-2 gap-2",children:a.map((i,n)=>o("div",{className:"relative aspect-square",children:o("img",{src:i.url,alt:i.alt||`Image ${n+1}`,className:"size-full rounded-lg object-cover"})},n))})}}},productCardRender:(t,e)=>{if(!t)return o("div",{style:{padding:"16px",border:"1px dashed #ccc",borderRadius:"8px",textAlign:"center"},children:r("p",{children:["Product loading... (handle: ",e,")"]})});const a=t?.featured_image||"",i=t?.title||"",n=t?.description||"",s=t?.average_rating;return o("div",{style:{border:"2px solid #4CAF50",borderRadius:"16px",padding:"16px",margin:"12px 0",backgroundColor:"#f0f9ff",boxShadow:"0 4px 12px rgba(76, 175, 80, 0.15)"},children:r("div",{style:{display:"flex",gap:"12px",alignItems:"center"},children:[a&&o("img",{src:a,alt:i,style:{width:"60px",height:"60px",borderRadius:"8px",objectFit:"cover"}}),r("div",{style:{flex:1},children:[o("h4",{style:{margin:"0 0 4px 0",fontSize:"16px",fontWeight:"bold"},children:i}),n&&r("p",{style:{margin:0,fontSize:"12px",color:"#666",lineHeight:1.4},children:[n.slice(0,80),"..."]}),s&&r("span",{style:{fontSize:"12px",color:"#FFB800"},children:["Rating: ",s.toFixed(1)]})]}),o("button",{style:{padding:"8px 16px",backgroundColor:"#4CAF50",color:"white",borderRadius:"8px",border:"none",cursor:"pointer"},onClick:()=>console.log("View product:",e,t),children:"View"})]})})}},render:t=>o(l,{...t,onOpen:()=>console.log("[LiveChat] Chat opened"),onClose:()=>console.log("[LiveChat] Chat closed"),onMessageSend:e=>console.log("[LiveChat] Message sent:",e),onError:e=>console.error("[LiveChat] Error:",e),onTextMessage:()=>console.log("[LiveChat] AI text message received"),onProductList:()=>console.log("[LiveChat] Product list received"),onPromotionList:()=>console.log("[LiveChat] Promotion list received"),onAddToCart:e=>{console.log("[LiveChat] Add to cart:",e),alert(`Added "${e.title}" to cart!`)},onCart:(e,a)=>{console.log("[LiveChat] Cart clicked:",{cartId:e,checkoutUrl:a}),alert(`Cart ID: ${e}`)}})};export{m as Default,g as default};
51
+ `}}},tags:["autodocs"],argTypes:{apiBaseUrl:{control:"text",description:"API \u57FA\u7840 URL"},headers:{control:"object",description:"\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0",table:{defaultValue:{summary:"undefined"}}},recaptchaSitekey:{control:"text",description:"Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1",table:{defaultValue:{summary:"undefined"}}},recaptchaAction:{control:"text",description:"reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F",table:{defaultValue:{summary:'"activity"'}}},site:{control:"text",description:"Shopify \u5E97\u94FA URL"},channelCode:{control:"text",description:"\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053",table:{defaultValue:{summary:"undefined"}}},welcomeMessage:{control:"text",description:"\u6B22\u8FCE\u6D88\u606F",table:{defaultValue:{summary:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}}},logoUrl:{control:"text",description:"Logo URL"},position:{control:"object",description:"\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61",table:{defaultValue:{summary:'{ bottom: "1.5rem", right: "1.5rem" }'}}}},args:{apiBaseUrl:"http://172.16.38.183:3003",site:"www.eufy.com",loginUserId:"test_test",welcomeMessage:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}};var g=c;const m={args:{loginUserId:"test_test1",apiBaseUrl:"https://beta-api-v2-livechat.anker.com",site:"beta.eufy.com",channelCode:"dtc",title:"eufy AI Assistant",cartId:"gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253",accessToken:"47b1aa2c0797043f9baba39388029d70",position:{bottom:"24px",right:"30px"},welcomeMessage:"",quickReplies:[{id:"1",label:"Product Info",value:"Tell me about your products",icon:"\u{1F4E6}"},{id:"2",label:"Track Order",value:"I want to track my order",icon:"\u{1F69A}"},{id:"3",label:"Support",value:"I need help with my device",icon:"\u{1F527}"},{id:"4",label:"Recommendations",value:"Recommend products for me",icon:"\u2B50"}],complianceConfig:{title:"Hi! I'm your eufy AI assistant.",content:"AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.",checkboxText:`By starting to use "Live Chat", you agree to Anker's <a href="https://www.anker.com/pages/privacy-policy" target="_blank" rel="noopener noreferrer" style="text-decoration: underline;">LIVE CHAT PRIVACY NOTICE</a>.`,agreeButtonText:"Agree"},recaptchaAction:"livechat",showNewSessionButton:!0,commonText:{learnMore:"Learn More",total:"Total"},customRenderers:{video:{render:t=>{const e=t;return r("div",{className:"w-full",children:[o("video",{src:e.url,controls:!0,className:"w-full rounded-lg",poster:e.poster,children:"Your browser does not support video playback"}),e.title&&o("p",{className:"mt-2 text-sm text-gray-600",children:e.title})]})}},image_gallery:{render:t=>{const a=t.images||[];return o("div",{className:"grid grid-cols-2 gap-2",children:a.map((i,n)=>o("div",{className:"relative aspect-square",children:o("img",{src:i.url,alt:i.alt||`Image ${n+1}`,className:"size-full rounded-lg object-cover"})},n))})}}},productCardRender:(t,e)=>{if(!t)return o("div",{style:{padding:"16px",border:"1px dashed #ccc",borderRadius:"8px",textAlign:"center"},children:r("p",{children:["Product loading... (handle: ",e,")"]})});const a=t?.featured_image||"",i=t?.title||"",n=t?.description||"",s=t?.average_rating;return o("div",{style:{border:"2px solid #4CAF50",borderRadius:"16px",padding:"16px",margin:"12px 0",backgroundColor:"#f0f9ff",boxShadow:"0 4px 12px rgba(76, 175, 80, 0.15)"},children:r("div",{style:{display:"flex",gap:"12px",alignItems:"center"},children:[a&&o("img",{src:a,alt:i,style:{width:"60px",height:"60px",borderRadius:"8px",objectFit:"cover"}}),r("div",{style:{flex:1},children:[o("h4",{style:{margin:"0 0 4px 0",fontSize:"16px",fontWeight:"bold"},children:i}),n&&r("p",{style:{margin:0,fontSize:"12px",color:"#666",lineHeight:1.4},children:[n.slice(0,80),"..."]}),s&&r("span",{style:{fontSize:"12px",color:"#FFB800"},children:["Rating: ",s.toFixed(1)]})]}),o("button",{style:{padding:"8px 16px",backgroundColor:"#4CAF50",color:"white",borderRadius:"8px",border:"none",cursor:"pointer"},onClick:()=>console.log("View product:",e,t),children:"View"})]})})}},render:t=>o(l,{...t,onOpen:()=>console.log("[LiveChat] Chat opened"),onClose:()=>console.log("[LiveChat] Chat closed"),onMessageSend:e=>console.log("[LiveChat] Message sent:",e),onError:e=>console.error("[LiveChat] Error:",e),onTextMessage:()=>console.log("[LiveChat] AI text message received"),onProductList:()=>console.log("[LiveChat] Product list received"),onPromotionList:()=>console.log("[LiveChat] Promotion list received"),onAddToCart:e=>{console.log("[LiveChat] Add to cart:",e),alert(`Added "${e.title}" to cart!`)},onCart:(e,a)=>{console.log("[LiveChat] Cart clicked:",{cartId:e,checkoutUrl:a}),alert(`Cart ID: ${e}`)}})};export{m as Default,g as default};
52
52
  //# sourceMappingURL=LiveChatWidget.stories.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/stories/LiveChatWidget.stories.tsx"],
4
- "sourcesContent": ["/**\n * LiveChatWidget Storybook Stories\n * \u5C55\u793A LiveChat \u7EC4\u4EF6\u7684\u5404\u79CD\u4F7F\u7528\u573A\u666F\u548C\u914D\u7F6E\n */\n\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { LiveChatWidget } from '../components/LiveChatWidget'\nimport type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'\nimport '../styles/livechat.css'\n\nconst meta: Meta<typeof LiveChatWidget> = {\n title: 'Campaign/LiveChatWidget',\n component: LiveChatWidget,\n parameters: {\n layout: 'fullscreen',\n docs: {\n story: {\n inline: false,\n iframeHeight: 500,\n },\n description: {\n component: `\n# LiveChat \u804A\u5929\u7EC4\u4EF6\n\n\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002\n\n## \u529F\u80FD\u7279\u6027\n\n- \uD83C\uDF88 **\u6C14\u6CE1\u5F39\u7A97**: \u53EF\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u7684\u60AC\u6D6E\u6C14\u6CE1\u6309\u94AE\n- \uD83D\uDCAC **\u6D41\u5F0F\u6D88\u606F**: \u57FA\u4E8E SSE \u7684\u5B9E\u65F6\u6D41\u5F0F\u54CD\u5E94\n- \uD83D\uDCE6 **\u591A\u79CD\u6D88\u606F\u7C7B\u578B**: \u6587\u672C\u3001\u5546\u54C1\u5361\u7247\u3001\u5546\u54C1\u5217\u8868\u3001\u653F\u7B56\u3001\u5FEB\u6377\u56DE\u590D\u7B49\n- \uD83C\uDFA8 **\u53EF\u5B9A\u5236**: \u652F\u6301\u81EA\u5B9A\u4E49\u54C1\u724C\u989C\u8272\u3001Logo\u3001\u6E32\u67D3\u5668\n- \uD83D\uDCF1 **\u54CD\u5E94\u5F0F**: \u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\n- \uD83D\uDCBE **\u4F1A\u8BDD\u7BA1\u7406**: \u81EA\u52A8\u7BA1\u7406 userId \u548C sessionId\n- \uD83D\uDD12 **\u5B89\u5168\u9632\u62A4**: \u5185\u7F6E XSS \u9632\u62A4\u548C\u8F93\u5165\u9A8C\u8BC1\n\n## \u57FA\u7840\u7528\u6CD5\n\n\\`\\`\\`tsx\nimport { LiveChatWidget } from '@anker-in/campaign-ui'\nimport '@anker-in/campaign-ui/livechat.css'\n\nfunction App() {\n return (\n <LiveChatWidget\n apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n site=\"www.eufy.com\"\n channel_code=\"web_homepage\"\n welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n />\n )\n}\n\\`\\`\\`\n\n## \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n\n\\`\\`\\`tsx\nconst customRenderers = {\n video: {\n render: (content) => (\n <video src={content.url} controls className=\"w-full rounded\" />\n )\n }\n}\n\n<LiveChatWidget\n apiBaseUrl=\"...\"\n site=\"...\"\n customRenderers={customRenderers}\n/>\n\\`\\`\\`\n `,\n },\n },\n },\n tags: ['autodocs'],\n argTypes: {\n apiBaseUrl: {\n control: 'text',\n description: 'API \u57FA\u7840 URL',\n },\n headers: {\n control: 'object',\n description: '\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaSitekey: {\n control: 'text',\n description: 'Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaAction: {\n control: 'text',\n description: 'reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F',\n table: {\n defaultValue: { summary: '\"activity\"' },\n },\n },\n site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\n },\n channelCode: {\n control: 'text',\n description: '\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n welcomeMessage: {\n control: 'text',\n description: '\u6B22\u8FCE\u6D88\u606F',\n table: {\n defaultValue: { summary: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F' },\n },\n },\n logoUrl: {\n control: 'text',\n description: 'Logo URL',\n },\n position: {\n control: 'object',\n description: '\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61',\n table: {\n defaultValue: { summary: '{ bottom: \"1.5rem\", right: \"1.5rem\" }' },\n },\n },\n },\n args: {\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'www.eufy.com',\n loginUserId: 'test_test',\n welcomeMessage: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F',\n },\n}\n\nexport default meta\ntype Story = StoryObj<typeof LiveChatWidget>\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E - \u5C55\u793A\u6240\u6709\u529F\u80FD\n */\nexport const Default: Story = {\n args: {\n // \u57FA\u7840\u914D\u7F6E\n loginUserId: 'test_test1',\n apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',\n site: 'beta.soundcore.com',\n channelCode: 'dtc',\n title: 'eufy AI Assistant',\n cartId: 'gid://shopify/Cart/hWNAAJweS9IkeRKib4LRy9PY?key=ff1f9b24e74b3f11f5574539e7cbbb2f',\n accessToken: '47b1aa2c0797043f9baba39388029d70',\n\n // \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n position: { bottom: '24px', right: '30px' },\n\n // \u6B22\u8FCE\u6D88\u606F\n welcomeMessage: '',\n\n // \u5FEB\u6377\u56DE\u590D\n quickReplies: [\n { id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '\uD83D\uDCE6' },\n { id: '2', label: 'Track Order', value: 'I want to track my order', icon: '\uD83D\uDE9A' },\n { id: '3', label: 'Support', value: 'I need help with my device', icon: '\uD83D\uDD27' },\n { id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '\u2B50' },\n ],\n\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n complianceConfig: {\n title: \"Hi! I'm your eufy AI assistant.\",\n content:\n 'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',\n checkboxText:\n 'By starting to use \"Live Chat\", you agree to Anker\\'s <a href=\"https://www.anker.com/pages/privacy-policy\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: underline;\">LIVE CHAT PRIVACY NOTICE</a>.',\n agreeButtonText: 'Agree',\n },\n\n // reCAPTCHA \u914D\u7F6E\uFF08\u53D6\u6D88\u6CE8\u91CA\u4EE5\u542F\u7528\uFF09\n // recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',\n recaptchaAction: 'livechat',\n\n // \u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n showNewSessionButton: true,\n\n // \u81EA\u5B9A\u4E49\u6587\u6848\n commonText: {\n learnMore: 'Learn More',\n total: 'Total',\n },\n\n // \u81EA\u5B9A\u4E49\u6D88\u606F\u6E32\u67D3\u5668\n customRenderers: {\n video: {\n render: (content: MessageContent) => {\n const videoContent = content as any\n return (\n <div className=\"w-full\">\n <video src={videoContent.url} controls className=\"w-full rounded-lg\" poster={videoContent.poster}>\n Your browser does not support video playback\n </video>\n {videoContent.title && <p className=\"mt-2 text-sm text-gray-600\">{videoContent.title}</p>}\n </div>\n )\n },\n } as MessageRenderer,\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n return (\n <div className=\"grid grid-cols-2 gap-2\">\n {images.map((image: any, index: number) => (\n <div key={index} className=\"relative aspect-square\">\n <img\n src={image.url}\n alt={image.alt || `Image ${index + 1}`}\n className=\"size-full rounded-lg object-cover\"\n />\n </div>\n ))}\n </div>\n )\n },\n } as MessageRenderer,\n },\n\n // \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\n productCardRender: (product, productHandle) => {\n // product \u53EF\u80FD\u4E3A undefined\uFF0C\u6B64\u65F6\u53EF\u7528 productHandle \u67E5\u8BE2\n if (!product) {\n return (\n <div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>\n <p>Product loading... (handle: {productHandle})</p>\n </div>\n )\n }\n\n const imageUrl = product?.featured_image || ''\n const title = product?.title || ''\n const description = product?.description || ''\n const averageRating = product?.average_rating\n\n return (\n <div\n style={{\n border: '2px solid #4CAF50',\n borderRadius: '16px',\n padding: '16px',\n margin: '12px 0',\n backgroundColor: '#f0f9ff',\n boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',\n }}\n >\n <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>\n {imageUrl && (\n <img\n src={imageUrl}\n alt={title}\n style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}\n />\n )}\n <div style={{ flex: 1 }}>\n <h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>\n {description && (\n <p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>\n {description.slice(0, 80)}...\n </p>\n )}\n {averageRating && (\n <span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>\n )}\n </div>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#4CAF50',\n color: 'white',\n borderRadius: '8px',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => console.log('View product:', productHandle, product)}\n >\n View\n </button>\n </div>\n </div>\n )\n },\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n // \u6240\u6709\u4E8B\u4EF6\u56DE\u8C03\n onOpen={() => console.log('[LiveChat] Chat opened')}\n onClose={() => console.log('[LiveChat] Chat closed')}\n onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}\n onError={(error: Error) => console.error('[LiveChat] Error:', error)}\n onTextMessage={() => console.log('[LiveChat] AI text message received')}\n onProductList={() => console.log('[LiveChat] Product list received')}\n onPromotionList={() => console.log('[LiveChat] Promotion list received')}\n onAddToCart={(product: any) => {\n console.log('[LiveChat] Add to cart:', product)\n alert(`Added \"${product.title}\" to cart!`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })\n alert(`Cart ID: ${cartId}`)\n }}\n />\n ),\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * LiveChatWidget Storybook Stories\n * \u5C55\u793A LiveChat \u7EC4\u4EF6\u7684\u5404\u79CD\u4F7F\u7528\u573A\u666F\u548C\u914D\u7F6E\n */\n\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { LiveChatWidget } from '../components/LiveChatWidget'\nimport type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'\nimport '../styles/livechat.css'\n\nconst meta: Meta<typeof LiveChatWidget> = {\n title: 'Campaign/LiveChatWidget',\n component: LiveChatWidget,\n parameters: {\n layout: 'fullscreen',\n docs: {\n story: {\n inline: false,\n iframeHeight: 500,\n },\n description: {\n component: `\n# LiveChat \u804A\u5929\u7EC4\u4EF6\n\n\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002\n\n## \u529F\u80FD\u7279\u6027\n\n- \uD83C\uDF88 **\u6C14\u6CE1\u5F39\u7A97**: \u53EF\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u7684\u60AC\u6D6E\u6C14\u6CE1\u6309\u94AE\n- \uD83D\uDCAC **\u6D41\u5F0F\u6D88\u606F**: \u57FA\u4E8E SSE \u7684\u5B9E\u65F6\u6D41\u5F0F\u54CD\u5E94\n- \uD83D\uDCE6 **\u591A\u79CD\u6D88\u606F\u7C7B\u578B**: \u6587\u672C\u3001\u5546\u54C1\u5361\u7247\u3001\u5546\u54C1\u5217\u8868\u3001\u653F\u7B56\u3001\u5FEB\u6377\u56DE\u590D\u7B49\n- \uD83C\uDFA8 **\u53EF\u5B9A\u5236**: \u652F\u6301\u81EA\u5B9A\u4E49\u54C1\u724C\u989C\u8272\u3001Logo\u3001\u6E32\u67D3\u5668\n- \uD83D\uDCF1 **\u54CD\u5E94\u5F0F**: \u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\n- \uD83D\uDCBE **\u4F1A\u8BDD\u7BA1\u7406**: \u81EA\u52A8\u7BA1\u7406 userId \u548C sessionId\n- \uD83D\uDD12 **\u5B89\u5168\u9632\u62A4**: \u5185\u7F6E XSS \u9632\u62A4\u548C\u8F93\u5165\u9A8C\u8BC1\n\n## \u57FA\u7840\u7528\u6CD5\n\n\\`\\`\\`tsx\nimport { LiveChatWidget } from '@anker-in/campaign-ui'\nimport '@anker-in/campaign-ui/livechat.css'\n\nfunction App() {\n return (\n <LiveChatWidget\n apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n site=\"www.eufy.com\"\n channel_code=\"web_homepage\"\n welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n />\n )\n}\n\\`\\`\\`\n\n## \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n\n\\`\\`\\`tsx\nconst customRenderers = {\n video: {\n render: (content) => (\n <video src={content.url} controls className=\"w-full rounded\" />\n )\n }\n}\n\n<LiveChatWidget\n apiBaseUrl=\"...\"\n site=\"...\"\n customRenderers={customRenderers}\n/>\n\\`\\`\\`\n `,\n },\n },\n },\n tags: ['autodocs'],\n argTypes: {\n apiBaseUrl: {\n control: 'text',\n description: 'API \u57FA\u7840 URL',\n },\n headers: {\n control: 'object',\n description: '\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaSitekey: {\n control: 'text',\n description: 'Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaAction: {\n control: 'text',\n description: 'reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F',\n table: {\n defaultValue: { summary: '\"activity\"' },\n },\n },\n site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\n },\n channelCode: {\n control: 'text',\n description: '\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n welcomeMessage: {\n control: 'text',\n description: '\u6B22\u8FCE\u6D88\u606F',\n table: {\n defaultValue: { summary: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F' },\n },\n },\n logoUrl: {\n control: 'text',\n description: 'Logo URL',\n },\n position: {\n control: 'object',\n description: '\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61',\n table: {\n defaultValue: { summary: '{ bottom: \"1.5rem\", right: \"1.5rem\" }' },\n },\n },\n },\n args: {\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'www.eufy.com',\n loginUserId: 'test_test',\n welcomeMessage: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F',\n },\n}\n\nexport default meta\ntype Story = StoryObj<typeof LiveChatWidget>\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E - \u5C55\u793A\u6240\u6709\u529F\u80FD\n */\nexport const Default: Story = {\n args: {\n // \u57FA\u7840\u914D\u7F6E\n loginUserId: 'test_test1',\n apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',\n site: 'beta.eufy.com',\n channelCode: 'dtc',\n title: 'eufy AI Assistant',\n cartId: 'gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253',\n accessToken: '47b1aa2c0797043f9baba39388029d70',\n\n // \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n position: { bottom: '24px', right: '30px' },\n\n // \u6B22\u8FCE\u6D88\u606F\n welcomeMessage: '',\n\n // \u5FEB\u6377\u56DE\u590D\n quickReplies: [\n { id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '\uD83D\uDCE6' },\n { id: '2', label: 'Track Order', value: 'I want to track my order', icon: '\uD83D\uDE9A' },\n { id: '3', label: 'Support', value: 'I need help with my device', icon: '\uD83D\uDD27' },\n { id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '\u2B50' },\n ],\n\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n complianceConfig: {\n title: \"Hi! I'm your eufy AI assistant.\",\n content:\n 'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',\n checkboxText:\n 'By starting to use \"Live Chat\", you agree to Anker\\'s <a href=\"https://www.anker.com/pages/privacy-policy\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: underline;\">LIVE CHAT PRIVACY NOTICE</a>.',\n agreeButtonText: 'Agree',\n },\n\n // reCAPTCHA \u914D\u7F6E\uFF08\u53D6\u6D88\u6CE8\u91CA\u4EE5\u542F\u7528\uFF09\n // recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',\n recaptchaAction: 'livechat',\n\n // \u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n showNewSessionButton: true,\n\n // \u81EA\u5B9A\u4E49\u6587\u6848\n commonText: {\n learnMore: 'Learn More',\n total: 'Total',\n },\n\n // \u81EA\u5B9A\u4E49\u6D88\u606F\u6E32\u67D3\u5668\n customRenderers: {\n video: {\n render: (content: MessageContent) => {\n const videoContent = content as any\n return (\n <div className=\"w-full\">\n <video src={videoContent.url} controls className=\"w-full rounded-lg\" poster={videoContent.poster}>\n Your browser does not support video playback\n </video>\n {videoContent.title && <p className=\"mt-2 text-sm text-gray-600\">{videoContent.title}</p>}\n </div>\n )\n },\n } as MessageRenderer,\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n return (\n <div className=\"grid grid-cols-2 gap-2\">\n {images.map((image: any, index: number) => (\n <div key={index} className=\"relative aspect-square\">\n <img\n src={image.url}\n alt={image.alt || `Image ${index + 1}`}\n className=\"size-full rounded-lg object-cover\"\n />\n </div>\n ))}\n </div>\n )\n },\n } as MessageRenderer,\n },\n\n // \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\n productCardRender: (product, productHandle) => {\n // product \u53EF\u80FD\u4E3A undefined\uFF0C\u6B64\u65F6\u53EF\u7528 productHandle \u67E5\u8BE2\n if (!product) {\n return (\n <div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>\n <p>Product loading... (handle: {productHandle})</p>\n </div>\n )\n }\n\n const imageUrl = product?.featured_image || ''\n const title = product?.title || ''\n const description = product?.description || ''\n const averageRating = product?.average_rating\n\n return (\n <div\n style={{\n border: '2px solid #4CAF50',\n borderRadius: '16px',\n padding: '16px',\n margin: '12px 0',\n backgroundColor: '#f0f9ff',\n boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',\n }}\n >\n <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>\n {imageUrl && (\n <img\n src={imageUrl}\n alt={title}\n style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}\n />\n )}\n <div style={{ flex: 1 }}>\n <h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>\n {description && (\n <p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>\n {description.slice(0, 80)}...\n </p>\n )}\n {averageRating && (\n <span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>\n )}\n </div>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#4CAF50',\n color: 'white',\n borderRadius: '8px',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => console.log('View product:', productHandle, product)}\n >\n View\n </button>\n </div>\n </div>\n )\n },\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n // \u6240\u6709\u4E8B\u4EF6\u56DE\u8C03\n onOpen={() => console.log('[LiveChat] Chat opened')}\n onClose={() => console.log('[LiveChat] Chat closed')}\n onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}\n onError={(error: Error) => console.error('[LiveChat] Error:', error)}\n onTextMessage={() => console.log('[LiveChat] AI text message received')}\n onProductList={() => console.log('[LiveChat] Product list received')}\n onPromotionList={() => console.log('[LiveChat] Promotion list received')}\n onAddToCart={(product: any) => {\n console.log('[LiveChat] Add to cart:', product)\n alert(`Added \"${product.title}\" to cart!`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })\n alert(`Cart ID: ${cartId}`)\n }}\n />\n ),\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["jsx", "jsxs", "LiveChatWidget", "meta", "LiveChatWidget_stories_default", "Default", "content", "videoContent", "images", "image", "index", "product", "productHandle", "imageUrl", "title", "description", "averageRating", "args", "message", "error", "cartId", "checkoutUrl"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anker-in/campaign-ui",
3
- "version": "0.4.2",
3
+ "version": "0.4.3-beta.0",
4
4
  "description": "Campaign UI components and utilities for Anker projects",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -36,6 +36,20 @@
36
36
  "**/*.css",
37
37
  "**/**/*.css"
38
38
  ],
39
+ "scripts": {
40
+ "dev": "pnpm run dev:css & tsup --watch",
41
+ "dev:css": "postcss src/styles/global.css -o style.css --watch",
42
+ "build": "pnpm run build:css & pnpm run build:js:esm & pnpm run build:js:cjs & pnpm run build:js:esm:types & pnpm run build:js:cjs:types",
43
+ "build:js:cjs": "node esbuild-cjs.mjs",
44
+ "build:js:cjs:types": "tsc --outdir dist/cjs",
45
+ "build:js:esm": "node esbuild-esm.mjs",
46
+ "build:js:esm:types": "tsc --outdir dist/esm",
47
+ "build:css": "postcss src/styles/global.css -o style.css",
48
+ "lint": "eslint \"src/**/*.ts*\"",
49
+ "test": "echo run @anker-in/campaign-ui tests",
50
+ "type-check": "tsc --noEmit",
51
+ "clean": "rm -rf .turbo node_modules dist style.css"
52
+ },
39
53
  "keywords": [],
40
54
  "author": "",
41
55
  "license": "ISC",
@@ -65,6 +79,7 @@
65
79
  "crypto-js": "^4.1.1"
66
80
  },
67
81
  "dependencies": {
82
+ "@anker-in/lib": "workspace:*",
68
83
  "@copilotkit/react-core": "1.1.2",
69
84
  "@copilotkit/react-ui": "1.1.2",
70
85
  "@copilotkit/runtime-client-gql": "1.1.2",
@@ -94,8 +109,7 @@
94
109
  "remark-gfm": "^4.0.1",
95
110
  "swiper": "^11.1.3",
96
111
  "tailwind-merge": "^2.3.0",
97
- "tailwindcss": "^3.4.3",
98
- "@anker-in/lib": "1.1.3"
112
+ "tailwindcss": "^3.4.3"
99
113
  },
100
114
  "publishConfig": {
101
115
  "access": "public",
@@ -103,19 +117,5 @@
103
117
  },
104
118
  "exclude": [
105
119
  "dist/**/*"
106
- ],
107
- "scripts": {
108
- "dev": "pnpm run dev:css & tsup --watch",
109
- "dev:css": "postcss src/styles/global.css -o style.css --watch",
110
- "build": "pnpm run build:css & pnpm run build:js:esm & pnpm run build:js:cjs & pnpm run build:js:esm:types & pnpm run build:js:cjs:types",
111
- "build:js:cjs": "node esbuild-cjs.mjs",
112
- "build:js:cjs:types": "tsc --outdir dist/cjs",
113
- "build:js:esm": "node esbuild-esm.mjs",
114
- "build:js:esm:types": "tsc --outdir dist/esm",
115
- "build:css": "postcss src/styles/global.css -o style.css",
116
- "lint": "eslint \"src/**/*.ts*\"",
117
- "test": "echo run @anker-in/campaign-ui tests",
118
- "type-check": "tsc --noEmit",
119
- "clean": "rm -rf .turbo node_modules dist style.css"
120
- }
121
- }
120
+ ]
121
+ }
@@ -191,7 +191,7 @@ export const ChatInput: React.FC<ChatInputProps> = ({
191
191
  <div className={`flex flex-col gap-2 bg-white px-4 py-4 ${className}`}>
192
192
  {/* 输入框容器 - 带渐变边框 */}
193
193
  <div
194
- className="livechat-input-border flex items-center gap-2 rounded-2xl"
194
+ className="flex items-center gap-2 rounded-2xl"
195
195
  style={{
196
196
  background: 'linear-gradient(to right, #7687F3, #7687F3, #4DA8F5, #A3DFCE)',
197
197
  padding: '2px',
@@ -229,7 +229,7 @@ export const ChatInput: React.FC<ChatInputProps> = ({
229
229
  type="button"
230
230
  onClick={handleSendClick}
231
231
  disabled={!canSend}
232
- className={`shrink-0 rounded-full p-2 transition-all ${canSend ? 'livechat-input-send active:scale-95' : 'livechat-input-send--disabled cursor-not-allowed '}`}
232
+ className={`shrink-0 rounded-full p-2 transition-all ${canSend ? ' active:scale-95' : 'cursor-not-allowed '}`}
233
233
  style={
234
234
  canSend
235
235
  ? {
@@ -132,7 +132,7 @@ export const ChatMessage: React.FC<ChatMessageProps> = ({
132
132
  <div
133
133
  className={cn(
134
134
  'w-fit min-w-0 overflow-hidden rounded-2xl ',
135
- isUser ? 'livechat-bubble-user text-white' : 'livechat-bubble-bot text-[#1D1D1F]',
135
+ isUser ? 'text-white' : 'text-[#1D1D1F]',
136
136
  isBubbleProductCard ? 'p-4' : 'p-3'
137
137
  )}
138
138
  style={{
@@ -51,13 +51,13 @@ const CartLineItem: React.FC<{
51
51
  <h4 className="line-clamp-2 text-sm tablet:text-[16px] font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]">
52
52
  {product.title}
53
53
  </h4>
54
- {variantTitle && (
55
- <p className="mt-0.5 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56]">{variantTitle}</p>
56
- )}
57
- <div className="flex items-end justify-between gap-2 mt-1">
58
- {/* 左侧:数量 */}
54
+ <div className="flex items-end justify-between gap-2">
55
+ {/* 左侧:标题、变体、数量 */}
59
56
  <div className="flex-1">
60
- <p className="text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]">×{quantity}</p>
57
+ {variantTitle && (
58
+ <p className="mt-0.5 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#4A4C56]">{variantTitle}</p>
59
+ )}
60
+ <p className="mt-1 text-sm font-bold leading-[1.4] tracking-[-0.02em] text-[#080A0F]">×{quantity}</p>
61
61
  </div>
62
62
 
63
63
  {/* 右侧:价格 */}
@@ -189,7 +189,7 @@ export const CartCard: MessageRenderer = {
189
189
  <button
190
190
  type="button"
191
191
  onClick={handleCart}
192
- className="livechat-btn-primary w-full rounded-full py-[10px] text-center text-sm font-bold leading-[1.4] tracking-[-0.02em] text-white"
192
+ className="w-full rounded-full py-[10px] text-center text-sm font-bold leading-[1.4] tracking-[-0.02em] text-white"
193
193
  style={{ backgroundColor: '#1D1D1F' }}
194
194
  >
195
195
  {mergedText.viewMore}
@@ -106,7 +106,7 @@ const CompactProductCard: React.FC<{
106
106
  {/* 折扣标签 */}
107
107
  {discountLabel && (
108
108
  <div
109
- className="livechat-tag-product mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white"
109
+ className="mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white"
110
110
  style={{ backgroundColor: '#005D8E', paddingTop: '6px', paddingBottom: '4px' }}
111
111
  >
112
112
  {discountLabel}
@@ -152,7 +152,7 @@ const CompactProductCard: React.FC<{
152
152
  <button
153
153
  type="button"
154
154
  onClick={handleAddToCart}
155
- className="livechat-btn-primary mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white"
155
+ className="mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white"
156
156
  style={{ backgroundColor: '#1D1D1F' }}
157
157
  >
158
158
  {addToCartText}
@@ -317,7 +317,7 @@ export const ProductComparison: React.FC<ProductComparisonProps> = ({ data, onAd
317
317
  <button
318
318
  type="button"
319
319
  onClick={handleAddToCart}
320
- className="livechat-btn-primary mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white"
320
+ className="mb-3 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white"
321
321
  style={{ backgroundColor: '#1D1D1F' }}
322
322
  >
323
323
  {mergedText.addToCart}
@@ -106,7 +106,7 @@ const CompactProductCard: React.FC<{
106
106
  {/* 折扣标签 */}
107
107
  {discountLabel && (
108
108
  <div
109
- className="livechat-tag-product mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white"
109
+ className="mb-1 w-fit rounded-full px-2 text-sm font-bold leading-none tracking-[-0.04em] text-white"
110
110
  style={{ backgroundColor: '#005D8E', paddingTop: '6px', paddingBottom: '4px' }}
111
111
  >
112
112
  {discountLabel}
@@ -152,7 +152,7 @@ const CompactProductCard: React.FC<{
152
152
  <button
153
153
  type="button"
154
154
  onClick={handleAddToCart}
155
- className="livechat-btn-primary mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white"
155
+ className="mt-2 w-fit rounded-full px-[20px] py-[10px] text-center text-sm font-bold leading-[1.2] tracking-[-0.04em] text-white"
156
156
  style={{ backgroundColor: '#1D1D1F' }}
157
157
  >
158
158
  {addToCartText}
@@ -60,12 +60,12 @@ export const TextBlock: MessageRenderer = {
60
60
  props.inline ? (
61
61
  <code
62
62
  {...props}
63
- className={`rounded px-1.5 py-0.5 font-mono text-xs ${isUser ? 'livechat-code-user bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}
63
+ className={`rounded px-1.5 py-0.5 font-mono text-xs ${isUser ? 'bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}
64
64
  />
65
65
  ) : (
66
66
  <code
67
67
  {...props}
68
- className={`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${isUser ? 'livechat-code-user bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}
68
+ className={`block overflow-x-auto rounded px-3 py-2 font-mono text-xs ${isUser ? 'bg-[#004A6E] text-white' : 'bg-gray-200 text-gray-800'}`}
69
69
  />
70
70
  ),
71
71
  // 自定义段落样式
@@ -40,9 +40,9 @@ export const ThinkingBlock: MessageRenderer = {
40
40
  <div className="flex items-center gap-2 py-1">
41
41
  {/* 思考动画 - 三个跳动的点 */}
42
42
  <div className="livechat-thinking-dots flex gap-1">
43
- <span className="livechat-loading-dot size-2 rounded-full" style={{ backgroundColor: 'rgba(0, 93, 142, 1)' }} />
44
- <span className="livechat-loading-dot size-2 rounded-full" style={{ backgroundColor: 'rgba(0, 93, 142, 0.6)' }} />
45
- <span className="livechat-loading-dot size-2 rounded-full" style={{ backgroundColor: 'rgba(0, 93, 142, 0.2)' }} />
43
+ <span className="size-2 rounded-full" style={{ backgroundColor: 'rgba(0, 93, 142, 1)' }} />
44
+ <span className="size-2 rounded-full" style={{ backgroundColor: 'rgba(0, 93, 142, 0.6)' }} />
45
+ <span className="size-2 rounded-full" style={{ backgroundColor: 'rgba(0, 93, 142, 0.2)' }} />
46
46
  </div>
47
47
 
48
48
  {/* 状态文本(可选) */}
@@ -5,24 +5,15 @@
5
5
 
6
6
  /**
7
7
  * 执行 Google reCAPTCHA 验证
8
- * 兼容 Enterprise 版 (recaptcha/enterprise.js) 和标准版 v3 (recaptcha/api.js)
9
- * 优先使用 Enterprise 版,回退到标准版
10
8
  */
11
9
  const executeRecaptcha = async (action: string, sitekey: string): Promise<string | false> => {
12
- if (typeof window === 'undefined') {
13
- console.warn('[LiveChat Fetcher] reCAPTCHA not available in non-browser environment')
14
- return false
15
- }
16
-
17
- const executor = window.grecaptcha?.enterprise?.execute ?? window.grecaptcha?.execute
18
-
19
- if (!executor) {
20
- console.warn('[LiveChat Fetcher] reCAPTCHA not loaded (neither enterprise nor standard v3)')
10
+ if (typeof window === 'undefined' || !window.grecaptcha?.enterprise?.execute) {
11
+ console.warn('[LiveChat Fetcher] reCAPTCHA not loaded')
21
12
  return false
22
13
  }
23
14
 
24
15
  try {
25
- const token = await executor(sitekey, { action })
16
+ const token = await window.grecaptcha.enterprise.execute(sitekey, { action })
26
17
  return token
27
18
  } catch (error) {
28
19
  console.error('[LiveChat Fetcher] reCAPTCHA execution failed:', error)
@@ -1,5 +1,4 @@
1
1
  import { useCallback, useEffect, useState } from 'react'
2
- import { useRouter } from 'next/router'
3
2
  import { Button, Checkbox, Picture, Text } from '@anker-in/headless-ui'
4
3
  import { classNames, fetcher, gaTrack, useHeadlessContext } from '@anker-in/lib'
5
4
  import Cookies from 'js-cookie'
@@ -43,9 +42,8 @@ const getAdCookie = () => {
43
42
  }
44
43
 
45
44
  export function CreditsSubscribeModal({ copy, onSuccess, ...props }: CreditsSubscribeModalProps) {
46
- const { brand } = useHeadlessContext()
45
+ const { brand, locale } = useHeadlessContext()
47
46
  const rounded = ROUNDED_BRANDS.includes(brand)
48
- const { locale } = useRouter()
49
47
  const [policy, setPolicy] = useState(false)
50
48
  const [email, setEmail] = useState('')
51
49
  const [errorMessage, setErrorMessage] = useState('')
@@ -149,10 +149,10 @@ export const Default: Story = {
149
149
  // 基础配置
150
150
  loginUserId: 'test_test1',
151
151
  apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',
152
- site: 'beta.soundcore.com',
152
+ site: 'beta.eufy.com',
153
153
  channelCode: 'dtc',
154
154
  title: 'eufy AI Assistant',
155
- cartId: 'gid://shopify/Cart/hWNAAJweS9IkeRKib4LRy9PY?key=ff1f9b24e74b3f11f5574539e7cbbb2f',
155
+ cartId: 'gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253',
156
156
  accessToken: '47b1aa2c0797043f9baba39388029d70',
157
157
 
158
158
  // 自定义位置
@@ -1,33 +0,0 @@
1
- /**
2
- * CartCard Storybook Stories
3
- * 展示购物车卡片组件的各种状态
4
- */
5
- import type { Meta, StoryObj } from '@storybook/react';
6
- import React from 'react';
7
- import type { CartContent } from '../components/LiveChatWidget/types';
8
- declare const CartCardWrapper: React.FC<{
9
- content: CartContent;
10
- }>;
11
- declare const meta: Meta<typeof CartCardWrapper>;
12
- export default meta;
13
- type Story = StoryObj<typeof CartCardWrapper>;
14
- /**
15
- * 空购物车状态
16
- */
17
- export declare const Empty: Story;
18
- /**
19
- * 单件商品
20
- */
21
- export declare const SingleItem: Story;
22
- /**
23
- * 多件商品
24
- */
25
- export declare const MultipleItems: Story;
26
- /**
27
- * 有折扣码的购物车
28
- */
29
- export declare const WithDiscount: Story;
30
- /**
31
- * 多个折扣码(部分失效)
32
- */
33
- export declare const WithMultipleDiscounts: Story;