@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
1
  import { useCallback, useEffect, useState } from 'react'
2
2
  import { Button, Text } from '@anker-in/headless-ui'
3
- import { classNames as cn, useHeadlessContext } from '@anker-in/lib'
3
+ import { gaTrack, classNames as cn, useHeadlessContext } from '@anker-in/lib'
4
4
  import type { CompleteProfileCopy } from '../../type'
5
5
  import { useUpdateProfile } from './hooks/useUpdateProfile'
6
6
  import useCountries from '../../../credits/context/hooks/useCountries'
@@ -9,15 +9,13 @@ import { ROUNDED_BRANDS } from '../../../../constants'
9
9
 
10
10
  type Props = {
11
11
  copy: CompleteProfileCopy
12
- shopifyStoreDomain?: string
13
12
  onClose: () => void
14
- onSuccess?: () => void
15
13
  }
16
14
 
17
- export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', onClose, onSuccess }: Props) {
18
- const { profile, fetchCreditInfo, alpcConfig } = useMemberPopupContext()
15
+ export default function CompleteProfilePanel({ copy, onClose }: Props) {
16
+ const { profile, fetchCreditInfo, alpcConfig, setIsProfileCompleteSuccess } = useMemberPopupContext()
19
17
  const { locale } = alpcConfig
20
- const { brand } = useHeadlessContext()
18
+ const { brand, storeDomain } = useHeadlessContext()
21
19
  const rounded = ROUNDED_BRANDS.includes(brand)
22
20
 
23
21
  const [firstName, setFirstName] = useState('')
@@ -29,7 +27,7 @@ export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', on
29
27
  const [lastNameError, setLastNameError] = useState('')
30
28
 
31
29
  const { updateProfile, isLoading } = useUpdateProfile({ locale, appName: alpcConfig.appName })
32
- const { countries } = useCountries({ shopifyStoreDomain })
30
+ const { countries } = useCountries({ shopifyStoreDomain: storeDomain })
33
31
 
34
32
  useEffect(() => {
35
33
  if (profile) {
@@ -41,6 +39,12 @@ export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', on
41
39
  }
42
40
  }, [profile])
43
41
 
42
+ useEffect(() => {
43
+ if (countries.length > 0 && !country) {
44
+ setCountry(countries[0].id)
45
+ }
46
+ }, [countries])
47
+
44
48
  const validate = useCallback(() => {
45
49
  let hasError = false
46
50
  if (!firstName.trim()) {
@@ -69,21 +73,43 @@ export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', on
69
73
  })
70
74
  if (success) {
71
75
  fetchCreditInfo(profile?.user_id)
72
- onSuccess?.()
76
+ setIsProfileCompleteSuccess(true)
77
+ gaTrack({
78
+ event: 'ga4Event',
79
+ event_name: 'lp_button',
80
+ event_parameters: {
81
+ position: 'earn_credits',
82
+ button_name: 'complete_profile_success',
83
+ info: 'Member Floating Window',
84
+ },
85
+ })
73
86
  onClose()
74
87
  }
75
- }, [validate, updateProfile, firstName, lastName, phone, country, birthDay, fetchCreditInfo, profile, onSuccess, onClose])
88
+ }, [
89
+ validate,
90
+ updateProfile,
91
+ firstName,
92
+ lastName,
93
+ phone,
94
+ country,
95
+ birthDay,
96
+ fetchCreditInfo,
97
+ profile,
98
+ setIsProfileCompleteSuccess,
99
+ onClose,
100
+ ])
76
101
 
