Skip to content

Commit

Permalink
wip: expand basic output spend and receive addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
begonaalvarezd committed Jan 29, 2024
1 parent 44fa7d8 commit ece7681
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 50 deletions.
10 changes: 8 additions & 2 deletions client/src/app/components/stardust/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import DropdownIcon from "~assets/dropdown-arrow.svg?react";
import { formatAmount } from "~helpers/stardust/valueFormatHelper";
import { IInput } from "~models/api/stardust/IInput";
import NetworkContext from "../../context/NetworkContext";
import { IPreExpandedConfig } from "./interfaces";

interface InputProps {
/**
Expand All @@ -20,15 +21,19 @@ interface InputProps {
* The network in context.
*/
readonly network: string;
/**
* Should the input be pre-expanded.
*/
readonly preExpandedConfig?: IPreExpandedConfig;
}

/**
* Component which will display an Input on stardust.
*/
const Input: React.FC<InputProps> = ({ input, network }) => {
const Input: React.FC<InputProps> = ({ input, network, preExpandedConfig }) => {
const history = useHistory();
const { tokenInfo } = useContext(NetworkContext);
const [isExpanded, setIsExpanded] = useState(false);
const [isExpanded, setIsExpanded] = useState(preExpandedConfig?.isPreExpanded ?? false);
const [isFormattedBalance, setIsFormattedBalance] = useState(true);

const fallbackInputView = (
Expand Down Expand Up @@ -89,6 +94,7 @@ const Input: React.FC<InputProps> = ({ input, network }) => {
amount={Number(input.output.output.amount)}
network={network}
showCopyAmount={true}
preExpandedConfig={preExpandedConfig}
/>
) : (
fallbackInputView
Expand Down
64 changes: 37 additions & 27 deletions client/src/app/components/stardust/Output.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class Output extends Component<OutputProps, OutputState> {
super(props);

this.state = {
isExpanded: this.props.isPreExpanded ?? false,
isExpanded: this.props.preExpandedConfig?.isPreExpanded ?? false,
isFormattedBalance: true,
};
}
Expand All @@ -71,7 +71,7 @@ class Output extends Component<OutputProps, OutputState> {
* @returns The node to render.
*/
public render(): ReactNode {
const { outputId, output, amount, showCopyAmount, network, isPreExpanded, displayFullOutputId, isLinksDisabled } = this.props;
const { outputId, output, amount, showCopyAmount, network, preExpandedConfig, displayFullOutputId, isLinksDisabled } = this.props;
const { isExpanded, isFormattedBalance } = this.state;
const tokenInfo: INodeInfoBaseToken = this.context.tokenInfo;

Expand Down Expand Up @@ -223,33 +223,43 @@ class Output extends Component<OutputProps, OutputState> {
{/* all output types except Treasury have common output conditions */}
{output.type !== OutputType.Treasury && (
<React.Fragment>
{(output as CommonOutput).unlockConditions.map((unlockCondition, idx) => (
<UnlockCondition key={idx} unlockCondition={unlockCondition} isPreExpanded={isPreExpanded} />
))}
{(output as CommonOutput).features?.map((feature, idx) => (
<Feature
key={idx}
feature={feature}
isPreExpanded={isPreExpanded}
isImmutable={false}
isParticipationEventMetadata={isParticipationOutput}
/>
))}
{output.type === OutputType.Alias &&
(output as AliasOutput).immutableFeatures?.map((immutableFeature, idx) => (
<Feature key={idx} feature={immutableFeature} isPreExpanded={isPreExpanded} isImmutable={true} />
))}
{(output as CommonOutput).unlockConditions.map((unlockCondition, idx) => {
const isPreExpanded = preExpandedConfig?.unlockConditions?.[idx] ?? false;
return (
<UnlockCondition key={idx} unlockCondition={unlockCondition} isPreExpanded={isPreExpanded} />
)
})}
{(output as CommonOutput).features?.map((feature, idx) => {
const isPreExpanded = preExpandedConfig?.features?.[idx] ?? false;
return (
<Feature
key={idx}
feature={feature}
isImmutable={false}
isParticipationEventMetadata={isParticipationOutput}
isPreExpanded={isPreExpanded}
/>
)
})}
{(output.type === OutputType.Alias) &&
(output as AliasOutput).immutableFeatures?.map((immutableFeature, idx) => {
const isPreExpanded = preExpandedConfig?.immutableFeatures?.[idx] ?? false;
return (<Feature key={idx} feature={immutableFeature} isImmutable={true} isPreExpanded={isPreExpanded} />)
})}
{output.type === OutputType.Nft &&
(output as NftOutput).immutableFeatures?.map((immutableFeature, idx) => (
<Feature key={idx} feature={immutableFeature} isPreExpanded={isPreExpanded} isImmutable={true} />
))}
(output as NftOutput).immutableFeatures?.map((immutableFeature, idx) => {
const isPreExpanded = preExpandedConfig?.immutableFeatures?.[idx] ?? false;
return (<Feature key={idx} feature={immutableFeature} isImmutable={true} isPreExpanded={isPreExpanded} />)
})}
{output.type === OutputType.Foundry &&
(output as FoundryOutput).immutableFeatures?.map((immutableFeature, idx) => (
<Feature key={idx} feature={immutableFeature} isPreExpanded={isPreExpanded} isImmutable={true} />
))}
{(output as CommonOutput).nativeTokens?.map((token, idx) => (
<NativeToken key={idx} tokenId={token.id} amount={Number(token.amount)} isPreExpanded={isPreExpanded} />
))}
(output as FoundryOutput).immutableFeatures?.map((immutableFeature, idx) => {
const isPreExpanded = preExpandedConfig?.immutableFeatures?.[idx] ?? false;
return (<Feature key={idx} feature={immutableFeature} isImmutable={true} isPreExpanded={isPreExpanded} />)
})}
{(output as CommonOutput).nativeTokens?.map((token, idx) => {
const isPreExpanded = preExpandedConfig?.nativeTokens?.[idx] ?? false;
return (<NativeToken key={idx} tokenId={token.id} amount={Number(token.amount)} isPreExpanded={isPreExpanded} />)
})}
</React.Fragment>
)}
</div>
Expand Down
11 changes: 6 additions & 5 deletions client/src/app/components/stardust/OutputProps.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Output } from "@iota/sdk-wasm/web";
import { IPreExpandedConfig } from "./interfaces";

export interface OutputProps {
/**
Expand All @@ -21,11 +22,6 @@ export interface OutputProps {
*/
showCopyAmount: boolean;

/**
* Should the output be pre-expanded.
*/
isPreExpanded?: boolean;

/**
* Should the outputId be displayed in full (default truncated).
*/
Expand All @@ -40,4 +36,9 @@ export interface OutputProps {
* Disable links if block is conflicting.
*/
isLinksDisabled?: boolean;

/**
* Should the output and its fields be pre-expanded.
*/
preExpandedConfig?: IPreExpandedConfig;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import Input from "../../Input";
import Output from "../../Output";
import Unlocks from "../../Unlocks";
import "./TransactionPayload.scss";
import { AddressUnlockCondition, CommonOutput, ExpirationUnlockCondition, OutputType, UnlockConditionType } from "@iota/sdk-wasm/web";
import { IPreExpandedConfig } from "../../interfaces";

/**
* Component which will display a transaction payload.
Expand Down Expand Up @@ -48,7 +50,8 @@ class TransactionPayload extends AsyncComponent<TransactionPayloadProps, Transac
* @returns The node to render.
*/
public render(): ReactNode {
const { network, inputs, unlocks, outputs, header, isLinksDisabled } = this.props;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { network, inputs, unlocks, outputs, header, isLinksDisabled, milestoneIndex } = this.props;

return (
<div className="transaction-payload">
Expand All @@ -68,9 +71,21 @@ class TransactionPayload extends AsyncComponent<TransactionPayloadProps, Transac
<span>{inputs.length}</span>
</div>
<div className="transaction-payload_outputs card--content">
{inputs.map((input, idx) => (
<Input key={idx} network={network} input={input} />
))}
{inputs.map((input, idx) => {
let preExpandedConfig: IPreExpandedConfig = {
isPreExpanded: input?.output?.output?.type === OutputType.Basic,
};
if (input?.output?.output && 'unlockConditions' in input.output.output) {
const commmonOutput = input.output.output as unknown as CommonOutput;
preExpandedConfig = {
...preExpandedConfig,
unlockConditions: commmonOutput.unlockConditions?.map(
(unlockCondition) => unlockCondition.type === UnlockConditionType.Address)
};

}
return (<Input key={idx} network={network} input={input} preExpandedConfig={preExpandedConfig} />)
})}
<Unlocks unlocks={unlocks} />
</div>
</div>
Expand All @@ -82,17 +97,40 @@ class TransactionPayload extends AsyncComponent<TransactionPayloadProps, Transac
<span>{outputs.length}</span>
</div>
<div className="transaction-payload_outputs card--content">
{outputs.map((output, idx) => (
<Output
key={idx}
outputId={output.id}
output={output.output}
amount={output.amount}
network={network}
showCopyAmount={true}
isLinksDisabled={isLinksDisabled}
/>
))}
{outputs.map((output, idx) => {
let preExpandedConfig: IPreExpandedConfig = {
isPreExpanded: output?.output?.type === OutputType.Basic,
};
if ('unlockConditions' in output.output) {
const commmonOutput = output.output as CommonOutput;
const expirationUnlockCondition: ExpirationUnlockCondition | undefined = (commmonOutput.unlockConditions?.find(unlockCondition => unlockCondition.type === UnlockConditionType.Expiration) as ExpirationUnlockCondition);
const addressUnlockCondition: AddressUnlockCondition | undefined = (commmonOutput.unlockConditions?.find(unlockCondition => unlockCondition.type === UnlockConditionType.Address) as AddressUnlockCondition);

const spentByAddress = addressUnlockCondition?.address
if (expirationUnlockCondition) {
// todo: check if the output was spent within the expiration time or not
}

preExpandedConfig = {
...preExpandedConfig,
unlockConditions: commmonOutput.unlockConditions?.map(
(unlockCondition) => 'address' in unlockCondition && unlockCondition.address === spentByAddress)
};

}
return (
<Output
key={idx}
outputId={output.id}
output={output.output}
amount={output.amount}
network={network}
showCopyAmount={true}
isLinksDisabled={isLinksDisabled}
preExpandedConfig={preExpandedConfig}
/>
)
})}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ export interface TransactionPayloadProps {
* Disable links if block is conflicting.
*/
isLinksDisabled?: boolean;

/**
* Milestone index.
*/
milestoneIndex?: number;
}
7 changes: 7 additions & 0 deletions client/src/app/components/stardust/interfaces/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface IPreExpandedConfig {
isPreExpanded?: boolean;
unlockConditions?: boolean[];
features?: boolean[];
immutableFeatures?: boolean[];
nativeTokens?: boolean[];
}
2 changes: 1 addition & 1 deletion client/src/app/routes/stardust/TransactionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ const TransactionPage: React.FC<RouteComponentProps<TransactionPageProps>> = ({
>
{inputs && unlocks && outputs ? (
<div className="section">
<TransactionPayload network={network} inputs={inputs} unlocks={unlocks} outputs={outputs} />
<TransactionPayload network={network} inputs={inputs} unlocks={unlocks} outputs={outputs} milestoneIndex={metadata?.referencedByMilestoneIndex} />
</div>
) : (
<></>
Expand Down
10 changes: 10 additions & 0 deletions client/src/helpers/dateHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ export class DateHelper {
return moment(valueInMs).format("YYYY-MM-DD HH:mm:ss");
}

/**
* Check if the date is expired.
* @param value The value to check in milliseconds.
* @param compareWith
* @returns Boolean if the date is expired.
*/
public static isExpired(value: number, compareWith: number = Date.now()): boolean {
return moment(moment(compareWith)).isAfter(value);
}

/**
* Check the value is in ms if not scale accordingly.
* @param valueInMs The value to format in milliseconds.
Expand Down

0 comments on commit ece7681

Please sign in to comment.