@adminide-stack/yantra-mobile 12.0.68 → 12.0.69-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/compute.js +8 -3
- package/lib/compute.js.map +1 -1
- package/lib/features/messaging/RegistrationScreen.js +358 -0
- package/lib/features/messaging/RegistrationScreen.js.map +1 -0
- package/lib/features/messaging/chatOperations.js +20 -0
- package/lib/features/messaging/chatOperations.js.map +1 -0
- package/lib/features/messaging/chatRegistrationStorage.js +1 -0
- package/lib/features/messaging/chatRegistrationStorage.js.map +1 -0
- package/lib/features/messaging/phoneNumbers.js +102 -0
- package/lib/features/messaging/phoneNumbers.js.map +1 -0
- package/lib/features/messaging/useChatViewer.js +16 -20
- package/lib/features/messaging/useChatViewer.js.map +1 -1
- package/lib/features/messaging/usePhoneVerification.js +147 -0
- package/lib/features/messaging/usePhoneVerification.js.map +1 -0
- package/lib/features/messaging/useYantraChatMembership.js +75 -0
- package/lib/features/messaging/useYantraChatMembership.js.map +1 -0
- package/lib/features/messaging/yantraChatOrg.js +17 -0
- package/lib/features/messaging/yantraChatOrg.js.map +1 -0
- package/lib/hooks/usePrerequisiteIds.js +5 -6
- package/lib/hooks/usePrerequisiteIds.js.map +1 -1
- package/lib/routes.json +8 -3
- package/lib/screens/ChatNative/index.js +72 -20
- package/lib/screens/ChatNative/index.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RegistrationScreen.js","sources":["../../../src/features/messaging/RegistrationScreen.tsx"],"sourcesContent":["/**\n * Registration screen for Yantra Chat.\n *\n * First-time users are prompted to register with their phone number.\n * The flow:\n * 1. User enters mobile number (country code in the same row)\n * 2. OTP is sent to their number\n * 3. User enters the OTP code to verify\n * 4. Phone number becomes their member ID in the Yantra Chat organization\n *\n * Follows the design from issue #1312.\n */\nimport React from 'react';\nimport {\n StyleSheet,\n View,\n Text,\n TouchableOpacity,\n TextInput,\n ActivityIndicator,\n ScrollView,\n Modal,\n Platform,\n} from 'react-native';\nimport { SafeAreaView } from 'react-native-safe-area-context';\nimport { Ionicons } from '@expo/vector-icons';\nimport { CHAT_REGISTRATION_TEST_OTP, usePhoneVerification } from './usePhoneVerification';\n\nfunction canShowDevTestOtpUi(): boolean {\n if (typeof __DEV__ !== 'undefined' && __DEV__) return true;\n return process.env.EXPO_PUBLIC_CHAT_ALLOW_TEST_OTP === 'true';\n}\n\ninterface RegistrationScreenProps {\n /** Called when registration completes successfully. */\n onRegistrationComplete: (phoneNumber: string) => void;\n /** Theme configuration. */\n theme: { colors: Record<string, string>; fonts: Record<string, Record<string, string>> };\n testID?: string;\n}\n\ninterface CountryOption {\n code: string;\n name: string;\n callingCode: string;\n}\n\nconst COUNTRIES: CountryOption[] = [\n { code: 'US', name: 'United States', callingCode: '+1' },\n { code: 'IN', name: 'India', callingCode: '+91' },\n { code: 'GB', name: 'United Kingdom', callingCode: '+44' },\n { code: 'CA', name: 'Canada', callingCode: '+1' },\n { code: 'AU', name: 'Australia', callingCode: '+61' },\n { code: 'FR', name: 'France', callingCode: '+33' },\n { code: 'DE', name: 'Germany', callingCode: '+49' },\n { code: 'ES', name: 'Spain', callingCode: '+34' },\n { code: 'IT', name: 'Italy', callingCode: '+39' },\n { code: 'BR', name: 'Brazil', callingCode: '+55' },\n { code: 'MX', name: 'Mexico', callingCode: '+52' },\n { code: 'SG', name: 'Singapore', callingCode: '+65' },\n { code: 'JP', name: 'Japan', callingCode: '+81' },\n { code: 'CN', name: 'China', callingCode: '+86' },\n];\n\nfunction PhoneRow({\n countryCode,\n callingCode,\n phone,\n onCountryPress,\n onChangePhone,\n disabled,\n theme,\n}: {\n countryCode: string;\n callingCode: string;\n phone: string;\n onCountryPress: () => void;\n onChangePhone: (v: string) => void;\n disabled: boolean;\n theme: RegistrationScreenProps['theme'];\n}) {\n return (\n <View\n style={[\n styles.phoneRow,\n {\n flexDirection: 'row',\n alignItems: 'center',\n borderColor: theme.colors.border,\n backgroundColor: theme.colors.card ?? '#fff',\n },\n ]}\n >\n <TouchableOpacity\n onPress={onCountryPress}\n disabled={disabled}\n style={[styles.countryChip, { flexDirection: 'row', alignItems: 'center' }]}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Select country code\"\n >\n <Text style={[styles.callingCode, { color: theme.colors.text }]}>{callingCode}</Text>\n <Ionicons name=\"chevron-down\" size={18} color={theme.colors.textSecondary} />\n </TouchableOpacity>\n <View style={[styles.phoneDivider, { backgroundColor: theme.colors.border }]} />\n <TextInput\n style={[styles.phoneInput, { color: theme.colors.text }]}\n placeholder=\"\"\n placeholderTextColor={theme.colors.placeholder}\n keyboardType=\"phone-pad\"\n textContentType=\"telephoneNumber\"\n value={phone}\n onChangeText={onChangePhone}\n editable={!disabled}\n maxLength={15}\n testID=\"chat-registration-phone\"\n />\n </View>\n );\n}\n\nexport function RegistrationScreen({ onRegistrationComplete, theme, testID }: RegistrationScreenProps) {\n const phoneVerification = usePhoneVerification('US');\n const selectedCountry = COUNTRIES.find((c) => c.code === phoneVerification.countryCode) || COUNTRIES[0];\n const [countryModalOpen, setCountryModalOpen] = React.useState(false);\n const accent = theme.colors.primary;\n const otpDigits = phoneVerification.otp.replace(/\\D/g, '');\n const usingTestOtp =\n phoneVerification.testOtpMode || (canShowDevTestOtpUi() && otpDigits === CHAT_REGISTRATION_TEST_OTP);\n\n React.useEffect(() => {\n if (phoneVerification.stage === 'verified' && phoneVerification.verifiedPhone) {\n void Promise.resolve(onRegistrationComplete(phoneVerification.verifiedPhone));\n }\n }, [phoneVerification.stage, phoneVerification.verifiedPhone, onRegistrationComplete]);\n\n const handleBack = React.useCallback(() => {\n if (phoneVerification.stage === 'otp') {\n phoneVerification.resetToInput();\n }\n }, [phoneVerification]);\n\n const handleSendOtp = React.useCallback(async () => {\n await phoneVerification.sendOtp();\n }, [phoneVerification]);\n\n const handleVerifyOtp = React.useCallback(async () => {\n await phoneVerification.verifyOtp();\n }, [phoneVerification]);\n\n const handleResend = React.useCallback(async () => {\n await phoneVerification.sendOtp();\n }, [phoneVerification]);\n\n return (\n <SafeAreaView\n style={[styles.container, { backgroundColor: theme.colors.background }]}\n edges={['top', 'left', 'right']}\n testID={testID}\n >\n <View style={[styles.header, { flexDirection: 'row', alignItems: 'center' }]}>\n {phoneVerification.stage === 'otp' ? (\n <TouchableOpacity onPress={handleBack} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}>\n <Ionicons name=\"chevron-back\" size={28} color={theme.colors.text} />\n </TouchableOpacity>\n ) : (\n <View style={{ width: 28 }} />\n )}\n <Text style={[styles.title, { color: theme.colors.text, flex: 1, textAlign: 'center' }]}>\n Yantra Chat\n </Text>\n <View style={{ width: 28 }} />\n </View>\n\n <ScrollView\n contentContainerStyle={styles.content}\n showsVerticalScrollIndicator={false}\n keyboardShouldPersistTaps=\"handled\"\n >\n {phoneVerification.stage === 'input' ? (\n <>\n <Text style={[styles.subtitle, { color: theme.colors.text }]}>Register to Chat</Text>\n <Text style={[styles.description, { color: theme.colors.textSecondary }]}>\n Enter your mobile number to get started. You'll receive an OTP to verify.\n </Text>\n\n <View style={styles.form}>\n <PhoneRow\n countryCode={phoneVerification.countryCode}\n callingCode={selectedCountry.callingCode}\n phone={phoneVerification.inputPhone}\n onCountryPress={() => setCountryModalOpen(true)}\n onChangePhone={phoneVerification.setInputPhone}\n disabled={phoneVerification.loading}\n theme={theme}\n />\n\n {phoneVerification.error ? (\n <View style={[styles.errorBox, { backgroundColor: theme.colors.error + '10' }]}>\n <Ionicons name=\"alert-circle\" size={16} color={theme.colors.error} />\n <Text style={[styles.errorText, { color: theme.colors.error }]}>\n {phoneVerification.error}\n </Text>\n </View>\n ) : null}\n\n <TouchableOpacity onPress={phoneVerification.continueWithTestOtp}>\n <Text style={[styles.linkText, { color: accent }]}>Continue with test OTP</Text>\n </TouchableOpacity>\n\n <TouchableOpacity\n onPress={handleSendOtp}\n disabled={phoneVerification.loading || !phoneVerification.inputPhone.trim()}\n style={[\n styles.button,\n {\n backgroundColor: phoneVerification.inputPhone.trim()\n ? accent\n : theme.colors.border,\n },\n ]}\n >\n {phoneVerification.loading ? (\n <ActivityIndicator color=\"#fff\" size=\"small\" />\n ) : (\n <Text style={styles.buttonText}>Send OTP</Text>\n )}\n </TouchableOpacity>\n </View>\n </>\n ) : (\n <>\n <Text style={[styles.subtitle, { color: theme.colors.text }]}>Verify your number</Text>\n <Text style={[styles.description, { color: theme.colors.textSecondary }]}>\n {usingTestOtp\n ? `Test mode: use code ${CHAT_REGISTRATION_TEST_OTP} and tap Continue.`\n : `Enter the 6-digit code sent to ${selectedCountry.callingCode} ${phoneVerification.inputPhone}`}\n </Text>\n\n <View style={styles.form}>\n <View\n style={[\n styles.otpInputContainer,\n {\n flexDirection: 'row',\n alignItems: 'center',\n borderColor: theme.colors.border,\n backgroundColor: theme.colors.card ?? '#fff',\n },\n ]}\n >\n <TextInput\n style={[styles.otpInput, { color: theme.colors.text, flex: 1 }]}\n placeholder=\"\"\n keyboardType=\"number-pad\"\n value={phoneVerification.otp}\n onChangeText={phoneVerification.setOtp}\n editable={!phoneVerification.loading}\n maxLength={6}\n testID=\"chat-registration-otp\"\n />\n </View>\n\n {phoneVerification.error ? (\n <View style={[styles.errorBox, { backgroundColor: theme.colors.error + '10' }]}>\n <Ionicons name=\"alert-circle\" size={16} color={theme.colors.error} />\n <Text style={[styles.errorText, { color: theme.colors.error }]}>\n {phoneVerification.error}\n </Text>\n </View>\n ) : null}\n\n <TouchableOpacity\n onPress={handleVerifyOtp}\n disabled={phoneVerification.loading || otpDigits.length < 6}\n style={[\n styles.button,\n {\n backgroundColor: otpDigits.length >= 6 ? accent : theme.colors.border,\n },\n ]}\n >\n {phoneVerification.loading ? (\n <ActivityIndicator color=\"#fff\" size=\"small\" />\n ) : (\n <Text style={styles.buttonText}>\n {usingTestOtp ? 'Continue' : 'Verify & Register'}\n </Text>\n )}\n </TouchableOpacity>\n\n {!usingTestOtp ? (\n <TouchableOpacity onPress={handleResend} disabled={phoneVerification.loading}>\n <Text style={[styles.linkText, { color: accent }]}>\n Didn't get the code? Resend\n </Text>\n </TouchableOpacity>\n ) : null}\n </View>\n </>\n )}\n </ScrollView>\n\n <Modal visible={countryModalOpen} animationType=\"slide\" presentationStyle=\"pageSheet\">\n <SafeAreaView style={[styles.modalFill, { backgroundColor: theme.colors.background }]}>\n <View style={[styles.modalHeader, { flexDirection: 'row', alignItems: 'center' }]}>\n <Text style={[styles.modalTitle, { color: theme.colors.text }]}>Country code</Text>\n <TouchableOpacity onPress={() => setCountryModalOpen(false)}>\n <Ionicons name=\"close\" size={26} color={theme.colors.text} />\n </TouchableOpacity>\n </View>\n <ScrollView>\n {COUNTRIES.map((country) => (\n <TouchableOpacity\n key={country.code}\n onPress={() => {\n phoneVerification.setCountryCode(country.code);\n setCountryModalOpen(false);\n }}\n style={[\n styles.countryListItem,\n phoneVerification.countryCode === country.code && {\n backgroundColor: accent + '18',\n },\n ]}\n >\n <Text style={[styles.countryListText, { color: theme.colors.text }]}>\n {country.name} ({country.callingCode})\n </Text>\n {phoneVerification.countryCode === country.code ? (\n <Ionicons name=\"checkmark\" size={20} color={accent} />\n ) : null}\n </TouchableOpacity>\n ))}\n </ScrollView>\n </SafeAreaView>\n </Modal>\n </SafeAreaView>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1 },\n header: {\n justifyContent: 'space-between',\n paddingHorizontal: 16,\n paddingVertical: 8,\n },\n title: { fontSize: 17, fontWeight: '600' },\n content: { padding: 20, paddingBottom: 40 },\n subtitle: { fontSize: 22, fontWeight: '700', marginBottom: 8 },\n description: { fontSize: 14, marginBottom: 24, lineHeight: 20 },\n form: { gap: 14 },\n phoneRow: {\n borderWidth: 1,\n borderRadius: 10,\n minHeight: 48,\n overflow: 'hidden',\n },\n countryChip: {\n paddingHorizontal: 12,\n paddingVertical: 12,\n },\n callingCode: { fontSize: 16, fontWeight: '600', marginRight: 4 },\n phoneDivider: { width: StyleSheet.hairlineWidth, alignSelf: 'stretch' },\n phoneInput: {\n flex: 1,\n paddingHorizontal: 12,\n paddingVertical: Platform.OS === 'ios' ? 12 : 10,\n fontSize: 16,\n },\n otpInputContainer: {\n borderWidth: 1,\n borderRadius: 10,\n paddingHorizontal: 16,\n },\n otpInput: {\n paddingVertical: 14,\n fontSize: 22,\n fontWeight: '600',\n letterSpacing: 6,\n textAlign: 'center',\n },\n button: {\n borderRadius: 10,\n paddingVertical: 14,\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: 4,\n },\n buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' },\n errorBox: {\n flexDirection: 'row',\n alignItems: 'center',\n borderRadius: 8,\n paddingHorizontal: 12,\n paddingVertical: 10,\n gap: 8,\n },\n errorText: { fontSize: 13, flex: 1 },\n linkText: { fontSize: 14, textAlign: 'center', fontWeight: '500' },\n modalFill: { flex: 1 },\n modalHeader: {\n justifyContent: 'space-between',\n paddingHorizontal: 16,\n paddingVertical: 12,\n },\n modalTitle: { fontSize: 18, fontWeight: '700' },\n countryListItem: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: 16,\n paddingVertical: 14,\n borderBottomWidth: StyleSheet.hairlineWidth,\n borderBottomColor: 'rgba(0,0,0,0.06)',\n },\n countryListText: { fontSize: 16 },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const YANTRA_CHAT_REGISTRATION_STATUS_QUERY = `
|
|
2
|
+
query YantraChatRegistrationStatus {
|
|
3
|
+
yantraChatRegistrationStatus {
|
|
4
|
+
registered
|
|
5
|
+
phoneE164
|
|
6
|
+
memberId
|
|
7
|
+
organizationId
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
`;
|
|
11
|
+
const REGISTER_YANTRA_CHAT_MEMBER_MUTATION = `
|
|
12
|
+
mutation RegisterYantraChatMember($phoneE164: String!, $displayName: String) {
|
|
13
|
+
registerYantraChatMember(phoneE164: $phoneE164, displayName: $displayName) {
|
|
14
|
+
registered
|
|
15
|
+
phoneE164
|
|
16
|
+
memberId
|
|
17
|
+
organizationId
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;export{REGISTER_YANTRA_CHAT_MEMBER_MUTATION,YANTRA_CHAT_REGISTRATION_STATUS_QUERY};//# sourceMappingURL=chatOperations.js.map
|
|
@@ -0,0 +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`;\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 * 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_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":"AAoJO,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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const YANTRA_CHAT_PHONE_STORAGE_KEY = "yantra-chat-registered-phone-e164";export{YANTRA_CHAT_PHONE_STORAGE_KEY};//# sourceMappingURL=chatRegistrationStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatRegistrationStorage.js","sources":["../../../src/features/messaging/chatRegistrationStorage.ts"],"sourcesContent":["/**\n * AsyncStorage cache for Yantra Chat registration (issue #1312).\n * Mongo `organizationMembers` is the source of truth (`yantraChatRegistrationStatus`);\n * this key only avoids flashing the registration screen while the status query runs.\n * It is not cleared on network/GraphQL errors (Metro reload, backend restart).\n */\nexport const YANTRA_CHAT_PHONE_STORAGE_KEY = 'yantra-chat-registered-phone-e164';\n"],"names":[],"mappings":"AAMO,MAAM,6BAAgC,GAAA"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const TRUNK_PREFIXES = {
|
|
2
|
+
// The overwhelmingly common case: a single leading 0.
|
|
3
|
+
DEFAULT: "0",
|
|
4
|
+
// Italy is the notable exception - the leading 0 is part of the number.
|
|
5
|
+
IT: ""
|
|
6
|
+
};
|
|
7
|
+
const CALLING_CODES = {
|
|
8
|
+
US: "1",
|
|
9
|
+
CA: "1",
|
|
10
|
+
GB: "44",
|
|
11
|
+
IE: "353",
|
|
12
|
+
FR: "33",
|
|
13
|
+
DE: "49",
|
|
14
|
+
ES: "34",
|
|
15
|
+
IT: "39",
|
|
16
|
+
NL: "31",
|
|
17
|
+
BE: "32",
|
|
18
|
+
CH: "41",
|
|
19
|
+
AT: "43",
|
|
20
|
+
SE: "46",
|
|
21
|
+
NO: "47",
|
|
22
|
+
DK: "45",
|
|
23
|
+
FI: "358",
|
|
24
|
+
PL: "48",
|
|
25
|
+
PT: "351",
|
|
26
|
+
GR: "30",
|
|
27
|
+
CZ: "420",
|
|
28
|
+
RO: "40",
|
|
29
|
+
HU: "36",
|
|
30
|
+
UA: "380",
|
|
31
|
+
RU: "7",
|
|
32
|
+
TR: "90",
|
|
33
|
+
IL: "972",
|
|
34
|
+
AE: "971",
|
|
35
|
+
SA: "966",
|
|
36
|
+
QA: "974",
|
|
37
|
+
KW: "965",
|
|
38
|
+
IN: "91",
|
|
39
|
+
PK: "92",
|
|
40
|
+
BD: "880",
|
|
41
|
+
LK: "94",
|
|
42
|
+
NP: "977",
|
|
43
|
+
CN: "86",
|
|
44
|
+
JP: "81",
|
|
45
|
+
KR: "82",
|
|
46
|
+
TW: "886",
|
|
47
|
+
HK: "852",
|
|
48
|
+
SG: "65",
|
|
49
|
+
MY: "60",
|
|
50
|
+
TH: "66",
|
|
51
|
+
VN: "84",
|
|
52
|
+
PH: "63",
|
|
53
|
+
ID: "62",
|
|
54
|
+
AU: "61",
|
|
55
|
+
NZ: "64",
|
|
56
|
+
ZA: "27",
|
|
57
|
+
NG: "234",
|
|
58
|
+
KE: "254",
|
|
59
|
+
EG: "20",
|
|
60
|
+
GH: "233",
|
|
61
|
+
BR: "55",
|
|
62
|
+
MX: "52",
|
|
63
|
+
AR: "54",
|
|
64
|
+
CL: "56",
|
|
65
|
+
CO: "57",
|
|
66
|
+
PE: "51"
|
|
67
|
+
};
|
|
68
|
+
const MIN_E164_DIGITS = 7;
|
|
69
|
+
const MAX_E164_DIGITS = 15;
|
|
70
|
+
function toE164(raw, defaultRegion) {
|
|
71
|
+
if (typeof raw !== "string") return null;
|
|
72
|
+
const cleaned = raw.replace(/[\s\-().]/g, "");
|
|
73
|
+
if (!cleaned) return null;
|
|
74
|
+
const withoutExt = cleaned.split(/[,;xX#]/)[0];
|
|
75
|
+
if (!withoutExt) return null;
|
|
76
|
+
let digits;
|
|
77
|
+
if (withoutExt.startsWith("+")) {
|
|
78
|
+
digits = withoutExt.slice(1).replace(/\D/g, "");
|
|
79
|
+
} else if (withoutExt.startsWith("00")) {
|
|
80
|
+
digits = withoutExt.slice(2).replace(/\D/g, "");
|
|
81
|
+
} else {
|
|
82
|
+
const region = (defaultRegion != null ? defaultRegion : "").toUpperCase();
|
|
83
|
+
const cc = CALLING_CODES[region];
|
|
84
|
+
if (!cc) return null;
|
|
85
|
+
let national = withoutExt.replace(/\D/g, "");
|
|
86
|
+
const trunk = region in TRUNK_PREFIXES ? TRUNK_PREFIXES[region] : TRUNK_PREFIXES.DEFAULT;
|
|
87
|
+
if (trunk && national.startsWith(trunk)) national = national.slice(trunk.length);
|
|
88
|
+
digits = national.startsWith(cc) && national.length >= MIN_E164_DIGITS + cc.length - 1 ? national : cc + national;
|
|
89
|
+
}
|
|
90
|
+
if (digits.length < MIN_E164_DIGITS || digits.length > MAX_E164_DIGITS) return null;
|
|
91
|
+
if (digits.startsWith("0")) return null;
|
|
92
|
+
return `+${digits}`;
|
|
93
|
+
}
|
|
94
|
+
function formatPhoneNumber(input, defaultRegion) {
|
|
95
|
+
return toE164(input, defaultRegion);
|
|
96
|
+
}
|
|
97
|
+
function isValidPhoneNumber(phoneNumber) {
|
|
98
|
+
if (!phoneNumber) return false;
|
|
99
|
+
if (!phoneNumber.startsWith("+")) return false;
|
|
100
|
+
const digits = phoneNumber.slice(1).replace(/\D/g, "");
|
|
101
|
+
return digits.length >= MIN_E164_DIGITS && digits.length <= MAX_E164_DIGITS;
|
|
102
|
+
}export{formatPhoneNumber,isValidPhoneNumber,toE164};//# sourceMappingURL=phoneNumbers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phoneNumbers.js","sources":["../../../src/features/messaging/phoneNumbers.ts"],"sourcesContent":["/**\n * Turning what the address book gives you into something matchable.\n *\n * This lives in the REMOTE, not the host, on purpose: it is pure logic with no\n * native dependency, it is where contact-matching actually goes wrong, and\n * keeping it here means a normalisation bug is a surface deploy rather than an\n * App Store release. The `contacts` seam hands over RAW strings plus a region\n * hint precisely so this can own the problem.\n *\n * Deliberately NOT libphonenumber. That library is ~500KB and every byte ships\n * in the remote bundle on every cold launch. What follows handles the cases\n * that actually occur in an address book; anything it cannot confidently place\n * is DROPPED rather than guessed, because a wrong match shows someone a\n * stranger's name attached to their friend's number, which is far worse than\n * simply not finding them.\n */\n\n/** National trunk prefixes stripped before applying a country code. */\nconst TRUNK_PREFIXES: Record<string, string> = {\n // The overwhelmingly common case: a single leading 0.\n DEFAULT: '0',\n // Italy is the notable exception - the leading 0 is part of the number.\n IT: '',\n};\n\n/** Country calling codes for the regions a device is likely to report. */\nconst CALLING_CODES: Record<string, string> = {\n US: '1',\n CA: '1',\n GB: '44',\n IE: '353',\n FR: '33',\n DE: '49',\n ES: '34',\n IT: '39',\n NL: '31',\n BE: '32',\n CH: '41',\n AT: '43',\n SE: '46',\n NO: '47',\n DK: '45',\n FI: '358',\n PL: '48',\n PT: '351',\n GR: '30',\n CZ: '420',\n RO: '40',\n HU: '36',\n UA: '380',\n RU: '7',\n TR: '90',\n IL: '972',\n AE: '971',\n SA: '966',\n QA: '974',\n KW: '965',\n IN: '91',\n PK: '92',\n BD: '880',\n LK: '94',\n NP: '977',\n CN: '86',\n JP: '81',\n KR: '82',\n TW: '886',\n HK: '852',\n SG: '65',\n MY: '60',\n TH: '66',\n VN: '84',\n PH: '63',\n ID: '62',\n AU: '61',\n NZ: '64',\n ZA: '27',\n NG: '234',\n KE: '254',\n EG: '20',\n GH: '233',\n BR: '55',\n MX: '52',\n AR: '54',\n CL: '56',\n CO: '57',\n PE: '51',\n};\n\n/** Longest calling code is 4 digits; shortest E.164 subscriber part is ~4. */\nconst MIN_E164_DIGITS = 7;\nconst MAX_E164_DIGITS = 15;\n\n/**\n * Normalise one raw address-book string to E.164 (`+<digits>`), or null.\n *\n * Returns null rather than a best guess whenever the result would be\n * speculative - see the file header for why a miss beats a wrong match.\n */\nexport function toE164(raw: string, defaultRegion?: string | null): string | null {\n if (typeof raw !== 'string') return null;\n\n // Strip everything a human might type: spaces, dashes, dots, parens,\n // and the invisible bidi marks iOS inserts around RTL-locale numbers.\n const cleaned = raw.replace(/[\\s\\-().]/g, '');\n if (!cleaned) return null;\n\n // Extensions are not diallable identity - \"555123456x89\" is one person.\n const withoutExt = cleaned.split(/[,;xX#]/)[0];\n if (!withoutExt) return null;\n\n let digits: string;\n if (withoutExt.startsWith('+')) {\n digits = withoutExt.slice(1).replace(/\\D/g, '');\n } else if (withoutExt.startsWith('00')) {\n // The international prefix used across most of Europe and Asia.\n digits = withoutExt.slice(2).replace(/\\D/g, '');\n } else {\n const region = (defaultRegion ?? '').toUpperCase();\n const cc = CALLING_CODES[region];\n // No region and no international prefix: the number is meaningless\n // without knowing where it was dialled from. Drop it.\n if (!cc) return null;\n\n let national = withoutExt.replace(/\\D/g, '');\n const trunk = region in TRUNK_PREFIXES ? TRUNK_PREFIXES[region] : TRUNK_PREFIXES.DEFAULT;\n if (trunk && national.startsWith(trunk)) national = national.slice(trunk.length);\n\n // A number that already begins with its own country code and is\n // plausibly full-length is international-without-the-plus, not a\n // national number that happens to start with those digits.\n digits =\n national.startsWith(cc) && national.length >= MIN_E164_DIGITS + cc.length - 1 ? national : cc + national;\n }\n\n if (digits.length < MIN_E164_DIGITS || digits.length > MAX_E164_DIGITS) return null;\n // A leading zero after the country code means the trunk prefix survived.\n if (digits.startsWith('0')) return null;\n\n return `+${digits}`;\n}\n\n/**\n * Region implied by an E.164 number's calling code (longest match wins), or null.\n * `+1` resolves to US, which parses identically to CA.\n */\nexport function regionFromE164(e164: string | null | undefined): string | null {\n if (!e164 || !e164.startsWith('+')) return null;\n const digits = e164.slice(1);\n let best: { region: string; len: number } | null = null;\n for (const [region, cc] of Object.entries(CALLING_CODES)) {\n if (digits.startsWith(cc) && (!best || cc.length > best.len)) best = { region, len: cc.length };\n }\n return best?.region ?? null;\n}\n\n/**\n * Every distinct E.164 number a contact has, in address-book order.\n *\n * De-duplicated because the same person routinely appears with the same number\n * written two ways (\"+1 555…\" and \"(555) …\"), and matching the same number\n * twice would show them twice in the results.\n */\nexport function contactE164s(\n phoneNumbers: readonly string[],\n defaultRegion?: string | null | readonly (string | null | undefined)[],\n): string[] {\n // A number saved without a country code is ambiguous, so each candidate region\n // contributes an interpretation. The server only matches verified member numbers,\n // so extra candidates cannot produce a match that is not real.\n const regions = Array.isArray(defaultRegion) ? defaultRegion : [defaultRegion as string | null | undefined];\n const seen = new Set<string>();\n for (const raw of phoneNumbers) {\n for (const region of regions) {\n const e164 = toE164(raw, region);\n if (e164) seen.add(e164);\n }\n }\n return Array.from(seen);\n}\n\nexport interface NormalizedContact {\n /** The device's stable id, echoed back so a match can be re-attached. */\n id: string;\n displayName: string;\n imageUri?: string | null;\n /** Distinct E.164 candidates; never empty (contacts without any are dropped). */\n e164: string[];\n /** Numbers exactly as saved in the address book, for display and SMS. */\n rawNumbers?: string[];\n}\n\n/**\n * Normalise a whole address book, dropping anything unmatchable.\n *\n * Also drops the viewer's OWN number, so nobody is offered a chat with\n * themselves - which happens on essentially every real device, because people\n * save their own contact card.\n */\nexport function normalizeContacts(\n contacts: ReadonlyArray<{ id: string; displayName: string; phoneNumbers: string[]; imageUri?: string | null }>,\n defaultRegion?: string | null | readonly (string | null | undefined)[],\n viewerE164?: string | null,\n): NormalizedContact[] {\n const mine = new Set(viewerE164 ? contactE164s([viewerE164], defaultRegion) : []);\n const out: NormalizedContact[] = [];\n for (const c of contacts) {\n const e164 = contactE164s(c.phoneNumbers ?? [], defaultRegion);\n // Any interpretation equal to the viewer's own number means this is their own card.\n if (!e164.length || e164.some((n) => mine.has(n))) continue;\n out.push({\n id: c.id,\n displayName: c.displayName,\n imageUri: c.imageUri ?? null,\n e164,\n rawNumbers: (c.phoneNumbers ?? []).map((n) => n.trim()).filter(Boolean),\n });\n }\n return out;\n}\n\n/**\n * The full set of numbers to ask the server about, capped.\n *\n * Address books of several thousand entries are ordinary, and the cap keeps one\n * request from becoming megabytes. Callers page through the rest.\n */\nexport function collectLookupNumbers(contacts: readonly NormalizedContact[], limit = 1000): string[] {\n const seen = new Set<string>();\n for (const c of contacts) {\n for (const n of c.e164) {\n seen.add(n);\n if (seen.size >= limit) return Array.from(seen);\n }\n }\n return Array.from(seen);\n}\n\n/**\n * Format a phone number string (user input) to E.164 format.\n * Used by the registration screen to normalize phone input before verification.\n */\nexport function formatPhoneNumber(input: string, defaultRegion?: string): string | null {\n return toE164(input, defaultRegion);\n}\n\n/**\n * Validate if a phone number string is a valid E.164 number.\n * Returns true if the number can be normalized to E.164 format.\n */\nexport function isValidPhoneNumber(phoneNumber: string | null): boolean {\n if (!phoneNumber) return false;\n if (!phoneNumber.startsWith('+')) return false;\n const digits = phoneNumber.slice(1).replace(/\\D/g, '');\n return digits.length >= MIN_E164_DIGITS && digits.length <= MAX_E164_DIGITS;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,32 +1,28 @@
|
|
|
1
|
-
import {useMemo}from'react';import {useSelector}from'react-redux';import {userSelector}from'@adminide-stack/user-auth0-client';import {
|
|
2
|
-
var _a
|
|
1
|
+
import {useMemo}from'react';import {useSelector}from'react-redux';import {userSelector}from'@adminide-stack/user-auth0-client';import {pickPrimaryDisplayName,pickAuthPicture}from'../../utils/authUserDisplay.js';import {useYantraChatMembership}from'./useYantraChatMembership.js';import {YANTRA_CHAT_ORG_SLUG}from'./yantraChatOrg.js';function useChatViewer() {
|
|
2
|
+
var _a;
|
|
3
3
|
const authUser = useSelector(userSelector);
|
|
4
|
-
const
|
|
5
|
-
orgName,
|
|
6
|
-
orgLoading
|
|
7
|
-
} = usePrerequisiteIds();
|
|
8
|
-
const {
|
|
9
|
-
data,
|
|
10
|
-
loading: profileLoading,
|
|
11
|
-
error: profileError
|
|
12
|
-
} = useAccountProfileQuery({
|
|
13
|
-
fetchPolicy: "cache-and-network",
|
|
14
|
-
errorPolicy: "all"
|
|
15
|
-
});
|
|
16
|
-
const userId = (_c = (_b = (_a = data == null ? void 0 : data.accountProfile) == null ? void 0 : _a.user) == null ? void 0 : _b.id) != null ? _c : null;
|
|
4
|
+
const userId = (_a = authUser == null ? void 0 : authUser.id) != null ? _a : null;
|
|
17
5
|
const displayName = useMemo(() => pickPrimaryDisplayName(authUser), [authUser]);
|
|
18
6
|
const avatarUrl = useMemo(() => pickAuthPicture(authUser), [authUser]);
|
|
7
|
+
const membership = useYantraChatMembership(userId, displayName);
|
|
8
|
+
const registrationStatus = membership.phoneE164 ? "registered" : membership.loading ? "registering" : "not-registered";
|
|
19
9
|
const viewer = useMemo(() => userId ? {
|
|
20
10
|
userId,
|
|
21
11
|
displayName,
|
|
22
12
|
avatarUrl,
|
|
23
|
-
orgName:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
orgName: YANTRA_CHAT_ORG_SLUG,
|
|
14
|
+
phoneE164: membership.phoneE164,
|
|
15
|
+
registrationStatus
|
|
16
|
+
} : null, [userId, displayName, avatarUrl, membership.phoneE164, registrationStatus]);
|
|
17
|
+
const ready = Boolean(authUser) && !membership.loading;
|
|
18
|
+
const error = membership.error || (!viewer && ready ? "Could not load your account." : null);
|
|
27
19
|
return {
|
|
28
20
|
viewer,
|
|
29
21
|
error,
|
|
30
|
-
ready
|
|
22
|
+
ready,
|
|
23
|
+
needsRegistration: membership.needsRegistration,
|
|
24
|
+
membershipLoading: membership.loading,
|
|
25
|
+
registerForChat: membership.register,
|
|
26
|
+
refreshMembership: membership.refresh
|
|
31
27
|
};
|
|
32
28
|
}export{useChatViewer};//# sourceMappingURL=useChatViewer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatViewer.js","sources":["../../../src/features/messaging/useChatViewer.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"useChatViewer.js","sources":["../../../src/features/messaging/useChatViewer.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport { useSelector } from 'react-redux';\nimport type { IUserState } from '@adminide-stack/core';\nimport { Store, userSelector } from '@adminide-stack/user-auth0-client';\nimport { pickAuthPicture, pickPrimaryDisplayName } from '../../utils/authUserDisplay';\nimport type { ChatViewer, ChatRegistrationStatus } from './chatHost';\nimport { useYantraChatMembership } from './useYantraChatMembership';\nimport { YANTRA_CHAT_ORG_SLUG } from './yantraChatOrg';\n\nexport interface ChatViewerState {\n viewer: ChatViewer | null;\n error: string | null;\n ready: boolean;\n needsRegistration: boolean;\n membershipLoading: boolean;\n registerForChat: (phoneE164: string) => Promise<string>;\n refreshMembership: () => Promise<void>;\n}\n\nexport function useChatViewer(): ChatViewerState {\n const authUser = useSelector<Store.Auth, IUserState>(userSelector);\n const userId = authUser?.id ?? null;\n const displayName = useMemo(() => pickPrimaryDisplayName(authUser), [authUser]);\n const avatarUrl = useMemo(() => pickAuthPicture(authUser), [authUser]);\n\n const membership = useYantraChatMembership(userId, displayName);\n\n const registrationStatus: ChatRegistrationStatus = membership.phoneE164\n ? 'registered'\n : membership.loading\n ? 'registering'\n : 'not-registered';\n\n const viewer = useMemo<ChatViewer | null>(\n () =>\n userId\n ? {\n userId,\n displayName,\n avatarUrl,\n orgName: YANTRA_CHAT_ORG_SLUG,\n phoneE164: membership.phoneE164,\n registrationStatus,\n }\n : null,\n [userId, displayName, avatarUrl, membership.phoneE164, registrationStatus],\n );\n\n const ready = Boolean(authUser) && !membership.loading;\n\n const error = membership.error || (!viewer && ready ? 'Could not load your account.' : null);\n\n return {\n viewer,\n error,\n ready,\n needsRegistration: membership.needsRegistration,\n membershipLoading: membership.loading,\n registerForChat: membership.register,\n refreshMembership: membership.refresh,\n };\n}\n"],"names":[],"mappings":"4UAiBO,SAAS,aAAiC,GAAA;AAjBjD,EAAA,IAAA,EAAA;AAkBE,EAAM,MAAA,QAAA,GAAW,YAAoC,YAAY,CAAA;AACjE,EAAM,MAAA,MAAA,GAAA,CAAS,EAAU,GAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAA,EAAA,KAAV,IAAgB,GAAA,EAAA,GAAA,IAAA;AAC/B,EAAM,MAAA,WAAA,GAAc,QAAQ,MAAM,sBAAA,CAAuB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA;AAC9E,EAAM,MAAA,SAAA,GAAY,QAAQ,MAAM,eAAA,CAAgB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA;AACrE,EAAM,MAAA,UAAA,GAAa,uBAAwB,CAAA,MAAA,EAAQ,WAAW,CAAA;AAC9D,EAAA,MAAM,qBAA6C,UAAW,CAAA,SAAA,GAAY,YAAe,GAAA,UAAA,CAAW,UAAU,aAAgB,GAAA,gBAAA;AAC9H,EAAM,MAAA,MAAA,GAAS,OAA2B,CAAA,MAAM,MAAS,GAAA;AAAA,IACvD,MAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAS,EAAA,oBAAA;AAAA,IACT,WAAW,UAAW,CAAA,SAAA;AAAA,IACtB;AAAA,GACF,GAAI,MAAM,CAAC,MAAA,EAAQ,aAAa,SAAW,EAAA,UAAA,CAAW,SAAW,EAAA,kBAAkB,CAAC,CAAA;AACpF,EAAA,MAAM,KAAQ,GAAA,OAAA,CAAQ,QAAQ,CAAA,IAAK,CAAC,UAAW,CAAA,OAAA;AAC/C,EAAA,MAAM,QAAQ,UAAW,CAAA,KAAA,KAAU,CAAC,MAAA,IAAU,QAAQ,8BAAiC,GAAA,IAAA,CAAA;AACvF,EAAO,OAAA;AAAA,IACL,MAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA;AAAA,IACA,mBAAmB,UAAW,CAAA,iBAAA;AAAA,IAC9B,mBAAmB,UAAW,CAAA,OAAA;AAAA,IAC9B,iBAAiB,UAAW,CAAA,QAAA;AAAA,IAC5B,mBAAmB,UAAW,CAAA;AAAA,GAChC;AACF"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {useState,useCallback}from'react';import {useSendPhoneOtpCodeMutation,useVerifyPhoneOtpCodeMutation}from'common/graphql';import {formatPhoneNumber,isValidPhoneNumber}from'./phoneNumbers.js';import {useObtainSystemToken}from'../../hooks/useObtainSystemToken.js';const CHAT_REGISTRATION_TEST_OTP = "123456";
|
|
2
|
+
function isChatTestOtpCode(code) {
|
|
3
|
+
return code.replace(/\D/g, "") === CHAT_REGISTRATION_TEST_OTP;
|
|
4
|
+
}
|
|
5
|
+
function canBypassOtpWithTestCode() {
|
|
6
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) return true;
|
|
7
|
+
return process.env.EXPO_PUBLIC_CHAT_ALLOW_TEST_OTP === "true";
|
|
8
|
+
}
|
|
9
|
+
function usePhoneVerification(defaultCountryCode) {
|
|
10
|
+
const [stage, setStage] = useState("input");
|
|
11
|
+
const [inputPhone, setInputPhone] = useState("");
|
|
12
|
+
const [countryCode, setCountryCode] = useState(defaultCountryCode);
|
|
13
|
+
const [otp, setOtp] = useState("");
|
|
14
|
+
const [verifiedPhone, setVerifiedPhone] = useState(null);
|
|
15
|
+
const [error, setError] = useState(null);
|
|
16
|
+
const [loading, setLoading] = useState(false);
|
|
17
|
+
const [testOtpMode, setTestOtpMode] = useState(false);
|
|
18
|
+
const [sendPhoneOtpMutation] = useSendPhoneOtpCodeMutation();
|
|
19
|
+
const [verifyPhoneOtpMutation] = useVerifyPhoneOtpCodeMutation();
|
|
20
|
+
const clearError = useCallback(() => setError(null), []);
|
|
21
|
+
const {
|
|
22
|
+
obtainSystemToken
|
|
23
|
+
} = useObtainSystemToken();
|
|
24
|
+
const resetToInput = useCallback(() => {
|
|
25
|
+
setStage("input");
|
|
26
|
+
setInputPhone("");
|
|
27
|
+
setOtp("");
|
|
28
|
+
setError(null);
|
|
29
|
+
setVerifiedPhone(null);
|
|
30
|
+
setTestOtpMode(false);
|
|
31
|
+
}, []);
|
|
32
|
+
const continueWithTestOtp = useCallback(() => {
|
|
33
|
+
clearError();
|
|
34
|
+
const normalized = formatPhoneNumber(inputPhone, countryCode);
|
|
35
|
+
if (!normalized || !isValidPhoneNumber(normalized)) {
|
|
36
|
+
setError("Please enter a valid mobile number");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
setTestOtpMode(true);
|
|
40
|
+
setOtp(CHAT_REGISTRATION_TEST_OTP);
|
|
41
|
+
setStage("otp");
|
|
42
|
+
}, [inputPhone, countryCode, clearError]);
|
|
43
|
+
const sendOtp = useCallback(async () => {
|
|
44
|
+
var _a;
|
|
45
|
+
clearError();
|
|
46
|
+
setTestOtpMode(false);
|
|
47
|
+
const normalized = formatPhoneNumber(inputPhone, countryCode);
|
|
48
|
+
if (!normalized || !isValidPhoneNumber(normalized)) {
|
|
49
|
+
setError("Please enter a valid mobile number");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
setLoading(true);
|
|
53
|
+
try {
|
|
54
|
+
const systemToken = await obtainSystemToken();
|
|
55
|
+
if (!systemToken) throw new Error("Unable to obtain cdecli system token");
|
|
56
|
+
const result = await sendPhoneOtpMutation({
|
|
57
|
+
variables: {
|
|
58
|
+
phoneNumber: {
|
|
59
|
+
phoneNumber: normalized
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
context: {
|
|
63
|
+
headers: {
|
|
64
|
+
"x-cdecli-system-token": systemToken
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
if (!((_a = result.data) == null ? void 0 : _a.sendPhoneOTPCode)) throw new Error("Failed to send OTP");
|
|
69
|
+
setOtp("");
|
|
70
|
+
setStage("otp");
|
|
71
|
+
setError(null);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
setError(err instanceof Error ? err.message : "Failed to send OTP");
|
|
74
|
+
} finally {
|
|
75
|
+
setLoading(false);
|
|
76
|
+
}
|
|
77
|
+
}, [inputPhone, countryCode, sendPhoneOtpMutation, clearError, obtainSystemToken]);
|
|
78
|
+
const verifyOtp = useCallback(async () => {
|
|
79
|
+
var _a;
|
|
80
|
+
clearError();
|
|
81
|
+
const code = otp.replace(/\D/g, "");
|
|
82
|
+
if (!code || code.length !== 6) {
|
|
83
|
+
setError("Please enter a valid 6-digit OTP");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const normalized = formatPhoneNumber(inputPhone, countryCode);
|
|
87
|
+
if (!normalized) {
|
|
88
|
+
setError("Please enter a valid phone number");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const useTestBypass = testOtpMode || canBypassOtpWithTestCode() && isChatTestOtpCode(code);
|
|
92
|
+
if (useTestBypass && isChatTestOtpCode(code)) {
|
|
93
|
+
setVerifiedPhone(normalized);
|
|
94
|
+
setStage("verified");
|
|
95
|
+
setTestOtpMode(false);
|
|
96
|
+
setError(null);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
setStage("verifying");
|
|
100
|
+
setLoading(true);
|
|
101
|
+
try {
|
|
102
|
+
const systemToken = await obtainSystemToken();
|
|
103
|
+
if (!systemToken) throw new Error("Unable to obtain cdecli system token");
|
|
104
|
+
const result = await verifyPhoneOtpMutation({
|
|
105
|
+
variables: {
|
|
106
|
+
phoneNumber: {
|
|
107
|
+
phoneNumber: normalized
|
|
108
|
+
},
|
|
109
|
+
otp: code
|
|
110
|
+
},
|
|
111
|
+
context: {
|
|
112
|
+
headers: {
|
|
113
|
+
"x-cdecli-system-token": systemToken
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
if (!((_a = result.data) == null ? void 0 : _a.verifyPhoneOTPCode)) throw new Error("Invalid or expired OTP");
|
|
118
|
+
setVerifiedPhone(normalized);
|
|
119
|
+
setStage("verified");
|
|
120
|
+
setTestOtpMode(false);
|
|
121
|
+
setError(null);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
setError(err instanceof Error ? err.message : "Failed to verify OTP");
|
|
124
|
+
setStage("otp");
|
|
125
|
+
} finally {
|
|
126
|
+
setLoading(false);
|
|
127
|
+
}
|
|
128
|
+
}, [otp, inputPhone, countryCode, testOtpMode, verifyPhoneOtpMutation, clearError, obtainSystemToken]);
|
|
129
|
+
return {
|
|
130
|
+
stage,
|
|
131
|
+
verifiedPhone,
|
|
132
|
+
inputPhone,
|
|
133
|
+
countryCode,
|
|
134
|
+
otp,
|
|
135
|
+
error,
|
|
136
|
+
loading,
|
|
137
|
+
testOtpMode,
|
|
138
|
+
setCountryCode,
|
|
139
|
+
setInputPhone,
|
|
140
|
+
setOtp,
|
|
141
|
+
sendOtp,
|
|
142
|
+
verifyOtp,
|
|
143
|
+
continueWithTestOtp,
|
|
144
|
+
resetToInput,
|
|
145
|
+
clearError
|
|
146
|
+
};
|
|
147
|
+
}export{CHAT_REGISTRATION_TEST_OTP,usePhoneVerification};//# sourceMappingURL=usePhoneVerification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePhoneVerification.js","sources":["../../../src/features/messaging/usePhoneVerification.ts"],"sourcesContent":["/**\n * Phone number verification flow for Yantra Chat registration.\n *\n * Manages the OTP verification process for phone-number-based membership.\n * Uses adminIde's existing `sendPhoneOTP` / `verifyPhoneOtp` mutations and Auth0's\n * `passwordlessLogin` endpoint.\n *\n * Phone numbers are normalized to E.164 format and serve as the member ID.\n */\nimport { useCallback, useState } from 'react';\nimport { useSendPhoneOtpCodeMutation, useVerifyPhoneOtpCodeMutation } from 'common/graphql';\nimport { formatPhoneNumber, isValidPhoneNumber } from './phoneNumbers';\nimport { useObtainSystemToken } from '../../hooks/useObtainSystemToken';\n\n/** Fixed code for \"Continue with test OTP\" and local dev bypass (no SMS verify). */\nexport const CHAT_REGISTRATION_TEST_OTP = '123456';\n\nfunction isChatTestOtpCode(code: string): boolean {\n return code.replace(/\\D/g, '') === CHAT_REGISTRATION_TEST_OTP;\n}\n\nfunction canBypassOtpWithTestCode(): boolean {\n if (typeof __DEV__ !== 'undefined' && __DEV__) return true;\n return process.env.EXPO_PUBLIC_CHAT_ALLOW_TEST_OTP === 'true';\n}\n\nexport interface PhoneVerificationState {\n /** Current stage of the verification flow. */\n stage: 'input' | 'otp' | 'verifying' | 'verified' | 'error';\n /** The phone number in E.164 format, if successfully verified. */\n verifiedPhone: string | null;\n /** The user-entered phone (raw input, before normalization). */\n inputPhone: string;\n /** Country code (ISO-3166 alpha-2) for phone normalization. */\n countryCode: string;\n /** OTP entered by the user. */\n otp: string;\n /** Error message if verification failed. */\n error: string | null;\n /** Busy: waiting for server response. */\n loading: boolean;\n /** User chose \"Continue with test OTP\" — skip server verify when code is 123456. */\n testOtpMode: boolean;\n}\n\nexport interface PhoneVerificationActions {\n setCountryCode: (code: string) => void;\n setInputPhone: (phone: string) => void;\n setOtp: (code: string) => void;\n sendOtp: () => Promise<void>;\n verifyOtp: () => Promise<void>;\n continueWithTestOtp: () => void;\n resetToInput: () => void;\n clearError: () => void;\n}\n\nexport interface UsePhoneVerificationResult extends PhoneVerificationState, PhoneVerificationActions {}\n\n/**\n * Manages the phone verification lifecycle.\n *\n * Starts with phone input, sends OTP, then prompts for the code.\n * On success, `verifiedPhone` contains the E.164 number ready to become\n * a member ID.\n */\nexport function usePhoneVerification(defaultCountryCode?: string): UsePhoneVerificationResult {\n const [stage, setStage] = useState<PhoneVerificationState['stage']>('input');\n const [inputPhone, setInputPhone] = useState('');\n const [countryCode, setCountryCode] = useState(defaultCountryCode || 'US');\n const [otp, setOtp] = useState('');\n const [verifiedPhone, setVerifiedPhone] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [testOtpMode, setTestOtpMode] = useState(false);\n\n const [sendPhoneOtpMutation] = useSendPhoneOtpCodeMutation();\n const [verifyPhoneOtpMutation] = useVerifyPhoneOtpCodeMutation();\n\n const clearError = useCallback(() => setError(null), []);\n const { obtainSystemToken } = useObtainSystemToken();\n\n const resetToInput = useCallback(() => {\n setStage('input');\n setInputPhone('');\n setOtp('');\n setError(null);\n setVerifiedPhone(null);\n setTestOtpMode(false);\n }, []);\n\n const continueWithTestOtp = useCallback(() => {\n clearError();\n const normalized = formatPhoneNumber(inputPhone, countryCode);\n if (!normalized || !isValidPhoneNumber(normalized)) {\n setError('Please enter a valid mobile number');\n return;\n }\n setTestOtpMode(true);\n setOtp(CHAT_REGISTRATION_TEST_OTP);\n setStage('otp');\n }, [inputPhone, countryCode, clearError]);\n\n const sendOtp = useCallback(async () => {\n clearError();\n setTestOtpMode(false);\n const normalized = formatPhoneNumber(inputPhone, countryCode);\n\n if (!normalized || !isValidPhoneNumber(normalized)) {\n setError('Please enter a valid mobile number');\n return;\n }\n\n setLoading(true);\n try {\n const systemToken = await obtainSystemToken();\n if (!systemToken) throw new Error('Unable to obtain cdecli system token');\n\n const result = await sendPhoneOtpMutation({\n variables: { phoneNumber: { phoneNumber: normalized } },\n context: { headers: { 'x-cdecli-system-token': systemToken } },\n });\n\n if (!result.data?.sendPhoneOTPCode) throw new Error('Failed to send OTP');\n setOtp('');\n setStage('otp');\n setError(null);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to send OTP');\n } finally {\n setLoading(false);\n }\n }, [inputPhone, countryCode, sendPhoneOtpMutation, clearError, obtainSystemToken]);\n\n const verifyOtp = useCallback(async () => {\n clearError();\n\n const code = otp.replace(/\\D/g, '');\n if (!code || code.length !== 6) {\n setError('Please enter a valid 6-digit OTP');\n return;\n }\n\n const normalized = formatPhoneNumber(inputPhone, countryCode);\n if (!normalized) {\n setError('Please enter a valid phone number');\n return;\n }\n\n // Test path: skip server verify (explicit test flow or dev code 123456).\n const useTestBypass = testOtpMode || (canBypassOtpWithTestCode() && isChatTestOtpCode(code));\n if (useTestBypass && isChatTestOtpCode(code)) {\n setVerifiedPhone(normalized);\n setStage('verified');\n setTestOtpMode(false);\n setError(null);\n return;\n }\n\n setStage('verifying');\n setLoading(true);\n try {\n const systemToken = await obtainSystemToken();\n if (!systemToken) throw new Error('Unable to obtain cdecli system token');\n\n const result = await verifyPhoneOtpMutation({\n variables: { phoneNumber: { phoneNumber: normalized }, otp: code },\n context: { headers: { 'x-cdecli-system-token': systemToken } },\n });\n\n if (!result.data?.verifyPhoneOTPCode) throw new Error('Invalid or expired OTP');\n setVerifiedPhone(normalized);\n setStage('verified');\n setTestOtpMode(false);\n setError(null);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to verify OTP');\n setStage('otp');\n } finally {\n setLoading(false);\n }\n }, [otp, inputPhone, countryCode, testOtpMode, verifyPhoneOtpMutation, clearError, obtainSystemToken]);\n\n return {\n stage,\n verifiedPhone,\n inputPhone,\n countryCode,\n otp,\n error,\n loading,\n testOtpMode,\n setCountryCode,\n setInputPhone,\n setOtp,\n sendOtp,\n verifyOtp,\n continueWithTestOtp,\n resetToInput,\n clearError,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {useState,useCallback,useEffect,useMemo}from'react';import {useApolloClient,gql}from'@apollo/client/index.js';import AsyncStorage from'@react-native-async-storage/async-storage';import {YANTRA_CHAT_REGISTRATION_STATUS_QUERY,REGISTER_YANTRA_CHAT_MEMBER_MUTATION}from'./chatOperations.js';import {YANTRA_CHAT_PHONE_STORAGE_KEY}from'./chatRegistrationStorage.js';const REGISTRATION_STATUS_DOCUMENT = gql(YANTRA_CHAT_REGISTRATION_STATUS_QUERY);
|
|
2
|
+
const REGISTER_MEMBER_DOCUMENT = gql(REGISTER_YANTRA_CHAT_MEMBER_MUTATION);
|
|
3
|
+
function useYantraChatMembership(userId, displayName) {
|
|
4
|
+
const client = useApolloClient();
|
|
5
|
+
const [phoneE164, setPhoneE164] = useState(null);
|
|
6
|
+
const [organizationId, setOrganizationId] = useState(null);
|
|
7
|
+
const [loading, setLoading] = useState(true);
|
|
8
|
+
const [error, setError] = useState(null);
|
|
9
|
+
const refresh = useCallback(async () => {
|
|
10
|
+
var _a, _b, _c, _d;
|
|
11
|
+
if (!userId) {
|
|
12
|
+
setLoading(false);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
setError(null);
|
|
16
|
+
try {
|
|
17
|
+
const cached = await AsyncStorage.getItem(YANTRA_CHAT_PHONE_STORAGE_KEY);
|
|
18
|
+
if (cached) setPhoneE164(cached);
|
|
19
|
+
const res = await client.query({
|
|
20
|
+
query: REGISTRATION_STATUS_DOCUMENT,
|
|
21
|
+
fetchPolicy: "network-only"
|
|
22
|
+
});
|
|
23
|
+
if ((_a = res.errors) == null ? void 0 : _a.length) {
|
|
24
|
+
setError((_c = (_b = res.errors[0]) == null ? void 0 : _b.message) != null ? _c : "Could not load chat registration");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const status = (_d = res.data) == null ? void 0 : _d.yantraChatRegistrationStatus;
|
|
28
|
+
if ((status == null ? void 0 : status.registered) && status.phoneE164) {
|
|
29
|
+
setPhoneE164(status.phoneE164);
|
|
30
|
+
setOrganizationId(status.organizationId);
|
|
31
|
+
await AsyncStorage.setItem(YANTRA_CHAT_PHONE_STORAGE_KEY, status.phoneE164);
|
|
32
|
+
} else if (status && status.registered === false) {
|
|
33
|
+
setPhoneE164(null);
|
|
34
|
+
await AsyncStorage.removeItem(YANTRA_CHAT_PHONE_STORAGE_KEY);
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
setError(err instanceof Error ? err.message : "Could not load chat registration");
|
|
38
|
+
} finally {
|
|
39
|
+
setLoading(false);
|
|
40
|
+
}
|
|
41
|
+
}, [client, userId]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
void refresh();
|
|
44
|
+
}, [refresh]);
|
|
45
|
+
const register = useCallback(async (phone) => {
|
|
46
|
+
var _a;
|
|
47
|
+
if (!userId) throw new Error("Not signed in");
|
|
48
|
+
setError(null);
|
|
49
|
+
const res = await client.mutate({
|
|
50
|
+
mutation: REGISTER_MEMBER_DOCUMENT,
|
|
51
|
+
variables: {
|
|
52
|
+
phoneE164: phone,
|
|
53
|
+
displayName
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
const payload = (_a = res.data) == null ? void 0 : _a.registerYantraChatMember;
|
|
57
|
+
if (!(payload == null ? void 0 : payload.registered) || !payload.phoneE164) {
|
|
58
|
+
throw new Error("Registration did not complete");
|
|
59
|
+
}
|
|
60
|
+
setPhoneE164(payload.phoneE164);
|
|
61
|
+
setOrganizationId(payload.organizationId);
|
|
62
|
+
await AsyncStorage.setItem(YANTRA_CHAT_PHONE_STORAGE_KEY, payload.phoneE164);
|
|
63
|
+
return payload.phoneE164;
|
|
64
|
+
}, [client, userId, displayName]);
|
|
65
|
+
const needsRegistration = useMemo(() => Boolean(userId) && !loading && !phoneE164, [userId, loading, phoneE164]);
|
|
66
|
+
return {
|
|
67
|
+
phoneE164,
|
|
68
|
+
organizationId,
|
|
69
|
+
loading,
|
|
70
|
+
error,
|
|
71
|
+
needsRegistration,
|
|
72
|
+
register,
|
|
73
|
+
refresh
|
|
74
|
+
};
|
|
75
|
+
}export{useYantraChatMembership};//# sourceMappingURL=useYantraChatMembership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useYantraChatMembership.js","sources":["../../../src/features/messaging/useYantraChatMembership.ts"],"sourcesContent":["/**\n * Yantra Chat registration status + register mutation (issue #1312).\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { gql, useApolloClient } from '@apollo/client';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport { REGISTER_YANTRA_CHAT_MEMBER_MUTATION, YANTRA_CHAT_REGISTRATION_STATUS_QUERY } from './chatOperations';\nimport { YANTRA_CHAT_PHONE_STORAGE_KEY } from './chatRegistrationStorage';\n\nconst REGISTRATION_STATUS_DOCUMENT = gql(YANTRA_CHAT_REGISTRATION_STATUS_QUERY);\nconst REGISTER_MEMBER_DOCUMENT = gql(REGISTER_YANTRA_CHAT_MEMBER_MUTATION);\n\ninterface RegistrationPayload {\n registered: boolean;\n phoneE164: string | null;\n memberId: string | null;\n organizationId: string;\n}\n\nexport function useYantraChatMembership(userId: string | null, displayName: string) {\n const client = useApolloClient();\n const [phoneE164, setPhoneE164] = useState<string | null>(null);\n const [organizationId, setOrganizationId] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(async () => {\n if (!userId) {\n setLoading(false);\n return;\n }\n setError(null);\n try {\n const cached = await AsyncStorage.getItem(YANTRA_CHAT_PHONE_STORAGE_KEY);\n if (cached) setPhoneE164(cached);\n\n const res = await client.query<{ yantraChatRegistrationStatus?: RegistrationPayload }>({\n query: REGISTRATION_STATUS_DOCUMENT,\n fetchPolicy: 'network-only',\n });\n\n if (res.errors?.length) {\n setError(res.errors[0]?.message ?? 'Could not load chat registration');\n // Keep AsyncStorage + in-memory phone on transient GraphQL errors (Metro reload, backend restart).\n return;\n }\n\n const status = res.data?.yantraChatRegistrationStatus;\n if (status?.registered && status.phoneE164) {\n setPhoneE164(status.phoneE164);\n setOrganizationId(status.organizationId);\n await AsyncStorage.setItem(YANTRA_CHAT_PHONE_STORAGE_KEY, status.phoneE164);\n } else if (status && status.registered === false) {\n setPhoneE164(null);\n await AsyncStorage.removeItem(YANTRA_CHAT_PHONE_STORAGE_KEY);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Could not load chat registration');\n // Network failure: do not clear cached registration.\n } finally {\n setLoading(false);\n }\n }, [client, userId]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const register = useCallback(\n async (phone: string) => {\n if (!userId) throw new Error('Not signed in');\n setError(null);\n const res = await client.mutate<{ registerYantraChatMember?: RegistrationPayload }>({\n mutation: REGISTER_MEMBER_DOCUMENT,\n variables: { phoneE164: phone, displayName },\n });\n const payload = res.data?.registerYantraChatMember;\n if (!payload?.registered || !payload.phoneE164) {\n throw new Error('Registration did not complete');\n }\n setPhoneE164(payload.phoneE164);\n setOrganizationId(payload.organizationId);\n await AsyncStorage.setItem(YANTRA_CHAT_PHONE_STORAGE_KEY, payload.phoneE164);\n return payload.phoneE164;\n },\n [client, userId, displayName],\n );\n\n const needsRegistration = useMemo(() => Boolean(userId) && !loading && !phoneE164, [userId, loading, phoneE164]);\n\n return {\n phoneE164,\n organizationId,\n loading,\n error,\n needsRegistration,\n register,\n refresh,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {CHAT_WORKSPACE}from'common';const YANTRA_CHAT_ORG_SLUG = "yantra-chat";
|
|
2
|
+
CHAT_WORKSPACE.CHAT_ORGANIZATION_ID;
|
|
3
|
+
CHAT_WORKSPACE.CHAT_ORGANIZATION_UUID;
|
|
4
|
+
function isYantraChatOrgSlug(orgName) {
|
|
5
|
+
const trimmed = orgName == null ? void 0 : orgName.trim();
|
|
6
|
+
if (!trimmed) return false;
|
|
7
|
+
return trimmed === YANTRA_CHAT_ORG_SLUG;
|
|
8
|
+
}
|
|
9
|
+
function pickWorkspaceOrgSlug(orgs) {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
if (!(orgs == null ? void 0 : orgs.length)) return null;
|
|
12
|
+
const first = orgs.find((o) => {
|
|
13
|
+
const name = typeof (o == null ? void 0 : o.name) === "string" ? o.name.trim() : "";
|
|
14
|
+
return name.length > 0 && !isYantraChatOrgSlug(name);
|
|
15
|
+
});
|
|
16
|
+
return (_b = (_a = first == null ? void 0 : first.name) == null ? void 0 : _a.trim()) != null ? _b : null;
|
|
17
|
+
}export{YANTRA_CHAT_ORG_SLUG,isYantraChatOrgSlug,pickWorkspaceOrgSlug};//# sourceMappingURL=yantraChatOrg.js.map
|