Skip to content

Commit

Permalink
Delete inputs and outputs from tx creation. UI fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
diegogurpegui committed May 23, 2020
1 parent b0b536a commit 4b77c9b
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 35 deletions.
54 changes: 54 additions & 0 deletions src/web/components/ButtonExpandable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

const ButtonExpandable = ({ icon, text, id, btnClass, className, onClick, align, type, size, ...otherProps }) => {
let iconElement = <></>;
if (typeof icon === 'string') {
iconElement = <FontAwesomeIcon icon={icon} className="fa-fw mx-1" />;
} else {
iconElement = icon;
}

return (
<button
type={type}
className={`btn btn-expandable btn-${btnClass} ${size !== null ? `btn-${size}` : ''} btn-expandable-${align} ${className}`}
id={id}
onClick={onClick}
{...otherProps}>
{align === 'right' ? (
<>
{iconElement}
<span>{text}</span>
</>
) : (
<>
<span>{text}</span>
{iconElement}
</>
)}
</button>
);
};

ButtonExpandable.propTypes = {
id: PropTypes.string,
text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
align: PropTypes.oneOf(['left', 'center', 'right']),
type: PropTypes.oneOf(['button', 'submit', 'reset']),
btnClass: PropTypes.oneOf(['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark', 'link']).isRequired,
size: PropTypes.oneOf(['sm', 'lg']),
onClick: PropTypes.func.isRequired,
};

ButtonExpandable.defaultProps = {
id: null,
align: 'left',
type: 'button',
size: null,
text: null,
};

export default ButtonExpandable;
1 change: 1 addition & 0 deletions src/web/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { default as AddressInputField } from './AddressInputField';
export { default as B58Input } from './B58Input';
export { default as B58InputField } from './B58InputField';
export { default as Button } from './Button';
export { default as ButtonExpandable } from './ButtonExpandable';
export { default as ButtonRadio } from './ButtonRadio';
export { default as HexInput } from './HexInput';
export { default as HexInputField } from './HexInputField';
Expand Down
35 changes: 32 additions & 3 deletions src/web/scss/main.scss
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
@import "variables";
@import "~bootstrap/scss/bootstrap";
@import 'variables';
@import '~bootstrap/scss/bootstrap';

.footer {
background-color: #f5f5f5;
}

.text-console {
font-family: "Courier New", Courier, monospace;
font-family: 'Courier New', Courier, monospace;
}

.list-dnd {
Expand All @@ -27,3 +27,32 @@
max-height: 13rem;
}
}

.btn-expandable {
width: 3em;
white-space: nowrap;
overflow-x: hidden;
transition: width 0.2s ease-out;
text-align: center;
span {
display: none;
white-space: nowrap;
}
&.btn-expandable-right {
text-align: right;
direction: rtl;
}

&:hover {
width: 7em;
span {
display: inline;
}
&.btn-expandable-right {
text-align: right;
span {
text-align: right;
}
}
}
}
95 changes: 84 additions & 11 deletions src/web/tx/CreateTxScreen.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

import txService from '../../service/tx';

import Button from '../components/Button';
import { Button, ButtonExpandable } from '../components';
import TxInputForm from './TxInputForm';
import TxOutputForm from './TxOutputForm';
import { TxInput, TxOutput } from '../../model';
Expand All @@ -18,17 +18,21 @@ class CreateTxScreen extends Component {
outputs: [],
tx: null,
errorMessage: '',
outputsOpReturn: 0,
};

txService.setTestnet(true);

this.onNetworkChange = this.onNetworkChange.bind(this);

this.onAddInput = this.onAddInput.bind(this);
this.onUpdateInput = this.onUpdateInput.bind(this);
this.onRemoveInput = this.onRemoveInput.bind(this);

this.onAddOutput = this.onAddOutput.bind(this);
this.onAddOpReturn = this.onAddOpReturn.bind(this);
this.onUpdateOutput = this.onUpdateOutput.bind(this);
this.onRemoveOutput = this.onRemoveOutput.bind(this);

this.submit = this.submit.bind(this);
}

Expand All @@ -42,14 +46,18 @@ class CreateTxScreen extends Component {
});
}

//#region Inputs

