Migrate the tx-sender page to Redocly

Update convert-template

Add basic page

Add it to the sidebar

Fix a broken link

Fix translate usage and add linebreaks

Fix indents

Add basic sidebar

Port over init button logic

Migrate submit_and_notify and start dest addr

Get the payment button working

Componentize the Send XRP Payment button

Add basic escrow button

Componentize payment channel

Migrate Trust For

Migrate Send Issued Currency

Add partial payment progres bar logic

Use the component for the partial payment

Add support for escrow finish

Log transactions in sidebar

Debugging partial payment setup

Add support for changing destinationAddress

Finish adding bootstrap growl notifications

Use 'client' instead of 'api'

Move DestinationAddressInput to component and remove ids

Split the page into separate files

Remove the old files for this page

Update links

Add space

Add comment deprecating bootstrap-growl jquery

Fix typing errors

PR Comments Pt 1

Small PR fixes

Encapsulate isValidDestinationAddress
This commit is contained in:
JST5000
2023-11-08 10:35:19 -08:00
committed by mDuo13
parent 64a91fc0a8
commit 0d0187b4ee
13 changed files with 1387 additions and 346 deletions

View File

@@ -0,0 +1,156 @@
import * as React from 'react';
import { useState } from 'react'
import { useTranslate } from '@portal/hooks';
import { clsx } from 'clsx'
import { type Transaction, type Wallet } from 'xrpl'
import { SubmitConstData, submitAndUpdateUI, canSendTransaction } from '../utils';
export interface TransactionButtonProps {
submitConstData: SubmitConstData,
connectionReady: boolean,
transaction: Transaction,
sendingWallet: Wallet | undefined
id: string, // Used to set all ids within component
content: {
buttonText: string,
units: string, // Displays after the input number
longerDescription: React.JSX.Element // JSX allows for embedding links within the longer description
buttonTitle?: string // Only used while loading bar is activated
},
inputSettings?: {
defaultValue: number, // Should NOT be a dynamic number
setInputValue: React.Dispatch<React.SetStateAction<number>>,
min: number,
max: number,
},
loadingBar?: {
id: string,
widthPercent: number,
description: string,
defaultOn: boolean,
},
checkBox?: {
setCheckValue: React.Dispatch<React.SetStateAction<boolean>>,
defaultValue: boolean,
description: string,
}
customOnClick?: Function
}
function shouldDisableButton(
connectionReady: boolean,
sendingWallet: Wallet | undefined,
waitingForTransaction: boolean,
loadingBar?: {
widthPercent: number
}
): boolean {
return !canSendTransaction(connectionReady, sendingWallet?.address)
|| waitingForTransaction
|| (!!(loadingBar?.widthPercent) && loadingBar.widthPercent < 100)
}
export function TransactionButton({
id,
submitConstData,
connectionReady,
transaction,
sendingWallet,
content,
inputSettings,
loadingBar,
checkBox,
customOnClick
}: TransactionButtonProps ) {
const { translate } = useTranslate()
const [waitingForTransaction, setWaitingForTransaction] = useState(false)
return (
<div>
<div className="form-group" id={id}>
{/* Optional loading bar - Used for Partial Payments setup and EscrowFinish wait time */}
{loadingBar?.id && <div className="progress mb-1" id={loadingBar?.id ?? ""}>
<div className={
clsx("progress-bar progress-bar-striped w-0",
(loadingBar?.widthPercent < 100 && loadingBar?.widthPercent > 0) && "progress-bar-animated")}
style={{width: (Math.min(loadingBar?.widthPercent + (loadingBar?.defaultOn ? 1 : 0), 100)).toString() + "%",
display: (loadingBar?.widthPercent >= 100) ? 'none' : ''}}>
&nbsp;
</div>
{(loadingBar?.widthPercent < 100 && loadingBar?.widthPercent > 0 || (loadingBar.defaultOn && loadingBar?.widthPercent === 0))
&& <small className="justify-content-center d-flex position-absolute w-100">
{translate(loadingBar?.description)}
</small>}
</div>}
<div className="input-group mb-3">
{/* Loading icon for when transaction is being submitted */}
<div className="input-group-prepend">
<span className="input-group-text loader" style={{display: waitingForTransaction ? '' : 'none'}}>
<img className="throbber" src="/img/xrp-loader-96.png" alt={translate("(loading)")} />
</span>
</div>
<button className={clsx("btn btn-primary form-control needs-connection",
(shouldDisableButton(connectionReady, sendingWallet, waitingForTransaction, loadingBar) && "disabled"))}
type="button" id={id + "_btn"}
disabled={shouldDisableButton(connectionReady, sendingWallet, waitingForTransaction, loadingBar)}
onClick={async () => {
setWaitingForTransaction(true)
customOnClick ? await customOnClick() : await submitAndUpdateUI(submitConstData, sendingWallet!, transaction)
setWaitingForTransaction(false)
}}
title={(loadingBar && (loadingBar.widthPercent > 0 && loadingBar.widthPercent < 100)) ? translate(content.buttonTitle) : ""}
>
{translate(content.buttonText)}
</button>
{inputSettings &&
<input id={id + "_amount"} className="form-control" type="number"
aria-describedby={id + "amount_help"}
defaultValue={inputSettings?.defaultValue}
min={inputSettings?.min}
max={inputSettings?.max}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
// Enforce min / max values
let { value, min, max } = event.target;
const newValue = Math.max(Number(min), Math.min(Number(max), Number(value)));
// Share the value so other logic can update based on it
inputSettings?.setInputValue(newValue)
}
} />}
{inputSettings && <div className="input-group-append">
<span className="input-group-text" id={id + "_help"}>
{translate(content.units)}
</span>
</div>
}
{/* Used for Escrow */}
{checkBox && <span className="input-group-text">
(
<input type="checkbox"
id={id + "_checkbox"}
defaultValue={checkBox.defaultValue ? 1 : 0}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => checkBox.setCheckValue(event.target.checked)} />
<label className="form-check-label" htmlFor={id + "_checkbox"}>
{translate(checkBox.description)}
</label>)
</span>}
</div>
<small className="form-text text-muted">
{content.longerDescription}
</small>
</div>
<hr />
</div>)
}