@anker-in/campaign-ui 0.4.3-beta.1 → 0.4.3
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/components/ChatInput.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/ChatInput.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/ChatMessage.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/CartCard.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ProductList.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +1 -1
- package/dist/cjs/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +2 -2
- 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/credits/creditsCash/CreditsCash.js +1 -1
- package/dist/cjs/components/credits/creditsCash/CreditsCash.js.map +2 -2
- package/dist/cjs/components/credits/creditsCash/RedeemableItem.js +1 -1
- package/dist/cjs/components/credits/creditsCash/RedeemableItem.js.map +2 -2
- package/dist/cjs/components/credits/creditsCash/type.d.ts +2 -0
- package/dist/cjs/components/credits/creditsCash/type.js +1 -1
- package/dist/cjs/components/credits/creditsCash/type.js.map +1 -1
- package/dist/cjs/components/credits/creditsMemberPrice/CreditsMemberPrice.js +1 -1
- package/dist/cjs/components/credits/creditsMemberPrice/CreditsMemberPrice.js.map +2 -2
- package/dist/cjs/components/credits/creditsMemberPrice/MemberPriceItem.js +1 -1
- package/dist/cjs/components/credits/creditsMemberPrice/MemberPriceItem.js.map +2 -2
- package/dist/cjs/components/credits/creditsMemberPrice/type.d.ts +2 -0
- package/dist/cjs/components/credits/creditsMemberPrice/type.js.map +1 -1
- package/dist/cjs/components/credits/creditsRedeemList/CreditsRedeemList.js +1 -1
- package/dist/cjs/components/credits/creditsRedeemList/CreditsRedeemList.js.map +2 -2
- package/dist/cjs/components/credits/creditsRedeemList/RedeemableItem.js +1 -1
- package/dist/cjs/components/credits/creditsRedeemList/RedeemableItem.js.map +2 -2
- package/dist/cjs/components/credits/creditsRedeemList/type.d.ts +1 -0
- package/dist/cjs/components/credits/creditsRedeemList/type.js.map +1 -1
- package/dist/cjs/components/credits/modal/SubscribeModal.js +1 -1
- package/dist/cjs/components/credits/modal/SubscribeModal.js.map +3 -3
- package/dist/cjs/components/credits/type.d.ts +1 -0
- package/dist/cjs/components/credits/type.js.map +1 -1
- package/dist/cjs/helpers/fetchResponse.d.ts +14 -0
- package/dist/cjs/helpers/fetchResponse.js +2 -0
- package/dist/cjs/helpers/fetchResponse.js.map +7 -0
- package/dist/cjs/helpers/fetcher.d.ts +2 -0
- package/dist/cjs/helpers/fetcher.js +2 -0
- package/dist/cjs/helpers/fetcher.js.map +7 -0
- package/dist/cjs/helpers/index.d.ts +2 -0
- package/dist/cjs/helpers/index.js +2 -0
- package/dist/cjs/helpers/index.js.map +7 -0
- package/dist/cjs/helpers/utils.d.ts +3 -0
- package/dist/cjs/helpers/utils.js +2 -0
- package/dist/cjs/helpers/utils.js.map +7 -0
- package/dist/cjs/stories/LiveChatWidget.stories.js +2 -2
- package/dist/cjs/stories/LiveChatWidget.stories.js.map +2 -2
- package/dist/cjs/tsconfig.tsbuildinfo +1 -0
- package/dist/esm/components/LiveChatWidget/components/ChatInput.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/ChatInput.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/ChatMessage.js +2 -2
- package/dist/esm/components/LiveChatWidget/components/ChatMessage.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/CartCard.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductCard.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductComparison.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ProductList.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js +1 -1
- package/dist/esm/components/LiveChatWidget/components/MessageContent/ThinkingBlock.js.map +2 -2
- 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/credits/creditsCash/CreditsCash.js +1 -1
- package/dist/esm/components/credits/creditsCash/CreditsCash.js.map +2 -2
- package/dist/esm/components/credits/creditsCash/RedeemableItem.js +1 -1
- package/dist/esm/components/credits/creditsCash/RedeemableItem.js.map +2 -2
- package/dist/esm/components/credits/creditsCash/type.d.ts +2 -0
- package/dist/esm/components/credits/creditsMemberPrice/CreditsMemberPrice.js +1 -1
- package/dist/esm/components/credits/creditsMemberPrice/CreditsMemberPrice.js.map +2 -2
- package/dist/esm/components/credits/creditsMemberPrice/MemberPriceItem.js +1 -1
- package/dist/esm/components/credits/creditsMemberPrice/MemberPriceItem.js.map +2 -2
- package/dist/esm/components/credits/creditsMemberPrice/type.d.ts +2 -0
- package/dist/esm/components/credits/creditsRedeemList/CreditsRedeemList.js +1 -1
- package/dist/esm/components/credits/creditsRedeemList/CreditsRedeemList.js.map +2 -2
- package/dist/esm/components/credits/creditsRedeemList/RedeemableItem.js +1 -1
- package/dist/esm/components/credits/creditsRedeemList/RedeemableItem.js.map +2 -2
- package/dist/esm/components/credits/creditsRedeemList/type.d.ts +1 -0
- package/dist/esm/components/credits/modal/SubscribeModal.js +1 -1
- package/dist/esm/components/credits/modal/SubscribeModal.js.map +3 -3
- package/dist/esm/components/credits/type.d.ts +1 -0
- package/dist/esm/helpers/fetchResponse.d.ts +14 -0
- package/dist/esm/helpers/fetchResponse.js +2 -0
- package/dist/esm/helpers/fetchResponse.js.map +7 -0
- package/dist/esm/helpers/fetcher.d.ts +2 -0
- package/dist/esm/helpers/fetcher.js +2 -0
- package/dist/esm/helpers/fetcher.js.map +7 -0
- package/dist/esm/helpers/index.d.ts +2 -0
- package/dist/esm/helpers/index.js +2 -0
- package/dist/esm/helpers/index.js.map +7 -0
- package/dist/esm/helpers/utils.d.ts +3 -0
- package/dist/esm/helpers/utils.js +2 -0
- package/dist/esm/helpers/utils.js.map +7 -0
- package/dist/esm/stories/LiveChatWidget.stories.js +1 -1
- package/dist/esm/stories/LiveChatWidget.stories.js.map +2 -2
- package/dist/esm/tsconfig.tsbuildinfo +1 -0
- package/package.json +2 -2
- package/src/components/LiveChatWidget/components/ChatInput.tsx +2 -2
- package/src/components/LiveChatWidget/components/ChatMessage.tsx +1 -1
- package/src/components/LiveChatWidget/components/MessageContent/CartCard.tsx +7 -7
- package/src/components/LiveChatWidget/components/MessageContent/ProductCard.tsx +2 -2
- package/src/components/LiveChatWidget/components/MessageContent/ProductComparison.tsx +1 -1
- package/src/components/LiveChatWidget/components/MessageContent/ProductList.tsx +2 -2
- package/src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx +2 -2
- package/src/components/LiveChatWidget/components/MessageContent/ThinkingBlock.tsx +3 -3
- package/src/components/LiveChatWidget/utils/fetcher.ts +12 -3
- package/src/components/credits/creditsCash/CreditsCash.tsx +1 -0
- package/src/components/credits/creditsCash/RedeemableItem.tsx +5 -3
- package/src/components/credits/creditsCash/type.ts +2 -1
- package/src/components/credits/creditsMemberPrice/CreditsMemberPrice.tsx +1 -0
- package/src/components/credits/creditsMemberPrice/MemberPriceItem.tsx +5 -3
- package/src/components/credits/creditsMemberPrice/type.ts +2 -1
- package/src/components/credits/creditsRedeemList/CreditsRedeemList.tsx +1 -0
- package/src/components/credits/creditsRedeemList/RedeemableItem.tsx +4 -1
- package/src/components/credits/creditsRedeemList/type.ts +1 -0
- package/src/components/credits/modal/SubscribeModal.tsx +3 -1
- package/src/components/credits/type.ts +1 -0
- package/src/stories/LiveChatWidget.stories.tsx +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/credits/creditsRedeemList/CreditsRedeemList.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Container, Heading, Tabs, TabsList, TabsTrigger } from '@anker-in/headless-ui'\nimport classNames from 'classnames'\nimport { useCallback, useMemo, useState } from 'react'\n\nimport RedeemCouponModal from './RedeemCouponModal'\nimport RedeemProductModal from './RedeemProductModal'\nimport RedeemVirtualProductModal from './RedeemVirtualProductModal'\nimport { useCreditsContext } from '../context/provider'\nimport useRedeemableList from '../context/hooks/useRedeemableList'\nimport { AlpcConsumeType, AlpcErrorCode, ConsumeType } from '../context/const'\nimport { useHeadlessContext, useProductsByHandles, gaTrack, classNames as cn } from '@anker-in/lib'\nimport type { RedeemableItem as RedeemableItemType } from '../type'\nimport { RedeemableItem } from './RedeemableItem'\nimport { ROUNDED_BRANDS } from '../../../constants'\nimport RulesModal from '../modal/RulesModal'\nimport { CreditsRedeemListCopy } from './type'\nimport { useRegistration } from '../../../components/registration'\nimport { numberFormat } from '../context/utils'\nimport useMyRewards from '../context/hooks/useMyRewards'\n\nexport const CreditsRedeemList = ({ copy, id }: { copy: CreditsRedeemListCopy; id?: string }) => {\n const {\n profile,\n openSignUpPopup,\n gtm: { pageGroup },\n pageCommon,\n creditInfo,\n } = useCreditsContext()\n const { authCodeActivate } = useRegistration()\n const { brand } = useHeadlessContext()\n const rounded = ROUNDED_BRANDS.includes(brand)\n\n const isLogin = Object.keys(profile || {}).length > 0\n\n const [activeTab, setActiveTab] = useState<string>(copy.list?.[0]?.label || '')\n\n const [popRedeemData, setPopRedeemData] = useState<RedeemableItemType | undefined>(undefined)\n\n const [rules, setRules] = useState<string | string[]>()\n\n const { listLoading, redeemableList, getRedeemableList } = useRedeemableList()\n\n // \u83B7\u53D6\u7528\u6237\u7684 ExternalProduct \u5151\u6362\u8BB0\u5F55\n const { myRewards } = useMyRewards({\n page: 1,\n pageSize: 100,\n consumeType: AlpcConsumeType.ExternalProduct,\n })\n\n // \u5408\u5E76 redeemModal \u6587\u6848\uFF0C\u4F18\u5148\u4F7F\u7528 copy.redeemModal\uFF0Cfallback \u5230 pageCommon.redeemModal\n const redeemModalCopy = useMemo(() => {\n return {\n ...(pageCommon?.redeemModal || {}),\n ...(copy.redeemModal || {}),\n }\n }, [copy.redeemModal, pageCommon?.redeemModal])\n\n const alpcList = useMemo(() => {\n return redeemableList.map(item => {\n return {\n id: item.id.toString(),\n title: item.name,\n consumeCredits: item.consume_credits,\n remainingInventory: item.remaining_inventory,\n isLimited: !!item.is_limited,\n consumeType: item.consume_type,\n handle: item.sku_handle,\n sku: item.goods_sku,\n image: item.goods_url,\n }\n })\n }, [copy.list, activeTab, redeemableList])\n\n const handles = alpcList.map(item => item.handle)\n const { data: products } = useProductsByHandles({ handles })\n\n const list = useMemo(() => {\n const currentList = copy.list?.find(item => item.label === activeTab)\n return (currentList?.list || [])\n .filter(item => alpcList.some(alpcItem => String(alpcItem.id) === String(item.id)))\n .map(item => {\n const alpcItem = alpcList.find(alpcItem => String(alpcItem.id) === String(item.id))\n const product = products?.find(product => product.handle === alpcItem?.handle)\n const variant = product?.variants.find(variant => variant.sku === alpcItem?.sku)\n // \u8FC7\u6EE4\u6389\u5E93\u5B58\u4E0D\u8DB3\u7684\u5546\u54C1\n if (alpcItem?.isLimited && (!alpcItem?.remainingInventory || alpcItem.remainingInventory <= 0)) return null\n if (alpcItem?.consumeType === AlpcConsumeType.Product && (!product || !variant)) return null\n\n // \u68C0\u67E5 GoGift \u662F\u5426\u5DF2\u7ECF\u5151\u6362\u8FC7\uFF08\u53EA\u6709 GoGift \u9650\u5236\u5151\u6362\u4E00\u6B21\uFF09\n const hasRedeemed = item.type === ConsumeType.GoGift &&\n isLogin &&\n myRewards.some(reward => reward.rule_id === Number(item.id))\n\n return {\n alpc: alpcList.find(alpcItem => String(alpcItem.id) === String(item.id)),\n config: item,\n product,\n variant,\n hasRedeemed,\n }\n })\n .filter(item => item !== null) as unknown as RedeemableItemType[]\n }, [alpcList, products, isLogin, myRewards])\n\n const handleRedeemError = useCallback(\n (errorCode: AlpcErrorCode) => {\n if (errorCode === AlpcErrorCode.CodeLpcRuleInventoryNotEnough) {\n getRedeemableList()\n }\n },\n [getRedeemableList]\n )\n\n return (\n <Container id={id} className={classNames('relative bg-[#F5F5F7]')}>\n <Heading as=\"h2\" size=\"4\" html={copy.title} />\n\n {/* \u53EF\u7528\u79EF\u5206\u5C55\u793A */}\n {isLogin && copy.availableCredits && (\n <p className=\"mt-[12px] text-[20px] l-xxl:text-[18px] l:text-[16px] font-bold text-[#4A4C56]\">\n {copy.availableCredits.includes('$credits') ? (\n <>\n {copy.availableCredits.split('$credits')[0]}\n <span\n className={cn(\n 'text-brand-color-0',\n brand === 'ankersolix' &&\n 'bg-gradient-to-r from-[#2c7ed0] via-[#00a9e1] via-[43%] to-[#00db84] bg-clip-text text-transparent'\n )}\n >\n {numberFormat(creditInfo?.available_credit || 0).toString()}\n </span>\n {copy.availableCredits.split('$credits')[1] || ''}\n </>\n ) : (\n copy.availableCredits\n )}\n </p>\n )}\n\n <Tabs\n shape={rounded ? 'rounded' : 'square'}\n align=\"left\"\n className={classNames('py-[24px] md:justify-center')}\n value={activeTab.toString()}\n onValueChange={value => {\n setActiveTab(value)\n gaTrack({\n event: 'ga4Event',\n event_name: 'lp_navigation',\n event_parameters: {\n navigation: value,\n page_group: pageGroup,\n },\n })\n }}\n >\n <TabsList>\n {(copy.list || []).map(item => (\n <TabsTrigger key={item.label} value={item.label}>\n {item.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n {/* PC\u7AEF */}\n {!!alpcList?.length && !listLoading && (\n <div\n className={classNames('relative grid grid-cols-4 gap-[16px] md:grid-cols-2 md:gap-[12px] md-xl:grid-cols-3')}\n >\n {list?.map(item => (\n <RedeemableItem\n key={item?.alpc?.id}\n copy={copy}\n item={item}\n onRedeem={(item: RedeemableItemType) => {\n if (!isLogin) {\n openSignUpPopup()\n } else if (!profile?.activated && !authCodeActivate.isActivateSuccess) {\n authCodeActivate.setAutoSendEmail(true)\n authCodeActivate.open()\n } else {\n setPopRedeemData(item)\n }\n }}\n onRulesOpen={setRules}\n />\n ))}\n </div>\n )}\n\n {(popRedeemData?.config?.type === ConsumeType.Coupon ||\n popRedeemData?.config?.type === ConsumeType.ShippingCoupon) &&\n redeemModalCopy?.coupon &&\n popRedeemData && (\n <RedeemCouponModal\n item={popRedeemData}\n copy={redeemModalCopy}\n onError={handleRedeemError}\n onClose={() => {\n setPopRedeemData(undefined)\n }}\n />\n )}\n {popRedeemData?.config?.type === ConsumeType.Product && redeemModalCopy?.product && popRedeemData && (\n <RedeemProductModal\n item={popRedeemData}\n copy={redeemModalCopy}\n onError={handleRedeemError}\n onClose={() => {\n setPopRedeemData(undefined)\n }}\n />\n )}\n {(popRedeemData?.config?.type === ConsumeType.GiftCard || popRedeemData?.config?.type === ConsumeType.GoGift) &&\n redeemModalCopy?.virtualProduct &&\n popRedeemData && (\n <RedeemVirtualProductModal\n item={popRedeemData}\n copy={redeemModalCopy}\n onError={handleRedeemError}\n onClose={() => {\n setPopRedeemData(undefined)\n }}\n />\n )}\n {rules && (\n <RulesModal\n overlayClassName=\"md:px-[16px] md:items-center\"\n className={cn('md:h-fit md:rounded-b-[16px]', !rounded && 'md:rounded-none')}\n isOpen={rules.length > 0}\n onClose={() => setRules([])}\n titleClassName=\"border-b-transparent h-[56px]\"\n rules={rules}\n scrollClassName=\"md:mt-[8px] md:mb-[24px] md:pt-0\"\n title={pageCommon?.ruleLabel}\n ruleClassName=\"text-[#1d1d1f] font-bold\"\n />\n )}\n </Container>\n )\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { Container, Heading, Tabs, TabsList, TabsTrigger } from '@anker-in/headless-ui'\nimport classNames from 'classnames'\nimport { useCallback, useMemo, useState } from 'react'\n\nimport RedeemCouponModal from './RedeemCouponModal'\nimport RedeemProductModal from './RedeemProductModal'\nimport RedeemVirtualProductModal from './RedeemVirtualProductModal'\nimport { useCreditsContext } from '../context/provider'\nimport useRedeemableList from '../context/hooks/useRedeemableList'\nimport { AlpcConsumeType, AlpcErrorCode, ConsumeType } from '../context/const'\nimport { useHeadlessContext, useProductsByHandles, gaTrack, classNames as cn } from '@anker-in/lib'\nimport type { RedeemableItem as RedeemableItemType } from '../type'\nimport { RedeemableItem } from './RedeemableItem'\nimport { ROUNDED_BRANDS } from '../../../constants'\nimport RulesModal from '../modal/RulesModal'\nimport { CreditsRedeemListCopy } from './type'\nimport { useRegistration } from '../../../components/registration'\nimport { numberFormat } from '../context/utils'\nimport useMyRewards from '../context/hooks/useMyRewards'\n\nexport const CreditsRedeemList = ({ copy, id }: { copy: CreditsRedeemListCopy; id?: string }) => {\n const {\n profile,\n openSignUpPopup,\n gtm: { pageGroup },\n pageCommon,\n creditInfo,\n } = useCreditsContext()\n const { authCodeActivate } = useRegistration()\n const { brand } = useHeadlessContext()\n const rounded = ROUNDED_BRANDS.includes(brand)\n\n const isLogin = Object.keys(profile || {}).length > 0\n\n const [activeTab, setActiveTab] = useState<string>(copy.list?.[0]?.label || '')\n\n const [popRedeemData, setPopRedeemData] = useState<RedeemableItemType | undefined>(undefined)\n\n const [rules, setRules] = useState<string | string[]>()\n\n const { listLoading, redeemableList, getRedeemableList } = useRedeemableList()\n\n // \u83B7\u53D6\u7528\u6237\u7684 ExternalProduct \u5151\u6362\u8BB0\u5F55\n const { myRewards } = useMyRewards({\n page: 1,\n pageSize: 100,\n consumeType: AlpcConsumeType.ExternalProduct,\n })\n\n // \u5408\u5E76 redeemModal \u6587\u6848\uFF0C\u4F18\u5148\u4F7F\u7528 copy.redeemModal\uFF0Cfallback \u5230 pageCommon.redeemModal\n const redeemModalCopy = useMemo(() => {\n return {\n ...(pageCommon?.redeemModal || {}),\n ...(copy.redeemModal || {}),\n }\n }, [copy.redeemModal, pageCommon?.redeemModal])\n\n const alpcList = useMemo(() => {\n return redeemableList.map(item => {\n return {\n id: item.id.toString(),\n title: item.name,\n consumeCredits: item.consume_credits,\n remainingInventory: item.remaining_inventory,\n isLimited: !!item.is_limited,\n consumeType: item.consume_type,\n handle: item.sku_handle,\n sku: item.goods_sku,\n image: item.goods_url,\n }\n })\n }, [copy.list, activeTab, redeemableList])\n\n const handles = alpcList.map(item => item.handle)\n const { data: products } = useProductsByHandles({ handles })\n\n const list = useMemo(() => {\n const currentList = copy.list?.find(item => item.label === activeTab)\n return (currentList?.list || [])\n .filter(item => alpcList.some(alpcItem => String(alpcItem.id) === String(item.id)))\n .map(item => {\n const alpcItem = alpcList.find(alpcItem => String(alpcItem.id) === String(item.id))\n const product = products?.find(product => product.handle === alpcItem?.handle)\n const variant = product?.variants.find(variant => variant.sku === alpcItem?.sku)\n // \u8FC7\u6EE4\u6389\u5E93\u5B58\u4E0D\u8DB3\u7684\u5546\u54C1\n if (alpcItem?.isLimited && (!alpcItem?.remainingInventory || alpcItem.remainingInventory <= 0)) return null\n if (alpcItem?.consumeType === AlpcConsumeType.Product && (!product || !variant)) return null\n\n // \u68C0\u67E5 GoGift \u662F\u5426\u5DF2\u7ECF\u5151\u6362\u8FC7\uFF08\u53EA\u6709 GoGift \u9650\u5236\u5151\u6362\u4E00\u6B21\uFF09\n const hasRedeemed = item.type === ConsumeType.GoGift &&\n isLogin &&\n myRewards.some(reward => reward.rule_id === Number(item.id))\n\n return {\n alpc: alpcList.find(alpcItem => String(alpcItem.id) === String(item.id)),\n config: item,\n product,\n variant,\n hasRedeemed,\n productHref: item.href,\n }\n })\n .filter(item => item !== null) as unknown as RedeemableItemType[]\n }, [alpcList, products, isLogin, myRewards])\n\n const handleRedeemError = useCallback(\n (errorCode: AlpcErrorCode) => {\n if (errorCode === AlpcErrorCode.CodeLpcRuleInventoryNotEnough) {\n getRedeemableList()\n }\n },\n [getRedeemableList]\n )\n\n return (\n <Container id={id} className={classNames('relative bg-[#F5F5F7]')}>\n <Heading as=\"h2\" size=\"4\" html={copy.title} />\n\n {/* \u53EF\u7528\u79EF\u5206\u5C55\u793A */}\n {isLogin && copy.availableCredits && (\n <p className=\"mt-[12px] text-[20px] l-xxl:text-[18px] l:text-[16px] font-bold text-[#4A4C56]\">\n {copy.availableCredits.includes('$credits') ? (\n <>\n {copy.availableCredits.split('$credits')[0]}\n <span\n className={cn(\n 'text-brand-color-0',\n brand === 'ankersolix' &&\n 'bg-gradient-to-r from-[#2c7ed0] via-[#00a9e1] via-[43%] to-[#00db84] bg-clip-text text-transparent'\n )}\n >\n {numberFormat(creditInfo?.available_credit || 0).toString()}\n </span>\n {copy.availableCredits.split('$credits')[1] || ''}\n </>\n ) : (\n copy.availableCredits\n )}\n </p>\n )}\n\n <Tabs\n shape={rounded ? 'rounded' : 'square'}\n align=\"left\"\n className={classNames('py-[24px] md:justify-center')}\n value={activeTab.toString()}\n onValueChange={value => {\n setActiveTab(value)\n gaTrack({\n event: 'ga4Event',\n event_name: 'lp_navigation',\n event_parameters: {\n navigation: value,\n page_group: pageGroup,\n },\n })\n }}\n >\n <TabsList>\n {(copy.list || []).map(item => (\n <TabsTrigger key={item.label} value={item.label}>\n {item.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n {/* PC\u7AEF */}\n {!!alpcList?.length && !listLoading && (\n <div\n className={classNames('relative grid grid-cols-4 gap-[16px] md:grid-cols-2 md:gap-[12px] md-xl:grid-cols-3')}\n >\n {list?.map(item => (\n <RedeemableItem\n key={item?.alpc?.id}\n copy={copy}\n item={item}\n onRedeem={(item: RedeemableItemType) => {\n if (!isLogin) {\n openSignUpPopup()\n } else if (!profile?.activated && !authCodeActivate.isActivateSuccess) {\n authCodeActivate.setAutoSendEmail(true)\n authCodeActivate.open()\n } else {\n setPopRedeemData(item)\n }\n }}\n onRulesOpen={setRules}\n />\n ))}\n </div>\n )}\n\n {(popRedeemData?.config?.type === ConsumeType.Coupon ||\n popRedeemData?.config?.type === ConsumeType.ShippingCoupon) &&\n redeemModalCopy?.coupon &&\n popRedeemData && (\n <RedeemCouponModal\n item={popRedeemData}\n copy={redeemModalCopy}\n onError={handleRedeemError}\n onClose={() => {\n setPopRedeemData(undefined)\n }}\n />\n )}\n {popRedeemData?.config?.type === ConsumeType.Product && redeemModalCopy?.product && popRedeemData && (\n <RedeemProductModal\n item={popRedeemData}\n copy={redeemModalCopy}\n onError={handleRedeemError}\n onClose={() => {\n setPopRedeemData(undefined)\n }}\n />\n )}\n {(popRedeemData?.config?.type === ConsumeType.GiftCard || popRedeemData?.config?.type === ConsumeType.GoGift) &&\n redeemModalCopy?.virtualProduct &&\n popRedeemData && (\n <RedeemVirtualProductModal\n item={popRedeemData}\n copy={redeemModalCopy}\n onError={handleRedeemError}\n onClose={() => {\n setPopRedeemData(undefined)\n }}\n />\n )}\n {rules && (\n <RulesModal\n overlayClassName=\"md:px-[16px] md:items-center\"\n className={cn('md:h-fit md:rounded-b-[16px]', !rounded && 'md:rounded-none')}\n isOpen={rules.length > 0}\n onClose={() => setRules([])}\n titleClassName=\"border-b-transparent h-[56px]\"\n rules={rules}\n scrollClassName=\"md:mt-[8px] md:mb-[24px] md:pt-0\"\n title={pageCommon?.ruleLabel}\n ruleClassName=\"text-[#1d1d1f] font-bold\"\n />\n )}\n </Container>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Fragment", "jsx", "jsxs", "Container", "Heading", "Tabs", "TabsList", "TabsTrigger", "classNames", "useCallback", "useMemo", "useState", "RedeemCouponModal", "RedeemProductModal", "RedeemVirtualProductModal", "useCreditsContext", "useRedeemableList", "AlpcConsumeType", "AlpcErrorCode", "ConsumeType", "useHeadlessContext", "useProductsByHandles", "gaTrack", "cn", "RedeemableItem", "ROUNDED_BRANDS", "RulesModal", "useRegistration", "numberFormat", "useMyRewards", "CreditsRedeemList", "copy", "id", "profile", "openSignUpPopup", "pageGroup", "pageCommon", "creditInfo", "authCodeActivate", "brand", "rounded", "isLogin", "activeTab", "setActiveTab", "popRedeemData", "setPopRedeemData", "rules", "setRules", "listLoading", "redeemableList", "getRedeemableList", "myRewards", "redeemModalCopy", "alpcList", "item", "handles", "products", "list", "alpcItem", "product", "variant", "hasRedeemed", "reward", "handleRedeemError", "errorCode", "value"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as t,jsxs as o}from"react/jsx-runtime";import{Button as I,Text as f,Picture as
|
|
1
|
+
import{jsx as t,jsxs as o}from"react/jsx-runtime";import{Button as I,Text as f,Picture as d}from"@anker-in/headless-ui";import{useMemo as s}from"react";import c from"classnames";import{useCreditsContext as k}from"../context/provider";import{AlpcConsumeType as v,ConsumeType as g}from"../context/const";import{numberFormat as P,extractVariantId as b}from"../context/utils";import{gaTrack as h,useHeadlessContext as S}from"@anker-in/lib";import{NoneProductValue as $}from"./NonProductValue";import{ROUNDED_BRANDS as z}from"../../../constants";function M({copy:a,className:y,item:e,onRulesOpen:_,onRedeem:N}){const{creditInfo:u,profile:l,gtm:{pageGroup:m,pageHandle:n},pageCommon:r}=k(),{brand:R}=S(),p=Object.keys(l||{}).length>0,C=z.includes(R),T=s(()=>!!(e.hasRedeemed||e.alpc?.remainingInventory<=0&&e.alpc?.isLimited||e.alpc?.consumeType===v.Product&&!e.variant?.availableForSale||p&&l?.activated&&e.alpc?.consumeCredits>Number(u?.available_credit||0)),[e.hasRedeemed,e.alpc?.remainingInventory,e.alpc?.isLimited,e.alpc?.consumeType,e.alpc?.consumeCredits,p,l?.activated,u?.available_credit,e.variant?.availableForSale]),x=s(()=>p?e.alpc?.consumeType===v.Product?e.variant?.availableForSale?a.btnRedeem:r?.soldOut||"Sold Out":a.btnRedeem:a.unlockRewards,[p,e.alpc?.consumeType,e.variant?.availableForSale,a.btnRedeem,a.unlockRewards,r?.soldOut]),w=s(()=>{if(e.productHref!==void 0)return e.productHref;if(!(e.config?.type!==g.Product||!e.product?.handle))return b(e.variant?.id)?`/products/${e.product.handle}?variant=${b(e.variant?.id)}${n?`&ref=${n}`:""}`:`/products/${e.product.handle}${n?`?ref=${n}`:""}`},[e.productHref,e.config?.type,e.product?.handle,e.variant?.id,n]);return o("div",{className:c("flex flex-col items-center rounded-[16px] bg-[#EAEAEC] p-[24px] md:rounded-[12px] md:px-[8px] xl:py-[16px] md-xl:px-[16px]",!C&&"rounded-none md:rounded-none",y),children:[e.config?.type===g.Product?t("a",{href:w,className:c("relative mx-auto h-[224px] w-fit md:my-[10px] l:h-[120px] l-xxl:h-[138px]"),children:t(d,{className:"h-full w-auto [&_img]:h-full [&_img]:object-contain",source:e.config?.image?.url||e.product?.images?.[0]?.url})}):o("div",{className:"relative mx-auto my-[30px] h-[164px] md:my-0 md:h-[66px] l-xxl:h-[138px] md-l:h-[80px]",children:[t(d,{source:r?.imageMapping?.[e.config?.type]?.url,className:"h-full [&_img]:h-full [&_img]:w-auto [&_img]:object-contain"}),t($,{item:e})]}),o("div",{className:c("mt-[10px] xl:mt-[8px] flex w-full flex-1 flex-col justify-between"),children:[t(f,{html:e.config?.title||e.alpc?.title,title:e.config?.title||e.alpc?.title,size:2,className:"line-clamp-2 h-[58px] text-[24px] leading-[1.2] l:h-[40px] l:text-[16px] l-xxl:h-[48px] l-xxl:text-[20px]"}),e.config?.rules?.length>0&&t("button",{type:"button",onClick:()=>{_(e.config?.rules||[]),h({event:"ga4Event",event_name:"lp_button",member_active_status:l?.activated?"active":"not active",event_parameters:{page_group:m,position:a.title,button_name:r?.ruleLabel,info:e.alpc?.id?.toString()}})},className:"mt-[8px] w-fit text-[16px] font-bold underline md:text-[14px] l:mt-0",tabIndex:0,onKeyDown:i=>{(i.key==="Enter"||i.key===" ")&&i.preventDefault()},children:r?.ruleLabel}),o("div",{children:[o("div",{className:"mt-[26px] flex items-center l:mt-[12px] l-xl:mt-[16px]",children:[t(d,{className:"size-[24px] l-xxl:size-[22px] md-l:size-[18px] md:size-[16px]",source:"https://cdn.shopify.com/s/files/1/0511/6346/3874/files/icon_hire_purchase.png?v=1757496783"}),t(f,{html:`${P(e.alpc?.consumeCredits)}`,size:2,as:"p",className:"ml-[4px] text-[24px] font-bold mt-[4px] leading-none l-xxl:text-[20px] l:text-[16px] "})]}),t(I,{disabled:T,variant:"primary",size:"lg",className:"mt-[8px] md:px-[8px] l:w-full",onClick:()=>{N(e),h({event:"ga4Event",event_name:"lp_button",member_active_status:l?.activated?"active":"not active",event_parameters:{page_group:m,position:a.title,button_name:x,info:e.alpc?.id?.toString()}})},children:x})]})]})]})}export{M as RedeemableItem};
|
|
2
2
|
//# sourceMappingURL=RedeemableItem.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/credits/creditsRedeemList/RedeemableItem.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Button, Text, Picture } from '@anker-in/headless-ui'\n\nimport { useMemo } from 'react'\n\nimport classNames from 'classnames'\nimport { useCreditsContext } from '../context/provider'\nimport type { RedeemableItem as RedeemableItemType } from '../type'\nimport { AlpcConsumeType, ConsumeType } from '../context/const'\nimport { numberFormat, extractVariantId } from '../context/utils'\nimport type { CreditsRedeemListCopy } from './type'\nimport { gaTrack, useHeadlessContext } from '@anker-in/lib'\nimport { NoneProductValue } from './NonProductValue'\nimport { ROUNDED_BRANDS } from '../../../constants'\n\nexport function RedeemableItem({\n copy,\n className,\n item,\n onRulesOpen,\n onRedeem,\n}: {\n copy: CreditsRedeemListCopy\n className?: string\n item: RedeemableItemType\n onRulesOpen: (rules: string[]) => void\n onRedeem: (item: RedeemableItemType) => void\n}) {\n const {\n creditInfo,\n profile,\n gtm: { pageGroup, pageHandle },\n pageCommon,\n } = useCreditsContext()\n const { brand } = useHeadlessContext()\n const isLogin = Object.keys(profile || {}).length > 0\n const rounded = ROUNDED_BRANDS.includes(brand)\n\n const isDisabled = useMemo(() => {\n if (item.hasRedeemed) {\n return true\n }\n\n if (item.alpc?.remainingInventory <= 0 && item.alpc?.isLimited) {\n // \u6709\u5E93\u5B58\u9650\u5236\n return true\n }\n\n if (item.alpc?.consumeType === AlpcConsumeType.Product) {\n if (!item.variant?.availableForSale) {\n return true\n }\n }\n if (isLogin && profile?.activated && item.alpc?.consumeCredits > Number(creditInfo?.available_credit || 0)) {\n return true\n }\n return false\n }, [\n item.hasRedeemed,\n item.alpc?.remainingInventory,\n item.alpc?.isLimited,\n item.alpc?.consumeType,\n item.alpc?.consumeCredits,\n isLogin,\n profile?.activated,\n creditInfo?.available_credit,\n item.variant?.availableForSale,\n ])\n\n const redeemButtonText = useMemo(() => {\n if (!isLogin) {\n return copy.unlockRewards\n }\n\n // \u7F3A\u8D27\u6587\u6848\n if (item.alpc?.consumeType === AlpcConsumeType.Product) {\n return item.variant?.availableForSale ? copy.btnRedeem : pageCommon?.soldOut || 'Sold Out'\n }\n return copy.btnRedeem\n }, [\n isLogin,\n item.alpc?.consumeType,\n item.variant?.availableForSale,\n copy.btnRedeem,\n copy.unlockRewards,\n pageCommon?.soldOut,\n ])\n\n // \u751F\u6210\u4EA7\u54C1 listing \u9875\u9762\u94FE\u63A5\n const productUrl = useMemo(() => {\n if (item.config?.type !== ConsumeType.Product || !item.product?.handle) {\n return undefined\n }\n return extractVariantId(item.variant?.id)\n ? `/products/${item.product.handle}?variant=${extractVariantId(item.variant?.id)}${pageHandle ? `&ref=${pageHandle}` : ''}`\n : `/products/${item.product.handle}${pageHandle ? `?ref=${pageHandle}` : ''}`\n }, [item.config?.type, item.product?.handle, item.variant?.id, pageHandle])\n\n return (\n <div\n className={classNames(\n 'flex flex-col items-center rounded-[16px] bg-[#EAEAEC] p-[24px] md:rounded-[12px] md:px-[8px] xl:py-[16px] md-xl:px-[16px]',\n !rounded && 'rounded-none md:rounded-none',\n className\n )}\n >\n {item.config?.type === ConsumeType.Product ? (\n <a\n href={productUrl}\n className={classNames('relative mx-auto h-[224px] w-fit md:my-[10px] l:h-[120px] l-xxl:h-[138px]')}\n >\n <Picture\n className=\"h-full w-auto [&_img]:h-full [&_img]:object-contain\"\n source={item.config?.image?.url || item.product?.images?.[0]?.url}\n ></Picture>\n </a>\n ) : (\n <div className=\"relative mx-auto my-[30px] h-[164px] md:my-0 md:h-[66px] l-xxl:h-[138px] md-l:h-[80px]\">\n <Picture\n source={pageCommon?.imageMapping?.[item.config?.type]?.url}\n className=\"h-full [&_img]:h-full [&_img]:w-auto [&_img]:object-contain\"\n ></Picture>\n\n <NoneProductValue item={item} />\n </div>\n )}\n <div className={classNames('mt-[10px] xl:mt-[8px] flex w-full flex-1 flex-col justify-between')}>\n <Text\n html={item.config?.title || item.alpc?.title}\n title={item.config?.title || item.alpc?.title}\n size={2}\n className=\"line-clamp-2 h-[58px] text-[24px] leading-[1.2] l:h-[40px] l:text-[16px] l-xxl:h-[48px] l-xxl:text-[20px]\"\n />\n {item.config?.rules?.length > 0 && (\n <button\n type=\"button\"\n onClick={() => {\n onRulesOpen(item.config?.rules || [])\n gaTrack({\n event: 'ga4Event',\n event_name: 'lp_button',\n member_active_status: profile?.activated ? 'active' : 'not active',\n event_parameters: {\n page_group: pageGroup,\n position: copy.title,\n button_name: pageCommon?.ruleLabel,\n info: item.alpc?.id?.toString(),\n },\n })\n }}\n className=\"mt-[8px] w-fit text-[16px] font-bold underline md:text-[14px] l:mt-0\"\n tabIndex={0}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n }\n }}\n >\n {pageCommon?.ruleLabel}\n </button>\n )}\n <div>\n <div className=\"mt-[26px] flex items-center l:mt-[12px] l-xl:mt-[16px]\">\n <Picture\n className=\"size-[24px] l-xxl:size-[22px] md-l:size-[18px] md:size-[16px]\"\n source=\"https://cdn.shopify.com/s/files/1/0511/6346/3874/files/icon_hire_purchase.png?v=1757496783\"\n />\n <Text\n html={`${numberFormat(item.alpc?.consumeCredits)}`}\n size={2}\n as=\"p\"\n className=\"ml-[4px] text-[24px] font-bold mt-[4px] leading-none l-xxl:text-[20px] l:text-[16px] \"\n />\n </div>\n\n <Button\n disabled={isDisabled}\n variant=\"primary\"\n size=\"lg\"\n className=\"mt-[8px] md:px-[8px] l:w-full\"\n onClick={() => {\n onRedeem(item)\n gaTrack({\n event: 'ga4Event',\n event_name: 'lp_button',\n member_active_status: profile?.activated ? 'active' : 'not active',\n event_parameters: {\n page_group: pageGroup,\n position: copy.title,\n button_name: redeemButtonText,\n info: item.alpc?.id?.toString(),\n },\n })\n }}\n >\n {redeemButtonText}\n </Button>\n </div>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { Button, Text, Picture } from '@anker-in/headless-ui'\n\nimport { useMemo } from 'react'\n\nimport classNames from 'classnames'\nimport { useCreditsContext } from '../context/provider'\nimport type { RedeemableItem as RedeemableItemType } from '../type'\nimport { AlpcConsumeType, ConsumeType } from '../context/const'\nimport { numberFormat, extractVariantId } from '../context/utils'\nimport type { CreditsRedeemListCopy } from './type'\nimport { gaTrack, useHeadlessContext } from '@anker-in/lib'\nimport { NoneProductValue } from './NonProductValue'\nimport { ROUNDED_BRANDS } from '../../../constants'\n\nexport function RedeemableItem({\n copy,\n className,\n item,\n onRulesOpen,\n onRedeem,\n}: {\n copy: CreditsRedeemListCopy\n className?: string\n item: RedeemableItemType\n onRulesOpen: (rules: string[]) => void\n onRedeem: (item: RedeemableItemType) => void\n}) {\n const {\n creditInfo,\n profile,\n gtm: { pageGroup, pageHandle },\n pageCommon,\n } = useCreditsContext()\n const { brand } = useHeadlessContext()\n const isLogin = Object.keys(profile || {}).length > 0\n const rounded = ROUNDED_BRANDS.includes(brand)\n\n const isDisabled = useMemo(() => {\n if (item.hasRedeemed) {\n return true\n }\n\n if (item.alpc?.remainingInventory <= 0 && item.alpc?.isLimited) {\n // \u6709\u5E93\u5B58\u9650\u5236\n return true\n }\n\n if (item.alpc?.consumeType === AlpcConsumeType.Product) {\n if (!item.variant?.availableForSale) {\n return true\n }\n }\n if (isLogin && profile?.activated && item.alpc?.consumeCredits > Number(creditInfo?.available_credit || 0)) {\n return true\n }\n return false\n }, [\n item.hasRedeemed,\n item.alpc?.remainingInventory,\n item.alpc?.isLimited,\n item.alpc?.consumeType,\n item.alpc?.consumeCredits,\n isLogin,\n profile?.activated,\n creditInfo?.available_credit,\n item.variant?.availableForSale,\n ])\n\n const redeemButtonText = useMemo(() => {\n if (!isLogin) {\n return copy.unlockRewards\n }\n\n // \u7F3A\u8D27\u6587\u6848\n if (item.alpc?.consumeType === AlpcConsumeType.Product) {\n return item.variant?.availableForSale ? copy.btnRedeem : pageCommon?.soldOut || 'Sold Out'\n }\n return copy.btnRedeem\n }, [\n isLogin,\n item.alpc?.consumeType,\n item.variant?.availableForSale,\n copy.btnRedeem,\n copy.unlockRewards,\n pageCommon?.soldOut,\n ])\n\n // \u751F\u6210\u4EA7\u54C1 listing \u9875\u9762\u94FE\u63A5\n const productUrl = useMemo(() => {\n if (item.productHref !== undefined) {\n return item.productHref\n }\n if (item.config?.type !== ConsumeType.Product || !item.product?.handle) {\n return undefined\n }\n return extractVariantId(item.variant?.id)\n ? `/products/${item.product.handle}?variant=${extractVariantId(item.variant?.id)}${pageHandle ? `&ref=${pageHandle}` : ''}`\n : `/products/${item.product.handle}${pageHandle ? `?ref=${pageHandle}` : ''}`\n }, [item.productHref, item.config?.type, item.product?.handle, item.variant?.id, pageHandle])\n\n return (\n <div\n className={classNames(\n 'flex flex-col items-center rounded-[16px] bg-[#EAEAEC] p-[24px] md:rounded-[12px] md:px-[8px] xl:py-[16px] md-xl:px-[16px]',\n !rounded && 'rounded-none md:rounded-none',\n className\n )}\n >\n {item.config?.type === ConsumeType.Product ? (\n <a\n href={productUrl}\n className={classNames('relative mx-auto h-[224px] w-fit md:my-[10px] l:h-[120px] l-xxl:h-[138px]')}\n >\n <Picture\n className=\"h-full w-auto [&_img]:h-full [&_img]:object-contain\"\n source={item.config?.image?.url || item.product?.images?.[0]?.url}\n ></Picture>\n </a>\n ) : (\n <div className=\"relative mx-auto my-[30px] h-[164px] md:my-0 md:h-[66px] l-xxl:h-[138px] md-l:h-[80px]\">\n <Picture\n source={pageCommon?.imageMapping?.[item.config?.type]?.url}\n className=\"h-full [&_img]:h-full [&_img]:w-auto [&_img]:object-contain\"\n ></Picture>\n\n <NoneProductValue item={item} />\n </div>\n )}\n <div className={classNames('mt-[10px] xl:mt-[8px] flex w-full flex-1 flex-col justify-between')}>\n <Text\n html={item.config?.title || item.alpc?.title}\n title={item.config?.title || item.alpc?.title}\n size={2}\n className=\"line-clamp-2 h-[58px] text-[24px] leading-[1.2] l:h-[40px] l:text-[16px] l-xxl:h-[48px] l-xxl:text-[20px]\"\n />\n {item.config?.rules?.length > 0 && (\n <button\n type=\"button\"\n onClick={() => {\n onRulesOpen(item.config?.rules || [])\n gaTrack({\n event: 'ga4Event',\n event_name: 'lp_button',\n member_active_status: profile?.activated ? 'active' : 'not active',\n event_parameters: {\n page_group: pageGroup,\n position: copy.title,\n button_name: pageCommon?.ruleLabel,\n info: item.alpc?.id?.toString(),\n },\n })\n }}\n className=\"mt-[8px] w-fit text-[16px] font-bold underline md:text-[14px] l:mt-0\"\n tabIndex={0}\n onKeyDown={e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n }\n }}\n >\n {pageCommon?.ruleLabel}\n </button>\n )}\n <div>\n <div className=\"mt-[26px] flex items-center l:mt-[12px] l-xl:mt-[16px]\">\n <Picture\n className=\"size-[24px] l-xxl:size-[22px] md-l:size-[18px] md:size-[16px]\"\n source=\"https://cdn.shopify.com/s/files/1/0511/6346/3874/files/icon_hire_purchase.png?v=1757496783\"\n />\n <Text\n html={`${numberFormat(item.alpc?.consumeCredits)}`}\n size={2}\n as=\"p\"\n className=\"ml-[4px] text-[24px] font-bold mt-[4px] leading-none l-xxl:text-[20px] l:text-[16px] \"\n />\n </div>\n\n <Button\n disabled={isDisabled}\n variant=\"primary\"\n size=\"lg\"\n className=\"mt-[8px] md:px-[8px] l:w-full\"\n onClick={() => {\n onRedeem(item)\n gaTrack({\n event: 'ga4Event',\n event_name: 'lp_button',\n member_active_status: profile?.activated ? 'active' : 'not active',\n event_parameters: {\n page_group: pageGroup,\n position: copy.title,\n button_name: redeemButtonText,\n info: item.alpc?.id?.toString(),\n },\n })\n }}\n >\n {redeemButtonText}\n </Button>\n </div>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["jsx", "jsxs", "Button", "Text", "Picture", "useMemo", "classNames", "useCreditsContext", "AlpcConsumeType", "ConsumeType", "numberFormat", "extractVariantId", "gaTrack", "useHeadlessContext", "NoneProductValue", "ROUNDED_BRANDS", "RedeemableItem", "copy", "className", "item", "onRulesOpen", "onRedeem", "creditInfo", "profile", "pageGroup", "pageHandle", "pageCommon", "brand", "isLogin", "rounded", "isDisabled", "redeemButtonText", "productUrl", "e"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as t,jsxs as g}from"react/jsx-runtime";import{useCallback as T,useEffect as P,useState as l}from"react";import{Button as
|
|
1
|
+
import{jsx as t,jsxs as g}from"react/jsx-runtime";import{useCallback as T,useEffect as P,useState as l}from"react";import{useRouter as k}from"next/router";import{Button as A,Checkbox as D,Picture as I,Text as x}from"@anker-in/headless-ui";import{classNames as n,fetcher as L,gaTrack as b,useHeadlessContext as R}from"@anker-in/lib";import r from"js-cookie";import{parse as B}from"query-string";import F from"crypto-js/sha256";import{useCreditsContext as H}from"../context/provider";import{ROUNDED_BRANDS as q}from"../../../constants";import{emailValidate as O}from"../context/utils";import{CreditsModalContainer as U}from"./ModalContainer";const V=()=>{if(typeof window>"u")return{register_source:""};const{search:e,href:a}=window.location||{},o=B(e);return{fbuy_ref_code:r.get("fbuy_ref_code"),affiliate:r.get("affiliate"),ref:r.get("ref_ads"),inviter_code:o.ic||o.inviter_code||r.get("inviter_code"),register_source:o.redirect||r.get("reg_source")||a,deals_type:r.get("deal"),transfer_id:r.get("transfer_id")}};function ee({copy:e,onSuccess:a,...o}){const{brand:p}=R(),m=q.includes(p),{locale:h}=k(),[d,M]=l(!1),[s,v]=l(""),[_,i]=l(""),[C,y]=l(""),[w,N]=l(!1),{profile:c}=H(),S=T(u=>{i(""),v(u.target?.value?.trim())},[]),E=T(async()=>{if(i(""),!s)return i("Please fill in your email");if(!O(s))return i("Invalid email address");if(!d)return i("Please agree to the policy");N(!0);const{register_source:u}=V(),f=await L({locale:h,action:"subscribe",url:"/api/multipass/subscribe/subscribe_emails",method:"POST",body:{email:s,register_source:u,brand:p,deals_type:e.dealsType||"vip_subscribe"},headers:{},type:""});N(!1),f.errors?i(f.errors||f.statusText):(y(e.successTips||"Subscribed successfully!"),a&&a(),setTimeout(()=>{y("")},3e3),b({subscribe_hashed_email:s?F(s):""}),b({event:"ga4Event",event_name:"subscribe",event_parameters:{page_group:e.dealsType||"vip_subscribe",position:"pop_up"}}),b({event:"uaEvent",eventCategory:"subscribe",eventAction:e.dealsType||"vip_subscribe",eventLabel:"pop_up",nonInteraction:!1}))},[s,d,h,p,e.dealsType,e.successTips,a]);return P(()=>{c&&c?.email&&v(c?.email)},[c]),t(U,{className:"w-[540px] md:h-auto",scrollClassName:"mb-[40px] min-l:px-[48px] md:mb-[24px]",titleClassName:"h-[56px]",useAnimation:!0,animationClassName:"md:translate-y-[100vh]",...o,children:g("div",{className:"flex flex-col gap-[16px] text-center min-l:px-[16px]",children:[t("div",{children:t(x,{className:n("mb-[24px] text-[22px] font-bold"),html:e.title})}),e.desc&&t(x,{className:"mb-[8px] text-left text-[16px] font-semibold leading-[1.4] text-[#1F2021]",html:e.desc}),g("div",{className:n("relative flex h-[52px] w-full overflow-hidden rounded-[2px] md:grid md:h-auto md:grid-rows-1 md:gap-[16px]",!m&&"rounded-none"),children:[t("input",{className:n("h-full flex-1 rounded-l-[2px] border-[1px] border-[#d8d8d8] px-[14px] py-[17px] text-[16px] font-semibold leading-[1] outline-none placeholder:text-[#999] md:h-[52px] md:rounded-[2px]",!m&&"rounded-none"),placeholder:e.placeholder,value:s,onChange:S}),t(A,{variant:"primary",onClick:E,loading:w,className:n("legacy-headless-ui-primary-button !h-full !min-w-0 !rounded-l-none !rounded-r-[2px] !px-[40px] !py-[13px]",!m&&"rounded-none"),children:t(I,{source:"https://cdn.shopify.com/s/files/1/0512/8568/8505/files/icon_email.png?v=1697527383",className:"h-[24px] w-[24px]",alt:"email"})})]}),g("div",{className:"flex w-full",children:[t(D,{checked:d,onCheckedChange:()=>M(!d),required:!0,className:"border-[#1d1d1f]"}),t("label",{className:"text-left ml-2 text-[14px] font-semibold text-[#777] [&_a]:underline",dangerouslySetInnerHTML:{__html:e?.policy||""}})]}),t("div",{className:n("w-full text-left text-[16px] font-semibold",_&&"text-[#F84D4F]",C&&"text-[#52C41A]"),children:t(x,{html:C||_||""})})]})})}export{ee as CreditsSubscribeModal};
|
|
2
2
|
//# sourceMappingURL=SubscribeModal.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/components/credits/modal/SubscribeModal.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useCallback, useEffect, useState } from 'react'\nimport { Button, Checkbox, Picture, Text } from '@anker-in/headless-ui'\nimport { classNames, fetcher, gaTrack, useHeadlessContext } from '@anker-in/lib'\nimport Cookies from 'js-cookie'\nimport { parse } from 'query-string'\nimport sha256 from 'crypto-js/sha256'\nimport { useCreditsContext } from '../context/provider'\nimport { ROUNDED_BRANDS } from '../../../constants'\nimport { emailValidate } from '../context/utils'\nimport { CreditsModalContainer, type ModalContainerProps } from './ModalContainer'\n\nexport type CreditsSubscribeModalCopy = {\n title: string\n desc?: string\n placeholder: string\n policy?: string\n successTips?: string\n dealsType?: string\n}\n\ninterface CreditsSubscribeModalProps extends ModalContainerProps {\n copy: CreditsSubscribeModalCopy\n onSuccess?: () => void\n}\n\nconst getAdCookie = () => {\n if (typeof window === 'undefined') {\n return { register_source: '' }\n }\n const { search, href } = window.location || {}\n const query = parse(search)\n\n return {\n fbuy_ref_code: Cookies.get('fbuy_ref_code'),\n affiliate: Cookies.get('affiliate'),\n ref: Cookies.get('ref_ads'),\n inviter_code: query.ic || query.inviter_code || Cookies.get('inviter_code'),\n register_source: query.redirect || Cookies.get('reg_source') || href,\n deals_type: Cookies.get('deal'),\n transfer_id: Cookies.get('transfer_id'),\n }\n}\n\nexport function CreditsSubscribeModal({ copy, onSuccess, ...props }: CreditsSubscribeModalProps) {\n const { brand
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["jsx", "jsxs", "useCallback", "useEffect", "useState", "Button", "Checkbox", "Picture", "Text", "classNames", "fetcher", "gaTrack", "useHeadlessContext", "Cookies", "parse", "sha256", "useCreditsContext", "ROUNDED_BRANDS", "emailValidate", "CreditsModalContainer", "getAdCookie", "search", "href", "query", "CreditsSubscribeModal", "copy", "onSuccess", "props", "brand", "
|
|
4
|
+
"sourcesContent": ["import { useCallback, useEffect, useState } from 'react'\nimport { useRouter } from 'next/router'\nimport { Button, Checkbox, Picture, Text } from '@anker-in/headless-ui'\nimport { classNames, fetcher, gaTrack, useHeadlessContext } from '@anker-in/lib'\nimport Cookies from 'js-cookie'\nimport { parse } from 'query-string'\nimport sha256 from 'crypto-js/sha256'\nimport { useCreditsContext } from '../context/provider'\nimport { ROUNDED_BRANDS } from '../../../constants'\nimport { emailValidate } from '../context/utils'\nimport { CreditsModalContainer, type ModalContainerProps } from './ModalContainer'\n\nexport type CreditsSubscribeModalCopy = {\n title: string\n desc?: string\n placeholder: string\n policy?: string\n successTips?: string\n dealsType?: string\n}\n\ninterface CreditsSubscribeModalProps extends ModalContainerProps {\n copy: CreditsSubscribeModalCopy\n onSuccess?: () => void\n}\n\nconst getAdCookie = () => {\n if (typeof window === 'undefined') {\n return { register_source: '' }\n }\n const { search, href } = window.location || {}\n const query = parse(search)\n\n return {\n fbuy_ref_code: Cookies.get('fbuy_ref_code'),\n affiliate: Cookies.get('affiliate'),\n ref: Cookies.get('ref_ads'),\n inviter_code: query.ic || query.inviter_code || Cookies.get('inviter_code'),\n register_source: query.redirect || Cookies.get('reg_source') || href,\n deals_type: Cookies.get('deal'),\n transfer_id: Cookies.get('transfer_id'),\n }\n}\n\nexport function CreditsSubscribeModal({ copy, onSuccess, ...props }: CreditsSubscribeModalProps) {\n const { brand } = useHeadlessContext()\n const rounded = ROUNDED_BRANDS.includes(brand)\n const { locale } = useRouter()\n const [policy, setPolicy] = useState(false)\n const [email, setEmail] = useState('')\n const [errorMessage, setErrorMessage] = useState('')\n const [successMessage, setSuccessMessage] = useState('')\n const [loading, setLoading] = useState(false)\n const { profile } = useCreditsContext()\n\n const handleEmailChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setErrorMessage('')\n setEmail(event.target?.value?.trim())\n }, [])\n\n const handleSubmit = useCallback(async () => {\n setErrorMessage('')\n if (!email) {\n return setErrorMessage('Please fill in your email')\n }\n\n if (!emailValidate(email)) {\n return setErrorMessage('Invalid email address')\n }\n\n if (!policy) {\n return setErrorMessage('Please agree to the policy')\n }\n\n setLoading(true)\n const { register_source } = getAdCookie()\n\n const result = await fetcher({\n locale,\n action: 'subscribe',\n url: '/api/multipass/subscribe/subscribe_emails',\n method: 'POST',\n body: {\n email,\n register_source,\n brand,\n deals_type: copy.dealsType || 'vip_subscribe',\n },\n headers: {},\n type: '',\n })\n setLoading(false)\n\n if (!result.errors) {\n setSuccessMessage(copy.successTips || 'Subscribed successfully!')\n if (onSuccess) {\n onSuccess()\n }\n setTimeout(() => {\n setSuccessMessage('')\n }, 3000)\n gaTrack({\n subscribe_hashed_email: email ? sha256(email) : '',\n })\n gaTrack({\n event: 'ga4Event',\n event_name: 'subscribe',\n event_parameters: {\n page_group: copy.dealsType || 'vip_subscribe',\n position: 'pop_up',\n },\n })\n gaTrack({\n event: 'uaEvent',\n eventCategory: 'subscribe',\n eventAction: copy.dealsType || 'vip_subscribe',\n eventLabel: 'pop_up',\n nonInteraction: false,\n })\n } else {\n setErrorMessage(result.errors || result.statusText)\n }\n }, [email, policy, locale, brand, copy.dealsType, copy.successTips, onSuccess])\n\n useEffect(() => {\n if (profile && profile?.email) {\n setEmail(profile?.email)\n }\n }, [profile])\n\n return (\n <CreditsModalContainer\n className=\"w-[540px] md:h-auto\"\n scrollClassName=\"mb-[40px] min-l:px-[48px] md:mb-[24px]\"\n titleClassName=\"h-[56px]\"\n useAnimation\n animationClassName=\"md:translate-y-[100vh]\"\n {...props}\n >\n <div className=\"flex flex-col gap-[16px] text-center min-l:px-[16px]\">\n <div>\n <Text className={classNames('mb-[24px] text-[22px] font-bold')} html={copy.title}></Text>\n </div>\n {copy.desc && (\n <Text\n className=\"mb-[8px] text-left text-[16px] font-semibold leading-[1.4] text-[#1F2021]\"\n html={copy.desc}\n ></Text>\n )}\n <div\n className={classNames(\n 'relative flex h-[52px] w-full overflow-hidden rounded-[2px] md:grid md:h-auto md:grid-rows-1 md:gap-[16px]',\n !rounded && 'rounded-none'\n )}\n >\n <input\n className={classNames(\n 'h-full flex-1 rounded-l-[2px] border-[1px] border-[#d8d8d8] px-[14px] py-[17px] text-[16px] font-semibold leading-[1] outline-none placeholder:text-[#999] md:h-[52px] md:rounded-[2px]',\n !rounded && 'rounded-none'\n )}\n placeholder={copy.placeholder}\n value={email}\n onChange={handleEmailChange}\n />\n <Button\n variant=\"primary\"\n onClick={handleSubmit}\n loading={loading}\n className={classNames(\n 'legacy-headless-ui-primary-button !h-full !min-w-0 !rounded-l-none !rounded-r-[2px] !px-[40px] !py-[13px]',\n !rounded && 'rounded-none'\n )}\n >\n <Picture\n source=\"https://cdn.shopify.com/s/files/1/0512/8568/8505/files/icon_email.png?v=1697527383\"\n className=\"h-[24px] w-[24px]\"\n alt=\"email\"\n />\n </Button>\n </div>\n <div className=\"flex w-full\">\n <Checkbox checked={policy} onCheckedChange={() => setPolicy(!policy)} required className=\"border-[#1d1d1f]\" />\n <label\n className=\"text-left ml-2 text-[14px] font-semibold text-[#777] [&_a]:underline\"\n dangerouslySetInnerHTML={{\n __html: copy?.policy || '',\n }}\n />\n </div>\n <div\n className={classNames(\n 'w-full text-left text-[16px] font-semibold',\n errorMessage && 'text-[#F84D4F]',\n successMessage && 'text-[#52C41A]'\n )}\n >\n <Text html={successMessage || errorMessage || ''} />\n </div>\n </div>\n </CreditsModalContainer>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["jsx", "jsxs", "useCallback", "useEffect", "useState", "useRouter", "Button", "Checkbox", "Picture", "Text", "classNames", "fetcher", "gaTrack", "useHeadlessContext", "Cookies", "parse", "sha256", "useCreditsContext", "ROUNDED_BRANDS", "emailValidate", "CreditsModalContainer", "getAdCookie", "search", "href", "query", "CreditsSubscribeModal", "copy", "onSuccess", "props", "brand", "rounded", "locale", "policy", "setPolicy", "email", "setEmail", "errorMessage", "setErrorMessage", "successMessage", "setSuccessMessage", "loading", "setLoading", "profile", "handleEmailChange", "event", "handleSubmit", "register_source", "result"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function getAsyncError(res: {
|
|
2
|
+
json: () => any;
|
|
3
|
+
status: any;
|
|
4
|
+
statusText: any;
|
|
5
|
+
}): Promise<{
|
|
6
|
+
status: any;
|
|
7
|
+
statusText: any;
|
|
8
|
+
errors: any;
|
|
9
|
+
type: any;
|
|
10
|
+
data: any;
|
|
11
|
+
message: any;
|
|
12
|
+
} | undefined>;
|
|
13
|
+
declare const handleFetchResponse: (res: Response) => Promise<any>;
|
|
14
|
+
export default handleFetchResponse;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
async function e(a){try{const t=await a.json();return{status:a.status,statusText:a.statusText,errors:t?.data?.error||t?.data?.code||a.statusText||a.status,type:t?.data?.type,data:t?.data,message:t?.data?.message}}catch(t){console.log(t)}}const o=async a=>{if(a.ok)try{const t=await a.json(),{errors:s}=t;return s&&s.length?{errors:s,status:a.status}:t}catch(t){console.log(t)}return await e(a)};var n=o;export{n as default,e as getAsyncError};
|
|
2
|
+
//# sourceMappingURL=fetchResponse.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/helpers/fetchResponse.ts"],
|
|
4
|
+
"sourcesContent": ["export async function getAsyncError(res: { json: () => any; status: any; statusText: any }) {\n try {\n const result = await res.json()\n return {\n status: res.status,\n statusText: res.statusText,\n errors: result?.data?.error || result?.data?.code || res.statusText || res.status,\n type: result?.data?.type,\n data: result?.data,\n message: result?.data?.message,\n }\n } catch (error) {\n console.log(error)\n }\n}\n\nconst handleFetchResponse = async (res: Response) => {\n if (res.ok) {\n try {\n const result = await res.json()\n const { errors } = result\n if (errors && errors.length) {\n return { errors, status: res.status }\n }\n\n return result\n } catch (error) {\n console.log(error)\n }\n }\n\n return await getAsyncError(res)\n}\n\nexport default handleFetchResponse\n"],
|
|
5
|
+
"mappings": "AAAA,eAAsBA,EAAcC,EAAwD,CAC1F,GAAI,CACF,MAAMC,EAAS,MAAMD,EAAI,KAAK,EAC9B,MAAO,CACL,OAAQA,EAAI,OACZ,WAAYA,EAAI,WAChB,OAAQC,GAAQ,MAAM,OAASA,GAAQ,MAAM,MAAQD,EAAI,YAAcA,EAAI,OAC3E,KAAMC,GAAQ,MAAM,KACpB,KAAMA,GAAQ,KACd,QAASA,GAAQ,MAAM,OACzB,CACF,OAASC,EAAO,CACd,QAAQ,IAAIA,CAAK,CACnB,CACF,CAEA,MAAMC,EAAsB,MAAOH,GAAkB,CACnD,GAAIA,EAAI,GACN,GAAI,CACF,MAAMC,EAAS,MAAMD,EAAI,KAAK,EACxB,CAAE,OAAAI,CAAO,EAAIH,EACnB,OAAIG,GAAUA,EAAO,OACZ,CAAE,OAAAA,EAAQ,OAAQJ,EAAI,MAAO,EAG/BC,CACT,OAASC,EAAO,CACd,QAAQ,IAAIA,CAAK,CACnB,CAGF,OAAO,MAAMH,EAAcC,CAAG,CAChC,EAEA,IAAOK,EAAQF",
|
|
6
|
+
"names": ["getAsyncError", "res", "result", "error", "handleFetchResponse", "errors", "fetchResponse_default"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import f from"./fetchResponse.js";const g=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),y=async({locale:e="en",url:s,method:a="POST",headers:l={},repeatKey:p,body:r,type:c,timeout:t=9e4})=>{let n="";c==="uploadFile"?n=r:n=r?JSON.stringify(r):"";const o=new AbortController;t&&setTimeout(()=>o.abort(),t);const i=await fetch(s,{method:a,mode:"cors",headers:{"current-language":e,...l},...t&&{signal:o.signal},...a!=="GET"&&{body:n}});return f(i)};var u=y;export{u as default};
|
|
2
|
+
//# sourceMappingURL=fetcher.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/helpers/fetcher.ts"],
|
|
4
|
+
"sourcesContent": ["import handleFetchResponse from './fetchResponse.js'\n\nconst isObject = (value: null) => {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nconst fetcher = async ({\n locale = 'en',\n url,\n method = 'POST',\n headers = {},\n repeatKey,\n body,\n type,\n timeout = 90000,\n}: any) => {\n // \u6DFB\u52A0\u8C37\u6B4C\u9A8C\u8BC1\n let bodyData = ''\n if (type === 'uploadFile') {\n bodyData = body\n } else {\n bodyData = body ? JSON.stringify(body) : ''\n }\n\n const controller = new AbortController()\n if (timeout) {\n // \u8D85\u65F6\u62A5\u9519\n setTimeout(() => controller.abort(), timeout)\n }\n\n const data = await fetch(url, {\n method,\n mode: 'cors',\n headers: {\n 'current-language': locale,\n ...headers,\n },\n ...(timeout && { signal: controller.signal }),\n ...(method !== 'GET' && { body: bodyData }),\n })\n return handleFetchResponse(data)\n}\n\nexport default fetcher\n"],
|
|
5
|
+
"mappings": "AAAA,OAAOA,MAAyB,qBAEhC,MAAMC,EAAYC,GACTA,IAAU,MAAQ,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,EAGtEC,EAAU,MAAO,CACrB,OAAAC,EAAS,KACT,IAAAC,EACA,OAAAC,EAAS,OACT,QAAAC,EAAU,CAAC,EACX,UAAAC,EACA,KAAAC,EACA,KAAAC,EACA,QAAAC,EAAU,GACZ,IAAW,CAET,IAAIC,EAAW,GACXF,IAAS,aACXE,EAAWH,EAEXG,EAAWH,EAAO,KAAK,UAAUA,CAAI,EAAI,GAG3C,MAAMI,EAAa,IAAI,gBACnBF,GAEF,WAAW,IAAME,EAAW,MAAM,EAAGF,CAAO,EAG9C,MAAMG,EAAO,MAAM,MAAMT,EAAK,CAC5B,OAAAC,EACA,KAAM,OACN,QAAS,CACP,mBAAoBF,EACpB,GAAGG,CACL,EACA,GAAII,GAAW,CAAE,OAAQE,EAAW,MAAO,EAC3C,GAAIP,IAAW,OAAS,CAAE,KAAMM,CAAS,CAC3C,CAAC,EACD,OAAOZ,EAAoBc,CAAI,CACjC,EAEA,IAAOC,EAAQZ",
|
|
6
|
+
"names": ["handleFetchResponse", "isObject", "value", "fetcher", "locale", "url", "method", "headers", "repeatKey", "body", "type", "timeout", "bodyData", "controller", "data", "fetcher_default"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/helpers/utils.ts"],
|
|
4
|
+
"sourcesContent": ["import { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport function noop(): any {}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAS,QAAAA,MAA6B,OACtC,OAAS,WAAAC,MAAe,iBAEjB,SAASC,KAAMC,EAAsB,CAC1C,OAAOF,EAAQD,EAAKG,CAAM,CAAC,CAC7B,CAEO,SAASC,GAAY,CAAC",
|
|
6
|
+
"names": ["clsx", "twMerge", "cn", "inputs", "noop"]
|
|
7
|
+
}
|
|
@@ -48,5 +48,5 @@ const customRenderers = {
|
|
|
48
48
|
customRenderers={customRenderers}
|
|
49
49
|
/>
|
|
50
50
|
\`\`\`
|
|
51
|
-
`}}},tags:["autodocs"],argTypes:{apiBaseUrl:{control:"text",description:"API \u57FA\u7840 URL"},headers:{control:"object",description:"\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0",table:{defaultValue:{summary:"undefined"}}},recaptchaSitekey:{control:"text",description:"Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1",table:{defaultValue:{summary:"undefined"}}},recaptchaAction:{control:"text",description:"reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F",table:{defaultValue:{summary:'"activity"'}}},site:{control:"text",description:"Shopify \u5E97\u94FA URL"},channelCode:{control:"text",description:"\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053",table:{defaultValue:{summary:"undefined"}}},welcomeMessage:{control:"text",description:"\u6B22\u8FCE\u6D88\u606F",table:{defaultValue:{summary:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}}},logoUrl:{control:"text",description:"Logo URL"},position:{control:"object",description:"\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61",table:{defaultValue:{summary:'{ bottom: "1.5rem", right: "1.5rem" }'}}}},args:{apiBaseUrl:"http://172.16.38.183:3003",site:"www.eufy.com",loginUserId:"test_test",welcomeMessage:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}};var g=c;const m={args:{loginUserId:"test_test1",apiBaseUrl:"https://beta-api-v2-livechat.anker.com",site:"beta.
|
|
51
|
+
`}}},tags:["autodocs"],argTypes:{apiBaseUrl:{control:"text",description:"API \u57FA\u7840 URL"},headers:{control:"object",description:"\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0",table:{defaultValue:{summary:"undefined"}}},recaptchaSitekey:{control:"text",description:"Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1",table:{defaultValue:{summary:"undefined"}}},recaptchaAction:{control:"text",description:"reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F",table:{defaultValue:{summary:'"activity"'}}},site:{control:"text",description:"Shopify \u5E97\u94FA URL"},channelCode:{control:"text",description:"\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053",table:{defaultValue:{summary:"undefined"}}},welcomeMessage:{control:"text",description:"\u6B22\u8FCE\u6D88\u606F",table:{defaultValue:{summary:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}}},logoUrl:{control:"text",description:"Logo URL"},position:{control:"object",description:"\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61",table:{defaultValue:{summary:'{ bottom: "1.5rem", right: "1.5rem" }'}}}},args:{apiBaseUrl:"http://172.16.38.183:3003",site:"www.eufy.com",loginUserId:"test_test",welcomeMessage:"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F"}};var g=c;const m={args:{loginUserId:"test_test1",apiBaseUrl:"https://beta-api-v2-livechat.anker.com",site:"beta.soundcore.com",channelCode:"dtc",title:"eufy AI Assistant",cartId:"gid://shopify/Cart/hWNAAJweS9IkeRKib4LRy9PY?key=ff1f9b24e74b3f11f5574539e7cbbb2f",accessToken:"47b1aa2c0797043f9baba39388029d70",position:{bottom:"24px",right:"30px"},welcomeMessage:"",quickReplies:[{id:"1",label:"Product Info",value:"Tell me about your products",icon:"\u{1F4E6}"},{id:"2",label:"Track Order",value:"I want to track my order",icon:"\u{1F69A}"},{id:"3",label:"Support",value:"I need help with my device",icon:"\u{1F527}"},{id:"4",label:"Recommendations",value:"Recommend products for me",icon:"\u2B50"}],complianceConfig:{title:"Hi! I'm your eufy AI assistant.",content:"AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.",checkboxText:`By starting to use "Live Chat", you agree to Anker's <a href="https://www.anker.com/pages/privacy-policy" target="_blank" rel="noopener noreferrer" style="text-decoration: underline;">LIVE CHAT PRIVACY NOTICE</a>.`,agreeButtonText:"Agree"},recaptchaAction:"livechat",showNewSessionButton:!0,commonText:{learnMore:"Learn More",total:"Total"},customRenderers:{video:{render:t=>{const e=t;return r("div",{className:"w-full",children:[o("video",{src:e.url,controls:!0,className:"w-full rounded-lg",poster:e.poster,children:"Your browser does not support video playback"}),e.title&&o("p",{className:"mt-2 text-sm text-gray-600",children:e.title})]})}},image_gallery:{render:t=>{const a=t.images||[];return o("div",{className:"grid grid-cols-2 gap-2",children:a.map((i,n)=>o("div",{className:"relative aspect-square",children:o("img",{src:i.url,alt:i.alt||`Image ${n+1}`,className:"size-full rounded-lg object-cover"})},n))})}}},productCardRender:(t,e)=>{if(!t)return o("div",{style:{padding:"16px",border:"1px dashed #ccc",borderRadius:"8px",textAlign:"center"},children:r("p",{children:["Product loading... (handle: ",e,")"]})});const a=t?.featured_image||"",i=t?.title||"",n=t?.description||"",s=t?.average_rating;return o("div",{style:{border:"2px solid #4CAF50",borderRadius:"16px",padding:"16px",margin:"12px 0",backgroundColor:"#f0f9ff",boxShadow:"0 4px 12px rgba(76, 175, 80, 0.15)"},children:r("div",{style:{display:"flex",gap:"12px",alignItems:"center"},children:[a&&o("img",{src:a,alt:i,style:{width:"60px",height:"60px",borderRadius:"8px",objectFit:"cover"}}),r("div",{style:{flex:1},children:[o("h4",{style:{margin:"0 0 4px 0",fontSize:"16px",fontWeight:"bold"},children:i}),n&&r("p",{style:{margin:0,fontSize:"12px",color:"#666",lineHeight:1.4},children:[n.slice(0,80),"..."]}),s&&r("span",{style:{fontSize:"12px",color:"#FFB800"},children:["Rating: ",s.toFixed(1)]})]}),o("button",{style:{padding:"8px 16px",backgroundColor:"#4CAF50",color:"white",borderRadius:"8px",border:"none",cursor:"pointer"},onClick:()=>console.log("View product:",e,t),children:"View"})]})})}},render:t=>o(l,{...t,onOpen:()=>console.log("[LiveChat] Chat opened"),onClose:()=>console.log("[LiveChat] Chat closed"),onMessageSend:e=>console.log("[LiveChat] Message sent:",e),onError:e=>console.error("[LiveChat] Error:",e),onTextMessage:()=>console.log("[LiveChat] AI text message received"),onProductList:()=>console.log("[LiveChat] Product list received"),onPromotionList:()=>console.log("[LiveChat] Promotion list received"),onAddToCart:e=>{console.log("[LiveChat] Add to cart:",e),alert(`Added "${e.title}" to cart!`)},onCart:(e,a)=>{console.log("[LiveChat] Cart clicked:",{cartId:e,checkoutUrl:a}),alert(`Cart ID: ${e}`)}})};export{m as Default,g as default};
|
|
52
52
|
//# sourceMappingURL=LiveChatWidget.stories.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/stories/LiveChatWidget.stories.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * LiveChatWidget Storybook Stories\n * \u5C55\u793A LiveChat \u7EC4\u4EF6\u7684\u5404\u79CD\u4F7F\u7528\u573A\u666F\u548C\u914D\u7F6E\n */\n\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { LiveChatWidget } from '../components/LiveChatWidget'\nimport type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'\nimport '../styles/livechat.css'\n\nconst meta: Meta<typeof LiveChatWidget> = {\n title: 'Campaign/LiveChatWidget',\n component: LiveChatWidget,\n parameters: {\n layout: 'fullscreen',\n docs: {\n story: {\n inline: false,\n iframeHeight: 500,\n },\n description: {\n component: `\n# LiveChat \u804A\u5929\u7EC4\u4EF6\n\n\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002\n\n## \u529F\u80FD\u7279\u6027\n\n- \uD83C\uDF88 **\u6C14\u6CE1\u5F39\u7A97**: \u53EF\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u7684\u60AC\u6D6E\u6C14\u6CE1\u6309\u94AE\n- \uD83D\uDCAC **\u6D41\u5F0F\u6D88\u606F**: \u57FA\u4E8E SSE \u7684\u5B9E\u65F6\u6D41\u5F0F\u54CD\u5E94\n- \uD83D\uDCE6 **\u591A\u79CD\u6D88\u606F\u7C7B\u578B**: \u6587\u672C\u3001\u5546\u54C1\u5361\u7247\u3001\u5546\u54C1\u5217\u8868\u3001\u653F\u7B56\u3001\u5FEB\u6377\u56DE\u590D\u7B49\n- \uD83C\uDFA8 **\u53EF\u5B9A\u5236**: \u652F\u6301\u81EA\u5B9A\u4E49\u54C1\u724C\u989C\u8272\u3001Logo\u3001\u6E32\u67D3\u5668\n- \uD83D\uDCF1 **\u54CD\u5E94\u5F0F**: \u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\n- \uD83D\uDCBE **\u4F1A\u8BDD\u7BA1\u7406**: \u81EA\u52A8\u7BA1\u7406 userId \u548C sessionId\n- \uD83D\uDD12 **\u5B89\u5168\u9632\u62A4**: \u5185\u7F6E XSS \u9632\u62A4\u548C\u8F93\u5165\u9A8C\u8BC1\n\n## \u57FA\u7840\u7528\u6CD5\n\n\\`\\`\\`tsx\nimport { LiveChatWidget } from '@anker-in/campaign-ui'\nimport '@anker-in/campaign-ui/livechat.css'\n\nfunction App() {\n return (\n <LiveChatWidget\n apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n site=\"www.eufy.com\"\n channel_code=\"web_homepage\"\n welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n />\n )\n}\n\\`\\`\\`\n\n## \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n\n\\`\\`\\`tsx\nconst customRenderers = {\n video: {\n render: (content) => (\n <video src={content.url} controls className=\"w-full rounded\" />\n )\n }\n}\n\n<LiveChatWidget\n apiBaseUrl=\"...\"\n site=\"...\"\n customRenderers={customRenderers}\n/>\n\\`\\`\\`\n `,\n },\n },\n },\n tags: ['autodocs'],\n argTypes: {\n apiBaseUrl: {\n control: 'text',\n description: 'API \u57FA\u7840 URL',\n },\n headers: {\n control: 'object',\n description: '\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaSitekey: {\n control: 'text',\n description: 'Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaAction: {\n control: 'text',\n description: 'reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F',\n table: {\n defaultValue: { summary: '\"activity\"' },\n },\n },\n site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\n },\n channelCode: {\n control: 'text',\n description: '\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n welcomeMessage: {\n control: 'text',\n description: '\u6B22\u8FCE\u6D88\u606F',\n table: {\n defaultValue: { summary: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F' },\n },\n },\n logoUrl: {\n control: 'text',\n description: 'Logo URL',\n },\n position: {\n control: 'object',\n description: '\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61',\n table: {\n defaultValue: { summary: '{ bottom: \"1.5rem\", right: \"1.5rem\" }' },\n },\n },\n },\n args: {\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'www.eufy.com',\n loginUserId: 'test_test',\n welcomeMessage: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F',\n },\n}\n\nexport default meta\ntype Story = StoryObj<typeof LiveChatWidget>\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E - \u5C55\u793A\u6240\u6709\u529F\u80FD\n */\nexport const Default: Story = {\n args: {\n // \u57FA\u7840\u914D\u7F6E\n loginUserId: 'test_test1',\n apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',\n site: 'beta.eufy.com',\n channelCode: 'dtc',\n title: 'eufy AI Assistant',\n cartId: 'gid://shopify/Cart/hWN7wB3Pa12gh78d8hPOAUBI?key=0e73db1d3fb5ac21da19099c45033253',\n accessToken: '47b1aa2c0797043f9baba39388029d70',\n\n // \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n position: { bottom: '24px', right: '30px' },\n\n // \u6B22\u8FCE\u6D88\u606F\n welcomeMessage: '',\n\n // \u5FEB\u6377\u56DE\u590D\n quickReplies: [\n { id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '\uD83D\uDCE6' },\n { id: '2', label: 'Track Order', value: 'I want to track my order', icon: '\uD83D\uDE9A' },\n { id: '3', label: 'Support', value: 'I need help with my device', icon: '\uD83D\uDD27' },\n { id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '\u2B50' },\n ],\n\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n complianceConfig: {\n title: \"Hi! I'm your eufy AI assistant.\",\n content:\n 'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',\n checkboxText:\n 'By starting to use \"Live Chat\", you agree to Anker\\'s <a href=\"https://www.anker.com/pages/privacy-policy\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: underline;\">LIVE CHAT PRIVACY NOTICE</a>.',\n agreeButtonText: 'Agree',\n },\n\n // reCAPTCHA \u914D\u7F6E\uFF08\u53D6\u6D88\u6CE8\u91CA\u4EE5\u542F\u7528\uFF09\n // recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',\n recaptchaAction: 'livechat',\n\n // \u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n showNewSessionButton: true,\n\n // \u81EA\u5B9A\u4E49\u6587\u6848\n commonText: {\n learnMore: 'Learn More',\n total: 'Total',\n },\n\n // \u81EA\u5B9A\u4E49\u6D88\u606F\u6E32\u67D3\u5668\n customRenderers: {\n video: {\n render: (content: MessageContent) => {\n const videoContent = content as any\n return (\n <div className=\"w-full\">\n <video src={videoContent.url} controls className=\"w-full rounded-lg\" poster={videoContent.poster}>\n Your browser does not support video playback\n </video>\n {videoContent.title && <p className=\"mt-2 text-sm text-gray-600\">{videoContent.title}</p>}\n </div>\n )\n },\n } as MessageRenderer,\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n return (\n <div className=\"grid grid-cols-2 gap-2\">\n {images.map((image: any, index: number) => (\n <div key={index} className=\"relative aspect-square\">\n <img\n src={image.url}\n alt={image.alt || `Image ${index + 1}`}\n className=\"size-full rounded-lg object-cover\"\n />\n </div>\n ))}\n </div>\n )\n },\n } as MessageRenderer,\n },\n\n // \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\n productCardRender: (product, productHandle) => {\n // product \u53EF\u80FD\u4E3A undefined\uFF0C\u6B64\u65F6\u53EF\u7528 productHandle \u67E5\u8BE2\n if (!product) {\n return (\n <div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>\n <p>Product loading... (handle: {productHandle})</p>\n </div>\n )\n }\n\n const imageUrl = product?.featured_image || ''\n const title = product?.title || ''\n const description = product?.description || ''\n const averageRating = product?.average_rating\n\n return (\n <div\n style={{\n border: '2px solid #4CAF50',\n borderRadius: '16px',\n padding: '16px',\n margin: '12px 0',\n backgroundColor: '#f0f9ff',\n boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',\n }}\n >\n <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>\n {imageUrl && (\n <img\n src={imageUrl}\n alt={title}\n style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}\n />\n )}\n <div style={{ flex: 1 }}>\n <h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>\n {description && (\n <p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>\n {description.slice(0, 80)}...\n </p>\n )}\n {averageRating && (\n <span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>\n )}\n </div>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#4CAF50',\n color: 'white',\n borderRadius: '8px',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => console.log('View product:', productHandle, product)}\n >\n View\n </button>\n </div>\n </div>\n )\n },\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n // \u6240\u6709\u4E8B\u4EF6\u56DE\u8C03\n onOpen={() => console.log('[LiveChat] Chat opened')}\n onClose={() => console.log('[LiveChat] Chat closed')}\n onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}\n onError={(error: Error) => console.error('[LiveChat] Error:', error)}\n onTextMessage={() => console.log('[LiveChat] AI text message received')}\n onProductList={() => console.log('[LiveChat] Product list received')}\n onPromotionList={() => console.log('[LiveChat] Promotion list received')}\n onAddToCart={(product: any) => {\n console.log('[LiveChat] Add to cart:', product)\n alert(`Added \"${product.title}\" to cart!`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })\n alert(`Cart ID: ${cartId}`)\n }}\n />\n ),\n}\n"],
|
|
5
|
-
"mappings": "AAwMY,OACE,OAAAA,EADF,QAAAC,MAAA,oBAlMZ,OAAS,kBAAAC,MAAsB,+BAE/B,MAAO,yBAEP,MAAMC,EAAoC,CACxC,MAAO,0BACP,UAAWD,EACX,WAAY,CACV,OAAQ,aACR,KAAM,CACJ,MAAO,CACL,OAAQ,GACR,aAAc,GAChB,EACA,YAAa,CACX,UAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAmDb,CACF,CACF,EACA,KAAM,CAAC,UAAU,EACjB,SAAU,CACR,WAAY,CACV,QAAS,OACT,YAAa,sBACf,EACA,QAAS,CACP,QAAS,SACT,YAAa,wGACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,iBAAkB,CAChB,QAAS,OACT,YAAa,2HACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,gBAAiB,CACf,QAAS,OACT,YAAa,wGACb,MAAO,CACL,aAAc,CAAE,QAAS,YAAa,CACxC,CACF,EACA,KAAM,CACJ,QAAS,OACT,YAAa,0BACf,EACA,YAAa,CACX,QAAS,OACT,YAAa,iFACb,MAAO,CACL,aAAc,CAAE,QAAS,WAAY,CACvC,CACF,EACA,eAAgB,CACd,QAAS,OACT,YAAa,2BACb,MAAO,CACL,aAAc,CAAE,QAAS,wHAA0B,CACrD,CACF,EACA,QAAS,CACP,QAAS,OACT,YAAa,UACf,EACA,SAAU,CACR,QAAS,SACT,YAAa,mDACb,MAAO,CACL,aAAc,CAAE,QAAS,uCAAwC,CACnE,CACF,CACF,EACA,KAAM,CACJ,WAAY,4BACZ,KAAM,eACN,YAAa,YACb,eAAgB,wHAClB,CACF,EAEA,IAAOE,EAAQD,EAMR,MAAME,EAAiB,CAC5B,KAAM,CAEJ,YAAa,aACb,WAAY,yCACZ,KAAM,
|
|
4
|
+
"sourcesContent": ["/**\n * LiveChatWidget Storybook Stories\n * \u5C55\u793A LiveChat \u7EC4\u4EF6\u7684\u5404\u79CD\u4F7F\u7528\u573A\u666F\u548C\u914D\u7F6E\n */\n\nimport type { Meta, StoryObj } from '@storybook/react'\nimport { LiveChatWidget } from '../components/LiveChatWidget'\nimport type { MessageRenderer, MessageContent } from '../components/LiveChatWidget'\nimport '../styles/livechat.css'\n\nconst meta: Meta<typeof LiveChatWidget> = {\n title: 'Campaign/LiveChatWidget',\n component: LiveChatWidget,\n parameters: {\n layout: 'fullscreen',\n docs: {\n story: {\n inline: false,\n iframeHeight: 500,\n },\n description: {\n component: `\n# LiveChat \u804A\u5929\u7EC4\u4EF6\n\n\u53EF\u590D\u7528\u7684\u6C14\u6CE1\u5F39\u7A97\u804A\u5929\u7EC4\u4EF6\uFF0C\u652F\u6301 SSE \u6D41\u5F0F\u6D88\u606F\u3001\u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\u548C\u591A\u79CD\u6D88\u606F\u7C7B\u578B\u3002\n\n## \u529F\u80FD\u7279\u6027\n\n- \uD83C\uDF88 **\u6C14\u6CE1\u5F39\u7A97**: \u53EF\u81EA\u5B9A\u4E49\u4F4D\u7F6E\u7684\u60AC\u6D6E\u6C14\u6CE1\u6309\u94AE\n- \uD83D\uDCAC **\u6D41\u5F0F\u6D88\u606F**: \u57FA\u4E8E SSE \u7684\u5B9E\u65F6\u6D41\u5F0F\u54CD\u5E94\n- \uD83D\uDCE6 **\u591A\u79CD\u6D88\u606F\u7C7B\u578B**: \u6587\u672C\u3001\u5546\u54C1\u5361\u7247\u3001\u5546\u54C1\u5217\u8868\u3001\u653F\u7B56\u3001\u5FEB\u6377\u56DE\u590D\u7B49\n- \uD83C\uDFA8 **\u53EF\u5B9A\u5236**: \u652F\u6301\u81EA\u5B9A\u4E49\u54C1\u724C\u989C\u8272\u3001Logo\u3001\u6E32\u67D3\u5668\n- \uD83D\uDCF1 **\u54CD\u5E94\u5F0F**: \u79FB\u52A8\u7AEF\u5168\u5C4F\uFF0C\u684C\u9762\u7AEF\u56FA\u5B9A\u5C3A\u5BF8\n- \uD83D\uDCBE **\u4F1A\u8BDD\u7BA1\u7406**: \u81EA\u52A8\u7BA1\u7406 userId \u548C sessionId\n- \uD83D\uDD12 **\u5B89\u5168\u9632\u62A4**: \u5185\u7F6E XSS \u9632\u62A4\u548C\u8F93\u5165\u9A8C\u8BC1\n\n## \u57FA\u7840\u7528\u6CD5\n\n\\`\\`\\`tsx\nimport { LiveChatWidget } from '@anker-in/campaign-ui'\nimport '@anker-in/campaign-ui/livechat.css'\n\nfunction App() {\n return (\n <LiveChatWidget\n apiBaseUrl=\"https://beta-api-livechat.anker.com\"\n site=\"www.eufy.com\"\n channel_code=\"web_homepage\"\n welcomeMessage=\"\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\"\n />\n )\n}\n\\`\\`\\`\n\n## \u81EA\u5B9A\u4E49\u6E32\u67D3\u5668\n\n\\`\\`\\`tsx\nconst customRenderers = {\n video: {\n render: (content) => (\n <video src={content.url} controls className=\"w-full rounded\" />\n )\n }\n}\n\n<LiveChatWidget\n apiBaseUrl=\"...\"\n site=\"...\"\n customRenderers={customRenderers}\n/>\n\\`\\`\\`\n `,\n },\n },\n },\n tags: ['autodocs'],\n argTypes: {\n apiBaseUrl: {\n control: 'text',\n description: 'API \u57FA\u7840 URL',\n },\n headers: {\n control: 'object',\n description: '\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\uFF0C\u5C06\u5728\u6240\u6709 API \u8BF7\u6C42\u4E2D\u6DFB\u52A0',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaSitekey: {\n control: 'text',\n description: 'Google reCAPTCHA v3 site key\uFF0C\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u81EA\u52A8\u542F\u7528 reCAPTCHA v3 \u9A8C\u8BC1',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n recaptchaAction: {\n control: 'text',\n description: 'reCAPTCHA action \u540D\u79F0\uFF0C\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u9A8C\u8BC1\u573A\u666F',\n table: {\n defaultValue: { summary: '\"activity\"' },\n },\n },\n site: {\n control: 'text',\n description: 'Shopify \u5E97\u94FA URL',\n },\n channelCode: {\n control: 'text',\n description: '\u6E20\u9053\u7F16\u7801\uFF0C\u7528\u4E8E\u6807\u8BC6\u6765\u6E90\u6E20\u9053',\n table: {\n defaultValue: { summary: 'undefined' },\n },\n },\n welcomeMessage: {\n control: 'text',\n description: '\u6B22\u8FCE\u6D88\u606F',\n table: {\n defaultValue: { summary: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F' },\n },\n },\n logoUrl: {\n control: 'text',\n description: 'Logo URL',\n },\n position: {\n control: 'object',\n description: '\u6C14\u6CE1\u6309\u94AE\u4F4D\u7F6E\u5BF9\u8C61',\n table: {\n defaultValue: { summary: '{ bottom: \"1.5rem\", right: \"1.5rem\" }' },\n },\n },\n },\n args: {\n apiBaseUrl: 'http://172.16.38.183:3003',\n site: 'www.eufy.com',\n loginUserId: 'test_test',\n welcomeMessage: '\u4F60\u597D\uFF01\u6211\u662F AI \u52A9\u624B\uFF0C\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u52A9\u4F60\u7684\u5417\uFF1F',\n },\n}\n\nexport default meta\ntype Story = StoryObj<typeof LiveChatWidget>\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E - \u5C55\u793A\u6240\u6709\u529F\u80FD\n */\nexport const Default: Story = {\n args: {\n // \u57FA\u7840\u914D\u7F6E\n loginUserId: 'test_test1',\n apiBaseUrl: 'https://beta-api-v2-livechat.anker.com',\n site: 'beta.soundcore.com',\n channelCode: 'dtc',\n title: 'eufy AI Assistant',\n cartId: 'gid://shopify/Cart/hWNAAJweS9IkeRKib4LRy9PY?key=ff1f9b24e74b3f11f5574539e7cbbb2f',\n accessToken: '47b1aa2c0797043f9baba39388029d70',\n\n // \u81EA\u5B9A\u4E49\u4F4D\u7F6E\n position: { bottom: '24px', right: '30px' },\n\n // \u6B22\u8FCE\u6D88\u606F\n welcomeMessage: '',\n\n // \u5FEB\u6377\u56DE\u590D\n quickReplies: [\n { id: '1', label: 'Product Info', value: 'Tell me about your products', icon: '\uD83D\uDCE6' },\n { id: '2', label: 'Track Order', value: 'I want to track my order', icon: '\uD83D\uDE9A' },\n { id: '3', label: 'Support', value: 'I need help with my device', icon: '\uD83D\uDD27' },\n { id: '4', label: 'Recommendations', value: 'Recommend products for me', icon: '\u2B50' },\n ],\n\n // \u6CD5\u89C4\u534F\u8BAE\u5F39\u7A97\n complianceConfig: {\n title: \"Hi! I'm your eufy AI assistant.\",\n content:\n 'AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data.',\n checkboxText:\n 'By starting to use \"Live Chat\", you agree to Anker\\'s <a href=\"https://www.anker.com/pages/privacy-policy\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: underline;\">LIVE CHAT PRIVACY NOTICE</a>.',\n agreeButtonText: 'Agree',\n },\n\n // reCAPTCHA \u914D\u7F6E\uFF08\u53D6\u6D88\u6CE8\u91CA\u4EE5\u542F\u7528\uFF09\n // recaptchaSitekey: '6LfS4J4pAAAAACX1e_WrxutmxxzCK7FU4WzVqL14',\n recaptchaAction: 'livechat',\n\n // \u663E\u793A\u65B0\u4F1A\u8BDD\u6309\u94AE\n showNewSessionButton: true,\n\n // \u81EA\u5B9A\u4E49\u6587\u6848\n commonText: {\n learnMore: 'Learn More',\n total: 'Total',\n },\n\n // \u81EA\u5B9A\u4E49\u6D88\u606F\u6E32\u67D3\u5668\n customRenderers: {\n video: {\n render: (content: MessageContent) => {\n const videoContent = content as any\n return (\n <div className=\"w-full\">\n <video src={videoContent.url} controls className=\"w-full rounded-lg\" poster={videoContent.poster}>\n Your browser does not support video playback\n </video>\n {videoContent.title && <p className=\"mt-2 text-sm text-gray-600\">{videoContent.title}</p>}\n </div>\n )\n },\n } as MessageRenderer,\n image_gallery: {\n render: (content: MessageContent) => {\n const galleryContent = content as any\n const images = galleryContent.images || []\n return (\n <div className=\"grid grid-cols-2 gap-2\">\n {images.map((image: any, index: number) => (\n <div key={index} className=\"relative aspect-square\">\n <img\n src={image.url}\n alt={image.alt || `Image ${index + 1}`}\n className=\"size-full rounded-lg object-cover\"\n />\n </div>\n ))}\n </div>\n )\n },\n } as MessageRenderer,\n },\n\n // \u81EA\u5B9A\u4E49\u4EA7\u54C1\u5361\u7247\u6E32\u67D3\n productCardRender: (product, productHandle) => {\n // product \u53EF\u80FD\u4E3A undefined\uFF0C\u6B64\u65F6\u53EF\u7528 productHandle \u67E5\u8BE2\n if (!product) {\n return (\n <div style={{ padding: '16px', border: '1px dashed #ccc', borderRadius: '8px', textAlign: 'center' }}>\n <p>Product loading... (handle: {productHandle})</p>\n </div>\n )\n }\n\n const imageUrl = product?.featured_image || ''\n const title = product?.title || ''\n const description = product?.description || ''\n const averageRating = product?.average_rating\n\n return (\n <div\n style={{\n border: '2px solid #4CAF50',\n borderRadius: '16px',\n padding: '16px',\n margin: '12px 0',\n backgroundColor: '#f0f9ff',\n boxShadow: '0 4px 12px rgba(76, 175, 80, 0.15)',\n }}\n >\n <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>\n {imageUrl && (\n <img\n src={imageUrl}\n alt={title}\n style={{ width: '60px', height: '60px', borderRadius: '8px', objectFit: 'cover' }}\n />\n )}\n <div style={{ flex: 1 }}>\n <h4 style={{ margin: '0 0 4px 0', fontSize: '16px', fontWeight: 'bold' }}>{title}</h4>\n {description && (\n <p style={{ margin: 0, fontSize: '12px', color: '#666', lineHeight: 1.4 }}>\n {description.slice(0, 80)}...\n </p>\n )}\n {averageRating && (\n <span style={{ fontSize: '12px', color: '#FFB800' }}>Rating: {averageRating.toFixed(1)}</span>\n )}\n </div>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#4CAF50',\n color: 'white',\n borderRadius: '8px',\n border: 'none',\n cursor: 'pointer',\n }}\n onClick={() => console.log('View product:', productHandle, product)}\n >\n View\n </button>\n </div>\n </div>\n )\n },\n },\n\n render: args => (\n <LiveChatWidget\n {...args}\n // \u6240\u6709\u4E8B\u4EF6\u56DE\u8C03\n onOpen={() => console.log('[LiveChat] Chat opened')}\n onClose={() => console.log('[LiveChat] Chat closed')}\n onMessageSend={(message: string) => console.log('[LiveChat] Message sent:', message)}\n onError={(error: Error) => console.error('[LiveChat] Error:', error)}\n onTextMessage={() => console.log('[LiveChat] AI text message received')}\n onProductList={() => console.log('[LiveChat] Product list received')}\n onPromotionList={() => console.log('[LiveChat] Promotion list received')}\n onAddToCart={(product: any) => {\n console.log('[LiveChat] Add to cart:', product)\n alert(`Added \"${product.title}\" to cart!`)\n }}\n onCart={(cartId: string, checkoutUrl?: string) => {\n console.log('[LiveChat] Cart clicked:', { cartId, checkoutUrl })\n alert(`Cart ID: ${cartId}`)\n }}\n />\n ),\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["jsx", "jsxs", "LiveChatWidget", "meta", "LiveChatWidget_stories_default", "Default", "content", "videoContent", "images", "image", "index", "product", "productHandle", "imageUrl", "title", "description", "averageRating", "args", "message", "error", "cartId", "checkoutUrl"]
|
|
7
7
|
}
|