@linktr.ee/messaging-react 1.21.0 → 1.21.2-rc-1771385662

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.21.0",
3
+ "version": "1.21.2-rc-1771385662",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -262,7 +262,8 @@ export const WithCustomMessagePreview: StoryFn = () => {
262
262
  participantName: 'Alice Urgent',
263
263
  participantId: 'participant-urgent',
264
264
  participantImage: 'https://i.pravatar.cc/150?img=36',
265
- lastMessageText: 'Critical issue needs immediate attention!',
265
+ lastMessageText:
266
+ 'Critical issue needs immediate attention! Please review the server logs for more details and escalate to the on-call engineer. This system outage is affecting multiple users, and we need to resolve it as soon as possible. Impacted services include messaging, notifications, and real-time updates. All hands are required to investigate and remediate the situation. If you have any questions or need additional resources, contact the incident commander immediately!',
266
267
  lastMessageTime: new Date(Date.now() - 1000 * 60), // 1 minute ago
267
268
  lastMessageMetadata: { custom_type: 'MESSAGE_URGENT' },
268
269
  unreadCount: 3,
@@ -36,6 +36,15 @@ const CustomChannelPreview = React.memo<CustomChannelPreviewProps>(
36
36
  onChannelSelect(channel)
37
37
  }
38
38
  }
39
+ const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
40
+ const isActivationKey = event.key === 'Enter' || event.key === ' '
41
+ const isRepeatedKeydown = event.repeat
42
+
43
+ if (!isActivationKey || isRepeatedKeydown) return
44
+
45
+ event.preventDefault()
46
+ handleClick()
47
+ }
39
48
 
40
49
  // Get participant info
41
50
  const members = Object.values(channel?.state?.members || {})
@@ -96,9 +105,11 @@ const CustomChannelPreview = React.memo<CustomChannelPreviewProps>(
96
105
  }
97
106
 
