@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.
- package/lib/features/messaging/InviteSheet.js +178 -0
- package/lib/features/messaging/InviteSheet.js.map +1 -0
- package/lib/features/messaging/NativeChatExperience.js +62 -35
- package/lib/features/messaging/NativeChatExperience.js.map +1 -1
- package/lib/features/messaging/RegistrationScreen.js +385 -192
- package/lib/features/messaging/RegistrationScreen.js.map +1 -1
- package/lib/features/messaging/chatInviteLink.js +6 -1
- package/lib/features/messaging/chatInviteLink.js.map +1 -1
- package/lib/features/messaging/countryPicker.js +25 -0
- package/lib/features/messaging/countryPicker.js.map +1 -0
- package/lib/features/messaging/mobileNumberCheck.js +56 -0
- package/lib/features/messaging/mobileNumberCheck.js.map +1 -0
- package/lib/features/messaging/phoneCountries.js +981 -0
- package/lib/features/messaging/phoneCountries.js.map +1 -0
- package/lib/features/messaging/phoneNumberRules.js +982 -0
- package/lib/features/messaging/phoneNumberRules.js.map +1 -0
- package/lib/features/messaging/phoneNumbers.js +30 -72
- package/lib/features/messaging/phoneNumbers.js.map +1 -1
- package/lib/features/messaging/usePhoneVerification.js +8 -6
- package/lib/features/messaging/usePhoneVerification.js.map +1 -1
- package/lib/screens/ChatNative/index.js +1 -1
- package/lib/screens/ChatNative/index.js.map +1 -1
- package/package.json +5 -4
|
@@ -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
|
|
64
|
-
return (
|
|
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
|
|
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 = (
|
|
109
|
+
const inviter = (_a2 = res.data) == null ? void 0 : _a2.yantraChatInviter;
|
|
109
110
|
if (!inviter) {
|
|
110
|
-
setInviteNotice(((
|
|
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
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (!link || !(viewer == null ? void 0 : viewer.userId)) return;
|
|
122
|
-
|
|
123
|
-
|
|
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: (
|
|
131
|
+
inviterName: (_a2 = viewer.displayName) != null ? _a2 : null
|
|
127
132
|
};
|
|
128
|
-
const url = (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
|
135
|
-
return (
|
|
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
|
|
147
|
-
const current = (
|
|
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
|
|
151
|
-
return void ((
|
|
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
|
|
154
|
-
return void ((
|
|
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
|
|
157
|
-
return void ((
|
|
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__ */
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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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"}
|