@anker-in/campaign-ui 0.5.0-beta.2 → 0.5.0-beta.21

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