huridocs/uwazi

View on GitHub
app/react/Markdown/components/BarChart.js

Summary

Maintainability
A
0 mins
Test Coverage
A
93%
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import Immutable from 'immutable';

import {
  ResponsiveContainer,
  BarChart,
  XAxis,
  YAxis,
  CartesianGrid,
  Bar,
  Tooltip,
  Cell,
} from 'recharts';

import { Loader } from 'app/components/Elements/Loader';
import { arrayUtils } from 'app/Charts';
import markdownDatasets from '../markdownDatasets';

const objectFlip = obj => {
  const flip = {};
  Object.keys(obj).forEach(key => {
    flip[obj[key]] = key;
  });
  return flip;
};

class BarChartComponent extends Component {
  parseAttributes() {
    const shortLabels = JSON.parse(this.props.shortLabels);
    const sort = JSON.parse(this.props.sort);
    const pluckCategories = JSON.parse(this.props.pluckCategories);
    return { sort, shortLabels, pluckCategories };
  }

  X() {
    if (this.props.layout === 'vertical') {
      return <XAxis type="number" dataKey="results" />;
    }
    return <XAxis dataKey="label" label="" />;
  }

  Y() {
    if (this.props.layout === 'vertical') {
      return <YAxis width={200} type="category" dataKey="label" />;
    }
    return <YAxis />;
  }

  render() {
    const {
      excludeZero,
      maxCategories,
      layout,
      property,
      data,
      classname,
      context,
      scatter,
      colors,
    } = this.props;
    let output = <Loader />;

    if (data) {
      const sliceColors = colors.split(',');
      const aggregateOthers = this.props.aggregateOthers === 'true';
      const { sort, shortLabels, pluckCategories } = this.parseAttributes();
      const shortLabelsFlipped = objectFlip(shortLabels);

      const formattedData = arrayUtils.formatDataForChart(data, property, {
        excludeZero: Boolean(excludeZero),
        context,
        scatter: Boolean(scatter),
        maxCategories,
        aggregateOthers,
        pluckCategories,
        sort,
        labelsMap: shortLabels,
      });

      output = (
        <ResponsiveContainer height={320}>
          <BarChart height={300} data={formattedData} layout={layout}>
            {this.X()}
            {this.Y()}

            <CartesianGrid strokeDasharray="2 4" />
            <Tooltip
              formatter={(value, _name, props) => {
                if (scatter) {
                  const { parent } = props.payload;
                  return shortLabelsFlipped[value] || [value, `\r\n${parent}`];
                }
                return shortLabelsFlipped[value] || value;
              }}
            />
            <Bar dataKey="results" fill="rgb(30, 28, 138)" stackId="unique">
              {formattedData.map((_entry, index) => (
                <Cell
                  // eslint-disable-next-line react/no-array-index-key
                  key={`cell-${index}`}
                  cursor="pointer"
                  fill={sliceColors[index % sliceColors.length]}
                />
              ))}
            </Bar>
          </BarChart>
        </ResponsiveContainer>
      );
    }

    return <div className={`BarChart ${classname}`}>{output}</div>;
  }
}

BarChartComponent.defaultProps = {
  context: 'System',
  scatter: false,
  excludeZero: false,
  layout: 'horizontal',
  maxCategories: '0',
  aggregateOthers: 'false',
  classname: '',
  data: null,
  colors: '#1e1c8a',
  shortLabels: '{}',
  sort: '{}',
  pluckCategories: '[]',
};

BarChartComponent.propTypes = {
  property: PropTypes.string.isRequired,
  context: PropTypes.string,
  scatter: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  excludeZero: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  classname: PropTypes.string,
  layout: PropTypes.string,
  maxCategories: PropTypes.string,
  aggregateOthers: PropTypes.string,
  data: PropTypes.instanceOf(Immutable.List),
  colors: PropTypes.string,
  shortLabels: PropTypes.string,
  sort: PropTypes.string,
  pluckCategories: PropTypes.string,
};

export const mapStateToProps = (state, props) => ({
  data: markdownDatasets.getAggregations(state, props),
  thesauris: state.thesauris,
});

export default connect(mapStateToProps)(BarChartComponent);