From fc69736975f1b73a104db81f3294a2ce7c9c0e16 Mon Sep 17 00:00:00 2001 From: nodirbek75 Date: Sat, 20 Sep 2025 21:49:48 +0500 Subject: [PATCH 1/2] add all the changes --- android/app/src/main/AndroidManifest.xml | 7 + app/app.tsx | 5 +- app/assets/illustrations/send-success.svg | 21 + app/assets/images/heart-symbol.png | Bin 0 -> 143398 bytes .../contact-picker/contact-picker.tsx | 445 +++++++++++++++ app/components/contact-picker/index.ts | 1 + app/components/home-screen/QuickStart.tsx | 35 +- app/components/input/EmailInput.tsx | 58 ++ app/components/input/PhoneNumberInput.tsx | 138 +++++ app/components/input/index.ts | 4 + app/graphql/front-end-mutations.ts | 25 + app/graphql/front-end-queries.ts | 10 + app/i18n/en/index.ts | 16 +- app/i18n/i18n-types.ts | 89 ++- app/i18n/raw-i18n/source/en.json | 16 +- .../navigation-container-wrapper.tsx | 11 + app/navigation/root-navigator.tsx | 12 + app/navigation/stack-param-lists.ts | 24 +- app/screens/authentication-screen/welcome.tsx | 17 +- .../get-started-screen/get-started-screen.tsx | 26 +- app/screens/index.ts | 2 + .../invite-friend/HandleInviteDeepLink.tsx | 172 ++++++ .../invite-friend/InviteDeepLinkHandler.tsx | 9 + app/screens/invite-friend/InviteFriend.tsx | 510 ++++++++++++++++++ .../invite-friend/InviteFriendSuccess.tsx | 64 +++ app/screens/invite-friend/index.ts | 4 + .../phone-auth-screen/phone-login-input.tsx | 103 +++- .../phone-registration-input.tsx | 101 +++- .../request-phone-code-login.ts | 79 ++- .../request-phone-code-registration.ts | 8 +- .../settings-screen/settings-screen.tsx | 3 +- .../settings/invite-friend.tsx | 24 + ios/LNFlash.xcodeproj/project.pbxproj | 4 + ios/LNFlash/Info.plist | 2 + ios/Podfile | 12 + ios/Podfile.lock | 373 ++++++------- package.json | 1 + yarn.lock | 5 + 38 files changed, 2226 insertions(+), 210 deletions(-) create mode 100644 app/assets/illustrations/send-success.svg create mode 100644 app/assets/images/heart-symbol.png create mode 100644 app/components/contact-picker/contact-picker.tsx create mode 100644 app/components/contact-picker/index.ts create mode 100644 app/components/input/EmailInput.tsx create mode 100644 app/components/input/PhoneNumberInput.tsx create mode 100644 app/components/input/index.ts create mode 100644 app/screens/invite-friend/HandleInviteDeepLink.tsx create mode 100644 app/screens/invite-friend/InviteDeepLinkHandler.tsx create mode 100644 app/screens/invite-friend/InviteFriend.tsx create mode 100644 app/screens/invite-friend/InviteFriendSuccess.tsx create mode 100644 app/screens/invite-friend/index.ts create mode 100644 app/screens/settings-screen/settings/invite-friend.tsx diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 2524f9558..7fabb373d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + @@ -35,6 +36,12 @@ + + + + + + diff --git a/app/app.tsx b/app/app.tsx index cf35c1d7e..2a36f82ad 100644 --- a/app/app.tsx +++ b/app/app.tsx @@ -45,6 +45,7 @@ import { NotificationsProvider } from "./components/notification" import { SafeAreaProvider } from "react-native-safe-area-context" import { FlashcardProvider } from "./contexts/Flashcard" import { NostrGroupChatProvider } from "./screens/chat/GroupChat/GroupChatProvider" +import { InviteDeepLinkHandler } from "./screens/invite-friend/InviteDeepLinkHandler" // FIXME should we only load the currently used local? // this would help to make the app load faster @@ -87,7 +88,9 @@ export const App = () => ( - + + + diff --git a/app/assets/illustrations/send-success.svg b/app/assets/illustrations/send-success.svg new file mode 100644 index 000000000..67572122b --- /dev/null +++ b/app/assets/illustrations/send-success.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/heart-symbol.png b/app/assets/images/heart-symbol.png new file mode 100644 index 0000000000000000000000000000000000000000..089e9252bd478787a5e99828dce0d56ba6fe9a13 GIT binary patch literal 143398 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 void + onSelectContact: (value: string, type: "phone" | "email") => void +} + +export const ContactPicker: React.FC = ({ + visible, + onClose, + onSelectContact, +}) => { + const styles = useStyles() + const { theme } = useTheme() + const { LL } = useI18nContext() + + const [contacts, setContacts] = useState([]) + const [filteredContacts, setFilteredContacts] = useState([]) + const [searchText, setSearchText] = useState("") + const [loading, setLoading] = useState(false) + const [permissionGranted, setPermissionGranted] = useState(false) + + // Request permission and load contacts when modal opens + useEffect(() => { + if (visible) { + checkAndRequestPermission() + } + }, [visible]) + + const checkAndRequestPermission = async () => { + try { + const permission = Platform.select({ + ios: PERMISSIONS.IOS.CONTACTS, + android: PERMISSIONS.ANDROID.READ_CONTACTS, + }) + + if (!permission) return + + const result = await check(permission) + + if (result === RESULTS.GRANTED) { + setPermissionGranted(true) + loadContacts() + } else if (result === RESULTS.BLOCKED) { + // Permission was previously denied and can't be requested + // On iOS, we can open settings + Alert.alert( + LL.common.permissionDenied?.() || "Permission Denied", + LL.common.contactsPermissionDeniedMessage?.() || + "Contacts permission has been denied. Please enable it in Settings.", + [ + { text: LL.common.cancel?.() || "Cancel", onPress: onClose, style: "cancel" }, + { + text: LL.common.openSettings?.() || "Open Settings", + onPress: () => { + openSettings().catch(() => { + console.warn("Cannot open settings") + }) + onClose() + }, + }, + ], + ) + } else { + // Request permission - this should show the native dialog + const requestResult = await request(permission) + + if (requestResult === RESULTS.GRANTED) { + setPermissionGranted(true) + loadContacts() + } else if (requestResult === RESULTS.BLOCKED) { + // User denied and selected "Don't ask again" or permission is blocked + Alert.alert( + LL.common.permissionDenied?.() || "Permission Denied", + LL.common.contactsPermissionDeniedMessage?.() || + "Contacts permission has been denied. Please enable it in Settings.", + [ + { + text: LL.common.cancel?.() || "Cancel", + onPress: onClose, + style: "cancel", + }, + { + text: LL.common.openSettings?.() || "Open Settings", + onPress: () => { + openSettings().catch(() => { + console.warn("Cannot open settings") + }) + onClose() + }, + }, + ], + ) + } else { + // User denied but can ask again later + onClose() + } + } + } catch (error) { + console.error("Error checking permissions:", error) + Alert.alert( + LL.common.error?.() || "Error", + "Failed to check permissions. Please try again.", + ) + } + } + + const loadContacts = async () => { + setLoading(true) + try { + Contacts.getAll() + .then((contactsList) => { + // Filter contacts with phone numbers or email addresses and sort alphabetically + const contactsWithContactInfo = contactsList + .filter( + (contact) => + (contact.phoneNumbers && contact.phoneNumbers.length > 0) || + (contact.emailAddresses && contact.emailAddresses.length > 0), + ) + .map((contact) => ({ + givenName: contact.givenName || "", + familyName: contact.familyName || "", + phoneNumbers: + contact.phoneNumbers?.map((phone) => ({ + label: phone.label || "mobile", + number: phone.number, + })) || [], + emailAddresses: + contact.emailAddresses?.map((email) => ({ + label: email.label || "personal", + email: email.email, + })) || [], + recordID: contact.recordID, + })) + .sort((a, b) => { + const nameA = `${a.givenName} ${a.familyName}`.toLowerCase() + const nameB = `${b.givenName} ${b.familyName}`.toLowerCase() + return nameA.localeCompare(nameB) + }) + + setContacts(contactsWithContactInfo) + setFilteredContacts(contactsWithContactInfo) + }) + .catch((error) => { + console.error("Error loading contacts:", error) + Alert.alert( + LL.common.error?.() || "Error", + LL.common.errorLoadingContacts?.() || + "Failed to load contacts. Please try again.", + ) + }) + } finally { + setLoading(false) + } + } + + const handleSearch = useCallback( + (text: string) => { + setSearchText(text) + if (text.trim() === "") { + setFilteredContacts(contacts) + } else { + const filtered = contacts.filter((contact) => { + const fullName = `${contact.givenName} ${contact.familyName}`.toLowerCase() + const searchLower = text.toLowerCase() + return ( + fullName.includes(searchLower) || + contact.phoneNumbers.some((phone) => + phone.number.replace(/\D/g, "").includes(text.replace(/\D/g, "")), + ) || + contact.emailAddresses.some((email) => + email.email.toLowerCase().includes(searchLower), + ) + ) + }) + setFilteredContacts(filtered) + } + }, + [contacts], + ) + + const handleSelectContact = (contact: Contact) => { + const totalPhones = contact.phoneNumbers.length + const totalEmails = contact.emailAddresses.length + const totalOptions = totalPhones + totalEmails + + // Case a: Only one phone number and no email + if (totalPhones === 1 && totalEmails === 0) { + onSelectContact(contact.phoneNumbers[0].number, "phone") + onClose() + return + } + + // Case e: No phone numbers and only one email + if (totalPhones === 0 && totalEmails === 1) { + onSelectContact(contact.emailAddresses[0].email, "email") + onClose() + return + } + + // For all other cases, show selection dialog + const options = [] + + // Add phone numbers to options + contact.phoneNumbers.forEach((phone) => { + options.push({ + text: `📱 ${phone.label}: ${phone.number}`, + onPress: () => { + onSelectContact(phone.number, "phone") + onClose() + }, + }) + }) + + // Add email addresses to options + contact.emailAddresses.forEach((email) => { + options.push({ + text: `✉️ ${email.label}: ${email.email}`, + onPress: () => { + onSelectContact(email.email, "email") + onClose() + }, + }) + }) + + // Add cancel button + options.push({ text: LL.common.cancel?.() || "Cancel", style: "cancel" }) + + // Show the selection dialog + Alert.alert( + LL.common.selectContactMethod?.() || "Select Contact Method", + undefined, + options, + ) + } + + const renderContact = ({ item }: { item: Contact }) => { + const fullName = `${item.givenName} ${item.familyName}`.trim() + + // Build display text for contact methods + let contactDisplay = "" + const totalContacts = item.phoneNumbers.length + item.emailAddresses.length + + if (totalContacts === 1) { + // Show the single contact method + if (item.phoneNumbers.length === 1) { + contactDisplay = item.phoneNumbers[0].number + } else if (item.emailAddresses.length === 1) { + contactDisplay = item.emailAddresses[0].email + } + } else { + // Show count of contact methods + const parts = [] + if (item.phoneNumbers.length > 0) { + parts.push( + `${item.phoneNumbers.length} phone${item.phoneNumbers.length > 1 ? "s" : ""}`, + ) + } + if (item.emailAddresses.length > 0) { + parts.push( + `${item.emailAddresses.length} email${ + item.emailAddresses.length > 1 ? "s" : "" + }`, + ) + } + contactDisplay = parts.join(", ") + } + + return ( + handleSelectContact(item)} + bottomDivider + containerStyle={styles.contactItem} + > + + {fullName} + + {contactDisplay} + + + + + ) + } + + return ( + + + + + + + + {LL.common.selectContact?.() || "Select Contact"} + + + + + + + {loading ? ( + + + + ) : ( + item.recordID} + contentContainerStyle={styles.listContainer} + ListEmptyComponent={ + + + {searchText + ? LL.common.noContactsFound?.() || "No contacts found" + : LL.common.noContactsWithPhone?.() || + "No contacts with phone numbers"} + + + } + /> + )} + + + ) +} + +const useStyles = makeStyles(({ colors }) => ({ + container: { + flex: 1, + backgroundColor: colors.background, + }, + header: { + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between", + paddingHorizontal: 16, + paddingVertical: 12, + borderBottomWidth: 1, + borderBottomColor: colors.divider, + }, + closeButton: { + width: 40, + height: 40, + justifyContent: "center", + alignItems: "center", + }, + title: { + flex: 1, + textAlign: "center", + }, + searchContainer: { + backgroundColor: "transparent", + borderTopWidth: 0, + borderBottomWidth: 1, + borderBottomColor: colors.divider, + }, + searchInputContainer: { + backgroundColor: colors.searchBg || colors.grey5, + }, + listContainer: { + flexGrow: 1, + }, + contactItem: { + backgroundColor: colors.background, + }, + contactName: { + fontSize: 16, + fontWeight: "500", + color: colors.black, + }, + contactPhone: { + fontSize: 14, + color: colors.grey3, + marginTop: 4, + }, + loadingContainer: { + flex: 1, + justifyContent: "center", + alignItems: "center", + }, + emptyContainer: { + flex: 1, + justifyContent: "center", + alignItems: "center", + paddingVertical: 50, + }, + emptyText: { + fontSize: 16, + color: colors.grey3, + textAlign: "center", + }, +})) diff --git a/app/components/contact-picker/index.ts b/app/components/contact-picker/index.ts new file mode 100644 index 000000000..9da42e7f4 --- /dev/null +++ b/app/components/contact-picker/index.ts @@ -0,0 +1 @@ +export * from "./contact-picker" diff --git a/app/components/home-screen/QuickStart.tsx b/app/components/home-screen/QuickStart.tsx index 129de243d..5d7771fd9 100644 --- a/app/components/home-screen/QuickStart.tsx +++ b/app/components/home-screen/QuickStart.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useState } from "react" -import { Dimensions, Linking, TouchableOpacity, View } from "react-native" +import { Dimensions, Linking, TouchableOpacity, View, Image } from "react-native" import { StackNavigationProp } from "@react-navigation/stack" import Carousel from "react-native-reanimated-carousel" import { Icon, makeStyles, Text, useTheme } from "@rneui/themed" @@ -13,6 +13,7 @@ import Flashcard from "@app/assets/icons/empty-flashcard.svg" import NonCustodialWallet from "@app/assets/illustrations/non-custodial-wallet.svg" import GoldWallet from "@app/assets/illustrations/gold-wallet.svg" import SecureWallet from "@app/assets/illustrations/secure-wallet.svg" +import FriendsIcon from "@app/assets/images/heart-symbol.png" // components import { UpgradeAccountModal } from "../upgrade-account-modal" @@ -64,6 +65,13 @@ const QuickStart = () => { } let carouselData = [ + { + type: "invite", + title: LL.HomeScreen.inviteTitle?.() || "Invite Friends", + description: LL.HomeScreen.inviteDesc?.() || "Get for inviting friends to Flash", + image: FriendsIcon, + onPress: () => navigation.navigate("InviteFriend"), + }, { type: "upgrade", title: LL.HomeScreen.upgradeTitle(), @@ -120,6 +128,9 @@ const QuickStart = () => { }, ] + if (persistentState?.closedQuickStartTypes?.includes("invite")) { + carouselData = carouselData.filter((el) => el.type !== "invite") + } if ( data?.me?.defaultAccount.level !== AccountLevel.Zero || persistentState?.closedQuickStartTypes?.includes("upgrade") @@ -177,10 +188,20 @@ const QuickStart = () => { } const renderItem = ({ item, index }: RenderItemProps) => { - const Image = item.image + const ImageOrAsset = item.image + const isAsset = typeof ImageOrAsset === "number" + const isHeartIcon = item.type === "invite" && isAsset + return ( - + {isAsset ? ( + + ) : ( + + )} {item.title} @@ -245,6 +266,14 @@ const useStyles = makeStyles(({ colors }) => ({ right: 0, padding: 5, }, + imageStyle: { + width: width / 3, + height: width / 3, + resizeMode: "contain", + }, + heartIconRotation: { + transform: [{ rotate: "-25deg" }], + }, })) export default QuickStart diff --git a/app/components/input/EmailInput.tsx b/app/components/input/EmailInput.tsx new file mode 100644 index 000000000..1d9929e08 --- /dev/null +++ b/app/components/input/EmailInput.tsx @@ -0,0 +1,58 @@ +import React from "react" +import { View } from "react-native" +import { Input, makeStyles, Text } from "@rneui/themed" + +type Props = { + title: string + email?: string + setEmail: (val: string) => void +} + +const EmailInput: React.FC = ({ title, email, setEmail }) => { + const styles = useStyles() + + return ( + + + {title} + + + + + + ) +} + +export default EmailInput + +const useStyles = makeStyles(({ colors }) => ({ + wrapper: {}, + header: { + marginBottom: 5, + }, + inputContainer: { + flexDirection: "row", + marginBottom: 10, + }, + inputComponentContainerStyle: { + flex: 1, + paddingLeft: 0, + paddingRight: 0, + }, + inputContainerStyle: { + borderWidth: 1, + borderRadius: 10, + borderColor: colors.border02, + paddingHorizontal: 10, + }, +})) diff --git a/app/components/input/PhoneNumberInput.tsx b/app/components/input/PhoneNumberInput.tsx new file mode 100644 index 000000000..7ee0dc00f --- /dev/null +++ b/app/components/input/PhoneNumberInput.tsx @@ -0,0 +1,138 @@ +import React, { useMemo } from "react" +import { TouchableOpacity, View } from "react-native" +import { Input, makeStyles, Text, useTheme } from "@rneui/themed" +import { + CountryCode as PhoneNumberCountryCode, + getCountryCallingCode, +} from "libphonenumber-js/mobile" +import CountryPicker, { + DARK_THEME, + DEFAULT_THEME, + Flag, + CountryCode, +} from "react-native-country-picker-modal" +import { PhoneCodeChannelType, useSupportedCountriesQuery } from "@app/graphql/generated" + +const DEFAULT_COUNTRY_CODE = "JM" +const PLACEHOLDER_PHONE_NUMBER = "876-555-7890" + +type Props = { + title: string + countryCode?: CountryCode + phoneNumber?: string + setCountryCode: (countryCode: CountryCode) => void + setPhoneNumber: (val: string) => void +} + +const PhoneNumberInput: React.FC = ({ + title, + countryCode, + phoneNumber, + setCountryCode, + setPhoneNumber, +}) => { + const styles = useStyles() + const { mode } = useTheme().theme + + const { data, loading } = useSupportedCountriesQuery() + const { isWhatsAppSupported, isSmsSupported, supportedCountries } = useMemo(() => { + const currentCountry = data?.globals?.supportedCountries.find( + (country) => country.id === countryCode, + ) + + const supportedCountries = (data?.globals?.supportedCountries.map( + (country) => country.id, + ) || []) as CountryCode[] + + const isWhatsAppSupported = + currentCountry?.supportedAuthChannels.includes(PhoneCodeChannelType.Whatsapp) || + false + const isSmsSupported = + currentCountry?.supportedAuthChannels.includes(PhoneCodeChannelType.Sms) || false + + return { + isWhatsAppSupported, + isSmsSupported, + supportedCountries, + } + }, [data?.globals, countryCode]) + + return ( + + + {title} + + + setCountryCode(country.cca2)} + renderFlagButton={({ countryCode, onOpen }) => + countryCode && ( + + + + +{getCountryCallingCode(countryCode as PhoneNumberCountryCode)} + + + ) + } + withCallingCodeButton={true} + withFilter={true} + withCallingCode={true} + filterProps={{ + autoFocus: true, + }} + /> + + + + ) +} + +export default PhoneNumberInput + +const useStyles = makeStyles(({ colors }) => ({ + wrapper: { + marginBottom: 10, + }, + header: { + marginBottom: 5, + }, + inputContainer: { + flexDirection: "row", + marginBottom: 10, + }, + countryPickerButtonStyle: { + flexDirection: "row", + alignItems: "center", + justifyContent: "center", + borderWidth: 1, + borderRadius: 10, + borderColor: colors.border02, + paddingHorizontal: 10, + }, + inputComponentContainerStyle: { + flex: 1, + marginLeft: 10, + paddingLeft: 0, + paddingRight: 0, + }, + inputContainerStyle: { + borderWidth: 1, + borderRadius: 10, + borderColor: colors.border02, + paddingHorizontal: 10, + }, +})) diff --git a/app/components/input/index.ts b/app/components/input/index.ts new file mode 100644 index 000000000..b76af91ba --- /dev/null +++ b/app/components/input/index.ts @@ -0,0 +1,4 @@ +import PhoneNumberInput from "./PhoneNumberInput" +import EmailInput from "./EmailInput" + +export { PhoneNumberInput, EmailInput } diff --git a/app/graphql/front-end-mutations.ts b/app/graphql/front-end-mutations.ts index 9f3cf05ad..16aa270be 100644 --- a/app/graphql/front-end-mutations.ts +++ b/app/graphql/front-end-mutations.ts @@ -195,3 +195,28 @@ gql` } } ` + +gql` + mutation createInvite($input: CreateInviteInput!) { + createInvite(input: $input) { + invite { + id + contact + method + status + createdAt + expiresAt + } + errors + } + } +` + +gql` + mutation redeemInvite($input: RedeemInviteInput!) { + redeemInvite(input: $input) { + success + errors + } + } +` diff --git a/app/graphql/front-end-queries.ts b/app/graphql/front-end-queries.ts index 80f42b50e..c9886016c 100644 --- a/app/graphql/front-end-queries.ts +++ b/app/graphql/front-end-queries.ts @@ -282,4 +282,14 @@ gql` denominatorCurrency } } + + query invitePreview($token: String!) { + invitePreview(token: $token) { + contact + method + isValid + inviterUsername + expiresAt + } + } ` diff --git a/app/i18n/en/index.ts b/app/i18n/en/index.ts index e627b6aca..0268c02a4 100644 --- a/app/i18n/en/index.ts +++ b/app/i18n/en/index.ts @@ -552,6 +552,8 @@ const en: BaseTranslation = { addFlashcard: "Add Flashcard", upgradeTitle: "Add your phone number", upgradeDesc: "Backup your cash wallet and increase transaction limits.", + inviteTitle: "Invite Friends", + inviteDesc: "Get rewards for inviting friends to Flash", currencyTitle:"Change to your local currency", currencyDesc: "Review our available currency list and select your currency.", flashcardTitle: "Get a Flashcard", @@ -835,7 +837,19 @@ const en: BaseTranslation = { advanceMode: "Enable Bitcoin Account (Advanced Mode)", keysManagement: "Key management", showBtcAccount: "Show Bitcoin account", - hideBtcAccount: "Hide Bitcoin account" + hideBtcAccount: "Hide Bitcoin account", + inviteFriend: "Invite a friend" + }, + InviteFriend: { + invitation: "Invitation", + title: "Invite a friend to Flash!", + subtitle: "Enter a phone number or email address to invite a friend. By inviting a friend, you confirm that the recipient has given consent to receive this invitation.", + phoneNumber: "Enter phone number", + email: "Enter email address", + invite: "Invite", + or: "OR", + invitationSuccessTitle: "Invitation has been sent to {value: string}", + done: "Done" }, NotificationSettingsScreen: { title: "Notification Settings", diff --git a/app/i18n/i18n-types.ts b/app/i18n/i18n-types.ts index 67d0e2ca8..c74cef34f 100644 --- a/app/i18n/i18n-types.ts +++ b/app/i18n/i18n-types.ts @@ -2708,7 +2708,7 @@ type RootTranslation = { */ advanceMode: string /** - * K​e​y​s​ ​m​a​n​a​g​e​m​e​n​t + * K​e​y​​ ​m​a​n​a​g​e​m​e​n​t */ keysManagement: string /** @@ -2719,6 +2719,49 @@ type RootTranslation = { * H​i​d​e​ ​B​i​t​c​o​i​n​ ​a​c​c​o​u​n​t */ hideBtcAccount: string + /** + * I​n​v​i​t​e​ ​a​ ​f​r​i​e​n​d + */ + inviteFriend: string + } + InviteFriend: { + /** + * I​n​v​i​t​a​t​i​o​n + */ + invitation: string + /** + * I​n​v​i​t​e​ ​a​ ​f​r​i​e​n​d​ ​t​o​ ​F​l​a​s​h​! + */ + title: string + /** + * E​n​t​e​r​ ​a​ ​p​h​o​n​e​ ​n​u​m​b​e​r​ ​o​r​ ​e​m​a​i​l​ ​a​d​d​r​e​s​s​ ​t​o​ ​i​n​v​i​t​e​ ​a​ ​f​r​i​e​n​d​. + */ + subtitle: string + /** + * E​n​t​e​r​ ​p​h​o​n​e​ ​n​u​m​b​e​r + */ + phoneNumber: string + /** + * E​n​t​e​r​ ​e​m​a​i​l​ ​a​d​d​r​e​s​s + */ + email: string + /** + * I​n​v​i​t​e + */ + invite: string + /** + * O​R + */ + or: string + /** + * I​n​v​i​t​a​t​i​o​n​ ​h​a​s​ ​b​e​e​n​ ​s​e​n​t​ ​t​o​ ​{​v​a​l​u​e​} + * @param {string} value + */ + invitationSuccessTitle: RequiredParams<'value'> + /** + * D​o​n​e + */ + done: string } NotificationSettingsScreen: { /** @@ -7401,7 +7444,7 @@ export type TranslationFunctions = { */ advanceMode: () => LocalizedString /** - * Keys management + * Key management */ keysManagement: () => LocalizedString /** @@ -7412,6 +7455,48 @@ export type TranslationFunctions = { * Hide Bitcoin account */ hideBtcAccount: () => LocalizedString + /** + * Invite a friend + */ + inviteFriend: () => LocalizedString + } + InviteFriend: { + /** + * Invitation + */ + invitation: () => LocalizedString + /** + * Invite a friend to Flash! + */ + title: () => LocalizedString + /** + * Enter a phone number or email address to invite a friend. + */ + subtitle: () => LocalizedString + /** + * Enter phone number + */ + phoneNumber: () => LocalizedString + /** + * Enter email address + */ + email: () => LocalizedString + /** + * Invite + */ + invite: () => LocalizedString + /** + * OR + */ + or: () => LocalizedString + /** + * Invitation has been sent to {value} + */ + invitationSuccessTitle: (arg: { value: string }) => LocalizedString + /** + * Done + */ + done: () => LocalizedString } NotificationSettingsScreen: { /** diff --git a/app/i18n/raw-i18n/source/en.json b/app/i18n/raw-i18n/source/en.json index 1416165e3..63d82909e 100644 --- a/app/i18n/raw-i18n/source/en.json +++ b/app/i18n/raw-i18n/source/en.json @@ -461,7 +461,7 @@ "unlockQuestion": "To unlock, answer the question:", "youEarned": "You Earned", "registerTitle": "Need to upgrade your account", - "registerContent": "Register with your phone number to receive bitcoin" + "registerContent": "Register with your phone number to receive sats" }, "GetStartedScreen": { "logInCreateAccount": "Log in / create account", @@ -772,7 +772,19 @@ "advanceMode": "Enable Bitcoin Account (Advanced Mode)", "keysManagement": "Key management", "showBtcAccount": "Show Bitcoin account", - "hideBtcAccount": "Hide Bitcoin account" + "hideBtcAccount": "Hide Bitcoin account", + "inviteFriend": "Invite a friend" + }, + "InviteFriend": { + "invitation": "Invitation", + "title": "Invite a friend to Flash!", + "subtitle": "Enter a phone number or email address to invite a friend.", + "phoneNumber": "Enter phone number", + "email": "Enter email address", + "invite": "Invite", + "or": "OR", + "invitationSuccessTitle": "Invitation has been sent to {value: string}", + "done": "Done" }, "NotificationSettingsScreen": { "title": "Notification Settings", diff --git a/app/navigation/navigation-container-wrapper.tsx b/app/navigation/navigation-container-wrapper.tsx index a093e123e..275c21658 100644 --- a/app/navigation/navigation-container-wrapper.tsx +++ b/app/navigation/navigation-container-wrapper.tsx @@ -89,10 +89,16 @@ export const NavigationContainerWrapper: React.FC = ({ Home: "/", }, }, + // Don't map invite URLs to any specific screen + // Let the InviteDeepLinkHandler handle them }, }, getInitialURL: async () => { const url = await Linking.getInitialURL() + // Don't let the navigation container handle invite URLs + if (url && url.includes("invite")) { + return null + } if (Boolean(url) && isAuthed && !isAppLocked) { return url } @@ -102,6 +108,11 @@ export const NavigationContainerWrapper: React.FC = ({ console.log("listener", listener) const onReceiveURL = ({ url }: { url: string }) => { console.log("onReceiveURL", url) + // Don't let the navigation container handle invite URLs + if (url && url.includes("invite")) { + console.log("Skipping invite URL in navigation container") + return + } listener(url) } // Listen to incoming links from deep linking diff --git a/app/navigation/root-navigator.tsx b/app/navigation/root-navigator.tsx index 242d9827c..f796c5509 100644 --- a/app/navigation/root-navigator.tsx +++ b/app/navigation/root-navigator.tsx @@ -87,6 +87,8 @@ import { TransactionHistoryTabs, USDTransactionHistory, SignInViaQRCode, + InviteFriend, + InviteFriendSuccess, } from "@app/screens" import { usePersistentStateContext } from "@app/store/persistent-state" import { NotificationSettingsScreen } from "@app/screens/settings-screen/notifications-screen" @@ -581,6 +583,16 @@ export const RootStack = () => { component={SupportGroupChatScreen} options={{ title: "Group Chat" }} /> + + ) } diff --git a/app/navigation/stack-param-lists.ts b/app/navigation/stack-param-lists.ts index 24979442f..1cb5a3441 100644 --- a/app/navigation/stack-param-lists.ts +++ b/app/navigation/stack-param-lists.ts @@ -20,7 +20,12 @@ import { NavigatorScreenParams } from "@react-navigation/native" export type RootStackParamList = { Reconciliation: { from: string; to: string } - getStarted: undefined + getStarted?: { + inviteToken?: string + prefilledContact?: string + contactMethod?: string + inviterUsername?: string + } UsernameSet?: { insideApp?: boolean } Welcome: undefined welcomeFirst: undefined @@ -104,7 +109,11 @@ export type RootStackParamList = { lnurl: string } phoneFlow?: NavigatorScreenParams - phoneRegistrationInitiate: undefined + phoneRegistrationInitiate?: { + inviteToken?: string + prefilledPhone?: string + inviterUsername?: string + } phoneRegistrationValidate: { phone: string channel: PhoneCodeChannelType @@ -120,7 +129,11 @@ export type RootStackParamList = { accountScreen: undefined notificationSettingsScreen: undefined transactionLimitsScreen: undefined - emailRegistrationInitiate: undefined + emailRegistrationInitiate?: { + inviteToken?: string + prefilledEmail?: string + inviterUsername?: string + } emailRegistrationValidate: { email: string; emailRegistrationId: string } emailLoginInitiate: undefined emailLoginValidate: { email: string; emailLoginId: string } @@ -152,6 +165,11 @@ export type RootStackParamList = { NostrSettingsScreen: undefined SignInViaQRCode: undefined Nip29GroupChat: { groupId: string } + InviteFriend: undefined + InviteFriendSuccess?: { + contact: string + method: string + } } export type ChatStackParamList = { diff --git a/app/screens/authentication-screen/welcome.tsx b/app/screens/authentication-screen/welcome.tsx index dd9ab4068..452dd9e6a 100644 --- a/app/screens/authentication-screen/welcome.tsx +++ b/app/screens/authentication-screen/welcome.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React, { useEffect } from "react" import { Text, Image, View } from "react-native" import { makeStyles, useTheme } from "@rneui/themed" import * as Animatable from "react-native-animatable" @@ -11,7 +11,8 @@ import AppLogo from "../../assets/logo/blink-logo-icon.png" // hooks import { useIsAuthed } from "@app/graphql/is-authed-context" -import { useAuthQuery } from "@app/graphql/generated" +import { useAuthQuery, useRedeemInviteMutation } from "@app/graphql/generated" +import { redeemPendingInvite } from "../invite-friend/HandleInviteDeepLink" // components import { PrimaryBtn } from "@app/components/buttons" @@ -24,6 +25,18 @@ export const Welcome: React.FC = ({ navigation }) => { const { colors } = useTheme().theme const { data } = useAuthQuery({ skip: !isAuthed }) + const [redeemInviteMutation] = useRedeemInviteMutation() + + useEffect(() => { + // Check and redeem pending invite when user reaches Welcome screen + if (isAuthed) { + redeemPendingInvite(redeemInviteMutation, true).then((result) => { + if (result.success) { + console.log("Invite redeemed successfully after onboarding") + } + }) + } + }, [isAuthed, redeemInviteMutation]) const onPressStart = () => { navigation.reset({ diff --git a/app/screens/get-started-screen/get-started-screen.tsx b/app/screens/get-started-screen/get-started-screen.tsx index d04ec929e..85bbe7bcf 100644 --- a/app/screens/get-started-screen/get-started-screen.tsx +++ b/app/screens/get-started-screen/get-started-screen.tsx @@ -30,7 +30,7 @@ const width = Dimensions.get("screen").width type Props = StackScreenProps -export const GetStartedScreen: React.FC = ({ navigation }) => { +export const GetStartedScreen: React.FC = ({ navigation, route }) => { const isFocused = useIsFocused() const { mode, colors } = useTheme().theme const { LL } = useI18nContext() @@ -43,6 +43,9 @@ export const GetStartedScreen: React.FC = ({ navigation }) => { const [error, setError] = useState(false) const [secretMenuCounter, setSecretMenuCounter] = useState(0) + const { inviteToken, prefilledContact, contactMethod, inviterUsername } = + route.params || {} + const AppLogo = mode === "dark" ? AppLogoDarkMode : AppLogoLightMode useEffect(() => { @@ -77,7 +80,26 @@ export const GetStartedScreen: React.FC = ({ navigation }) => { routes: [{ name: "authenticationCheck" }], }) } else { - navigation.navigate("phoneFlow") + // If we have an invite token, go to phone registration instead of login + if (inviteToken && prefilledContact) { + if (contactMethod === "EMAIL") { + navigation.navigate("emailRegistrationInitiate", { + inviteToken, + prefilledEmail: prefilledContact, + inviterUsername, + }) + } else { + // For SMS or WHATSAPP + navigation.navigate("phoneRegistrationInitiate", { + inviteToken, + prefilledPhone: prefilledContact, + inviterUsername, + }) + } + } else { + // No invite, go to normal phone login flow + navigation.navigate("phoneFlow") + } } } diff --git a/app/screens/index.ts b/app/screens/index.ts index 35a694751..ca17be404 100644 --- a/app/screens/index.ts +++ b/app/screens/index.ts @@ -1,3 +1,5 @@ export * from "./backup-screen" export * from "./import-wallet-screen" export * from "./transaction-history" +export * from "./settings-screen" +export * from "./invite-friend" diff --git a/app/screens/invite-friend/HandleInviteDeepLink.tsx b/app/screens/invite-friend/HandleInviteDeepLink.tsx new file mode 100644 index 000000000..bff13b2ed --- /dev/null +++ b/app/screens/invite-friend/HandleInviteDeepLink.tsx @@ -0,0 +1,172 @@ +import { useEffect } from "react" +import { Linking, Alert } from "react-native" +import { useNavigation, NavigationProp } from "@react-navigation/native" +import { + useRedeemInviteMutation, + useInvitePreviewLazyQuery, +} from "@app/graphql/generated" +import AsyncStorage from "@react-native-async-storage/async-storage" +import { useIsAuthed } from "@app/graphql/is-authed-context" +import { RootStackParamList } from "@app/navigation/stack-param-lists" + +export const useInviteDeepLink = () => { + const navigation = useNavigation>() + const [redeemInvite] = useRedeemInviteMutation() + const [fetchInvitePreview] = useInvitePreviewLazyQuery() + const isAuthed = useIsAuthed() + + useEffect(() => { + // Handle initial URL (when app is opened from link) + Linking.getInitialURL().then((url) => { + if (url) { + handleDeepLink(url) + } + }) + + // Handle URL changes (when app is already open) + const subscription = Linking.addEventListener("url", (event) => { + handleDeepLink(event.url) + }) + + return () => { + subscription.remove() + } + }, [isAuthed, navigation, redeemInvite, fetchInvitePreview]) + + const handleDeepLink = async (url: string) => { + // Only handle invite URLs + if (!url.includes("invite")) { + return + } + + // Parse the URL to get the token + // Expected format: flash://invite?token=xxxxx or https://getflash.io/invite?token=xxxxx + const tokenRegex = /[?&]token=([a-f0-9]{40})/ + + const tokenMatch = url.match(tokenRegex) + if (!tokenMatch || !tokenMatch[1]) { + return + } + + const token = tokenMatch[1] + + try { + // Store token for later use (after signup/login) + await AsyncStorage.setItem("pendingInviteToken", token) + + // Fetch invite preview to get details + const { data: previewData, error } = await fetchInvitePreview({ + variables: { token }, + fetchPolicy: "network-only", // Force fresh fetch, bypass cache + context: { + // Add a header to indicate this is the recipient requesting their own invite + headers: { + "X-Invite-Recipient": "true", + }, + }, + }) + + if (error) { + Alert.alert("Error", "Unable to fetch invitation details. Please try again.") + return + } + + if (!previewData?.invitePreview?.isValid) { + Alert.alert( + "Invalid Invitation", + "This invitation link is invalid or has expired.", + [{ text: "OK" }], + ) + return + } + + const { contact, method, inviterUsername } = previewData.invitePreview + + // Backend now returns full contact for the intended recipient + + if (isAuthed) { + // Existing user - show message but don't redeem + Alert.alert( + "Invitation for New Users", + `This invitation from ${ + inviterUsername || "a friend" + } is for new users only. Share it with friends who haven't joined yet!`, + [{ text: "OK" }], + ) + } else { + // If not logged in, navigate to phone login flow (which handles both login and registration) + // Store the invite details for use after successful authentication + // Add a small delay to ensure navigation is ready + setTimeout(() => { + if (method === "EMAIL") { + navigation.navigate("emailLoginInitiate", { + inviteToken: token, + prefilledEmail: contact, + inviterUsername: inviterUsername || undefined, + } as any) + } else { + // For SMS or WHATSAPP, go to phone login flow + navigation.navigate("phoneFlow", { + screen: "phoneLoginInitiate", + params: { + inviteToken: token, + prefilledPhone: contact, + inviterUsername: inviterUsername || undefined, + }, + } as any) + } + }, 500) + } + } catch (error) { + console.error("Error handling invite deep link:", error) + Alert.alert("Error", "Unable to process invitation. Please try again.") + } + } +} + +// Helper function to check and redeem pending invite after login +export const redeemPendingInvite = async ( + redeemInviteMutation: any, + showAlert = true, +) => { + try { + const token = await AsyncStorage.getItem("pendingInviteToken") + + if (!token) { + return { success: false, message: "No pending invite" } + } + + // Call the redeemInvite mutation + const { data } = await redeemInviteMutation({ + variables: { + input: { token }, + }, + }) + + // Clear the token after attempting redemption + await AsyncStorage.removeItem("pendingInviteToken") + + if (data?.redeemInvite?.success) { + if (showAlert) { + Alert.alert( + "Welcome!", + "You've successfully accepted the invitation and joined through a referral.", + [{ text: "OK" }], + ) + } + return { success: true, message: "Invite redeemed successfully" } + } else if (data?.redeemInvite?.errors?.[0]) { + const errorMessage = data.redeemInvite.errors[0] + // Only show alert for non-duplicate errors + if (showAlert && !errorMessage.includes("already been used")) { + Alert.alert("Notice", errorMessage) + } + return { success: false, message: errorMessage } + } + + return { success: false, message: "Unknown error" } + } catch (error) { + console.error("Error redeeming pending invite:", error) + return { success: false, message: "Error redeeming invite" } + } +} diff --git a/app/screens/invite-friend/InviteDeepLinkHandler.tsx b/app/screens/invite-friend/InviteDeepLinkHandler.tsx new file mode 100644 index 000000000..c068c5500 --- /dev/null +++ b/app/screens/invite-friend/InviteDeepLinkHandler.tsx @@ -0,0 +1,9 @@ +import React from "react" +import { useInviteDeepLink } from "./HandleInviteDeepLink" + +export const InviteDeepLinkHandler: React.FC = ({ + children, +}) => { + useInviteDeepLink() + return <>{children} +} diff --git a/app/screens/invite-friend/InviteFriend.tsx b/app/screens/invite-friend/InviteFriend.tsx new file mode 100644 index 000000000..74f911f48 --- /dev/null +++ b/app/screens/invite-friend/InviteFriend.tsx @@ -0,0 +1,510 @@ +import React, { useState } from "react" +import { View, Alert, TouchableOpacity, ScrollView } from "react-native" +import { makeStyles, Text, useTheme } from "@rneui/themed" +import { StackScreenProps } from "@react-navigation/stack" +import { CountryCode } from "react-native-country-picker-modal" +import { RootStackParamList } from "@app/navigation/stack-param-lists" +import { useI18nContext } from "@app/i18n/i18n-react" +import { + parsePhoneNumber, + CountryCode as PhoneNumberCountryCode, +} from "libphonenumber-js/mobile" +import validator from "validator" +import { useCreateInviteMutation, InviteMethod } from "@app/graphql/generated" +import Icon from "react-native-vector-icons/Ionicons" + +// components +import { Screen } from "@app/components/screen" +import { PrimaryBtn } from "@app/components/buttons" +import { EmailInput, PhoneNumberInput } from "@app/components/input" +import { ContactPicker } from "@app/components/contact-picker" +import { ButtonGroup } from "@app/components/button-group" + +type Props = StackScreenProps +type InputMethod = "contacts" | "phone" | "email" + +const InviteFriend: React.FC = ({ navigation }) => { + const { LL } = useI18nContext() + const styles = useStyles() + const { colors } = useTheme().theme + + // State for input method selection + const [inputMethod, setInputMethod] = useState("contacts") + + // State for different input types + const [countryCode, setCountryCode] = useState("JM") + const [phoneNumber, setPhoneNumber] = useState() + const [email, setEmail] = useState() + const [loading, setLoading] = useState(false) + const [phoneMethod, setPhoneMethod] = useState<"whatsapp" | "sms">("whatsapp") + const [showContactPicker, setShowContactPicker] = useState(false) + + const [createInvite] = useCreateInviteMutation() + + const handleContactSelect = (selectedValue: string, type: "phone" | "email") => { + if (type === "email") { + // Handle email selection + setEmail(selectedValue) + setInputMethod("email") + } else { + // Handle phone number selection + try { + const parsed = parsePhoneNumber(selectedValue) + if (parsed && parsed.isValid()) { + setCountryCode(parsed.country as CountryCode) + setPhoneNumber(parsed.nationalNumber) + // Automatically switch to phone tab after selecting contact + setInputMethod("phone") + } else { + // If parsing fails, just set the raw number + const cleanNumber = selectedValue.replace(/[^\d+]/g, "") + if (cleanNumber.startsWith("+")) { + // Try to extract country code from international format + // Handle common Caribbean countries with +1 + if (cleanNumber.startsWith("+1876")) { + setCountryCode("JM" as CountryCode) + setPhoneNumber(cleanNumber.replace("+1", "")) + } else if (cleanNumber.startsWith("+1868")) { + setCountryCode("TT" as CountryCode) + setPhoneNumber(cleanNumber.replace("+1", "")) + } else if (cleanNumber.startsWith("+1246")) { + setCountryCode("BB" as CountryCode) + setPhoneNumber(cleanNumber.replace("+1", "")) + } else if (cleanNumber.startsWith("+1")) { + // Default to US for other +1 numbers + setCountryCode("US" as CountryCode) + setPhoneNumber(cleanNumber.replace("+1", "")) + } else { + // Remove + and set as phone number + setPhoneNumber(cleanNumber.replace("+", "")) + } + } else { + setPhoneNumber(cleanNumber) + } + // Switch to phone tab + setInputMethod("phone") + } + } catch (error) { + console.error("Error parsing contact phone number:", error) + // Just set the number as-is + const cleanNumber = selectedValue.replace(/[^\d]/g, "") + setPhoneNumber(cleanNumber) + setInputMethod("phone") + } + } + setShowContactPicker(false) + } + + const onSubmit = async () => { + // Validate inputs based on selected method + let contact: string = "" + let method: InviteMethod = InviteMethod.Email + + if (inputMethod === "email") { + if (email && validator.isEmail(email)) { + contact = email + method = InviteMethod.Email + } else { + Alert.alert("Error", "Please enter a valid email address") + return + } + } else if (inputMethod === "phone" || inputMethod === "contacts") { + if (countryCode && phoneNumber) { + const parsedPhoneNumber = parsePhoneNumber( + phoneNumber, + countryCode as PhoneNumberCountryCode, + ) + if (parsedPhoneNumber?.isValid()) { + contact = parsedPhoneNumber.format("E.164") + method = phoneMethod === "whatsapp" ? InviteMethod.Whatsapp : InviteMethod.Sms + } else { + Alert.alert("Error", "Please enter a valid phone number") + return + } + } else { + Alert.alert("Error", "Please enter a phone number") + return + } + } + + if (!contact) { + Alert.alert("Error", "Please enter contact information") + return + } + + // Send invite + setLoading(true) + try { + const { data } = await createInvite({ + variables: { + input: { + contact, + method, + }, + }, + }) + + if (data?.createInvite?.invite) { + navigation.navigate("InviteFriendSuccess", { + contact: data.createInvite.invite.contact, + method: data.createInvite.invite.method, + }) + } else if (data?.createInvite?.errors && data.createInvite.errors.length > 0) { + Alert.alert("Error", data.createInvite.errors[0]) + } + } catch (error) { + console.error("Error sending invite:", error) + Alert.alert("Error", "Unable to send invitation. Please try again.") + } finally { + setLoading(false) + } + } + + const isButtonDisabled = () => { + if (loading) return true + + if (inputMethod === "email") { + return !email || !validator.isEmail(email) + } else if (inputMethod === "phone" || inputMethod === "contacts") { + return !phoneNumber || phoneNumber.length === 0 + } + + return true + } + + const renderInputContent = () => { + switch (inputMethod) { + case "contacts": + return ( + + setShowContactPicker(true)} + > + + + {phoneNumber || email + ? phoneNumber + ? `Phone: ${phoneNumber}` + : `Email: ${email}` + : "Tap to select from contacts"} + + + Choose a friend from your phone's contact list + + + + ) + + case "phone": + return ( + + + + {/* SMS/WhatsApp selection */} + + Send via: + setPhoneMethod(id as "whatsapp" | "sms")} + /> + + + ) + + case "email": + return ( + + + + We'll send an invitation link to this email address + + + ) + + default: + return null + } + } + + return ( + + + {/* Header */} + + + {LL.InviteFriend.title()} + + + {LL.InviteFriend.subtitle()} + + + + {/* Icon-based Method Selector */} + + Choose how to invite: + + setInputMethod("contacts")} + > + + + + + Contacts + + + + setInputMethod("phone")} + > + + + + + Phone + + + + setInputMethod("email")} + > + + + + + Email + + + + + + {/* Input Content Area */} + {renderInputContent()} + + + {/* Submit Button */} + + + {/* Contact Picker Modal */} + setShowContactPicker(false)} + onSelectContact={handleContactSelect} + /> + + ) +} + +const useStyles = makeStyles(({ colors }) => ({ + screenStyle: { + padding: 20, + flexGrow: 1, + }, + main: { + flex: 1, + }, + header: { + marginBottom: 24, + }, + title: { + marginBottom: 12, + fontSize: 28, + }, + subtitle: { + color: colors.grey3, + fontSize: 16, + lineHeight: 22, + }, + selectorContainer: { + marginBottom: 32, + }, + selectorTitle: { + fontSize: 16, + fontWeight: "600", + color: colors.black, + marginBottom: 20, + textAlign: "center", + }, + iconSelector: { + flexDirection: "row", + justifyContent: "space-around", + paddingHorizontal: 10, + }, + iconButton: { + alignItems: "center", + opacity: 0.7, + }, + iconButtonActive: { + opacity: 1, + }, + iconCircle: { + width: 80, + height: 80, + borderRadius: 40, + backgroundColor: colors.grey5, + alignItems: "center", + justifyContent: "center", + borderWidth: 2, + borderColor: colors.grey4, + marginBottom: 8, + }, + iconCircleActive: { + backgroundColor: colors.primary, + borderColor: colors.primary, + shadowColor: colors.primary, + shadowOffset: { + width: 0, + height: 4, + }, + shadowOpacity: 0.3, + shadowRadius: 8, + elevation: 8, + }, + iconLabel: { + fontSize: 14, + fontWeight: "500", + color: colors.grey2, + }, + iconLabelActive: { + color: colors.primary, + fontWeight: "700", + }, + inputContainer: { + minHeight: 200, + marginBottom: 24, + }, + inputContent: { + paddingTop: 16, + }, + selectContactButton: { + alignItems: "center", + justifyContent: "center", + paddingVertical: 32, + paddingHorizontal: 24, + borderRadius: 12, + backgroundColor: colors.grey5, + borderWidth: 2, + borderColor: colors.primary, + borderStyle: "dashed", + }, + selectContactIcon: { + color: colors.primary, + }, + selectContactText: { + marginTop: 16, + fontSize: 18, + fontWeight: "600", + color: colors.black, + textAlign: "center", + }, + selectContactSubtext: { + marginTop: 8, + fontSize: 14, + color: colors.grey3, + textAlign: "center", + }, + phoneMethodSelector: { + marginTop: 24, + }, + sendViaText: { + fontSize: 14, + fontWeight: "600", + color: colors.black, + marginBottom: 12, + }, + inputHint: { + marginTop: 12, + fontSize: 14, + color: colors.grey3, + textAlign: "center", + paddingHorizontal: 16, + }, + submitButton: { + marginBottom: 10, + }, +})) + +export default InviteFriend diff --git a/app/screens/invite-friend/InviteFriendSuccess.tsx b/app/screens/invite-friend/InviteFriendSuccess.tsx new file mode 100644 index 000000000..e16f53d6a --- /dev/null +++ b/app/screens/invite-friend/InviteFriendSuccess.tsx @@ -0,0 +1,64 @@ +import React from "react" +import { Dimensions, View } from "react-native" +import { makeStyles, Text, useTheme } from "@rneui/themed" +import { useSafeAreaInsets } from "react-native-safe-area-context" +import { RootStackParamList } from "@app/navigation/stack-param-lists" +import { StackScreenProps } from "@react-navigation/stack" +import { useI18nContext } from "@app/i18n/i18n-react" + +// components +import { Screen } from "@app/components/screen" +import { PrimaryBtn } from "@app/components/buttons" + +// assets +import SendSuccess from "@app/assets/illustrations/send-success.svg" + +const width = Dimensions.get("window").width + +type Props = StackScreenProps + +const InviteFriendSuccess: React.FC = ({ navigation, route }) => { + const { LL } = useI18nContext() + const { bottom } = useSafeAreaInsets() + const { colors } = useTheme().theme + const styles = useStyles() + + // Get the contact from route params, or use default + const contact = route.params?.contact || "your friend" + const method = route.params?.method || "EMAIL" + + const onPressDone = () => { + navigation.popToTop() + } + + return ( + + + + + {LL.InviteFriend.invitationSuccessTitle({ value: contact })} + + + + + ) +} + +export default InviteFriendSuccess + +const useStyles = makeStyles(() => ({ + container: { + flex: 1, + alignItems: "center", + justifyContent: "center", + }, +})) diff --git a/app/screens/invite-friend/index.ts b/app/screens/invite-friend/index.ts new file mode 100644 index 000000000..8ecb22e96 --- /dev/null +++ b/app/screens/invite-friend/index.ts @@ -0,0 +1,4 @@ +import InviteFriend from "./InviteFriend" +import InviteFriendSuccess from "./InviteFriendSuccess" + +export { InviteFriend, InviteFriendSuccess } diff --git a/app/screens/phone-auth-screen/phone-login-input.tsx b/app/screens/phone-auth-screen/phone-login-input.tsx index 90fae5f17..469063dfa 100644 --- a/app/screens/phone-auth-screen/phone-login-input.tsx +++ b/app/screens/phone-auth-screen/phone-login-input.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react" +import React, { useEffect, useState } from "react" import { ActivityIndicator, View } from "react-native" import { StackScreenProps } from "@react-navigation/stack" import { TouchableOpacity } from "react-native-gesture-handler" @@ -37,11 +37,16 @@ const PLACEHOLDER_PHONE_NUMBER = "123-456-7890" type Props = StackScreenProps -export const PhoneLoginInitiateScreen: React.FC = ({ navigation }) => { +export const PhoneLoginInitiateScreen: React.FC = ({ navigation, route }) => { const { LL } = useI18nContext() const { colors, mode } = useTheme().theme const styles = useStyles() + // Check if this is an invite signup + const hasInviteToken = !!(route?.params as any)?.inviteToken + console.log("PhoneLoginInitiate: Route params:", JSON.stringify(route?.params)) + console.log("PhoneLoginInitiate: Has invite token:", hasInviteToken) + const { submitPhoneNumber, captchaLoading, @@ -57,10 +62,102 @@ export const PhoneLoginInitiateScreen: React.FC = ({ navigation }) => { setCountryCode, supportedCountries, loadingSupportedCountries, - } = useRequestPhoneCodeLogin() + } = useRequestPhoneCodeLogin(hasInviteToken) + + // Handle pre-filled phone from invite + const [hasPreFilled, setHasPreFilled] = React.useState(false) + const [targetCountryCode, setTargetCountryCode] = React.useState< + CountryCode | undefined + >() + + useEffect(() => { + const handlePrefilledPhone = async () => { + const params = route?.params as any + + // Only pre-fill once and if we have the phone number parameter + if (params?.prefilledPhone && !hasPreFilled) { + setHasPreFilled(true) + + try { + // Import parsePhoneNumber at the top of the file + const { parsePhoneNumber } = await import("libphonenumber-js/mobile") + + // Check for specific Caribbean country codes + if (params.prefilledPhone.startsWith("+1876")) { + // Jamaica + const numberWithoutCountryCode = params.prefilledPhone.replace("+1", "") + setPhoneNumber(numberWithoutCountryCode) + setTargetCountryCode("JM" as CountryCode) + } else if (params.prefilledPhone.startsWith("+1868")) { + // Trinidad and Tobago + const numberWithoutCountryCode = params.prefilledPhone.replace("+1", "") + setPhoneNumber(numberWithoutCountryCode) + setTargetCountryCode("TT" as CountryCode) + } else if (params.prefilledPhone.startsWith("+1246")) { + // Barbados + const numberWithoutCountryCode = params.prefilledPhone.replace("+1", "") + setPhoneNumber(numberWithoutCountryCode) + setTargetCountryCode("BB" as CountryCode) + } else { + // Try parsing with libphonenumber + const parsed = parsePhoneNumber(params.prefilledPhone) + if (parsed && parsed.isValid()) { + const countryCode = parsed.country as CountryCode + const nationalNumber = parsed.nationalNumber + setTargetCountryCode(countryCode) + setPhoneNumber(nationalNumber) + } else { + // If parsing fails, try to extract what we can + if (params.prefilledPhone.startsWith("+1")) { + // Default to US for other +1 numbers + setTargetCountryCode("US" as CountryCode) + const numberWithoutCountry = params.prefilledPhone.replace("+1", "") + setPhoneNumber(numberWithoutCountry) + } else { + // Just set the number without country code + const cleanNumber = params.prefilledPhone.replace(/[^\d]/g, "") + setPhoneNumber(cleanNumber) + } + } + } + + // Store invite token for later redemption + if (params.inviteToken) { + const AsyncStorage = ( + await import("@react-native-async-storage/async-storage") + ).default + await AsyncStorage.setItem("pendingInviteToken", params.inviteToken) + } + } catch (error) { + console.error("Error parsing pre-filled phone:", error) + // If all else fails, just set what we have + const cleanNumber = params.prefilledPhone.replace(/[^\d]/g, "") + setPhoneNumber(cleanNumber) + } + } + } + + handlePrefilledPhone() + }, [route?.params, setPhoneNumber, hasPreFilled]) + + // Set country code when status changes and we have a target + useEffect(() => { + if (status === RequestPhoneCodeStatus.InputtingPhoneNumber && targetCountryCode) { + // Add a small delay to ensure the component is ready + setTimeout(() => { + setCountryCode(targetCountryCode) + // Clear the target after setting + setTargetCountryCode(undefined) + }, 100) + } + }, [status, targetCountryCode, setCountryCode]) useEffect(() => { + console.log("PhoneLoginInitiate: Status changed to:", status) if (status === RequestPhoneCodeStatus.SuccessRequestingCode) { + console.log("PhoneLoginInitiate: Success! Navigating to validation screen") + console.log("Phone:", validatedPhoneNumber) + console.log("Channel:", phoneCodeChannel) setStatus(RequestPhoneCodeStatus.InputtingPhoneNumber) navigation.navigate("phoneLoginValidate", { phone: validatedPhoneNumber || "", diff --git a/app/screens/phone-auth-screen/phone-registration-input.tsx b/app/screens/phone-auth-screen/phone-registration-input.tsx index d968682b9..20bf34df1 100644 --- a/app/screens/phone-auth-screen/phone-registration-input.tsx +++ b/app/screens/phone-auth-screen/phone-registration-input.tsx @@ -9,6 +9,7 @@ import CountryPicker, { import { CountryCode as PhoneNumberCountryCode, getCountryCallingCode, + parsePhoneNumber, } from "libphonenumber-js/mobile" import { ContactSupportButton } from "@app/components/contact-support-button/contact-support-button" import { useI18nContext } from "@app/i18n/i18n-react" @@ -24,11 +25,19 @@ import { GaloySecondaryButton } from "@app/components/atomic/galoy-secondary-but import { GaloyErrorBox } from "@app/components/atomic/galoy-error-box" import { PhoneCodeChannelType } from "@app/graphql/generated" import { TouchableOpacity } from "react-native-gesture-handler" +import { RouteProp, useRoute } from "@react-navigation/native" +import { RootStackParamList } from "@app/navigation/stack-param-lists" +import AsyncStorage from "@react-native-async-storage/async-storage" const DEFAULT_COUNTRY_CODE = "SV" const PLACEHOLDER_PHONE_NUMBER = "123-456-7890" -export const PhoneRegistrationInitiateScreen: React.FC = () => { +type Props = { + route?: RouteProp +} + +export const PhoneRegistrationInitiateScreen: React.FC = () => { + const route = useRoute>() const styles = useStyles() const { @@ -50,6 +59,96 @@ export const PhoneRegistrationInitiateScreen: React.FC = () => { const { LL } = useI18nContext() + // State to track if we've already pre-filled + const [hasPreFilled, setHasPreFilled] = React.useState(false) + const [targetCountryCode, setTargetCountryCode] = React.useState< + CountryCode | undefined + >() + + // Handle pre-filled phone from invite + React.useEffect(() => { + const handlePrefilledPhone = async () => { + const params = route.params as any + + // Only pre-fill once and if we have the phone number parameter + if (params?.prefilledPhone && !hasPreFilled) { + setHasPreFilled(true) + + try { + // First check for specific country codes that might be problematic + // Jamaica numbers start with +1876 + if (params.prefilledPhone.startsWith("+1876")) { + // Jamaica - keep the area code 876 as part of the phone number + // Remove only the +1 country code + const numberWithoutCountryCode = params.prefilledPhone.replace("+1", "") + + // Set phone number immediately + setPhoneNumber(numberWithoutCountryCode) + + // Store the target country code to set later + setTargetCountryCode("JM" as CountryCode) + } else if (params.prefilledPhone.startsWith("+1868")) { + // Trinidad and Tobago + const numberWithoutCountryCode = params.prefilledPhone.replace("+1", "") + setPhoneNumber(numberWithoutCountryCode) + setTargetCountryCode("TT" as CountryCode) + } else if (params.prefilledPhone.startsWith("+1246")) { + // Barbados + const numberWithoutCountryCode = params.prefilledPhone.replace("+1", "") + setPhoneNumber(numberWithoutCountryCode) + setTargetCountryCode("BB" as CountryCode) + } else { + // Try parsing with libphonenumber + const parsed = parsePhoneNumber(params.prefilledPhone) + if (parsed && parsed.isValid()) { + const countryCode = parsed.country as CountryCode + const nationalNumber = parsed.nationalNumber + + setTargetCountryCode(countryCode) + setPhoneNumber(nationalNumber) + } else { + // If parsing fails, try to extract what we can + if (params.prefilledPhone.startsWith("+1")) { + // Default to US for other +1 numbers + setTargetCountryCode("US" as CountryCode) + const numberWithoutCountry = params.prefilledPhone.replace("+1", "") + setPhoneNumber(numberWithoutCountry) + } else { + // Just set the number without country code + const cleanNumber = params.prefilledPhone.replace(/[^\d]/g, "") + setPhoneNumber(cleanNumber) + } + } + } + + // Store invite token for later redemption + if (params.inviteToken) { + await AsyncStorage.setItem("pendingInviteToken", params.inviteToken) + } + } catch (error) { + console.error("Error parsing pre-filled phone:", error) + // If all else fails, just set what we have + const cleanNumber = params.prefilledPhone.replace(/[^\d]/g, "") + setPhoneNumber(cleanNumber) + } + } + } + + handlePrefilledPhone() + }, [route.params, setPhoneNumber, hasPreFilled]) + + // Set country code when status changes to InputtingPhoneNumber and we have a target + React.useEffect(() => { + if (status === RequestPhoneCodeStatus.InputtingPhoneNumber && targetCountryCode) { + // Add a small delay to ensure the component is ready + setTimeout(() => { + setCountryCode(targetCountryCode) + // Clear the target after setting + setTargetCountryCode(undefined) + }, 100) + } + }, [status, targetCountryCode, setCountryCode]) + if (status === RequestPhoneCodeStatus.LoadingCountryCode) { return ( diff --git a/app/screens/phone-auth-screen/request-phone-code-login.ts b/app/screens/phone-auth-screen/request-phone-code-login.ts index 8d229779b..f309ff21d 100644 --- a/app/screens/phone-auth-screen/request-phone-code-login.ts +++ b/app/screens/phone-auth-screen/request-phone-code-login.ts @@ -10,6 +10,7 @@ import { gql } from "@apollo/client" import { PhoneCodeChannelType, useCaptchaRequestAuthCodeMutation, + useUserPhoneRegistrationInitiateMutation, useSupportedCountriesQuery, } from "@app/graphql/generated" @@ -87,7 +88,10 @@ gql` } ` -export const useRequestPhoneCodeLogin = (): UseRequestPhoneCodeReturn => { +export const useRequestPhoneCodeLogin = ( + isInviteSignup = false, +): UseRequestPhoneCodeReturn => { + console.log("useRequestPhoneCodeLogin: isInviteSignup =", isInviteSignup) const [status, setStatus] = useState( RequestPhoneCodeStatus.LoadingCountryCode, ) @@ -102,6 +106,7 @@ export const useRequestPhoneCodeLogin = (): UseRequestPhoneCodeReturn => { const [error, setError] = useState() const [captchaRequestAuthCode] = useCaptchaRequestAuthCodeMutation() + const [userPhoneRegistrationInitiate] = useUserPhoneRegistrationInitiateMutation() const { data, loading: loadingSupportedCountries } = useSupportedCountriesQuery() const { isWhatsAppSupported, isSmsSupported, allSupportedCountries } = useMemo(() => { @@ -157,7 +162,13 @@ export const useRequestPhoneCodeLogin = (): UseRequestPhoneCodeReturn => { // Handle the error gracefully by not logging it } - setCountryCode(defaultCountryCode) + // Only set country code if not already set (e.g., from pre-filled invite) + setCountryCode((prevCountryCode) => { + if (prevCountryCode) { + return prevCountryCode + } + return defaultCountryCode + }) setStatus(RequestPhoneCodeStatus.InputtingPhoneNumber) } @@ -182,15 +193,29 @@ export const useRequestPhoneCodeLogin = (): UseRequestPhoneCodeReturn => { setStatus(RequestPhoneCodeStatus.InputtingPhoneNumber) } - const submitPhoneNumber = (phoneCodeChannel: PhoneCodeChannelType) => { + const submitPhoneNumber = async (phoneCodeChannel: PhoneCodeChannelType) => { + console.log("submitPhoneNumber called with channel:", phoneCodeChannel) + console.log("Current status:", status) + console.log("isInviteSignup:", isInviteSignup) + console.log("rawPhoneNumber:", rawPhoneNumber) + console.log("countryCode:", countryCode) + if ( status === RequestPhoneCodeStatus.LoadingCountryCode || status === RequestPhoneCodeStatus.RequestingCode ) { + console.log("submitPhoneNumber: Returning early due to status:", status) return } const parsedPhoneNumber = parsePhoneNumber(rawPhoneNumber, countryCode) + console.log( + "Parsed phone number:", + parsedPhoneNumber?.number, + "isValid:", + parsedPhoneNumber?.isValid(), + ) + phoneCodeChannel && setPhoneCodeChannel(phoneCodeChannel) if (parsedPhoneNumber?.isValid()) { if ( @@ -198,20 +223,64 @@ export const useRequestPhoneCodeLogin = (): UseRequestPhoneCodeReturn => { (phoneCodeChannel === PhoneCodeChannelType.Sms && !isSmsSupported) || (phoneCodeChannel === PhoneCodeChannelType.Whatsapp && !isWhatsAppSupported) ) { + console.log("submitPhoneNumber: Unsupported country/channel") + console.log("Country:", parsedPhoneNumber.country) + console.log("isSmsSupported:", isSmsSupported) + console.log("isWhatsAppSupported:", isWhatsAppSupported) setStatus(RequestPhoneCodeStatus.Error) setError(ErrorType.UnsupportedCountryError) return } setValidatedPhoneNumber(parsedPhoneNumber.number) + console.log("Set validated phone number:", parsedPhoneNumber.number) if (skipRequestPhoneCode) { + console.log("Skipping request phone code (local environment)") setStatus(RequestPhoneCodeStatus.SuccessRequestingCode) return } - setStatus(RequestPhoneCodeStatus.CompletingCaptcha) - registerCaptcha() + // If this is an invite signup, use registration flow (no captcha needed) + if (isInviteSignup) { + console.log("=== INVITE SIGNUP FLOW - USING REGISTRATION API ===") + console.log("About to call userPhoneRegistrationInitiate mutation") + console.log("Phone number:", parsedPhoneNumber.number) + console.log("Channel:", phoneCodeChannel) + + setStatus(RequestPhoneCodeStatus.RequestingCode) + try { + console.log("Calling userPhoneRegistrationInitiate mutation...") + const res = await userPhoneRegistrationInitiate({ + variables: { + input: { phone: parsedPhoneNumber.number, channel: phoneCodeChannel }, + }, + }) + + console.log("Registration API response:", JSON.stringify(res.data)) + + if (res.data?.userPhoneRegistrationInitiate?.errors?.length) { + console.log( + "Registration API returned errors:", + res.data.userPhoneRegistrationInitiate.errors, + ) + setStatus(RequestPhoneCodeStatus.Error) + setError(ErrorType.RequestCodeError) + } else { + console.log("Registration API SUCCESS - code should be sent via Twilio") + setStatus(RequestPhoneCodeStatus.SuccessRequestingCode) + } + } catch (error) { + console.error("Error requesting registration code:", error) + setStatus(RequestPhoneCodeStatus.Error) + setError(ErrorType.RequestCodeError) + } + } else { + // Regular login flow with captcha + console.log("=== REGULAR LOGIN FLOW - USING CAPTCHA ===") + setStatus(RequestPhoneCodeStatus.CompletingCaptcha) + registerCaptcha() + } } else { setStatus(RequestPhoneCodeStatus.Error) setError(ErrorType.InvalidPhoneNumberError) diff --git a/app/screens/phone-auth-screen/request-phone-code-registration.ts b/app/screens/phone-auth-screen/request-phone-code-registration.ts index b36210b8b..5209ada46 100644 --- a/app/screens/phone-auth-screen/request-phone-code-registration.ts +++ b/app/screens/phone-auth-screen/request-phone-code-registration.ts @@ -150,7 +150,13 @@ export const useRequestPhoneCodeRegistration = (): UseRequestPhoneCodeReturn => console.error(error) } - setCountryCode(defaultCountryCode) + // Only set country code if not already set + setCountryCode((prevCountryCode) => { + if (prevCountryCode) { + return prevCountryCode + } + return defaultCountryCode + }) setStatus(RequestPhoneCodeStatus.InputtingPhoneNumber) } diff --git a/app/screens/settings-screen/settings-screen.tsx b/app/screens/settings-screen/settings-screen.tsx index 00991bcbf..ccc4caa7f 100644 --- a/app/screens/settings-screen/settings-screen.tsx +++ b/app/screens/settings-screen/settings-screen.tsx @@ -31,6 +31,7 @@ import { GenerateReportsSetting } from "./settings/generate-reports" import { SettingsGroup } from "./group" import { EmailSetting } from "./account/settings/email" import { ChatSetting } from "./chat-setting" +import { InviteFriendSetting } from "./settings/invite-friend" // import { TotpSetting } from "./totp" gql` @@ -81,7 +82,7 @@ const items = { ExportCsvSetting, // ApiAccessSetting ], - community: [JoinCommunitySetting], + community: [JoinCommunitySetting, InviteFriendSetting], } export const SettingsScreen: React.FC = () => { diff --git a/app/screens/settings-screen/settings/invite-friend.tsx b/app/screens/settings-screen/settings/invite-friend.tsx new file mode 100644 index 000000000..4ada7eb31 --- /dev/null +++ b/app/screens/settings-screen/settings/invite-friend.tsx @@ -0,0 +1,24 @@ +import { useI18nContext } from "@app/i18n/i18n-react" +import { useNavigation } from "@react-navigation/native" +import { StackNavigationProp } from "@react-navigation/stack" +import { RootStackParamList } from "@app/navigation/stack-param-lists" + +// components +import { SettingsRow } from "../row" + +export const InviteFriendSetting: React.FC = () => { + const { LL } = useI18nContext() + const navigation = useNavigation>() + + const onNavigate = () => { + navigation.navigate("InviteFriend") + } + + return ( + + ) +} diff --git a/ios/LNFlash.xcodeproj/project.pbxproj b/ios/LNFlash.xcodeproj/project.pbxproj index a0c1ea64c..adbce65b8 100644 --- a/ios/LNFlash.xcodeproj/project.pbxproj +++ b/ios/LNFlash.xcodeproj/project.pbxproj @@ -380,6 +380,7 @@ "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift/Promises_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RNPermissions/RNPermissionsPrivacyInfo.bundle", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf", @@ -419,6 +420,7 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FBLPromises_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Promises_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/QBImagePicker.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNPermissionsPrivacyInfo.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf", @@ -557,6 +559,7 @@ "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift/Promises_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RNPermissions/RNPermissionsPrivacyInfo.bundle", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf", @@ -596,6 +599,7 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FBLPromises_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Promises_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/QBImagePicker.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNPermissionsPrivacyInfo.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf", diff --git a/ios/LNFlash/Info.plist b/ios/LNFlash/Info.plist index f7a9a9823..0f75210d6 100644 --- a/ios/LNFlash/Info.plist +++ b/ios/LNFlash/Info.plist @@ -101,6 +101,8 @@ NSCameraUsageDescription Activate your camera to scan QR codes + NSContactsUsageDescription + Access your contacts to easily invite friends to Flash NSFaceIDUsageDescription $(PRODUCT_NAME) requires FaceID access for quick and secure authentication. NSLocationWhenInUseUsageDescription diff --git a/ios/Podfile b/ios/Podfile index 43f1cf4b4..f72d04cda 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,9 +1,21 @@ require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' +require_relative '../node_modules/react-native-permissions/scripts/setup' + use_modular_headers! platform :ios, '13.4' prepare_react_native_project! + + +# ⬇️ react-native-permissions setup +setup_permissions([ + 'Contacts', + 'Camera', + 'PhotoLibrary', + 'LocationWhenInUse', + 'FaceID' +]) # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded # diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 68e37c227..74f25d3f7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -13,14 +13,14 @@ PODS: - BVLinearGradient (2.8.3): - React-Core - DoubleConversion (1.1.6) - - FBLazyVector (0.72.9) - - FBReactNativeSpec (0.72.9): + - FBLazyVector (0.72.7) + - FBReactNativeSpec (0.72.7): - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.72.9) - - RCTTypeSafety (= 0.72.9) - - React-Core (= 0.72.9) - - React-jsi (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) + - RCTRequired (= 0.72.7) + - RCTTypeSafety (= 0.72.7) + - React-Core (= 0.72.7) + - React-jsi (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) - Firebase/AnalyticsWithoutAdIdSupport (11.12.0): - Firebase/CoreOnly - FirebaseAnalytics/WithoutAdIdSupport (~> 11.12.0) @@ -158,9 +158,9 @@ PODS: - GoogleUtilities/Logger - GoogleUtilities/Privacy - GT3Captcha-iOS (0.15.9) - - hermes-engine (0.72.9): - - hermes-engine/Pre-built (= 0.72.9) - - hermes-engine/Pre-built (0.72.9) + - hermes-engine (0.72.7): + - hermes-engine/Pre-built (= 0.72.7) + - hermes-engine/Pre-built (0.72.7) - libevent (2.1.12) - nanopb (3.30910.0): - nanopb/decode (= 3.30910.0) @@ -188,26 +188,26 @@ PODS: - fmt (~> 6.2.1) - glog - libevent - - RCTRequired (0.72.9) - - RCTTypeSafety (0.72.9): - - FBLazyVector (= 0.72.9) - - RCTRequired (= 0.72.9) - - React-Core (= 0.72.9) - - React (0.72.9): - - React-Core (= 0.72.9) - - React-Core/DevSupport (= 0.72.9) - - React-Core/RCTWebSocket (= 0.72.9) - - React-RCTActionSheet (= 0.72.9) - - React-RCTAnimation (= 0.72.9) - - React-RCTBlob (= 0.72.9) - - React-RCTImage (= 0.72.9) - - React-RCTLinking (= 0.72.9) - - React-RCTNetwork (= 0.72.9) - - React-RCTSettings (= 0.72.9) - - React-RCTText (= 0.72.9) - - React-RCTVibration (= 0.72.9) - - React-callinvoker (0.72.9) - - React-Codegen (0.72.9): + - RCTRequired (0.72.7) + - RCTTypeSafety (0.72.7): + - FBLazyVector (= 0.72.7) + - RCTRequired (= 0.72.7) + - React-Core (= 0.72.7) + - React (0.72.7): + - React-Core (= 0.72.7) + - React-Core/DevSupport (= 0.72.7) + - React-Core/RCTWebSocket (= 0.72.7) + - React-RCTActionSheet (= 0.72.7) + - React-RCTAnimation (= 0.72.7) + - React-RCTBlob (= 0.72.7) + - React-RCTImage (= 0.72.7) + - React-RCTLinking (= 0.72.7) + - React-RCTNetwork (= 0.72.7) + - React-RCTSettings (= 0.72.7) + - React-RCTText (= 0.72.7) + - React-RCTVibration (= 0.72.7) + - React-callinvoker (0.72.7) + - React-Codegen (0.72.7): - DoubleConversion - FBReactNativeSpec - glog @@ -222,11 +222,11 @@ PODS: - React-rncore - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-Core (0.72.9): + - React-Core (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.9) + - React-Core/Default (= 0.72.7) - React-cxxreact - React-hermes - React-jsi @@ -236,7 +236,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/CoreModulesHeaders (0.72.9): + - React-Core/CoreModulesHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -250,7 +250,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/Default (0.72.9): + - React-Core/Default (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -263,23 +263,23 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/DevSupport (0.72.9): + - React-Core/DevSupport (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.9) - - React-Core/RCTWebSocket (= 0.72.9) + - React-Core/Default (= 0.72.7) + - React-Core/RCTWebSocket (= 0.72.7) - React-cxxreact - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector (= 0.72.9) + - React-jsinspector (= 0.72.7) - React-perflogger - React-runtimeexecutor - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTActionSheetHeaders (0.72.9): + - React-Core/RCTActionSheetHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -293,7 +293,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTAnimationHeaders (0.72.9): + - React-Core/RCTAnimationHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -307,7 +307,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTBlobHeaders (0.72.9): + - React-Core/RCTBlobHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -321,7 +321,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTImageHeaders (0.72.9): + - React-Core/RCTImageHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -335,7 +335,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTLinkingHeaders (0.72.9): + - React-Core/RCTLinkingHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -349,7 +349,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTNetworkHeaders (0.72.9): + - React-Core/RCTNetworkHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -363,7 +363,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTSettingsHeaders (0.72.9): + - React-Core/RCTSettingsHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -377,7 +377,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTTextHeaders (0.72.9): + - React-Core/RCTTextHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -391,7 +391,7 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTVibrationHeaders (0.72.9): + - React-Core/RCTVibrationHeaders (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -405,11 +405,11 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTWebSocket (0.72.9): + - React-Core/RCTWebSocket (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.9) + - React-Core/Default (= 0.72.7) - React-cxxreact - React-hermes - React-jsi @@ -419,57 +419,57 @@ PODS: - React-utils - SocketRocket (= 0.6.1) - Yoga - - React-CoreModules (0.72.9): + - React-CoreModules (0.72.7): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.9) - - React-Codegen (= 0.72.9) - - React-Core/CoreModulesHeaders (= 0.72.9) - - React-jsi (= 0.72.9) + - RCTTypeSafety (= 0.72.7) + - React-Codegen (= 0.72.7) + - React-Core/CoreModulesHeaders (= 0.72.7) + - React-jsi (= 0.72.7) - React-RCTBlob - - React-RCTImage (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) + - React-RCTImage (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) - SocketRocket (= 0.6.1) - - React-cxxreact (0.72.9): + - React-cxxreact (0.72.7): - boost (= 1.76.0) - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.9) - - React-debug (= 0.72.9) - - React-jsi (= 0.72.9) - - React-jsinspector (= 0.72.9) - - React-logger (= 0.72.9) - - React-perflogger (= 0.72.9) - - React-runtimeexecutor (= 0.72.9) - - React-debug (0.72.9) - - React-hermes (0.72.9): + - React-callinvoker (= 0.72.7) + - React-debug (= 0.72.7) + - React-jsi (= 0.72.7) + - React-jsinspector (= 0.72.7) + - React-logger (= 0.72.7) + - React-perflogger (= 0.72.7) + - React-runtimeexecutor (= 0.72.7) + - React-debug (0.72.7) + - React-hermes (0.72.7): - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - RCT-Folly/Futures (= 2021.07.22.00) - - React-cxxreact (= 0.72.9) + - React-cxxreact (= 0.72.7) - React-jsi - - React-jsiexecutor (= 0.72.9) - - React-jsinspector (= 0.72.9) - - React-perflogger (= 0.72.9) - - React-jsi (0.72.9): + - React-jsiexecutor (= 0.72.7) + - React-jsinspector (= 0.72.7) + - React-perflogger (= 0.72.7) + - React-jsi (0.72.7): - boost (= 1.76.0) - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-jsiexecutor (0.72.9): + - React-jsiexecutor (0.72.7): - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.72.9) - - React-jsi (= 0.72.9) - - React-perflogger (= 0.72.9) - - React-jsinspector (0.72.9) - - React-logger (0.72.9): + - React-cxxreact (= 0.72.7) + - React-jsi (= 0.72.7) + - React-perflogger (= 0.72.7) + - React-jsinspector (0.72.7) + - React-logger (0.72.7): - glog - react-native-aes (2.0.0): - React-Core @@ -477,6 +477,9 @@ PODS: - react-native-config/App (= 1.5.1) - react-native-config/App (1.5.1): - React-Core + - react-native-contacts (8.0.7): + - RCT-Folly (= 2021.07.22.00) + - React-Core - react-native-date-picker (5.0.7): - React-Core - react-native-document-picker (9.1.0): @@ -526,7 +529,7 @@ PODS: - react-native-webview (13.8.1): - RCT-Folly (= 2021.07.22.00) - React-Core - - React-NativeModulesApple (0.72.9): + - React-NativeModulesApple (0.72.7): - hermes-engine - React-callinvoker - React-Core @@ -535,17 +538,17 @@ PODS: - React-runtimeexecutor - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-perflogger (0.72.9) - - React-RCTActionSheet (0.72.9): - - React-Core/RCTActionSheetHeaders (= 0.72.9) - - React-RCTAnimation (0.72.9): + - React-perflogger (0.72.7) + - React-RCTActionSheet (0.72.7): + - React-Core/RCTActionSheetHeaders (= 0.72.7) + - React-RCTAnimation (0.72.7): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.9) - - React-Codegen (= 0.72.9) - - React-Core/RCTAnimationHeaders (= 0.72.9) - - React-jsi (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) - - React-RCTAppDelegate (0.72.9): + - RCTTypeSafety (= 0.72.7) + - React-Codegen (= 0.72.7) + - React-Core/RCTAnimationHeaders (= 0.72.7) + - React-jsi (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) + - React-RCTAppDelegate (0.72.7): - RCT-Folly - RCTRequired - RCTTypeSafety @@ -557,54 +560,54 @@ PODS: - React-RCTNetwork - React-runtimescheduler - ReactCommon/turbomodule/core - - React-RCTBlob (0.72.9): + - React-RCTBlob (0.72.7): - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.72.9) - - React-Core/RCTBlobHeaders (= 0.72.9) - - React-Core/RCTWebSocket (= 0.72.9) - - React-jsi (= 0.72.9) - - React-RCTNetwork (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) - - React-RCTImage (0.72.9): + - React-Codegen (= 0.72.7) + - React-Core/RCTBlobHeaders (= 0.72.7) + - React-Core/RCTWebSocket (= 0.72.7) + - React-jsi (= 0.72.7) + - React-RCTNetwork (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) + - React-RCTImage (0.72.7): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.9) - - React-Codegen (= 0.72.9) - - React-Core/RCTImageHeaders (= 0.72.9) - - React-jsi (= 0.72.9) - - React-RCTNetwork (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) - - React-RCTLinking (0.72.9): - - React-Codegen (= 0.72.9) - - React-Core/RCTLinkingHeaders (= 0.72.9) - - React-jsi (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) - - React-RCTNetwork (0.72.9): + - RCTTypeSafety (= 0.72.7) + - React-Codegen (= 0.72.7) + - React-Core/RCTImageHeaders (= 0.72.7) + - React-jsi (= 0.72.7) + - React-RCTNetwork (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) + - React-RCTLinking (0.72.7): + - React-Codegen (= 0.72.7) + - React-Core/RCTLinkingHeaders (= 0.72.7) + - React-jsi (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) + - React-RCTNetwork (0.72.7): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.9) - - React-Codegen (= 0.72.9) - - React-Core/RCTNetworkHeaders (= 0.72.9) - - React-jsi (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) - - React-RCTSettings (0.72.9): + - RCTTypeSafety (= 0.72.7) + - React-Codegen (= 0.72.7) + - React-Core/RCTNetworkHeaders (= 0.72.7) + - React-jsi (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) + - React-RCTSettings (0.72.7): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.9) - - React-Codegen (= 0.72.9) - - React-Core/RCTSettingsHeaders (= 0.72.9) - - React-jsi (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) - - React-RCTText (0.72.9): - - React-Core/RCTTextHeaders (= 0.72.9) - - React-RCTVibration (0.72.9): + - RCTTypeSafety (= 0.72.7) + - React-Codegen (= 0.72.7) + - React-Core/RCTSettingsHeaders (= 0.72.7) + - React-jsi (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) + - React-RCTText (0.72.7): + - React-Core/RCTTextHeaders (= 0.72.7) + - React-RCTVibration (0.72.7): - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.72.9) - - React-Core/RCTVibrationHeaders (= 0.72.9) - - React-jsi (= 0.72.9) - - ReactCommon/turbomodule/core (= 0.72.9) - - React-rncore (0.72.9) - - React-runtimeexecutor (0.72.9): - - React-jsi (= 0.72.9) - - React-runtimescheduler (0.72.9): + - React-Codegen (= 0.72.7) + - React-Core/RCTVibrationHeaders (= 0.72.7) + - React-jsi (= 0.72.7) + - ReactCommon/turbomodule/core (= 0.72.7) + - React-rncore (0.72.7) + - React-runtimeexecutor (0.72.7): + - React-jsi (= 0.72.7) + - React-runtimescheduler (0.72.7): - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) @@ -612,30 +615,30 @@ PODS: - React-debug - React-jsi - React-runtimeexecutor - - React-utils (0.72.9): + - React-utils (0.72.7): - glog - RCT-Folly (= 2021.07.22.00) - React-debug - - ReactCommon/turbomodule/bridging (0.72.9): + - ReactCommon/turbomodule/bridging (0.72.7): - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.9) - - React-cxxreact (= 0.72.9) - - React-jsi (= 0.72.9) - - React-logger (= 0.72.9) - - React-perflogger (= 0.72.9) - - ReactCommon/turbomodule/core (0.72.9): + - React-callinvoker (= 0.72.7) + - React-cxxreact (= 0.72.7) + - React-jsi (= 0.72.7) + - React-logger (= 0.72.7) + - React-perflogger (= 0.72.7) + - ReactCommon/turbomodule/core (0.72.7): - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.9) - - React-cxxreact (= 0.72.9) - - React-jsi (= 0.72.9) - - React-logger (= 0.72.9) - - React-perflogger (= 0.72.9) + - React-callinvoker (= 0.72.7) + - React-cxxreact (= 0.72.7) + - React-jsi (= 0.72.7) + - React-logger (= 0.72.7) + - React-perflogger (= 0.72.7) - RNBootSplash (4.7.5): - React-Core - RNCAsyncStorage (1.21.0): @@ -714,10 +717,9 @@ PODS: - RCT-Folly (= 2021.07.22.00) - React-Core - ReactCommon/turbomodule/core - - RNScreens (3.34.0): + - RNScreens (3.29.0): - RCT-Folly (= 2021.07.22.00) - React-Core - - React-RCTImage - RNSecureRandom (1.0.1): - React - RNShare (10.2.1): @@ -767,6 +769,7 @@ DEPENDENCIES: - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - react-native-aes (from `../node_modules/react-native-aes-crypto`) - react-native-config (from `../node_modules/react-native-config`) + - react-native-contacts (from `../node_modules/react-native-contacts`) - react-native-date-picker (from `../node_modules/react-native-date-picker`) - react-native-document-picker (from `../node_modules/react-native-document-picker`) - react-native-fingerprint-scanner (from `../node_modules/react-native-fingerprint-scanner`) @@ -888,6 +891,7 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-2023-08-07-RNv0.72.4-813b2def12bc9df02654b3e3653ae4a68d0572e0 RCT-Folly: :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" RCTRequired: @@ -922,6 +926,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-aes-crypto" react-native-config: :path: "../node_modules/react-native-config" + react-native-contacts: + :path: "../node_modules/react-native-contacts" react-native-date-picker: :path: "../node_modules/react-native-date-picker" react-native-document-picker: @@ -1067,8 +1073,8 @@ SPEC CHECKSUMS: BreezSDKLiquid: ebab2b6ffdbf45986b193624c0b37d2a5eb65b24 BVLinearGradient: 880f91a7854faff2df62518f0281afb1c60d49a3 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 - FBLazyVector: dc178b8748748c036ef9493a5d59d6d1f91a36ce - FBReactNativeSpec: d0aaae78e93c89dc2d691d8052a4d2aeb1b461ee + FBLazyVector: 5fbbff1d7734827299274638deb8ba3024f6c597 + FBReactNativeSpec: 638095fe8a01506634d77b260ef8a322019ac671 Firebase: 735108d2d0b67827cd929bfe8254983907c4479f FirebaseABTesting: 01b54808f64fda9d96adc2653bc393e88e21f0da FirebaseAnalytics: 2979c21ead00c520feff30db97ebadd669442f2a @@ -1091,29 +1097,30 @@ SPEC CHECKSUMS: GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 GT3Captcha-iOS: aeb6fed2e8594099821430a89208679e5a55b740 - hermes-engine: 9b9bb14184a11b8ceb4131b09abf634880f0f46d + hermes-engine: 9180d43df05c1ed658a87cc733dc3044cf90c00a libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 OpenSSL-Universal: 6082b0bf950e5636fe0d78def171184e2b3899c2 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 - RCTRequired: f30c3213569b1dc43659ecc549a6536e1e11139e - RCTTypeSafety: e1ed3137728804fa98bce30b70e3da0b8e23054e - React: 54070abee263d5773486987f1cf3a3616710ed52 - React-callinvoker: 794ea19cc4d8ce25921893141e131b9d6b7d02eb - React-Codegen: 10359be5377b1a652839bcfe7b6b5bd7f73ae9f6 - React-Core: 7e2a9c4594083ecc68b91fc4a3f4d567e8c8b3b3 - React-CoreModules: 87cc386c2200862672b76bb02c4574b4b1d11b3c - React-cxxreact: 1100498800597e812f0ce4ec365f4ea47ac39719 - React-debug: 4dca41301a67ab2916b2c99bef60344a7b653ac5 - React-hermes: b871a77ba1c427ca00f075759dc0cc9670484c94 - React-jsi: 1f8d073a00264c6a701c4b7b4f4ef9946f9b2455 - React-jsiexecutor: 5a169b1dd1abad06bed40ab7e1aca883c657d865 - React-jsinspector: 54205b269da20c51417e0fc02c4cde9f29a4bf1a - React-logger: f42d2f2bc4cbb5d19d7c0ce84b8741b1e54e88c8 + RCTRequired: 83bca1c184feb4d2e51c72c8369b83d641443f95 + RCTTypeSafety: 13c4a87a16d7db6cd66006ce9759f073402ef85b + React: e67aa9f99957c7611c392b5e49355d877d6525e2 + React-callinvoker: 2790c09d964c2e5404b5410cde91b152e3746b7b + React-Codegen: e6e05e105ca7cdb990f4d609985a2a689d8d0653 + React-Core: 9283f1e7d0d5e3d33ad298547547b1b43912534c + React-CoreModules: 6312c9b2fec4329d9ae6a2b8c350032d1664c51b + React-cxxreact: 7da72565656c8ac7f97c9a031d0b199bbdec0640 + React-debug: 4accb2b9dc09b575206d2c42f4082990a52ae436 + React-hermes: 1299a94f255f59a72d5baa54a2ca2e1eee104947 + React-jsi: 2208de64c3a41714ac04e86975386fc49116ea13 + React-jsiexecutor: c49502e5d02112247ee4526bc3ccfc891ae3eb9b + React-jsinspector: 8baadae51f01d867c3921213a25ab78ab4fbcd91 + React-logger: 8edc785c47c8686c7962199a307015e2ce9a0e4f react-native-aes: c75c46aa744bef7c2415fdf7f5b2dcb75ca4364d react-native-config: 86038147314e2e6d10ea9972022aa171e6b1d4d8 + react-native-contacts: d9a770b48e7784cbea18ca4e11ec3eed9d3c4686 react-native-date-picker: 06a4d96ab525a163c7a90bccd68833d136b0bb13 react-native-document-picker: b4f4a23b73f864ce17965b284c0757648993805b react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe @@ -1133,23 +1140,23 @@ SPEC CHECKSUMS: react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253 react-native-view-shot: 6b7ed61d77d88580fed10954d45fad0eb2d47688 react-native-webview: bdc091de8cf7f8397653e30182efcd9f772e03b3 - React-NativeModulesApple: 9f72feb8a04020b32417f768a7e1e40eec91fef4 - React-perflogger: cb433f318c6667060fc1f62e26eb58d6eb30a627 - React-RCTActionSheet: 0af3f8ac067e8a1dde902810b7ad169d0a0ec31e - React-RCTAnimation: 453a88e76ba6cb49819686acd8b21ce4d9ee4232 - React-RCTAppDelegate: b9fb07959f227ddd2c458c42ed5ceacbd1e1e367 - React-RCTBlob: fa513d56cdc2b7ad84a7758afc4863c1edd6a8b1 - React-RCTImage: 8e059fbdfab18b86127424dc3742532aab960760 - React-RCTLinking: 05ae2aa525b21a7f1c5069c14330700f470efd97 - React-RCTNetwork: 7ed9d99d028c53e9a23e318f65937f499ba8a6fd - React-RCTSettings: 8b12ebf04d4baa0e259017fcef6cf7abd7d8ac51 - React-RCTText: a062ade9ff1591c46bcb6c5055fd4f96c154b8aa - React-RCTVibration: 87c490b6f01746ab8f9b4e555f514cc030c06731 - React-rncore: 140bc11b316da7003bf039844aef39e1c242d7ad - React-runtimeexecutor: 226ebef5f625878d3028b196cbecbbdeb6f208e4 - React-runtimescheduler: a7b1442e155c6f131d8bdfaac47abdc303f50788 - React-utils: a3ffbc321572ee91911d7bc30965abe9aa4e16af - ReactCommon: 180205f326d59f52e12fa724f5278fcf8fb6afc3 + React-NativeModulesApple: b6868ee904013a7923128892ee4a032498a1024a + React-perflogger: 31ea61077185eb1428baf60c0db6e2886f141a5a + React-RCTActionSheet: 392090a3abc8992eb269ef0eaa561750588fc39d + React-RCTAnimation: 4b3cc6a29474bc0d78c4f04b52ab59bf760e8a9b + React-RCTAppDelegate: 89b015b29885109addcabecdf3b2e833905437c7 + React-RCTBlob: 3e23dcbe6638897b5605e46d0d62955d78e8d27b + React-RCTImage: 8a5d339d614a90a183fc1b8b6a7eb44e2e703943 + React-RCTLinking: b37dfbf646d77c326f9eae094b1fcd575b1c24c7 + React-RCTNetwork: 8bed9b2461c7d8a7d14e63df9b16181c448beebc + React-RCTSettings: 506a5f09a455123a8873801b70aa7b4010b76b01 + React-RCTText: 3c71ecaad8ee010b79632ea2590f86c02f5cce17 + React-RCTVibration: d1b78ca38f61ea4b3e9ebb2ddbd0b5662631d99b + React-rncore: bfc2f6568b6fecbae6f2f774e95c60c3c9e95bf2 + React-runtimeexecutor: 47b0a2d5bbb416db65ef881a6f7bdcfefa0001ab + React-runtimescheduler: 7649c3b46c8dee1853691ecf60146a16ae59253c + React-utils: 56838edeaaf651220d1e53cd0b8934fb8ce68415 + ReactCommon: 5f704096ccf7733b390f59043b6fa9cc180ee4f6 RNBootSplash: 85f6b879c080e958afdb4c62ee04497b05fd7552 RNCAsyncStorage: 618d03a5f52fbccb3d7010076bc54712844c18ef RNCClipboard: 60fed4b71560d7bfe40e9d35dea9762b024da86d @@ -1170,12 +1177,12 @@ SPEC CHECKSUMS: RNKeychain: a65256b6ca6ba6976132cc4124b238a5b13b3d9c RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 RNNotifee: 8e2d3df3f0e9ce8f5d1fe4c967431138190b6175 - RNPermissions: 294531ede5a64d1528463e88fffef05675842042 + RNPermissions: 7a582458b515f5a9c1cba42dec3069d99975ccdf RNQrGenerator: 1676221c08bfabec978242989c733810dad20959 RNRate: ef3bcff84f39bb1d1e41c5593d3eea4aab2bd73a RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9 RNReanimated: fdbaa9c964bbab7fac50c90862b6cc5f041679b9 - RNScreens: 80369e822c4f123c3f076c9ea4141991c17770f9 + RNScreens: 3c5b9f4a9dcde752466854b6109b79c0e205dad3 RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef RNShare: 0fad69ae2d71de9d1f7b9a43acf876886a6cb99c RNSVG: ba3e7232f45e34b7b47e74472386cf4e1a676d0a @@ -1183,9 +1190,9 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654 VisionCamera: 1910a51e4c6f6b049650086d343090f267b4c260 - Yoga: eddf2bbe4a896454c248a8f23b4355891eb720a6 + Yoga: 4c3aa327e4a6a23eeacd71f61c81df1bcdf677d5 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: fed83b93e96c4c2f3d9c69483ced921bac08ce31 +PODFILE CHECKSUM: 50930cce21f222e3be3732b10aa64a17e84e029c COCOAPODS: 1.16.2 diff --git a/package.json b/package.json index bb8726aa8..5928097ba 100644 --- a/package.json +++ b/package.json @@ -128,6 +128,7 @@ "react-native-base64": "^0.2.1", "react-native-bootsplash": "^4.6.0", "react-native-config": "^1.5.1", + "react-native-contacts": "^8.0.7", "react-native-countdown-circle-timer": "^3.2.1", "react-native-country-picker-modal": "^2.0.0", "react-native-crypto": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index b7dc058bf..608beafed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20796,6 +20796,11 @@ react-native-config@^1.5.1: resolved "https://registry.yarnpkg.com/react-native-config/-/react-native-config-1.5.1.tgz#73c94f511493e9b7ff9350cdf351d203a1b05acc" integrity sha512-g1xNgt1tV95FCX+iWz6YJonxXkQX0GdD3fB8xQtR1GUBEqweB9zMROW77gi2TygmYmUkBI7LU4pES+zcTyK4HA== +react-native-contacts@^8.0.7: + version "8.0.7" + resolved "https://registry.yarnpkg.com/react-native-contacts/-/react-native-contacts-8.0.7.tgz#486fcc1cc267a2c5bceb51f46263a3e10dbb2650" + integrity sha512-9JyH+3MXZcOD1+Lm+kl1DeQzT24ayZ//LonTSZM2cln66mHgC2MzW1wBQAJ7EL9eu5NSjSav4c4BIWuOsods6Q== + react-native-countdown-circle-timer@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/react-native-countdown-circle-timer/-/react-native-countdown-circle-timer-3.2.1.tgz#077548e943fcf24b47c7e5ce2f12c1dfa35833c2" From 48e62341c7e6d828708a1c31ec5f36b1e0b13ec3 Mon Sep 17 00:00:00 2001 From: Dread <34528298+islandbitcoin@users.noreply.github.com> Date: Wed, 29 Oct 2025 19:52:44 -0400 Subject: [PATCH 2/2] Remove SMS option and rebase --- app/graphql/generated.gql | 35 ++++ app/graphql/generated.ts | 224 ++++++++++++++++++++- app/i18n/i18n-types.ts | 32 ++- app/i18n/raw-i18n/source/en.json | 4 +- app/screens/invite-friend/InviteFriend.tsx | 52 ++--- ios/Podfile.lock | 140 ++++++------- 6 files changed, 373 insertions(+), 114 deletions(-) diff --git a/app/graphql/generated.gql b/app/graphql/generated.gql index 81163878e..3e3820f68 100644 --- a/app/graphql/generated.gql +++ b/app/graphql/generated.gql @@ -264,6 +264,22 @@ mutation captchaRequestAuthCode($input: CaptchaRequestAuthCodeInput!) { } } +mutation createInvite($input: CreateInviteInput!) { + createInvite(input: $input) { + invite { + id + contact + method + status + createdAt + expiresAt + __typename + } + errors + __typename + } +} + mutation deviceNotificationTokenCreate($input: DeviceNotificationTokenCreateInput!) { deviceNotificationTokenCreate(input: $input) { errors { @@ -517,6 +533,14 @@ mutation quizCompleted($input: QuizCompletedInput!) { } } +mutation redeemInvite($input: RedeemInviteInput!) { + redeemInvite(input: $input) { + success + errors + __typename + } +} + mutation userContactUpdateAlias($input: UserContactUpdateAliasInput!) { userContactUpdateAlias(input: $input) { errors { @@ -1101,6 +1125,17 @@ query homeUnauthed { } } +query invitePreview($token: String!) { + invitePreview(token: $token) { + contact + method + isValid + inviterUsername + expiresAt + __typename + } +} + query language { me { id diff --git a/app/graphql/generated.ts b/app/graphql/generated.ts index a8cb4512e..a161bcd54 100644 --- a/app/graphql/generated.ts +++ b/app/graphql/generated.ts @@ -36,7 +36,7 @@ export type Scalars = { EndpointUrl: { input: string; output: string; } /** Feedback shared with our user */ Feedback: { input: string; output: string; } - /** (Positive) Cent amount (1/100 of a dollar) as a float */ + /** Cent amount (1/100 of a dollar) as a float, can be positive or negative */ FractionalCentAmount: { input: number; output: number; } /** Hex-encoded string of 32 bytes */ Hex32Bytes: { input: string; output: string; } @@ -210,7 +210,7 @@ export type BtcWallet = Wallet & { readonly __typename: 'BTCWallet'; readonly accountId: Scalars['ID']['output']; /** A balance stored in BTC. */ - readonly balance: Scalars['SignedAmount']['output']; + readonly balance: Scalars['FractionalCentAmount']['output']; readonly id: Scalars['ID']['output']; readonly lnurlp?: Maybe; /** An unconfirmed incoming onchain balance. */ @@ -369,6 +369,17 @@ export type Country = { readonly supportedAuthChannels: ReadonlyArray; }; +export type CreateInviteInput = { + readonly contact: Scalars['String']['input']; + readonly method: InviteMethod; +}; + +export type CreateInvitePayload = { + readonly __typename: 'CreateInvitePayload'; + readonly errors: ReadonlyArray; + readonly invite?: Maybe; +}; + export type Currency = { readonly __typename: 'Currency'; readonly flag: Scalars['String']['output']; @@ -450,6 +461,12 @@ export type InitiateCashoutInput = { readonly walletId: Scalars['WalletId']['input']; }; +export type InitiatedCashoutResponse = { + readonly __typename: 'InitiatedCashoutResponse'; + readonly errors: ReadonlyArray; + readonly journalId?: Maybe; +}; + export type InitiationVia = InitiationViaIntraLedger | InitiationViaLn | InitiationViaOnChain; export type InitiationViaIntraLedger = { @@ -498,6 +515,40 @@ export type IntraLedgerUsdPaymentSendInput = { readonly walletId: Scalars['WalletId']['input']; }; +export type Invite = { + readonly __typename: 'Invite'; + readonly contact: Scalars['String']['output']; + readonly createdAt: Scalars['String']['output']; + readonly expiresAt: Scalars['String']['output']; + readonly id: Scalars['ID']['output']; + readonly method: InviteMethod; + readonly status: InviteStatus; +}; + +export const InviteMethod = { + Email: 'EMAIL', + Sms: 'SMS', + Whatsapp: 'WHATSAPP' +} as const; + +export type InviteMethod = typeof InviteMethod[keyof typeof InviteMethod]; +export type InvitePreview = { + readonly __typename: 'InvitePreview'; + readonly contact: Scalars['String']['output']; + readonly expiresAt: Scalars['String']['output']; + readonly inviterUsername?: Maybe; + readonly isValid: Scalars['Boolean']['output']; + readonly method: Scalars['String']['output']; +}; + +export const InviteStatus = { + Accepted: 'ACCEPTED', + Expired: 'EXPIRED', + Pending: 'PENDING', + Sent: 'SENT' +} as const; + +export type InviteStatus = typeof InviteStatus[keyof typeof InviteStatus]; export const InvoicePaymentStatus = { Expired: 'EXPIRED', Paid: 'PAID', @@ -734,13 +785,14 @@ export type Mutation = { readonly callbackEndpointDelete: SuccessPayload; readonly captchaCreateChallenge: CaptchaCreateChallengePayload; readonly captchaRequestAuthCode: SuccessPayload; + readonly createInvite: CreateInvitePayload; readonly deviceNotificationTokenCreate: SuccessPayload; readonly feedbackSubmit: SuccessPayload; /** * Start the Cashout process; * User sends USD to Flash via Ibex and receives USD or JMD to bank account. */ - readonly initiateCashout: SuccessPayload; + readonly initiateCashout: InitiatedCashoutResponse; /** * Actions a payment which is internal to the ledger e.g. it does * not use onchain/lightning. Returns payment status (success, @@ -823,6 +875,7 @@ export type Mutation = { readonly onChainUsdPaymentSend: PaymentSendPayload; readonly onChainUsdPaymentSendAsBtcDenominated: PaymentSendPayload; readonly quizCompleted: QuizCompletedPayload; + readonly redeemInvite: RedeemInvitePayload; /** * Returns an offer from Flash for a user to withdraw from their USD wallet (denominated in cents). * The user can review this offer and then execute the withdrawal by calling the initiateCashout mutation. @@ -896,6 +949,11 @@ export type MutationCaptchaRequestAuthCodeArgs = { }; +export type MutationCreateInviteArgs = { + input: CreateInviteInput; +}; + + export type MutationDeviceNotificationTokenCreateArgs = { input: DeviceNotificationTokenCreateInput; }; @@ -1026,6 +1084,11 @@ export type MutationQuizCompletedArgs = { }; +export type MutationRedeemInviteArgs = { + input: RedeemInviteInput; +}; + + export type MutationRequestCashoutArgs = { input: RequestCashoutInput; }; @@ -1347,6 +1410,7 @@ export type Query = { readonly hasPromptedSetDefaultAccount: Scalars['Boolean']['output']; readonly hiddenBalanceToolTip: Scalars['Boolean']['output']; readonly hideBalance: Scalars['Boolean']['output']; + readonly invitePreview?: Maybe; readonly isFlashNpub?: Maybe; readonly lnInvoicePaymentStatus: LnInvoicePaymentStatusPayload; readonly me?: Maybe; @@ -1382,6 +1446,11 @@ export type QueryBtcPriceListArgs = { }; +export type QueryInvitePreviewArgs = { + token: Scalars['String']['input']; +}; + + export type QueryIsFlashNpubArgs = { input: IsFlashNpubInput; }; @@ -1480,6 +1549,16 @@ export type RealtimePricePayload = { readonly realtimePrice?: Maybe; }; +export type RedeemInviteInput = { + readonly token: Scalars['String']['input']; +}; + +export type RedeemInvitePayload = { + readonly __typename: 'RedeemInvitePayload'; + readonly errors: ReadonlyArray; + readonly success: Scalars['Boolean']['output']; +}; + export type RequestCashoutInput = { /** Amount in USD cents. */ readonly amount: Scalars['USDCents']['input']; @@ -1638,7 +1717,7 @@ export type UpgradePayload = { export type UsdWallet = Wallet & { readonly __typename: 'UsdWallet'; readonly accountId: Scalars['ID']['output']; - readonly balance: Scalars['SignedAmount']['output']; + readonly balance: Scalars['FractionalCentAmount']['output']; readonly id: Scalars['ID']['output']; readonly lnurlp?: Maybe; /** An unconfirmed incoming onchain balance. */ @@ -1896,7 +1975,7 @@ export type UserUpdateUsernamePayload = { /** A generic wallet which stores value in one of our supported currencies. */ export type Wallet = { readonly accountId: Scalars['ID']['output']; - readonly balance: Scalars['SignedAmount']['output']; + readonly balance: Scalars['FractionalCentAmount']['output']; readonly id: Scalars['ID']['output']; readonly lnurlp?: Maybe; readonly pendingIncomingBalance: Scalars['SignedAmount']['output']; @@ -2112,6 +2191,20 @@ export type UserUpdateNpubMutationVariables = Exact<{ export type UserUpdateNpubMutation = { readonly __typename: 'Mutation', readonly userUpdateNpub: { readonly __typename: 'UserUpdateNpubPayload', readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly code?: string | null }>, readonly user?: { readonly __typename: 'User', readonly id: string, readonly npub?: string | null } | null } }; +export type CreateInviteMutationVariables = Exact<{ + input: CreateInviteInput; +}>; + + +export type CreateInviteMutation = { readonly __typename: 'Mutation', readonly createInvite: { readonly __typename: 'CreateInvitePayload', readonly errors: ReadonlyArray, readonly invite?: { readonly __typename: 'Invite', readonly id: string, readonly contact: string, readonly method: InviteMethod, readonly status: InviteStatus, readonly createdAt: string, readonly expiresAt: string } | null } }; + +export type RedeemInviteMutationVariables = Exact<{ + input: RedeemInviteInput; +}>; + + +export type RedeemInviteMutation = { readonly __typename: 'Mutation', readonly redeemInvite: { readonly __typename: 'RedeemInvitePayload', readonly success: boolean, readonly errors: ReadonlyArray } }; + export type AuthQueryVariables = Exact<{ [key: string]: never; }>; @@ -2213,6 +2306,13 @@ export type RealtimePriceUnauthedQueryVariables = Exact<{ export type RealtimePriceUnauthedQuery = { readonly __typename: 'Query', readonly realtimePrice: { readonly __typename: 'RealtimePrice', readonly timestamp: number, readonly denominatorCurrency: string, readonly btcSatPrice: { readonly __typename: 'PriceOfOneSatInMinorUnit', readonly base: number, readonly offset: number }, readonly usdCentPrice: { readonly __typename: 'PriceOfOneUsdCentInMinorUnit', readonly base: number, readonly offset: number } } }; +export type InvitePreviewQueryVariables = Exact<{ + token: Scalars['String']['input']; +}>; + + +export type InvitePreviewQuery = { readonly __typename: 'Query', readonly invitePreview?: { readonly __typename: 'InvitePreview', readonly contact: string, readonly method: string, readonly isValid: boolean, readonly inviterUsername?: string | null, readonly expiresAt: string } | null }; + export type RealtimePriceWsSubscriptionVariables = Exact<{ currency: Scalars['DisplayCurrency']['input']; }>; @@ -3617,6 +3717,81 @@ export function useUserUpdateNpubMutation(baseOptions?: Apollo.MutationHookOptio export type UserUpdateNpubMutationHookResult = ReturnType; export type UserUpdateNpubMutationResult = Apollo.MutationResult; export type UserUpdateNpubMutationOptions = Apollo.BaseMutationOptions; +export const CreateInviteDocument = gql` + mutation createInvite($input: CreateInviteInput!) { + createInvite(input: $input) { + invite { + id + contact + method + status + createdAt + expiresAt + } + errors + } +} + `; +export type CreateInviteMutationFn = Apollo.MutationFunction; + +/** + * __useCreateInviteMutation__ + * + * To run a mutation, you first call `useCreateInviteMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateInviteMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [createInviteMutation, { data, loading, error }] = useCreateInviteMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useCreateInviteMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(CreateInviteDocument, options); + } +export type CreateInviteMutationHookResult = ReturnType; +export type CreateInviteMutationResult = Apollo.MutationResult; +export type CreateInviteMutationOptions = Apollo.BaseMutationOptions; +export const RedeemInviteDocument = gql` + mutation redeemInvite($input: RedeemInviteInput!) { + redeemInvite(input: $input) { + success + errors + } +} + `; +export type RedeemInviteMutationFn = Apollo.MutationFunction; + +/** + * __useRedeemInviteMutation__ + * + * To run a mutation, you first call `useRedeemInviteMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useRedeemInviteMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [redeemInviteMutation, { data, loading, error }] = useRedeemInviteMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useRedeemInviteMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(RedeemInviteDocument, options); + } +export type RedeemInviteMutationHookResult = ReturnType; +export type RedeemInviteMutationResult = Apollo.MutationResult; +export type RedeemInviteMutationOptions = Apollo.BaseMutationOptions; export const AuthDocument = gql` query auth { me { @@ -4397,6 +4572,45 @@ export function useRealtimePriceUnauthedLazyQuery(baseOptions?: Apollo.LazyQuery export type RealtimePriceUnauthedQueryHookResult = ReturnType; export type RealtimePriceUnauthedLazyQueryHookResult = ReturnType; export type RealtimePriceUnauthedQueryResult = Apollo.QueryResult; +export const InvitePreviewDocument = gql` + query invitePreview($token: String!) { + invitePreview(token: $token) { + contact + method + isValid + inviterUsername + expiresAt + } +} + `; + +/** + * __useInvitePreviewQuery__ + * + * To run a query within a React component, call `useInvitePreviewQuery` and pass it any options that fit your needs. + * When your component renders, `useInvitePreviewQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useInvitePreviewQuery({ + * variables: { + * token: // value for 'token' + * }, + * }); + */ +export function useInvitePreviewQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(InvitePreviewDocument, options); + } +export function useInvitePreviewLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(InvitePreviewDocument, options); + } +export type InvitePreviewQueryHookResult = ReturnType; +export type InvitePreviewLazyQueryHookResult = ReturnType; +export type InvitePreviewQueryResult = Apollo.QueryResult; export const RealtimePriceWsDocument = gql` subscription realtimePriceWs($currency: DisplayCurrency!) { realtimePrice(input: {currency: $currency}) { diff --git a/app/i18n/i18n-types.ts b/app/i18n/i18n-types.ts index c74cef34f..0278e1d7e 100644 --- a/app/i18n/i18n-types.ts +++ b/app/i18n/i18n-types.ts @@ -1728,6 +1728,14 @@ type RootTranslation = { * B​a​c​k​u​p​ ​y​o​u​r​ ​c​a​s​h​ ​w​a​l​l​e​t​ ​a​n​d​ ​i​n​c​r​e​a​s​e​ ​t​r​a​n​s​a​c​t​i​o​n​ ​l​i​m​i​t​s​. */ upgradeDesc: string + /** + * I​n​v​i​t​e​ ​F​r​i​e​n​d​s + */ + inviteTitle: string + /** + * G​e​t​ ​r​e​w​a​r​d​s​ ​f​o​r​ ​i​n​v​i​t​i​n​g​ ​f​r​i​e​n​d​s​ ​t​o​ ​F​l​a​s​h + */ + inviteDesc: string /** * C​h​a​n​g​e​ ​t​o​ ​y​o​u​r​ ​l​o​c​a​l​ ​c​u​r​r​e​n​c​y */ @@ -2708,7 +2716,7 @@ type RootTranslation = { */ advanceMode: string /** - * K​e​y​​ ​m​a​n​a​g​e​m​e​n​t + * K​e​y​ ​m​a​n​a​g​e​m​e​n​t */ keysManagement: string /** @@ -2734,7 +2742,7 @@ type RootTranslation = { */ title: string /** - * E​n​t​e​r​ ​a​ ​p​h​o​n​e​ ​n​u​m​b​e​r​ ​o​r​ ​e​m​a​i​l​ ​a​d​d​r​e​s​s​ ​t​o​ ​i​n​v​i​t​e​ ​a​ ​f​r​i​e​n​d​. + * E​n​t​e​r​ ​a​ ​p​h​o​n​e​ ​n​u​m​b​e​r​ ​o​r​ ​e​m​a​i​l​ ​a​d​d​r​e​s​s​ ​t​o​ ​i​n​v​i​t​e​ ​a​ ​f​r​i​e​n​d​.​ ​B​y​ ​i​n​v​i​t​i​n​g​ ​a​ ​f​r​i​e​n​d​,​ ​y​o​u​ ​c​o​n​f​i​r​m​ ​t​h​a​t​ ​t​h​e​ ​r​e​c​i​p​i​e​n​t​ ​h​a​s​ ​g​i​v​e​n​ ​c​o​n​s​e​n​t​ ​t​o​ ​r​e​c​e​i​v​e​ ​t​h​i​s​ ​i​n​v​i​t​a​t​i​o​n​. */ subtitle: string /** @@ -6503,6 +6511,14 @@ export type TranslationFunctions = { * Backup your cash wallet and increase transaction limits. */ upgradeDesc: () => LocalizedString + /** + * Invite Friends + */ + inviteTitle: () => LocalizedString + /** + * Get rewards for inviting friends to Flash + */ + inviteDesc: () => LocalizedString /** * Change to your local currency */ @@ -7284,23 +7300,23 @@ export type TranslationFunctions = { /** * The amount you entered is less than the minimum amount required to send an on-chain transaction {amount}. Please consider sending this amount via Lightning! */ - onchainMinAmountInvoiceError: (arg: { amount: number | string }) => LocalizedString + onchainMinAmountInvoiceError: (arg: { amount: number }) => LocalizedString /** * The amount on the invoice is less than minimum amount {amount} */ - minAmountInvoiceError: (arg: { amount: number | string }) => LocalizedString + minAmountInvoiceError: (arg: { amount: number }) => LocalizedString /** * The amount on the invoice is greater than maximum amount {amount} */ - maxAmountInvoiceError: (arg: { amount: number | string }) => LocalizedString + maxAmountInvoiceError: (arg: { amount: number }) => LocalizedString /** * The conversion amount is less than minimum required amount {amount} */ - minAmountConvertError: (arg: { amount: number | string }) => LocalizedString + minAmountConvertError: (arg: { amount: number }) => LocalizedString /** * The conversion amount is greater than maximum amount {amount} */ - maxAmountConvertError: (arg: { amount: number | string }) => LocalizedString + maxAmountConvertError: (arg: { amount: number }) => LocalizedString } SettingsScreen: { /** @@ -7470,7 +7486,7 @@ export type TranslationFunctions = { */ title: () => LocalizedString /** - * Enter a phone number or email address to invite a friend. + * Enter a phone number or email address to invite a friend. By inviting a friend, you confirm that the recipient has given consent to receive this invitation. */ subtitle: () => LocalizedString /** diff --git a/app/i18n/raw-i18n/source/en.json b/app/i18n/raw-i18n/source/en.json index 63d82909e..780fa594b 100644 --- a/app/i18n/raw-i18n/source/en.json +++ b/app/i18n/raw-i18n/source/en.json @@ -521,6 +521,8 @@ "addFlashcard": "Add Flashcard", "upgradeTitle": "Add your phone number", "upgradeDesc": "Backup your cash wallet and increase transaction limits.", + "inviteTitle": "Invite Friends", + "inviteDesc": "Get rewards for inviting friends to Flash", "currencyTitle": "Change to your local currency", "currencyDesc": "Review our available currency list and select your currency.", "flashcardTitle": "Get a Flashcard", @@ -778,7 +780,7 @@ "InviteFriend": { "invitation": "Invitation", "title": "Invite a friend to Flash!", - "subtitle": "Enter a phone number or email address to invite a friend.", + "subtitle": "Enter a phone number or email address to invite a friend. By inviting a friend, you confirm that the recipient has given consent to receive this invitation.", "phoneNumber": "Enter phone number", "email": "Enter email address", "invite": "Invite", diff --git a/app/screens/invite-friend/InviteFriend.tsx b/app/screens/invite-friend/InviteFriend.tsx index 74f911f48..c73b118fe 100644 --- a/app/screens/invite-friend/InviteFriend.tsx +++ b/app/screens/invite-friend/InviteFriend.tsx @@ -18,7 +18,6 @@ import { Screen } from "@app/components/screen" import { PrimaryBtn } from "@app/components/buttons" import { EmailInput, PhoneNumberInput } from "@app/components/input" import { ContactPicker } from "@app/components/contact-picker" -import { ButtonGroup } from "@app/components/button-group" type Props = StackScreenProps type InputMethod = "contacts" | "phone" | "email" @@ -36,7 +35,6 @@ const InviteFriend: React.FC = ({ navigation }) => { const [phoneNumber, setPhoneNumber] = useState() const [email, setEmail] = useState() const [loading, setLoading] = useState(false) - const [phoneMethod, setPhoneMethod] = useState<"whatsapp" | "sms">("whatsapp") const [showContactPicker, setShowContactPicker] = useState(false) const [createInvite] = useCreateInviteMutation() @@ -116,7 +114,7 @@ const InviteFriend: React.FC = ({ navigation }) => { ) if (parsedPhoneNumber?.isValid()) { contact = parsedPhoneNumber.format("E.164") - method = phoneMethod === "whatsapp" ? InviteMethod.Whatsapp : InviteMethod.Sms + method = InviteMethod.Whatsapp } else { Alert.alert("Error", "Please enter a valid phone number") return @@ -211,25 +209,12 @@ const InviteFriend: React.FC = ({ navigation }) => { setPhoneNumber={setPhoneNumber} /> - {/* SMS/WhatsApp selection */} - - Send via: - setPhoneMethod(id as "whatsapp" | "sms")} - /> + {/* WhatsApp indicator */} + + + + Invitation will be sent via WhatsApp + ) @@ -309,7 +294,7 @@ const InviteFriend: React.FC = ({ navigation }) => { ]} > @@ -320,7 +305,7 @@ const InviteFriend: React.FC = ({ navigation }) => { inputMethod === "phone" && styles.iconLabelActive, ]} > - Phone + WhatsApp @@ -486,14 +471,21 @@ const useStyles = makeStyles(({ colors }) => ({ color: colors.grey3, textAlign: "center", }, - phoneMethodSelector: { - marginTop: 24, + whatsappIndicator: { + flexDirection: "row", + alignItems: "center", + justifyContent: "center", + marginTop: 16, + paddingVertical: 8, + paddingHorizontal: 12, + backgroundColor: colors.grey5, + borderRadius: 8, }, - sendViaText: { + whatsappText: { fontSize: 14, - fontWeight: "600", - color: colors.black, - marginBottom: 12, + color: colors.grey1, + marginLeft: 8, + fontWeight: "500", }, inputHint: { marginTop: 12, diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 74f25d3f7..21a74446e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1068,10 +1068,10 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f boost: 7dcd2de282d72e344012f7d6564d024930a6a440 - breez_sdk_liquid: c1ca8548830cd519e7443e9358b2ea97b4cc4461 + breez_sdk_liquid: 481504dda7faf1e6a66208fa9b451e307079113e breez_sdk_liquidFFI: 1091fe9e2d677e7c3b0296848037338b419d0405 BreezSDKLiquid: ebab2b6ffdbf45986b193624c0b37d2a5eb65b24 - BVLinearGradient: 880f91a7854faff2df62518f0281afb1c60d49a3 + BVLinearGradient: cb006ba232a1f3e4f341bb62c42d1098c284da70 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: 5fbbff1d7734827299274638deb8ba3024f6c597 FBReactNativeSpec: 638095fe8a01506634d77b260ef8a322019ac671 @@ -1103,49 +1103,49 @@ SPEC CHECKSUMS: OpenSSL-Universal: 6082b0bf950e5636fe0d78def171184e2b3899c2 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 - RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCT-Folly: 8dc08ca5a393b48b1c523ab6220dfdcc0fe000ad RCTRequired: 83bca1c184feb4d2e51c72c8369b83d641443f95 RCTTypeSafety: 13c4a87a16d7db6cd66006ce9759f073402ef85b React: e67aa9f99957c7611c392b5e49355d877d6525e2 React-callinvoker: 2790c09d964c2e5404b5410cde91b152e3746b7b - React-Codegen: e6e05e105ca7cdb990f4d609985a2a689d8d0653 - React-Core: 9283f1e7d0d5e3d33ad298547547b1b43912534c - React-CoreModules: 6312c9b2fec4329d9ae6a2b8c350032d1664c51b - React-cxxreact: 7da72565656c8ac7f97c9a031d0b199bbdec0640 + React-Codegen: 89173b1974099c3082e50c83e9d04113ede45792 + React-Core: 27990a32ca0cfc04872600440f618365b7c35433 + React-CoreModules: 2a1850a46d60b901cceef4e64bcf5bf6a0130206 + React-cxxreact: 03d370d58a083a1c8b5a69b9095c1ac9f57b2f94 React-debug: 4accb2b9dc09b575206d2c42f4082990a52ae436 - React-hermes: 1299a94f255f59a72d5baa54a2ca2e1eee104947 - React-jsi: 2208de64c3a41714ac04e86975386fc49116ea13 - React-jsiexecutor: c49502e5d02112247ee4526bc3ccfc891ae3eb9b + React-hermes: 0a9e25fbf4dbcd8ca89de9a89a0cce2fce45989f + React-jsi: 0c473d4292f9a10469b3755767bf28d0b35fbeb6 + React-jsiexecutor: 00fdf7bd0e99ab878109ce1b51cb6212d76683e4 React-jsinspector: 8baadae51f01d867c3921213a25ab78ab4fbcd91 - React-logger: 8edc785c47c8686c7962199a307015e2ce9a0e4f - react-native-aes: c75c46aa744bef7c2415fdf7f5b2dcb75ca4364d - react-native-config: 86038147314e2e6d10ea9972022aa171e6b1d4d8 - react-native-contacts: d9a770b48e7784cbea18ca4e11ec3eed9d3c4686 - react-native-date-picker: 06a4d96ab525a163c7a90bccd68833d136b0bb13 - react-native-document-picker: b4f4a23b73f864ce17965b284c0757648993805b - react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe - react-native-geetest-module: ed6a20774a7975640b79a2f639327c674a488cb5 - react-native-get-random-values: 384787fd76976f5aec9465aff6fa9e9129af1e74 - react-native-html-to-pdf: 4c5c6e26819fe202971061594058877aa9b25265 - react-native-image-picker: 5e076db26cd81660cfb6db5bcf517cfa12054d45 - react-native-in-app-review: db8bb167a5f238e7ceca5c242d6b36ce8c4404a4 - react-native-maps: 084fccedd6785bd41e85a13a26e8e6252a45b594 - react-native-nfc-manager: 2a87d561c4fa832e6597a5f2f7c197808c019ab8 - react-native-pager-view: e26d35e382d86950c936f8917e3beb9188115ccc - react-native-quick-crypto: b859e7bc40b1fdd0d9f4b0a1475304fd3e2e216c - react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846 - react-native-safe-area-context: 0ee144a6170530ccc37a0fd9388e28d06f516a89 - react-native-secure-key-store: 910e6df6bc33cb790aba6ee24bc7818df1fe5898 - react-native-slider: cc89964e1432fa31aa9db7a0fa9b21e26b5d5152 - react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253 - react-native-view-shot: 6b7ed61d77d88580fed10954d45fad0eb2d47688 - react-native-webview: bdc091de8cf7f8397653e30182efcd9f772e03b3 - React-NativeModulesApple: b6868ee904013a7923128892ee4a032498a1024a + React-logger: 61efd44da84482aabbbbb478a49b893c7c912f99 + react-native-aes: bed3ca6c47c5a5ebd5bac683efdf737c874f6d3f + react-native-config: 136f9755ccc991cc6438053a44363259ad4c7813 + react-native-contacts: 2be02d0d63726f388cac53413044a7299391365f + react-native-date-picker: 585252087d4820b4cd8f2cf80068f6e8f5b72413 + react-native-document-picker: 74f5ca4179532f9ff205275990af514d1f2e22d8 + react-native-fingerprint-scanner: 91bf6825709dd7bd3abc4588a4772eb097a2b2d8 + react-native-geetest-module: cecd5dfca2c7f815a8e724c11137b35c92e900d3 + react-native-get-random-values: ce0b8796c99e2b85e3202bd500b1ef286a17a02e + react-native-html-to-pdf: 7a49e6c58ac5221bcc093027b195f4b214f27a9d + react-native-image-picker: 7a3502135a13fc56d406f5213b7346de6bc5f38b + react-native-in-app-review: b3d1eed3d1596ebf6539804778272c4c65e4a400 + react-native-maps: 2173cbaddcef764af9a8ed56883b7672d6fc8337 + react-native-nfc-manager: ab799bdeecbb12b199bccdb0065cbb4d3271c1e4 + react-native-pager-view: 8f36f88437684bf5ea86f9172a91c266d99b975f + react-native-quick-crypto: 1daacdde8771548da81d783a1778aba55a7bbf8c + react-native-randombytes: 3c8f3e89d12487fd03a2f966c288d495415fc116 + react-native-safe-area-context: bf9d9d58f0f6726d4a6257088044c2595017579d + react-native-secure-key-store: eb45b44bdec3f48e9be5cdfca0f49ddf64892ea6 + react-native-slider: 2ee855f44d8024139690ad4581cec2d51c616456 + react-native-video: 2aad0d963bf3952bd9ebb2f53fab799338e8e202 + react-native-view-shot: d1a701eb0719c6dccbd20b4bb43b1069f304cb70 + react-native-webview: 11105d80264df1a56fbbb0c774311a52bb287388 + React-NativeModulesApple: 2f7a355e9b4c83b9509bf6dd798dc5f63ab8bc7d React-perflogger: 31ea61077185eb1428baf60c0db6e2886f141a5a React-RCTActionSheet: 392090a3abc8992eb269ef0eaa561750588fc39d React-RCTAnimation: 4b3cc6a29474bc0d78c4f04b52ab59bf760e8a9b - React-RCTAppDelegate: 89b015b29885109addcabecdf3b2e833905437c7 - React-RCTBlob: 3e23dcbe6638897b5605e46d0d62955d78e8d27b + React-RCTAppDelegate: b6febbe1109554fee87d3fea1c50cca511429fec + React-RCTBlob: 76113160e3cdc0f678795823c1a7c9d69b2db099 React-RCTImage: 8a5d339d614a90a183fc1b8b6a7eb44e2e703943 React-RCTLinking: b37dfbf646d77c326f9eae094b1fcd575b1c24c7 React-RCTNetwork: 8bed9b2461c7d8a7d14e63df9b16181c448beebc @@ -1154,42 +1154,42 @@ SPEC CHECKSUMS: React-RCTVibration: d1b78ca38f61ea4b3e9ebb2ddbd0b5662631d99b React-rncore: bfc2f6568b6fecbae6f2f774e95c60c3c9e95bf2 React-runtimeexecutor: 47b0a2d5bbb416db65ef881a6f7bdcfefa0001ab - React-runtimescheduler: 7649c3b46c8dee1853691ecf60146a16ae59253c - React-utils: 56838edeaaf651220d1e53cd0b8934fb8ce68415 - ReactCommon: 5f704096ccf7733b390f59043b6fa9cc180ee4f6 - RNBootSplash: 85f6b879c080e958afdb4c62ee04497b05fd7552 - RNCAsyncStorage: 618d03a5f52fbccb3d7010076bc54712844c18ef - RNCClipboard: 60fed4b71560d7bfe40e9d35dea9762b024da86d - RNDateTimePicker: 65e1d202799460b286ff5e741d8baf54695e8abd - RNDeviceInfo: db5c64a060e66e5db3102d041ebe3ef307a85120 - RNFBAnalytics: 8d1705b9076df1ed0b72a165d78c303e8569807b - RNFBApp: fa5825b36d8362ce9b993cac8bf070d116848640 - RNFBAppCheck: f98d1bd525efe4e22f28c6070796434c9baf6e9a - RNFBCrashlytics: 14dcfb073e7d9f41189400128e203d5314a8c606 - RNFBMessaging: 32a107c0463048f1c03df06ab235bf56e976299a - RNFBPerf: a3f48919b73a6355113735a463f048a772fc79a4 - RNFBRemoteConfig: f2d4de1a288ede64e777f3229c7746ed4127ccb3 - RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592 - RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 - RNGestureHandler: c0d04458598fcb26052494ae23dda8f8f5162b13 - RNImageCropPicker: 14fe1c29298fb4018f3186f455c475ab107da332 - RNInAppBrowser: e36d6935517101ccba0e875bac8ad7b0cb655364 - RNKeychain: a65256b6ca6ba6976132cc4124b238a5b13b3d9c - RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 - RNNotifee: 8e2d3df3f0e9ce8f5d1fe4c967431138190b6175 - RNPermissions: 7a582458b515f5a9c1cba42dec3069d99975ccdf - RNQrGenerator: 1676221c08bfabec978242989c733810dad20959 - RNRate: ef3bcff84f39bb1d1e41c5593d3eea4aab2bd73a - RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9 - RNReanimated: fdbaa9c964bbab7fac50c90862b6cc5f041679b9 - RNScreens: 3c5b9f4a9dcde752466854b6109b79c0e205dad3 - RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef - RNShare: 0fad69ae2d71de9d1f7b9a43acf876886a6cb99c - RNSVG: ba3e7232f45e34b7b47e74472386cf4e1a676d0a - RNVectorIcons: 64e6a523ac30a3241efa9baf1ffbcc5e76ff747a + React-runtimescheduler: d12a963f61390fcd1b957a9c9ebee3c0f775dede + React-utils: 22f94a6e85b1323ffb1b9a747a1c03c5e6eaead6 + ReactCommon: ef602e9cfb8940ad7c08aa4cdc228d802e194e5c + RNBootSplash: 21095c4567847829470786b03b6892c5efed5299 + RNCAsyncStorage: a03b770a50541a761447cea9c24536047832124d + RNCClipboard: 4abb037e8fe3b98a952564c9e0474f91c492df6d + RNDateTimePicker: 47b54bf36a41c29d75ac62a05af1b38a9a721631 + RNDeviceInfo: addb9b427c2822a2d8e94c87a136a224e0af738c + RNFBAnalytics: 81e00e4209b0a6268c2a8b262d7e451493bda824 + RNFBApp: 2b2bb0f17eb6732e2e90d9c57bfde443cd7fc681 + RNFBAppCheck: 6e2df9110387283d00ff126d3903c9f79987d1c8 + RNFBCrashlytics: 266758adee95705af20f106c767e19588a5de665 + RNFBMessaging: 4627e84e9e363953357dd122543e4223c49e6bc1 + RNFBPerf: 594a4c7bb12fb68e920e101192539da748973da8 + RNFBRemoteConfig: 4842e7c1b0bb8d2f9c2acc3b811e6395eddfe550 + RNFileViewer: 4b5d83358214347e4ab2d4ca8d5c1c90d869e251 + RNFS: 89de7d7f4c0f6bafa05343c578f61118c8282ed8 + RNGestureHandler: 627182485becfd74f122c83f93cce2be20c2e8c8 + RNImageCropPicker: 874e26cbf0ce9d06a11002cbadf29c8b7f2f5565 + RNInAppBrowser: 6d3eb68d471b9834335c664704719b8be1bfdb20 + RNKeychain: df33ae4d27df06622fc14190b790ba8749f6be76 + RNLocalize: 8bf466de4c92d4721b254aabe1ff0a1456e7b9f4 + RNNotifee: 8768d065bf1e2f9f8f347b4bd79147431c7eacd6 + RNPermissions: 963fdb9cf67420e1eaf915940f523b340aa0e2b8 + RNQrGenerator: 60eab4f7c9e3f09db78029636fe356dca5cb585f + RNRate: 7641919330e0d6688ad885a985b4bd697ed7d14c + RNReactNativeHapticFeedback: a6fb5b7a981683bf58af43e3fb827d4b7ed87f83 + RNReanimated: 49a1e0d191bdaefe1b394eb258bc52a42bcf704c + RNScreens: a425ae50ad66d024a6e936121bf5c9fbe6a5cdc6 + RNSecureRandom: b64d263529492a6897e236a22a2c4249aa1b53dc + RNShare: 694e19d7f74ac4c04de3a8af0649e9ccc03bd8b1 + RNSVG: 6d5ed33b6635ed6d6ecb50744dcf127580c39ed5 + RNVectorIcons: 2bb1ff267624f4e79188d65908c959fd284c5003 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654 - VisionCamera: 1910a51e4c6f6b049650086d343090f267b4c260 + VisionCamera: 29095ffe0a146b6254c3db34636d10298b169f36 Yoga: 4c3aa327e4a6a23eeacd71f61c81df1bcdf677d5 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5