@adminide-stack/yantra-mobile 12.0.73 → 12.0.74-alpha.1

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.
@@ -0,0 +1,178 @@
1
+ import {jsxs,jsx}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,Modal,Pressable,View,Text,Platform}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {SafeAreaView}from'react-native-safe-area-context';import {Avatar}from'./ChatComponents.js';const WHATSAPP_GREEN = "#25D366";
2
+ const MESSAGES_GREEN = "#34C759";
3
+ function InviteSheet({
4
+ visible,
5
+ name,
6
+ number,
7
+ imageUri,
8
+ canWhatsApp,
9
+ theme,
10
+ onClose,
11
+ onChoose,
12
+ onCopy
13
+ }) {
14
+ const pending = React.useRef(null);
15
+ const [copied, setCopied] = React.useState(false);
16
+ React.useEffect(() => {
17
+ if (visible) setCopied(false);
18
+ }, [visible]);
19
+ const runPending = React.useCallback(() => {
20
+ const channel = pending.current;
21
+ pending.current = null;
22
+ if (channel) onChoose(channel);
23
+ }, [onChoose]);
24
+ const choose = (channel) => {
25
+ pending.current = channel;
26
+ onClose();
27
+ if (Platform.OS !== "ios") setTimeout(runPending, 250);
28
+ };
29
+ const copy = () => {
30
+ onCopy();
31
+ setCopied(true);
32
+ setTimeout(onClose, 900);
33
+ };
34
+ const row = (icon, tint, label, detail, run, testID) => /* @__PURE__ */ jsx(
35
+ Pressable,
36
+ {
37
+ onPress: run,
38
+ accessibilityRole: "button",
39
+ accessibilityLabel: label,
40
+ testID,
41
+ style: ({
42
+ pressed
43
+ }) => ({
44
+ backgroundColor: pressed ? theme.surface : "transparent"
45
+ }),
46
+ children: /* @__PURE__ */ jsxs(View, { style: [styles.row, {
47
+ flexDirection: "row",
48
+ alignItems: "center"
49
+ }], children: [
50
+ /* @__PURE__ */ jsx(View, { style: [styles.icon, {
51
+ backgroundColor: tint
52
+ }], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: icon, size: 22, color: "#ffffff" }) }),
53
+ /* @__PURE__ */ jsxs(View, { style: {
54
+ flex: 1
55
+ }, children: [
56
+ /* @__PURE__ */ jsx(Text, { style: [styles.label, {
57
+ color: theme.text
58
+ }], children: label }),
59
+ /* @__PURE__ */ jsx(Text, { style: [styles.detail, {
60
+ color: theme.textMuted
61
+ }], numberOfLines: 1, children: detail })
62
+ ] }),
63
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "chevron-right", size: 22, color: theme.textMuted })
64
+ ] })
65
+ }
66
+ );
67
+ return /* @__PURE__ */ jsxs(Modal, { visible, transparent: true, animationType: "slide", onRequestClose: onClose, onDismiss: runPending, children: [
68
+ /* @__PURE__ */ jsx(Pressable, { style: styles.backdrop, onPress: onClose, accessibilityLabel: "Close" }),
69
+ /* @__PURE__ */ jsxs(SafeAreaView, { edges: ["bottom"], style: [styles.sheet, {
70
+ backgroundColor: theme.bg
71
+ }], children: [
72
+ /* @__PURE__ */ jsx(View, { style: [styles.handle, {
73
+ backgroundColor: theme.border
74
+ }] }),
75
+ /* @__PURE__ */ jsxs(View, { style: styles.header, children: [
76
+ /* @__PURE__ */ jsx(Avatar, { name, uri: imageUri, size: 56, theme, variant: "initials" }),
77
+ /* @__PURE__ */ jsxs(Text, { style: [styles.title, {
78
+ color: theme.text
79
+ }], numberOfLines: 1, children: [
80
+ "Invite ",
81
+ name
82
+ ] }),
83
+ /* @__PURE__ */ jsxs(Text, { style: [styles.subtitle, {
84
+ color: theme.textMuted
85
+ }], numberOfLines: 2, children: [
86
+ number ? `${number} \xB7 ` : "",
87
+ "Send a link to join you on Yantra Chat"
88
+ ] })
89
+ ] }),
90
+ /* @__PURE__ */ jsxs(View, { style: [styles.group, {
91
+ borderColor: theme.border
92
+ }], children: [
93
+ row("message-text", MESSAGES_GREEN, "Messages", "Send as a text message", () => choose("sms"), "invite-sms"),
94
+ canWhatsApp ? row("whatsapp", WHATSAPP_GREEN, "WhatsApp", "Open a WhatsApp chat with the invite", () => choose("whatsapp"), "invite-whatsapp") : null,
95
+ row(copied ? "check" : "link-variant", copied ? MESSAGES_GREEN : theme.accent, copied ? "Link copied" : "Copy invite link", copied ? "Paste it anywhere" : "Paste it into any app", copy, "invite-copy"),
96
+ row("dots-horizontal", "#64748b", "More options", "Telegram, Mail and other apps", () => choose("share"), "invite-share")
97
+ ] }),
98
+ /* @__PURE__ */ jsx(Pressable, { onPress: onClose, accessibilityRole: "button", accessibilityLabel: "Cancel", children: ({
99
+ pressed
100
+ }) => /* @__PURE__ */ jsx(View, { style: [styles.cancel, {
101
+ alignItems: "center",
102
+ backgroundColor: pressed ? theme.border : theme.surface
103
+ }], children: /* @__PURE__ */ jsx(Text, { style: [styles.cancelText, {
104
+ color: theme.text
105
+ }], children: "Cancel" }) }) })
106
+ ] })
107
+ ] });
108
+ }
109
+ const styles = StyleSheet.create({
110
+ backdrop: {
111
+ flex: 1,
112
+ backgroundColor: "rgba(15, 23, 42, 0.4)"
113
+ },
114
+ sheet: {
115
+ borderTopLeftRadius: 20,
116
+ borderTopRightRadius: 20,
117
+ paddingTop: 8,
118
+ paddingBottom: 8
119
+ },
120
+ handle: {
121
+ alignSelf: "center",
122
+ width: 36,
123
+ height: 5,
124
+ borderRadius: 3,
125
+ marginBottom: 12
126
+ },
127
+ header: {
128
+ alignItems: "center",
129
+ paddingHorizontal: 24,
130
+ paddingBottom: 18,
131
+ gap: 4
132
+ },
133
+ title: {
134
+ fontSize: 19,
135
+ fontWeight: "700",
136
+ marginTop: 10
137
+ },
138
+ subtitle: {
139
+ fontSize: 14,
140
+ textAlign: "center"
141
+ },
142
+ group: {
143
+ marginHorizontal: 16,
144
+ borderRadius: 14,
145
+ borderWidth: StyleSheet.hairlineWidth,
146
+ overflow: "hidden"
147
+ },
148
+ row: {
149
+ paddingHorizontal: 14,
150
+ paddingVertical: 12,
151
+ gap: 14
152
+ },
153
+ icon: {
154
+ width: 38,
155
+ height: 38,
156
+ borderRadius: 10,
157
+ alignItems: "center",
158
+ justifyContent: "center"
159
+ },
160
+ label: {
161
+ fontSize: 16,
162
+ fontWeight: "600"
163
+ },
164
+ detail: {
165
+ fontSize: 13,
166
+ marginTop: 1
167
+ },
168
+ cancel: {
169
+ marginHorizontal: 16,
170
+ marginTop: 12,
171
+ borderRadius: 14,
172
+ paddingVertical: 14
173
+ },
174
+ cancelText: {
175
+ fontSize: 16,
176
+ fontWeight: "600"
177
+ }
178
+ });export{InviteSheet};//# sourceMappingURL=InviteSheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InviteSheet.js","sources":["../../../src/features/messaging/InviteSheet.tsx"],"sourcesContent":["/**\n * \"Invite <name>\" - the ways to send a contact the Yantra Chat invite: Messages, WhatsApp,\n * copying the link, or the system share sheet for everything else (Telegram, Mail, ...).\n *\n * Nothing is sent from here: every option opens an app with the invite prefilled and the\n * person sends it themselves.\n */\nimport * as React from 'react';\nimport { Modal, Platform, Pressable, StyleSheet, Text, View } from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { Avatar, type ChatTheme } from './ChatComponents';\n\nexport type InviteChannel = 'sms' | 'whatsapp' | 'copy' | 'share';\n\nconst WHATSAPP_GREEN = '#25D366';\nconst MESSAGES_GREEN = '#34C759';\n\nexport function InviteSheet({\n visible,\n name,\n number,\n imageUri,\n canWhatsApp,\n theme,\n onClose,\n onChoose,\n onCopy,\n}: {\n visible: boolean;\n name: string;\n /** As saved in the address book, shown under the name. */\n number?: string | null;\n imageUri?: string | null;\n /** False when the contact has no number WhatsApp can open. */\n canWhatsApp: boolean;\n theme: ChatTheme;\n onClose: () => void;\n /** Runs once the sheet is gone, so a share sheet or composer can present over the app. */\n onChoose: (channel: Exclude<InviteChannel, 'copy'>) => void;\n /** Copy runs while the sheet is open, so it can confirm in place. */\n onCopy: () => void;\n}) {\n const pending = React.useRef<Exclude<InviteChannel, 'copy'> | null>(null);\n const [copied, setCopied] = React.useState(false);\n\n React.useEffect(() => {\n if (visible) setCopied(false);\n }, [visible]);\n\n const runPending = React.useCallback(() => {\n const channel = pending.current;\n pending.current = null;\n if (channel) onChoose(channel);\n }, [onChoose]);\n\n const choose = (channel: Exclude<InviteChannel, 'copy'>) => {\n pending.current = channel;\n onClose();\n // iOS cannot present the share sheet while this modal is still animating away; it says\n // when it is gone through onDismiss. Android has no such event and no such limit.\n if (Platform.OS !== 'ios') setTimeout(runPending, 250);\n };\n\n const copy = () => {\n onCopy();\n setCopied(true);\n setTimeout(onClose, 900);\n };\n\n const row = (\n icon: React.ComponentProps<typeof MaterialCommunityIcons>['name'],\n tint: string,\n label: string,\n detail: string,\n run: () => void,\n testID: string,\n ) => (\n <Pressable\n onPress={run}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n testID={testID}\n // Only the pressed tint on the Pressable; layout lives on the View inside (as in AttachSheet).\n style={({ pressed }) => ({ backgroundColor: pressed ? theme.surface : 'transparent' })}\n >\n <View style={[styles.row, { flexDirection: 'row', alignItems: 'center' }]}>\n <View style={[styles.icon, { backgroundColor: tint }]}>\n <MaterialCommunityIcons name={icon} size={22} color=\"#ffffff\" />\n </View>\n <View style={{ flex: 1 }}>\n <Text style={[styles.label, { color: theme.text }]}>{label}</Text>\n <Text style={[styles.detail, { color: theme.textMuted }]} numberOfLines={1}>\n {detail}\n </Text>\n </View>\n <MaterialCommunityIcons name=\"chevron-right\" size={22} color={theme.textMuted} />\n </View>\n </Pressable>\n );\n\n return (\n <Modal visible={visible} transparent animationType=\"slide\" onRequestClose={onClose} onDismiss={runPending}>\n <Pressable style={styles.backdrop} onPress={onClose} accessibilityLabel=\"Close\" />\n <SafeAreaView edges={['bottom']} style={[styles.sheet, { backgroundColor: theme.bg }]}>\n <View style={[styles.handle, { backgroundColor: theme.border }]} />\n\n <View style={styles.header}>\n <Avatar name={name} uri={imageUri} size={56} theme={theme} variant=\"initials\" />\n <Text style={[styles.title, { color: theme.text }]} numberOfLines={1}>\n Invite {name}\n </Text>\n <Text style={[styles.subtitle, { color: theme.textMuted }]} numberOfLines={2}>\n {number ? `${number} · ` : ''}Send a link to join you on Yantra Chat\n </Text>\n </View>\n\n <View style={[styles.group, { borderColor: theme.border }]}>\n {row(\n 'message-text',\n MESSAGES_GREEN,\n 'Messages',\n 'Send as a text message',\n () => choose('sms'),\n 'invite-sms',\n )}\n {canWhatsApp\n ? row(\n 'whatsapp',\n WHATSAPP_GREEN,\n 'WhatsApp',\n 'Open a WhatsApp chat with the invite',\n () => choose('whatsapp'),\n 'invite-whatsapp',\n )\n : null}\n {row(\n copied ? 'check' : 'link-variant',\n copied ? MESSAGES_GREEN : theme.accent,\n copied ? 'Link copied' : 'Copy invite link',\n copied ? 'Paste it anywhere' : 'Paste it into any app',\n copy,\n 'invite-copy',\n )}\n {row(\n 'dots-horizontal',\n '#64748b',\n 'More options',\n 'Telegram, Mail and other apps',\n () => choose('share'),\n 'invite-share',\n )}\n </View>\n\n <Pressable onPress={onClose} accessibilityRole=\"button\" accessibilityLabel=\"Cancel\">\n {({ pressed }) => (\n <View\n style={[\n styles.cancel,\n { alignItems: 'center', backgroundColor: pressed ? theme.border : theme.surface },\n ]}\n >\n <Text style={[styles.cancelText, { color: theme.text }]}>Cancel</Text>\n </View>\n )}\n </Pressable>\n </SafeAreaView>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n backdrop: { flex: 1, backgroundColor: 'rgba(15, 23, 42, 0.4)' },\n sheet: { borderTopLeftRadius: 20, borderTopRightRadius: 20, paddingTop: 8, paddingBottom: 8 },\n handle: { alignSelf: 'center', width: 36, height: 5, borderRadius: 3, marginBottom: 12 },\n header: { alignItems: 'center', paddingHorizontal: 24, paddingBottom: 18, gap: 4 },\n title: { fontSize: 19, fontWeight: '700', marginTop: 10 },\n subtitle: { fontSize: 14, textAlign: 'center' },\n group: {\n marginHorizontal: 16,\n borderRadius: 14,\n borderWidth: StyleSheet.hairlineWidth,\n overflow: 'hidden',\n },\n row: { paddingHorizontal: 14, paddingVertical: 12, gap: 14 },\n icon: { width: 38, height: 38, borderRadius: 10, alignItems: 'center', justifyContent: 'center' },\n label: { fontSize: 16, fontWeight: '600' },\n detail: { fontSize: 13, marginTop: 1 },\n cancel: { marginHorizontal: 16, marginTop: 12, borderRadius: 14, paddingVertical: 14 },\n cancelText: { fontSize: 16, fontWeight: '600' },\n});\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import {jsx}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,AppState,Platform,BackHandler,View,ActivityIndicator}from'react-native';import {chatThemes,EmptyState}from'./ChatComponents.js';import {useAppTheme}from'../../theme/AppThemeProvider.js';import {ConversationListScreen}from'./ConversationListScreen.js';import {ContactsScreen}from'./ContactsScreen.js';import {ThreadScreen}from'./ThreadScreen.js';import {useConversations,useThread,useMarkRead}from'./useChatData.js';import {VIEW_CHANNEL_MUTATION,YANTRA_CHAT_INVITER_QUERY}from'./chatOperations.js';import {buildChatInviteUrl,chatInviteMessage}from'./chatInviteLink.js';import {useContactMatches}from'./useContactMatches.js';const DEFAULT_INVITE_WEB_BASE = "https://yantra.app";
1
+ import {jsx,jsxs}from'react/jsx-runtime';import*as React from'react';import {StyleSheet,AppState,Platform,BackHandler,View,ActivityIndicator}from'react-native';import {chatThemes,EmptyState}from'./ChatComponents.js';import {useAppTheme}from'../../theme/AppThemeProvider.js';import {ConversationListScreen}from'./ConversationListScreen.js';import {ContactsScreen}from'./ContactsScreen.js';import {ThreadScreen}from'./ThreadScreen.js';import {useConversations,useThread,useMarkRead}from'./useChatData.js';import {VIEW_CHANNEL_MUTATION,YANTRA_CHAT_INVITER_QUERY}from'./chatOperations.js';import {buildChatInviteUrl,chatInviteMessage,whatsAppInviteUrl}from'./chatInviteLink.js';import {InviteSheet}from'./InviteSheet.js';import {useContactMatches}from'./useContactMatches.js';const DEFAULT_INVITE_WEB_BASE = "https://yantra.app";
2
2
  function NativeChatExperience({
3
3
  viewer,
4
4
  sessionError,
@@ -9,6 +9,7 @@ function NativeChatExperience({
9
9
  onInternalRouteChange,
10
10
  testID
11
11
  }) {
12
+ var _a, _b, _c, _d, _e;
12
13
  const {
13
14
  isDark
14
15
  } = useAppTheme();
@@ -60,8 +61,8 @@ function NativeChatExperience({
60
61
  return () => sub.remove();
61
62
  }, [route, contactsGranted]);
62
63
  const activeConversation = React.useMemo(() => {
63
- var _a;
64
- return (_a = conversations.conversations.find((c) => c.id === activeChannelId)) != null ? _a : null;
64
+ var _a2;
65
+ return (_a2 = conversations.conversations.find((c) => c.id === activeChannelId)) != null ? _a2 : null;
65
66
  }, [conversations.conversations, activeChannelId]);
66
67
  React.useEffect(() => {
67
68
  if (Platform.OS !== "android") return void 0;
@@ -99,15 +100,15 @@ function NativeChatExperience({
99
100
  if (openedPeer.current === peer) return;
100
101
  openedPeer.current = peer;
101
102
  void (async () => {
102
- var _a, _b;
103
+ var _a2, _b2;
103
104
  const res = await services.gql.query(YANTRA_CHAT_INVITER_QUERY, {
104
105
  userId: peer.userId
105
106
  }, {
106
107
  fetchPolicy: "network-only"
107
108
  });
108
- const inviter = (_a = res.data) == null ? void 0 : _a.yantraChatInviter;
109
+ const inviter = (_a2 = res.data) == null ? void 0 : _a2.yantraChatInviter;
109
110
  if (!inviter) {
110
- setInviteNotice(((_b = res.errors) == null ? void 0 : _b.length) ? "Could not open this invite. Check your connection and open the link again." : "This invite link is not valid anymore. Ask for a new one.");
111
+ setInviteNotice(((_b2 = res.errors) == null ? void 0 : _b2.length) ? "Could not open this invite. Check your connection and open the link again." : "This invite link is not valid anymore. Ask for a new one.");
111
112
  return;
112
113
  }
113
114
  const id = await openDirect(inviter.userId, inviter.displayName);
@@ -115,24 +116,44 @@ function NativeChatExperience({
115
116
  else setInviteNotice(`Could not start a conversation with ${inviter.displayName}. Please try again.`);
116
117
  })();
117
118
  }, [initialPeer, viewer == null ? void 0 : viewer.userId, services.gql, openDirect, openThread]);
118
- const inviteContact = React.useCallback(async (contact) => {
119
- var _a, _b, _c, _d, _e;
120
- const link = services.link;
121
- if (!link || !(viewer == null ? void 0 : viewer.userId)) return;
122
- const smsTo = ((_a = contact.rawNumbers) == null ? void 0 : _a.length) ? contact.rawNumbers.slice(0, 1) : contact.e164.slice(0, 1);
123
- if (!smsTo.length) return;
119
+ const [inviteTarget, setInviteTarget] = React.useState(null);
120
+ const [inviteSheetOpen, setInviteSheetOpen] = React.useState(false);
121
+ const inviteContact = React.useCallback((contact) => {
122
+ if (!services.link || !(viewer == null ? void 0 : viewer.userId)) return;
123
+ setInviteTarget(contact);
124
+ setInviteSheetOpen(true);
125
+ }, [services.link, viewer == null ? void 0 : viewer.userId]);
126
+ const inviteMessage = React.useMemo(() => {
127
+ var _a2, _b2, _c2, _d2;
128
+ if (!(viewer == null ? void 0 : viewer.userId)) return "";
124
129
  const invite = {
125
130
  inviterId: viewer.userId,
126
- inviterName: (_b = viewer.displayName) != null ? _b : null
131
+ inviterName: (_a2 = viewer.displayName) != null ? _a2 : null
127
132
  };
128
- const url = (_e = (_d = (_c = services.phone) == null ? void 0 : _c.chatInviteUrl) == null ? void 0 : _d.call(_c, invite)) != null ? _e : buildChatInviteUrl(DEFAULT_INVITE_WEB_BASE, invite);
129
- const body = chatInviteMessage(viewer.displayName, url);
130
- const result = await link.composeSms(smsTo, body);
131
- if (result === "unavailable") await link.share(body);
132
- }, [services.link, services.phone, viewer]);
133
+ const url = (_d2 = (_c2 = (_b2 = services.phone) == null ? void 0 : _b2.chatInviteUrl) == null ? void 0 : _c2.call(_b2, invite)) != null ? _d2 : buildChatInviteUrl(DEFAULT_INVITE_WEB_BASE, invite);
134
+ return chatInviteMessage(viewer.displayName, url);
135
+ }, [services.phone, viewer == null ? void 0 : viewer.userId, viewer == null ? void 0 : viewer.displayName]);
136
+ const sendInvite = React.useCallback(async (channel) => {
137
+ var _a2;
138
+ const link = services.link;
139
+ const contact = inviteTarget;
140
+ if (!link || !contact || !inviteMessage) return;
141
+ if (channel === "whatsapp") {
142
+ const url = whatsAppInviteUrl(contact.e164[0], inviteMessage);
143
+ if (url) {
144
+ await link.openUrl(url);
145
+ return;
146
+ }
147
+ }
148
+ if (channel === "sms") {
149
+ const smsTo = ((_a2 = contact.rawNumbers) == null ? void 0 : _a2.length) ? contact.rawNumbers.slice(0, 1) : contact.e164.slice(0, 1);
150
+ if (smsTo.length && await link.composeSms(smsTo, inviteMessage) === "opened") return;
151
+ }
152
+ await link.share(inviteMessage);
153
+ }, [services.link, inviteTarget, inviteMessage]);
133
154
  const activeTitle = React.useMemo(() => {
134
- var _a, _b;
135
- return (_b = (_a = conversations.conversations.find((c) => c.id === activeChannelId)) == null ? void 0 : _a.title) != null ? _b : "Chat";
155
+ var _a2, _b2;
156
+ return (_b2 = (_a2 = conversations.conversations.find((c) => c.id === activeChannelId)) == null ? void 0 : _a2.title) != null ? _b2 : "Chat";
136
157
  }, [conversations.conversations, activeChannelId]);
137
158
  if (sessionError) {
138
159
  return /* @__PURE__ */ jsx(Shell, { theme, testID, children: /* @__PURE__ */ jsx(EmptyState, { icon: "alert-circle-outline", title: "Chat is unavailable", detail: sessionError, theme }) });
@@ -143,28 +164,34 @@ function NativeChatExperience({
143
164
  if (route === "thread" && activeChannelId) {
144
165
  const threadError = thread.error === dismissedError ? null : thread.error;
145
166
  return /* @__PURE__ */ jsx(Shell, { theme, testID, children: /* @__PURE__ */ jsx(ThreadScreen, { title: activeTitle, avatarUrl: activeConversation == null ? void 0 : activeConversation.avatarUrl, messages: thread.messages, loading: thread.loading, loadingMore: thread.loadingMore, error: threadError, theme, connectionState: services.gql.connectionState, haptics: services.haptics, onBack: () => setRoute("list"), onSend: (body) => void thread.send(body), onLoadMore: thread.loadMore, onRetry: thread.retry, onReact: (messageId, emoji) => {
146
- var _a, _b;
147
- const current = (_b = (_a = thread.messages.find((m) => m.id === messageId)) == null ? void 0 : _a.reactions.find((r) => r.mine)) == null ? void 0 : _b.reaction;
167
+ var _a2, _b2;
168
+ const current = (_b2 = (_a2 = thread.messages.find((m) => m.id === messageId)) == null ? void 0 : _a2.reactions.find((r) => r.mine)) == null ? void 0 : _b2.reaction;
148
169
  thread.react(messageId, current === emoji ? null : emoji);
149
170
  }, onCopyText: services.clipboard ? (text) => {
150
- var _a;
151
- return void ((_a = services.clipboard) == null ? void 0 : _a.copy(text));
171
+ var _a2;
172
+ return void ((_a2 = services.clipboard) == null ? void 0 : _a2.copy(text));
152
173
  } : void 0, onShareText: services.link ? (text) => {
153
- var _a;
154
- return void ((_a = services.link) == null ? void 0 : _a.share(text));
174
+ var _a2;
175
+ return void ((_a2 = services.link) == null ? void 0 : _a2.share(text));
155
176
  } : void 0, media: services.media, audio: services.audio, onSendAttachments: thread.sendAttachments ? (files, caption, kind) => {
156
- var _a;
157
- return void ((_a = thread.sendAttachments) == null ? void 0 : _a.call(thread, files, caption, kind));
177
+ var _a2;
178
+ return void ((_a2 = thread.sendAttachments) == null ? void 0 : _a2.call(thread, files, caption, kind));
158
179
  } : void 0, onDismissError: () => setDismissedError(thread.error) }) });
159
180
  }
160
181
  if (route === "contacts") {
161
- return /* @__PURE__ */ jsx(Shell, { theme, testID, children: /* @__PURE__ */ jsx(ContactsScreen, { permission: contactMatches.permission, loading: contactMatches.loading, error: startChatError != null ? startChatError : contactMatches.error, onYantra: contactMatches.onYantra, invitable: contactMatches.invitable, theme, busyContactId, onBack: () => setRoute("list"), onRequestAccess: () => void contactMatches.requestAccess(), onOpenSettings: () => void contactMatches.openSettings(), onStartChat: (c) => void startChatWith(c), onInvite: (c) => void inviteContact(c), limited: contactMatches.limited, onChooseMoreContacts: contactMatches.chooseMoreContacts ? () => {
162
- var _a;
163
- return void ((_a = contactMatches.chooseMoreContacts) == null ? void 0 : _a.call(contactMatches));
164
- } : void 0, onDismissError: () => {
165
- if (startChatError) setStartChatError(null);
166
- else void contactMatches.refresh();
167
- } }) });
182
+ return /* @__PURE__ */ jsxs(Shell, { theme, testID, children: [
183
+ /* @__PURE__ */ jsx(ContactsScreen, { permission: contactMatches.permission, loading: contactMatches.loading, error: startChatError != null ? startChatError : contactMatches.error, onYantra: contactMatches.onYantra, invitable: contactMatches.invitable, theme, busyContactId, onBack: () => setRoute("list"), onRequestAccess: () => void contactMatches.requestAccess(), onOpenSettings: () => void contactMatches.openSettings(), onStartChat: (c) => void startChatWith(c), onInvite: inviteContact, limited: contactMatches.limited, onChooseMoreContacts: contactMatches.chooseMoreContacts ? () => {
184
+ var _a2;
185
+ return void ((_a2 = contactMatches.chooseMoreContacts) == null ? void 0 : _a2.call(contactMatches));
186
+ } : void 0, onDismissError: () => {
187
+ if (startChatError) setStartChatError(null);
188
+ else void contactMatches.refresh();
189
+ } }),
190
+ /* @__PURE__ */ jsx(InviteSheet, { visible: inviteSheetOpen, name: inviteTarget ? ((_a = inviteTarget.match) == null ? void 0 : _a.displayName) || inviteTarget.displayName : "", number: (_d = (_c = (_b = inviteTarget == null ? void 0 : inviteTarget.rawNumbers) == null ? void 0 : _b[0]) != null ? _c : inviteTarget == null ? void 0 : inviteTarget.e164[0]) != null ? _d : null, imageUri: (_e = inviteTarget == null ? void 0 : inviteTarget.imageUri) != null ? _e : null, canWhatsApp: Boolean(inviteTarget && whatsAppInviteUrl(inviteTarget.e164[0], "x")), theme, onClose: () => setInviteSheetOpen(false), onChoose: (channel) => void sendInvite(channel), onCopy: () => {
191
+ var _a2;
192
+ if (inviteMessage) void ((_a2 = services.link) == null ? void 0 : _a2.copy(inviteMessage));
193
+ } })
194
+ ] });
168
195
  }
169
196
  const listError = conversations.error === dismissedError ? null : conversations.error;
170
197
  return /* @__PURE__ */ jsx(Shell, { theme, testID, children: /* @__PURE__ */ jsx(ConversationListScreen, { conversations: conversations.conversations, loading: conversations.loading, refreshing: conversations.refreshing, error: listError, theme, connectionState: services.gql.connectionState, canInvite: true, onRefresh: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"NativeChatExperience.js","sources":["../../../src/features/messaging/NativeChatExperience.tsx"],"sourcesContent":["/**\n * The chat remote's exposed root (`chat_native/Chat`).\n *\n * Owns its own navigation as local state - the remote must not import\n * @react-navigation, because a second copy of the navigator would not share the\n * host's container. Android hardware back is handled with RN's own BackHandler.\n *\n * Everything here is plain react-native (plus expo-image and\n * @expo/vector-icons, both host-shared singletons) - no gluestack, no\n * NativeWind, no Apollo - because a federated remote may only use what the host\n * shares, and every extra dependency is another way to fail to load on a device\n * in a way the simulator will not reproduce.\n */\nimport * as React from 'react';\nimport { ActivityIndicator, AppState, BackHandler, Platform, StyleSheet, Text, View } from 'react-native';\nimport type { NativeChatExperienceProps } from './chatHost';\nimport { chatThemes, EmptyState } from './ChatComponents';\nimport { useAppTheme } from '../../theme/AppThemeProvider';\nimport { ConversationListScreen } from './ConversationListScreen';\nimport { ContactsScreen } from './ContactsScreen';\nimport { ThreadScreen } from './ThreadScreen';\nimport { useConversations, useMarkRead, useThread } from './useChatData';\nimport { VIEW_CHANNEL_MUTATION, YANTRA_CHAT_INVITER_QUERY } from './chatOperations';\nimport { buildChatInviteUrl, chatInviteMessage } from './chatInviteLink';\n\n/** Used only when the host predates `chatInviteUrl`; the host supplies the per-environment domain. */\nconst DEFAULT_INVITE_WEB_BASE = 'https://yantra.app';\nimport { useContactMatches, type MatchedContact } from './useContactMatches';\nimport type { WirePost } from './chatModel';\n\n/** The screens the remote routes between internally. */\nexport type ChatRoute = 'list' | 'thread' | 'contacts' | 'newGroup' | 'groupInfo';\n\nexport function NativeChatExperience({\n viewer,\n sessionError,\n services,\n initialChannelId,\n initialPeer,\n onActiveChannelChange,\n onInternalRouteChange,\n testID,\n}: NativeChatExperienceProps) {\n const { isDark } = useAppTheme();\n const theme = isDark ? chatThemes.dark : chatThemes.light;\n\n const [route, setRoute] = React.useState<ChatRoute>(initialChannelId ? 'thread' : 'list');\n const [activeChannelId, setActiveChannelId] = React.useState<string | null>(initialChannelId ?? null);\n const [dismissedError, setDismissedError] = React.useState<string | null>(null);\n\n const conversations = useConversations(services, viewer, { syncListRealtime: route === 'list' });\n const contactMatches = useContactMatches(services.gql, services.contacts, viewer, services.phone);\n const [busyContactId, setBusyContactId] = React.useState<string | null>(null);\n const [startChatError, setStartChatError] = React.useState<string | null>(null);\n const onThreadListUpdate = React.useCallback(\n (post: WirePost) => {\n if (!activeChannelId) return;\n conversations.applyConversationMessage(activeChannelId, post);\n // The viewer is looking at this thread, so a message arriving here is already read.\n conversations.markRead(activeChannelId);\n },\n [activeChannelId, conversations.applyConversationMessage, conversations.markRead],\n );\n const thread = useThread(services.gql, route === 'thread' ? activeChannelId : null, viewer, {\n onConversationMessage: onThreadListUpdate,\n media: services.media,\n });\n\n // Clearing the badge is local-first; the mutation is fire-and-forget.\n useMarkRead(services.gql, route === 'thread' ? activeChannelId : null, conversations.markRead);\n\n // Mark read again on LEAVING a thread, so messages that arrived while it was open\n // are not counted as unread by the server on the next list load.\n const threadOpenRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n const open = route === 'thread' ? activeChannelId : null;\n const left = threadOpenRef.current;\n if (left && left !== open) void services.gql.mutate(VIEW_CHANNEL_MUTATION, { id: left });\n threadOpenRef.current = open;\n }, [route, activeChannelId, services.gql]);\n\n // The host suppresses a foreground push banner for the conversation already\n // on screen, so it has to be told every time that changes.\n React.useEffect(() => {\n onActiveChannelChange?.(route === 'thread' ? activeChannelId : null);\n }, [route, activeChannelId, onActiveChannelChange]);\n\n React.useEffect(() => {\n const internal: 'list' | 'thread' | 'contacts' | 'register' =\n route === 'thread' ? 'thread' : route === 'contacts' ? 'contacts' : 'list';\n onInternalRouteChange?.(internal);\n }, [route, onInternalRouteChange]);\n\n // The address book changes outside the app, so re-read it whenever the picker opens\n // and whenever the app returns to the foreground while the picker is showing.\n const refreshContactsRef = React.useRef(contactMatches.refresh);\n refreshContactsRef.current = contactMatches.refresh;\n const contactsGranted = contactMatches.permission === 'granted';\n React.useEffect(() => {\n if (route !== 'contacts' || !contactsGranted) return undefined;\n void refreshContactsRef.current();\n const sub = AppState.addEventListener('change', (state) => {\n if (state === 'active') void refreshContactsRef.current();\n });\n return () => sub.remove();\n }, [route, contactsGranted]);\n\n const activeConversation = React.useMemo(\n () => conversations.conversations.find((c) => c.id === activeChannelId) ?? null,\n [conversations.conversations, activeChannelId],\n );\n\n // Android back pops the internal stack before the host's navigator sees it.\n React.useEffect(() => {\n if (Platform.OS !== 'android') return undefined;\n const sub = BackHandler.addEventListener('hardwareBackPress', () => {\n if (route === 'list') return false;\n setRoute('list');\n return true;\n });\n return () => sub.remove();\n }, [route]);\n\n const openThread = React.useCallback((id: string) => {\n setActiveChannelId(id);\n setRoute('thread');\n }, []);\n\n /**\n * Open (or reuse) the conversation with a matched contact. createDirectChannel\n * is idempotent server-side, so tapping someone you already talk to lands in\n * the existing thread rather than making a second one.\n */\n const startChatWith = React.useCallback(\n async (contact: MatchedContact) => {\n if (!contact.match || busyContactId) return;\n setBusyContactId(contact.id);\n setStartChatError(null);\n try {\n const id = await conversations.openDirect(contact.match.userId, contact.match.displayName);\n if (id) openThread(id);\n else setStartChatError('Could not start this conversation. Please try again.');\n } finally {\n setBusyContactId(null);\n }\n },\n [conversations, openThread, busyContactId],\n );\n\n // Opened from a chat invite link: go straight into the conversation with the inviter\n // (createDirectChannel is idempotent, so reopening an old invite lands in the same thread).\n // The link is editable by anyone, so the server has to vouch for the inviter first, and\n // its name is used - never the one in the link.\n // Tracks the invite object, not the user: every tap on a link arrives as a new object,\n // so reopening a link retries, while re-renders of the same one do not.\n const openedPeer = React.useRef<typeof initialPeer | null>(null);\n const [inviteNotice, setInviteNotice] = React.useState<string | null>(null);\n const { openDirect } = conversations;\n React.useEffect(() => {\n const peer = initialPeer;\n if (!peer?.userId || !viewer?.userId || peer.userId === viewer.userId) return;\n if (openedPeer.current === peer) return;\n openedPeer.current = peer;\n void (async () => {\n const res = await services.gql.query<{\n yantraChatInviter?: { userId: string; displayName: string } | null;\n }>(YANTRA_CHAT_INVITER_QUERY, { userId: peer.userId }, { fetchPolicy: 'network-only' });\n const inviter = res.data?.yantraChatInviter;\n if (!inviter) {\n setInviteNotice(\n res.errors?.length\n ? 'Could not open this invite. Check your connection and open the link again.'\n : 'This invite link is not valid anymore. Ask for a new one.',\n );\n return;\n }\n const id = await openDirect(inviter.userId, inviter.displayName);\n if (id) openThread(id);\n else setInviteNotice(`Could not start a conversation with ${inviter.displayName}. Please try again.`);\n })();\n }, [initialPeer, viewer?.userId, services.gql, openDirect, openThread]);\n\n /**\n * Invite someone who is not here yet.\n *\n * With phone-based membership (issue #1312):\n * 1. Call the connector to generate a deep link\n * 2. Open SMS composer with the deep link (user approves before sending)\n * 3. Fall back to share sheet where SMS is unavailable (simulators)\n *\n * The deep link includes the invitee's phone and the inviter's phone,\n * enabling install-then-attribute and direct link-back to the inviter\n * after the app is installed.\n */\n const inviteContact = React.useCallback(\n async (contact: MatchedContact) => {\n const link = services.link;\n\n if (!link || !viewer?.userId) return;\n const smsTo = contact.rawNumbers?.length ? contact.rawNumbers.slice(0, 1) : contact.e164.slice(0, 1);\n if (!smsTo.length) return;\n\n // The link names the inviter (so the app can open this conversation on arrival) and\n // carries no phone numbers.\n const invite = { inviterId: viewer.userId, inviterName: viewer.displayName ?? null };\n const url = services.phone?.chatInviteUrl?.(invite) ?? buildChatInviteUrl(DEFAULT_INVITE_WEB_BASE, invite);\n const body = chatInviteMessage(viewer.displayName, url);\n\n // Saved numbers, not our E.164 guesses: the phone dials them in its own region.\n const result = await link.composeSms(smsTo, body);\n if (result === 'unavailable') await link.share(body);\n },\n [services.link, services.phone, viewer],\n );\n\n const activeTitle = React.useMemo(\n () => conversations.conversations.find((c) => c.id === activeChannelId)?.title ?? 'Chat',\n [conversations.conversations, activeChannelId],\n );\n\n if (sessionError) {\n return (\n <Shell theme={theme} testID={testID}>\n <EmptyState\n icon=\"alert-circle-outline\"\n title=\"Chat is unavailable\"\n detail={sessionError}\n theme={theme}\n />\n </Shell>\n );\n }\n\n // Session still resolving: a spinner, never an error. org/user arrive a beat\n // after mount and a flash of failure reads as a broken feature.\n if (!viewer) {\n return (\n <Shell theme={theme} testID={testID}>\n <View style={styles.center}>\n <ActivityIndicator />\n </View>\n </Shell>\n );\n }\n\n if (route === 'thread' && activeChannelId) {\n const threadError = thread.error === dismissedError ? null : thread.error;\n return (\n <Shell theme={theme} testID={testID}>\n <ThreadScreen\n title={activeTitle}\n avatarUrl={activeConversation?.avatarUrl}\n messages={thread.messages}\n loading={thread.loading}\n loadingMore={thread.loadingMore}\n error={threadError}\n theme={theme}\n connectionState={services.gql.connectionState}\n haptics={services.haptics}\n onBack={() => setRoute('list')}\n onSend={(body) => void thread.send(body)}\n onLoadMore={thread.loadMore}\n onRetry={thread.retry}\n onReact={(messageId, emoji) => {\n const current = thread.messages\n .find((m) => m.id === messageId)\n ?.reactions.find((r) => r.mine)?.reaction;\n // Tapping your current Tapback removes it, as in iMessage.\n thread.react(messageId, current === emoji ? null : emoji);\n }}\n onCopyText={services.clipboard ? (text) => void services.clipboard?.copy(text) : undefined}\n onShareText={services.link ? (text) => void services.link?.share(text) : undefined}\n media={services.media}\n audio={services.audio}\n onSendAttachments={\n thread.sendAttachments\n ? (files, caption, kind) => void thread.sendAttachments?.(files, caption, kind)\n : undefined\n }\n onDismissError={() => setDismissedError(thread.error)}\n />\n </Shell>\n );\n }\n\n if (route === 'contacts') {\n return (\n <Shell theme={theme} testID={testID}>\n <ContactsScreen\n permission={contactMatches.permission}\n loading={contactMatches.loading}\n error={startChatError ?? contactMatches.error}\n onYantra={contactMatches.onYantra}\n invitable={contactMatches.invitable}\n theme={theme}\n busyContactId={busyContactId}\n onBack={() => setRoute('list')}\n onRequestAccess={() => void contactMatches.requestAccess()}\n onOpenSettings={() => void contactMatches.openSettings()}\n onStartChat={(c) => void startChatWith(c)}\n onInvite={(c) => void inviteContact(c)}\n limited={contactMatches.limited}\n onChooseMoreContacts={\n contactMatches.chooseMoreContacts ? () => void contactMatches.chooseMoreContacts?.() : undefined\n }\n onDismissError={() => {\n if (startChatError) setStartChatError(null);\n else void contactMatches.refresh();\n }}\n />\n </Shell>\n );\n }\n\n const listError = conversations.error === dismissedError ? null : conversations.error;\n return (\n <Shell theme={theme} testID={testID}>\n <ConversationListScreen\n conversations={conversations.conversations}\n loading={conversations.loading}\n refreshing={conversations.refreshing}\n error={listError}\n theme={theme}\n connectionState={services.gql.connectionState}\n canInvite\n onRefresh={() => {\n conversations.refresh();\n void contactMatches.refresh();\n }}\n onRetry={conversations.refresh}\n loadingMore={conversations.loadingMore}\n onLoadMore={conversations.loadMore}\n onOpen={openThread}\n onNewChat={() => setRoute('contacts')}\n onDismissError={() => setDismissedError(conversations.error)}\n notice={inviteNotice}\n onDismissNotice={() => setInviteNotice(null)}\n />\n </Shell>\n );\n}\n\nfunction Shell({ theme, testID, children }: { theme: { bg: string }; testID?: string; children: React.ReactNode }) {\n return (\n <View testID={testID ?? 'chat-native'} style={[styles.fill, { backgroundColor: theme.bg }]}>\n {children}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center' },\n});\n\nexport default NativeChatExperience;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NativeChatExperience.js","sources":["../../../src/features/messaging/NativeChatExperience.tsx"],"sourcesContent":["/**\n * The chat remote's exposed root (`chat_native/Chat`).\n *\n * Owns its own navigation as local state - the remote must not import\n * @react-navigation, because a second copy of the navigator would not share the\n * host's container. Android hardware back is handled with RN's own BackHandler.\n *\n * Everything here is plain react-native (plus expo-image and\n * @expo/vector-icons, both host-shared singletons) - no gluestack, no\n * NativeWind, no Apollo - because a federated remote may only use what the host\n * shares, and every extra dependency is another way to fail to load on a device\n * in a way the simulator will not reproduce.\n */\nimport * as React from 'react';\nimport { ActivityIndicator, AppState, BackHandler, Platform, StyleSheet, Text, View } from 'react-native';\nimport type { NativeChatExperienceProps } from './chatHost';\nimport { chatThemes, EmptyState } from './ChatComponents';\nimport { useAppTheme } from '../../theme/AppThemeProvider';\nimport { ConversationListScreen } from './ConversationListScreen';\nimport { ContactsScreen } from './ContactsScreen';\nimport { ThreadScreen } from './ThreadScreen';\nimport { useConversations, useMarkRead, useThread } from './useChatData';\nimport { VIEW_CHANNEL_MUTATION, YANTRA_CHAT_INVITER_QUERY } from './chatOperations';\nimport { buildChatInviteUrl, chatInviteMessage, whatsAppInviteUrl } from './chatInviteLink';\nimport { InviteSheet, type InviteChannel } from './InviteSheet';\n\n/** Used only when the host predates `chatInviteUrl`; the host supplies the per-environment domain. */\nconst DEFAULT_INVITE_WEB_BASE = 'https://yantra.app';\nimport { useContactMatches, type MatchedContact } from './useContactMatches';\nimport type { WirePost } from './chatModel';\n\n/** The screens the remote routes between internally. */\nexport type ChatRoute = 'list' | 'thread' | 'contacts' | 'newGroup' | 'groupInfo';\n\nexport function NativeChatExperience({\n viewer,\n sessionError,\n services,\n initialChannelId,\n initialPeer,\n onActiveChannelChange,\n onInternalRouteChange,\n testID,\n}: NativeChatExperienceProps) {\n const { isDark } = useAppTheme();\n const theme = isDark ? chatThemes.dark : chatThemes.light;\n\n const [route, setRoute] = React.useState<ChatRoute>(initialChannelId ? 'thread' : 'list');\n const [activeChannelId, setActiveChannelId] = React.useState<string | null>(initialChannelId ?? null);\n const [dismissedError, setDismissedError] = React.useState<string | null>(null);\n\n const conversations = useConversations(services, viewer, { syncListRealtime: route === 'list' });\n const contactMatches = useContactMatches(services.gql, services.contacts, viewer, services.phone);\n const [busyContactId, setBusyContactId] = React.useState<string | null>(null);\n const [startChatError, setStartChatError] = React.useState<string | null>(null);\n const onThreadListUpdate = React.useCallback(\n (post: WirePost) => {\n if (!activeChannelId) return;\n conversations.applyConversationMessage(activeChannelId, post);\n // The viewer is looking at this thread, so a message arriving here is already read.\n conversations.markRead(activeChannelId);\n },\n [activeChannelId, conversations.applyConversationMessage, conversations.markRead],\n );\n const thread = useThread(services.gql, route === 'thread' ? activeChannelId : null, viewer, {\n onConversationMessage: onThreadListUpdate,\n media: services.media,\n });\n\n // Clearing the badge is local-first; the mutation is fire-and-forget.\n useMarkRead(services.gql, route === 'thread' ? activeChannelId : null, conversations.markRead);\n\n // Mark read again on LEAVING a thread, so messages that arrived while it was open\n // are not counted as unread by the server on the next list load.\n const threadOpenRef = React.useRef<string | null>(null);\n React.useEffect(() => {\n const open = route === 'thread' ? activeChannelId : null;\n const left = threadOpenRef.current;\n if (left && left !== open) void services.gql.mutate(VIEW_CHANNEL_MUTATION, { id: left });\n threadOpenRef.current = open;\n }, [route, activeChannelId, services.gql]);\n\n // The host suppresses a foreground push banner for the conversation already\n // on screen, so it has to be told every time that changes.\n React.useEffect(() => {\n onActiveChannelChange?.(route === 'thread' ? activeChannelId : null);\n }, [route, activeChannelId, onActiveChannelChange]);\n\n React.useEffect(() => {\n const internal: 'list' | 'thread' | 'contacts' | 'register' =\n route === 'thread' ? 'thread' : route === 'contacts' ? 'contacts' : 'list';\n onInternalRouteChange?.(internal);\n }, [route, onInternalRouteChange]);\n\n // The address book changes outside the app, so re-read it whenever the picker opens\n // and whenever the app returns to the foreground while the picker is showing.\n const refreshContactsRef = React.useRef(contactMatches.refresh);\n refreshContactsRef.current = contactMatches.refresh;\n const contactsGranted = contactMatches.permission === 'granted';\n React.useEffect(() => {\n if (route !== 'contacts' || !contactsGranted) return undefined;\n void refreshContactsRef.current();\n const sub = AppState.addEventListener('change', (state) => {\n if (state === 'active') void refreshContactsRef.current();\n });\n return () => sub.remove();\n }, [route, contactsGranted]);\n\n const activeConversation = React.useMemo(\n () => conversations.conversations.find((c) => c.id === activeChannelId) ?? null,\n [conversations.conversations, activeChannelId],\n );\n\n // Android back pops the internal stack before the host's navigator sees it.\n React.useEffect(() => {\n if (Platform.OS !== 'android') return undefined;\n const sub = BackHandler.addEventListener('hardwareBackPress', () => {\n if (route === 'list') return false;\n setRoute('list');\n return true;\n });\n return () => sub.remove();\n }, [route]);\n\n const openThread = React.useCallback((id: string) => {\n setActiveChannelId(id);\n setRoute('thread');\n }, []);\n\n /**\n * Open (or reuse) the conversation with a matched contact. createDirectChannel\n * is idempotent server-side, so tapping someone you already talk to lands in\n * the existing thread rather than making a second one.\n */\n const startChatWith = React.useCallback(\n async (contact: MatchedContact) => {\n if (!contact.match || busyContactId) return;\n setBusyContactId(contact.id);\n setStartChatError(null);\n try {\n const id = await conversations.openDirect(contact.match.userId, contact.match.displayName);\n if (id) openThread(id);\n else setStartChatError('Could not start this conversation. Please try again.');\n } finally {\n setBusyContactId(null);\n }\n },\n [conversations, openThread, busyContactId],\n );\n\n // Opened from a chat invite link: go straight into the conversation with the inviter\n // (createDirectChannel is idempotent, so reopening an old invite lands in the same thread).\n // The link is editable by anyone, so the server has to vouch for the inviter first, and\n // its name is used - never the one in the link.\n // Tracks the invite object, not the user: every tap on a link arrives as a new object,\n // so reopening a link retries, while re-renders of the same one do not.\n const openedPeer = React.useRef<typeof initialPeer | null>(null);\n const [inviteNotice, setInviteNotice] = React.useState<string | null>(null);\n const { openDirect } = conversations;\n React.useEffect(() => {\n const peer = initialPeer;\n if (!peer?.userId || !viewer?.userId || peer.userId === viewer.userId) return;\n if (openedPeer.current === peer) return;\n openedPeer.current = peer;\n void (async () => {\n const res = await services.gql.query<{\n yantraChatInviter?: { userId: string; displayName: string } | null;\n }>(YANTRA_CHAT_INVITER_QUERY, { userId: peer.userId }, { fetchPolicy: 'network-only' });\n const inviter = res.data?.yantraChatInviter;\n if (!inviter) {\n setInviteNotice(\n res.errors?.length\n ? 'Could not open this invite. Check your connection and open the link again.'\n : 'This invite link is not valid anymore. Ask for a new one.',\n );\n return;\n }\n const id = await openDirect(inviter.userId, inviter.displayName);\n if (id) openThread(id);\n else setInviteNotice(`Could not start a conversation with ${inviter.displayName}. Please try again.`);\n })();\n }, [initialPeer, viewer?.userId, services.gql, openDirect, openThread]);\n\n /**\n * Invite someone who is not here yet: tapping Invite opens the invite sheet (Messages,\n * WhatsApp, copy link, share sheet) and the chosen app opens with the invite prefilled.\n * Nothing is sent without the person tapping Send there.\n *\n * The link names the inviter (so the app can open this conversation on arrival) and\n * carries no phone numbers.\n */\n const [inviteTarget, setInviteTarget] = React.useState<MatchedContact | null>(null);\n const [inviteSheetOpen, setInviteSheetOpen] = React.useState(false);\n\n const inviteContact = React.useCallback(\n (contact: MatchedContact) => {\n if (!services.link || !viewer?.userId) return;\n setInviteTarget(contact);\n setInviteSheetOpen(true);\n },\n [services.link, viewer?.userId],\n );\n\n const inviteMessage = React.useMemo(() => {\n if (!viewer?.userId) return '';\n const invite = { inviterId: viewer.userId, inviterName: viewer.displayName ?? null };\n const url = services.phone?.chatInviteUrl?.(invite) ?? buildChatInviteUrl(DEFAULT_INVITE_WEB_BASE, invite);\n return chatInviteMessage(viewer.displayName, url);\n }, [services.phone, viewer?.userId, viewer?.displayName]);\n\n const sendInvite = React.useCallback(\n async (channel: Exclude<InviteChannel, 'copy'>) => {\n const link = services.link;\n const contact = inviteTarget;\n if (!link || !contact || !inviteMessage) return;\n if (channel === 'whatsapp') {\n const url = whatsAppInviteUrl(contact.e164[0], inviteMessage);\n if (url) {\n await link.openUrl(url);\n return;\n }\n }\n if (channel === 'sms') {\n // Saved numbers, not our E.164 guesses: the phone dials them in its own region.\n const smsTo = contact.rawNumbers?.length ? contact.rawNumbers.slice(0, 1) : contact.e164.slice(0, 1);\n if (smsTo.length && (await link.composeSms(smsTo, inviteMessage)) === 'opened') return;\n }\n // 'share', and the fallback where Messages is unavailable (every simulator).\n await link.share(inviteMessage);\n },\n [services.link, inviteTarget, inviteMessage],\n );\n\n const activeTitle = React.useMemo(\n () => conversations.conversations.find((c) => c.id === activeChannelId)?.title ?? 'Chat',\n [conversations.conversations, activeChannelId],\n );\n\n if (sessionError) {\n return (\n <Shell theme={theme} testID={testID}>\n <EmptyState\n icon=\"alert-circle-outline\"\n title=\"Chat is unavailable\"\n detail={sessionError}\n theme={theme}\n />\n </Shell>\n );\n }\n\n // Session still resolving: a spinner, never an error. org/user arrive a beat\n // after mount and a flash of failure reads as a broken feature.\n if (!viewer) {\n return (\n <Shell theme={theme} testID={testID}>\n <View style={styles.center}>\n <ActivityIndicator />\n </View>\n </Shell>\n );\n }\n\n if (route === 'thread' && activeChannelId) {\n const threadError = thread.error === dismissedError ? null : thread.error;\n return (\n <Shell theme={theme} testID={testID}>\n <ThreadScreen\n title={activeTitle}\n avatarUrl={activeConversation?.avatarUrl}\n messages={thread.messages}\n loading={thread.loading}\n loadingMore={thread.loadingMore}\n error={threadError}\n theme={theme}\n connectionState={services.gql.connectionState}\n haptics={services.haptics}\n onBack={() => setRoute('list')}\n onSend={(body) => void thread.send(body)}\n onLoadMore={thread.loadMore}\n onRetry={thread.retry}\n onReact={(messageId, emoji) => {\n const current = thread.messages\n .find((m) => m.id === messageId)\n ?.reactions.find((r) => r.mine)?.reaction;\n // Tapping your current Tapback removes it, as in iMessage.\n thread.react(messageId, current === emoji ? null : emoji);\n }}\n onCopyText={services.clipboard ? (text) => void services.clipboard?.copy(text) : undefined}\n onShareText={services.link ? (text) => void services.link?.share(text) : undefined}\n media={services.media}\n audio={services.audio}\n onSendAttachments={\n thread.sendAttachments\n ? (files, caption, kind) => void thread.sendAttachments?.(files, caption, kind)\n : undefined\n }\n onDismissError={() => setDismissedError(thread.error)}\n />\n </Shell>\n );\n }\n\n if (route === 'contacts') {\n return (\n <Shell theme={theme} testID={testID}>\n <ContactsScreen\n permission={contactMatches.permission}\n loading={contactMatches.loading}\n error={startChatError ?? contactMatches.error}\n onYantra={contactMatches.onYantra}\n invitable={contactMatches.invitable}\n theme={theme}\n busyContactId={busyContactId}\n onBack={() => setRoute('list')}\n onRequestAccess={() => void contactMatches.requestAccess()}\n onOpenSettings={() => void contactMatches.openSettings()}\n onStartChat={(c) => void startChatWith(c)}\n onInvite={inviteContact}\n limited={contactMatches.limited}\n onChooseMoreContacts={\n contactMatches.chooseMoreContacts ? () => void contactMatches.chooseMoreContacts?.() : undefined\n }\n onDismissError={() => {\n if (startChatError) setStartChatError(null);\n else void contactMatches.refresh();\n }}\n />\n <InviteSheet\n visible={inviteSheetOpen}\n name={inviteTarget ? inviteTarget.match?.displayName || inviteTarget.displayName : ''}\n number={inviteTarget?.rawNumbers?.[0] ?? inviteTarget?.e164[0] ?? null}\n imageUri={inviteTarget?.imageUri ?? null}\n canWhatsApp={Boolean(inviteTarget && whatsAppInviteUrl(inviteTarget.e164[0], 'x'))}\n theme={theme}\n onClose={() => setInviteSheetOpen(false)}\n onChoose={(channel) => void sendInvite(channel)}\n onCopy={() => {\n if (inviteMessage) void services.link?.copy(inviteMessage);\n }}\n />\n </Shell>\n );\n }\n\n const listError = conversations.error === dismissedError ? null : conversations.error;\n return (\n <Shell theme={theme} testID={testID}>\n <ConversationListScreen\n conversations={conversations.conversations}\n loading={conversations.loading}\n refreshing={conversations.refreshing}\n error={listError}\n theme={theme}\n connectionState={services.gql.connectionState}\n canInvite\n onRefresh={() => {\n conversations.refresh();\n void contactMatches.refresh();\n }}\n onRetry={conversations.refresh}\n loadingMore={conversations.loadingMore}\n onLoadMore={conversations.loadMore}\n onOpen={openThread}\n onNewChat={() => setRoute('contacts')}\n onDismissError={() => setDismissedError(conversations.error)}\n notice={inviteNotice}\n onDismissNotice={() => setInviteNotice(null)}\n />\n </Shell>\n );\n}\n\nfunction Shell({ theme, testID, children }: { theme: { bg: string }; testID?: string; children: React.ReactNode }) {\n return (\n <View testID={testID ?? 'chat-native'} style={[styles.fill, { backgroundColor: theme.bg }]}>\n {children}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center' },\n});\n\nexport default NativeChatExperience;\n"],"names":["_a","_b","_c","_d"],"mappings":"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"}