<commit_before>import React from "react";
import FormattedAsset from "../Utility/FormattedAsset";
import {Link, PropTypes} from "react-router";
import classNames from "classnames";
import Translate from "react-translate-component";
import counterpart from "counterpart";
import {operations} from "chain/chain_types";
import market_utils from "common/market_utils";
import utils from "common/utils";
import BlockTime from "./BlockTime";
import Aes from "ecc/aes";
import PublicKey from "ecc/key_public";
import PrivateKeyStore from "stores/PrivateKeyStore";
import WalletDb from "stores/WalletDb";
import LinkToAccountById from "../Blockchain/LinkToAccountById";
import LinkToAssetById from "../Blockchain/LinkToAssetById";
import BindToChainState from "../Utility/BindToChainState";
import FormattedPrice from "../Utility/FormattedPrice";
import ChainTypes from "../Utility/ChainTypes";
import ChainStore from "api/ChainStore";
import account_constants from "chain/account_constants";

require("./operations.scss");

let ops = Object.keys(operations);
let listings = account_constants.account_listing;

class TransactionLabel extends React.Component {
    shouldComponentUpdate(nextProps) {
        return (
            nextProps.color !== this.props.color ||
            nextProps.type !== this.props.type
        );
    }
    render() {
        let trxTypes = counterpart.translate("transaction.trxTypes");
        let labelClass = classNames("label", this.props.color || "info");
        return (
            <span className={labelClass}>
                {trxTypes[ops[this.props.type]]}
            </span>
        );
    }
}

@BindToChainState({keep_updating:true})
class Row extends React.Component {
    static contextTypes = {
        history: PropTypes.history
    }

    static propTypes = {
        dynGlobalObject: ChainTypes.ChainObject.isRequired,
    }

    static defaultProps = {
        dynGlobalObject: "2.1.0"
    }

    constructor(props) {
        super(props);
        this.showDetails = this.showDetails.bind(this);
    }

    showDetails(e) {
        e.preventDefault();
        this.context.history.pushState(null, `/block/${this.props.block}`);
    }

    render() {
        let {block, fee, color, type, key, hideDate, hideFee, hideOpLabel} = this.props;

        let last_irreversible_block_num = this.props.dynGlobalObject.get("last_irreversible_block_num" );
        let pending = null;
        if( block > last_irreversible_block_num )
           pending = <span>(<Translate content="operation.pending" blocks={block - last_irreversible_block_num} />)</span>

        fee.amount = parseInt(fee.amount, 10);
        return (
                <tr key={key}>
                    {hideOpLabel ? null : <td className="left-td"><a href onClick={this.showDetails}><TransactionLabel color={color} type={type} /></a></td>}
                    <td>{this.props.info}&nbsp;{pending}&nbsp;{hideFee ? null : <span className="facolor-fee">(<FormattedAsset amount={fee.amount} asset={fee.asset_id} /> fee)</span>}</td>
                    <td className="cursor-pointer" onClick={this.showDetails}><BlockTime block_number={block}/></td>
                </tr>
            );
    }
}

class Operation extends React.Component {

    static defaultProps = {
        op: [],
        current: "",
        block: false,
        hideDate: false,
        hideFee: false,
        hideOpLabel: false,
        csvExportMode: false
    }

    static propTypes = {
        op: React.PropTypes.array.isRequired,
        current: React.PropTypes.string,
        block: React.PropTypes.number,
        hideDate: React.PropTypes.bool,
        hideFee: React.PropTypes.bool,
        csvExportMode: React.PropTypes.bool
    }

    // shouldComponentUpdate(nextProps) {
    //     return utils.are_equal_shallow(nextProps.op, this.props.op);
    // }

    linkToAccount(name_or_id) {
        if(!name_or_id) return <span>-</span>;
        return utils.is_object_id(name_or_id) ?
            <LinkToAccountById account={name_or_id}/> :
            <Link to={`/account/${name_or_id}/overview`}>{name_or_id}</Link>;
    }

    linkToAsset(symbol_or_id) {
        if(!symbol_or_id) return <span>-</span>;
        return utils.is_object_id(symbol_or_id) ?
            <LinkToAssetById asset={symbol_or_id}/> :
            <Link to={`/asset/${symbol_or_id}`}>{symbol_or_id}</Link>;
    }

