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

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 (137) 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/esm/components/credits/context/hooks/useCountries.js +1 -1
  38. package/dist/esm/components/credits/context/hooks/useCountries.js.map +3 -3
  39. package/dist/esm/components/memberPopup/MemberPopup.d.ts +1 -1
  40. package/dist/esm/components/memberPopup/MemberPopup.js +1 -1
  41. package/dist/esm/components/memberPopup/MemberPopup.js.map +3 -3
  42. package/dist/esm/components/memberPopup/context/provider.d.ts +3 -3
  43. package/dist/esm/components/memberPopup/context/provider.js +1 -1
  44. package/dist/esm/components/memberPopup/context/provider.js.map +3 -3
  45. package/dist/esm/components/memberPopup/panels/ActivitiesSubscribePanel.d.ts +7 -0
  46. package/dist/esm/components/memberPopup/panels/ActivitiesSubscribePanel.js +2 -0
  47. package/dist/esm/components/memberPopup/panels/ActivitiesSubscribePanel.js.map +7 -0
  48. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.d.ts +9 -7
  49. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js +1 -1
  50. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js.map +3 -3
  51. package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.d.ts +1 -2
  52. package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.js +1 -1
  53. package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.js.map +3 -3
  54. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.d.ts +1 -2
  55. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.js +1 -1
  56. package/dist/esm/components/memberPopup/panels/EarnCredits/ActivatePanel.js.map +3 -3
  57. package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfileModal.js +1 -1
  58. package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfileModal.js.map +2 -2
  59. package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.d.ts +1 -3
  60. package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js +1 -1
  61. package/dist/esm/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.js.map +3 -3
  62. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.d.ts +1 -2
  63. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js +1 -1
  64. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.js.map +3 -3
  65. package/dist/esm/components/memberPopup/panels/EarnCredits/index.d.ts +1 -8
  66. package/dist/esm/components/memberPopup/panels/EarnCredits/index.js +1 -1
  67. package/dist/esm/components/memberPopup/panels/EarnCredits/index.js.map +3 -3
  68. package/dist/esm/components/memberPopup/panels/Referral/index.js +1 -1
  69. package/dist/esm/components/memberPopup/panels/Referral/index.js.map +3 -3
  70. package/dist/esm/components/memberPopup/type.d.ts +29 -3
  71. package/dist/esm/components/memberPopup/type.js +1 -1
  72. package/dist/esm/components/memberPopup/type.js.map +2 -2
  73. package/package.json +1 -1
  74. package/src/components/credits/context/hooks/useCountries.ts +4 -15
  75. package/src/components/memberPopup/MemberPopup.tsx +170 -177
  76. package/src/components/memberPopup/context/provider.tsx +24 -4
  77. package/src/components/memberPopup/panels/ActivitiesSubscribePanel.tsx +194 -0
  78. package/src/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.tsx +93 -60
  79. package/src/components/memberPopup/panels/ConsumeCredits/index.tsx +199 -87
  80. package/src/components/memberPopup/panels/EarnCredits/ActivatePanel.tsx +30 -15
  81. package/src/components/memberPopup/panels/EarnCredits/CompleteProfileModal.tsx +6 -1
  82. package/src/components/memberPopup/panels/EarnCredits/CompleteProfilePanel.tsx +65 -35
  83. package/src/components/memberPopup/panels/EarnCredits/SubscribeEmailPanel.tsx +15 -6
  84. package/src/components/memberPopup/panels/EarnCredits/index.tsx +131 -86
  85. package/src/components/memberPopup/panels/Referral/index.tsx +35 -16
  86. package/src/components/memberPopup/type.ts +26 -3
  87. package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.d.ts +0 -10
  88. package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.js +0 -2
  89. package/dist/cjs/components/memberPopup/panels/Activity/SubscribeModal.js.map +0 -7
  90. package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.d.ts +0 -7
  91. package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js +0 -2
  92. package/dist/cjs/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js.map +0 -7
  93. package/dist/cjs/components/memberPopup/panels/Activity/index.d.ts +0 -7
  94. package/dist/cjs/components/memberPopup/panels/Activity/index.js +0 -2
  95. package/dist/cjs/components/memberPopup/panels/Activity/index.js.map +0 -7
  96. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.d.ts +0 -19
  97. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js +0 -2
  98. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js.map +0 -7
  99. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.d.ts +0 -10
  100. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.js +0 -2
  101. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribeModal.js.map +0 -7
  102. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.d.ts +0 -9
  103. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.js +0 -2
  104. package/dist/cjs/components/memberPopup/panels/EarnCredits/SubscribePanel.js.map +0 -7
  105. package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.d.ts +0 -13
  106. package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js +0 -2
  107. package/dist/cjs/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js.map +0 -7
  108. package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.d.ts +0 -10
  109. package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.js +0 -2
  110. package/dist/esm/components/memberPopup/panels/Activity/SubscribeModal.js.map +0 -7
  111. package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.d.ts +0 -7
  112. package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js +0 -2
  113. package/dist/esm/components/memberPopup/panels/Activity/hooks/useActivitySubscribe.js.map +0 -7
  114. package/dist/esm/components/memberPopup/panels/Activity/index.d.ts +0 -7
  115. package/dist/esm/components/memberPopup/panels/Activity/index.js +0 -2
  116. package/dist/esm/components/memberPopup/panels/Activity/index.js.map +0 -7
  117. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.d.ts +0 -19
  118. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js +0 -2
  119. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.js.map +0 -7
  120. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.d.ts +0 -10
  121. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.js +0 -2
  122. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribeModal.js.map +0 -7
  123. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.d.ts +0 -9
  124. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.js +0 -2
  125. package/dist/esm/components/memberPopup/panels/EarnCredits/SubscribePanel.js.map +0 -7
  126. package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.d.ts +0 -13
  127. package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js +0 -2
  128. package/dist/esm/components/memberPopup/panels/Referral/hooks/useReferralDashboard.js.map +0 -7
  129. package/dist/index.d.mts +0 -1775
  130. package/dist/index.d.ts +0 -1775
  131. package/dist/index.js +0 -18542
  132. package/dist/index.js.map +0 -1
  133. package/dist/index.mjs +0 -18514
  134. package/dist/index.mjs.map +0 -1
  135. package/src/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.tsx +0 -150
  136. package/src/components/memberPopup/panels/EarnCredits/SubscribeModal.tsx +0 -144
  137. package/src/components/memberPopup/panels/EarnCredits/SubscribePanel.tsx +0 -147
