@linktr.ee/messaging-react 3.4.2-rc-1782453771 → 3.4.2-rc-1782480798
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-ql9pImRa.js → Card-BKi2g6x-.js} +2 -2
- package/dist/{Card-ql9pImRa.js.map → Card-BKi2g6x-.js.map} +1 -1
- package/dist/{Card-BIa-47Ne.cjs → Card-BMmrCMqJ.cjs} +2 -2
- package/dist/{Card-BIa-47Ne.cjs.map → Card-BMmrCMqJ.cjs.map} +1 -1
- package/dist/{Card-BaXLsSK2.js → Card-BYu6OBuX.js} +2 -2
- package/dist/{Card-BaXLsSK2.js.map → Card-BYu6OBuX.js.map} +1 -1
- package/dist/{Card-BkVj6kGN.cjs → Card-DtIjtWy6.cjs} +2 -2
- package/dist/{Card-BkVj6kGN.cjs.map → Card-DtIjtWy6.cjs.map} +1 -1
- package/dist/{Card-52LnCirC.js → Card-DvE5BCPf.js} +3 -3
- package/dist/{Card-52LnCirC.js.map → Card-DvE5BCPf.js.map} +1 -1
- package/dist/{Card-CcTyYY9N.cjs → Card-VO-i6CuV.cjs} +2 -2
- package/dist/{Card-CcTyYY9N.cjs.map → Card-VO-i6CuV.cjs.map} +1 -1
- package/dist/{LockedThumbnail-D0ASm7LP.cjs → LockedThumbnail-Cl8uwCxM.cjs} +2 -2
- package/dist/{LockedThumbnail-D0ASm7LP.cjs.map → LockedThumbnail-Cl8uwCxM.cjs.map} +1 -1
- package/dist/{LockedThumbnail-C3YOnS-o.js → LockedThumbnail-DTkd_kEt.js} +2 -2
- package/dist/{LockedThumbnail-C3YOnS-o.js.map → LockedThumbnail-DTkd_kEt.js.map} +1 -1
- package/dist/index-CSSe9eu7.cjs +2 -0
- package/dist/index-CSSe9eu7.cjs.map +1 -0
- package/dist/{index-CbWEp3Zs.js → index-IzhF38yj.js} +3447 -3212
- package/dist/index-IzhF38yj.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +25 -13
- package/dist/index.js +14 -13
- package/package.json +2 -2
- package/src/components/ChannelList/CustomChannelPreview.stories.tsx +0 -63
- package/src/components/ChannelList/CustomChannelPreview.test.tsx +8 -58
- package/src/components/ChannelList/CustomChannelPreview.tsx +10 -7
- package/src/components/ChannelView.stories.tsx +7 -38
- package/src/components/ChannelView.test.tsx +15 -29
- package/src/components/ChannelView.tsx +9 -19
- package/src/components/CustomMessage/StreamAttachmentMessage.test.tsx +109 -0
- package/src/components/CustomMessage/StreamAttachmentMessage.tsx +408 -0
- package/src/components/CustomMessage/index.tsx +42 -0
- package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +34 -0
- package/src/components/CustomMessageInput/index.tsx +23 -1
- package/src/components/MessagingShell/index.tsx +2 -0
- package/src/hooks/useChannelStar.ts +6 -9
- package/src/index.ts +1 -0
- package/src/stream-custom-data.ts +1 -16
- package/src/types.ts +18 -0
- package/dist/index-CbWEp3Zs.js.map +0 -1
- package/dist/index-DkqM2z_j.cjs +0 -2
- package/dist/index-DkqM2z_j.cjs.map +0 -1
- package/src/components/ParticipantBadges.tsx +0 -39
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-CSSe9eu7.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.ts
CHANGED
|
@@ -149,7 +149,7 @@ export declare const ChannelView: default_2.NamedExoticComponent<ChannelViewProp
|
|
|
149
149
|
* Props that MessagingShell passes through to ChannelView.
|
|
150
150
|
* ChannelViewProps is the source of truth for these props.
|
|
151
151
|
*/
|
|
152
|
-
declare type ChannelViewPassthroughProps = Pick<ChannelViewProps, 'renderMessageInputActions' | 'renderConversationFooter' | 'CustomChannelEmptyState' | 'onBlockParticipantClick' | 'onReportParticipantClick' | 'dmAgentEnabled' | 'onMessageSent' | 'chatbotVotingEnabled' | 'viewerLanguage' | 'renderHeaderTitleBadges' | 'renderChannelBanner' | 'customChannelActions' | 'renderChannelActions' | 'onParticipantNameClick' | 'renderMessage' | 'onMessageLinkClick' | 'showChannelInfo'>;
|
|
152
|
+
declare type ChannelViewPassthroughProps = Pick<ChannelViewProps, 'renderMessageInputActions' | 'renderConversationFooter' | 'CustomChannelEmptyState' | 'onBlockParticipantClick' | 'onReportParticipantClick' | 'dmAgentEnabled' | 'onMessageSent' | 'chatbotVotingEnabled' | 'viewerLanguage' | 'renderHeaderTitleBadges' | 'renderChannelBanner' | 'customChannelActions' | 'renderChannelActions' | 'onParticipantNameClick' | 'renderMessage' | 'onMessageLinkClick' | 'showChannelInfo' | 'composerInput'>;
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
155
|
* ChannelView component props
|
|
@@ -351,6 +351,22 @@ export declare interface ChannelViewProps {
|
|
|
351
351
|
* Use this to render staged paid or media attachments inside the input.
|
|
352
352
|
*/
|
|
353
353
|
attachmentPreviewList?: ComponentType;
|
|
354
|
+
/**
|
|
355
|
+
* Replace the entire inner composer — the textarea + send arrangement — with
|
|
356
|
+
* a host-owned component. Passed to Stream's `<MessageInput>` as the `Input`
|
|
357
|
+
* component, so it runs inside the message-input context and reuses the
|
|
358
|
+
* library's send pipeline (`doSendMessageRequest`, message metadata, DM-agent
|
|
359
|
+
* suppression), attachments, and previews via the Stream hooks
|
|
360
|
+
* (`useMessageInputContext`, `useMessageComposerHasSendableData`,
|
|
361
|
+
* `TextareaComposer`, …). Use it when a surface needs a different composer
|
|
362
|
+
* layout (e.g. a full-width textarea above a toolbar row) than the default.
|
|
363
|
+
*
|
|
364
|
+
* The outer wrapper — frozen handling and the `renderMessageInputActions` /
|
|
365
|
+
* `renderMessageInputFooter` slots — is unchanged. Read the exported
|
|
366
|
+
* `useComposerLocked()` hook to honour the frozen state. Defaults to the
|
|
367
|
+
* built-in composer when omitted.
|
|
368
|
+
*/
|
|
369
|
+
composerInput?: ComponentType;
|
|
354
370
|
/**
|
|
355
371
|
* Fired when the participant's name in the channel header is clicked. When
|
|
356
372
|
* provided, the name renders as a button with a trailing caret (an affordance
|
|
@@ -1376,6 +1392,14 @@ export declare interface SentCardProps extends LockedAttachmentBaseProps {
|
|
|
1376
1392
|
onFetchSource?: () => Promise<LockedAttachmentSource | void>;
|
|
1377
1393
|
}
|
|
1378
1394
|
|
|
1395
|
+
/**
|
|
1396
|
+
* Read the composer's locked (frozen-channel) state from inside a custom
|
|
1397
|
+
* composer supplied via `composerInput`. Returns true when the channel is
|
|
1398
|
+
* frozen; mirror the default composer by rendering the textarea read-only and
|
|
1399
|
+
* disabling the send control.
|
|
1400
|
+
*/
|
|
1401
|
+
export declare const useComposerLocked: () => boolean;
|
|
1402
|
+
|
|
1379
1403
|
export declare function useCustomMessage<K extends keyof CustomMessageRegistry>(key: K): CustomMessageRegistry[K];
|
|
1380
1404
|
|
|
1381
1405
|
/**
|
|
@@ -1471,13 +1495,6 @@ declare module 'stream-chat' {
|
|
|
1471
1495
|
*/
|
|
1472
1496
|
chatbot_paused?: boolean;
|
|
1473
1497
|
}
|
|
1474
|
-
interface CustomMemberData {
|
|
1475
|
-
/**
|
|
1476
|
-
* Whether the member should be identified as a customer in participant UI.
|
|
1477
|
-
* Stored on the channel member so it is scoped to this conversation.
|
|
1478
|
-
*/
|
|
1479
|
-
customer?: boolean;
|
|
1480
|
-
}
|
|
1481
1498
|
interface CustomMessageData {
|
|
1482
1499
|
/**
|
|
1483
1500
|
* When true, hides the date timestamp in system messages.
|
|
@@ -1495,10 +1512,5 @@ declare module 'stream-chat' {
|
|
|
1495
1512
|
*/
|
|
1496
1513
|
dm_agent_system_type?: DmAgentSystemType;
|
|
1497
1514
|
}
|
|
1498
|
-
interface CustomUserData {
|
|
1499
|
-
is_account?: boolean;
|
|
1500
|
-
is_follower?: boolean;
|
|
1501
|
-
username?: string;
|
|
1502
|
-
}
|
|
1503
1515
|
}
|
|
1504
1516
|
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { a as e, b as t, C as i, c as
|
|
1
|
+
import { a as e, b as t, C as i, c as o, d as n, e as m, F as g, f as r, L as l, h as M, M as u, i as L, j as c, k as h, l as d, m as p, n as C, o as v, p as A, q as k, s as F, t as b, u as f, v as x, w as y, x as P, y as S, z as q, B as z, D as B, E as D } from "./index-IzhF38yj.js";
|
|
2
2
|
export {
|
|
3
3
|
e as ActionButton,
|
|
4
4
|
t as Avatar,
|
|
5
5
|
i as ChannelEmptyState,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
o as ChannelList,
|
|
7
|
+
n as ChannelView,
|
|
8
8
|
m as CustomMessageProvider,
|
|
9
9
|
g as FaqList,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
r as FaqListItem,
|
|
11
|
+
l as LinkAttachment,
|
|
12
12
|
M as LockedAttachment,
|
|
13
13
|
u as MediaMessage,
|
|
14
14
|
L as MessageAttachment,
|
|
@@ -16,19 +16,20 @@ export {
|
|
|
16
16
|
h as MessagingProvider,
|
|
17
17
|
d as MessagingShell,
|
|
18
18
|
p as buildCompactMetaLabel,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
C as formatFileSize,
|
|
20
|
+
v as formatRelativeTime,
|
|
21
|
+
A as getFileExtensionLabel,
|
|
22
|
+
k as getMessageDisplayText,
|
|
23
|
+
F as isLinkAttachment,
|
|
24
24
|
b as isUuidLike,
|
|
25
25
|
f as messageAttachmentGroupPositionFromStream,
|
|
26
26
|
x as normalizeLanguageCode,
|
|
27
27
|
y as resolveLinkAttachment,
|
|
28
28
|
P as resolveMediaFromMessage,
|
|
29
29
|
S as resolveParticipantDisplayName,
|
|
30
|
-
q as
|
|
31
|
-
z as
|
|
32
|
-
B as
|
|
30
|
+
q as useComposerLocked,
|
|
31
|
+
z as useCustomMessage,
|
|
32
|
+
B as useMessageVote,
|
|
33
|
+
D as useMessaging
|
|
33
34
|
};
|
|
34
35
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linktr.ee/messaging-react",
|
|
3
|
-
"version": "3.4.2-rc-
|
|
3
|
+
"version": "3.4.2-rc-1782480798",
|
|
4
4
|
"description": "React messaging components built on messaging-core for web applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@linktr.ee/component-library": "11.8.6",
|
|
41
|
-
"@linktr.ee/messaging-core": "2.3.0-rc-
|
|
41
|
+
"@linktr.ee/messaging-core": "2.3.0-rc-1782480798",
|
|
42
42
|
"@phosphor-icons/react": "^2.1.10"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
@@ -55,8 +55,6 @@ const createMockChannel = (options: {
|
|
|
55
55
|
thumb_url?: string
|
|
56
56
|
}>
|
|
57
57
|
lastMessageMetadata?: CustomMessageData['metadata']
|
|
58
|
-
isCustomer?: boolean
|
|
59
|
-
isStarred?: boolean
|
|
60
58
|
}): Channel => {
|
|
61
59
|
const {
|
|
62
60
|
id,
|
|
@@ -68,8 +66,6 @@ const createMockChannel = (options: {
|
|
|
68
66
|
unreadCount = 0,
|
|
69
67
|
lastMessageAttachments,
|
|
70
68
|
lastMessageMetadata,
|
|
71
|
-
isCustomer = false,
|
|
72
|
-
isStarred = false,
|
|
73
69
|
} = options
|
|
74
70
|
|
|
75
71
|
const eventListeners = new Map<string, Set<(...args: unknown[]) => void>>()
|
|
@@ -93,12 +89,8 @@ const createMockChannel = (options: {
|
|
|
93
89
|
image: participantImage,
|
|
94
90
|
},
|
|
95
91
|
user_id: participantId,
|
|
96
|
-
...(isCustomer ? { customer: true } : {}),
|
|
97
92
|
},
|
|
98
93
|
},
|
|
99
|
-
membership: {
|
|
100
|
-
pinned_at: isStarred ? now().toISOString() : null,
|
|
101
|
-
},
|
|
102
94
|
messages:
|
|
103
95
|
lastMessageText || lastMessageAttachments || lastMessageMetadata
|
|
104
96
|
? ([
|
|
@@ -257,61 +249,6 @@ ChatbotMessage.args = {
|
|
|
257
249
|
}),
|
|
258
250
|
}
|
|
259
251
|
|
|
260
|
-
export const ParticipantBadges: StoryFn = () => {
|
|
261
|
-
const channels = [
|
|
262
|
-
createMockChannel({
|
|
263
|
-
id: 'channel-customer',
|
|
264
|
-
participantName: 'Alice Customer',
|
|
265
|
-
participantId: 'participant-customer',
|
|
266
|
-
participantImage: 'https://i.pravatar.cc/150?img=40',
|
|
267
|
-
lastMessageText: 'I bought this from your Linktree',
|
|
268
|
-
lastMessageTime: minutesAgo(2),
|
|
269
|
-
isCustomer: true,
|
|
270
|
-
}),
|
|
271
|
-
createMockChannel({
|
|
272
|
-
id: 'channel-starred',
|
|
273
|
-
participantName: 'Bob Starred',
|
|
274
|
-
participantId: 'participant-starred',
|
|
275
|
-
participantImage: 'https://i.pravatar.cc/150?img=41',
|
|
276
|
-
lastMessageText: 'Following up on this thread',
|
|
277
|
-
lastMessageTime: minutesAgo(8),
|
|
278
|
-
isStarred: true,
|
|
279
|
-
}),
|
|
280
|
-
createMockChannel({
|
|
281
|
-
id: 'channel-customer-starred',
|
|
282
|
-
participantName: 'Carol Customer',
|
|
283
|
-
participantId: 'participant-customer-starred',
|
|
284
|
-
participantImage: 'https://i.pravatar.cc/150?img=42',
|
|
285
|
-
lastMessageText: 'Thanks for the quick reply',
|
|
286
|
-
lastMessageTime: minutesAgo(15),
|
|
287
|
-
isCustomer: true,
|
|
288
|
-
isStarred: true,
|
|
289
|
-
}),
|
|
290
|
-
]
|
|
291
|
-
|
|
292
|
-
return (
|
|
293
|
-
<div className="w-[360px] bg-chalk border border-sand rounded-lg overflow-hidden">
|
|
294
|
-
{channels.map((channel) => (
|
|
295
|
-
<CustomChannelPreview
|
|
296
|
-
key={channel.id}
|
|
297
|
-
channel={channel}
|
|
298
|
-
onChannelSelect={(channel) => {
|
|
299
|
-
console.log('Channel selected:', channel.id)
|
|
300
|
-
}}
|
|
301
|
-
/>
|
|
302
|
-
))}
|
|
303
|
-
</div>
|
|
304
|
-
)
|
|
305
|
-
}
|
|
306
|
-
ParticipantBadges.parameters = {
|
|
307
|
-
docs: {
|
|
308
|
-
description: {
|
|
309
|
-
story:
|
|
310
|
-
'Shows the built-in customer badge from participant.member customer data and the starred badge from the current user membership pinned_at value.',
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
}
|
|
314
|
-
|
|
315
252
|
export const TipMessage: StoryFn<ComponentProps> = Template.bind({})
|
|
316
253
|
TipMessage.args = {
|
|
317
254
|
channel: createMockChannel({
|
|
@@ -12,15 +12,12 @@ const mockUser = {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
type MockChannel = Channel & {
|
|
15
|
-
emitMemberUpdated: (member?: {
|
|
16
|
-
pinned_at?: string | null
|
|
17
|
-
user_id?: string
|
|
18
|
-
}) => void
|
|
15
|
+
emitMemberUpdated: (member?: { pinned_at?: string | null }) => void
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
const createMockChannel = (messages: Partial<LocalMessage>[]): MockChannel => {
|
|
22
19
|
const memberUpdatedListeners = new Set<
|
|
23
|
-
(event: { member?: { pinned_at?: string | null
|
|
20
|
+
(event: { member?: { pinned_at?: string | null } }) => void
|
|
24
21
|
>()
|
|
25
22
|
|
|
26
23
|
return {
|
|
@@ -41,34 +38,24 @@ const createMockChannel = (messages: Partial<LocalMessage>[]): MockChannel => {
|
|
|
41
38
|
on: vi.fn(
|
|
42
39
|
(
|
|
43
40
|
eventName: string,
|
|
44
|
-
listener: (event: {
|
|
45
|
-
member?: { pinned_at?: string | null; user_id?: string }
|
|
46
|
-
}) => void
|
|
41
|
+
listener: (event: { member?: { pinned_at?: string | null } }) => void
|
|
47
42
|
) => {
|
|
48
43
|
if (eventName === 'member.updated') {
|
|
49
44
|
memberUpdatedListeners.add(listener)
|
|
50
45
|
}
|
|
51
|
-
return {
|
|
52
|
-
unsubscribe: () => memberUpdatedListeners.delete(listener),
|
|
53
|
-
}
|
|
54
46
|
}
|
|
55
47
|
),
|
|
56
48
|
off: vi.fn(
|
|
57
49
|
(
|
|
58
50
|
eventName: string,
|
|
59
|
-
listener: (event: {
|
|
60
|
-
member?: { pinned_at?: string | null; user_id?: string }
|
|
61
|
-
}) => void
|
|
51
|
+
listener: (event: { member?: { pinned_at?: string | null } }) => void
|
|
62
52
|
) => {
|
|
63
53
|
if (eventName === 'member.updated') {
|
|
64
54
|
memberUpdatedListeners.delete(listener)
|
|
65
55
|
}
|
|
66
56
|
}
|
|
67
57
|
),
|
|
68
|
-
emitMemberUpdated: (member?: {
|
|
69
|
-
pinned_at?: string | null
|
|
70
|
-
user_id?: string
|
|
71
|
-
}) => {
|
|
58
|
+
emitMemberUpdated: (member?: { pinned_at?: string | null }) => {
|
|
72
59
|
memberUpdatedListeners.forEach((listener) => listener({ member }))
|
|
73
60
|
},
|
|
74
61
|
} as unknown as MockChannel
|
|
@@ -266,21 +253,6 @@ describe('CustomChannelPreview', () => {
|
|
|
266
253
|
expect(screen.getByText('No messages yet')).toBeInTheDocument()
|
|
267
254
|
})
|
|
268
255
|
|
|
269
|
-
it('shows a customer badge from participant member data', () => {
|
|
270
|
-
const channel = createMockChannel([])
|
|
271
|
-
channel.state.members['participant-1'] = {
|
|
272
|
-
user: { id: 'participant-1', name: 'Alice' },
|
|
273
|
-
user_id: 'participant-1',
|
|
274
|
-
customer: true,
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
renderWithProviders(
|
|
278
|
-
<CustomChannelPreview {...defaultProps} channel={channel} />
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
expect(screen.getByRole('img', { name: 'Customer' })).toBeInTheDocument()
|
|
282
|
-
})
|
|
283
|
-
|
|
284
256
|
it('updates starred state when the channel membership changes', () => {
|
|
285
257
|
const channel = createMockChannel([])
|
|
286
258
|
|
|
@@ -289,37 +261,15 @@ describe('CustomChannelPreview', () => {
|
|
|
289
261
|
)
|
|
290
262
|
|
|
291
263
|
expect(
|
|
292
|
-
screen.queryByRole('
|
|
264
|
+
screen.queryByRole('heading', { name: /starred conversation/i })
|
|
293
265
|
).not.toBeInTheDocument()
|
|
294
266
|
|
|
295
267
|
act(() => {
|
|
296
|
-
channel.emitMemberUpdated({
|
|
297
|
-
pinned_at: new Date().toISOString(),
|
|
298
|
-
user_id: mockUser.id,
|
|
299
|
-
})
|
|
268
|
+
channel.emitMemberUpdated({ pinned_at: new Date().toISOString() })
|
|
300
269
|
})
|
|
301
270
|
|
|
302
271
|
expect(
|
|
303
|
-
screen.getByRole('
|
|
272
|
+
screen.getByRole('heading', { name: /starred conversation/i })
|
|
304
273
|
).toBeInTheDocument()
|
|
305
274
|
})
|
|
306
|
-
|
|
307
|
-
it('ignores starred updates for other members', () => {
|
|
308
|
-
const channel = createMockChannel([])
|
|
309
|
-
|
|
310
|
-
renderWithProviders(
|
|
311
|
-
<CustomChannelPreview {...defaultProps} channel={channel} />
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
act(() => {
|
|
315
|
-
channel.emitMemberUpdated({
|
|
316
|
-
pinned_at: new Date().toISOString(),
|
|
317
|
-
user_id: 'participant-1',
|
|
318
|
-
})
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
expect(
|
|
322
|
-
screen.queryByRole('img', { name: 'Starred conversation' })
|
|
323
|
-
).not.toBeInTheDocument()
|
|
324
|
-
})
|
|
325
275
|
})
|
|
@@ -8,7 +8,6 @@ import { getMessageDisplayText } from '../../utils/getMessageDisplayText'
|
|
|
8
8
|
import { resolveParticipantDisplayName } from '../../utils/resolveParticipantDisplayName'
|
|
9
9
|
import { Avatar } from '../Avatar'
|
|
10
10
|
import { isChatbotMessage } from '../CustomMessage/MessageTag'
|
|
11
|
-
import { ParticipantBadges } from '../ParticipantBadges'
|
|
12
11
|
|
|
13
12
|
import { useChannelListContext } from './ChannelListContext'
|
|
14
13
|
|
|
@@ -140,18 +139,22 @@ const CustomChannelPreview = React.memo<ChannelPreviewUIComponentProps>(
|
|
|
140
139
|
name={participantName}
|
|
141
140
|
image={participantImage}
|
|
142
141
|
size={48}
|
|
142
|
+
starred={isChannelStarred}
|
|
143
143
|
/>
|
|
144
144
|
|
|
145
145
|
{/* Content column */}
|
|
146
146
|
<div className="flex-1 min-w-0 flex flex-col gap-1">
|
|
147
147
|
{/* Name and timestamp row */}
|
|
148
148
|
<div className="flex items-center justify-between gap-2">
|
|
149
|
-
<h3
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
<h3
|
|
150
|
+
className={classNames(
|
|
151
|
+
'text-sm font-medium truncate text-[#191918]'
|
|
152
|
+
)}
|
|
153
|
+
>
|
|
154
|
+
{isChannelStarred && (
|
|
155
|
+
<span className="sr-only">Starred conversation. </span>
|
|
156
|
+
)}
|
|
157
|
+
{participantName}
|
|
155
158
|
</h3>
|
|
156
159
|
{lastMessageTime && (
|
|
157
160
|
<span className="text-xs text-[#717070] flex-shrink-0">
|
|
@@ -41,14 +41,7 @@ const createMockChannel = async (
|
|
|
41
41
|
client: StreamChat,
|
|
42
42
|
hasMessages = true,
|
|
43
43
|
followerStatus?: string | boolean,
|
|
44
|
-
isFrozen = false
|
|
45
|
-
{
|
|
46
|
-
isCustomer = false,
|
|
47
|
-
isStarred = false,
|
|
48
|
-
}: {
|
|
49
|
-
isCustomer?: boolean
|
|
50
|
-
isStarred?: boolean
|
|
51
|
-
} = {}
|
|
44
|
+
isFrozen = false
|
|
52
45
|
) => {
|
|
53
46
|
const participant = mockParticipants[0]
|
|
54
47
|
|
|
@@ -149,12 +142,8 @@ const createMockChannel = async (
|
|
|
149
142
|
user_id: participant.id,
|
|
150
143
|
role: 'member',
|
|
151
144
|
is_account: true,
|
|
152
|
-
...(isCustomer ? { customer: true } : {}),
|
|
153
145
|
},
|
|
154
146
|
}
|
|
155
|
-
channel.state.membership = {
|
|
156
|
-
pinned_at: isStarred ? now().toISOString() : null,
|
|
157
|
-
} as ChannelMemberResponse
|
|
158
147
|
return {
|
|
159
148
|
channel: channelData,
|
|
160
149
|
members: [],
|
|
@@ -182,8 +171,6 @@ const createMockChannel = async (
|
|
|
182
171
|
type TemplateProps = ComponentProps & {
|
|
183
172
|
followerStatus?: string | boolean
|
|
184
173
|
isFrozen?: boolean
|
|
185
|
-
isCustomer?: boolean
|
|
186
|
-
isStarred?: boolean
|
|
187
174
|
typingUser?: {
|
|
188
175
|
id: string
|
|
189
176
|
name?: string
|
|
@@ -195,8 +182,6 @@ const Template: StoryFn<TemplateProps> = (args) => {
|
|
|
195
182
|
const {
|
|
196
183
|
followerStatus,
|
|
197
184
|
isFrozen = false,
|
|
198
|
-
isCustomer = false,
|
|
199
|
-
isStarred = false,
|
|
200
185
|
typingUser,
|
|
201
186
|
...channelViewProps
|
|
202
187
|
} = args
|
|
@@ -212,13 +197,12 @@ const Template: StoryFn<TemplateProps> = (args) => {
|
|
|
212
197
|
const [channel, setChannel] = React.useState<ChannelType | null>(null)
|
|
213
198
|
|
|
214
199
|
useEffect(() => {
|
|
215
|
-
createMockChannel(client, true, followerStatus, isFrozen
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}, [client, followerStatus, isCustomer, isFrozen, isStarred])
|
|
200
|
+
createMockChannel(client, true, followerStatus, isFrozen).then(
|
|
201
|
+
(mockChannel) => {
|
|
202
|
+
setChannel(mockChannel)
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
}, [client, followerStatus, isFrozen])
|
|
222
206
|
|
|
223
207
|
useEffect(() => {
|
|
224
208
|
if (!channel || !typingUser) {
|
|
@@ -323,21 +307,6 @@ WithHeaderTitleBadges.parameters = {
|
|
|
323
307
|
},
|
|
324
308
|
}
|
|
325
309
|
|
|
326
|
-
export const ParticipantBadges: StoryFn<TemplateProps> = Template.bind({})
|
|
327
|
-
ParticipantBadges.args = {
|
|
328
|
-
showBackButton: false,
|
|
329
|
-
isCustomer: true,
|
|
330
|
-
isStarred: true,
|
|
331
|
-
}
|
|
332
|
-
ParticipantBadges.parameters = {
|
|
333
|
-
docs: {
|
|
334
|
-
description: {
|
|
335
|
-
story:
|
|
336
|
-
'Shows the built-in customer badge from participant.customer and the starred badge from the current user membership pinned_at value in the channel header.',
|
|
337
|
-
},
|
|
338
|
-
},
|
|
339
|
-
}
|
|
340
|
-
|
|
341
310
|
export const RestrictedOfficialChannel: StoryFn<TemplateProps> = Template.bind(
|
|
342
311
|
{}
|
|
343
312
|
)
|
|
@@ -98,11 +98,9 @@ const createChannel = ({
|
|
|
98
98
|
username: undefined as string | undefined,
|
|
99
99
|
is_account: true,
|
|
100
100
|
},
|
|
101
|
-
otherMemberCustomer = false,
|
|
102
101
|
}: {
|
|
103
102
|
currentUserId?: 'visitor-1' | 'linker-1'
|
|
104
103
|
currentUserRole?: 'owner' | 'member'
|
|
105
|
-
otherMemberCustomer?: boolean
|
|
106
104
|
otherUser?: {
|
|
107
105
|
id: string
|
|
108
106
|
name?: string
|
|
@@ -135,7 +133,6 @@ const createChannel = ({
|
|
|
135
133
|
otherUser.is_account ?? currentUserId === 'visitor-1',
|
|
136
134
|
},
|
|
137
135
|
role: currentUserRole === 'owner' ? 'member' : 'owner',
|
|
138
|
-
customer: otherMemberCustomer,
|
|
139
136
|
},
|
|
140
137
|
},
|
|
141
138
|
membership: {},
|
|
@@ -290,49 +287,38 @@ describe('ChannelView', () => {
|
|
|
290
287
|
expect(screen.queryByTestId('conversation-footer')).not.toBeInTheDocument()
|
|
291
288
|
})
|
|
292
289
|
|
|
293
|
-
it('does not pass starred to avatar when
|
|
290
|
+
it('does not pass starred to avatar when showStarButton is false', () => {
|
|
294
291
|
mockIsStarred = true
|
|
295
292
|
const channel = createChannel()
|
|
296
293
|
|
|
297
294
|
renderWithProviders(
|
|
298
|
-
<ChannelView channel={channel} showStarButton={
|
|
295
|
+
<ChannelView channel={channel} showStarButton={false} />
|
|
299
296
|
)
|
|
300
297
|
|
|
301
298
|
expect(avatarRenderCalls.length).toBeGreaterThan(0)
|
|
302
|
-
expect(avatarRenderCalls.every((call) =>
|
|
299
|
+
expect(avatarRenderCalls.every((call) => call.starred === false)).toBe(true)
|
|
303
300
|
})
|
|
304
301
|
|
|
305
|
-
it('
|
|
302
|
+
it('passes starred to avatar when showStarButton is true and channel is starred', () => {
|
|
303
|
+
mockIsStarred = true
|
|
304
|
+
const channel = createChannel()
|
|
305
|
+
|
|
306
306
|
renderWithProviders(
|
|
307
|
-
<ChannelView
|
|
308
|
-
channel={createChannel({ otherMemberCustomer: true })}
|
|
309
|
-
renderHeaderTitleBadges={() => (
|
|
310
|
-
<span data-testid="custom-header-badge">VIP</span>
|
|
311
|
-
)}
|
|
312
|
-
/>
|
|
307
|
+
<ChannelView channel={channel} showStarButton={true} />
|
|
313
308
|
)
|
|
314
309
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
expect(customerBadges.length).toBeGreaterThan(0)
|
|
319
|
-
expect(customBadges.length).toBe(customerBadges.length)
|
|
320
|
-
customerBadges.forEach((badge, index) => {
|
|
321
|
-
expect(
|
|
322
|
-
badge.compareDocumentPosition(customBadges[index]) &
|
|
323
|
-
Node.DOCUMENT_POSITION_FOLLOWING
|
|
324
|
-
).toBeTruthy()
|
|
325
|
-
})
|
|
310
|
+
expect(avatarRenderCalls.length).toBeGreaterThan(0)
|
|
311
|
+
expect(avatarRenderCalls.every((call) => call.starred === true)).toBe(true)
|
|
326
312
|
})
|
|
327
313
|
|
|
328
|
-
it('
|
|
314
|
+
it('does not pass starred to avatar by default (showStarButton defaults to false)', () => {
|
|
329
315
|
mockIsStarred = true
|
|
316
|
+
const channel = createChannel()
|
|
330
317
|
|
|
331
|
-
renderWithProviders(<ChannelView channel={
|
|
318
|
+
renderWithProviders(<ChannelView channel={channel} />)
|
|
332
319
|
|
|
333
|
-
expect(
|
|
334
|
-
|
|
335
|
-
).toBeGreaterThan(0)
|
|
320
|
+
expect(avatarRenderCalls.length).toBeGreaterThan(0)
|
|
321
|
+
expect(avatarRenderCalls.every((call) => call.starred === false)).toBe(true)
|
|
336
322
|
})
|
|
337
323
|
|
|
338
324
|
it('passes dmAgentEnabled to avatar when dmAgentEnabled is true for visitor view', () => {
|