@linktr.ee/messaging-react 1.30.0 → 1.30.1-rc-1776660256

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.
@@ -25,11 +25,12 @@ export interface VisitorCardProps extends LockedAttachmentBaseProps {
25
25
  */
26
26
  onUnlock?: () => Promise<LockedAttachmentSource>
27
27
  /** Called when the visitor clicks Download on an unlocked card. */
28
- onDownload?: () => void
28
+ onDownload?: () => void
29
29
  }
30
30
 
31
- const getLockIcon = (paymentStatus?: PaymentStatus): React.ElementType =>
32
- paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon
31
+ const getLockIcon = (paymentStatus?: PaymentStatus): React.ElementType => {
32
+ return paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon
33
+ }
33
34
 
34
35
 
35
36
  interface LockOverlayProps {
@@ -48,18 +49,18 @@ const LockOverlay: React.FC<LockOverlayProps> = (props) => {
48
49
  }
49
50
 
50
51
  interface LockedPreviewProps {
51
- thumbnail?: string
52
+ thumbnailUrl?: string
52
53
  mimeType: string
53
54
  LockIcon: React.ElementType
54
55
  }
55
56
 
56
57
  const LockedPreview: React.FC<LockedPreviewProps> = (props) => {
57
- const { thumbnail, mimeType, LockIcon } = props
58
+ const { thumbnailUrl, mimeType, LockIcon } = props
58
59
  return (
59
60
  <div className="relative aspect-video overflow-hidden bg-black/5">
60
- {thumbnail ? (
61
+ {thumbnailUrl ? (
61
62
  <img
62
- src={thumbnail}
63
+ src={thumbnailUrl}
63
64
  alt=""
64
65
  className="absolute inset-0 h-full w-full object-cover"
65
66
  />
@@ -78,8 +79,8 @@ const LockedPreview: React.FC<LockedPreviewProps> = (props) => {
78
79
 
79
80
 
80
81
  interface ImagePreviewProps {
81
- source?: string
82
- thumbnail?: string
82
+ sourceUrl?: string
83
+ thumbnailUrl?: string
83
84
  mimeType: string
84
85
  title?: string
85
86
  paymentStatus?: PaymentStatus
@@ -87,17 +88,17 @@ interface ImagePreviewProps {
87
88
  }
88
89
 
89
90
  const ImagePreview: React.FC<ImagePreviewProps> = (props) => {
90
- const { source, thumbnail, mimeType, title, paymentStatus, isLocked } = props
91
+ const { sourceUrl, thumbnailUrl, mimeType, title, paymentStatus, isLocked } = props
91
92
  const [sourceReady, setSourceReady] = useState(false)
92
93
 
93
94
  useEffect(() => {
94
95
  setSourceReady(false)
95
- }, [source])
96
+ }, [sourceUrl])
96
97
 
97
98
  if (isLocked) {
98
99
  return (
99
100
  <LockedPreview
100
- thumbnail={thumbnail}
101
+ thumbnailUrl={thumbnailUrl}
101
102
  mimeType={mimeType}
102
103
  LockIcon={getLockIcon(paymentStatus)}
103
104
  />
@@ -107,7 +108,7 @@ const ImagePreview: React.FC<ImagePreviewProps> = (props) => {
107
108
  return (
108
109
  <div className="relative overflow-hidden bg-black/5">
109
110
  <img
110
- src={source}
111
+ src={sourceUrl}
111
112
  alt={title}
112
113
  className={`block w-full transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}
113
114
  onLoad={() => setSourceReady(true)}
@@ -117,19 +118,19 @@ const ImagePreview: React.FC<ImagePreviewProps> = (props) => {
117
118
  }
118
119
 
119
120
  interface DocumentPreviewProps {
120
- thumbnail?: string
121
+ thumbnailUrl?: string
121
122
  mimeType: string
122
123
  paymentStatus?: PaymentStatus
123
124
  isLocked: boolean
124
125
  }
125
126
 
126
127
  const DocumentPreview: React.FC<DocumentPreviewProps> = (props) => {
127
- const { thumbnail, mimeType, paymentStatus, isLocked } = props
128
+ const { thumbnailUrl, mimeType, paymentStatus, isLocked } = props
128
129
  return (
129
130
  <div className="relative aspect-video overflow-hidden bg-black/5">
130
- {thumbnail ? (
131
+ {thumbnailUrl ? (
131
132
  <img
132
- src={thumbnail}
133
+ src={thumbnailUrl}
133
134
  alt=""
134
135
  className="absolute inset-0 h-full w-full object-cover"
135
136
  />
@@ -147,25 +148,25 @@ const DocumentPreview: React.FC<DocumentPreviewProps> = (props) => {
147
148
  }
148
149
 
149
150
  interface MediaPreviewProps {
150
- source?: string
151
- thumbnail?: string
151
+ sourceUrl?: string
152
+ thumbnailUrl?: string
152
153
  mimeType: string
153
154
  paymentStatus?: PaymentStatus
154
155
  isLocked: boolean
155
156
  }
156
157
 
157
158
  const MediaPreview: React.FC<MediaPreviewProps> = (props) => {
158
- const { source, thumbnail, mimeType, paymentStatus, isLocked } = props
159
+ const { sourceUrl, thumbnailUrl, mimeType, paymentStatus, isLocked } = props
159
160
  if (isLocked) {
160
161
  return (
161
162
  <LockedPreview
162
- thumbnail={thumbnail}
163
+ thumbnailUrl={thumbnailUrl}
163
164
  mimeType={mimeType}
164
165
  LockIcon={getLockIcon(paymentStatus)}
165
166
  />
166
167
  )
167
168
  }
168
- return <MediaPlayer source={source!} mimeType={mimeType} poster={thumbnail} />
169
+ return <MediaPlayer source={sourceUrl!} mimeType={mimeType} poster={thumbnailUrl} />
169
170
  }
170
171
 
171
172
 
@@ -180,13 +181,14 @@ const LoadingDots = () => (
180
181
  interface CardActionsProps {
181
182
  isLocked: boolean
182
183
  unlockLoading: boolean
183
- source?: string
184
+ sourceUrl?: string
185
+ redeemUrl?: string
184
186
  onUnlock?: () => void
185
187
  onDownload?: () => void
186
188
  }
187
189
 
188
190
  const CardActions: React.FC<CardActionsProps> = (props) => {
189
- const { isLocked, unlockLoading, source, onUnlock, onDownload } = props
191
+ const { isLocked, unlockLoading, sourceUrl, redeemUrl, onUnlock, onDownload } = props
190
192
 
191
193
  if (isLocked && onUnlock) {
192
194
  return (
@@ -208,10 +210,12 @@ const CardActions: React.FC<CardActionsProps> = (props) => {
208
210
  )
209
211
  }
210
212
 
211
- if (!isLocked && onDownload && source) {
213
+ if (!isLocked && onDownload && sourceUrl) {
212
214
  return (
213
215
  <a
214
- href={source}
216
+ href={redeemUrl ?? sourceUrl}
217
+ target="_blank"
218
+ rel="noopener noreferrer"
215
219
  onClick={onDownload}
216
220
  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]"
217
221
  >
@@ -229,22 +233,26 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
229
233
  const {
230
234
  title,
231
235
  amountText,
232
- thumbnail,
233
- source: sourceProp,
236
+ thumbnailUrl,
237
+ sourceUrl: sourceProp,
234
238
  mimeType = 'application/octet-stream',
235
239
  detail,
236
240
  onUnlock,
237
241
  onDownload,
238
242
  paymentStatus,
239
243
  } = props
240
- const [source, setSource] = useState(sourceProp)
244
+ const [sourceUrl, setSourceUrl] = useState(sourceProp)
245
+ const [redeemUrl, setRedeemUrl] = useState<string | undefined>(undefined)
241
246
  const [unlockLoading, setUnlockLoading] = useState(false)
242
247
 
243
248
  useEffect(() => {
244
- if (sourceProp !== undefined) setSource(sourceProp)
249
+ if (sourceProp !== undefined) {
250
+ setSourceUrl(sourceProp)
251
+ setRedeemUrl(undefined)
252
+ }
245
253
  }, [sourceProp])
246
254
 
247
- const isLocked = source === undefined
255
+ const isLocked = sourceUrl === undefined
248
256
  const sourceType = getSourceType(mimeType)
249
257
 
250
258
  const handleUnlock = async () => {
@@ -252,7 +260,8 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
252
260
  setUnlockLoading(true)
253
261
  try {
254
262
  const result = await onUnlock()
255
- setSource(result.source)
263
+ setSourceUrl(result.sourceUrl)
264
+ setRedeemUrl(result.redeemUrl)
256
265
  } catch (err) {
257
266
  if (isDevBuild()) console.debug('[LockedAttachment] onUnlock failed', err)
258
267
  } finally {
@@ -264,8 +273,8 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
264
273
  if (sourceType === 'image') {
265
274
  mediaPreview = (
266
275
  <ImagePreview
267
- source={source}
268
- thumbnail={thumbnail}
276
+ sourceUrl={sourceUrl}
277
+ thumbnailUrl={thumbnailUrl}
269
278
  mimeType={mimeType}
270
279
  title={title}
271
280
  paymentStatus={paymentStatus}
@@ -275,7 +284,7 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
275
284
  } else if (sourceType === 'document') {
276
285
  mediaPreview = (
277
286
  <DocumentPreview
278
- thumbnail={thumbnail}
287
+ thumbnailUrl={thumbnailUrl}
279
288
  mimeType={mimeType}
280
289
  paymentStatus={paymentStatus}
281
290
  isLocked={isLocked}
@@ -284,8 +293,8 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
284
293
  } else {
285
294
  mediaPreview = (
286
295
  <MediaPreview
287
- source={source}
288
- thumbnail={thumbnail}
296
+ sourceUrl={sourceUrl}
297
+ thumbnailUrl={thumbnailUrl}
289
298
  mimeType={mimeType}
290
299
  paymentStatus={paymentStatus}
291
300
  isLocked={isLocked}
@@ -294,7 +303,7 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
294
303
  }
295
304
 
296
305
  return (
297
- <div className="w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-card">
306
+ <div className="w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]">
298
307
  {mediaPreview}
299
308
  <div className="px-4 pb-3 pt-3">
300
309
  <p className="mb-1.5 truncate text-base font-medium text-black">
@@ -333,7 +342,8 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
333
342
  <CardActions
334
343
  isLocked={isLocked}
335
344
  unlockLoading={unlockLoading}
336
- source={source}
345
+ sourceUrl={sourceUrl}
346
+ redeemUrl={redeemUrl}
337
347
  onUnlock={onUnlock ? handleUnlock : undefined}
338
348
  onDownload={onDownload}
339
349
  />
@@ -8,7 +8,7 @@ const VisitorCardLazy = React.lazy(() => import('./components/Visitor'))
8
8
 
9
9
  const LockedAttachmentFallback = () => (
10
10
  <div
11
- className="w-[280px] min-h-[200px] animate-pulse rounded-[24px] bg-black/[0.06] shadow-[0px_0px_0px_1px_rgba(0,0,0,0.04),0px_1px_2px_0px_rgba(0,0,0,0.04)]"
11
+ className="w-[280px] min-h-[200px] animate-pulse rounded-[24px] bg-black/[0.06] shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]"
12
12
  aria-hidden
13
13
  />
14
14
  )
@@ -3,8 +3,8 @@ import type { PaymentStatus } from '../../stream-custom-data'
3
3
  export interface LockedAttachmentBaseProps {
4
4
  title?: string
5
5
  mimeType?: string
6
- thumbnail?: string
7
- source?: string
6
+ thumbnailUrl?: string
7
+ sourceUrl?: string
8
8
  detail?: string
9
9
  amountText?: string
10
10
  paymentStatus?: PaymentStatus
package/src/types.ts CHANGED
@@ -118,7 +118,10 @@ export interface ChannelListProps {
118
118
  }
119
119
 
120
120
  export interface LockedAttachmentSource {
121
- source: string
121
+ /** Proxied URL used by the media player for in-app playback. */
122
+ sourceUrl: string
123
+ /** URL opened when the visitor clicks Download — may be a file or a web destination. */
124
+ redeemUrl?: string
122
125
  }
123
126
 
124
127
  /**
@@ -1 +0,0 @@
1
- {"version":3,"file":"Creator-77XnrIxc.js","sources":["../src/components/LockedAttachment/components/Creator.tsx"],"sourcesContent":["import {\n CheckCircleIcon,\n EyeIcon,\n EyeSlashIcon,\n LockIcon,\n LockOpenIcon,\n PauseIcon,\n PlayIcon,\n XIcon,\n} from '@phosphor-icons/react'\nimport classNames from 'classnames'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { LockedAttachmentBaseProps } from '../types'\nimport { renderTypeIcon } from '../utils/icons'\nimport { getSourceType } from '../utils/mimeType'\n\nimport MediaPlayer from './MediaPlayer'\n\nexport interface CreatorCardProps extends LockedAttachmentBaseProps {\n isPreview?: boolean\n placeholderTitle?: string\n placeholderAmountText?: string\n onDismiss?: () => void\n}\n\ninterface CloseButtonProps {\n onClose: () => void\n}\n\nconst CloseButton: React.FC<CloseButtonProps> = (props) => {\n const { onClose } = props\n return (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"absolute left-3 top-3 z-40 flex size-8 items-center justify-center rounded-full bg-black/60 text-white\"\n aria-label=\"Close preview\"\n >\n <EyeIcon className=\"size-4\" weight=\"fill\" />\n </button>\n )\n}\n\ninterface CollapsedThumbnailProps {\n thumbnail?: string\n mimeType: string\n overlayIcon?: React.ElementType\n darkOverlay?: boolean\n onClick?: () => void\n}\n\nconst CollapsedThumbnail: React.FC<CollapsedThumbnailProps> = (props) => {\n const { thumbnail, mimeType, overlayIcon: OverlayIcon, darkOverlay, onClick } = props\n return (\n <button\n type=\"button\"\n disabled={!onClick}\n className={classNames(\n 'relative aspect-video block w-full overflow-hidden border-0 bg-black/5 p-0 text-left appearance-none',\n { 'cursor-pointer': !!onClick, 'cursor-default': !onClick }\n )}\n onClick={onClick}\n aria-label={OverlayIcon ? 'Toggle preview' : undefined}\n >\n {thumbnail ? (\n <img\n src={thumbnail}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n {darkOverlay && (\n <div className=\"pointer-events-none absolute inset-0 bg-black/30\" />\n )}\n {OverlayIcon && (\n <div className=\"pointer-events-none absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white\">\n <OverlayIcon className=\"size-4\" weight=\"fill\" />\n </div>\n )}\n </button>\n )\n}\n\n\ninterface AudioPreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n}\n\nconst AudioPreview: React.FC<AudioPreviewProps> = (props) => {\n const { source, thumbnail, mimeType } = props\n const [playing, setPlaying] = useState(false)\n const [played, setPlayed] = useState(0)\n const [seeking, setSeeking] = useState(false)\n const audioRef = useRef<HTMLAudioElement>(null)\n const trackRef = useRef<HTMLDivElement>(null)\n const rafRef = useRef<number | null>(null)\n\n useEffect(() => {\n const el = audioRef.current\n if (!el) return\n if (playing) {\n void el.play().catch(() => setPlaying(false))\n } else {\n el.pause()\n }\n }, [playing])\n\n useEffect(() => {\n if (!playing) {\n if (rafRef.current !== null) cancelAnimationFrame(rafRef.current)\n return\n }\n const tick = () => {\n const el = audioRef.current\n if (el && el.duration && !seeking) setPlayed(el.currentTime / el.duration)\n rafRef.current = requestAnimationFrame(tick)\n }\n rafRef.current = requestAnimationFrame(tick)\n return () => {\n if (rafRef.current !== null) cancelAnimationFrame(rafRef.current)\n }\n }, [playing, seeking])\n\n const [audioReady, setAudioReady] = useState(false)\n\n useEffect(() => {\n setPlaying(false)\n setPlayed(0)\n setAudioReady(false)\n }, [source])\n\n const getFraction = useCallback(\n (e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent) => {\n const track = trackRef.current\n if (!track) return 0\n const clientX =\n 'touches' in e\n ? (e.touches[0]?.clientX ?? e.changedTouches[0]?.clientX ?? 0)\n : e.clientX\n const rect = track.getBoundingClientRect()\n return Math.max(0, Math.min(1, (clientX - rect.left) / rect.width))\n },\n []\n )\n\n const seekTo = useCallback((fraction: number) => {\n const el = audioRef.current\n if (el && el.duration) el.currentTime = fraction * el.duration\n }, [])\n\n useEffect(() => {\n if (!seeking) return\n const onMove = (e: MouseEvent | TouchEvent) => {\n const f = getFraction(e)\n setPlayed(f)\n seekTo(f)\n }\n const onUp = (e: MouseEvent | TouchEvent) => {\n setSeeking(false)\n seekTo(getFraction(e))\n }\n window.addEventListener('mousemove', onMove)\n window.addEventListener('mouseup', onUp)\n window.addEventListener('touchmove', onMove, { passive: true })\n window.addEventListener('touchend', onUp)\n return () => {\n window.removeEventListener('mousemove', onMove)\n window.removeEventListener('mouseup', onUp)\n window.removeEventListener('touchmove', onMove)\n window.removeEventListener('touchend', onUp)\n }\n }, [seeking, getFraction, seekTo])\n\n const toggle = useCallback(() => setPlaying((p) => !p), [])\n\n return (\n <div className=\"relative\">\n {source && (\n <audio\n ref={audioRef}\n src={source}\n loop\n onCanPlay={() => setAudioReady(true)}\n onEnded={() => {\n setPlaying(false)\n setPlayed(0)\n }}\n >\n <track kind=\"captions\" />\n </audio>\n )}\n <CollapsedThumbnail\n thumbnail={thumbnail}\n mimeType={mimeType}\n overlayIcon={source && audioReady ? (playing ? PauseIcon : PlayIcon) : undefined}\n onClick={source && audioReady ? toggle : undefined}\n />\n {source && audioReady && (\n <div className=\"absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent\">\n <div\n ref={trackRef}\n role=\"slider\"\n aria-label=\"Playback position\"\n aria-valuenow={Math.round(played * 100)}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n className=\"relative flex h-4 w-full cursor-pointer items-center\"\n onMouseDown={(e) => {\n e.stopPropagation()\n setSeeking(true)\n const f = getFraction(e)\n setPlayed(f)\n seekTo(f)\n }}\n onTouchStart={(e) => {\n e.stopPropagation()\n setSeeking(true)\n const f = getFraction(e)\n setPlayed(f)\n seekTo(f)\n }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))\n if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))\n }}\n >\n <div className=\"w-full overflow-hidden rounded-full bg-white/30 h-1\">\n <div\n className=\"h-full rounded-full bg-white\"\n style={{ width: `${Math.round(played * 100)}%` }}\n />\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\ninterface VideoPreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n}\n\nconst VideoPreview: React.FC<VideoPreviewProps> = (props) => {\n const { source, thumbnail, mimeType } = props\n const [expanded, setExpanded] = useState(false)\n const collapse = () => setExpanded(false)\n\n useEffect(() => {\n setExpanded(false)\n }, [source])\n\n if (!source) {\n return <CollapsedThumbnail thumbnail={thumbnail} mimeType={mimeType} />\n }\n\n return (\n <div\n className={classNames('relative overflow-hidden', {\n 'aspect-video': !expanded,\n })}\n >\n <MediaPlayer\n source={source}\n mimeType={mimeType}\n poster={thumbnail}\n playing={expanded}\n loop\n controls={false}\n showProgress\n onContainerClick={collapse}\n muted\n />\n {!expanded && (\n <button\n type=\"button\"\n className=\"absolute inset-0 block cursor-pointer border-0 p-0 text-left appearance-none\"\n onClick={() => setExpanded(true)}\n aria-label=\"Expand video preview\"\n >\n {thumbnail ? (\n <img\n src={thumbnail}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n <div className=\"pointer-events-none absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white\">\n <EyeSlashIcon className=\"size-4\" weight=\"fill\" />\n </div>\n </button>\n )}\n {expanded && <CloseButton onClose={collapse} />}\n </div>\n )\n}\n\ninterface ImagePreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n title?: string\n}\n\nconst ImagePreview: React.FC<ImagePreviewProps> = (props) => {\n const { source, thumbnail, mimeType, title } = props\n const [expanded, setExpanded] = useState(false)\n const collapse = () => setExpanded(false)\n\n useEffect(() => {\n setExpanded(false)\n }, [source])\n\n if (expanded && source) {\n return (\n <div className=\"relative\">\n <button\n type=\"button\"\n className=\"block w-full cursor-pointer border-0 p-0 text-left appearance-none\"\n onClick={collapse}\n aria-label=\"Close preview\"\n >\n <img src={source} alt={title ?? ''} className=\"block w-full\" />\n </button>\n <CloseButton onClose={collapse} />\n </div>\n )\n }\n\n return (\n <CollapsedThumbnail\n thumbnail={thumbnail}\n mimeType={mimeType}\n overlayIcon={source ? EyeSlashIcon : undefined}\n onClick={source ? () => setExpanded(true) : undefined}\n />\n )\n}\n\n\nconst CreatorCard: React.FC<CreatorCardProps> = (props) => {\n const {\n title,\n mimeType = 'application/octet-stream',\n thumbnail,\n source,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n placeholderAmountText,\n paymentStatus,\n onDismiss,\n isPreview = false,\n } = props\n const sourceType = getSourceType(mimeType)\n const displayAmountText = amountText ?? placeholderAmountText\n const isPlaceholderAmount = !amountText && !!placeholderAmountText\n\n let mediaPreview: React.ReactNode\n if (isPreview && sourceType === 'audio') {\n mediaPreview = (\n <AudioPreview source={source} thumbnail={thumbnail} mimeType={mimeType} />\n )\n } else if (isPreview && sourceType === 'video') {\n mediaPreview = (\n <VideoPreview source={source} thumbnail={thumbnail} mimeType={mimeType} />\n )\n } else if (isPreview && sourceType === 'image') {\n mediaPreview = (\n <ImagePreview\n source={source}\n thumbnail={thumbnail}\n mimeType={mimeType}\n title={title}\n />\n )\n } else {\n const lockedOverlayIcon = onDismiss\n ? undefined\n : paymentStatus === 'paid'\n ? LockOpenIcon\n : LockIcon\n mediaPreview = (\n <CollapsedThumbnail\n thumbnail={thumbnail}\n mimeType={mimeType}\n overlayIcon={lockedOverlayIcon}\n darkOverlay\n />\n )\n }\n\n return (\n <div className=\"relative w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-card\">\n {onDismiss && (\n <button\n type=\"button\"\n onClick={onDismiss}\n className=\"absolute right-3 top-3 z-50 flex size-8 items-center justify-center rounded-full bg-black/60 text-white\"\n aria-label=\"Dismiss attachment\"\n >\n <XIcon className=\"size-4\" weight=\"bold\" />\n </button>\n )}\n {mediaPreview}\n <div className=\"px-4 pb-3 pt-3\">\n <p\n className={classNames('mb-1.5 truncate text-base font-medium', {\n 'text-black/30': !title,\n 'text-black': !!title,\n })}\n >\n {title || placeholderTitle}\n </p>\n <div className=\"flex items-center gap-1\">\n {renderTypeIcon(mimeType, {\n className: 'size-5 shrink-0 text-black/55',\n weight: 'regular',\n })}\n {detail && (\n <span className=\"text-xs font-medium text-black/55\">{detail}</span>\n )}\n {paymentStatus === 'paid' ? (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-[#008236]\">\n Purchased\n </span>\n <CheckCircleIcon\n className=\"size-4 text-[#008236]\"\n weight=\"bold\"\n />\n </>\n ) : (\n displayAmountText && (\n <>\n <span\n className={classNames('text-xs font-medium', {\n 'text-black/30': isPlaceholderAmount,\n 'text-black/55': !isPlaceholderAmount,\n })}\n >\n •\n </span>\n <span\n className={classNames('text-xs font-medium', {\n 'text-black/30': isPlaceholderAmount,\n 'text-black/55': !isPlaceholderAmount,\n })}\n >\n {displayAmountText}\n </span>\n </>\n )\n )}\n </div>\n </div>\n </div>\n )\n}\n\nexport default CreatorCard\n"],"names":["CloseButton","props","onClose","jsx","EyeIcon","CollapsedThumbnail","thumbnail","mimeType","OverlayIcon","darkOverlay","onClick","jsxs","classNames","AudioPreview","source","playing","setPlaying","useState","played","setPlayed","seeking","setSeeking","audioRef","useRef","trackRef","rafRef","useEffect","el","tick","audioReady","setAudioReady","getFraction","useCallback","e","track","clientX","_a","_b","rect","seekTo","fraction","onMove","f","onUp","toggle","p","PauseIcon","PlayIcon","VideoPreview","expanded","setExpanded","collapse","MediaPlayer","EyeSlashIcon","ImagePreview","title","CreatorCard","detail","amountText","placeholderTitle","placeholderAmountText","paymentStatus","onDismiss","isPreview","sourceType","getSourceType","displayAmountText","isPlaceholderAmount","mediaPreview","LockOpenIcon","LockIcon","XIcon","renderTypeIcon","Fragment","CheckCircleIcon"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"MediaPlayer-Bf-xPB8Z.js","sources":["../src/components/LockedAttachment/utils/mimeType.ts","../src/components/LockedAttachment/utils/icons.ts","../src/components/LockedAttachment/components/MediaPlayer.tsx"],"sourcesContent":["export type AttachmentSourceType = 'image' | 'audio' | 'video' | 'document'\n\nexport type DocumentIconType =\n | 'pdf'\n | 'doc'\n | 'xls'\n | 'csv'\n | 'ppt'\n | 'zip'\n | 'text'\n | 'markdown'\n | 'generic'\n\nconst DOCUMENT_ICON_PATTERNS: Array<[RegExp, DocumentIconType]> = [\n [/pdf/, 'pdf'],\n [/wordprocessingml|msword|\\.doc/, 'doc'],\n [/spreadsheetml|ms-excel|\\.xls/, 'xls'],\n [/csv/, 'csv'],\n [/presentationml|ms-powerpoint|\\.ppt/, 'ppt'],\n [/zip|x-rar|x-7z|x-tar|x-gzip/, 'zip'],\n [/plain|rtf/, 'text'],\n [/markdown/, 'markdown'],\n]\n\nexport function getSourceType(mimeType: string): AttachmentSourceType {\n if (mimeType.startsWith('video/')) return 'video'\n if (mimeType.startsWith('audio/')) return 'audio'\n if (mimeType.startsWith('image/')) return 'image'\n return 'document'\n}\n\nexport function getDocumentIconType(mimeType: string): DocumentIconType {\n const match = DOCUMENT_ICON_PATTERNS.find(([pattern]) =>\n pattern.test(mimeType)\n )\n return match ? match[1] : 'generic'\n}\n","import {\n FileIcon,\n FileCsvIcon,\n FileDocIcon,\n FileMdIcon,\n FilePdfIcon,\n FilePptIcon,\n FileTextIcon,\n FileXlsIcon,\n FileZipIcon,\n ImageIcon,\n SpeakerHighIcon,\n VideoCameraIcon,\n IconProps,\n} from '@phosphor-icons/react'\nimport React from 'react'\n\nimport { getDocumentIconType, getSourceType } from './mimeType'\nimport type { AttachmentSourceType } from './mimeType'\n\nexport const MEDIA_TYPE_ICON: Record<AttachmentSourceType, React.ElementType> =\n {\n video: VideoCameraIcon,\n audio: SpeakerHighIcon,\n image: ImageIcon,\n document: FileIcon,\n }\n\nconst DOCUMENT_ICON_COMPONENT = {\n pdf: FilePdfIcon,\n doc: FileDocIcon,\n xls: FileXlsIcon,\n csv: FileCsvIcon,\n ppt: FilePptIcon,\n zip: FileZipIcon,\n text: FileTextIcon,\n markdown: FileMdIcon,\n generic: FileIcon,\n} as const\n\nexport function getTypeIcon(mimeType: string): React.ElementType {\n const sourceType = getSourceType(mimeType)\n if (sourceType !== 'document') return MEDIA_TYPE_ICON[sourceType]\n return DOCUMENT_ICON_COMPONENT[getDocumentIconType(mimeType)]\n}\n\n/** Use instead of `<TypeIcon />` where TypeIcon = getTypeIcon(mime) to satisfy react-hooks/static-components. */\nexport function renderTypeIcon(\n mimeType: string,\n props: IconProps\n): React.ReactElement {\n return React.createElement(getTypeIcon(mimeType), props)\n}\n","import { CircleNotchIcon, PauseIcon, PlayIcon } from '@phosphor-icons/react'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport { isDevBuild } from '../../../utils/isDevBuild'\nimport { renderTypeIcon } from '../utils/icons'\nimport { getSourceType, type AttachmentSourceType } from '../utils/mimeType'\n\nconst getPlayerBg = (sourceType: AttachmentSourceType, poster?: string) =>\n sourceType === 'audio' && !poster ? 'bg-black/5' : 'bg-black'\n\nfunction getClientXFromEvent(\n e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent\n): number {\n if ('touches' in e) {\n return e.touches[0]?.clientX ?? e.changedTouches[0]?.clientX ?? 0\n }\n return e.clientX\n}\n\nexport interface MediaPlayerProps {\n source: string\n mimeType: string\n poster?: string\n autoPlay?: boolean\n /** Controlled playing state. When provided, syncs to internal play/pause. */\n playing?: boolean\n loop?: boolean\n controls?: boolean\n showProgress?: boolean\n onContainerClick?: () => void\n /** When true, requests muted playback (helps autoplay policies on video). */\n muted?: boolean\n}\n\nconst MediaPlayer: React.FC<MediaPlayerProps> = ({\n source,\n mimeType,\n poster,\n autoPlay = false,\n playing: playingProp,\n loop = false,\n controls = true,\n showProgress = false,\n onContainerClick,\n muted = false,\n}) => {\n const sourceType = getSourceType(mimeType)\n const [playing, setPlaying] = useState(autoPlay)\n\n // Sync controlled playing prop to internal state\n const prevPlayingPropRef = useRef(playingProp)\n useEffect(() => {\n if (\n playingProp !== undefined &&\n playingProp !== prevPlayingPropRef.current\n ) {\n prevPlayingPropRef.current = playingProp\n setPlaying(playingProp)\n }\n }, [playingProp])\n const [played, setPlayed] = useState(0)\n const [seeking, setSeeking] = useState(false)\n const [scrubberHovered, setScrubberHovered] = useState(false)\n const [videoAspect, setVideoAspect] = useState<number | null>(null)\n const [buffering, setBuffering] = useState(false)\n /** True until the first canPlay fires for the current source — hides controls/spinner behind poster. */\n const [initialLoad, setInitialLoad] = useState(true)\n /** Set when autoplay/play() was rejected so user can start via gesture (no controls UI). */\n const [manualPlayRequired, setManualPlayRequired] = useState(false)\n const playerRef = useRef<HTMLMediaElement>(null)\n const trackRef = useRef<HTMLDivElement>(null)\n const rafRef = useRef<number | null>(null)\n\n useEffect(() => {\n setManualPlayRequired(false)\n setInitialLoad(true)\n }, [source])\n\n useEffect(() => {\n if (!playing) {\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current)\n rafRef.current = null\n }\n return\n }\n const tick = () => {\n const el = playerRef.current\n if (el && el.duration && !seeking) setPlayed(el.currentTime / el.duration)\n rafRef.current = requestAnimationFrame(tick)\n }\n rafRef.current = requestAnimationFrame(tick)\n return () => {\n if (rafRef.current !== null) cancelAnimationFrame(rafRef.current)\n }\n }, [playing, seeking])\n\n // ReactPlayer v3 uses native HTML media elements and does not support a\n // declarative `playing` prop — playback must be driven imperatively.\n useEffect(() => {\n const el = playerRef.current\n if (!el) return\n if (playing) {\n void el.play().catch((err) => {\n setPlaying(false)\n setManualPlayRequired(true)\n if (isDevBuild()) {\n console.debug('[MediaPlayer] play() failed', err)\n }\n })\n } else {\n el.pause()\n }\n }, [playing])\n\n const startPlaybackFromGesture = useCallback(() => {\n setManualPlayRequired(false)\n setPlaying(true)\n }, [])\n\n const getFraction = useCallback(\n (e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent) => {\n const track = trackRef.current\n if (!track) return 0\n const rect = track.getBoundingClientRect()\n return Math.max(\n 0,\n Math.min(1, (getClientXFromEvent(e) - rect.left) / rect.width)\n )\n },\n []\n )\n\n const seekTo = useCallback((fraction: number) => {\n const el = playerRef.current\n if (el && el.duration) el.currentTime = fraction * el.duration\n }, [])\n\n const handleTrackPointerDown = (\n e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>\n ) => {\n e.stopPropagation()\n setSeeking(true)\n const fraction = getFraction(e)\n setPlayed(fraction)\n seekTo(fraction)\n }\n\n useEffect(() => {\n if (!seeking) return\n const onMove = (e: MouseEvent | TouchEvent) => setPlayed(getFraction(e))\n const onUp = (e: MouseEvent | TouchEvent) => {\n setSeeking(false)\n seekTo(getFraction(e))\n }\n window.addEventListener('mousemove', onMove)\n window.addEventListener('mouseup', onUp)\n window.addEventListener('touchmove', onMove, { passive: true })\n window.addEventListener('touchend', onUp)\n return () => {\n window.removeEventListener('mousemove', onMove)\n window.removeEventListener('mouseup', onUp)\n window.removeEventListener('touchmove', onMove)\n window.removeEventListener('touchend', onUp)\n }\n }, [seeking, getFraction, seekTo])\n\n // Use natural aspect ratio once metadata loads, fall back to 16:9 before then.\n const aspectStyle = videoAspect\n ? { aspectRatio: String(videoAspect) }\n : undefined\n const aspectClass = !videoAspect ? ' aspect-video' : ''\n const scrubberPercent = Math.round(played * 100)\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n className={`relative cursor-pointer overflow-hidden ${getPlayerBg(sourceType, poster)}${aspectClass}`}\n style={aspectStyle}\n onClick={() => {\n if (manualPlayRequired) return\n if (onContainerClick) {\n onContainerClick()\n return\n }\n if (controls) setPlaying((p) => !p)\n }}\n onKeyDown={(e) => {\n if (e.key !== 'Enter' && e.key !== ' ') return\n e.preventDefault()\n if (manualPlayRequired) return\n if (onContainerClick) {\n onContainerClick()\n return\n }\n if (controls) setPlaying((p) => !p)\n }}\n >\n {poster && (\n <img\n src={poster}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n )}\n {!poster && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n {initialLoad && poster && (\n <div className=\"absolute inset-0 z-20\">\n <img src={poster} alt=\"\" className=\"h-full w-full object-cover\" />\n </div>\n )}\n <div className=\"absolute inset-0\">\n {sourceType === 'audio' ? (\n <audio\n ref={playerRef as React.RefObject<HTMLAudioElement>}\n src={source}\n loop={loop}\n muted={muted}\n style={{ width: '100%', height: '100%' }}\n onLoadStart={() => setBuffering(true)}\n onCanPlay={() => { setBuffering(false); setInitialLoad(false) }}\n onWaiting={() => setBuffering(true)}\n onPlay={() => setManualPlayRequired(false)}\n onEnded={() => {\n if (!loop) {\n setPlaying(false)\n setPlayed(0)\n }\n }}\n >\n <track kind=\"captions\" />\n </audio>\n ) : (\n <video\n ref={playerRef as React.RefObject<HTMLVideoElement>}\n src={source}\n poster={poster}\n loop={loop}\n muted={muted}\n playsInline\n style={{ width: '100%', height: '100%' }}\n onLoadStart={() => setBuffering(true)}\n onCanPlay={() => { setBuffering(false); setInitialLoad(false) }}\n onWaiting={() => setBuffering(true)}\n onPlay={() => setManualPlayRequired(false)}\n onLoadedMetadata={() => {\n const el = playerRef.current\n if (el instanceof HTMLVideoElement && el.videoWidth && el.videoHeight) {\n setVideoAspect(el.videoWidth / el.videoHeight)\n }\n }}\n onEnded={() => {\n if (!loop) {\n setPlaying(false)\n setPlayed(0)\n }\n }}\n >\n <track kind=\"captions\" />\n </video>\n )}\n </div>\n\n {buffering && !manualPlayRequired && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n <CircleNotchIcon\n className=\"size-8 animate-spin text-white/80\"\n weight=\"bold\"\n />\n </div>\n )}\n\n {manualPlayRequired && !controls && (\n <div\n className=\"absolute inset-0 z-30 flex cursor-pointer items-center justify-center bg-black/35\"\n role=\"button\"\n tabIndex={0}\n aria-label=\"Play preview\"\n onClick={(e) => {\n e.stopPropagation()\n startPlaybackFromGesture()\n }}\n onKeyDown={(e) => {\n if (e.key !== 'Enter' && e.key !== ' ') return\n e.preventDefault()\n e.stopPropagation()\n startPlaybackFromGesture()\n }}\n >\n <span className=\"flex size-16 items-center justify-center rounded-full bg-white/20 text-white backdrop-blur-sm\">\n <PlayIcon className=\"size-9 translate-x-0.5\" weight=\"fill\" />\n </span>\n </div>\n )}\n\n {showProgress && !controls && (\n <div className=\"absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent\">\n <div\n role=\"slider\"\n aria-label=\"Playback position\"\n aria-valuenow={scrubberPercent}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n ref={trackRef}\n className=\"relative flex h-4 w-full cursor-pointer items-center\"\n onMouseDown={handleTrackPointerDown}\n onTouchStart={handleTrackPointerDown}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))\n if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))\n }}\n >\n <div className=\"w-full overflow-hidden rounded-full bg-white/30 h-1\">\n <div\n className=\"h-full rounded-full bg-white\"\n style={{ width: `${scrubberPercent}%` }}\n />\n </div>\n </div>\n </div>\n )}\n\n {controls && (\n <div className=\"absolute inset-x-0 bottom-0 flex items-center gap-2 bg-gradient-to-t from-black/60 to-transparent px-3 pb-2.5 pt-6 transition-all duration-200\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n setPlaying((p) => !p)\n }}\n className=\"shrink-0 text-white\"\n aria-label={playing ? 'Pause' : 'Play'}\n >\n {playing ? (\n <PauseIcon className=\"size-5\" weight=\"fill\" />\n ) : (\n <PlayIcon className=\"size-5 translate-x-px\" weight=\"fill\" />\n )}\n </button>\n\n <div\n role=\"slider\"\n aria-label=\"Playback position\"\n aria-valuenow={scrubberPercent}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n ref={trackRef}\n className=\"relative flex h-4 w-full cursor-pointer items-center\"\n onMouseDown={handleTrackPointerDown}\n onTouchStart={handleTrackPointerDown}\n onClick={(e) => e.stopPropagation()}\n onMouseEnter={() => setScrubberHovered(true)}\n onMouseLeave={() => setScrubberHovered(false)}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))\n if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))\n }}\n >\n <div\n className={`w-full overflow-hidden rounded-full bg-white/30 transition-all duration-200 ${scrubberHovered || seeking ? 'h-1.5' : 'h-1'}`}\n >\n <div\n className=\"h-full rounded-full bg-white\"\n style={{ width: `${scrubberPercent}%` }}\n />\n </div>\n <div\n className={`absolute size-3 -translate-x-1/2 rounded-full bg-white shadow transition-[opacity,transform] duration-200 ${scrubberHovered || seeking ? 'scale-100 opacity-100' : 'scale-0 opacity-0'}`}\n style={{ left: `${scrubberPercent}%` }}\n />\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default MediaPlayer\n"],"names":["DOCUMENT_ICON_PATTERNS","getSourceType","mimeType","getDocumentIconType","match","pattern","MEDIA_TYPE_ICON","VideoCameraIcon","SpeakerHighIcon","ImageIcon","FileIcon","DOCUMENT_ICON_COMPONENT","FilePdfIcon","FileDocIcon","FileXlsIcon","FileCsvIcon","FilePptIcon","FileZipIcon","FileTextIcon","FileMdIcon","getTypeIcon","sourceType","renderTypeIcon","props","React","getPlayerBg","poster","getClientXFromEvent","e","_a","_b","MediaPlayer","source","autoPlay","playingProp","loop","controls","showProgress","onContainerClick","muted","playing","setPlaying","useState","prevPlayingPropRef","useRef","useEffect","played","setPlayed","seeking","setSeeking","scrubberHovered","setScrubberHovered","videoAspect","setVideoAspect","buffering","setBuffering","initialLoad","setInitialLoad","manualPlayRequired","setManualPlayRequired","playerRef","trackRef","rafRef","tick","el","err","startPlaybackFromGesture","useCallback","getFraction","track","rect","seekTo","fraction","handleTrackPointerDown","onMove","onUp","aspectStyle","aspectClass","scrubberPercent","jsxs","p","jsx","CircleNotchIcon","PlayIcon","PauseIcon"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Visitor-C9HSYm3D.js","sources":["../src/components/LockedAttachment/components/Visitor.tsx"],"sourcesContent":["import {\n CheckCircleIcon,\n DownloadSimpleIcon,\n LockOpenIcon,\n LockSimpleIcon,\n} from '@phosphor-icons/react'\nimport React, { useEffect, useState } from 'react'\n\nimport { isDevBuild } from '../../../utils/isDevBuild'\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n PaymentStatus,\n} from '../types'\nimport { renderTypeIcon } from '../utils/icons'\nimport { getSourceType } from '../utils/mimeType'\n\nimport MediaPlayer from './MediaPlayer'\n\nexport interface VisitorCardProps extends LockedAttachmentBaseProps {\n /**\n * Called when the visitor clicks Unlock. Return the resolved source URL.\n * The component manages loading state and sets source internally on resolution.\n * Omit to hide the Unlock button.\n */\n onUnlock?: () => Promise<LockedAttachmentSource>\n /** Called when the visitor clicks Download on an unlocked card. */\n onDownload?: () => void \n}\n\nconst getLockIcon = (paymentStatus?: PaymentStatus): React.ElementType =>\n paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon\n\n\ninterface LockOverlayProps {\n icon: React.ElementType\n}\n\nconst LockOverlay: React.FC<LockOverlayProps> = (props) => {\n const { icon: Icon } = props\n return (\n <div className=\"absolute inset-0 bg-black/30\">\n <div className=\"absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60\">\n <Icon className=\"size-4 text-white\" weight=\"fill\" />\n </div>\n </div>\n )\n}\n\ninterface LockedPreviewProps {\n thumbnail?: string\n mimeType: string\n LockIcon: React.ElementType\n}\n\nconst LockedPreview: React.FC<LockedPreviewProps> = (props) => {\n const { thumbnail, mimeType, LockIcon } = props\n return (\n <div className=\"relative aspect-video overflow-hidden bg-black/5\">\n {thumbnail ? (\n <img\n src={thumbnail}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n <LockOverlay icon={LockIcon} />\n </div>\n )\n}\n\n\ninterface ImagePreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n title?: string\n paymentStatus?: PaymentStatus\n isLocked: boolean\n}\n\nconst ImagePreview: React.FC<ImagePreviewProps> = (props) => {\n const { source, thumbnail, mimeType, title, paymentStatus, isLocked } = props\n const [sourceReady, setSourceReady] = useState(false)\n\n useEffect(() => {\n setSourceReady(false)\n }, [source])\n\n if (isLocked) {\n return (\n <LockedPreview\n thumbnail={thumbnail}\n mimeType={mimeType}\n LockIcon={getLockIcon(paymentStatus)}\n />\n )\n }\n\n return (\n <div className=\"relative overflow-hidden bg-black/5\">\n <img\n src={source}\n alt={title}\n className={`block w-full transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}\n onLoad={() => setSourceReady(true)}\n />\n </div>\n )\n}\n\ninterface DocumentPreviewProps {\n thumbnail?: string\n mimeType: string\n paymentStatus?: PaymentStatus\n isLocked: boolean\n}\n\nconst DocumentPreview: React.FC<DocumentPreviewProps> = (props) => {\n const { thumbnail, mimeType, paymentStatus, isLocked } = props\n return (\n <div className=\"relative aspect-video overflow-hidden bg-black/5\">\n {thumbnail ? (\n <img\n src={thumbnail}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n {isLocked && <LockOverlay icon={getLockIcon(paymentStatus)} />}\n </div>\n )\n}\n\ninterface MediaPreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n paymentStatus?: PaymentStatus\n isLocked: boolean\n}\n\nconst MediaPreview: React.FC<MediaPreviewProps> = (props) => {\n const { source, thumbnail, mimeType, paymentStatus, isLocked } = props\n if (isLocked) {\n return (\n <LockedPreview\n thumbnail={thumbnail}\n mimeType={mimeType}\n LockIcon={getLockIcon(paymentStatus)}\n />\n )\n }\n return <MediaPlayer source={source!} mimeType={mimeType} poster={thumbnail} />\n}\n\n\nconst LoadingDots = () => (\n <span className=\"flex items-center gap-1\">\n <span className=\"size-1 rounded-full bg-white animate-bounce [animation-delay:-0.3s]\" />\n <span className=\"size-1 rounded-full bg-white animate-bounce [animation-delay:-0.15s]\" />\n <span className=\"size-1 rounded-full bg-white animate-bounce\" />\n </span>\n)\n\ninterface CardActionsProps {\n isLocked: boolean\n unlockLoading: boolean\n source?: string\n onUnlock?: () => void\n onDownload?: () => void\n}\n\nconst CardActions: React.FC<CardActionsProps> = (props) => {\n const { isLocked, unlockLoading, source, onUnlock, onDownload } = props\n\n if (isLocked && onUnlock) {\n return (\n <button\n type=\"button\"\n onClick={onUnlock}\n disabled={unlockLoading}\n 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\"\n >\n {unlockLoading ? (\n <LoadingDots />\n ) : (\n <>\n <LockSimpleIcon className=\"size-4\" weight=\"fill\" />\n Unlock\n </>\n )}\n </button>\n )\n }\n\n if (!isLocked && onDownload && source) {\n return (\n <a\n href={source}\n onClick={onDownload}\n 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]\"\n >\n <DownloadSimpleIcon className=\"size-4\" weight=\"bold\" />\n Download\n </a>\n )\n }\n\n return null\n}\n\n\nconst VisitorCard: React.FC<VisitorCardProps> = (props) => {\n const {\n title,\n amountText,\n thumbnail,\n source: sourceProp,\n mimeType = 'application/octet-stream',\n detail,\n onUnlock,\n onDownload,\n paymentStatus,\n } = props\n const [source, setSource] = useState(sourceProp)\n const [unlockLoading, setUnlockLoading] = useState(false)\n\n useEffect(() => {\n if (sourceProp !== undefined) setSource(sourceProp)\n }, [sourceProp])\n\n const isLocked = source === undefined\n const sourceType = getSourceType(mimeType)\n\n const handleUnlock = async () => {\n if (!onUnlock) return\n setUnlockLoading(true)\n try {\n const result = await onUnlock()\n setSource(result.source)\n } catch (err) {\n if (isDevBuild()) console.debug('[LockedAttachment] onUnlock failed', err)\n } finally {\n setUnlockLoading(false)\n }\n }\n\n let mediaPreview: React.ReactNode\n if (sourceType === 'image') {\n mediaPreview = (\n <ImagePreview\n source={source}\n thumbnail={thumbnail}\n mimeType={mimeType}\n title={title}\n paymentStatus={paymentStatus}\n isLocked={isLocked}\n />\n )\n } else if (sourceType === 'document') {\n mediaPreview = (\n <DocumentPreview\n thumbnail={thumbnail}\n mimeType={mimeType}\n paymentStatus={paymentStatus}\n isLocked={isLocked}\n />\n )\n } else {\n mediaPreview = (\n <MediaPreview\n source={source}\n thumbnail={thumbnail}\n mimeType={mimeType}\n paymentStatus={paymentStatus}\n isLocked={isLocked}\n />\n )\n }\n\n return (\n <div className=\"w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-card\">\n {mediaPreview}\n <div className=\"px-4 pb-3 pt-3\">\n <p className=\"mb-1.5 truncate text-base font-medium text-black\">\n {title}\n </p>\n <div className=\"flex items-center gap-1\">\n {renderTypeIcon(mimeType, {\n className: 'size-5 shrink-0 text-black/55',\n weight: 'regular',\n })}\n {detail && (\n <span className=\"text-xs font-medium text-black/55\">{detail}</span>\n )}\n {paymentStatus === 'paid' ? (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-[#008236]\">\n Purchased\n </span>\n <CheckCircleIcon\n className=\"size-4 text-[#008236]\"\n weight=\"bold\"\n />\n </>\n ) : (\n amountText && (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-black/55\">\n {amountText}\n </span>\n </>\n )\n )}\n </div>\n <CardActions\n isLocked={isLocked}\n unlockLoading={unlockLoading}\n source={source}\n onUnlock={onUnlock ? handleUnlock : undefined}\n onDownload={onDownload}\n />\n </div>\n </div>\n )\n}\n\nexport default VisitorCard\n"],"names":["getLockIcon","paymentStatus","LockOpenIcon","LockSimpleIcon","LockOverlay","props","Icon","jsx","LockedPreview","thumbnail","mimeType","LockIcon","jsxs","ImagePreview","source","title","isLocked","sourceReady","setSourceReady","useState","useEffect","DocumentPreview","MediaPreview","MediaPlayer","LoadingDots","CardActions","unlockLoading","onUnlock","onDownload","Fragment","DownloadSimpleIcon","VisitorCard","amountText","sourceProp","detail","setSource","setUnlockLoading","sourceType","getSourceType","handleUnlock","result","mediaPreview","renderTypeIcon","CheckCircleIcon"],"mappings":"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"}