@@ -0,0 +1,194 @@
1
+ import { useCallback, useEffect, useState } from 'react'
2
+ import { Button, Checkbox, Picture, Text } from '@anker-in/headless-ui'
3
+ import { gaTrack, classNames as cn, useHeadlessContext } from '@anker-in/lib'
4
+ import Cookies from 'js-cookie'
5
+ import { parse } from 'query-string'
6
+ import { emailValidate } from '../../credits/context/utils'
7
+ import { useMemberPopupContext } from '../context/provider'
8
+ import type { SubscribeModalCopy } from '../type'
9
+ import { ROUNDED_BRANDS } from '../../../constants'
10
+
11
+ type Props = {
12
+ copy: SubscribeModalCopy
13
+ email?: string
14
+ }
15
+
16
+ function getAdCookie() {
17
+ if (typeof window === 'undefined') return { register_source: '' }
18
+ const { search, href } = window.location
19
+ const query = parse(search)
20
+ return {
21
+ fbuy_ref_code: Cookies.get('fbuy_ref_code'),
22
+ ref: Cookies.get('ref_ads'),
23
+ inviter_code: query.ic ?? query.inviter_code ?? Cookies.get('inviter_code'),
24
+ register_source: query.redirect ?? Cookies.get('reg_source') ?? href,
25
+ }
26
+ }
27
+
28
+ async function getRecaptchaToken(sitekey: string): Promise<string> {
29
+ if (typeof window === 'undefined' || !window?.grecaptcha?.execute) return ''
30
+ if (!sitekey) return ''
31
+ try {
32
+ return await window.grecaptcha.execute(sitekey, { action: 'activity' })
33
+ } catch {
34
+ return ''
35
+ }
36
+ }
37
+
38
+ export default function ActivitiesSubscribeModal({ copy, email: initialEmail }: Props) {
39
+ const { alpcConfig, setIsSubscribeSuccess, pageHandle } = useMemberPopupContext()
40
+ const { locale } = alpcConfig
41
+ const { brand: headlessBrand, storeDomain, recaptchaSitekey } = useHeadlessContext()
42
+ const rounded = ROUNDED_BRANDS.includes(headlessBrand)
43
+ const [policy, setPolicy] = useState(false)
44
+ const [email, setEmail] = useState(initialEmail ?? '')
45
+ const [errorMessage, setErrorMessage] = useState('')
46
+ const [successMessage, setSuccessMessage] = useState('')
47
+ const [loading, setLoading] = useState(false)
48
+
49
+ useEffect(() => {
50
+ if (initialEmail) setEmail(initialEmail)
51
+ }, [initialEmail])
52
+
53
+ const handleSubmit = useCallback(async () => {
54
+ setErrorMessage('')
55
+ if (!email) return setErrorMessage('Please fill in your email')
56
+ if (!emailValidate(email)) return setErrorMessage('Invalid email address')
57
+ if (!policy) return setErrorMessage('Please agree to the policy')
58
+
59
+ setLoading(true)
60
+ const { register_source } = getAdCookie()
61
+ const recaptchaToken = await getRecaptchaToken(recaptchaSitekey || '')
62
+ try {
63
+ const response = await fetch('/api/multipass/rainbowbridge/activities', {
64
+ method: 'POST',
65
+ headers: {
66
+ 'Content-Type': 'application/json',
67
+ 'current-language': locale,
68
+ 'X-Recaptcha-Token': recaptchaToken,
69
+ },
70
+ body: JSON.stringify({
71
+ email,
72
+ register_source,
73
+ shopify_domain: storeDomain,
74
+ single_brand_subscribe: copy.single_brand_subscribe ?? true,
75
+ genre: copy.genre ?? copy.dealsType ?? '',
76
+ sub_brand_type: copy.sub_brand_type ?? '',
77
+ }),
78
+ })
79
+ const result = await response.json()
80
+ if (!result?.data?.is_new_subscribe) {
81
+ setSuccessMessage(copy.subscribedLabel ?? "You've already subscribed!")
82
+ } else if (!result?.data?.errors) {
83
+ setSuccessMessage(copy.successTips ?? 'Subscribed successfully!')
84
+ setIsSubscribeSuccess(true)
85
+ gaTrack({
86
+ event: 'ga4Event',
87
+ event_name: 'subscribe',
88
+ event_parameters: {
89
+ page_group: copy.dealsType ?? copy.genre ?? '',
90
+ position: 'sticky',
91
+ info: 'Member Floating Window',
92
+ },
93
+ })
94
+ } else {
95
+ setErrorMessage(result?.data?.errors ?? 'Error occurred')
96
+ }
97
+ } catch {
98
+ setErrorMessage('Network error')
99
+ } finally {
100
+ setLoading(false)
101
+ }
102
+ }, [email, policy, locale, storeDomain, copy, setIsSubscribeSuccess])
103
+
104
+ return (
105
+ <div className="flex flex-col">
106
+ <Text className="text-[22px] font-bold leading-[1.2]" html={copy.title} />
107
+ {copy.desc && <Text className="text-[16px] mt-[16px] font-bold text-[#1E2024]" html={copy.desc} />}
108
+
109
+ <input
110
+ className={cn(
111
+ 'h-[46px] w-full border mt-[8px] px-[14px] text-[16px] outline-none placeholder:text-[#999]',
112
+ rounded ? 'rounded-[4px]' : 'rounded-none'
113
+ )}
114
+ placeholder={copy.placeholder}
115
+ value={email}
116
+ onChange={e => {
117
+ setErrorMessage('')
118
+ setEmail(e.target.value.trim())
119
+ }}
120
+ />
121
+
122
+ <div className="flex w-full mt-[8px] items-start gap-[8px]">
123
+ <Checkbox checked={policy} onCheckedChange={() => setPolicy(v => !v)} className="border-[#1d1d1f] mt-[2px]" />
124
+ <label
125
+ className="text-left text-[14px] font-bold text-[#4A4C56] [&_a]:underline"
126
+ dangerouslySetInnerHTML={{ __html: copy.policy ?? '' }}
127
+ />
128
+ </div>
129
+
130
+ <button
131
+ className={cn(
132
+ 'w-full cursor-pointer bg-[#080a0f] mt-[16px] py-[14px] text-[14px] font-[700] text-white disabled:opacity-60',
133
+ rounded ? 'rounded-[4px]' : 'rounded-none'
134
+ )}
135
+ disabled={loading}
136
+ onClick={handleSubmit}
137
+ >
138
+ {copy.buttonLabel ?? 'Subscribe'}
139
+ </button>
140
+
141
+ {errorMessage && (
142
+ <div className="text-left mt-[4px] text-[16px] font-semibold text-[#f84d4f]">
143
+ <Text html={errorMessage} />
144
+ </div>
145
+ )}
146
+ <div className="text-left mt-[4px] text-[16px] font-semibold text-[#52c41a]">
147
+ <Text html={successMessage} />
148
+ </div>
149
+
150
+ {copy.promo && (
151
+ <div className="flex mt-[32px] flex-col text-left">
152
+ <div className="flex flex-col">
153
+ {copy.promo?.title && <Text className="text-[18px] font-bold leading-[1.2]" html={copy.promo.title} />}
154
+ {copy.promo.description && (
155
+ <Text className="text-[14px] text-[#080A0F] mt-[8px] font-bold" html={copy.promo.description} />
156
+ )}
157
+ {copy.promo.learnMoreLabel && copy.promo.learnMoreUrl && (
158
+ <a
159
+ href={(() => {
160
+ try {
161
+ if (!pageHandle) return copy.promo!.learnMoreUrl!
162
+ const url = new URL(copy.promo!.learnMoreUrl!, window.location.href)
163
+ url.searchParams.set('ref', `${pageHandle}_subscribe`)
164
+ return url.toString()
165
+ } catch {
166
+ return copy.promo!.learnMoreUrl!
167
+ }
168
+ })()}
169
+ target="_blank"
170
+ rel="noopener noreferrer"
171
+ className="flex mt-[8px] items-center gap-[4px] text-[14px] font-bold"
172
+ >
173
+ {copy.promo.learnMoreLabel}
174
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
175
+ <path
176
+ d="M5.52827 3.52876C5.78862 3.26841 6.21063 3.26841 6.47098 3.52876L10.471 7.52876C10.7313 7.78911 10.7313 8.21112 10.471 8.47147L6.47098 12.4715C6.21063 12.7318 5.78862 12.7318 5.52827 12.4715C5.26792 12.2111 5.26792 11.7891 5.52827 11.5288L9.05692 8.00011L5.52827 4.47147C5.26792 4.21112 5.26792 3.78911 5.52827 3.52876Z"
177
+ fill="#080A0F"
178
+ />
179
+ </svg>
180
+ </a>
181
+ )}
182
+ </div>
183
+ {copy.promo.image?.url && (
184
+ <Picture
185
+ source={copy.promo.image.url}
186
+ alt={copy.promo.image.alt ?? ''}
187
+ className={cn('h-[100px] mt-[8px] w-full object-cover', rounded ? 'rounded-[8px]' : 'rounded-none')}
188
+ />
189
+ )}
190
+ </div>
191
+ )}
192
+ </div>
193
+ )
194
+ }
@@ -1,41 +1,34 @@
1
1
  import { useCallback, useEffect, useState } from 'react'
