Skip to content

Commit

Permalink
feat(c3Chart): issues/283 add base c3 component
Browse files Browse the repository at this point in the history
* c3Chart, adds a c3 wrapper component, initial tests
  • Loading branch information
cdcabrera committed Jun 16, 2020
1 parent ca46b09 commit 958a93b
Show file tree
Hide file tree
Showing 7 changed files with 429 additions and 7 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
}
],
"react/forbid-prop-types": 0,
"react/jsx-curly-newline": 0,
"react/jsx-filename-extension": 0,
"react/jsx-fragments": [ 1, "element" ],
"react/jsx-props-no-spreading": 0,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"@redhat-cloud-services/frontend-components-notifications": "1.0.3",
"@redhat-cloud-services/frontend-components-utilities": "1.0.3",
"axios": "^0.19.2",
"c3": "^0.7.15",
"classnames": "^2.2.6",
"i18next": "^19.4.4",
"i18next-xhr-backend": "^3.2.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`C3Chart Component should pass child components: child components 1`] = `
<div
className="curiosity-c3chart null"
style={Object {}}
>
<div
className="curiosity-c3chart-container"
/>
<div
className="curiosity-c3chart-description"
>
lorem
<span>
ipsum
</span>
</div>
</div>
`;

exports[`C3Chart Component should render a basic component: basic 1`] = `
<div
className="curiosity-c3chart null"
style={Object {}}
>
<div
className="curiosity-c3chart-container"
/>
<div
className="curiosity-c3chart-description"
/>
</div>
`;

exports[`C3Chart Component should return a chart and config reference: references 1`] = `
<div
className="curiosity-c3chart null"
style={Object {}}
>
<div
className="curiosity-c3chart-container"
/>
<div
className="curiosity-c3chart-description"
>
<span>
<Component />
and
{"data":{"columns":[]}}
</span>
</div>
</div>
`;
51 changes: 51 additions & 0 deletions src/components/c3Chart/__tests__/c3Chart.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { C3Chart } from '../c3Chart';

describe('C3Chart Component', () => {
it('should render a basic component', () => {
const props = {};
const component = shallow(<C3Chart {...props} />);

expect(component).toMatchSnapshot('basic');
});

it('should run componentWillUnmount method successfully', () => {
const component = mount(<C3Chart />);
const componentWillUnmount = jest.spyOn(component.instance(), 'componentWillUnmount');
component.unmount();
expect(componentWillUnmount).toHaveBeenCalled();
});

it('should pass child components', () => {
const props = {};
const component = shallow(
<C3Chart {...props}>
lorem <span>ipsum</span>
</C3Chart>
);

expect(component).toMatchSnapshot('child components');
});

it('should return a chart and config reference', () => {
const props = {
config: {
data: {
columns: []
}
}
};
const component = shallow(
<C3Chart {...props}>
{({ chart, config }) => (
<span>
{chart} and {JSON.stringify(config)}
</span>
)}
</C3Chart>
);

expect(component).toMatchSnapshot('references');
});
});
110 changes: 110 additions & 0 deletions src/components/c3Chart/c3Chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from 'react';
import PropTypes from 'prop-types';
import c3 from 'c3';
import _isEqual from 'lodash/isEqual';
import 'c3/c3.min.css';
import { helpers } from '../../common';

/**
* C3 wrapper.
* Uses aspects from https://github.com/bcbcarl/react-c3js and https://github.com/wuct/react-c3-component
*
* @augments React.Component
*/
class C3Chart extends React.Component {
state = { chart: null };

node = React.createRef();

componentDidMount() {
this.generateChart();
}

componentDidUpdate(prevProps) {
const { config } = this.props;

if (!_isEqual(prevProps.config.data, config.data)) {
this.generateChart();
}
}

componentWillUnmount() {
const { chart } = this.state;
if (chart) {
chart.destroy();
}
this.setState({ chart: null });
}

generateChart() {
const { chart } = this.state;
const { config, onComplete } = this.props;

let updatedChart = chart;
if (!updatedChart) {
updatedChart = c3.generate({ bindto: this.node.current, ...config });
}

updatedChart.load({
...config.data,
unload: config.unloadBeforeLoad || false,
done: () => {
this.setState({ chart: updatedChart }, () => {
if (config.done) {
config.done({ chart: updatedChart, config });
} else {
onComplete({ chart: updatedChart, config });
}
});
}
});
}

render() {
const { chart } = this.state;
const { className, children, config, style } = this.props;

return (
<div className={`curiosity-c3chart ${className}`} style={style}>
<div ref={this.node} className="curiosity-c3chart-container" />
{chart && (
<div className="curiosity-c3chart-description">
{(typeof children === 'function' && children({ chart, config })) || children}
</div>
)}
</div>
);
}
}

/**
* Prop types.
*
* @type {{children: Node|Function, onComplete: Function, className: string, style: object, config}}
*/
C3Chart.propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
className: PropTypes.string,
config: PropTypes.shape({
unloadBeforeLoad: PropTypes.bool,
data: PropTypes.object,
done: PropTypes.func
}),
onComplete: PropTypes.func,
style: PropTypes.object
};

/**
* Default props.
*
* @type {{children: null, onComplete: Function, className: null, style: {}, config: {}}}
*/
C3Chart.defaultProps = {
children: null,
className: null,
config: {},
onComplete: helpers.noop,
style: {}
};

export { C3Chart as default, C3Chart };
11 changes: 11 additions & 0 deletions src/setupTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

jest.mock('c3', () => ({
generate: () => ({
destroy: jest.fn(),
focus: jest.fn(),
hide: jest.fn(),
load: ({ done }) => done && done(),
revert: jest.fn(),
toggle: jest.fn()
})
}));

global.window.insights = {
chrome: {
auth: {
Expand Down
Loading

0 comments on commit 958a93b

Please sign in to comment.