    render() {
        let {op, current, block} = this.props;
        let line = null, column = null, color = "info";

        switch (ops[op[0]]) { // For a list of trx types, see chain_types.coffee

            case "transfer":
                let memo_text = null;

                if(op[1].memo) {
                    let memo = op[1].memo;
                    let from_private_key = PrivateKeyStore.getState().keys.get(memo.from)
                    let to_private_key = PrivateKeyStore.getState().keys.get(memo.to)
                    let private_key = from_private_key ? from_private_key : to_private_key;
                    let public_key = from_private_key ? memo.to : memo.from;
                    public_key = PublicKey.fromPublicKeyString(public_key)

                    try {
                        private_key = WalletDb.decryptTcomb_PrivateKey(private_key);
                    }
                    catch(e) {
                        private_key = null;
                    }
                    try {
                        memo_text = private_key ? Aes.decrypt_with_checksum(
                            private_key,
                            public_key,
                            memo.nonce,
                            memo.message
                        ).toString() : null;
                    } catch(e) {
                        console.log("transfer memo exception ...", e);
                        memo_text = "*";
                    }
                }

                color = "success";
                op[1].amount.amount = parseFloat(op[1].amount.amount);

                if (memo_text && memo_text.length > 35) {
                    memo_text = memo_text.substr(0, 35) + "...";
                }

                // if (current === op[1].from) {

                //     column = (
                //         <span>
                //             <Translate component="span" content="transaction.sent" />
                //             &nbsp;<FormattedAsset style={{fontWeight: "bold"}} amount={op[1].amount.amount} asset={op[1].amount.asset_id} />
                //             &nbsp;<Translate component="span" content="transaction.to" /> {this.linkToAccount(op[1].to)}
                //             {memo_text ? <div className="memo">{memo_text}</div> : null}
                //         </span>
                //     );
                // } else if(current === op[1].to){
                //     column = (
                //         <span key={"transfer_" + this.props.key} className="right-td">
                //             <Translate component="span" content="transaction.received"/>
                //             &nbsp;<FormattedAsset style={{fontWeight: "bold"}} amount={op[1].amount.amount} asset={op[1].amount.asset_id}/>
                //             &nbsp;<Translate component="span" content="transaction.from"/> {this.linkToAccount(op[1].from)}
                //             {memo_text ? <div className="memo">{memo_text}</div> : null}
                //         </span>
                //     );
                // } else {
                    column = (
                        <span key={"transfer_" + this.props.key} className="right-td">
                            {this.linkToAccount(op[1].from)}
                            &nbsp;<Translate component="span" content="transaction.sent"/>
                            &nbsp;<FormattedAsset style={{fontWeight: "bold"}} amount={op[1].amount.amount} asset={op[1].amount.asset_id}/>
                            &nbsp;<Translate component="span" content="transaction.to"/> {this.linkToAccount(op[1].to)}
                            {memo_text ? <div className="memo">{memo_text}</div> : null}
                        </span>
                    );
                // }

                break;

            case "limit_order_create":
                color = "warning";
                let o = op[1];
                let isAsk = market_utils.isAskOp(op[1]);
                // if (!inverted) {
                //     isAsk = !isAsk;
                // }
                column = (
                        <span>
                        <BindToChainState.Wrapper asset_sell={op[1].amount_to_sell.asset_id} asset_min={op[1].min_to_receive.asset_id}>
                            { ({asset_sell, asset_min}) =>
                                isAsk ?
                                    <span>
                                        {this.linkToAccount(op[1].seller)}&nbsp;
                                        <Translate
                                            component="span"
                                            content="transaction.limit_order_sell"
                                            sell_amount={utils.format_asset(op[1].amount_to_sell.amount, asset_sell, false, false)}<commit_msg>Add tooltip showing full memo fix #636<commit_after>import React from "react";
import FormattedAsset from "../Utility/FormattedAsset";
import {Link, PropTypes} from "react-router";
import classNames from "classnames";
import Translate from "react-translate-component";
import counterpart from "counterpart";
import {operations} from "chain/chain_types";
import market_utils from "common/market_utils";
import utils from "common/utils";
import BlockTime from "./BlockTime";
import Aes from "ecc/aes";
import PublicKey from "ecc/key_public";
import PrivateKeyStore from "stores/PrivateKeyStore";
import WalletDb from "stores/WalletDb";
import LinkToAccountById from "../Blockchain/LinkToAccountById";
import LinkToAssetById from "../Blockchain/LinkToAssetById";
import BindToChainState from "../Utility/BindToChainState";
import FormattedPrice from "../Utility/FormattedPrice";
import ChainTypes from "../Utility/ChainTypes";
import ChainStore from "api/ChainStore";
import account_constants from "chain/account_constants";

require("./operations.scss");

let ops = Object.keys(operations);
let listings = account_constants.account_listing;

class TransactionLabel extends React.Component {
    shouldComponentUpdate(nextProps) {
        return (
            nextProps.color !== this.props.color ||
            nextProps.type !== this.props.type
        );
    }
    render() {
        let trxTypes = counterpart.translate("transaction.trxTypes");
        let labelClass = classNames("label", this.props.color || "info");
        return (
            <span className={labelClass}>
                {trxTypes[ops[this.props.type]]}
            </span>
        );
    }
}

@BindToChainState({keep_updating:true})
class Row extends React.Component {
    static contextTypes = {
        history: PropTypes.history
    }

    static propTypes = {
        dynGlobalObject: ChainTypes.ChainObject.isRequired,
    }

    static defaultProps = {
        dynGlobalObject: "2.1.0"
    }

    constructor(props) {
        super(props);
        this.showDetails = this.showDetails.bind(this);
    }

    showDetails(e) {
        e.preventDefault();
        this.context.history.pushState(null, `/block/${this.props.block}`);
    }

    render() {
        let {block, fee, color, type, key, hideDate, hideFee, hideOpLabel} = this.props;

        let last_irreversible_block_num = this.props.dynGlobalObject.get("last_irreversible_block_num" );
        let pending = null;
        if( block > last_irreversible_block_num )
           pending = <span>(<Translate content="operation.pending" blocks={block - last_irreversible_block_num} />)</span>

        fee.amount = parseInt(fee.amount, 10);
        return (
                <tr key={key}>
                    {hideOpLabel ? null : <td className="left-td"><a href onClick={this.showDetails}><TransactionLabel color={color} type={type} /></a></td>}
                    <td>{this.props.info}&nbsp;{pending}&nbsp;{hideFee ? null : <span className="facolor-fee">(<FormattedAsset amount={fee.amount} asset={fee.asset_id} /> fee)</span>}</td>
                    <td className="cursor-pointer" onClick={this.showDetails}><BlockTime block_number={block}/></td>
                </tr>
            );
    }
}

class Operation extends React.Component {

    static defaultProps = {
        op: [],
        current: "",
        block: false,
        hideDate: false,
        hideFee: false,
        hideOpLabel: false,
        csvExportMode: false
    }

    static propTypes = {
        op: React.PropTypes.array.isRequired,
        current: React.PropTypes.string,
        block: React.PropTypes.number,
        hideDate: React.PropTypes.bool,
        hideFee: React.PropTypes.bool,
        csvExportMode: React.PropTypes.bool
    }

    // shouldComponentUpdate(nextProps) {
    //     return utils.are_equal_shallow(nextProps.op, this.props.op);
    // }

    linkToAccount(name_or_id) {
        if(!name_or_id) return <span>-</span>;
        return utils.is_object_id(name_or_id) ?
            <LinkToAccountById account={name_or_id}/> :
            <Link to={`/account/${name_or_id}/overview`}>{name_or_id}</Link>;
    }

    linkToAsset(symbol_or_id) {
        if(!symbol_or_id) return <span>-</span>;
        return utils.is_object_id(symbol_or_id) ?
            <LinkToAssetById asset={symbol_or_id}/> :
            <Link to={`/asset/${symbol_or_id}`}>{symbol_or_id}</Link>;
    }

    render() {
        let {op, current, block} = this.props;
        let line = null, column = null, color = "info";

        switch (ops[op[0]]) { // For a list of trx types, see chain_types.coffee

            case "transfer":
                let memo_text = null;

                if(op[1].memo) {
                    let memo = op[1].memo;
                    let from_private_key = PrivateKeyStore.getState().keys.get(memo.from)
                    let to_private_key = PrivateKeyStore.getState().keys.get(memo.to)
                    let private_key = from_private_key ? from_private_key : to_private_key;
                    let public_key = from_private_key ? memo.to : memo.from;
                    public_key = PublicKey.fromPublicKeyString(public_key)

                    try {
                        private_key = WalletDb.decryptTcomb_PrivateKey(private_key);
                    }
                    catch(e) {
                        private_key = null;
                    }
                    try {
                        memo_text = private_key ? Aes.decrypt_with_checksum(
                            private_key,
                            public_key,
                            memo.nonce,
                            memo.message
                        ).toString() : null;
                    } catch(e) {
                        console.log("transfer memo exception ...", e);
                        memo_text = "*";
                    }
                }

                color = "success";
                op[1].amount.amount = parseFloat(op[1].amount.amount);
                let full_memo = memo_text;
                if (memo_text && memo_text.length > 35) {

                    memo_text = memo_text.substr(0, 35) + "...";
                }

                // if (current === op[1].from) {

                //     column = (
                //         <span>
                //             <Translate component="span" content="transaction.sent" />
                //             &nbsp;<FormattedAsset style={{fontWeight: "bold"}} amount={op[1].amount.amount} asset={op[1].amount.asset_id} />
                //             &nbsp;<Translate component="span" content="transaction.to" /> {this.linkToAccount(op[1].to)}
                //             {memo_text ? <div className="memo">{memo_text}</div> : null}
                //         </span>
                //     );
                // } else if(current === op[1].to){
                //     column = (
                //         <span key={"transfer_" + this.props.key} className="right-td">
                //             <Translate component="span" content="transaction.received"/>
                //             &nbsp;<FormattedAsset style={{fontWeight: "bold"}} amount={op[1].amount.amount} asset={op[1].amount.asset_id}/>
                //             &nbsp;<Translate component="span" content="transaction.from"/> {this.linkToAccount(op[1].from)}
                //             {memo_text ? <div className="memo">{memo_text}</div> : null}
                //         </span>
                //     );
                // } else {
                    column = (
                        <span key={"transfer_" + this.props.key} className="right-td">
                            {this.linkToAccount(op[1].from)}
                            &nbsp;<Translate component="span" content="transaction.sent"/>
                            &nbsp;<FormattedAsset style={{fontWeight: "bold"}} amount={op[1].amount.amount} asset={op[1].amount.asset_id}/>
                            &nbsp;<Translate component="span" content="transaction.to"/> {this.linkToAccount(op[1].to)}
                            {memo_text ? <div className="memo"><span data-tip={full_memo} data-place="bottom" data-offset="{'bottom': 10}" data-type="light" data-html>{memo_text}</span></div> : null}
                        </span>
                    );
                // }

                break;

            case "limit_order_create":
                color = "warning";
                let o = op[1];
                let isAsk = market_utils.isAskOp(op[1]);
                // if (!inverted) {
                //     isAsk = !isAsk;
                // }
                column = (
                        <span>
                        <BindToChainState.Wrapper asset_sell={op[1].amount_to_sell.asset_id} asset_min={op[1].min_to_receive.asset_id}>
                            { ({asset_sell, asset_min}) =>
                                isAsk ?
                                    <span>
                                        {this.linkToAccount(op[1].seller)}&nbsp;
                                        <Translate
                                            component="span"
                                            content="transaction.limit_order_sell"
                                            sell_amount={utils.format_asset(op[1].amount_to_sell.amount, asset_sell, false, false)}
{'fraction_non_alphanumeric': 0.12728153771603942, 'fraction_numerical': 0.0038227534593226727, 'mean_word_length': 1.689934829833454, 'pattern_counts': {'":': 4, '<': 115, '<?xml version=': 0, '>': 119, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3510245', 'n_tokens_mistral': 5208, 'n_tokens_neox': 4984, 'n_words': 886}