77
102
  return (
78
- <div className="flex flex-col gap-[20px]">
79
- {copy.subtitle && (
80
- <Text className="text-[14px] text-[#1d1d1f]" html={copy.subtitle} />
81
- )}
103
+ <div className="flex flex-col gap-[16px]">
104
+ {copy.subtitle && <Text className="text-[14px] text-[#1d1d1f]" html={copy.subtitle} />}
82
105
 
83
106
  <div>
84
107
  <label className="block text-[14px] font-[700] text-[#1d1d1f]">{copy.email}</label>
85
108
  <input
86
- className={cn('mt-[8px] h-[46px] w-full border border-[#d8d8d8] bg-[#f5f5f5] px-[12px] text-[14px] text-[#999]', rounded ? 'rounded-[4px]' : 'rounded-none')}
109
+ className={cn(
110
+ 'mt-[8px] h-[46px] w-full border border-[#d8d8d8] bg-[#f5f5f5] px-[12px] text-[14px] text-[#999]',
111
+ rounded ? 'rounded-[4px]' : 'rounded-none'
112
+ )}
87
113
  value={profile?.email ?? ''}
88
114
  disabled
89
115
  />
@@ -100,7 +126,10 @@ export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', on
100
126
  rounded ? 'rounded-[4px]' : 'rounded-none'
101
127
  )}
102
128
  value={firstName}
103
- onChange={e => { setFirstName(e.target.value); setFirstNameError('') }}
129
+ onChange={e => {
130
+ setFirstName(e.target.value)
131
+ setFirstNameError('')
132
+ }}
104
133
  />
105
134
  {firstNameError && <Text className="mt-[4px] text-[12px] text-[#f84d4f]" html={firstNameError} />}
106
135
  </div>
@@ -116,7 +145,10 @@ export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', on
116
145
  rounded ? 'rounded-[4px]' : 'rounded-none'
117
146
  )}
118
147
  value={lastName}
119
- onChange={e => { setLastName(e.target.value); setLastNameError('') }}
148
+ onChange={e => {
149
+ setLastName(e.target.value)
150
+ setLastNameError('')
151
+ }}
120
152
  />
121
153
  {lastNameError && <Text className="mt-[4px] text-[12px] text-[#f84d4f]" html={lastNameError} />}
122
154
  </div>
@@ -124,7 +156,10 @@ export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', on
124
156
  <div>
125
157
  <label className="block text-[14px] font-[700] text-[#1d1d1f]">{copy.birthday}</label>
126
158
  <input
127
- className={cn('mt-[8px] h-[46px] w-full border border-[#d8d8d8] px-[12px] text-[14px] outline-none', rounded ? 'rounded-[4px]' : 'rounded-none')}
159
+ className={cn(
160
+ 'mt-[8px] h-[46px] w-full border border-[#d8d8d8] px-[12px] text-[14px] outline-none',
161
+ rounded ? 'rounded-[4px]' : 'rounded-none'
162
+ )}
128
163
  type="date"
129
164
  value={birthDay}
130
165
  onChange={e => setBirthDay(e.target.value)}
@@ -134,7 +169,10 @@ export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', on
134
169
  <div>
135
170
  <label className="block text-[14px] font-[700] text-[#1d1d1f]">{copy.phone}</label>
136
171
  <input
137
- className={cn('mt-[8px] h-[46px] w-full border border-[#d8d8d8] px-[12px] text-[14px] outline-none', rounded ? 'rounded-[4px]' : 'rounded-none')}
172
+ className={cn(
173
+ 'mt-[8px] h-[46px] w-full border border-[#d8d8d8] px-[12px] text-[14px] outline-none',
174
+ rounded ? 'rounded-[4px]' : 'rounded-none'
175
+ )}
138
176
  value={phone}
139
177
  onChange={e => setPhone(e.target.value)}
140
178
  />
