diff --git a/__tests__/screens/global-error.spec.tsx b/__tests__/screens/global-error.spec.tsx index b70cdf708d..a7045f5f1d 100644 --- a/__tests__/screens/global-error.spec.tsx +++ b/__tests__/screens/global-error.spec.tsx @@ -21,6 +21,7 @@ jest.mock("@react-native-community/push-notification-ios", () => ({})) jest.mock("react-native-walkthrough-tooltip", () => ({})) jest.mock("react-native-fingerprint-scanner", () => ({})) jest.mock("react-native-snap-carousel", () => ({})) +jest.mock("react-native-markdown-display", () => ({})) jest.mock("react-native-maps", () => ({})) jest.mock("react-native-phone-number-input", () => ({})) jest.mock("victory-native", () => ({})) diff --git a/app/components/floor-tooltip/floor-tooltip.tsx b/app/components/floor-tooltip/floor-tooltip.tsx new file mode 100644 index 0000000000..bb7bb7d8a1 --- /dev/null +++ b/app/components/floor-tooltip/floor-tooltip.tsx @@ -0,0 +1,87 @@ +import { useI18nContext } from "@app/i18n/i18n-react" +import { bankName } from "@app/screens/send-bitcoin-screen/send-bitcoin-destination-screen" +import { palette } from "@app/theme" +import * as React from "react" +import { Text, View, TouchableOpacity, ScrollView } from "react-native" +import { Icon } from "react-native-elements" +import EStyleSheet from "react-native-extended-stylesheet" +import Markdown from "react-native-markdown-display" +import Modal from "react-native-modal" + +const styles = EStyleSheet.create({ + modalStyle: { margin: 0, flexDirection: "column", justifyContent: "flex-end" }, + fillerOpacity: { flex: 3 }, + modalCard: { + backgroundColor: palette.white, + flex: 2, + borderTopLeftRadius: 40, + borderTopRightRadius: 40, + padding: 24, + }, + modalTitleContainer: { flexDirection: "row", alignItems: "center", marginBottom: 10 }, + modalTitleText: { fontSize: 24 }, + iconContainer: { marginRight: 12 }, + markdownText: { fontSize: 20, marginBottom: 20 }, +}) + +type FloorTooltipProps = { + size?: number + type: "info" | "advice" + title?: string + text: string +} + +export const FloorTooltip: React.FC = ({ + size, + type, + title, + text, +}) => { + const { LL } = useI18nContext() + const [isVisible, setIsVisible] = React.useState(false) + const toggleModal = () => setIsVisible(!isVisible) + + let iconParams + let defaultTitle + switch (type) { + case "info": + iconParams = { + name: "info", + type: "fontisto", + } + defaultTitle = LL.common.bankInfo({ bankName }) + break + case "advice": + iconParams = { + name: "lightbulb", + type: "foundation", + } + defaultTitle = LL.common.bankAdvice({ bankName }) + break + } + const modalTitle = title || defaultTitle + + return ( + + + toggleModal} + coverScreen + style={styles.modalStyle} + backdropOpacity={0.2} + > + + + + + {modalTitle} + + + {text} + + + + + ) +} diff --git a/app/components/payment-destination-display/payment-destination-display.tsx b/app/components/payment-destination-display/payment-destination-display.tsx index 0c19953b06..9df49ecc64 100644 --- a/app/components/payment-destination-display/payment-destination-display.tsx +++ b/app/components/payment-destination-display/payment-destination-display.tsx @@ -1,3 +1,4 @@ +import { lnDomain } from "@app/screens/send-bitcoin-screen/send-bitcoin-destination-screen" import { palette } from "@app/theme" import React from "react" import { ActivityIndicator, Text } from "react-native" @@ -11,7 +12,13 @@ const styles = EStyleSheet.create({ }, }) -export const PaymentDestinationDisplay = ({ destination }: { destination?: string }) => { +export const PaymentDestinationDisplay = ({ + destination, + paymentType, +}: { + destination?: string + paymentType?: string +}) => { if (!destination) { return } @@ -19,7 +26,10 @@ export const PaymentDestinationDisplay = ({ destination }: { destination?: strin if (destination.length < 40) { return ( - {destination} + + {destination} + {paymentType === "intraledger" ? `@${lnDomain}` : ""} + ) } diff --git a/app/hooks/use-app-config.ts b/app/hooks/use-app-config.ts index e1a19a2997..d579dd9e3d 100644 --- a/app/hooks/use-app-config.ts +++ b/app/hooks/use-app-config.ts @@ -19,6 +19,7 @@ export const useAppConfig = () => { ...state, isUsdDisabled: !state.isUsdDisabled, })) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [persistentStateContext.updateState]) return { appConfig, toggleUsdDisabled } diff --git a/app/i18n/en/index.ts b/app/i18n/en/index.ts index c303d11fda..a6cfc69f1c 100644 --- a/app/i18n/en/index.ts +++ b/app/i18n/en/index.ts @@ -553,6 +553,31 @@ const en: BaseTranslation = { "This is the maximum fee you will be charged for this transaction. It may end up being less once the payment has been made.", feeError: "Failed to calculate fee", }, + SendBitcoinDestinationScreen: { + usernameNowAddress: "{bankName: string} usernames are now {bankName: string} addresses.", + usernameNowAddressInfo: "When you enter a {bankName: string} username, we will add \"@{lnDomain: string}\" to it (e.g maria@{lnDomain: string}) to make it an address. Your username is now a {bankName: string} address too.\n\nGo to your {bankName: string} address page from your Settings to learn how to use it or to share it to receive payments.", + enterValidDestination: "Please enter a valid destination", + destinationOptions: "You can send to a {bankName: string} address, LN address, LN invoice, or BTC address.", + expiredInvoice: "This invoice has expired. Please generate a new invoice.", + wrongNetwork: "This invoice is for a different network. Please generate a new invoice.", + invalidAmount: "This contains an invalid amount. Please regenerate with a valid amount.", + usernameDoesNotExist: "{lnAddress: string} doesn't seem to be a {bankName: string} address that exists.", + usernameDoesNotExistAdvice: "Either make sure the spelling is right or ask the recipient for an LN invoice or BTC address instead.", + selfPaymentError: "{lnAddress: string} is your {bankName: string} address.", + selfPaymentAdvice: "If you want to send money to another account that you own, you can use an invoice, LN or BTC address instead.", + lnAddressError: "We can't reach this Lightning address. If you are sure it exists, you can try again later.", + lnAddressAdvice: "Either make sure the spelling is right or ask the recipient for an invoice or BTC address instead.", + unknownLightning: "We can't parse this Lightning address. Please try again.", + unknownOnchain: "We can't parse this Bitcoin address. Please try again.", + newBankAddressUsername: "{lnAddress: string} exists as a {bankName: string} address, but you've never sent money to it.", + confirmModal: { + title: "You've never sent money to \"{lnAddress: string}\" before.", + body: "Please make sure the recipient gave you a {bankName: string} address, **not a username from another wallet**. Otherwise, the money will go to a {bankName: string} Account that has the “{lnAddress: string}” address.\n\nCheck the spelling of the first part of the address as well. e.g. jackie and jack1e are 2 different addresses", + warning: "If the {bankName: string} address is entered incorrectly, {bankName: string} can't undo the transaction.", + checkBox: "{lnAddress: string} is the right address.", + confirmButton: "I'm 100% sure", + } + }, SendBitcoinScreen: { amount: "Amount", amountExceed: "Amount exceeds your balance of {balance: string}", @@ -571,10 +596,7 @@ const en: BaseTranslation = { note: "Note or label", success: "Payment has been sent successfully", title: "Send Bitcoin", - usernameNotFound: "A user matching the entered username could not be found.", - failedToFetchLnurlParams: "Failed to fetch lnurl params", failedToFetchLnurlInvoice: "Failed to fetch lnurl invoice", - youCantSendAPaymentToYourself: "You can't send a payment to yourself", }, SettingsScreen: { activated: "Activated", @@ -666,6 +688,8 @@ const en: BaseTranslation = { backHome: "Back home", bank: "Bank", bankAccount: "Cash Account", + bankAdvice: "{bankName: string} Advice", + bankInfo: "{bankName: string} Info", bitcoin: "Bitcoin", bitcoinPrice: "Bitcoin Price", btcAccount: "BTC Account", diff --git a/app/i18n/es/index.ts b/app/i18n/es/index.ts index b47bc752a3..f66a99b953 100644 --- a/app/i18n/es/index.ts +++ b/app/i18n/es/index.ts @@ -594,10 +594,32 @@ const es: Translation = { note: "Nota", success: "El pago se ha enviado correctamente.", title: "Enviar Bitcoin", - usernameNotFound: "El usuario no fue encontrado.", - failedToFetchLnurlParams: "No se pudieron recuperar los parámetros de lnurl", failedToFetchLnurlInvoice: "Error al obtener la factura de lnurl", - youCantSendAPaymentToYourself: "No puedes enviar un pago a ti mismo", + }, + SendBitcoinDestinationScreen: { + usernameNowAddress: "Los nombres de usuario de {bankName} ahora son direcciones de {bankName}.", + usernameNowAddressInfo: "Cuando ingrese un nombre de usuario de {bankName}, le agregaremos \"@{lnDomain}\" (por ejemplo, maria@{lnDomain}) para convertirlo en una dirección. Tu nombre de usuario ahora también es una dirección de {bankName}.\n\nLos nombres de usuario de {bankName} solo permitían transacciones dentro de {bankName}, mientras que las direcciones de {bankName} permiten realizar pagos con personas que usan diferentes billeteras.", + enterValidDestination: "Introduzca un destino válido.", + destinationOptions: "Puedes enviar a una dirección {bankName}, una dirección LN, una factura LN o una dirección {bankName}.", + expiredInvoice: "Esta factura ha caducado. Por favor, genere una nueva factura.", + wrongNetwork: "Esta factura es para una red diferente. Por favor, genere una nueva factura.", + invalidAmount: "Esto contiene un monto inválido. Por favor, ingrese nuevamente con un monto válido.", + usernameDoesNotExist: "{lnAddress} no parece ser una dirección de {bankName} que exista.", + usernameDoesNotExistAdvice: "En su lugar, puede pedirle al destinatario una factura o una dirección BTC.", + selfPaymentError: "{lnAddress} es su dirección de {bankName}.", + selfPaymentAdvice: "Si desea enviar dinero a otra billetera de su propiedad, puede usar una factura, una dirección LN o BTC en su lugar.", + lnAddressError: "No podemos comunicarnos con esta dirección Lightning. Si está seguro de que existe, puede volver a intentarlo más tarde.", + lnAddressAdvice: "En su lugar, puede pedirle al destinatario una factura o una dirección BTC.", + unknownLightning: "No podemos verificar esta dirección Lightning. Por favor, inténtalo de nuevo con una dirección diferente.", + unknownOnchain: "No podemos verificar esta dirección Bitcoin. Por favor, inténtelo de nuevo con una dirección diferente.", + newBankAddressUsername: "{lnAddress} existe como dirección de {bankName}, pero nunca has enviado dinero a esta dirección.", + confirmModal: { + title: "Nunca antes ha enviado dinero a \"{lnAddress}\".", + body: "Asegúrate que tu destinatario te haya dado una dirección de {bankName}, **no un nombre de usuario de otra billetera**. De lo contrario, el dinero irá a una {bankName} que tenga la dirección “{lnAddress}”.\n\nRevisa también la ortografía de la primera parte de la dirección por ejemplo: “jackie” y “jack1e” ya que son 2 direcciones diferentes.", + warning: "Si la dirección de {bankName} se ingresa incorrectamente, {bankName} no puede deshacer la transacción.", + checkBox: "{lnAddress} si es la dirección correcta.", + confirmButton: "Estoy 100% seguro", + } }, SettingsScreen: { activated: "Activada", @@ -691,6 +713,10 @@ const es: Translation = { bank: "Banco", backHome: "Atrás", bankAccount: "Cuenta de efectivo", + // TO DO: Translate + bankAdvice: "{bankName} Tip", + // TO DO: Translate + bankInfo: "{bankName} Info", bitcoin: "Bitcoin", bitcoinPrice: "Precio de Bitcoin", btcAccount: "Cuenta BTC", diff --git a/app/i18n/fr-CA/index.ts b/app/i18n/fr-CA/index.ts index dc1b36e9b7..8e1680b1fe 100644 --- a/app/i18n/fr-CA/index.ts +++ b/app/i18n/fr-CA/index.ts @@ -564,6 +564,32 @@ const frCA: Translation = { "Il s'agit des frais maximum qui vous seront facturés pour cette transaction. Il peut finir par être inférieur une fois le paiement effectué.", feeError: "Échec du calcul des frais", }, + // TODO translate the below section + SendBitcoinDestinationScreen: { + usernameNowAddress: "{bankName} usernames are now {bankName} addresses.", + usernameNowAddressInfo: "When you enter a {bankName} username, we will add “@{lnDomain}” to it (e.g maria@{lnDomain}) to make it an address. Your username is now a {bankName} address too.\n\nGo to your {bankName} address page from your Settings to learn how to use it or to share it to receive payments.", + enterValidDestination: "Please enter a valid destination", + destinationOptions: "You can send to a {bankName} address, LN address, LN invoice, or BTC address.", + expiredInvoice: "This invoice has expired. Please generate a new invoice.", + wrongNetwork: "This invoice is for a different network. Please generate a new invoice.", + invalidAmount: "This contains an invalid amount. Please regenerate with a valid amount.", + usernameDoesNotExist: "{lnAddress} doesn't seem to be a {bankName} address that exists.", + usernameDoesNotExistAdvice: "Either make sure the spelling is right or ask the recipient for an LN invoice or BTC address instead.", + selfPaymentError: "{lnAddress} is your {bankName} address.", + selfPaymentAdvice: "If you want to send money to another account that you own, you can use an invoice, LN or BTC address instead.", + lnAddressError: "We can't reach this Lightning address. If you are sure it exists, you can try again later.", + lnAddressAdvice: "Either make sure the spelling is right or ask the recipient for an invoice or BTC address instead.", + unknownLightning: "We can't parse this Lightning address. Please try again.", + unknownOnchain: "We can't parse this Bitcoin address. Please try again.", + newBankAddressUsername: "{lnAddress} exists as a {bankName} address, but you've never sent money to it.", + confirmModal: { + title: "You've never sent money to \"{lnAddress}\" before.", + body: "Please make sure the recipient gave you a {bankName} address, **not a username from another wallet**. Otherwise, the money will go to a {bankName} Account that has the “{lnAddress}” address.\n\nCheck the spelling of the first part of the address as well. e.g. jackie and jack1e are 2 different addresses", + warning: "If the {bankName} address is entered incorrectly, {bankName} can't undo the transaction.", + checkBox: "{lnAddress} is the right address.", + confirmButton: "I'm 100% sure", + } + }, SendBitcoinScreen: { amount: "Montant", amountExceed: "Le montant excède votre solde de {balance}", @@ -582,10 +608,7 @@ const frCA: Translation = { note: "note optionnelle", success: "Le paiement a été envoyé avec succès", title: "Envoyer des bitcoins", - usernameNotFound: "Un usager correspondant au nom saisi est introuvable.", - failedToFetchLnurlParams: "Impossible de récupérer les paramètres lnurl", failedToFetchLnurlInvoice: "Échec de la récupération de la facture lnurl", - youCantSendAPaymentToYourself: "Vous ne pouvez pas envoyer de paiement à vous-même", }, SettingsScreen: { activated: "Activé", @@ -680,6 +703,10 @@ const frCA: Translation = { bankAccount: "Compte comptant", bitcoin: "Bitcoin", bitcoinPrice: "Prix Bitcoin", + // TO DO: Translate + bankAdvice: "{bankName} Advice", + // TO DO: Translate + bankInfo: "{bankName} Info", cancel: "Annuler", close: "Fermer", confirm: "Confirmer", diff --git a/app/i18n/i18n-types.ts b/app/i18n/i18n-types.ts index bcf25d70b2..dcbd86e195 100644 --- a/app/i18n/i18n-types.ts +++ b/app/i18n/i18n-types.ts @@ -1774,6 +1774,113 @@ type RootTranslation = { */ feeError: string } + SendBitcoinDestinationScreen: { + /** + * {bankName} usernames are now {bankName} addresses. + * @param {string} bankName + */ + usernameNowAddress: RequiredParams<'bankName' | 'bankName'> + /** + * When you enter a {bankName} username, we will add “@{lnDomain}” to it (e.g maria@{lnDomain}) to make it an address. Your username is now a {bankName} address too. + + Go to your {bankName} address page from your Settings to learn how to use it or to share it to receive payments. + * @param {string} bankName + * @param {string} lnDomain + */ + usernameNowAddressInfo: RequiredParams<'bankName' | 'bankName' | 'bankName' | 'lnDomain' | 'lnDomain'> + /** + * Please enter a valid destination + */ + enterValidDestination: string + /** + * You can send to a {bankName} address, LN address, LN invoice, or BTC address. + * @param {string} bankName + */ + destinationOptions: RequiredParams<'bankName'> + /** + * This invoice has expired. Please generate a new invoice. + */ + expiredInvoice: string + /** + * This invoice is for a different network. Please generate a new invoice. + */ + wrongNetwork: string + /** + * This contains an invalid amount. Please regenerate with a valid amount. + */ + invalidAmount: string + /** + * {lnAddress} doesn't seem to be a {bankName} address that exists. + * @param {string} bankName + * @param {string} lnAddress + */ + usernameDoesNotExist: RequiredParams<'bankName' | 'lnAddress'> + /** + * Either make sure the spelling is right or ask the recipient for an LN invoice or BTC address instead. + */ + usernameDoesNotExistAdvice: string + /** + * {lnAddress} is your {bankName} address. + * @param {string} bankName + * @param {string} lnAddress + */ + selfPaymentError: RequiredParams<'bankName' | 'lnAddress'> + /** + * If you want to send money to another account that you own, you can use an invoice, LN or BTC address instead. + */ + selfPaymentAdvice: string + /** + * We can't reach this Lightning address. If you are sure it exists, you can try again later. + */ + lnAddressError: string + /** + * Either make sure the spelling is right or ask the recipient for an invoice or BTC address instead. + */ + lnAddressAdvice: string + /** + * We can't parse this Lightning address. Please try again. + */ + unknownLightning: string + /** + * We can't parse this Bitcoin address. Please try again. + */ + unknownOnchain: string + /** + * {lnAddress} exists as a {bankName} address, but you've never sent money to it. + * @param {string} bankName + * @param {string} lnAddress + */ + newBankAddressUsername: RequiredParams<'bankName' | 'lnAddress'> + confirmModal: { + /** + * You've never sent money to "{lnAddress}" before. + * @param {string} lnAddress + */ + title: RequiredParams<'lnAddress'> + /** + * Please make sure the recipient gave you a {bankName} address, **not a username from another wallet**. Otherwise, the money will go to a {bankName} Account that has the “{lnAddress}” address. + + Check the spelling of the first part of the address as well. e.g. jackie and jack1e are 2 different addresses + * @param {string} bankName + * @param {string} lnAddress + */ + body: RequiredParams<'bankName' | 'bankName' | 'lnAddress'> + /** + * If the {bankName} address is entered incorrectly, {bankName} can't undo the transaction. + * @param {string} bankName + */ + warning: RequiredParams<'bankName' | 'bankName'> + /** + * {lnAddress} is the right address. + * @param {string} lnAddress + */ + checkBox: RequiredParams<'lnAddress'> + /** + * I'm 100% sure + */ + confirmButton: string + } + } SendBitcoinScreen: { /** * Amount @@ -1840,22 +1947,10 @@ type RootTranslation = { * Send Bitcoin */ title: string - /** - * A user matching the entered username could not be found. - */ - usernameNotFound: string - /** - * Failed to fetch lnurl params - */ - failedToFetchLnurlParams: string /** * Failed to fetch lnurl invoice */ failedToFetchLnurlInvoice: string - /** - * You can't send a payment to yourself - */ - youCantSendAPaymentToYourself: string } SettingsScreen: { /** @@ -2131,6 +2226,16 @@ type RootTranslation = { * Cash Account */ bankAccount: string + /** + * {bankName} Advice + * @param {string} bankName + */ + bankAdvice: RequiredParams<'bankName'> + /** + * {bankName} Info + * @param {string} bankName + */ + bankInfo: RequiredParams<'bankName'> /** * Bitcoin */ @@ -4263,6 +4368,98 @@ export type TranslationFunctions = { */ feeError: () => LocalizedString } + SendBitcoinDestinationScreen: { + /** + * {bankName} usernames are now {bankName} addresses. + */ + usernameNowAddress: (arg: { bankName: string }) => LocalizedString + /** + * When you enter a {bankName} username, we will add “@{lnDomain}” to it (e.g maria@{lnDomain}) to make it an address. Your username is now a {bankName} address too. + + Go to your {bankName} address page from your Settings to learn how to use it or to share it to receive payments. + */ + usernameNowAddressInfo: (arg: { bankName: string, lnDomain: string }) => LocalizedString + /** + * Please enter a valid destination + */ + enterValidDestination: () => LocalizedString + /** + * You can send to a {bankName} address, LN address, LN invoice, or BTC address. + */ + destinationOptions: (arg: { bankName: string }) => LocalizedString + /** + * This invoice has expired. Please generate a new invoice. + */ + expiredInvoice: () => LocalizedString + /** + * This invoice is for a different network. Please generate a new invoice. + */ + wrongNetwork: () => LocalizedString + /** + * This contains an invalid amount. Please regenerate with a valid amount. + */ + invalidAmount: () => LocalizedString + /** + * {lnAddress} doesn't seem to be a {bankName} address that exists. + */ + usernameDoesNotExist: (arg: { bankName: string, lnAddress: string }) => LocalizedString + /** + * Either make sure the spelling is right or ask the recipient for an LN invoice or BTC address instead. + */ + usernameDoesNotExistAdvice: () => LocalizedString + /** + * {lnAddress} is your {bankName} address. + */ + selfPaymentError: (arg: { bankName: string, lnAddress: string }) => LocalizedString + /** + * If you want to send money to another account that you own, you can use an invoice, LN or BTC address instead. + */ + selfPaymentAdvice: () => LocalizedString + /** + * We can't reach this Lightning address. If you are sure it exists, you can try again later. + */ + lnAddressError: () => LocalizedString + /** + * Either make sure the spelling is right or ask the recipient for an invoice or BTC address instead. + */ + lnAddressAdvice: () => LocalizedString + /** + * We can't parse this Lightning address. Please try again. + */ + unknownLightning: () => LocalizedString + /** + * We can't parse this Bitcoin address. Please try again. + */ + unknownOnchain: () => LocalizedString + /** + * {lnAddress} exists as a {bankName} address, but you've never sent money to it. + */ + newBankAddressUsername: (arg: { bankName: string, lnAddress: string }) => LocalizedString + confirmModal: { + /** + * You've never sent money to "{lnAddress}" before. + */ + title: (arg: { lnAddress: string }) => LocalizedString + /** + * Please make sure the recipient gave you a {bankName} address, **not a username from another wallet**. Otherwise, the money will go to a {bankName} Account that has the “{lnAddress}” address. + + Check the spelling of the first part of the address as well. e.g. jackie and jack1e are 2 different addresses + */ + body: (arg: { bankName: string, lnAddress: string }) => LocalizedString + /** + * If the {bankName} address is entered incorrectly, {bankName} can't undo the transaction. + */ + warning: (arg: { bankName: string }) => LocalizedString + /** + * {lnAddress} is the right address. + */ + checkBox: (arg: { lnAddress: string }) => LocalizedString + /** + * I'm 100% sure + */ + confirmButton: () => LocalizedString + } + } SendBitcoinScreen: { /** * Amount @@ -4328,22 +4525,10 @@ export type TranslationFunctions = { * Send Bitcoin */ title: () => LocalizedString - /** - * A user matching the entered username could not be found. - */ - usernameNotFound: () => LocalizedString - /** - * Failed to fetch lnurl params - */ - failedToFetchLnurlParams: () => LocalizedString /** * Failed to fetch lnurl invoice */ failedToFetchLnurlInvoice: () => LocalizedString - /** - * You can't send a payment to yourself - */ - youCantSendAPaymentToYourself: () => LocalizedString } SettingsScreen: { /** @@ -4614,6 +4799,14 @@ export type TranslationFunctions = { * Cash Account */ bankAccount: () => LocalizedString + /** + * {bankName} Advice + */ + bankAdvice: (arg: { bankName: string }) => LocalizedString + /** + * {bankName} Info + */ + bankInfo: (arg: { bankName: string }) => LocalizedString /** * Bitcoin */ diff --git a/app/i18n/pt-BR/index.ts b/app/i18n/pt-BR/index.ts index d8e06cad67..f5bc523307 100644 --- a/app/i18n/pt-BR/index.ts +++ b/app/i18n/pt-BR/index.ts @@ -562,6 +562,32 @@ const ptBR: Translation = { "Esta é a taxa máxima que será cobrada por esta transação. Pode acabar sendo menor uma vez que o pagamento foi feito.", feeError: "Falha ao calcular a taxa", }, + // TODO translate the below section + SendBitcoinDestinationScreen: { + usernameNowAddress: "{bankName} usernames are now {bankName} addresses.", + usernameNowAddressInfo: "When you enter a {bankName} username, we will add “@{lnDomain}” to it (e.g maria@{lnDomain}) to make it an address. Your username is now a {bankName} address too.\n\nGo to your {bankName} address page from your Settings to learn how to use it or to share it to receive payments.", + enterValidDestination: "Please enter a valid destination", + destinationOptions: "You can send to a {bankName} address, LN address, LN invoice, or BTC address.", + expiredInvoice: "This invoice has expired. Please generate a new invoice.", + wrongNetwork: "This invoice is for a different network. Please generate a new invoice.", + invalidAmount: "This contains an invalid amount. Please regenerate with a valid amount.", + usernameDoesNotExist: "{lnAddress} doesn't seem to be a {bankName} address that exists.", + usernameDoesNotExistAdvice: "Either make sure the spelling is right or ask the recipient for an LN invoice or BTC address instead.", + selfPaymentError: "{lnAddress} is your {bankName} address.", + selfPaymentAdvice: "If you want to send money to another account that you own, you can use an invoice, LN or BTC address instead.", + lnAddressError: "We can't reach this Lightning address. If you are sure it exists, you can try again later.", + lnAddressAdvice: "Either make sure the spelling is right or ask the recipient for an invoice or BTC address instead.", + unknownLightning: "We can't parse this Lightning address. Please try again.", + unknownOnchain: "We can't parse this Bitcoin address. Please try again.", + newBankAddressUsername: "{lnAddress} exists as a {bankName} address, but you've never sent money to it.", + confirmModal: { + title: "You've never sent money to \"{lnAddress}\" before.", + body: "Please make sure the recipient gave you a {bankName} address, **not a username from another wallet**. Otherwise, the money will go to a {bankName} Account that has the “{lnAddress}” address.\n\nCheck the spelling of the first part of the address as well. e.g. jackie and jack1e are 2 different addresses", + warning: "If the {bankName} address is entered incorrectly, {bankName} can't undo the transaction.", + checkBox: "{lnAddress} is the right address.", + confirmButton: "I'm 100% sure", + } + }, SendBitcoinScreen: { amount: "quantidade", amountExceed: "O valor excede seu saldo de {balance}", @@ -577,15 +603,11 @@ const ptBR: Translation = { note: "Nota opcional", success: "Pagamento enviado com sucesso", title: "Enviar Bitcoin", - usernameNotFound: - "Um usuário correspondente ao nome de usuário digitado não pôde ser encontrado.", - failedToFetchLnurlParams: "Falha ao buscar parâmetros lnurl", failedToFetchLnurlInvoice: "Falha ao buscar a fatura lnurl", // TODO review the below 3 translations amountIsRequired: "Quantidade é obrigatória", destination: "Destino", destinationIsRequired: "Destino é obrigatório", - youCantSendAPaymentToYourself: "Você não pode enviar um pagamento para você mesmo", }, SettingsScreen: { activated: "Ativado", @@ -675,6 +697,10 @@ const ptBR: Translation = { back: "Voltar", bank: "Banco", bankAccount: "Conta de Dinheiro", + // TO DO: Translate + bankAdvice: "{bankName} Advice", + // TO DO: Translate + bankInfo: "{bankName} Info", bitcoin: "Bitcoin", bitcoinPrice: "Preço do Bitcoin", cancel: "Cancelar", diff --git a/app/navigation/stack-param-lists.ts b/app/navigation/stack-param-lists.ts index e83cbbd479..a39d35ddbb 100644 --- a/app/navigation/stack-param-lists.ts +++ b/app/navigation/stack-param-lists.ts @@ -2,7 +2,8 @@ import { PaymentAmount, WalletCurrency } from "@app/types/amounts" import { WalletDescriptor } from "@app/types/wallets" import { LnUrlPayServiceResponse } from "lnurl-pay/dist/types/types" -import { GaloyGQL, PaymentType } from "@galoymoney/client" +import { GaloyGQL } from "@galoymoney/client" +import { PaymentType } from "@galoymoney/client/dist/parsing-v2" import { contacts_me_contacts } from "../screens/contacts-screen/__generated__/contacts" import { AccountType, AuthenticationScreenPurpose, PinScreenPurpose } from "../utils/enum" @@ -44,7 +45,7 @@ export type RootStackParamList = { username?: string } sendBitcoinDetails: { - fixedAmount: PaymentAmount | undefined + fixedAmount?: PaymentAmount destination: string note?: string lnurl?: LnUrlPayServiceResponse diff --git a/app/screens/send-bitcoin-screen/confirm-destination-modal.tsx b/app/screens/send-bitcoin-screen/confirm-destination-modal.tsx new file mode 100644 index 0000000000..5cefe08bb0 --- /dev/null +++ b/app/screens/send-bitcoin-screen/confirm-destination-modal.tsx @@ -0,0 +1,134 @@ +import { palette } from "@app/theme" +import React, { Dispatch, useCallback, useState } from "react" +import { Text, View } from "react-native" +import { Button, CheckBox } from "react-native-elements" +import EStyleSheet from "react-native-extended-stylesheet" +import Modal from "react-native-modal" +import { bankName, lnDomain } from "./send-bitcoin-destination-screen" +import { + SendBitcoinDestinationAction, + SendBitcoinDestinationState, +} from "./send-bitcoin-reducer" +import Markdown from "react-native-markdown-display" +import { useI18nContext } from "@app/i18n/i18n-react" + +export type ConfirmDestinationModalProps = { + destinationState: SendBitcoinDestinationState + dispatchDestinationStateAction: Dispatch +} + +const styles = EStyleSheet.create({ + modalCard: { + backgroundColor: palette.white, + borderRadius: "16rem", + padding: "18rem", + }, + titleContainer: { + marginBottom: "12rem", + }, + bodyContainer: { + marginBottom: "16rem", + }, + titleText: { + fontSize: "20rem", + color: palette.darkGrey, + fontWeight: "bold", + }, + bodyText: { + fontSize: "16rem", + marginBottom: "16rem", + }, + warningText: { + fontSize: "16rem", + color: palette.red, + }, + checkBoxContainer: { + flexDirection: "row", + alignItems: "center", + }, + confirmButton: { + backgroundColor: palette.blue, + borderRadius: "12rem", + padding: "16rem", + marginBottom: "12rem", + }, + disabledConfirmButton: { + backgroundColor: palette.violetteBlue, + borderRadius: "12rem", + padding: "16rem", + marginBottom: "12rem", + }, + cancelButton: { + backgroundColor: palette.white, + }, + cancelButtonTitle: { + color: palette.blue, + }, +}) + +export const ConfirmDestinationModal: React.FC = ({ + destinationState, + dispatchDestinationStateAction, +}) => { + const [confirmationEnabled, setConfirmationEnabled] = useState(false) + const { LL } = useI18nContext() + const confirmDestination = useCallback(() => { + dispatchDestinationStateAction({ + type: "set-confirmed", + payload: { unparsedDestination: destinationState.unparsedDestination }, + }) + }, [destinationState, dispatchDestinationStateAction]) + + if (destinationState.destinationState !== "requires-confirmation") return null + + const lnAddress = destinationState.confirmationType.username + "@" + lnDomain + + return ( + + + + + {LL.SendBitcoinDestinationScreen.confirmModal.title({ lnAddress })} + + + + + {LL.SendBitcoinDestinationScreen.confirmModal.body({ bankName, lnAddress })} + + + {LL.SendBitcoinDestinationScreen.confirmModal.warning({ bankName })} + + + setConfirmationEnabled(!confirmationEnabled)} + /> + + {LL.SendBitcoinDestinationScreen.confirmModal.checkBox({ lnAddress })} + + + + +