onAddInput(event) {
const { inputs } = this.state;
// get the last index used
let lastIndex = 0;
if (inputs.length > 0) {
lastIndex = inputs.reduce((acc, currentValue) => (currentValue >= acc.index ? currentValue : acc.index), inputs[0]);
lastIndex = Math.max.apply(
Math,
inputs.map((input) => input.index),
);
}

const txInput = new TxInput({ index: lastIndex + 1 });
inputs.push(txInput);

Expand All @@ -70,12 +78,44 @@ class CreateTxScreen extends Component {
});
}

onRemoveInput(inputIndex) {
const { inputs } = this.state;

const arrayIndex = inputIndex - 1;
// remove the input at position index
inputs.splice(arrayIndex, 1);

// update in two parts to prevent React mixing and confusing the indexes (used for listing)
this.setState(
{
inputs,
},
() => {
// now update index for following indexes
for (let i = arrayIndex; i < inputs.length; i++) {
inputs[i].index = inputs[i].index - 1;
}

this.setState({
inputs,
});
},
);
}

//#endregion Inputs

//#region Outputs

onAddOutput() {
const { outputs } = this.state;
// get the last index used
let lastIndex = 0;
if (outputs.length > 0) {
lastIndex = outputs.reduce((acc, currentValue) => (currentValue >= acc.index ? currentValue : acc.index), outputs[0]);
lastIndex = Math.max.apply(
Math,
outputs.map((output) => output.index),
);
}

const txOutput = new TxOutput(Constants.TXOUTPUT_STANDARD, lastIndex + 1);
Expand All @@ -87,20 +127,22 @@ class CreateTxScreen extends Component {
}

onAddOpReturn() {
const { outputs, outputsOpReturn } = this.state;
const { outputs } = this.state;

// get the last index used
let lastIndex = 0;
if (outputs.length > 0) {
lastIndex = outputs.reduce((acc, currentValue) => (currentValue >= acc.index ? currentValue : acc.index), outputs[0]);
lastIndex = Math.max.apply(
Math,
outputs.map((output) => output.index),
);
}

const txOutput = new TxOutput(Constants.TXOUTPUT_OPRETURN, lastIndex + 1);
outputs.push(txOutput);

this.setState({
outputs,
outputsOpReturn: outputsOpReturn + 1,
});
}

Expand All @@ -116,6 +158,33 @@ class CreateTxScreen extends Component {
});
}

onRemoveOutput(outputIndex) {
const { outputs } = this.state;

const arrayIndex = outputIndex - 1;
// remove the output at position index
outputs.splice(arrayIndex, 1);

// update in two parts to prevent React mixing and confusing the indexes (used for listing)
this.setState(
{
outputs,
},
() => {
// now update index for following indexes
for (let i = arrayIndex; i < outputs.length; i++) {
outputs[i].index = outputs[i].index - 1;
}

this.setState({
outputs,
});
},
);
}

//#endregion Outputs

submit() {
const { inputs, outputs } = this.state;

Expand All @@ -134,7 +203,8 @@ class CreateTxScreen extends Component {
}

render() {
const { isTestnet, inputs, outputs, tx, errorMessage, outputsOpReturn } = this.state;
const { isTestnet, inputs, outputs, tx, errorMessage } = this.state;

// calculate the estimated fee
let estimatedFee = 0;
inputs.forEach((input) => {
Expand All @@ -144,6 +214,9 @@ class CreateTxScreen extends Component {
estimatedFee -= output.amount;
});

// calculate how many opreturns are
const outputsOpReturn = outputs.filter((output) => output.type === Constants.TXOUTPUT_OPRETURN).length;

return (
<div>
<h1>Create Transaction</h1>
Expand Down Expand Up @@ -196,7 +269,7 @@ class CreateTxScreen extends Component {
Inputs
</h2>
{inputs.map((input) => (
<TxInputForm key={input.index} item={input} onUpdate={this.onUpdateInput} />
<TxInputForm key={input.index} item={input} onUpdate={this.onUpdateInput} onRemove={this.onRemoveInput} />
))}
</div>
<div className="col-sm-auto d-flex align-items-center">
Expand All @@ -217,7 +290,7 @@ class CreateTxScreen extends Component {
Outputs
</h2>
{outputs.map((output) => (
<TxOutputForm key={output.index} item={output} onUpdate={this.onUpdateOutput} />
<TxOutputForm key={output.index} item={output} onUpdate={this.onUpdateOutput} onRemove={this.onRemoveOutput} />
))}
<div className="card bg-light mb-1">
<div className="card-body">
Expand Down
Loading

0 comments on commit 4b77c9b

Please sign in to comment.