@anker-in/campaign-ui 0.5.0-beta.9 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
  2. package/dist/cjs/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +3 -3
  3. package/dist/cjs/components/credits/context/hooks/useShippingCountries.d.ts +8 -0
  4. package/dist/cjs/components/credits/context/hooks/useShippingCountries.js +2 -0
  5. package/dist/cjs/components/credits/context/hooks/useShippingCountries.js.map +7 -0
  6. package/dist/cjs/components/credits/creditsRedeemList/RedeemProductModal/Address.js +1 -1
  7. package/dist/cjs/components/credits/creditsRedeemList/RedeemProductModal/Address.js.map +3 -3
  8. package/dist/cjs/components/credits/creditsRedeemList/RedeemProductModal/index.js +1 -1
  9. package/dist/cjs/components/credits/creditsRedeemList/RedeemProductModal/index.js.map +3 -3
  10. package/dist/cjs/components/memberPopup/MemberPopup.d.ts +1 -1
  11. package/dist/cjs/components/memberPopup/MemberPopup.js +1 -1
  12. package/dist/cjs/components/memberPopup/MemberPopup.js.map +3 -3
  13. package/dist/cjs/components/memberPopup/context/provider.d.ts +3 -3
  14. package/dist/cjs/components/memberPopup/context/provider.js +1 -1
  15. package/dist/cjs/components/memberPopup/context/provider.js.map +3 -3
  16. package/dist/cjs/components/memberPopup/panels/ActivitiesSubscribePanel.d.ts +1 -4
  17. package/dist/cjs/components/memberPopup/panels/ActivitiesSubscribePanel.js +1 -1
  18. package/dist/cjs/components/memberPopup/panels/ActivitiesSubscribePanel.js.map +3 -3
  19. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.d.ts +8 -7
  20. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js +1 -1
  21. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js.map +3 -3
  22. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/index.d.ts +1 -2
  23. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/index.js +1 -1
  24. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/index.js.map +3 -3
  25. package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivatePanel.d.ts +1 -2
  26. package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivatePanel.js +1 -1
  27. package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivatePanel.js.map +3 -3
  28. package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.d.ts +1 -3
  29. package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js +1 -1
  30. package/dist/cjs/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js.map +3 -3
  31. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.d.ts +1 -2
  32. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js +1 -1
  33. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js.map +3 -3
  34. package/dist/cjs/components/memberPopup/panels/EarnCredits/index.d.ts +1 -8
  35. package/dist/cjs/components/memberPopup/panels/EarnCredits/index.js +1 -1
  36. package/dist/cjs/components/memberPopup/panels/EarnCredits/index.js.map +3 -3
  37. package/dist/cjs/components/memberPopup/panels/Referral/index.js +1 -1
  38. package/dist/cjs/components/memberPopup/panels/Referral/index.js.map +3 -3
  39. package/dist/cjs/components/memberPopup/type.d.ts +19 -2
  40. package/dist/cjs/components/memberPopup/type.js +1 -1
  41. package/dist/cjs/components/memberPopup/type.js.map +1 -1
  42. package/dist/cjs/templates/Credits.js +1 -1
  43. package/dist/cjs/templates/Credits.js.map +3 -3
  44. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js +1 -1
  45. package/dist/esm/components/LiveChatWidget/components/MessageContent/TextBlock.js.map +3 -3
  46. package/dist/esm/components/credits/context/hooks/useShippingCountries.d.ts +8 -0
  47. package/dist/esm/components/credits/context/hooks/useShippingCountries.js +2 -0
  48. package/dist/esm/components/credits/context/hooks/useShippingCountries.js.map +7 -0
  49. package/dist/esm/components/credits/creditsRedeemList/RedeemProductModal/Address.js +1 -1
  50. package/dist/esm/components/credits/creditsRedeemList/RedeemProductModal/Address.js.map +3 -3
  51. package/dist/esm/components/credits/creditsRedeemList/RedeemProductModal/index.js +1 -1
  52. package/dist/esm/components/credits/creditsRedeemList/RedeemProductModal/index.js.map +3 -3
  53. package/dist/esm/components/memberPopup/MemberPopup.d.ts +1 -1
  54. package/dist/esm/components/memberPopup/MemberPopup.js +1 -1
  55. package/dist/esm/components/memberPopup/MemberPopup.js.map +3 -3
  56. package/dist/esm/components/memberPopup/context/provider.d.ts +3 -3
  57. package/dist/esm/components/memberPopup/context/provider.js +1 -1
  58. package/dist/esm/components/memberPopup/context/provider.js.map +3 -3
  59. package/dist/esm/components/memberPopup/panels/ActivitiesSubscribePanel.d.ts +1 -4
  60. package/dist/esm/components/memberPopup/panels/ActivitiesSubscribePanel.js +1 -1
  61. package/dist/esm/components/memberPopup/panels/ActivitiesSubscribePanel.js.map +3 -3
  62. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.d.ts +8 -7
  63. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js +1 -1
  64. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js.map +3 -3
  65. package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.d.ts +1 -2
  66. package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.js +1 -1
  67. package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.js.map +3 -3
  68. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.d.ts +1 -2
  69. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.js +1 -1
  70. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.js.map +3 -3
  71. package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.d.ts +1 -3
  72. package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js +1 -1
  73. package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js.map +3 -3
  74. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.d.ts +1 -2
  75. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js +1 -1
  76. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js.map +3 -3
  77. package/dist/esm/components/memberPopup/panels/EarnCredits/index.d.ts +1 -8
  78. package/dist/esm/components/memberPopup/panels/EarnCredits/index.js +1 -1
  79. package/dist/esm/components/memberPopup/panels/EarnCredits/index.js.map +3 -3
  80. package/dist/esm/components/memberPopup/panels/Referral/index.js +1 -1
  81. package/dist/esm/components/memberPopup/panels/Referral/index.js.map +3 -3
  82. package/dist/esm/components/memberPopup/type.d.ts +19 -2
  83. package/dist/esm/components/memberPopup/type.js +1 -1
  84. package/dist/esm/components/memberPopup/type.js.map +1 -1
  85. package/dist/esm/templates/Credits.js +1 -1
  86. package/dist/esm/templates/Credits.js.map +3 -3
  87. package/package.json +2 -1
  88. package/src/components/LiveChatWidget/components/MessageContent/TextBlock.tsx +7 -5
  89. package/src/components/credits/context/hooks/useShippingCountries.ts +60 -0
  90. package/src/components/credits/creditsRedeemList/RedeemProductModal/Address.tsx +2 -2
  91. package/src/components/credits/creditsRedeemList/RedeemProductModal/index.tsx +2 -2
  92. package/src/components/memberPopup/MemberPopup.tsx +166 -178
  93. package/src/components/memberPopup/context/provider.tsx +24 -4
  94. package/src/components/memberPopup/panels/ActivitiesSubscribePanel.tsx +66 -73
  95. package/src/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.tsx +38 -55
  96. package/src/components/memberPopup/panels/ConsumeCredits/index.tsx +207 -106
  97. package/src/components/memberPopup/panels/EarnCredits/ActivatePanel.tsx +32 -16
  98. package/src/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.tsx +60 -35
  99. package/src/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.tsx +32 -22
  100. package/src/components/memberPopup/panels/EarnCredits/index.tsx +55 -48
  101. package/src/components/memberPopup/panels/Referral/index.tsx +40 -22
  102. package/src/components/memberPopup/type.ts +20 -3
  103. package/src/templates/Credits.tsx +25 -0
  104. package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.d.ts +0 -10
  105. package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.js +0 -2
  106. package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.js.map +0 -7
  107. package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.d.ts +0 -7
  108. package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js +0 -2
  109. package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js.map +0 -7
  110. package/dist/cjs/components/memberPopup/panels/Activity/index.d.ts +0 -7
  111. package/dist/cjs/components/memberPopup/panels/Activity/index.js +0 -2
  112. package/dist/cjs/components/memberPopup/panels/Activity/index.js.map +0 -7
  113. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.d.ts +0 -19
  114. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js +0 -2
  115. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js.map +0 -7
  116. package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivitiesSubscribePanel.d.ts +0 -11
  117. package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivitiesSubscribePanel.js +0 -2
  118. package/dist/cjs/components/memberPopup/panels/EarnCredits/ActivitiesSubscribePanel.js.map +0 -7
  119. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.d.ts +0 -10
  120. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.js +0 -2
  121. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.js.map +0 -7
  122. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.d.ts +0 -9
  123. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.js +0 -2
  124. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.js.map +0 -7
  125. package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.d.ts +0 -13
  126. package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js +0 -2
  127. package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js.map +0 -7
  128. package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.d.ts +0 -10
  129. package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.js +0 -2
  130. package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.js.map +0 -7
  131. package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.d.ts +0 -7
  132. package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js +0 -2
  133. package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js.map +0 -7
  134. package/dist/esm/components/memberPopup/panels/Activity/index.d.ts +0 -7
  135. package/dist/esm/components/memberPopup/panels/Activity/index.js +0 -2
  136. package/dist/esm/components/memberPopup/panels/Activity/index.js.map +0 -7
  137. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.d.ts +0 -19
  138. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js +0 -2
  139. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js.map +0 -7
  140. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivitiesSubscribePanel.d.ts +0 -11
  141. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivitiesSubscribePanel.js +0 -2
  142. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivitiesSubscribePanel.js.map +0 -7
  143. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.d.ts +0 -10
  144. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.js +0 -2
  145. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.js.map +0 -7
  146. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.d.ts +0 -9
  147. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.js +0 -2
  148. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.js.map +0 -7
  149. package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.d.ts +0 -13
  150. package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js +0 -2
  151. package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js.map +0 -7
  152. package/dist/index.d.mts +0 -1775
  153. package/dist/index.d.ts +0 -1775
  154. package/dist/index.js +0 -18542
  155. package/dist/index.js.map +0 -1
  156. package/dist/index.mjs +0 -18514
  157. package/dist/index.mjs.map +0 -1
  158. package/src/components/memberPopup/panels/EarnCredits/CompleteProfileModal.tsx +0 -191
