@adminide-stack/yantra-mobile 12.0.69-alpha.15 → 12.0.69-alpha.17

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.
@@ -1,4 +1,4 @@
1
- import {navigationRef}from'@common-stack/client-react';import {isAuthenticatedSelector}from'@adminide-stack/user-auth0-client';import AsyncStorage from'@react-native-async-storage/async-storage';import {CommonActions}from'@react-navigation/native';import {useState,useEffect}from'react';import {Linking}from'react-native';import {useSelector}from'react-redux';import {parseChatInviteUrl}from'./chatInviteLink.js';var __defProp = Object.defineProperty;
1
+ import {navigationRef}from'@common-stack/client-react';import {isAuthenticatedSelector}from'@adminide-stack/user-auth0-client';import AsyncStorage from'@react-native-async-storage/async-storage';import {CommonActions}from'@react-navigation/native';import {useState,useRef,useEffect}from'react';import {Linking}from'react-native';import {useSelector}from'react-redux';import {parseChatInviteUrl}from'./chatInviteLink.js';var __defProp = Object.defineProperty;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -18,6 +18,8 @@ var __spreadValues = (a, b) => {
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
  const PENDING_KEY = "yantra-chat-pending-invite";
21
+ const CHAT_ROUTE = "MainStack.ChatNative";
22
+ const SIGN_UP_ROUTE = "MainStack.SignUp";
21
23
  const PENDING_TTL_MS = 24 * 60 * 60 * 1e3;
22
24
  async function readPending() {
23
25
  var _a;
@@ -40,6 +42,7 @@ async function readPending() {
40
42
  function ChatInviteDeepLink() {
41
43
  const isAuthenticated = useSelector(isAuthenticatedSelector);
42
44
  const [invite, setInvite] = useState(null);
45
+ const sentToSignUp = useRef(null);
43
46
  useEffect(() => {
44
47
  let active = true;
45
48
  const adopt = (url) => {
@@ -63,26 +66,47 @@ function ChatInviteDeepLink() {
63
66
  };
64
67
  }, []);
65
68
  useEffect(() => {
66
- if (!invite || !isAuthenticated) return void 0;
69
+ var _a;
70
+ if (!invite) return void 0;
71
+ const chatParams = {
72
+ inviterId: invite.inviterId,
73
+ inviterName: (_a = invite.inviterName) != null ? _a : void 0,
74
+ inviteAt: Date.now()
75
+ };
76
+ if (isAuthenticated && sentToSignUp.current === invite) {
77
+ sentToSignUp.current = null;
78
+ setInvite(null);
79
+ void AsyncStorage.removeItem(PENDING_KEY).catch(() => void 0);
80
+ return void 0;
81
+ }
82
+ if (!isAuthenticated && sentToSignUp.current === invite) return void 0;
67
83
  let cancelled = false;
84
+ let timer;
68
85
  const tryOpen = () => {
69
- var _a;
70
86
  if (cancelled) return;
71
87
  if (!navigationRef.isReady()) {
72
88
  timer = setTimeout(tryOpen, 400);
73
89
  return;
74
90
  }
91
+ if (isAuthenticated) {
92
+ navigationRef.dispatch(CommonActions.navigate({
93
+ name: CHAT_ROUTE,
94
+ params: chatParams
95
+ }));
96
+ setInvite(null);
97
+ void AsyncStorage.removeItem(PENDING_KEY).catch(() => void 0);
98
+ return;
99
+ }
100
+ sentToSignUp.current = invite;
75
101
  navigationRef.dispatch(CommonActions.navigate({
76
- name: "MainStack.ChatNative",
77
- params: {
78
- inviterId: invite.inviterId,
79
- inviterName: (_a = invite.inviterName) != null ? _a : void 0
80
- }
102
+ name: SIGN_UP_ROUTE,
103
+ params: __spreadValues({
104
+ isSignupDefault: true,
105
+ redirect: CHAT_ROUTE
106
+ }, chatParams)
81
107
  }));
82
- setInvite(null);
83
- void AsyncStorage.removeItem(PENDING_KEY).catch(() => void 0);
84
108
  };
85
- let timer = setTimeout(tryOpen, 0);
109
+ timer = setTimeout(tryOpen, 0);
86
110
  return () => {
87
111
  cancelled = true;
88
112
  if (timer) clearTimeout(timer);
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInviteDeepLink.js","sources":["../../../src/features/messaging/ChatInviteDeepLink.tsx"],"sourcesContent":["/**\n * Chat invite links on a phone (`<web>/chat/invite?by=&n=`, `yantraapp://chat/invite?...`).\n *\n * Mounted once at the app root, next to the organization `InviteDeepLink`, because an\n * invitee may arrive signed out and every route is auth-gated. The inviter is parked in\n * storage across the sign-in round trip; once there is a session and the navigator is\n * ready, it opens Chat, which registers the user if needed and then opens the\n * conversation with the inviter.\n */\nimport { navigationRef } from '@common-stack/client-react';\nimport { isAuthenticatedSelector } from '@adminide-stack/user-auth0-client';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport { CommonActions } from '@react-navigation/native';\nimport { useEffect, useState } from 'react';\nimport { Linking } from 'react-native';\nimport { useSelector } from 'react-redux';\nimport { parseChatInviteUrl, type ChatInvite } from './chatInviteLink';\n\nconst PENDING_KEY = 'yantra-chat-pending-invite';\n/** An invite nobody acted on for a day is stale; do not surprise the user with it later. */\nconst PENDING_TTL_MS = 24 * 60 * 60 * 1000;\n\nasync function readPending(): Promise<ChatInvite | null> {\n try {\n const raw = await AsyncStorage.getItem(PENDING_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as ChatInvite & { at?: number };\n if (!parsed?.inviterId || !parsed.at || Date.now() - parsed.at > PENDING_TTL_MS) {\n await AsyncStorage.removeItem(PENDING_KEY);\n return null;\n }\n return { inviterId: parsed.inviterId, inviterName: parsed.inviterName ?? null };\n } catch {\n return null;\n }\n}\n\nexport function ChatInviteDeepLink(): null {\n const isAuthenticated = useSelector(isAuthenticatedSelector);\n const [invite, setInvite] = useState<ChatInvite | null>(null);\n\n useEffect(() => {\n let active = true;\n const adopt = (url: string | null) => {\n const next = parseChatInviteUrl(url);\n if (!next || !active) return;\n setInvite(next);\n void AsyncStorage.setItem(PENDING_KEY, JSON.stringify({ ...next, at: Date.now() })).catch(() => undefined);\n };\n void Linking.getInitialURL()\n .then(adopt)\n .catch(() => undefined);\n const sub = Linking.addEventListener('url', ({ url }) => adopt(url));\n void readPending().then((parked) => {\n if (parked && active) setInvite((current) => current ?? parked);\n });\n return () => {\n active = false;\n sub.remove();\n };\n }, []);\n\n useEffect(() => {\n if (!invite || !isAuthenticated) return undefined;\n let cancelled = false;\n // The navigator mounts after auth resolves; wait for it rather than dropping the invite.\n const tryOpen = () => {\n if (cancelled) return;\n if (!navigationRef.isReady()) {\n timer = setTimeout(tryOpen, 400);\n return;\n }\n navigationRef.dispatch(\n CommonActions.navigate({\n name: 'MainStack.ChatNative',\n params: { inviterId: invite.inviterId, inviterName: invite.inviterName ?? undefined },\n }),\n );\n setInvite(null);\n void AsyncStorage.removeItem(PENDING_KEY).catch(() => undefined);\n };\n let timer: ReturnType<typeof setTimeout> | undefined = setTimeout(tryOpen, 0);\n return () => {\n cancelled = true;\n if (timer) clearTimeout(timer);\n };\n }, [invite, isAuthenticated]);\n\n return null;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ChatInviteDeepLink.js","sources":["../../../src/features/messaging/ChatInviteDeepLink.tsx"],"sourcesContent":["/**\n * Chat invite links on a phone (`<web>/chat/invite?by=&n=`, `yantraapp://chat/invite?...`).\n *\n * Mounted once at the app root, next to the organization `InviteDeepLink`, because an\n * invitee may arrive signed out and every route is auth-gated.\n *\n * - Signed out: opens Sign up (with Log in one tap away for existing accounts), whose\n * `redirect` brings them to Chat with the invite once they are in.\n * - Signed in: opens Chat directly.\n *\n * Chat then asks for Yantra Chat registration if needed and opens the conversation with\n * the inviter. The invite is also parked in storage, so it survives the app being closed\n * in the middle of signing up.\n */\nimport { navigationRef } from '@common-stack/client-react';\nimport { isAuthenticatedSelector } from '@adminide-stack/user-auth0-client';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport { CommonActions } from '@react-navigation/native';\nimport { useEffect, useRef, useState } from 'react';\nimport { Linking } from 'react-native';\nimport { useSelector } from 'react-redux';\nimport { parseChatInviteUrl, type ChatInvite } from './chatInviteLink';\n\nconst PENDING_KEY = 'yantra-chat-pending-invite';\nconst CHAT_ROUTE = 'MainStack.ChatNative';\n/** The auth package's sign-up route (AuthMobileNavigationRoutesEnum.SignUp). */\nconst SIGN_UP_ROUTE = 'MainStack.SignUp';\n/** An invite nobody acted on for a day is stale; do not surprise the user with it later. */\nconst PENDING_TTL_MS = 24 * 60 * 60 * 1000;\n\nasync function readPending(): Promise<ChatInvite | null> {\n try {\n const raw = await AsyncStorage.getItem(PENDING_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as ChatInvite & { at?: number };\n if (!parsed?.inviterId || !parsed.at || Date.now() - parsed.at > PENDING_TTL_MS) {\n await AsyncStorage.removeItem(PENDING_KEY);\n return null;\n }\n return { inviterId: parsed.inviterId, inviterName: parsed.inviterName ?? null };\n } catch {\n return null;\n }\n}\n\nexport function ChatInviteDeepLink(): null {\n const isAuthenticated = useSelector(isAuthenticatedSelector);\n const [invite, setInvite] = useState<ChatInvite | null>(null);\n /** The invite already handed to Sign up; its `redirect` opens Chat, so it must not be opened twice. */\n const sentToSignUp = useRef<ChatInvite | null>(null);\n\n useEffect(() => {\n let active = true;\n const adopt = (url: string | null) => {\n const next = parseChatInviteUrl(url);\n if (!next || !active) return;\n setInvite(next);\n void AsyncStorage.setItem(PENDING_KEY, JSON.stringify({ ...next, at: Date.now() })).catch(() => undefined);\n };\n void Linking.getInitialURL()\n .then(adopt)\n .catch(() => undefined);\n const sub = Linking.addEventListener('url', ({ url }) => adopt(url));\n void readPending().then((parked) => {\n if (parked && active) setInvite((current) => current ?? parked);\n });\n return () => {\n active = false;\n sub.remove();\n };\n }, []);\n\n useEffect(() => {\n if (!invite) return undefined;\n const chatParams = {\n inviterId: invite.inviterId,\n inviterName: invite.inviterName ?? undefined,\n inviteAt: Date.now(),\n };\n\n if (isAuthenticated && sentToSignUp.current === invite) {\n // Sign up's own redirect is opening Chat with this invite.\n sentToSignUp.current = null;\n setInvite(null);\n void AsyncStorage.removeItem(PENDING_KEY).catch(() => undefined);\n return undefined;\n }\n if (!isAuthenticated && sentToSignUp.current === invite) return undefined;\n\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n // The navigator mounts after auth resolves; wait for it rather than dropping the invite.\n const tryOpen = () => {\n if (cancelled) return;\n if (!navigationRef.isReady()) {\n timer = setTimeout(tryOpen, 400);\n return;\n }\n if (isAuthenticated) {\n navigationRef.dispatch(CommonActions.navigate({ name: CHAT_ROUTE, params: chatParams }));\n setInvite(null);\n void AsyncStorage.removeItem(PENDING_KEY).catch(() => undefined);\n return;\n }\n // Not signed in: register first, then come back to this invite.\n sentToSignUp.current = invite;\n navigationRef.dispatch(\n CommonActions.navigate({\n name: SIGN_UP_ROUTE,\n params: { isSignupDefault: true, redirect: CHAT_ROUTE, ...chatParams },\n }),\n );\n };\n timer = setTimeout(tryOpen, 0);\n return () => {\n cancelled = true;\n if (timer) clearTimeout(timer);\n };\n }, [invite, isAuthenticated]);\n\n return null;\n}\n"],"names":[],"mappings":"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"}
@@ -11,6 +11,8 @@ import {jsx,jsxs}from'react/jsx-runtime';import*as React from'react';import {Sty
11
11
  onOpen,
12
12
  onNewChat,
13
13
  onDismissError,
14
+ notice = null,
15
+ onDismissNotice,
14
16
  loadingMore = false,
15
17
  onLoadMore
16
18
  }) {
@@ -52,6 +54,7 @@ import {jsx,jsxs}from'react/jsx-runtime';import*as React from'react';import {Sty
52
54
  ] }),
53
55
  /* @__PURE__ */ jsx(ConnectionBanner, { state: connectionState, theme }),
54
56
  /* @__PURE__ */ jsx(InlineBanner, { message: error, theme, onDismiss: onDismissError }),
57
+ /* @__PURE__ */ jsx(InlineBanner, { message: notice, theme, onDismiss: () => onDismissNotice == null ? void 0 : onDismissNotice() }),
55
58
  error ? /* @__PURE__ */ jsx(Pressable, { onPress: onRetry, accessibilityRole: "button", accessibilityLabel: "Retry loading chats", style: [styles.retryBanner, {
56
59
  backgroundColor: theme.surface
57
60
  }], children: /* @__PURE__ */ jsx(Text, { style: [styles.retryBannerText, {
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationListScreen.js","sources":["../../../src/features/messaging/ConversationListScreen.tsx"],"sourcesContent":["/**\n * The conversation list — iOS Messages-style home screen.\n */\nimport * as React from 'react';\nimport {\n ActivityIndicator,\n FlatList,\n Pressable,\n RefreshControl,\n StyleSheet,\n Text,\n TextInput,\n View,\n} from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { ConnectionBanner, ConversationRow, EmptyState, InlineBanner, type ChatTheme } from './ChatComponents';\nimport { conversationListKey, dedupeConversationList, type ChatConversation } from './chatModel';\nimport type { ChatConnectionState } from './chatHost';\n\nexport function ConversationListScreen({\n conversations,\n loading,\n refreshing,\n error,\n theme,\n connectionState,\n canInvite,\n onRefresh,\n onRetry,\n onOpen,\n onNewChat,\n onDismissError,\n loadingMore = false,\n onLoadMore,\n}: {\n conversations: ChatConversation[];\n loading: boolean;\n refreshing: boolean;\n loadingMore?: boolean;\n onLoadMore?: () => void;\n error: string | null;\n theme: ChatTheme;\n connectionState: ChatConnectionState;\n canInvite: boolean;\n onRefresh: () => void;\n onRetry: () => void;\n onOpen: (id: string) => void;\n onNewChat: () => void;\n onDismissError: () => void;\n}) {\n const [now, setNow] = React.useState(() => Date.now());\n const [query, setQuery] = React.useState('');\n React.useEffect(() => {\n const t = setInterval(() => setNow(Date.now()), 60_000);\n return () => clearInterval(t);\n }, []);\n\n const visible = React.useMemo(() => {\n const deduped = dedupeConversationList(conversations);\n const q = query.trim().toLowerCase();\n if (!q) return deduped;\n return deduped.filter((c) => c.title.toLowerCase().includes(q) || c.subtitle.toLowerCase().includes(q));\n }, [conversations, query]);\n\n const Separator = React.useCallback(\n () => <View style={[styles.separator, { backgroundColor: theme.border }]} />,\n [theme.border],\n );\n\n const listHeader = (\n <View style={[styles.listHeader, { flexDirection: 'row', alignItems: 'center' }]}>\n <Text style={[styles.listTitle, { color: theme.text }]}>Messages</Text>\n {canInvite ? (\n <Pressable\n onPress={onNewChat}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Compose new message\"\n style={styles.headerCompose}\n testID=\"chat-new\"\n >\n <MaterialCommunityIcons name=\"square-edit-outline\" size={26} color={theme.accent} />\n </Pressable>\n ) : (\n <View style={styles.headerComposeSpacer} />\n )}\n </View>\n );\n\n return (\n <View style={[styles.fill, { backgroundColor: theme.bg }]}>\n {listHeader}\n <View style={[styles.searchWrap, { backgroundColor: theme.surface }]}>\n <MaterialCommunityIcons name=\"magnify\" size={20} color={theme.textMuted} />\n <TextInput\n value={query}\n onChangeText={setQuery}\n placeholder=\"Search\"\n placeholderTextColor={theme.textMuted}\n style={[styles.searchInput, { color: theme.text }]}\n testID=\"chat-search\"\n />\n </View>\n\n <ConnectionBanner state={connectionState} theme={theme} />\n <InlineBanner message={error} theme={theme} onDismiss={onDismissError} />\n {error ? (\n <Pressable\n onPress={onRetry}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Retry loading chats\"\n style={[styles.retryBanner, { backgroundColor: theme.surface }]}\n >\n <Text style={[styles.retryBannerText, { color: theme.accent }]}>Retry loading chats</Text>\n </Pressable>\n ) : null}\n\n {loading && conversations.length === 0 ? (\n <View style={styles.center}>\n <ActivityIndicator color={theme.accent} />\n </View>\n ) : (\n <FlatList\n data={visible}\n keyExtractor={(c) => conversationListKey(c)}\n ItemSeparatorComponent={Separator}\n renderItem={({ item }) => (\n <ConversationRow conversation={item} theme={theme} now={now} onPress={() => onOpen(item.id)} />\n )}\n refreshControl={\n <RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor={theme.textMuted} />\n }\n // Paging would skip rows while a search filter is hiding most of them.\n onEndReached={query.trim() ? undefined : onLoadMore}\n onEndReachedThreshold={0.5}\n ListFooterComponent={\n loadingMore ? <ActivityIndicator style={styles.moreSpinner} color={theme.accent} /> : null\n }\n contentContainerStyle={visible.length === 0 ? styles.fill : undefined}\n ListEmptyComponent={\n <EmptyState\n icon=\"message-text-outline\"\n title={query.trim() ? 'No chats found' : 'No conversations yet'}\n detail={\n query.trim()\n ? 'Try a different name or message.'\n : canInvite\n ? 'Tap the compose button to find people from your contacts.'\n : 'Contacts are unavailable in this build, so new chats cannot be started here yet.'\n }\n theme={theme}\n action={canInvite && !query.trim() ? { label: 'New chat', onPress: onNewChat } : undefined}\n />\n }\n testID=\"chat-conversation-list\"\n />\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center' },\n moreSpinner: { paddingVertical: 16 },\n listHeader: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: 16,\n paddingTop: 4,\n paddingBottom: 4,\n },\n listTitle: { fontSize: 34, fontWeight: '700', letterSpacing: 0.35 },\n headerCompose: {\n width: 44,\n height: 44,\n alignItems: 'center',\n justifyContent: 'center',\n },\n headerComposeSpacer: { width: 44 },\n searchWrap: {\n flexDirection: 'row',\n alignItems: 'center',\n marginHorizontal: 16,\n marginBottom: 6,\n borderRadius: 10,\n paddingHorizontal: 10,\n height: 36,\n },\n searchInput: { flex: 1, marginLeft: 8, fontSize: 16, paddingVertical: 0 },\n separator: { height: StyleSheet.hairlineWidth, marginLeft: 82 },\n retryBanner: { alignItems: 'center', paddingVertical: 10 },\n retryBannerText: { fontSize: 14, fontWeight: '600' },\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ConversationListScreen.js","sources":["../../../src/features/messaging/ConversationListScreen.tsx"],"sourcesContent":["/**\n * The conversation list — iOS Messages-style home screen.\n */\nimport * as React from 'react';\nimport {\n ActivityIndicator,\n FlatList,\n Pressable,\n RefreshControl,\n StyleSheet,\n Text,\n TextInput,\n View,\n} from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { ConnectionBanner, ConversationRow, EmptyState, InlineBanner, type ChatTheme } from './ChatComponents';\nimport { conversationListKey, dedupeConversationList, type ChatConversation } from './chatModel';\nimport type { ChatConnectionState } from './chatHost';\n\nexport function ConversationListScreen({\n conversations,\n loading,\n refreshing,\n error,\n theme,\n connectionState,\n canInvite,\n onRefresh,\n onRetry,\n onOpen,\n onNewChat,\n onDismissError,\n notice = null,\n onDismissNotice,\n loadingMore = false,\n onLoadMore,\n}: {\n conversations: ChatConversation[];\n loading: boolean;\n refreshing: boolean;\n loadingMore?: boolean;\n onLoadMore?: () => void;\n error: string | null;\n theme: ChatTheme;\n connectionState: ChatConnectionState;\n canInvite: boolean;\n onRefresh: () => void;\n onRetry: () => void;\n onOpen: (id: string) => void;\n onNewChat: () => void;\n onDismissError: () => void;\n /** A one-off message that is not a load failure (e.g. an invite that could not be opened). */\n notice?: string | null;\n onDismissNotice?: () => void;\n}) {\n const [now, setNow] = React.useState(() => Date.now());\n const [query, setQuery] = React.useState('');\n React.useEffect(() => {\n const t = setInterval(() => setNow(Date.now()), 60_000);\n return () => clearInterval(t);\n }, []);\n\n const visible = React.useMemo(() => {\n const deduped = dedupeConversationList(conversations);\n const q = query.trim().toLowerCase();\n if (!q) return deduped;\n return deduped.filter((c) => c.title.toLowerCase().includes(q) || c.subtitle.toLowerCase().includes(q));\n }, [conversations, query]);\n\n const Separator = React.useCallback(\n () => <View style={[styles.separator, { backgroundColor: theme.border }]} />,\n [theme.border],\n );\n\n const listHeader = (\n <View style={[styles.listHeader, { flexDirection: 'row', alignItems: 'center' }]}>\n <Text style={[styles.listTitle, { color: theme.text }]}>Messages</Text>\n {canInvite ? (\n <Pressable\n onPress={onNewChat}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Compose new message\"\n style={styles.headerCompose}\n testID=\"chat-new\"\n >\n <MaterialCommunityIcons name=\"square-edit-outline\" size={26} color={theme.accent} />\n </Pressable>\n ) : (\n <View style={styles.headerComposeSpacer} />\n )}\n </View>\n );\n\n return (\n <View style={[styles.fill, { backgroundColor: theme.bg }]}>\n {listHeader}\n <View style={[styles.searchWrap, { backgroundColor: theme.surface }]}>\n <MaterialCommunityIcons name=\"magnify\" size={20} color={theme.textMuted} />\n <TextInput\n value={query}\n onChangeText={setQuery}\n placeholder=\"Search\"\n placeholderTextColor={theme.textMuted}\n style={[styles.searchInput, { color: theme.text }]}\n testID=\"chat-search\"\n />\n </View>\n\n <ConnectionBanner state={connectionState} theme={theme} />\n <InlineBanner message={error} theme={theme} onDismiss={onDismissError} />\n <InlineBanner message={notice} theme={theme} onDismiss={() => onDismissNotice?.()} />\n {error ? (\n <Pressable\n onPress={onRetry}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Retry loading chats\"\n style={[styles.retryBanner, { backgroundColor: theme.surface }]}\n >\n <Text style={[styles.retryBannerText, { color: theme.accent }]}>Retry loading chats</Text>\n </Pressable>\n ) : null}\n\n {loading && conversations.length === 0 ? (\n <View style={styles.center}>\n <ActivityIndicator color={theme.accent} />\n </View>\n ) : (\n <FlatList\n data={visible}\n keyExtractor={(c) => conversationListKey(c)}\n ItemSeparatorComponent={Separator}\n renderItem={({ item }) => (\n <ConversationRow conversation={item} theme={theme} now={now} onPress={() => onOpen(item.id)} />\n )}\n refreshControl={\n <RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor={theme.textMuted} />\n }\n // Paging would skip rows while a search filter is hiding most of them.\n onEndReached={query.trim() ? undefined : onLoadMore}\n onEndReachedThreshold={0.5}\n ListFooterComponent={\n loadingMore ? <ActivityIndicator style={styles.moreSpinner} color={theme.accent} /> : null\n }\n contentContainerStyle={visible.length === 0 ? styles.fill : undefined}\n ListEmptyComponent={\n <EmptyState\n icon=\"message-text-outline\"\n title={query.trim() ? 'No chats found' : 'No conversations yet'}\n detail={\n query.trim()\n ? 'Try a different name or message.'\n : canInvite\n ? 'Tap the compose button to find people from your contacts.'\n : 'Contacts are unavailable in this build, so new chats cannot be started here yet.'\n }\n theme={theme}\n action={canInvite && !query.trim() ? { label: 'New chat', onPress: onNewChat } : undefined}\n />\n }\n testID=\"chat-conversation-list\"\n />\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center' },\n moreSpinner: { paddingVertical: 16 },\n listHeader: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: 16,\n paddingTop: 4,\n paddingBottom: 4,\n },\n listTitle: { fontSize: 34, fontWeight: '700', letterSpacing: 0.35 },\n headerCompose: {\n width: 44,\n height: 44,\n alignItems: 'center',\n justifyContent: 'center',\n },\n headerComposeSpacer: { width: 44 },\n searchWrap: {\n flexDirection: 'row',\n alignItems: 'center',\n marginHorizontal: 16,\n marginBottom: 6,\n borderRadius: 10,\n paddingHorizontal: 10,\n height: 36,\n },\n searchInput: { flex: 1, marginLeft: 8, fontSize: 16, paddingVertical: 0 },\n separator: { height: StyleSheet.hairlineWidth, marginLeft: 82 },\n retryBanner: { alignItems: 'center', paddingVertical: 10 },\n retryBannerText: { fontSize: 14, 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}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}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";
2
2
  function NativeChatExperience({
3
3
  viewer,
4
4
  sessionError,
@@ -88,19 +88,32 @@ function NativeChatExperience({
88
88
  }
89
89
  }, [conversations, openThread, busyContactId]);
90
90
  const openedPeer = React.useRef(null);
91
+ const [inviteNotice, setInviteNotice] = React.useState(null);
91
92
  const {
92
93
  openDirect
93
94
  } = conversations;
94
95
  React.useEffect(() => {
95
- var _a;
96
96
  const peer = initialPeer;
97
97
  if (!(peer == null ? void 0 : peer.userId) || !(viewer == null ? void 0 : viewer.userId) || peer.userId === viewer.userId) return;
98
- if (openedPeer.current === peer.userId) return;
99
- openedPeer.current = peer.userId;
100
- void openDirect(peer.userId, ((_a = peer.name) == null ? void 0 : _a.trim()) || "Yantra Chat").then((id) => {
98
+ if (openedPeer.current === peer) return;
99
+ openedPeer.current = peer;
100
+ void (async () => {
101
+ var _a, _b;
102
+ const res = await services.gql.query(YANTRA_CHAT_INVITER_QUERY, {
103
+ userId: peer.userId
104
+ }, {
105
+ fetchPolicy: "network-only"
106
+ });
107
+ const inviter = (_a = res.data) == null ? void 0 : _a.yantraChatInviter;
108
+ if (!inviter) {
109
+ 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.");
110
+ return;
111
+ }
112
+ const id = await openDirect(inviter.userId, inviter.displayName);
101
113
  if (id) openThread(id);
102
- });
103
- }, [initialPeer, viewer == null ? void 0 : viewer.userId, openDirect, openThread]);
114
+ else setInviteNotice(`Could not start a conversation with ${inviter.displayName}. Please try again.`);
115
+ })();
116
+ }, [initialPeer, viewer == null ? void 0 : viewer.userId, services.gql, openDirect, openThread]);
104
117
  const inviteContact = React.useCallback(async (contact) => {
105
118
  var _a, _b, _c, _d, _e;
106
119
  const link = services.link;
@@ -150,7 +163,7 @@ function NativeChatExperience({
150
163
  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: () => {
151
164
  conversations.refresh();
152
165
  void contactMatches.refresh();
153
- }, onRetry: conversations.refresh, loadingMore: conversations.loadingMore, onLoadMore: conversations.loadMore, onOpen: openThread, onNewChat: () => setRoute("contacts"), onDismissError: () => setDismissedError(conversations.error) }) });
166
+ }, onRetry: conversations.refresh, loadingMore: conversations.loadingMore, onLoadMore: conversations.loadMore, onOpen: openThread, onNewChat: () => setRoute("contacts"), onDismissError: () => setDismissedError(conversations.error), notice: inviteNotice, onDismissNotice: () => setInviteNotice(null) }) });
154
167
  }
155
168
  function Shell({
156
169
  theme,
@@ -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 } 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 });\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 const openedPeer = React.useRef<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.userId) return;\n openedPeer.current = peer.userId;\n void openDirect(peer.userId, peer.name?.trim() || 'Yantra Chat').then((id) => {\n if (id) openThread(id);\n });\n }, [initialPeer, viewer?.userId, 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 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 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 />\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 } 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 });\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 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 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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"}
@@ -123,4 +123,13 @@ const YANTRA_CHAT_MEMBERS_QUERY = `
123
123
  avatarUrl
124
124
  }
125
125
  }
126
- `;export{CHANNELS_QUERY,CONTACT_MATCHES_QUERY,CREATE_DIRECT_CHANNEL_MUTATION,MESSAGES_QUERY,MESSAGE_ADDED_SUBSCRIPTION_WS,POST_FIELDS,REACTION_CHANGED_SUBSCRIPTION_WS,REGISTER_YANTRA_CHAT_MEMBER_MUTATION,SEND_MESSAGE_MUTATION,SET_MESSAGE_REACTION_MUTATION,VIEW_CHANNEL_MUTATION,YANTRA_CHAT_MEMBERS_QUERY,YANTRA_CHAT_REGISTRATION_STATUS_QUERY};//# sourceMappingURL=chatOperations.js.map
126
+ `;
127
+ const YANTRA_CHAT_INVITER_QUERY = `
128
+ query YantraChatInviter($userId: String!) {
129
+ yantraChatInviter(userId: $userId) {
130
+ userId
131
+ displayName
132
+ avatarUrl
133
+ }
134
+ }
135
+ `;export{CHANNELS_QUERY,CONTACT_MATCHES_QUERY,CREATE_DIRECT_CHANNEL_MUTATION,MESSAGES_QUERY,MESSAGE_ADDED_SUBSCRIPTION_WS,POST_FIELDS,REACTION_CHANGED_SUBSCRIPTION_WS,REGISTER_YANTRA_CHAT_MEMBER_MUTATION,SEND_MESSAGE_MUTATION,SET_MESSAGE_REACTION_MUTATION,VIEW_CHANNEL_MUTATION,YANTRA_CHAT_INVITER_QUERY,YANTRA_CHAT_MEMBERS_QUERY,YANTRA_CHAT_REGISTRATION_STATUS_QUERY};//# sourceMappingURL=chatOperations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chatOperations.js","sources":["../../../src/features/messaging/chatOperations.ts"],"sourcesContent":["/**\n * Every GraphQL operation the chat remote sends, as plain strings.\n *\n * Strings, not `gql` documents, because the remote must not import\n * @apollo/client or graphql - the host parses and executes these on the app's\n * own client (see `ChatGraphQLSeam`). The upside beyond bundle size is that the\n * QUERY SHAPE ships over the air: a missing field or a wrong argument is a\n * surface deploy, not an App Store release.\n *\n * HARD REQUIREMENT - every operation is NAMED, and every subscription's name\n * ends in `_WS`. `portable-devices/mobile/src/config/base-apollo-client.ts`\n * routes ws-vs-http with `operationName.endsWith('_WS')`; an anonymous\n * operation makes that `undefined.endsWith(...)`, which throws for EVERY\n * operation the app sends, not just this one. `chatOperations.test.ts` asserts\n * both properties over every export in this file, so a new operation cannot\n * quietly break the app's transport.\n */\n\n/**\n * Shared field set for a message.\n *\n * `author` and `creator` are both selected on purpose: messenger-box populates\n * `author` on some write paths and `creator` on others (`sendMessage` sets\n * creator), and a transcript that reads only one shows \"Unknown\" for half the\n * messages. `chatModel.pickAuthor` collapses them.\n */\nexport const POST_FIELDS = `\n id\n message\n type\n createdAt\n updatedAt\n editedAt\n deletedAt\n rootId\n parentId\n filenames\n props\n author { id givenName familyName username email picture }\n creator { id givenName familyName username email picture }\n reactionSummary { reaction count userIds }\n`;\n\nconst CHANNEL_FIELDS = `\n id\n type\n orgName\n title\n displayName\n topic\n lastPostAt\n totalMsgCount\n createdAt\n lastMessage { ${POST_FIELDS} }\n creator { id givenName familyName username email picture }\n members { id user { id givenName familyName username email picture } msgCount lastViewedAt }\n`;\n\n/**\n * The conversation list.\n *\n * `criteria.members.$elemMatch.user` is NOT sent: the server derives membership\n * from the session (`accountId`) and a client-supplied member filter is exactly\n * the kind of thing that lets a caller read someone else's list. Org scoping is\n * likewise server-side now (`channelOrgScope`). Native Messages passes\n * `criteria: { type: DIRECT, orgName: yantra-chat }` via `nativeChatChannelQuery`.\n */\nexport const CHANNELS_QUERY = `\n query ChatChannels($limit: Int, $skip: Int, $criteria: AnyObject, $sort: Sort) {\n channelsByUser(limit: $limit, skip: $skip, criteria: $criteria, sort: $sort) {\n ${CHANNEL_FIELDS}\n }\n }\n`;\n\n/**\n * One page of a transcript, newest first.\n *\n * Paged with `skip`, which is what the server exposes. That is offset paging and\n * it can repeat or drop a row if messages arrive mid-scroll; `chatModel.mergePosts`\n * de-duplicates by id so the visible effect is bounded. A cursor (`before: id`)\n * would be strictly better and is worth adding server-side later.\n */\nexport const MESSAGES_QUERY = `\n query ChatMessages($channelId: ID, $limit: Int! = 30, $skip: Int! = 0, $sort: Sort) {\n messages(channelId: $channelId, limit: $limit, skip: $skip, sort: $sort) {\n totalCount\n data {\n ${POST_FIELDS}\n }\n }\n }\n`;\n\nexport const SEND_MESSAGE_MUTATION = `\n mutation ChatSendMessage($channelId: String!, $messageInput: MessageInput!) {\n sendMessage(channelId: $channelId, messageInput: $messageInput) {\n ${POST_FIELDS}\n }\n }\n`;\n\n/** Marks the channel read for the caller; drives the unread badge to zero. */\nexport const VIEW_CHANNEL_MUTATION = `\n mutation ChatViewChannel($id: ID!) {\n viewChannel(id: $id)\n }\n`;\n\n/**\n * Opens (or returns) the 1:1 conversation with `receiver`.\n *\n * Idempotent server-side: an existing DM for the pair comes back rather than a\n * duplicate, so the UI can call this every time someone taps a contact without\n * checking first.\n */\nexport const CREATE_DIRECT_CHANNEL_MUTATION = `\n mutation ChatCreateDirectChannel($receiver: [ID]!, $displayName: String!) {\n createDirectChannel(receiver: $receiver, displayName: $displayName) {\n ${CHANNEL_FIELDS}\n }\n }\n`;\n\n/**\n * Live messages for one channel.\n *\n * `_WS` suffix is load-bearing - see the file header. `directTo` is left unset:\n * the server treats it as a second, user-scoped topic and passing the wrong one\n * silently delivers nothing.\n */\nexport const MESSAGE_ADDED_SUBSCRIPTION_WS = `\n subscription ChatMessageAdded_WS($channelId: String) {\n chatMessageAdded(channelId: $channelId) {\n ${POST_FIELDS}\n }\n }\n`;\n\n/**\n * Set the viewer's single Tapback on a message; `reaction: null` removes it.\n * Returns the message's reactions after the change.\n */\nexport const SET_MESSAGE_REACTION_MUTATION = `\n mutation ChatSetMessageReaction($channelId: String!, $postId: ID!, $reaction: String) {\n setMessageReaction(channelId: $channelId, postId: $postId, reaction: $reaction) {\n reaction\n count\n userIds\n }\n }\n`;\n\n/** Live reaction changes for one channel. `_WS` suffix is load-bearing - see the file header. */\nexport const REACTION_CHANGED_SUBSCRIPTION_WS = `\n subscription ChatReactionChanged_WS($channelId: String!) {\n chatReactionChanged(channelId: $channelId) {\n channelId\n postId\n reactions { reaction count userIds }\n }\n }\n`;\n\n/**\n * Which of these phone numbers already have an account.\n *\n * Sends SHA-256 hashes of E.164 numbers, never the numbers - the server never\n * receives a plaintext address book. Returns AnyObject: a list of\n * `{phoneHash, userId, username, displayName, picture}`.\n */\nexport const CONTACT_MATCHES_QUERY = `\n query ChatContactMatches($phoneHashes: [String!]!) {\n chatContactMatches(phoneHashes: $phoneHashes)\n }\n`;\n\nexport const YANTRA_CHAT_REGISTRATION_STATUS_QUERY = `\n query YantraChatRegistrationStatus {\n yantraChatRegistrationStatus {\n registered\n phoneE164\n memberId\n organizationId\n }\n }\n`;\n\nexport const REGISTER_YANTRA_CHAT_MEMBER_MUTATION = `\n mutation RegisterYantraChatMember($phoneE164: String!, $displayName: String) {\n registerYantraChatMember(phoneE164: $phoneE164, displayName: $displayName) {\n registered\n phoneE164\n memberId\n organizationId\n }\n }\n`;\n\nexport const MATCH_YANTRA_CHAT_MEMBERS_QUERY = `\n query MatchYantraChatMembersByPhone($phones: [String!]!, $viewerPhoneE164: String) {\n matchYantraChatMembersByPhone(phones: $phones, viewerPhoneE164: $viewerPhoneE164) {\n phoneE164\n userId\n displayName\n avatarUrl\n }\n }\n`;\n\nexport const YANTRA_CHAT_MEMBERS_QUERY = `\n query YantraChatMembers {\n yantraChatMembers {\n phoneE164\n userId\n displayName\n avatarUrl\n }\n }\n`;\n\n/** Composer draft persistence, server-side and per (member, channel). */\nexport const SET_DRAFT_MUTATION = `\n mutation ChatSetDraft($channelId: ID!, $text: String!) {\n setChannelDraft(channelId: $channelId, text: $text)\n }\n`;\n\nexport const DRAFT_QUERY = `\n query ChatDraft($channelId: ID!) {\n channelDraft(channelId: $channelId)\n }\n`;\n\n/** Every operation, for the contract test and for host-side preflight. */\nexport const CHAT_OPERATIONS: Readonly<Record<string, string>> = Object.freeze({\n CHANNELS_QUERY,\n CONTACT_MATCHES_QUERY,\n YANTRA_CHAT_REGISTRATION_STATUS_QUERY,\n REGISTER_YANTRA_CHAT_MEMBER_MUTATION,\n MATCH_YANTRA_CHAT_MEMBERS_QUERY,\n YANTRA_CHAT_MEMBERS_QUERY,\n MESSAGES_QUERY,\n SEND_MESSAGE_MUTATION,\n VIEW_CHANNEL_MUTATION,\n CREATE_DIRECT_CHANNEL_MUTATION,\n MESSAGE_ADDED_SUBSCRIPTION_WS,\n SET_MESSAGE_REACTION_MUTATION,\n REACTION_CHANGED_SUBSCRIPTION_WS,\n SET_DRAFT_MUTATION,\n DRAFT_QUERY,\n});\n\n/**\n * The operation name inside a document string.\n *\n * Used by the contract test and by the host seam for logging. Intentionally a\n * regex rather than a parse: pulling in `graphql` to read a name would defeat\n * the whole point of shipping strings.\n */\nexport function operationNameOf(document: string): string | null {\n const match = /\\b(?:query|mutation|subscription)\\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(document);\n return match ? match[1] : null;\n}\n\nexport function operationTypeOf(document: string): 'query' | 'mutation' | 'subscription' | null {\n const match = /\\b(query|mutation|subscription)\\s+[A-Za-z_]/.exec(document);\n return match ? (match[1] as 'query' | 'mutation' | 'subscription') : null;\n}\n"],"names":[],"mappings":"AA0BO,MAAM,WAAc,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgB3B,MAAM,cAAiB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAA,EAUH,WAAW,CAAA;AAAA;AAAA;AAAA,CAAA;AAcxB,MAAM,cAAiB,GAAA;AAAA;AAAA;AAAA,YAAA,EAGhB,cAAc;AAAA;AAAA;AAAA;AAarB,MAAM,cAAiB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAA,EAKZ,WAAW;AAAA;AAAA;AAAA;AAAA;AAKtB,MAAM,qBAAwB,GAAA;AAAA;AAAA;AAAA,YAAA,EAGvB,WAAW;AAAA;AAAA;AAAA;AAMlB,MAAM,qBAAwB,GAAA;AAAA;AAAA;AAAA;AAAA;AAa9B,MAAM,8BAAiC,GAAA;AAAA;AAAA;AAAA,YAAA,EAGhC,cAAc;AAAA;AAAA;AAAA;AAYrB,MAAM,6BAAgC,GAAA;AAAA;AAAA;AAAA,YAAA,EAG/B,WAAW;AAAA;AAAA;AAAA;AASlB,MAAM,6BAAgC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWtC,MAAM,gCAAmC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBzC,MAAM,qBAAwB,GAAA;AAAA;AAAA;AAAA;AAAA;AAK9B,MAAM,qCAAwC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAU9C,MAAM,oCAAuC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoB7C,MAAM,yBAA4B,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA"}
1
+ {"version":3,"file":"chatOperations.js","sources":["../../../src/features/messaging/chatOperations.ts"],"sourcesContent":["/**\n * Every GraphQL operation the chat remote sends, as plain strings.\n *\n * Strings, not `gql` documents, because the remote must not import\n * @apollo/client or graphql - the host parses and executes these on the app's\n * own client (see `ChatGraphQLSeam`). The upside beyond bundle size is that the\n * QUERY SHAPE ships over the air: a missing field or a wrong argument is a\n * surface deploy, not an App Store release.\n *\n * HARD REQUIREMENT - every operation is NAMED, and every subscription's name\n * ends in `_WS`. `portable-devices/mobile/src/config/base-apollo-client.ts`\n * routes ws-vs-http with `operationName.endsWith('_WS')`; an anonymous\n * operation makes that `undefined.endsWith(...)`, which throws for EVERY\n * operation the app sends, not just this one. `chatOperations.test.ts` asserts\n * both properties over every export in this file, so a new operation cannot\n * quietly break the app's transport.\n */\n\n/**\n * Shared field set for a message.\n *\n * `author` and `creator` are both selected on purpose: messenger-box populates\n * `author` on some write paths and `creator` on others (`sendMessage` sets\n * creator), and a transcript that reads only one shows \"Unknown\" for half the\n * messages. `chatModel.pickAuthor` collapses them.\n */\nexport const POST_FIELDS = `\n id\n message\n type\n createdAt\n updatedAt\n editedAt\n deletedAt\n rootId\n parentId\n filenames\n props\n author { id givenName familyName username email picture }\n creator { id givenName familyName username email picture }\n reactionSummary { reaction count userIds }\n`;\n\nconst CHANNEL_FIELDS = `\n id\n type\n orgName\n title\n displayName\n topic\n lastPostAt\n totalMsgCount\n createdAt\n lastMessage { ${POST_FIELDS} }\n creator { id givenName familyName username email picture }\n members { id user { id givenName familyName username email picture } msgCount lastViewedAt }\n`;\n\n/**\n * The conversation list.\n *\n * `criteria.members.$elemMatch.user` is NOT sent: the server derives membership\n * from the session (`accountId`) and a client-supplied member filter is exactly\n * the kind of thing that lets a caller read someone else's list. Org scoping is\n * likewise server-side now (`channelOrgScope`). Native Messages passes\n * `criteria: { type: DIRECT, orgName: yantra-chat }` via `nativeChatChannelQuery`.\n */\nexport const CHANNELS_QUERY = `\n query ChatChannels($limit: Int, $skip: Int, $criteria: AnyObject, $sort: Sort) {\n channelsByUser(limit: $limit, skip: $skip, criteria: $criteria, sort: $sort) {\n ${CHANNEL_FIELDS}\n }\n }\n`;\n\n/**\n * One page of a transcript, newest first.\n *\n * Paged with `skip`, which is what the server exposes. That is offset paging and\n * it can repeat or drop a row if messages arrive mid-scroll; `chatModel.mergePosts`\n * de-duplicates by id so the visible effect is bounded. A cursor (`before: id`)\n * would be strictly better and is worth adding server-side later.\n */\nexport const MESSAGES_QUERY = `\n query ChatMessages($channelId: ID, $limit: Int! = 30, $skip: Int! = 0, $sort: Sort) {\n messages(channelId: $channelId, limit: $limit, skip: $skip, sort: $sort) {\n totalCount\n data {\n ${POST_FIELDS}\n }\n }\n }\n`;\n\nexport const SEND_MESSAGE_MUTATION = `\n mutation ChatSendMessage($channelId: String!, $messageInput: MessageInput!) {\n sendMessage(channelId: $channelId, messageInput: $messageInput) {\n ${POST_FIELDS}\n }\n }\n`;\n\n/** Marks the channel read for the caller; drives the unread badge to zero. */\nexport const VIEW_CHANNEL_MUTATION = `\n mutation ChatViewChannel($id: ID!) {\n viewChannel(id: $id)\n }\n`;\n\n/**\n * Opens (or returns) the 1:1 conversation with `receiver`.\n *\n * Idempotent server-side: an existing DM for the pair comes back rather than a\n * duplicate, so the UI can call this every time someone taps a contact without\n * checking first.\n */\nexport const CREATE_DIRECT_CHANNEL_MUTATION = `\n mutation ChatCreateDirectChannel($receiver: [ID]!, $displayName: String!) {\n createDirectChannel(receiver: $receiver, displayName: $displayName) {\n ${CHANNEL_FIELDS}\n }\n }\n`;\n\n/**\n * Live messages for one channel.\n *\n * `_WS` suffix is load-bearing - see the file header. `directTo` is left unset:\n * the server treats it as a second, user-scoped topic and passing the wrong one\n * silently delivers nothing.\n */\nexport const MESSAGE_ADDED_SUBSCRIPTION_WS = `\n subscription ChatMessageAdded_WS($channelId: String) {\n chatMessageAdded(channelId: $channelId) {\n ${POST_FIELDS}\n }\n }\n`;\n\n/**\n * Set the viewer's single Tapback on a message; `reaction: null` removes it.\n * Returns the message's reactions after the change.\n */\nexport const SET_MESSAGE_REACTION_MUTATION = `\n mutation ChatSetMessageReaction($channelId: String!, $postId: ID!, $reaction: String) {\n setMessageReaction(channelId: $channelId, postId: $postId, reaction: $reaction) {\n reaction\n count\n userIds\n }\n }\n`;\n\n/** Live reaction changes for one channel. `_WS` suffix is load-bearing - see the file header. */\nexport const REACTION_CHANGED_SUBSCRIPTION_WS = `\n subscription ChatReactionChanged_WS($channelId: String!) {\n chatReactionChanged(channelId: $channelId) {\n channelId\n postId\n reactions { reaction count userIds }\n }\n }\n`;\n\n/**\n * Which of these phone numbers already have an account.\n *\n * Sends SHA-256 hashes of E.164 numbers, never the numbers - the server never\n * receives a plaintext address book. Returns AnyObject: a list of\n * `{phoneHash, userId, username, displayName, picture}`.\n */\nexport const CONTACT_MATCHES_QUERY = `\n query ChatContactMatches($phoneHashes: [String!]!) {\n chatContactMatches(phoneHashes: $phoneHashes)\n }\n`;\n\nexport const YANTRA_CHAT_REGISTRATION_STATUS_QUERY = `\n query YantraChatRegistrationStatus {\n yantraChatRegistrationStatus {\n registered\n phoneE164\n memberId\n organizationId\n }\n }\n`;\n\nexport const REGISTER_YANTRA_CHAT_MEMBER_MUTATION = `\n mutation RegisterYantraChatMember($phoneE164: String!, $displayName: String) {\n registerYantraChatMember(phoneE164: $phoneE164, displayName: $displayName) {\n registered\n phoneE164\n memberId\n organizationId\n }\n }\n`;\n\nexport const MATCH_YANTRA_CHAT_MEMBERS_QUERY = `\n query MatchYantraChatMembersByPhone($phones: [String!]!, $viewerPhoneE164: String) {\n matchYantraChatMembersByPhone(phones: $phones, viewerPhoneE164: $viewerPhoneE164) {\n phoneE164\n userId\n displayName\n avatarUrl\n }\n }\n`;\n\nexport const YANTRA_CHAT_MEMBERS_QUERY = `\n query YantraChatMembers {\n yantraChatMembers {\n phoneE164\n userId\n displayName\n avatarUrl\n }\n }\n`;\n\n/**\n * The sender of a chat invite link, as the server knows them. The link's own `n=` name\n * is editable by anyone, so the conversation is opened with this name, and only when\n * the id belongs to a registered member (null otherwise).\n */\nexport const YANTRA_CHAT_INVITER_QUERY = `\n query YantraChatInviter($userId: String!) {\n yantraChatInviter(userId: $userId) {\n userId\n displayName\n avatarUrl\n }\n }\n`;\n\n/** Composer draft persistence, server-side and per (member, channel). */\nexport const SET_DRAFT_MUTATION = `\n mutation ChatSetDraft($channelId: ID!, $text: String!) {\n setChannelDraft(channelId: $channelId, text: $text)\n }\n`;\n\nexport const DRAFT_QUERY = `\n query ChatDraft($channelId: ID!) {\n channelDraft(channelId: $channelId)\n }\n`;\n\n/** Every operation, for the contract test and for host-side preflight. */\nexport const CHAT_OPERATIONS: Readonly<Record<string, string>> = Object.freeze({\n CHANNELS_QUERY,\n CONTACT_MATCHES_QUERY,\n YANTRA_CHAT_REGISTRATION_STATUS_QUERY,\n REGISTER_YANTRA_CHAT_MEMBER_MUTATION,\n MATCH_YANTRA_CHAT_MEMBERS_QUERY,\n YANTRA_CHAT_MEMBERS_QUERY,\n YANTRA_CHAT_INVITER_QUERY,\n MESSAGES_QUERY,\n SEND_MESSAGE_MUTATION,\n VIEW_CHANNEL_MUTATION,\n CREATE_DIRECT_CHANNEL_MUTATION,\n MESSAGE_ADDED_SUBSCRIPTION_WS,\n SET_MESSAGE_REACTION_MUTATION,\n REACTION_CHANGED_SUBSCRIPTION_WS,\n SET_DRAFT_MUTATION,\n DRAFT_QUERY,\n});\n\n/**\n * The operation name inside a document string.\n *\n * Used by the contract test and by the host seam for logging. Intentionally a\n * regex rather than a parse: pulling in `graphql` to read a name would defeat\n * the whole point of shipping strings.\n */\nexport function operationNameOf(document: string): string | null {\n const match = /\\b(?:query|mutation|subscription)\\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(document);\n return match ? match[1] : null;\n}\n\nexport function operationTypeOf(document: string): 'query' | 'mutation' | 'subscription' | null {\n const match = /\\b(query|mutation|subscription)\\s+[A-Za-z_]/.exec(document);\n return match ? (match[1] as 'query' | 'mutation' | 'subscription') : null;\n}\n"],"names":[],"mappings":"AA0BO,MAAM,WAAc,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgB3B,MAAM,cAAiB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAA,EAUH,WAAW,CAAA;AAAA;AAAA;AAAA,CAAA;AAcxB,MAAM,cAAiB,GAAA;AAAA;AAAA;AAAA,YAAA,EAGhB,cAAc;AAAA;AAAA;AAAA;AAarB,MAAM,cAAiB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAA,EAKZ,WAAW;AAAA;AAAA;AAAA;AAAA;AAKtB,MAAM,qBAAwB,GAAA;AAAA;AAAA;AAAA,YAAA,EAGvB,WAAW;AAAA;AAAA;AAAA;AAMlB,MAAM,qBAAwB,GAAA;AAAA;AAAA;AAAA;AAAA;AAa9B,MAAM,8BAAiC,GAAA;AAAA;AAAA;AAAA,YAAA,EAGhC,cAAc;AAAA;AAAA;AAAA;AAYrB,MAAM,6BAAgC,GAAA;AAAA;AAAA;AAAA,YAAA,EAG/B,WAAW;AAAA;AAAA;AAAA;AASlB,MAAM,6BAAgC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWtC,MAAM,gCAAmC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBzC,MAAM,qBAAwB,GAAA;AAAA;AAAA;AAAA;AAAA;AAK9B,MAAM,qCAAwC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAU9C,MAAM,oCAAuC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoB7C,MAAM,yBAA4B,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBlC,MAAM,yBAA4B,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA"}
@@ -46,10 +46,15 @@ function ChatNativeScreen() {
46
46
  const channelId = typeof (params == null ? void 0 : params.channelId) === "string" ? params.channelId : void 0;
47
47
  const inviterId = typeof (params == null ? void 0 : params.inviterId) === "string" ? params.inviterId : void 0;
48
48
  const inviterName = typeof (params == null ? void 0 : params.inviterName) === "string" ? params.inviterName : null;
49
- const initialPeer = React__default.useMemo(() => inviterId ? {
50
- userId: inviterId,
51
- name: inviterName
52
- } : void 0, [inviterId, inviterName]);
49
+ const inviteAt = typeof (params == null ? void 0 : params.inviteAt) === "number" ? params.inviteAt : 0;
50
+ const initialPeer = React__default.useMemo(
51
+ () => inviterId ? {
52
+ userId: inviterId,
53
+ name: inviterName
54
+ } : void 0,
55
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- inviteAt: a new object per link open
56
+ [inviterId, inviterName, inviteAt]
57
+ );
53
58
  const handleRegistrationComplete = useCallback(async (phoneNumber) => {
54
59
  try {
55
60
  await registerForChat(phoneNumber);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/screens/ChatNative/index.tsx"],"sourcesContent":["/**\n * Native Chats screen - the host route for the federated CHAT surface.\n *\n * Same delivery contract as CanvasBoard and Characters: the App (the MF host)\n * registers the federated component and injects the seams it owns; this screen\n * only reads the registry and contributes the two things the remote cannot\n * know - who is signed in, and where navigation should go.\n *\n * Opening it triggers the runtime fetch of `chat_native/Chat` from the\n * chat-native surface; in a release build none of that code ships in the\n * binary.\n *\n * If the user is not yet registered with Yantra Chat (phone-based membership),\n * they are prompted to register before accessing the chat surface.\n */\nimport React, { useCallback, useEffect } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { useNavigation, useRoute } from '@react-navigation/native';\nimport { getNativeChatExperience } from '../../features/messaging/nativeChatRegistry';\nimport { useChatViewer } from '../../features/messaging/useChatViewer';\nimport { RegistrationScreen } from '../../features/messaging/RegistrationScreen';\nimport { mobileColors } from '../../theme/mobileTokens';\nimport { useAppTheme } from '../../theme/AppThemeProvider';\n\nexport interface ChatNativeRouteParams {\n /** Deep link from a push tap or an Apps tile: open straight into a thread. */\n channelId?: string;\n /** From a chat invite link (`/chat/invite?by=&n=`): open the conversation with the inviter. */\n inviterId?: string;\n inviterName?: string;\n orgName?: string;\n}\n\n/** Only `setParams` is used; the header flag is read by the host stack, not by this screen. */\ntype ChatNativeNavigation = {\n setParams(params: Partial<ChatNativeRouteParams> & { hideNavigationHeader?: boolean }): void;\n goBack(): void;\n};\n\nfunction buildRegistrationTheme(isDark: boolean) {\n const c = mobileColors(isDark);\n return {\n colors: {\n background: c.bg,\n card: c.surface,\n text: c.text,\n textSecondary: c.textMuted,\n placeholder: isDark ? '#64748b' : '#94a3b8',\n primary: c.primary,\n error: c.dangerText,\n border: c.border,\n },\n fonts: {\n regular: { fontFamily: 'system' },\n medium: { fontFamily: 'system', fontWeight: '500' as const },\n bold: { fontFamily: 'system', fontWeight: '700' as const },\n },\n };\n}\n\nexport default function ChatNativeScreen() {\n const route = useRoute();\n const navigation = useNavigation<ChatNativeNavigation>();\n const { isDark } = useAppTheme();\n const theme = buildRegistrationTheme(isDark);\n\n const Chat = getNativeChatExperience();\n const { viewer, error, ready, needsRegistration, registerForChat, membershipLoading } = useChatViewer();\n\n const params = route.params as ChatNativeRouteParams | undefined;\n const channelId = typeof params?.channelId === 'string' ? params.channelId : undefined;\n const inviterId = typeof params?.inviterId === 'string' ? params.inviterId : undefined;\n const inviterName = typeof params?.inviterName === 'string' ? params.inviterName : null;\n const initialPeer = React.useMemo(\n () => (inviterId ? { userId: inviterId, name: inviterName } : undefined),\n [inviterId, inviterName],\n );\n\n const handleRegistrationComplete = useCallback(\n async (phoneNumber: string) => {\n try {\n await registerForChat(phoneNumber);\n } catch (err) {\n console.error('[ChatNative] Yantra Chat registration failed', err);\n throw err;\n }\n },\n [registerForChat],\n );\n\n const handleInternalRouteChange = useCallback(\n (internal: 'list' | 'thread' | 'contacts' | 'register') => {\n navigation.setParams({ hideNavigationHeader: internal !== 'list' });\n },\n [navigation],\n );\n\n // Hide stack header on registration, thread, and contacts — each screen owns its top bar.\n useEffect(() => {\n const hide = needsRegistration || membershipLoading;\n navigation.setParams({ hideNavigationHeader: hide });\n }, [needsRegistration, membershipLoading, navigation]);\n\n if (!Chat) {\n // A build without the federation host (or before App registered it).\n // Say so instead of rendering a blank screen.\n return (\n <SafeAreaView style={[styles.fill, isDark && styles.fillDark]}>\n <View style={styles.center}>\n <Text style={[styles.title, isDark && styles.textLight]}>Chat unavailable</Text>\n <Text style={[styles.detail, isDark && styles.textMuted]}>\n This build does not carry the federation host runtime.\n </Text>\n </View>\n </SafeAreaView>\n );\n }\n\n // Show registration screen if user is not registered yet\n if (needsRegistration || membershipLoading) {\n if (membershipLoading && !needsRegistration) {\n return (\n <View\n style={[\n styles.fill,\n { backgroundColor: theme.colors.background, justifyContent: 'center', alignItems: 'center' },\n ]}\n >\n <Text style={{ color: theme.colors.textSecondary }}>Loading…</Text>\n </View>\n );\n }\n return (\n <View style={[styles.fill, { backgroundColor: theme.colors.background }]}>\n <RegistrationScreen\n onRegistrationComplete={handleRegistrationComplete}\n theme={theme}\n testID=\"chat-registration-screen\"\n />\n </View>\n );\n }\n\n return (\n <SafeAreaView\n style={[styles.fill, isDark && styles.fillDark, { backgroundColor: theme.colors.background }]}\n edges={['left', 'right', 'bottom']}\n >\n <Chat\n viewer={viewer}\n sessionError={ready ? error : null}\n initialChannelId={channelId}\n initialPeer={initialPeer}\n onClose={() => navigation.goBack()}\n onInternalRouteChange={handleInternalRouteChange}\n />\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1, backgroundColor: '#f8fafc' },\n fillDark: { backgroundColor: '#0f172a' },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 24 },\n title: { fontSize: 17, fontWeight: '600', color: '#0f172a', marginBottom: 6 },\n detail: { fontSize: 13, color: '#64748b', textAlign: 'center' },\n textLight: { color: '#f1f5f9' },\n textMuted: { color: '#94a3b8' },\n});\n"],"names":["React"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/screens/ChatNative/index.tsx"],"sourcesContent":["/**\n * Native Chats screen - the host route for the federated CHAT surface.\n *\n * Same delivery contract as CanvasBoard and Characters: the App (the MF host)\n * registers the federated component and injects the seams it owns; this screen\n * only reads the registry and contributes the two things the remote cannot\n * know - who is signed in, and where navigation should go.\n *\n * Opening it triggers the runtime fetch of `chat_native/Chat` from the\n * chat-native surface; in a release build none of that code ships in the\n * binary.\n *\n * If the user is not yet registered with Yantra Chat (phone-based membership),\n * they are prompted to register before accessing the chat surface.\n */\nimport React, { useCallback, useEffect } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { useNavigation, useRoute } from '@react-navigation/native';\nimport { getNativeChatExperience } from '../../features/messaging/nativeChatRegistry';\nimport { useChatViewer } from '../../features/messaging/useChatViewer';\nimport { RegistrationScreen } from '../../features/messaging/RegistrationScreen';\nimport { mobileColors } from '../../theme/mobileTokens';\nimport { useAppTheme } from '../../theme/AppThemeProvider';\n\nexport interface ChatNativeRouteParams {\n /** Deep link from a push tap or an Apps tile: open straight into a thread. */\n channelId?: string;\n /** From a chat invite link (`/chat/invite?by=&n=`): open the conversation with the inviter. */\n inviterId?: string;\n inviterName?: string;\n /** When the invite link was opened; makes reopening the same link a fresh attempt. */\n inviteAt?: number;\n orgName?: string;\n}\n\n/** Only `setParams` is used; the header flag is read by the host stack, not by this screen. */\ntype ChatNativeNavigation = {\n setParams(params: Partial<ChatNativeRouteParams> & { hideNavigationHeader?: boolean }): void;\n goBack(): void;\n};\n\nfunction buildRegistrationTheme(isDark: boolean) {\n const c = mobileColors(isDark);\n return {\n colors: {\n background: c.bg,\n card: c.surface,\n text: c.text,\n textSecondary: c.textMuted,\n placeholder: isDark ? '#64748b' : '#94a3b8',\n primary: c.primary,\n error: c.dangerText,\n border: c.border,\n },\n fonts: {\n regular: { fontFamily: 'system' },\n medium: { fontFamily: 'system', fontWeight: '500' as const },\n bold: { fontFamily: 'system', fontWeight: '700' as const },\n },\n };\n}\n\nexport default function ChatNativeScreen() {\n const route = useRoute();\n const navigation = useNavigation<ChatNativeNavigation>();\n const { isDark } = useAppTheme();\n const theme = buildRegistrationTheme(isDark);\n\n const Chat = getNativeChatExperience();\n const { viewer, error, ready, needsRegistration, registerForChat, membershipLoading } = useChatViewer();\n\n const params = route.params as ChatNativeRouteParams | undefined;\n const channelId = typeof params?.channelId === 'string' ? params.channelId : undefined;\n const inviterId = typeof params?.inviterId === 'string' ? params.inviterId : undefined;\n const inviterName = typeof params?.inviterName === 'string' ? params.inviterName : null;\n const inviteAt = typeof params?.inviteAt === 'number' ? params.inviteAt : 0;\n const initialPeer = React.useMemo(\n () => (inviterId ? { userId: inviterId, name: inviterName } : undefined),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- inviteAt: a new object per link open\n [inviterId, inviterName, inviteAt],\n );\n\n const handleRegistrationComplete = useCallback(\n async (phoneNumber: string) => {\n try {\n await registerForChat(phoneNumber);\n } catch (err) {\n console.error('[ChatNative] Yantra Chat registration failed', err);\n throw err;\n }\n },\n [registerForChat],\n );\n\n const handleInternalRouteChange = useCallback(\n (internal: 'list' | 'thread' | 'contacts' | 'register') => {\n navigation.setParams({ hideNavigationHeader: internal !== 'list' });\n },\n [navigation],\n );\n\n // Hide stack header on registration, thread, and contacts — each screen owns its top bar.\n useEffect(() => {\n const hide = needsRegistration || membershipLoading;\n navigation.setParams({ hideNavigationHeader: hide });\n }, [needsRegistration, membershipLoading, navigation]);\n\n if (!Chat) {\n // A build without the federation host (or before App registered it).\n // Say so instead of rendering a blank screen.\n return (\n <SafeAreaView style={[styles.fill, isDark && styles.fillDark]}>\n <View style={styles.center}>\n <Text style={[styles.title, isDark && styles.textLight]}>Chat unavailable</Text>\n <Text style={[styles.detail, isDark && styles.textMuted]}>\n This build does not carry the federation host runtime.\n </Text>\n </View>\n </SafeAreaView>\n );\n }\n\n // Show registration screen if user is not registered yet\n if (needsRegistration || membershipLoading) {\n if (membershipLoading && !needsRegistration) {\n return (\n <View\n style={[\n styles.fill,\n { backgroundColor: theme.colors.background, justifyContent: 'center', alignItems: 'center' },\n ]}\n >\n <Text style={{ color: theme.colors.textSecondary }}>Loading…</Text>\n </View>\n );\n }\n return (\n <View style={[styles.fill, { backgroundColor: theme.colors.background }]}>\n <RegistrationScreen\n onRegistrationComplete={handleRegistrationComplete}\n theme={theme}\n testID=\"chat-registration-screen\"\n />\n </View>\n );\n }\n\n return (\n <SafeAreaView\n style={[styles.fill, isDark && styles.fillDark, { backgroundColor: theme.colors.background }]}\n edges={['left', 'right', 'bottom']}\n >\n <Chat\n viewer={viewer}\n sessionError={ready ? error : null}\n initialChannelId={channelId}\n initialPeer={initialPeer}\n onClose={() => navigation.goBack()}\n onInternalRouteChange={handleInternalRouteChange}\n />\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n fill: { flex: 1, backgroundColor: '#f8fafc' },\n fillDark: { backgroundColor: '#0f172a' },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 24 },\n title: { fontSize: 17, fontWeight: '600', color: '#0f172a', marginBottom: 6 },\n detail: { fontSize: 13, color: '#64748b', textAlign: 'center' },\n textLight: { color: '#f1f5f9' },\n textMuted: { color: '#94a3b8' },\n});\n"],"names":["React"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminide-stack/yantra-mobile",
3
- "version": "12.0.69-alpha.15",
3
+ "version": "12.0.69-alpha.17",
4
4
  "description": "Sample core for higher packages to depend on",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -25,7 +25,7 @@
25
25
  "uuid": "^9.0.0"
26
26
  },
27
27
  "devDependencies": {
28
- "common": "12.0.69-alpha.12"
28
+ "common": "12.0.69-alpha.17"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@admin-layout/gluestack-ui-mobile": "*",
@@ -41,7 +41,7 @@
41
41
  "@messenger-box/platform-mobile": "*",
42
42
  "@react-native-async-storage/async-storage": "*",
43
43
  "@react-navigation/native": "*",
44
- "common": "12.0.69-alpha.12",
44
+ "common": "12.0.69-alpha.16",
45
45
  "expo-constants": "*",
46
46
  "expo-secure-store": "*",
47
47
  "expo-web-browser": "*",
@@ -58,5 +58,5 @@
58
58
  "typescript": {
59
59
  "definition": "lib/index.d.ts"
60
60
  },
61
- "gitHead": "90eef68fd5da16fd662a700f078d254e5bcf4073"
61
+ "gitHead": "afa5bdb1795ccd0c2f222f0d3beb2acf2c5ec206"
62
62
  }