@anker-in/campaign-ui 0.5.0-beta.5 → 0.5.0-beta.7

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 (24) hide show
  1. package/dist/cjs/components/memberPopup/MemberPopup.js +1 -1
  2. package/dist/cjs/components/memberPopup/MemberPopup.js.map +2 -2
  3. package/dist/cjs/components/memberPopup/panels/ActivitiesSubscribePanel.js +1 -1
  4. package/dist/cjs/components/memberPopup/panels/ActivitiesSubscribePanel.js.map +2 -2
  5. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.d.ts +2 -1
  6. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js +1 -1
  7. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js.map +3 -3
  8. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/index.js +1 -1
  9. package/dist/cjs/components/memberPopup/panels/ConsumeCredits/index.js.map +2 -2
  10. package/dist/esm/components/memberPopup/MemberPopup.js +1 -1
  11. package/dist/esm/components/memberPopup/MemberPopup.js.map +2 -2
  12. package/dist/esm/components/memberPopup/panels/ActivitiesSubscribePanel.js +1 -1
  13. package/dist/esm/components/memberPopup/panels/ActivitiesSubscribePanel.js.map +3 -3
  14. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.d.ts +2 -1
  15. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js +1 -1
  16. package/dist/esm/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.js.map +3 -3
  17. package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.js +1 -1
  18. package/dist/esm/components/memberPopup/panels/ConsumeCredits/index.js.map +2 -2
  19. package/package.json +1 -1
  20. package/src/components/memberPopup/MemberPopup.tsx +1 -0
  21. package/src/components/memberPopup/panels/ActivitiesSubscribePanel.tsx +25 -29
  22. package/src/components/memberPopup/panels/ConsumeCredits/RedeemCouponPanel.tsx +61 -28
  23. package/src/components/memberPopup/panels/ConsumeCredits/index.tsx +2 -1
  24. package/src/components/memberPopup/panels/ConsumeCredits/RedeemCouponModal.tsx +0 -150