@@ -143,34 +181,26 @@ export default function CompleteProfilePanel({ copy, shopifyStoreDomain = '', on
143
181
  <div>
144
182
  <label className="block text-[14px] font-[700] text-[#1d1d1f]">{copy.country}</label>
145
183
  <select
146
- className={cn('mt-[8px] h-[46px] w-full border border-[#d8d8d8] px-[12px] text-[14px] outline-none', rounded ? 'rounded-[4px]' : 'rounded-none')}
184
+ className={cn(
185
+ 'mt-[8px] h-[46px] w-full border border-[#d8d8d8] px-[12px] text-[14px] outline-none',
186
+ rounded ? 'rounded-[4px]' : 'rounded-none'
187
+ )}
147
188
  value={country}
148
189
  onChange={e => setCountry(e.target.value)}
149
190
  >
150
- <option value="" />
151
191
  {countries.map((c: { id: string; name: string }) => (
152
- <option key={c.id} value={c.id}>{c.name}</option>
192
+ <option key={c.id} value={c.id}>
193
+ {c.name}
194
+ </option>
153
195
  ))}
154
196
  </select>
155
197
  </div>
156
198
 
157
199
  <div className="flex gap-[12px]">
158
- <Button
159
- variant="secondary"
160
- size="lg"
161
- className="flex-1"
162
- onClick={onClose}
163
- disabled={isLoading}
164
- >
200
+ <Button variant="secondary" size="lg" className="flex-1" onClick={onClose} disabled={isLoading}>
165
201
  {copy.cancel}
166
202
  </Button>
167
- <Button
168
- variant="primary"
169
- size="lg"
170
- className="flex-1"
171
- loading={isLoading}
172
- onClick={handleSubmit}
173
- >
203
+ <Button variant="primary" size="lg" className="flex-1" loading={isLoading} onClick={handleSubmit}>
174
204
  {copy.save}
175
205
  </Button>
176
206
  </div>
@@ -1,6 +1,6 @@
1
1
  import { useCallback, useEffect, useState } from 'react'
2
2
  import { Checkbox, Text } from '@anker-in/headless-ui'
3
- import { classNames as cn, useHeadlessContext } from '@anker-in/lib'
3
+ import { gaTrack, classNames as cn, useHeadlessContext } from '@anker-in/lib'
4
4
  import Cookies from 'js-cookie'
5
5
  import { parse } from 'query-string'
6
6
  import { emailValidate } from '../../../credits/context/utils'
@@ -12,7 +12,6 @@ type Props = {
12
12
  copy: SubscribeModalCopy
13
13
  email?: string
14
14
  onClose: () => void
15
- onSuccess?: () => void
16
15
  }
17
16
 
18
17
  function getAdCookie() {
@@ -27,8 +26,8 @@ function getAdCookie() {
27
26
  }
28
27
  }
29
28
 
30
- export default function SubscribeEmailPanel({ copy, email: initialEmail, onClose, onSuccess }: Props) {
31
- const { alpcConfig } = useMemberPopupContext()
29
+ export default function SubscribeEmailPanel({ copy, email: initialEmail, onClose }: Props) {
30
+ const { alpcConfig, setIsSubscribeSuccess, fetchCreditInfo, profile } = useMemberPopupContext()
32
31
  const { brand, locale } = alpcConfig
33
32
  const { brand: headlessBrand } = useHeadlessContext()
34
33
  const rounded = ROUNDED_BRANDS.includes(headlessBrand)
@@ -64,7 +63,17 @@ export default function SubscribeEmailPanel({ copy, email: initialEmail, onClose
64
63
  const result = await response.json()
65
64
  if (!result.errors) {
66
65
  setSuccessMessage(copy.successTips ?? 'Subscribed successfully!')
67
- onSuccess?.()
66
+ setIsSubscribeSuccess(true)
67
+ if (profile?.user_id) fetchCreditInfo(profile.user_id)
68
+ gaTrack({
69
+ event: 'ga4Event',
70
+ event_name: 'subscribe',
71
+ event_parameters: {
72
+ page_group: copy.dealsType ?? '',
73
+ position: 'sticky',
74
+ info: '',
75
+ },
76
+ })
68
77
  setTimeout(() => {
69
78
  setSuccessMessage('')
70
79
  onClose()
@@ -77,7 +86,7 @@ export default function SubscribeEmailPanel({ copy, email: initialEmail, onClose
77
86
  } finally {
78
87
  setLoading(false)
79
88
  }
80
- }, [email, policy, locale, brand, copy, onClose, onSuccess])
89
+ }, [email, policy, locale, brand, copy, onClose, setIsSubscribeSuccess])
81
90
 
82
91
  return (
83
92
  <div className="flex flex-col gap-[12px]">
@@ -1,5 +1,5 @@
1
1
  import { useMemo } from 'react'
2
- import { classNames as cn, useHeadlessContext } from '@anker-in/lib'
2
+ import { gaTrack, classNames as cn, useHeadlessContext } from '@anker-in/lib'
3
3
  import { useMemberPopupContext } from '../../context/provider'
4
4
  import { useViewStack } from '../../context/viewStack'
5
5
  import { useSubscribed } from './hooks/useSubscribed'
@@ -23,91 +23,128 @@ function TaskIcon({ id, className }: { id: EarnCreditsTaskType; className?: stri
23
23
 
24
24
  type Props = {
25
25
  copy: EarnCreditsCopy
26
- onClose: () => void
27
- isSubscribeSuccess?: boolean
28
- isActivateSuccess?: boolean
29
- isProfileCompleteSuccess?: boolean
30
- onSubscribeSuccess?: () => void
31
- onActivateSuccess?: () => void
32
- onProfileCompleteSuccess?: () => void
33
26
  }
34
27
 
35
- function EarnCredits({
36
- copy,
37
- onClose,
38
- isSubscribeSuccess = false,
39
- isActivateSuccess = false,
40
- isProfileCompleteSuccess = false,
41
- onSubscribeSuccess,
42
- onActivateSuccess,
43
- onProfileCompleteSuccess,
44
- }: Props) {
45
- const { profile, openSignUpPopup, alpcConfig, creditInfo } = useMemberPopupContext()
28
+ function EarnCredits({ copy }: Props) {
29
+ const {
30
+ profile,
31
+ openSignUpPopup,
32
+ alpcConfig,
33
+ creditInfo,
34
+ isSubscribeSuccess,
35
+ isActivateSuccess,
36
+ isProfileCompleteSuccess,
37
+ } = useMemberPopupContext()
46
38
  const { pushView } = useViewStack()
47
39
  const { locale } = alpcConfig
48
40
  const { brand } = useHeadlessContext()
49
41
  const rounded = ROUNDED_BRANDS.includes(brand)
50
42
 
43
+ console.log('creditInfo', creditInfo)
44
+
51
45
  const isLogin = !!profile
52
46
 
53
47
  const isSubscribed = useSubscribed({
54
48
  userId: profile?.user_id,
55
- brand: alpcConfig.brand,
49
+ brand: brand,
56
50
  email: profile?.email,
57
51
  locale,
58
52
  apiBaseUrl: alpcConfig.apiBaseUrl,
59
53
  })
60
54
 
61
55
  const profileCompleted = useMemo(() => {
62
- return isProfileCompleteSuccess || (!!(profile?.first_name || profile?.last_name) && !!profile?.phone_number && !!profile?.dob)
56
+ return (
57
+ isProfileCompleteSuccess ||
58
+ (!!(profile?.first_name || profile?.last_name) && !!profile?.phone_number && !!profile?.dob)
59
+ )
63
60
  }, [profile, isProfileCompleteSuccess])
64
61
 
65
- const taskStates: Record<EarnCreditsTaskType, { finished: boolean; onClick?: () => void; link?: string }> = useMemo(() => ({
66
- [EarnCreditsTaskType.Activate]: {
67
- finished: !!profile?.activated || isActivateSuccess,
68
- onClick: isLogin
69
- ? () => pushView({
70
- type: MemberPopupPanelType.Activate,
71
- props: { onSuccess: onActivateSuccess },
72
- })
73
- : openSignUpPopup,
74
- },
75
- [EarnCreditsTaskType.CompleteProfile]: {
76
- finished: profileCompleted,
77
- onClick: isLogin
78
- ? () => pushView({
79
- type: MemberPopupPanelType.CompleteProfile,
80
- props: { onSuccess: onProfileCompleteSuccess },
81
- })
82
- : openSignUpPopup,
83
- },
84
- [EarnCreditsTaskType.Subscribe]: {
85
- finished: isSubscribed || isSubscribeSuccess,
86
- onClick: isLogin
87
- ? () => pushView({
88
- type: MemberPopupPanelType.SubscribeEmail,
89
- props: { onSuccess: onSubscribeSuccess },
90
- })
91
- : openSignUpPopup,
92
- },
93
- [EarnCreditsTaskType.Shop]: {
94
- finished: false,
95
- link: copy.goShopLink,
96
- onClick: isLogin ? undefined : openSignUpPopup,
97
- },
98
- }), [profile, isLogin, isActivateSuccess, isProfileCompleteSuccess, profileCompleted, isSubscribed, isSubscribeSuccess, openSignUpPopup, pushView, copy.goShopLink])
62
+ function trackTaskButton(taskId: EarnCreditsTaskType) {
63
+ const taskButtonNameMap: Record<EarnCreditsTaskType, string> = {
64
+ [EarnCreditsTaskType.Activate]: 'activate',
65
+ [EarnCreditsTaskType.CompleteProfile]: 'complete_profile',
66
+ [EarnCreditsTaskType.Subscribe]: 'subscribe',
67
+ [EarnCreditsTaskType.Shop]: 'shop',
68
+ }
69
+ gaTrack({
70
+ event: 'ga4Event',
71
+ event_name: 'lp_button',
72
+ event_parameters: {
73
+ position: 'earn_credits',
74
+ button_name: taskButtonNameMap[taskId],
75
+ info: 'Member Floating Window',
76
+ },
77
+ })
78
+ }
79
+
80
+ const taskStates: Record<EarnCreditsTaskType, { finished: boolean; onClick?: () => void; link?: string }> = useMemo(
81
+ () => ({
82
+ [EarnCreditsTaskType.Activate]: {
83
+ finished: !!profile?.activated || isActivateSuccess,
84
+ onClick: isLogin
85
+ ? () => {
86
+ trackTaskButton(EarnCreditsTaskType.Activate)
87
+ pushView({
88
+ type: MemberPopupPanelType.Activate,
89
+ })
90
+ }
91
+ : openSignUpPopup,
92
+ },
93
+ [EarnCreditsTaskType.CompleteProfile]: {
94
+ finished: profileCompleted,
95
+ onClick: isLogin
96
+ ? () => {
97
+ trackTaskButton(EarnCreditsTaskType.CompleteProfile)
98
+ pushView({
99
+ type: MemberPopupPanelType.CompleteProfile,
100
+ })
101
+ }
102
+ : openSignUpPopup,
103
+ },
104
+ [EarnCreditsTaskType.Subscribe]: {
105
+ finished: isSubscribed || isSubscribeSuccess,
106
+ onClick: isLogin
107
+ ? () => {
108
+ trackTaskButton(EarnCreditsTaskType.Subscribe)
109
+ pushView({
110
+ type: MemberPopupPanelType.SubscribeEmail,
111
+ })
112
+ }
113
+ : openSignUpPopup,
114
+ },
115
+ [EarnCreditsTaskType.Shop]: {
116
+ finished: false,
117
+ link: copy.goShopLink,
118
+ onClick: isLogin ? () => trackTaskButton(EarnCreditsTaskType.Shop) : openSignUpPopup,
119
+ },
120
+ }),
121
+ [
122
+ profile,
123
+ isLogin,
124
+ isActivateSuccess,
125
+ isProfileCompleteSuccess,
126
+ profileCompleted,
127
+ isSubscribed,
128
+ isSubscribeSuccess,
129
+ openSignUpPopup,
130
+ pushView,
131
+ copy.goShopLink,
132
+ ]
133
+ )
99
134
 
100
135
  const list = useMemo(() => {
101
- return copy.list.map(item => {
102
- const state = taskStates[item.id]
103
- if (!state) return null
104
- const buttonLabel = state.finished
105
- ? copy.completed
106
- : isLogin
107
- ? getNotFinishedLabel(item.id, copy)
108
- : copy.joinNow
109
- return { ...item, ...state, buttonLabel }
110
- }).filter(Boolean) as (typeof copy.list[number] & {
136
+ return copy.list
137
+ .map(item => {
138
+ const state = taskStates[item.id]
139
+ if (!state) return null
140
+ const buttonLabel = state.finished
141
+ ? copy.completed
142
+ : isLogin
143
+ ? getNotFinishedLabel(item.id, copy)
144
+ : copy.joinNow
145
+ return { ...item, ...state, buttonLabel }
146
+ })
147
+ .filter(Boolean) as ((typeof copy.list)[number] & {
111
148
  finished: boolean
112
149
  onClick?: () => void
113
150
  link?: string
@@ -122,15 +159,18 @@ function EarnCredits({
122
159
  {copy.title && <h2 className="text-[24px] font-[700] leading-[1.2] text-[#080a0f]">{copy.title}</h2>}
123
160
  </div>
124
161
 
125
- {isLogin && creditInfo && (
126
- <div className={cn('flex items-center gap-[12px] bg-[#f5f6f7] p-[16px]', rounded ? 'rounded-[8px]' : 'rounded-none')}>
162
+ {isLogin && (
163
+ <div
164
+ className={cn(
165
+ 'flex items-center gap-[12px] bg-[#f5f6f7] p-[16px]',
166
+ rounded ? 'rounded-[8px]' : 'rounded-none'
167
+ )}
168
+ >
127
169
  <div className="flex flex-1 flex-col gap-[4px]">
128
- <div className="text-[14px] font-[700] text-[#1e2024]">
129
- {copy.balanceLabel ?? 'AnkerCredits Balance'}
130
- </div>
170
+ <div className="text-[14px] font-[700] text-[#1e2024]">{copy.balanceLabel ?? 'AnkerCredits Balance'}</div>
131
171
  <div className="flex items-end gap-[4px]">
132
172
  <span className="text-[24px] font-[700] leading-[1.2] text-[#1e2024]">
133
- {numberFormat(creditInfo.available_credit)}
173
+ {numberFormat(creditInfo?.available_credit ?? 0)}
134
174
  </span>
135
175
  <span className="text-[14px] font-[700] leading-[1.4] text-[#1e2024]">
136
176
  {copy.creditUnit ?? 'ankercredits'}
@@ -139,12 +179,10 @@ function EarnCredits({
139
179
  </div>
140
180
  <div className="h-full w-px bg-[#dadce0]" />
141
181
  <div className="flex flex-1 flex-col gap-[4px]">
142
- <div className="text-[14px] font-[700] text-[#1e2024]">
143
- {copy.comingSoonLabel ?? 'Coming Soon'}
144
- </div>
182
+ <div className="text-[14px] font-[700] text-[#1e2024]">{copy.comingSoonLabel ?? 'Coming Soon'}</div>
145
183
  <div className="flex items-end gap-[4px]">
146
184
  <span className="text-[24px] font-[700] leading-[1.2] text-[#1e2024]">
147
- {numberFormat(creditInfo.pending_credit ?? 0)}
185
+ {numberFormat(creditInfo?.pending_credit ?? 0)}
148
186
  </span>
149
187
  <span className="text-[14px] font-[700] leading-[1.4] text-[#1e2024]">
150
188
  {copy.creditUnit ?? 'ankercredits'}
@@ -156,15 +194,13 @@ function EarnCredits({
156
194
  </div>
157
195
 
158
196
  <div className="flex flex-col gap-[16px]">
159
- {copy.subtitle && (
160
- <p className="text-[16px] font-[700] text-[#1e2024]">{copy.subtitle}</p>
161
- )}
197
+ {copy.subtitle && <p className="text-[16px] font-[700] text-[#1e2024]">{copy.subtitle}</p>}
162
198
 
163
199
  <div className="flex flex-col">
164
200
  {list.map((item, idx) => (
165
201
  <div key={idx} className="relative py-[16px]">
166
202
  {idx > 0 && <div className="absolute left-0 right-0 top-0 h-px bg-[#dadce0]" />}
167
- <div className={cn('flex items-center gap-[12px]', item.finished && 'opacity-60')}>
203
+ <div className={cn('flex items-center gap-[12px]')}>
168
204
  <TaskIcon id={item.id} className="size-[24px] shrink-0" />
169
205
  <div className="flex-1">
170
206
  <div className="text-[16px] font-[700] text-[#1e2024]">{item.title}</div>
@@ -172,12 +208,16 @@ function EarnCredits({
172
208
  <div className="mt-[4px] text-[14px] font-[700] text-[#4a4c56]">{item.description}</div>
173
209
  )}
174
210
  </div>
175
- {!item.finished && item.link ? (
211
+ {!item.finished && item.link && isLogin ? (
176
212
  <a
177
213
  href={item.link}
178
214
  target="_blank"
179
215
  rel="noopener noreferrer"
180
- className={cn('cursor-pointer bg-[#080a0f] min-w-[118px] px-[20px] pb-[10px] pt-[11px] text-[14px] font-[700] leading-[1.2] text-white', rounded ? 'rounded-[4px]' : 'rounded-none')}
216
+ className={cn(
217
+ 'cursor-pointer bg-[#080a0f] min-w-[118px] px-[20px] pb-[10px] pt-[11px] text-[14px] font-[700] leading-[1.2] text-white',
218
+ rounded ? 'rounded-[4px]' : 'rounded-none'
219
+ )}
220
+ onClick={() => trackTaskButton(item.id)}
181
221
  >
182
222
  {item.buttonLabel}
183
223
  </a>
@@ -186,7 +226,8 @@ function EarnCredits({
186
226
  className={cn(
187
227
  'cursor-pointer min-w-[118px] px-[20px] pb-[10px] pt-[11px] text-[14px] font-[700] leading-[1.2] text-white',
188
228
  item.finished ? 'bg-[#767880]' : 'bg-[#080a0f]',
189
- rounded ? 'rounded-[4px]' : 'rounded-none'
229
+ rounded ? 'rounded-[4px]' : 'rounded-none',
230
+ item.finished && 'opacity-60'
190
231
  )}
191
232
  disabled={item.finished}
192
233
  onClick={!item.finished ? item.onClick : undefined}
@@ -205,10 +246,14 @@ function EarnCredits({
205
246
 
206
247
  function getNotFinishedLabel(id: EarnCreditsTaskType, copy: EarnCreditsCopy): string {
207
248
  switch (id) {
208
- case EarnCreditsTaskType.Activate: return copy.activate
209
- case EarnCreditsTaskType.CompleteProfile: return copy.completeProfileLabel
210
- case EarnCreditsTaskType.Subscribe: return copy.subscribeLabel
211
- case EarnCreditsTaskType.Shop: return copy.shopNow
249
+ case EarnCreditsTaskType.Activate:
250
+ return copy.activate
251
+ case EarnCreditsTaskType.CompleteProfile:
252
+ return copy.completeProfileLabel
253
+ case EarnCreditsTaskType.Subscribe:
254
+ return copy.subscribeLabel
255
+ case EarnCreditsTaskType.Shop:
256
+ return copy.shopNow
212
257
  }
213
258
  }
214
259
 
@@ -1,5 +1,5 @@
1
1
  import { Picture } from '@anker-in/headless-ui'
2
- import { classNames as cn, useHeadlessContext } from '@anker-in/lib'
2
+ import { gaTrack, classNames as cn, useHeadlessContext } from '@anker-in/lib'
3
3
  import { useMemberPopupContext } from '../../context/provider'
4
4
  import { useReferralOverview } from './hooks/useReferralOverview'
5
5
  import { formatPrice } from '../../../credits/context/utils'
@@ -13,7 +13,7 @@ type Props = {
13
13
  }
14
14
 
15
15
  function Referral({ copy, onClose }: Props) {
16
- const { profile, alpcConfig } = useMemberPopupContext()
16
+ const { profile, alpcConfig, pageHandle } = useMemberPopupContext()
17
17
  const isLogin = !!profile
18
18
  const { brand, currencyCode = 'USD' as string } = useHeadlessContext()
19
19
  const rounded = ROUNDED_BRANDS.includes(brand)
@@ -23,19 +23,37 @@ function Referral({ copy, onClose }: Props) {
23
23
  const cashAvailable = data?.data?.data?.available ?? 0
24
24
  const cashPending = data?.data?.data?.pending ?? 0
25
25
 
26
- console.log('cashAvailable', cashAvailable)
27
- console.log('cashPending', cashPending)
28
- console.log('data', data)
29
- console.log('data.data', data?.data)
26
+ function buildRefUrl(url: string) {
27
+ try {
28
+ if (!pageHandle) return url
29
+ const target = new URL(url, window.location.href)
30
+ target.searchParams.set('ref', `${pageHandle}_referral`)
31
+ return target.toString()
32
+ } catch {
33
+ return url
34
+ }
35
+ }
36
+
37
+ function trackReferralCta() {
38
+ gaTrack({
39
+ event: 'ga4Event',
40
+ event_name: 'lp_button',
41
+ event_parameters: {
42
+ position: 'referral',
43
+ button_name: 'referral_cta',
44
+ info: 'Member Floating Window',
45
+ },
46
+ })
47
+ }
30
48
 
31
49
  return (
32
- <div className="flex flex-col gap-[12px]">
50
+ <div className="flex flex-col">
33
51
  {copy.title && <h2 className="text-[24px] font-[700] leading-[1.2] text-[#080a0f]">{copy.title}</h2>}
34
52
 
35
53
  {isLogin && (
36
54
  <div
37
55
  className={cn(
38
- 'flex items-center gap-[12px] bg-[#f5f6f7] p-[16px]',
56
+ 'flex items-center mt-[16px] gap-[12px] bg-[#f5f6f7] p-[16px]',
39
57
  rounded ? 'rounded-[8px]' : 'rounded-none'
40
58
  )}
41
59
  >
@@ -56,14 +74,14 @@ function Referral({ copy, onClose }: Props) {
56
74
  )}
57
75
 
58
76
  {(copy.howToTitle || copy.howToDescription) && (
59
- <div className="flex flex-col gap-[8px]">
60
- {copy.howToTitle && (
61
- <h3 className="text-[20px] font-[700] leading-[1.2] text-[#080a0f]">{copy.howToTitle}</h3>
77
+ <div className="flex mt-[32px] flex-col gap-[8px]">
78
+ {copy.howToTitle && <h3 className="text-[20px] font-bold leading-[1.2] text-[#080a0f]">{copy.howToTitle}</h3>}
79
+ {copy.howToDescription && (
80
+ <p className="text-[14px] font-bold leading-[1.4] text-[#080A0F]">{copy.howToDescription}</p>
62
81
  )}
63
- {copy.howToDescription && <p className="text-[14px] leading-[1.5] text-[#1e2024]">{copy.howToDescription}</p>}
64
82
  {copy.learnMoreLabel && copy.learnMoreUrl && (
65
83
  <a
66
- href={copy.learnMoreUrl}
84
+ href={buildRefUrl(copy.learnMoreUrl)}
67
85
  target="_blank"
68
86
  rel="noopener noreferrer"
69
87
  className="flex items-center gap-[4px] text-[14px] font-[700] text-[#080a0f] underline"
@@ -84,19 +102,20 @@ function Referral({ copy, onClose }: Props) {
84
102
  <Picture
85
103
  source={copy.image.url}
86
104
  alt={copy.image.alt ?? ''}
87
- className={cn('h-[100px] w-full object-cover', rounded ? 'rounded-[8px]' : 'rounded-none')}
105
+ className={cn('mt-[8px] w-full', rounded ? 'rounded-[8px]' : 'rounded-none')}
88
106
  />
89
107
  )}
90
108
 
91
109
  {copy.ctaButton && (
92
110
  <a
93
- href={copy.ctaUrl ?? '#'}
111
+ href={copy.ctaUrl ? buildRefUrl(copy.ctaUrl) : '#'}
94
112
  target="_blank"
95
113
  rel="noopener noreferrer"
96
114
  className={cn(
97
- 'block w-full cursor-pointer bg-[#080a0f] py-[14px] text-center text-[14px] font-[700] text-white',
115
+ 'block w-full mt-[16px] cursor-pointer bg-[#080a0f] py-[14px] text-center text-[14px] font-[700] text-white',
98
116
  rounded ? 'rounded-[4px]' : 'rounded-none'
99
117
  )}
118
+ onClick={trackReferralCta}
100
119
  >
101
120
  {copy.ctaButton}
102
121
  </a>