lodash#orderBy JavaScript Examples

The following examples show how to use lodash#orderBy. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: helpers.js    From paigeniedringhaus.com with MIT License 6 votes vote down vote up
sortArrayByDate = (arr) => {
  const sortedArr = orderBy(
    arr,
    (item) => {
      return moment(item.date).format('YYYYMMDD');
    },
    ['desc'],
  );
  return sortedArr;
}
Example #2
Source File: index.js    From hzero-front with Apache License 2.0 6 votes vote down vote up
/**
   * 查询api调用总数
   */
  @Bind()
  queryApiInvokeCount(startTime, endTime) {
    const beginDate = startTime.format().split('T')[0];
    const endDate = endTime.format().split('T')[0];
    this.setState({ apiInvokeLoading: true });
    const params = {
      beginDate,
      endDate,
    };
    fetchApiInvokeCount(params).then((res) => {
      let obj = {};
      if (res && !res.failed) {
        const { details = [], entities = [] } = res;
        if (details.length && entities.length) {
          const handleDetails = details.map((item) => ({
            ...item,
            sortIndex: entities.indexOf(item.service),
          }));
          const finalDetails = orderBy(handleDetails, ['sortIndex'], ['asc']);
          res.details = finalDetails;
        }
        obj = res;
      }
      this.setState({
        apiInvokeData: obj,
        apiInvokeLoading: false,
      });
    });
    this.getApiInvokeChart();
  }
Example #3
Source File: ObjectListItemSources.js    From sampo-ui with MIT License 6 votes vote down vote up
ObjectListItemSources = props => {
  let { data, externalLink } = props
  data = Array.isArray(data) ? data : [data]
  data = orderBy(data, 'prefLabel')

  return (
    <sup>
      {data.map((source, index) =>
        <React.Fragment key={source.id}>
          <ObjectListItemLink
            externalLink={externalLink}
            data={source}
            label={source.prefLabel}
          />
          {!(data.length === index + 1) && <span>, </span>}
        </React.Fragment>
      )}
    </sup>
  )
}
Example #4
Source File: LeafletConfig.js    From sampo-ui with MIT License 6 votes vote down vote up
createInstanceListing = instances => {
  let root
  if (Array.isArray(instances)) {
    root = document.createElement('ul')
    instances = orderBy(instances, 'prefLabel')
    instances.forEach(i => {
      const li = document.createElement('li')
      const link = document.createElement('a')
      link.addEventListener('click', () => history.push(i.dataProviderUrl))
      link.textContent = i.prefLabel
      link.style.cssText = 'cursor: pointer; text-decoration: underline'
      li.appendChild(link)
      root.appendChild(li)
    })
  } else {
    root = document.createElement('p')
    const link = document.createElement('a')
    link.addEventListener('click', () => history.push(instances.dataProviderUrl))
    link.textContent = instances.prefLabel
    link.style.cssText = 'cursor: pointer; text-decoration: underline'
    root.appendChild(link)
  }
  return root
}
Example #5
Source File: country.js    From rakning-c19-app with MIT License 6 votes vote down vote up
getAll() {
    if (!this.countries) {
      this.countries = orderBy(
        this.countriesData || require('./resources/countries.json'),
        ['name'],
        ['asc'],
      );
    }

    return this.countries;
  }
Example #6
Source File: StatChart.js    From covid19 with MIT License 6 votes vote down vote up
StatChart = ({ data, dataKey, color }) => {
  const sortedData = orderBy(data, 'date.date')

  return (
    <ResponsiveContainer width="100%" height={128}>
      <LineChart data={sortedData}>
        <Tooltip
          separator=""
          formatter={(value) => [commaNumber(value)]}
          labelFormatter={() => ''}
        />
        <Line
          type="monotone"
          dataKey={dataKey}
          stroke={theme.colors[color]}
          strokeWidth={3}
          dot={false}
        />
      </LineChart>
    </ResponsiveContainer>
  )
}
Example #7
Source File: index.js    From gobench with Apache License 2.0 6 votes vote down vote up
getMetricDataPolling = async (metrics, oldData = []) => {
  return await Promise.all(metrics.map(mtr => {
    const oldMetricData = oldData.find(o => mtr.id === get(o, ['id'], ''))
    const timestamp = get(oldMetricData, 'lastTimestamp', '')
    return getMetricData(mtr.id, mtr.type, timestamp)
      .then(mData => {
        if (mData.length > 0) {
          const dataByType = getDataByType(mData, mtr.type)
          const oldMetricChartData = get(oldMetricData, ['chartData', 'data'], [])
          const newData = [...oldMetricChartData, ...dataByType]
          return {
            ...oldMetricData,
            lastTimestamp: get(orderBy(mData, ['time'], 'desc'), '[0].time'),
            chartData: {
              name: mtr.title,
              data: newData
            }
          }
        }
        return oldMetricData
      })
  }))
    .then(rs => rs)
    .catch(err => err)
}
Example #8
Source File: RelatedNews.js    From ecomloop.github.io with MIT License 5 votes vote down vote up
getRelatedNews = (currentNews, allNews) => {

    const maxPosts = 3;
    const currentCategories = (currentNews.extractedkeywords + "," + currentNews.keywords).split(",") || [];
    const currentTags = currentNews.tags.split(",") || [];

    // console.log("******** in related news")
    // console.log(allNews)
    // console.log(currentNews)
    // console.log(currentCategories)
    // console.log(currentTags)
    
    // Don't include the current post in posts list
    allNews = allNews.filter((post) => post.node.id !== currentNews.id);

    const identityMap = {};

    //Map over all posts, add to map and add points
    for (let post of allNews) {

        const id = post.node.id;
        if (!identityMap.hasOwnProperty(id)) {
            identityMap[id] = {
                news: post,
                points: 0
            }
        }

        // For category matches, we add 2 points
        const categoryPoints = 2;
        const categories = (post.node.extractedkeywords + "," + post.node.keywords).split(",") || [];
        categories.forEach((category) => {
            if (includes(...currentCategories, category)) {
                identityMap[id].points += categoryPoints;
            }
        })

        // For tags matches, we add 1 point
        const tagPoint = 1;
        const tags = post.node.tags.split(",") || [];
        tags.forEach((aTag) => {
            if (includes(currentTags, aTag)) {
                identityMap[id].points += tagPoint;
            }
        })

    }

    // Convert the identity map to an array
    const arrayIdentityMap = Object.keys(identityMap).map((id) => identityMap[id]);

    // Use a lodash utility function to sort them 
    // by points, from greatest to least
    const similarPosts = orderBy(
        arrayIdentityMap, ['points'], ['desc']
    )

    //console.log("***** relatedNews Output ",similarPosts.splice(0, maxPosts))
    // return the max number posts requested
    return similarPosts.splice(0, maxPosts);

}
Example #9
Source File: reducers.js    From chromeless with Mozilla Public License 2.0 5 votes vote down vote up
filteredSortedAppIds = (state = null, action) => {
  switch (action.type) {
    case INSTALLED_UPDATE_SORTED_APP_IDS: {
      return action.sortedAppIds;
    }
    case CLEAN_APP_MANAGEMENT: {
      // keep apps which are in installing/updating state
      if (!state) return null;
      const newLst = state.filter((id) => (action.apps[id].status === INSTALLING));
      return newLst;
    }
    case SET_APP: {
      if (!state) return null;

      // if the app is not supposed to be in search result
      // just return the current state
      const processedQuery = action.activeQuery.trim().toLowerCase();
      const currentApp = { ...action.apps[action.id], ...action.app };
      if (!(
        currentApp.name.toLowerCase().includes(processedQuery)
        || (currentApp.url && currentApp.url.toLowerCase().includes(processedQuery))
      )) {
        return state;
      }

      // if id is not in list, insert at sorted position
      if (state.indexOf(action.id) < 0) {
        const index = sortedIndexBy(state, action.id, (id) => {
          const app = id === action.id ? { ...action.apps[id], ...action.app } : action.apps[id];
          return iterateeFunc(app, action.sortInstalledAppBy);
        });
        state.splice(index, 0, action.id);
        return [...state];
      }
      // if sorting value is updated, remove and reinsert id at new index
      if (
        (action.sortInstalledAppBy === 'name' && action.app.name)
        || (action.sortInstalledAppBy === 'last-updated' && (action.app.lastUpdated))
      ) {
        const newState = without(state, action.id);
        const index = sortedIndexBy(newState, action.id, (id) => {
          const app = id === action.id ? { ...action.apps[id], ...action.app } : action.apps[id];
          return iterateeFunc(app, action.sortInstalledAppBy);
        });
        newState.splice(index, 0, action.id);
        return newState;
      }
      return state;
    }
    case REMOVE_APP: {
      if (!state) return null;
      return without(state, action.id);
    }
    case SORT_APPS: {
      if (!state) return null;
      // resort
      return orderBy(state, (id) => {
        const app = action.apps[id];
        return iterateeFunc(app, action.sortInstalledAppBy);
      });
    }
    default: return state;
  }
}
Example #10
Source File: reducers.js    From chromeless with Mozilla Public License 2.0 5 votes vote down vote up
sortedAppIds = (state = [], action) => {
  switch (action.type) {
    case CLEAN_APP_MANAGEMENT: {
      // keep apps which are in installing/updating state
      const newLst = state.filter((id) => (action.apps[id].status === INSTALLING));
      return newLst;
    }
    case SET_APP: {
      // if id is not in list, insert at sorted position
      if (state.indexOf(action.id) < 0) {
        const index = sortedIndexBy(state, action.id, (id) => {
          const app = id === action.id ? { ...action.apps[id], ...action.app } : action.apps[id];
          return iterateeFunc(app, action.sortInstalledAppBy);
        });
        state.splice(index, 0, action.id);
        return [...state];
      }
      // if sorting value is updated, remove and reinsert id at new index
      if (
        (action.sortInstalledAppBy === 'name' && action.app.name)
        || (action.sortInstalledAppBy === 'last-updated' && (action.app.lastUpdated))
      ) {
        const newState = without(state, action.id);
        const index = sortedIndexBy(newState, action.id, (id) => {
          const app = id === action.id ? { ...action.apps[id], ...action.app } : action.apps[id];
          return iterateeFunc(app, action.sortInstalledAppBy);
        });
        newState.splice(index, 0, action.id);
        return newState;
      }
      return state;
    }
    case REMOVE_APP: {
      return without(state, action.id);
    }
    case SORT_APPS: {
      // resort
      const parts = action.sortInstalledAppBy.split('/');
      const key = parts[0];
      const order = parts.length > 0 ? parts[1] : 'asc';
      return orderBy(state, (id) => {
        const app = action.apps[id];
        return iterateeFunc(app, key);
      }, [order]);
    }
    default: return state;
  }
}
Example #11
Source File: index.js    From hzero-front with Apache License 2.0 5 votes vote down vote up
render() {
    const {
      tenantInitLog: { logList, pagination, enumMap, picData },
      listLoading,
      picLoading = false,
    } = this.props;
    const { currentLog, isShowImg } = this.state;
    let imgData = {};
    if (!isEmpty(picData)) {
      imgData = groupBy(orderBy(picData, 'orderSeq'), 'processorType');
    }
    const filterProps = {
      onSearch: this.handleSearch,
      onRef: this.handleBindRef,
      enumMap,
    };
    const listProps = {
      isShowImg,
      dataSource: logList,
      pagination,
      picProps: {
        dataSource: imgData,
        loading: picLoading,
        type: !isEmpty(currentLog) && currentLog.initType.toLowerCase(),
      },
      loading: listLoading,
      onChange: this.handleSearch,
      onSearchPic: this.handleSearchPic,
      onOpenPic: this.handleOpenImgModal,
      onClosePic: this.handleCloseImgModal,
    };
    return (
      <>
        <Header title={intl.get(`${viewTitle}.tenant.init.log`).d('租户初始化处理日志')} />
        <Content>
          <FilterForm {...filterProps} />
          <ListTable {...listProps} />
        </Content>
      </>
    );
  }
