@linktr.ee/messaging-react 4.0.0-rc-1786390369 → 4.0.0
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-DlOQrDhW.js → Card-DNfF_nfR.js} +2 -2
- package/dist/{Card-DlOQrDhW.js.map → Card-DNfF_nfR.js.map} +1 -1
- package/dist/index-B0CZqFER.cjs.map +1 -1
- package/dist/{index-CB548cbP.js → index-Dyxu8r07.js} +104 -104
- package/dist/index-Dyxu8r07.js.map +1 -0
- package/dist/index.d.ts +9 -7
- package/dist/index.js +1 -1
- package/dist/testing.d.ts +2 -2
- package/package.json +2 -2
- package/src/components/ChannelView.outbound-resolution.integration.test.tsx +1 -1
- package/src/components/ChannelView.tsx +3 -3
- package/src/components/CustomMessage/CustomMessage.stories.tsx +4 -4
- package/src/components/CustomMessage/OutboundContext.test.ts +17 -14
- package/src/components/CustomMessage/OutboundContext.ts +22 -22
- package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +2 -2
- package/src/components/CustomMessage/index.tsx +5 -3
- package/src/stream-custom-data.ts +2 -2
- package/src/types.ts +7 -5
- package/dist/index-CB548cbP.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -393,10 +393,11 @@ export declare interface ChannelViewProps {
|
|
|
393
393
|
*/
|
|
394
394
|
onOutboundClick?: OutboundClickHandler;
|
|
395
395
|
/**
|
|
396
|
-
* Resolves an outbound record id to the current
|
|
397
|
-
* host must provide a new resolver reference
|
|
398
|
-
* changes so ChannelView re-renders and publishes
|
|
399
|
-
* rows. Missing records stay unresolved and render
|
|
396
|
+
* Resolves `metadata.outbound_id` (an outbound record id) to the current
|
|
397
|
+
* automation id and name. The host must provide a new resolver reference
|
|
398
|
+
* when a returned outbound changes so ChannelView re-renders and publishes
|
|
399
|
+
* the new value to memoized rows. Missing records stay unresolved and render
|
|
400
|
+
* no label.
|
|
400
401
|
*/
|
|
401
402
|
resolveOutbound?: OutboundResolver;
|
|
402
403
|
/**
|
|
@@ -1403,8 +1404,8 @@ export declare interface MessageMetadata {
|
|
|
1403
1404
|
*/
|
|
1404
1405
|
sent_from?: 'stack_detail';
|
|
1405
1406
|
/**
|
|
1406
|
-
* Opaque
|
|
1407
|
-
*
|
|
1407
|
+
* Opaque outbound record id on automation messages. The Stream wire field is
|
|
1408
|
+
* `outbound_id`; resolver APIs name this value `outboundRecordId` explicitly.
|
|
1408
1409
|
*/
|
|
1409
1410
|
outbound_id?: string;
|
|
1410
1411
|
}
|
|
@@ -1549,7 +1550,7 @@ export declare function optimizeMessagingAttachmentUrl(url: string | undefined |
|
|
|
1549
1550
|
|
|
1550
1551
|
export declare type OutboundClickHandler = (outbound: ResolvedOutbound) => void;
|
|
1551
1552
|
|
|
1552
|
-
export declare type OutboundResolver = (
|
|
1553
|
+
export declare type OutboundResolver = (outboundRecordId: string) => ResolvedOutbound | undefined;
|
|
1553
1554
|
|
|
1554
1555
|
/**
|
|
1555
1556
|
* Generic participant interface for different host environments
|
|
@@ -1636,6 +1637,7 @@ export declare interface ReceivedBubbleProps extends MessageBubbleBaseProps {
|
|
|
1636
1637
|
export declare function resolveConversationParticipant(members: ChannelMembers | undefined, currentUserId: string | undefined, channelType: string | undefined): ChannelMember | undefined;
|
|
1637
1638
|
|
|
1638
1639
|
export declare type ResolvedOutbound = {
|
|
1640
|
+
/** Automation id referenced by the outbound record. */
|
|
1639
1641
|
id: string;
|
|
1640
1642
|
name?: string;
|
|
1641
1643
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, b as t, C as i, c as n, d as o, e as m, F as r, f as l, L as g, h as c, M, i as h, j as L, k as u, l as d, R as p, m as C, n as v, p as A, q as k, s as F, t as b, u as P, v as f, w as x, o as y, x as z, y as S, z as q, B, D, E, G as R } from "./index-
|
|
1
|
+
import { a as e, b as t, C as i, c as n, d as o, e as m, F as r, f as l, L as g, h as c, M, i as h, j as L, k as u, l as d, R as p, m as C, n as v, p as A, q as k, s as F, t as b, u as P, v as f, w as x, o as y, x as z, y as S, z as q, B, D, E, G as R } from "./index-Dyxu8r07.js";
|
|
2
2
|
export {
|
|
3
3
|
e as ActionButton,
|
|
4
4
|
t as Avatar,
|
package/dist/testing.d.ts
CHANGED
|
@@ -57,8 +57,8 @@ export declare interface MessageMetadata {
|
|
|
57
57
|
*/
|
|
58
58
|
sent_from?: 'stack_detail';
|
|
59
59
|
/**
|
|
60
|
-
* Opaque
|
|
61
|
-
*
|
|
60
|
+
* Opaque outbound record id on automation messages. The Stream wire field is
|
|
61
|
+
* `outbound_id`; resolver APIs name this value `outboundRecordId` explicitly.
|
|
62
62
|
*/
|
|
63
63
|
outbound_id?: string;
|
|
64
64
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linktr.ee/messaging-react",
|
|
3
|
-
"version": "4.0.0
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "React messaging components built on messaging-core for web applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"chromatic:local": "yarn storybook:build && chromatic"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@linktr.ee/messaging-core": "2.4.0
|
|
53
|
+
"@linktr.ee/messaging-core": "^2.4.0",
|
|
54
54
|
"@linktr.ee/messaging-taxonomy": "^0.9.0",
|
|
55
55
|
"@phosphor-icons/react": "^2.1.10"
|
|
56
56
|
},
|
|
@@ -54,7 +54,7 @@ const createChannel = () => {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
describe('ChannelView outbound resolution', () => {
|
|
57
|
-
it('updates an existing Stream message row when its outbound lookup resolves', async () => {
|
|
57
|
+
it('updates an existing Stream message row when its outbound record lookup resolves', async () => {
|
|
58
58
|
const { channel, client } = createChannel()
|
|
59
59
|
const firstResolver = () => undefined
|
|
60
60
|
const secondResolver = () => ({
|
|
@@ -19,7 +19,7 @@ import { CustomMessage } from './CustomMessage'
|
|
|
19
19
|
import { CustomMessageActions } from './CustomMessage/CustomMessageActions'
|
|
20
20
|
import {
|
|
21
21
|
OutboundContext,
|
|
22
|
-
|
|
22
|
+
useOutboundsByRecordId,
|
|
23
23
|
} from './CustomMessage/OutboundContext'
|
|
24
24
|
import { CustomMessageInput } from './CustomMessageInput'
|
|
25
25
|
import { CustomSystemMessage } from './CustomSystemMessage'
|
|
@@ -105,7 +105,7 @@ const ChannelViewInner: React.FC<{
|
|
|
105
105
|
: undefined
|
|
106
106
|
// Resolve outside memoized Stream rows so current automation details publish
|
|
107
107
|
// without remounting the rows.
|
|
108
|
-
const
|
|
108
|
+
const outboundsByRecordId = useOutboundsByRecordId(messages, resolveOutbound)
|
|
109
109
|
|
|
110
110
|
const hasVisibleMessages = channel.state.messages.some(
|
|
111
111
|
(message) => message.type !== 'deleted'
|
|
@@ -159,7 +159,7 @@ const ChannelViewInner: React.FC<{
|
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
return (
|
|
162
|
-
<OutboundContext.Provider value={
|
|
162
|
+
<OutboundContext.Provider value={outboundsByRecordId}>
|
|
163
163
|
<WithComponents
|
|
164
164
|
overrides={{
|
|
165
165
|
Message: MessageOverride,
|
|
@@ -27,7 +27,7 @@ import type { OutboundResolver } from '../../types'
|
|
|
27
27
|
import CustomTypingIndicator from '../CustomTypingIndicator'
|
|
28
28
|
|
|
29
29
|
import { CustomMessageActions } from './CustomMessageActions'
|
|
30
|
-
import { OutboundContext,
|
|
30
|
+
import { OutboundContext, buildOutboundsByRecordId } from './OutboundContext'
|
|
31
31
|
|
|
32
32
|
import { CustomMessage } from './index'
|
|
33
33
|
|
|
@@ -167,8 +167,8 @@ const TemplateInner: React.FC<{
|
|
|
167
167
|
return () => clearTimeout(timer)
|
|
168
168
|
}, [channel, client, typingUser])
|
|
169
169
|
|
|
170
|
-
const
|
|
171
|
-
() =>
|
|
170
|
+
const outboundsByRecordId = React.useMemo(
|
|
171
|
+
() => buildOutboundsByRecordId(messages, resolveOutbound),
|
|
172
172
|
[messages, resolveOutbound]
|
|
173
173
|
)
|
|
174
174
|
|
|
@@ -183,7 +183,7 @@ const TemplateInner: React.FC<{
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
return (
|
|
186
|
-
<OutboundContext.Provider value={
|
|
186
|
+
<OutboundContext.Provider value={outboundsByRecordId}>
|
|
187
187
|
<Chat client={client}>
|
|
188
188
|
<div className="h-screen w-full bg-white">
|
|
189
189
|
<Channel
|
|
@@ -3,12 +3,15 @@ import { describe, expect, it, vi } from 'vitest'
|
|
|
3
3
|
import { renderHook } from '../../test/utils'
|
|
4
4
|
import type { OutboundResolver } from '../../types'
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
buildOutboundsByRecordId,
|
|
8
|
+
useOutboundsByRecordId,
|
|
9
|
+
} from './OutboundContext'
|
|
7
10
|
|
|
8
|
-
describe('
|
|
11
|
+
describe('buildOutboundsByRecordId', () => {
|
|
9
12
|
it('returns undefined when no resolver is provided', () => {
|
|
10
13
|
expect(
|
|
11
|
-
|
|
14
|
+
buildOutboundsByRecordId(
|
|
12
15
|
[{ metadata: { outbound_id: 'outbound-1' } }],
|
|
13
16
|
undefined
|
|
14
17
|
)
|
|
@@ -18,19 +21,19 @@ describe('buildOutboundsById', () => {
|
|
|
18
21
|
it('returns undefined without invoking the resolver when there are no messages', () => {
|
|
19
22
|
const resolveOutbound = vi.fn()
|
|
20
23
|
|
|
21
|
-
expect(
|
|
22
|
-
expect(
|
|
24
|
+
expect(buildOutboundsByRecordId(undefined, resolveOutbound)).toBeUndefined()
|
|
25
|
+
expect(buildOutboundsByRecordId([], resolveOutbound)).toBeUndefined()
|
|
23
26
|
expect(resolveOutbound).not.toHaveBeenCalled()
|
|
24
27
|
})
|
|
25
28
|
|
|
26
|
-
it('resolves each unique outbound id once', () => {
|
|
27
|
-
const resolveOutbound = vi.fn((
|
|
28
|
-
id: `automation-for-${
|
|
29
|
-
name: `name-for-${
|
|
29
|
+
it('resolves each unique outbound record id once', () => {
|
|
30
|
+
const resolveOutbound = vi.fn((outboundRecordId: string) => ({
|
|
31
|
+
id: `automation-for-${outboundRecordId}`,
|
|
32
|
+
name: `name-for-${outboundRecordId}`,
|
|
30
33
|
}))
|
|
31
34
|
|
|
32
35
|
expect(
|
|
33
|
-
|
|
36
|
+
buildOutboundsByRecordId(
|
|
34
37
|
[
|
|
35
38
|
{ metadata: { outbound_id: 'outbound-1' } },
|
|
36
39
|
{ metadata: { outbound_id: 'outbound-1' } },
|
|
@@ -54,7 +57,7 @@ describe('buildOutboundsById', () => {
|
|
|
54
57
|
|
|
55
58
|
it('omits outbound records the resolver cannot resolve', () => {
|
|
56
59
|
expect(
|
|
57
|
-
|
|
60
|
+
buildOutboundsByRecordId(
|
|
58
61
|
[{ metadata: { outbound_id: 'outbound-1' } }],
|
|
59
62
|
() => undefined
|
|
60
63
|
)
|
|
@@ -62,17 +65,17 @@ describe('buildOutboundsById', () => {
|
|
|
62
65
|
})
|
|
63
66
|
})
|
|
64
67
|
|
|
65
|
-
describe('
|
|
68
|
+
describe('useOutboundsByRecordId', () => {
|
|
66
69
|
const messages = [{ metadata: { outbound_id: 'outbound-1' } }]
|
|
67
70
|
|
|
68
71
|
const renderWithResolver = (resolver: OutboundResolver) =>
|
|
69
72
|
renderHook(
|
|
70
73
|
({ resolveOutbound }: { resolveOutbound: OutboundResolver }) =>
|
|
71
|
-
|
|
74
|
+
useOutboundsByRecordId(messages, resolveOutbound),
|
|
72
75
|
{ initialProps: { resolveOutbound: resolver } }
|
|
73
76
|
)
|
|
74
77
|
|
|
75
|
-
it('publishes a renamed automation under the same outbound id', () => {
|
|
78
|
+
it('publishes a renamed automation under the same outbound record id', () => {
|
|
76
79
|
const { result, rerender } = renderWithResolver(() => ({
|
|
77
80
|
id: 'automation-1',
|
|
78
81
|
name: 'July 9th Class absentee',
|
|
@@ -2,18 +2,18 @@ import { createContext, useState } from 'react'
|
|
|
2
2
|
|
|
3
3
|
import type { OutboundResolver, ResolvedOutbound } from '../../types'
|
|
4
4
|
|
|
5
|
-
/** Current outbound sources keyed by the record id stored on each message. */
|
|
6
|
-
export type
|
|
5
|
+
/** Current outbound sources keyed by the outbound record id stored on each message. */
|
|
6
|
+
export type OutboundsByRecordId = Readonly<Record<string, ResolvedOutbound>>
|
|
7
7
|
|
|
8
|
-
export const OutboundContext = createContext<
|
|
8
|
+
export const OutboundContext = createContext<OutboundsByRecordId | undefined>(
|
|
9
9
|
undefined
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const outboundRecordIdFromMessage = (message: {
|
|
13
13
|
metadata?: { outbound_id?: unknown }
|
|
14
14
|
}): string | undefined => {
|
|
15
|
-
const
|
|
16
|
-
return typeof
|
|
15
|
+
const outboundRecordId = message.metadata?.outbound_id
|
|
16
|
+
return typeof outboundRecordId === 'string' ? outboundRecordId : undefined
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -22,10 +22,10 @@ const outboundIdFromMessage = (message: {
|
|
|
22
22
|
* Built outside memoized Stream rows so a new resolver reference can publish
|
|
23
23
|
* current automation details without remounting the Stream message rows.
|
|
24
24
|
*/
|
|
25
|
-
export const
|
|
25
|
+
export const buildOutboundsByRecordId = (
|
|
26
26
|
messages: readonly { metadata?: { outbound_id?: unknown } }[] | undefined,
|
|
27
27
|
resolveOutbound: OutboundResolver | undefined
|
|
28
|
-
):
|
|
28
|
+
): OutboundsByRecordId | undefined => {
|
|
29
29
|
if (!resolveOutbound || !messages?.length) {
|
|
30
30
|
return undefined
|
|
31
31
|
}
|
|
@@ -34,13 +34,13 @@ export const buildOutboundsById = (
|
|
|
34
34
|
let outbounds: Record<string, ResolvedOutbound> | undefined
|
|
35
35
|
|
|
36
36
|
for (const message of messages) {
|
|
37
|
-
const
|
|
38
|
-
if (!
|
|
37
|
+
const outboundRecordId = outboundRecordIdFromMessage(message)
|
|
38
|
+
if (!outboundRecordId || seen.has(outboundRecordId)) {
|
|
39
39
|
continue
|
|
40
40
|
}
|
|
41
|
-
seen.add(
|
|
41
|
+
seen.add(outboundRecordId)
|
|
42
42
|
|
|
43
|
-
const resolved = resolveOutbound(
|
|
43
|
+
const resolved = resolveOutbound(outboundRecordId)
|
|
44
44
|
if (!resolved) {
|
|
45
45
|
continue
|
|
46
46
|
}
|
|
@@ -48,7 +48,7 @@ export const buildOutboundsById = (
|
|
|
48
48
|
outbounds ??= {}
|
|
49
49
|
// Snapshot resolver-owned values so a host that mutates and reuses its
|
|
50
50
|
// cached object cannot also mutate the previously published context map.
|
|
51
|
-
outbounds[
|
|
51
|
+
outbounds[outboundRecordId] = {
|
|
52
52
|
id: resolved.id,
|
|
53
53
|
...(resolved.name !== undefined ? { name: resolved.name } : {}),
|
|
54
54
|
}
|
|
@@ -58,8 +58,8 @@ export const buildOutboundsById = (
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const areOutboundsEqual = (
|
|
61
|
-
previous:
|
|
62
|
-
next:
|
|
61
|
+
previous: OutboundsByRecordId | undefined,
|
|
62
|
+
next: OutboundsByRecordId | undefined
|
|
63
63
|
): boolean => {
|
|
64
64
|
if (previous === next) {
|
|
65
65
|
return true
|
|
@@ -75,9 +75,9 @@ const areOutboundsEqual = (
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
return previousIds.every(
|
|
78
|
-
(
|
|
79
|
-
previous[
|
|
80
|
-
previous[
|
|
78
|
+
(outboundRecordId) =>
|
|
79
|
+
previous[outboundRecordId].id === next[outboundRecordId]?.id &&
|
|
80
|
+
previous[outboundRecordId].name === next[outboundRecordId]?.name
|
|
81
81
|
)
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -86,13 +86,13 @@ const areOutboundsEqual = (
|
|
|
86
86
|
* the resolved id/name pairs actually change — so context consumers update for
|
|
87
87
|
* late-arriving outbounds without thrashing on unrelated renders.
|
|
88
88
|
*/
|
|
89
|
-
export const
|
|
89
|
+
export const useOutboundsByRecordId = (
|
|
90
90
|
messages: readonly { metadata?: { outbound_id?: unknown } }[] | undefined,
|
|
91
91
|
resolveOutbound: OutboundResolver | undefined
|
|
92
|
-
):
|
|
93
|
-
const outbounds =
|
|
92
|
+
): OutboundsByRecordId | undefined => {
|
|
93
|
+
const outbounds = buildOutboundsByRecordId(messages, resolveOutbound)
|
|
94
94
|
const [publishedOutbounds, setPublishedOutbounds] = useState<
|
|
95
|
-
|
|
95
|
+
OutboundsByRecordId | undefined
|
|
96
96
|
>(outbounds)
|
|
97
97
|
|
|
98
98
|
if (!areOutboundsEqual(publishedOutbounds, outbounds)) {
|
|
@@ -187,11 +187,11 @@ export const SentMessageDeliveryStatus = ({
|
|
|
187
187
|
return null
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
const
|
|
190
|
+
const outboundRecordId = message.metadata?.outbound_id
|
|
191
191
|
const outboundStatus =
|
|
192
192
|
message.status !== 'sending' &&
|
|
193
193
|
message.status !== 'failed' &&
|
|
194
|
-
|
|
194
|
+
outboundRecordId &&
|
|
195
195
|
resolvedOutbound ? (
|
|
196
196
|
<OutboundStatus
|
|
197
197
|
outbound={resolvedOutbound}
|
|
@@ -468,10 +468,12 @@ const MemoizedCustomMessage = React.memo(
|
|
|
468
468
|
|
|
469
469
|
export const CustomMessage = (props: CustomMessageUIComponentProps) => {
|
|
470
470
|
const messageContext = useMessageContext('CustomMessage')
|
|
471
|
-
const
|
|
472
|
-
const
|
|
471
|
+
const outboundsByRecordId = useContext(OutboundContext)
|
|
472
|
+
const outboundRecordId = messageContext.message.metadata?.outbound_id
|
|
473
473
|
const resolvedOutbound =
|
|
474
|
-
typeof
|
|
474
|
+
typeof outboundRecordId === 'string'
|
|
475
|
+
? outboundsByRecordId?.[outboundRecordId]
|
|
476
|
+
: undefined
|
|
475
477
|
|
|
476
478
|
return (
|
|
477
479
|
<MemoizedCustomMessage
|
|
@@ -67,8 +67,8 @@ export interface MessageMetadata {
|
|
|
67
67
|
*/
|
|
68
68
|
sent_from?: 'stack_detail'
|
|
69
69
|
/**
|
|
70
|
-
* Opaque
|
|
71
|
-
*
|
|
70
|
+
* Opaque outbound record id on automation messages. The Stream wire field is
|
|
71
|
+
* `outbound_id`; resolver APIs name this value `outboundRecordId` explicitly.
|
|
72
72
|
*/
|
|
73
73
|
outbound_id?: string
|
|
74
74
|
}
|
package/src/types.ts
CHANGED
|
@@ -37,6 +37,7 @@ export type MessageLinkClickHandler = (
|
|
|
37
37
|
) => void
|
|
38
38
|
|
|
39
39
|
export type ResolvedOutbound = {
|
|
40
|
+
/** Automation id referenced by the outbound record. */
|
|
40
41
|
id: string
|
|
41
42
|
name?: string
|
|
42
43
|
}
|
|
@@ -44,7 +45,7 @@ export type ResolvedOutbound = {
|
|
|
44
45
|
export type OutboundClickHandler = (outbound: ResolvedOutbound) => void
|
|
45
46
|
|
|
46
47
|
export type OutboundResolver = (
|
|
47
|
-
|
|
48
|
+
outboundRecordId: string
|
|
48
49
|
) => ResolvedOutbound | undefined
|
|
49
50
|
|
|
50
51
|
export type ChannelPreviewProps = ChannelPreviewUIComponentProps & {
|
|
@@ -373,10 +374,11 @@ export interface ChannelViewProps {
|
|
|
373
374
|
onOutboundClick?: OutboundClickHandler
|
|
374
375
|
|
|
375
376
|
/**
|
|
376
|
-
* Resolves an outbound record id to the current
|
|
377
|
-
* host must provide a new resolver reference
|
|
378
|
-
* changes so ChannelView re-renders and publishes
|
|
379
|
-
* rows. Missing records stay unresolved and render
|
|
377
|
+
* Resolves `metadata.outbound_id` (an outbound record id) to the current
|
|
378
|
+
* automation id and name. The host must provide a new resolver reference
|
|
379
|
+
* when a returned outbound changes so ChannelView re-renders and publishes
|
|
380
|
+
* the new value to memoized rows. Missing records stay unresolved and render
|
|
381
|
+
* no label.
|
|
380
382
|
*/
|
|
381
383
|
resolveOutbound?: OutboundResolver
|
|
382
384
|
|