@anker-in/campaign-ui 0.5.3 → 0.5.4-beta.1
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.
- package/dist/cjs/components/credits/creditsFaq/index.js +1 -1
- package/dist/cjs/components/credits/creditsFaq/index.js.map +3 -3
- package/dist/cjs/components/credits/creditsMemberPrice/CreditsMemberPrice.js +1 -1
- package/dist/cjs/components/credits/creditsMemberPrice/CreditsMemberPrice.js.map +2 -2
- package/dist/cjs/components/credits/creditsRedeemList/CreditsRedeemList.js +1 -1
- package/dist/cjs/components/credits/creditsRedeemList/CreditsRedeemList.js.map +3 -3
- package/dist/cjs/components/credits/modal/ActivitiesModal.js +1 -1
- package/dist/cjs/components/credits/modal/ActivitiesModal.js.map +3 -3
- package/dist/cjs/components/credits/modal/RewardsModal.js +1 -1
- package/dist/cjs/components/credits/modal/RewardsModal.js.map +3 -3
- package/dist/esm/components/credits/creditsFaq/index.js +1 -1
- package/dist/esm/components/credits/creditsFaq/index.js.map +3 -3
- package/dist/esm/components/credits/creditsMemberPrice/CreditsMemberPrice.js +1 -1
- package/dist/esm/components/credits/creditsMemberPrice/CreditsMemberPrice.js.map +3 -3
- package/dist/esm/components/credits/creditsRedeemList/CreditsRedeemList.js +1 -1
- package/dist/esm/components/credits/creditsRedeemList/CreditsRedeemList.js.map +3 -3
- package/dist/esm/components/credits/modal/ActivitiesModal.js +1 -1
- package/dist/esm/components/credits/modal/ActivitiesModal.js.map +3 -3
- package/dist/esm/components/credits/modal/RewardsModal.js +1 -1
- package/dist/esm/components/credits/modal/RewardsModal.js.map +3 -3
- package/package.json +1 -1
- package/src/components/credits/creditsFaq/index.tsx +47 -42
- package/src/components/credits/creditsMemberPrice/CreditsMemberPrice.tsx +35 -42
- package/src/components/credits/creditsRedeemList/CreditsRedeemList.tsx +66 -58
- package/src/components/credits/modal/ActivitiesModal.tsx +62 -56
- package/src/components/credits/modal/RewardsModal.tsx +43 -30
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Container, Heading, Tabs, TabsList, TabsTrigger } from '@anker-in/headless-ui'
|
|
1
|
+
import { Container, Heading, Tabs, TabsContent, TabsList, TabsTrigger } from '@anker-in/headless-ui'
|
|
2
2
|
import classNames from 'classnames'
|
|
3
3
|
import { useCallback, useMemo, useState } from 'react'
|
|
4
4
|
|
|
@@ -32,8 +32,6 @@ export const CreditsRedeemList = ({ copy, id }: { copy: CreditsRedeemListCopy; i
|
|
|
32
32
|
|
|
33
33
|
const isLogin = Object.keys(profile || {}).length > 0
|
|
34
34
|
|
|
35
|
-
const [activeTab, setActiveTab] = useState<string>(copy.list?.[0]?.label || '')
|
|
36
|
-
|
|
37
35
|
const [popRedeemData, setPopRedeemData] = useState<RedeemableItemType | undefined>(undefined)
|
|
38
36
|
|
|
39
37
|
const [rules, setRules] = useState<string | string[]>()
|
|
@@ -69,38 +67,43 @@ export const CreditsRedeemList = ({ copy, id }: { copy: CreditsRedeemListCopy; i
|
|
|
69
67
|
image: item.goods_url,
|
|
70
68
|
}
|
|
71
69
|
})
|
|
72
|
-
}, [
|
|
70
|
+
}, [redeemableList])
|
|
73
71
|
|
|
74
72
|
const handles = alpcList.map(item => item.handle)
|
|
75
73
|
const { data: products } = useProductsByHandles({ handles })
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
75
|
+
// 按 tab label 分组预计算列表,配合 TabsContent 声明式渲染,避免手动 activeTab 字符串比较
|
|
76
|
+
const listByTab = useMemo(() => {
|
|
77
|
+
const map = new Map<string, RedeemableItemType[]>()
|
|
78
|
+
;(copy.list || []).forEach(categoryItem => {
|
|
79
|
+
const items = (categoryItem.list || [])
|
|
80
|
+
.filter(item => alpcList.some(alpcItem => String(alpcItem.id) === String(item.id)))
|
|
81
|
+
.map(item => {
|
|
82
|
+
const alpcItem = alpcList.find(alpcItem => String(alpcItem.id) === String(item.id))
|
|
83
|
+
const product = products?.find(product => product.handle === alpcItem?.handle)
|
|
84
|
+
const variant = product?.variants.find(variant => variant.sku === alpcItem?.sku)
|
|
85
|
+
// 过滤掉库存不足的商品
|
|
86
|
+
if (alpcItem?.isLimited && (!alpcItem?.remainingInventory || alpcItem.remainingInventory <= 0)) return null
|
|
87
|
+
if (alpcItem?.consumeType === AlpcConsumeType.Product && (!product || !variant)) return null
|
|
88
|
+
|
|
89
|
+
// 检查 GoGift 是否已经兑换过(只有 GoGift 限制兑换一次)
|
|
90
|
+
const hasRedeemed = item.type === ConsumeType.GoGift &&
|
|
91
|
+
isLogin &&
|
|
92
|
+
myRewards.some(reward => reward.rule_id === Number(item.id))
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
alpc: alpcItem,
|
|
96
|
+
config: item,
|
|
97
|
+
product,
|
|
98
|
+
variant,
|
|
99
|
+
hasRedeemed,
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
.filter(item => item !== null) as unknown as RedeemableItemType[]
|
|
103
|
+
map.set(categoryItem.label, items)
|
|
104
|
+
})
|
|
105
|
+
return map
|
|
106
|
+
}, [copy.list, alpcList, products, isLogin, myRewards])
|
|
104
107
|
|
|
105
108
|
const handleRedeemError = useCallback(
|
|
106
109
|
(errorCode: AlpcErrorCode) => {
|
|
@@ -142,9 +145,8 @@ export const CreditsRedeemList = ({ copy, id }: { copy: CreditsRedeemListCopy; i
|
|
|
142
145
|
shape={rounded ? 'rounded' : 'square'}
|
|
143
146
|
align="left"
|
|
144
147
|
className={classNames('py-[24px] md:justify-center')}
|
|
145
|
-
|
|
148
|
+
defaultValue={copy.list?.[0]?.label || ''}
|
|
146
149
|
onValueChange={value => {
|
|
147
|
-
setActiveTab(value)
|
|
148
150
|
gaTrack({
|
|
149
151
|
event: 'ga4Event',
|
|
150
152
|
event_name: 'lp_navigation',
|
|
@@ -162,32 +164,38 @@ export const CreditsRedeemList = ({ copy, id }: { copy: CreditsRedeemListCopy; i
|
|
|
162
164
|
</TabsTrigger>
|
|
163
165
|
))}
|
|
164
166
|
</TabsList>
|
|
167
|
+
{(copy.list || []).map(categoryItem => (
|
|
168
|
+
<TabsContent key={categoryItem.label} value={categoryItem.label}>
|
|
169
|
+
{/* PC端 */}
|
|
170
|
+
{!!alpcList?.length && !listLoading && (
|
|
171
|
+
<div
|
|
172
|
+
className={classNames(
|
|
173
|
+
'relative grid grid-cols-4 gap-[16px] md:grid-cols-2 md:gap-[12px] md-xl:grid-cols-3'
|
|
174
|
+
)}
|
|
175
|
+
>
|
|
176
|
+
{(listByTab.get(categoryItem.label) || [])?.map(item => (
|
|
177
|
+
<RedeemableItem
|
|
178
|
+
key={item?.alpc?.id}
|
|
179
|
+
copy={copy}
|
|
180
|
+
item={item}
|
|
181
|
+
onRedeem={(item: RedeemableItemType) => {
|
|
182
|
+
if (!isLogin) {
|
|
183
|
+
openSignUpPopup()
|
|
184
|
+
} else if (!profile?.activated && !authCodeActivate.isActivateSuccess) {
|
|
185
|
+
authCodeActivate.setAutoSendEmail(true)
|
|
186
|
+
authCodeActivate.open()
|
|
187
|
+
} else {
|
|
188
|
+
setPopRedeemData(item)
|
|
189
|
+
}
|
|
190
|
+
}}
|
|
191
|
+
onRulesOpen={setRules}
|
|
192
|
+
/>
|
|
193
|
+
))}
|
|
194
|
+
</div>
|
|
195
|
+
)}
|
|
196
|
+
</TabsContent>
|
|
197
|
+
))}
|
|
165
198
|
</Tabs>
|
|
166
|
-
{/* PC端 */}
|
|
167
|
-
{!!alpcList?.length && !listLoading && (
|
|
168
|
-
<div
|
|
169
|
-
className={classNames('relative grid grid-cols-4 gap-[16px] md:grid-cols-2 md:gap-[12px] md-xl:grid-cols-3')}
|
|
170
|
-
>
|
|
171
|
-
{list?.map(item => (
|
|
172
|
-
<RedeemableItem
|
|
173
|
-
key={item?.alpc?.id}
|
|
174
|
-
copy={copy}
|
|
175
|
-
item={item}
|
|
176
|
-
onRedeem={(item: RedeemableItemType) => {
|
|
177
|
-
if (!isLogin) {
|
|
178
|
-
openSignUpPopup()
|
|
179
|
-
} else if (!profile?.activated && !authCodeActivate.isActivateSuccess) {
|
|
180
|
-
authCodeActivate.setAutoSendEmail(true)
|
|
181
|
-
authCodeActivate.open()
|
|
182
|
-
} else {
|
|
183
|
-
setPopRedeemData(item)
|
|
184
|
-
}
|
|
185
|
-
}}
|
|
186
|
-
onRulesOpen={setRules}
|
|
187
|
-
/>
|
|
188
|
-
))}
|
|
189
|
-
</div>
|
|
190
|
-
)}
|
|
191
199
|
|
|
192
200
|
{(popRedeemData?.config?.type === ConsumeType.Coupon ||
|
|
193
201
|
popRedeemData?.config?.type === ConsumeType.ShippingCoupon) &&
|
|
@@ -5,7 +5,7 @@ import useActivities from '../context/hooks/useActivities'
|
|
|
5
5
|
import type { Task } from '../context/response'
|
|
6
6
|
import { CreditsModalContainer, type ModalContainerProps } from './ModalContainer'
|
|
7
7
|
import { classNames as cn, useHeadlessContext } from '@anker-in/lib'
|
|
8
|
-
import { Tabs, TabsList, TabsTrigger } from '@anker-in/headless-ui'
|
|
8
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@anker-in/headless-ui'
|
|
9
9
|
import LoadingDots from './LoadingDots'
|
|
10
10
|
import { Picture, Text } from '@anker-in/headless-ui'
|
|
11
11
|
import { ROUNDED_BRANDS } from '../../../constants'
|
|
@@ -55,7 +55,6 @@ function ActivitiesModal({ data, ...props }: ActivitiesModalProps) {
|
|
|
55
55
|
}
|
|
56
56
|
}, [props.isOpen, page])
|
|
57
57
|
|
|
58
|
-
const [activeTab, setActiveTab] = useState(CreditType.All)
|
|
59
58
|
const tabs = useMemo(() => {
|
|
60
59
|
const tabs = [
|
|
61
60
|
{
|
|
@@ -82,7 +81,7 @@ function ActivitiesModal({ data, ...props }: ActivitiesModalProps) {
|
|
|
82
81
|
|
|
83
82
|
const { activities = [], canNext, isLoading } = useActivities(myActivitiesOptions)
|
|
84
83
|
|
|
85
|
-
const
|
|
84
|
+
const allList = useMemo(() => {
|
|
86
85
|
const taskNameMap = {
|
|
87
86
|
[TaskSubType.Activation]: data.activationTask,
|
|
88
87
|
[TaskSubType.UpdateName]: data.updateNameTask,
|
|
@@ -114,7 +113,7 @@ function ActivitiesModal({ data, ...props }: ActivitiesModalProps) {
|
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
|
|
117
|
-
|
|
116
|
+
return activities.map(item => ({
|
|
118
117
|
title: getTitle(item),
|
|
119
118
|
date: new Date(item.create_time * 1000),
|
|
120
119
|
value: item.credit,
|
|
@@ -123,27 +122,6 @@ function ActivitiesModal({ data, ...props }: ActivitiesModalProps) {
|
|
|
123
122
|
credit_type: item.credit_type,
|
|
124
123
|
status: item.status,
|
|
125
124
|
}))
|
|
126
|
-
|
|
127
|
-
let filtered = all || []
|
|
128
|
-
if (activeTab === CreditType.Earned) {
|
|
129
|
-
filtered = filtered?.filter(item => item.type === 1)
|
|
130
|
-
} else if (activeTab === CreditType.Deducted) {
|
|
131
|
-
filtered = filtered?.filter(item => item.type === 2 && item.status !== 3)
|
|
132
|
-
} else if (activeTab === CreditType.Expired) {
|
|
133
|
-
filtered = filtered?.filter(item => item.type === 2 && item.status === 3)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return filtered.map(item => {
|
|
137
|
-
let { value, ...otherItem } = item
|
|
138
|
-
if (item.type === CreditType.Deducted && value > 0) {
|
|
139
|
-
value = -value
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
value,
|
|
144
|
-
...otherItem,
|
|
145
|
-
}
|
|
146
|
-
})
|
|
147
125
|
}, [
|
|
148
126
|
data.activationTask,
|
|
149
127
|
data.updateNameTask,
|
|
@@ -157,10 +135,36 @@ function ActivitiesModal({ data, ...props }: ActivitiesModalProps) {
|
|
|
157
135
|
data.uploadReceiptTask,
|
|
158
136
|
data.shoppingTask,
|
|
159
137
|
activities,
|
|
160
|
-
activeTab,
|
|
161
138
|
taskIdToTypeMapping,
|
|
162
139
|
])
|
|
163
140
|
|
|
141
|
+
const normalizeValue = useCallback((item: (typeof allList)[number]) => {
|
|
142
|
+
let { value, ...otherItem } = item
|
|
143
|
+
if (item.type === CreditType.Deducted && value > 0) {
|
|
144
|
+
value = -value
|
|
145
|
+
}
|
|
146
|
+
return { value, ...otherItem }
|
|
147
|
+
}, [])
|
|
148
|
+
|
|
149
|
+
// 按 tab 类型预计算列表,配合 TabsContent 声明式渲染,避免手动 activeTab 数值比较
|
|
150
|
+
const listByTab = useMemo(() => {
|
|
151
|
+
const map = new Map<CreditType, ReturnType<typeof normalizeValue>[]>()
|
|
152
|
+
map.set(CreditType.All, allList.map(normalizeValue))
|
|
153
|
+
map.set(
|
|
154
|
+
CreditType.Earned,
|
|
155
|
+
allList.filter(item => item.type === 1).map(normalizeValue)
|
|
156
|
+
)
|
|
157
|
+
map.set(
|
|
158
|
+
CreditType.Deducted,
|
|
159
|
+
allList.filter(item => item.type === 2 && item.status !== 3).map(normalizeValue)
|
|
160
|
+
)
|
|
161
|
+
map.set(
|
|
162
|
+
CreditType.Expired,
|
|
163
|
+
allList.filter(item => item.type === 2 && item.status === 3).map(normalizeValue)
|
|
164
|
+
)
|
|
165
|
+
return map
|
|
166
|
+
}, [allList, normalizeValue])
|
|
167
|
+
|
|
164
168
|
const handleScrollEnd = useCallback(() => {
|
|
165
169
|
if (!canNext) {
|
|
166
170
|
return
|
|
@@ -168,36 +172,8 @@ function ActivitiesModal({ data, ...props }: ActivitiesModalProps) {
|
|
|
168
172
|
setPage(page + 1)
|
|
169
173
|
}, [page, canNext])
|
|
170
174
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
title={data.title}
|
|
174
|
-
className={cn('h-[800px] w-[640px]')}
|
|
175
|
-
useAnimation
|
|
176
|
-
animationClassName="md:translate-y-[100vh]"
|
|
177
|
-
scrollClassName="flex flex-col"
|
|
178
|
-
{...props}
|
|
179
|
-
onScrollEnd={handleScrollEnd}
|
|
180
|
-
>
|
|
181
|
-
<div className="w-full sticky top-0 bg-white z-10 pb-[24px] overflow-x-auto">
|
|
182
|
-
<Tabs
|
|
183
|
-
align="left"
|
|
184
|
-
shape={rounded ? 'rounded' : 'square'}
|
|
185
|
-
value={activeTab.toString()}
|
|
186
|
-
onValueChange={value => {
|
|
187
|
-
setActiveTab(Number(value))
|
|
188
|
-
}}
|
|
189
|
-
className=""
|
|
190
|
-
>
|
|
191
|
-
<TabsList>
|
|
192
|
-
{tabs.map(tab => (
|
|
193
|
-
<TabsTrigger key={tab.type} value={tab.type.toString()}>
|
|
194
|
-
{tab.title}
|
|
195
|
-
</TabsTrigger>
|
|
196
|
-
))}
|
|
197
|
-
</TabsList>
|
|
198
|
-
</Tabs>
|
|
199
|
-
</div>
|
|
200
|
-
|
|
175
|
+
const renderList = (list: ReturnType<typeof normalizeValue>[]) => (
|
|
176
|
+
<>
|
|
201
177
|
<div className="flex-1 overflow-auto overscroll-contain">
|
|
202
178
|
<div className="grid gap-[18px] md:gap-[12px]">
|
|
203
179
|
{isLoading && (
|
|
@@ -259,6 +235,36 @@ function ActivitiesModal({ data, ...props }: ActivitiesModalProps) {
|
|
|
259
235
|
</div>
|
|
260
236
|
{/* 积分到账时间提醒 */}
|
|
261
237
|
{list.length > 0 && <div className="mt-[12px] pb-[24px] text-[14px] font-semibold text-[#999]">{data.tips}</div>}
|
|
238
|
+
</>
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<CreditsModalContainer
|
|
243
|
+
title={data.title}
|
|
244
|
+
className={cn('h-[800px] w-[640px]')}
|
|
245
|
+
useAnimation
|
|
246
|
+
animationClassName="md:translate-y-[100vh]"
|
|
247
|
+
scrollClassName="flex flex-col"
|
|
248
|
+
{...props}
|
|
249
|
+
onScrollEnd={handleScrollEnd}
|
|
250
|
+
>
|
|
251
|
+
<Tabs align="left" shape={rounded ? 'rounded' : 'square'} defaultValue={tabs[0]?.type?.toString()} className="flex-1 flex flex-col">
|
|
252
|
+
<div className="w-full sticky top-0 bg-white z-10 pb-[24px] overflow-x-auto">
|
|
253
|
+
<TabsList>
|
|
254
|
+
{tabs.map(tab => (
|
|
255
|
+
<TabsTrigger key={tab.type} value={tab.type.toString()}>
|
|
256
|
+
{tab.title}
|
|
257
|
+
</TabsTrigger>
|
|
258
|
+
))}
|
|
259
|
+
</TabsList>
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
{tabs.map(tab => (
|
|
263
|
+
<TabsContent key={tab.type} value={tab.type.toString()} className="flex-1 flex flex-col">
|
|
264
|
+
{renderList(listByTab.get(tab.type) || [])}
|
|
265
|
+
</TabsContent>
|
|
266
|
+
))}
|
|
267
|
+
</Tabs>
|
|
262
268
|
</CreditsModalContainer>
|
|
263
269
|
)
|
|
264
270
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Tabs, TabsList, TabsTrigger, Picture } from '@anker-in/headless-ui'
|
|
1
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger, Picture } from '@anker-in/headless-ui'
|
|
2
2
|
import classNames from 'classnames'
|
|
3
3
|
import clipboard from 'copy-to-clipboard'
|
|
4
4
|
import dayjs from 'dayjs'
|
|
@@ -245,35 +245,10 @@ function RewardsModal({ data, ...props }: RewardsModalProps) {
|
|
|
245
245
|
}, [])
|
|
246
246
|
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
useAnimation
|
|
253
|
-
animationClassName="md:translate-y-[100vh]"
|
|
254
|
-
scrollClassName="md:mb-0 flex flex-col"
|
|
255
|
-
{...props}
|
|
256
|
-
onScrollEnd={handleScrollEnd}
|
|
257
|
-
>
|
|
258
|
-
<div className="shrink-0">
|
|
259
|
-
<Tabs
|
|
260
|
-
align="left"
|
|
261
|
-
shape={rounded ? 'rounded' : 'square'}
|
|
262
|
-
value={activeTab.toString()}
|
|
263
|
-
onValueChange={value => {
|
|
264
|
-
setActiveTab(Number(value))
|
|
265
|
-
}}
|
|
266
|
-
>
|
|
267
|
-
<TabsList>
|
|
268
|
-
{tabs.map(tab => (
|
|
269
|
-
<TabsTrigger key={tab.type} value={tab.type.toString()}>
|
|
270
|
-
{tab.title}
|
|
271
|
-
</TabsTrigger>
|
|
272
|
-
))}
|
|
273
|
-
</TabsList>
|
|
274
|
-
</Tabs>
|
|
275
|
-
</div>
|
|
276
|
-
|
|
248
|
+
// 每个 tab 对应一次独立的接口请求(consumeType 不同),当前只有激活 tab 的数据存在于客户端。
|
|
249
|
+
// TabsContent 只挂载当前激活的一个,各 tab 复用同一份 list/isLoading 状态是安全的。
|
|
250
|
+
const renderContent = () => (
|
|
251
|
+
<>
|
|
277
252
|
{isLoading && (
|
|
278
253
|
<div className="flex flex-1 flex-col items-center justify-center">
|
|
279
254
|
<LoadingDots />
|
|
@@ -365,6 +340,44 @@ function RewardsModal({ data, ...props }: RewardsModalProps) {
|
|
|
365
340
|
)}
|
|
366
341
|
</div>
|
|
367
342
|
)}
|
|
343
|
+
</>
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
return (
|
|
347
|
+
<CreditsModalContainer
|
|
348
|
+
title={data.title}
|
|
349
|
+
className={classNames('h-[800px] w-[640px]')}
|
|
350
|
+
useAnimation
|
|
351
|
+
animationClassName="md:translate-y-[100vh]"
|
|
352
|
+
scrollClassName="md:mb-0 flex flex-col"
|
|
353
|
+
{...props}
|
|
354
|
+
onScrollEnd={handleScrollEnd}
|
|
355
|
+
>
|
|
356
|
+
<Tabs
|
|
357
|
+
align="left"
|
|
358
|
+
shape={rounded ? 'rounded' : 'square'}
|
|
359
|
+
value={activeTab.toString()}
|
|
360
|
+
onValueChange={value => {
|
|
361
|
+
setActiveTab(Number(value))
|
|
362
|
+
}}
|
|
363
|
+
className="flex flex-1 flex-col"
|
|
364
|
+
>
|
|
365
|
+
<div className="shrink-0">
|
|
366
|
+
<TabsList>
|
|
367
|
+
{tabs.map(tab => (
|
|
368
|
+
<TabsTrigger key={tab.type} value={tab.type.toString()}>
|
|
369
|
+
{tab.title}
|
|
370
|
+
</TabsTrigger>
|
|
371
|
+
))}
|
|
372
|
+
</TabsList>
|
|
373
|
+
</div>
|
|
374
|
+
|
|
375
|
+
{tabs.map(tab => (
|
|
376
|
+
<TabsContent key={tab.type} value={tab.type.toString()} className="flex flex-1 flex-col">
|
|
377
|
+
{renderContent()}
|
|
378
|
+
</TabsContent>
|
|
379
|
+
))}
|
|
380
|
+
</Tabs>
|
|
368
381
|
</CreditsModalContainer>
|
|
369
382
|
)
|
|
370
383
|
}
|