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
This commit is contained in:
Thebora Kompanioni 2022-08-04 16:26:11 +02:00 committed by GitHub
parent 2d9d13ea90
commit 29eca37535
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 1 deletions

View file

@ -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() {
/>
)}
<rb.Button
ref={submitButtonRef}
variant={isCoinjoin ? 'dark' : 'danger'}
type="submit"
disabled={isOperationDisabled || isLoading || isSending || !formIsValid}
@ -917,6 +931,91 @@ export default function Send() {
t('send.button_send_without_improved_privacy')
)}
</rb.Button>
<ConfirmModal
isShown={showConfirmInputsModal}
title={t('send.confirm_modal.title')}
onCancel={() => setShowConfirmInputsModal(false)}
onConfirm={() => {
submitButtonRef.current?.click()
}}
>
<rb.Container className="mt-2">
<rb.Row className="mt-2 mb-3">
<rb.Col xs={12} className="text-center">
{isCoinjoin ? (
<strong className="text-success">{t('send.confirm_modal.text_collaborative_tx_enabled')}</strong>
) : (
<strong className="text-danger">{t('send.confirm_modal.text_collaborative_tx_disabled')}</strong>
)}
</rb.Col>
</rb.Row>
<rb.Row>
<rb.Col xs={3} className="text-end">
<strong>{t('send.confirm_modal.label_source_jar')}</strong>
</rb.Col>
<rb.Col xs={9} className="text-start">
{t('send.confirm_modal.text_source_jar', {
jarId: `#${account}`,
})}
</rb.Col>
</rb.Row>
<rb.Row>
<rb.Col xs={3} className="text-end">
<strong>{t('send.confirm_modal.label_recipient')}</strong>
</rb.Col>
<rb.Col xs={9} className="text-start text-break slashed-zeroes">
{destination}
</rb.Col>
</rb.Row>
<rb.Row>
<rb.Col xs={3} className="text-end">
<strong>{t('send.confirm_modal.label_amount')}</strong>
</rb.Col>
<rb.Col xs={9} className="text-start">
{isSweep ? (
<div className="d-flex justify-content-start align-items-center">
<Trans i18nKey="send.confirm_modal.text_sweep_balance">
Sweep
<Balance
valueString={amountFieldValue().toString()}
convertToUnit={settings.unit}
showBalance={true}
/>
</Trans>
<rb.OverlayTrigger
placement="right"
overlay={
<rb.Popover>
<rb.Popover.Body>{t('send.confirm_modal.text_sweep_info_popover')}</rb.Popover.Body>
</rb.Popover>
}
>
<div className="d-inline-flex align-items-center">
<Sprite className={styles.infoIcon} symbol="info" width="13" height="13" />
</div>
</rb.OverlayTrigger>
</div>
) : (
<Balance
valueString={amountFieldValue().toString()}
convertToUnit={settings.unit}
showBalance={true}
/>
)}
</rb.Col>
</rb.Row>
{isCoinjoin && (
<rb.Row>
<rb.Col xs={3} className="text-end">
<strong>{t('send.confirm_modal.label_num_collaborators')}</strong>
</rb.Col>
<rb.Col xs={9} className="text-start">
{numCollaborators}
</rb.Col>
</rb.Row>
)}
</rb.Container>
</ConfirmModal>
</div>
</>
)

View file

@ -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%;

View file

@ -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</1> or <3>time-locked</3>. 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</5> for more details.",
"confirm_modal": {
"title": "Confirm payment",
"label_amount": "Amount",
"text_sweep_balance": "Sweep whole jar (<1></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 }}</2> confirmations in the source jar. Select another jar to send from or fund this jar and wait for <6>{{ minConfirmations }}</6> blocks.",
"hint_missing_confirmations": "A collaborative transaction requires one of your UTXOs to have <2>{{ minConfirmations }}</2> or more confirmations. Select another jar to send from or wait for <6>{{ amountOfMissingConfirmations }}</6> more block(s).",