mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-21 04:05:49 +00:00
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
157 lines
6.4 KiB
TypeScript
157 lines
6.4 KiB
TypeScript
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' : ''}}>
|
|
|
|
</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>)
|
|
}
|