@linktr.ee/messaging-react 1.40.2 → 2.0.1-rc-1778656305
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Card-CAC3fPjy.js +107 -0
- package/dist/Card-CAC3fPjy.js.map +1 -0
- package/dist/Card-DLUBUg_w.js +132 -0
- package/dist/Card-DLUBUg_w.js.map +1 -0
- package/dist/Card-_StSlnYh.js +163 -0
- package/dist/Card-_StSlnYh.js.map +1 -0
- package/dist/LockedThumbnail-p5RsFOug.js +220 -0
- package/dist/LockedThumbnail-p5RsFOug.js.map +1 -0
- package/dist/assets/index.css +1 -1
- package/dist/index-B1h46F9x.js +3092 -0
- package/dist/index-B1h46F9x.js.map +1 -0
- package/dist/index.d.ts +109 -30
- package/dist/index.js +14 -12
- package/package.json +2 -2
- package/src/components/ChannelInfoDialog/ChannelInfoDialog.test.tsx +2 -14
- package/src/components/ChannelInfoDialog/index.tsx +4 -8
- package/src/components/ChannelList/ChannelListContext.tsx +2 -0
- package/src/components/ChannelList/CustomChannelPreview.tsx +14 -3
- package/src/components/ChannelList/index.tsx +9 -1
- package/src/components/ChannelView.test.tsx +11 -0
- package/src/components/ChannelView.tsx +44 -33
- package/src/components/CustomMessage/index.tsx +24 -7
- package/src/components/CustomTypingIndicator/CustomTypingIndicator.stories.tsx +57 -17
- package/src/components/CustomTypingIndicator/CustomTypingIndicator.test.tsx +187 -0
- package/src/components/CustomTypingIndicator/DmAgentContext.ts +3 -0
- package/src/components/CustomTypingIndicator/index.tsx +101 -37
- package/src/components/LockedAttachment/LockedAttachment.stories.tsx +230 -89
- package/src/components/LockedAttachment/components/Composer/Card.tsx +221 -0
- package/src/components/LockedAttachment/components/Composer/index.ts +2 -0
- package/src/components/LockedAttachment/components/Received/Card.tsx +191 -0
- package/src/components/LockedAttachment/components/Received/CardActions.tsx +91 -0
- package/src/components/LockedAttachment/components/Received/index.ts +2 -0
- package/src/components/LockedAttachment/components/Sent/Card.tsx +177 -0
- package/src/components/LockedAttachment/components/Sent/index.ts +2 -0
- package/src/components/LockedAttachment/components/_shared/CardBody.tsx +94 -0
- package/src/components/LockedAttachment/components/_shared/GalleryThumbnail.tsx +178 -0
- package/src/components/LockedAttachment/components/_shared/LockBadge.tsx +39 -0
- package/src/components/LockedAttachment/components/_shared/LockedCardShell.tsx +36 -0
- package/src/components/LockedAttachment/components/_shared/LockedThumbnail.tsx +128 -0
- package/src/components/LockedAttachment/index.tsx +43 -12
- package/src/components/LockedAttachment/types.ts +17 -0
- package/src/components/MediaMessage/index.tsx +2 -2
- package/src/components/MessagingShell/index.tsx +4 -4
- package/src/index.ts +18 -2
- package/src/stories/mocks.tsx +2 -9
- package/src/styles.css +7 -0
- package/src/types.ts +11 -1
- package/src/utils/getMessageDisplayText.test.ts +44 -0
- package/src/utils/getMessageDisplayText.ts +27 -0
- package/dist/Card-A0lkei-S.js +0 -138
- package/dist/Card-A0lkei-S.js.map +0 -1
- package/dist/Card-DXoAKkv0.js +0 -127
- package/dist/Card-DXoAKkv0.js.map +0 -1
- package/dist/index-B_PLgcDi.js +0 -2994
- package/dist/index-B_PLgcDi.js.map +0 -1
- package/src/components/LockedAttachment/components/Creator/Card.tsx +0 -210
- package/src/components/LockedAttachment/components/Creator/index.tsx +0 -2
- package/src/components/LockedAttachment/components/Visitor/Card.tsx +0 -155
- package/src/components/LockedAttachment/components/Visitor/CardActions.tsx +0 -62
- package/src/components/LockedAttachment/components/Visitor/LockBadge.tsx +0 -12
- package/src/components/LockedAttachment/components/Visitor/index.ts +0 -2
package/dist/index.d.ts
CHANGED
|
@@ -101,6 +101,11 @@ export declare interface ChannelListProps {
|
|
|
101
101
|
sort?: ChannelSort;
|
|
102
102
|
customEmptyStateIndicator?: React.ComponentType<EmptyStateIndicatorProps>;
|
|
103
103
|
renderMessagePreview?: (message: LocalMessage | undefined, defaultPreview?: string) => React.ReactNode;
|
|
104
|
+
/**
|
|
105
|
+
* Language code used to pick translated message text from Stream Chat i18n.
|
|
106
|
+
* Falls back to message.text when no matching translation exists.
|
|
107
|
+
*/
|
|
108
|
+
viewerLanguage?: string;
|
|
104
109
|
}
|
|
105
110
|
|
|
106
111
|
/**
|
|
@@ -112,7 +117,7 @@ export declare const ChannelView: default_2.NamedExoticComponent<ChannelViewProp
|
|
|
112
117
|
* Props that MessagingShell passes through to ChannelView.
|
|
113
118
|
* ChannelViewProps is the source of truth for these props.
|
|
114
119
|
*/
|
|
115
|
-
declare type ChannelViewPassthroughProps = Pick<ChannelViewProps, 'renderMessageInputActions' | 'renderConversationFooter' | 'CustomChannelEmptyState' | 'onDeleteConversationClick' | 'onBlockParticipantClick' | 'onReportParticipantClick' | 'dmAgentEnabled' | 'messageMetadata' | 'onMessageSent' | 'showStarButton' | 'chatbotVotingEnabled' | 'renderChannelBanner' | 'customProfileContent' | 'customChannelActions' | 'renderMessage' | 'sendButton'>;
|
|
120
|
+
declare type ChannelViewPassthroughProps = Pick<ChannelViewProps, 'renderMessageInputActions' | 'renderConversationFooter' | 'CustomChannelEmptyState' | 'onDeleteConversationClick' | 'onBlockParticipantClick' | 'onReportParticipantClick' | 'dmAgentEnabled' | 'messageMetadata' | 'onMessageSent' | 'showStarButton' | 'chatbotVotingEnabled' | 'viewerLanguage' | 'renderChannelBanner' | 'customProfileContent' | 'customChannelActions' | 'renderMessage' | 'sendButton'>;
|
|
116
121
|
|
|
117
122
|
/**
|
|
118
123
|
* ChannelView component props
|
|
@@ -185,6 +190,11 @@ export declare interface ChannelViewProps {
|
|
|
185
190
|
* Defaults to false.
|
|
186
191
|
*/
|
|
187
192
|
chatbotVotingEnabled?: boolean;
|
|
193
|
+
/**
|
|
194
|
+
* Language code used to pick translated message text from Stream Chat i18n.
|
|
195
|
+
* Falls back to message.text when no matching translation exists.
|
|
196
|
+
*/
|
|
197
|
+
viewerLanguage?: string;
|
|
188
198
|
/**
|
|
189
199
|
* Custom render function for a banner/card component that renders
|
|
190
200
|
* between the channel header and message list.
|
|
@@ -231,15 +241,38 @@ export declare interface ChannelViewProps {
|
|
|
231
241
|
sendButton?: ComponentType<any>;
|
|
232
242
|
}
|
|
233
243
|
|
|
234
|
-
export declare interface
|
|
244
|
+
export declare interface ComposerCardProps extends LockedAttachmentBaseProps {
|
|
245
|
+
/** Placeholder shown in the title slot before the composer types one. */
|
|
235
246
|
placeholderTitle?: string;
|
|
247
|
+
/** Placeholder shown in the amount slot before one is configured. */
|
|
236
248
|
placeholderAmountText?: string;
|
|
237
|
-
|
|
249
|
+
/**
|
|
250
|
+
* When provided, renders a dismiss X in the thumbnail corner. Called when
|
|
251
|
+
* the composer clicks it to remove the attachment.
|
|
252
|
+
*/
|
|
238
253
|
onDismiss?: () => void;
|
|
254
|
+
/** Fired the first time the composer taps the thumbnail to preview. */
|
|
239
255
|
onPreviewClick?: () => void;
|
|
256
|
+
/**
|
|
257
|
+
* Lazily loads the underlying source so the composer can preview the
|
|
258
|
+
* attachment they're about to send. Called the first time the thumbnail is
|
|
259
|
+
* tapped; the returned source is cached and reused on subsequent toggles.
|
|
260
|
+
*/
|
|
240
261
|
onFetchSource?: () => Promise<LockedAttachmentSource | void>;
|
|
262
|
+
/**
|
|
263
|
+
* When provided, renders a pencil button in the body bottom-right that the
|
|
264
|
+
* composer can use to edit the attachment metadata (e.g. open the price /
|
|
265
|
+
* gallery editor). Matches the Composer "Button" instance in Figma.
|
|
266
|
+
*/
|
|
267
|
+
onEditClick?: () => void;
|
|
241
268
|
}
|
|
242
269
|
|
|
270
|
+
/**
|
|
271
|
+
* @deprecated Renamed to `SentCardProps`. Drafting usages (with `onDismiss`)
|
|
272
|
+
* should migrate to `ComposerCardProps`.
|
|
273
|
+
*/
|
|
274
|
+
export declare type CreatorCardProps = SentCardProps;
|
|
275
|
+
|
|
243
276
|
export declare const CustomMessageProvider: Provider<Partial<CustomMessageRegistry>>;
|
|
244
277
|
|
|
245
278
|
export declare interface CustomMessageRegistry {
|
|
@@ -283,11 +316,19 @@ export declare interface FaqListProps {
|
|
|
283
316
|
*/
|
|
284
317
|
export declare const formatRelativeTime: (date: Date) => string;
|
|
285
318
|
|
|
319
|
+
export declare function getMessageDisplayText({ message, viewerLanguage, }: {
|
|
320
|
+
message?: MessageWithI18n | null;
|
|
321
|
+
viewerLanguage?: string;
|
|
322
|
+
}): string | undefined;
|
|
323
|
+
|
|
286
324
|
export declare function isLinkAttachment(a: Attachment): boolean;
|
|
287
325
|
|
|
288
326
|
export declare const LockedAttachment: {
|
|
289
|
-
|
|
290
|
-
|
|
327
|
+
Composer: (props: ComposerCardProps) => JSX_2.Element;
|
|
328
|
+
Sent: (props: SentCardProps) => JSX_2.Element;
|
|
329
|
+
Received: (props: ReceivedCardProps) => JSX_2.Element;
|
|
330
|
+
Creator: (props: SentCardProps) => JSX_2.Element;
|
|
331
|
+
Visitor: (props: ReceivedCardProps) => JSX_2.Element;
|
|
291
332
|
};
|
|
292
333
|
|
|
293
334
|
declare interface LockedAttachmentBaseProps {
|
|
@@ -297,6 +338,14 @@ declare interface LockedAttachmentBaseProps {
|
|
|
297
338
|
detail?: string;
|
|
298
339
|
amountText?: string;
|
|
299
340
|
paymentStatus?: PaymentStatus;
|
|
341
|
+
/**
|
|
342
|
+
* When provided with 2+ items, the card renders as a mixed-media carousel
|
|
343
|
+
* (e.g. a couple of photos + a video) instead of a single thumbnail. Each
|
|
344
|
+
* item brings its own thumbnail and optional source so that
|
|
345
|
+
* `LockedAttachment.Composer` / `.Sent` / `.Received` can all share the
|
|
346
|
+
* same carousel chrome.
|
|
347
|
+
*/
|
|
348
|
+
gallery?: LockedAttachmentGalleryItem[];
|
|
300
349
|
}
|
|
301
350
|
|
|
302
351
|
export declare interface LockedAttachmentContextValue {
|
|
@@ -306,6 +355,15 @@ export declare interface LockedAttachmentContextValue {
|
|
|
306
355
|
onFetchSource?: (message: LocalMessage, channel: Channel) => Promise<LockedAttachmentSource | void>;
|
|
307
356
|
}
|
|
308
357
|
|
|
358
|
+
export declare interface LockedAttachmentGalleryItem {
|
|
359
|
+
/** MIME type of this carousel item — drives the per-item play / lock affordance. */
|
|
360
|
+
mimeType: string;
|
|
361
|
+
/** Poster image used for both the locked (blurred) and unlocked preview state. */
|
|
362
|
+
thumbnailUrl?: string;
|
|
363
|
+
/** Underlying source (image or video URL) — shown only when unlocked. */
|
|
364
|
+
sourceUrl?: string;
|
|
365
|
+
}
|
|
366
|
+
|
|
309
367
|
export declare interface LockedAttachmentSource {
|
|
310
368
|
/** Proxied URL used by the media player for in-app playback. */
|
|
311
369
|
sourceUrl: string;
|
|
@@ -358,6 +416,10 @@ declare interface MessageVoteButtonsProps {
|
|
|
358
416
|
onVoteDown: () => void;
|
|
359
417
|
}
|
|
360
418
|
|
|
419
|
+
declare type MessageWithI18n = Pick<LocalMessage, 'text'> & {
|
|
420
|
+
i18n?: Record<string, string> | null;
|
|
421
|
+
};
|
|
422
|
+
|
|
361
423
|
/**
|
|
362
424
|
* Messaging capabilities configuration
|
|
363
425
|
*/
|
|
@@ -462,13 +524,14 @@ export declare interface MessagingShellProps extends ChannelViewPassthroughProps
|
|
|
462
524
|
renderMessagePreview?: (message: LocalMessage | undefined, defaultPreview?: string) => React.ReactNode;
|
|
463
525
|
}
|
|
464
526
|
|
|
527
|
+
export declare function normalizeLanguageCode(language?: string): string | undefined;
|
|
528
|
+
|
|
465
529
|
/**
|
|
466
530
|
* Generic participant interface for different host environments
|
|
467
531
|
*/
|
|
468
532
|
export declare interface Participant {
|
|
469
533
|
id: string;
|
|
470
534
|
name: string;
|
|
471
|
-
email?: string;
|
|
472
535
|
image?: string;
|
|
473
536
|
username?: string;
|
|
474
537
|
phone?: string;
|
|
@@ -481,10 +544,48 @@ export declare interface Participant {
|
|
|
481
544
|
*/
|
|
482
545
|
declare type PaymentStatus = 'pending' | 'paid' | 'failed' | 'refunded';
|
|
483
546
|
|
|
547
|
+
export declare interface ReceivedCardProps extends LockedAttachmentBaseProps {
|
|
548
|
+
/**
|
|
549
|
+
* Called when the recipient clicks Unlock on an unpaid attachment.
|
|
550
|
+
* Use this to open a checkout flow. Omit to hide the Unlock button.
|
|
551
|
+
*/
|
|
552
|
+
onUnlockClick?: () => void;
|
|
553
|
+
/**
|
|
554
|
+
* Called to fetch the attachment source — fired automatically when
|
|
555
|
+
* `paymentStatus` transitions to `'paid'`, or immediately on click when
|
|
556
|
+
* `paymentStatus` is already `'paid'`. Return a `LockedAttachmentSource`
|
|
557
|
+
* to unlock the card.
|
|
558
|
+
*/
|
|
559
|
+
onFetchSource?: () => Promise<LockedAttachmentSource | void>;
|
|
560
|
+
/**
|
|
561
|
+
* Called when the recipient clicks Download on an unlocked card.
|
|
562
|
+
* Omit to hide the Download button.
|
|
563
|
+
*/
|
|
564
|
+
onDownloadClick?: () => void;
|
|
565
|
+
/**
|
|
566
|
+
* When true, shows a loading spinner on the Unlock button.
|
|
567
|
+
* Driven by the LockedAttachmentContext (e.g. checkout in progress).
|
|
568
|
+
*/
|
|
569
|
+
isUnlocking?: boolean;
|
|
570
|
+
}
|
|
571
|
+
|
|
484
572
|
export declare function resolveLinkAttachment(message: LocalMessage): Attachment | undefined;
|
|
485
573
|
|
|
486
574
|
export declare function resolveMediaFromMessage(message: LocalMessage): MediaMessageResolved | null;
|
|
487
575
|
|
|
576
|
+
export declare interface SentCardProps extends LockedAttachmentBaseProps {
|
|
577
|
+
/** Placeholder shown in the title slot when no title is set. */
|
|
578
|
+
placeholderTitle?: string;
|
|
579
|
+
/** Fired the first time the sender taps the thumbnail to preview their own attachment. */
|
|
580
|
+
onPreviewClick?: () => void;
|
|
581
|
+
/**
|
|
582
|
+
* Lazily loads the underlying source so the sender can preview the attachment.
|
|
583
|
+
* Called the first time the thumbnail is tapped; the returned source is cached
|
|
584
|
+
* and reused on subsequent toggles.
|
|
585
|
+
*/
|
|
586
|
+
onFetchSource?: () => Promise<LockedAttachmentSource | void>;
|
|
587
|
+
}
|
|
588
|
+
|
|
488
589
|
export declare function useCustomMessage<K extends keyof CustomMessageRegistry>(key: K): CustomMessageRegistry[K];
|
|
489
590
|
|
|
490
591
|
/**
|
|
@@ -508,30 +609,8 @@ declare interface UseMessageVoteResult {
|
|
|
508
609
|
*/
|
|
509
610
|
export declare const useMessaging: () => MessagingContextValue;
|
|
510
611
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
* Called when the visitor clicks Unlock on an unpaid attachment.
|
|
514
|
-
* Use this to open a checkout flow. Omit to hide the Unlock button.
|
|
515
|
-
*/
|
|
516
|
-
onUnlockClick?: () => void;
|
|
517
|
-
/**
|
|
518
|
-
* Called to fetch the attachment source — fired automatically when
|
|
519
|
-
* paymentStatus transitions to 'paid', or immediately on click when
|
|
520
|
-
* paymentStatus is already 'paid'. Return a LockedAttachmentSource to
|
|
521
|
-
* unlock the card.
|
|
522
|
-
*/
|
|
523
|
-
onFetchSource?: () => Promise<LockedAttachmentSource | void>;
|
|
524
|
-
/**
|
|
525
|
-
* Called when the visitor clicks Download on an unlocked card.
|
|
526
|
-
* Omit to hide the Download button.
|
|
527
|
-
*/
|
|
528
|
-
onDownloadClick?: () => void;
|
|
529
|
-
/**
|
|
530
|
-
* When true, shows loading dots on the Unlock button.
|
|
531
|
-
* Driven by the LockedAttachmentContext (e.g. checkout in progress, payment processing).
|
|
532
|
-
*/
|
|
533
|
-
isUnlocking?: boolean;
|
|
534
|
-
}
|
|
612
|
+
/** @deprecated Renamed to `ReceivedCardProps`. */
|
|
613
|
+
export declare type VisitorCardProps = ReceivedCardProps;
|
|
535
614
|
|
|
536
615
|
export declare type VoteSelection = 'up' | 'down' | null;
|
|
537
616
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as e, b as t, C as i, c as n, d as o, e as g, F as m, f as M, L as r, M as l, h as u, i as h, j as L, k as d, l as C, m as c, n as v, o as A, p as k, u as p, q as F, s as f } from "./index-B1h46F9x.js";
|
|
2
2
|
export {
|
|
3
3
|
e as ActionButton,
|
|
4
4
|
t as Avatar,
|
|
@@ -7,18 +7,20 @@ export {
|
|
|
7
7
|
o as ChannelView,
|
|
8
8
|
g as CustomMessageProvider,
|
|
9
9
|
m as FaqList,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
M as FaqListItem,
|
|
11
|
+
r as LockedAttachment,
|
|
12
12
|
l as MediaMessage,
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
u as MessageVoteButtons,
|
|
14
|
+
h as MessagingProvider,
|
|
15
15
|
L as MessagingShell,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
A as
|
|
21
|
-
k as
|
|
22
|
-
|
|
16
|
+
d as formatRelativeTime,
|
|
17
|
+
C as getMessageDisplayText,
|
|
18
|
+
c as isLinkAttachment,
|
|
19
|
+
v as normalizeLanguageCode,
|
|
20
|
+
A as resolveLinkAttachment,
|
|
21
|
+
k as resolveMediaFromMessage,
|
|
22
|
+
p as useCustomMessage,
|
|
23
|
+
F as useMessageVote,
|
|
24
|
+
f as useMessaging
|
|
23
25
|
};
|
|
24
26
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linktr.ee/messaging-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1-rc-1778656305",
|
|
4
4
|
"description": "React messaging components built on messaging-core for web applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@linktr.ee/component-library": "11.8.6",
|
|
37
|
-
"@linktr.ee/messaging-core": "^
|
|
37
|
+
"@linktr.ee/messaging-core": "^2.0.0",
|
|
38
38
|
"@phosphor-icons/react": "^2.1.10"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
@@ -65,14 +65,13 @@ const createChannel = () =>
|
|
|
65
65
|
}) as unknown as Channel
|
|
66
66
|
|
|
67
67
|
const createParticipant = (
|
|
68
|
-
overrides: Partial<{ name: string;
|
|
68
|
+
overrides: Partial<{ name: string; username: string }> = {}
|
|
69
69
|
) =>
|
|
70
70
|
({
|
|
71
71
|
user: {
|
|
72
72
|
id: 'linker-1',
|
|
73
73
|
name: overrides.name ?? 'Linker',
|
|
74
74
|
image: undefined,
|
|
75
|
-
email: overrides.email,
|
|
76
75
|
username: overrides.username,
|
|
77
76
|
},
|
|
78
77
|
role: 'member',
|
|
@@ -99,18 +98,7 @@ describe('ChannelInfoDialog', () => {
|
|
|
99
98
|
expect(nameEl).toBeInTheDocument()
|
|
100
99
|
})
|
|
101
100
|
|
|
102
|
-
it('renders participant
|
|
103
|
-
renderWithProviders(
|
|
104
|
-
<ChannelInfoDialog
|
|
105
|
-
{...defaultProps()}
|
|
106
|
-
participant={createParticipant({ email: 'linker@example.com' })}
|
|
107
|
-
/>
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
expect(screen.getByText('linker@example.com')).toBeInTheDocument()
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('renders participant username as secondary info when no email', () => {
|
|
101
|
+
it('renders participant username as secondary info', () => {
|
|
114
102
|
renderWithProviders(
|
|
115
103
|
<ChannelInfoDialog
|
|
116
104
|
{...defaultProps()}
|
|
@@ -12,9 +12,8 @@ import ActionButton from '../ActionButton'
|
|
|
12
12
|
import { Avatar } from '../Avatar'
|
|
13
13
|
import { CloseButton } from '../CloseButton'
|
|
14
14
|
|
|
15
|
-
// Custom user type with
|
|
15
|
+
// Custom user type with username
|
|
16
16
|
type CustomUser = {
|
|
17
|
-
email?: string
|
|
18
17
|
username?: string
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -180,13 +179,10 @@ export const ChannelInfoDialog: React.FC<ChannelInfoDialogProps> = ({
|
|
|
180
179
|
const participantName =
|
|
181
180
|
participant.user?.name || participant.user?.id || 'Unknown member'
|
|
182
181
|
const participantImage = participant.user?.image
|
|
183
|
-
const participantEmail = (participant.user as CustomUser)?.email
|
|
184
182
|
const participantUsername = (participant.user as CustomUser)?.username
|
|
185
|
-
const participantSecondary =
|
|
186
|
-
?
|
|
187
|
-
:
|
|
188
|
-
? `linktr.ee/${participantUsername}`
|
|
189
|
-
: undefined
|
|
183
|
+
const participantSecondary = participantUsername
|
|
184
|
+
? `linktr.ee/${participantUsername}`
|
|
185
|
+
: undefined
|
|
190
186
|
const participantId = participant.user?.id || 'unknown'
|
|
191
187
|
|
|
192
188
|
return (
|
|
@@ -9,6 +9,7 @@ type ChannelListContextValue = {
|
|
|
9
9
|
message: LocalMessage | undefined,
|
|
10
10
|
defaultPreview?: string
|
|
11
11
|
) => React.ReactNode
|
|
12
|
+
viewerLanguage?: string
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const ChannelListContext = React.createContext<ChannelListContextValue>({
|
|
@@ -16,6 +17,7 @@ const ChannelListContext = React.createContext<ChannelListContextValue>({
|
|
|
16
17
|
onChannelSelect: () => {},
|
|
17
18
|
debug: false,
|
|
18
19
|
renderMessagePreview: undefined,
|
|
20
|
+
viewerLanguage: undefined,
|
|
19
21
|
})
|
|
20
22
|
|
|
21
23
|
export const ChannelListProvider = ChannelListContext.Provider
|
|
@@ -4,6 +4,7 @@ import { ChannelPreviewUIComponentProps } from 'stream-chat-react'
|
|
|
4
4
|
|
|
5
5
|
import { useChannelStar } from '../../hooks/useChannelStar'
|
|
6
6
|
import { formatRelativeTime } from '../../utils/formatRelativeTime'
|
|
7
|
+
import { getMessageDisplayText } from '../../utils/getMessageDisplayText'
|
|
7
8
|
import { Avatar } from '../Avatar'
|
|
8
9
|
import { isChatbotMessage } from '../CustomMessage/MessageTag'
|
|
9
10
|
|
|
@@ -14,8 +15,13 @@ import { useChannelListContext } from './ChannelListContext'
|
|
|
14
15
|
*/
|
|
15
16
|
const CustomChannelPreview = React.memo<ChannelPreviewUIComponentProps>(
|
|
16
17
|
({ channel, unread }) => {
|
|
17
|
-
const {
|
|
18
|
-
|
|
18
|
+
const {
|
|
19
|
+
selectedChannel,
|
|
20
|
+
onChannelSelect,
|
|
21
|
+
debug,
|
|
22
|
+
renderMessagePreview,
|
|
23
|
+
viewerLanguage,
|
|
24
|
+
} = useChannelListContext()
|
|
19
25
|
|
|
20
26
|
const isSelected = selectedChannel?.id === channel?.id
|
|
21
27
|
|
|
@@ -53,7 +59,12 @@ const CustomChannelPreview = React.memo<ChannelPreviewUIComponentProps>(
|
|
|
53
59
|
})()
|
|
54
60
|
|
|
55
61
|
const getLastMessageText = () => {
|
|
56
|
-
|
|
62
|
+
const displayText = getMessageDisplayText({
|
|
63
|
+
message: lastMessage,
|
|
64
|
+
viewerLanguage,
|
|
65
|
+
})
|
|
66
|
+
if (displayText) return displayText
|
|
67
|
+
|
|
57
68
|
const isTip = lastMessage?.metadata?.custom_type === 'MESSAGE_TIP'
|
|
58
69
|
if (isTip) return '💵 Sent a tip'
|
|
59
70
|
|
|
@@ -28,6 +28,7 @@ export const ChannelList = React.memo<ChannelListProps>(
|
|
|
28
28
|
className,
|
|
29
29
|
customEmptyStateIndicator,
|
|
30
30
|
renderMessagePreview,
|
|
31
|
+
viewerLanguage,
|
|
31
32
|
}) => {
|
|
32
33
|
// Track renders
|
|
33
34
|
const renderCountRef = React.useRef(0)
|
|
@@ -64,8 +65,15 @@ export const ChannelList = React.memo<ChannelListProps>(
|
|
|
64
65
|
onChannelSelect,
|
|
65
66
|
debug,
|
|
66
67
|
renderMessagePreview,
|
|
68
|
+
viewerLanguage,
|
|
67
69
|
}),
|
|
68
|
-
[
|
|
70
|
+
[
|
|
71
|
+
selectedChannel,
|
|
72
|
+
onChannelSelect,
|
|
73
|
+
debug,
|
|
74
|
+
renderMessagePreview,
|
|
75
|
+
viewerLanguage,
|
|
76
|
+
]
|
|
69
77
|
)
|
|
70
78
|
|
|
71
79
|
return (
|
|
@@ -28,6 +28,17 @@ vi.mock('stream-chat-react', () => ({
|
|
|
28
28
|
),
|
|
29
29
|
useMessageContext: () => ({ message: { id: 'message-1', text: 'hello' } }),
|
|
30
30
|
useChannelStateContext: () => ({ channel: activeChannel }),
|
|
31
|
+
useChatContext: () => ({ client: { user: { id: 'visitor-1' } } }),
|
|
32
|
+
useTypingContext: () => ({ typing: {} }),
|
|
33
|
+
useAIState: () => ({ aiState: 'AI_STATE_IDLE' }),
|
|
34
|
+
AIStates: {
|
|
35
|
+
Error: 'AI_STATE_ERROR',
|
|
36
|
+
ExternalSources: 'AI_STATE_EXTERNAL_SOURCES',
|
|
37
|
+
Generating: 'AI_STATE_GENERATING',
|
|
38
|
+
Idle: 'AI_STATE_IDLE',
|
|
39
|
+
Stop: 'AI_STATE_STOP',
|
|
40
|
+
Thinking: 'AI_STATE_THINKING',
|
|
41
|
+
},
|
|
31
42
|
}))
|
|
32
43
|
|
|
33
44
|
vi.mock('../providers/MessagingProvider', () => ({
|
|
@@ -28,6 +28,7 @@ import { CustomMessage } from './CustomMessage'
|
|
|
28
28
|
import { CustomMessageInput } from './CustomMessageInput'
|
|
29
29
|
import { CustomSystemMessage } from './CustomSystemMessage'
|
|
30
30
|
import CustomTypingIndicator from './CustomTypingIndicator'
|
|
31
|
+
import { DmAgentEnabledContext } from './CustomTypingIndicator/DmAgentContext'
|
|
31
32
|
import { ChannelEmptyState } from './MessagingShell/ChannelEmptyState'
|
|
32
33
|
import { LoadingState } from './MessagingShell/LoadingState'
|
|
33
34
|
|
|
@@ -257,6 +258,7 @@ const ChannelViewInner: React.FC<{
|
|
|
257
258
|
message: NonNullable<MessageUIComponentProps['message']>
|
|
258
259
|
) => React.ReactNode
|
|
259
260
|
dmAgentEnabled?: boolean
|
|
261
|
+
viewerLanguage?: string
|
|
260
262
|
}> = ({
|
|
261
263
|
onBack,
|
|
262
264
|
showBackButton,
|
|
@@ -275,6 +277,7 @@ const ChannelViewInner: React.FC<{
|
|
|
275
277
|
customChannelActions,
|
|
276
278
|
renderMessage,
|
|
277
279
|
dmAgentEnabled = false,
|
|
280
|
+
viewerLanguage,
|
|
278
281
|
}) => {
|
|
279
282
|
const { channel } = useChannelStateContext()
|
|
280
283
|
const infoDialogRef = useRef<HTMLDialogElement>(null)
|
|
@@ -339,7 +342,11 @@ const ChannelViewInner: React.FC<{
|
|
|
339
342
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
340
343
|
const { message } = useMessageContext('ChannelView')
|
|
341
344
|
const messageNode = (
|
|
342
|
-
<CustomMessage
|
|
345
|
+
<CustomMessage
|
|
346
|
+
{...props}
|
|
347
|
+
chatbotVotingEnabled={chatbotVotingEnabled}
|
|
348
|
+
viewerLanguage={viewerLanguage}
|
|
349
|
+
/>
|
|
343
350
|
)
|
|
344
351
|
|
|
345
352
|
if (!renderMessage || !message) {
|
|
@@ -348,7 +355,7 @@ const ChannelViewInner: React.FC<{
|
|
|
348
355
|
|
|
349
356
|
return renderMessage(messageNode, message)
|
|
350
357
|
},
|
|
351
|
-
[chatbotVotingEnabled, renderMessage]
|
|
358
|
+
[chatbotVotingEnabled, renderMessage, viewerLanguage]
|
|
352
359
|
)
|
|
353
360
|
|
|
354
361
|
return (
|
|
@@ -436,6 +443,7 @@ export const ChannelView = React.memo<ChannelViewProps>(
|
|
|
436
443
|
customChannelActions,
|
|
437
444
|
renderMessage,
|
|
438
445
|
sendButton,
|
|
446
|
+
viewerLanguage,
|
|
439
447
|
}) => {
|
|
440
448
|
// Custom send message handler that:
|
|
441
449
|
// 1. Applies messageMetadata if provided
|
|
@@ -488,37 +496,40 @@ export const ChannelView = React.memo<ChannelViewProps>(
|
|
|
488
496
|
className
|
|
489
497
|
)}
|
|
490
498
|
>
|
|
491
|
-
<
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
499
|
+
<DmAgentEnabledContext.Provider value={dmAgentEnabled ?? false}>
|
|
500
|
+
<Channel
|
|
501
|
+
channel={channel}
|
|
502
|
+
MessageSystem={CustomSystemMessage}
|
|
503
|
+
EmptyStateIndicator={CustomChannelEmptyState}
|
|
504
|
+
LoadingIndicator={LoadingState}
|
|
505
|
+
DateSeparator={CustomDateSeparator}
|
|
506
|
+
TypingIndicator={CustomTypingIndicator}
|
|
507
|
+
doSendMessageRequest={doSendMessageRequest}
|
|
508
|
+
{...(sendButton ? { SendButton: sendButton } : {})}
|
|
509
|
+
>
|
|
510
|
+
<ChannelViewInner
|
|
511
|
+
onBack={onBack}
|
|
512
|
+
showBackButton={showBackButton}
|
|
513
|
+
renderMessageInputActions={renderMessageInputActions}
|
|
514
|
+
renderConversationFooter={renderConversationFooter}
|
|
515
|
+
onLeaveConversation={onLeaveConversation}
|
|
516
|
+
onBlockParticipant={onBlockParticipant}
|
|
517
|
+
CustomChannelEmptyState={CustomChannelEmptyState}
|
|
518
|
+
showDeleteConversation={showDeleteConversation}
|
|
519
|
+
onDeleteConversationClick={onDeleteConversationClick}
|
|
520
|
+
onBlockParticipantClick={onBlockParticipantClick}
|
|
521
|
+
onReportParticipantClick={onReportParticipantClick}
|
|
522
|
+
showStarButton={showStarButton}
|
|
523
|
+
dmAgentEnabled={dmAgentEnabled}
|
|
524
|
+
chatbotVotingEnabled={chatbotVotingEnabled}
|
|
525
|
+
renderChannelBanner={renderChannelBanner}
|
|
526
|
+
customProfileContent={customProfileContent}
|
|
527
|
+
customChannelActions={customChannelActions}
|
|
528
|
+
renderMessage={renderMessage}
|
|
529
|
+
viewerLanguage={viewerLanguage}
|
|
530
|
+
/>
|
|
531
|
+
</Channel>
|
|
532
|
+
</DmAgentEnabledContext.Provider>
|
|
522
533
|
</div>
|
|
523
534
|
)
|
|
524
535
|
}
|