diff --git a/.typesafe-i18n.json b/.typesafe-i18n.json
index d40474af1..753a37c8d 100644
--- a/.typesafe-i18n.json
+++ b/.typesafe-i18n.json
@@ -1,5 +1,5 @@
{
"adapter": "react",
- "$schema": "https://unpkg.com/typesafe-i18n@5.26.2/schema/typesafe-i18n.json",
+ "$schema": "https://unpkg.com/typesafe-i18n@5.27.1/schema/typesafe-i18n.json",
"outputPath": "./app/i18n"
}
\ No newline at end of file
diff --git a/app/assets/icons/arrow-down-to-bracket.svg b/app/assets/icons/arrow-down-to-bracket.svg
new file mode 100644
index 000000000..b2fa9fff6
--- /dev/null
+++ b/app/assets/icons/arrow-down-to-bracket.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/assets/icons/arrow-up-down.svg b/app/assets/icons/arrow-up-down.svg
new file mode 100644
index 000000000..57c0bc041
--- /dev/null
+++ b/app/assets/icons/arrow-up-down.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/assets/icons/arrow-up-from-bracket.svg b/app/assets/icons/arrow-up-from-bracket.svg
new file mode 100644
index 000000000..7ce3e68b0
--- /dev/null
+++ b/app/assets/icons/arrow-up-from-bracket.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/components/button-group/button-group.tsx b/app/components/button-group/button-group.tsx
index ee940524a..ae52fa8c2 100644
--- a/app/components/button-group/button-group.tsx
+++ b/app/components/button-group/button-group.tsx
@@ -1,13 +1,13 @@
import React from "react"
-import { StyleProp, TouchableWithoutFeedback, View, ViewStyle } from "react-native"
-import { Text, makeStyles } from "@rneui/themed"
+import { StyleProp, TouchableOpacity, View, ViewStyle } from "react-native"
+import { Text, makeStyles, useTheme } from "@rneui/themed"
import Icon from "react-native-vector-icons/Ionicons"
import { testProps } from "@app/utils/testProps"
type ButtonForButtonGroupProps = {
id: string
text: string
- icon:
+ icon?:
| string
| {
selected: React.ReactElement
@@ -21,22 +21,37 @@ const ButtonForButtonGroup: React.FC<
onPress: () => void
}
> = ({ text, icon, selected, onPress }) => {
+ const { colors } = useTheme().theme
const styles = useStyles(Boolean(selected))
return (
-
-
-
- {text}
-
- {typeof icon === "string" ? (
-
+
+ {icon &&
+ (typeof icon === "string" ? (
+
) : selected ? (
icon.selected
) : (
icon.normal
- )}
-
-
+ ))}
+
+ {text}
+
+
)
}
@@ -85,20 +100,19 @@ const useStyles = makeStyles(({ colors }, selected: boolean) => ({
flex: 1,
flexDirection: "row",
alignItems: "center",
- justifyContent: "space-between",
- padding: 10,
- paddingVertical: 15,
- marginHorizontal: 3,
- borderRadius: 5,
- backgroundColor: selected ? colors.grey4 : colors.grey5,
+ padding: 15,
+ borderRadius: 10,
+ borderWidth: 1,
+ borderColor: colors.grey4,
+ backgroundColor: colors.grey5,
},
- text: {
+ iconText: {
fontSize: 16,
color: selected ? colors.primary : colors.grey1,
+ marginRight: 8,
},
buttonGroup: {
flexDirection: "row",
- justifyContent: "space-between",
- alignItems: "center",
+ gap: 10,
},
}))
diff --git a/app/components/buttons/IconBtn.tsx b/app/components/buttons/IconBtn.tsx
index 638de9c5d..ea17a6588 100644
--- a/app/components/buttons/IconBtn.tsx
+++ b/app/components/buttons/IconBtn.tsx
@@ -10,6 +10,7 @@ import QR from "@app/assets/icons/qr-code-new.svg"
import Setting from "@app/assets/icons/setting.svg"
import CardRemove from "@app/assets/icons/card-remove.svg"
import Dollar from "@app/assets/icons/dollar-new.svg"
+import ArrowUpDown from "@app/assets/icons/arrow-up-down.svg"
const icons = {
up: ArrowUp,
@@ -19,6 +20,7 @@ const icons = {
setting: Setting,
cardRemove: CardRemove,
dollar: Dollar,
+ upDown: ArrowUpDown,
}
type IconNamesType = keyof typeof icons
diff --git a/app/components/cashout-flow/index.ts b/app/components/cashout-flow/index.ts
deleted file mode 100644
index 338db47b5..000000000
--- a/app/components/cashout-flow/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import CashoutFromWallet from "./CashoutFromWallet"
-import CashoutPercentage from "./CashoutPercentage"
-import CashoutCard from "./CashoutCard"
-
-export { CashoutFromWallet, CashoutPercentage, CashoutCard }
diff --git a/app/components/home-screen/Buttons.tsx b/app/components/home-screen/Buttons.tsx
index 61d274f40..a8814dbcd 100644
--- a/app/components/home-screen/Buttons.tsx
+++ b/app/components/home-screen/Buttons.tsx
@@ -68,13 +68,13 @@ const Buttons: React.FC = ({ setModalVisible, setDefaultAccountModalVisib
})
}
- // if (currentLevel === AccountLevel.Two) {
- // buttons.push({
- // title: LL.Cashout.title(),
- // target: "CashoutDetails",
- // icon: "dollar",
- // })
- // }
+ if (currentLevel === AccountLevel.Two || currentLevel === AccountLevel.Three) {
+ buttons.push({
+ title: LL.HomeScreen.transfer(),
+ target: "TopupCashout",
+ icon: "upDown",
+ })
+ }
return (
diff --git a/app/components/topup-cashout-flow/BridgeKycModal.tsx b/app/components/topup-cashout-flow/BridgeKycModal.tsx
new file mode 100644
index 000000000..d73068fc1
--- /dev/null
+++ b/app/components/topup-cashout-flow/BridgeKycModal.tsx
@@ -0,0 +1,223 @@
+import React, { useState } from "react"
+import {
+ KeyboardAvoidingView,
+ Modal,
+ Platform,
+ ScrollView,
+ TouchableOpacity,
+ View,
+} from "react-native"
+import { Icon, Text, makeStyles, useTheme } from "@rneui/themed"
+import { useSafeAreaInsets } from "react-native-safe-area-context"
+import { useI18nContext } from "@app/i18n/i18n-react"
+
+import { InputField } from "@app/components/account-upgrade-flow"
+import { PrimaryBtn } from "@app/components/buttons"
+import { ButtonGroup } from "@app/components/button-group"
+
+type BridgeKycModalProps = {
+ visible: boolean
+ onClose: () => void
+ onSubmit: (data: { fullName: string; email: string; kycType: string }) => void
+}
+
+const BridgeKycModal: React.FC = ({
+ visible,
+ onClose,
+ onSubmit,
+}) => {
+ const styles = useStyles()
+ const { colors, mode } = useTheme().theme
+ const bottom = useSafeAreaInsets().bottom
+ const { LL } = useI18nContext()
+
+ const [fullName, setFullName] = useState("")
+ const [email, setEmail] = useState("")
+ const [kycType, setKycType] = useState("")
+
+ const [fullNameErr, setFullNameErr] = useState()
+ const [emailErr, setEmailErr] = useState()
+ const [kycTypeErr, setKycTypeErr] = useState()
+
+ const kycTypeButtons = [
+ { id: "individual", text: LL.BridgeKyc.individual() },
+ { id: "business", text: LL.BridgeKyc.business() },
+ ]
+
+ const validate = (): boolean => {
+ let isValid = true
+
+ if (!fullName.trim()) {
+ setFullNameErr(LL.BridgeKyc.fullNameRequired())
+ isValid = false
+ }
+
+ if (!email.trim()) {
+ setEmailErr(LL.BridgeKyc.emailRequired())
+ isValid = false
+ } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim())) {
+ setEmailErr(LL.BridgeKyc.invalidEmail())
+ isValid = false
+ }
+
+ if (!kycType) {
+ setKycTypeErr(LL.BridgeKyc.kycTypeRequired())
+ isValid = false
+ }
+
+ return isValid
+ }
+
+ const handleSubmit = () => {
+ if (!validate()) return
+ onSubmit({ fullName: fullName.trim(), email: email.trim(), kycType })
+ }
+
+ const handleClose = () => {
+ setFullName("")
+ setEmail("")
+ setKycType("")
+ setFullNameErr(undefined)
+ setEmailErr(undefined)
+ setKycTypeErr(undefined)
+ onClose()
+ }
+
+ return (
+
+
+
+ true}
+ >
+
+ {LL.BridgeKyc.title()}
+
+
+
+
+
+
+
+ {LL.BridgeKyc.description()}
+
+
+ {
+ setFullNameErr(undefined)
+ setFullName(val)
+ }}
+ />
+
+ {
+ setEmailErr(undefined)
+ setEmail(val)
+ }}
+ />
+
+
+
+ {LL.BridgeKyc.kycType()}
+
+ {
+ setKycTypeErr(undefined)
+ setKycType(id)
+ }}
+ style={styles.kycTypeRow}
+ />
+ {!!kycTypeErr && (
+
+ {kycTypeErr}
+
+ )}
+
+
+
+
+
+
+
+
+ )
+}
+
+export default BridgeKycModal
+
+const useStyles = makeStyles(() => ({
+ backdrop: {
+ flex: 1,
+ justifyContent: "flex-end",
+ },
+ keyboardAvoid: {
+ justifyContent: "flex-end",
+ },
+ modalContainer: {
+ borderTopLeftRadius: 20,
+ borderTopRightRadius: 20,
+ paddingTop: 20,
+ paddingHorizontal: 20,
+ },
+ modalHeader: {
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ marginBottom: 15,
+ },
+ closeBtn: {
+ padding: 5,
+ },
+ description: {
+ marginBottom: 20,
+ },
+ submitBtn: {
+ marginTop: 10,
+ },
+ kycTypeWrapper: {
+ marginBottom: 15,
+ },
+ kycTypeRow: {
+ marginTop: 5,
+ marginBottom: 2,
+ },
+}))
diff --git a/app/components/topup-cashout-flow/CashWalletCutoverModal.tsx b/app/components/topup-cashout-flow/CashWalletCutoverModal.tsx
new file mode 100644
index 000000000..3f1b34d1d
--- /dev/null
+++ b/app/components/topup-cashout-flow/CashWalletCutoverModal.tsx
@@ -0,0 +1,105 @@
+import React, { useState } from "react"
+import { useWindowDimensions, View } from "react-native"
+import Modal from "react-native-modal"
+import { makeStyles, Text, useTheme } from "@rneui/themed"
+import { useI18nContext } from "@app/i18n/i18n-react"
+import { PrimaryBtn } from "@app/components/buttons"
+import DollarIllustration from "@app/assets/illustrations/dollar.svg"
+
+const CashWalletCutoverModal = () => {
+ const { LL } = useI18nContext()
+ const styles = useStyles()
+ const { width } = useWindowDimensions()
+ const { colors } = useTheme().theme
+
+ const [visible, setVisible] = useState(false)
+
+ const illustrationSize = Math.min(width * 0.35, 140)
+
+ return (
+ setVisible(false)}
+ onSwipeComplete={() => setVisible(false)}
+ swipeDirection={["down"]}
+ style={styles.modal}
+ useNativeDriverForBackdrop
+ >
+
+
+
+
+
+
+
+
+
+
+ {LL.CashWalletCutover.title()}
+
+
+ {LL.CashWalletCutover.body()}
+
+
+
+ setVisible(false)}
+ />
+
+
+
+ )
+}
+
+export default CashWalletCutoverModal
+
+const useStyles = makeStyles(({ colors }) => ({
+ modal: {
+ justifyContent: "flex-end",
+ margin: 0,
+ },
+ sheet: {
+ backgroundColor: colors.white,
+ borderTopLeftRadius: 24,
+ borderTopRightRadius: 24,
+ paddingHorizontal: 24,
+ paddingBottom: 40,
+ paddingTop: 12,
+ alignItems: "center",
+ },
+ handle: {
+ width: 40,
+ height: 4,
+ borderRadius: 2,
+ backgroundColor: colors.grey4,
+ marginBottom: 20,
+ },
+ illustrationContainer: {
+ alignItems: "center",
+ marginBottom: 20,
+ },
+ illustrationCircle: {
+ width: 140,
+ height: 140,
+ borderRadius: 70,
+ backgroundColor: colors.grey5,
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ title: {
+ textAlign: "center",
+ marginBottom: 12,
+ },
+ body: {
+ textAlign: "center",
+ paddingHorizontal: 8,
+ marginBottom: 28,
+ },
+ buttonContainer: {
+ width: "100%",
+ },
+}))
diff --git a/app/components/cashout-flow/CashoutCard.tsx b/app/components/topup-cashout-flow/CashoutCard.tsx
similarity index 96%
rename from app/components/cashout-flow/CashoutCard.tsx
rename to app/components/topup-cashout-flow/CashoutCard.tsx
index e6054f974..a3d2ececd 100644
--- a/app/components/cashout-flow/CashoutCard.tsx
+++ b/app/components/topup-cashout-flow/CashoutCard.tsx
@@ -4,7 +4,7 @@ import { makeStyles, Text } from "@rneui/themed"
type Props = {
title: string
- detail: string | number
+ detail?: string | number
}
const CashoutCard: React.FC = ({ title, detail }) => {
diff --git a/app/components/cashout-flow/CashoutFromWallet.tsx b/app/components/topup-cashout-flow/CashoutFromWallet.tsx
similarity index 100%
rename from app/components/cashout-flow/CashoutFromWallet.tsx
rename to app/components/topup-cashout-flow/CashoutFromWallet.tsx
diff --git a/app/components/cashout-flow/CashoutPercentage.tsx b/app/components/topup-cashout-flow/CashoutPercentage.tsx
similarity index 100%
rename from app/components/cashout-flow/CashoutPercentage.tsx
rename to app/components/topup-cashout-flow/CashoutPercentage.tsx
diff --git a/app/components/topup-cashout-flow/CashoutWithdrawTo.tsx b/app/components/topup-cashout-flow/CashoutWithdrawTo.tsx
new file mode 100644
index 000000000..fa7bf19b2
--- /dev/null
+++ b/app/components/topup-cashout-flow/CashoutWithdrawTo.tsx
@@ -0,0 +1,99 @@
+import React, { useState } from "react"
+import { TouchableOpacity, View } from "react-native"
+import { Icon, makeStyles, Text, useTheme } from "@rneui/themed"
+
+import { useI18nContext } from "@app/i18n/i18n-react"
+import { useLatestAccountUpgradeRequestQuery } from "@app/graphql/generated"
+
+const CashoutWithdrawTo: React.FC = () => {
+ const styles = useStyles()
+ const { colors } = useTheme().theme
+ const { LL } = useI18nContext()
+ const [expanded, setExpanded] = useState(false)
+
+ const { data } = useLatestAccountUpgradeRequestQuery({
+ fetchPolicy: "cache-first",
+ })
+
+ const bankAccount = data?.latestAccountUpgradeRequest.upgradeRequest?.bankAccount
+ console.log(">>>>>>>>>>>?????????", data)
+
+ if (!bankAccount) return null
+
+ const maskedAccount = `**********${String(bankAccount.accountNumber).slice(-4)}`
+
+ return (
+
+
+ {LL.Cashout.withdrawTo()}
+
+ setExpanded(!expanded)}
+ activeOpacity={0.7}
+ >
+
+ {maskedAccount}
+
+
+ {expanded && (
+
+
+
+
+
+
+
+ )}
+
+
+ )
+}
+
+const DetailRow: React.FC<{ label: string; value: string }> = ({ label, value }) => {
+ const styles = useStyles()
+ return (
+
+
+ {label}
+
+ {value}
+
+ )
+}
+
+export default CashoutWithdrawTo
+
+const useStyles = makeStyles(({ colors }) => ({
+ card: {
+ borderRadius: 10,
+ marginTop: 5,
+ marginBottom: 15,
+ padding: 15,
+ backgroundColor: colors.grey5,
+ },
+ header: {
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ },
+ details: {
+ marginTop: 12,
+ },
+ detailRow: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ paddingVertical: 4,
+ },
+ detailLabel: {
+ color: colors.grey3,
+ },
+}))
diff --git a/app/components/topup-cashout-flow/TransferOptionModal.tsx b/app/components/topup-cashout-flow/TransferOptionModal.tsx
new file mode 100644
index 000000000..aeb1a2cb9
--- /dev/null
+++ b/app/components/topup-cashout-flow/TransferOptionModal.tsx
@@ -0,0 +1,117 @@
+import React from "react"
+import { Modal, TouchableOpacity, View } from "react-native"
+import { Icon, Text, makeStyles, useTheme } from "@rneui/themed"
+import { useSafeAreaInsets } from "react-native-safe-area-context"
+
+export type TransferOption = {
+ icon: string
+ title: string
+ description: string
+ onPress: () => void
+ pending?: boolean
+}
+
+type Props = {
+ visible: boolean
+ title: string
+ options: TransferOption[]
+ onClose: () => void
+}
+
+const TransferOptionModal: React.FC = ({ visible, title, options, onClose }) => {
+ const styles = useStyles()
+ const { colors, mode } = useTheme().theme
+ const bottom = useSafeAreaInsets().bottom
+
+ return (
+
+
+
+
+ {title}
+
+
+
+
+ {options.map((option, index) => (
+
+
+
+ {option.title}
+
+ {option.description}
+
+
+
+
+ ))}
+
+
+
+ )
+}
+
+export default TransferOptionModal
+
+const useStyles = makeStyles(({ colors }) => ({
+ backdrop: {
+ flex: 1,
+ justifyContent: "flex-end",
+ },
+ modalContainer: {
+ borderTopLeftRadius: 20,
+ borderTopRightRadius: 20,
+ paddingTop: 20,
+ paddingHorizontal: 20,
+ },
+ modalHeader: {
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ marginBottom: 15,
+ },
+ closeBtn: {
+ padding: 5,
+ },
+ optionBtn: {
+ flexDirection: "row",
+ alignItems: "center",
+ borderRadius: 15,
+ borderWidth: 1,
+ borderColor: colors.border01 || "#dedede",
+ marginBottom: 10,
+ paddingHorizontal: 15,
+ paddingVertical: 15,
+ },
+ optionTextWrapper: {
+ flex: 1,
+ rowGap: 3,
+ marginHorizontal: 15,
+ },
+}))
diff --git a/app/components/topup-cashout-flow/index.ts b/app/components/topup-cashout-flow/index.ts
new file mode 100644
index 000000000..a6007391c
--- /dev/null
+++ b/app/components/topup-cashout-flow/index.ts
@@ -0,0 +1,17 @@
+import CashoutFromWallet from "./CashoutFromWallet"
+import CashoutPercentage from "./CashoutPercentage"
+import CashoutCard from "./CashoutCard"
+import CashoutWithdrawTo from "./CashoutWithdrawTo"
+import CashWalletCutoverModal from "./CashWalletCutoverModal"
+
+export {
+ CashoutFromWallet,
+ CashoutPercentage,
+ CashoutCard,
+ CashoutWithdrawTo,
+ CashWalletCutoverModal,
+}
+
+export { default as TransferOptionModal } from "./TransferOptionModal"
+export type { TransferOption } from "./TransferOptionModal"
+export { default as BridgeKycModal } from "./BridgeKycModal"
diff --git a/app/graphql/front-end-mutations.ts b/app/graphql/front-end-mutations.ts
index b9de734ee..f9ef679de 100644
--- a/app/graphql/front-end-mutations.ts
+++ b/app/graphql/front-end-mutations.ts
@@ -117,36 +117,34 @@ gql`
}
}
- # mutation RequestCashout($input: RequestCashoutInput!) {
- # requestCashout(input: $input) {
- # errors {
- # code
- # message
- # path
- # }
- # offer {
- # exchangeRate
- # expiresAt
- # flashFee
- # offerId
- # receiveJmd
- # receiveUsd
- # send
- # walletId
- # }
- # }
- # }
-
- # mutation InitiateCashout($input: InitiateCashoutInput!) {
- # initiateCashout(input: $input) {
- # errors {
- # path
- # message
- # code
- # }
- # success
- # }
- # }
+ mutation RequestCashout($input: RequestCashoutInput!) {
+ requestCashout(input: $input) {
+ errors {
+ code
+ message
+ }
+ offer {
+ exchangeRate
+ expiresAt
+ flashFee
+ offerId
+ receiveJmd
+ receiveUsd
+ send
+ walletId
+ }
+ }
+ }
+
+ mutation InitiateCashout($input: InitiateCashoutInput!) {
+ initiateCashout(input: $input) {
+ errors {
+ code
+ message
+ }
+ id
+ }
+ }
mutation accountDelete {
accountDelete {
@@ -212,4 +210,17 @@ gql`
uploadUrl
}
}
+
+ mutation BridgeInitiateKyc($input: BridgeInitiateKycInput!) {
+ bridgeInitiateKyc(input: $input) {
+ errors {
+ code
+ message
+ }
+ kycLink {
+ kycLink
+ tosLink
+ }
+ }
+ }
`
diff --git a/app/graphql/front-end-queries.ts b/app/graphql/front-end-queries.ts
index d0715234c..b670de713 100644
--- a/app/graphql/front-end-queries.ts
+++ b/app/graphql/front-end-queries.ts
@@ -292,11 +292,14 @@ gql`
title
}
bankAccount {
+ accountName
accountNumber
accountType
bankBranch
bankName
currency
+ id
+ isDefault
}
currentLevel
fullName
@@ -315,4 +318,22 @@ gql`
name
}
}
+
+ query BridgeKycStatus {
+ bridgeKycStatus
+ }
+
+ query BridgeVirtualAccount {
+ bridgeVirtualAccount {
+ accountNumber
+ accountNumberLast4
+ bankName
+ id
+ kycLink
+ message
+ pending
+ routingNumber
+ tosLink
+ }
+ }
`
diff --git a/app/graphql/generated.gql b/app/graphql/generated.gql
index 311d81c91..b2bc45471 100644
--- a/app/graphql/generated.gql
+++ b/app/graphql/generated.gql
@@ -81,6 +81,22 @@ fragment TransactionList on TransactionConnection {
__typename
}
+mutation BridgeInitiateKyc($input: BridgeInitiateKycInput!) {
+ bridgeInitiateKyc(input: $input) {
+ errors {
+ code
+ message
+ __typename
+ }
+ kycLink {
+ kycLink
+ tosLink
+ __typename
+ }
+ __typename
+ }
+}
+
mutation IdDocumentUploadUrlGenerate($input: IdDocumentUploadUrlGenerateInput!) {
idDocumentUploadUrlGenerate(input: $input) {
errors {
@@ -94,6 +110,18 @@ mutation IdDocumentUploadUrlGenerate($input: IdDocumentUploadUrlGenerateInput!)
}
}
+mutation InitiateCashout($input: InitiateCashoutInput!) {
+ initiateCashout(input: $input) {
+ errors {
+ code
+ message
+ __typename
+ }
+ id
+ __typename
+ }
+}
+
mutation MerchantMapSuggest($input: MerchantMapSuggestInput!) {
merchantMapSuggest(input: $input) {
errors {
@@ -119,6 +147,28 @@ mutation MerchantMapSuggest($input: MerchantMapSuggestInput!) {
}
}
+mutation RequestCashout($input: RequestCashoutInput!) {
+ requestCashout(input: $input) {
+ errors {
+ code
+ message
+ __typename
+ }
+ offer {
+ exchangeRate
+ expiresAt
+ flashFee
+ offerId
+ receiveJmd
+ receiveUsd
+ send
+ walletId
+ __typename
+ }
+ __typename
+ }
+}
+
mutation accountDelete {
accountDelete {
errors {
@@ -828,6 +878,25 @@ mutation userUpdateUsername($input: UserUpdateUsernameInput!) {
}
}
+query BridgeKycStatus {
+ bridgeKycStatus
+}
+
+query BridgeVirtualAccount {
+ bridgeVirtualAccount {
+ accountNumber
+ accountNumberLast4
+ bankName
+ id
+ kycLink
+ message
+ pending
+ routingNumber
+ tosLink
+ __typename
+ }
+}
+
query ExportCsvSetting($walletIds: [WalletId!]!) {
me {
id
@@ -859,11 +928,14 @@ query LatestAccountUpgradeRequest {
__typename
}
bankAccount {
+ accountName
accountNumber
accountType
- bankBranch
- bankName
+ bank
+ branchCode
currency
+ id
+ isDefault
__typename
}
currentLevel
diff --git a/app/graphql/generated.ts b/app/graphql/generated.ts
index a840b8000..c282cec03 100644
--- a/app/graphql/generated.ts
+++ b/app/graphql/generated.ts
@@ -17,6 +17,8 @@ export type Scalars = {
Boolean: { input: boolean; output: boolean; }
Int: { input: number; output: number; }
Float: { input: number; output: number; }
+ /** Bank account number. Accepts String or Int and coerces to String. */
+ AccountNumber: { input: string; output: string; }
/** An Opaque Bearer token */
AuthToken: { input: string; output: string; }
/** (Positive) Cent amount (1/100 of a dollar) */
@@ -262,8 +264,9 @@ export type BtcWallet = Wallet & {
readonly __typename: 'BTCWallet';
readonly accountId: Scalars['ID']['output'];
/** A balance stored in BTC. */
- readonly balance: Scalars['FractionalCentAmount']['output'];
+ readonly balance?: Maybe;
readonly id: Scalars['ID']['output'];
+ readonly isExternal: Scalars['Boolean']['output'];
readonly lnurlp?: Maybe;
/** An unconfirmed incoming onchain balance. */
readonly pendingIncomingBalance: Scalars['SignedAmount']['output'];
@@ -299,21 +302,98 @@ export type Bank = {
export type BankAccount = {
readonly __typename: 'BankAccount';
- readonly accountNumber: Scalars['Int']['output'];
+ readonly accountName: Scalars['String']['output'];
+ readonly accountNumber: Scalars['String']['output'];
readonly accountType: Scalars['String']['output'];
- readonly bankBranch: Scalars['String']['output'];
- readonly bankName: Scalars['String']['output'];
+ /** Name of the bank institution */
+ readonly bank: Scalars['String']['output'];
+ readonly branchCode: Scalars['String']['output'];
+ /** Account currency (e.g. JMD, USD) */
readonly currency: Scalars['String']['output'];
+ /** ERPNext bank account identifier */
+ readonly id: Scalars['ID']['output'];
+ readonly isDefault: Scalars['Boolean']['output'];
};
export type BankAccountInput = {
- readonly accountNumber: Scalars['Int']['input'];
+ readonly accountNumber: Scalars['AccountNumber']['input'];
readonly accountType: Scalars['String']['input'];
readonly bankBranch: Scalars['String']['input'];
readonly bankName: Scalars['String']['input'];
readonly currency: Scalars['String']['input'];
};
+export type BridgeAddExternalAccountPayload = {
+ readonly __typename: 'BridgeAddExternalAccountPayload';
+ readonly errors: ReadonlyArray;
+ readonly externalAccount?: Maybe;
+};
+
+export type BridgeCreateVirtualAccountPayload = {
+ readonly __typename: 'BridgeCreateVirtualAccountPayload';
+ readonly errors: ReadonlyArray;
+ readonly virtualAccount?: Maybe;
+};
+
+export type BridgeExternalAccount = {
+ readonly __typename: 'BridgeExternalAccount';
+ readonly accountNumberLast4: Scalars['String']['output'];
+ readonly bankName: Scalars['String']['output'];
+ readonly id: Scalars['ID']['output'];
+ readonly status: Scalars['String']['output'];
+};
+
+export type BridgeInitiateKycInput = {
+ readonly email?: InputMaybe;
+ readonly full_name?: InputMaybe;
+ readonly type?: InputMaybe;
+};
+
+export type BridgeInitiateKycPayload = {
+ readonly __typename: 'BridgeInitiateKycPayload';
+ readonly errors: ReadonlyArray;
+ readonly kycLink?: Maybe;
+};
+
+export type BridgeInitiateWithdrawalInput = {
+ readonly amount: Scalars['String']['input'];
+ readonly externalAccountId: Scalars['ID']['input'];
+};
+
+export type BridgeInitiateWithdrawalPayload = {
+ readonly __typename: 'BridgeInitiateWithdrawalPayload';
+ readonly errors: ReadonlyArray;
+ readonly withdrawal?: Maybe;
+};
+
+export type BridgeKycLink = {
+ readonly __typename: 'BridgeKycLink';
+ readonly kycLink: Scalars['String']['output'];
+ readonly tosLink: Scalars['String']['output'];
+};
+
+export type BridgeVirtualAccount = {
+ readonly __typename: 'BridgeVirtualAccount';
+ readonly accountNumber?: Maybe;
+ readonly accountNumberLast4?: Maybe;
+ readonly bankName?: Maybe;
+ readonly id?: Maybe;
+ readonly kycLink?: Maybe;
+ readonly message?: Maybe;
+ readonly pending?: Maybe;
+ readonly routingNumber?: Maybe;
+ readonly tosLink?: Maybe;
+};
+
+export type BridgeWithdrawal = {
+ readonly __typename: 'BridgeWithdrawal';
+ readonly amount: Scalars['String']['output'];
+ readonly createdAt: Scalars['String']['output'];
+ readonly currency: Scalars['String']['output'];
+ readonly id: Scalars['ID']['output'];
+ readonly status: Scalars['String']['output'];
+};
+
export type BuildInformation = {
readonly __typename: 'BuildInformation';
readonly commitHash?: Maybe;
@@ -375,17 +455,17 @@ export type CaptchaRequestAuthCodeInput = {
export type CashoutOffer = {
readonly __typename: 'CashoutOffer';
/** The rate used when withdrawing to a JMD bank account */
- readonly exchangeRate: Scalars['JMDCents']['output'];
+ readonly exchangeRate?: Maybe;
/** The time at which this offer is no longer accepted by Flash */
readonly expiresAt: Scalars['Timestamp']['output'];
- /** The amount that Flash is charging for it's services */
+ /** The amount that Flash is charging for its services */
readonly flashFee: Scalars['USDCents']['output'];
/** ID of the offer */
readonly offerId: Scalars['ID']['output'];
- /** The amount Flash owes to the user denominated in JMD as cents */
- readonly receiveJmd: Scalars['JMDCents']['output'];
- /** The amount Flash owes to the user denominated in USD as cents */
- readonly receiveUsd: Scalars['USDCents']['output'];
+ /** The amount Flash owes to the user denominated in JMD cents (null for USD payouts) */
+ readonly receiveJmd?: Maybe;
+ /** The amount Flash owes to the user denominated in USD cents (null for JMD payouts) */
+ readonly receiveUsd?: Maybe;
/** The amount the user is sending to flash */
readonly send: Scalars['USDCents']['output'];
/** ID for the users USD wallet to send from */
@@ -552,7 +632,7 @@ export type InitiateCashoutInput = {
export type InitiatedCashoutResponse = {
readonly __typename: 'InitiatedCashoutResponse';
readonly errors: ReadonlyArray;
- readonly journalId?: Maybe;
+ readonly id?: Maybe;
};
export type InitiationVia = InitiationViaIntraLedger | InitiationViaLn | InitiationViaOnChain;
@@ -835,6 +915,10 @@ export type Mutation = {
readonly accountEnableNotificationChannel: AccountUpdateNotificationSettingsPayload;
readonly accountUpdateDefaultWalletId: AccountUpdateDefaultWalletIdPayload;
readonly accountUpdateDisplayCurrency: AccountUpdateDisplayCurrencyPayload;
+ readonly bridgeAddExternalAccount: BridgeAddExternalAccountPayload;
+ readonly bridgeCreateVirtualAccount: BridgeCreateVirtualAccountPayload;
+ readonly bridgeInitiateKyc: BridgeInitiateKycPayload;
+ readonly bridgeInitiateWithdrawal: BridgeInitiateWithdrawalPayload;
readonly businessAccountUpgradeRequest: AccountUpgradePayload;
readonly callbackEndpointAdd: CallbackEndpointAddPayload;
readonly callbackEndpointDelete: SuccessPayload;
@@ -935,6 +1019,7 @@ export type Mutation = {
* The user can review this offer and then execute the withdrawal by calling the initiateCashout mutation.
*/
readonly requestCashout: RequestCashoutResponse;
+ readonly updateExternalWallet: UpdateExternalWalletPayload;
/** @deprecated will be moved to AccountContact */
readonly userContactUpdateAlias: UserContactUpdateAliasPayload;
readonly userEmailDelete: UserEmailDeletePayload;
@@ -988,6 +1073,16 @@ export type MutationAccountUpdateDisplayCurrencyArgs = {
};
+export type MutationBridgeInitiateKycArgs = {
+ input: BridgeInitiateKycInput;
+};
+
+
+export type MutationBridgeInitiateWithdrawalArgs = {
+ input: BridgeInitiateWithdrawalInput;
+};
+
+
export type MutationBusinessAccountUpgradeRequestArgs = {
input: BusinessAccountUpgradeRequestInput;
};
@@ -1148,6 +1243,11 @@ export type MutationRequestCashoutArgs = {
};
+export type MutationUpdateExternalWalletArgs = {
+ input: UpdateExternalWalletInput;
+};
+
+
export type MutationUserContactUpdateAliasArgs = {
input: UserContactUpdateAliasInput;
};
@@ -1453,6 +1553,10 @@ export type Query = {
readonly __typename: 'Query';
readonly accountDefaultWallet: PublicWallet;
readonly beta: Scalars['Boolean']['output'];
+ readonly bridgeExternalAccounts?: Maybe>>;
+ readonly bridgeKycStatus?: Maybe;
+ readonly bridgeVirtualAccount?: Maybe;
+ readonly bridgeWithdrawals?: Maybe>>;
/** @deprecated Deprecated in favor of realtimePrice */
readonly btcPrice?: Maybe;
readonly btcPriceList?: Maybe>>;
@@ -1608,6 +1712,8 @@ export type RealtimePricePayload = {
export type RequestCashoutInput = {
/** Amount in USD cents. */
readonly amount: Scalars['USDCents']['input'];
+ /** ERPNext bank account identifier to receive the cashout. */
+ readonly bankAccountId: Scalars['ID']['input'];
/** ID for a USD wallet belonging to the current user. */
readonly walletId: Scalars['WalletId']['input'];
};
@@ -1806,6 +1912,16 @@ export const TxStatus = {
} as const;
export type TxStatus = typeof TxStatus[keyof typeof TxStatus];
+export type UpdateExternalWalletInput = {
+ readonly lnurlp: Scalars['Lnurl']['input'];
+};
+
+export type UpdateExternalWalletPayload = {
+ readonly __typename: 'UpdateExternalWalletPayload';
+ readonly errors: ReadonlyArray;
+ readonly walletId?: Maybe;
+};
+
export type UpgradePayload = {
readonly __typename: 'UpgradePayload';
readonly authToken?: Maybe;
@@ -1817,8 +1933,9 @@ export type UpgradePayload = {
export type UsdWallet = Wallet & {
readonly __typename: 'UsdWallet';
readonly accountId: Scalars['ID']['output'];
- readonly balance: Scalars['FractionalCentAmount']['output'];
+ readonly balance?: Maybe;
readonly id: Scalars['ID']['output'];
+ readonly isExternal: Scalars['Boolean']['output'];
readonly lnurlp?: Maybe;
/** An unconfirmed incoming onchain balance. */
readonly pendingIncomingBalance: Scalars['SignedAmount']['output'];
@@ -1846,8 +1963,44 @@ export type UsdWalletTransactionsByAddressArgs = {
last?: InputMaybe;
};
+/** A wallet belonging to an account which contains a USDT balance and a list of transactions. */
+export type UsdtWallet = Wallet & {
+ readonly __typename: 'UsdtWallet';
+ readonly accountId: Scalars['ID']['output'];
+ readonly balance: Scalars['FractionalCentAmount']['output'];
+ readonly id: Scalars['ID']['output'];
+ readonly isExternal: Scalars['Boolean']['output'];
+ readonly lnurlp?: Maybe;
+ /** An unconfirmed incoming onchain balance. */
+ readonly pendingIncomingBalance: Scalars['SignedAmount']['output'];
+ readonly transactions?: Maybe;
+ readonly transactionsByAddress?: Maybe;
+ readonly walletCurrency: WalletCurrency;
+};
+
+
+/** A wallet belonging to an account which contains a USDT balance and a list of transactions. */
+export type UsdtWalletTransactionsArgs = {
+ after?: InputMaybe;
+ before?: InputMaybe;
+ first?: InputMaybe;
+ last?: InputMaybe;
+};
+
+
+/** A wallet belonging to an account which contains a USDT balance and a list of transactions. */
+export type UsdtWalletTransactionsByAddressArgs = {
+ address: Scalars['OnChainAddress']['input'];
+ after?: InputMaybe;
+ before?: InputMaybe;
+ first?: InputMaybe;
+ last?: InputMaybe;
+};
+
export type User = {
readonly __typename: 'User';
+ /** Bank accounts available for cashout */
+ readonly bankAccounts: ReadonlyArray;
/**
* Get single contact details.
* Can include the transactions associated with the contact.
@@ -2075,8 +2228,9 @@ 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['FractionalCentAmount']['output'];
+ readonly balance?: Maybe;
readonly id: Scalars['ID']['output'];
+ readonly isExternal: Scalars['Boolean']['output'];
readonly lnurlp?: Maybe;
readonly pendingIncomingBalance: Scalars['SignedAmount']['output'];
/**
@@ -2113,7 +2267,8 @@ export type WalletTransactionsByAddressArgs = {
export const WalletCurrency = {
Btc: 'BTC',
- Usd: 'USD'
+ Usd: 'USD',
+ Usdt: 'USDT'
} as const;
export type WalletCurrency = typeof WalletCurrency[keyof typeof WalletCurrency];
@@ -2154,7 +2309,7 @@ export type AnalyticsQueryVariables = Exact<{ [key: string]: never; }>;
export type AnalyticsQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly username?: string | null, readonly id: string } | null, readonly globals?: { readonly __typename: 'Globals', readonly network: Network } | null };
-export type MyWalletsFragment = { readonly __typename: 'ConsumerAccount', readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> };
+export type MyWalletsFragment = { readonly __typename: 'ConsumerAccount', readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> };
export type RealtimePriceQueryVariables = Exact<{ [key: string]: never; }>;
@@ -2272,6 +2427,20 @@ export type MerchantMapSuggestMutationVariables = Exact<{
export type MerchantMapSuggestMutation = { readonly __typename: 'Mutation', readonly merchantMapSuggest: { readonly __typename: 'MerchantPayload', readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly code?: string | null, readonly message: string, readonly path?: ReadonlyArray | null }>, readonly merchant?: { readonly __typename: 'Merchant', readonly createdAt: number, readonly id: string, readonly title: string, readonly username: string, readonly validated: boolean, readonly coordinates: { readonly __typename: 'Coordinates', readonly latitude: number, readonly longitude: number } } | null } };
+export type RequestCashoutMutationVariables = Exact<{
+ input: RequestCashoutInput;
+}>;
+
+
+export type RequestCashoutMutation = { readonly __typename: 'Mutation', readonly requestCashout: { readonly __typename: 'RequestCashoutResponse', readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly code?: string | null, readonly message: string }>, readonly offer?: { readonly __typename: 'CashoutOffer', readonly exchangeRate?: number | null, readonly expiresAt: number, readonly flashFee: number, readonly offerId: string, readonly receiveJmd?: number | null, readonly receiveUsd?: number | null, readonly send: number, readonly walletId: string } | null } };
+
+export type InitiateCashoutMutationVariables = Exact<{
+ input: InitiateCashoutInput;
+}>;
+
+
+export type InitiateCashoutMutation = { readonly __typename: 'Mutation', readonly initiateCashout: { readonly __typename: 'InitiatedCashoutResponse', readonly id?: string | null, readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly code?: string | null, readonly message: string }> } };
+
export type AccountDeleteMutationVariables = Exact<{ [key: string]: never; }>;
@@ -2305,6 +2474,13 @@ export type IdDocumentUploadUrlGenerateMutationVariables = Exact<{
export type IdDocumentUploadUrlGenerateMutation = { readonly __typename: 'Mutation', readonly idDocumentUploadUrlGenerate: { readonly __typename: 'IdDocumentUploadUrlPayload', readonly fileKey?: string | null, readonly uploadUrl?: string | null, readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly code?: string | null, readonly message: string }> } };
+export type BridgeInitiateKycMutationVariables = Exact<{
+ input: BridgeInitiateKycInput;
+}>;
+
+
+export type BridgeInitiateKycMutation = { readonly __typename: 'Mutation', readonly bridgeInitiateKyc: { readonly __typename: 'BridgeInitiateKycPayload', readonly errors: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly code?: string | null, readonly message: string }>, readonly kycLink?: { readonly __typename: 'BridgeKycLink', readonly kycLink: string, readonly tosLink: string } | null } };
+
export type AuthQueryVariables = Exact<{ [key: string]: never; }>;
@@ -2313,7 +2489,7 @@ export type AuthQuery = { readonly __typename: 'Query', readonly me?: { readonly
export type HomeAuthedQueryVariables = Exact<{ [key: string]: never; }>;
-export type HomeAuthedQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly language: string, readonly username?: string | null, readonly phone?: string | null, readonly npub?: string | null, readonly email?: { readonly __typename: 'Email', readonly address?: string | null, readonly verified?: boolean | null } | null, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly level: AccountLevel, readonly defaultWalletId: string, readonly transactions?: { readonly __typename: 'TransactionConnection', readonly pageInfo: { readonly __typename: 'PageInfo', readonly hasNextPage: boolean, readonly hasPreviousPage: boolean, readonly startCursor?: string | null, readonly endCursor?: string | null }, readonly edges?: ReadonlyArray<{ readonly __typename: 'TransactionEdge', readonly cursor: string, readonly node: { readonly __typename: 'Transaction', readonly id: string, readonly status: TxStatus, readonly direction: TxDirection, readonly memo?: string | null, readonly createdAt: number, readonly settlementAmount: number, readonly settlementFee: number, readonly settlementDisplayFee: string, readonly settlementCurrency: WalletCurrency, readonly settlementDisplayAmount: string, readonly settlementDisplayCurrency: string, readonly settlementPrice: { readonly __typename: 'PriceOfOneSettlementMinorUnitInDisplayMinorUnit', readonly base: number, readonly offset: number, readonly currencyUnit: string, readonly formattedAmount: string }, readonly initiationVia: { readonly __typename: 'InitiationViaIntraLedger', readonly counterPartyWalletId?: string | null, readonly counterPartyUsername?: string | null } | { readonly __typename: 'InitiationViaLn', readonly paymentHash: string } | { readonly __typename: 'InitiationViaOnChain', readonly address: string }, readonly settlementVia: { readonly __typename: 'SettlementViaIntraLedger', readonly counterPartyWalletId?: string | null, readonly counterPartyUsername?: string | null } | { readonly __typename: 'SettlementViaLn', readonly paymentSecret?: string | null } | { readonly __typename: 'SettlementViaOnChain', readonly transactionHash?: string | null } } }> | null } | null, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type HomeAuthedQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly language: string, readonly username?: string | null, readonly phone?: string | null, readonly npub?: string | null, readonly email?: { readonly __typename: 'Email', readonly address?: string | null, readonly verified?: boolean | null } | null, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly level: AccountLevel, readonly defaultWalletId: string, readonly transactions?: { readonly __typename: 'TransactionConnection', readonly pageInfo: { readonly __typename: 'PageInfo', readonly hasNextPage: boolean, readonly hasPreviousPage: boolean, readonly startCursor?: string | null, readonly endCursor?: string | null }, readonly edges?: ReadonlyArray<{ readonly __typename: 'TransactionEdge', readonly cursor: string, readonly node: { readonly __typename: 'Transaction', readonly id: string, readonly status: TxStatus, readonly direction: TxDirection, readonly memo?: string | null, readonly createdAt: number, readonly settlementAmount: number, readonly settlementFee: number, readonly settlementDisplayFee: string, readonly settlementCurrency: WalletCurrency, readonly settlementDisplayAmount: string, readonly settlementDisplayCurrency: string, readonly settlementPrice: { readonly __typename: 'PriceOfOneSettlementMinorUnitInDisplayMinorUnit', readonly base: number, readonly offset: number, readonly currencyUnit: string, readonly formattedAmount: string }, readonly initiationVia: { readonly __typename: 'InitiationViaIntraLedger', readonly counterPartyWalletId?: string | null, readonly counterPartyUsername?: string | null } | { readonly __typename: 'InitiationViaLn', readonly paymentHash: string } | { readonly __typename: 'InitiationViaOnChain', readonly address: string }, readonly settlementVia: { readonly __typename: 'SettlementViaIntraLedger', readonly counterPartyWalletId?: string | null, readonly counterPartyUsername?: string | null } | { readonly __typename: 'SettlementViaLn', readonly paymentSecret?: string | null } | { readonly __typename: 'SettlementViaOnChain', readonly transactionHash?: string | null } } }> | null } | null, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type HomeUnauthedQueryVariables = Exact<{ [key: string]: never; }>;
@@ -2333,17 +2509,17 @@ export type TransactionListForDefaultAccountQuery = { readonly __typename: 'Quer
export type SetDefaultAccountModalQueryVariables = Exact<{ [key: string]: never; }>;
-export type SetDefaultAccountModalQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type SetDefaultAccountModalQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type ConversionScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type ConversionScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type ConversionScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type CashoutScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type CashoutScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type CashoutScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type WalletCsvTransactionsQueryVariables = Exact<{
walletIds: ReadonlyArray | Scalars['WalletId']['input'];
@@ -2355,12 +2531,12 @@ export type WalletCsvTransactionsQuery = { readonly __typename: 'Query', readonl
export type WalletOverviewScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type WalletOverviewScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type WalletOverviewScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type SendBitcoinDestinationQueryVariables = Exact<{ [key: string]: never; }>;
-export type SendBitcoinDestinationQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network } | null, readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string } | { readonly __typename: 'UsdWallet', readonly id: string }> }, readonly contacts: ReadonlyArray<{ readonly __typename: 'UserContact', readonly id: string, readonly username: string }> } | null };
+export type SendBitcoinDestinationQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network } | null, readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string } | { readonly __typename: 'UsdWallet', readonly id: string } | { readonly __typename: 'UsdtWallet', readonly id: string }> }, readonly contacts: ReadonlyArray<{ readonly __typename: 'UserContact', readonly id: string, readonly username: string }> } | null };
export type AccountDefaultWalletQueryVariables = Exact<{
username: Scalars['Username']['input'];
@@ -2372,7 +2548,7 @@ export type AccountDefaultWalletQuery = { readonly __typename: 'Query', readonly
export type SendBitcoinDetailsScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type SendBitcoinDetailsScreenQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network } | null, readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly walletCurrency: WalletCurrency, readonly balance: number } | { readonly __typename: 'UsdWallet', readonly id: string, readonly walletCurrency: WalletCurrency, readonly balance: number }> } } | null };
+export type SendBitcoinDetailsScreenQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network } | null, readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly walletCurrency: WalletCurrency, readonly balance?: number | null } | { readonly __typename: 'UsdWallet', readonly id: string, readonly walletCurrency: WalletCurrency, readonly balance?: number | null } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly walletCurrency: WalletCurrency, readonly balance: number }> } } | null };
export type SendBitcoinWithdrawalLimitsQueryVariables = Exact<{ [key: string]: never; }>;
@@ -2387,12 +2563,12 @@ export type SendBitcoinInternalLimitsQuery = { readonly __typename: 'Query', rea
export type SendBitcoinConfirmationScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type SendBitcoinConfirmationScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type SendBitcoinConfirmationScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type ScanningQrCodeScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type ScanningQrCodeScreenQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network } | null, readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string } | { readonly __typename: 'UsdWallet', readonly id: string }> }, readonly contacts: ReadonlyArray<{ readonly __typename: 'UserContact', readonly id: string, readonly username: string }> } | null };
+export type ScanningQrCodeScreenQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network } | null, readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string } | { readonly __typename: 'UsdWallet', readonly id: string } | { readonly __typename: 'UsdtWallet', readonly id: string }> }, readonly contacts: ReadonlyArray<{ readonly __typename: 'UserContact', readonly id: string, readonly username: string }> } | null };
export type RealtimePriceUnauthedQueryVariables = Exact<{
currency: Scalars['DisplayCurrency']['input'];
@@ -2411,13 +2587,23 @@ export type NpubByUsernameQuery = { readonly __typename: 'Query', readonly npubB
export type LatestAccountUpgradeRequestQueryVariables = Exact<{ [key: string]: never; }>;
-export type LatestAccountUpgradeRequestQuery = { readonly __typename: 'Query', readonly latestAccountUpgradeRequest: { readonly __typename: 'AccountUpgradeRequestPayload', readonly errors?: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly code?: string | null, readonly message: string } | null> | null, readonly upgradeRequest?: { readonly __typename: 'AccountUpgradeRequest', readonly currentLevel: AccountLevel, readonly fullName: string, readonly terminalsRequested: number, readonly status: string, readonly requestedLevel: AccountLevel, readonly phoneNumber: string, readonly email?: string | null, readonly idDocument: boolean, readonly address: { readonly __typename: 'Address', readonly city: string, readonly country: string, readonly line1: string, readonly line2?: string | null, readonly postalCode?: string | null, readonly state: string, readonly title: string }, readonly bankAccount?: { readonly __typename: 'BankAccount', readonly accountNumber: number, readonly accountType: string, readonly bankBranch: string, readonly bankName: string, readonly currency: string } | null } | null } };
+export type LatestAccountUpgradeRequestQuery = { readonly __typename: 'Query', readonly latestAccountUpgradeRequest: { readonly __typename: 'AccountUpgradeRequestPayload', readonly errors?: ReadonlyArray<{ readonly __typename: 'GraphQLApplicationError', readonly code?: string | null, readonly message: string } | null> | null, readonly upgradeRequest?: { readonly __typename: 'AccountUpgradeRequest', readonly currentLevel: AccountLevel, readonly fullName: string, readonly terminalsRequested: number, readonly status: string, readonly requestedLevel: AccountLevel, readonly phoneNumber: string, readonly email?: string | null, readonly idDocument: boolean, readonly address: { readonly __typename: 'Address', readonly city: string, readonly country: string, readonly line1: string, readonly line2?: string | null, readonly postalCode?: string | null, readonly state: string, readonly title: string }, readonly bankAccount?: { readonly __typename: 'BankAccount', readonly accountName: string, readonly accountNumber: string, readonly accountType: string, readonly bank: string, readonly branchCode: string, readonly currency: string, readonly id: string, readonly isDefault: boolean } | null } | null } };
export type SupportedBanksQueryVariables = Exact<{ [key: string]: never; }>;
export type SupportedBanksQuery = { readonly __typename: 'Query', readonly supportedBanks: ReadonlyArray<{ readonly __typename: 'Bank', readonly name: string }> };
+export type BridgeKycStatusQueryVariables = Exact<{ [key: string]: never; }>;
+
+
+export type BridgeKycStatusQuery = { readonly __typename: 'Query', readonly bridgeKycStatus?: string | null };
+
+export type BridgeVirtualAccountQueryVariables = Exact<{ [key: string]: never; }>;
+
+
+export type BridgeVirtualAccountQuery = { readonly __typename: 'Query', readonly bridgeVirtualAccount?: { readonly __typename: 'BridgeVirtualAccount', readonly accountNumber?: string | null, readonly accountNumberLast4?: string | null, readonly bankName?: string | null, readonly id?: string | null, readonly kycLink?: string | null, readonly message?: string | null, readonly pending?: boolean | null, readonly routingNumber?: string | null, readonly tosLink?: string | null } | null };
+
export type RealtimePriceWsSubscriptionVariables = Exact<{
currency: Scalars['DisplayCurrency']['input'];
}>;
@@ -2624,7 +2810,7 @@ export type MyLnUpdatesSubscription = { readonly __typename: 'Subscription', rea
export type PaymentRequestQueryVariables = Exact<{ [key: string]: never; }>;
-export type PaymentRequestQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network, readonly feesInformation: { readonly __typename: 'FeesInformation', readonly deposit: { readonly __typename: 'DepositFeesInformation', readonly minBankFee: string, readonly minBankFeeThreshold: string } } } | null, readonly me?: { readonly __typename: 'User', readonly id: string, readonly username?: string | null, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type PaymentRequestQuery = { readonly __typename: 'Query', readonly globals?: { readonly __typename: 'Globals', readonly network: Network, readonly feesInformation: { readonly __typename: 'FeesInformation', readonly deposit: { readonly __typename: 'DepositFeesInformation', readonly minBankFee: string, readonly minBankFeeThreshold: string } } } | null, readonly me?: { readonly __typename: 'User', readonly id: string, readonly username?: string | null, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type LnNoAmountInvoiceCreateMutationVariables = Exact<{
input: LnNoAmountInvoiceCreateInput;
@@ -2664,7 +2850,7 @@ export type FeedbackSubmitMutation = { readonly __typename: 'Mutation', readonly
export type AccountScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type AccountScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly phone?: string | null, readonly totpEnabled: boolean, readonly email?: { readonly __typename: 'Email', readonly address?: string | null, readonly verified?: boolean | null } | null, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly level: AccountLevel, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type AccountScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly phone?: string | null, readonly totpEnabled: boolean, readonly email?: { readonly __typename: 'Email', readonly address?: string | null, readonly verified?: boolean | null } | null, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly level: AccountLevel, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type UserEmailDeleteMutationVariables = Exact<{ [key: string]: never; }>;
@@ -2686,7 +2872,7 @@ export type UserTotpDeleteMutation = { readonly __typename: 'Mutation', readonly
export type WarningSecureAccountQueryVariables = Exact<{ [key: string]: never; }>;
-export type WarningSecureAccountQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly level: AccountLevel, readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type WarningSecureAccountQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly level: AccountLevel, readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type AccountUpdateDefaultWalletIdMutationVariables = Exact<{
input: AccountUpdateDefaultWalletIdInput;
@@ -2698,7 +2884,7 @@ export type AccountUpdateDefaultWalletIdMutation = { readonly __typename: 'Mutat
export type SetDefaultWalletScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type SetDefaultWalletScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
+export type SetDefaultWalletScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> } } | null };
export type AccountUpdateDisplayCurrencyMutationVariables = Exact<{
input: AccountUpdateDisplayCurrencyInput;
@@ -2755,7 +2941,7 @@ export type AccountDisableNotificationCategoryMutation = { readonly __typename:
export type SettingsScreenQueryVariables = Exact<{ [key: string]: never; }>;
-export type SettingsScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly phone?: string | null, readonly username?: string | null, readonly language: string, readonly totpEnabled: boolean, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> }, readonly email?: { readonly __typename: 'Email', readonly address?: string | null, readonly verified?: boolean | null } | null } | null };
+export type SettingsScreenQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly phone?: string | null, readonly username?: string | null, readonly language: string, readonly totpEnabled: boolean, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly defaultWalletId: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdWallet', readonly id: string, readonly balance?: number | null, readonly walletCurrency: WalletCurrency } | { readonly __typename: 'UsdtWallet', readonly id: string, readonly balance: number, readonly walletCurrency: WalletCurrency }> }, readonly email?: { readonly __typename: 'Email', readonly address?: string | null, readonly verified?: boolean | null } | null } | null };
export type ExportCsvSettingQueryVariables = Exact<{
walletIds: ReadonlyArray | Scalars['WalletId']['input'];
@@ -2805,7 +2991,7 @@ export type DeviceNotificationTokenCreateMutation = { readonly __typename: 'Muta
export type WalletsQueryVariables = Exact<{ [key: string]: never; }>;
-export type WalletsQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly walletCurrency: WalletCurrency, readonly id: string, readonly lnurlp?: string | null } | { readonly __typename: 'UsdWallet', readonly walletCurrency: WalletCurrency, readonly id: string, readonly lnurlp?: string | null }> } } | null };
+export type WalletsQuery = { readonly __typename: 'Query', readonly me?: { readonly __typename: 'User', readonly id: string, readonly defaultAccount: { readonly __typename: 'ConsumerAccount', readonly id: string, readonly wallets: ReadonlyArray<{ readonly __typename: 'BTCWallet', readonly walletCurrency: WalletCurrency, readonly id: string, readonly lnurlp?: string | null } | { readonly __typename: 'UsdWallet', readonly walletCurrency: WalletCurrency, readonly id: string, readonly lnurlp?: string | null } | { readonly __typename: 'UsdtWallet', readonly walletCurrency: WalletCurrency, readonly id: string, readonly lnurlp?: string | null }> } } | null };
export const MyWalletsFragmentDoc = gql`
fragment MyWallets on ConsumerAccount {
@@ -3718,6 +3904,89 @@ export function useMerchantMapSuggestMutation(baseOptions?: Apollo.MutationHookO
export type MerchantMapSuggestMutationHookResult = ReturnType;
export type MerchantMapSuggestMutationResult = Apollo.MutationResult;
export type MerchantMapSuggestMutationOptions = Apollo.BaseMutationOptions;
+export const RequestCashoutDocument = gql`
+ mutation RequestCashout($input: RequestCashoutInput!) {
+ requestCashout(input: $input) {
+ errors {
+ code
+ message
+ }
+ offer {
+ exchangeRate
+ expiresAt
+ flashFee
+ offerId
+ receiveJmd
+ receiveUsd
+ send
+ walletId
+ }
+ }
+}
+ `;
+export type RequestCashoutMutationFn = Apollo.MutationFunction;
+
+/**
+ * __useRequestCashoutMutation__
+ *
+ * To run a mutation, you first call `useRequestCashoutMutation` within a React component and pass it any options that fit your needs.
+ * When your component renders, `useRequestCashoutMutation` 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 [requestCashoutMutation, { data, loading, error }] = useRequestCashoutMutation({
+ * variables: {
+ * input: // value for 'input'
+ * },
+ * });
+ */
+export function useRequestCashoutMutation(baseOptions?: Apollo.MutationHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useMutation(RequestCashoutDocument, options);
+ }
+export type RequestCashoutMutationHookResult = ReturnType;
+export type RequestCashoutMutationResult = Apollo.MutationResult;
+export type RequestCashoutMutationOptions = Apollo.BaseMutationOptions;
+export const InitiateCashoutDocument = gql`
+ mutation InitiateCashout($input: InitiateCashoutInput!) {
+ initiateCashout(input: $input) {
+ errors {
+ code
+ message
+ }
+ id
+ }
+}
+ `;
+export type InitiateCashoutMutationFn = Apollo.MutationFunction;
+
+/**
+ * __useInitiateCashoutMutation__
+ *
+ * To run a mutation, you first call `useInitiateCashoutMutation` within a React component and pass it any options that fit your needs.
+ * When your component renders, `useInitiateCashoutMutation` 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 [initiateCashoutMutation, { data, loading, error }] = useInitiateCashoutMutation({
+ * variables: {
+ * input: // value for 'input'
+ * },
+ * });
+ */
+export function useInitiateCashoutMutation(baseOptions?: Apollo.MutationHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useMutation(InitiateCashoutDocument, options);
+ }
+export type InitiateCashoutMutationHookResult = ReturnType;
+export type InitiateCashoutMutationResult = Apollo.MutationResult;
+export type InitiateCashoutMutationOptions = Apollo.BaseMutationOptions;
export const AccountDeleteDocument = gql`
mutation accountDelete {
accountDelete {
@@ -3905,6 +4174,46 @@ export function useIdDocumentUploadUrlGenerateMutation(baseOptions?: Apollo.Muta
export type IdDocumentUploadUrlGenerateMutationHookResult = ReturnType;
export type IdDocumentUploadUrlGenerateMutationResult = Apollo.MutationResult;
export type IdDocumentUploadUrlGenerateMutationOptions = Apollo.BaseMutationOptions;
+export const BridgeInitiateKycDocument = gql`
+ mutation BridgeInitiateKyc($input: BridgeInitiateKycInput!) {
+ bridgeInitiateKyc(input: $input) {
+ errors {
+ code
+ message
+ }
+ kycLink {
+ kycLink
+ tosLink
+ }
+ }
+}
+ `;
+export type BridgeInitiateKycMutationFn = Apollo.MutationFunction;
+
+/**
+ * __useBridgeInitiateKycMutation__
+ *
+ * To run a mutation, you first call `useBridgeInitiateKycMutation` within a React component and pass it any options that fit your needs.
+ * When your component renders, `useBridgeInitiateKycMutation` 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 [bridgeInitiateKycMutation, { data, loading, error }] = useBridgeInitiateKycMutation({
+ * variables: {
+ * input: // value for 'input'
+ * },
+ * });
+ */
+export function useBridgeInitiateKycMutation(baseOptions?: Apollo.MutationHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useMutation(BridgeInitiateKycDocument, options);
+ }
+export type BridgeInitiateKycMutationHookResult = ReturnType;
+export type BridgeInitiateKycMutationResult = Apollo.MutationResult;
+export type BridgeInitiateKycMutationOptions = Apollo.BaseMutationOptions;
export const AuthDocument = gql`
query auth {
me {
@@ -4697,11 +5006,14 @@ export const LatestAccountUpgradeRequestDocument = gql`
title
}
bankAccount {
+ accountName
accountNumber
accountType
- bankBranch
- bankName
+ bank
+ branchCode
currency
+ id
+ isDefault
}
currentLevel
fullName
@@ -4776,6 +5088,80 @@ export function useSupportedBanksLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt
export type SupportedBanksQueryHookResult = ReturnType;
export type SupportedBanksLazyQueryHookResult = ReturnType;
export type SupportedBanksQueryResult = Apollo.QueryResult;
+export const BridgeKycStatusDocument = gql`
+ query BridgeKycStatus {
+ bridgeKycStatus
+}
+ `;
+
+/**
+ * __useBridgeKycStatusQuery__
+ *
+ * To run a query within a React component, call `useBridgeKycStatusQuery` and pass it any options that fit your needs.
+ * When your component renders, `useBridgeKycStatusQuery` 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 } = useBridgeKycStatusQuery({
+ * variables: {
+ * },
+ * });
+ */
+export function useBridgeKycStatusQuery(baseOptions?: Apollo.QueryHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useQuery(BridgeKycStatusDocument, options);
+ }
+export function useBridgeKycStatusLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useLazyQuery(BridgeKycStatusDocument, options);
+ }
+export type BridgeKycStatusQueryHookResult = ReturnType;
+export type BridgeKycStatusLazyQueryHookResult = ReturnType;
+export type BridgeKycStatusQueryResult = Apollo.QueryResult;
+export const BridgeVirtualAccountDocument = gql`
+ query BridgeVirtualAccount {
+ bridgeVirtualAccount {
+ accountNumber
+ accountNumberLast4
+ bankName
+ id
+ kycLink
+ message
+ pending
+ routingNumber
+ tosLink
+ }
+}
+ `;
+
+/**
+ * __useBridgeVirtualAccountQuery__
+ *
+ * To run a query within a React component, call `useBridgeVirtualAccountQuery` and pass it any options that fit your needs.
+ * When your component renders, `useBridgeVirtualAccountQuery` 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 } = useBridgeVirtualAccountQuery({
+ * variables: {
+ * },
+ * });
+ */
+export function useBridgeVirtualAccountQuery(baseOptions?: Apollo.QueryHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useQuery(BridgeVirtualAccountDocument, options);
+ }
+export function useBridgeVirtualAccountLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useLazyQuery(BridgeVirtualAccountDocument, options);
+ }
+export type BridgeVirtualAccountQueryHookResult = ReturnType;
+export type BridgeVirtualAccountLazyQueryHookResult = ReturnType;
+export type BridgeVirtualAccountQueryResult = Apollo.QueryResult;
export const RealtimePriceWsDocument = gql`
subscription realtimePriceWs($currency: DisplayCurrency!) {
realtimePrice(input: {currency: $currency}) {
diff --git a/app/i18n/en/index.ts b/app/i18n/en/index.ts
index 6fdabfa47..feb0f03db 100644
--- a/app/i18n/en/index.ts
+++ b/app/i18n/en/index.ts
@@ -89,7 +89,18 @@ const en: BaseTranslation = {
receiveAmount: "Receive Amount",
fee: "Fee",
success: "Settlement request initiated successfully.",
- disclaimer: `Please Note: Bank transfers are usually confirmed on the same-day, but may take longer if submitted during the following times:\n\n- Weekdays after 2:00pm\n- Fridays & weekends\n\nTransactions completed after 2:00 pm on weekdays are not confirmed by the bank until the following business day. Please contact us if you do not see your funds within 2-3 business days.\n`
+ disclaimer: `Please Note: Bank transfers are usually confirmed on the same-day, but may take longer if submitted during the following times:\n\n- Weekdays after 2:00pm\n- Fridays & weekends\n\nTransactions completed after 2:00 pm on weekdays are not confirmed by the bank until the following business day. Please contact us if you do not see your funds within 2-3 business days.\n`,
+ withdrawTo: "Withdraw to",
+ bankName: "Bank Name",
+ bankBranch: "Bank Branch",
+ accountNumber: "Account Number",
+ accountType: "Account Type",
+ currency: "Currency",
+ },
+ CashWalletCutover: {
+ title: "Cash Wallet Updated",
+ body: "Your Cash Wallet has been upgraded from USD to USDT. Your balance has been automatically migrated. No action is needed on your part.",
+ dismissButton: "Got it",
},
ConversionDetailsScreen: {
title: "Swap",
@@ -538,6 +549,7 @@ const en: BaseTranslation = {
balance: "Refresh Balance",
showQrCode: "Topup via QR",
send: "Send",
+ transfer: "Transfer",
sweep: "Sweep to Wallet",
pay: "Pay",
title: "Home",
@@ -568,6 +580,82 @@ const en: BaseTranslation = {
backupTitle: "Backup your BTC wallet",
backupDesc: "Backup and secure your Bitcoin wallet using recovery phrase."
},
+ TopUpScreen: {
+ title: "Top Up",
+ bankTransfer: "Bank Transfer",
+ bankTransferDesc: "Transfer funds from your bank",
+ debitCreditCard: "Debit/Credit Card",
+ debitCreditCardDesc: "Pay with your debit or credit card"
+ },
+ TopupDetails: {
+ title: "Card Payment",
+ bankTransfer: "Bank Transfer",
+ email: "Email",
+ emailPlaceholder: "Enter your email address",
+ wallet: "Wallet",
+ walletPlaceholder: "Select wallet",
+ amount: "Amount (USD)",
+ amountPlaceholder: "Enter amount",
+ continue: "Continue",
+ usdWallet: "USD Wallet",
+ btcWallet: "BTC Wallet",
+ invalidEmail: "Please enter a valid email address",
+ invalidAmount: "Please enter a valid amount",
+ minimumAmount: "Minimum amount is $1.00"
+ },
+ BridgeKyc: {
+ title: "International Transfer",
+ description: "Please provide your details to set up international transfers",
+ fullName: "Full Name",
+ fullNamePlaceholder: "Enter your full name",
+ email: "Email",
+ emailPlaceholder: "Enter your email address",
+ kycType: "Account Type",
+ kycTypePlaceholder: "Select account type",
+ individual: "Individual",
+ business: "Business",
+ submit: "Submit",
+ fullNameRequired: "Full name is required",
+ emailRequired: "Email is required",
+ invalidEmail: "Please enter a valid email address",
+ kycTypeRequired: "Please select an account type",
+ },
+ FygaroWebViewScreen: {
+ title: "Fygaro Payment",
+ loading: "Loading payment page...",
+ error: "Failed to load payment page",
+ retry: "Retry"
+ },
+ BankTransfer: {
+ title: "Bank Transfer",
+ desc1: "Your order has been created. To complete the order, please transfer ${amount: number} USD to the bank details provided below.",
+ desc2: "Use {code: string} as the reference description. This unique code will help us associate the payment with your Flash account and process the Bitcoin transfer.",
+ desc3: "After we have received your payment, you will be credited with ${amount: number} USD in your Cash wallet, with a ${fee: number} USD fee deducted. You can then choose when you convert those USD to Bitcoin on your own using the Convert functionality in the mobile app.",
+ accountType: "Account Type",
+ destinationBank: "Destination Bank",
+ accountNumber: "Account Number",
+ typeOfClient: "Type of Client",
+ receiverName: "Receiver's Name",
+ email: "Email",
+ amount: "Amount",
+ uniqueCode: "Unique Code",
+ fees: "Fees",
+ desc4: "After payment completion on your end you can send us an email to {email: string} with a screenshot of your payment confirmation.",
+ desc5: "Your payment will be processed even if we don't receive this email, but having this confirmation can help accelerate the order.",
+ backHome: "Back to Home",
+ virtualBankTransfer: "Virtual Bank Transfer",
+ bankName: "Bank Name",
+ routingNumber: "Routing Number"
+ },
+ PaymentSuccessScreen: {
+ title: "Payment Successful",
+ successMessage: "Your payment has been processed successfully",
+ amountSent: "Amount Sent",
+ depositedTo: "Deposited to",
+ transactionId: "Transaction ID",
+ done: "Done",
+ viewTransaction: "View Transaction"
+ },
PinScreen: {
attemptsRemaining: "Incorrect PIN. {attemptsRemaining: number} attempts remaining.",
oneAttemptRemaining: "Incorrect PIN. 1 attempt remaining.",
@@ -1109,6 +1197,18 @@ const en: BaseTranslation = {
TransferScreen: {
title: "Transfer",
percentageToConvert: "% to convert",
+ topUp: "Top Up",
+ topUpDesc: "Add funds to your wallet",
+ settle: "Settle",
+ settleDesc: "Cashout funds from your wallet",
+ selectSettleMethod: "Settle to",
+ selectTopUpMethod: "Top up via",
+ jmdBankAccount: "JMD Bank Account",
+ jmdBankAccountDesc: "Withdraw to your Jamaican bank account",
+ internationalBankAccount: "International Bank Account",
+ internationalBankAccountDesc: "Withdraw to your international bank account",
+ internationalBankTransfer: "International Bank Transfer",
+ internationalBankTransferDesc: "Transfer from your international bank account",
},
UpgradeAccountModal: {
title: "Upgrade your account",
@@ -1386,7 +1486,7 @@ const en: BaseTranslation = {
email: "Email",
enjoyingApp: "Enjoying the app?",
statusPage: "Status Page",
- //telegram: "Telegram",
+ // telegram: "Telegram",
discord: "Discord",
mattermost: "Mattermost",
thankYouText: "Thank you for the feedback, would you like to suggest an improvement?",
diff --git a/app/i18n/i18n-types.ts b/app/i18n/i18n-types.ts
index 34a2ae561..a49084794 100644
--- a/app/i18n/i18n-types.ts
+++ b/app/i18n/i18n-types.ts
@@ -311,6 +311,44 @@ type RootTranslation = {
*/
disclaimer: string
+ /**
+ * Withdraw to
+ */
+ withdrawTo: string
+ /**
+ * Bank Name
+ */
+ bankName: string
+ /**
+ * Bank Branch
+ */
+ bankBranch: string
+ /**
+ * Account Number
+ */
+ accountNumber: string
+ /**
+ * Account Type
+ */
+ accountType: string
+ /**
+ * Currency
+ */
+ currency: string
+ }
+ CashWalletCutover: {
+ /**
+ * Cash Wallet Updated
+ */
+ title: string
+ /**
+ * Your Cash Wallet has been upgraded from USD to USDT. Your balance has been automatically migrated. No action is needed on your part.
+ */
+ body: string
+ /**
+ * Got it
+ */
+ dismissButton: string
}
ConversionDetailsScreen: {
/**
@@ -1672,6 +1710,10 @@ type RootTranslation = {
* Send
*/
send: string
+ /**
+ * Transfer
+ */
+ transfer: string
/**
* Sweep to Wallet
*/
@@ -1790,6 +1832,279 @@ type RootTranslation = {
*/
backupDesc: string
}
+ TopUpScreen: {
+ /**
+ * Top Up
+ */
+ title: string
+ /**
+ * Bank Transfer
+ */
+ bankTransfer: string
+ /**
+ * Transfer funds from your bank
+ */
+ bankTransferDesc: string
+ /**
+ * Debit/Credit Card
+ */
+ debitCreditCard: string
+ /**
+ * Pay with your debit or credit card
+ */
+ debitCreditCardDesc: string
+ }
+ TopupDetails: {
+ /**
+ * Card Payment
+ */
+ title: string
+ /**
+ * Bank Transfer
+ */
+ bankTransfer: string
+ /**
+ * Email
+ */
+ email: string
+ /**
+ * Enter your email address
+ */
+ emailPlaceholder: string
+ /**
+ * Wallet
+ */
+ wallet: string
+ /**
+ * Select wallet
+ */
+ walletPlaceholder: string
+ /**
+ * Amount (USD)
+ */
+ amount: string
+ /**
+ * Enter amount
+ */
+ amountPlaceholder: string
+ /**
+ * Continue
+ */
+ 'continue': string
+ /**
+ * USD Wallet
+ */
+ usdWallet: string
+ /**
+ * BTC Wallet
+ */
+ btcWallet: string
+ /**
+ * Please enter a valid email address
+ */
+ invalidEmail: string
+ /**
+ * Please enter a valid amount
+ */
+ invalidAmount: string
+ /**
+ * Minimum amount is $1.00
+ */
+ minimumAmount: string
+ }
+ BridgeKyc: {
+ /**
+ * International Transfer
+ */
+ title: string
+ /**
+ * Please provide your details to set up international transfers
+ */
+ description: string
+ /**
+ * Full Name
+ */
+ fullName: string
+ /**
+ * Enter your full name
+ */
+ fullNamePlaceholder: string
+ /**
+ * Email
+ */
+ email: string
+ /**
+ * Enter your email address
+ */
+ emailPlaceholder: string
+ /**
+ * Account Type
+ */
+ kycType: string
+ /**
+ * Select account type
+ */
+ kycTypePlaceholder: string
+ /**
+ * Individual
+ */
+ individual: string
+ /**
+ * Business
+ */
+ business: string
+ /**
+ * Submit
+ */
+ submit: string
+ /**
+ * Full name is required
+ */
+ fullNameRequired: string
+ /**
+ * Email is required
+ */
+ emailRequired: string
+ /**
+ * Please enter a valid email address
+ */
+ invalidEmail: string
+ /**
+ * Please select an account type
+ */
+ kycTypeRequired: string
+ }
+ FygaroWebViewScreen: {
+ /**
+ * Fygaro Payment
+ */
+ title: string
+ /**
+ * Loading payment page...
+ */
+ loading: string
+ /**
+ * Failed to load payment page
+ */
+ error: string
+ /**
+ * Retry
+ */
+ retry: string
+ }
+ BankTransfer: {
+ /**
+ * Bank Transfer
+ */
+ title: string
+ /**
+ * Your order has been created. To complete the order, please transfer ${amount} USD to the bank details provided below.
+ * @param {number} amount
+ */
+ desc1: RequiredParams<'amount'>
+ /**
+ * Use {code} as the reference description. This unique code will help us associate the payment with your Flash account and process the Bitcoin transfer.
+ * @param {string} code
+ */
+ desc2: RequiredParams<'code'>
+ /**
+ * After we have received your payment, you will be credited with ${amount} USD in your Cash wallet, with a ${fee} USD fee deducted. You can then choose when you convert those USD to Bitcoin on your own using the Convert functionality in the mobile app.
+ * @param {number} amount
+ * @param {number} fee
+ */
+ desc3: RequiredParams<'amount' | 'fee'>
+ /**
+ * Account Type
+ */
+ accountType: string
+ /**
+ * Destination Bank
+ */
+ destinationBank: string
+ /**
+ * Account Number
+ */
+ accountNumber: string
+ /**
+ * Type of Client
+ */
+ typeOfClient: string
+ /**
+ * Receiver's Name
+ */
+ receiverName: string
+ /**
+ * Email
+ */
+ email: string
+ /**
+ * Amount
+ */
+ amount: string
+ /**
+ * Unique Code
+ */
+ uniqueCode: string
+ /**
+ * Fees
+ */
+ fees: string
+ /**
+ * After payment completion on your end you can send us an email to {email} with a screenshot of your payment confirmation.
+ * @param {string} email
+ */
+ desc4: RequiredParams<'email'>
+ /**
+ * Your payment will be processed even if we don't receive this email, but having this confirmation can help accelerate the order.
+ */
+ desc5: string
+ /**
+ * Back to Home
+ */
+ backHome: string
+ /**
+ * Virtual Bank Transfer
+ */
+ virtualBankTransfer: string
+ /**
+ * Bank Name
+ */
+ bankName: string
+ /**
+ * Routing Number
+ */
+ routingNumber: string
+ }
+ PaymentSuccessScreen: {
+ /**
+ * Payment Successful
+ */
+ title: string
+ /**
+ * Your payment has been processed successfully
+ */
+ successMessage: string
+ /**
+ * Amount Sent
+ */
+ amountSent: string
+ /**
+ * Deposited to
+ */
+ depositedTo: string
+ /**
+ * Transaction ID
+ */
+ transactionId: string
+ /**
+ * Done
+ */
+ done: string
+ /**
+ * View Transaction
+ */
+ viewTransaction: string
+ }
PinScreen: {
/**
* Incorrect PIN. {attemptsRemaining} attempts remaining.
@@ -3607,6 +3922,54 @@ type RootTranslation = {
* % to convert
*/
percentageToConvert: string
+ /**
+ * Top Up
+ */
+ topUp: string
+ /**
+ * Add funds to your wallet
+ */
+ topUpDesc: string
+ /**
+ * Settle
+ */
+ settle: string
+ /**
+ * Cashout funds from your wallet
+ */
+ settleDesc: string
+ /**
+ * Settle to
+ */
+ selectSettleMethod: string
+ /**
+ * Top up via
+ */
+ selectTopUpMethod: string
+ /**
+ * JMD Bank Account
+ */
+ jmdBankAccount: string
+ /**
+ * Withdraw to your Jamaican bank account
+ */
+ jmdBankAccountDesc: string
+ /**
+ * International Bank Account
+ */
+ internationalBankAccount: string
+ /**
+ * Withdraw to your international bank account
+ */
+ internationalBankAccountDesc: string
+ /**
+ * International Bank Transfer
+ */
+ internationalBankTransfer: string
+ /**
+ * Transfer from your international bank account
+ */
+ internationalBankTransferDesc: string
}
UpgradeAccountModal: {
/**
@@ -5538,6 +5901,44 @@ export type TranslationFunctions = {
*/
disclaimer: () => LocalizedString
+ /**
+ * Withdraw to
+ */
+ withdrawTo: () => LocalizedString
+ /**
+ * Bank Name
+ */
+ bankName: () => LocalizedString
+ /**
+ * Bank Branch
+ */
+ bankBranch: () => LocalizedString
+ /**
+ * Account Number
+ */
+ accountNumber: () => LocalizedString
+ /**
+ * Account Type
+ */
+ accountType: () => LocalizedString
+ /**
+ * Currency
+ */
+ currency: () => LocalizedString
+ }
+ CashWalletCutover: {
+ /**
+ * Cash Wallet Updated
+ */
+ title: () => LocalizedString
+ /**
+ * Your Cash Wallet has been upgraded from USD to USDT. Your balance has been automatically migrated. No action is needed on your part.
+ */
+ body: () => LocalizedString
+ /**
+ * Got it
+ */
+ dismissButton: () => LocalizedString
}
ConversionDetailsScreen: {
/**
@@ -6895,6 +7296,10 @@ export type TranslationFunctions = {
* Send
*/
send: () => LocalizedString
+ /**
+ * Transfer
+ */
+ transfer: () => LocalizedString
/**
* Sweep to Wallet
*/
@@ -7013,6 +7418,275 @@ export type TranslationFunctions = {
*/
backupDesc: () => LocalizedString
}
+ TopUpScreen: {
+ /**
+ * Top Up
+ */
+ title: () => LocalizedString
+ /**
+ * Bank Transfer
+ */
+ bankTransfer: () => LocalizedString
+ /**
+ * Transfer funds from your bank
+ */
+ bankTransferDesc: () => LocalizedString
+ /**
+ * Debit/Credit Card
+ */
+ debitCreditCard: () => LocalizedString
+ /**
+ * Pay with your debit or credit card
+ */
+ debitCreditCardDesc: () => LocalizedString
+ }
+ TopupDetails: {
+ /**
+ * Card Payment
+ */
+ title: () => LocalizedString
+ /**
+ * Bank Transfer
+ */
+ bankTransfer: () => LocalizedString
+ /**
+ * Email
+ */
+ email: () => LocalizedString
+ /**
+ * Enter your email address
+ */
+ emailPlaceholder: () => LocalizedString
+ /**
+ * Wallet
+ */
+ wallet: () => LocalizedString
+ /**
+ * Select wallet
+ */
+ walletPlaceholder: () => LocalizedString
+ /**
+ * Amount (USD)
+ */
+ amount: () => LocalizedString
+ /**
+ * Enter amount
+ */
+ amountPlaceholder: () => LocalizedString
+ /**
+ * Continue
+ */
+ 'continue': () => LocalizedString
+ /**
+ * USD Wallet
+ */
+ usdWallet: () => LocalizedString
+ /**
+ * BTC Wallet
+ */
+ btcWallet: () => LocalizedString
+ /**
+ * Please enter a valid email address
+ */
+ invalidEmail: () => LocalizedString
+ /**
+ * Please enter a valid amount
+ */
+ invalidAmount: () => LocalizedString
+ /**
+ * Minimum amount is $1.00
+ */
+ minimumAmount: () => LocalizedString
+ }
+ BridgeKyc: {
+ /**
+ * International Transfer
+ */
+ title: () => LocalizedString
+ /**
+ * Please provide your details to set up international transfers
+ */
+ description: () => LocalizedString
+ /**
+ * Full Name
+ */
+ fullName: () => LocalizedString
+ /**
+ * Enter your full name
+ */
+ fullNamePlaceholder: () => LocalizedString
+ /**
+ * Email
+ */
+ email: () => LocalizedString
+ /**
+ * Enter your email address
+ */
+ emailPlaceholder: () => LocalizedString
+ /**
+ * Account Type
+ */
+ kycType: () => LocalizedString
+ /**
+ * Select account type
+ */
+ kycTypePlaceholder: () => LocalizedString
+ /**
+ * Individual
+ */
+ individual: () => LocalizedString
+ /**
+ * Business
+ */
+ business: () => LocalizedString
+ /**
+ * Submit
+ */
+ submit: () => LocalizedString
+ /**
+ * Full name is required
+ */
+ fullNameRequired: () => LocalizedString
+ /**
+ * Email is required
+ */
+ emailRequired: () => LocalizedString
+ /**
+ * Please enter a valid email address
+ */
+ invalidEmail: () => LocalizedString
+ /**
+ * Please select an account type
+ */
+ kycTypeRequired: () => LocalizedString
+ }
+ FygaroWebViewScreen: {
+ /**
+ * Fygaro Payment
+ */
+ title: () => LocalizedString
+ /**
+ * Loading payment page...
+ */
+ loading: () => LocalizedString
+ /**
+ * Failed to load payment page
+ */
+ error: () => LocalizedString
+ /**
+ * Retry
+ */
+ retry: () => LocalizedString
+ }
+ BankTransfer: {
+ /**
+ * Bank Transfer
+ */
+ title: () => LocalizedString
+ /**
+ * Your order has been created. To complete the order, please transfer ${amount} USD to the bank details provided below.
+ */
+ desc1: (arg: { amount: number }) => LocalizedString
+ /**
+ * Use {code} as the reference description. This unique code will help us associate the payment with your Flash account and process the Bitcoin transfer.
+ */
+ desc2: (arg: { code: string }) => LocalizedString
+ /**
+ * After we have received your payment, you will be credited with ${amount} USD in your Cash wallet, with a ${fee} USD fee deducted. You can then choose when you convert those USD to Bitcoin on your own using the Convert functionality in the mobile app.
+ */
+ desc3: (arg: { amount: number, fee: number }) => LocalizedString
+ /**
+ * Account Type
+ */
+ accountType: () => LocalizedString
+ /**
+ * Destination Bank
+ */
+ destinationBank: () => LocalizedString
+ /**
+ * Account Number
+ */
+ accountNumber: () => LocalizedString
+ /**
+ * Type of Client
+ */
+ typeOfClient: () => LocalizedString
+ /**
+ * Receiver's Name
+ */
+ receiverName: () => LocalizedString
+ /**
+ * Email
+ */
+ email: () => LocalizedString
+ /**
+ * Amount
+ */
+ amount: () => LocalizedString
+ /**
+ * Unique Code
+ */
+ uniqueCode: () => LocalizedString
+ /**
+ * Fees
+ */
+ fees: () => LocalizedString
+ /**
+ * After payment completion on your end you can send us an email to {email} with a screenshot of your payment confirmation.
+ */
+ desc4: (arg: { email: string }) => LocalizedString
+ /**
+ * Your payment will be processed even if we don't receive this email, but having this confirmation can help accelerate the order.
+ */
+ desc5: () => LocalizedString
+ /**
+ * Back to Home
+ */
+ backHome: () => LocalizedString
+ /**
+ * Virtual Bank Transfer
+ */
+ virtualBankTransfer: () => LocalizedString
+ /**
+ * Bank Name
+ */
+ bankName: () => LocalizedString
+ /**
+ * Routing Number
+ */
+ routingNumber: () => LocalizedString
+
+ }
+ PaymentSuccessScreen: {
+ /**
+ * Payment Successful
+ */
+ title: () => LocalizedString
+ /**
+ * Your payment has been processed successfully
+ */
+ successMessage: () => LocalizedString
+ /**
+ * Amount Sent
+ */
+ amountSent: () => LocalizedString
+ /**
+ * Deposited to
+ */
+ depositedTo: () => LocalizedString
+ /**
+ * Transaction ID
+ */
+ transactionId: () => LocalizedString
+ /**
+ * Done
+ */
+ done: () => LocalizedString
+ /**
+ * View Transaction
+ */
+ viewTransaction: () => LocalizedString
+ }
PinScreen: {
/**
* Incorrect PIN. {attemptsRemaining} attempts remaining.
@@ -8779,6 +9453,54 @@ export type TranslationFunctions = {
* % to convert
*/
percentageToConvert: () => LocalizedString
+ /**
+ * Top Up
+ */
+ topUp: () => LocalizedString
+ /**
+ * Add funds to your wallet
+ */
+ topUpDesc: () => LocalizedString
+ /**
+ * Settle
+ */
+ settle: () => LocalizedString
+ /**
+ * Cashout funds from your wallet
+ */
+ settleDesc: () => LocalizedString
+ /**
+ * Settle to
+ */
+ selectSettleMethod: () => LocalizedString
+ /**
+ * Top up via
+ */
+ selectTopUpMethod: () => LocalizedString
+ /**
+ * JMD Bank Account
+ */
+ jmdBankAccount: () => LocalizedString
+ /**
+ * Withdraw to your Jamaican bank account
+ */
+ jmdBankAccountDesc: () => LocalizedString
+ /**
+ * International Bank Account
+ */
+ internationalBankAccount: () => LocalizedString
+ /**
+ * Withdraw to your international bank account
+ */
+ internationalBankAccountDesc: () => LocalizedString
+ /**
+ * International Bank Transfer
+ */
+ internationalBankTransfer: () => LocalizedString
+ /**
+ * Transfer from your international bank account
+ */
+ internationalBankTransferDesc: () => LocalizedString
}
UpgradeAccountModal: {
/**
diff --git a/app/i18n/raw-i18n/source/en.json b/app/i18n/raw-i18n/source/en.json
index 43215625e..5687dd6b0 100644
--- a/app/i18n/raw-i18n/source/en.json
+++ b/app/i18n/raw-i18n/source/en.json
@@ -77,7 +77,18 @@
"receiveAmount": "Receive Amount",
"fee": "Fee",
"success": "Settlement request initiated successfully.",
- "disclaimer": "Please Note: Bank transfers are usually confirmed on the same-day, but may take longer if submitted during the following times:\n\n- Weekdays after 2:00pm\n- Fridays & weekends\n\nTransactions completed after 2:00 pm on weekdays are not confirmed by the bank until the following business day. Please contact us if you do not see your funds within 2-3 business days.\n"
+ "disclaimer": "Please Note: Bank transfers are usually confirmed on the same-day, but may take longer if submitted during the following times:\n\n- Weekdays after 2:00pm\n- Fridays & weekends\n\nTransactions completed after 2:00 pm on weekdays are not confirmed by the bank until the following business day. Please contact us if you do not see your funds within 2-3 business days.\n",
+ "withdrawTo": "Withdraw to",
+ "bankName": "Bank Name",
+ "bankBranch": "Bank Branch",
+ "accountNumber": "Account Number",
+ "accountType": "Account Type",
+ "currency": "Currency"
+ },
+ "CashWalletCutover": {
+ "title": "Cash Wallet Updated",
+ "body": "Your Cash Wallet has been upgraded from USD to USDT. Your balance has been automatically migrated. No action is needed on your part.",
+ "dismissButton": "Got it"
},
"ConversionDetailsScreen": {
"title": "Swap",
@@ -507,6 +518,7 @@
"balance": "Refresh Balance",
"showQrCode": "Topup via QR",
"send": "Send",
+ "transfer": "Transfer",
"sweep": "Sweep to Wallet",
"pay": "Pay",
"title": "Home",
@@ -537,6 +549,82 @@
"backupTitle": "Backup your BTC wallet",
"backupDesc": "Backup and secure your Bitcoin wallet using recovery phrase."
},
+ "TopUpScreen": {
+ "title": "Top Up",
+ "bankTransfer": "Bank Transfer",
+ "bankTransferDesc": "Transfer funds from your bank",
+ "debitCreditCard": "Debit/Credit Card",
+ "debitCreditCardDesc": "Pay with your debit or credit card"
+ },
+ "TopupDetails": {
+ "title": "Card Payment",
+ "bankTransfer": "Bank Transfer",
+ "email": "Email",
+ "emailPlaceholder": "Enter your email address",
+ "wallet": "Wallet",
+ "walletPlaceholder": "Select wallet",
+ "amount": "Amount (USD)",
+ "amountPlaceholder": "Enter amount",
+ "continue": "Continue",
+ "usdWallet": "USD Wallet",
+ "btcWallet": "BTC Wallet",
+ "invalidEmail": "Please enter a valid email address",
+ "invalidAmount": "Please enter a valid amount",
+ "minimumAmount": "Minimum amount is $1.00"
+ },
+ "BridgeKyc": {
+ "title": "International Transfer",
+ "description": "Please provide your details to set up international transfers",
+ "fullName": "Full Name",
+ "fullNamePlaceholder": "Enter your full name",
+ "email": "Email",
+ "emailPlaceholder": "Enter your email address",
+ "kycType": "Account Type",
+ "kycTypePlaceholder": "Select account type",
+ "individual": "Individual",
+ "business": "Business",
+ "submit": "Submit",
+ "fullNameRequired": "Full name is required",
+ "emailRequired": "Email is required",
+ "invalidEmail": "Please enter a valid email address",
+ "kycTypeRequired": "Please select an account type"
+ },
+ "FygaroWebViewScreen": {
+ "title": "Fygaro Payment",
+ "loading": "Loading payment page...",
+ "error": "Failed to load payment page",
+ "retry": "Retry"
+ },
+ "BankTransfer": {
+ "title": "Bank Transfer",
+ "desc1": "Your order has been created. To complete the order, please transfer ${amount: number} USD to the bank details provided below.",
+ "desc2": "Use {code: string} as the reference description. This unique code will help us associate the payment with your Flash account and process the Bitcoin transfer.",
+ "desc3": "After we have received your payment, you will be credited with ${amount: number} USD in your Cash wallet, with a ${fee: number} USD fee deducted. You can then choose when you convert those USD to Bitcoin on your own using the Convert functionality in the mobile app.",
+ "accountType": "Account Type",
+ "destinationBank": "Destination Bank",
+ "accountNumber": "Account Number",
+ "typeOfClient": "Type of Client",
+ "receiverName": "Receiver's Name",
+ "email": "Email",
+ "amount": "Amount",
+ "uniqueCode": "Unique Code",
+ "fees": "Fees",
+ "desc4": "After payment completion on your end you can send us an email to {email: string} with a screenshot of your payment confirmation.",
+ "desc5": "Your payment will be processed even if we don't receive this email, but having this confirmation can help accelerate the order.",
+ "backHome": "Back to Home",
+ "virtualBankTransfer": "Virtual Bank Transfer",
+ "bankName": "Bank Name",
+ "routingNumber": "Routing Number"
+ },
+ "PaymentSuccessScreen": {
+ "title": "Payment Successful",
+ "successMessage": "Your payment has been processed successfully",
+ "amountSent": "Amount Sent",
+ "depositedTo": "Deposited to",
+ "transactionId": "Transaction ID",
+ "done": "Done",
+ "viewTransaction": "View Transaction"
+ },
"PinScreen": {
"attemptsRemaining": "Incorrect PIN. {attemptsRemaining: number} attempts remaining.",
"oneAttemptRemaining": "Incorrect PIN. 1 attempt remaining.",
@@ -709,7 +797,6 @@
"amount": "Amount",
"MinOnChainLimit": "Minimum amount for this transaction is US$2.00",
"MinOnChainSatLimit": "Minimum amount for this transaction is 5,500 sats",
- "MinFlashcardLimit": "Minimum amount when reloading from flashcard is 100 sats",
"amountExceed": "Amount exceeds your balance of {balance: string}",
"amountExceedsLimit": "Amount exceeds your remaining daily limit of {limit: string}",
"upgradeAccountToIncreaseLimit": "Upgrade your account to increase your limit",
@@ -1035,7 +1122,19 @@
},
"TransferScreen": {
"title": "Transfer",
- "percentageToConvert": "% to convert"
+ "percentageToConvert": "% to convert",
+ "topUp": "Top Up",
+ "topUpDesc": "Add funds to your wallet",
+ "settle": "Settle",
+ "settleDesc": "Cashout funds from your wallet",
+ "selectSettleMethod": "Settle to",
+ "selectTopUpMethod": "Top up via",
+ "jmdBankAccount": "JMD Bank Account",
+ "jmdBankAccountDesc": "Withdraw to your Jamaican bank account",
+ "internationalBankAccount": "International Bank Account",
+ "internationalBankAccountDesc": "Withdraw to your international bank account",
+ "internationalBankTransfer": "International Bank Transfer",
+ "internationalBankTransferDesc": "Transfer from your international bank account"
},
"UpgradeAccountModal": {
"title": "Upgrade your account",
diff --git a/app/navigation/root-navigator.tsx b/app/navigation/root-navigator.tsx
index 8d519a3d0..4077a1a2f 100644
--- a/app/navigation/root-navigator.tsx
+++ b/app/navigation/root-navigator.tsx
@@ -108,11 +108,6 @@ import HomeInactive from "@app/assets/icons/home-inactive.svg"
import MapActive from "@app/assets/icons/map-active.svg"
import MapInactive from "@app/assets/icons/map-inactive.svg"
import ScanQR from "@app/assets/icons/scan-qr.svg"
-import {
- CashoutDetails,
- CashoutConfirmation,
- CashoutSuccess,
-} from "@app/screens/cashout-screen"
import { NostrSettingsScreen } from "@app/screens/settings-screen/nostr-settings/nostr-settings-screen"
import ContactDetailsScreen from "@app/screens/chat/contactDetailsScreen"
import { SupportGroupChatScreen } from "@app/screens/chat/GroupChat/SupportGroupChat"
@@ -129,6 +124,18 @@ import {
Success,
} from "@app/screens/account-upgrade-flow"
import { FeaturedProfileView } from "@app/screens/featured-profile-view"
+import {
+ BankTransfer,
+ BridgeKycWebView,
+ TopupDetails,
+ TopupSuccess,
+ TopupCashout,
+ CardPayment,
+ CashoutDetails,
+ CashoutConfirmation,
+ CashoutSuccess,
+ PaymentSuccessScreen,
+} from "@app/screens/topup-cashout-flow"
const useStyles = makeStyles(({ colors }) => ({
bottomNavigatorStyle: {
@@ -655,6 +662,35 @@ export const RootStack = () => {
gestureEnabled: false,
}}
/>
+
+
+
+
+
+
+
+
+
)
}
@@ -757,7 +793,8 @@ export const PrimaryNavigator = () => {
title: LL.HomeScreen.title(),
tabBarAccessibilityLabel: LL.HomeScreen.title(),
tabBarTestID: LL.HomeScreen.title(),
- tabBarIcon: ({ focused, color }) => (focused ? : ),
+ tabBarIcon: ({ focused, color }) =>
+ focused ? : ,
}}
/>
{/* {
headerShown: false,
tabBarAccessibilityLabel: LL.MapScreen.title(),
tabBarTestID: LL.MapScreen.title(),
- tabBarIcon: ({ focused, color }) => (focused ? : ),
+ tabBarIcon: ({ focused, color }) =>
+ focused ? : ,
}}
/>
{
setIsVisible={setIsUnverifiedSeedModalVisible}
/>
+
)
}
diff --git a/app/screens/topup-cashout-flow/BankTransfer.tsx b/app/screens/topup-cashout-flow/BankTransfer.tsx
new file mode 100644
index 000000000..ece91e7da
--- /dev/null
+++ b/app/screens/topup-cashout-flow/BankTransfer.tsx
@@ -0,0 +1,185 @@
+import React from "react"
+import { View } from "react-native"
+import { makeStyles, Text } from "@rneui/themed"
+import { StackScreenProps } from "@react-navigation/stack"
+import { RootStackParamList } from "@app/navigation/stack-param-lists"
+
+// hooks
+import { useI18nContext } from "@app/i18n/i18n-react"
+import { useSafeAreaInsets } from "react-native-safe-area-context"
+
+// components
+import { Screen } from "@app/components/screen"
+import { PrimaryBtn } from "@app/components/buttons"
+
+// gql
+import { useBridgeVirtualAccountQuery } from "@app/graphql/generated"
+
+type Props = StackScreenProps
+
+const BankTransfer: React.FC = ({ navigation, route }) => {
+ const styles = useStyles()
+ const { bottom } = useSafeAreaInsets()
+ const { LL } = useI18nContext()
+
+ const { data } = useBridgeVirtualAccountQuery()
+
+ const { amount, wallet, paymentType } = route.params
+ const fee = amount * 0.02
+
+ if (paymentType === "bridge") {
+ return (
+
+
+ {LL.BankTransfer.virtualBankTransfer()}
+
+
+ {LL.BankTransfer.desc1({ amount: amount + fee })}
+
+
+ {LL.BankTransfer.bankName()}
+
+ {data?.bridgeVirtualAccount?.bankName}
+
+
+
+ {LL.BankTransfer.accountNumber()}
+
+ {data?.bridgeVirtualAccount?.accountNumber}
+
+
+
+ {LL.BankTransfer.routingNumber()}
+
+ {data?.bridgeVirtualAccount?.routingNumber}
+
+
+
+ )
+ }
+
+ return (
+
+
+ {LL.BankTransfer.title()}
+
+
+ {LL.BankTransfer.desc1({ amount: amount + fee })}
+
+
+ {LL.BankTransfer.desc2({ code: "UUM7MJRD" })}
+
+
+ {LL.BankTransfer.desc3({ amount: amount, fee: fee })}
+
+
+
+ {LL.BankTransfer.accountType()}
+
+ Checking
+
+
+
+ {LL.BankTransfer.destinationBank()}
+
+ Banco Hipotecario
+
+
+
+ {LL.BankTransfer.accountNumber()}
+
+ 00210312362
+
+
+
+ {LL.BankTransfer.typeOfClient()}
+
+ Corporate
+
+
+
+ {LL.BankTransfer.receiverName()}
+
+ BBW SA de CV
+
+
+
+ {LL.BankTransfer.email()}
+
+ fiat@blink.sv
+
+
+
+ {LL.BankTransfer.amount()}
+
+ {`${amount + fee} USD`}
+
+
+
+ {LL.BankTransfer.uniqueCode()}
+
+ UUM7MJRD
+
+
+
+ {LL.BankTransfer.fees()}
+
+ {`${fee} USD`}
+
+
+
+
+ {LL.BankTransfer.desc4({ email: "fiat@blink.sv" })}
+
+
+ {LL.BankTransfer.desc5()}
+
+ navigation.reset({ index: 0, routes: [{ name: "Primary" }] })}
+ btnStyle={{ marginBottom: bottom + 20, marginTop: 20 }}
+ />
+
+ )
+}
+
+export default BankTransfer
+
+const useStyles = makeStyles(({ colors }) => ({
+ container: {
+ flex: 1,
+ paddingHorizontal: 20,
+ },
+ title: {
+ textAlign: "center",
+ marginBottom: 30,
+ },
+ desc: {
+ marginBottom: 15,
+ },
+ bankDetails: {
+ marginVertical: 20,
+ },
+ fieldContainer: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ backgroundColor: colors.grey5,
+ padding: 20,
+ borderRadius: 10,
+ marginBottom: 15,
+ },
+ input: {
+ borderWidth: 1,
+ borderColor: colors.grey3,
+ borderRadius: 12,
+ padding: 16,
+ fontSize: 16,
+ backgroundColor: colors.white,
+ color: colors.black,
+ marginTop: 8,
+ },
+ buttonGroup: {
+ marginTop: 8,
+ },
+}))
diff --git a/app/screens/topup-cashout-flow/BridgeKycWebView.tsx b/app/screens/topup-cashout-flow/BridgeKycWebView.tsx
new file mode 100644
index 000000000..dff28ea63
--- /dev/null
+++ b/app/screens/topup-cashout-flow/BridgeKycWebView.tsx
@@ -0,0 +1,292 @@
+import React, { useState, useRef, useCallback } from "react"
+import {
+ View,
+ ActivityIndicator,
+ Linking,
+ Platform,
+ TouchableOpacity,
+} from "react-native"
+import { StackScreenProps } from "@react-navigation/stack"
+import { Text, makeStyles, useTheme } from "@rneui/themed"
+import { RootStackParamList } from "@app/navigation/stack-param-lists"
+import { WebView, WebViewNavigation } from "react-native-webview"
+import Icon from "react-native-vector-icons/Ionicons"
+import { Screen } from "@app/components/screen"
+import { PrimaryBtn } from "@app/components/buttons"
+
+type Props = StackScreenProps
+
+type Step = "tos" | "kyc"
+
+// Injected JS to detect ToS acceptance.
+// The Bridge ToS page is a SPA — after clicking "Accept", the page content
+// updates inline without a URL change. We intercept the Accept button click,
+// then poll for the page content change that indicates acceptance.
+const TOS_INJECTED_JS = `(function() {
+ var accepted = false;
+ var initialText = '';
+
+ function notifyAccepted() {
+ if (accepted) return;
+ accepted = true;
+ window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'tos_accepted' }));
+ }
+
+ function checkForContentChange() {
+ if (accepted) return;
+ var currentText = document.body ? document.body.innerText : '';
+ var buttons = document.querySelectorAll('button');
+ var hasAcceptButton = false;
+ buttons.forEach(function(btn) {
+ if (btn.innerText.trim().toLowerCase() === 'accept') hasAcceptButton = true;
+ });
+ if (!hasAcceptButton && initialText && currentText !== initialText) {
+ notifyAccepted();
+ }
+ }
+
+ setTimeout(function() {
+ initialText = document.body ? document.body.innerText : '';
+ }, 2000);
+
+ document.addEventListener('click', function(e) {
+ var target = e.target;
+ while (target && target !== document.body) {
+ if (target.tagName === 'BUTTON' || target.tagName === 'A') {
+ var text = (target.innerText || '').trim().toLowerCase();
+ if (text === 'accept' || text === 'i accept' || text === 'agree') {
+ setTimeout(checkForContentChange, 1500);
+ setTimeout(checkForContentChange, 3000);
+ setTimeout(checkForContentChange, 5000);
+ break;
+ }
+ }
+ target = target.parentElement;
+ }
+ }, true);
+
+ if (document.body) {
+ var clickedAccept = false;
+ document.addEventListener('click', function() { clickedAccept = true; }, true);
+ var observer = new MutationObserver(function() {
+ if (clickedAccept) checkForContentChange();
+ });
+ observer.observe(document.body, { childList: true, subtree: true });
+ }
+ true;
+})();`
+
+// iOS zoom prevention: force 16px font on inputs, disable text-size-adjust,
+// and use MutationObserver for dynamically added inputs.
+const KYC_ZOOM_PREVENTION_JS = `(function(){
+ document.querySelectorAll('meta[name="viewport"]').forEach(m=>m.remove());
+ var meta=document.createElement('meta');
+ meta.name='viewport';
+ meta.content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no';
+ document.head.insertBefore(meta,document.head.firstChild);
+ var style=document.createElement('style');
+ style.innerHTML='input,textarea,select{font-size:16px!important}*{-webkit-text-size-adjust:100%!important;touch-action:manipulation!important}';
+ document.head.appendChild(style);
+ var preventZoom=function(e){if(e.target&&(e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA')){e.target.style.fontSize='16px';e.target.style.transform='none'}};
+ document.addEventListener('focusin',preventZoom,true);
+ document.querySelectorAll('input,textarea,select').forEach(function(el){el.style.fontSize='16px'});
+ var observer=new MutationObserver(function(mutations){mutations.forEach(function(m){m.addedNodes.forEach(function(n){if(n.nodeType===1){var inputs=n.querySelectorAll?n.querySelectorAll('input,textarea,select'):[];inputs.forEach(function(el){el.style.fontSize='16px'})}})})});
+ if(document.body){observer.observe(document.body,{childList:true,subtree:true})}
+ true})();`
+
+// Viewport meta injection before content loads to prevent initial zoom.
+const VIEWPORT_INJECTION_JS = `(function(){const forceViewport=()=>{const content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no';document.querySelectorAll('meta[name="viewport"]').forEach(m=>m.remove());const meta=document.createElement('meta');meta.name='viewport';meta.content=content;if(document.head){document.head.insertBefore(meta,document.head.firstChild)}else{document.documentElement.appendChild(meta)}};forceViewport();document.addEventListener('DOMContentLoaded',forceViewport);window.addEventListener('load',forceViewport);if(document.documentElement){document.documentElement.style.touchAction='pan-x pan-y'}true})();`
+
+const BridgeKycWebView: React.FC = ({ navigation, route }) => {
+ const styles = useStyles()
+ const { colors } = useTheme().theme
+ const webViewRef = useRef(null)
+ const [isLoading, setIsLoading] = useState(true)
+ const [currentStep, setCurrentStep] = useState("tos")
+ const [error, setError] = useState(false)
+ const isNavigating = useRef(false)
+
+ const { tosLink, kycLink } = route.params
+
+ const currentUrl = currentStep === "tos" ? tosLink : kycLink
+
+ const safeGoBack = useCallback(() => {
+ if (isNavigating.current) return
+ isNavigating.current = true
+ navigation.goBack()
+ }, [navigation])
+
+ const handleNavigationStateChange = useCallback(
+ (navState: WebViewNavigation) => {
+ const { url } = navState
+
+ if (currentStep === "kyc") {
+ if (
+ url.includes("complete") ||
+ url.includes("success") ||
+ url.includes("verified")
+ ) {
+ safeGoBack()
+ }
+ }
+ },
+ [currentStep, safeGoBack],
+ )
+
+ const handleMessage = useCallback(
+ (event: { nativeEvent: { data: string } }) => {
+ try {
+ const data = JSON.parse(event.nativeEvent.data)
+ if (currentStep === "tos" && data.type === "tos_accepted") {
+ setCurrentStep("kyc")
+ setIsLoading(true)
+ } else if (currentStep === "kyc" && data.status === "completed") {
+ safeGoBack()
+ }
+ } catch {
+ // Not JSON - ignore
+ }
+ },
+ [currentStep, safeGoBack],
+ )
+
+ const handleRetry = () => {
+ setError(false)
+ setIsLoading(true)
+ webViewRef.current?.reload()
+ }
+
+ const closeButton = (
+
+
+
+
+
+ )
+
+ if (error) {
+ return (
+
+ {closeButton}
+
+
+ Failed to load
+
+
+
+
+ )
+ }
+
+ return (
+
+ {closeButton}
+
+ {isLoading && (
+
+
+
+ {currentStep === "tos"
+ ? "Loading Terms of Service..."
+ : "Loading KYC Verification..."}
+
+
+ )}
+ {
+ setIsLoading(false)
+ setError(false)
+ }}
+ onError={() => {
+ setIsLoading(false)
+ setError(true)
+ }}
+ injectedJavaScriptBeforeContentLoaded={VIEWPORT_INJECTION_JS}
+ injectedJavaScript={
+ currentStep === "tos" ? TOS_INJECTED_JS : KYC_ZOOM_PREVENTION_JS
+ }
+ style={styles.webView}
+ javaScriptEnabled
+ domStorageEnabled
+ startInLoadingState
+ scalesPageToFit={false}
+ bounces={false}
+ sharedCookiesEnabled
+ thirdPartyCookiesEnabled
+ onShouldStartLoadWithRequest={(request) => {
+ // During ToS step, open terms/privacy links in external browser
+ if (currentStep === "tos" && request.url !== tosLink) {
+ const url = request.url.toLowerCase()
+ if (url.includes("www.bridge.xyz/legal")) {
+ Linking.openURL(request.url)
+ return false
+ }
+ }
+ return true
+ }}
+ originWhitelist={["https://*", "http://*"]}
+ userAgent={
+ Platform.OS === "ios"
+ ? "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
+ : undefined
+ }
+ />
+
+
+ )
+}
+
+const useStyles = makeStyles(({ colors }) => ({
+ closeButtonWrapper: {
+ position: "absolute",
+ zIndex: 1,
+ top: 15,
+ right: 15,
+ },
+ closeButton: {
+ width: 44,
+ height: 44,
+ borderRadius: 22,
+ backgroundColor: colors.white,
+ justifyContent: "center",
+ alignItems: "center",
+ shadowColor: colors.black,
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.15,
+ shadowRadius: 4,
+ elevation: 5,
+ },
+ container: { flex: 1 },
+ centerContainer: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ padding: 20,
+ },
+ loadingContainer: {
+ position: "absolute",
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ justifyContent: "center",
+ alignItems: "center",
+ backgroundColor: "rgba(255, 255, 255, 0.9)",
+ zIndex: 1,
+ },
+ loadingText: { marginTop: 16, textAlign: "center" },
+ errorText: { textAlign: "center", marginBottom: 24 },
+ retryButton: { marginTop: 16 },
+ webView: { flex: 1 },
+}))
+
+export default BridgeKycWebView
diff --git a/app/screens/topup-cashout-flow/CardPayment.tsx b/app/screens/topup-cashout-flow/CardPayment.tsx
new file mode 100644
index 000000000..1104a936b
--- /dev/null
+++ b/app/screens/topup-cashout-flow/CardPayment.tsx
@@ -0,0 +1,374 @@
+/**
+ * CardPayment Component
+ *
+ * This component handles the web-based card payment flow for topping up Flash wallets.
+ * It embeds external payment provider forms (Fygaro, PayPal, Stripe) in a WebView
+ * and manages the entire payment lifecycle.
+ *
+ * Key features:
+ * - Embeds Fygaro payment form (and other providers) in WebView
+ * - Prevents iOS zoom issues when users tap input fields
+ * - Domain whitelisting for security
+ * - Handles payment success/failure callbacks
+ * - Desktop user agent spoofing on iOS to prevent mobile-specific issues
+ */
+
+import React, { useState, useRef } from "react"
+import { View, ActivityIndicator, Alert, Platform } from "react-native"
+import { StackScreenProps } from "@react-navigation/stack"
+import { Text, makeStyles, useTheme } from "@rneui/themed"
+import { RootStackParamList } from "@app/navigation/stack-param-lists"
+import { WebView } from "react-native-webview"
+import { Screen } from "@app/components/screen"
+import { PrimaryBtn } from "@app/components/buttons"
+import { useI18nContext } from "@app/i18n/i18n-react"
+import { useHomeAuthedQuery } from "@app/graphql/generated"
+import { useIsAuthed } from "@app/graphql/is-authed-context"
+
+type Props = StackScreenProps
+
+const CardPayment: React.FC = ({ navigation, route }) => {
+ const isAuthed = useIsAuthed()
+ const styles = useStyles()
+ const { colors } = useTheme().theme
+ const { LL } = useI18nContext()
+ const webViewRef = useRef(null)
+ const [isLoading, setIsLoading] = useState(true)
+ const [error, setError] = useState(false)
+
+ // Get authenticated user data to extract username for webhook processing
+ const { data } = useHomeAuthedQuery({ skip: !isAuthed, fetchPolicy: "cache-first" })
+ const { amount, wallet } = route.params
+ const username = data?.me?.username || "user"
+
+ /**
+ * Build Fygaro payment URL with critical parameters:
+ * - amount: The payment amount in USD
+ * - client_reference: Flash username (CRITICAL: used by webhook to identify user)
+ *
+ * NOTE: The user will enter their email directly on Fygaro's form to avoid
+ * double entry. The email is only for Fygaro's records, not for Flash processing.
+ */
+ const paymentUrl = `https://fygaro.com/en/pb/bd4a34c1-3d24-4315-a2b8-627518f70916?amount=${amount}&client_reference=${username}`
+
+ /**
+ * Domain whitelist for security.
+ *
+ * Only allows navigation to trusted payment provider domains.
+ * This prevents:
+ * - Phishing attacks via redirect
+ * - Malicious JavaScript injection
+ * - Data exfiltration to unauthorized domains
+ *
+ * Includes all necessary domains for:
+ * - Fygaro (primary provider)
+ * - PayPal (Fygaro uses PayPal for processing)
+ * - Stripe (future provider support)
+ */
+ const allowedDomains = [
+ "fygaro.com",
+ "www.fygaro.com",
+ "api.fygaro.com",
+ "checkout.fygaro.com",
+ // PayPal domains (required for Fygaro's PayPal integration)
+ "www.paypal.com",
+ "checkout.paypal.com",
+ "paypalobjects.com",
+ "paypal-activation.com",
+ "paypal.com",
+ "paypal-cdn.com",
+ "paypal-experience.com",
+ "paypal-dynamic-assets.com",
+ "paypalcorp.com",
+ // Stripe domains (for future integration)
+ "stripe.com",
+ "checkout.stripe.com",
+ "js.stripe.com",
+ "m.stripe.com",
+ ]
+
+ /**
+ * Monitors URL changes to detect payment completion.
+ *
+ * Payment providers redirect to specific URLs on success/failure:
+ * - Success: URL contains "success" or "payment_success"
+ * - Failure: URL contains "error", "failed", or "cancelled"
+ *
+ * On success: Navigate to success screen (webhook will handle actual crediting)
+ * On failure: Show error alert and allow retry
+ *
+ * NOTE: The actual account crediting happens via webhook on the backend.
+ * This frontend handling is just for UX feedback.
+ */
+ const handleNavigationStateChange = ({ url }: { url: string }) => {
+ if (url.includes("success") || url.includes("payment_success")) {
+ // Payment succeeded - navigate to success screen
+ // The webhook will handle the actual wallet credit
+ navigation.navigate("paymentSuccess", {
+ amount,
+ wallet,
+ transactionId: `txn_${Date.now()}`, // Temporary ID for UI
+ })
+ } else if (
+ url.includes("error") ||
+ url.includes("failed") ||
+ url.includes("cancelled")
+ ) {
+ // Payment failed - show error and allow retry
+ Alert.alert("Payment Failed", "Your payment was not completed. Please try again.", [
+ { text: "OK", onPress: () => navigation.goBack() },
+ ])
+ }
+ }
+
+ /**
+ * Validates if a URL is from an allowed domain.
+ *
+ * Security function that checks URLs against our whitelist.
+ * Handles:
+ * - Exact domain matches (paypal.com)
+ * - Subdomain matches (checkout.paypal.com)
+ * - Invalid URLs (returns false)
+ *
+ * This prevents navigation to untrusted domains.
+ */
+ const isAllowedDomain = (url: string): boolean => {
+ try {
+ const domain = new URL(url).hostname
+ return allowedDomains.some(
+ (allowed) =>
+ domain === allowed || // Exact match
+ domain.endsWith(`.${allowed}`) || // Subdomain match
+ allowed.endsWith(`.${domain}`), // Parent domain match
+ )
+ } catch {
+ // Invalid URL - deny by default
+ return false
+ }
+ }
+
+ const handleRetry = () => {
+ setError(false)
+ setIsLoading(true)
+ webViewRef.current?.reload()
+ }
+
+ if (error) {
+ return (
+
+
+
+ {LL.FygaroWebViewScreen.error()}
+
+
+
+
+ )
+ }
+
+ return (
+
+
+ {isLoading && (
+
+
+
+ {LL.FygaroWebViewScreen.loading()}
+
+
+ )}
+ {
+ setIsLoading(false)
+ setError(false)
+ }}
+ onError={() => {
+ setIsLoading(false)
+ setError(true)
+ }}
+ /**
+ * URL navigation filter for security and iOS compatibility.
+ *
+ * This callback determines which URLs the WebView can navigate to.
+ * Platform-specific logic:
+ *
+ * iOS:
+ * - Allows about:, blob:, data: schemes (prevents warnings)
+ * - Allows all HTTPS URLs (PayPal requires many domains)
+ * - Blocks HTTP to enforce encryption
+ *
+ * Android:
+ * - Uses strict domain whitelist
+ * - More restrictive but more secure
+ *
+ * The iOS approach is less restrictive due to PayPal's complex
+ * redirect flow that uses many subdomains not in our whitelist.
+ */
+ onShouldStartLoadWithRequest={({ url }) => {
+ // Allow about: URLs (used for iframes) to prevent iOS warnings
+ if (url.startsWith("about:")) {
+ return true
+ }
+
+ // Allow blob: and data: URLs for embedded content
+ if (url.startsWith("blob:") || url.startsWith("data:")) {
+ return true
+ }
+
+ // iOS: Allow HTTPS and internal URLs
+ // Less restrictive due to PayPal's complex domain requirements
+ if (Platform.OS === "ios") {
+ return url.startsWith("https://") || !url.startsWith("http")
+ }
+
+ // Android: Use domain whitelist for stricter security
+ return isAllowedDomain(url)
+ }}
+ style={styles.webView}
+ javaScriptEnabled
+ domStorageEnabled
+ startInLoadingState
+ scalesPageToFit={false}
+ bounces={false}
+ scrollEnabled
+ allowsBackForwardNavigationGestures
+ allowsInlineMediaPlayback
+ allowsFullscreenVideo={false}
+ allowFileAccess={false}
+ allowUniversalAccessFromFileURLs={false}
+ mixedContentMode="never"
+ originWhitelist={["https://*", "http://*", "about:*", "data:*", "blob:*"]}
+ sharedCookiesEnabled
+ thirdPartyCookiesEnabled
+ cacheEnabled
+ incognito={false}
+ webviewDebuggingEnabled={__DEV__}
+ automaticallyAdjustContentInsets={false}
+ contentInsetAdjustmentBehavior="never"
+ allowsLinkPreview={false}
+ injectedJavaScriptForMainFrameOnly
+ /**
+ * Custom User Agent for iOS to prevent zoom issues.
+ *
+ * CRITICAL: This desktop user agent prevents iOS WebView from:
+ * - Auto-zooming when users tap input fields
+ * - Showing mobile-specific layouts that break
+ * - Triggering viewport zoom on focus
+ *
+ * Without this, iOS WebView zooms in when users tap the
+ * payment form fields, creating a poor user experience.
+ *
+ * Android doesn't need this workaround.
+ */
+ userAgent={
+ Platform.OS === "ios"
+ ? "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
+ : undefined
+ }
+ dataDetectorTypes="none"
+ /**
+ * Pre-content JavaScript injection for early zoom prevention.
+ *
+ * Executes BEFORE the page content loads to:
+ * - Force viewport meta tag with no zoom
+ * - Set touch-action CSS to prevent pinch zoom
+ * - Run on multiple events to catch dynamic content
+ *
+ * This is the first line of defense against iOS zoom issues.
+ */
+ injectedJavaScriptBeforeContentLoaded={`(function(){const forceViewport=()=>{const content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no';document.querySelectorAll('meta[name="viewport"]').forEach(m=>m.remove());const meta=document.createElement('meta');meta.name='viewport';meta.content=content;if(document.head){document.head.insertBefore(meta,document.head.firstChild)}else{document.documentElement.appendChild(meta)}};forceViewport();document.addEventListener('DOMContentLoaded',forceViewport);window.addEventListener('load',forceViewport);if(document.documentElement){document.documentElement.style.touchAction='pan-x pan-y'}true})();`}
+ /**
+ * Post-content JavaScript injection for comprehensive zoom prevention.
+ *
+ * This aggressive approach handles:
+ * 1. Viewport meta tag enforcement
+ * 2. CSS styles to prevent zoom (16px font size is key)
+ * 3. Focus event handlers to reset zoom on input focus
+ * 4. MutationObserver to handle dynamically added inputs
+ * 5. Double-tap prevention
+ *
+ * The 16px font size is critical - iOS auto-zooms on inputs
+ * with font size less than 16px.
+ *
+ * Combined with desktop user agent, this completely prevents
+ * the iOS zoom issue that occurs when users tap payment form fields.
+ */
+ injectedJavaScript={`(function(){
+ // Zoom prevention code only
+ document.querySelectorAll('meta[name="viewport"]').forEach(m=>m.remove());
+ const meta=document.createElement('meta');
+ meta.name='viewport';
+ meta.content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no';
+ document.head.insertBefore(meta,document.head.firstChild);
+
+ const style=document.createElement('style');
+ style.innerHTML='*{-webkit-text-size-adjust:100%!important;text-size-adjust:100%!important;-webkit-user-select:none!important;user-select:none!important;touch-action:manipulation!important}html,body{touch-action:pan-x pan-y!important;overflow-x:hidden!important}input,textarea,select,button{font-size:16px!important;transform:none!important;zoom:reset!important;-webkit-appearance:none!important}input:focus,textarea:focus,select:focus{font-size:16px!important;zoom:1!important}';
+ document.head.appendChild(style);
+
+ const preventZoom=e=>{if(e.target&&(e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA')){e.target.style.fontSize='16px';e.target.style.transform='scale(1)';e.target.style.zoom='1';const oldMeta=document.querySelector('meta[name="viewport"]');if(oldMeta){oldMeta.content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no'}}};
+ document.addEventListener('focusin',preventZoom,true);
+ document.addEventListener('focus',preventZoom,true);
+
+ // Watch for dynamically added inputs and apply zoom prevention
+ const observer=new MutationObserver(mutations=>{
+ mutations.forEach(mutation=>{
+ mutation.addedNodes.forEach(node=>{
+ if(node.nodeType===1){
+ const inputs=node.querySelectorAll?node.querySelectorAll('input, textarea, select'):[];
+ inputs.forEach(input=>{
+ input.style.fontSize='16px';
+ input.addEventListener('focus',preventZoom,true);
+ });
+ }
+ })
+ })
+ });
+
+ if(document.body){observer.observe(document.body,{childList:true,subtree:true})}
+
+ document.querySelectorAll('input, textarea, select').forEach(el=>{el.style.fontSize='16px';el.addEventListener('focus',preventZoom,true)});
+
+ let lastTouchEnd=0;
+ document.addEventListener('touchend',e=>{const now=Date.now();if(now-lastTouchEnd<=300){e.preventDefault()}lastTouchEnd=now},{passive:false});
+
+ true
+ })();`}
+ />
+
+
+ )
+}
+
+const useStyles = makeStyles(() => ({
+ container: { flex: 1 },
+ centerContainer: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ padding: 20,
+ },
+ loadingContainer: {
+ position: "absolute",
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ justifyContent: "center",
+ alignItems: "center",
+ backgroundColor: "rgba(255, 255, 255, 0.9)",
+ zIndex: 1,
+ },
+ loadingText: { marginTop: 16, textAlign: "center" },
+ errorText: { textAlign: "center", marginBottom: 24 },
+ retryButton: { marginTop: 16 },
+ webView: { flex: 1 },
+}))
+
+export default CardPayment
diff --git a/app/screens/cashout-screen/CashoutConfirmation.tsx b/app/screens/topup-cashout-flow/CashoutConfirmation.tsx
similarity index 76%
rename from app/screens/cashout-screen/CashoutConfirmation.tsx
rename to app/screens/topup-cashout-flow/CashoutConfirmation.tsx
index 526f77f8c..7ca651b46 100644
--- a/app/screens/cashout-screen/CashoutConfirmation.tsx
+++ b/app/screens/topup-cashout-flow/CashoutConfirmation.tsx
@@ -7,10 +7,11 @@ import moment from "moment"
// components
import { Screen } from "@app/components/screen"
import { PrimaryBtn } from "@app/components/buttons"
-import { CashoutCard, CashoutFromWallet } from "@app/components/cashout-flow"
+import { CashoutCard, CashoutFromWallet, CashoutWithdrawTo } from "@app/components/topup-cashout-flow"
// hooks
import { useI18nContext } from "@app/i18n/i18n-react"
+import { useSafeAreaInsets } from "react-native-safe-area-context"
import { useActivityIndicator, useDisplayCurrency } from "@app/hooks"
import { useCashoutScreenQuery, useInitiateCashoutMutation } from "@app/graphql/generated"
@@ -25,8 +26,9 @@ type Props = StackScreenProps
const CashoutConfirmation: React.FC = ({ navigation, route }) => {
const styles = useStyles()
const { colors } = useTheme().theme
+ const { bottom } = useSafeAreaInsets()
const { LL } = useI18nContext()
- const { formatMoneyAmount } = useDisplayCurrency()
+ const { moneyAmountToDisplayCurrencyString, displayCurrency } = useDisplayCurrency()
const { toggleActivityIndicator } = useActivityIndicator()
const [errorMsg, setErrorMsg] = useState()
@@ -55,8 +57,7 @@ const CashoutConfirmation: React.FC = ({ navigation, route }) => {
const onConfirm = async () => {
toggleActivityIndicator(true)
const res = await initiateCashout({ variables: { input: { walletId, offerId } } })
- console.log("RESPONSE>>>>>>>>>>>>", res)
- if (res.data?.initiateCashout.success) {
+ if (res.data?.initiateCashout.journalId) {
navigation.navigate("CashoutSuccess")
} else {
setErrorMsg(res.data?.initiateCashout.errors[0].message)
@@ -64,15 +65,15 @@ const CashoutConfirmation: React.FC = ({ navigation, route }) => {
toggleActivityIndicator(false)
}
- const formattedSendAmount = formatMoneyAmount({
+ const formattedSendAmount = moneyAmountToDisplayCurrencyString({
moneyAmount: toUsdMoneyAmount(send ?? NaN),
})
- const formattedReceiveUsdAmount = formatMoneyAmount({
+ const formattedReceiveUsdAmount = moneyAmountToDisplayCurrencyString({
moneyAmount: toUsdMoneyAmount(receiveUsd ?? NaN),
})
- const formattedFeeAmount = formatMoneyAmount({
+ const formattedFeeAmount = moneyAmountToDisplayCurrencyString({
moneyAmount: toUsdMoneyAmount(flashFee ?? NaN),
})
@@ -83,13 +84,17 @@ const CashoutConfirmation: React.FC = ({ navigation, route }) => {
{LL.Cashout.valid({ time: moment(expiresAt).fromNow(true) })}
-
+
+
{!!errorMsg && (
{errorMsg}
@@ -98,7 +103,7 @@ const CashoutConfirmation: React.FC = ({ navigation, route }) => {
@@ -107,13 +112,9 @@ const CashoutConfirmation: React.FC = ({ navigation, route }) => {
export default CashoutConfirmation
-const useStyles = makeStyles(({ colors }) => ({
+const useStyles = makeStyles(() => ({
valid: {
alignSelf: "center",
marginBottom: 10,
},
- buttonContainer: {
- marginHorizontal: 20,
- marginBottom: 20,
- },
}))
diff --git a/app/screens/cashout-screen/CashoutDetails.tsx b/app/screens/topup-cashout-flow/CashoutDetails.tsx
similarity index 93%
rename from app/screens/cashout-screen/CashoutDetails.tsx
rename to app/screens/topup-cashout-flow/CashoutDetails.tsx
index d1c419ed6..dffa4442c 100644
--- a/app/screens/cashout-screen/CashoutDetails.tsx
+++ b/app/screens/topup-cashout-flow/CashoutDetails.tsx
@@ -7,7 +7,7 @@ import { RootStackParamList } from "@app/navigation/stack-param-lists"
// components
import { Screen } from "@app/components/screen"
import { AmountInput } from "@app/components/amount-input"
-import { CashoutFromWallet, CashoutPercentage } from "@app/components/cashout-flow"
+import { CashoutFromWallet, CashoutPercentage } from "@app/components/topup-cashout-flow"
// hooks
import { useCashoutScreenQuery, useRequestCashoutMutation } from "@app/graphql/generated"
@@ -24,12 +24,14 @@ import {
import { getUsdWallet } from "@app/graphql/wallets-utils"
import { View } from "react-native"
import { PrimaryBtn } from "@app/components/buttons"
+import { useSafeAreaInsets } from "react-native-safe-area-context"
type Props = StackScreenProps
const CashoutDetails = ({ navigation }: Props) => {
const styles = useStyles()
const { colors } = useTheme().theme
+ const { bottom } = useSafeAreaInsets()
const { LL } = useI18nContext()
const { zeroDisplayAmount } = useDisplayCurrency()
const { convertMoneyAmount } = usePriceConversion()
@@ -61,7 +63,7 @@ const CashoutDetails = ({ navigation }: Props) => {
toggleActivityIndicator(true)
const res = await requestCashout({
variables: {
- input: { walletId: usdWallet.id, usdAmount: settlementSendAmount.amount },
+ input: { walletId: usdWallet.id, amount: settlementSendAmount.amount },
},
})
console.log("Response: ", res.data?.requestCashout)
@@ -116,7 +118,7 @@ const CashoutDetails = ({ navigation }: Props) => {
@@ -132,8 +134,4 @@ const useStyles = makeStyles(() => ({
flexDirection: "column",
margin: 20,
},
- buttonContainer: {
- marginHorizontal: 20,
- marginBottom: 20,
- },
}))
diff --git a/app/screens/cashout-screen/CashoutSuccess.tsx b/app/screens/topup-cashout-flow/CashoutSuccess.tsx
similarity index 100%
rename from app/screens/cashout-screen/CashoutSuccess.tsx
rename to app/screens/topup-cashout-flow/CashoutSuccess.tsx
diff --git a/app/screens/topup-cashout-flow/TopupCashout.tsx b/app/screens/topup-cashout-flow/TopupCashout.tsx
new file mode 100644
index 000000000..1cbf77c73
--- /dev/null
+++ b/app/screens/topup-cashout-flow/TopupCashout.tsx
@@ -0,0 +1,246 @@
+import React, { useCallback, useMemo, useState } from "react"
+import { Alert, RefreshControl, ScrollView, TouchableOpacity, View } from "react-native"
+import { RootStackParamList } from "@app/navigation/stack-param-lists"
+import { Icon, Text, makeStyles, useTheme } from "@rneui/themed"
+import { StackScreenProps } from "@react-navigation/stack"
+import { useI18nContext } from "@app/i18n/i18n-react"
+import { useFocusEffect } from "@react-navigation/native"
+
+// components
+import { Screen } from "@app/components/screen"
+import { TransferOptionModal, BridgeKycModal } from "@app/components/topup-cashout-flow"
+import type { TransferOption } from "@app/components/topup-cashout-flow"
+
+// assets
+import ArrowDown from "@app/assets/icons/arrow-down-to-bracket.svg"
+import ArrowUp from "@app/assets/icons/arrow-up-from-bracket.svg"
+
+// hooks
+import {
+ useBridgeInitiateKycMutation,
+ useBridgeKycStatusQuery,
+} from "@app/graphql/generated"
+import { useActivityIndicator } from "@app/hooks"
+
+type Props = StackScreenProps
+
+const TopupCashout: React.FC = ({ navigation }) => {
+ const styles = useStyles()
+ const { LL } = useI18nContext()
+ const { colors } = useTheme().theme
+ const { toggleActivityIndicator } = useActivityIndicator()
+
+ const [topupModalVisible, setTopupModalVisible] = useState(false)
+ const [settleModalVisible, setSettleModalVisible] = useState(false)
+ const [bridgeKycModalVisible, setBridgeKycModalVisible] = useState(false)
+ const [refreshing, setRefreshing] = useState(false)
+
+ const [initiateBridgeKyc] = useBridgeInitiateKycMutation()
+ const { data: kycStatusData, refetch: refetchKycStatus } = useBridgeKycStatusQuery({
+ fetchPolicy: "cache-and-network",
+ })
+
+ useFocusEffect(
+ useCallback(() => {
+ refetchKycStatus()
+ }, [refetchKycStatus]),
+ )
+
+ const onRefresh = useCallback(async () => {
+ setRefreshing(true)
+ await refetchKycStatus()
+ setRefreshing(false)
+ }, [refetchKycStatus])
+
+ const topupOptions: TransferOption[] = useMemo(
+ () => [
+ {
+ icon: "card",
+ title: LL.TopUpScreen.debitCreditCard(),
+ description: LL.TopUpScreen.debitCreditCardDesc(),
+ onPress: () => {
+ setTopupModalVisible(false)
+ navigation.navigate("TopupDetails", { paymentType: "card" })
+ },
+ },
+ {
+ icon: "business",
+ title: LL.TopUpScreen.bankTransfer(),
+ description: LL.TopUpScreen.bankTransferDesc(),
+ onPress: () => {
+ setTopupModalVisible(false)
+ navigation.navigate("TopupDetails", { paymentType: "bankTransfer" })
+ },
+ },
+ {
+ icon: "globe",
+ title: LL.TransferScreen.internationalBankTransfer(),
+ description: LL.TransferScreen.internationalBankTransferDesc(),
+ pending: kycStatusData?.bridgeKycStatus === "pending",
+ onPress: () => {
+ setTopupModalVisible(false)
+ checkBridgeKyc("topup")
+ },
+ },
+ ],
+ [LL, navigation, kycStatusData?.bridgeKycStatus],
+ )
+
+ const settleOptions: TransferOption[] = useMemo(
+ () => [
+ {
+ icon: "business",
+ title: LL.TransferScreen.jmdBankAccount(),
+ description: LL.TransferScreen.jmdBankAccountDesc(),
+ onPress: () => {
+ setSettleModalVisible(false)
+ navigation.navigate("CashoutDetails")
+ },
+ },
+ {
+ icon: "globe",
+ title: LL.TransferScreen.internationalBankAccount(),
+ description: LL.TransferScreen.internationalBankAccountDesc(),
+ pending: kycStatusData?.bridgeKycStatus === "pending",
+ onPress: () => {
+ setSettleModalVisible(false)
+ checkBridgeKyc("settle")
+ },
+ },
+ ],
+ [LL, navigation, kycStatusData?.bridgeKycStatus],
+ )
+
+ const checkBridgeKyc = (type: "topup" | "settle") => {
+ if (kycStatusData?.bridgeKycStatus === "pending") {
+ Alert.alert("KYC Pending", "Your KYC status is pending. Please wait for approval.")
+ } else if (kycStatusData?.bridgeKycStatus === "approved") {
+ type === "topup"
+ ? navigation.navigate("TopupDetails", { paymentType: "bridge" })
+ : navigation.navigate("CashoutDetails")
+ } else {
+ setBridgeKycModalVisible(true)
+ }
+ }
+
+ const getBridgeKycLink = async (data: {
+ fullName: string
+ email: string
+ kycType: string
+ }) => {
+ toggleActivityIndicator(true)
+ try {
+ const res = await initiateBridgeKyc({
+ variables: {
+ input: {
+ full_name: data.fullName,
+ email: data.email,
+ type: data.kycType,
+ },
+ },
+ })
+ toggleActivityIndicator(false)
+ console.log("BRIDGE INITIATE KYC RESPONSE: ", res)
+
+ const errors = res.data?.bridgeInitiateKyc?.errors
+ if (errors && errors.length > 0) {
+ Alert.alert("Error", errors[0].message)
+ return
+ }
+
+ const kycLink = res.data?.bridgeInitiateKyc?.kycLink
+ if (kycLink?.tosLink && kycLink?.kycLink) {
+ navigation.navigate("BridgeKycWebView", {
+ tosLink: kycLink.tosLink,
+ kycLink: kycLink.kycLink,
+ })
+ }
+ } catch (err) {
+ toggleActivityIndicator(false)
+ Alert.alert("Error", "Something went wrong. Please try again.")
+ }
+ }
+
+ return (
+
+ }
+ >
+
+ {LL.TransferScreen.title()}
+
+ setTopupModalVisible(true)}>
+
+
+ {LL.TransferScreen.topUp()}
+
+ {LL.TransferScreen.topUpDesc()}
+
+
+
+
+ setSettleModalVisible(true)}>
+
+
+ {LL.TransferScreen.settle()}
+
+ {LL.TransferScreen.settleDesc()}
+
+
+
+
+
+
+ setTopupModalVisible(false)}
+ />
+ setSettleModalVisible(false)}
+ />
+
+ setBridgeKycModalVisible(false)}
+ onSubmit={(data) => {
+ setBridgeKycModalVisible(false)
+ getBridgeKycLink(data)
+ }}
+ />
+
+ )
+}
+
+const useStyles = makeStyles(() => ({
+ container: {
+ flexGrow: 1,
+ paddingHorizontal: 20,
+ },
+ title: {
+ textAlign: "center",
+ marginBottom: 30,
+ },
+ btn: {
+ flexDirection: "row",
+ alignItems: "center",
+ borderRadius: 20,
+ borderWidth: 1,
+ borderColor: "#dedede",
+ marginBottom: 20,
+ minHeight: 100,
+ paddingHorizontal: 20,
+ },
+ btnTextWrapper: {
+ flex: 1,
+ rowGap: 5,
+ marginHorizontal: 15,
+ },
+}))
+
+export default TopupCashout
diff --git a/app/screens/topup-cashout-flow/TopupDetails.tsx b/app/screens/topup-cashout-flow/TopupDetails.tsx
new file mode 100644
index 000000000..827a4c0b9
--- /dev/null
+++ b/app/screens/topup-cashout-flow/TopupDetails.tsx
@@ -0,0 +1,222 @@
+/**
+ * TopupDetails Component
+ *
+ * This screen collects payment details before initiating the topup flow.
+ * Users select:
+ * 1. Target wallet (USD or BTC)
+ * 2. Amount to topup
+ *
+ * Previously, this screen also collected email address, but that was removed
+ * to avoid double entry - users now enter email directly on Fygaro's form.
+ *
+ * The component supports both card payments (Fygaro) and bank transfers,
+ * routing to the appropriate flow based on the selected payment type.
+ */
+
+import React, { useState } from "react"
+import { View, TextInput, Alert } from "react-native"
+import { Text, makeStyles, useTheme } from "@rneui/themed"
+import { StackScreenProps } from "@react-navigation/stack"
+import { RootStackParamList } from "@app/navigation/stack-param-lists"
+
+// components
+import { Screen } from "@app/components/screen"
+import { PrimaryBtn } from "@app/components/buttons"
+import { ButtonGroup } from "@app/components/button-group"
+
+// hooks
+import { useI18nContext } from "@app/i18n/i18n-react"
+import { useSafeAreaInsets } from "react-native-safe-area-context"
+import { usePersistentStateContext } from "@app/store/persistent-state"
+
+// assets
+import Cash from "@app/assets/icons/cash.svg"
+import Bitcoin from "@app/assets/icons/bitcoin.svg"
+
+type Props = StackScreenProps
+
+const TopupDetails: React.FC = ({ navigation, route }) => {
+ const { colors } = useTheme().theme
+ const { LL } = useI18nContext()
+ const { bottom } = useSafeAreaInsets()
+ const styles = useStyles()({ bottom })
+
+ const { persistentState } = usePersistentStateContext()
+
+ /**
+ * Component state:
+ * - selectedWallet: Which wallet to credit (USD or BTC)
+ * - amount: Topup amount in USD
+ * - isLoading: Loading state for navigation
+ *
+ * NOTE: Email field was removed to prevent double entry.
+ * Users enter email on Fygaro's payment form instead.
+ */
+ const [selectedWallet, setSelectedWallet] = useState("USD")
+ const [amount, setAmount] = useState("")
+ const [isLoading, setIsLoading] = useState(false)
+
+ /**
+ * Validates the entered amount.
+ * Minimum topup amount is $1.00 to prevent micro-transactions
+ * that would be unprofitable due to processing fees.
+ */
+ const validateAmount = (amount: string): boolean => {
+ const numAmount = parseFloat(amount)
+ return !isNaN(numAmount) && numAmount >= 1.0
+ }
+
+ /**
+ * Handles the continue button press.
+ *
+ * Validates amount and navigates to the appropriate payment flow:
+ * - Card payment: Goes to CardPayment (WebView with Fygaro)
+ * - Bank transfer: Goes to BankTransfer screen
+ *
+ * The wallet type and amount are passed to the next screen.
+ * The wallet type will be included in the webhook metadata
+ * to ensure the correct wallet is credited.
+ */
+ const handleContinue = async () => {
+ if (!validateAmount(amount)) {
+ Alert.alert("Invalid Amount", LL.TopupDetails.minimumAmount())
+ return
+ }
+
+ setIsLoading(true)
+
+ try {
+ if (
+ route.params.paymentType === "bankTransfer" ||
+ route.params.paymentType === "bridge"
+ ) {
+ navigation.navigate("BankTransfer", {
+ amount: parseFloat(amount),
+ wallet: selectedWallet,
+ paymentType: route.params.paymentType,
+ })
+ } else {
+ // Card payment flow via Fygaro WebView
+ navigation.navigate("CardPayment", {
+ amount: parseFloat(amount),
+ wallet: selectedWallet, // Will be sent to webhook via metadata
+ })
+ }
+ } catch (error) {
+ Alert.alert("Error", "Failed to initiate payment. Please try again.")
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ /**
+ * Wallet selection buttons configuration.
+ *
+ * Users can choose to credit either:
+ * - USD wallet: Fiat balance for USD transactions
+ * - BTC wallet: Bitcoin balance (amount converted at current rate)
+ *
+ * The selected wallet type is passed through the payment flow
+ * and included in the webhook metadata to ensure correct crediting.
+ */
+ const walletButtons = [
+ {
+ id: "USD",
+ text: LL.TopupDetails.usdWallet(),
+ icon: {
+ selected: ,
+ normal: ,
+ },
+ },
+ ]
+
+ if (persistentState.isAdvanceMode) {
+ walletButtons.push({
+ id: "BTC",
+ text: LL.TopupDetails.btcWallet(),
+ icon: {
+ selected: ,
+ normal: ,
+ },
+ })
+ }
+
+ return (
+
+
+
+ {route.params.paymentType === "card"
+ ? LL.TopupDetails.title()
+ : route.params.paymentType === "bridge"
+ ? LL.BankTransfer.virtualBankTransfer()
+ : LL.TopupDetails.bankTransfer()}
+
+
+
+
+ {LL.TopupDetails.wallet()}
+
+
+
+
+
+
+ {LL.TopupDetails.amount()}
+
+
+
+
+
+
+ )
+}
+
+const useStyles = makeStyles(({ colors }) => (props: { bottom: number }) => ({
+ container: {
+ flex: 1,
+ paddingHorizontal: 20,
+ },
+ title: {
+ textAlign: "center" as const,
+ marginBottom: 30,
+ },
+ fieldContainer: {
+ marginBottom: 24,
+ },
+ input: {
+ borderWidth: 1,
+ borderColor: colors.grey3,
+ borderRadius: 12,
+ padding: 16,
+ fontSize: 16,
+ backgroundColor: colors.white,
+ color: colors.black,
+ marginTop: 8,
+ },
+ buttonGroup: {
+ marginTop: 8,
+ },
+ primaryButton: {
+ marginHorizontal: 20,
+ marginBottom: Math.max(20, props.bottom),
+ },
+}))
+
+export default TopupDetails
diff --git a/app/screens/topup-cashout-flow/TopupSuccess.tsx b/app/screens/topup-cashout-flow/TopupSuccess.tsx
new file mode 100644
index 000000000..46da2ffe2
--- /dev/null
+++ b/app/screens/topup-cashout-flow/TopupSuccess.tsx
@@ -0,0 +1,78 @@
+import React from "react"
+import { View } from "react-native"
+import { makeStyles, Text, useTheme } from "@rneui/themed"
+import { StackScreenProps } from "@react-navigation/stack"
+import { RootStackParamList } from "@app/navigation/stack-param-lists"
+
+// components
+import {
+ SuccessIconAnimation,
+ SuccessTextAnimation,
+} from "@app/components/success-animation"
+import { Screen } from "@app/components/screen"
+import { PrimaryBtn } from "@app/components/buttons"
+import { GaloyIcon } from "@app/components/atomic/galoy-icon"
+
+// hooks
+import { useI18nContext } from "@app/i18n/i18n-react"
+import { useSafeAreaInsets } from "react-native-safe-area-context"
+
+type Props = StackScreenProps
+
+const TopupSuccess: React.FC = () => {
+ const styles = useStyles()
+ const { colors } = useTheme().theme
+ const { LL } = useI18nContext()
+ const { bottom } = useSafeAreaInsets()
+
+ const onPressDone = () => {}
+
+ return (
+
+
+
+
+
+
+
+ USD Wallet Topped Up
+
+
+ $200
+
+
+ J$35.11
+
+
+
+
+
+ )
+}
+
+export default TopupSuccess
+
+const useStyles = makeStyles(() => ({
+ container: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ successText: {
+ textAlign: "center",
+ color: "#fff",
+ marginBottom: 8,
+ },
+}))
diff --git a/app/screens/topup-cashout-flow/index.ts b/app/screens/topup-cashout-flow/index.ts
new file mode 100644
index 000000000..8a6dae363
--- /dev/null
+++ b/app/screens/topup-cashout-flow/index.ts
@@ -0,0 +1,23 @@
+import BridgeKycWebView from "./BridgeKycWebView"
+import TopupCashout from "./TopupCashout"
+import TopupDetails from "./TopupDetails"
+import BankTransfer from "./BankTransfer"
+import CardPayment from "./CardPayment"
+import TopupSuccess from "./TopupSuccess"
+import CashoutDetails from "./CashoutDetails"
+import CashoutConfirmation from "./CashoutConfirmation"
+import CashoutSuccess from "./CashoutSuccess"
+import PaymentSuccessScreen from "./payment-success-screen"
+
+export {
+ BridgeKycWebView,
+ TopupCashout,
+ TopupDetails,
+ BankTransfer,
+ CardPayment,
+ TopupSuccess,
+ CashoutDetails,
+ CashoutConfirmation,
+ CashoutSuccess,
+ PaymentSuccessScreen,
+}
diff --git a/app/screens/topup-cashout-flow/payment-success-screen.tsx b/app/screens/topup-cashout-flow/payment-success-screen.tsx
new file mode 100644
index 000000000..d6f1cb23e
--- /dev/null
+++ b/app/screens/topup-cashout-flow/payment-success-screen.tsx
@@ -0,0 +1,155 @@
+import React from "react"
+import { View } from "react-native"
+import { useNavigation, useRoute, RouteProp } from "@react-navigation/native"
+import { StackNavigationProp } from "@react-navigation/stack"
+import { Text, makeStyles, useTheme } from "@rneui/themed"
+import { Screen } from "@app/components/screen"
+import { useI18nContext } from "@app/i18n/i18n-react"
+import { RootStackParamList } from "@app/navigation/stack-param-lists"
+import { PrimaryBtn } from "@app/components/buttons"
+
+type PaymentSuccessScreenProps = {
+ navigation: StackNavigationProp
+ route: RouteProp
+}
+
+const PaymentSuccessScreen: React.FC = () => {
+ const { colors } = useTheme().theme
+ const { LL } = useI18nContext()
+ const navigation = useNavigation>()
+ const route = useRoute>()
+ const styles = useStyles()
+
+ const { amount, wallet, transactionId } = route.params
+
+ const handleDone = () => {
+ // Navigate back to home screen
+ navigation.navigate("Primary")
+ }
+
+ const handleViewTransaction = () => {
+ // TODO: Navigate to transaction details
+ console.log("Navigate to transaction details:", transactionId)
+ handleDone()
+ }
+
+ return (
+
+
+
+ ✓
+
+
+ {LL.PaymentSuccessScreen.title()}
+
+
+
+ {LL.PaymentSuccessScreen.successMessage()}
+
+
+
+
+
+ {LL.PaymentSuccessScreen.amountSent()}:
+
+
+ ${amount.toFixed(2)}
+
+
+
+
+
+ {LL.PaymentSuccessScreen.depositedTo()}:
+
+
+ {wallet} Wallet
+
+
+
+
+
+ {LL.PaymentSuccessScreen.transactionId()}:
+
+
+ {transactionId}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+const useStyles = makeStyles(({ colors }) => ({
+ container: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ padding: 20,
+ },
+ successContainer: {
+ alignItems: "center",
+ width: "100%",
+ },
+ successIcon: {
+ fontSize: 80,
+ marginBottom: 20,
+ textAlign: "center",
+ },
+ title: {
+ textAlign: "center",
+ marginBottom: 16,
+ },
+ message: {
+ textAlign: "center",
+ marginBottom: 32,
+ },
+ detailsContainer: {
+ width: "100%",
+ backgroundColor: colors.grey5,
+ borderRadius: 16,
+ padding: 20,
+ marginBottom: 32,
+ },
+ detailRow: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ marginBottom: 12,
+ },
+ detailLabel: {
+ flex: 1,
+ },
+ detailValue: {
+ fontWeight: "600",
+ textAlign: "right",
+ },
+ buttonContainer: {
+ width: "100%",
+ gap: 16,
+ },
+ primaryButton: {
+ marginTop: 8,
+ },
+ secondaryButton: {
+ marginTop: 8,
+ },
+}))
+
+export default PaymentSuccessScreen
diff --git a/codegen.yml b/codegen.yml
index 9574c39e8..6f26055d7 100644
--- a/codegen.yml
+++ b/codegen.yml
@@ -1,6 +1,6 @@
overwrite: true
-schema: "https://api.flashapp.me/graphql"
-# schema: "http://localhost:4002/graphql"
+# schema: "https://api.flashapp.me/graphql"
+schema: "http://localhost:4002/graphql"
# schema: "https://raw.githubusercontent.com/lnflash/flash/feature/merchant-map-suggest/src/graphql/public/schema.graphql"
documents:
- "app/**/*.ts"
@@ -28,6 +28,7 @@ generates:
nonOptionalTypename: true
scalars:
AccountApiKeyLabel: "string"
+ AccountNumber: "string"
AuthToken: "string"
CentAmount: "number"
ContactAlias: "string"
diff --git a/ios/LNFlash.xcodeproj/project.pbxproj b/ios/LNFlash.xcodeproj/project.pbxproj
index 0de92366f..9be536376 100644
--- a/ios/LNFlash.xcodeproj/project.pbxproj
+++ b/ios/LNFlash.xcodeproj/project.pbxproj
@@ -12,9 +12,9 @@
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
- 3152A8AF830F40A7AB689E42 /* (null) in Resources */ = {isa = PBXBuildFile; };
- 3E3C92C2FC91412D8DFDE94D /* (null) in Resources */ = {isa = PBXBuildFile; };
- 560415592C5B4119B9F91553 /* (null) in Resources */ = {isa = PBXBuildFile; };
+ 3152A8AF830F40A7AB689E42 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ 3E3C92C2FC91412D8DFDE94D /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ 560415592C5B4119B9F91553 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
5CDD582462391BD4A7901BD8 /* libPods-LNFlash.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B660162FC198C5D612BB44A /* libPods-LNFlash.a */; };
69B54F686F5835A64060EE6D /* libPods-LNFlash-Alt.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 177D9FE829C0CBCE225C8178 /* libPods-LNFlash-Alt.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
@@ -27,18 +27,18 @@
8647B9CB2DFD831600E2F160 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
8647B9CC2DFD831600E2F160 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 86FB60FB2BC40BBC0088C78C /* PrivacyInfo.xcprivacy */; };
8647B9CD2DFD831600E2F160 /* coins.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 0147E0DC2BAE64B90071CDF2 /* coins.mp3 */; };
- 8647B9CE2DFD831600E2F160 /* (null) in Resources */ = {isa = PBXBuildFile; };
- 8647B9CF2DFD831600E2F160 /* (null) in Resources */ = {isa = PBXBuildFile; };
- 8647B9D02DFD831600E2F160 /* (null) in Resources */ = {isa = PBXBuildFile; };
- 8647B9D12DFD831600E2F160 /* (null) in Resources */ = {isa = PBXBuildFile; };
- 8647B9D22DFD831600E2F160 /* (null) in Resources */ = {isa = PBXBuildFile; };
- 8647B9D32DFD831600E2F160 /* (null) in Resources */ = {isa = PBXBuildFile; };
+ 8647B9CE2DFD831600E2F160 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ 8647B9CF2DFD831600E2F160 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ 8647B9D02DFD831600E2F160 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ 8647B9D12DFD831600E2F160 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ 8647B9D22DFD831600E2F160 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ 8647B9D32DFD831600E2F160 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
8647B9ED2DFEAFE500E2F160 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8647B9EC2DFEAFE500E2F160 /* GoogleService-Info.plist */; };
8647B9EF2DFEAFF900E2F160 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8647B9EE2DFEAFF900E2F160 /* GoogleService-Info.plist */; };
86FB60FC2BC40BBC0088C78C /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 86FB60FB2BC40BBC0088C78C /* PrivacyInfo.xcprivacy */; };
- 94D9F3C84EB547D68D41C50F /* (null) in Resources */ = {isa = PBXBuildFile; };
- BD157A9851974C298EB06CB7 /* (null) in Resources */ = {isa = PBXBuildFile; };
- C426C81D58C8450C878B6086 /* (null) in Resources */ = {isa = PBXBuildFile; };
+ 94D9F3C84EB547D68D41C50F /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ BD157A9851974C298EB06CB7 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ C426C81D58C8450C878B6086 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
C61EE0AD23C530E30054100C /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C61EE0AC23C530E30054100C /* AuthenticationServices.framework */; };
F1D71F3628CE5C9A00636277 /* AppDelegate.h in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FAF1A68108700A75B9A /* AppDelegate.h */; };
/* End PBXBuildFile section */
@@ -285,12 +285,12 @@
86FB60FC2BC40BBC0088C78C /* PrivacyInfo.xcprivacy in Resources */,
0147E0DD2BAE64B90071CDF2 /* coins.mp3 in Resources */,
8647B9ED2DFEAFE500E2F160 /* GoogleService-Info.plist in Resources */,
- 560415592C5B4119B9F91553 /* (null) in Resources */,
- 3E3C92C2FC91412D8DFDE94D /* (null) in Resources */,
- BD157A9851974C298EB06CB7 /* (null) in Resources */,
- 3152A8AF830F40A7AB689E42 /* (null) in Resources */,
- 94D9F3C84EB547D68D41C50F /* (null) in Resources */,
- C426C81D58C8450C878B6086 /* (null) in Resources */,
+ 560415592C5B4119B9F91553 /* BuildFile in Resources */,
+ 3E3C92C2FC91412D8DFDE94D /* BuildFile in Resources */,
+ BD157A9851974C298EB06CB7 /* BuildFile in Resources */,
+ 3152A8AF830F40A7AB689E42 /* BuildFile in Resources */,
+ 94D9F3C84EB547D68D41C50F /* BuildFile in Resources */,
+ C426C81D58C8450C878B6086 /* BuildFile in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -304,12 +304,12 @@
8647B9CC2DFD831600E2F160 /* PrivacyInfo.xcprivacy in Resources */,
8647B9CD2DFD831600E2F160 /* coins.mp3 in Resources */,
8647B9EF2DFEAFF900E2F160 /* GoogleService-Info.plist in Resources */,
- 8647B9CE2DFD831600E2F160 /* (null) in Resources */,
- 8647B9CF2DFD831600E2F160 /* (null) in Resources */,
- 8647B9D02DFD831600E2F160 /* (null) in Resources */,
- 8647B9D12DFD831600E2F160 /* (null) in Resources */,
- 8647B9D22DFD831600E2F160 /* (null) in Resources */,
- 8647B9D32DFD831600E2F160 /* (null) in Resources */,
+ 8647B9CE2DFD831600E2F160 /* BuildFile in Resources */,
+ 8647B9CF2DFD831600E2F160 /* BuildFile in Resources */,
+ 8647B9D02DFD831600E2F160 /* BuildFile in Resources */,
+ 8647B9D12DFD831600E2F160 /* BuildFile in Resources */,
+ 8647B9D22DFD831600E2F160 /* BuildFile in Resources */,
+ 8647B9D32DFD831600E2F160 /* BuildFile in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -339,8 +339,6 @@
"$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = "[CP-User] [RNFB] Core Configuration";
- outputPaths = (
- );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##########################################################################\n##########################################################################\n#\n# NOTE THAT IF YOU CHANGE THIS FILE YOU MUST RUN pod install AFTERWARDS\n#\n# This file is installed as an Xcode build script in the project file\n# by cocoapods, and you will not see your changes until you pod install\n#\n##########################################################################\n##########################################################################\n\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"note: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"note: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"note: -> RNFB build script started\"\necho \"note: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"note: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"note: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n if ! _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\"); then\n echo \"error: Failed to parse firebase.json, check for syntax errors.\"\n exit 1\n fi\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"error: python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_analytics_storage\n _ANALYTICS_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_analytics_storage\")\n if [[ $_ANALYTICS_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_storage\n _ANALYTICS_AD_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_storage\")\n if [[ $_ANALYTICS_AD_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_user_data\n _ANALYTICS_AD_USER_DATA=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_user_data\")\n if [[ $_ANALYTICS_AD_USER_DATA ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_USER_DATA\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"note: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"note: <- RNFB build script finished\"\n";
@@ -355,8 +353,6 @@
"$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = "[CP-User] [RNFB] Crashlytics Configuration";
- outputPaths = (
- );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\nif [[ ${PODS_ROOT} ]]; then\n echo \"info: Exec FirebaseCrashlytics Run from Pods\"\n \"${PODS_ROOT}/FirebaseCrashlytics/run\"\nelse\n echo \"info: Exec FirebaseCrashlytics Run from framework\"\n \"${PROJECT_DIR}/FirebaseCrashlytics.framework/run\"\nfi\n";
@@ -494,8 +490,6 @@
"$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = "[CP-User] [RNFB] Core Configuration";
- outputPaths = (
- );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##########################################################################\n##########################################################################\n#\n# NOTE THAT IF YOU CHANGE THIS FILE YOU MUST RUN pod install AFTERWARDS\n#\n# This file is installed as an Xcode build script in the project file\n# by cocoapods, and you will not see your changes until you pod install\n#\n##########################################################################\n##########################################################################\n\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"note: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"note: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"note: -> RNFB build script started\"\necho \"note: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"note: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"note: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n if ! _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\"); then\n echo \"error: Failed to parse firebase.json, check for syntax errors.\"\n exit 1\n fi\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"error: python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_analytics_storage\n _ANALYTICS_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_analytics_storage\")\n if [[ $_ANALYTICS_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_storage\n _ANALYTICS_AD_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_storage\")\n if [[ $_ANALYTICS_AD_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_user_data\n _ANALYTICS_AD_USER_DATA=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_user_data\")\n if [[ $_ANALYTICS_AD_USER_DATA ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_USER_DATA\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"note: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"note: <- RNFB build script finished\"\n";
@@ -758,8 +752,6 @@
"$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
);
name = "[CP-User] [RNFB] Crashlytics Configuration";
- outputPaths = (
- );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\nif [[ ${PODS_ROOT} ]]; then\n echo \"info: Exec FirebaseCrashlytics Run from Pods\"\n \"${PODS_ROOT}/FirebaseCrashlytics/run\"\nelse\n echo \"info: Exec FirebaseCrashlytics Run from framework\"\n \"${PROJECT_DIR}/FirebaseCrashlytics.framework/run\"\nfi\n";
diff --git a/package.json b/package.json
index dc07387ab..f2e3f1236 100644
--- a/package.json
+++ b/package.json
@@ -272,6 +272,7 @@
"@wdio/local-runner": "^8.10.5",
"@wdio/mocha-framework": "^8.12.1",
"@wdio/spec-reporter": "^8.10.5",
+ "@whatwg-node/promise-helpers": "^1.3.2",
"babel-jest": "^29.6.3",
"babel-loader": "^9.1.2",
"babel-plugin-module-resolver": "^5.0.0",
diff --git a/yarn.lock b/yarn.lock
index a8ec0c412..6f2e1f1d6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8196,6 +8196,13 @@
dependencies:
tslib "^2.6.3"
+"@whatwg-node/promise-helpers@^1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@whatwg-node/promise-helpers/-/promise-helpers-1.3.2.tgz#3b54987ad6517ef6db5920c66a6f0dada606587d"
+ integrity sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA==
+ dependencies:
+ tslib "^2.6.3"
+
"@whatwg-node/server@^0.7.3":
version "0.7.7"
resolved "https://registry.yarnpkg.com/@whatwg-node/server/-/server-0.7.7.tgz#daaae73999cf8ea4d4f7e617276dcb8e84a6e49e"
@@ -24133,12 +24140,7 @@ tslib@^1.8.1, tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
- integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
-
-tslib@^2.6.3, tslib@^2.7.0, tslib@^2.8.0, tslib@^2.8.1:
+tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2, tslib@^2.6.3, tslib@^2.7.0, tslib@^2.8.0, tslib@^2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==