mirror of
https://github.com/joinmarket-webui/jam.git
synced 2026-08-17 13:07:34 +02:00
ui(Send): hide "number of collaborators" behind send options (#595)
This commit is contained in:
parent
da27812406
commit
9d1575ffec
11 changed files with 213 additions and 237 deletions
33
src/components/Accordion.tsx
Normal file
33
src/components/Accordion.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { PropsWithChildren, useState } from 'react'
|
||||
import { useSettings } from '../context/SettingsContext'
|
||||
import * as rb from 'react-bootstrap'
|
||||
import Sprite from './Sprite'
|
||||
|
||||
interface AccordionProps {
|
||||
title: string
|
||||
defaultOpen?: boolean
|
||||
}
|
||||
|
||||
const Accordion = ({ title, defaultOpen = false, children }: PropsWithChildren<AccordionProps>) => {
|
||||
const settings = useSettings()
|
||||
const [isOpen, setIsOpen] = useState(defaultOpen)
|
||||
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<rb.Button
|
||||
variant={settings.theme}
|
||||
className="d-flex align-items-center bg-transparent border-0 w-100 px-0 py-2"
|
||||
onClick={() => setIsOpen((current) => !current)}
|
||||
>
|
||||
{title}
|
||||
<Sprite symbol={`caret-${isOpen ? 'up' : 'down'}`} className="ms-1" width="20" height="20" />
|
||||
</rb.Button>
|
||||
<hr className="m-0 pb-4 text-secondary" />
|
||||
<rb.Collapse in={isOpen}>
|
||||
<div>{children}</div>
|
||||
</rb.Collapse>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Accordion
|
||||
|
|
@ -18,6 +18,7 @@ import { EarnReportOverlay } from './EarnReport'
|
|||
import { OrderbookOverlay } from './Orderbook'
|
||||
import Balance from './Balance'
|
||||
import styles from './Earn.module.css'
|
||||
import Accordion from './Accordion'
|
||||
|
||||
// In order to prevent state mismatch, the 'maker stop' response is delayed shortly.
|
||||
// Even though the API response suggests that the maker has started or stopped immediately, it seems that this is not always the case.
|
||||
|
|
@ -176,7 +177,6 @@ export default function Earn({ wallet }) {
|
|||
const serviceInfo = useServiceInfo()
|
||||
const reloadServiceInfo = useReloadServiceInfo()
|
||||
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
const [alert, setAlert] = useState(null)
|
||||
const [serviceInfoAlert, setServiceInfoAlert] = useState(null)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
|
@ -472,24 +472,11 @@ export default function Earn({ wallet }) {
|
|||
{!serviceInfo?.coinjoinInProgress && (
|
||||
<Formik initialValues={initialValues} validate={validate} onSubmit={onSubmit}>
|
||||
{({ handleSubmit, setFieldValue, handleChange, handleBlur, values, touched, errors, isSubmitting }) => (
|
||||
<rb.Form onSubmit={handleSubmit} noValidate>
|
||||
{!serviceInfo?.makerRunning && !isWaitingMakerStart && !isWaitingMakerStop && (
|
||||
<div className={styles['settings-container']}>
|
||||
<rb.Button
|
||||
variant={`${settings.theme}`}
|
||||
className={`${styles['settings-btn']} d-flex align-items-center`}
|
||||
onClick={() => setShowSettings((current) => !current)}
|
||||
>
|
||||
{t('earn.button_settings')}
|
||||
<Sprite
|
||||
symbol={`caret-${showSettings ? 'up' : 'down'}`}
|
||||
className="ms-1"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
</rb.Button>
|
||||
{showSettings && (
|
||||
<div className="my-4">
|
||||
<>
|
||||
<rb.Form onSubmit={handleSubmit} noValidate>
|
||||
{!serviceInfo?.makerRunning && !isWaitingMakerStart && !isWaitingMakerStop && (
|
||||
<Accordion title={t('earn.button_settings')}>
|
||||
<>
|
||||
<rb.Form.Group className="mb-4 d-flex justify-content-center" controlId="offertype">
|
||||
<SegmentedTabs
|
||||
name="offertype"
|
||||
|
|
@ -518,16 +505,16 @@ export default function Earn({ wallet }) {
|
|||
typeof values.feeRel === 'number' ? `(${factorToPercentage(values.feeRel)}%)` : '',
|
||||
})}
|
||||
</rb.Form.Label>
|
||||
<div className="mb-2">
|
||||
<rb.Form.Text className="text-secondary">{t('earn.description_rel_fee')}</rb.Form.Text>
|
||||
</div>
|
||||
<rb.Form.Text className="d-block text-secondary mb-2">
|
||||
{t('earn.description_rel_fee')}
|
||||
</rb.Form.Text>
|
||||
{isLoading ? (
|
||||
<rb.Placeholder as="div" animation="wave">
|
||||
<rb.Placeholder xs={12} className={styles['input-loader']} />
|
||||
</rb.Placeholder>
|
||||
) : (
|
||||
<rb.InputGroup>
|
||||
<rb.InputGroup.Text id="feeRel-addon1" className={styles['input-group-text']}>
|
||||
<rb.InputGroup hasValidation>
|
||||
<rb.InputGroup.Text id="feeRel-addon1" className={styles.inputGroupText}>
|
||||
%
|
||||
</rb.InputGroup.Text>
|
||||
<rb.Form.Control
|
||||
|
|
@ -543,13 +530,13 @@ export default function Earn({ wallet }) {
|
|||
onBlur={handleBlur}
|
||||
value={typeof values.feeRel === 'number' ? factorToPercentage(values.feeRel) : ''}
|
||||
isValid={touched.feeRel && !errors.feeRel}
|
||||
isInvalid={touched.feeRel && errors.feeRel}
|
||||
isInvalid={touched.feeRel && !!errors.feeRel}
|
||||
min={0}
|
||||
step={feeRelPercentageStep}
|
||||
/>
|
||||
<rb.Form.Control.Feedback type="invalid">{errors.feeRel}</rb.Form.Control.Feedback>
|
||||
</rb.InputGroup>
|
||||
)}
|
||||
<rb.Form.Control.Feedback type="invalid">{errors.feeRel}</rb.Form.Control.Feedback>
|
||||
</rb.Form.Group>
|
||||
) : (
|
||||
<rb.Form.Group className="mb-3" controlId="feeAbs">
|
||||
|
|
@ -561,16 +548,16 @@ export default function Earn({ wallet }) {
|
|||
: '',
|
||||
})}
|
||||
</rb.Form.Label>
|
||||
<div className="mb-2">
|
||||
<rb.Form.Text className="text-secondary">{t('earn.description_abs_fee')}</rb.Form.Text>
|
||||
</div>
|
||||
<rb.Form.Text className="d-block text-secondary mb-2">
|
||||
{t('earn.description_abs_fee')}
|
||||
</rb.Form.Text>
|
||||
{isLoading ? (
|
||||
<rb.Placeholder as="div" animation="wave">
|
||||
<rb.Placeholder xs={12} className={styles['input-loader']} />
|
||||
</rb.Placeholder>
|
||||
) : (
|
||||
<rb.InputGroup>
|
||||
<rb.InputGroup.Text id="feeAbs-addon1" className={styles['input-group-text']}>
|
||||
<rb.InputGroup hasValidation>
|
||||
<rb.InputGroup.Text id="feeAbs-addon1" className={styles.inputGroupText}>
|
||||
<Sprite symbol="sats" width="24" height="24" />
|
||||
</rb.InputGroup.Text>
|
||||
<rb.Form.Control
|
||||
|
|
@ -583,13 +570,13 @@ export default function Earn({ wallet }) {
|
|||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
isValid={touched.feeAbs && !errors.feeAbs}
|
||||
isInvalid={touched.feeAbs && errors.feeAbs}
|
||||
isInvalid={touched.feeAbs && !!errors.feeAbs}
|
||||
min={0}
|
||||
step={1}
|
||||
/>
|
||||
<rb.Form.Control.Feedback type="invalid">{errors.feeAbs}</rb.Form.Control.Feedback>
|
||||
</rb.InputGroup>
|
||||
)}
|
||||
<rb.Form.Control.Feedback type="invalid">{errors.feeAbs}</rb.Form.Control.Feedback>
|
||||
</rb.Form.Group>
|
||||
)}
|
||||
|
||||
|
|
@ -600,8 +587,8 @@ export default function Earn({ wallet }) {
|
|||
<rb.Placeholder xs={12} className={styles['input-loader']} />
|
||||
</rb.Placeholder>
|
||||
) : (
|
||||
<rb.InputGroup>
|
||||
<rb.InputGroup.Text id="minsize-addon1" className={styles['input-group-text']}>
|
||||
<rb.InputGroup hasValidation>
|
||||
<rb.InputGroup.Text id="minsize-addon1" className={styles.inputGroupText}>
|
||||
<Sprite symbol="sats" width="24" height="24" />
|
||||
</rb.InputGroup.Text>
|
||||
<rb.Form.Control
|
||||
|
|
@ -617,46 +604,44 @@ export default function Earn({ wallet }) {
|
|||
min={0}
|
||||
step={1000}
|
||||
/>
|
||||
<rb.Form.Control.Feedback type="invalid">{errors.minsize}</rb.Form.Control.Feedback>
|
||||
</rb.InputGroup>
|
||||
)}
|
||||
<rb.Form.Control.Feedback type="invalid">{errors.minsize}</rb.Form.Control.Feedback>
|
||||
</rb.Form.Group>
|
||||
</>
|
||||
</Accordion>
|
||||
)}
|
||||
<div className="mt-4">
|
||||
<rb.Button
|
||||
variant="dark"
|
||||
type="submit"
|
||||
className={styles['earn-btn']}
|
||||
disabled={isLoading || isSubmitting || isWaitingMakerStart || isWaitingMakerStop}
|
||||
>
|
||||
<div className="d-flex justify-content-center align-items-center">
|
||||
{(isWaitingMakerStart || isWaitingMakerStop) && (
|
||||
<rb.Spinner
|
||||
as="span"
|
||||
animation="border"
|
||||
size="sm"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
className="me-2"
|
||||
/>
|
||||
)}
|
||||
{isWaitingMakerStart || isWaitingMakerStop ? (
|
||||
<>
|
||||
{isWaitingMakerStart && t('earn.text_starting')}
|
||||
{isWaitingMakerStop && t('earn.text_stopping')}
|
||||
</>
|
||||
) : (
|
||||
<>{serviceInfo?.makerRunning === true ? t('earn.button_stop') : t('earn.button_start')}</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<hr className="m-0" />
|
||||
</rb.Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-4">
|
||||
<rb.Button
|
||||
variant="dark"
|
||||
type="submit"
|
||||
className={styles['earn-btn']}
|
||||
disabled={isLoading || isSubmitting || isWaitingMakerStart || isWaitingMakerStop}
|
||||
>
|
||||
<div className="d-flex justify-content-center align-items-center">
|
||||
{(isWaitingMakerStart || isWaitingMakerStop) && (
|
||||
<rb.Spinner
|
||||
as="span"
|
||||
animation="border"
|
||||
size="sm"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
className="me-2"
|
||||
/>
|
||||
)}
|
||||
{isWaitingMakerStart || isWaitingMakerStop ? (
|
||||
<>
|
||||
{isWaitingMakerStart && t('earn.text_starting')}
|
||||
{isWaitingMakerStop && t('earn.text_stopping')}
|
||||
</>
|
||||
) : (
|
||||
<>{serviceInfo?.makerRunning === true ? t('earn.button_stop') : t('earn.button_start')}</>
|
||||
)}
|
||||
</div>
|
||||
</rb.Button>
|
||||
</div>
|
||||
</rb.Form>
|
||||
</rb.Form>
|
||||
</>
|
||||
)}
|
||||
</Formik>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -17,19 +17,7 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.settings-container {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.settings-container button.settings-btn {
|
||||
background-color: transparent !important;
|
||||
border: none;
|
||||
padding-left: 0;
|
||||
height: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.settings-container .input-group-text {
|
||||
.inputGroupText {
|
||||
width: 5ch;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ const withTooltip = (node: React.ReactElement, tooltip: string) => {
|
|||
// `TableNode` is known to have same properties as `ObwatchApi.Order`, hence prefer casting over object destructuring
|
||||
const toOrder = (tableNode: TableTypes.TableNode) => tableNode as unknown as ObwatchApi.Order
|
||||
|
||||
const renderOrderType = (val: string, t: TFunction<'translation', undefined>) => {
|
||||
const renderOrderType = (val: string, t: TFunction) => {
|
||||
if (val === ObwatchApi.ABSOLUTE_ORDER_TYPE_VAL) {
|
||||
return withTooltip(<rb.Badge bg="info">{t('orderbook.text_offer_type_absolute')}</rb.Badge>, val)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { CopyButton } from './CopyButton'
|
|||
import { ShareButton, checkIsWebShareAPISupported } from './ShareButton'
|
||||
import { SelectableJar, jarFillLevel } from './jars/Jar'
|
||||
import styles from './Receive.module.css'
|
||||
import Accordion from './Accordion'
|
||||
|
||||
export default function Receive({ wallet }) {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -25,7 +26,6 @@ export default function Receive({ wallet }) {
|
|||
const [amount, setAmount] = useState('')
|
||||
const [selectedJarIndex, setSelectedJarIndex] = useState(parseInt(location.state?.account, 10) || 0)
|
||||
const [addressCount, setAddressCount] = useState(0)
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
|
||||
const sortedAccountBalances = useMemo(() => {
|
||||
if (!walletInfo) return []
|
||||
|
|
@ -105,66 +105,53 @@ export default function Receive({ wallet }) {
|
|||
</rb.Card>
|
||||
</div>
|
||||
<rb.Form onSubmit={onSubmit} validated={validated} noValidate>
|
||||
<div className={styles['settings-container']}>
|
||||
<rb.Button
|
||||
variant={`${settings.theme}`}
|
||||
className={`${styles['settings-btn']} d-flex align-items-center`}
|
||||
onClick={() => setShowSettings((current) => !current)}
|
||||
>
|
||||
{t('receive.button_settings')}
|
||||
<Sprite symbol={`caret-${showSettings ? 'up' : 'down'}`} className="ms-1" width="20" height="20" />
|
||||
</rb.Button>
|
||||
{showSettings && (
|
||||
<div className="my-4">
|
||||
{!walletInfo || sortedAccountBalances.length === 0 ? (
|
||||
<rb.Placeholder as="div" animation="wave">
|
||||
<rb.Placeholder className={styles.jarsPlaceholder} />
|
||||
</rb.Placeholder>
|
||||
) : (
|
||||
<div className={styles.jarsContainer}>
|
||||
{sortedAccountBalances.map((it) => (
|
||||
<SelectableJar
|
||||
key={it.accountIndex}
|
||||
index={it.accountIndex}
|
||||
balance={it.calculatedTotalBalanceInSats}
|
||||
isSelectable={true}
|
||||
isSelected={it.accountIndex === selectedJarIndex}
|
||||
fillLevel={jarFillLevel(
|
||||
it.calculatedTotalBalanceInSats,
|
||||
walletInfo.balanceSummary.calculatedTotalBalanceInSats
|
||||
)}
|
||||
onClick={(jarIndex) => setSelectedJarIndex(jarIndex)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<rb.Form.Group controlId="amountSats">
|
||||
<rb.Form.Label>{t('receive.label_amount')}</rb.Form.Label>
|
||||
<rb.InputGroup>
|
||||
<rb.InputGroup.Text id="amountSats-addon1" className={styles.inputGroupText}>
|
||||
<Sprite symbol="sats" width="24" height="24" />
|
||||
</rb.InputGroup.Text>
|
||||
<rb.Form.Control
|
||||
aria-label={t('receive.label_amount')}
|
||||
className="slashed-zeroes"
|
||||
name="amount"
|
||||
type="number"
|
||||
placeholder="0"
|
||||
value={amount}
|
||||
disabled={isLoading}
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
min={0}
|
||||
step={1}
|
||||
<Accordion title={t('receive.button_settings')}>
|
||||
<div>
|
||||
{!walletInfo || sortedAccountBalances.length === 0 ? (
|
||||
<rb.Placeholder as="div" animation="wave">
|
||||
<rb.Placeholder className={styles.jarsPlaceholder} />
|
||||
</rb.Placeholder>
|
||||
) : (
|
||||
<div className={styles.jarsContainer}>
|
||||
{sortedAccountBalances.map((it) => (
|
||||
<SelectableJar
|
||||
key={it.accountIndex}
|
||||
index={it.accountIndex}
|
||||
balance={it.calculatedTotalBalanceInSats}
|
||||
isSelectable={true}
|
||||
isSelected={it.accountIndex === selectedJarIndex}
|
||||
fillLevel={jarFillLevel(
|
||||
it.calculatedTotalBalanceInSats,
|
||||
walletInfo.balanceSummary.calculatedTotalBalanceInSats
|
||||
)}
|
||||
onClick={(jarIndex) => setSelectedJarIndex(jarIndex)}
|
||||
/>
|
||||
</rb.InputGroup>
|
||||
<rb.Form.Control.Feedback type="invalid">
|
||||
{t('receive.feedback_invalid_amount')}
|
||||
</rb.Form.Control.Feedback>
|
||||
</rb.Form.Group>
|
||||
</div>
|
||||
)}
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<rb.Form.Group controlId="amountSats">
|
||||
<rb.Form.Label>{t('receive.label_amount')}</rb.Form.Label>
|
||||
<rb.InputGroup>
|
||||
<rb.InputGroup.Text id="amountSats-addon1" className={styles.inputGroupText}>
|
||||
<Sprite symbol="sats" width="24" height="24" />
|
||||
</rb.InputGroup.Text>
|
||||
<rb.Form.Control
|
||||
aria-label={t('receive.label_amount')}
|
||||
className="slashed-zeroes"
|
||||
name="amount"
|
||||
type="number"
|
||||
placeholder="0"
|
||||
value={amount}
|
||||
disabled={isLoading}
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
min={0}
|
||||
step={1}
|
||||
/>
|
||||
</rb.InputGroup>
|
||||
<rb.Form.Control.Feedback type="invalid">{t('receive.feedback_invalid_amount')}</rb.Form.Control.Feedback>
|
||||
</rb.Form.Group>
|
||||
</div>
|
||||
</Accordion>
|
||||
|
||||
<div className="mt-4 d-flex justify-content-center">
|
||||
<rb.Button
|
||||
|
|
|
|||
|
|
@ -14,18 +14,6 @@
|
|||
border-color: rgba(222, 222, 222, 1);
|
||||
}
|
||||
|
||||
.settings-container {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.settings-container button.settings-btn {
|
||||
background-color: transparent !important;
|
||||
border: none;
|
||||
padding-left: 0;
|
||||
height: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.receive form input {
|
||||
height: 3.5rem;
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -38,65 +38,62 @@ const CollaboratorsSelector = ({
|
|||
}
|
||||
|
||||
return (
|
||||
// @ts-ignore FIXME: "Property 'disabled' does not exist on type..."
|
||||
<rb.Form noValidate className={styles.collaboratorsSelector} disabled={disabled}>
|
||||
<rb.Form.Group>
|
||||
<rb.Form.Label className="mb-0">{t('send.label_num_collaborators', { numCollaborators })}</rb.Form.Label>
|
||||
<div className="mb-2">
|
||||
<rb.Form.Text className="text-secondary">{t('send.description_num_collaborators')}</rb.Form.Text>
|
||||
</div>
|
||||
<div className="d-flex flex-row flex-wrap gap-2">
|
||||
{defaultCollaboratorsSelection.map((number) => {
|
||||
const isSelected = !usesCustomNumCollaborators && numCollaborators === number
|
||||
return (
|
||||
<rb.Button
|
||||
key={number}
|
||||
variant={settings.theme === 'light' ? 'white' : 'dark'}
|
||||
className={classNames(styles.collaboratorsSelectorElement, 'border', 'border-1', {
|
||||
[styles.selected]: isSelected,
|
||||
})}
|
||||
onClick={() => {
|
||||
setUsesCustomNumCollaborators(false)
|
||||
setNumCollaborators(number)
|
||||
}}
|
||||
disabled={disabled}
|
||||
>
|
||||
{number}
|
||||
</rb.Button>
|
||||
)
|
||||
<rb.Form.Group className={styles.collaboratorsSelector}>
|
||||
<rb.Form.Label className="mb-0">{t('send.label_num_collaborators', { numCollaborators })}</rb.Form.Label>
|
||||
<div className="mb-2">
|
||||
<rb.Form.Text className="text-secondary">{t('send.description_num_collaborators')}</rb.Form.Text>
|
||||
</div>
|
||||
<div className="d-flex flex-row flex-wrap gap-2">
|
||||
{defaultCollaboratorsSelection.map((number) => {
|
||||
const isSelected = !usesCustomNumCollaborators && numCollaborators === number
|
||||
return (
|
||||
<rb.Button
|
||||
key={number}
|
||||
variant={settings.theme === 'light' ? 'white' : 'dark'}
|
||||
className={classNames(styles.collaboratorsSelectorElement, 'border', 'border-1', {
|
||||
[styles.selected]: isSelected,
|
||||
})}
|
||||
onClick={() => {
|
||||
setUsesCustomNumCollaborators(false)
|
||||
setNumCollaborators(number)
|
||||
}}
|
||||
disabled={disabled}
|
||||
>
|
||||
{number}
|
||||
</rb.Button>
|
||||
)
|
||||
})}
|
||||
<rb.Form.Control
|
||||
type="number"
|
||||
min={minNumCollaborators}
|
||||
max={99}
|
||||
isInvalid={!isValidNumCollaborators(numCollaborators, minNumCollaborators)}
|
||||
placeholder={t('send.input_num_collaborators_placeholder')}
|
||||
defaultValue=""
|
||||
className={classNames(styles.collaboratorsSelectorElement, 'border', 'border-1', {
|
||||
[styles.selected]: usesCustomNumCollaborators,
|
||||
})}
|
||||
<rb.Form.Control
|
||||
type="number"
|
||||
min={minNumCollaborators}
|
||||
max={99}
|
||||
isInvalid={!isValidNumCollaborators(numCollaborators, minNumCollaborators)}
|
||||
placeholder={t('send.input_num_collaborators_placeholder')}
|
||||
defaultValue=""
|
||||
className={classNames(styles.collaboratorsSelectorElement, 'border', 'border-1', {
|
||||
[styles.selected]: usesCustomNumCollaborators,
|
||||
})}
|
||||
onChange={(e) => {
|
||||
onChange={(e) => {
|
||||
setUsesCustomNumCollaborators(true)
|
||||
validateAndSetCustomNumCollaborators(e.target.value)
|
||||
}}
|
||||
onClick={(e) => {
|
||||
// @ts-ignore - FIXME: "Property 'value' does not exist on type 'EventTarget'"
|
||||
if (e.target.value !== '') {
|
||||
setUsesCustomNumCollaborators(true)
|
||||
validateAndSetCustomNumCollaborators(e.target.value)
|
||||
}}
|
||||
onClick={(e) => {
|
||||
// @ts-ignore - FIXME: "Property 'value' does not exist on type 'EventTarget'"
|
||||
if (e.target.value !== '') {
|
||||
setUsesCustomNumCollaborators(true)
|
||||
// @ts-ignore - FIXME: "Property 'value' does not exist on type 'EventTarget'"
|
||||
validateAndSetCustomNumCollaborators(e.target.value)
|
||||
}
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{usesCustomNumCollaborators && (
|
||||
<rb.Form.Control.Feedback type="invalid">
|
||||
{t('send.error_invalid_num_collaborators', { minNumCollaborators, maxNumCollaborators: 99 })}
|
||||
</rb.Form.Control.Feedback>
|
||||
)}
|
||||
</div>
|
||||
</rb.Form.Group>
|
||||
</rb.Form>
|
||||
validateAndSetCustomNumCollaborators(e.target.value)
|
||||
}
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{usesCustomNumCollaborators && (
|
||||
<rb.Form.Control.Feedback type="invalid">
|
||||
{t('send.error_invalid_num_collaborators', { minNumCollaborators, maxNumCollaborators: 99 })}
|
||||
</rb.Form.Control.Feedback>
|
||||
)}
|
||||
</div>
|
||||
</rb.Form.Group>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import {
|
|||
isValidJarIndex,
|
||||
isValidNumCollaborators,
|
||||
} from './helpers'
|
||||
import Accordion from '../Accordion'
|
||||
|
||||
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)
|
||||
|
|
@ -602,19 +603,16 @@ export default function Send({ wallet }: SendProps) {
|
|||
)}
|
||||
</>
|
||||
</rb.Fade>
|
||||
|
||||
{alert && (
|
||||
<rb.Alert className="slashed-zeroes" variant={alert.variant}>
|
||||
{alert.message}
|
||||
</rb.Alert>
|
||||
)}
|
||||
|
||||
{paymentSuccessfulInfoAlert && (
|
||||
<rb.Alert className="small slashed-zeroes break-word" variant={paymentSuccessfulInfoAlert.variant}>
|
||||
{paymentSuccessfulInfoAlert.message}
|
||||
</rb.Alert>
|
||||
)}
|
||||
|
||||
{!isLoading && !isOperationDisabled && isCoinjoin && !coinjoinPreconditionSummary.isFulfilled && (
|
||||
<div className="mb-4">
|
||||
<CoinjoinPreconditionViolationAlert
|
||||
|
|
@ -623,7 +621,6 @@ export default function Send({ wallet }: SendProps) {
|
|||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isLoading && walletInfo && (
|
||||
<JarSelectorModal
|
||||
isShown={destinationJarPickerShown}
|
||||
|
|
@ -657,7 +654,6 @@ export default function Send({ wallet }: SendProps) {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<rb.Form id="send-form" onSubmit={onSubmit} noValidate className={styles['send-form']}>
|
||||
<rb.Form.Group className="mb-4 flex-grow-1" controlId="sourceJarIndex">
|
||||
<rb.Form.Label>{t('send.label_source_jar')}</rb.Form.Label>
|
||||
|
|
@ -805,24 +801,26 @@ export default function Send({ wallet }: SendProps) {
|
|||
</rb.Form.Control.Feedback>
|
||||
{isSweep && frozenOrLockedWarning()}
|
||||
</rb.Form.Group>
|
||||
<rb.Form.Group controlId="isCoinjoin" className={`${isCoinjoin ? 'mb-3' : ''}`}>
|
||||
<ToggleSwitch
|
||||
label={t('send.toggle_coinjoin')}
|
||||
subtitle={t('send.toggle_coinjoin_subtitle')}
|
||||
toggledOn={isCoinjoin}
|
||||
onToggle={(isToggled) => setIsCoinjoin(isToggled)}
|
||||
disabled={isLoading || isOperationDisabled}
|
||||
/>
|
||||
</rb.Form.Group>
|
||||
<Accordion title={t('send.sending_options')}>
|
||||
<rb.Form.Group controlId="isCoinjoin" className={`${isCoinjoin ? 'mb-3' : ''}`}>
|
||||
<ToggleSwitch
|
||||
label={t('send.toggle_coinjoin')}
|
||||
subtitle={t('send.toggle_coinjoin_subtitle')}
|
||||
toggledOn={isCoinjoin}
|
||||
onToggle={(isToggled) => setIsCoinjoin(isToggled)}
|
||||
disabled={isLoading || isOperationDisabled}
|
||||
/>
|
||||
</rb.Form.Group>
|
||||
<div className={isCoinjoin ? 'd-block' : 'd-none'}>
|
||||
<CollaboratorsSelector
|
||||
numCollaborators={numCollaborators}
|
||||
setNumCollaborators={setNumCollaborators}
|
||||
minNumCollaborators={minNumCollaborators}
|
||||
disabled={isLoading || isOperationDisabled}
|
||||
/>
|
||||
</div>
|
||||
</Accordion>
|
||||
</rb.Form>
|
||||
{isCoinjoin && (
|
||||
<CollaboratorsSelector
|
||||
numCollaborators={numCollaborators}
|
||||
setNumCollaborators={setNumCollaborators}
|
||||
minNumCollaborators={minNumCollaborators}
|
||||
disabled={isLoading || isOperationDisabled}
|
||||
/>
|
||||
)}
|
||||
<rb.Button
|
||||
ref={submitButtonRef}
|
||||
variant={submitButtonOptions.variant}
|
||||
|
|
@ -840,7 +838,6 @@ export default function Send({ wallet }: SendProps) {
|
|||
<>{submitButtonOptions.text}</>
|
||||
)}
|
||||
</rb.Button>
|
||||
|
||||
{showConfirmAbortModal && (
|
||||
<ConfirmModal
|
||||
isShown={showConfirmAbortModal}
|
||||
|
|
@ -851,7 +848,6 @@ export default function Send({ wallet }: SendProps) {
|
|||
{t('send.confirm_abort_modal.text_body')}
|
||||
</ConfirmModal>
|
||||
)}
|
||||
|
||||
{showConfirmSendModal && (
|
||||
<PaymentConfirmModal
|
||||
isShown={true}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ interface Result {
|
|||
mustReload: boolean
|
||||
}
|
||||
|
||||
const errorResolver = (t: TFunction<'translation', undefined>, i18nKey: string | string[]) => ({
|
||||
const errorResolver = (t: TFunction, i18nKey: string | string[]) => ({
|
||||
resolver: (_: Response, reason: string) => `${t(i18nKey)} ${reason}`,
|
||||
fallbackReason: t('global.errors.reason_unknown'),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@
|
|||
"label_amount": "Amount in sats",
|
||||
"placeholder_amount": "Enter amount...",
|
||||
"feedback_invalid_amount": "Please provide a valid amount.",
|
||||
"sending_options": "Sending options",
|
||||
"toggle_coinjoin": "Send as collaborative transaction",
|
||||
"toggle_coinjoin_subtitle": "Collaborative transactions improve the privacy of yourself and others.",
|
||||
"button_send": "Send",
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@
|
|||
"label_amount": "Montant en sats",
|
||||
"placeholder_amount": "Entrez le montant...",
|
||||
"feedback_invalid_amount": "Veuillez fournir un montant valide.",
|
||||
"sending_options": "Options d'envoi",
|
||||
"toggle_coinjoin": "Envoyer en tant que transaction collaborative pour une meilleure confidentialité",
|
||||
"button_send": "Envoyer",
|
||||
"text_sending": "Envoi de ",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue