@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.
Files changed (33) hide show
  1. package/dist/Card-1CQEn-OT.js +171 -0
  2. package/dist/Card-1CQEn-OT.js.map +1 -0
  3. package/dist/Card-ClE_iExA.js +177 -0
  4. package/dist/Card-ClE_iExA.js.map +1 -0
  5. package/dist/{MediaPlayer-BCsdmsON.js → MediaPlayer-B9Ws2NeE.js} +115 -135
  6. package/dist/MediaPlayer-B9Ws2NeE.js.map +1 -0
  7. package/dist/index.d.ts +3 -2
  8. package/dist/index.js +79 -63
  9. package/dist/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/components/ChannelView.stories.tsx +38 -7
  12. package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +127 -0
  13. package/src/components/CustomMessageInput/index.tsx +25 -8
  14. package/src/components/LockedAttachment/LockedAttachment.stories.tsx +136 -93
  15. package/src/components/LockedAttachment/components/Creator/Card.tsx +106 -106
  16. package/src/components/LockedAttachment/components/Creator/CardThumbnail.tsx +114 -0
  17. package/src/components/LockedAttachment/components/MediaPlayer.tsx +80 -66
  18. package/src/components/LockedAttachment/components/Visitor/Card.tsx +53 -78
  19. package/src/components/LockedAttachment/components/Visitor/CardActions.tsx +3 -3
  20. package/src/components/LockedAttachment/components/Visitor/CardThumbnail.tsx +81 -0
  21. package/src/components/LockedAttachment/types.ts +2 -0
  22. package/dist/Card-C5t3dZ5q.js +0 -350
  23. package/dist/Card-C5t3dZ5q.js.map +0 -1
  24. package/dist/Card-Cn2va-Qr.js +0 -205
  25. package/dist/Card-Cn2va-Qr.js.map +0 -1
  26. package/dist/MediaPlayer-BCsdmsON.js.map +0 -1
  27. package/src/components/LockedAttachment/components/Creator/CardAudioPreview.tsx +0 -161
  28. package/src/components/LockedAttachment/components/Creator/CardCollapsedThumbnail.tsx +0 -58
  29. package/src/components/LockedAttachment/components/Creator/CardImagePreview.tsx +0 -56
  30. package/src/components/LockedAttachment/components/Creator/CardVideoPreview.tsx +0 -91
  31. package/src/components/LockedAttachment/components/Visitor/CardImagePreview.tsx +0 -39
  32. package/src/components/LockedAttachment/components/Visitor/CardMediaPreview.tsx +0 -36
  33. package/src/components/LockedAttachment/components/Visitor/CardThumbnailPreview.tsx +0 -45
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "1.31.0",
3
+ "version": "1.32.1-rc-1777007852",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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 & { followerStatus?: string | boolean }
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((mockChannel) => {
175
- setChannel(mockChannel)
176
- })
177
- }, [client, followerStatus])
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={!hasSendableData}
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
- <div className="message-input flex items-center gap-2 p-4">
64
- {renderActions && renderActions?.()}
65
- <MessageInput Input={CustomMessageInputInner} />
66
- </div>
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: AUDIO_THUMBNAIL,
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: DOCUMENT_THUMBNAIL,
55
- sourceUrl: DOCUMENT_SOURCE,
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 = ({ variants, }: {
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
- <Table>
93
- <TableHead variants={VARIANTS} />
94
- <tbody>
95
- <tr>
96
- <td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
97
- Locked
98
- </td>
99
- {VARIANTS.map(({ title, mimeType, detail, thumbnailUrl }) => (
100
- <td key={mimeType} className="align-top">
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
- </tr>
113
- <tr>
114
- <td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
115
- Purchased
116
- </td>
117
- {VARIANTS.map(({ title, mimeType, detail, thumbnailUrl }) => (
118
- <td key={mimeType} className="align-top">
119
- <LockedAttachment.Visitor
120
- title={title}
121
- amountText="AU$9.99"
122
- thumbnailUrl={thumbnailUrl}
123
- mimeType={mimeType}
124
- detail={detail}
125
- paymentStatus="paid"
126
- onUnlockClick={() => {}}
127
- onDownloadClick={() => {}}
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
- </tr>
132
- <tr>
133
- <td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
134
- Unlocked
135
- </td>
136
- {VARIANTS.map(({ title, mimeType, detail, thumbnailUrl, sourceUrl }) => (
137
- <td key={mimeType} className="align-top">
138
- <LockedAttachment.Visitor
139
- title={title}
140
- thumbnailUrl={thumbnailUrl}
141
- mimeType={mimeType}
142
- detail={detail}
143
- amountText="AU$9.99"
144
- paymentStatus="paid"
145
- onUnlockClick={() => Promise.resolve({ sourceUrl })}
146
- onDownloadClick={() => {}}
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
- </tr>
151
- </tbody>
152
- </Table>
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(({ mimeType, detail, thumbnailUrl, sourceUrl }) => (
164
- <td key={mimeType} className="align-top">
165
- <LockedAttachment.Creator
166
- isPreview={true}
167
- thumbnailUrl={thumbnailUrl}
168
- sourceUrl={sourceUrl}
169
- mimeType={mimeType}
170
- detail={detail}
171
- placeholderAmountText="A$0.00"
172
- onDismiss={undefined}
173
- />
174
- </td>
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, sourceUrl }) => (
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, sourceUrl }) => (
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, sourceUrl }) => (
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
  ))}