Example #12
Source File: networkService.js    From web-wallet with Apache License 2.0 5 votes vote down vote up
async getBalances () {
    try {
      const _childchainBalances = await this.childChain.getBalance(this.account);
      const childchainBalances = await Promise.all(_childchainBalances.map(
        async i => {
          const token = await getToken(i.currency);
          return {
            ...token,
            amount: i.amount.toString()
          };
        }
      ));

      const rootErc20Balances = await Promise.all(childchainBalances.map(
        async i => {
          if (i.name !== 'ETH') {
            const balance = await OmgUtil.getErc20Balance({
              web3: this.web3,
              address: this.account,
              erc20Address: i.currency
            });
            return {
              ...i,
              amount: balance.toString()
            };
          }
        }
      ));

      const _rootEthBalance = await this.web3.eth.getBalance(this.account);
      const ethToken = await getToken(OmgUtil.transaction.ETH_CURRENCY);
      const rootchainEthBalance = {
        ...ethToken,
        amount: _rootEthBalance
      };

      return {
        rootchain: orderBy([ rootchainEthBalance, ...rootErc20Balances.filter(i => !!i) ], i => i.currency),
        childchain: orderBy(childchainBalances, i => i.currency)
      };
    } catch (error) {
      throw new WebWalletError({
        originalError: error,
        reportToSentry: false,
        reportToUi: false
      });
    }
  }