@@ -1,6 +1,6 @@
1
- import { useMemo, useState } from 'react'
1
+ import { useEffect, useMemo, useState } from 'react'
2
2
  import { Picture, Button } from '@anker-in/headless-ui'
3
- import { classNames as cn, useProductsByHandles, useHeadlessContext } from '@anker-in/lib'
3
+ import { gaTrack, classNames as cn, useProductsByHandles, useHeadlessContext } from '@anker-in/lib'
4
4
  import { useMemberPopupContext } from '../../context/provider'
5
5
  import { useViewStack } from '../../context/viewStack'
6
6
  import { useRedeemableList } from './hooks/useRedeemableList'
@@ -19,24 +19,28 @@ type EnrichedItem = ConsumeCreditsItem & {
19
19
  alpcData: ConsumeCreditRuleResponse
20
20
  insufficient: boolean
21
21
  soldOut: boolean
22
+ disabled: boolean
22
23
  product?: any
23
24
  variant?: any
24
25
  }
25
26
 
26
27
  type Props = {
27
28
  copy: ConsumeCreditsopy
28
- onClose: () => void
29
29
  }
30
30
 
31
- function ConsumeCredits({ copy, onClose }: Props) {
32
- const { profile, creditInfo, openSignUpPopup, alpcConfig } = useMemberPopupContext()
31
+ function ConsumeCredits({ copy }: Props) {
32
+ const { profile, creditInfo, openSignUpPopup, alpcConfig, isActivateSuccess, fetchCreditInfo, pageHandle } =
33
+ useMemberPopupContext()
33
34
  const { pushView } = useViewStack()
34
35
  const { brand } = useHeadlessContext()
35
36
  const rounded = ROUNDED_BRANDS.includes(brand)
36
37
 
37
38
  const [redeemAndBuyError, setRedeemAndBuyError] = useState('')
38
39
  const [loadingId, setLoadingId] = useState<string | number | null>(null)
39
- const [isActivateSuccess, setIsActivateSuccess] = useState(false)
40
+
41
+ useEffect(() => {
42
+ if (profile?.user_id) fetchCreditInfo(profile.user_id)
43
+ }, [])
40
44
 
41
45
  const isLogin = !!profile
42
46
  const { redeemableList, listLoading } = useRedeemableList(alpcConfig)
@@ -52,40 +56,53 @@ function ConsumeCredits({ copy, onClose }: Props) {
52
56
  if (!alpcData) return null
53
57
 
54
58
  const availableCredit = Number(creditInfo?.available_credit ?? 0)
55
- const insufficient = isLogin && !!profile?.activated && alpcData.consume_credits > availableCredit
56
- const soldOut = alpcData.is_limited && (!alpcData.remaining_inventory || alpcData.remaining_inventory <= 0)
57
-
58
- let product
59
- let variant
60
- if (
61
- (item.type === ConsumeCreditsItemType.RedeemAndBuy ||
62
- item.type === ConsumeCreditsItemType.Product) &&
63
- item.product
64
- ) {
65
- product = products?.find((p: any) => p.handle === item.product!.handle)
66
- variant = product?.variants?.find((v: any) => v.sku === item.product!.sku) ?? product?.variants?.[0]
67
- if (item.type === ConsumeCreditsItemType.RedeemAndBuy && (!product || !variant)) return null
68
- }
59
+ const insufficient = alpcData.consume_credits > availableCredit
60
+ const alpcSoldOut = alpcData.is_limited && (!alpcData.remaining_inventory || alpcData.remaining_inventory <= 0)
69
61
 
70
- return { ...item, alpcData, insufficient, soldOut, product, variant }
62
+ const isPhysicalProduct =
63
+ item.type === ConsumeCreditsItemType.RedeemAndBuy || item.type === ConsumeCreditsItemType.Product
64
+ const product = products?.find((p: any) => p.handle === item.product?.handle)
65
+ const variant = product?.variants?.find((v: any) => v.sku === item.product?.sku) ?? product?.variants?.[0]
66
+ if (isPhysicalProduct && (!product || !variant || !variant?.availableForSale || alpcSoldOut)) {
67
+ return null
68
+ }
69
+ if (item.type === ConsumeCreditsItemType.RedeemAndBuy && item.price == null) {
70
+ return null
71
+ }
72
+ return { ...item, alpcData, insufficient, product, variant }
71
73
  })
72
74
  .filter(Boolean) as EnrichedItem[]
73
75
  }, [copy.list, redeemableList, creditInfo, profile, isLogin, products])
