@linktr.ee/messaging-react 3.5.6 → 3.5.7-rc-1783064389
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-DYe76Xh3.cjs → Card-BY5GWs2L.cjs} +2 -2
- package/dist/{Card-DYe76Xh3.cjs.map → Card-BY5GWs2L.cjs.map} +1 -1
- package/dist/{Card-B5lE5A2D.js → Card-CpgkVykU.js} +3 -3
- package/dist/{Card-B5lE5A2D.js.map → Card-CpgkVykU.js.map} +1 -1
- package/dist/{Card-D_N5hclc.cjs → Card-CsQmLvWE.cjs} +2 -2
- package/dist/{Card-D_N5hclc.cjs.map → Card-CsQmLvWE.cjs.map} +1 -1
- package/dist/{Card-rblNjC58.js → Card-CuWniEOV.js} +2 -2
- package/dist/{Card-rblNjC58.js.map → Card-CuWniEOV.js.map} +1 -1
- package/dist/{Card-MBp3Wg6r.js → Card-DQdw5-A_.js} +2 -2
- package/dist/{Card-MBp3Wg6r.js.map → Card-DQdw5-A_.js.map} +1 -1
- package/dist/{Card-CAJnEq1K.cjs → Card-DdUewLf6.cjs} +2 -2
- package/dist/{Card-CAJnEq1K.cjs.map → Card-DdUewLf6.cjs.map} +1 -1
- package/dist/{LockedThumbnail-BqyPPVrO.js → LockedThumbnail-D5hLQ6Kz.js} +2 -2
- package/dist/{LockedThumbnail-BqyPPVrO.js.map → LockedThumbnail-D5hLQ6Kz.js.map} +1 -1
- package/dist/{LockedThumbnail-C7PpVZQ0.cjs → LockedThumbnail-s_LZkGm4.cjs} +2 -2
- package/dist/{LockedThumbnail-C7PpVZQ0.cjs.map → LockedThumbnail-s_LZkGm4.cjs.map} +1 -1
- package/dist/{index-BXzwYXLT.js → index-3vM1UOPb.js} +1738 -1557
- package/dist/index-3vM1UOPb.js.map +1 -0
- package/dist/index-BIJpO0jL.cjs +2 -0
- package/dist/index-BIJpO0jL.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/src/components/ChannelHeaderRedesign.tsx +231 -0
- package/src/components/ChannelView.stories.tsx +65 -11
- package/src/components/ChannelView.test.tsx +30 -12
- package/src/components/ChannelView.tsx +50 -22
- package/dist/index-BXzwYXLT.js.map +0 -1
- package/dist/index-BflWZq0e.cjs +0 -2
- package/dist/index-BflWZq0e.cjs.map +0 -1
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-BIJpO0jL.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.resolveConversationParticipant=e.resolveConversationParticipant;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.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as c, i as u, j as L, k as h, l as d, m as p, n as v, o as C, p as A, q as k, s as F, t as P, u as b, v as f, w as x, x as y, y as S, z as q, B as z, D as B, E as D, G as E } from "./index-
|
|
1
|
+
import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as c, i as u, j as L, k as h, l as d, m as p, n as v, o as C, p as A, q as k, s as F, t as P, u as b, v as f, w as x, x as y, y as S, z as q, B as z, D as B, E as D, G as E } from "./index-3vM1UOPb.js";
|
|
2
2
|
export {
|
|
3
3
|
e as ActionButton,
|
|
4
4
|
t as Avatar,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linktr.ee/messaging-react",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.7-rc-1783064389",
|
|
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": "
|
|
41
|
+
"@linktr.ee/messaging-core": "2.3.0-rc-1783064389",
|
|
42
42
|
"@phosphor-icons/react": "^2.1.10"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ArrowLeftIcon,
|
|
3
|
+
CaretRightIcon,
|
|
4
|
+
CurrencyDollarIcon,
|
|
5
|
+
StarIcon,
|
|
6
|
+
} from '@phosphor-icons/react'
|
|
7
|
+
import classNames from 'classnames'
|
|
8
|
+
import React from 'react'
|
|
9
|
+
import type { ChannelMemberResponse, Channel as ChannelType } from 'stream-chat'
|
|
10
|
+
import { useChannelStateContext, useChatContext } from 'stream-chat-react'
|
|
11
|
+
|
|
12
|
+
import { useChannelStar } from '../hooks/useChannelStar'
|
|
13
|
+
import type { ChannelViewProps } from '../types'
|
|
14
|
+
import { resolveConversationParticipant } from '../utils/resolveConversationParticipant'
|
|
15
|
+
import { resolveParticipantDisplayName } from '../utils/resolveParticipantDisplayName'
|
|
16
|
+
|
|
17
|
+
import { Avatar } from './Avatar'
|
|
18
|
+
import { ChannelActionsMenu } from './ChannelActionsMenu'
|
|
19
|
+
|
|
20
|
+
const ICON_BTN_CLASS =
|
|
21
|
+
'pointer-events-auto flex size-10 flex-shrink-0 items-center justify-center rounded-full bg-white/65 shadow-[0px_4px_8px_0px_rgba(0,0,0,0.06),0px_0px_0px_1px_rgba(0,0,0,0.04)] backdrop-blur-[40px] transition-filter duration-150 hover:brightness-95 aria-expanded:brightness-95 focus-ring'
|
|
22
|
+
|
|
23
|
+
const CUSTOMER_PAID_TAG = 'CUSTOMER_PAID'
|
|
24
|
+
|
|
25
|
+
const isCustomerPaidTag = (value: unknown) =>
|
|
26
|
+
typeof value === 'string' &&
|
|
27
|
+
value
|
|
28
|
+
.trim()
|
|
29
|
+
.replace(/[\s-]+/g, '_')
|
|
30
|
+
.toUpperCase() === CUSTOMER_PAID_TAG
|
|
31
|
+
|
|
32
|
+
const hasCustomerPaidTag = (participant?: ChannelMemberResponse) => {
|
|
33
|
+
const member = participant as
|
|
34
|
+
| {
|
|
35
|
+
customerTag?: unknown
|
|
36
|
+
customer_tag?: unknown
|
|
37
|
+
}
|
|
38
|
+
| undefined
|
|
39
|
+
|
|
40
|
+
return [member?.customerTag, member?.customer_tag].some(isCustomerPaidTag)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ChannelHeaderRedesignProps {
|
|
44
|
+
onBack?: () => void
|
|
45
|
+
showBackButton: boolean
|
|
46
|
+
showStarButton?: boolean
|
|
47
|
+
dmAgentEnabled?: boolean
|
|
48
|
+
onLeaveConversation?: (channel: ChannelType) => void
|
|
49
|
+
onBlockParticipant?: (participantId?: string) => void
|
|
50
|
+
showDeleteConversation?: boolean
|
|
51
|
+
showBlockParticipant?: boolean
|
|
52
|
+
showReportParticipant?: boolean
|
|
53
|
+
onDeleteConversationClick?: () => void
|
|
54
|
+
onBlockParticipantClick?: () => void
|
|
55
|
+
onReportParticipantClick?: () => void
|
|
56
|
+
customChannelActions?: React.ReactNode
|
|
57
|
+
renderChannelActions?: React.ReactNode
|
|
58
|
+
showChannelInfo?: boolean
|
|
59
|
+
onParticipantNameClick: () => void
|
|
60
|
+
renderHeaderTitleBadges?: ChannelViewProps['renderHeaderTitleBadges']
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const ChannelHeaderRedesign: React.FC<ChannelHeaderRedesignProps> = ({
|
|
64
|
+
onBack,
|
|
65
|
+
showBackButton,
|
|
66
|
+
showStarButton = false,
|
|
67
|
+
dmAgentEnabled = false,
|
|
68
|
+
onLeaveConversation,
|
|
69
|
+
onBlockParticipant,
|
|
70
|
+
showDeleteConversation = true,
|
|
71
|
+
showBlockParticipant = true,
|
|
72
|
+
showReportParticipant = true,
|
|
73
|
+
onDeleteConversationClick,
|
|
74
|
+
onBlockParticipantClick,
|
|
75
|
+
onReportParticipantClick,
|
|
76
|
+
customChannelActions,
|
|
77
|
+
renderChannelActions,
|
|
78
|
+
showChannelInfo = true,
|
|
79
|
+
onParticipantNameClick,
|
|
80
|
+
renderHeaderTitleBadges,
|
|
81
|
+
}) => {
|
|
82
|
+
const { channel } = useChannelStateContext()
|
|
83
|
+
const { client } = useChatContext()
|
|
84
|
+
|
|
85
|
+
const participant = React.useMemo(
|
|
86
|
+
() =>
|
|
87
|
+
resolveConversationParticipant(
|
|
88
|
+
channel.state?.members,
|
|
89
|
+
client?.userID,
|
|
90
|
+
channel.type
|
|
91
|
+
),
|
|
92
|
+
[channel.state?.members, client?.userID, channel.type]
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
const participantName = resolveParticipantDisplayName(participant?.user)
|
|
96
|
+
const participantImage = participant?.user?.image
|
|
97
|
+
const isStarred = useChannelStar(channel)
|
|
98
|
+
const isPaidCustomer = hasCustomerPaidTag(participant)
|
|
99
|
+
const headerTitleBadges = renderHeaderTitleBadges?.({
|
|
100
|
+
channel,
|
|
101
|
+
participant,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const handleStarClick = async () => {
|
|
105
|
+
try {
|
|
106
|
+
if (isStarred) {
|
|
107
|
+
await (channel as ChannelType).unpin()
|
|
108
|
+
} else {
|
|
109
|
+
await (channel as ChannelType).pin()
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error(
|
|
113
|
+
'[ChannelHeaderRedesign] Failed to update pinned status:',
|
|
114
|
+
error
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<div className="@container pointer-events-none sticky top-0 z-10 w-full bg-[linear-gradient(180deg,#FBFAF9_0%,rgba(251,250,249,0.92)_58%,rgba(251,250,249,0)_100%)]">
|
|
121
|
+
<div className="grid min-h-[100px] grid-cols-[40px_minmax(0,1fr)_40px] items-start pb-2 pt-5 @lg:min-h-[104px] @lg:pt-6">
|
|
122
|
+
<div className="flex items-start">
|
|
123
|
+
{showBackButton && (
|
|
124
|
+
<button
|
|
125
|
+
className={classNames(
|
|
126
|
+
ICON_BTN_CLASS,
|
|
127
|
+
'messaging-channel-view-back-button-mobile messaging-channel-view-back-button-desktop'
|
|
128
|
+
)}
|
|
129
|
+
onClick={onBack || (() => {})}
|
|
130
|
+
type="button"
|
|
131
|
+
aria-label="Back to conversations"
|
|
132
|
+
>
|
|
133
|
+
<ArrowLeftIcon className="size-5 text-black/90" />
|
|
134
|
+
</button>
|
|
135
|
+
)}
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div className="flex min-w-0 justify-center" data-dd-privacy="mask">
|
|
139
|
+
<button
|
|
140
|
+
type="button"
|
|
141
|
+
onClick={onParticipantNameClick}
|
|
142
|
+
aria-label={`View details for ${participantName}`}
|
|
143
|
+
className="group pointer-events-auto flex min-w-0 max-w-full appearance-none flex-col items-center border-0 bg-transparent px-2 focus-ring focus-visible:outline-none"
|
|
144
|
+
>
|
|
145
|
+
<Avatar
|
|
146
|
+
id={participant?.user?.id || channel.id || 'unknown'}
|
|
147
|
+
name={participantName}
|
|
148
|
+
image={participantImage}
|
|
149
|
+
dmAgentEnabled={dmAgentEnabled}
|
|
150
|
+
shape="circle"
|
|
151
|
+
size={48}
|
|
152
|
+
className="-mb-2"
|
|
153
|
+
/>
|
|
154
|
+
<span className="relative z-10 inline-flex max-w-full items-center justify-center rounded-full border border-white/10 bg-white/65 py-1.5 pl-3 pr-2 shadow-[0px_0px_0px_0px_rgba(0,0,0,0.04),0px_1px_2px_0px_rgba(0,0,0,0.04),0px_8px_32px_0px_rgba(0,0,0,0.1)] backdrop-blur-[2px] transition-colors duration-150 group-hover:bg-white/80">
|
|
155
|
+
<span className="min-w-0 truncate text-sm font-bold leading-[1.43] tracking-[0.28px] text-black/90">
|
|
156
|
+
{participantName}
|
|
157
|
+
</span>
|
|
158
|
+
<div className="ml-2 flex gap-1">
|
|
159
|
+
{isPaidCustomer && (
|
|
160
|
+
<span
|
|
161
|
+
aria-label="Paid customer"
|
|
162
|
+
className="flex size-4 shrink-0 items-center justify-center rounded-full bg-[#34C759] text-white"
|
|
163
|
+
>
|
|
164
|
+
<CurrencyDollarIcon className="size-2.5" weight="bold" />
|
|
165
|
+
</span>
|
|
166
|
+
)}
|
|
167
|
+
{showStarButton && isStarred && (
|
|
168
|
+
<span
|
|
169
|
+
aria-label="Starred conversation"
|
|
170
|
+
className="flex size-4 shrink-0 items-center justify-center rounded-full bg-[#FFD60A] text-white"
|
|
171
|
+
>
|
|
172
|
+
<StarIcon className="size-2.5" weight="fill" />
|
|
173
|
+
</span>
|
|
174
|
+
)}
|
|
175
|
+
{headerTitleBadges && (
|
|
176
|
+
<span className="shrink-0">{headerTitleBadges}</span>
|
|
177
|
+
)}
|
|
178
|
+
<CaretRightIcon
|
|
179
|
+
aria-hidden="true"
|
|
180
|
+
className="size-4 shrink-0 text-black/65"
|
|
181
|
+
weight="bold"
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
184
|
+
</span>
|
|
185
|
+
</button>
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<div className="flex items-start justify-end gap-2">
|
|
189
|
+
{showStarButton && (
|
|
190
|
+
<button
|
|
191
|
+
className={ICON_BTN_CLASS}
|
|
192
|
+
onClick={handleStarClick}
|
|
193
|
+
type="button"
|
|
194
|
+
aria-pressed={isStarred}
|
|
195
|
+
aria-label={
|
|
196
|
+
isStarred ? 'Unstar conversation' : 'Star conversation'
|
|
197
|
+
}
|
|
198
|
+
>
|
|
199
|
+
<StarIcon
|
|
200
|
+
className={classNames('size-5', {
|
|
201
|
+
'text-[#FFD60A]': isStarred,
|
|
202
|
+
'text-black/90': !isStarred,
|
|
203
|
+
})}
|
|
204
|
+
weight={isStarred ? 'fill' : 'regular'}
|
|
205
|
+
/>
|
|
206
|
+
</button>
|
|
207
|
+
)}
|
|
208
|
+
{showChannelInfo &&
|
|
209
|
+
(renderChannelActions !== undefined ? (
|
|
210
|
+
renderChannelActions
|
|
211
|
+
) : (
|
|
212
|
+
<ChannelActionsMenu
|
|
213
|
+
channel={channel as ChannelType}
|
|
214
|
+
participant={participant}
|
|
215
|
+
showDeleteConversation={showDeleteConversation}
|
|
216
|
+
showBlockParticipant={showBlockParticipant}
|
|
217
|
+
showReportParticipant={showReportParticipant}
|
|
218
|
+
onLeaveConversation={onLeaveConversation}
|
|
219
|
+
onBlockParticipant={onBlockParticipant}
|
|
220
|
+
onDeleteConversationClick={onDeleteConversationClick}
|
|
221
|
+
onBlockParticipantClick={onBlockParticipantClick}
|
|
222
|
+
onReportParticipantClick={onReportParticipantClick}
|
|
223
|
+
customChannelActions={customChannelActions}
|
|
224
|
+
triggerClassName={ICON_BTN_CLASS}
|
|
225
|
+
/>
|
|
226
|
+
))}
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
)
|
|
231
|
+
}
|
|
@@ -16,6 +16,7 @@ import { ChannelView } from './ChannelView'
|
|
|
16
16
|
import { ChannelEmptyState } from './MessagingShell/ChannelEmptyState'
|
|
17
17
|
|
|
18
18
|
type ComponentProps = React.ComponentProps<typeof ChannelView>
|
|
19
|
+
const SCROLLABLE_MESSAGE_COUNT = 10
|
|
19
20
|
|
|
20
21
|
const meta: Meta<ComponentProps> = {
|
|
21
22
|
title: 'ChannelView',
|
|
@@ -41,7 +42,9 @@ const createMockChannel = async (
|
|
|
41
42
|
client: StreamChat,
|
|
42
43
|
hasMessages = true,
|
|
43
44
|
followerStatus?: string | boolean,
|
|
44
|
-
isFrozen = false
|
|
45
|
+
isFrozen = false,
|
|
46
|
+
participantCustomerTag?: string,
|
|
47
|
+
hasScrollableMessages = false
|
|
45
48
|
) => {
|
|
46
49
|
const participant = mockParticipants[0]
|
|
47
50
|
|
|
@@ -101,6 +104,34 @@ const createMockChannel = async (
|
|
|
101
104
|
cid: 'messaging:storybook-channel-1',
|
|
102
105
|
mentioned_users: [],
|
|
103
106
|
},
|
|
107
|
+
...(hasScrollableMessages
|
|
108
|
+
? Array.from({ length: SCROLLABLE_MESSAGE_COUNT }, (_, index) => {
|
|
109
|
+
const isParticipantMessage = index % 2 === 0
|
|
110
|
+
const user = isParticipantMessage ? participant : mockUser
|
|
111
|
+
const text = isParticipantMessage
|
|
112
|
+
? `Here is another message to show how the redesigned header floats above the thread (${index + 1}).`
|
|
113
|
+
: `Replying so the conversation has enough content to scroll under the header (${index + 1}).`
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
id: `msg-extra-${index + 1}`,
|
|
117
|
+
text,
|
|
118
|
+
type: 'regular' as const,
|
|
119
|
+
created_at: minutesAgo(Math.max(1, 25 - index)),
|
|
120
|
+
updated_at: minutesAgo(Math.max(1, 25 - index)),
|
|
121
|
+
user,
|
|
122
|
+
html: `<p>${text}</p>`,
|
|
123
|
+
attachments: [],
|
|
124
|
+
latest_reactions: [],
|
|
125
|
+
own_reactions: [],
|
|
126
|
+
reaction_counts: {},
|
|
127
|
+
reaction_scores: {},
|
|
128
|
+
reply_count: 0,
|
|
129
|
+
status: 'received',
|
|
130
|
+
cid: 'messaging:storybook-channel-1',
|
|
131
|
+
mentioned_users: [],
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
: []),
|
|
104
135
|
]
|
|
105
136
|
: []
|
|
106
137
|
|
|
@@ -118,7 +149,11 @@ const createMockChannel = async (
|
|
|
118
149
|
}
|
|
119
150
|
|
|
120
151
|
// Create a real channel using the client
|
|
121
|
-
const channel = client.channel(
|
|
152
|
+
const channel = client.channel(
|
|
153
|
+
'messaging',
|
|
154
|
+
'storybook-channel-1',
|
|
155
|
+
channelData
|
|
156
|
+
)
|
|
122
157
|
|
|
123
158
|
// Mock the watch method to return mocked data
|
|
124
159
|
channel.watch = async () => {
|
|
@@ -142,6 +177,7 @@ const createMockChannel = async (
|
|
|
142
177
|
user_id: participant.id,
|
|
143
178
|
role: 'member',
|
|
144
179
|
is_account: true,
|
|
180
|
+
customerTag: participantCustomerTag,
|
|
145
181
|
},
|
|
146
182
|
}
|
|
147
183
|
return {
|
|
@@ -176,12 +212,16 @@ type TemplateProps = ComponentProps & {
|
|
|
176
212
|
name?: string
|
|
177
213
|
image?: string
|
|
178
214
|
}
|
|
215
|
+
participantCustomerTag?: string
|
|
216
|
+
hasScrollableMessages?: boolean
|
|
179
217
|
}
|
|
180
218
|
|
|
181
219
|
const Template: StoryFn<TemplateProps> = (args) => {
|
|
182
220
|
const {
|
|
183
221
|
followerStatus,
|
|
184
222
|
isFrozen = false,
|
|
223
|
+
participantCustomerTag,
|
|
224
|
+
hasScrollableMessages,
|
|
185
225
|
typingUser,
|
|
186
226
|
...channelViewProps
|
|
187
227
|
} = args
|
|
@@ -193,16 +233,27 @@ const Template: StoryFn<TemplateProps> = (args) => {
|
|
|
193
233
|
client.user = mockUser
|
|
194
234
|
return client
|
|
195
235
|
})
|
|
196
|
-
|
|
236
|
+
|
|
197
237
|
const [channel, setChannel] = React.useState<ChannelType | null>(null)
|
|
198
238
|
|
|
199
239
|
useEffect(() => {
|
|
200
|
-
createMockChannel(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
240
|
+
createMockChannel(
|
|
241
|
+
client,
|
|
242
|
+
true,
|
|
243
|
+
followerStatus,
|
|
244
|
+
isFrozen,
|
|
245
|
+
participantCustomerTag,
|
|
246
|
+
hasScrollableMessages
|
|
247
|
+
).then((mockChannel) => {
|
|
248
|
+
setChannel(mockChannel)
|
|
249
|
+
})
|
|
250
|
+
}, [
|
|
251
|
+
client,
|
|
252
|
+
followerStatus,
|
|
253
|
+
isFrozen,
|
|
254
|
+
participantCustomerTag,
|
|
255
|
+
hasScrollableMessages,
|
|
256
|
+
])
|
|
206
257
|
|
|
207
258
|
useEffect(() => {
|
|
208
259
|
if (!channel || !typingUser) {
|
|
@@ -256,6 +307,9 @@ export const ParticipantIdentityTrigger: StoryFn<TemplateProps> = Template.bind(
|
|
|
256
307
|
)
|
|
257
308
|
ParticipantIdentityTrigger.args = {
|
|
258
309
|
showBackButton: false,
|
|
310
|
+
showStarButton: true,
|
|
311
|
+
participantCustomerTag: 'CUSTOMER_PAID',
|
|
312
|
+
hasScrollableMessages: true,
|
|
259
313
|
onParticipantNameClick: () =>
|
|
260
314
|
// eslint-disable-next-line no-alert
|
|
261
315
|
window.alert('Participant details clicked — open Thread content'),
|
|
@@ -264,7 +318,7 @@ ParticipantIdentityTrigger.parameters = {
|
|
|
264
318
|
docs: {
|
|
265
319
|
description: {
|
|
266
320
|
story:
|
|
267
|
-
'Header with `onParticipantNameClick` set: the
|
|
321
|
+
'Header with `onParticipantNameClick` set: the redesigned floating header centers the avatar and name pill, shows paid/star badges when present, and fires the callback when clicked (shows an alert here). With the prop omitted (see Default) the previous header remains in use.',
|
|
268
322
|
},
|
|
269
323
|
},
|
|
270
324
|
}
|
|
@@ -542,7 +596,7 @@ const EmptyTemplate: StoryFn<ComponentProps> = (args) => {
|
|
|
542
596
|
client.user = mockUser
|
|
543
597
|
return client
|
|
544
598
|
})
|
|
545
|
-
|
|
599
|
+
|
|
546
600
|
const [channel, setChannel] = React.useState<ChannelType | null>(null)
|
|
547
601
|
|
|
548
602
|
useEffect(() => {
|
|
@@ -22,7 +22,9 @@ vi.mock('stream-chat-react', () => ({
|
|
|
22
22
|
Window: ({ children }: { children: React.ReactNode }) => (
|
|
23
23
|
<div data-testid="window">{children}</div>
|
|
24
24
|
),
|
|
25
|
-
MessageList: () =>
|
|
25
|
+
MessageList: ({ head }: { head?: React.ReactElement }) => (
|
|
26
|
+
<div data-testid="message-list">{head}</div>
|
|
27
|
+
),
|
|
26
28
|
WithComponents: ({ children }: { children: React.ReactNode }) => (
|
|
27
29
|
<>{children}</>
|
|
28
30
|
),
|
|
@@ -100,9 +102,11 @@ const createChannel = ({
|
|
|
100
102
|
username: undefined as string | undefined,
|
|
101
103
|
is_account: true,
|
|
102
104
|
},
|
|
105
|
+
otherMemberCustomerTag,
|
|
103
106
|
}: {
|
|
104
107
|
currentUserId?: 'visitor-1' | 'linker-1'
|
|
105
108
|
currentUserRole?: 'owner' | 'member'
|
|
109
|
+
otherMemberCustomerTag?: string
|
|
106
110
|
otherUser?: {
|
|
107
111
|
id: string
|
|
108
112
|
name?: string
|
|
@@ -134,6 +138,7 @@ const createChannel = ({
|
|
|
134
138
|
is_account:
|
|
135
139
|
otherUser.is_account ?? currentUserId === 'visitor-1',
|
|
136
140
|
},
|
|
141
|
+
customerTag: otherMemberCustomerTag,
|
|
137
142
|
role: currentUserRole === 'owner' ? 'member' : 'owner',
|
|
138
143
|
},
|
|
139
144
|
},
|
|
@@ -203,7 +208,7 @@ describe('ChannelView', () => {
|
|
|
203
208
|
)
|
|
204
209
|
})
|
|
205
210
|
|
|
206
|
-
it('renders the
|
|
211
|
+
it('renders the redesigned header button when onParticipantNameClick is provided', () => {
|
|
207
212
|
const onParticipantNameClick = vi.fn()
|
|
208
213
|
renderWithProviders(
|
|
209
214
|
<ChannelView
|
|
@@ -212,29 +217,42 @@ describe('ChannelView', () => {
|
|
|
212
217
|
/>
|
|
213
218
|
)
|
|
214
219
|
|
|
215
|
-
|
|
216
|
-
// hidden via CSS), so there is at least one match.
|
|
217
|
-
const buttons = screen.getAllByRole('button', {
|
|
220
|
+
const button = screen.getByRole('button', {
|
|
218
221
|
name: /view details for linker/i,
|
|
219
222
|
})
|
|
220
|
-
expect(
|
|
221
|
-
expect(buttons[0]).toHaveClass(
|
|
223
|
+
expect(button).toHaveClass(
|
|
222
224
|
'appearance-none',
|
|
223
225
|
'border-0',
|
|
224
226
|
'bg-transparent',
|
|
225
|
-
'
|
|
226
|
-
'px-1',
|
|
227
|
-
'py-0.5'
|
|
227
|
+
'flex-col'
|
|
228
228
|
)
|
|
229
229
|
|
|
230
230
|
const avatars = screen.getAllByTestId('avatar')
|
|
231
231
|
expect(avatars.length).toBeGreaterThanOrEqual(1)
|
|
232
|
-
expect(avatars[0].closest('button')).toBe(
|
|
232
|
+
expect(avatars[0].closest('button')).toBe(button)
|
|
233
|
+
expect(screen.getByTestId('channel-actions-menu')).toBeInTheDocument()
|
|
233
234
|
|
|
234
|
-
|
|
235
|
+
button.click()
|
|
235
236
|
expect(onParticipantNameClick).toHaveBeenCalledTimes(1)
|
|
236
237
|
})
|
|
237
238
|
|
|
239
|
+
it('renders redesigned header badges for paid and starred conversations', () => {
|
|
240
|
+
mockIsStarred = true
|
|
241
|
+
|
|
242
|
+
renderWithProviders(
|
|
243
|
+
<ChannelView
|
|
244
|
+
channel={createChannel({
|
|
245
|
+
otherMemberCustomerTag: 'CUSTOMER_PAID',
|
|
246
|
+
})}
|
|
247
|
+
onParticipantNameClick={vi.fn()}
|
|
248
|
+
showStarButton={true}
|
|
249
|
+
/>
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
expect(screen.getByLabelText('Paid customer')).toBeInTheDocument()
|
|
253
|
+
expect(screen.getByLabelText('Starred conversation')).toBeInTheDocument()
|
|
254
|
+
})
|
|
255
|
+
|
|
238
256
|
it('renders the actions menu by default', () => {
|
|
239
257
|
renderWithProviders(<ChannelView channel={createChannel()} />)
|
|
240
258
|
|
|
@@ -25,6 +25,7 @@ import { resolveParticipantDisplayName } from '../utils/resolveParticipantDispla
|
|
|
25
25
|
|
|
26
26
|
import { Avatar } from './Avatar'
|
|
27
27
|
import { ChannelActionsMenu } from './ChannelActionsMenu'
|
|
28
|
+
import { ChannelHeaderRedesign } from './ChannelHeaderRedesign'
|
|
28
29
|
import { CustomDateSeparator } from './CustomDateSeparator'
|
|
29
30
|
import { CustomMessage } from './CustomMessage'
|
|
30
31
|
import { CustomMessageActions } from './CustomMessage/CustomMessageActions'
|
|
@@ -497,27 +498,28 @@ const ChannelViewInner: React.FC<{
|
|
|
497
498
|
>
|
|
498
499
|
<Window>
|
|
499
500
|
{/* Custom Channel Header */}
|
|
500
|
-
|
|
501
|
-
<
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
501
|
+
{!onParticipantNameClick && (
|
|
502
|
+
<div key="lt-channel-header">
|
|
503
|
+
<CustomChannelHeader
|
|
504
|
+
onBack={onBack}
|
|
505
|
+
showBackButton={showBackButton}
|
|
506
|
+
showChannelInfo={showChannelInfo}
|
|
507
|
+
showStarButton={showStarButton}
|
|
508
|
+
dmAgentEnabled={showDmAgentHeader}
|
|
509
|
+
onLeaveConversation={onLeaveConversation}
|
|
510
|
+
onBlockParticipant={onBlockParticipant}
|
|
511
|
+
showDeleteConversation={showDeleteConversation}
|
|
512
|
+
showBlockParticipant={showBlockParticipant}
|
|
513
|
+
showReportParticipant={showReportParticipant}
|
|
514
|
+
onDeleteConversationClick={onDeleteConversationClick}
|
|
515
|
+
onBlockParticipantClick={onBlockParticipantClick}
|
|
516
|
+
onReportParticipantClick={onReportParticipantClick}
|
|
517
|
+
customChannelActions={customChannelActions}
|
|
518
|
+
renderChannelActions={renderChannelActions}
|
|
519
|
+
renderHeaderTitleBadges={renderHeaderTitleBadges}
|
|
520
|
+
/>
|
|
521
|
+
</div>
|
|
522
|
+
)}
|
|
521
523
|
|
|
522
524
|
{/* Custom Banner/Summary */}
|
|
523
525
|
{renderChannelBanner ? (
|
|
@@ -531,7 +533,33 @@ const ChannelViewInner: React.FC<{
|
|
|
531
533
|
key="lt-channel-message-list"
|
|
532
534
|
className="flex-1 overflow-hidden relative"
|
|
533
535
|
>
|
|
534
|
-
<MessageList
|
|
536
|
+
<MessageList
|
|
537
|
+
head={
|
|
538
|
+
onParticipantNameClick ? (
|
|
539
|
+
<ChannelHeaderRedesign
|
|
540
|
+
onBack={onBack}
|
|
541
|
+
showBackButton={showBackButton}
|
|
542
|
+
showChannelInfo={showChannelInfo}
|
|
543
|
+
showStarButton={showStarButton}
|
|
544
|
+
dmAgentEnabled={showDmAgentHeader}
|
|
545
|
+
onLeaveConversation={onLeaveConversation}
|
|
546
|
+
onBlockParticipant={onBlockParticipant}
|
|
547
|
+
showDeleteConversation={showDeleteConversation}
|
|
548
|
+
showBlockParticipant={showBlockParticipant}
|
|
549
|
+
showReportParticipant={showReportParticipant}
|
|
550
|
+
onDeleteConversationClick={onDeleteConversationClick}
|
|
551
|
+
onBlockParticipantClick={onBlockParticipantClick}
|
|
552
|
+
onReportParticipantClick={onReportParticipantClick}
|
|
553
|
+
customChannelActions={customChannelActions}
|
|
554
|
+
renderChannelActions={renderChannelActions}
|
|
555
|
+
onParticipantNameClick={onParticipantNameClick}
|
|
556
|
+
renderHeaderTitleBadges={renderHeaderTitleBadges}
|
|
557
|
+
/>
|
|
558
|
+
) : undefined
|
|
559
|
+
}
|
|
560
|
+
hideDeletedMessages
|
|
561
|
+
hideNewMessageSeparator={false}
|
|
562
|
+
/>
|
|
535
563
|
</div>
|
|
536
564
|
|
|
537
565
|
{renderConversationFooter ? (
|