@linktr.ee/messaging-react 2.0.0 → 2.0.1-rc-1778656305
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/Card-CAC3fPjy.js +107 -0
- package/dist/Card-CAC3fPjy.js.map +1 -0
- package/dist/Card-DLUBUg_w.js +132 -0
- package/dist/Card-DLUBUg_w.js.map +1 -0
- package/dist/Card-_StSlnYh.js +163 -0
- package/dist/Card-_StSlnYh.js.map +1 -0
- package/dist/LockedThumbnail-p5RsFOug.js +220 -0
- package/dist/LockedThumbnail-p5RsFOug.js.map +1 -0
- package/dist/assets/index.css +1 -1
- package/dist/{index-Brz9orsI.js → index-B1h46F9x.js} +811 -772
- package/dist/index-B1h46F9x.js.map +1 -0
- package/dist/index.d.ts +87 -28
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/src/components/ChannelView.test.tsx +11 -0
- package/src/components/ChannelView.tsx +35 -32
- package/src/components/CustomMessage/index.tsx +2 -3
- package/src/components/CustomTypingIndicator/CustomTypingIndicator.stories.tsx +57 -17
- package/src/components/CustomTypingIndicator/CustomTypingIndicator.test.tsx +187 -0
- package/src/components/CustomTypingIndicator/DmAgentContext.ts +3 -0
- package/src/components/CustomTypingIndicator/index.tsx +101 -37
- package/src/components/LockedAttachment/LockedAttachment.stories.tsx +230 -89
- package/src/components/LockedAttachment/components/Composer/Card.tsx +221 -0
- package/src/components/LockedAttachment/components/Composer/index.ts +2 -0
- package/src/components/LockedAttachment/components/Received/Card.tsx +191 -0
- package/src/components/LockedAttachment/components/Received/CardActions.tsx +91 -0
- package/src/components/LockedAttachment/components/Received/index.ts +2 -0
- package/src/components/LockedAttachment/components/Sent/Card.tsx +177 -0
- package/src/components/LockedAttachment/components/Sent/index.ts +2 -0
- package/src/components/LockedAttachment/components/_shared/CardBody.tsx +94 -0
- package/src/components/LockedAttachment/components/_shared/GalleryThumbnail.tsx +178 -0
- package/src/components/LockedAttachment/components/_shared/LockBadge.tsx +39 -0
- package/src/components/LockedAttachment/components/_shared/LockedCardShell.tsx +36 -0
- package/src/components/LockedAttachment/components/_shared/LockedThumbnail.tsx +128 -0
- package/src/components/LockedAttachment/index.tsx +43 -12
- package/src/components/LockedAttachment/types.ts +17 -0
- package/src/components/MediaMessage/index.tsx +2 -2
- package/src/index.ts +6 -1
- package/src/styles.css +7 -0
- package/dist/Card-BHknCeHw.js +0 -138
- package/dist/Card-BHknCeHw.js.map +0 -1
- package/dist/Card-DT7_ms2p.js +0 -127
- package/dist/Card-DT7_ms2p.js.map +0 -1
- package/dist/index-Brz9orsI.js.map +0 -1
- package/src/components/LockedAttachment/components/Creator/Card.tsx +0 -210
- package/src/components/LockedAttachment/components/Creator/index.tsx +0 -2
- package/src/components/LockedAttachment/components/Visitor/Card.tsx +0 -155
- package/src/components/LockedAttachment/components/Visitor/CardActions.tsx +0 -62
- package/src/components/LockedAttachment/components/Visitor/LockBadge.tsx +0 -12
- package/src/components/LockedAttachment/components/Visitor/index.ts +0 -2
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CheckCircleIcon,
|
|
3
|
-
EyeIcon,
|
|
4
|
-
EyeSlashIcon,
|
|
5
|
-
LockIcon,
|
|
6
|
-
LockOpenIcon,
|
|
7
|
-
XIcon,
|
|
8
|
-
} from '@phosphor-icons/react'
|
|
9
|
-
import classNames from 'classnames'
|
|
10
|
-
import React, { useCallback, useRef, useState } from 'react'
|
|
11
|
-
|
|
12
|
-
import AttachmentCard, { AttachmentThumbnail } from '../../../AttachmentCard'
|
|
13
|
-
import type {
|
|
14
|
-
LockedAttachmentBaseProps,
|
|
15
|
-
LockedAttachmentSource,
|
|
16
|
-
PaymentStatus,
|
|
17
|
-
} from '../../types'
|
|
18
|
-
|
|
19
|
-
export interface CreatorCardProps extends LockedAttachmentBaseProps {
|
|
20
|
-
placeholderTitle?: string
|
|
21
|
-
placeholderAmountText?: string
|
|
22
|
-
isUnlocking?: boolean
|
|
23
|
-
onDismiss?: () => void
|
|
24
|
-
onPreviewClick?: () => void
|
|
25
|
-
onFetchSource?: () => Promise<LockedAttachmentSource | void>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function headerSlots(props: {
|
|
29
|
-
onDismiss?: () => void
|
|
30
|
-
onToggle?: () => void
|
|
31
|
-
isExpanded?: boolean
|
|
32
|
-
paymentStatus?: PaymentStatus
|
|
33
|
-
isLoading?: boolean
|
|
34
|
-
}): { topLeft?: React.ReactNode; topRight?: React.ReactNode } {
|
|
35
|
-
const { onDismiss, onToggle, isExpanded, paymentStatus, isLoading } = props
|
|
36
|
-
|
|
37
|
-
if (onDismiss) {
|
|
38
|
-
return {
|
|
39
|
-
topLeft: undefined,
|
|
40
|
-
topRight: (
|
|
41
|
-
<button
|
|
42
|
-
type="button"
|
|
43
|
-
onClick={onDismiss}
|
|
44
|
-
className="flex size-8 items-center justify-center rounded-full bg-black/60 text-white"
|
|
45
|
-
aria-label="Dismiss attachment"
|
|
46
|
-
>
|
|
47
|
-
<XIcon className="size-4" weight="bold" />
|
|
48
|
-
</button>
|
|
49
|
-
),
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (onToggle) {
|
|
54
|
-
const Icon = isExpanded ? EyeIcon : EyeSlashIcon
|
|
55
|
-
return {
|
|
56
|
-
topLeft: (
|
|
57
|
-
<button
|
|
58
|
-
type="button"
|
|
59
|
-
onClick={onToggle}
|
|
60
|
-
className="flex size-8 items-center justify-center rounded-full bg-black/60 text-white"
|
|
61
|
-
aria-label={isExpanded ? 'Hide preview' : 'Show preview'}
|
|
62
|
-
aria-pressed={isExpanded}
|
|
63
|
-
>
|
|
64
|
-
<Icon className="size-4" weight="fill" />
|
|
65
|
-
</button>
|
|
66
|
-
),
|
|
67
|
-
topRight: undefined,
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const Icon = paymentStatus === 'paid' ? LockOpenIcon : LockIcon
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
topLeft: (
|
|
75
|
-
<div className="flex size-8 items-center justify-center rounded-full bg-black/60 text-white">
|
|
76
|
-
{isLoading ? (
|
|
77
|
-
<span className="size-4 animate-spin rounded-full border-2 border-white/30 border-t-white" />
|
|
78
|
-
) : (
|
|
79
|
-
<Icon className="size-4" weight="fill" />
|
|
80
|
-
)}
|
|
81
|
-
</div>
|
|
82
|
-
),
|
|
83
|
-
topRight: undefined,
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const CreatorCard: React.FC<CreatorCardProps> = ({
|
|
88
|
-
title,
|
|
89
|
-
mimeType = 'application/octet-stream',
|
|
90
|
-
thumbnailUrl,
|
|
91
|
-
detail,
|
|
92
|
-
amountText,
|
|
93
|
-
placeholderTitle = 'Attachment title',
|
|
94
|
-
placeholderAmountText,
|
|
95
|
-
paymentStatus,
|
|
96
|
-
isUnlocking,
|
|
97
|
-
onDismiss,
|
|
98
|
-
onPreviewClick,
|
|
99
|
-
onFetchSource,
|
|
100
|
-
}) => {
|
|
101
|
-
const [source, setSource] = useState<LockedAttachmentSource | undefined>()
|
|
102
|
-
const [isPreviewVisible, setIsPreviewVisible] = useState(false)
|
|
103
|
-
const [isLoadingPreview, setLoadingPreview] = useState(false)
|
|
104
|
-
const fetchingRef = useRef(false)
|
|
105
|
-
|
|
106
|
-
const effectiveSourceUrl = isPreviewVisible ? source?.sourceUrl : undefined
|
|
107
|
-
const effectiveThumbnailUrl = isPreviewVisible ? (source?.thumbnailUrl ?? thumbnailUrl) : thumbnailUrl
|
|
108
|
-
const isBusy = isLoadingPreview || isUnlocking
|
|
109
|
-
|
|
110
|
-
const handleToggle = useCallback(async () => {
|
|
111
|
-
onPreviewClick?.()
|
|
112
|
-
if (isPreviewVisible) {
|
|
113
|
-
setIsPreviewVisible(false)
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
if (source) {
|
|
117
|
-
setIsPreviewVisible(true)
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
if (!onFetchSource) return
|
|
121
|
-
if (fetchingRef.current) return
|
|
122
|
-
fetchingRef.current = true
|
|
123
|
-
setLoadingPreview(true)
|
|
124
|
-
try {
|
|
125
|
-
const result = await onFetchSource()
|
|
126
|
-
if (result) {
|
|
127
|
-
setSource(result)
|
|
128
|
-
setIsPreviewVisible(true)
|
|
129
|
-
}
|
|
130
|
-
} finally {
|
|
131
|
-
fetchingRef.current = false
|
|
132
|
-
setLoadingPreview(false)
|
|
133
|
-
}
|
|
134
|
-
}, [isPreviewVisible, source, onPreviewClick, onFetchSource])
|
|
135
|
-
|
|
136
|
-
const toggleHandler = onFetchSource || onPreviewClick ? handleToggle : undefined
|
|
137
|
-
|
|
138
|
-
const statusBadge =
|
|
139
|
-
paymentStatus === 'paid' ? (
|
|
140
|
-
<React.Fragment>
|
|
141
|
-
<span className="text-xs font-medium text-white/55">•</span>
|
|
142
|
-
<span className="text-xs font-medium text-[#34c759]">Sold</span>
|
|
143
|
-
<CheckCircleIcon className="size-4 text-[#34c759]" weight="bold" />
|
|
144
|
-
</React.Fragment>
|
|
145
|
-
) : (
|
|
146
|
-
<React.Fragment>
|
|
147
|
-
<span className="text-xs font-medium text-white/55">•</span>
|
|
148
|
-
<span
|
|
149
|
-
className={classNames('text-xs font-medium', {
|
|
150
|
-
'text-white/30': !amountText,
|
|
151
|
-
'text-white/55': !!amountText,
|
|
152
|
-
})}
|
|
153
|
-
>
|
|
154
|
-
{amountText || placeholderAmountText}
|
|
155
|
-
</span>
|
|
156
|
-
</React.Fragment>
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
const { topLeft, topRight } = headerSlots({
|
|
160
|
-
onDismiss,
|
|
161
|
-
onToggle: isBusy ? undefined : toggleHandler,
|
|
162
|
-
isExpanded: isPreviewVisible,
|
|
163
|
-
paymentStatus,
|
|
164
|
-
isLoading: isBusy,
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
return (
|
|
168
|
-
<AttachmentCard
|
|
169
|
-
variant="dark"
|
|
170
|
-
title={title}
|
|
171
|
-
placeholderTitle={placeholderTitle}
|
|
172
|
-
mimeType={mimeType}
|
|
173
|
-
detail={detail}
|
|
174
|
-
statusBadge={statusBadge}
|
|
175
|
-
topLeft={topLeft}
|
|
176
|
-
topRight={topRight}
|
|
177
|
-
thumbnail={
|
|
178
|
-
<button
|
|
179
|
-
type="button"
|
|
180
|
-
disabled={!toggleHandler || isBusy}
|
|
181
|
-
className={classNames(
|
|
182
|
-
'relative block w-full overflow-hidden border-0 bg-white/10 p-0 text-left appearance-none',
|
|
183
|
-
{ 'cursor-pointer': !!toggleHandler && !isBusy, 'cursor-default': !toggleHandler || isBusy }
|
|
184
|
-
)}
|
|
185
|
-
onClick={isBusy ? undefined : toggleHandler}
|
|
186
|
-
aria-label={toggleHandler ? 'Toggle preview' : undefined}
|
|
187
|
-
aria-busy={isBusy}
|
|
188
|
-
>
|
|
189
|
-
<AttachmentThumbnail
|
|
190
|
-
mimeType={mimeType}
|
|
191
|
-
sourceUrl={effectiveSourceUrl}
|
|
192
|
-
thumbnailUrl={effectiveThumbnailUrl}
|
|
193
|
-
title={title}
|
|
194
|
-
variant="dark"
|
|
195
|
-
mediaPlayerProps={
|
|
196
|
-
effectiveSourceUrl
|
|
197
|
-
? { autoPlay: true, loop: true, controls: true, muted: false }
|
|
198
|
-
: undefined
|
|
199
|
-
}
|
|
200
|
-
/>
|
|
201
|
-
{!isPreviewVisible && (
|
|
202
|
-
<div className="pointer-events-none absolute inset-0 bg-black/30" />
|
|
203
|
-
)}
|
|
204
|
-
</button>
|
|
205
|
-
}
|
|
206
|
-
/>
|
|
207
|
-
)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export default CreatorCard
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { CheckCircleIcon } from '@phosphor-icons/react'
|
|
2
|
-
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
3
|
-
|
|
4
|
-
import AttachmentCard, { AttachmentThumbnail } from '../../../AttachmentCard'
|
|
5
|
-
import type {
|
|
6
|
-
LockedAttachmentBaseProps,
|
|
7
|
-
LockedAttachmentSource,
|
|
8
|
-
} from '../../types'
|
|
9
|
-
|
|
10
|
-
import CardActions from './CardActions'
|
|
11
|
-
import { LockBadge } from './LockBadge'
|
|
12
|
-
|
|
13
|
-
export interface VisitorCardProps extends LockedAttachmentBaseProps {
|
|
14
|
-
/**
|
|
15
|
-
* Called when the visitor clicks Unlock on an unpaid attachment.
|
|
16
|
-
* Use this to open a checkout flow. Omit to hide the Unlock button.
|
|
17
|
-
*/
|
|
18
|
-
onUnlockClick?: () => void
|
|
19
|
-
/**
|
|
20
|
-
* Called to fetch the attachment source — fired automatically when
|
|
21
|
-
* paymentStatus transitions to 'paid', or immediately on click when
|
|
22
|
-
* paymentStatus is already 'paid'. Return a LockedAttachmentSource to
|
|
23
|
-
* unlock the card.
|
|
24
|
-
*/
|
|
25
|
-
onFetchSource?: () => Promise<LockedAttachmentSource | void>
|
|
26
|
-
/**
|
|
27
|
-
* Called when the visitor clicks Download on an unlocked card.
|
|
28
|
-
* Omit to hide the Download button.
|
|
29
|
-
*/
|
|
30
|
-
onDownloadClick?: () => void
|
|
31
|
-
/**
|
|
32
|
-
* When true, shows loading dots on the Unlock button.
|
|
33
|
-
* Driven by the LockedAttachmentContext (e.g. checkout in progress, payment processing).
|
|
34
|
-
*/
|
|
35
|
-
isUnlocking?: boolean
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const VisitorCard: React.FC<VisitorCardProps> = ({
|
|
39
|
-
title,
|
|
40
|
-
amountText,
|
|
41
|
-
thumbnailUrl,
|
|
42
|
-
mimeType = 'application/octet-stream',
|
|
43
|
-
detail,
|
|
44
|
-
onUnlockClick,
|
|
45
|
-
onFetchSource,
|
|
46
|
-
onDownloadClick,
|
|
47
|
-
paymentStatus,
|
|
48
|
-
isUnlocking = false,
|
|
49
|
-
}) => {
|
|
50
|
-
const [source, setSource] = useState<LockedAttachmentSource | undefined>()
|
|
51
|
-
|
|
52
|
-
const cardRef = useRef<HTMLDivElement>(null)
|
|
53
|
-
const fetchingRef = useRef(false)
|
|
54
|
-
|
|
55
|
-
const onFetchSourceRef = useRef(onFetchSource)
|
|
56
|
-
onFetchSourceRef.current = onFetchSource
|
|
57
|
-
|
|
58
|
-
const effectiveSourceUrl = source?.sourceUrl
|
|
59
|
-
const effectiveThumbnail = source?.thumbnailUrl ?? thumbnailUrl
|
|
60
|
-
const effectiveRedeemUrl = source?.redeemUrl
|
|
61
|
-
|
|
62
|
-
const fetchSource = useCallback(async (): Promise<void> => {
|
|
63
|
-
if (fetchingRef.current) return
|
|
64
|
-
fetchingRef.current = true
|
|
65
|
-
try {
|
|
66
|
-
const result = await onFetchSourceRef.current?.()
|
|
67
|
-
if (result) setSource(result)
|
|
68
|
-
} finally {
|
|
69
|
-
fetchingRef.current = false
|
|
70
|
-
}
|
|
71
|
-
}, [])
|
|
72
|
-
|
|
73
|
-
const handleUnlockClick = useCallback(() => {
|
|
74
|
-
if (paymentStatus === 'paid') {
|
|
75
|
-
void fetchSource()
|
|
76
|
-
} else {
|
|
77
|
-
onUnlockClick?.()
|
|
78
|
-
}
|
|
79
|
-
}, [paymentStatus, fetchSource, onUnlockClick])
|
|
80
|
-
|
|
81
|
-
// Fetch source when card is in viewport
|
|
82
|
-
useEffect(() => {
|
|
83
|
-
if (!cardRef.current) return
|
|
84
|
-
if (paymentStatus !== 'paid' || source !== undefined) return
|
|
85
|
-
|
|
86
|
-
const observer = new IntersectionObserver(
|
|
87
|
-
([entry]) => {
|
|
88
|
-
if (entry.isIntersecting) {
|
|
89
|
-
void fetchSource()
|
|
90
|
-
observer.disconnect()
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
{ threshold: 1.0 }
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
observer.observe(cardRef.current)
|
|
97
|
-
return () => observer.disconnect()
|
|
98
|
-
}, [paymentStatus, source, fetchSource])
|
|
99
|
-
|
|
100
|
-
const isLocked = effectiveSourceUrl === undefined
|
|
101
|
-
|
|
102
|
-
const statusBadge =
|
|
103
|
-
paymentStatus === 'paid' ? (
|
|
104
|
-
<React.Fragment>
|
|
105
|
-
<span className="text-xs font-medium text-black/55">•</span>
|
|
106
|
-
<span className="text-xs font-medium text-[#008236]">Purchased</span>
|
|
107
|
-
<CheckCircleIcon className="size-4 text-[#008236]" weight="bold" />
|
|
108
|
-
</React.Fragment>
|
|
109
|
-
) : amountText != null ? (
|
|
110
|
-
<React.Fragment>
|
|
111
|
-
<span className="text-xs font-medium text-black/55">•</span>
|
|
112
|
-
<span className="text-xs font-medium text-black/55">{amountText}</span>
|
|
113
|
-
</React.Fragment>
|
|
114
|
-
) : null
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<AttachmentCard
|
|
118
|
-
variant="light"
|
|
119
|
-
rootRef={cardRef}
|
|
120
|
-
data-testid="locked-attachment"
|
|
121
|
-
title={title}
|
|
122
|
-
mimeType={mimeType}
|
|
123
|
-
detail={detail}
|
|
124
|
-
statusBadge={statusBadge}
|
|
125
|
-
thumbnail={
|
|
126
|
-
<div className="relative">
|
|
127
|
-
<AttachmentThumbnail
|
|
128
|
-
mimeType={mimeType}
|
|
129
|
-
sourceUrl={effectiveSourceUrl}
|
|
130
|
-
thumbnailUrl={effectiveThumbnail}
|
|
131
|
-
title={title}
|
|
132
|
-
variant="light"
|
|
133
|
-
containedImage={!isLocked}
|
|
134
|
-
/>
|
|
135
|
-
{isLocked && (
|
|
136
|
-
<div className="pointer-events-none absolute inset-0 bg-black/30">
|
|
137
|
-
<LockBadge paymentStatus={paymentStatus} />
|
|
138
|
-
</div>
|
|
139
|
-
)}
|
|
140
|
-
</div>
|
|
141
|
-
}
|
|
142
|
-
action={
|
|
143
|
-
<CardActions
|
|
144
|
-
isUnlocking={isUnlocking}
|
|
145
|
-
sourceUrl={effectiveSourceUrl}
|
|
146
|
-
redeemUrl={effectiveRedeemUrl}
|
|
147
|
-
onUnlockClicked={handleUnlockClick}
|
|
148
|
-
onDownloadClicked={onDownloadClick}
|
|
149
|
-
/>
|
|
150
|
-
}
|
|
151
|
-
/>
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export default VisitorCard
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { DownloadSimpleIcon, LockSimpleIcon } from '@phosphor-icons/react'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
interface CardActionsProps {
|
|
5
|
-
sourceUrl?: string
|
|
6
|
-
redeemUrl?: string
|
|
7
|
-
onUnlockClicked?: () => void
|
|
8
|
-
onDownloadClicked?: () => void
|
|
9
|
-
isUnlocking?: boolean
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const CardActions: React.FC<CardActionsProps> = (props) => {
|
|
13
|
-
const {
|
|
14
|
-
isUnlocking = false,
|
|
15
|
-
sourceUrl,
|
|
16
|
-
redeemUrl,
|
|
17
|
-
onUnlockClicked,
|
|
18
|
-
onDownloadClicked,
|
|
19
|
-
} = props
|
|
20
|
-
|
|
21
|
-
const isLocked = sourceUrl === undefined
|
|
22
|
-
|
|
23
|
-
if (isLocked && onUnlockClicked != null) {
|
|
24
|
-
return (
|
|
25
|
-
<button
|
|
26
|
-
type="button"
|
|
27
|
-
onClick={onUnlockClicked}
|
|
28
|
-
disabled={isUnlocking}
|
|
29
|
-
className="mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none text-white hover:bg-[#2a2928] disabled:opacity-70"
|
|
30
|
-
>
|
|
31
|
-
{isUnlocking ? (
|
|
32
|
-
<span className="size-4 animate-spin rounded-full border-2 border-white/30 border-t-white" />
|
|
33
|
-
) : (
|
|
34
|
-
<React.Fragment>
|
|
35
|
-
<LockSimpleIcon className="size-4" weight="fill" />
|
|
36
|
-
Unlock
|
|
37
|
-
</React.Fragment>
|
|
38
|
-
)}
|
|
39
|
-
</button>
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (!isLocked && onDownloadClicked != null && sourceUrl != null) {
|
|
44
|
-
return (
|
|
45
|
-
<a
|
|
46
|
-
href={redeemUrl ?? sourceUrl}
|
|
47
|
-
target="_blank"
|
|
48
|
-
rel="noopener noreferrer"
|
|
49
|
-
onClick={onDownloadClicked}
|
|
50
|
-
className="mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none !text-white hover:bg-[#2a2928]"
|
|
51
|
-
>
|
|
52
|
-
<DownloadSimpleIcon className="size-4" weight="bold" />
|
|
53
|
-
Download
|
|
54
|
-
</a>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return null
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
export default CardActions
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { LockOpenIcon, LockSimpleIcon } from '@phosphor-icons/react'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
import type { PaymentStatus } from '../../types'
|
|
5
|
-
|
|
6
|
-
export const LockBadge: React.FC<{ paymentStatus?: PaymentStatus }> = ({
|
|
7
|
-
paymentStatus,
|
|
8
|
-
}) => (
|
|
9
|
-
<div className="absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white">
|
|
10
|
-
{paymentStatus === 'paid' ? <LockOpenIcon /> : <LockSimpleIcon />}
|
|
11
|
-
</div>
|
|
12
|
-
)
|