74
76
 
77
+ const isActivate = profile?.activated || isActivateSuccess
78
+
75
79
  function getButtonLabel(item: (typeof list)[number]) {
76
- if (!isLogin) return copy.unlockRewards
77
- if (item.soldOut) return copy.soldOut
80
+ if (!isLogin || !isActivate) {
81
+ return copy.unlockRewards
82
+ }
83
+ if (item.soldOut) {
84
+ return copy.soldOut
85
+ }
78
86
  return copy.btnRedeem
79
87
  }
80
88
 
81
89
  function isDisabled(item: (typeof list)[number]) {
82
- if (
83
- item.type === ConsumeCreditsItemType.GiftCard ||
84
- item.type === ConsumeCreditsItemType.Product
85
- ) {
86
- return item.insufficient
90
+ if (!isLogin || !isActivate) {
91
+ return false
87
92
  }
88
- return item.soldOut || item.insufficient
93
+ return item.insufficient
94
+ }
95
+
96
+ function trackRedeemButton(itemTitle: string) {
97
+ gaTrack({
98
+ event: 'ga4Event',
99
+ event_name: 'lp_button',
100
+ event_parameters: {
101
+ position: 'consume_credits',
102
+ button_name: 'redeem',
103
+ info: 'Member Floating Window',
104
+ },
105
+ })
89
106
  }
90
107
 
91
108
  async function handleRedeem(item: (typeof list)[number]) {
@@ -93,23 +110,28 @@ function ConsumeCredits({ copy, onClose }: Props) {
93
110
  openSignUpPopup()
94
111
  return
95
112
  }
96
- if (!profile?.activated && !isActivateSuccess) {
113
+ if (!isActivate) {
97
114
  pushView({
98
115
  type: MemberPopupPanelType.Activate,
99
- props: { onSuccess: () => setIsActivateSuccess(true) },
100
116
  })
101
117
  return
102
118
  }
103
- if (
104
- item.type === ConsumeCreditsItemType.GiftCard ||
105
- item.type === ConsumeCreditsItemType.Product
106
- ) {
119
+ if (item.type === ConsumeCreditsItemType.GiftCard || item.type === ConsumeCreditsItemType.Product) {
107
120
  if (copy.creditsPage?.url) {
108
- window.open(copy.creditsPage.url, '_blank', 'noopener,noreferrer')
121
+ const sectionId = copy.creditsPage.redeemListSectionId ?? 'creditsRedeemList'
122
+ const targetUrl = new URL(copy.creditsPage.url, window.location.href)
123
+ targetUrl.searchParams.set('section', sectionId)
124
+ targetUrl.hash = sectionId
125
+ if (pageHandle) {
126
+ targetUrl.searchParams.set('ref', `${pageHandle}_consume_credits`)
127
+ }
128
+ trackRedeemButton(item.title)
129
+ window.open(targetUrl.toString(), '_blank', 'noopener,noreferrer')
109
130
  }
110
131
  return
111
132
  }
112
133
  if (item.type === ConsumeCreditsItemType.Coupon) {
134
+ trackRedeemButton(item.title)
113
135
  pushView({
114
136
  type: MemberPopupPanelType.RedeemCoupon,
115
137
  props: {
@@ -119,7 +141,6 @@ function ConsumeCredits({ copy, onClose }: Props) {
119
141
  ? { url: copy.imageMapping[item.type]!.url, alt: item.image?.alt }
120
142
  : item.image,
121
143
  itemValue: item.value,
122
- itemOff: copy.off,
123
144
  itemRules: item.rules,
124
145
  redeemId: Number(item.redeemId),
125
146
  userId: profile?.user_id,
@@ -129,12 +150,22 @@ function ConsumeCredits({ copy, onClose }: Props) {
129
150
  } else {
130
151
  setRedeemAndBuyError('')
131
152
  setLoadingId(item.redeemId)
153
+ trackRedeemButton(item.title)
132
154
  try {
133
155
  await redeemAndBuy({
134
156
  productVariant: item.variant,
135
157
  redeemId: Number(item.redeemId),
136
158
  userId: profile?.user_id,
137
159
  })
160
+ gaTrack({
161
+ event: 'ga4Event',
162
+ event_name: 'lp_button',
163
+ event_parameters: {
164
+ position: 'consume_credits',
165
+ button_name: 'redeem_success',
166
+ info: 'Member Floating Window',
167
+ },
168
+ })
138
169
  } catch (e: any) {
139
170
  setRedeemAndBuyError(e?.message ?? copy.redeemModal.commonError)
140
171
  } finally {
@@ -145,99 +176,169 @@ function ConsumeCredits({ copy, onClose }: Props) {
145
176
 
146
177
  return (
147
178
  <>
148
- <div className="flex flex-1 flex-col gap-[12px]">
179
+ <div className="flex flex-1 flex-col">
149
180
  <div className="flex flex-col gap-[8px]">
150
181
  {copy.title && <h2 className="text-[24px] font-[700] leading-[1.2] text-[#080a0f]">{copy.title}</h2>}
151
- {copy.subtitle && <p className="text-[16px] font-[700] leading-snug text-[#4a4c56]">{copy.subtitle}</p>}
182
+ {copy.subtitle && (
183
+ <p className="text-[16px] mt-[8px] font-[700] leading-snug text-[#4a4c56]">{copy.subtitle}</p>
184
+ )}
152
185
  </div>
153
186
 
154
- {copy.insufficientCredits && creditInfo && (
155
- <div className="text-[14px] font-[700] text-[#1d1d1f]">
156
- {copy.insufficientCredits}: {numberFormat(creditInfo.available_credit)} {copy.pointUnit}
187
+ {isLogin && (
188
+ <div
189
+ className={cn(
190
+ 'flex items-center mt-[16px] gap-[12px] bg-[#f5f6f7] p-[16px]',
191
+ rounded ? 'rounded-[8px]' : 'rounded-none'
192
+ )}
193
+ >
194
+ <div className="flex flex-1 flex-col gap-[4px]">
195
+ <div className="text-[14px] font-[700] text-[#1e2024]">{copy.balanceLabel ?? 'AnkerCredits Balance'}</div>
196
+ <div className="flex items-end gap-[4px]">
197
+ <span className="text-[24px] font-[700] leading-[1.2] text-[#1e2024]">
198
+ {numberFormat(creditInfo?.available_credit || 0)}
199
+ </span>
200
+ <span className="text-[14px] font-[700] leading-[1.4] text-[#1e2024]">
201
+ {copy.creditUnit ?? 'ankercredits'}
202
+ </span>
203
+ </div>
204
+ </div>
205
+ <div className="h-full w-px bg-[#dadce0]" />
206
+ <div className="flex flex-1 flex-col gap-[4px]">
207
+ <div className="text-[14px] font-[700] text-[#1e2024]">{copy.comingSoonLabel ?? 'Coming Soon'}</div>
208
+ <div className="flex items-end gap-[4px]">
209
+ <span className="text-[24px] font-[700] leading-[1.2] text-[#1e2024]">
210
+ {numberFormat(creditInfo?.pending_credit || 0)}
211
+ </span>
212
+ <span className="text-[14px] font-[700] leading-[1.4] text-[#1e2024]">
213
+ {copy.creditUnit ?? 'ankercredits'}
214
+ </span>
215
+ </div>
216
+ </div>
157
217
  </div>
158
218
  )}
159
- {redeemAndBuyError && <div className="text-[14px] font-[700] text-[#f84d4f]">{redeemAndBuyError}</div>}
219
+ {redeemAndBuyError && <div className="text-[14px] mt-[8px] font-[700] text-[#f84d4f]">{redeemAndBuyError}</div>}
160
220
 
161
221
  {listLoading ? (
162
222
  <div className="flex flex-1 items-center justify-center py-[32px]">
163
223
  <div className="size-[32px] animate-spin rounded-full border-[3px] border-[#080a0f] border-t-transparent" />
164
224
  </div>
165
225
  ) : (
166
- <div className="flex flex-col">
167
- {list.map((item, idx) => {
168
- const hasProduct = !!item.product
169
- return (
170
- <div key={idx} className="relative py-[16px]">
171
- {idx > 0 && <div className="absolute inset-x-0 top-0 h-px bg-[#dadce0]" />}
172
- <div className="flex items-center gap-[12px]">
173
- {(() => {
174
- const mappedImgUrl = copy.imageMapping?.[item.type]?.url
175
- const imgUrl = hasProduct
176
- ? (item.variant?.image?.url ?? item.product?.images?.[0]?.url ?? item.image?.url)
177
- : (mappedImgUrl ?? item.image?.url)
178
- const imgAlt = hasProduct
179
- ? (item.variant?.image?.altText ?? item.product?.images?.[0]?.alt ?? item.image?.alt ?? '')
180
- : (item.image?.alt ?? '')
181
- if (!imgUrl) return null
182
- return (
183
- <div className={cn('relative size-[64px] shrink-0 overflow-hidden', rounded ? 'rounded-[4px]' : 'rounded-none')}>
184
- <Picture
185
- source={imgUrl}
186
- alt={imgAlt}
187
- className="flex size-full items-center justify-center"
188
- imgClassName={hasProduct ? 'object-cover' : 'h-full w-auto object-contain'}
189
- />
190
- {!hasProduct && item.value && (
191
- <div className="absolute bottom-[16px] left-[4px] text-[12px] font-[800] leading-none text-white">
192
- {item.value} {copy.off}
226
+ <div className="flex mt-[16px] flex-col">
227
+ {list.map((item, idx) => {
228
+ return (
229
+ <div key={idx} className="relative py-[16px]">
230
+ {idx > 0 && <div className="absolute inset-x-0 top-0 h-px bg-[#dadce0]" />}
231
+ <div className="flex items-center gap-[12px]">
232
+ {(() => {
233
+ const phsicalProduct =
234
+ item.type === ConsumeCreditsItemType.Product ||
235
+ item.type === ConsumeCreditsItemType.RedeemAndBuy
236
+ const imgUrl = phsicalProduct
237
+ ? (item.variant?.image?.url ?? item.product?.images?.[0]?.url ?? item.image?.url)
238
+ : item.image?.url || copy.imageMapping?.[item.type]?.url
239
+ const imgAlt = phsicalProduct
240
+ ? (item.variant?.image?.altText ?? item.product?.images?.[0]?.alt ?? item.image?.alt ?? '')
241
+ : (item.image?.alt ?? '')
242
+ if (!imgUrl) return null
243
+ return (
244
+ <div
245
+ className={cn(
246
+ 'relative size-[64px] shrink-0 overflow-hidden',
247
+ rounded ? 'rounded-[4px]' : 'rounded-none'
248
+ )}
249
+ >
250
+ <Picture
251
+ source={imgUrl}
252
+ alt={imgAlt}
253
+ className="flex size-full items-center justify-center"
254
+ imgClassName={phsicalProduct ? 'object-cover' : 'h-full w-auto object-contain'}
255
+ />
256
+ {item.type === ConsumeCreditsItemType.Coupon && item.value && (
257
+ <div className="absolute bottom-[16px] left-[4px] text-[12px] font-[800] leading-none text-white">
258
+ {item.value && `${item.value} ${copy.off}`}
259
+ </div>
260
+ )}
261
+ {item.type === ConsumeCreditsItemType.GiftCard && item.value && (
262
+ <div className="absolute bottom-[16px] left-[4px] text-[12px] font-[800] leading-none text-white">
263
+ {item.value && `${item.value} ${copy.giftCard || 'Gift Card'}`}
264
+ </div>
265
+ )}
266
+ </div>
267
+ )
268
+ })()}
269
+ <div className="min-w-0 flex-1">
270
+ <div className="text-[16px] font-[700] text-[#1e2024] line-clamp-2">
271
+ {item.product?.title ?? item.title ?? item.alpcData?.name}
272
+ </div>
273
+ <div className="mt-[4px] text-[14px] text-[#666]">
274
+ {item.type === ConsumeCreditsItemType.RedeemAndBuy ? (
275
+ <div>
276
+ <span>
277
+ {numberFormat(item.alpcData.consume_credits)} {copy.creditUnit ?? ''} + $
278
+ {Number(item.price).toFixed(2)}
279
+ </span>
280
+ {item.variant?.price?.amount && (
281
+ <span className="text-[12px] ml-1 text-[#999] line-through">
282
+ ${Number(item.variant.price.amount).toFixed(2)}
283
+ </span>
284
+ )}
285
+ </div>
286
+ ) : (
287
+ `${numberFormat(item.alpcData.consume_credits)} ${copy.creditUnit ?? ''}`
288
+ )}
289
+ </div>
290
+ </div>
291
+ <div className="relative group">
292
+ <Button
293
+ size="base"
294
+ disabled={isDisabled(item)}
295
+ loading={loadingId === item.redeemId}
296
+ onClick={() => handleRedeem(item)}
297
+ >
298
+ {getButtonLabel(item)}
299
+ </Button>
300
+ {item.insufficient && isLogin && isActivate && (
301
+ <div className="pointer-events-none absolute right-0 top-full z-[100] mt-[10px] hidden w-[200px] group-hover:block">
302
+ <div className="relative bg-[#6D6D6F] p-[16px] text-[14px] font-[700] text-white shadow">
303
+ <p className="text-pretty tracking-[-0.02em] text-[14px]">{copy.insufficientCredits}</p>
304
+ <div className="absolute -top-[8px] right-[20px] size-[16px] origin-top-left rotate-45 rounded-[2px] bg-[#6D6D6F]" />
305
+ </div>
193
306
  </div>
194
307
  )}
195
308
  </div>
196
- )
197
- })()}
198
- <div className="min-w-0 flex-1">
199
- <div className="text-[16px] font-[700] text-[#1e2024] line-clamp-2">
200
- {hasProduct && item.product?.title
201
- ? item.product.title
202
- : item.title}
203
- </div>
204
- <div className="mt-[4px] text-[14px] text-[#666]">
205
- {hasProduct && item.price != null
206
- ? `${numberFormat(item.alpcData.consume_credits)} ${copy.pointUnit ?? ''} + $${Number(item.price).toFixed(2)}`
207
- : `${numberFormat(item.alpcData.consume_credits)} ${copy.pointUnit ?? ''}`}
208
309
  </div>
209
310
  </div>
210
- <div className="relative group">
211
- <Button
212
- className={cn('bg-[#080a0f] px-[20px] pb-[10px] pt-[11px] text-[14px] font-[700] leading-[1.2] text-white', rounded ? 'rounded-[4px]' : 'rounded-none')}
213
- disabled={isDisabled(item)}
214
- loading={loadingId === item.redeemId}
215
- onClick={() => handleRedeem(item)}
216
- >
217
- {getButtonLabel(item)}
218
- </Button>
219
- {item.insufficient && (
220
- <div className="pointer-events-none absolute right-0 top-full z-[100] mt-[10px] hidden w-[200px] group-hover:block">
221
- <div className="relative bg-[#6D6D6F] p-[16px] text-[14px] font-[700] text-white shadow">
222
- <p className="text-pretty tracking-[-0.02em] text-[14px]">{copy.insufficientCredits}</p>
223
- <div className="absolute -top-[8px] right-[20px] size-[16px] origin-top-left rotate-45 rounded-[2px] bg-[#6D6D6F]" />
224
- </div>
225
- </div>
226
- )}
227
- </div>
228
- </div>
229
- </div>
230
- )
231
- })}
232
- </div>
311
+ )
312
+ })}
313
+ </div>
233
314
  )}
234
315
 
235
316
  {copy.creditsPage?.url && (
236
317
  <a
237
- href={copy.creditsPage.url}
318
+ href={(() => {
319
+ if (!pageHandle) return copy.creditsPage!.url
320
+ try {
321
+ const url = new URL(copy.creditsPage!.url, window.location.href)
322
+ url.searchParams.set('ref', `${pageHandle}_consume_credits`)
323
+ return url.toString()
324
+ } catch {
325
+ return copy.creditsPage!.url
326
+ }
327
+ })()}
238
328
  target="_blank"
239
329
  rel="noopener noreferrer"
240
330
  className="mt-auto self-start text-[14px] font-[700] text-[#080a0f] underline"
331
+ onClick={() =>
332
+ gaTrack({
333
+ event: 'ga4Event',
334
+ event_name: 'lp_button',
335
+ event_parameters: {
336
+ position: 'consume_credits',
337
+ button_name: 'credits_page_link',
338
+ info: 'Member Floating Window',
339
+ },
340
+ })
341
+ }
241
342
  >
242
343
  {copy.creditsPage.label ?? 'Go to Credits Page'}
243
344
  </a>
@@ -11,15 +11,16 @@ import {
11
11
  import { Message } from '../../../registration/authCodeActivate/Message'
12
12
  import type { AuthCodeActivateCopy } from '../../type'
13
13
  import { useRegistration } from '../../../registration'
14
+ import { useMemberPopupContext } from '../../context/provider'
14
15
  import { ROUNDED_BRANDS } from '../../../../constants'
15
16
 
16
17
  type Props = {
17
18
  copy: AuthCodeActivateCopy
18
19
  onClose: () => void
19
- onSuccess?: () => void
20
20
  }
21
21
 
22
- export default function ActivatePanel({ copy, onClose, onSuccess }: Props) {
22
+ export default function ActivatePanel({ copy, onClose }: Props) {
23
+ const { setIsActivateSuccess, fetchCreditInfo, profile } = useMemberPopupContext()
23
24
  const { locale, brand } = useHeadlessContext()
24
25
  const { email } = useRegistration()
25
26
  const rounded = ROUNDED_BRANDS.includes(brand)
@@ -165,14 +166,36 @@ export default function ActivatePanel({ copy, onClose, onSuccess }: Props) {
165
166
  if (data.status >= 200 && data.status < 300) {
166
167
  setMessageStatus('success')
167
168
  setMessageText(copy?.authSuccessMessage || '')
168
- onSuccess?.()
169
+ setIsActivateSuccess(true)
170
+ if (profile?.user_id) setTimeout(() => fetchCreditInfo(profile.user_id), 3000)
171
+ gaTrack({
172
+ event: 'ga4Event',
173
+ event_name: 'lp_button',
174
+ event_parameters: {
175
+ page_group: 'reg_sub_pop',
176
+ position: 'auth_code',
177
+ button_name: 'check_and_active',
178
+ info: 'Member Floating Window',
179
+ },
180
+ })
169
181
  setTimeout(() => {
170
182
  onClose()
171
183
  }, 3000)
172
184
  } else {
173
185
  const errorCode = data?.data?.error_code ?? data?.error_code
174
186
  if (errorCode === '104') {
175
- onSuccess?.()
187
+ setIsActivateSuccess(true)
188
+ if (profile?.user_id) setTimeout(() => fetchCreditInfo(profile.user_id), 3000)
189
+ gaTrack({
190
+ event: 'ga4Event',
191
+ event_name: 'lp_button',
192
+ event_parameters: {
193
+ page_group: 'reg_sub_pop',
194
+ position: 'auth_code',
195
+ button_name: 'check_and_active',
196
+ info: 'Member Floating Window',
197
+ },
198
+ })
176
199
  setTimeout(() => {
177
200
  onClose()
178
201
  }, 3000)
@@ -194,16 +217,6 @@ export default function ActivatePanel({ copy, onClose, onSuccess }: Props) {
194
217
  setMessageText('')
195
218
  clearTimeout(timer)
196
219
  }, 5000)
197
-
198
- gaTrack({
199
- event: 'ga4Event',
200
- event_name: 'lp_button',
201
- event_parameters: {
202
- page_group: 'reg_sub_pop',
203
- position: 'auth_code',
204
- button_name: 'check_and_active',
205
- },
206
- })
207
220
  }, [
208
221
  code,
209
222
  copy?.codeEmptyError,
@@ -215,7 +228,9 @@ export default function ActivatePanel({ copy, onClose, onSuccess }: Props) {
215
228
  sendEmailData,
216
229
  triggerEmailValidation,
217
230
  onClose,
218
- onSuccess,
231
+ setIsActivateSuccess,
232
+ fetchCreditInfo,
233
+ profile,
219
234
  ])
220
235
 
221
236
  return (
@@ -311,7 +326,8 @@ export default function ActivatePanel({ copy, onClose, onSuccess }: Props) {
311
326
  <Button
312
327
  type="submit"
313
328
  loading={emailValidationLoading}
314
- className="mt-6 flex h-[54px] w-full cursor-pointer items-center justify-center px-8 py-[15px] text-center text-base font-bold leading-[100%] text-white min-l:mt-8"
329
+ className="mt-6 w-full min-l:mt-8"
330
+ size="base"
315
331
  onClick={handleAuthCodeSubmit}
316
332
  >
317
333
  {copy.buttonText}