From fc80868617f55c0dc358996e57cb34113faf2eea Mon Sep 17 00:00:00 2001 From: Sandipan Dey Date: Thu, 13 Jul 2023 02:42:20 +0530 Subject: [PATCH] feat: added copy and share invoice --- app/components/note-input/note-input.tsx | 1 - .../receive-bitcoin-screen/receive-screen.tsx | 54 ++++++++++++--- .../use-receive-bitcoin.ts | 66 +++++++++++++++++-- 3 files changed, 107 insertions(+), 14 deletions(-) diff --git a/app/components/note-input/note-input.tsx b/app/components/note-input/note-input.tsx index 3a60141c08..6e0ed17e59 100644 --- a/app/components/note-input/note-input.tsx +++ b/app/components/note-input/note-input.tsx @@ -13,7 +13,6 @@ export type NoteInputProps = { value?: string | undefined editable?: boolean | undefined style?: StyleProp - disabled?: boolean | undefined } export const NoteInput: React.FC = ({ diff --git a/app/screens/receive-bitcoin-screen/receive-screen.tsx b/app/screens/receive-bitcoin-screen/receive-screen.tsx index 53cfdf4838..668469c389 100644 --- a/app/screens/receive-bitcoin-screen/receive-screen.tsx +++ b/app/screens/receive-bitcoin-screen/receive-screen.tsx @@ -6,7 +6,7 @@ import { useI18nContext } from "@app/i18n/i18n-react" import { requestNotificationPermission } from "@app/utils/notifications" import { useIsFocused, useNavigation } from "@react-navigation/native" import React, { useEffect, useState } from "react" -import { TextInput, View } from "react-native" +import { Pressable, TextInput, View } from "react-native" import { TouchableWithoutFeedback } from "react-native-gesture-handler" import { testProps } from "../../utils/testProps" import { MyLnUpdateSub } from "./my-ln-updates-sub" @@ -24,6 +24,7 @@ import { QRView } from "./qr-view" import { AmountInput } from "@app/components/amount-input" import NoteIcon from "@app/assets/icons/note.svg" import { NoteInput } from "@app/components/note-input" +import Icon from "react-native-vector-icons/Ionicons" const ReceiveScreen = () => { const { @@ -71,7 +72,6 @@ const ReceiveScreen = () => { regenerateInvoice, info, state, - canSetAmount, canSetMemo, canUsePaycode, canSetReceivingWalletDescriptor, @@ -79,8 +79,6 @@ const ReceiveScreen = () => { setReceivingWallet, } = request - console.log({ memoChangeText: request.memoChangeText, memo: request.memo }) - return ( { style={styles.receivingWalletPicker} disabled={!canSetReceivingWalletDescriptor} /> + + {request.extraDetails} + { err={state === PaymentRequestState.Error ? LL.ReceiveScreen.error() : ""} style={styles.qrView} /> - - {request.extraDetails} + + + + + + + {LL.ReceiveScreen.copyInvoice()} + + + + + + + + + {LL.ReceiveScreen.shareInvoice()} + + + + { value={request.memoChangeText || ""} editable={canSetMemo} style={styles.note} - disabled={!canSetMemo} /> @@ -196,7 +220,21 @@ const useStyles = makeStyles(({ colors }) => ({ flexDirection: "row", justifyContent: "center", alignItems: "center", - marginBottom: 15, + marginBottom: 10, + }, + invoiceActions: { + flexDirection: "row", + justifyContent: "center", + marginBottom: 10, + }, + copyInvoiceContainer: { + flex: 2, + marginLeft: 10, + }, + shareInvoiceContainer: { + flex: 2, + alignItems: "flex-end", + marginRight: 10, }, })) diff --git a/app/screens/receive-bitcoin-screen/use-receive-bitcoin.ts b/app/screens/receive-bitcoin-screen/use-receive-bitcoin.ts index 06ef36b8f5..4342793a3a 100644 --- a/app/screens/receive-bitcoin-screen/use-receive-bitcoin.ts +++ b/app/screens/receive-bitcoin-screen/use-receive-bitcoin.ts @@ -1,4 +1,4 @@ -import { memo, useEffect, useState } from "react" +import { memo, useEffect, useMemo, useState } from "react" import { BaseCreatePaymentRequestCreationDataParams, Invoice, @@ -19,7 +19,7 @@ import { import { createPaymentRequestCreationData } from "./payment/payment-request-creation-data" import { usePriceConversion } from "@app/hooks" -import { WalletDescriptor } from "@app/types/wallets" +import Clipboard from "@react-native-clipboard/clipboard" import { gql } from "@apollo/client" import { useIsAuthed } from "@app/graphql/is-authed-context" import { getBtcWallet, getDefaultWallet, getUsdWallet } from "@app/graphql/wallets-utils" @@ -27,6 +27,11 @@ import { createPaymentRequest } from "./payment/payment-request" import { MoneyAmount, WalletOrDisplayCurrency } from "@app/types/amounts" import { useLnUpdateHashPaid } from "@app/graphql/ln-update-context" import { secondsToHMS } from "./payment/helpers" +import { toastShow } from "@app/utils/toast" +import { useI18nContext } from "@app/i18n/i18n-react" + +import crashlytics from "@react-native-firebase/crashlytics" +import { Alert, Share } from "react-native" gql` query paymentRequest { @@ -126,6 +131,7 @@ export const useReceiveBitcoin = () => { const [expiresInSeconds, setExpiresInSeconds] = useState(null) + const { LL } = useI18nContext() const isAuthed = useIsAuthed() const { data } = usePaymentRequestQuery({ @@ -273,6 +279,53 @@ export const useReceiveBitcoin = () => { } }, [memoChangeText, setPRCD]) + const { copyToClipboard, share } = useMemo(() => { + if (!pr) { + return {} + } + + const paymentFullUri = pr.info?.data?.getFullUriFn({}) + + const copyToClipboard = () => { + if (!paymentFullUri) return + + Clipboard.setString(paymentFullUri) + + toastShow({ + message: (translations) => translations.ReceiveScreen.copyClipboard(), + currentTranslation: LL, + type: "success", + }) + } + + const share = async () => { + if (!paymentFullUri) return + try { + const result = await Share.share({ message: paymentFullUri }) + + if (result.action === Share.sharedAction) { + if (result.activityType) { + // shared with activity type of result.activityType + } else { + // shared + } + } else if (result.action === Share.dismissedAction) { + // dismissed + } + } catch (err) { + if (err instanceof Error) { + crashlytics().recordError(err) + Alert.alert(err.message) + } + } + } + + return { + copyToClipboard, + share, + } + }, [pr?.info?.data, LL]) + if (!prcd) return null const setType = (type: InvoiceType) => { @@ -329,9 +382,10 @@ export const useReceiveBitcoin = () => { pr?.info?.data?.invoiceType === "OnChain" && pr.info.data.address ) { - extraDetails = `${pr.info.data.address.slice(0, 6)}......${pr.info.data.address.slice( - -6, - )}` + extraDetails = `Verify: ${pr.info.data.address.slice( + 0, + 6, + )}......${pr.info.data.address.slice(-6)}` } return { @@ -346,5 +400,7 @@ export const useReceiveBitcoin = () => { feesInformation: data?.globals?.feesInformation, memoChangeText, setMemoChangeText, + copyToClipboard, + share, } }