98
107
  return (
99
- <button
100
- type="button"
108
+ <div
109
+ role="button"
110
+ tabIndex={0}
101
111
  onClick={handleClick}
112
+ onKeyDown={handleKeyDown}
102
113
  className={classNames(
103
114
  'group w-full px-4 py-3 transition-colors text-left max-w-full overflow-hidden focus-ring',
104
115
  {
@@ -149,7 +160,7 @@ const CustomChannelPreview = React.memo<CustomChannelPreviewProps>(
149
160
  </div>
150
161
  </div>
151
162
  </div>
152
- </button>
163
+ </div>
153
164
  )
154
165
  }
155
166
  )
@@ -154,6 +154,21 @@ WithTipTag.args = {
154
154
  ],
155
155
  }
156
156
 
157
+ /** Tip message without amount_text (backend may not set it). Tag shows "Delivered with tip". */
158
+ export const WithTipTagNoAmount: StoryFn<TemplateProps> = Template.bind({})
159
+ WithTipTagNoAmount.args = {
160
+ messages: [
161
+ { id: 'msg-1', text: 'Love your content!', user: participant },
162
+ {
163
+ id: 'msg-2',
164
+ text: "Here's a tip for you!",
165
+ user: participant,
166
+ metadata: { custom_type: 'MESSAGE_TIP' },
167
+ },
168
+ { id: 'msg-3', text: 'Thank you! 🙏', user: mockUser },
169
+ ],
170
+ }
171
+
157
172
  export const TipOnly: StoryFn<TemplateProps> = Template.bind({})
158
173
  TipOnly.args = {
159
174
  messages: [
@@ -168,6 +183,21 @@ TipOnly.args = {
168
183
  ],
169
184
  }
170
185
 
186
+ /** Tip-only bubble without amount_text. Tag shows "Tip". */
187
+ export const TipOnlyNoAmount: StoryFn<TemplateProps> = Template.bind({})
188
+ TipOnlyNoAmount.args = {
189
+ messages: [
190
+ { id: 'msg-1', text: 'Hello!', user: participant },
191
+ {
192
+ id: 'msg-2',
193
+ text: '',
194
+ user: participant,
195
+ metadata: { custom_type: 'MESSAGE_TIP' },
196
+ },
197
+ { id: 'msg-3', text: 'Thank you for the tip!', user: mockUser },
198
+ ],
199
+ }
200
+
171
201
  export const MixedTags: StoryFn<TemplateProps> = Template.bind({})
172
202
  MixedTags.args = {
173
203
  messages: [
@@ -196,6 +226,12 @@ MixedTags.args = {
196
226
  user: participant,
197
227
  metadata: { custom_type: 'MESSAGE_PAID', amount_text: '$10.00' },
198
228
  },
229
+ {
230
+ id: 'msg-6b',
231
+ text: 'Another paid message (no amount_text).',
232
+ user: participant,
233
+ metadata: { custom_type: 'MESSAGE_PAID' },
234
+ },
199
235
  { id: 'msg-7', text: 'Got it, thanks!', user: mockUser },
200
236
  {
201
237
  id: 'msg-8',
@@ -48,6 +48,14 @@ Tip.args = {
48
48
  }),
49
49
  }
50
50
 
51
+ /** Tip with only custom_type (no amount_text). Matches backend when we don't set amount_text. */
52
+ export const TipWithoutAmount: StoryFn<ComponentProps> = Template.bind({})
53
+ TipWithoutAmount.args = {
54
+ message: createMockMessage({
55
+ metadata: { custom_type: 'MESSAGE_TIP' },
56
+ }),
57
+ }
58
+
51
59
  export const TipStandalone: StoryFn<ComponentProps> = Template.bind({})
52
60
  TipStandalone.args = {
53
61
  message: createMockMessage({
@@ -57,6 +65,16 @@ TipStandalone.args = {
57
65
  standalone: true,
58
66
  }
59
67
 
68
+ /** Tip-only bubble with no amount_text (fallback label "Tip"). */
69
+ export const TipStandaloneWithoutAmount: StoryFn<ComponentProps> = Template.bind({})
70
+ TipStandaloneWithoutAmount.args = {
71
+ message: createMockMessage({
72
+ text: '',
73
+ metadata: { custom_type: 'MESSAGE_TIP' },
74
+ }),
75
+ standalone: true,
76
+ }
77
+
60
78
  export const Paid: StoryFn<ComponentProps> = Template.bind({})
61
79
  Paid.args = {
62
80
  message: createMockMessage({
@@ -64,6 +82,14 @@ Paid.args = {
64
82
  }),
65
83
  }
66
84
 
85
+ /** Paid with only custom_type (no amount_text). Fallback label "Delivered with tip". */
86
+ export const PaidWithoutAmount: StoryFn<ComponentProps> = Template.bind({})
87
+ PaidWithoutAmount.args = {
88
+ message: createMockMessage({
89
+ metadata: { custom_type: 'MESSAGE_PAID' },
90
+ }),
91
+ }
92
+
67
93
  export const Chatbot: StoryFn<ComponentProps> = Template.bind({})
68
94
  Chatbot.args = {
69
95
  message: createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } }),
@@ -78,7 +104,7 @@ export const AllVariants: StoryFn = () => {
78
104
  return (
79
105
  <div className="p-12 flex flex-col gap-4">
80
106
  <div className="flex items-center gap-4">
81
- <span className="text-sm w-32">Tip:</span>
107
+ <span className="text-sm w-40">Tip (with amount):</span>
82
108
  <MessageTag
83
109
  message={createMockMessage({
84
110
  metadata: { custom_type: 'MESSAGE_TIP', amount_text: '$10.50' },
@@ -86,7 +112,15 @@ export const AllVariants: StoryFn = () => {
86
112
  />
87
113
  </div>
88
114
  <div className="flex items-center gap-4">
89
- <span className="text-sm w-32">Paid:</span>
115
+ <span className="text-sm w-40">Tip (no amount_text):</span>
116
+ <MessageTag
117
+ message={createMockMessage({
118
+ metadata: { custom_type: 'MESSAGE_TIP' },
119
+ })}
120
+ />
121
+ </div>
122
+ <div className="flex items-center gap-4">
123
+ <span className="text-sm w-40">Paid (with amount):</span>
90
124
  <MessageTag
91
125
  message={createMockMessage({
92
126
  metadata: { custom_type: 'MESSAGE_PAID', amount_text: '$25.00' },
@@ -94,7 +128,15 @@ export const AllVariants: StoryFn = () => {
94
128
  />
95
129
  </div>
96
130
  <div className="flex items-center gap-4">
97
- <span className="text-sm w-32">Tip (standalone):</span>
131
+ <span className="text-sm w-40">Paid (no amount_text):</span>
132
+ <MessageTag
133
+ message={createMockMessage({
134
+ metadata: { custom_type: 'MESSAGE_PAID' },
135
+ })}
136
+ />
137
+ </div>
138
+ <div className="flex items-center gap-4">
139
+ <span className="text-sm w-40">Tip standalone (with amount):</span>
98
140
  <MessageTag
99
141
  message={createMockMessage({
100
142
  text: '',
@@ -104,13 +146,23 @@ export const AllVariants: StoryFn = () => {
104
146
  />
105
147
  </div>
106
148
  <div className="flex items-center gap-4">
107
- <span className="text-sm w-32">Chatbot:</span>
149
+ <span className="text-sm w-40">Tip standalone (no amount_text):</span>
150
+ <MessageTag
151
+ message={createMockMessage({
152
+ text: '',
153
+ metadata: { custom_type: 'MESSAGE_TIP' },
154
+ })}
155
+ standalone
156
+ />
157
+ </div>
158
+ <div className="flex items-center gap-4">
159
+ <span className="text-sm w-40">Chatbot:</span>
108
160
  <MessageTag
109
161
  message={createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } })}
110
162
  />
111
163
  </div>
112
164
  <div className="flex items-center gap-4">
113
- <span className="text-sm w-32">No tag:</span>
165
+ <span className="text-sm w-40">No tag:</span>
114
166
  <MessageTag message={createMockMessage()} />
115
167
  <span className="text-xs text-stone">(renders nothing)</span>
116
168
  </div>
@@ -54,15 +54,17 @@ export const MessageTag = ({
54
54
 
55
55
  if (isTipOrPaid) {
56
56
  const amountText = message.metadata?.amount_text
57
- if (!amountText) return null
58
-
59
57
  const className = standalone
60
58
  ? 'message-tip-standalone'
61
59
  : 'message-tag message-tag--tip'
62
60
 
63
- const label = standalone
64
- ? `${amountText} tip`
65
- : `Delivered with ${amountText} tip`
61
+ const label = amountText
62
+ ? standalone
63
+ ? `${amountText} tip`
64
+ : `Delivered with ${amountText} tip`
65
+ : standalone
66
+ ? 'Tip'
67
+ : 'Delivered with tip'
66
68
 
67
69
  return (
68
70
  <div className={className}>