@@ -14,6 +14,7 @@ type Props = {
14
14
  itemImage?: { url: string; alt?: string }
15
15
  itemValue?: string
16
16
  itemOff?: string
17
+ itemRules?: string[]
17
18
  redeemId: number
18
19
  userId?: string
19
20
  copy: RedeemCouponModalCopy
@@ -29,6 +30,7 @@ export default function RedeemCouponPanel({
29
30
  itemImage,
30
31
  itemValue,
31
32
  itemOff,
33
+ itemRules,
32
34
  redeemId,
33
35
  userId,
34
36
  copy,
@@ -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
+ {itemOff ? ` ${itemOff}` : ''}
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
@@ -125,7 +134,10 @@ export default function RedeemCouponPanel({
125
134
  <Text className="text-[20px] font-[700]" html={copy.successTitle} />
126
135
  <Text className="text-[14px] font-[700] text-[#6d6d6f]" html={copy.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
142
  if (copy.successButtonUrl) window.location.href = copy.successButtonUrl
131
143
  onClose()
@@ -136,7 +148,28 @@ export default function RedeemCouponPanel({
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={copy.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
+ {copy.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
  }
@@ -116,6 +116,7 @@ function ConsumeCredits({ copy, onClose }: Props) {
116
116
  : item.image,
117
117
  itemValue: item.value,
118
118
  itemOff: copy.off,
119
+ itemRules: item.rules,
119
120
  redeemId: Number(item.redeemId),
120
121
  userId: profile?.user_id,
121
122
  alpcConfig,
@@ -183,7 +184,7 @@ function ConsumeCredits({ copy, onClose }: Props) {
183
184
  imgClassName={hasProduct ? 'object-cover' : 'h-full w-auto object-contain'}
184
185
  />
185
186
  {!hasProduct && item.value && (
186
- <div className="absolute bottom-[20px] left-[4px] text-[14px] font-[800] leading-none text-white">
187
+ <div className="absolute bottom-[16px] left-[4px] text-[12px] font-[800] leading-none text-white">
187
188
  {item.value} {copy.off}
188
189
  </div>
189
190
  )}
@@ -1,150 +0,0 @@
1
- import { useCallback, useEffect, useState } from 'react'
2
- import { Button, Text } from '@anker-in/headless-ui'
3
- import { classNames as cn } from '@anker-in/lib'
4
- import { CreditsModalContainer } from '../../../credits/modal/ModalContainer'
5
- import { AlpcErrorCode } from '../../../credits/context/const'
6
- import { useRedeemCoupon } from './hooks/useRedeemCoupon'
7
- import useCopy from '../../../credits/context/hooks/useCopy'
8
- import type { RedeemCouponModalCopy, AlpcConfig } from '../../type'
9
-
10
- type Props = {
11
- isOpen: boolean
12
- onClose: () => void
13
- itemTitle: string
14
- itemCredits: number
15
- itemImage?: { url: string; alt?: string }
16
- redeemId: number
17
- userId?: string
18
- copy: RedeemCouponModalCopy
19
- pointUnit?: string
20
- alpcConfig: AlpcConfig
21
- onError?: (code: number) => void
22
- }
23
-
24
- export function RedeemCouponModal({
25
- isOpen,
26
- onClose,
27
- itemTitle,
28
- itemCredits,
29
- itemImage,
30
- redeemId,
31
- userId,
32
- copy,
33
- pointUnit = 'pts',
34
- alpcConfig,
35
- onError,
36
- }: Props) {
37
- const [couponCode, setCouponCode] = useState<string>()
38
- const [errorInfo, setErrorInfo] = useState('')
39
- const [disabled, setDisabled] = useState(false)
40
- const { copy: copyText, copied } = useCopy()
41
-
42
- const { isMutating: loading, trigger } = useRedeemCoupon(alpcConfig)
43
-
44
- const handleConfirm = useCallback(async () => {
45
- setErrorInfo('')
46
- const { data } = await trigger({ user_id: userId, rule_id: redeemId })
47
- if (!data) {
48
- setErrorInfo(copy.commonError)
49
- return
50
- }
51
- if (data.data?.success) {
52
- setCouponCode(data.data.coupon_code)
53
- } else {
54
- let msg = copy.commonError
55
- if (data.code === AlpcErrorCode.CodeLpcShopifyCouponRuleRedeemLimit) {
56
- msg = copy.redeemLimitError
57
- setDisabled(true)
58
- } else if (data.code === AlpcErrorCode.CodeLpcRuleInventoryNotEnough) {
59
- msg = copy.inventoryNotEnough
60
- setDisabled(true)
61
- } else if (data.code === AlpcErrorCode.CodeLpcNotEnoughCredits) {
62
- msg = copy.creditsNotEnough
63
- setDisabled(true)
64
- } else if (data.code === AlpcErrorCode.CodeCrossSiteError) {
65
- msg = copy.crossSiteError
66
- setDisabled(true)
67
- }
68
- setErrorInfo(msg)
69
- onError?.(data.code)
70
- }
71
- }, [trigger, userId, redeemId, copy, onError])
72
-
73
- useEffect(() => {
74
- if (!isOpen) {
75
- setCouponCode(undefined)
76
- setErrorInfo('')
77
- setDisabled(false)
78
- }
79
- }, [isOpen])
80
-
81
- return (
82
- <CreditsModalContainer
83
- isOpen={isOpen}
84
- onClose={onClose}
85
- className="w-[540px] md:h-auto"
86
- scrollClassName="mb-[40px] px-0 min-l:px-0 md:mb-[24px]"
87
- titleClassName="h-[56px] bg-[#f5f5f7]"
88
- >
89
- <div className="bg-[#f5f5f7] px-[48px] pb-[24px] md:px-[16px]">
90
- {itemImage?.url && (
91
- <div className="relative mx-auto h-[164px] w-[324px]">
92
- <img src={itemImage.url} alt={itemImage.alt ?? ''} className="h-full w-full object-cover" />
93
- </div>
94
- )}
95
- <p className={cn('mt-[30px] text-center text-[24px] font-bold md:mt-[18px] md:text-[20px]')}>
96
- {itemCredits} {pointUnit}
97
- </p>
98
- </div>
99
-
100
- <div className="bg-white px-[48px] pt-[24px] text-center md:px-[16px]">
101
- {!couponCode ? (
102
- <>
103
- <Text className="block text-[24px] font-bold md:text-[20px]" html={copy.confirmTitle} />
104
- <Button
105
- loading={loading}
106
- variant="primary"
107
- size="lg"
108
- className="mt-[16px] w-full"
109
- onClick={handleConfirm}
110
- disabled={disabled}
111
- >
112
- {copy.confirmButton}
113
- </Button>
114
- </>
115
- ) : (
116
- <>
117
- <div className="flex items-center justify-center gap-[10px]">
118
- <span className="text-[24px] font-bold">{couponCode}</span>
119
- <button
120
- className={cn('text-[16px] font-bold underline', copied && 'pointer-events-none')}
121
- onClick={() => copyText(couponCode)}
122
- >
123
- {copied ? 'Copied' : 'Copy'}
124
- </button>
125
- </div>
126
- <Text className="mb-[4px] mt-[16px] text-[24px] font-bold md:text-[20px]" html={copy.successTitle} />
127
- <Text className="text-[16px] font-bold text-[#6d6d6f] md:text-[14px]" html={copy.successDesc} />
128
- <Button
129
- variant="primary"
130
- size="lg"
131
- className="mt-[16px] w-full"
132
- onClick={() => {
133
- if (copy.successButtonUrl) window.location.href = copy.successButtonUrl
134
- onClose()
135
- }}
136
- >
137
- {copy.successButton}
138
- </Button>
139
- </>
140
- )}
141
- </div>
142
-
143
- {errorInfo && (
144
- <div className="bg-white px-[48px] py-[12px] text-center md:px-[16px]">
145
- <Text className="text-[14px] font-semibold text-[#ff0000]" html={errorInfo} />
146
- </div>
147
- )}
148
- </CreditsModalContainer>
149
- )
150
- }