Example #13
Source File: Deposits.js    From web-wallet with Apache License 2.0 5 votes vote down vote up
function Deposits ({ searchHistory }) {
  const [ page, setPage ] = useState(1);

  const ethDeposits = useSelector(selectEthDeposits, isEqual);
  const erc20Deposits = useSelector(selectErc20Deposits, isEqual);
  const loading = useSelector(selectLoading([ 'DEPOSIT/GETALL' ]));

  useEffect(() => {
    setPage(1);
  }, [ searchHistory ]);

  const deposits = orderBy(
    [ ...ethDeposits, ...erc20Deposits ],
    i => i.blockNumber, 'desc'
  );
  const _deposits = deposits.filter(i => {
    return i.transactionHash.includes(searchHistory) || i.returnValues.token.includes(searchHistory);
  });

  const startingIndex = page === 1 ? 0 : ((page - 1) * PER_PAGE);
  const endingIndex = page * PER_PAGE;
  const paginatedDeposits = _deposits.slice(startingIndex, endingIndex);

  return (
    <div className={styles.transactionSection}>
      <div className={styles.transactions}>
        <Pager
          currentPage={page}
          isLastPage={paginatedDeposits.length < PER_PAGE}
          onClickNext={() => setPage(page + 1)}
          onClickBack={() => setPage(page - 1)}
        />
        {!paginatedDeposits.length && !loading && (
          <div className={styles.disclaimer}>No deposit history.</div>
        )}
        {!paginatedDeposits.length && loading && (
          <div className={styles.disclaimer}>Loading...</div>
        )}
        {paginatedDeposits.map((i, index) => {
          return (
            <Transaction
              key={index}
              link={`${config.etherscanUrl}/tx/${i.transactionHash}`}
              title={truncate(i.transactionHash, 6, 4, '...')}
              midTitle='Deposit'
              subTitle={`Token: ${i.tokenInfo.name}`}
              status={i.status === 'Pending' ? 'Pending' : logAmount(i.returnValues.amount, i.tokenInfo.decimals)}
              statusPercentage={i.pendingPercentage <= 100 ? i.pendingPercentage : ''}
              subStatus={`Block ${i.blockNumber}`}
              tooltip={'For re-org protection, deposits require 10 block confirmations before the UTXO is available to spend.'}
            />
          );
        })}
      </div>
    </div>
  );
}
Example #14
Source File: StatsCell.js    From covid19 with MIT License 5 votes vote down vote up
Success = ({ countries = [], country = 'usa' }) => {
  // Calculate stats
  const [counts, setCounts] = useState([])
  const stat = (key) =>
    commaNumber(last(map(orderBy(counts, 'date.date'), key)))
  useEffect(() => {
    setCounts(find(countries, ['iso', country])?.dailyCounts)
  }, [country])

  return (
    <div>
      <section>
        <StatChart data={counts} dataKey="newCases" color="green" />
        <Stat value={stat('newCases')} label="New cases" />
      </section>
      <section>
        <StatChart data={counts} dataKey="currentlyInfected" color="yellow" />
        <Stat value={stat('currentlyInfected')} label="Currently infected" />
      </section>
      <section>
        <StatChart data={counts} dataKey="totalCases" color="orange" />
        <Stat value={stat('totalCases')} label="Confirmed cases" />
      </section>
      <section>
        <StatChart data={counts} dataKey="totalDeaths" color="red" />
        <Stat value={stat('totalDeaths')} label="Confirmed deaths" />
      </section>
      <style jsx>{`
        div {
          display: grid;
          grid-gap: 1rem;
          margin-top: 2rem;
        }
        @media (min-width: 48em) {
          div {
            grid-template-columns: repeat(4, 1fr);
          }
        }
        section {
          position: relative;
          min-height: 8rem;
        }
        section :global(.recharts-responsive-container) {
          position: absolute !important;
          top: 0;
          left: 0;
          right: 0;
        }
      `}</style>
    </div>
  )
}
Example #15
Source File: tableUtil.js    From lens-extension-cc with MIT License 5 votes vote down vote up
sortData = (obj, sortBy, order, path) => {
  const sortByValueArr = Object.keys(obj).map((key) => {
    return { [key]: get(obj[key], path[sortBy]) };
  });

  const sorted = orderBy(sortByValueArr, Object.keys(obj), [order]);
  return sorted.map(Object.keys);
}
Example #16
Source File: RelatedPosts.js    From ecomloop.github.io with MIT License 5 votes vote down vote up
getRelatedPosts = (currentPost, allPosts) => {

    const maxPosts = 3;
    const currentCatetory = currentPost.node.frontmatter.categories || "";
    const currentTags = currentPost.node.frontmatter.tags || [];

    // console.log("******** in related post")
    // console.log(allPosts)
    // console.log(currentPost)
    // console.log(currentCatetory)
    // console.log(currentTags)

    // Don't include the current post in posts list
    allPosts = allPosts.filter((post) => post.node.id !== currentPost.node.id);

    const identityMap = {};

    //Map over all posts, add to map and add points
    for (let post of allPosts) {

        const id = post.node.id;
        if (!identityMap.hasOwnProperty(id)) {
            identityMap[id] = {
                post: post,
                points: 0
            }
        }

        // For category matches, we add 2 points
        const categoryPoints = 2;
        //if (post.node.frontmatter.categories.category === currentCatetory) {
            //identityMap[id].points += categoryPoints;
        //}
        post.node.frontmatter.categories.forEach(({category}) => {
            if (includes(...currentCatetory, category)) {
                identityMap[id].points += categoryPoints;
            }
        })

        // For tags matches, we add 1 point
        const tagPoint = 1;
        post.node.frontmatter.tags.forEach((aTag) => {
            if (includes(currentTags, aTag)) {
                identityMap[id].points += tagPoint;
            }
        })

    }

    // Convert the identity map to an array
    const arrayIdentityMap = Object.keys(identityMap).map((id) => identityMap[id]);

    // Use a lodash utility function to sort them 
    // by points, from greatest to least
    const similarPosts = orderBy(
        arrayIdentityMap, ['points'], ['desc']
    )

    //console.log(similarPosts.splice(0, maxPosts))
    // return the max number posts requested
    return similarPosts.splice(0, maxPosts);

}
Example #17
Source File: RelatedShops.jsx    From emprezzo with MIT License 5 votes vote down vote up
getRelatedShops = (currentShop, allshops) => {

    const maxPosts = 4;
    const currentCategories = currentShop.category?currentShop.category.split(","):[];
    const currentTags = currentShop.tags?currentShop.tags.split(","):[];

    // console.log("******** in related shops")
    // console.log(allshops)
    // console.log(currentShop)
    // console.log(currentCategories)
    // console.log(currentTags)

    // Don't include the current post in posts list
    allshops = allshops.filter((post) => post.id !== currentShop.id);

    const identityMap = {};

    //Map over all posts, add to map and add points
    for (let post of allshops) {
        const id = post.id;
        if (!identityMap.hasOwnProperty(id)) {
            identityMap[id] = {
                shop: post,
                points: 0
            }
        }

        // For category matches, we add 2 points
        const categoryPoints = 2;
        const categories = post.category?post.category.split(","):[];
        categories.forEach((category) => {
            if (includes(...currentCategories, category)) {
                identityMap[id].points += categoryPoints;
            }
        })

        // For tags matches, we add 1 point
        const tagPoint = 1;
        const tags = post.tags?post.tags.split(","):[];
        tags.forEach((aTag) => {
            if (includes(currentTags, aTag)) {
                identityMap[id].points += tagPoint;
            }
        })

    }

    // Convert the identity map to an array
    const arrayIdentityMap = Object.keys(identityMap).map((id) => identityMap[id]);

    // Use a lodash utility function to sort them
    // by points, from greatest to least
    const similarPosts = orderBy(
        arrayIdentityMap, ['points'], ['desc']
    )

    //console.log("***** relatedShops Output ",similarPosts.splice(0, maxPosts))
    // return the max number posts requested
    return similarPosts.splice(0, maxPosts);

}
Example #18
Source File: fullTextSearch.js    From sampo-ui with MIT License 5 votes vote down vote up
handleFullTextSearchAction = (state, action, initialState) => {
  switch (action.type) {
    case FETCH_FULL_TEXT_RESULTS:
      return {
        ...state,
        fetching: true
      }
    case UPDATE_RESULTS:
      return {
        ...state,
        query: action.query,
        results: action.data,
        fetching: false
      }
    case CLEAR_RESULTS:
      return initialState
    case SORT_FULL_TEXT_RESULTS: {
      let sortBy
      let sortDirection
      if (action.sortBy === state.sortBy) {
        sortBy = state.sortBy
        sortDirection = state.sortDirection === 'asc' ? 'desc' : 'asc'
      }
      if (action.sortBy !== state.sortBy) {
        sortBy = action.sortBy
        sortDirection = 'asc'
      }
      const sortByProperty = state.properties.find(property => property.id === sortBy)
      const sortByPath = sortByProperty.valueType === 'object' ? `${sortBy}.prefLabel` : sortBy
      return {
        ...state,
        sortBy,
        sortDirection,
        results: orderBy(
          state.results,
          sortByPath,
          sortDirection
        )
      }
    }
    default:
      return state
  }
}
Example #19
Source File: index.js    From sampo-ui with MIT License 5 votes vote down vote up
filterResults = createSelector(
  [getResults, getFacets, getLastlyUpdatedFacet, getSortBy, getSortDirection],
  (results, facets, lastlyUpdatedFacet, sortBy, sortDirection) => {
    if (results == null) {
      return {
        clientFSResults: null,
        clientFSFacetValues: null
      }
    }

    // Filter results by current facet selections
    for (const [facetID, facet] of Object.entries(facets)) {
      const { filterType, selectionsSet } = facet
      if (filterType === 'clientFSLiteral' && selectionsSet.size !== 0) {
        results = results.filter(result => selectionsSet.has(result[facetID]))
      }
    }
    results = orderBy(results, sortBy, sortDirection)

    // Calculate values for all facets
    const facetValues = {}
    let skipFacetID = ''
    // Initialize the facetValues object with facet IDs
    for (const facetId in facets) {
      facetValues[facetId] = {}
    }
    // If a facet selection was added, first handle that facet
    if (lastlyUpdatedFacet !== null) {
      // console.log(lastlyUpdatedFacet.facetID)
      // console.log(facets[lastlyUpdatedFacet.facetID])
      skipFacetID = lastlyUpdatedFacet.facetID
      lastlyUpdatedFacet.values = lastlyUpdatedFacet.values.map(value => ({
        ...value,
        selected: facets[lastlyUpdatedFacet.facetID].selectionsSet.has(value.id)
      }))
      facetValues[lastlyUpdatedFacet.facetID] = lastlyUpdatedFacet.values
    }
    // Then handle all the remainder facets
    for (const result of results) {
      for (const [facetID, facet] of Object.entries(facets)) {
        const { filterType, selectionsSet } = facet
        if (facetID !== skipFacetID && filterType === 'clientFSLiteral' && has(result, facetID)) {
          const literalValue = result[facetID]
          if (!has(facetValues[facetID], literalValue)) {
            facetValues[facetID][literalValue] = {
              id: literalValue,
              prefLabel: literalValue,
              selected: selectionsSet.has(literalValue),
              instanceCount: 1,
              parent: null
            }
          } else {
            facetValues[facetID][literalValue].instanceCount += 1
          }
        }
      }
    }
    for (const facetID in facetValues) {
      facetValues[facetID] = orderBy(facetValues[facetID], 'prefLabel')
    }
    // console.log(results)
    // console.log(facetValues)
    return {
      clientFSResults: results,
      clientFSFacetValues: facetValues
    }
  }
)
Example #20
Source File: TransformationsList.js    From ui-data-export with Apache License 2.0 5 votes vote down vote up
TransformationsList = ({
  transformations,
  allTransformations,
}) => {
  const [sortedTransformations, setSortedTransformations] = useState([]);
  const intl = useIntl();

  const formatter = useMemo(() => ({
    fieldName: record => {
      const transformation = allTransformations.find(({ fieldId }) => fieldId === record.fieldId);

      return transformation?.displayName;
    },
    transformation: record => (
      <pre
        title={record.transformation}
        className={css.transformation}
      >
        {record.transformation}
      </pre>
    ),
  }), [allTransformations]);

  const columnMapping = useMemo(() => ({
    fieldName: intl.formatMessage({ id: 'ui-data-export.mappingProfiles.transformations.fieldName' }),
    transformation: intl.formatMessage({ id: 'ui-data-export.mappingProfiles.transformations.transformation' }),
  }), [intl]);

  useEffect(() => {
    const formattedTransformations = orderBy(transformations.map(transformation => ({
      fieldName: formatter.fieldName(transformation),
      transformation: formatter.transformation(transformation),
    })), 'fieldName', 'asc');

    setSortedTransformations(formattedTransformations);
  }, [transformations, formatter]);

  return (
    <MultiColumnList
      id="mapping-profile-transformations-list"
      contentData={sortedTransformations}
      columnMapping={columnMapping}
      columnWidths={columnWidths}
      visibleColumns={visibleColumns}
      isEmptyMessage={intl.formatMessage({ id: 'ui-data-export.mappingProfiles.transformations.emptyMessage' })}
    />
  );
}
Example #21
Source File: Exits.js    From web-wallet with Apache License 2.0 4 votes vote down vote up
function Exits ({ searchHistory }) {
  const [ page, setPage ] = useState(1);
  const [ processExitModal, setProcessExitModal ] = useState(false);

  const pendingExits = orderBy(useSelector(selectPendingExits, isEqual), i => i.blockNumber, 'desc');
  const exitedExits = orderBy(useSelector(selectExitedExits, isEqual), i => i.blockNumber, 'desc');
  const loading = useSelector(selectLoading([ 'EXIT/GETALL' ]));

  const _pendingExits = pendingExits.filter(i => {
    return i.transactionHash.includes(searchHistory);
  });

  const _exitedExits = exitedExits.filter(i => {
    return i.transactionHash.includes(searchHistory);
  });

  const renderPending = _pendingExits.map((i, index) => {
    const exitableMoment = moment.unix(i.exitableAt);
    const isExitable = moment().isAfter(exitableMoment);

    function getStatus () {
      if (i.status === 'Confirmed' && i.pendingPercentage >= 100) {
        return 'In Challenge Period';
      }
      return i.status;
    }

    return (
      <Transaction
        key={`pending-${index}`}
        button={
          i.exitableAt && isExitable
            ? {
              onClick: () => setProcessExitModal(i),
              text: 'Process Exit'
            }
            : undefined
        }
        link={`${config.etherscanUrl}/tx/${i.transactionHash}`}
        status={getStatus()}
        subStatus={`Block ${i.blockNumber}`}
        statusPercentage={i.pendingPercentage <= 100 ? i.pendingPercentage : ''}
        title={truncate(i.transactionHash, 6, 4, '...')}
        midTitle={i.exitableAt ? `Exitable ${exitableMoment.format('lll')}` : ''}
        subTitle={i.currency ? truncate(i.currency, 6, 4, '...'): ''}
      />
    );
  });

  const renderExited = _exitedExits.map((i, index) => {
    return (
      <Transaction
        key={`exited-${index}`}
        link={`${config.etherscanUrl}/tx/${i.transactionHash}`}
        status='Exited'
        subStatus={`Block ${i.blockNumber}`}
        title={truncate(i.transactionHash, 6, 4, '...')}
      />
    );
  });

  const allExits = [ ...renderPending, ...renderExited ];

  const startingIndex = page === 1 ? 0 : ((page - 1) * PER_PAGE);
  const endingIndex = page * PER_PAGE;
  const paginatedExits = allExits.slice(startingIndex, endingIndex);

  return (
    <>
      <ProcessExitsModal
        exitData={processExitModal}
        open={!!processExitModal}
        toggle={() => setProcessExitModal(false)}
      />
      <div className={styles.section}>
        <div className={styles.subTitle}>Exits</div>
        <div className={styles.transactionSection}>
          <div className={styles.transactions}>
            <Pager
              currentPage={page}
              isLastPage={paginatedExits.length < PER_PAGE}
              onClickNext={() => setPage(page + 1)}
              onClickBack={() => setPage(page - 1)}
            />
            {!allExits.length && !loading && (
              <div className={styles.disclaimer}>No exit history.</div>
            )}
            {!allExits.length && loading && (
              <div className={styles.disclaimer}>Loading...</div>
            )}
            {React.Children.toArray(paginatedExits)}
          </div>
        </div>
      </div>
    </>
  );
}
Example #22
Source File: FederatedResults.js    From sampo-ui with MIT License 4 votes vote down vote up
FederatedResults = props => {
  const { rootUrl, perspective, screenSize, clientFSState, layoutConfig, portalConfig } = props
  const { searchMode } = perspective
  const perspectiveID = perspective.id
  const { maps } = clientFSState
  const { mapClusters, mapMarkers } = maps
  const layerControlExpanded = screenSize === 'md' ||
    screenSize === 'lg' ||
    screenSize === 'xl'
  let groupedResults = []
  if (props.location.pathname.endsWith('statistics')) {
    const grouped = groupBy(props.clientFSResults, clientFSState.groupBy)
    for (const key in grouped) {
      groupedResults.push({
        category: key,
        prefLabel: key,
        instanceCount: grouped[key].length
      })
    }
    groupedResults = orderBy(groupedResults, 'instanceCount', 'desc')
  }
  return (
    <>
      <PerspectiveTabs
        tabs={perspective.tabs}
        screenSize={props.screenSize}
        layoutConfig={layoutConfig}
      />
      <Route
        exact path={`${rootUrl}/${perspectiveID}/${searchMode}`}
        render={() => <Redirect to={`${rootUrl}/${perspectiveID}/${searchMode}/table`} />}
      />
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/table`}>
        <VirtualizedTable
          portalConfig={portalConfig}
          list={Immutable.List(props.clientFSResults)}
          clientFSState={props.clientFSState}
          clientFSSortResults={props.clientFSSortResults}
          perspectiveID={perspectiveID}
          layoutConfig={layoutConfig}
        />
      </Route>
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/map_clusters`}>
        <LeafletMap
          portalConfig={portalConfig}
          perspectiveConfig={perspective}
          center={mapClusters.center}
          zoom={mapClusters.zoom}
          results={props.clientFSResults}
          leafletMapState={props.leafletMapState}
          resultClass='mapClusters'
          pageType='clientFSResults'
          mapMode='cluster'
          createPopUpContent={props.leafletConfig.createPopUpContentNameSampo}
          fetchResults={props.fetchResults}
          fetchGeoJSONLayers={props.fetchGeoJSONLayers}
          clearGeoJSONLayers={props.clearGeoJSONLayers}
          fetchByURI={props.fetchByURI}
          fetching={false}
          showInstanceCountInClusters={false}
          updateFacetOption={props.updateFacetOption}
          showError={props.showError}
          showExternalLayers
          layerControlExpanded={layerControlExpanded}
          layerConfigs={props.leafletConfig.layerConfigs}
          updateMapBounds={props.updateMapBounds}
          layoutConfig={layoutConfig}
        />
      </Route>
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/map_markers`}>
        {props.clientFSResults.length < 500
          ? (
            <LeafletMap
              portalConfig={portalConfig}
              perspectiveConfig={perspective}
              center={mapMarkers.center}
              zoom={mapMarkers.zoom}
              results={props.clientFSResults}
              leafletMapState={props.leafletMapState}
              resultClass='mapMarkers'
              pageType='clientFSResults'
              mapMode='marker'
              createPopUpContent={props.leafletConfig.createPopUpContentNameSampo}
              fetchResults={props.fetchResults}
              fetchGeoJSONLayers={props.fetchGeoJSONLayers}
              clearGeoJSONLayers={props.clearGeoJSONLayers}
              fetchByURI={props.fetchByURI}
              fetching={false}
              showInstanceCountInClusters={false}
              updateFacetOption={props.updateFacetOption}
              showError={props.showError}
              showExternalLayers
              layerControlExpanded={layerControlExpanded}
              layerConfigs={props.leafletConfig.layerConfigs}
              updateMapBounds={props.updateMapBounds}
              layoutConfig={layoutConfig}
            />
            )
          : <ResultInfo message={intl.get('leafletMap.tooManyResults')} />}
      </Route>
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/statistics`}>
        <ApexCharts
          portalConfig={portalConfig}
          layoutConfig={layoutConfig}
          perspectiveConfig={props.perspectiveConfig}
          apexChartsConfig={props.apexChartsConfig}
          results={groupedResults}
          pageType='clientFSResults'
          facetUpdateID={props.clientFSState.facetUpdateID}
          resultClassConfig={{
            createChartData: 'createApexPieChartData',
            property: props.clientFSState.groupBy,
            title: {
              text: props.clientFSState.groupByLabel,
              align: 'left'
            }
          }}
        />
      </Route>
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/download`}>
        <CSVButton
          results={props.clientFSResults}
          layoutConfig={layoutConfig}
          portalConfig={portalConfig}
        />
      </Route>

    </>
  )
}
Example #23
Source File: ObjectListCollapsible.js    From sampo-ui with MIT License 4 votes vote down vote up
ObjectListCollapsible = props => {
  const {
    sortValues, sortBy, sortByConvertDataTypeTo, makeLink, externalLink, linkAsButton, columnId, showSource,
    sourceExternalLink, numberedList, collapsedMaxWords, classes, shortenLabel
  } = props
  let { data } = props

  const sortList = data => {
    if (has(props, 'columnId') && props.columnId.endsWith('Timespan')) {
      data = data.sort((a, b) => {
        a = has(a, 'start') ? ISOStringToDate(a.start) : ISOStringToDate(a.end)
        b = has(b, 'start') ? ISOStringToDate(b.start) : ISOStringToDate(b.end)
        // arrange from the most recent to the oldest
        return a > b ? 1 : a < b ? -1 : 0
      })
    } else if (props.columnId === 'event') {
      data = orderBy(data, 'date')
    } else if (props.sortBy) {
      if (sortByConvertDataTypeTo && sortByConvertDataTypeTo === 'integer') {
        data.forEach(item => {
          item[sortBy] = parseInt(item[sortBy])
        })
      }
      data = orderBy(data, sortBy)
    } else {
      data = orderBy(data, 'prefLabel')
    }
    return data
  }

  const renderItem = ({ addThreeDots, itemData, isFirstValue = false }) => {
    if (columnId === 'event') {
      return (
        <>
          <ObjectListItemEvent
            data={itemData}
            isFirstValue={isFirstValue}
          />
          {addThreeDots &&
            <span className={classes.threeDots} onClick={() => props.onExpandClick(props.rowId)}> ...</span>}
        </>
      )
    } else {
      return (
        <>
          <ObjectListItem
            data={itemData}
            shortenLabel={shortenLabel}
            makeLink={makeLink}
            externalLink={externalLink}
            linkAsButton={linkAsButton}
            isFirstValue={isFirstValue}
            collapsedMaxWords={collapsedMaxWords}
          />
          {addThreeDots &&
            <span className={classes.threeDots} onClick={() => props.onExpandClick(props.rowId)}> ...</span>}
          {showSource && itemData.source &&
            <ObjectListItemSources
              data={itemData.source}
              shortenLabel={shortenLabel}
              externalLink={sourceExternalLink}
            />}
        </>
      )
    }
  }

  const renderListItems = data =>
    <>
      {data.map(item =>
        <li key={item.id}>
          {renderItem({ collapsed: false, itemData: item })}
        </li>
      )}
    </>

  const renderBulletedList = data =>
    <ul className={classNames(classes.resultTableList, classes.valueList)}>
      {renderListItems(data)}
    </ul>

  const renderNumberedList = data =>
    <ol className={classes.resultTableList}>
      {renderListItems(data)}
    </ol>

  if (data == null || data === '-') {
    return '-'
  } else if (Array.isArray(data)) {
    data = sortValues ? sortList(data) : data
    return (
      <>
        {!props.expanded && renderItem({ addThreeDots: true, itemData: data[0], isFirstValue: true })}
        <Collapse in={props.expanded} timeout='auto' unmountOnExit>
          {numberedList ? renderNumberedList(data) : renderBulletedList(data)}
        </Collapse>
      </>
    )
  } else {
    return renderItem({ addThreeDots: shortenLabel, itemData: data })
  }
}
Example #24
Source File: networkService.js    From web-wallet with Apache License 2.0 4 votes vote down vote up
async getTransferTypedData ({
    utxos,
    recipient,
    value,
    currency,
    feeToken,
    metadata
  }) {
    if (!utxos || !utxos.length) {
      try {
        const _utxos = await this.childChain.getUtxos(this.account);
        utxos = orderBy(_utxos, i => i.amount, 'desc');
      } catch (error) {
        throw new WebWalletError({
          originalError: error,
          customErrorMessage: 'Could not fetch account utxos. Please try transfer again.',
          reportToSentry: false,
          reportToUi: true
        });
      }
    }

    const allFees = await this.fetchFees();
    const feeInfo = allFees.find(i => i.currency === feeToken);
    if (!feeInfo) {
      throw new WebWalletError({
        originalError: new Error(`${feeToken} is not a supported fee token.`),
        customErrorMessage: `${feeToken} is not a supported fee token.`,
        reportToSentry: false,
        reportToUi: true
      });
    }

    const isAddress = this.web3.utils.isAddress(recipient);
    if (!isAddress) {
      recipient = await this.web3.eth.ens.getAddress(recipient);
    }
    if (!recipient) {
      throw new WebWalletError({
        originalError: new Error('Not a valid ENS name.'),
        customErrorMessage: 'Not a valid ENS name.',
        reportToSentry: false,
        reportToUi: true
      });
    }

    try {
      const payments = [ {
        owner: recipient,
        currency,
        amount: new BN(value.toString())
      } ];
      const fee = {
        currency: feeToken,
        amount: new BN(feeInfo.amount.toString())
      };
      const txBody = OmgUtil.transaction.createTransactionBody({
        fromAddress: this.account,
        fromUtxos: utxos,
        payments,
        fee,
        metadata: metadata || OmgUtil.transaction.NULL_METADATA
      });
      const typedData = OmgUtil.transaction.getTypedData(txBody, this.plasmaContractAddress);
      return { txBody, typedData };
    } catch (error) {
      if (error.message.includes('Insufficient funds')) {
        throw new WebWalletError({
          originalError: error,
          customErrorMessage: error.message,
          reportToSentry: false,
          reportToUi: true
        });
      }

      if (error.message.includes('Inputs must be an array of size')) {
        throw new WebWalletError({
          originalError: error,
          customErrorMessage: 'This transaction will require more than 4 UTXOs. Please merge some UTXOs then try again.',
          reportToSentry: false,
          reportToUi: true
        });
      }

      throw new WebWalletError({
        originalError: error,
        customErrorMessage: 'Could not create the transaction. Please try again.',
        reportToSentry: false,
        reportToUi: true
      });
    }
  }
Example #25
Source File: Transactions.js    From web-wallet with Apache License 2.0 4 votes vote down vote up
function Transactions () {
  const dispatch = useDispatch();
  const [ page, setPage ] = useState(1);
  const [ searchHistory, setSearchHistory ] = useState('');

  const loading = useSelector(selectLoading([ 'TRANSACTION/GETALL' ]));
  const activeTab = useSelector(selectActiveHistoryTab, isEqual);
  const unorderedTransactions = useSelector(selectChildchainTransactions, isEqual);
  const transactions = orderBy(unorderedTransactions, i => i.block.timestamp, 'desc');

  function renderStatus (utxo) {
    if (utxo.status === 'Pending') {
      return 'Pending';
    }
    const total = utxo.outputs.reduce((prev, curr) => {
      if (curr.owner !== networkService.account) {
        return prev.add(new BN(curr.amount));
      }
      return prev;
    }, new BN(0));
    return `${total.toString()}`;
  }

  const _transactions = transactions.filter(i => {
    return i.txhash.includes(searchHistory) || i.metadata.toLowerCase().includes(searchHistory);
  });

  const startingIndex = page === 1 ? 0 : ((page - 1) * PER_PAGE);
  const endingIndex = page * PER_PAGE;
  const paginatedTransactions = _transactions.slice(startingIndex, endingIndex);

  return (
    <div className={styles.container}>
      <div className={styles.header}>
        <h2>History</h2>
        <Input
          icon
          placeholder='Search history'
          value={searchHistory}
          onChange={i => {
            setPage(1);
            setSearchHistory(i.target.value.toLowerCase());
          }}
          className={styles.searchBar}
        />
      </div>

      <div className={styles.data}>
        <div className={styles.section}>
          <Tabs
            onClick={tab => {
              setPage(1);
              dispatch(setActiveHistoryTab(tab));
            }}
            activeTab={activeTab}
            tabs={[ 'Transactions', 'Deposits' ]}
          />

          {activeTab === 'Transactions' && (
            <div className={styles.transactions}>
              <Pager
                currentPage={page}
                isLastPage={paginatedTransactions.length < PER_PAGE}
                onClickNext={() => setPage(page + 1)}
                onClickBack={() => setPage(page - 1)}
              />
              {!paginatedTransactions.length && !loading && (
                <div className={styles.disclaimer}>No transaction history.</div>
              )}
              {!paginatedTransactions.length && loading && (
                <div className={styles.disclaimer}>Loading...</div>
              )}
              {paginatedTransactions.map((i, index) => {
                return (
                  <Transaction
                    key={index}
                    link={
                      i.status === 'Pending'
                        ? undefined
                        : `${config.blockExplorerUrl}/transaction/${i.txhash}`
                    }
                    title={`${truncate(i.txhash, 6, 4, '...')}`}
                    midTitle={i.metadata ? i.metadata : '-'}
                    subTitle={moment.unix(i.block.timestamp).format('lll')}
                    status={renderStatus(i)}
                    subStatus={`Block ${i.block.blknum}`}
                  />
                );
              })}
            </div>
          )}

          {activeTab === 'Deposits' && <Deposits searchHistory={searchHistory} />}
        </div>

        <Exits searchHistory={searchHistory} />
      </div>
    </div>
  );
}
Example #26
Source File: TransferModal.js    From web-wallet with Apache License 2.0 4 votes vote down vote up
function TransferModal ({ open }) {
  const dispatch = useDispatch();

  const [ currency, setCurrency ] = useState('');
  const [ value, setValue ] = useState('');
  const [ feeToken, setFeeToken ] = useState('');
  const [ recipient, setRecipient ] = useState('');
  const [ metadata, setMetadata ] = useState('');
  const [ usableFees, setUsableFees ] = useState([]);
  const [ ledgerModal, setLedgerModal ] = useState(false);
  const [ typedData, setTypedData ] = useState({});

  const [ utxoPicker, setUtxoPicker ] = useState(false);
  const [ utxos, setUtxos ] = useState([]);
  const [ selectedUtxos, setSelectedUtxos ] = useState([]);
  const [ selectedFeeUtxos, setSelectedFeeUtxos ] = useState([]);

  const balances = useSelector(selectChildchainBalance, isEqual);
  const fees = useSelector(selectFees, isEqual);
  const ledgerConnect = useSelector(selectLedger);

  const feesLoading = useSelector(selectLoading([ 'FEE/GET' ]));
  const loading = useSelector(selectLoading([ 'TRANSFER/CREATE' ]));

  useEffect(() => {
    async function fetchUTXOS () {
      const _utxos = await networkService.getUtxos();
      const utxos = orderBy(_utxos, i => i.currency, 'desc');
      setUtxos(utxos);
    }
    if (open) {
      fetchUTXOS();
    }
  }, [ open ]);

  useEffect(() => {
    if (Object.keys(fees).length) {
      const usableFees = balances.filter(balance => {
        const feeObject = fees[balance.currency];
        if (feeObject) {
          if (new BN(balance.amount).gte(new BN(feeObject.amount))) {
            return true;
          }
        }
        return false;
      }).map(i => {
        const feeObject = fees[i.currency];
        const feeAmount = new BN(feeObject.amount).div(new BN(feeObject.subunit_to_unit));
        return {
          title: i.name,
          value: i.currency,
          subTitle: `Fee Amount: ${feeAmount.toFixed()}`
        };
      });
      setUsableFees(usableFees);
    }
  }, [ balances, fees, open ]);

  useEffect(() => {
    if (balances.length && !currency) {
      setCurrency(balances[0].currency);
    }
  }, [ balances, currency, open ]);

  useEffect(() => {
    if (usableFees.length && !feeToken) {
      setFeeToken(usableFees[0].value);
    }
  }, [ usableFees, feeToken ]);

  const selectOptions = balances.map(i => ({
    title: i.name,
    value: i.currency,
    subTitle: `Balance: ${logAmount(i.amount, i.decimals)}`
  }));

  async function submit ({ useLedgerSign }) {
    if (
      value > 0 &&
      currency &&
      feeToken &&
      recipient
    ) {
      try {
        const valueTokenInfo = await getToken(currency);
        const { txBody, typedData } = await dispatch(getTransferTypedData({
          utxos: [ ...selectedUtxos, ...selectedFeeUtxos ],
          recipient,
          value: powAmount(value, valueTokenInfo.decimals),
          currency,
          feeToken,
          metadata
        }));
        setTypedData(typedData);
        const res = await dispatch(transfer({
          useLedgerSign,
          txBody,
          typedData
        }));
        if (res) {
          dispatch(setActiveHistoryTab('Transactions'));
          dispatch(openAlert('Transfer submitted. You will be blocked from making further transactions until the transfer is confirmed.'));
          handleClose();
        }
      } catch (err) {
        //
      }
    }
  }

  function handleClose () {
    setCurrency('');
    setValue('');
    setFeeToken('');
    setRecipient('');
    setSelectedUtxos([]);
    setUtxos([]);
    setUtxoPicker(false);
    setMetadata('');
    setLedgerModal(false);
    dispatch(closeModal('transferModal'));
  }

  const disabledTransfer = value <= 0 ||
    !currency ||
    !feeToken ||
    !recipient ||
    new BN(value).gt(new BN(getMaxTransferValue()));

  function getMaxTransferValue () {
    const transferingBalanceObject = balances.find(i => i.currency.toLowerCase() === currency.toLowerCase());
    if (!transferingBalanceObject) {
      return;
    }
    if (currency.toLowerCase() === feeToken.toLowerCase()) {
      const availableAmount = new BN(transferingBalanceObject.amount).minus(new BN(fees[feeToken.toLowerCase()].amount));
      return logAmount(availableAmount, transferingBalanceObject.decimals);
    }
    return logAmount(transferingBalanceObject.amount, transferingBalanceObject.decimals);
  }

  function handleUtxoClick (utxo) {
    const isSelected = selectedUtxos.some(i => i.utxo_pos === utxo.utxo_pos);
    if (isSelected) {
      return setSelectedUtxos(selectedUtxos.filter(i => i.utxo_pos !== utxo.utxo_pos));
    }
    if ((selectedUtxos.length + selectedFeeUtxos.length) < 4) {
      return setSelectedUtxos([ ...selectedUtxos, utxo ]);
    }
  }

  function handleFeeUtxoClick (utxo) {
    const isSelected = selectedFeeUtxos.some(i => i.utxo_pos === utxo.utxo_pos);
    if (isSelected) {
      return setSelectedFeeUtxos(selectedFeeUtxos.filter(i => i.utxo_pos !== utxo.utxo_pos));
    }
    if ((selectedUtxos.length + selectedFeeUtxos.length) < 4) {
      return setSelectedFeeUtxos([ ...selectedFeeUtxos, utxo ]);
    }
  }

  function handleUtxoPickerBack () {
    setSelectedUtxos([]);
    setSelectedFeeUtxos([]);
    setUtxoPicker(false);
  }

  function renderUtxoPicker () {
    const currencyUtxos = utxos
      .filter(i => i.currency.toLowerCase() === currency.toLowerCase())
      .filter(i => !!i);

    const feeUtxos = utxos
      .filter(i => i.currency.toLowerCase() === feeToken.toLowerCase())
      .filter(i => !!i);

    const selectedCurrencyAmount = selectedUtxos.reduce((acc, cur) => {
      return acc.plus(new BN(cur.amount.toString()));
    }, new BN(0));

    const selectedFeeAmount = selectedFeeUtxos.reduce((acc, cur) => {
      return acc.plus(new BN(cur.amount.toString()));
    }, new BN(0));

    const currencyObject = balances.find(i => i.currency.toLowerCase() === currency.toLowerCase());
    const currencyCoverAmount = new BN(powAmount(value.toString(), currencyObject.decimals));

    const feeObject = fees[feeToken.toLowerCase()];
    const feeCoverAmount = new BN(feeObject.amount.toString());

    const sameCurrency = feeToken.toLowerCase() === currency.toLowerCase();
    const utxoPickerDisabled = sameCurrency
      ? currencyCoverAmount.plus(feeCoverAmount).gt(selectedCurrencyAmount)
      : currencyCoverAmount.gt(selectedCurrencyAmount) || feeCoverAmount.gt(selectedFeeAmount);

    function renderCurrencyPick () {
      const enough = sameCurrency
        ? currencyCoverAmount.plus(feeCoverAmount).lte(selectedCurrencyAmount)
        : currencyCoverAmount.lte(selectedCurrencyAmount);

      return (
        <>
          <div className={styles.description}>
            Transfer amount to cover: {sameCurrency
              ? logAmount(currencyCoverAmount.plus(feeCoverAmount), currencyObject.decimals)
              : logAmount(currencyCoverAmount, currencyObject.decimals)}
          </div>

          <div className={[ styles.list, !sameCurrency ? styles.doubleList : '' ].join(' ')}>
            {!currencyUtxos.length && (
              <div className={styles.disclaimer}>You do not have any UTXOs for this token on the OMG Network.</div>
            )}
            {currencyUtxos.map((i, index) => {
              const selected = selectedUtxos.some(selected => selected.utxo_pos === i.utxo_pos);
              return (
                <div
                  key={index}
                  onClick={() => {
                    if (!enough || selected) {
                      handleUtxoClick(i);
                    }
                  }}
                  className={[
                    styles.utxo,
                    selected ? styles.selected : ''
                  ].join(' ')}
                >
                  <div className={styles.title}>
                    {i.tokenInfo.name}
                  </div>

                  <div className={styles.value}>
                    <div className={styles.amount}>
                      {logAmount(i.amount.toString(), i.tokenInfo.decimals)}
                    </div>

                    <div className={styles.check}>
                      {selected && <Check />}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </>
      );
    }

    function renderFeePick () {
      const logFeeAmount = new BN(feeObject.amount.toString()).div(new BN(feeObject.subunit_to_unit.toString()));
      const enough = selectedFeeAmount.gte(feeCoverAmount);
      return (
        <>
          <div className={styles.description}>
            Fee amount to cover: {logFeeAmount.toFixed()}
          </div>

          <div className={[ styles.list, !sameCurrency ? styles.doubleList : '' ].join(' ')}>
            {!feeUtxos.length && (
              <div className={styles.disclaimer}>You do not have any fee UTXOs on the OMG Network.</div>
            )}
            {feeUtxos.map((i, index) => {
              const selected = selectedFeeUtxos.some(selected => selected.utxo_pos === i.utxo_pos);
              return (
                <div
                  key={index}
                  onClick={() => {
                    if (!enough || selected) {
                      handleFeeUtxoClick(i);
                    }
                  }}
                  className={[
                    styles.utxo,
                    selected ? styles.selected : ''
                  ].join(' ')}
                >
                  <div className={styles.title}>
                    {i.tokenInfo.name}
                  </div>

                  <div className={styles.value}>
                    <div className={styles.amount}>
                      {logAmount(i.amount.toString(), i.tokenInfo.decimals)}
                    </div>

                    <div className={styles.check}>
                      {selected && <Check />}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </>
      );
    }

    return (
      <>
        <h2>Select UTXOs</h2>
        <div className={styles.description}>
          By default, this wallet will automatically pick UTXOs to cover your transaction amount. However, if you are a more advanced user, you can pick the UTXOs you would like to spend in this transaction manually.
        </div>

        {renderCurrencyPick()}
        {!sameCurrency && renderFeePick()}

        <div className={styles.disclaimer}>You can select a maximum of 4 UTXOs.</div>

        <div className={styles.buttons}>
          <Button
            onClick={handleUtxoPickerBack}
            type='outline'
            className={styles.button}
          >
            USE DEFAULT
          </Button>

          <Button
            className={styles.button}
            onClick={() => setUtxoPicker(false)}
            type='primary'
            disabled={utxoPickerDisabled}
          >
            SELECT UTXOS
          </Button>
        </div>
      </>
    );
  }

  function renderTransferScreen () {
    return (
      <>
        <h2>Transfer</h2>
        <div className={styles.address}>
          {`From address : ${networkService.account}`}
        </div>

        <Input
          label='To Address'
          placeholder='Hash or ENS name'
          paste
          value={recipient}
          onChange={i => setRecipient(i.target.value)}
        />

        <InputSelect
          label='Amount to transfer'
          placeholder={0}
          value={value}
          onChange={i => {
            setValue(i.target.value);
            setSelectedUtxos([]);
            setSelectedFeeUtxos([]);
          }}
          selectOptions={selectOptions}
          onSelect={i => {
            setCurrency(i.target.value);
            setSelectedUtxos([]);
            setSelectedFeeUtxos([]);
          }}
          selectValue={currency}
          maxValue={getMaxTransferValue()}
        />

        {value > 0 && (
          <div
            className={styles.utxoPickLink}
            onClick={() => setUtxoPicker(true)}
          >
            {selectedUtxos.length ? 'Change Selected UTXOs' : 'Advanced UTXO Select'}
          </div>
        )}

        <Select
          loading={feesLoading}
          label='Fee'
          value={feeToken}
          options={usableFees}
          onSelect={i => {
            setFeeToken(i.target.value);
            setSelectedUtxos([]);
            setSelectedFeeUtxos([]);
          }}
          error="No balance to pay fees"
        />

        <Input
          label='Message'
          placeholder='-'
          value={metadata}
          onChange={i => setMetadata(i.target.value || '')}
        />

        <div className={styles.buttons}>
          <Button
            onClick={handleClose}
            type='outline'
            className={styles.button}
          >
            CANCEL
          </Button>

          <Button
            className={styles.button}
            onClick={() => {
              ledgerConnect
                ? setLedgerModal(true)
                : submit({ useLedgerSign: false });
            }}
            type='primary'
            loading={loading}
            tooltip='Your transfer transaction is still pending. Please wait for confirmation.'
            disabled={disabledTransfer}
          >
            {ledgerConnect ? 'TRANSFER WITH LEDGER' : 'TRANSFER'}
          </Button>
        </div>
      </>
    );
  }

  return (
    <Modal open={open}>
      {!ledgerModal && !utxoPicker && renderTransferScreen()}
      {!ledgerModal && utxoPicker && renderUtxoPicker()}
      {ledgerModal && (
        <LedgerPrompt
          loading={loading}
          submit={submit}
          handleClose={handleClose}
          typedData={typedData}
        />
      )}
    </Modal>
  );
}
Example #27
Source File: MergeModal.js    From web-wallet with Apache License 2.0 4 votes vote down vote up
function MergeModal ({ open }) {
  const dispatch = useDispatch();

  const [ selectedUTXOs, setSelectedUTXOs ] = useState([]);
  const [ searchUTXO, setSearchUTXO ] = useState('');
  const [ utxos, setUtxos ] = useState([]);
  const [ ledgerModal, setLedgerModal ] = useState(false);
  const [ typedData, setTypedData ] = useState({});

  const loading = useSelector(selectLoading([ 'TRANSFER/CREATE' ]));
  const ledgerConnect = useSelector(selectLedger);

  useEffect(() => {
    async function fetchUTXOS () {
      const _utxos = await networkService.getUtxos();
      const utxos = orderBy(_utxos, i => i.currency, 'desc');
      setUtxos(utxos);
    }
    if (open) {
      fetchUTXOS();
    }
  }, [ open ]);

  useEffect(() => {
    if (selectedUTXOs.length) {
      setSearchUTXO(selectedUTXOs[0].currency);
      const { typedData } = networkService.getMergeTypedData(selectedUTXOs);
      setTypedData(typedData);
    }
    if (!selectedUTXOs.length) {
      setSearchUTXO('');
    }
  }, [ selectedUTXOs ]);

  async function submit ({ useLedgerSign }) {
    if (selectedUTXOs.length > 1 && selectedUTXOs.length < 5) {
      const res = await dispatch(mergeUtxos(useLedgerSign, selectedUTXOs));
      if (res) {
        dispatch(setActiveHistoryTab('Transactions'));
        dispatch(openAlert('Merge submitted. You will be blocked from making further transactions until the merge is confirmed.'));
        handleClose();
      }
    }
  }

  function handleClose () {
    setSelectedUTXOs([]);
    setSearchUTXO('');
    setLedgerModal(false);
    dispatch(closeModal('mergeModal'));
  }

  function handleUtxoClick (utxo) {
    const isSelected = selectedUTXOs.some(i => i.utxo_pos === utxo.utxo_pos);
    if (isSelected) {
      setSelectedUTXOs(selectedUTXOs.filter(i => i.utxo_pos !== utxo.utxo_pos));
    }
    if (!isSelected && selectedUTXOs.length < 4) {
      setSelectedUTXOs([ ...selectedUTXOs, utxo ]);
    }
  }

  function renderMergeScreen () {
    const _utxos = utxos
      .filter(i => i.currency.includes(searchUTXO))
      .filter(i => i);

    return (
      <>
        <h2>Merge UTXOs</h2>
        <div className={styles.disclaimer}>Select the UTXOs you want to merge</div>

        <div className={styles.list}>
          {!utxos.length && (
            <div className={styles.disclaimer}>You do not have any UTXOs on the OMG Network.</div>
          )}
          {_utxos.map((i, index) => {
            const selected = selectedUTXOs.some(selected => selected.utxo_pos === i.utxo_pos);
            return (
              <div
                key={index}
                onClick={() => handleUtxoClick(i)}
                className={[
                  styles.utxo,
                  selected ? styles.selected : ''
                ].join(' ')}
              >
                <div className={styles.title}>
                  {i.tokenInfo.name}
                </div>

                <div className={styles.value}>
                  <div className={styles.amount}>
                    {logAmount(i.amount.toString(), i.tokenInfo.decimals)}
                  </div>

                  <div className={styles.check}>
                    {selected && <Check />}
                  </div>
                </div>
              </div>
            );
          })}
        </div>

        <div className={styles.disclaimer}>You can select a maximum of 4 UTXOs to merge at once.</div>

        <div className={styles.buttons}>
          <Button
            onClick={handleClose}
            type='outline'
            className={styles.button}
          >
            CANCEL
          </Button>
          {ledgerConnect ? (
            <Button
              onClick={() => setLedgerModal(true)}
              type='primary'
              className={styles.button}
              loading={loading}
              tooltip='Your merge transaction is still pending. Please wait for confirmation.'
              disabled={selectedUTXOs.length <= 1 || selectedUTXOs.length > 4}
            >
            MERGE WITH LEDGER
            </Button>) : (
            <Button
              onClick={submit}
              type='primary'
              className={styles.button}
              loading={loading}
              tooltip='Your merge transaction is still pending. Please wait for confirmation.'
              disabled={selectedUTXOs.length <= 1 || selectedUTXOs.length > 4}
            >
            MERGE
            </Button>)}
        </div>
      </>
    );
  }

  return (
    <Modal open={open}>
      {!ledgerModal && renderMergeScreen()}
      {ledgerModal && (
        <LedgerPrompt
          loading={loading}
          submit={submit}
          handleClose={handleClose}
          typedData={typedData}
        />
      )}
    </Modal>
  );
}
Example #28
Source File: SelectStep.js    From web-wallet with Apache License 2.0 4 votes vote down vote up
function SelectStep ({
  setSelectedUTXO,
  selectedUTXO,
  handleClose,
  setStep,
  gasPrice,
  setGasPrice,
  selectedSpeed,
  setSelectedSpeed
}) {
  const dispatch = useDispatch();

  const [ utxos, setUtxos ] = useState([]);
  const [ searchUTXO, setSearchUTXO ] = useState('');

  const submitLoading = useSelector(selectLoading([
    `QUEUE/GET_${selectedUTXO ? selectedUTXO.currency : ''}`,
    'EXIT/CREATE'
  ]));

  useEffect(() => {
    async function fetchUTXOS () {
      const _utxos = await networkService.getUtxos();
      const utxos = orderBy(_utxos, i => i.currency, 'desc');
      setUtxos(utxos);
    }
    fetchUTXOS();
  }, []);

  async function doCheckExitQueue () {
    const res = await dispatch(checkForExitQueue(selectedUTXO.currency));
    if (!res) {
      return setStep(2);
    }
    return doExit();
  }

  async function doExit () {
    const res = await dispatch(exitUtxo(selectedUTXO, gasPrice));
    if (res) {
      dispatch(openAlert('Exit submitted. You will be blocked from making further transactions until the exit is confirmed.'));
      handleClose();
    }
  }

  const _utxos = useMemo(() => {
    return utxos.filter(i => {
      return i.currency.toLowerCase().includes(searchUTXO.toLowerCase()) ||
        i.tokenInfo.name.toLowerCase().includes(searchUTXO.toLowerCase());
    }).filter(i => !!i);
  }, [ utxos, searchUTXO ]);

  function closeModal () {
    setSearchUTXO('');
    setSelectedSpeed('normal');
    handleClose();
  }

  return (
    <>
      <h2>Start Standard Exit</h2>

      <Input
        label='Select a UTXO to exit from the OMG Network'
        icon
        placeholder='Search by token'
        value={searchUTXO}
        onChange={i => setSearchUTXO(i.target.value)}
      />

      <div className={styles.list}>
        {!utxos.length && (
          <div className={styles.disclaimer}>You do not have any UTXOs on the OMG Network.</div>
        )}
        {_utxos.map((i, index) => {
          return (
            <div
              key={index}
              onClick={() => setSelectedUTXO(i)}
              className={[
                styles.utxo,
                selectedUTXO === i ? styles.selected : ''
              ].join(' ')}
            >
              <div className={styles.title}>
                {i.tokenInfo.name}
              </div>

              <div className={styles.value}>
                <div className={styles.amount}>
                  {logAmount(i.amount.toString(), i.tokenInfo.decimals)}
                </div>

                <div className={styles.check}>
                  {selectedUTXO === i && <Check />}
                </div>
              </div>
            </div>
          );
        })}
      </div>

      <GasPicker
        selectedSpeed={selectedSpeed}
        setSelectedSpeed={setSelectedSpeed}
        setGasPrice={setGasPrice}
      />

      <div className={styles.buttons}>
        <Button
          onClick={closeModal}
          type='outline'
          style={{ flex: 0 }}
        >
          CANCEL
        </Button>
        <Button
          onClick={doCheckExitQueue}
          type='primary'
          style={{ flex: 0 }}
          loading={submitLoading}
          tooltip='Your exit transaction is still pending. Please wait for confirmation.'
          disabled={!selectedUTXO}
        >
          SUBMIT EXIT
        </Button>
      </div>
    </>
  );
}
Example #29
Source File: MultiLinePlot.jsx    From covince with MIT License 4 votes vote down vote up
MultiLinePlot = props => {
  const {
    activeLineages,
    area_data,
    chartZoom,
    className,
    darkMode,
    date,
    groupStackedColours = true,
    height = 120,
    parameter,
    preset: deprecatedPreset,
    setDate,
    stroke = 'blueGray',
    tooltipEnabled,
    type,
    width,
    /* xAxis: xAxisConfig = {}, */
    yAxis: yAxisConfig,
    zoomEnabled
  } = props

  const preset = useMemo(() => {
    if (parameter && parameter.format === 'percentage') return 'percentage'

    // back compat
    if (deprecatedPreset) return deprecatedPreset
    if (parameter && parameter.id === 'p') return 'percentage'

    return null
  }, [parameter, deprecatedPreset])

  const precision = useMemo(() => {
    return parameter ? parameter.precision : undefined
  }, [parameter])

  const chart = useMemo(() => {
    const dataByDate = {}
    const lineageSum = {}

    for (const d of area_data) {
      if (d.parameter === parameter.id && d.lineage !== 'total') {
        const next = {
          ...dataByDate[d.date],
          date: d.date,
          [d.lineage]: d.mean,
          [`${d.lineage}_range`]: d.range
        }
        if (d.lineage in activeLineages && activeLineages[d.lineage].active) {
          next.maxY = Math.max(next.maxY || 0, d.range[1] || d.mean)
          next.sumY = (next.sumY || 0) + d.mean
        }
        dataByDate[d.date] = next
        const sum = lineageSum[d.lineage] || 0
        lineageSum[d.lineage] = (sum + d.mean)
      }
    }

    const data =
      orderBy(Object.values(dataByDate), 'date', 'asc')
        .map((d, index) => ({ ...d, index }))

    const dates = data.map(_ => _.date)

    const lineages = []
    for (const lineage of Object.keys(lineageSum)) {
      const { active, colour } = activeLineages[lineage]
      if (active) {
        lineages.push({ lineage, colour, average: lineageSum[lineage] / dates.length })
      }
    }

    const ordered = orderBy(lineages, 'average', 'asc')
    let sorted

    if (groupStackedColours) {
      sorted = []
      while (ordered.length > 0) {
        const [item] = ordered.splice(0, 1)
        if (sorted.includes(item)) continue
        sorted.push(item)
        for (let i = 0; i < ordered.length; i++) {
          const other = ordered[i]
          if (item.colour === other.colour) {
            sorted.push(other)
          }
        }
      }
    } else {
      sorted = ordered
    }

    return {
      lineages: sorted,
      data,
      dates
    }
  }, [area_data, activeLineages, groupStackedColours])

  const { data, dates } = chart

  const chartProps = useMemo(() => ({
    width,
    height,
    margin: { top: 12, left: 0, right: 24 }
  }), [width, height])

  const { dateRange, setChartZoom, clearChartZoom } = chartZoom

  const xAxisDomain = useMemo(() => {
    const minIndex = 0
    const maxIndex = data.length - 1
    if (dateRange && dates.length) {
      const [minDate, maxDate] = dateRange
      const min = minDate ? Math.max(dates.indexOf(minDate), minIndex) : minIndex
      let max = maxDate ? dates.indexOf(maxDate) : maxIndex
      if (max === -1) max = maxIndex
      return min < max ? [min, max] : [max, min]
    }
    return [minIndex, maxIndex]
  }, [dateRange, dates])

  const xAxisProps = useMemo(() => {
    const indices = Object.keys(dates)
    let ticks = indices
    if (dateRange) {
      const [minIndex, maxIndex] = xAxisDomain
      ticks = indices.slice(minIndex, maxIndex + 1)
    }
    return {
      allowDataOverflow: true,
      dataKey: 'index',
      domain: xAxisDomain,
      ticks,
      type: 'number'
    }
  }, [xAxisDomain, dates])

  const [zoomArea, setZoomArea] = React.useState({})
  const [isHovering, setIsHovering] = React.useState(false)

  const eventHandlers = useMemo(() => {
    const clickHandlers = {
      onClick: item => {
        if (date && item && !zoomArea.dragged) { // do not set date if not visible on chart
          setDate(data[item.activeLabel].date)
        }
        if (zoomEnabled) {
          setZoomArea({ dragged: zoomArea.dragged })
        }
      },
      onMouseDown: e => {
        if (e && zoomEnabled) {
          setZoomArea({ start: e.activeLabel, end: e.activeLabel, dragged: false })
        }
      },
      onMouseMove: e => {
        if (e) {
          setIsHovering(e.activeLabel !== undefined)
          if (zoomArea.start === undefined) return
          let end = e.activeLabel
          if (e.activeLabel === undefined) { // outside of axes
            end = xAxisDomain[zoomArea.end >= data.length / 2 ? 1 : 0]
          }
          setZoomArea({ start: zoomArea.start, end, dragged: true })
        }
      },
      onMouseLeave: e => {
        setIsHovering(false)
      },
      onMouseUp: (_, e) => {
        if (zoomArea.end !== zoomArea.start) {
          const xStart = data[zoomArea.start].date
          const xEnd = data[zoomArea.end].date
          const args = xStart < xEnd ? [xStart, xEnd] : [xEnd, xStart]
          setChartZoom(...args)
        }
        setZoomArea({ dragged: zoomArea.dragged })
      }
    }
    if (!tooltipEnabled) { // touch handlers need to be replaced when tooltip is missing
      return {
        ...clickHandlers,
        onTouchStart: clickHandlers.onMouseDown,
        onTouchMove: clickHandlers.onMouseMove,
        onTouchEnd: clickHandlers.onMouseUp
      }
    }
    return clickHandlers
  }, [zoomEnabled, data, zoomArea, isHovering])

  const cursor = useMemo(() => {
    if (zoomArea.start) return 'ew-resize'
    if (isHovering) return 'crosshair'
    return undefined
  }, [zoomArea, isHovering])

  return (
    <div
      className={classNames('relative select-none focus:outline-none', className)}
      onDoubleClick={clearChartZoom}
    >
      <MainChart
        {...{
          ...chartProps,
          ...eventHandlers,
          activeLineages,
          chart,
          dateRange,
          cursor,
          darkMode,
          precision,
          preset,
          stroke,
          tooltipEnabled,
          type,
          xAxisProps,
          yAxisConfig,
          zoomArea
        }}
      />
      <div className='absolute top-0 left-0 pointer-events-none'>
        <ComposedChart {...chartProps} data={data}>
          <XAxis
            {...xAxisProps}
            tick={false}
            stroke='none'
          />
          <YAxis
            width={48}
            tick={false}
            stroke='none'
          />
          <ReferenceLine
            x={dates.indexOf(date)}
            stroke={tailwindColors[stroke][darkMode ? 300 : 400]}
            label=''
            strokeWidth={2}
            style={{ mixBlendMode: darkMode ? 'screen' : 'multiply' }}
          />
        </ComposedChart>
      </div>
    </div>
  )
}