From 29eca37535b026d2c3eddb87170c8345bf287bc2 Mon Sep 17 00:00:00 2001 From: Thebora Kompanioni Date: Thu, 4 Aug 2022 16:26:11 +0200 Subject: [PATCH] feat: payment confirm modal (#446) * feat: payment confirm modal * dev: show success text in confirm modal if privacy is enabled * dev: improved sweep text in confirm modal * dev: display source jar in confirm modal * review: improve sweep info in confirm modal --- src/components/Send.jsx | 101 ++++++++++++++++++++++++++- src/components/Send.module.css | 7 ++ src/i18n/locales/en/translation.json | 12 ++++ 3 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/components/Send.jsx b/src/components/Send.jsx index 633c1624..4ec43a91 100644 --- a/src/components/Send.jsx +++ b/src/components/Send.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useMemo } from 'react' +import React, { useEffect, useState, useMemo, useRef } from 'react' import { Link, useLocation } from 'react-router-dom' import { Trans, useTranslation } from 'react-i18next' import * as rb from 'react-bootstrap' @@ -19,6 +19,7 @@ import * as Api from '../libs/JmWalletApi' import { SATS, formatBtc, formatSats } from '../utils' import { routes } from '../constants/routes' import styles from './Send.module.css' +import { ConfirmModal } from './Modal' const IS_COINJOIN_DEFAULT_VAL = true // initial value for `minimum_makers` from the default joinmarket.cfg (last check on 2022-02-20 of v0.9.5) @@ -297,6 +298,9 @@ export default function Send() { [isInitializing, waitForUtxosToBeSpent] ) + const [showConfirmInputsModal, setShowConfirmInputsModal] = useState(false) + const submitButtonRef = useRef(null) + useEffect(() => { setTakerStartedInfoAlert((current) => (isCoinjoinInProgress ? current : null)) }, [isCoinjoinInProgress]) @@ -542,10 +546,19 @@ export default function Send() { if (isLoading || isOperationDisabled) return + setPaymentSuccessfulInfoAlert(null) + const form = e.currentTarget const isValid = formIsValid if (isValid) { + if (!showConfirmInputsModal) { + setShowConfirmInputsModal(true) + return + } + + setShowConfirmInputsModal(false) + const counterparties = parseInt(numCollaborators, 10) if (isSweep && amount !== 0) { @@ -900,6 +913,7 @@ export default function Send() { /> )} + setShowConfirmInputsModal(false)} + onConfirm={() => { + submitButtonRef.current?.click() + }} + > + + + + {isCoinjoin ? ( + {t('send.confirm_modal.text_collaborative_tx_enabled')} + ) : ( + {t('send.confirm_modal.text_collaborative_tx_disabled')} + )} + + + + + {t('send.confirm_modal.label_source_jar')} + + + {t('send.confirm_modal.text_source_jar', { + jarId: `#${account}`, + })} + + + + + {t('send.confirm_modal.label_recipient')} + + + {destination} + + + + + {t('send.confirm_modal.label_amount')} + + + {isSweep ? ( +
+ + Sweep + + + + {t('send.confirm_modal.text_sweep_info_popover')} + + } + > +
+ +
+
+
+ ) : ( + + )} +
+
+ {isCoinjoin && ( + + + {t('send.confirm_modal.label_num_collaborators')} + + + {numCollaborators} + + + )} +
+
) diff --git a/src/components/Send.module.css b/src/components/Send.module.css index db0154b6..4026b839 100644 --- a/src/components/Send.module.css +++ b/src/components/Send.module.css @@ -150,6 +150,13 @@ input[type='number'] { filter: blur(2px); } +.infoIcon { + margin: 2px 0 0 0.25rem; + color: var(--bs-gray-500); + border: 1px solid var(--bs-gray-500); + border-radius: 50%; +} + .accordion-button { border: none; width: 100%; diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index d5bb94cc..9f27196e 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -188,6 +188,18 @@ "sweep_amount_breakdown_frozen_balance": "Frozen or locked balance", "sweep_amount_breakdown_estimated_amount": "Estimated amount to be sent", "sweep_amount_breakdown_explanation": "A sweep transaction will consume all UTXOs of a mixdepth leaving no coins behind except those that have been <1>frozen or <3>time-locked. Onchain transaction fees and market maker fees will be deducted from the amount so as to leave zero change. The exact transaction amount can only be calculated by JoinMarket at the point when the transaction is made. Therefore the estimated amount shown might deviate from the actually sent amount. Refer to the <5>JoinMarket documentation for more details.", + "confirm_modal": { + "title": "Confirm payment", + "label_amount": "Amount", + "text_sweep_balance": "Sweep whole jar (<1>)", + "text_sweep_info_popover": "The exact transaction amount can only be calculated by JoinMarket at the point when the transaction is made.", + "label_recipient": "Recipient", + "label_source_jar": "Send from", + "text_source_jar": "Jar {{ jarId }}", + "label_num_collaborators": "Collaborators", + "text_collaborative_tx_enabled": "Payment with privacy improvement", + "text_collaborative_tx_disabled": "Payment without privacy improvement" + }, "coinjoin_precondition": { "hint_missing_utxos": "To execute a collaborative transaction you need at least one UTXO with <2>{{ minConfirmations }} confirmations in the source jar. Select another jar to send from or fund this jar and wait for <6>{{ minConfirmations }} blocks.", "hint_missing_confirmations": "A collaborative transaction requires one of your UTXOs to have <2>{{ minConfirmations }} or more confirmations. Select another jar to send from or wait for <6>{{ amountOfMissingConfirmations }} more block(s).",