2
2
  import { Text, Button } from '@anker-in/headless-ui'
3
- import { useHeadlessContext, classNames as cn } from '@anker-in/lib'
3
+ import { gaTrack, useHeadlessContext, classNames as cn } from '@anker-in/lib'
4
4
  import { AlpcErrorCode } from '../../../credits/context/const'
5
5
  import { useRedeemCoupon } from './hooks/useRedeemCoupon'
6
6
  import useCopy from '../../../credits/context/hooks/useCopy'
7
- import type { RedeemCouponModalCopy, AlpcConfig } from '../../type'
7
+ import type { ConsumeCreditsopy, AlpcConfig } from '../../type'
8
8
  import { ROUNDED_BRANDS } from '../../../../constants'
9
9
 
10
- type Props = {
11
- onClose: () => void
10
+ type RedeemCouponItem = {
12
11
  itemTitle: string
13
12
  itemCredits: number
14
13
  itemImage?: { url: string; alt?: string }
15
14
  itemValue?: string
16
- itemOff?: string
15
+ itemRules?: string[]
17
16
  redeemId: number
18
17
  userId?: string
19
- copy: RedeemCouponModalCopy
20
- pointUnit?: string
21
18
  alpcConfig: AlpcConfig
19
+ }
20
+
21
+ type Props = {
22
+ onClose: () => void
23
+ item: RedeemCouponItem
24
+ copy: ConsumeCreditsopy
22
25
  onError?: (code: number) => void
23
26
  }
24
27
 
25
- export default function RedeemCouponPanel({
26
- onClose,
27
- itemTitle,
28
- itemCredits,
29
- itemImage,
30
- itemValue,
31
- itemOff,
32
- redeemId,
33
- userId,
34
- copy,
35
- pointUnit = 'pts',
36
- alpcConfig,
37
- onError,
38
- }: Props) {
28
+ export default function RedeemCouponPanel({ onClose, item, copy, onError }: Props) {
29
+ const { itemTitle, itemCredits, itemImage, itemValue, itemRules, redeemId, userId, alpcConfig } = item
30
+ const { redeemModal, creditUnit } = copy
31
+ const pointUnit = creditUnit ?? 'pts'
39
32
  const [couponCode, setCouponCode] = useState<string>()
40
33
  const [errorInfo, setErrorInfo] = useState('')
41
34
  const [disabled, setDisabled] = useState(false)
@@ -49,30 +42,39 @@ export default function RedeemCouponPanel({
49
42
  setErrorInfo('')
50
43
  const { data } = await trigger({ user_id: userId, rule_id: redeemId })
51
44
  if (!data) {
52
- setErrorInfo(copy.commonError)
45
+ setErrorInfo(redeemModal.commonError)
53
46
  return
54
47
  }
55
48
  if (data.data?.success) {
56
49
  setCouponCode(data.data.coupon_code)
50
+ gaTrack({
51
+ event: 'ga4Event',
52
+ event_name: 'lp_button',
53
+ event_parameters: {
54
+ position: 'consume_credits',
55
+ button_name: 'redeem_coupon_success',
56
+ info: 'Member Floating Window',
57
+ },
58
+ })
57
59
  } else {
58
- let msg = copy.commonError
60
+ let msg = redeemModal.commonError
59
61
  if (data.code === AlpcErrorCode.CodeLpcShopifyCouponRuleRedeemLimit) {
60
- msg = copy.redeemLimitError
62
+ msg = redeemModal.redeemLimitError
61
63
  setDisabled(true)
62
64
  } else if (data.code === AlpcErrorCode.CodeLpcRuleInventoryNotEnough) {
63
- msg = copy.inventoryNotEnough
65
+ msg = redeemModal.inventoryNotEnough
64
66
  setDisabled(true)
65
67
  } else if (data.code === AlpcErrorCode.CodeLpcNotEnoughCredits) {
66
- msg = copy.creditsNotEnough
68
+ msg = redeemModal.creditsNotEnough
67
69
  setDisabled(true)
68
70
  } else if (data.code === AlpcErrorCode.CodeCrossSiteError) {
69
- msg = copy.crossSiteError
71
+ msg = redeemModal.crossSiteError
70
72
  setDisabled(true)
71
73
  }
72
74
  setErrorInfo(msg)
73
75
  onError?.(data.code)
74
76
  }
75
- }, [trigger, userId, redeemId, copy, onError])
77
+ }, [trigger, userId, redeemId, redeemModal, onError])
76
78
 
77
79
  useEffect(() => {
78
80
  setCouponCode(undefined)
@@ -80,38 +82,45 @@ export default function RedeemCouponPanel({
80
82
  setDisabled(false)
81
83
  }, [redeemId])
82
84
 
85
+ const rulesSection = itemRules && itemRules.length > 0 && (
86
+ <div className="w-full text-[16px] font-bold leading-[1.4] text-[#6D6D6F] md:mt-[12px] md:text-[14px]">
87
+ <ul className="ml-4 grid grid-flow-row gap-[4px]">
88
+ {itemRules?.map((text, index) => (
89
+ <li className="list-disc" key={index}>
90
+ <Text html={text} className="font-bold" />
91
+ </li>
92
+ ))}
93
+ </ul>
94
+ </div>
95
+ )
96
+
83
97
  return (
84
- <div className="flex flex-col gap-[16px]">
98
+ <div className="flex flex-col">
85
99
  {itemImage?.url && (
86
- <div className={cn('relative overflow-hidden w-fit mx-auto', rounded ? 'rounded-[8px]' : 'rounded-none')}>
87
- <img src={itemImage.url} alt={itemImage.alt ?? ''} className="mx-auto h-[140px] object-contain" />
88
- {itemValue && (
89
- <div className="absolute bottom-[20px] left-[20px] text-[32px] font-[800] leading-none text-white">
90
- {itemValue}
91
- {itemOff ? ` ${itemOff}` : ''}
92
- </div>
93
- )}
100
+ <div className="relative w-full px-[24px]">
101
+ <div className={cn('relative mx-auto overflow-hidden', rounded ? 'rounded-[8px]' : 'rounded-none')}>
102
+ <img src={itemImage.url} alt={itemImage.alt ?? ''} className="mx-auto h-[140px] w-full object-cover" />
103
+ {itemValue && (
104
+ <div className="absolute bottom-[20px] left-[20px] text-[32px] font-[800] leading-none text-white">
105
+ {itemValue}
106
+ {redeemModal.off ? ` ${redeemModal.off}` : ''}
107
+ </div>
108
+ )}
109
+ </div>
94
110
  </div>
95
111
  )}
96
112
 
97
- <p className="text-center text-[24px] font-[700] text-[#1d1d1f]">
98
- {itemCredits} {pointUnit}
99
- </p>
100
-
101
- {!couponCode ? (
102
- <div className="flex flex-col gap-[12px] text-center">
103
- <Text className="block text-[20px] font-[700]" html={copy.confirmTitle} />
104
- <Button
105
- className={cn('w-full py-[12px] text-[14px] font-[700] text-white disabled:opacity-60 bg-[#080a0f]', rounded ? 'rounded-[4px]' : 'rounded-none')}
106
- disabled={disabled}
107
- loading={loading}
108
- onClick={handleConfirm}
109
- >
110
- {copy.confirmButton}
111
- </Button>
113
+ {!couponCode && (
114
+ <div className="flex flex-col gap-[16px] px-[24px] py-[20px]">
115
+ <p className="text-center text-[24px] font-[700] text-[#1d1d1f]">
116
+ {itemCredits} {pointUnit}
117
+ </p>
118
+ {rulesSection}
112
119
  </div>
113
- ) : (
114
- <div className="flex flex-col gap-[12px] text-center">
120
+ )}
121
+
122
+ {couponCode && (
123
+ <div className="flex mt-[16px] flex-col gap-[8px] text-center">
115
124
  <div className="flex items-center justify-center gap-[10px]">
116
125
  <span className="text-[24px] font-[700]">{couponCode}</span>
117
126
  <button
@@ -122,21 +131,45 @@ export default function RedeemCouponPanel({
122
131
  {copied ? 'Copied' : 'Copy'}
123
132
  </button>
124
133
  </div>
125
- <Text className="text-[20px] font-[700]" html={copy.successTitle} />
126
- <Text className="text-[14px] font-[700] text-[#6d6d6f]" html={copy.successDesc} />
134
+ <Text className="text-[20px] font-[700]" html={redeemModal.successTitle} />
135
+ <Text className="text-[14px] font-[700] text-[#6d6d6f]" html={redeemModal.successDesc} />
127
136
  <Button
128
- className={cn('w-full py-[12px] text-[14px] font-[700] text-white bg-[#080a0f]', rounded ? 'rounded-[4px]' : 'rounded-none')}
137
+ className={cn(
138
+ 'w-full py-[12px] text-[14px] font-[700] text-white bg-[#080a0f]',
139
+ rounded ? 'rounded-[4px]' : 'rounded-none'
140
+ )}
129
141
  onClick={() => {
130
- if (copy.successButtonUrl) window.location.href = copy.successButtonUrl
142
+ if (redeemModal.successButtonUrl) window.location.href = redeemModal.successButtonUrl
131
143
  onClose()
132
144
  }}
133
145
  >
134
- {copy.successButton}
146
+ {redeemModal.successButton}
135
147
  </Button>
136
148
  </div>
137
149
  )}
138
150
 
139
- {errorInfo && <Text className="text-center text-[14px] font-[700] text-[#ff0000]" html={errorInfo} />}
151
+ {!couponCode && (
152
+ <div className="sticky bottom-0 bg-white border-t border-[#e5e5e5] pt-[10px]">
153
+ <div className="flex flex-col gap-[8px] text-center">
154
+ <Text className="block text-[16px] font-[700] leading-[1.3]" html={redeemModal.confirmTitle} />
155
+ <Button
156
+ className={cn(
157
+ 'w-full py-[12px] text-[14px] font-[700] text-white disabled:opacity-60 bg-[#080a0f]',
158
+ rounded ? 'rounded-[4px]' : 'rounded-none'
159
+ )}
160
+ disabled={disabled}
161
+ loading={loading}
162
+ onClick={handleConfirm}
163
+ >
164
+ {redeemModal.confirmButton}
165
+ </Button>
166
+ </div>
167
+
168
+ {errorInfo && (
169
+ <Text className="mt-[8px] text-center text-[14px] font-[700] text-[#ff0000]" html={errorInfo} />
170
+ )}
171
+ </div>
172
+ )}
140
173
  </div>
141
174
  )
142
175
  }