@anker-in/campaign-ui 0.4.6 → 0.5.0-beta.1
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/cjs/components/LiveChatWidget/LiveChatWidget.js +1 -1
- package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/api/chat.d.ts +1 -1
- package/dist/cjs/components/LiveChatWidget/api/chat.js +2 -2
- package/dist/cjs/components/LiveChatWidget/api/chat.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/components/MessageList.js +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageList.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/hooks/useChatAPI.js +1 -1
- package/dist/cjs/components/LiveChatWidget/hooks/useChatAPI.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/hooks/useChatState.d.ts +5 -0
- package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js +1 -1
- package/dist/cjs/components/LiveChatWidget/hooks/useChatState.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/utils/fetcher.d.ts +3 -1
- package/dist/cjs/components/LiveChatWidget/utils/fetcher.js +1 -1
- package/dist/cjs/components/LiveChatWidget/utils/fetcher.js.map +3 -3
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +1 -1
- package/dist/cjs/components/index.js.map +2 -2
- package/dist/cjs/components/memberPopup/MemberPopup.d.ts +9 -0
- package/dist/cjs/components/memberPopup/MemberPopup.js +2 -0
- package/dist/cjs/components/memberPopup/MemberPopup.js.map +7 -0
- package/dist/cjs/components/memberPopup/context/provider.d.ts +11 -0
- package/dist/cjs/components/memberPopup/context/provider.js +2 -0
- package/dist/cjs/components/memberPopup/context/provider.js.map +7 -0
- package/dist/cjs/components/memberPopup/context/viewStack.d.ts +12 -0
- package/dist/cjs/components/memberPopup/context/viewStack.js +2 -0
- package/dist/cjs/components/memberPopup/context/viewStack.js.map +7 -0
- package/dist/cjs/components/memberPopup/icons.d.ts +27 -0
- package/dist/cjs/components/memberPopup/icons.js +2 -0
- package/dist/cjs/components/memberPopup/icons.js.map +7 -0
- package/dist/cjs/components/memberPopup/index.d.ts +4 -0
- package/dist/cjs/components/memberPopup/index.js +2 -0
- package/dist/cjs/components/memberPopup/index.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.d.ts +10 -0
- package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.js +2 -0
- package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.d.ts +7 -0
- package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js +2 -0
- package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/Activity/index.d.ts +7 -0
- package/dist/cjs/components/memberPopup/panels/Activity/index.js +2 -0
- package/dist/cjs/components/memberPopup/panels/Activity/index.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.d.ts +19 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js +2 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.d.ts +20 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js +2 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemAndBuy.d.ts +12 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemAndBuy.js +2 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemAndBuy.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemCoupon.d.ts +17 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemCoupon.js +2 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemCoupon.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemableList.d.ts +8 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemableList.js +2 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemableList.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/index.d.ts +7 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/index.js +2 -0
- package/dist/cjs/components/memberPopup/panels/ConsumeCredits/index.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivatePanel.d.ts +8 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivatePanel.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivatePanel.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfileModal.d.ts +10 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfileModal.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfileModal.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.d.ts +9 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.d.ts +9 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.d.ts +10 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.d.ts +9 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useActivities.d.ts +18 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useActivities.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useActivities.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useSubscribed.d.ts +9 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useSubscribed.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useSubscribed.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useUpdateProfile.d.ts +17 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useUpdateProfile.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/hooks/useUpdateProfile.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/index.d.ts +13 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/index.js +2 -0
- package/dist/cjs/components/memberPopup/panels/EarnCredits/index.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.d.ts +13 -0
- package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js +2 -0
- package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralOverview.d.ts +12 -0
- package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralOverview.js +2 -0
- package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralOverview.js.map +7 -0
- package/dist/cjs/components/memberPopup/panels/Referral/index.d.ts +7 -0
- package/dist/cjs/components/memberPopup/panels/Referral/index.js +2 -0
- package/dist/cjs/components/memberPopup/panels/Referral/index.js.map +7 -0
- package/dist/cjs/components/memberPopup/type.d.ts +201 -0
- package/dist/cjs/components/memberPopup/type.js +2 -0
- package/dist/cjs/components/memberPopup/type.js.map +7 -0
- package/dist/esm/components/LiveChatWidget/LiveChatWidget.js +1 -1
- package/dist/esm/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/api/chat.d.ts +1 -1
- package/dist/esm/components/LiveChatWidget/api/chat.js +2 -2
- package/dist/esm/components/LiveChatWidget/api/chat.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/components/MessageList.js +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageList.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/hooks/useChatAPI.js +1 -1
- package/dist/esm/components/LiveChatWidget/hooks/useChatAPI.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/hooks/useChatState.d.ts +5 -0
- package/dist/esm/components/LiveChatWidget/hooks/useChatState.js +1 -1
- package/dist/esm/components/LiveChatWidget/hooks/useChatState.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/utils/fetcher.d.ts +3 -1
- package/dist/esm/components/LiveChatWidget/utils/fetcher.js +1 -1
- package/dist/esm/components/LiveChatWidget/utils/fetcher.js.map +3 -3
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +1 -1
- package/dist/esm/components/index.js.map +2 -2
- package/dist/esm/components/memberPopup/MemberPopup.d.ts +9 -0
- package/dist/esm/components/memberPopup/MemberPopup.js +2 -0
- package/dist/esm/components/memberPopup/MemberPopup.js.map +7 -0
- package/dist/esm/components/memberPopup/context/provider.d.ts +11 -0
- package/dist/esm/components/memberPopup/context/provider.js +2 -0
- package/dist/esm/components/memberPopup/context/provider.js.map +7 -0
- package/dist/esm/components/memberPopup/context/viewStack.d.ts +12 -0
- package/dist/esm/components/memberPopup/context/viewStack.js +2 -0
- package/dist/esm/components/memberPopup/context/viewStack.js.map +7 -0
- package/dist/esm/components/memberPopup/icons.d.ts +27 -0
- package/dist/esm/components/memberPopup/icons.js +2 -0
- package/dist/esm/components/memberPopup/icons.js.map +7 -0
- package/dist/esm/components/memberPopup/index.d.ts +4 -0
- package/dist/esm/components/memberPopup/index.js +2 -0
- package/dist/esm/components/memberPopup/index.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.d.ts +10 -0
- package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.js +2 -0
- package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.d.ts +7 -0
- package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js +2 -0
- package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/Activity/index.d.ts +7 -0
- package/dist/esm/components/memberPopup/panels/Activity/index.js +2 -0
- package/dist/esm/components/memberPopup/panels/Activity/index.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.d.ts +19 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js +2 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.d.ts +20 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js +2 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemAndBuy.d.ts +12 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemAndBuy.js +2 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemAndBuy.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemCoupon.d.ts +17 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemCoupon.js +2 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemCoupon.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemableList.d.ts +8 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemableList.js +2 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemableList.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.d.ts +7 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.js +2 -0
- package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.d.ts +8 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfileModal.d.ts +10 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfileModal.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfileModal.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.d.ts +9 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.d.ts +9 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.d.ts +10 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.d.ts +9 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useActivities.d.ts +18 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useActivities.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useActivities.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useSubscribed.d.ts +9 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useSubscribed.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useSubscribed.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useUpdateProfile.d.ts +17 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useUpdateProfile.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/hooks/useUpdateProfile.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/index.d.ts +13 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/index.js +2 -0
- package/dist/esm/components/memberPopup/panels/EarnCredits/index.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.d.ts +13 -0
- package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js +2 -0
- package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralOverview.d.ts +12 -0
- package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralOverview.js +2 -0
- package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralOverview.js.map +7 -0
- package/dist/esm/components/memberPopup/panels/Referral/index.d.ts +7 -0
- package/dist/esm/components/memberPopup/panels/Referral/index.js +2 -0
- package/dist/esm/components/memberPopup/panels/Referral/index.js.map +7 -0
- package/dist/esm/components/memberPopup/type.d.ts +201 -0
- package/dist/esm/components/memberPopup/type.js +2 -0
- package/dist/esm/components/memberPopup/type.js.map +7 -0
- package/dist/index.d.mts +1775 -0
- package/dist/index.d.ts +1775 -0
- package/dist/index.js +18542 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +18514 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +1 -1
- package/src/components/LiveChatWidget/LiveChatWidget.tsx +6 -4
- package/src/components/LiveChatWidget/api/chat.ts +3 -2
- package/src/components/LiveChatWidget/components/MessageList.tsx +20 -4
- package/src/components/LiveChatWidget/hooks/useChatAPI.ts +2 -3
- package/src/components/LiveChatWidget/hooks/useChatState.ts +27 -7
- package/src/components/LiveChatWidget/utils/fetcher.ts +15 -2
- package/src/components/index.ts +2 -0
- package/src/components/memberPopup/MemberPopup.tsx +283 -0
- package/src/components/memberPopup/context/provider.tsx +52 -0
- package/src/components/memberPopup/context/viewStack.tsx +23 -0
- package/src/components/memberPopup/icons.tsx +147 -0
- package/src/components/memberPopup/index.ts +24 -0
- package/src/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.tsx +150 -0
- package/src/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.tsx +142 -0
- package/src/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemAndBuy.ts +33 -0
- package/src/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemCoupon.ts +38 -0
- package/src/components/memberPopup/panels/ConsumeCredits/hooks/useRedeemableList.ts +55 -0
- package/src/components/memberPopup/panels/ConsumeCredits/index.tsx +220 -0
- package/src/components/memberPopup/panels/EarnCredits/ActivatePanel.tsx +323 -0
- package/src/components/memberPopup/panels/EarnCredits/CompleteProfileModal.tsx +186 -0
- package/src/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.tsx +179 -0
- package/src/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.tsx +130 -0
- package/src/components/memberPopup/panels/EarnCredits/SubscribeModal.tsx +144 -0
- package/src/components/memberPopup/panels/EarnCredits/SubscribePanel.tsx +147 -0
- package/src/components/memberPopup/panels/EarnCredits/hooks/useActivities.ts +64 -0
- package/src/components/memberPopup/panels/EarnCredits/hooks/useSubscribed.ts +32 -0
- package/src/components/memberPopup/panels/EarnCredits/hooks/useUpdateProfile.ts +50 -0
- package/src/components/memberPopup/panels/EarnCredits/index.tsx +215 -0
- package/src/components/memberPopup/panels/Referral/hooks/useReferralOverview.ts +41 -0
- package/src/components/memberPopup/panels/Referral/index.tsx +108 -0
- package/src/components/memberPopup/type.ts +213 -0
- package/tailwind.config.ts +4 -0
- package/dist/cjs/stories/CartCard.stories.d.ts +0 -33
- package/dist/cjs/stories/CartCard.stories.js +0 -21
- package/dist/cjs/stories/CartCard.stories.js.map +0 -7
- package/dist/esm/stories/CartCard.stories.d.ts +0 -33
- package/dist/esm/stories/CartCard.stories.js +0 -21
- package/dist/esm/stories/CartCard.stories.js.map +0 -7
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var j=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var gt=Object.getOwnPropertyNames;var pt=Object.prototype.hasOwnProperty;var ft=(e,c)=>{for(var f in c)j(e,f,{get:c[f],enumerable:!0})},ht=(e,c,f,M)=>{if(c&&typeof c=="object"||typeof c=="function")for(let d of gt(c))!pt.call(e,d)&&d!==f&&j(e,d,{get:()=>c[d],enumerable:!(M=lt(c,d))||M.enumerable});return e};var Ct=e=>ht(j({},"__esModule",{value:!0}),e);var vt={};ft(vt,{useChatState:()=>St});module.exports=Ct(vt);var a=require("react"),$=require("../utils/userId"),X=require("./useSession"),G=require("../utils/productTransformers"),Y=require("../utils/cartTransformers");function mt(e,c,f,M,d){const o=[],g=/\{\{(?:product:)?([^}]+)\}\}/g;let u=0,l,x=!1;for(;(l=g.exec(e))!==null;){x=!0;const m=e.slice(u,l.index);m&&o.push({type:"text",text:m});const p=l[1].trim(),y=c.get(p),T=f.get(p);y?console.log("[useChatState] \u{1F3AF} \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1:",p,"\u2192",y.title):console.log("[useChatState] \u{1F4E6} \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2:",p),o.push({type:"product_card",data:{product:y,rawProduct:T,productHandle:p,onAddToCart:M,productCardRender:d}}),u=g.lastIndex}if(x){const m=e.slice(u);return{contents:o,remainingBuffer:m}}else{const m=e.match(/\{\{[^}]*$/);if(m){const p=e.slice(0,m.index);return p&&o.push({type:"text",text:p}),{contents:o,remainingBuffer:m[0]}}else return e&&o.push({type:"text",text:e}),{contents:o,remainingBuffer:""}}}function xt(e,c,f,M,d){const o=[],g=/\{\{(?:product:)?([^}]+)\}\}/g;let u=0,l;for(;(l=g.exec(e))!==null;){const m=e.slice(u,l.index).trim(),p=l[1].trim();m&&o.push({type:"text",text:m});const y=c.get(p),T=f.get(p);console.log(y?`[useChatState] \u2705 \u627E\u5230\u4EA7\u54C1\u5339\u914D: ${p} \u2192 ${y.title}`:`[useChatState] \u{1F4E6} \u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2: ${p}`),o.push({type:"product_card",data:{product:y,rawProduct:T,productHandle:p,onAddToCart:M,productCardRender:d}}),u=g.lastIndex}const x=e.slice(u).trim();return x&&o.push({type:"text",text:x}),o}function Mt(e,c,f,M,d){const o=[];for(const g of e)if(g.type==="text"){const l=xt(g.text,c,f,M,d);o.push(...l)}else{if(g.type==="product_list")continue;o.push(g)}return o}function yt(e,c,f){if(!e.content.some(u=>u.type==="text"&&/\{\{(?:product:)?[^}]+\}\}/.test(u.text)))return e;console.log("[useChatState] \u68C0\u6D4B\u5230\u5386\u53F2\u6D88\u606F\u9700\u8981\u91CD\u7EC4, \u6D88\u606FID:",e.id);const d=new Map,o=new Map;e.structured_content&&e.structured_content.forEach(u=>{u.type==="product_list"&&Array.isArray(u.data)&&u.data.forEach(l=>{l&&l.handle&&(o.set(l.handle,l),console.log("[useChatState] \u4ECE structured_content \u63D0\u53D6\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:",l.handle))})}),e.content.forEach(u=>{u.type==="product_list"&&u.data.products.forEach(x=>{x&&x.handle&&d.set(x.handle,x)})});const g=Mt(e.content,d,o,c,f);return{...e,content:g}}function St(e={}){const{welcomeMessage:c,site:f,open:M,onOpenChange:d,onOpen:o,onClose:g,onMessageSend:u,onError:l,onTextMessage:x,onProductList:m,onPromotionList:p,onAddToCart:y,onCart:T,productCardRender:U,productComparisonRender:Z}=e,{sessionId:B,saveSession:H,clearSession:L}=(0,X.useSession)(),[tt,N]=(0,a.useState)(void 0);(0,a.useEffect)(()=>{(0,$.getUserId)().then(h=>N(h))},[]);const[et,D]=(0,a.useState)(()=>c?[{id:`welcome-${Date.now()}`,role:"assistant",content:[{type:"text",text:c}],timestamp:Date.now()}]:[]),[nt,q]=(0,a.useState)(!1),R=M!==void 0,z=R?M:nt,[st,rt]=(0,a.useState)(""),[at,b]=(0,a.useState)(!1),t=(0,a.useRef)(null),V=(0,a.useRef)(!1),_=(0,a.useRef)(new Map),P=(0,a.useRef)(new Map),S=(0,a.useRef)(""),v=(0,a.useRef)([]),J=(0,a.useRef)(null),ot=(0,a.useCallback)(()=>{R||q(!0),d?.(!0),o?.()},[R,d,o]),ct=(0,a.useCallback)(()=>{R||q(!1),d?.(!1),g?.()},[R,d,g]),it=(0,a.useCallback)(()=>{const h=!z;R||q(h),d?.(h),h?o?.():g?.()},[R,z,d,o,g]),A=(0,a.useCallback)(h=>{if(!h){console.warn("[useChatState] Attempted to add null/undefined message");return}D(I=>[...I,h])},[]),dt=(0,a.useCallback)(h=>{const I=h.filter(k=>k!=null);I.length!==h.length&&console.warn("[useChatState] Filtered out null/undefined messages from batch set");const O=I.map(k=>yt(k,y,U));D(O)},[y,U]),F=(0,a.useCallback)(()=>{D([])},[]),W=(0,a.useCallback)((h,I)=>{const{event:O,data:k}=h;if(!(O!=="message_start"&&I!==J.current))switch(O){case"message_start":{b(!0),V.current=!1,S.current="",v.current=[];const s=k;s.sessionId&&s.sessionId!==B&&H(s.sessionId),s.userId&&((0,$.saveUserId)(s.userId),N(s.userId)),D(r=>{const n=r[r.length-1];if(n&&n.role==="assistant"&&n.content.length===1&&n.content[0].type==="thinking")return t.current=n,r;{const w=`msg-${Date.now()}`;return t.current={id:w,role:"assistant",content:[{type:"thinking",data:{status:"thinking"}}],timestamp:Date.now()},[...r,t.current]}});break}case"content_delta":{const s=k,r=s.delta||s.text||"";if(t.current&&r){V.current||(V.current=!0,x?.()),t.current.content.some(i=>i.type==="thinking")&&(t.current.content=t.current.content.filter(i=>i.type!=="thinking")),S.current+=r;const{contents:C,remainingBuffer:w}=mt(S.current,_.current,P.current,y,U);S.current=w,C.length>0&&(C.forEach(i=>{const E=t.current.content[t.current.content.length-1];i.type==="text"&&E&&E.type==="text"?E.text+=i.text:t.current.content.push(i)}),D(i=>{if(!t.current)return i;const E=[...i],K=E.findIndex(Q=>Q&&Q.id===t.current.id);return K>=0?E[K]={...t.current}:E.push({...t.current}),E}))}break}case"content_block":{const s=k;if(t.current){const r=s.type||s.data?.type,n=s.data;if(!r||!n){console.warn("[useChatState] Invalid content_block:",s);break}let C;if(r==="product_list"&&Array.isArray(n)){m?.(),n.forEach(i=>{i&&i.handle&&(P.current.set(i.handle,i),console.log("[useChatState] \u7F13\u5B58\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:",i.handle))}),(0,G.transformProducts)(n,f).forEach(i=>{i&&i.handle&&(_.current.set(i.handle,i),console.log("[useChatState] \u5EFA\u7ACB\u4EA7\u54C1\u6620\u5C04:",{handle:i.handle,title:i.title}))}),console.log("[useChatState] \u2705 \u4EA7\u54C1\u5217\u8868\u5DF2\u7F13\u5B58\uFF0C\u4E0D\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\uFF08\u907F\u514D\u95EA\u70C1\uFF09");break}else r==="product_comparison"&&n.products?C={type:"product_comparison",data:{products:(0,G.transformProducts)(n.products,f),dimensions:n.dimensions||{},productComparisonRender:Z}}:r==="faq_list"&&n.found!==void 0?C={type:"faq_list",data:n}:r==="quick_replies"&&n.replies?C={type:"quick_replies",data:{replies:n.replies}}:r==="policy"&&n.title&&n.content?C={type:"policy",data:{title:n.title,content:n.content}}:r==="promotion_list"&&n.found!==void 0?(p?.(n.results||[]),C={type:"promotion_list",data:n}):r==="cart"&&n.id!==void 0?C={type:"cart",data:{...(0,Y.transformCartData)(n),onCart:T}}:C={type:r,data:n};console.log("[useChatState] \u2705 \u5361\u7247\u5DF2\u7F13\u5B58\uFF0C\u7B49\u5F85\u6587\u672C\u5B8C\u6210\u540E\u663E\u793A:",r),v.current.push(C)}break}case"tool_start":case"tool_end":break;case"message_end":{if(b(!1),t.current&&S.current){console.log("[useChatState] \u5904\u7406\u5269\u4F59\u7F13\u51B2\u533A:",S.current);const s=t.current.content[t.current.content.length-1];s&&s.type==="text"?s.text+=S.current:t.current.content.push({type:"text",text:S.current})}t.current&&v.current.length>0&&(console.log("[useChatState] \u{1F4CB} \u6587\u672C\u5DF2\u5B8C\u6210\uFF0C\u73B0\u5728\u6DFB\u52A0",v.current.length,"\u4E2A\u7F13\u5B58\u7684\u5361\u7247"),t.current.content.push(...v.current)),t.current&&t.current.content.some(r=>r.type==="thinking")&&(console.log("[useChatState] \u26A0\uFE0F message_end \u65F6\u4ECD\u5B58\u5728 thinking block\uFF0C\u7ACB\u5373\u79FB\u9664\uFF08\u89C6\u4E3A\u8D85\u65F6\uFF09"),t.current.content=t.current.content.filter(r=>r.type!=="thinking"),t.current.content.length===0&&t.current.content.push({type:"text",text:"Response timed out, please try again."})),t.current&&D(s=>{if(!t.current)return s;const r=[...s],n=r.findIndex(C=>C&&C.id===t.current.id);return n>=0&&(r[n]={...t.current}),r}),S.current="",v.current=[],_.current.clear(),P.current.clear(),t.current=null;break}case"status":{k.type==="session_expired"&&(F(),L(),c&&A({id:`welcome-${Date.now()}`,role:"assistant",content:[{type:"text",text:c}],timestamp:Date.now()}));break}case"error":{const s=k;b(!1),S.current="",v.current=[],_.current.clear(),P.current.clear(),t.current=null,A({id:`error-${Date.now()}`,role:"system",content:[{type:"error",data:{message:s.message,code:s.code}}],timestamp:Date.now()}),l?.(new Error(s.message));break}case"done":{b(!1),S.current="",v.current=[],_.current.clear(),P.current.clear(),t.current=null;break}default:break}},[c,f,A,F,L,H,B,l,x,m,p,y,T]),ut=(0,a.useCallback)(()=>{const h=`stream-${Date.now()}-${Math.random().toString(36).slice(2)}`;return J.current=h,S.current="",v.current=[],_.current.clear(),P.current.clear(),t.current=null,I=>W(I,h)},[W]);return{messages:et,isOpen:z,userId:tt,sessionId:B,inputValue:st,isStreaming:at,openChat:ot,closeChat:ct,toggleChat:it,setInputValue:rt,setUserId:N,addMessage:A,setMessages:dt,clearMessages:F,handleSSEEvent:W,startStream:ut,saveSession:H,clearSession:L}}
|
|
2
2
|
//# sourceMappingURL=useChatState.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/LiveChatWidget/hooks/useChatState.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * \u804A\u5929\u72B6\u6001\u7BA1\u7406 Hook\n * \u7BA1\u7406\u6D88\u606F\u5217\u8868\u3001\u7A97\u53E3\u72B6\u6001\u3001\u8F93\u5165\u6846\u72B6\u6001\u3001\u6D41\u5F0F\u6D88\u606F\u7D2F\u79EF\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u72B6\u6001\u7BA1\u7406\u7B56\u7565\n */\n\nimport { useState, useCallback, useRef, useEffect } from 'react'\nimport type { Message, MessageContent, SSEEvent, StatusData, ErrorData, MessageStartData, BackendCartData, Product, TextContent, ProductCardContent, ProductListContent } from '../types'\nimport { getUserId, saveUserId } from '../utils/userId'\nimport { useSession } from './useSession'\nimport { transformProducts } from '../utils/productTransformers'\nimport { transformCartData } from '../utils/cartTransformers'\n\n// ============================================================================\n// \u8F85\u52A9\u51FD\u6570\uFF1A\u6587\u672C\u89E3\u6790\u548C\u6D88\u606F\u91CD\u7EC4\n// ============================================================================\n\n/**\n * \u5B9E\u65F6\u89E3\u6790\u6D41\u5F0F\u6587\u672C\u4E2D\u7684\u4EA7\u54C1\u5360\u4F4D\u7B26\n * \u5904\u7406\u7F13\u51B2\u533A\u4E2D\u7684\u6587\u672C\uFF0C\u68C0\u6D4B\u5B8C\u6574\u7684 {{product:xxx}} \u5360\u4F4D\u7B26\n *\n * @param buffer \u5F53\u524D\u7F13\u51B2\u533A\u5185\u5BB9\uFF08\u5305\u542B\u65B0\u63A5\u6536\u7684\u6587\u672C\uFF09\n * @param productMap handle \u2192 Product \u7684\u6620\u5C04\u8868\n * @param rawProductMap handle \u2192 raw backend product \u7684\u6620\u5C04\u8868\n * @param onAddToCart \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n * @param productCardRender \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @returns { contents: \u9700\u8981\u6DFB\u52A0\u7684\u5185\u5BB9\u6570\u7EC4, remainingBuffer: \u5269\u4F59\u7F13\u51B2\u533A\u5185\u5BB9 }\n */\nfunction parseStreamingText(\n buffer: string,\n productMap: Map<string, Product>,\n rawProductMap: Map<string, any>,\n onAddToCart?: (product: Product) => void,\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n): { contents: MessageContent[]; remainingBuffer: string } {\n const contents: MessageContent[] = []\n const regex = /\\{\\{(?:product:)?([^}]+)\\}\\}/g\n\n let lastIndex = 0\n let match: RegExpExecArray | null\n let foundMatch = false\n\n // \u67E5\u627E\u6240\u6709\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\n while ((match = regex.exec(buffer)) !== null) {\n foundMatch = true\n\n // \u63D0\u53D6\u5360\u4F4D\u7B26\u524D\u7684\u6587\u672C\n const beforeText = buffer.slice(lastIndex, match.index)\n if (beforeText) {\n contents.push({ type: 'text', text: beforeText } as TextContent)\n }\n\n // \u63D0\u53D6\u4EA7\u54C1 ID \u5E76\u521B\u5EFA\u4EA7\u54C1\u5361\u7247\n const productId = match[1].trim()\n const product = productMap.get(productId)\n const rawProduct = rawProductMap.get(productId)\n\n // \u65E0\u8BBA\u662F\u5426\u627E\u5230\u4EA7\u54C1\u6570\u636E\uFF0C\u90FD\u6E32\u67D3 product_card\uFF0C\u5E94\u7528\u5C42\u53EF\u901A\u8FC7 productHandle \u67E5\u8BE2\u4EA7\u54C1\n if (product) {\n console.log('[useChatState] \uD83C\uDFAF \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1:', productId, '\u2192', product.title)\n } else {\n console.log('[useChatState] \uD83D\uDCE6 \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2:', productId)\n }\n\n contents.push({\n type: 'product_card',\n data: {\n product: product,\n rawProduct: rawProduct,\n productHandle: productId,\n onAddToCart: onAddToCart,\n productCardRender: productCardRender\n }\n } as ProductCardContent)\n\n lastIndex = regex.lastIndex\n }\n\n // \u5982\u679C\u627E\u5230\u4E86\u81F3\u5C11\u4E00\u4E2A\u5B8C\u6574\u5360\u4F4D\u7B26\n if (foundMatch) {\n // \u8FD4\u56DE\u5269\u4F59\u7684\u6587\u672C\u4F5C\u4E3A\u7F13\u51B2\u533A\uFF08\u53EF\u80FD\u5305\u542B\u4E0D\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\uFF09\n const remainingBuffer = buffer.slice(lastIndex)\n return { contents, remainingBuffer }\n } else {\n // \u6CA1\u6709\u627E\u5230\u5B8C\u6574\u5360\u4F4D\u7B26\uFF0C\u68C0\u67E5\u662F\u5426\u6709\u4E0D\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\u5F00\u5934\n // \u4F8B\u5982\uFF1A\u7F13\u51B2\u533A\u662F \"some text {{prod\"\uFF0C\u6211\u4EEC\u9700\u8981\u4FDD\u7559 \"{{prod\" \u7B49\u5F85\u66F4\u591A\u6587\u672C\n const incompleteMatch = buffer.match(/\\{\\{[^}]*$/)\n\n if (incompleteMatch) {\n // \u6709\u4E0D\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\u5F00\u5934\n const completeText = buffer.slice(0, incompleteMatch.index)\n if (completeText) {\n contents.push({ type: 'text', text: completeText } as TextContent)\n }\n return { contents, remainingBuffer: incompleteMatch[0] }\n } else {\n // \u6CA1\u6709\u4E0D\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\uFF0C\u6574\u4E2A\u7F13\u51B2\u533A\u90FD\u662F\u666E\u901A\u6587\u672C\n if (buffer) {\n contents.push({ type: 'text', text: buffer } as TextContent)\n }\n return { contents, remainingBuffer: '' }\n }\n }\n}\n\n/**\n * \u89E3\u6790\u6587\u672C\u4E2D\u7684 {{handle}}\uFF0C\u8FD4\u56DE [text, product_card, text, ...] \u6570\u7EC4\uFF08\u7528\u4E8E\u5386\u53F2\u6D88\u606F\u91CD\u7EC4\uFF09\n *\n * @param text \u5305\u542B {{handle}} \u6807\u8BB0\u7684\u6587\u672C\n * @param productMap handle \u2192 Product \u7684\u6620\u5C04\u8868\n * @param rawProductMap handle \u2192 raw backend product \u7684\u6620\u5C04\u8868\n * @param onAddToCart \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n * @param productCardRender \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @returns MessageContent \u6570\u7EC4\n *\n * @example\n * \u8F93\u5165\uFF1A\n * text: \"\u6211\u63A8\u8350\u4EE5\u4E0B\u4EA7\u54C1\uFF1A\\n{{product-handle}}\\n\u8FD9\u6B3E\u4EA7\u54C1\u6027\u4EF7\u6BD4\u5F88\u9AD8\u3002\"\n * productMap: Map { 'product-handle' => Product {...} }\n * \u8F93\u51FA\uFF1A\n * [\n * { type: 'text', text: '\u6211\u63A8\u8350\u4EE5\u4E0B\u4EA7\u54C1\uFF1A' },\n * { type: 'product_card', data: { product: {...}, onAddToCart } },\n * { type: 'text', text: '\u8FD9\u6B3E\u4EA7\u54C1\u6027\u4EF7\u6BD4\u5F88\u9AD8\u3002' }\n * ]\n */\nfunction parseTextWithProductIds(\n text: string,\n productMap: Map<string, Product>,\n rawProductMap: Map<string, any>,\n onAddToCart?: (product: Product) => void,\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n): MessageContent[] {\n const result: MessageContent[] = []\n // \u4FEE\u6539\u6B63\u5219\u8868\u8FBE\u5F0F\u4EE5\u5339\u914D {{product:ID}} \u683C\u5F0F\n // \u5339\u914D {{product:xxx}} \u6216 {{xxx}}\uFF08\u517C\u5BB9\u4E24\u79CD\u683C\u5F0F\uFF09\n const regex = /\\{\\{(?:product:)?([^}]+)\\}\\}/g\n\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n while ((match = regex.exec(text)) !== null) {\n const beforeText = text.slice(lastIndex, match.index).trim()\n // match[1] \u662F\u6355\u83B7\u7EC4\u4E2D\u7684\u5185\u5BB9\uFF0C\u5373 product: \u540E\u9762\u7684 ID\n const productId = match[1].trim()\n\n // \u6DFB\u52A0\u524D\u9762\u7684\u6587\u672C\uFF08\u5982\u679C\u6709\uFF09\n if (beforeText) {\n result.push({\n type: 'text',\n text: beforeText,\n } as TextContent)\n }\n\n // \u6DFB\u52A0\u4EA7\u54C1\u5361\u7247\uFF08\u65E0\u8BBA\u662F\u5426\u627E\u5230\u4EA7\u54C1\u6570\u636E\uFF0C\u90FD\u6E32\u67D3 product_card\uFF09\n const product = productMap.get(productId)\n const rawProduct = rawProductMap.get(productId)\n if (product) {\n console.log(`[useChatState] \u2705 \u627E\u5230\u4EA7\u54C1\u5339\u914D: ${productId} \u2192 ${product.title}`)\n } else {\n console.log(`[useChatState] \uD83D\uDCE6 \u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2: ${productId}`)\n }\n\n result.push({\n type: 'product_card',\n data: {\n product: product,\n rawProduct: rawProduct,\n productHandle: productId,\n onAddToCart: onAddToCart,\n productCardRender: productCardRender,\n },\n } as ProductCardContent)\n\n lastIndex = regex.lastIndex\n }\n\n // \u6DFB\u52A0\u6700\u540E\u5269\u4F59\u7684\u6587\u672C\n const remainingText = text.slice(lastIndex).trim()\n if (remainingText) {\n result.push({\n type: 'text',\n text: remainingText,\n } as TextContent)\n }\n\n return result\n}\n\n/**\n * \u91CD\u7EC4\u6D88\u606F\u5185\u5BB9\uFF1A\u89E3\u6790\u6587\u672C\u4E2D\u7684 {{handle}}\uFF0C\u66FF\u6362\u4E3A\u4EA7\u54C1\u5361\u7247\n *\n * \u5904\u7406\u903B\u8F91\uFF1A\n * 1. \u904D\u5386\u6D88\u606F\u7684\u6240\u6709 content blocks\n * 2. \u5BF9\u4E8E text \u7C7B\u578B\uFF0C\u89E3\u6790\u5176\u4E2D\u7684 {{handle}} \u5E76\u62C6\u5206\u4E3A\u591A\u4E2A content\n * 3. \u8DF3\u8FC7 product_list \u7C7B\u578B\uFF08\u5DF2\u7ECF\u88AB\u62C6\u5206\u5230\u6587\u672C\u4E2D\uFF09\n * 4. \u5176\u4ED6\u7C7B\u578B\u76F4\u63A5\u4FDD\u7559\n *\n * @param contents \u539F\u59CB\u6D88\u606F\u5185\u5BB9\u6570\u7EC4\n * @param productMap handle \u2192 Product \u7684\u6620\u5C04\u8868\n * @param rawProductMap handle \u2192 raw backend product \u7684\u6620\u5C04\u8868\n * @param onAddToCart \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n * @param productCardRender \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @returns \u91CD\u7EC4\u540E\u7684\u6D88\u606F\u5185\u5BB9\u6570\u7EC4\n */\nfunction reorganizeMessageContent(\n contents: MessageContent[],\n productMap: Map<string, Product>,\n rawProductMap: Map<string, any>,\n onAddToCart?: (product: Product) => void,\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n): MessageContent[] {\n const result: MessageContent[] = []\n\n for (const content of contents) {\n // \u53EA\u5904\u7406\u6587\u672C\u7C7B\u578B\n if (content.type === 'text') {\n const textContent = content as TextContent\n const segments = parseTextWithProductIds(textContent.text, productMap, rawProductMap, onAddToCart, productCardRender)\n result.push(...segments)\n }\n // \u8DF3\u8FC7 product_list\uFF08\u5DF2\u7ECF\u88AB\u62C6\u5206\u5230\u6587\u672C\u4E2D\uFF09\n else if (content.type === 'product_list') {\n continue\n }\n // \u5176\u4ED6\u7C7B\u578B\u76F4\u63A5\u4FDD\u7559\n else {\n result.push(content)\n }\n }\n\n return result\n}\n\n/**\n * \u5904\u7406\u5355\u6761\u6D88\u606F\u7684\u91CD\u7EC4\uFF08\u7528\u4E8E\u5386\u53F2\u6D88\u606F\u52A0\u8F7D\uFF09\n * \u5982\u679C\u6D88\u606F\u5305\u542B\u5E26\u6709 {{}} \u7684\u6587\u672C\uFF0C\u5219\u8FDB\u884C\u91CD\u7EC4\n *\n * @param message \u539F\u59CB\u6D88\u606F\n * @param onAddToCart \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n * @param productCardRender \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @returns \u91CD\u7EC4\u540E\u7684\u6D88\u606F\uFF08\u5982\u679C\u9700\u8981\u91CD\u7EC4\uFF09\uFF0C\u5426\u5219\u8FD4\u56DE\u539F\u6D88\u606F\n */\nfunction maybeReorganizeHistoricalMessage(\n message: Message,\n onAddToCart?: (product: Product) => void,\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n): Message {\n // \u68C0\u67E5\u6D88\u606F\u662F\u5426\u5305\u542B\u5E26\u6709 {{}} \u7684\u6587\u672C\n const hasPlaceholder = message.content.some(\n c => c.type === 'text' && /\\{\\{(?:product:)?[^}]+\\}\\}/.test((c as TextContent).text)\n )\n if (!hasPlaceholder) {\n return message // \u6CA1\u6709\u5360\u4F4D\u7B26\uFF0C\u4E0D\u9700\u8981\u91CD\u7EC4\n }\n\n console.log('[useChatState] \u68C0\u6D4B\u5230\u5386\u53F2\u6D88\u606F\u9700\u8981\u91CD\u7EC4, \u6D88\u606FID:', message.id)\n\n // \u6784\u5EFA\u4EA7\u54C1\u6620\u5C04 (handle \u2192 Product)\n const productMap = new Map<string, Product>()\n // \u4ECE structured_content \u4E2D\u63D0\u53D6\u539F\u59CB\u540E\u7AEF\u4EA7\u54C1\u6570\u636E (handle \u2192 rawProduct)\n const rawProductMap = new Map<string, any>()\n\n // \u4F18\u5148\u4ECE structured_content \u83B7\u53D6\u539F\u59CB\u4EA7\u54C1\u6570\u636E\uFF08\u5982\u679C\u5B58\u5728\uFF09\n if (message.structured_content) {\n message.structured_content.forEach(structuredContent => {\n if (structuredContent.type === 'product_list' && Array.isArray(structuredContent.data)) {\n structuredContent.data.forEach((rawProduct: any) => {\n if (rawProduct && rawProduct.handle) {\n rawProductMap.set(rawProduct.handle, rawProduct)\n console.log('[useChatState] \u4ECE structured_content \u63D0\u53D6\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:', rawProduct.handle)\n }\n })\n }\n })\n }\n\n // \u6784\u5EFA\u8F6C\u6362\u540E\u7684\u4EA7\u54C1\u6620\u5C04\uFF08\u7528\u4E8E\u9ED8\u8BA4\u6E32\u67D3\uFF09\n message.content.forEach(content => {\n if (content.type === 'product_list') {\n const productListContent = content as ProductListContent\n productListContent.data.products.forEach(product => {\n if (product && product.handle) {\n productMap.set(product.handle, product)\n }\n })\n }\n })\n\n // \u91CD\u7EC4\u6D88\u606F\u5185\u5BB9\n const reorganizedContent = reorganizeMessageContent(message.content, productMap, rawProductMap, onAddToCart, productCardRender)\n\n // \u8FD4\u56DE\u65B0\u6D88\u606F\u5BF9\u8C61\n return {\n ...message,\n content: reorganizedContent,\n }\n}\n\nexport interface UseChatStateOptions {\n /**\n * \u521D\u59CB\u6B22\u8FCE\u6D88\u606F\n */\n welcomeMessage?: string\n\n /**\n * Shopify \u5E97\u94FA\u57DF\u540D\n */\n site?: string\n\n /**\n * \u53D7\u63A7\u6A21\u5F0F\uFF1A\u662F\u5426\u6253\u5F00\u804A\u5929\u7A97\u53E3\n * \u63D0\u4F9B\u6B64\u53C2\u6570\u65F6\uFF0C\u7EC4\u4EF6\u5904\u4E8E\u53D7\u63A7\u6A21\u5F0F\n */\n open?: boolean\n\n /**\n * \u53D7\u63A7\u6A21\u5F0F\uFF1A\u72B6\u6001\u53D8\u5316\u56DE\u8C03\uFF08\u5FC5\u9700\uFF09\n * \u7528\u4E8E\u540C\u6B65\u72B6\u6001\u5230\u7236\u7EC4\u4EF6\n */\n onOpenChange?: (open: boolean) => void\n\n /**\n * \u7A97\u53E3\u6253\u5F00\u4E8B\u4EF6\u76D1\u542C\uFF08\u53EF\u9009\uFF09\n * \u7528\u4E8E\u57CB\u70B9\u3001\u65E5\u5FD7\u7B49\u526F\u4F5C\u7528\n */\n onOpen?: () => void\n\n /**\n * \u7A97\u53E3\u5173\u95ED\u4E8B\u4EF6\u76D1\u542C\uFF08\u53EF\u9009\uFF09\n * \u7528\u4E8E\u57CB\u70B9\u3001\u65E5\u5FD7\u7B49\u526F\u4F5C\u7528\n */\n onClose?: () => void\n\n /**\n * \u6D88\u606F\u53D1\u9001\u56DE\u8C03\n */\n onMessageSend?: (message: string) => void\n\n /**\n * \u9519\u8BEF\u5904\u7406\u56DE\u8C03\n */\n onError?: (error: Error) => void\n\n /**\n * AI \u6D88\u606F\u56DE\u8C03\n */\n /**\n * AI \u56DE\u590D\u6587\u672C\u6D88\u606F\u65F6\u89E6\u53D1\n */\n onTextMessage?: () => void\n\n /**\n * AI \u56DE\u590D\u5546\u54C1\u5217\u8868\u5361\u7247\u65F6\u89E6\u53D1\n */\n onProductList?: () => void\n\n /**\n * AI \u56DE\u590D\u4FC3\u9500\u5361\u7247\u65F6\u89E6\u53D1\n * @param promotions \u4FC3\u9500\u6D3B\u52A8\u6570\u7EC4\u6570\u636E\n */\n onPromotionList?: (promotions: any[]) => void\n\n /**\n * \u5546\u54C1\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: any) => void\n\n /**\n * \u8D2D\u7269\u8F66\u6309\u94AE\u70B9\u51FB\u56DE\u8C03\n */\n onCart?: (cartId: string, checkoutUrl?: string) => void\n\n /**\n * \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @param product \u4EA7\u54C1\u6570\u636E\uFF08\u5982\u679C\u5728 product_list \u4E2D\u627E\u5230\uFF09\uFF0C\u5426\u5219\u4E3A undefined\n * @param productHandle \u6587\u672C\u5360\u4F4D\u7B26\u4E2D\u7684\u4EA7\u54C1 ID\uFF0C\u53EF\u7528\u4E8E\u5E94\u7528\u5C42\u67E5\u8BE2\u4EA7\u54C1\u6570\u636E\n */\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n\n /**\n * \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5BF9\u6BD4\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @param data \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\uFF08\u5305\u542B products \u548C dimensions\uFF09\n */\n productComparisonRender?: (data: any) => React.ReactNode\n}\n\nexport interface UseChatStateReturn {\n /**\n * \u6D88\u606F\u5217\u8868\n */\n messages: Message[]\n\n /**\n * \u804A\u5929\u7A97\u53E3\u662F\u5426\u6253\u5F00\n */\n isOpen: boolean\n\n /**\n * \u7528\u6237 ID\uFF08undefined \u8868\u793A\u5C1A\u672A\u521D\u59CB\u5316\uFF0C\u7A7A\u5B57\u7B26\u4E32\u8868\u793A\u7531\u540E\u7AEF\u751F\u6210\uFF09\n */\n userId: string | undefined\n\n /**\n * \u4F1A\u8BDD ID\n */\n sessionId: string | null\n\n /**\n * \u8F93\u5165\u6846\u5185\u5BB9\n */\n inputValue: string\n\n /**\n * \u662F\u5426\u6B63\u5728\u63A5\u6536\u6D41\u5F0F\u6D88\u606F\n */\n isStreaming: boolean\n\n /**\n * \u6253\u5F00\u804A\u5929\u7A97\u53E3\n */\n openChat: () => void\n\n /**\n * \u5173\u95ED\u804A\u5929\u7A97\u53E3\n */\n closeChat: () => void\n\n /**\n * \u5207\u6362\u804A\u5929\u7A97\u53E3\u72B6\u6001\n */\n toggleChat: () => void\n\n /**\n * \u8BBE\u7F6E\u8F93\u5165\u6846\u5185\u5BB9\n */\n setInputValue: (value: string) => void\n\n /**\n * \u8BBE\u7F6E\u7528\u6237 ID\uFF08\u7528\u4E8E\u4FDD\u5B58\u540E\u7AEF\u8FD4\u56DE\u7684 userId\uFF09\n */\n setUserId: (id: string) => void\n\n /**\n * \u6DFB\u52A0\u6D88\u606F\u5230\u5217\u8868\n */\n addMessage: (message: Message) => void\n\n /**\n * \u6279\u91CF\u8BBE\u7F6E\u6D88\u606F\u5217\u8868\uFF08\u7528\u4E8E\u52A0\u8F7D\u5386\u53F2\uFF09\n */\n setMessages: (messages: Message[]) => void\n\n /**\n * \u6E05\u7A7A\u6D88\u606F\u5217\u8868\n */\n clearMessages: () => void\n\n /**\n * \u5904\u7406 SSE \u4E8B\u4EF6\n */\n handleSSEEvent: (event: SSEEvent) => void\n\n /**\n * \u4FDD\u5B58\u4F1A\u8BDD ID\n */\n saveSession: (id: string) => void\n\n /**\n * \u6E05\u7A7A\u4F1A\u8BDD\n */\n clearSession: () => void\n}\n\n/**\n * \u804A\u5929\u72B6\u6001\u7BA1\u7406 Hook\n *\n * \u529F\u80FD\uFF1A\n * 1. \u7BA1\u7406\u6D88\u606F\u5217\u8868\uFF08\u6DFB\u52A0\u3001\u6E05\u7A7A\u3001\u6279\u91CF\u8BBE\u7F6E\uFF09\n * 2. \u7BA1\u7406\u7A97\u53E3\u72B6\u6001\uFF08\u6253\u5F00\u3001\u5173\u95ED\u3001\u5207\u6362\uFF09\n * 3. \u7BA1\u7406\u8F93\u5165\u6846\u72B6\u6001\n * 4. \u5904\u7406 SSE \u6D41\u5F0F\u6D88\u606F\u4E8B\u4EF6\n * 5. \u7D2F\u79EF\u6D41\u5F0F\u6587\u672C\u5185\u5BB9\n *\n * @param options Hook \u914D\u7F6E\u9009\u9879\n * @returns \u72B6\u6001\u7BA1\u7406\u5DE5\u5177\u5BF9\u8C61\n */\nexport function useChatState(options: UseChatStateOptions = {}): UseChatStateReturn {\n const {\n welcomeMessage,\n site,\n open: controlledOpen,\n onOpenChange,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n productCardRender,\n productComparisonRender,\n } = options\n\n // \u4F1A\u8BDD\u7BA1\u7406\n const { sessionId, saveSession, clearSession } = useSession()\n\n // \u7528\u6237 ID (\u521D\u59CB\u5316\u65F6\u5F02\u6B65\u751F\u6210\uFF0Cundefined \u8868\u793A\u5C1A\u672A\u521D\u59CB\u5316)\n const [userId, setUserId] = useState<string | undefined>(undefined)\n\n // \u521D\u59CB\u5316 userId\n useEffect(() => {\n getUserId().then(id => setUserId(id))\n }, [])\n\n // \u6D88\u606F\u5217\u8868\n const [messages, setMessagesState] = useState<Message[]>(() => {\n // \u5982\u679C\u6709\u6B22\u8FCE\u6D88\u606F\uFF0C\u521D\u59CB\u5316\u65F6\u6DFB\u52A0\n if (welcomeMessage) {\n return [\n {\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: [{ type: 'text', text: welcomeMessage }],\n timestamp: Date.now(),\n },\n ]\n }\n return []\n })\n\n // \u804A\u5929\u7A97\u53E3\u662F\u5426\u6253\u5F00\uFF08\u652F\u6301\u53D7\u63A7\u548C\u975E\u53D7\u63A7\u4E24\u79CD\u6A21\u5F0F\uFF09\n const [internalOpen, setInternalOpen] = useState(false)\n const isControlled = controlledOpen !== undefined\n const isOpen = isControlled ? controlledOpen : internalOpen\n\n // \u8F93\u5165\u6846\u5185\u5BB9\n const [inputValue, setInputValue] = useState('')\n\n // \u662F\u5426\u6B63\u5728\u63A5\u6536\u6D41\u5F0F\u6D88\u606F\n const [isStreaming, setIsStreaming] = useState(false)\n\n // \u5F53\u524D\u6B63\u5728\u7D2F\u79EF\u7684\u6D41\u5F0F\u6D88\u606F (\u4E34\u65F6\u5B58\u50A8)\n const currentMessageRef = useRef<Message | null>(null)\n\n // \u6807\u8BB0\u5F53\u524D\u6D88\u606F\u662F\u5426\u5DF2\u89E6\u53D1 onTextMessage \u56DE\u8C03\uFF08\u907F\u514D\u91CD\u590D\u89E6\u53D1\uFF09\n const textMessageCallbackTriggeredRef = useRef<boolean>(false)\n\n // \u4EA7\u54C1\u6620\u5C04\u7F13\u5B58 (handle \u2192 Product)\uFF0C\u7528\u4E8E\u5B9E\u65F6\u89E3\u6790\u5360\u4F4D\u7B26\n const productMapRef = useRef<Map<string, Product>>(new Map())\n\n // \u539F\u59CB\u4EA7\u54C1\u6570\u636E\u7F13\u5B58 (handle \u2192 raw backend product)\uFF0C\u7528\u4E8E productCardRender\n const rawProductMapRef = useRef<Map<string, any>>(new Map())\n\n // \u6587\u672C\u7F13\u51B2\u533A\uFF0C\u7528\u4E8E\u5B58\u50A8\u672A\u5B8C\u6210\u7684\u6587\u672C\uFF08\u5904\u7406\u5360\u4F4D\u7B26\u8DE8\u8D8A\u591A\u4E2A delta \u7684\u60C5\u51B5\uFF09\n const textBufferRef = useRef<string>('')\n\n // \u5361\u7247\u7F13\u5B58\u961F\u5217\uFF0C\u7528\u4E8E\u5B58\u50A8\u9700\u8981\u5EF6\u8FDF\u663E\u793A\u7684\u5361\u7247\uFF08\u5728\u6587\u672C\u5B8C\u6210\u540E\u663E\u793A\uFF09\n const pendingCardsRef = useRef<MessageContent[]>([])\n\n /**\n * \u6253\u5F00\u804A\u5929\u7A97\u53E3\n */\n const openChat = useCallback(() => {\n if (!isControlled) {\n setInternalOpen(true)\n }\n onOpenChange?.(true)\n onOpen?.()\n }, [isControlled, onOpenChange, onOpen])\n\n /**\n * \u5173\u95ED\u804A\u5929\u7A97\u53E3\n */\n const closeChat = useCallback(() => {\n if (!isControlled) {\n setInternalOpen(false)\n }\n onOpenChange?.(false)\n onClose?.()\n }, [isControlled, onOpenChange, onClose])\n\n /**\n * \u5207\u6362\u804A\u5929\u7A97\u53E3\u72B6\u6001\n */\n const toggleChat = useCallback(() => {\n const newState = !isOpen\n if (!isControlled) {\n setInternalOpen(newState)\n }\n onOpenChange?.(newState)\n if (newState) {\n onOpen?.()\n } else {\n onClose?.()\n }\n }, [isControlled, isOpen, onOpenChange, onOpen, onClose])\n\n /**\n * \u6DFB\u52A0\u6D88\u606F\u5230\u5217\u8868\n */\n const addMessage = useCallback((message: Message) => {\n // \u9632\u62A4\uFF1A\u5982\u679C\u6D88\u606F\u4E3A null \u6216 undefined\uFF0C\u4E0D\u6DFB\u52A0\n if (!message) {\n console.warn('[useChatState] Attempted to add null/undefined message')\n return\n }\n setMessagesState(prev => [...prev, message])\n }, [])\n\n /**\n * \u6279\u91CF\u8BBE\u7F6E\u6D88\u606F\u5217\u8868\uFF08\u7528\u4E8E\u52A0\u8F7D\u5386\u53F2\uFF09\n */\n const setMessages = useCallback(\n (newMessages: Message[]) => {\n // \u9632\u62A4\uFF1A\u8FC7\u6EE4\u6389 null/undefined \u6D88\u606F\n const validMessages = newMessages.filter(msg => msg != null)\n if (validMessages.length !== newMessages.length) {\n console.warn('[useChatState] Filtered out null/undefined messages from batch set')\n }\n\n // \u5BF9\u6BCF\u6761\u5386\u53F2\u6D88\u606F\u8FDB\u884C\u91CD\u7EC4\uFF08\u5982\u679C\u9700\u8981\uFF09\n const reorganizedMessages = validMessages.map(msg => maybeReorganizeHistoricalMessage(msg, onAddToCart, productCardRender))\n\n setMessagesState(reorganizedMessages)\n },\n [onAddToCart, productCardRender]\n )\n\n /**\n * \u6E05\u7A7A\u6D88\u606F\u5217\u8868\n */\n const clearMessages = useCallback(() => {\n setMessagesState([])\n }, [])\n\n /**\n * \u5904\u7406 SSE \u4E8B\u4EF6\n * \u6839\u636E\u4E8B\u4EF6\u7C7B\u578B\u8FDB\u884C\u4E0D\u540C\u7684\u5904\u7406\n */\n const handleSSEEvent = useCallback(\n (event: SSEEvent) => {\n const { event: eventType, data } = event\n\n switch (eventType) {\n case 'message_start': {\n // \u5F00\u59CB\u63A5\u6536\u65B0\u6D88\u606F\n setIsStreaming(true)\n\n // \u91CD\u7F6E\u6587\u672C\u6D88\u606F\u56DE\u8C03\u6807\u8BB0\n textMessageCallbackTriggeredRef.current = false\n\n // \u91CD\u7F6E\u6587\u672C\u7F13\u51B2\u533A\n textBufferRef.current = ''\n\n // \u91CD\u7F6E\u5361\u7247\u7F13\u5B58\u961F\u5217\n pendingCardsRef.current = []\n\n // T039: \u4FDD\u5B58 sessionId \u548C userId\uFF08\u5982\u679C\u540E\u7AEF\u8FD4\u56DE\uFF09\n const messageStartData = data as MessageStartData & { userId?: string }\n if (messageStartData.sessionId && messageStartData.sessionId !== sessionId) {\n saveSession(messageStartData.sessionId)\n }\n // \u4FDD\u5B58\u540E\u7AEF\u8FD4\u56DE\u7684 userId\uFF08\u5982\u679C\u6709\uFF09\n if (messageStartData.userId) {\n saveUserId(messageStartData.userId)\n setUserId(messageStartData.userId)\n }\n\n // \u68C0\u67E5\u6700\u540E\u4E00\u6761\u6D88\u606F\u662F\u5426\u662F thinking \u6D88\u606F\uFF08\u7528\u6237\u53D1\u9001\u6D88\u606F\u65F6\u5DF2\u6DFB\u52A0\uFF09\n setMessagesState(prev => {\n const lastMessage = prev[prev.length - 1]\n const hasThinking =\n lastMessage &&\n lastMessage.role === 'assistant' &&\n lastMessage.content.length === 1 &&\n lastMessage.content[0].type === 'thinking'\n\n if (hasThinking) {\n // \u590D\u7528\u5DF2\u5B58\u5728\u7684 thinking \u6D88\u606F\n currentMessageRef.current = lastMessage\n return prev // \u4E0D\u9700\u8981\u6DFB\u52A0\u65B0\u6D88\u606F\n } else {\n // \u6CA1\u6709 thinking \u6D88\u606F\uFF0C\u521B\u5EFA\u65B0\u7684\uFF08\u517C\u5BB9\u5176\u4ED6\u573A\u666F\uFF09\n const messageId = `msg-${Date.now()}`\n currentMessageRef.current = {\n id: messageId,\n role: 'assistant',\n content: [{ type: 'thinking', data: { status: 'thinking' } }],\n timestamp: Date.now(),\n }\n return [...prev, currentMessageRef.current!]\n }\n })\n break\n }\n\n case 'content_delta': {\n // \u7D2F\u79EF\u6D41\u5F0F\u6587\u672C\u5185\u5BB9\uFF0C\u5E76\u5B9E\u65F6\u68C0\u6D4B\u4EA7\u54C1\u5360\u4F4D\u7B26\n const deltaData = data as any\n const deltaText = deltaData.delta || deltaData.text || ''\n\n if (currentMessageRef.current && deltaText) {\n // \u89E6\u53D1\u6587\u672C\u6D88\u606F\u56DE\u8C03\uFF08\u4EC5\u89E6\u53D1\u4E00\u6B21\uFF09\n if (!textMessageCallbackTriggeredRef.current) {\n textMessageCallbackTriggeredRef.current = true\n onTextMessage?.()\n }\n\n // \u79FB\u9664\u601D\u8003\u6C14\u6CE1\uFF08\u5982\u679C\u5B58\u5728\uFF09\n const hasThinking = currentMessageRef.current.content.some(c => c.type === 'thinking')\n if (hasThinking) {\n currentMessageRef.current.content = currentMessageRef.current.content.filter(c => c.type !== 'thinking')\n }\n\n // \u5C06\u65B0\u6587\u672C\u6DFB\u52A0\u5230\u7F13\u51B2\u533A\n textBufferRef.current += deltaText\n\n // \u5B9E\u65F6\u89E3\u6790\u7F13\u51B2\u533A\u4E2D\u7684\u5360\u4F4D\u7B26\n const { contents, remainingBuffer } = parseStreamingText(\n textBufferRef.current,\n productMapRef.current,\n rawProductMapRef.current,\n onAddToCart,\n productCardRender\n )\n\n // \u66F4\u65B0\u7F13\u51B2\u533A\u4E3A\u5269\u4F59\u5185\u5BB9\n textBufferRef.current = remainingBuffer\n\n // \u5C06\u89E3\u6790\u51FA\u7684\u5185\u5BB9\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\n if (contents.length > 0) {\n contents.forEach(content => {\n const lastContent = currentMessageRef.current!.content[\n currentMessageRef.current!.content.length - 1\n ] as MessageContent | undefined\n\n // \u5982\u679C\u662F\u6587\u672C\u5185\u5BB9\u4E14\u6700\u540E\u4E00\u4E2A\u4E5F\u662F\u6587\u672C\uFF0C\u5219\u5408\u5E76\n if (content.type === 'text' && lastContent && lastContent.type === 'text') {\n lastContent.text += content.text\n } else {\n // \u5426\u5219\u6DFB\u52A0\u65B0\u5185\u5BB9\n currentMessageRef.current!.content.push(content)\n }\n })\n\n // \u66F4\u65B0\u6D88\u606F\u5217\u8868\u4EE5\u89E6\u53D1\u6E32\u67D3\n setMessagesState(prev => {\n if (!currentMessageRef.current) return prev\n\n const updated = [...prev]\n const existingIndex = updated.findIndex(m => m && m.id === currentMessageRef.current!.id)\n\n if (existingIndex >= 0) {\n updated[existingIndex] = { ...currentMessageRef.current! }\n } else {\n updated.push({ ...currentMessageRef.current! })\n }\n\n return updated\n })\n }\n }\n break\n }\n\n case 'content_block': {\n // \u63A5\u6536\u7ED3\u6784\u5316\u5185\u5BB9\u5757\uFF08\u5546\u54C1\u3001\u653F\u7B56\u7B49\uFF09\n // API \u8FD4\u56DE\u683C\u5F0F\u53D8\u66F4:\n // \u65B0\u683C\u5F0F: {index: number, type: string, data: {...}} <- type \u5728\u5916\u5C42\n // \u65E7\u683C\u5F0F: {index: number, data: {type: string, ...}} <- type \u5728 data \u5185\n const blockData = data as any\n if (currentMessageRef.current) {\n // \u83B7\u53D6 type \u548C data\n // \u4F18\u5148\u4ECE\u5916\u5C42\u83B7\u53D6 type\uFF0C\u517C\u5BB9\u65E7\u683C\u5F0F\u4ECE data \u5185\u83B7\u53D6\n const contentType = blockData.type || blockData.data?.type\n const contentData = blockData.data\n\n if (!contentType || !contentData) {\n console.warn('[useChatState] Invalid content_block:', blockData)\n break\n }\n\n // ============================================================\n // \u8F6C\u6362\u6570\u636E\u7ED3\u6784\u4EE5\u5339\u914D\u7C7B\u578B\u5B9A\u4E49\n // \u6839\u636E\u540E\u7AEF\u6570\u636E\u7ED3\u6784\u89C4\u8303\uFF08\u98DE\u4E66\u6587\u6863\uFF09\u8FDB\u884C\u8F6C\u6362\n // ============================================================\n let messageContent: MessageContent\n\n // ========== 1. \u4EA7\u54C1\u5217\u8868\u5361\u7247 (Product List) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"product_list\", data: [product1, product2, ...]}\n // data \u76F4\u63A5\u662F\u4EA7\u54C1\u6570\u7EC4\uFF0C\u4E0D\u662F {products: [...]}\n if (contentType === 'product_list' && Array.isArray(contentData)) {\n // \u89E6\u53D1\u5546\u54C1\u5217\u8868\u56DE\u8C03\n onProductList?.()\n\n // \u7F13\u5B58\u539F\u59CB\u540E\u7AEF\u4EA7\u54C1\u6570\u636E\uFF08\u7528\u4E8E productCardRender\uFF09\n // \u4F7F\u7528 handle \u4F5C\u4E3A key \u8FDB\u884C\u5339\u914D\n contentData.forEach((rawProduct: any) => {\n if (rawProduct && rawProduct.handle) {\n rawProductMapRef.current.set(rawProduct.handle, rawProduct)\n console.log('[useChatState] \u7F13\u5B58\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:', rawProduct.handle)\n }\n })\n\n // \u4F7F\u7528\u7EDF\u4E00\u7684\u4EA7\u54C1\u8F6C\u6362\u5DE5\u5177\u51FD\u6570\n const transformedProducts = transformProducts(contentData, site)\n\n // \u5EFA\u7ACB\u4EA7\u54C1\u6620\u5C04\u7F13\u5B58 (handle \u2192 Product)\n // \u7528\u4E8E\u540E\u7EED\u5728 message_end \u65F6\u89E3\u6790\u6587\u672C\u4E2D\u7684 {{handle}}\n transformedProducts.forEach(product => {\n if (product && product.handle) {\n productMapRef.current.set(product.handle, product)\n\n console.log('[useChatState] \u5EFA\u7ACB\u4EA7\u54C1\u6620\u5C04:', {\n handle: product.handle,\n title: product.title,\n })\n }\n })\n\n // \u26A0\uFE0F \u4E0D\u8981\u628A product_list \u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\uFF0C\u907F\u514D\u95EA\u70C1\n // \u7B49\u5230 message_end \u65F6\uFF0C\u901A\u8FC7\u6587\u672C\u89E3\u6790\u521B\u5EFA product_card\uFF0C\u76F4\u63A5\u663E\u793A\u6700\u7EC8\u7684\u4EA4\u66FF\u683C\u5F0F\n console.log('[useChatState] \u2705 \u4EA7\u54C1\u5217\u8868\u5DF2\u7F13\u5B58\uFF0C\u4E0D\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\uFF08\u907F\u514D\u95EA\u70C1\uFF09')\n break // \u76F4\u63A5\u8DF3\u51FA\uFF0C\u4E0D\u6267\u884C\u540E\u7EED\u7684 push \u64CD\u4F5C\n }\n // ========== 2. \u4EA7\u54C1\u5BF9\u6BD4\u5361\u7247 (Product Comparison) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"product_comparison\", data: {products: [...], dimensions: {...}}}\n else if (contentType === 'product_comparison' && contentData.products) {\n // \u4F7F\u7528\u7EDF\u4E00\u7684\u4EA7\u54C1\u8F6C\u6362\u5DE5\u5177\u51FD\u6570\n const transformedProducts = transformProducts(contentData.products, site)\n\n messageContent = {\n type: 'product_comparison',\n data: {\n products: transformedProducts,\n dimensions: contentData.dimensions || {},\n productComparisonRender: productComparisonRender,\n },\n } as MessageContent\n }\n // ========== 3. FAQ \u5217\u8868\u5361\u7247 (FAQ List) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"faq_list\", data: {found, count, total, results: [...]}}\n else if (contentType === 'faq_list' && contentData.found !== undefined) {\n messageContent = {\n type: 'faq_list',\n data: contentData, // \u76F4\u63A5\u4F7F\u7528\uFF0C\u7ED3\u6784\u5DF2\u5339\u914D\n } as MessageContent\n }\n // ========== 4. \u5FEB\u6377\u56DE\u590D (Quick Replies) ==========\n else if (contentType === 'quick_replies' && contentData.replies) {\n messageContent = {\n type: 'quick_replies',\n data: {\n replies: contentData.replies,\n },\n } as MessageContent\n }\n // ========== 5. \u653F\u7B56\u5185\u5BB9 (Policy) ==========\n else if (contentType === 'policy' && contentData.title && contentData.content) {\n messageContent = {\n type: 'policy',\n data: {\n title: contentData.title,\n content: contentData.content,\n },\n } as MessageContent\n }\n // ========== 6. \u4FC3\u9500\u6D3B\u52A8\u5217\u8868 (Promotion List) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"promotion_list\", data: {found, count, total, results: [...]}}\n else if (contentType === 'promotion_list' && contentData.found !== undefined) {\n // \u89E6\u53D1\u4FC3\u9500\u5361\u7247\u56DE\u8C03\uFF0C\u4F20\u9012\u4FC3\u9500\u6D3B\u52A8\u6570\u7EC4\n onPromotionList?.(contentData.results || [])\n\n messageContent = {\n type: 'promotion_list',\n data: contentData, // \u76F4\u63A5\u4F7F\u7528\uFF0C\u7ED3\u6784\u5DF2\u5339\u914D\n } as MessageContent\n }\n // ========== 7. \u8D2D\u7269\u8F66 (Cart) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"cart\", data: {id, lines: {edges: [...]}, cost, ...}} (Shopify GraphQL)\n // \u9700\u8981\u8F6C\u6362\u4E3A\u524D\u7AEF\u683C\u5F0F: {cartId, lines: [...], cost, ...}\n else if (contentType === 'cart' && contentData.id !== undefined) {\n // \u8F6C\u6362\u540E\u7AEF Shopify GraphQL \u683C\u5F0F\u4E3A\u524D\u7AEF\u6807\u51C6\u683C\u5F0F\n const transformedData = transformCartData(contentData as BackendCartData)\n messageContent = {\n type: 'cart',\n data: {\n ...transformedData,\n onCart: onCart, // \u6CE8\u5165\u8D2D\u7269\u8F66\u6309\u94AE\u56DE\u8C03\n },\n } as MessageContent\n }\n // ========== 8. \u5176\u4ED6\u7C7B\u578B\uFF08\u901A\u7528\u5904\u7406\uFF09 ==========\n else {\n messageContent = {\n type: contentType,\n data: contentData,\n } as MessageContent\n }\n\n // \u26A0\uFE0F \u91CD\u8981\u4FEE\u6539\uFF1A\u5C06\u5361\u7247\u7F13\u5B58\u8D77\u6765\uFF0C\u4E0D\u7ACB\u5373\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\n // \u7B49\u5F85 message_end \u65F6\uFF0C\u5728\u6587\u672C\u5B8C\u6210\u540E\u518D\u7EDF\u4E00\u6DFB\u52A0\u5361\u7247\n console.log('[useChatState] \u2705 \u5361\u7247\u5DF2\u7F13\u5B58\uFF0C\u7B49\u5F85\u6587\u672C\u5B8C\u6210\u540E\u663E\u793A:', contentType)\n pendingCardsRef.current.push(messageContent)\n\n // \u4E0D\u518D\u7ACB\u5373\u66F4\u65B0\u6D88\u606F\u5217\u8868\uFF0C\u907F\u514D\u5361\u7247\u5728\u6587\u672C\u4E4B\u524D\u663E\u793A\n // \u539F\u6765\u7684\u4EE3\u7801\uFF1A\n // currentMessageRef.current.content.push(messageContent)\n // setMessagesState(prev => { ... })\n }\n break\n }\n\n case 'tool_start':\n case 'tool_end': {\n // \u5DE5\u5177\u8C03\u7528\u4E8B\u4EF6\uFF0C\u6682\u65F6\u5FFD\u7565\n // \u53EF\u4EE5\u5728\u672A\u6765\u7528\u4E8E\u663E\u793A\u5DE5\u5177\u8C03\u7528\u72B6\u6001\n break\n }\n\n case 'message_end': {\n // \u6D88\u606F\u63A5\u6536\u5B8C\u6210\n setIsStreaming(false)\n\n // \u5904\u7406\u7F13\u51B2\u533A\u4E2D\u5269\u4F59\u7684\u6587\u672C\uFF08\u5982\u679C\u6709\uFF09\n if (currentMessageRef.current && textBufferRef.current) {\n console.log('[useChatState] \u5904\u7406\u5269\u4F59\u7F13\u51B2\u533A:', textBufferRef.current)\n\n const lastContent = currentMessageRef.current.content[\n currentMessageRef.current.content.length - 1\n ] as MessageContent | undefined\n\n // \u5982\u679C\u6700\u540E\u4E00\u4E2A\u5185\u5BB9\u662F\u6587\u672C\uFF0C\u5219\u5408\u5E76\n if (lastContent && lastContent.type === 'text') {\n lastContent.text += textBufferRef.current\n } else {\n // \u5426\u5219\u6DFB\u52A0\u4E3A\u65B0\u7684\u6587\u672C\u5757\n currentMessageRef.current.content.push({\n type: 'text',\n text: textBufferRef.current,\n })\n }\n }\n\n // \u26A0\uFE0F \u91CD\u8981\u4FEE\u6539\uFF1A\u5728\u6587\u672C\u5B8C\u6210\u540E\uFF0C\u6DFB\u52A0\u6240\u6709\u7F13\u5B58\u7684\u5361\u7247\n if (currentMessageRef.current && pendingCardsRef.current.length > 0) {\n console.log('[useChatState] \uD83D\uDCCB \u6587\u672C\u5DF2\u5B8C\u6210\uFF0C\u73B0\u5728\u6DFB\u52A0', pendingCardsRef.current.length, '\u4E2A\u7F13\u5B58\u7684\u5361\u7247')\n\n // \u5C06\u6240\u6709\u7F13\u5B58\u7684\u5361\u7247\u6DFB\u52A0\u5230\u6D88\u606F\u5185\u5BB9\u4E2D\n currentMessageRef.current.content.push(...pendingCardsRef.current)\n }\n\n // \u26A0\uFE0F \u8D85\u65F6\u68C0\u6D4B\uFF1A\u5982\u679C message_end \u65F6\u4ECD\u5B58\u5728 thinking block\uFF0C\u89C6\u4E3A\u8D85\u65F6/\u5F02\u5E38\n // \u6CE8\u610F\uFF1A\u5728\u6DFB\u52A0\u5361\u7247\u4E4B\u540E\u68C0\u6D4B\uFF0C\u8FD9\u6837\u5982\u679C\u6709\u5361\u7247\u5C31\u4E0D\u4F1A\u6DFB\u52A0\u8D85\u65F6\u63D0\u793A\n if (currentMessageRef.current) {\n const hasThinking = currentMessageRef.current.content.some(c => c.type === 'thinking')\n\n if (hasThinking) {\n console.log('[useChatState] \u26A0\uFE0F message_end \u65F6\u4ECD\u5B58\u5728 thinking block\uFF0C\u7ACB\u5373\u79FB\u9664\uFF08\u89C6\u4E3A\u8D85\u65F6\uFF09')\n\n // \u79FB\u9664 thinking block\n currentMessageRef.current.content = currentMessageRef.current.content.filter(c => c.type !== 'thinking')\n\n // \u5982\u679C\u6CA1\u6709\u5176\u4ED6\u5185\u5BB9\uFF08\u5305\u62EC\u7F13\u5B58\u7684\u5361\u7247\uFF09\uFF0C\u6DFB\u52A0\u8D85\u65F6\u63D0\u793A\n if (currentMessageRef.current.content.length === 0) {\n currentMessageRef.current.content.push({\n type: 'text',\n text: 'Response timed out, please try again.',\n } as TextContent)\n }\n }\n }\n\n // \u66F4\u65B0\u6D88\u606F\u5217\u8868\uFF08\u7EDF\u4E00\u66F4\u65B0\uFF0C\u5305\u542B\u6587\u672C\u548C\u5361\u7247\uFF09\n if (currentMessageRef.current) {\n setMessagesState(prev => {\n if (!currentMessageRef.current) return prev\n\n const updated = [...prev]\n const existingIndex = updated.findIndex(m => m && m.id === currentMessageRef.current!.id)\n\n if (existingIndex >= 0) {\n updated[existingIndex] = { ...currentMessageRef.current! }\n }\n\n return updated\n })\n }\n\n // \u6E05\u7A7A\u7F13\u51B2\u533A\u3001\u4EA7\u54C1\u6620\u5C04\u548C\u5361\u7247\u7F13\u5B58\n textBufferRef.current = ''\n pendingCardsRef.current = []\n productMapRef.current.clear()\n rawProductMapRef.current.clear()\n currentMessageRef.current = null\n break\n }\n\n case 'status': {\n // T040: \u72B6\u6001\u66F4\u65B0\uFF08\u5982\u4F1A\u8BDD\u8FC7\u671F\uFF09\n const statusData = data as StatusData\n if (statusData.type === 'session_expired') {\n // \u4F1A\u8BDD\u8FC7\u671F\uFF0C\u6E05\u7A7A\u6D88\u606F\u5217\u8868\u548C\u4F1A\u8BDD\n clearMessages()\n clearSession()\n if (welcomeMessage) {\n addMessage({\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: [{ type: 'text', text: welcomeMessage }],\n timestamp: Date.now(),\n })\n }\n }\n break\n }\n\n case 'error': {\n // \u9519\u8BEF\u5904\u7406\n const errorData = data as ErrorData\n setIsStreaming(false)\n\n // \u6E05\u7406\u7F13\u5B58\uFF08\u9632\u6B62\u6CC4\u6F0F\u5230\u4E0B\u6B21\u6D88\u606F\uFF09\n textBufferRef.current = ''\n pendingCardsRef.current = []\n productMapRef.current.clear()\n rawProductMapRef.current.clear()\n currentMessageRef.current = null\n\n // \u6DFB\u52A0\u9519\u8BEF\u6D88\u606F\u5230\u754C\u9762\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: errorData.message,\n code: errorData.code,\n },\n },\n ],\n timestamp: Date.now(),\n })\n\n onError?.(new Error(errorData.message))\n break\n }\n\n case 'done': {\n // \u6D41\u7ED3\u675F\n setIsStreaming(false)\n\n // \u6E05\u7406\u7F13\u5B58\uFF08\u9632\u6B62\u6CC4\u6F0F\u5230\u4E0B\u6B21\u6D88\u606F\uFF09\n textBufferRef.current = ''\n pendingCardsRef.current = []\n productMapRef.current.clear()\n rawProductMapRef.current.clear()\n\n // \u6E05\u7406\u5F53\u524D\u6D88\u606F\u5F15\u7528\n currentMessageRef.current = null\n break\n }\n\n default:\n // \u5176\u4ED6\u4E8B\u4EF6\u7C7B\u578B\uFF08tool_start, tool_end \u7B49\uFF09\n break\n }\n },\n [\n welcomeMessage,\n site,\n addMessage,\n clearMessages,\n clearSession,\n saveSession,\n sessionId,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n ]\n )\n\n\n return {\n messages,\n isOpen,\n userId,\n sessionId,\n inputValue,\n isStreaming,\n openChat,\n closeChat,\n toggleChat,\n setInputValue,\n setUserId,\n addMessage,\n setMessages,\n clearMessages,\n handleSSEEvent,\n saveSession,\n clearSession,\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["useChatState_exports", "__export", "useChatState", "__toCommonJS", "import_react", "import_userId", "import_useSession", "import_productTransformers", "import_cartTransformers", "parseStreamingText", "buffer", "productMap", "rawProductMap", "onAddToCart", "productCardRender", "contents", "regex", "lastIndex", "match", "foundMatch", "beforeText", "productId", "product", "rawProduct", "remainingBuffer", "incompleteMatch", "completeText", "parseTextWithProductIds", "text", "result", "remainingText", "reorganizeMessageContent", "content", "segments", "maybeReorganizeHistoricalMessage", "message", "c", "structuredContent", "reorganizedContent", "options", "welcomeMessage", "site", "controlledOpen", "onOpenChange", "onOpen", "onClose", "onMessageSend", "onError", "onTextMessage", "onProductList", "onPromotionList", "onCart", "productComparisonRender", "sessionId", "saveSession", "clearSession", "userId", "setUserId", "id", "messages", "setMessagesState", "internalOpen", "setInternalOpen", "isControlled", "isOpen", "inputValue", "setInputValue", "isStreaming", "setIsStreaming", "currentMessageRef", "textMessageCallbackTriggeredRef", "productMapRef", "rawProductMapRef", "textBufferRef", "pendingCardsRef", "openChat", "closeChat", "toggleChat", "newState", "addMessage", "prev", "setMessages", "newMessages", "validMessages", "msg", "reorganizedMessages", "clearMessages", "handleSSEEvent", "event", "eventType", "data", "messageStartData", "lastMessage", "messageId", "deltaData", "deltaText", "lastContent", "updated", "existingIndex", "m", "blockData", "contentType", "contentData", "messageContent", "errorData"]
|
|
4
|
+
"sourcesContent": ["/**\n * \u804A\u5929\u72B6\u6001\u7BA1\u7406 Hook\n * \u7BA1\u7406\u6D88\u606F\u5217\u8868\u3001\u7A97\u53E3\u72B6\u6001\u3001\u8F93\u5165\u6846\u72B6\u6001\u3001\u6D41\u5F0F\u6D88\u606F\u7D2F\u79EF\n * \u57FA\u4E8E specs/livechat-widget/plan.md \u7684\u72B6\u6001\u7BA1\u7406\u7B56\u7565\n */\n\nimport { useState, useCallback, useRef, useEffect } from 'react'\nimport type { Message, MessageContent, SSEEvent, StatusData, ErrorData, MessageStartData, BackendCartData, Product, TextContent, ProductCardContent, ProductListContent } from '../types'\nimport { getUserId, saveUserId } from '../utils/userId'\nimport { useSession } from './useSession'\nimport { transformProducts } from '../utils/productTransformers'\nimport { transformCartData } from '../utils/cartTransformers'\n\n// ============================================================================\n// \u8F85\u52A9\u51FD\u6570\uFF1A\u6587\u672C\u89E3\u6790\u548C\u6D88\u606F\u91CD\u7EC4\n// ============================================================================\n\n/**\n * \u5B9E\u65F6\u89E3\u6790\u6D41\u5F0F\u6587\u672C\u4E2D\u7684\u4EA7\u54C1\u5360\u4F4D\u7B26\n * \u5904\u7406\u7F13\u51B2\u533A\u4E2D\u7684\u6587\u672C\uFF0C\u68C0\u6D4B\u5B8C\u6574\u7684 {{product:xxx}} \u5360\u4F4D\u7B26\n *\n * @param buffer \u5F53\u524D\u7F13\u51B2\u533A\u5185\u5BB9\uFF08\u5305\u542B\u65B0\u63A5\u6536\u7684\u6587\u672C\uFF09\n * @param productMap handle \u2192 Product \u7684\u6620\u5C04\u8868\n * @param rawProductMap handle \u2192 raw backend product \u7684\u6620\u5C04\u8868\n * @param onAddToCart \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n * @param productCardRender \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @returns { contents: \u9700\u8981\u6DFB\u52A0\u7684\u5185\u5BB9\u6570\u7EC4, remainingBuffer: \u5269\u4F59\u7F13\u51B2\u533A\u5185\u5BB9 }\n */\nfunction parseStreamingText(\n buffer: string,\n productMap: Map<string, Product>,\n rawProductMap: Map<string, any>,\n onAddToCart?: (product: Product) => void,\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n): { contents: MessageContent[]; remainingBuffer: string } {\n const contents: MessageContent[] = []\n const regex = /\\{\\{(?:product:)?([^}]+)\\}\\}/g\n\n let lastIndex = 0\n let match: RegExpExecArray | null\n let foundMatch = false\n\n // \u67E5\u627E\u6240\u6709\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\n while ((match = regex.exec(buffer)) !== null) {\n foundMatch = true\n\n // \u63D0\u53D6\u5360\u4F4D\u7B26\u524D\u7684\u6587\u672C\n const beforeText = buffer.slice(lastIndex, match.index)\n if (beforeText) {\n contents.push({ type: 'text', text: beforeText } as TextContent)\n }\n\n // \u63D0\u53D6\u4EA7\u54C1 ID \u5E76\u521B\u5EFA\u4EA7\u54C1\u5361\u7247\n const productId = match[1].trim()\n const product = productMap.get(productId)\n const rawProduct = rawProductMap.get(productId)\n\n // \u65E0\u8BBA\u662F\u5426\u627E\u5230\u4EA7\u54C1\u6570\u636E\uFF0C\u90FD\u6E32\u67D3 product_card\uFF0C\u5E94\u7528\u5C42\u53EF\u901A\u8FC7 productHandle \u67E5\u8BE2\u4EA7\u54C1\n if (product) {\n console.log('[useChatState] \uD83C\uDFAF \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1:', productId, '\u2192', product.title)\n } else {\n console.log('[useChatState] \uD83D\uDCE6 \u5B9E\u65F6\u68C0\u6D4B\u5230\u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2:', productId)\n }\n\n contents.push({\n type: 'product_card',\n data: {\n product: product,\n rawProduct: rawProduct,\n productHandle: productId,\n onAddToCart: onAddToCart,\n productCardRender: productCardRender\n }\n } as ProductCardContent)\n\n lastIndex = regex.lastIndex\n }\n\n // \u5982\u679C\u627E\u5230\u4E86\u81F3\u5C11\u4E00\u4E2A\u5B8C\u6574\u5360\u4F4D\u7B26\n if (foundMatch) {\n // \u8FD4\u56DE\u5269\u4F59\u7684\u6587\u672C\u4F5C\u4E3A\u7F13\u51B2\u533A\uFF08\u53EF\u80FD\u5305\u542B\u4E0D\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\uFF09\n const remainingBuffer = buffer.slice(lastIndex)\n return { contents, remainingBuffer }\n } else {\n // \u6CA1\u6709\u627E\u5230\u5B8C\u6574\u5360\u4F4D\u7B26\uFF0C\u68C0\u67E5\u662F\u5426\u6709\u4E0D\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\u5F00\u5934\n // \u4F8B\u5982\uFF1A\u7F13\u51B2\u533A\u662F \"some text {{prod\"\uFF0C\u6211\u4EEC\u9700\u8981\u4FDD\u7559 \"{{prod\" \u7B49\u5F85\u66F4\u591A\u6587\u672C\n const incompleteMatch = buffer.match(/\\{\\{[^}]*$/)\n\n if (incompleteMatch) {\n // \u6709\u4E0D\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\u5F00\u5934\n const completeText = buffer.slice(0, incompleteMatch.index)\n if (completeText) {\n contents.push({ type: 'text', text: completeText } as TextContent)\n }\n return { contents, remainingBuffer: incompleteMatch[0] }\n } else {\n // \u6CA1\u6709\u4E0D\u5B8C\u6574\u7684\u5360\u4F4D\u7B26\uFF0C\u6574\u4E2A\u7F13\u51B2\u533A\u90FD\u662F\u666E\u901A\u6587\u672C\n if (buffer) {\n contents.push({ type: 'text', text: buffer } as TextContent)\n }\n return { contents, remainingBuffer: '' }\n }\n }\n}\n\n/**\n * \u89E3\u6790\u6587\u672C\u4E2D\u7684 {{handle}}\uFF0C\u8FD4\u56DE [text, product_card, text, ...] \u6570\u7EC4\uFF08\u7528\u4E8E\u5386\u53F2\u6D88\u606F\u91CD\u7EC4\uFF09\n *\n * @param text \u5305\u542B {{handle}} \u6807\u8BB0\u7684\u6587\u672C\n * @param productMap handle \u2192 Product \u7684\u6620\u5C04\u8868\n * @param rawProductMap handle \u2192 raw backend product \u7684\u6620\u5C04\u8868\n * @param onAddToCart \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n * @param productCardRender \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @returns MessageContent \u6570\u7EC4\n *\n * @example\n * \u8F93\u5165\uFF1A\n * text: \"\u6211\u63A8\u8350\u4EE5\u4E0B\u4EA7\u54C1\uFF1A\\n{{product-handle}}\\n\u8FD9\u6B3E\u4EA7\u54C1\u6027\u4EF7\u6BD4\u5F88\u9AD8\u3002\"\n * productMap: Map { 'product-handle' => Product {...} }\n * \u8F93\u51FA\uFF1A\n * [\n * { type: 'text', text: '\u6211\u63A8\u8350\u4EE5\u4E0B\u4EA7\u54C1\uFF1A' },\n * { type: 'product_card', data: { product: {...}, onAddToCart } },\n * { type: 'text', text: '\u8FD9\u6B3E\u4EA7\u54C1\u6027\u4EF7\u6BD4\u5F88\u9AD8\u3002' }\n * ]\n */\nfunction parseTextWithProductIds(\n text: string,\n productMap: Map<string, Product>,\n rawProductMap: Map<string, any>,\n onAddToCart?: (product: Product) => void,\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n): MessageContent[] {\n const result: MessageContent[] = []\n // \u4FEE\u6539\u6B63\u5219\u8868\u8FBE\u5F0F\u4EE5\u5339\u914D {{product:ID}} \u683C\u5F0F\n // \u5339\u914D {{product:xxx}} \u6216 {{xxx}}\uFF08\u517C\u5BB9\u4E24\u79CD\u683C\u5F0F\uFF09\n const regex = /\\{\\{(?:product:)?([^}]+)\\}\\}/g\n\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n while ((match = regex.exec(text)) !== null) {\n const beforeText = text.slice(lastIndex, match.index).trim()\n // match[1] \u662F\u6355\u83B7\u7EC4\u4E2D\u7684\u5185\u5BB9\uFF0C\u5373 product: \u540E\u9762\u7684 ID\n const productId = match[1].trim()\n\n // \u6DFB\u52A0\u524D\u9762\u7684\u6587\u672C\uFF08\u5982\u679C\u6709\uFF09\n if (beforeText) {\n result.push({\n type: 'text',\n text: beforeText,\n } as TextContent)\n }\n\n // \u6DFB\u52A0\u4EA7\u54C1\u5361\u7247\uFF08\u65E0\u8BBA\u662F\u5426\u627E\u5230\u4EA7\u54C1\u6570\u636E\uFF0C\u90FD\u6E32\u67D3 product_card\uFF09\n const product = productMap.get(productId)\n const rawProduct = rawProductMap.get(productId)\n if (product) {\n console.log(`[useChatState] \u2705 \u627E\u5230\u4EA7\u54C1\u5339\u914D: ${productId} \u2192 ${product.title}`)\n } else {\n console.log(`[useChatState] \uD83D\uDCE6 \u4EA7\u54C1\u5360\u4F4D\u7B26\uFF0C\u4EA7\u54C1\u6570\u636E\u5F85\u5E94\u7528\u5C42\u67E5\u8BE2: ${productId}`)\n }\n\n result.push({\n type: 'product_card',\n data: {\n product: product,\n rawProduct: rawProduct,\n productHandle: productId,\n onAddToCart: onAddToCart,\n productCardRender: productCardRender,\n },\n } as ProductCardContent)\n\n lastIndex = regex.lastIndex\n }\n\n // \u6DFB\u52A0\u6700\u540E\u5269\u4F59\u7684\u6587\u672C\n const remainingText = text.slice(lastIndex).trim()\n if (remainingText) {\n result.push({\n type: 'text',\n text: remainingText,\n } as TextContent)\n }\n\n return result\n}\n\n/**\n * \u91CD\u7EC4\u6D88\u606F\u5185\u5BB9\uFF1A\u89E3\u6790\u6587\u672C\u4E2D\u7684 {{handle}}\uFF0C\u66FF\u6362\u4E3A\u4EA7\u54C1\u5361\u7247\n *\n * \u5904\u7406\u903B\u8F91\uFF1A\n * 1. \u904D\u5386\u6D88\u606F\u7684\u6240\u6709 content blocks\n * 2. \u5BF9\u4E8E text \u7C7B\u578B\uFF0C\u89E3\u6790\u5176\u4E2D\u7684 {{handle}} \u5E76\u62C6\u5206\u4E3A\u591A\u4E2A content\n * 3. \u8DF3\u8FC7 product_list \u7C7B\u578B\uFF08\u5DF2\u7ECF\u88AB\u62C6\u5206\u5230\u6587\u672C\u4E2D\uFF09\n * 4. \u5176\u4ED6\u7C7B\u578B\u76F4\u63A5\u4FDD\u7559\n *\n * @param contents \u539F\u59CB\u6D88\u606F\u5185\u5BB9\u6570\u7EC4\n * @param productMap handle \u2192 Product \u7684\u6620\u5C04\u8868\n * @param rawProductMap handle \u2192 raw backend product \u7684\u6620\u5C04\u8868\n * @param onAddToCart \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n * @param productCardRender \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @returns \u91CD\u7EC4\u540E\u7684\u6D88\u606F\u5185\u5BB9\u6570\u7EC4\n */\nfunction reorganizeMessageContent(\n contents: MessageContent[],\n productMap: Map<string, Product>,\n rawProductMap: Map<string, any>,\n onAddToCart?: (product: Product) => void,\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n): MessageContent[] {\n const result: MessageContent[] = []\n\n for (const content of contents) {\n // \u53EA\u5904\u7406\u6587\u672C\u7C7B\u578B\n if (content.type === 'text') {\n const textContent = content as TextContent\n const segments = parseTextWithProductIds(textContent.text, productMap, rawProductMap, onAddToCart, productCardRender)\n result.push(...segments)\n }\n // \u8DF3\u8FC7 product_list\uFF08\u5DF2\u7ECF\u88AB\u62C6\u5206\u5230\u6587\u672C\u4E2D\uFF09\n else if (content.type === 'product_list') {\n continue\n }\n // \u5176\u4ED6\u7C7B\u578B\u76F4\u63A5\u4FDD\u7559\n else {\n result.push(content)\n }\n }\n\n return result\n}\n\n/**\n * \u5904\u7406\u5355\u6761\u6D88\u606F\u7684\u91CD\u7EC4\uFF08\u7528\u4E8E\u5386\u53F2\u6D88\u606F\u52A0\u8F7D\uFF09\n * \u5982\u679C\u6D88\u606F\u5305\u542B\u5E26\u6709 {{}} \u7684\u6587\u672C\uFF0C\u5219\u8FDB\u884C\u91CD\u7EC4\n *\n * @param message \u539F\u59CB\u6D88\u606F\n * @param onAddToCart \u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n * @param productCardRender \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @returns \u91CD\u7EC4\u540E\u7684\u6D88\u606F\uFF08\u5982\u679C\u9700\u8981\u91CD\u7EC4\uFF09\uFF0C\u5426\u5219\u8FD4\u56DE\u539F\u6D88\u606F\n */\nfunction maybeReorganizeHistoricalMessage(\n message: Message,\n onAddToCart?: (product: Product) => void,\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n): Message {\n // \u68C0\u67E5\u6D88\u606F\u662F\u5426\u5305\u542B\u5E26\u6709 {{}} \u7684\u6587\u672C\n const hasPlaceholder = message.content.some(\n c => c.type === 'text' && /\\{\\{(?:product:)?[^}]+\\}\\}/.test((c as TextContent).text)\n )\n if (!hasPlaceholder) {\n return message // \u6CA1\u6709\u5360\u4F4D\u7B26\uFF0C\u4E0D\u9700\u8981\u91CD\u7EC4\n }\n\n console.log('[useChatState] \u68C0\u6D4B\u5230\u5386\u53F2\u6D88\u606F\u9700\u8981\u91CD\u7EC4, \u6D88\u606FID:', message.id)\n\n // \u6784\u5EFA\u4EA7\u54C1\u6620\u5C04 (handle \u2192 Product)\n const productMap = new Map<string, Product>()\n // \u4ECE structured_content \u4E2D\u63D0\u53D6\u539F\u59CB\u540E\u7AEF\u4EA7\u54C1\u6570\u636E (handle \u2192 rawProduct)\n const rawProductMap = new Map<string, any>()\n\n // \u4F18\u5148\u4ECE structured_content \u83B7\u53D6\u539F\u59CB\u4EA7\u54C1\u6570\u636E\uFF08\u5982\u679C\u5B58\u5728\uFF09\n if (message.structured_content) {\n message.structured_content.forEach(structuredContent => {\n if (structuredContent.type === 'product_list' && Array.isArray(structuredContent.data)) {\n structuredContent.data.forEach((rawProduct: any) => {\n if (rawProduct && rawProduct.handle) {\n rawProductMap.set(rawProduct.handle, rawProduct)\n console.log('[useChatState] \u4ECE structured_content \u63D0\u53D6\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:', rawProduct.handle)\n }\n })\n }\n })\n }\n\n // \u6784\u5EFA\u8F6C\u6362\u540E\u7684\u4EA7\u54C1\u6620\u5C04\uFF08\u7528\u4E8E\u9ED8\u8BA4\u6E32\u67D3\uFF09\n message.content.forEach(content => {\n if (content.type === 'product_list') {\n const productListContent = content as ProductListContent\n productListContent.data.products.forEach(product => {\n if (product && product.handle) {\n productMap.set(product.handle, product)\n }\n })\n }\n })\n\n // \u91CD\u7EC4\u6D88\u606F\u5185\u5BB9\n const reorganizedContent = reorganizeMessageContent(message.content, productMap, rawProductMap, onAddToCart, productCardRender)\n\n // \u8FD4\u56DE\u65B0\u6D88\u606F\u5BF9\u8C61\n return {\n ...message,\n content: reorganizedContent,\n }\n}\n\nexport interface UseChatStateOptions {\n /**\n * \u521D\u59CB\u6B22\u8FCE\u6D88\u606F\n */\n welcomeMessage?: string\n\n /**\n * Shopify \u5E97\u94FA\u57DF\u540D\n */\n site?: string\n\n /**\n * \u53D7\u63A7\u6A21\u5F0F\uFF1A\u662F\u5426\u6253\u5F00\u804A\u5929\u7A97\u53E3\n * \u63D0\u4F9B\u6B64\u53C2\u6570\u65F6\uFF0C\u7EC4\u4EF6\u5904\u4E8E\u53D7\u63A7\u6A21\u5F0F\n */\n open?: boolean\n\n /**\n * \u53D7\u63A7\u6A21\u5F0F\uFF1A\u72B6\u6001\u53D8\u5316\u56DE\u8C03\uFF08\u5FC5\u9700\uFF09\n * \u7528\u4E8E\u540C\u6B65\u72B6\u6001\u5230\u7236\u7EC4\u4EF6\n */\n onOpenChange?: (open: boolean) => void\n\n /**\n * \u7A97\u53E3\u6253\u5F00\u4E8B\u4EF6\u76D1\u542C\uFF08\u53EF\u9009\uFF09\n * \u7528\u4E8E\u57CB\u70B9\u3001\u65E5\u5FD7\u7B49\u526F\u4F5C\u7528\n */\n onOpen?: () => void\n\n /**\n * \u7A97\u53E3\u5173\u95ED\u4E8B\u4EF6\u76D1\u542C\uFF08\u53EF\u9009\uFF09\n * \u7528\u4E8E\u57CB\u70B9\u3001\u65E5\u5FD7\u7B49\u526F\u4F5C\u7528\n */\n onClose?: () => void\n\n /**\n * \u6D88\u606F\u53D1\u9001\u56DE\u8C03\n */\n onMessageSend?: (message: string) => void\n\n /**\n * \u9519\u8BEF\u5904\u7406\u56DE\u8C03\n */\n onError?: (error: Error) => void\n\n /**\n * AI \u6D88\u606F\u56DE\u8C03\n */\n /**\n * AI \u56DE\u590D\u6587\u672C\u6D88\u606F\u65F6\u89E6\u53D1\n */\n onTextMessage?: () => void\n\n /**\n * AI \u56DE\u590D\u5546\u54C1\u5217\u8868\u5361\u7247\u65F6\u89E6\u53D1\n */\n onProductList?: () => void\n\n /**\n * AI \u56DE\u590D\u4FC3\u9500\u5361\u7247\u65F6\u89E6\u53D1\n * @param promotions \u4FC3\u9500\u6D3B\u52A8\u6570\u7EC4\u6570\u636E\n */\n onPromotionList?: (promotions: any[]) => void\n\n /**\n * \u5546\u54C1\u6DFB\u52A0\u5230\u8D2D\u7269\u8F66\u56DE\u8C03\n */\n onAddToCart?: (product: any) => void\n\n /**\n * \u8D2D\u7269\u8F66\u6309\u94AE\u70B9\u51FB\u56DE\u8C03\n */\n onCart?: (cartId: string, checkoutUrl?: string) => void\n\n /**\n * \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @param product \u4EA7\u54C1\u6570\u636E\uFF08\u5982\u679C\u5728 product_list \u4E2D\u627E\u5230\uFF09\uFF0C\u5426\u5219\u4E3A undefined\n * @param productHandle \u6587\u672C\u5360\u4F4D\u7B26\u4E2D\u7684\u4EA7\u54C1 ID\uFF0C\u53EF\u7528\u4E8E\u5E94\u7528\u5C42\u67E5\u8BE2\u4EA7\u54C1\u6570\u636E\n */\n productCardRender?: (product: any, productHandle: string) => React.ReactNode\n\n /**\n * \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5BF9\u6BD4\u5361\u7247\u6E32\u67D3\u51FD\u6570\n * @param data \u4EA7\u54C1\u5BF9\u6BD4\u6570\u636E\uFF08\u5305\u542B products \u548C dimensions\uFF09\n */\n productComparisonRender?: (data: any) => React.ReactNode\n}\n\nexport interface UseChatStateReturn {\n /**\n * \u6D88\u606F\u5217\u8868\n */\n messages: Message[]\n\n /**\n * \u804A\u5929\u7A97\u53E3\u662F\u5426\u6253\u5F00\n */\n isOpen: boolean\n\n /**\n * \u7528\u6237 ID\uFF08undefined \u8868\u793A\u5C1A\u672A\u521D\u59CB\u5316\uFF0C\u7A7A\u5B57\u7B26\u4E32\u8868\u793A\u7531\u540E\u7AEF\u751F\u6210\uFF09\n */\n userId: string | undefined\n\n /**\n * \u4F1A\u8BDD ID\n */\n sessionId: string | null\n\n /**\n * \u8F93\u5165\u6846\u5185\u5BB9\n */\n inputValue: string\n\n /**\n * \u662F\u5426\u6B63\u5728\u63A5\u6536\u6D41\u5F0F\u6D88\u606F\n */\n isStreaming: boolean\n\n /**\n * \u6253\u5F00\u804A\u5929\u7A97\u53E3\n */\n openChat: () => void\n\n /**\n * \u5173\u95ED\u804A\u5929\u7A97\u53E3\n */\n closeChat: () => void\n\n /**\n * \u5207\u6362\u804A\u5929\u7A97\u53E3\u72B6\u6001\n */\n toggleChat: () => void\n\n /**\n * \u8BBE\u7F6E\u8F93\u5165\u6846\u5185\u5BB9\n */\n setInputValue: (value: string) => void\n\n /**\n * \u8BBE\u7F6E\u7528\u6237 ID\uFF08\u7528\u4E8E\u4FDD\u5B58\u540E\u7AEF\u8FD4\u56DE\u7684 userId\uFF09\n */\n setUserId: (id: string) => void\n\n /**\n * \u6DFB\u52A0\u6D88\u606F\u5230\u5217\u8868\n */\n addMessage: (message: Message) => void\n\n /**\n * \u6279\u91CF\u8BBE\u7F6E\u6D88\u606F\u5217\u8868\uFF08\u7528\u4E8E\u52A0\u8F7D\u5386\u53F2\uFF09\n */\n setMessages: (messages: Message[]) => void\n\n /**\n * \u6E05\u7A7A\u6D88\u606F\u5217\u8868\n */\n clearMessages: () => void\n\n /**\n * \u5904\u7406 SSE \u4E8B\u4EF6\n */\n handleSSEEvent: (event: SSEEvent) => void\n\n /**\n * \u5F00\u59CB\u65B0\u7684 stream \u4F1A\u8BDD\uFF0C\u8FD4\u56DE\u7ED1\u5B9A\u4E86\u5F53\u524D streamId \u7684\u4E8B\u4EF6\u5904\u7406\u5668\u3002\n * \u8C03\u7528\u6B64\u65B9\u6CD5\u4F1A\u4F7F\u4E4B\u524D\u6240\u6709 stream \u7684\u4E8B\u4EF6\u5904\u7406\u5668\u5931\u6548\uFF0C\u9632\u6B62\u5E76\u53D1 stream \u6C61\u67D3\u5171\u4EAB buffer\u3002\n */\n startStream: () => (event: SSEEvent) => void\n\n /**\n * \u4FDD\u5B58\u4F1A\u8BDD ID\n */\n saveSession: (id: string) => void\n\n /**\n * \u6E05\u7A7A\u4F1A\u8BDD\n */\n clearSession: () => void\n}\n\n/**\n * \u804A\u5929\u72B6\u6001\u7BA1\u7406 Hook\n *\n * \u529F\u80FD\uFF1A\n * 1. \u7BA1\u7406\u6D88\u606F\u5217\u8868\uFF08\u6DFB\u52A0\u3001\u6E05\u7A7A\u3001\u6279\u91CF\u8BBE\u7F6E\uFF09\n * 2. \u7BA1\u7406\u7A97\u53E3\u72B6\u6001\uFF08\u6253\u5F00\u3001\u5173\u95ED\u3001\u5207\u6362\uFF09\n * 3. \u7BA1\u7406\u8F93\u5165\u6846\u72B6\u6001\n * 4. \u5904\u7406 SSE \u6D41\u5F0F\u6D88\u606F\u4E8B\u4EF6\n * 5. \u7D2F\u79EF\u6D41\u5F0F\u6587\u672C\u5185\u5BB9\n *\n * @param options Hook \u914D\u7F6E\u9009\u9879\n * @returns \u72B6\u6001\u7BA1\u7406\u5DE5\u5177\u5BF9\u8C61\n */\nexport function useChatState(options: UseChatStateOptions = {}): UseChatStateReturn {\n const {\n welcomeMessage,\n site,\n open: controlledOpen,\n onOpenChange,\n onOpen,\n onClose,\n onMessageSend,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n productCardRender,\n productComparisonRender,\n } = options\n\n // \u4F1A\u8BDD\u7BA1\u7406\n const { sessionId, saveSession, clearSession } = useSession()\n\n // \u7528\u6237 ID (\u521D\u59CB\u5316\u65F6\u5F02\u6B65\u751F\u6210\uFF0Cundefined \u8868\u793A\u5C1A\u672A\u521D\u59CB\u5316)\n const [userId, setUserId] = useState<string | undefined>(undefined)\n\n // \u521D\u59CB\u5316 userId\n useEffect(() => {\n getUserId().then(id => setUserId(id))\n }, [])\n\n // \u6D88\u606F\u5217\u8868\n const [messages, setMessagesState] = useState<Message[]>(() => {\n // \u5982\u679C\u6709\u6B22\u8FCE\u6D88\u606F\uFF0C\u521D\u59CB\u5316\u65F6\u6DFB\u52A0\n if (welcomeMessage) {\n return [\n {\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: [{ type: 'text', text: welcomeMessage }],\n timestamp: Date.now(),\n },\n ]\n }\n return []\n })\n\n // \u804A\u5929\u7A97\u53E3\u662F\u5426\u6253\u5F00\uFF08\u652F\u6301\u53D7\u63A7\u548C\u975E\u53D7\u63A7\u4E24\u79CD\u6A21\u5F0F\uFF09\n const [internalOpen, setInternalOpen] = useState(false)\n const isControlled = controlledOpen !== undefined\n const isOpen = isControlled ? controlledOpen : internalOpen\n\n // \u8F93\u5165\u6846\u5185\u5BB9\n const [inputValue, setInputValue] = useState('')\n\n // \u662F\u5426\u6B63\u5728\u63A5\u6536\u6D41\u5F0F\u6D88\u606F\n const [isStreaming, setIsStreaming] = useState(false)\n\n // \u5F53\u524D\u6B63\u5728\u7D2F\u79EF\u7684\u6D41\u5F0F\u6D88\u606F (\u4E34\u65F6\u5B58\u50A8)\n const currentMessageRef = useRef<Message | null>(null)\n\n // \u6807\u8BB0\u5F53\u524D\u6D88\u606F\u662F\u5426\u5DF2\u89E6\u53D1 onTextMessage \u56DE\u8C03\uFF08\u907F\u514D\u91CD\u590D\u89E6\u53D1\uFF09\n const textMessageCallbackTriggeredRef = useRef<boolean>(false)\n\n // \u4EA7\u54C1\u6620\u5C04\u7F13\u5B58 (handle \u2192 Product)\uFF0C\u7528\u4E8E\u5B9E\u65F6\u89E3\u6790\u5360\u4F4D\u7B26\n const productMapRef = useRef<Map<string, Product>>(new Map())\n\n // \u539F\u59CB\u4EA7\u54C1\u6570\u636E\u7F13\u5B58 (handle \u2192 raw backend product)\uFF0C\u7528\u4E8E productCardRender\n const rawProductMapRef = useRef<Map<string, any>>(new Map())\n\n // \u6587\u672C\u7F13\u51B2\u533A\uFF0C\u7528\u4E8E\u5B58\u50A8\u672A\u5B8C\u6210\u7684\u6587\u672C\uFF08\u5904\u7406\u5360\u4F4D\u7B26\u8DE8\u8D8A\u591A\u4E2A delta \u7684\u60C5\u51B5\uFF09\n const textBufferRef = useRef<string>('')\n\n // \u5361\u7247\u7F13\u5B58\u961F\u5217\uFF0C\u7528\u4E8E\u5B58\u50A8\u9700\u8981\u5EF6\u8FDF\u663E\u793A\u7684\u5361\u7247\uFF08\u5728\u6587\u672C\u5B8C\u6210\u540E\u663E\u793A\uFF09\n const pendingCardsRef = useRef<MessageContent[]>([])\n\n // \u5F53\u524D\u6D3B\u8DC3 stream \u7684\u552F\u4E00 ID\uFF0C\u7528\u4E8E\u4E22\u5F03\u8FC7\u671F stream \u7684\u4E8B\u4EF6\uFF0C\u9632\u6B62\u5E76\u53D1 stream \u5171\u4EAB buffer\n const activeStreamIdRef = useRef<string | null>(null)\n\n /**\n * \u6253\u5F00\u804A\u5929\u7A97\u53E3\n */\n const openChat = useCallback(() => {\n if (!isControlled) {\n setInternalOpen(true)\n }\n onOpenChange?.(true)\n onOpen?.()\n }, [isControlled, onOpenChange, onOpen])\n\n /**\n * \u5173\u95ED\u804A\u5929\u7A97\u53E3\n */\n const closeChat = useCallback(() => {\n if (!isControlled) {\n setInternalOpen(false)\n }\n onOpenChange?.(false)\n onClose?.()\n }, [isControlled, onOpenChange, onClose])\n\n /**\n * \u5207\u6362\u804A\u5929\u7A97\u53E3\u72B6\u6001\n */\n const toggleChat = useCallback(() => {\n const newState = !isOpen\n if (!isControlled) {\n setInternalOpen(newState)\n }\n onOpenChange?.(newState)\n if (newState) {\n onOpen?.()\n } else {\n onClose?.()\n }\n }, [isControlled, isOpen, onOpenChange, onOpen, onClose])\n\n /**\n * \u6DFB\u52A0\u6D88\u606F\u5230\u5217\u8868\n */\n const addMessage = useCallback((message: Message) => {\n // \u9632\u62A4\uFF1A\u5982\u679C\u6D88\u606F\u4E3A null \u6216 undefined\uFF0C\u4E0D\u6DFB\u52A0\n if (!message) {\n console.warn('[useChatState] Attempted to add null/undefined message')\n return\n }\n setMessagesState(prev => [...prev, message])\n }, [])\n\n /**\n * \u6279\u91CF\u8BBE\u7F6E\u6D88\u606F\u5217\u8868\uFF08\u7528\u4E8E\u52A0\u8F7D\u5386\u53F2\uFF09\n */\n const setMessages = useCallback(\n (newMessages: Message[]) => {\n // \u9632\u62A4\uFF1A\u8FC7\u6EE4\u6389 null/undefined \u6D88\u606F\n const validMessages = newMessages.filter(msg => msg != null)\n if (validMessages.length !== newMessages.length) {\n console.warn('[useChatState] Filtered out null/undefined messages from batch set')\n }\n\n // \u5BF9\u6BCF\u6761\u5386\u53F2\u6D88\u606F\u8FDB\u884C\u91CD\u7EC4\uFF08\u5982\u679C\u9700\u8981\uFF09\n const reorganizedMessages = validMessages.map(msg => maybeReorganizeHistoricalMessage(msg, onAddToCart, productCardRender))\n\n setMessagesState(reorganizedMessages)\n },\n [onAddToCart, productCardRender]\n )\n\n /**\n * \u6E05\u7A7A\u6D88\u606F\u5217\u8868\n */\n const clearMessages = useCallback(() => {\n setMessagesState([])\n }, [])\n\n /**\n * \u5904\u7406 SSE \u4E8B\u4EF6\n * \u6839\u636E\u4E8B\u4EF6\u7C7B\u578B\u8FDB\u884C\u4E0D\u540C\u7684\u5904\u7406\n */\n const handleSSEEvent = useCallback(\n (event: SSEEvent, streamId?: string) => {\n const { event: eventType, data } = event\n\n // \u5E76\u53D1 stream \u9632\u62A4\uFF1A\u9664 message_start \u5916\u7684\u6240\u6709\u4E8B\u4EF6\u5FC5\u987B\u5339\u914D\u5F53\u524D\u6D3B\u8DC3 streamId\n if (eventType !== 'message_start' && streamId !== activeStreamIdRef.current) {\n return\n }\n\n switch (eventType) {\n case 'message_start': {\n setIsStreaming(true)\n\n textMessageCallbackTriggeredRef.current = false\n textBufferRef.current = ''\n pendingCardsRef.current = []\n\n // T039: \u4FDD\u5B58 sessionId \u548C userId\uFF08\u5982\u679C\u540E\u7AEF\u8FD4\u56DE\uFF09\n const messageStartData = data as MessageStartData & { userId?: string }\n if (messageStartData.sessionId && messageStartData.sessionId !== sessionId) {\n saveSession(messageStartData.sessionId)\n }\n // \u4FDD\u5B58\u540E\u7AEF\u8FD4\u56DE\u7684 userId\uFF08\u5982\u679C\u6709\uFF09\n if (messageStartData.userId) {\n saveUserId(messageStartData.userId)\n setUserId(messageStartData.userId)\n }\n\n // \u68C0\u67E5\u6700\u540E\u4E00\u6761\u6D88\u606F\u662F\u5426\u662F thinking \u6D88\u606F\uFF08\u7528\u6237\u53D1\u9001\u6D88\u606F\u65F6\u5DF2\u6DFB\u52A0\uFF09\n setMessagesState(prev => {\n const lastMessage = prev[prev.length - 1]\n const hasThinking =\n lastMessage &&\n lastMessage.role === 'assistant' &&\n lastMessage.content.length === 1 &&\n lastMessage.content[0].type === 'thinking'\n\n if (hasThinking) {\n // \u590D\u7528\u5DF2\u5B58\u5728\u7684 thinking \u6D88\u606F\n currentMessageRef.current = lastMessage\n return prev // \u4E0D\u9700\u8981\u6DFB\u52A0\u65B0\u6D88\u606F\n } else {\n // \u6CA1\u6709 thinking \u6D88\u606F\uFF0C\u521B\u5EFA\u65B0\u7684\uFF08\u517C\u5BB9\u5176\u4ED6\u573A\u666F\uFF09\n const messageId = `msg-${Date.now()}`\n currentMessageRef.current = {\n id: messageId,\n role: 'assistant',\n content: [{ type: 'thinking', data: { status: 'thinking' } }],\n timestamp: Date.now(),\n }\n return [...prev, currentMessageRef.current!]\n }\n })\n break\n }\n\n case 'content_delta': {\n // \u7D2F\u79EF\u6D41\u5F0F\u6587\u672C\u5185\u5BB9\uFF0C\u5E76\u5B9E\u65F6\u68C0\u6D4B\u4EA7\u54C1\u5360\u4F4D\u7B26\n const deltaData = data as any\n const deltaText = deltaData.delta || deltaData.text || ''\n\n if (currentMessageRef.current && deltaText) {\n // \u89E6\u53D1\u6587\u672C\u6D88\u606F\u56DE\u8C03\uFF08\u4EC5\u89E6\u53D1\u4E00\u6B21\uFF09\n if (!textMessageCallbackTriggeredRef.current) {\n textMessageCallbackTriggeredRef.current = true\n onTextMessage?.()\n }\n\n // \u79FB\u9664\u601D\u8003\u6C14\u6CE1\uFF08\u5982\u679C\u5B58\u5728\uFF09\n const hasThinking = currentMessageRef.current.content.some(c => c.type === 'thinking')\n if (hasThinking) {\n currentMessageRef.current.content = currentMessageRef.current.content.filter(c => c.type !== 'thinking')\n }\n\n // \u5C06\u65B0\u6587\u672C\u6DFB\u52A0\u5230\u7F13\u51B2\u533A\n textBufferRef.current += deltaText\n\n // \u5B9E\u65F6\u89E3\u6790\u7F13\u51B2\u533A\u4E2D\u7684\u5360\u4F4D\u7B26\n const { contents, remainingBuffer } = parseStreamingText(\n textBufferRef.current,\n productMapRef.current,\n rawProductMapRef.current,\n onAddToCart,\n productCardRender\n )\n\n // \u66F4\u65B0\u7F13\u51B2\u533A\u4E3A\u5269\u4F59\u5185\u5BB9\n textBufferRef.current = remainingBuffer\n\n // \u5C06\u89E3\u6790\u51FA\u7684\u5185\u5BB9\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\n if (contents.length > 0) {\n contents.forEach(content => {\n const lastContent = currentMessageRef.current!.content[\n currentMessageRef.current!.content.length - 1\n ] as MessageContent | undefined\n\n // \u5982\u679C\u662F\u6587\u672C\u5185\u5BB9\u4E14\u6700\u540E\u4E00\u4E2A\u4E5F\u662F\u6587\u672C\uFF0C\u5219\u5408\u5E76\n if (content.type === 'text' && lastContent && lastContent.type === 'text') {\n lastContent.text += content.text\n } else {\n // \u5426\u5219\u6DFB\u52A0\u65B0\u5185\u5BB9\n currentMessageRef.current!.content.push(content)\n }\n })\n\n // \u66F4\u65B0\u6D88\u606F\u5217\u8868\u4EE5\u89E6\u53D1\u6E32\u67D3\n setMessagesState(prev => {\n if (!currentMessageRef.current) return prev\n\n const updated = [...prev]\n const existingIndex = updated.findIndex(m => m && m.id === currentMessageRef.current!.id)\n\n if (existingIndex >= 0) {\n updated[existingIndex] = { ...currentMessageRef.current! }\n } else {\n updated.push({ ...currentMessageRef.current! })\n }\n\n return updated\n })\n }\n }\n break\n }\n\n case 'content_block': {\n // \u63A5\u6536\u7ED3\u6784\u5316\u5185\u5BB9\u5757\uFF08\u5546\u54C1\u3001\u653F\u7B56\u7B49\uFF09\n // API \u8FD4\u56DE\u683C\u5F0F\u53D8\u66F4:\n // \u65B0\u683C\u5F0F: {index: number, type: string, data: {...}} <- type \u5728\u5916\u5C42\n // \u65E7\u683C\u5F0F: {index: number, data: {type: string, ...}} <- type \u5728 data \u5185\n const blockData = data as any\n if (currentMessageRef.current) {\n // \u83B7\u53D6 type \u548C data\n // \u4F18\u5148\u4ECE\u5916\u5C42\u83B7\u53D6 type\uFF0C\u517C\u5BB9\u65E7\u683C\u5F0F\u4ECE data \u5185\u83B7\u53D6\n const contentType = blockData.type || blockData.data?.type\n const contentData = blockData.data\n\n if (!contentType || !contentData) {\n console.warn('[useChatState] Invalid content_block:', blockData)\n break\n }\n\n // ============================================================\n // \u8F6C\u6362\u6570\u636E\u7ED3\u6784\u4EE5\u5339\u914D\u7C7B\u578B\u5B9A\u4E49\n // \u6839\u636E\u540E\u7AEF\u6570\u636E\u7ED3\u6784\u89C4\u8303\uFF08\u98DE\u4E66\u6587\u6863\uFF09\u8FDB\u884C\u8F6C\u6362\n // ============================================================\n let messageContent: MessageContent\n\n // ========== 1. \u4EA7\u54C1\u5217\u8868\u5361\u7247 (Product List) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"product_list\", data: [product1, product2, ...]}\n // data \u76F4\u63A5\u662F\u4EA7\u54C1\u6570\u7EC4\uFF0C\u4E0D\u662F {products: [...]}\n if (contentType === 'product_list' && Array.isArray(contentData)) {\n // \u89E6\u53D1\u5546\u54C1\u5217\u8868\u56DE\u8C03\n onProductList?.()\n\n // \u7F13\u5B58\u539F\u59CB\u540E\u7AEF\u4EA7\u54C1\u6570\u636E\uFF08\u7528\u4E8E productCardRender\uFF09\n // \u4F7F\u7528 handle \u4F5C\u4E3A key \u8FDB\u884C\u5339\u914D\n contentData.forEach((rawProduct: any) => {\n if (rawProduct && rawProduct.handle) {\n rawProductMapRef.current.set(rawProduct.handle, rawProduct)\n console.log('[useChatState] \u7F13\u5B58\u539F\u59CB\u4EA7\u54C1\u6570\u636E, handle:', rawProduct.handle)\n }\n })\n\n // \u4F7F\u7528\u7EDF\u4E00\u7684\u4EA7\u54C1\u8F6C\u6362\u5DE5\u5177\u51FD\u6570\n const transformedProducts = transformProducts(contentData, site)\n\n // \u5EFA\u7ACB\u4EA7\u54C1\u6620\u5C04\u7F13\u5B58 (handle \u2192 Product)\n // \u7528\u4E8E\u540E\u7EED\u5728 message_end \u65F6\u89E3\u6790\u6587\u672C\u4E2D\u7684 {{handle}}\n transformedProducts.forEach(product => {\n if (product && product.handle) {\n productMapRef.current.set(product.handle, product)\n\n console.log('[useChatState] \u5EFA\u7ACB\u4EA7\u54C1\u6620\u5C04:', {\n handle: product.handle,\n title: product.title,\n })\n }\n })\n\n // \u26A0\uFE0F \u4E0D\u8981\u628A product_list \u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\uFF0C\u907F\u514D\u95EA\u70C1\n // \u7B49\u5230 message_end \u65F6\uFF0C\u901A\u8FC7\u6587\u672C\u89E3\u6790\u521B\u5EFA product_card\uFF0C\u76F4\u63A5\u663E\u793A\u6700\u7EC8\u7684\u4EA4\u66FF\u683C\u5F0F\n console.log('[useChatState] \u2705 \u4EA7\u54C1\u5217\u8868\u5DF2\u7F13\u5B58\uFF0C\u4E0D\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\uFF08\u907F\u514D\u95EA\u70C1\uFF09')\n break // \u76F4\u63A5\u8DF3\u51FA\uFF0C\u4E0D\u6267\u884C\u540E\u7EED\u7684 push \u64CD\u4F5C\n }\n // ========== 2. \u4EA7\u54C1\u5BF9\u6BD4\u5361\u7247 (Product Comparison) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"product_comparison\", data: {products: [...], dimensions: {...}}}\n else if (contentType === 'product_comparison' && contentData.products) {\n // \u4F7F\u7528\u7EDF\u4E00\u7684\u4EA7\u54C1\u8F6C\u6362\u5DE5\u5177\u51FD\u6570\n const transformedProducts = transformProducts(contentData.products, site)\n\n messageContent = {\n type: 'product_comparison',\n data: {\n products: transformedProducts,\n dimensions: contentData.dimensions || {},\n productComparisonRender: productComparisonRender,\n },\n } as MessageContent\n }\n // ========== 3. FAQ \u5217\u8868\u5361\u7247 (FAQ List) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"faq_list\", data: {found, count, total, results: [...]}}\n else if (contentType === 'faq_list' && contentData.found !== undefined) {\n messageContent = {\n type: 'faq_list',\n data: contentData, // \u76F4\u63A5\u4F7F\u7528\uFF0C\u7ED3\u6784\u5DF2\u5339\u914D\n } as MessageContent\n }\n // ========== 4. \u5FEB\u6377\u56DE\u590D (Quick Replies) ==========\n else if (contentType === 'quick_replies' && contentData.replies) {\n messageContent = {\n type: 'quick_replies',\n data: {\n replies: contentData.replies,\n },\n } as MessageContent\n }\n // ========== 5. \u653F\u7B56\u5185\u5BB9 (Policy) ==========\n else if (contentType === 'policy' && contentData.title && contentData.content) {\n messageContent = {\n type: 'policy',\n data: {\n title: contentData.title,\n content: contentData.content,\n },\n } as MessageContent\n }\n // ========== 6. \u4FC3\u9500\u6D3B\u52A8\u5217\u8868 (Promotion List) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"promotion_list\", data: {found, count, total, results: [...]}}\n else if (contentType === 'promotion_list' && contentData.found !== undefined) {\n // \u89E6\u53D1\u4FC3\u9500\u5361\u7247\u56DE\u8C03\uFF0C\u4F20\u9012\u4FC3\u9500\u6D3B\u52A8\u6570\u7EC4\n onPromotionList?.(contentData.results || [])\n\n messageContent = {\n type: 'promotion_list',\n data: contentData, // \u76F4\u63A5\u4F7F\u7528\uFF0C\u7ED3\u6784\u5DF2\u5339\u914D\n } as MessageContent\n }\n // ========== 7. \u8D2D\u7269\u8F66 (Cart) ==========\n // \u540E\u7AEF\u683C\u5F0F: {type: \"cart\", data: {id, lines: {edges: [...]}, cost, ...}} (Shopify GraphQL)\n // \u9700\u8981\u8F6C\u6362\u4E3A\u524D\u7AEF\u683C\u5F0F: {cartId, lines: [...], cost, ...}\n else if (contentType === 'cart' && contentData.id !== undefined) {\n // \u8F6C\u6362\u540E\u7AEF Shopify GraphQL \u683C\u5F0F\u4E3A\u524D\u7AEF\u6807\u51C6\u683C\u5F0F\n const transformedData = transformCartData(contentData as BackendCartData)\n messageContent = {\n type: 'cart',\n data: {\n ...transformedData,\n onCart: onCart, // \u6CE8\u5165\u8D2D\u7269\u8F66\u6309\u94AE\u56DE\u8C03\n },\n } as MessageContent\n }\n // ========== 8. \u5176\u4ED6\u7C7B\u578B\uFF08\u901A\u7528\u5904\u7406\uFF09 ==========\n else {\n messageContent = {\n type: contentType,\n data: contentData,\n } as MessageContent\n }\n\n // \u26A0\uFE0F \u91CD\u8981\u4FEE\u6539\uFF1A\u5C06\u5361\u7247\u7F13\u5B58\u8D77\u6765\uFF0C\u4E0D\u7ACB\u5373\u6DFB\u52A0\u5230\u6D88\u606F\u4E2D\n // \u7B49\u5F85 message_end \u65F6\uFF0C\u5728\u6587\u672C\u5B8C\u6210\u540E\u518D\u7EDF\u4E00\u6DFB\u52A0\u5361\u7247\n console.log('[useChatState] \u2705 \u5361\u7247\u5DF2\u7F13\u5B58\uFF0C\u7B49\u5F85\u6587\u672C\u5B8C\u6210\u540E\u663E\u793A:', contentType)\n pendingCardsRef.current.push(messageContent)\n\n // \u4E0D\u518D\u7ACB\u5373\u66F4\u65B0\u6D88\u606F\u5217\u8868\uFF0C\u907F\u514D\u5361\u7247\u5728\u6587\u672C\u4E4B\u524D\u663E\u793A\n // \u539F\u6765\u7684\u4EE3\u7801\uFF1A\n // currentMessageRef.current.content.push(messageContent)\n // setMessagesState(prev => { ... })\n }\n break\n }\n\n case 'tool_start':\n case 'tool_end': {\n // \u5DE5\u5177\u8C03\u7528\u4E8B\u4EF6\uFF0C\u6682\u65F6\u5FFD\u7565\n // \u53EF\u4EE5\u5728\u672A\u6765\u7528\u4E8E\u663E\u793A\u5DE5\u5177\u8C03\u7528\u72B6\u6001\n break\n }\n\n case 'message_end': {\n // \u6D88\u606F\u63A5\u6536\u5B8C\u6210\n setIsStreaming(false)\n\n // \u5904\u7406\u7F13\u51B2\u533A\u4E2D\u5269\u4F59\u7684\u6587\u672C\uFF08\u5982\u679C\u6709\uFF09\n if (currentMessageRef.current && textBufferRef.current) {\n console.log('[useChatState] \u5904\u7406\u5269\u4F59\u7F13\u51B2\u533A:', textBufferRef.current)\n\n const lastContent = currentMessageRef.current.content[\n currentMessageRef.current.content.length - 1\n ] as MessageContent | undefined\n\n // \u5982\u679C\u6700\u540E\u4E00\u4E2A\u5185\u5BB9\u662F\u6587\u672C\uFF0C\u5219\u5408\u5E76\n if (lastContent && lastContent.type === 'text') {\n lastContent.text += textBufferRef.current\n } else {\n // \u5426\u5219\u6DFB\u52A0\u4E3A\u65B0\u7684\u6587\u672C\u5757\n currentMessageRef.current.content.push({\n type: 'text',\n text: textBufferRef.current,\n })\n }\n }\n\n // \u26A0\uFE0F \u91CD\u8981\u4FEE\u6539\uFF1A\u5728\u6587\u672C\u5B8C\u6210\u540E\uFF0C\u6DFB\u52A0\u6240\u6709\u7F13\u5B58\u7684\u5361\u7247\n if (currentMessageRef.current && pendingCardsRef.current.length > 0) {\n console.log('[useChatState] \uD83D\uDCCB \u6587\u672C\u5DF2\u5B8C\u6210\uFF0C\u73B0\u5728\u6DFB\u52A0', pendingCardsRef.current.length, '\u4E2A\u7F13\u5B58\u7684\u5361\u7247')\n\n // \u5C06\u6240\u6709\u7F13\u5B58\u7684\u5361\u7247\u6DFB\u52A0\u5230\u6D88\u606F\u5185\u5BB9\u4E2D\n currentMessageRef.current.content.push(...pendingCardsRef.current)\n }\n\n // \u26A0\uFE0F \u8D85\u65F6\u68C0\u6D4B\uFF1A\u5982\u679C message_end \u65F6\u4ECD\u5B58\u5728 thinking block\uFF0C\u89C6\u4E3A\u8D85\u65F6/\u5F02\u5E38\n // \u6CE8\u610F\uFF1A\u5728\u6DFB\u52A0\u5361\u7247\u4E4B\u540E\u68C0\u6D4B\uFF0C\u8FD9\u6837\u5982\u679C\u6709\u5361\u7247\u5C31\u4E0D\u4F1A\u6DFB\u52A0\u8D85\u65F6\u63D0\u793A\n if (currentMessageRef.current) {\n const hasThinking = currentMessageRef.current.content.some(c => c.type === 'thinking')\n\n if (hasThinking) {\n console.log('[useChatState] \u26A0\uFE0F message_end \u65F6\u4ECD\u5B58\u5728 thinking block\uFF0C\u7ACB\u5373\u79FB\u9664\uFF08\u89C6\u4E3A\u8D85\u65F6\uFF09')\n\n // \u79FB\u9664 thinking block\n currentMessageRef.current.content = currentMessageRef.current.content.filter(c => c.type !== 'thinking')\n\n // \u5982\u679C\u6CA1\u6709\u5176\u4ED6\u5185\u5BB9\uFF08\u5305\u62EC\u7F13\u5B58\u7684\u5361\u7247\uFF09\uFF0C\u6DFB\u52A0\u8D85\u65F6\u63D0\u793A\n if (currentMessageRef.current.content.length === 0) {\n currentMessageRef.current.content.push({\n type: 'text',\n text: 'Response timed out, please try again.',\n } as TextContent)\n }\n }\n }\n\n // \u66F4\u65B0\u6D88\u606F\u5217\u8868\uFF08\u7EDF\u4E00\u66F4\u65B0\uFF0C\u5305\u542B\u6587\u672C\u548C\u5361\u7247\uFF09\n if (currentMessageRef.current) {\n setMessagesState(prev => {\n if (!currentMessageRef.current) return prev\n\n const updated = [...prev]\n const existingIndex = updated.findIndex(m => m && m.id === currentMessageRef.current!.id)\n\n if (existingIndex >= 0) {\n updated[existingIndex] = { ...currentMessageRef.current! }\n }\n\n return updated\n })\n }\n\n // \u6E05\u7A7A\u7F13\u51B2\u533A\u3001\u4EA7\u54C1\u6620\u5C04\u548C\u5361\u7247\u7F13\u5B58\n textBufferRef.current = ''\n pendingCardsRef.current = []\n productMapRef.current.clear()\n rawProductMapRef.current.clear()\n currentMessageRef.current = null\n break\n }\n\n case 'status': {\n // T040: \u72B6\u6001\u66F4\u65B0\uFF08\u5982\u4F1A\u8BDD\u8FC7\u671F\uFF09\n const statusData = data as StatusData\n if (statusData.type === 'session_expired') {\n // \u4F1A\u8BDD\u8FC7\u671F\uFF0C\u6E05\u7A7A\u6D88\u606F\u5217\u8868\u548C\u4F1A\u8BDD\n clearMessages()\n clearSession()\n if (welcomeMessage) {\n addMessage({\n id: `welcome-${Date.now()}`,\n role: 'assistant',\n content: [{ type: 'text', text: welcomeMessage }],\n timestamp: Date.now(),\n })\n }\n }\n break\n }\n\n case 'error': {\n // \u9519\u8BEF\u5904\u7406\n const errorData = data as ErrorData\n setIsStreaming(false)\n\n // \u6E05\u7406\u7F13\u5B58\uFF08\u9632\u6B62\u6CC4\u6F0F\u5230\u4E0B\u6B21\u6D88\u606F\uFF09\n textBufferRef.current = ''\n pendingCardsRef.current = []\n productMapRef.current.clear()\n rawProductMapRef.current.clear()\n currentMessageRef.current = null\n\n // \u6DFB\u52A0\u9519\u8BEF\u6D88\u606F\u5230\u754C\u9762\n addMessage({\n id: `error-${Date.now()}`,\n role: 'system',\n content: [\n {\n type: 'error',\n data: {\n message: errorData.message,\n code: errorData.code,\n },\n },\n ],\n timestamp: Date.now(),\n })\n\n onError?.(new Error(errorData.message))\n break\n }\n\n case 'done': {\n // \u6D41\u7ED3\u675F\n setIsStreaming(false)\n\n // \u6E05\u7406\u7F13\u5B58\uFF08\u9632\u6B62\u6CC4\u6F0F\u5230\u4E0B\u6B21\u6D88\u606F\uFF09\n textBufferRef.current = ''\n pendingCardsRef.current = []\n productMapRef.current.clear()\n rawProductMapRef.current.clear()\n\n // \u6E05\u7406\u5F53\u524D\u6D88\u606F\u5F15\u7528\n currentMessageRef.current = null\n break\n }\n\n default:\n // \u5176\u4ED6\u4E8B\u4EF6\u7C7B\u578B\uFF08tool_start, tool_end \u7B49\uFF09\n break\n }\n },\n [\n welcomeMessage,\n site,\n addMessage,\n clearMessages,\n clearSession,\n saveSession,\n sessionId,\n onError,\n onTextMessage,\n onProductList,\n onPromotionList,\n onAddToCart,\n onCart,\n ]\n )\n\n\n const startStream = useCallback((): ((event: SSEEvent) => void) => {\n const streamId = `stream-${Date.now()}-${Math.random().toString(36).slice(2)}`\n activeStreamIdRef.current = streamId\n textBufferRef.current = ''\n pendingCardsRef.current = []\n productMapRef.current.clear()\n rawProductMapRef.current.clear()\n currentMessageRef.current = null\n return (event: SSEEvent) => handleSSEEvent(event, streamId)\n }, [handleSSEEvent])\n\n return {\n messages,\n isOpen,\n userId,\n sessionId,\n inputValue,\n isStreaming,\n openChat,\n closeChat,\n toggleChat,\n setInputValue,\n setUserId,\n addMessage,\n setMessages,\n clearMessages,\n handleSSEEvent,\n startStream,\n saveSession,\n clearSession,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["useChatState_exports", "__export", "useChatState", "__toCommonJS", "import_react", "import_userId", "import_useSession", "import_productTransformers", "import_cartTransformers", "parseStreamingText", "buffer", "productMap", "rawProductMap", "onAddToCart", "productCardRender", "contents", "regex", "lastIndex", "match", "foundMatch", "beforeText", "productId", "product", "rawProduct", "remainingBuffer", "incompleteMatch", "completeText", "parseTextWithProductIds", "text", "result", "remainingText", "reorganizeMessageContent", "content", "segments", "maybeReorganizeHistoricalMessage", "message", "c", "structuredContent", "reorganizedContent", "options", "welcomeMessage", "site", "controlledOpen", "onOpenChange", "onOpen", "onClose", "onMessageSend", "onError", "onTextMessage", "onProductList", "onPromotionList", "onCart", "productComparisonRender", "sessionId", "saveSession", "clearSession", "userId", "setUserId", "id", "messages", "setMessagesState", "internalOpen", "setInternalOpen", "isControlled", "isOpen", "inputValue", "setInputValue", "isStreaming", "setIsStreaming", "currentMessageRef", "textMessageCallbackTriggeredRef", "productMapRef", "rawProductMapRef", "textBufferRef", "pendingCardsRef", "activeStreamIdRef", "openChat", "closeChat", "toggleChat", "newState", "addMessage", "prev", "setMessages", "newMessages", "validMessages", "msg", "reorganizedMessages", "clearMessages", "handleSSEEvent", "event", "streamId", "eventType", "data", "messageStartData", "lastMessage", "messageId", "deltaData", "deltaText", "lastContent", "updated", "existingIndex", "m", "blockData", "contentType", "contentData", "messageContent", "errorData", "startStream"]
|
|
7
7
|
}
|
|
@@ -15,12 +15,14 @@ export interface FetcherOptions {
|
|
|
15
15
|
recaptchaSitekey?: string;
|
|
16
16
|
recaptchaAction?: string;
|
|
17
17
|
recaptchaHeaderKey?: string;
|
|
18
|
+
/** 外部传入的 AbortSignal,用于提前中止请求 */
|
|
19
|
+
signal?: AbortSignal;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
22
|
* Fetcher 函数
|
|
21
23
|
* 支持 reCAPTCHA 和自定义 headers
|
|
22
24
|
*/
|
|
23
|
-
export declare const fetcher: ({ url, method, headers, body, timeout, needRecaptcha, recaptchaSitekey, recaptchaAction, recaptchaHeaderKey, }: FetcherOptions) => Promise<Response>;
|
|
25
|
+
export declare const fetcher: ({ url, method, headers, body, timeout, needRecaptcha, recaptchaSitekey, recaptchaAction, recaptchaHeaderKey, signal: externalSignal, }: FetcherOptions) => Promise<Response>;
|
|
24
26
|
/**
|
|
25
27
|
* 扩展 Window 接口以支持 grecaptcha
|
|
26
28
|
*/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var d=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var m=(t,e)=>{for(var r in e)d(t,r,{get:e[r],enumerable:!0})},v=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of y(e))!w.call(t,o)&&o!==r&&d(t,o,{get:()=>e[o],enumerable:!(n=T(e,o))||n.enumerable});return t};var C=t=>v(d({},"__esModule",{value:!0}),t);var R={};m(R,{fetcher:()=>k});module.exports=C(R);const P=async(t,e)=>{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(e,{action:t})}catch(n){return console.error("[LiveChat Fetcher] reCAPTCHA execution failed:",n),!1}};async function A(t,e,r="X-Recaptcha-Token"){const n=await P(t,e);return n?{[r]:n}:{}}const k=async({url:t,method:e="POST",headers:r={},body:n,timeout:o=9e4,needRecaptcha:u=!1,recaptchaSitekey:l,recaptchaAction:f="",recaptchaHeaderKey:b="X-Recaptcha-Token",signal:a})=>{let h={};u&&(l?h=await A(f,l,b):console.warn("[LiveChat Fetcher] needRecaptcha=true but recaptchaSitekey is missing"));const g=n?JSON.stringify(n):void 0,c=new AbortController;let i;o&&(i=setTimeout(()=>c.abort(),o));const p=()=>c.abort();a&&(a.aborted?c.abort():a.addEventListener("abort",p,{once:!0}));try{const s=await fetch(t,{method:e,mode:"cors",headers:{"Content-Type":"application/json",...r,...h},signal:c.signal,...e!=="GET"&&g&&{body:g}});return i&&clearTimeout(i),s}catch(s){throw i&&clearTimeout(i),s}finally{a?.removeEventListener("abort",p)}};
|
|
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
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,eAAAC,EAAAH,GAUA,MAAMI,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,
|
|
6
|
-
"names": ["fetcher_exports", "__export", "fetcher", "__toCommonJS", "executeRecaptcha", "action", "sitekey", "executor", "error", "getRecaptchaHeaders", "headerKey", "recaptchaToken", "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 * \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 /** \u5916\u90E8\u4F20\u5165\u7684 AbortSignal\uFF0C\u7528\u4E8E\u63D0\u524D\u4E2D\u6B62\u8BF7\u6C42 */\n signal?: AbortSignal\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 signal: externalSignal,\n}: FetcherOptions): Promise<Response> => {\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 const bodyData = body ? JSON.stringify(body) : undefined\n\n // \u5408\u5E76\u5916\u90E8 signal\uFF08\u7528\u4E8E\u624B\u52A8\u4E2D\u6B62\uFF09\u548C\u8D85\u65F6 signal\n const controller = new AbortController()\n let timeoutTimer: NodeJS.Timeout | undefined\n if (timeout) {\n timeoutTimer = setTimeout(() => controller.abort(), timeout)\n }\n // \u5982\u679C\u5916\u90E8 signal \u5DF2\u4E2D\u6B62\u6216\u5728\u8BF7\u6C42\u671F\u95F4\u4E2D\u6B62\uFF0C\u540C\u6B65\u5230\u5185\u90E8 controller\n const onExternalAbort = () => controller.abort()\n if (externalSignal) {\n if (externalSignal.aborted) {\n controller.abort()\n } else {\n externalSignal.addEventListener('abort', onExternalAbort, { once: true })\n }\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 } finally {\n externalSignal?.removeEventListener('abort', onExternalAbort)\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": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,eAAAC,EAAAH,GAUA,MAAMI,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,CAuBO,MAAMT,EAAU,MAAO,CAC5B,IAAAU,EACA,OAAAC,EAAS,OACT,QAAAC,EAAU,CAAC,EACX,KAAAC,EACA,QAAAC,EAAU,IACV,cAAAC,EAAgB,GAChB,iBAAAC,EACA,gBAAAC,EAAkB,GAClB,mBAAAC,EAAqB,oBACrB,OAAQC,CACV,IAAyC,CACvC,IAAIC,EAA2C,CAAC,EAC5CL,IACGC,EAGHI,EAAmB,MAAMb,EAAoBU,EAAiBD,EAAkBE,CAAkB,EAFlG,QAAQ,KAAK,uEAAuE,GAMxF,MAAMG,EAAWR,EAAO,KAAK,UAAUA,CAAI,EAAI,OAGzCS,EAAa,IAAI,gBACvB,IAAIC,EACAT,IACFS,EAAe,WAAW,IAAMD,EAAW,MAAM,EAAGR,CAAO,GAG7D,MAAMU,EAAkB,IAAMF,EAAW,MAAM,EAC3CH,IACEA,EAAe,QACjBG,EAAW,MAAM,EAEjBH,EAAe,iBAAiB,QAASK,EAAiB,CAAE,KAAM,EAAK,CAAC,GAI5E,GAAI,CACF,MAAMC,EAAW,MAAM,MAAMf,EAAK,CAChC,OAAAC,EACA,KAAM,OACN,QAAS,CACP,eAAgB,mBAChB,GAAGC,EACH,GAAGQ,CACL,EACA,OAAQE,EAAW,OACnB,GAAIX,IAAW,OAASU,GAAY,CAAE,KAAMA,CAAS,CACvD,CAAC,EAED,OAAIE,GACF,aAAaA,CAAY,EAGpBE,CACT,OAASnB,EAAO,CACd,MAAIiB,GACF,aAAaA,CAAY,EAErBjB,CACR,QAAE,CACAa,GAAgB,oBAAoB,QAASK,CAAe,CAC9D,CACF",
|
|
6
|
+
"names": ["fetcher_exports", "__export", "fetcher", "__toCommonJS", "executeRecaptcha", "action", "sitekey", "executor", "error", "getRecaptchaHeaders", "headerKey", "recaptchaToken", "url", "method", "headers", "body", "timeout", "needRecaptcha", "recaptchaSitekey", "recaptchaAction", "recaptchaHeaderKey", "externalSignal", "recaptchaHeaders", "bodyData", "controller", "timeoutTimer", "onExternalAbort", "response"]
|
|
7
7
|
}
|
|
@@ -2,5 +2,6 @@ export { default as Chat } from './chat/index';
|
|
|
2
2
|
export { Role, ActionExecutionMessage, TextMessage, useCopilotChat, useCopilotAction, useCopilotReadable, } from './chat/utils';
|
|
3
3
|
export * from './credits/index.js';
|
|
4
4
|
export * from './registration/index.js';
|
|
5
|
+
export * from './memberPopup/index.js';
|
|
5
6
|
export { LiveChatWidget } from './LiveChatWidget/index.js';
|
|
6
7
|
export type { LiveChatWidgetProps, Message, MessageContent, MessageRole, MessageContentType, MessageMetadata, MessageRenderer, QuickReply, ProductCardContent, ProductListContent, PolicyContent, QuickRepliesContent, ThinkingContent, ErrorContent, SSEEvent, ChatStreamRequest, } from './LiveChatWidget/index.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var l=Object.create;var C=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var M=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty;var f=(e,t)=>{for(var s in t)C(e,s,{get:t[s],enumerable:!0})},i=(e,t,s,p)=>{if(t&&typeof t=="object"||typeof t=="function")for(let
|
|
1
|
+
"use strict";var l=Object.create;var C=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var M=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty;var f=(e,t)=>{for(var s in t)C(e,s,{get:t[s],enumerable:!0})},i=(e,t,s,p)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of x(t))!c.call(e,a)&&a!==s&&C(e,a,{get:()=>t[a],enumerable:!(p=u(t,a))||p.enumerable});return e},r=(e,t,s)=>(i(e,t,"default"),s&&i(s,t,"default")),m=(e,t,s)=>(s=e!=null?l(M(e)):{},i(t||!e||!e.__esModule?C(s,"default",{value:e,enumerable:!0}):s,e)),h=e=>i(C({},"__esModule",{value:!0}),e);var n={};f(n,{ActionExecutionMessage:()=>o.ActionExecutionMessage,Chat:()=>g.default,LiveChatWidget:()=>d.LiveChatWidget,Role:()=>o.Role,TextMessage:()=>o.TextMessage,useCopilotAction:()=>o.useCopilotAction,useCopilotChat:()=>o.useCopilotChat,useCopilotReadable:()=>o.useCopilotReadable});module.exports=h(n);var g=m(require("./chat/index")),o=require("./chat/utils");r(n,require("./credits/index.js"),module.exports);r(n,require("./registration/index.js"),module.exports);r(n,require("./memberPopup/index.js"),module.exports);var d=require("./LiveChatWidget/index.js");
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { default as Chat } from './chat/index'\n\nexport {\n Role,\n ActionExecutionMessage,\n TextMessage,\n useCopilotChat,\n useCopilotAction,\n useCopilotReadable,\n} from './chat/utils'\n\nexport * from './credits/index.js'\n\nexport * from './registration/index.js'\n\n\n\n// LiveChatWidget \u5BFC\u51FA\nexport { LiveChatWidget } from './LiveChatWidget/index.js'\nexport type {\n LiveChatWidgetProps,\n Message,\n MessageContent,\n MessageRole,\n MessageContentType,\n MessageMetadata,\n MessageRenderer,\n QuickReply,\n ProductCardContent,\n ProductListContent,\n PolicyContent,\n QuickRepliesContent,\n ThinkingContent,\n ErrorContent,\n SSEEvent,\n ChatStreamRequest,\n} from './LiveChatWidget/index.js'\n"],
|
|
5
|
-
"mappings": "wmBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mSAAAE,EAAAF,GAAA,IAAAG,EAAgC,2BAEhCC,EAOO,wBAEPC,EAAAL,EAAc,8BAXd,gBAaAK,EAAAL,EAAc,mCAbd,
|
|
4
|
+
"sourcesContent": ["export { default as Chat } from './chat/index'\n\nexport {\n Role,\n ActionExecutionMessage,\n TextMessage,\n useCopilotChat,\n useCopilotAction,\n useCopilotReadable,\n} from './chat/utils'\n\nexport * from './credits/index.js'\n\nexport * from './registration/index.js'\n\nexport * from './memberPopup/index.js'\n\n\n\n// LiveChatWidget \u5BFC\u51FA\nexport { LiveChatWidget } from './LiveChatWidget/index.js'\nexport type {\n LiveChatWidgetProps,\n Message,\n MessageContent,\n MessageRole,\n MessageContentType,\n MessageMetadata,\n MessageRenderer,\n QuickReply,\n ProductCardContent,\n ProductListContent,\n PolicyContent,\n QuickRepliesContent,\n ThinkingContent,\n ErrorContent,\n SSEEvent,\n ChatStreamRequest,\n} from './LiveChatWidget/index.js'\n"],
|
|
5
|
+
"mappings": "wmBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mSAAAE,EAAAF,GAAA,IAAAG,EAAgC,2BAEhCC,EAOO,wBAEPC,EAAAL,EAAc,8BAXd,gBAaAK,EAAAL,EAAc,mCAbd,gBAeAK,EAAAL,EAAc,kCAfd,gBAoBA,IAAAM,EAA+B",
|
|
6
6
|
"names": ["components_exports", "__export", "__toCommonJS", "import_chat", "import_utils", "__reExport", "import_LiveChatWidget"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type HeadlessConfig } from '@anker-in/lib';
|
|
2
|
+
import { type MemberPopupCopy, type MemberPopupContextValue } from './type';
|
|
3
|
+
type MemberPopupProps = MemberPopupContextValue & {
|
|
4
|
+
headlessConfig: HeadlessConfig;
|
|
5
|
+
copy: MemberPopupCopy;
|
|
6
|
+
bottomOffset?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function MemberPopup({ copy, bottomOffset, ...providerProps }: MemberPopupProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";"use client";var D=Object.create;var g=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,q=Object.prototype.hasOwnProperty;var F=(e,i)=>{for(var n in i)g(e,n,{get:i[n],enumerable:!0})},h=(e,i,n,u)=>{if(i&&typeof i=="object"||typeof i=="function")for(let a of U(i))!q.call(e,a)&&a!==n&&g(e,a,{get:()=>i[a],enumerable:!(u=L(i,a))||u.enumerable});return e};var m=(e,i,n)=>(n=e!=null?D(B(e)):{},h(i||!e||!e.__esModule?g(n,"default",{value:e,enumerable:!0}):n,e)),G=e=>h(g({},"__esModule",{value:!0}),e);var oe={};F(oe,{MemberPopup:()=>ee});module.exports=G(oe);var t=require("react/jsx-runtime"),r=require("react"),I=require("@anker-in/headless-ui"),f=require("@anker-in/lib"),o=require("./type"),k=require("./context/provider"),M=require("./context/provider"),O=require("./context/viewStack"),p=require("./icons"),A=require("../../constants");const J=(0,r.lazy)(()=>import("./panels/EarnCredits")),K=(0,r.lazy)(()=>import("./panels/ConsumeCredits")),Q=(0,r.lazy)(()=>import("./panels/Referral")),W=(0,r.lazy)(()=>import("./panels/EarnCredits/CompleteProfilePanel")),X=(0,r.lazy)(()=>import("./panels/EarnCredits/SubscribePanel")),Y=(0,r.lazy)(()=>import("./panels/EarnCredits/SubscribeEmailPanel")),Z=(0,r.lazy)(()=>import("./panels/EarnCredits/ActivatePanel")),$=(0,r.lazy)(()=>import("./panels/ConsumeCredits/RedeemCouponPanel"));function ee({copy:e,bottomOffset:i="24px",...n}){return(0,t.jsx)(k.MemberPopupProvider,{...n,earnCreditsCopy:e.earnCredits,children:(0,t.jsx)(te,{copy:e,bottomOffset:i})})}function te({copy:e,bottomOffset:i}){const{profile:n,openSignInPopup:u,openSignUpPopup:a}=(0,M.useMemberPopupContext)(),{brand:x,storeDomain:C}=(0,f.useHeadlessContext)(),v=A.ROUNDED_BRANDS.includes(x),V=!!n,[S,N]=(0,r.useState)(!1),[y,P]=(0,r.useState)([]),[R,z]=(0,r.useState)(!1),[E,H]=(0,r.useState)(!1),[T,j]=(0,r.useState)(!1),s=y[y.length-1]??null,b=(0,r.useCallback)(l=>{P(d=>[...d,l])},[]),c=(0,r.useCallback)(()=>{P(l=>l.slice(0,-1))},[]);function _(l,d){switch(l){case o.MemberPopupActionType.ExternalLink:d&&window.open(d,"_blank","noopener,noreferrer");break;case o.MemberPopupActionType.OpenEarnCredits:b({type:o.MemberPopupPanelType.EarnCredits});break;case o.MemberPopupActionType.OpenConsumeCredits:b({type:o.MemberPopupPanelType.ConsumeCredits});break;case o.MemberPopupActionType.OpenReferral:b({type:o.MemberPopupPanelType.Referral});break;case o.MemberPopupActionType.OpenSubscribe:b({type:o.MemberPopupPanelType.Subscribe});break}}function w(){N(!1),P([])}return(0,t.jsxs)(O.ViewStackContext.Provider,{value:{pushView:b,popView:c},children:[S&&(0,t.jsx)("div",{className:"fixed inset-0 z-[998]",onClick:w}),(0,t.jsxs)("div",{className:"fixed right-0 z-[999] flex flex-col items-end pr-[16px]",style:{bottom:i},children:[S&&(0,t.jsxs)("div",{className:(0,f.classNames)("relative mb-[8px] flex w-[420px] max-w-[calc(100vw-32px)] min-h-[600px] flex-col overflow-hidden bg-white shadow-[0_8px_32px_rgba(0,0,0,0.16)] cmp-md:w-[358px] cmp-sm:w-[258px]",v?"rounded-[12px]":"rounded-none"),onClick:l=>l.stopPropagation(),children:[(0,t.jsx)("div",{className:"absolute right-[-8px] top-[24px] size-0 border-y-8 border-l-8 border-y-transparent border-l-white"}),(0,t.jsxs)("div",{className:"flex items-center justify-between px-[16px] pb-[8px] pt-[16px]",children:[(0,t.jsx)("button",{className:"flex size-[24px] cursor-pointer items-center justify-center",onClick:c,"aria-label":"Back",children:(0,t.jsx)(p.IconSwitch,{})}),(0,t.jsx)("button",{className:"flex size-[24px] cursor-pointer items-center justify-center",onClick:w,"aria-label":"Close",children:(0,t.jsx)(p.IconClose,{})})]}),(0,t.jsxs)("div",{className:"flex flex-1 flex-col gap-[12px] overflow-y-auto p-[16px]",style:{maxHeight:"min(calc(80vh - 118px), 606px)"},children:[s===null&&(0,t.jsxs)(t.Fragment,{children:[(e.title||e.subtitle)&&(0,t.jsxs)("div",{className:"flex flex-col gap-[4px]",children:[e.title&&(0,t.jsx)("h2",{className:"text-[24px] font-[700] leading-[1.2] text-[#080a0f]",children:e.title}),e.subtitle&&(0,t.jsx)("p",{className:"text-[16px] font-[700] leading-snug text-[#4a4c56]",children:e.subtitle})]}),e.list.map((l,d)=>(0,t.jsx)(se,{item:l,onAction:_,rounded:v},d))]}),s!==null&&(0,t.jsxs)(r.Suspense,{fallback:(0,t.jsx)("div",{className:"flex items-center justify-center py-[32px]",children:(0,t.jsx)("div",{className:"size-[32px] animate-spin rounded-full border-[3px] border-[#080a0f] border-t-transparent"})}),children:[s.type===o.MemberPopupPanelType.EarnCredits&&e.earnCredits&&(0,t.jsx)(J,{copy:e.earnCredits,onClose:c,isSubscribeSuccess:R,isActivateSuccess:E,isProfileCompleteSuccess:T,onSubscribeSuccess:()=>z(!0),onActivateSuccess:()=>H(!0),onProfileCompleteSuccess:()=>j(!0)}),s.type===o.MemberPopupPanelType.ConsumeCredits&&e.consumeCredits&&(0,t.jsx)(K,{copy:e.consumeCredits,onClose:c}),s.type===o.MemberPopupPanelType.Referral&&e.referral&&(0,t.jsx)(Q,{copy:e.referral,onClose:c}),s.type===o.MemberPopupPanelType.CompleteProfile&&e.earnCredits&&(0,t.jsx)(W,{copy:e.earnCredits.completeProfile,shopifyStoreDomain:C,onClose:c,onSuccess:s.props?.onSuccess}),s.type===o.MemberPopupPanelType.Subscribe&&e.subscribe&&(0,t.jsx)(X,{copy:e.subscribe,email:n?.email,onClose:c,onSuccess:s.props?.onSuccess}),s.type===o.MemberPopupPanelType.SubscribeEmail&&e.earnCredits&&(0,t.jsx)(Y,{copy:e.earnCredits.subscribe,email:n?.email,onClose:c,onSuccess:s.props?.onSuccess}),s.type===o.MemberPopupPanelType.Activate&&e.earnCredits&&(0,t.jsx)(Z,{copy:e.earnCredits.authCodeActivate,onClose:c,onSuccess:s.props?.onSuccess}),s.type===o.MemberPopupPanelType.RedeemCoupon&&s.props&&e.consumeCredits&&(0,t.jsx)($,{itemTitle:s.props.itemTitle,itemCredits:s.props.itemCredits,itemImage:s.props.itemImage,itemValue:s.props.itemValue,itemOff:s.props.itemOff,redeemId:s.props.redeemId,userId:s.props.userId,alpcConfig:s.props.alpcConfig,copy:e.consumeCredits.redeemModal,pointUnit:e.consumeCredits.pointUnit,onClose:c})]})]}),e.footer&&!V&&(0,t.jsx)("div",{className:"border-t border-[#dadce0] p-[16px]",children:(0,t.jsxs)("div",{className:"flex items-center justify-between gap-[16px]",children:[(0,t.jsxs)("div",{className:"flex items-center gap-[4px]",children:[(0,t.jsx)("span",{className:"text-[14px] font-[700] text-[#080a0f]",children:e.footer.loginHint}),(0,t.jsx)("button",{className:"cursor-pointer text-[14px] font-[700] text-[#080a0f] underline",onClick:u,children:e.footer.loginLabel})]}),(0,t.jsx)("div",{className:"flex shrink-0 items-center gap-[8px]",children:(0,t.jsx)("button",{className:(0,f.classNames)("cursor-pointer border-[1.6px] border-[#080a0f] px-[20px] pb-[10px] pt-[11px] text-[14px] font-[700] leading-[1.2] text-[#080a0f]",v?"rounded-[4px]":"rounded-none"),onClick:a,children:e.footer.joinLabel})})]})})]}),(0,t.jsx)("button",{className:"flex cursor-pointer items-center justify-center rounded-full bg-white shadow-lg",onClick:()=>N(l=>!l),"aria-label":e.triggerImg.alt??"Open member popup",children:(0,t.jsx)(I.Picture,{source:e.triggerImg.url,alt:e.triggerImg.alt??"",className:"size-[58px]"})})]})]})}function se({item:e,onAction:i,rounded:n}){const u={[o.MemberPopupActionType.OpenEarnCredits]:p.IconCredit,[o.MemberPopupActionType.OpenConsumeCredits]:p.IconBag,[o.MemberPopupActionType.OpenReferral]:p.IconReferral,[o.MemberPopupActionType.OpenSubscribe]:p.IconSubscription};return(0,t.jsxs)("div",{className:(0,f.classNames)("flex flex-col gap-[16px] bg-[#f5f6f7] p-[16px]",n?"rounded-[8px]":"rounded-none"),children:[(0,t.jsxs)("div",{className:"flex flex-col gap-[4px]",children:[(0,t.jsx)("h3",{className:"text-[20px] font-[700] leading-[1.2] text-[#1e2024]",children:e.title}),e.description&&(0,t.jsx)("p",{className:"text-[14px] font-[700] leading-[1.43] text-[#1e2024]",children:e.description})]}),(0,t.jsx)("div",{className:"flex flex-col gap-[16px]",children:e.links.map((a,x)=>{const C=u[a.type];return(0,t.jsxs)("div",{children:[x>0&&(0,t.jsx)("div",{className:"mb-[16px] h-px bg-[#dadce0]"}),(0,t.jsxs)("button",{className:"flex w-full cursor-pointer items-center gap-[12px]",onClick:()=>i(a.type,a.url),children:[C&&(0,t.jsx)(C,{className:"size-[24px] shrink-0"}),(0,t.jsx)("span",{className:"flex-1 text-left text-[14px] font-[700] text-[#1e2024]",children:a.label}),(0,t.jsx)(p.IconArrow,{className:"size-[16px] shrink-0"})]})]},x)})})]})}
|
|
2
|
+
//# sourceMappingURL=MemberPopup.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/components/memberPopup/MemberPopup.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport { lazy, Suspense, useState, useCallback } from 'react'\nimport { Picture } from '@anker-in/headless-ui'\nimport { type HeadlessConfig, useHeadlessContext, classNames as cn } from '@anker-in/lib'\nimport {\n MemberPopupActionType,\n MemberPopupPanelType,\n type MemberPopupCopy,\n type MemberPopupContextValue,\n type MemberPopupItem,\n} from './type'\nimport { MemberPopupProvider } from './context/provider'\nimport { useMemberPopupContext } from './context/provider'\nimport { ViewStackContext, type ViewPayload } from './context/viewStack'\nimport { IconClose, IconArrow, IconCredit, IconBag, IconReferral, IconSwitch, IconSubscription } from './icons'\nimport { ROUNDED_BRANDS } from '../../constants'\n\nconst EarnCredits = lazy(() => import('./panels/EarnCredits'))\nconst ConsumeCredits = lazy(() => import('./panels/ConsumeCredits'))\nconst Referral = lazy(() => import('./panels/Referral'))\nconst CompleteProfile = lazy(() => import('./panels/EarnCredits/CompleteProfilePanel'))\nconst Subscribe = lazy(() => import('./panels/EarnCredits/SubscribePanel'))\nconst SubscribeEmail = lazy(() => import('./panels/EarnCredits/SubscribeEmailPanel'))\nconst Activate = lazy(() => import('./panels/EarnCredits/ActivatePanel'))\nconst RedeemCoupon = lazy(() => import('./panels/ConsumeCredits/RedeemCouponPanel'))\n\ntype MemberPopupProps = MemberPopupContextValue & {\n headlessConfig: HeadlessConfig\n copy: MemberPopupCopy\n bottomOffset?: string\n}\n\nexport function MemberPopup({ copy, bottomOffset = '24px', ...providerProps }: MemberPopupProps) {\n return (\n <MemberPopupProvider {...providerProps} earnCreditsCopy={copy.earnCredits}>\n <MemberPopupContent copy={copy} bottomOffset={bottomOffset} />\n </MemberPopupProvider>\n )\n}\n\ntype MemberPopupContentProps = {\n copy: MemberPopupCopy\n bottomOffset: string\n}\n\nfunction MemberPopupContent({ copy, bottomOffset }: MemberPopupContentProps) {\n const { profile, openSignInPopup, openSignUpPopup } = useMemberPopupContext()\n const { brand, storeDomain } = useHeadlessContext()\n const rounded = ROUNDED_BRANDS.includes(brand)\n const isLogin = !!profile\n const [isOpen, setIsOpen] = useState(false)\n const [viewStack, setViewStack] = useState<ViewPayload[]>([])\n const [isSubscribeSuccess, setIsSubscribeSuccess] = useState(false)\n const [isActivateSuccess, setIsActivateSuccess] = useState(false)\n const [isProfileCompleteSuccess, setIsProfileCompleteSuccess] = useState(false)\n\n const currentView = viewStack[viewStack.length - 1] ?? null\n\n const pushView = useCallback((view: ViewPayload) => {\n setViewStack(prev => [...prev, view])\n }, [])\n\n const popView = useCallback(() => {\n setViewStack(prev => prev.slice(0, -1))\n }, [])\n\n function handleAction(type: MemberPopupActionType, url?: string) {\n switch (type) {\n case MemberPopupActionType.ExternalLink:\n if (url) window.open(url, '_blank', 'noopener,noreferrer')\n break\n case MemberPopupActionType.OpenEarnCredits:\n pushView({ type: MemberPopupPanelType.EarnCredits })\n break\n case MemberPopupActionType.OpenConsumeCredits:\n pushView({ type: MemberPopupPanelType.ConsumeCredits })\n break\n case MemberPopupActionType.OpenReferral:\n pushView({ type: MemberPopupPanelType.Referral })\n break\n case MemberPopupActionType.OpenSubscribe:\n pushView({ type: MemberPopupPanelType.Subscribe })\n break\n }\n }\n\n function handleClose() {\n setIsOpen(false)\n setViewStack([])\n }\n\n return (\n <ViewStackContext.Provider value={{ pushView, popView }}>\n {isOpen && (\n <div\n className=\"fixed inset-0 z-[998]\"\n onClick={handleClose}\n />\n )}\n <div className=\"fixed right-0 z-[999] flex flex-col items-end pr-[16px]\" style={{ bottom: bottomOffset }}>\n {isOpen && (\n <div\n className={cn('relative mb-[8px] flex w-[420px] max-w-[calc(100vw-32px)] min-h-[600px] flex-col overflow-hidden bg-white shadow-[0_8px_32px_rgba(0,0,0,0.16)] cmp-md:w-[358px] cmp-sm:w-[258px]', rounded ? 'rounded-[12px]' : 'rounded-none')}\n onClick={e => e.stopPropagation()}\n >\n <div className=\"absolute right-[-8px] top-[24px] size-0 border-y-8 border-l-8 border-y-transparent border-l-white\" />\n <div className=\"flex items-center justify-between px-[16px] pb-[8px] pt-[16px]\">\n <button\n className=\"flex size-[24px] cursor-pointer items-center justify-center\"\n onClick={popView}\n aria-label=\"Back\"\n >\n <IconSwitch />\n </button>\n <button\n className=\"flex size-[24px] cursor-pointer items-center justify-center\"\n onClick={handleClose}\n aria-label=\"Close\"\n >\n <IconClose />\n </button>\n </div>\n\n <div\n className=\"flex flex-1 flex-col gap-[12px] overflow-y-auto p-[16px]\"\n style={{ maxHeight: 'min(calc(80vh - 118px), 606px)' }}\n >\n {currentView === null && (\n <>\n {(copy.title || copy.subtitle) && (\n <div className=\"flex flex-col gap-[4px]\">\n {copy.title && (\n <h2 className=\"text-[24px] font-[700] leading-[1.2] text-[#080a0f]\">{copy.title}</h2>\n )}\n {copy.subtitle && (\n <p className=\"text-[16px] font-[700] leading-snug text-[#4a4c56]\">{copy.subtitle}</p>\n )}\n </div>\n )}\n {copy.list.map((item, i) => (\n <HomeCard key={i} item={item} onAction={handleAction} rounded={rounded} />\n ))}\n </>\n )}\n\n {currentView !== null && (\n <Suspense\n fallback={\n <div className=\"flex items-center justify-center py-[32px]\">\n <div className=\"size-[32px] animate-spin rounded-full border-[3px] border-[#080a0f] border-t-transparent\" />\n </div>\n }\n >\n {currentView.type === MemberPopupPanelType.EarnCredits && copy.earnCredits && (\n <EarnCredits\n copy={copy.earnCredits}\n onClose={popView}\n isSubscribeSuccess={isSubscribeSuccess}\n isActivateSuccess={isActivateSuccess}\n isProfileCompleteSuccess={isProfileCompleteSuccess}\n onSubscribeSuccess={() => setIsSubscribeSuccess(true)}\n onActivateSuccess={() => setIsActivateSuccess(true)}\n onProfileCompleteSuccess={() => setIsProfileCompleteSuccess(true)}\n />\n )}\n {currentView.type === MemberPopupPanelType.ConsumeCredits && copy.consumeCredits && (\n <ConsumeCredits copy={copy.consumeCredits} onClose={popView} />\n )}\n {currentView.type === MemberPopupPanelType.Referral && copy.referral && (\n <Referral copy={copy.referral} onClose={popView} />\n )}\n {currentView.type === MemberPopupPanelType.CompleteProfile && copy.earnCredits && (\n <CompleteProfile copy={copy.earnCredits.completeProfile} shopifyStoreDomain={storeDomain} onClose={popView} onSuccess={currentView.props?.onSuccess} />\n )}\n {currentView.type === MemberPopupPanelType.Subscribe && copy.subscribe && (\n <Subscribe copy={copy.subscribe} email={profile?.email} onClose={popView} onSuccess={currentView.props?.onSuccess} />\n )}\n {currentView.type === MemberPopupPanelType.SubscribeEmail && copy.earnCredits && (\n <SubscribeEmail copy={copy.earnCredits.subscribe} email={profile?.email} onClose={popView} onSuccess={currentView.props?.onSuccess} />\n )}\n {currentView.type === MemberPopupPanelType.Activate && copy.earnCredits && (\n <Activate copy={copy.earnCredits.authCodeActivate} onClose={popView} onSuccess={currentView.props?.onSuccess} />\n )}\n {currentView.type === MemberPopupPanelType.RedeemCoupon && currentView.props && copy.consumeCredits && (\n <RedeemCoupon\n itemTitle={currentView.props.itemTitle}\n itemCredits={currentView.props.itemCredits}\n itemImage={currentView.props.itemImage}\n itemValue={currentView.props.itemValue}\n itemOff={currentView.props.itemOff}\n redeemId={currentView.props.redeemId}\n userId={currentView.props.userId}\n alpcConfig={currentView.props.alpcConfig}\n copy={copy.consumeCredits.redeemModal}\n pointUnit={copy.consumeCredits.pointUnit}\n onClose={popView}\n />\n )}\n </Suspense>\n )}\n </div>\n\n {copy.footer && !isLogin && (\n <div className=\"border-t border-[#dadce0] p-[16px]\">\n <div className=\"flex items-center justify-between gap-[16px]\">\n <div className=\"flex items-center gap-[4px]\">\n <span className=\"text-[14px] font-[700] text-[#080a0f]\">{copy.footer.loginHint}</span>\n <button\n className=\"cursor-pointer text-[14px] font-[700] text-[#080a0f] underline\"\n onClick={openSignInPopup}\n >\n {copy.footer.loginLabel}\n </button>\n </div>\n <div className=\"flex shrink-0 items-center gap-[8px]\">\n <button\n className={cn('cursor-pointer border-[1.6px] border-[#080a0f] px-[20px] pb-[10px] pt-[11px] text-[14px] font-[700] leading-[1.2] text-[#080a0f]', rounded ? 'rounded-[4px]' : 'rounded-none')}\n onClick={openSignUpPopup}\n >\n {copy.footer.joinLabel}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n )}\n\n <button\n className=\"flex cursor-pointer items-center justify-center rounded-full bg-white shadow-lg\"\n onClick={() => setIsOpen(prev => !prev)}\n aria-label={copy.triggerImg.alt ?? 'Open member popup'}\n >\n <Picture source={copy.triggerImg.url} alt={copy.triggerImg.alt ?? ''} className=\"size-[58px]\" />\n </button>\n </div>\n </ViewStackContext.Provider>\n )\n}\n\ntype HomeCardProps = {\n item: MemberPopupItem\n onAction: (type: MemberPopupActionType, url?: string) => void\n rounded: boolean\n}\n\nfunction HomeCard({ item, onAction, rounded }: HomeCardProps) {\n const ACTION_ICON: Partial<Record<MemberPopupActionType, typeof IconCredit>> = {\n [MemberPopupActionType.OpenEarnCredits]: IconCredit,\n [MemberPopupActionType.OpenConsumeCredits]: IconBag,\n [MemberPopupActionType.OpenReferral]: IconReferral,\n [MemberPopupActionType.OpenSubscribe]: IconSubscription,\n }\n\n return (\n <div className={cn('flex flex-col gap-[16px] bg-[#f5f6f7] p-[16px]', rounded ? 'rounded-[8px]' : 'rounded-none')}>\n <div className=\"flex flex-col gap-[4px]\">\n <h3 className=\"text-[20px] font-[700] leading-[1.2] text-[#1e2024]\">{item.title}</h3>\n {item.description && <p className=\"text-[14px] font-[700] leading-[1.43] text-[#1e2024]\">{item.description}</p>}\n </div>\n\n <div className=\"flex flex-col gap-[16px]\">\n {item.links.map((link, i) => {\n const IconComponent = ACTION_ICON[link.type]\n return (\n <div key={i}>\n {i > 0 && <div className=\"mb-[16px] h-px bg-[#dadce0]\" />}\n <button\n className=\"flex w-full cursor-pointer items-center gap-[12px]\"\n onClick={() => onAction(link.type, link.url)}\n >\n {IconComponent && <IconComponent className=\"size-[24px] shrink-0\" />}\n <span className=\"flex-1 text-left text-[14px] font-[700] text-[#1e2024]\">{link.label}</span>\n <IconArrow className=\"size-[16px] shrink-0\" />\n </button>\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["MemberPopup_exports", "__export", "MemberPopup", "__toCommonJS", "import_jsx_runtime", "import_react", "import_headless_ui", "import_lib", "import_type", "import_provider", "import_viewStack", "import_icons", "import_constants", "EarnCredits", "ConsumeCredits", "Referral", "CompleteProfile", "Subscribe", "SubscribeEmail", "Activate", "RedeemCoupon", "copy", "bottomOffset", "providerProps", "MemberPopupContent", "profile", "openSignInPopup", "openSignUpPopup", "brand", "storeDomain", "rounded", "isLogin", "isOpen", "setIsOpen", "viewStack", "setViewStack", "isSubscribeSuccess", "setIsSubscribeSuccess", "isActivateSuccess", "setIsActivateSuccess", "isProfileCompleteSuccess", "setIsProfileCompleteSuccess", "currentView", "pushView", "view", "prev", "popView", "handleAction", "type", "url", "handleClose", "cn", "e", "item", "i", "HomeCard", "onAction", "ACTION_ICON", "link", "IconComponent"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { type HeadlessConfig } from '@anker-in/lib';
|
|
3
|
+
import type { EarnCreditsCopy, MemberPopupContextValue } from '../type';
|
|
4
|
+
export declare const MemberPopupContext: import("react").Context<MemberPopupContextValue>;
|
|
5
|
+
type MemberPopupProviderProps = MemberPopupContextValue & {
|
|
6
|
+
headlessConfig: HeadlessConfig;
|
|
7
|
+
earnCreditsCopy?: EarnCreditsCopy;
|
|
8
|
+
};
|
|
9
|
+
export declare function MemberPopupProvider({ children, headlessConfig, earnCreditsCopy, ...contextValue }: PropsWithChildren<MemberPopupProviderProps>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function useMemberPopupContext(): MemberPopupContextValue;
|
|
11
|
+
export {};
|