@linktr.ee/messaging-react 1.22.1 → 1.22.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "1.22.1",
3
+ "version": "1.22.2",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,157 @@
1
+ import { Channel, LocalMessage, StreamChat } from 'stream-chat'
2
+ import { describe, expect, it, vi } from 'vitest'
3
+
4
+ import { renderWithProviders, screen } from '../../test/utils'
5
+
6
+ import CustomChannelPreview from './CustomChannelPreview'
7
+
8
+ const mockUser = {
9
+ id: 'current-user',
10
+ name: 'Current User',
11
+ }
12
+
13
+ const createMockChannel = (
14
+ messages: Partial<LocalMessage>[]
15
+ ): Channel =>
16
+ ({
17
+ id: 'channel-1',
18
+ cid: 'messaging:channel-1',
19
+ _client: { userID: mockUser.id } as unknown as StreamChat,
20
+ state: {
21
+ members: {
22
+ [mockUser.id]: { user: mockUser, user_id: mockUser.id },
23
+ 'participant-1': {
24
+ user: { id: 'participant-1', name: 'Alice' },
25
+ user_id: 'participant-1',
26
+ },
27
+ },
28
+ messages: messages as LocalMessage[],
29
+ },
30
+ }) as unknown as Channel
31
+
32
+ describe('CustomChannelPreview', () => {
33
+ const defaultProps = {
34
+ onChannelSelect: vi.fn(),
35
+ }
36
+
37
+ it('shows the latest non-system message when the last message is a system message', () => {
38
+ const channel = createMockChannel([
39
+ {
40
+ id: 'msg-1',
41
+ text: 'Hello there!',
42
+ type: 'regular',
43
+ created_at: new Date('2026-01-01T00:00:00.000Z'),
44
+ user: { id: 'participant-1', name: 'Alice' },
45
+ },
46
+ {
47
+ id: 'msg-2',
48
+ text: 'DM Agent has left the conversation',
49
+ type: 'system',
50
+ created_at: new Date('2026-01-01T00:01:00.000Z'),
51
+ },
52
+ ])
53
+
54
+ renderWithProviders(
55
+ <CustomChannelPreview {...defaultProps} channel={channel} />
56
+ )
57
+
58
+ expect(screen.getByText('Hello there!')).toBeInTheDocument()
59
+ expect(
60
+ screen.queryByText('DM Agent has left the conversation')
61
+ ).not.toBeInTheDocument()
62
+ })
63
+
64
+ it('skips multiple consecutive system messages to find the latest non-system message', () => {
65
+ const channel = createMockChannel([
66
+ {
67
+ id: 'msg-1',
68
+ text: 'Nice to meet you!',
69
+ type: 'regular',
70
+ created_at: new Date('2026-01-01T00:00:00.000Z'),
71
+ user: { id: 'participant-1', name: 'Alice' },
72
+ },
73
+ {
74
+ id: 'msg-2',
75
+ text: 'DM Agent has left the conversation',
76
+ type: 'system',
77
+ created_at: new Date('2026-01-01T00:01:00.000Z'),
78
+ },
79
+ {
80
+ id: 'msg-3',
81
+ text: 'DM Agent has rejoined the conversation',
82
+ type: 'system',
83
+ created_at: new Date('2026-01-01T00:02:00.000Z'),
84
+ },
85
+ ])
86
+
87
+ renderWithProviders(
88
+ <CustomChannelPreview {...defaultProps} channel={channel} />
89
+ )
90
+
91
+ expect(screen.getByText('Nice to meet you!')).toBeInTheDocument()
92
+ expect(
93
+ screen.queryByText('DM Agent has left the conversation')
94
+ ).not.toBeInTheDocument()
95
+ expect(
96
+ screen.queryByText('DM Agent has rejoined the conversation')
97
+ ).not.toBeInTheDocument()
98
+ })
99
+
100
+ it('shows fallback text when all messages are system messages', () => {
101
+ const channel = createMockChannel([
102
+ {
103
+ id: 'msg-1',
104
+ text: 'DM Agent has left the conversation',
105
+ type: 'system',
106
+ created_at: new Date('2026-01-01T00:00:00.000Z'),
107
+ },
108
+ {
109
+ id: 'msg-2',
110
+ text: 'DM Agent has rejoined the conversation',
111
+ type: 'system',
112
+ created_at: new Date('2026-01-01T00:01:00.000Z'),
113
+ },
114
+ ])
115
+
116
+ renderWithProviders(
117
+ <CustomChannelPreview {...defaultProps} channel={channel} />
118
+ )
119
+
120
+ expect(screen.getByText('No messages yet')).toBeInTheDocument()
121
+ })
122
+
123
+ it('shows the latest message when it is not a system message', () => {
124
+ const channel = createMockChannel([
125
+ {
126
+ id: 'msg-1',
127
+ text: 'First message',
128
+ type: 'regular',
129
+ created_at: new Date('2026-01-01T00:00:00.000Z'),
130
+ user: { id: 'participant-1', name: 'Alice' },
131
+ },
132
+ {
133
+ id: 'msg-2',
134
+ text: 'Latest message',
135
+ type: 'regular',
136
+ created_at: new Date('2026-01-01T00:01:00.000Z'),
137
+ user: { id: 'participant-1', name: 'Alice' },
138
+ },
139
+ ])
140
+
141
+ renderWithProviders(
142
+ <CustomChannelPreview {...defaultProps} channel={channel} />
143
+ )
144
+
145
+ expect(screen.getByText('Latest message')).toBeInTheDocument()
146
+ })
147
+
148
+ it('shows fallback text when there are no messages', () => {
149
+ const channel = createMockChannel([])
150
+
151
+ renderWithProviders(
152
+ <CustomChannelPreview {...defaultProps} channel={channel} />
153
+ )
154
+
155
+ expect(screen.getByText('No messages yet')).toBeInTheDocument()
156
+ })
157
+ })
@@ -54,9 +54,15 @@ const CustomChannelPreview = React.memo<CustomChannelPreviewProps>(
54
54
  const participantName = participant?.user?.name || 'Conversation'
55
55
  const participantImage = participant?.user?.image
56
56
 
57
- // Get last message and format timestamp
58
- const lastMessage =
59
- channel?.state?.messages?.[channel.state.messages.length - 1]
57
+ // Get last non-system message for preview
58
+ const lastMessage = (() => {
59
+ const messages = channel?.state?.messages
60
+ if (!messages?.length) return undefined
61
+ for (let i = messages.length - 1; i >= 0; i--) {
62
+ if (messages[i].type !== 'system') return messages[i]
63
+ }
64
+ return undefined
65
+ })()
60
66
 
61
67
  const getLastMessageText = () => {
62
68
  if (lastMessage?.text) return lastMessage.text
package/src/styles.css CHANGED
@@ -239,7 +239,7 @@
239
239
  justify-content: center;
240
240
  gap: 10px;
241
241
  margin-inline: auto;
242
- margin-bottom: 4px;
242
+ margin-bottom: 8px;
243
243
  width: fit-content;
244
244
  max-width: min(100%, 480px);
245
245
  padding: 12px;