@linktr.ee/messaging-react 1.31.0 → 1.32.1-rc-1777007852
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-1CQEn-OT.js +171 -0
- package/dist/Card-1CQEn-OT.js.map +1 -0
- package/dist/Card-ClE_iExA.js +177 -0
- package/dist/Card-ClE_iExA.js.map +1 -0
- package/dist/{MediaPlayer-BCsdmsON.js → MediaPlayer-B9Ws2NeE.js} +115 -135
- package/dist/MediaPlayer-B9Ws2NeE.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +79 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ChannelView.stories.tsx +38 -7
- package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +127 -0
- package/src/components/CustomMessageInput/index.tsx +25 -8
- package/src/components/LockedAttachment/LockedAttachment.stories.tsx +136 -93
- package/src/components/LockedAttachment/components/Creator/Card.tsx +106 -106
- package/src/components/LockedAttachment/components/Creator/CardThumbnail.tsx +114 -0
- package/src/components/LockedAttachment/components/MediaPlayer.tsx +80 -66
- package/src/components/LockedAttachment/components/Visitor/Card.tsx +53 -78
- package/src/components/LockedAttachment/components/Visitor/CardActions.tsx +3 -3
- package/src/components/LockedAttachment/components/Visitor/CardThumbnail.tsx +81 -0
- package/src/components/LockedAttachment/types.ts +2 -0
- package/dist/Card-C5t3dZ5q.js +0 -350
- package/dist/Card-C5t3dZ5q.js.map +0 -1
- package/dist/Card-Cn2va-Qr.js +0 -205
- package/dist/Card-Cn2va-Qr.js.map +0 -1
- package/dist/MediaPlayer-BCsdmsON.js.map +0 -1
- package/src/components/LockedAttachment/components/Creator/CardAudioPreview.tsx +0 -161
- package/src/components/LockedAttachment/components/Creator/CardCollapsedThumbnail.tsx +0 -58
- package/src/components/LockedAttachment/components/Creator/CardImagePreview.tsx +0 -56
- package/src/components/LockedAttachment/components/Creator/CardVideoPreview.tsx +0 -91
- package/src/components/LockedAttachment/components/Visitor/CardImagePreview.tsx +0 -39
- package/src/components/LockedAttachment/components/Visitor/CardMediaPreview.tsx +0 -36
- package/src/components/LockedAttachment/components/Visitor/CardThumbnailPreview.tsx +0 -45
package/package.json
CHANGED
|
@@ -39,7 +39,8 @@ const mockUser = {
|
|
|
39
39
|
const createMockChannel = async (
|
|
40
40
|
client: StreamChat,
|
|
41
41
|
hasMessages = true,
|
|
42
|
-
followerStatus?: string | boolean
|
|
42
|
+
followerStatus?: string | boolean,
|
|
43
|
+
isFrozen = false
|
|
43
44
|
) => {
|
|
44
45
|
const participant = mockParticipants[0]
|
|
45
46
|
|
|
@@ -105,6 +106,7 @@ const createMockChannel = async (
|
|
|
105
106
|
// Prepare channel data with optional follower status
|
|
106
107
|
const channelData: Record<string, unknown> = {
|
|
107
108
|
members: [mockUser.id, participant.id],
|
|
109
|
+
frozen: isFrozen,
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
// Add follower status if provided
|
|
@@ -155,10 +157,13 @@ const createMockChannel = async (
|
|
|
155
157
|
return channel
|
|
156
158
|
}
|
|
157
159
|
|
|
158
|
-
type TemplateProps = ComponentProps & {
|
|
160
|
+
type TemplateProps = ComponentProps & {
|
|
161
|
+
followerStatus?: string | boolean
|
|
162
|
+
isFrozen?: boolean
|
|
163
|
+
}
|
|
159
164
|
|
|
160
165
|
const Template: StoryFn<TemplateProps> = (args) => {
|
|
161
|
-
const { followerStatus, ...channelViewProps } = args
|
|
166
|
+
const { followerStatus, isFrozen = false, ...channelViewProps } = args
|
|
162
167
|
const [client] = React.useState(() => {
|
|
163
168
|
const client = new StreamChat('mock-api-key', {
|
|
164
169
|
allowServerSideConnect: true,
|
|
@@ -171,10 +176,12 @@ const Template: StoryFn<TemplateProps> = (args) => {
|
|
|
171
176
|
const [channel, setChannel] = React.useState<ChannelType | null>(null)
|
|
172
177
|
|
|
173
178
|
useEffect(() => {
|
|
174
|
-
createMockChannel(client, true, followerStatus).then(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
createMockChannel(client, true, followerStatus, isFrozen).then(
|
|
180
|
+
(mockChannel) => {
|
|
181
|
+
setChannel(mockChannel)
|
|
182
|
+
}
|
|
183
|
+
)
|
|
184
|
+
}, [client, followerStatus, isFrozen])
|
|
178
185
|
|
|
179
186
|
if (!channel) {
|
|
180
187
|
return <div>Loading...</div>
|
|
@@ -524,3 +531,27 @@ NoFollowerStatus.parameters = {
|
|
|
524
531
|
},
|
|
525
532
|
},
|
|
526
533
|
}
|
|
534
|
+
|
|
535
|
+
export const FrozenChannel: StoryFn<TemplateProps> = Template.bind({})
|
|
536
|
+
FrozenChannel.args = {
|
|
537
|
+
showBackButton: false,
|
|
538
|
+
isFrozen: true,
|
|
539
|
+
renderMessageInputActions: (channel) => (
|
|
540
|
+
<button
|
|
541
|
+
onClick={() => console.log('Custom action clicked', channel.id)}
|
|
542
|
+
className="p-2 hover:bg-sand rounded-lg"
|
|
543
|
+
aria-label="Attach file"
|
|
544
|
+
type="button"
|
|
545
|
+
>
|
|
546
|
+
📎
|
|
547
|
+
</button>
|
|
548
|
+
),
|
|
549
|
+
}
|
|
550
|
+
FrozenChannel.parameters = {
|
|
551
|
+
docs: {
|
|
552
|
+
description: {
|
|
553
|
+
story:
|
|
554
|
+
'Channel view for a frozen conversation. The message composer renders in its disabled frozen state while the rest of the conversation remains readable.',
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { renderWithProviders, screen } from '../../test/utils'
|
|
5
|
+
|
|
6
|
+
import { CustomMessageInput } from '.'
|
|
7
|
+
|
|
8
|
+
let mockChannelData: Record<string, unknown> = {}
|
|
9
|
+
|
|
10
|
+
vi.mock('stream-chat-react', () => ({
|
|
11
|
+
MessageInput: ({
|
|
12
|
+
Input,
|
|
13
|
+
}: {
|
|
14
|
+
Input: React.ComponentType
|
|
15
|
+
}) => (
|
|
16
|
+
<div data-testid="stream-message-input">
|
|
17
|
+
<Input />
|
|
18
|
+
</div>
|
|
19
|
+
),
|
|
20
|
+
SimpleAttachmentSelector: () => (
|
|
21
|
+
<div data-testid="simple-attachment-selector" />
|
|
22
|
+
),
|
|
23
|
+
TextareaComposer: ({
|
|
24
|
+
maxRows: _maxRows,
|
|
25
|
+
...props
|
|
26
|
+
}: React.TextareaHTMLAttributes<HTMLTextAreaElement> & { maxRows?: number }) => (
|
|
27
|
+
<textarea data-testid="textarea-composer" {...props} />
|
|
28
|
+
),
|
|
29
|
+
AttachmentPreviewList: () => <div data-testid="attachment-preview-list" />,
|
|
30
|
+
QuotedMessagePreview: () => <div data-testid="quoted-message-preview" />,
|
|
31
|
+
useChannelStateContext: () => ({
|
|
32
|
+
channel: { data: mockChannelData },
|
|
33
|
+
}),
|
|
34
|
+
useMessageInputContext: () => ({
|
|
35
|
+
handleSubmit: vi.fn(),
|
|
36
|
+
}),
|
|
37
|
+
useMessageComposerHasSendableData: () => false,
|
|
38
|
+
}))
|
|
39
|
+
|
|
40
|
+
vi.mock('../CustomLinkPreviewList', () => ({
|
|
41
|
+
CustomLinkPreviewList: () => <div data-testid="custom-link-preview-list" />,
|
|
42
|
+
}))
|
|
43
|
+
|
|
44
|
+
describe('CustomMessageInput', () => {
|
|
45
|
+
it('renders the interactive message input when channel is not frozen', () => {
|
|
46
|
+
mockChannelData = {}
|
|
47
|
+
|
|
48
|
+
const { container } = renderWithProviders(<CustomMessageInput />)
|
|
49
|
+
|
|
50
|
+
const messageInput = container.firstElementChild
|
|
51
|
+
expect(messageInput).not.toHaveAttribute('aria-disabled')
|
|
52
|
+
expect(messageInput).not.toHaveAttribute('inert')
|
|
53
|
+
expect(screen.getByTestId('stream-message-input')).toBeInTheDocument()
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('renders the frozen message input when channel is frozen', () => {
|
|
57
|
+
mockChannelData = { frozen: true }
|
|
58
|
+
|
|
59
|
+
const { container } = renderWithProviders(<CustomMessageInput />)
|
|
60
|
+
|
|
61
|
+
const messageInput = container.firstElementChild
|
|
62
|
+
expect(messageInput).toHaveAttribute('aria-disabled', 'true')
|
|
63
|
+
expect(messageInput).toHaveAttribute('inert')
|
|
64
|
+
expect(screen.getByTestId('stream-message-input')).toBeInTheDocument()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('makes the textarea read-only and disables send when channel is frozen', () => {
|
|
68
|
+
mockChannelData = { frozen: true }
|
|
69
|
+
|
|
70
|
+
renderWithProviders(<CustomMessageInput />)
|
|
71
|
+
|
|
72
|
+
const textarea = screen.getByTestId('textarea-composer')
|
|
73
|
+
expect(textarea).toHaveAttribute('aria-disabled', 'true')
|
|
74
|
+
expect(textarea).toHaveAttribute('readonly')
|
|
75
|
+
expect(textarea).toHaveAttribute('tabindex', '-1')
|
|
76
|
+
expect(textarea).not.toHaveAttribute('autofocus')
|
|
77
|
+
|
|
78
|
+
const sendButton = screen.getByRole('button', { name: /send/i })
|
|
79
|
+
expect(sendButton).toBeDisabled()
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('renders the existing attachment selector when channel is frozen', () => {
|
|
83
|
+
mockChannelData = { frozen: true }
|
|
84
|
+
|
|
85
|
+
renderWithProviders(<CustomMessageInput />)
|
|
86
|
+
|
|
87
|
+
expect(screen.getByTestId('simple-attachment-selector')).toBeInTheDocument()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('renders adjacent actions inside the disabled container when frozen', () => {
|
|
91
|
+
mockChannelData = { frozen: true }
|
|
92
|
+
|
|
93
|
+
const { container } = renderWithProviders(
|
|
94
|
+
<CustomMessageInput
|
|
95
|
+
renderActions={() => (
|
|
96
|
+
<button data-testid="custom-action" type="button">
|
|
97
|
+
Action
|
|
98
|
+
</button>
|
|
99
|
+
)}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
const messageInput = container.firstElementChild
|
|
104
|
+
const action = screen.getByTestId('custom-action')
|
|
105
|
+
|
|
106
|
+
expect(messageInput).toHaveAttribute('aria-disabled', 'true')
|
|
107
|
+
expect(messageInput?.contains(action)).toBe(true)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('renders adjacent actions in the interactive container when not frozen', () => {
|
|
111
|
+
mockChannelData = {}
|
|
112
|
+
|
|
113
|
+
const { container } = renderWithProviders(
|
|
114
|
+
<CustomMessageInput
|
|
115
|
+
renderActions={() => (
|
|
116
|
+
<button data-testid="custom-action" type="button">
|
|
117
|
+
Action
|
|
118
|
+
</button>
|
|
119
|
+
)}
|
|
120
|
+
/>
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
const messageInput = container.firstElementChild
|
|
124
|
+
expect(messageInput).not.toHaveAttribute('aria-disabled')
|
|
125
|
+
expect(screen.getByTestId('custom-action')).toBeInTheDocument()
|
|
126
|
+
})
|
|
127
|
+
})
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
QuotedMessagePreview,
|
|
7
7
|
SimpleAttachmentSelector,
|
|
8
8
|
TextareaComposer,
|
|
9
|
+
useChannelStateContext,
|
|
9
10
|
useMessageComposerHasSendableData,
|
|
10
11
|
useMessageInputContext,
|
|
11
12
|
} from 'stream-chat-react'
|
|
@@ -13,8 +14,11 @@ import {
|
|
|
13
14
|
import { CustomLinkPreviewList } from '../CustomLinkPreviewList'
|
|
14
15
|
|
|
15
16
|
const CustomMessageInputInner: React.FC = () => {
|
|
17
|
+
const { channel } = useChannelStateContext()
|
|
18
|
+
const isFrozen = channel?.data?.frozen === true
|
|
16
19
|
const { handleSubmit } = useMessageInputContext()
|
|
17
20
|
const hasSendableData = useMessageComposerHasSendableData()
|
|
21
|
+
const isSendDisabled = isFrozen || !hasSendableData
|
|
18
22
|
|
|
19
23
|
return (
|
|
20
24
|
<>
|
|
@@ -28,20 +32,23 @@ const CustomMessageInputInner: React.FC = () => {
|
|
|
28
32
|
<div className="flex">
|
|
29
33
|
<div className="w-full ml-2 mr-4 self-center leading-[0]">
|
|
30
34
|
<TextareaComposer
|
|
35
|
+
aria-disabled={isFrozen || undefined}
|
|
31
36
|
className="w-full resize-none outline-none leading-6"
|
|
32
37
|
// While this might usually be considered an anti-pattern, in most
|
|
33
38
|
// cases, when a message thread is rendered, we want the input to
|
|
34
39
|
// gain focus automatically.
|
|
35
40
|
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
36
|
-
autoFocus
|
|
41
|
+
autoFocus={!isFrozen}
|
|
37
42
|
maxRows={4}
|
|
43
|
+
readOnly={isFrozen}
|
|
44
|
+
tabIndex={isFrozen ? -1 : undefined}
|
|
38
45
|
/>
|
|
39
46
|
</div>
|
|
40
47
|
<button
|
|
41
48
|
aria-label="Send"
|
|
42
49
|
className="str-chat__send-button mt-auto flex justify-center items-center flex-shrink-0 rounded-full size-8 bg-[#121110] disabled:bg-[#F1F0EE] disabled:text-black/20 text-white focus-ring"
|
|
43
50
|
data-testid="send-button"
|
|
44
|
-
disabled={
|
|
51
|
+
disabled={isSendDisabled}
|
|
45
52
|
onClick={handleSubmit}
|
|
46
53
|
type="button"
|
|
47
54
|
>
|
|
@@ -59,9 +66,19 @@ export interface CustomMessageInputProps {
|
|
|
59
66
|
|
|
60
67
|
export const CustomMessageInput: React.FC<CustomMessageInputProps> = ({
|
|
61
68
|
renderActions,
|
|
62
|
-
}) =>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
}) => {
|
|
70
|
+
const { channel } = useChannelStateContext()
|
|
71
|
+
const isFrozen = channel?.data?.frozen === true
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
// @ts-expect-error Only React 19 onwards has `inert` in its types.
|
|
76
|
+
inert={isFrozen ? '' : undefined}
|
|
77
|
+
aria-disabled={isFrozen || undefined}
|
|
78
|
+
className="message-input flex items-center gap-2 p-4 aria-disabled:opacity-40"
|
|
79
|
+
>
|
|
80
|
+
{renderActions?.()}
|
|
81
|
+
<MessageInput Input={CustomMessageInputInner} />
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import type { Meta, StoryFn } from '@storybook/react'
|
|
2
|
-
import React from 'react'
|
|
2
|
+
import React, { useState } from 'react'
|
|
3
3
|
|
|
4
4
|
import LockedAttachment from '.'
|
|
5
5
|
|
|
6
6
|
const VIDEO_THUMBNAIL_BLURRED = '/video-thumbnail-blurred.jpg'
|
|
7
|
+
const VIDEO_THUMBNAIL = '/video-thumbnail.jpg'
|
|
7
8
|
const VIDEO_SOURCE = '/video-source.mp4'
|
|
8
9
|
|
|
9
10
|
const IMAGE_THUMBNAIL_BLURRED = '/image-thumbnail-blurred.jpg'
|
|
11
|
+
const IMAGE_THUMBNAIL = '/image-thumbnail.jpg'
|
|
10
12
|
const IMAGE_SOURCE = '/image-source.jpg'
|
|
11
13
|
|
|
14
|
+
const DOCUMENT_THUMBNAIL_BLURRED = '/document-thumbnail-blurred.jpg'
|
|
12
15
|
const DOCUMENT_THUMBNAIL = '/document-thumbnail.jpg'
|
|
13
16
|
const DOCUMENT_SOURCE = '/document-source.pdf'
|
|
14
17
|
|
|
18
|
+
const AUDIO_THUMBNAIL_BLURRED = '/audio-thumbnail-blurred.jpg'
|
|
15
19
|
const AUDIO_THUMBNAIL = '/audio-thumbnail.jpg'
|
|
16
20
|
const AUDIO_SOURCE = '/audio-source.mp3'
|
|
17
21
|
|
|
@@ -28,6 +32,7 @@ const VARIANTS = [
|
|
|
28
32
|
mimeType: 'video/mp4',
|
|
29
33
|
detail: '1:20',
|
|
30
34
|
thumbnailUrl: VIDEO_THUMBNAIL_BLURRED,
|
|
35
|
+
thumbnailUnlockedUrl: VIDEO_THUMBNAIL,
|
|
31
36
|
sourceUrl: VIDEO_SOURCE,
|
|
32
37
|
},
|
|
33
38
|
{
|
|
@@ -35,7 +40,8 @@ const VARIANTS = [
|
|
|
35
40
|
title: 'Morning Meditation',
|
|
36
41
|
mimeType: 'audio/mpeg',
|
|
37
42
|
detail: '4:35',
|
|
38
|
-
thumbnailUrl:
|
|
43
|
+
thumbnailUrl: AUDIO_THUMBNAIL_BLURRED,
|
|
44
|
+
thumbnailUnlockedUrl: AUDIO_THUMBNAIL,
|
|
39
45
|
sourceUrl: AUDIO_SOURCE,
|
|
40
46
|
},
|
|
41
47
|
{
|
|
@@ -44,6 +50,7 @@ const VARIANTS = [
|
|
|
44
50
|
mimeType: 'image/jpeg',
|
|
45
51
|
detail: '3.2 MB',
|
|
46
52
|
thumbnailUrl: IMAGE_THUMBNAIL_BLURRED,
|
|
53
|
+
thumbnailUnlockedUrl: IMAGE_THUMBNAIL,
|
|
47
54
|
sourceUrl: IMAGE_SOURCE,
|
|
48
55
|
},
|
|
49
56
|
{
|
|
@@ -51,15 +58,8 @@ const VARIANTS = [
|
|
|
51
58
|
title: 'Strength Training Guide',
|
|
52
59
|
mimeType: 'application/zip',
|
|
53
60
|
detail: '14 files',
|
|
54
|
-
thumbnailUrl:
|
|
55
|
-
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
label: 'Unknown',
|
|
59
|
-
title: 'Unknown Attachment',
|
|
60
|
-
mimeType: 'application/octet-stream',
|
|
61
|
-
detail: undefined,
|
|
62
|
-
thumbnailUrl: undefined,
|
|
61
|
+
thumbnailUrl: DOCUMENT_THUMBNAIL_BLURRED,
|
|
62
|
+
thumbnailUnlockedUrl: DOCUMENT_THUMBNAIL,
|
|
63
63
|
sourceUrl: DOCUMENT_SOURCE,
|
|
64
64
|
},
|
|
65
65
|
]
|
|
@@ -70,7 +70,9 @@ const Table = ({ children }: { children: React.ReactNode }) => (
|
|
|
70
70
|
</div>
|
|
71
71
|
)
|
|
72
72
|
|
|
73
|
-
const TableHead = ({
|
|
73
|
+
const TableHead = ({
|
|
74
|
+
variants,
|
|
75
|
+
}: {
|
|
74
76
|
variants: { label: string; mimeType: string }[]
|
|
75
77
|
}) => (
|
|
76
78
|
<thead>
|
|
@@ -88,69 +90,105 @@ const TableHead = ({ variants, }: {
|
|
|
88
90
|
</thead>
|
|
89
91
|
)
|
|
90
92
|
|
|
91
|
-
export const Visitor: StoryFn = () =>
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<LockedAttachment.Visitor
|
|
102
|
-
title={title}
|
|
103
|
-
amountText="AU$9.99"
|
|
104
|
-
thumbnailUrl={thumbnailUrl}
|
|
105
|
-
mimeType={mimeType}
|
|
106
|
-
detail={detail}
|
|
107
|
-
onUnlockClick={() => {}}
|
|
108
|
-
onDownloadClick={() => {}}
|
|
109
|
-
/>
|
|
93
|
+
export const Visitor: StoryFn = () => {
|
|
94
|
+
const [isPaid, setPaid] = useState<string | undefined>()
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<Table>
|
|
98
|
+
<TableHead variants={VARIANTS} />
|
|
99
|
+
<tbody>
|
|
100
|
+
<tr>
|
|
101
|
+
<td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
|
|
102
|
+
Locked
|
|
110
103
|
</td>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
104
|
+
{VARIANTS.map(
|
|
105
|
+
({
|
|
106
|
+
title,
|
|
107
|
+
mimeType,
|
|
108
|
+
detail,
|
|
109
|
+
thumbnailUrl,
|
|
110
|
+
thumbnailUnlockedUrl,
|
|
111
|
+
sourceUrl,
|
|
112
|
+
}) => (
|
|
113
|
+
<td key={mimeType} className="align-top">
|
|
114
|
+
<LockedAttachment.Visitor
|
|
115
|
+
title={title}
|
|
116
|
+
thumbnailUrl={thumbnailUrl}
|
|
117
|
+
mimeType={mimeType}
|
|
118
|
+
detail={detail}
|
|
119
|
+
paymentStatus={isPaid === mimeType ? 'paid' : undefined}
|
|
120
|
+
amountText="AU$9.99"
|
|
121
|
+
onUnlockClick={() => setPaid(mimeType)}
|
|
122
|
+
onDownloadClick={() => alert('Download clicked')}
|
|
123
|
+
onFetchSource={async () => {
|
|
124
|
+
return Promise.resolve({
|
|
125
|
+
sourceUrl: sourceUrl,
|
|
126
|
+
thumbnailUrl: thumbnailUnlockedUrl,
|
|
127
|
+
})
|
|
128
|
+
}}
|
|
129
|
+
/>
|
|
130
|
+
</td>
|
|
131
|
+
)
|
|
132
|
+
)}
|
|
133
|
+
</tr>
|
|
134
|
+
<tr>
|
|
135
|
+
<td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
|
|
136
|
+
Purchased
|
|
129
137
|
</td>
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
138
|
+
{VARIANTS.map(({ title, mimeType, detail, thumbnailUrl }) => (
|
|
139
|
+
<td key={mimeType} className="align-top">
|
|
140
|
+
<LockedAttachment.Visitor
|
|
141
|
+
title={title}
|
|
142
|
+
thumbnailUrl={thumbnailUrl}
|
|
143
|
+
mimeType={mimeType}
|
|
144
|
+
detail={detail}
|
|
145
|
+
amountText="AU$9.99"
|
|
146
|
+
paymentStatus="paid"
|
|
147
|
+
onUnlockClick={() => alert('Unlock clicked')}
|
|
148
|
+
onDownloadClick={() => alert('Download clicked')}
|
|
149
|
+
/>
|
|
150
|
+
</td>
|
|
151
|
+
))}
|
|
152
|
+
</tr>
|
|
153
|
+
<tr>
|
|
154
|
+
<td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
|
|
155
|
+
Unlocked
|
|
148
156
|
</td>
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
{VARIANTS.map(
|
|
158
|
+
({
|
|
159
|
+
title,
|
|
160
|
+
mimeType,
|
|
161
|
+
detail,
|
|
162
|
+
thumbnailUrl,
|
|
163
|
+
thumbnailUnlockedUrl,
|
|
164
|
+
sourceUrl,
|
|
165
|
+
}) => (
|
|
166
|
+
<td key={mimeType} className="align-top">
|
|
167
|
+
<LockedAttachment.Visitor
|
|
168
|
+
title={title}
|
|
169
|
+
thumbnailUrl={thumbnailUrl}
|
|
170
|
+
mimeType={mimeType}
|
|
171
|
+
detail={detail}
|
|
172
|
+
amountText="AU$9.99"
|
|
173
|
+
paymentStatus="paid"
|
|
174
|
+
onUnlockClick={() => console.log('Unlock clicked')}
|
|
175
|
+
onDownloadClick={() => alert('Download clicked')}
|
|
176
|
+
onFetchSource={async () => {
|
|
177
|
+
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
178
|
+
return Promise.resolve({
|
|
179
|
+
sourceUrl: sourceUrl,
|
|
180
|
+
thumbnailUrl: thumbnailUnlockedUrl,
|
|
181
|
+
})
|
|
182
|
+
}}
|
|
183
|
+
/>
|
|
184
|
+
</td>
|
|
185
|
+
)
|
|
186
|
+
)}
|
|
187
|
+
</tr>
|
|
188
|
+
</tbody>
|
|
189
|
+
</Table>
|
|
190
|
+
)
|
|
191
|
+
}
|
|
154
192
|
|
|
155
193
|
export const Creator: StoryFn = () => (
|
|
156
194
|
<Table>
|
|
@@ -160,30 +198,39 @@ export const Creator: StoryFn = () => (
|
|
|
160
198
|
<td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
|
|
161
199
|
Preview
|
|
162
200
|
</td>
|
|
163
|
-
{VARIANTS.map(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
201
|
+
{VARIANTS.map(
|
|
202
|
+
({
|
|
203
|
+
mimeType,
|
|
204
|
+
detail,
|
|
205
|
+
thumbnailUrl,
|
|
206
|
+
thumbnailUnlockedUrl,
|
|
207
|
+
sourceUrl,
|
|
208
|
+
}) => (
|
|
209
|
+
<td key={mimeType} className="align-top">
|
|
210
|
+
<LockedAttachment.Creator
|
|
211
|
+
placeholderTitle="Attachment title"
|
|
212
|
+
placeholderAmountText="AU$0.00"
|
|
213
|
+
thumbnailUrl={thumbnailUrl}
|
|
214
|
+
mimeType={mimeType}
|
|
215
|
+
detail={detail}
|
|
216
|
+
onPreviewClick={() => ({
|
|
217
|
+
sourceUrl: sourceUrl,
|
|
218
|
+
thumbnailUrl: thumbnailUnlockedUrl,
|
|
219
|
+
})}
|
|
220
|
+
/>
|
|
221
|
+
</td>
|
|
222
|
+
)
|
|
223
|
+
)}
|
|
176
224
|
</tr>
|
|
177
225
|
<tr>
|
|
178
226
|
<td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
|
|
179
227
|
Pending
|
|
180
228
|
</td>
|
|
181
|
-
{VARIANTS.map(({ title, mimeType, detail, thumbnailUrl
|
|
229
|
+
{VARIANTS.map(({ title, mimeType, detail, thumbnailUrl }) => (
|
|
182
230
|
<td key={mimeType} className="align-top">
|
|
183
231
|
<LockedAttachment.Creator
|
|
184
232
|
title={title}
|
|
185
233
|
thumbnailUrl={thumbnailUrl}
|
|
186
|
-
sourceUrl={sourceUrl}
|
|
187
234
|
mimeType={mimeType}
|
|
188
235
|
detail={detail}
|
|
189
236
|
amountText="AU$9.99"
|
|
@@ -196,16 +243,14 @@ export const Creator: StoryFn = () => (
|
|
|
196
243
|
<td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
|
|
197
244
|
Sent
|
|
198
245
|
</td>
|
|
199
|
-
{VARIANTS.map(({ title, mimeType, detail, thumbnailUrl
|
|
246
|
+
{VARIANTS.map(({ title, mimeType, detail, thumbnailUrl }) => (
|
|
200
247
|
<td key={mimeType} className="align-top">
|
|
201
248
|
<LockedAttachment.Creator
|
|
202
249
|
title={title}
|
|
203
250
|
thumbnailUrl={thumbnailUrl}
|
|
204
|
-
sourceUrl={sourceUrl}
|
|
205
251
|
mimeType={mimeType}
|
|
206
252
|
detail={detail}
|
|
207
253
|
amountText="AU$9.99"
|
|
208
|
-
onDismiss={undefined}
|
|
209
254
|
/>
|
|
210
255
|
</td>
|
|
211
256
|
))}
|
|
@@ -214,17 +259,15 @@ export const Creator: StoryFn = () => (
|
|
|
214
259
|
<td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
|
|
215
260
|
Sold
|
|
216
261
|
</td>
|
|
217
|
-
{VARIANTS.map(({ title, mimeType, detail, thumbnailUrl
|
|
262
|
+
{VARIANTS.map(({ title, mimeType, detail, thumbnailUrl }) => (
|
|
218
263
|
<td key={mimeType} className="align-top">
|
|
219
264
|
<LockedAttachment.Creator
|
|
220
265
|
title={title}
|
|
221
266
|
thumbnailUrl={thumbnailUrl}
|
|
222
|
-
sourceUrl={sourceUrl}
|
|
223
267
|
mimeType={mimeType}
|
|
224
268
|
detail={detail}
|
|
225
269
|
amountText="AU$9.99"
|
|
226
270
|
paymentStatus="paid"
|
|
227
|
-
onDismiss={undefined}
|
|
228
271
|
/>
|
|
229
272
|
</td>
|
|
230
273
|
))}
|