@robono/messaging-react-native 0.3.2 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.4.0 — release candidate
2
+
3
+ The complete Expo messenger connects managed notifications and adds the standard Account notification action. Permissions are requested only when the user chooses to enable alerts.
4
+
1
5
  # Changelog
2
6
 
3
7
  ## 0.3.2 — 2026-11-03
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Optional Robono messaging screens
2
2
 
3
- Use a ready-made direct or group conversation screen, replace its sections, or compose the exported components into your own layout. Use `ExpoMessenger` for the complete inbox and conversation flow, or the individual components inside your existing navigation. Notification registration is explicit; nothing requests permission on mount. The shared icon controls require `react-native-svg` (install it with your framework’s native dependency installer).
3
+ Use a ready-made direct or group conversation screen, replace its sections, or compose the exported components into your own layout. Use `ExpoMessenger` for the complete inbox and conversation flow, or the individual components inside your existing navigation. The complete Expo messenger connects notification registration; nothing requests permission on mount. The shared icon controls require `react-native-svg` (install it with your framework’s native dependency installer).
4
4
 
5
5
  ## Recommended installation
6
6
 
@@ -23,10 +23,10 @@ try { await messenger.signOut(); } finally { await session.signOut(); }
23
23
  ```
24
24
 
25
25
  Install the native dependencies below and rebuild both platforms. For alerts
26
- outside the app, use the explicit `./expo-notifications` connector and follow
26
+ outside the app, `createExpoMessenger` connects the managed service automatically. Use the Account screen’s Enable notifications action and follow
27
27
  `@robono/server/NOTIFICATIONS.md`: iPhone needs **your** Apple Team ID, APNs Key ID,
28
28
  private .p8 key and Bundle ID; Android needs **your** Firebase project, app
29
- configuration and a server-only service account. Never ship private keys in the
29
+ configuration and a service-account key uploaded in Robono’s private notification setup. Never ship private keys in the
30
30
  app. Website chat itself does not require these mobile credentials.
31
31
 
32
32
  The supplied group owner, shared-media, reply and pinned-message screens use the
@@ -316,3 +316,9 @@ The phone button opens Messenger’s method choices when a number exists; otherw
316
316
  it starts the available internet call directly. Groups never show a carrier choice.
317
317
  `MessagingCallingScreen` and `ExpoMessagingCallingScreen` still accept existing
318
318
  `onCall`/`onVideoCall` callbacks and use these same controls.
319
+
320
+ ## Managed notification lifecycle
321
+
322
+ Server 0.18.0 and mobile 0.4.0 remove the customer notification database and worker. Upload your Apple/Google app credentials once under Your app → Message notifications. Include `notifications.register-device` in your server’s authenticated-user permission policy. Spread the complete connection returned by `createExpoMessenger` into `ExpoMessenger`; this includes its notification connection and Account action. Pass `notifications:false` when your app owns notifications instead.
323
+
324
+ Always await `messenger.signOut()` before ending your host login session, using a finally block to finish host sign-out even if the network is unavailable. The host still owns its global notification presentation handler; compose it with `withMessagingNotificationPresentation` if needed. Custom screens can continue using the separate `./expo-notifications` connector. Apple/Google permissions and a real device are required to prove background delivery; signing in and seeing a chat is not enough.
package/SBOM.spdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "@robono/messaging-react-native@0.3.2",
6
- "documentNamespace": "https://robono.com/sbom/messaging-react-native/0.3.2/7c7c4927b016f6233ad8e4563e02de9c8df27d60",
5
+ "name": "@robono/messaging-react-native@0.4.0",
6
+ "documentNamespace": "https://robono.com/sbom/messaging-react-native/0.4.0/df93062ac58d4fd402541897dfd40f8ae91159af",
7
7
  "creationInfo": {
8
- "created": "2026-11-03T15:38:34.815Z",
8
+ "created": "2026-11-03T17:17:17.082Z",
9
9
  "creators": [
10
10
  "Organization: Robono (support@robono.com)"
11
11
  ]
@@ -14,11 +14,11 @@
14
14
  {
15
15
  "name": "@robono/messaging-react-native",
16
16
  "SPDXID": "SPDXRef-Package",
17
- "versionInfo": "0.3.2",
17
+ "versionInfo": "0.4.0",
18
18
  "downloadLocation": "NOASSERTION",
19
19
  "filesAnalyzed": true,
20
20
  "packageVerificationCode": {
21
- "packageVerificationCodeValue": "7c7c4927b016f6233ad8e4563e02de9c8df27d60"
21
+ "packageVerificationCodeValue": "df93062ac58d4fd402541897dfd40f8ae91159af"
22
22
  },
23
23
  "licenseConcluded": "LicenseRef-RobonoSDK",
24
24
  "licenseDeclared": "LicenseRef-RobonoSDK",
@@ -36,11 +36,11 @@
36
36
  "checksums": [
37
37
  {
38
38
  "algorithm": "SHA256",
39
- "checksumValue": "9af199e3a2c07244175c80fb3848beba06b8b365a400a011f93d22cc8ccd80be"
39
+ "checksumValue": "3ad21d9130f6c3953de7f4b420c491768e135d9bf0c02f561382196c9e876e3e"
40
40
  },
41
41
  {
42
42
  "algorithm": "SHA1",
43
- "checksumValue": "5edab04e1f038dcc9d814799e74174b272c3e5ce"
43
+ "checksumValue": "e604f509e91d873085a8cfb6993676e9e1b2cc9e"
44
44
  }
45
45
  ],
46
46
  "licenseConcluded": "LicenseRef-RobonoSDK",
@@ -74,11 +74,11 @@
74
74
  "checksums": [
75
75
  {
76
76
  "algorithm": "SHA256",
77
- "checksumValue": "5d9649c9611ee3b73e05cc1e8c89b6569e0985866fdef68525ea93009fec30ff"
77
+ "checksumValue": "0178b3d65e7ab8495ef4fe70c59ee701724f62f877b2a75c18a6dca25a40305e"
78
78
  },
79
79
  {
80
80
  "algorithm": "SHA1",
81
- "checksumValue": "794edf72936cb189bf268fc8fb250651a7329c08"
81
+ "checksumValue": "e655ea1cc58912218c2c9f0e89ee38f83dc53b33"
82
82
  }
83
83
  ],
84
84
  "licenseConcluded": "LicenseRef-RobonoSDK",
@@ -112,11 +112,11 @@
112
112
  "checksums": [
113
113
  {
114
114
  "algorithm": "SHA256",
115
- "checksumValue": "9d88b0be65dd7834430c83be21496f0147986ae3906305d75e3cc0be9878f0ac"
115
+ "checksumValue": "2f1328361b2b432a4f48bc2bb013656ddbdc50353cfba9b5a45c19c0b3adeca2"
116
116
  },
117
117
  {
118
118
  "algorithm": "SHA1",
119
- "checksumValue": "c3ebeae533a3df823a689309f5a75d94e7590a6d"
119
+ "checksumValue": "1d464839cbe9a033b2a8646f332b420142146b48"
120
120
  }
121
121
  ],
122
122
  "licenseConcluded": "LicenseRef-RobonoSDK",
@@ -131,11 +131,11 @@
131
131
  "checksums": [
132
132
  {
133
133
  "algorithm": "SHA256",
134
- "checksumValue": "47f2a13ed065f66fd1569ac705a4261913e0979bdc5fe0243152f07c4a81837a"
134
+ "checksumValue": "23c883ef666006f80afdee2d2913305802bdafb8b06ce78a3298980569bdf159"
135
135
  },
136
136
  {
137
137
  "algorithm": "SHA1",
138
- "checksumValue": "977c0c985514f21d4c4cf012d386aa14391c7648"
138
+ "checksumValue": "b39d43604a9a9fae4cf123cb3e4039077f21b3bc"
139
139
  }
140
140
  ],
141
141
  "licenseConcluded": "LicenseRef-RobonoSDK",
@@ -454,11 +454,11 @@
454
454
  "checksums": [
455
455
  {
456
456
  "algorithm": "SHA256",
457
- "checksumValue": "99d0315cddd300ded5adcbd384b95fc1e4a4ad69fac7e2301913ee60b30365aa"
457
+ "checksumValue": "ef3667bec0990a840f4571f2958e7f48853797094cea5cdf723aaacfe44103e2"
458
458
  },
459
459
  {
460
460
  "algorithm": "SHA1",
461
- "checksumValue": "8ccd529d1584aba8ed1c8300f22cbd9882bb2630"
461
+ "checksumValue": "6b0c8bf03df2f377244091aa3b9f096d8ae7be55"
462
462
  }
463
463
  ],
464
464
  "licenseConcluded": "LicenseRef-RobonoSDK",
@@ -473,11 +473,11 @@
473
473
  "checksums": [
474
474
  {
475
475
  "algorithm": "SHA256",
476
- "checksumValue": "2fdecf67669c4b883e5ea488ed2f87ff5be052a219e7977164c81b6b4a8add0b"
476
+ "checksumValue": "774ac074b995f3608d0107c74f529a35f35ec0ea34781f475e6bc37140ce3c4c"
477
477
  },
478
478
  {
479
479
  "algorithm": "SHA1",
480
- "checksumValue": "4d244898fd03f1ec1d70468fa52c14bcb1aa44ff"
480
+ "checksumValue": "e74a6a17ae2816161cd051b7bf705f1b3ef3ab51"
481
481
  }
482
482
  ],
483
483
  "licenseConcluded": "LicenseRef-RobonoSDK",
@@ -2297,11 +2297,11 @@
2297
2297
  "checksums": [
2298
2298
  {
2299
2299
  "algorithm": "SHA256",
2300
- "checksumValue": "f866a465d4d88faaa63726301dfff1818e89ace4373ad72e401a19c6f2ff5f9b"
2300
+ "checksumValue": "e6fc746e005ab4ba2d3e7aef1aa1563ec1065446bb500b26bee414b74c7915aa"
2301
2301
  },
2302
2302
  {
2303
2303
  "algorithm": "SHA1",
2304
- "checksumValue": "ef809d7ff2addfdcc39f2aded2391b45fdd2651b"
2304
+ "checksumValue": "8684309e2e3d99cfc41ef651bce2dad428cf1cf7"
2305
2305
  }
2306
2306
  ],
2307
2307
  "licenseConcluded": "LicenseRef-RobonoSDK",
package/dist/account.d.ts CHANGED
@@ -5,6 +5,7 @@ export interface MessagingAccount {
5
5
  avatarUrl?: string;
6
6
  phone?: string;
7
7
  email?: string;
8
+ onEnableNotifications?: () => void | Promise<void>;
8
9
  onEditProfile?: () => void | Promise<void>;
9
10
  onSignOut?: () => void | Promise<void>;
10
11
  }
package/dist/account.js CHANGED
@@ -15,13 +15,13 @@ export function MessagingAccountScreen({ account, companyName, onClose }) {
15
15
  await action();
16
16
  onClose();
17
17
  }
18
- catch {
18
+ catch (e) {
19
19
  setVisible(true);
20
- setError('The change could not be completed. Please try again.');
20
+ setError(e instanceof Error ? e.message : 'The change could not be completed. Please try again.');
21
21
  }
22
22
  finally {
23
23
  setBusy(false);
24
24
  } };
25
25
  return _jsx(MessagingPopup, { visible: visible, onDismiss: dismissed, title: "Account", closeLabel: "Close account", closeDisabled: busy, background: c.background, contentWidth: 640, onClose: () => { if (!busy)
26
- onClose(); }, children: _jsxs(ScrollView, { contentContainerStyle: { gap: 16, paddingBottom: 12 }, children: [_jsxs(View, { style: { backgroundColor: '#111111', borderRadius: 16, padding: 16, gap: 14 }, children: [_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 14 }, children: [account?.avatarUrl ? _jsx(Image, { source: { uri: account.avatarUrl }, style: { width: 56, height: 56, borderRadius: 28 } }) : _jsx(View, { style: { width: 56, height: 56, borderRadius: 28, backgroundColor: '#252525', alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "person-circle-outline", color: c.foreground, size: 36 }) }), _jsxs(View, { style: { flex: 1, gap: 4 }, children: [_jsx(Text, { style: { color: c.foreground, fontSize: 20, fontWeight: '600' }, children: account?.name ?? 'Your account' }), _jsx(Text, { style: { color: c.secondary, fontSize: 14 }, children: companyName })] })] }), account?.phone && _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: account.phone }), account?.email && _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: account.email }), account?.onEditProfile && _jsxs(Pressable, { accessibilityRole: "button", accessibilityLabel: "Edit profile", disabled: busy, onPress: () => begin(account.onEditProfile), style: { minHeight: 44, flexDirection: 'row', alignItems: 'center', gap: 10 }, children: [_jsx(MessageIcon, { name: "edit", color: c.foreground, size: 20 }), _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: "Edit profile" })] })] }), account?.onSignOut && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Sign out", disabled: busy, onPress: () => begin(account.onSignOut), style: { backgroundColor: '#111111', borderRadius: 12, minHeight: 52, paddingHorizontal: 16, justifyContent: 'center' }, children: _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: "Sign out" }) }), !!error && _jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 15 }, children: error })] }) });
26
+ onClose(); }, children: _jsxs(ScrollView, { contentContainerStyle: { gap: 16, paddingBottom: 12 }, children: [_jsxs(View, { style: { backgroundColor: '#111111', borderRadius: 16, padding: 16, gap: 14 }, children: [_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 14 }, children: [account?.avatarUrl ? _jsx(Image, { source: { uri: account.avatarUrl }, style: { width: 56, height: 56, borderRadius: 28 } }) : _jsx(View, { style: { width: 56, height: 56, borderRadius: 28, backgroundColor: '#252525', alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "person-circle-outline", color: c.foreground, size: 36 }) }), _jsxs(View, { style: { flex: 1, gap: 4 }, children: [_jsx(Text, { style: { color: c.foreground, fontSize: 20, fontWeight: '600' }, children: account?.name ?? 'Your account' }), _jsx(Text, { style: { color: c.secondary, fontSize: 14 }, children: companyName })] })] }), account?.phone && _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: account.phone }), account?.email && _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: account.email }), account?.onEditProfile && _jsxs(Pressable, { accessibilityRole: "button", accessibilityLabel: "Edit profile", disabled: busy, onPress: () => begin(account.onEditProfile), style: { minHeight: 44, flexDirection: 'row', alignItems: 'center', gap: 10 }, children: [_jsx(MessageIcon, { name: "edit", color: c.foreground, size: 20 }), _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: "Edit profile" })] })] }), account?.onEnableNotifications && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Enable notifications", disabled: busy, onPress: () => void run(account.onEnableNotifications), style: { backgroundColor: '#111111', borderRadius: 12, minHeight: 52, paddingHorizontal: 16, justifyContent: 'center' }, children: _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: "Enable notifications" }) }), account?.onSignOut && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Sign out", disabled: busy, onPress: () => begin(account.onSignOut), style: { backgroundColor: '#111111', borderRadius: 12, minHeight: 52, paddingHorizontal: 16, justifyContent: 'center' }, children: _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: "Sign out" }) }), !!error && _jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 15 }, children: error })] }) });
27
27
  }
@@ -8,6 +8,7 @@ export declare function createExpoMessenger(options: {
8
8
  userId: string;
9
9
  getAccessToken: () => Promise<string>;
10
10
  fetch?: typeof fetch;
11
+ notifications?: false;
11
12
  persistence?: false;
12
13
  namespace?: string;
13
14
  audioSession?: MessagingAudioSession;
@@ -17,10 +18,18 @@ export declare function createExpoMessenger(options: {
17
18
  inbox: MessagingInboxClient;
18
19
  storage: import("./media-controller.js").MessagingMediaStorage;
19
20
  audioSession: MessagingAudioSession;
21
+ notifications: {
22
+ start(open: (conversationId: string, messageId: string) => Promise<void>): Promise<void>;
23
+ enable(): Promise<void>;
24
+ } | undefined;
20
25
  signOut(): Promise<void>;
21
26
  dispose(): void;
22
27
  };
23
28
  export interface ExpoMessengerProps extends Omit<ExpoMessagingScreenProps, 'contact' | 'renderConversation' | 'onBack'> {
29
+ notifications?: {
30
+ start: (open: (conversationId: string, messageId: string) => Promise<void>) => Promise<void>;
31
+ enable: () => Promise<void>;
32
+ };
24
33
  inbox: MessagingInboxClient;
25
34
  contacts?: Record<string, {
26
35
  name: string;
@@ -32,4 +41,4 @@ export interface ExpoMessengerProps extends Omit<ExpoMessagingScreenProps, 'cont
32
41
  onSelectConversation?: (conversation: ConversationSummary | null) => void;
33
42
  }
34
43
  /** Supplied inbox, group creation, conversation, settings and media screens. */
35
- export declare function ExpoMessenger({ inbox, contacts, initialConversation, selectedConversation, onSelectConversation, ...props }: ExpoMessengerProps): React.JSX.Element;
44
+ export declare function ExpoMessenger({ inbox, contacts, initialConversation, selectedConversation, onSelectConversation, notifications, ...props }: ExpoMessengerProps): React.JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useSyncExternalStore } from 'react';
2
+ import { connectExpoMessagingNotifications } from './expo-notifications.js';
3
+ import { useEffect, useState, useSyncExternalStore } from 'react';
3
4
  import { createMessagingTransport, defaultMessagingSettings, MessagingInboxClient } from '@robono/messaging';
4
5
  import { ExpoMessagingScreen } from './expo-screen.js';
5
6
  import { createExpoMessagingClient } from './expo-outbox.js';
@@ -18,13 +19,60 @@ export function createExpoMessenger(options) {
18
19
  const inbox = new MessagingInboxClient({ request: createMessagingTransport({ ...options, url: endpoint.href }) });
19
20
  const storage = createExpoMessagingStorage({ url: media.href, getAccessToken: options.getAccessToken, ...(options.fetch ? { fetch: options.fetch } : {}) });
20
21
  const audioSession = options.audioSession ?? createExpoMessagingAudioSession({ isCallActive: options.isCallActive });
21
- return { client, inbox, storage, audioSession,
22
- async signOut() { inbox.dispose(); await client.signOut(); },
23
- dispose() { inbox.dispose(); client.dispose(); },
22
+ let connection = null, pending = null, closed = false;
23
+ let openNotification;
24
+ const notifications = options.notifications === false ? undefined : {
25
+ async start(open) {
26
+ openNotification = open;
27
+ if (closed || connection)
28
+ return;
29
+ if (pending)
30
+ return pending;
31
+ const url = new URL(endpoint);
32
+ url.searchParams.set('service', 'notifications');
33
+ const request = createMessagingTransport({ ...options, url: endpoint.href });
34
+ pending = (async () => {
35
+ const n = await connectExpoMessagingNotifications({ url: url.href, userId: options.userId, getAccessToken: options.getAccessToken, ...(options.fetch ? { fetch: options.fetch } : {}),
36
+ authorize: async (e) => { try {
37
+ return (await request('list', { conversationId: e.conversationId, messageIds: [e.messageId], notificationMessageId: e.messageId })).notificationAllowed === true;
38
+ }
39
+ catch {
40
+ return false;
41
+ } },
42
+ open: e => open(e.conversationId, e.messageId), refresh: () => inbox.refresh().then(() => { }), onError: () => { },
43
+ });
44
+ if (closed) {
45
+ await n.signOut();
46
+ return;
47
+ }
48
+ connection = n;
49
+ await n.ready;
50
+ })();
51
+ try {
52
+ await pending;
53
+ }
54
+ finally {
55
+ pending = null;
56
+ }
57
+ }, async enable() { if (!connection && openNotification)
58
+ await notifications.start(openNotification); if (!connection)
59
+ throw Error('Notifications are not connected yet. Check your Apple/Google setup in Robono.'); if (!await connection.enable())
60
+ throw Error('Allow notifications in your phone’s app settings.'); },
61
+ };
62
+ return { client, inbox, storage, audioSession, notifications,
63
+ async signOut() { closed = true; try {
64
+ await pending?.catch(() => { });
65
+ await connection?.signOut();
66
+ }
67
+ finally {
68
+ inbox.dispose();
69
+ await client.signOut();
70
+ } },
71
+ dispose() { closed = true; connection?.dispose(); inbox.dispose(); client.dispose(); },
24
72
  };
25
73
  }
26
74
  /** Supplied inbox, group creation, conversation, settings and media screens. */
27
- export function ExpoMessenger({ inbox, contacts = {}, initialConversation, selectedConversation, onSelectConversation, ...props }) {
75
+ export function ExpoMessenger({ inbox, contacts = {}, initialConversation, selectedConversation, onSelectConversation, notifications, ...props }) {
28
76
  const [internal, setInternal] = useState(initialConversation ?? null), [newGroup, setNewGroup] = useState(false);
29
77
  const selected = selectedConversation === undefined ? internal : selectedConversation;
30
78
  const setSelected = (row) => { setInternal(row); onSelectConversation?.(row); };
@@ -34,6 +82,9 @@ export function ExpoMessenger({ inbox, contacts = {}, initialConversation, selec
34
82
  void props.client.open(row.id).then(async () => { if (messageId && props.client.getSnapshot().conversationId === row.id)
35
83
  await props.client.focusMessage(messageId); }).catch(() => { });
36
84
  };
85
+ useEffect(() => { void notifications?.start(async (id, message) => { await inbox.refresh(); const row = inbox.getSnapshot().conversations.find(c => c.id === id); if (row)
86
+ open(row, message); }).catch(() => { }); }, [notifications, inbox]);
87
+ const account = notifications ? { name: props.account?.name ?? 'Your account', ...props.account, onEnableNotifications: () => notifications.enable() } : props.account;
37
88
  const contact = selected?.kind === 'group' ? { name: selected.name ?? 'Group' } : contacts[selected?.contactId ?? ''] ?? { name: selected?.contactId ?? 'Chat' };
38
- return _jsx(ExpoMessagingScreen, { ...props, contact: contact, participants: props.participants ?? contacts, extras: selected ? props.extras : undefined, callActions: selected ? { ...props.callActions, phoneNumber: contacts[selected.contactId ?? '']?.phoneNumber ?? props.callActions?.phoneNumber } : undefined, onBack: () => { props.client.stop(); setSelected(null); void inbox.refresh().catch(() => { }); }, renderConversation: screen => _jsx(MessagingProvider, { ...screen, children: selected ? _jsx(MessagingConversation, {}) : _jsxs(_Fragment, { children: [_jsx(MessagingInbox, { client: inbox, userId: props.userId, contacts: contacts, companyName: props.companyName, appearance: props.appearance, active: props.active !== false, headerActions: _jsx(MessagingAccountMenu, { onNewGroup: inboxState.groupCreationAvailable ? () => setNewGroup(true) : undefined }), onSelect: open, onDeleted: id => props.client.forgetConversation(id) }), newGroup && _jsx(MessagingGroupEditor, { client: props.client, inbox: inbox, userId: props.userId, contacts: contacts, groups: inboxState.groups, accent: (props.appearance ?? inboxState.appearance ?? defaultMessagingSettings().appearance).colors.accent, onClose: () => setNewGroup(false), onSaved: (id, name) => { setNewGroup(false); const row = inbox.getSnapshot().conversations.find(c => c.id === id) ?? { id, kind: 'group', name, contactId: null, lastMessage: null, unreadCount: 0, canSend: true }; open(row); } })] }) }) });
89
+ return _jsx(ExpoMessagingScreen, { ...props, account: account, contact: contact, participants: props.participants ?? contacts, extras: selected ? props.extras : undefined, callActions: selected ? { ...props.callActions, phoneNumber: contacts[selected.contactId ?? '']?.phoneNumber ?? props.callActions?.phoneNumber } : undefined, onBack: () => { props.client.stop(); setSelected(null); void inbox.refresh().catch(() => { }); }, renderConversation: screen => _jsx(MessagingProvider, { ...screen, children: selected ? _jsx(MessagingConversation, {}) : _jsxs(_Fragment, { children: [_jsx(MessagingInbox, { client: inbox, userId: props.userId, contacts: contacts, companyName: props.companyName, appearance: props.appearance, active: props.active !== false, headerActions: _jsx(MessagingAccountMenu, { onNewGroup: inboxState.groupCreationAvailable ? () => setNewGroup(true) : undefined }), onSelect: open, onDeleted: id => props.client.forgetConversation(id) }), newGroup && _jsx(MessagingGroupEditor, { client: props.client, inbox: inbox, userId: props.userId, contacts: contacts, groups: inboxState.groups, accent: (props.appearance ?? inboxState.appearance ?? defaultMessagingSettings().appearance).colors.accent, onClose: () => setNewGroup(false), onSaved: (id, name) => { setNewGroup(false); const row = inbox.getSnapshot().conversations.find(c => c.id === id) ?? { id, kind: 'group', name, contactId: null, lastMessage: null, unreadCount: 0, canSend: true }; open(row); } })] }) }) });
39
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robono/messaging-react-native",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Optional, composable direct and group messaging screens for Robono.",