diff --git a/src/components/Badge.js b/src/components/Badge.js index 666f63601..90f5c183d 100644 --- a/src/components/Badge.js +++ b/src/components/Badge.js @@ -1,13 +1,27 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {omit} from 'ramda'; import {Badge as RSBadge} from 'reactstrap'; +import Link from '../private/Link'; const Badge = props => { - const {children, loading_state, ...otherProps} = props; + const {children, href, loading_state, setProps, ...otherProps} = props; + + const incrementClicks = () => { + if (setProps) { + setProps({ + n_clicks: props.n_clicks + 1, + n_clicks_timestamp: Date.now() + }); + } + }; + + otherProps[href ? 'preOnClick' : 'onClick'] = incrementClicks; + return ( { ); }; +Badge.defaultProps = { + n_clicks: 0, + n_clicks_timestamp: -1 +}; + Badge.propTypes = { /** * The ID of this component, used to identify dash components @@ -84,7 +103,30 @@ Badge.propTypes = { * Holds the name of the component that is loading */ component_name: PropTypes.string - }) + }), + + /** + * If true, the browser will treat this as an external link, + * forcing a page refresh at the new location. If false, + * this just changes the location without triggering a page + * refresh. Use this if you are observing dcc.Location, for + * instance. Defaults to true for absolute URLs and false + * otherwise. + */ + external_link: PropTypes.bool, + + /** + * An integer that represents the number of times + * that this element has been clicked on. + */ + n_clicks: PropTypes.number, + + /** + * An integer that represents the time (in ms since 1970) + * at which n_clicks changed. This can be used to tell + * which button was changed most recently. + */ + n_clicks_timestamp: PropTypes.number }; export default Badge; diff --git a/src/components/__tests__/Badge.test.js b/src/components/__tests__/Badge.test.js new file mode 100644 index 000000000..d4a79b81e --- /dev/null +++ b/src/components/__tests__/Badge.test.js @@ -0,0 +1,25 @@ +import React from 'react'; +import {mount, shallow} from 'enzyme'; + +import Badge from '../Badge'; + +describe('Badge', () => { + it('should track clicks', () => { + const mockSetProps = jest.fn(); + const wrapper = shallow(Badge); + wrapper.simulate('click'); + expect(mockSetProps.mock.calls).toHaveLength(1); + expect(mockSetProps.mock.calls[0][0].n_clicks).toBe(1); + expect(typeof mockSetProps.mock.calls[0][0].n_clicks_timestamp).toBe( + 'number' + ); + }); + + it('should render as link when href is set', () => { + const href = '#href'; + const wrapper = mount(Badge); + const linkComponent = wrapper.find('a'); + expect(linkComponent.exists()).toBe(true); + expect(linkComponent.prop('href')).toEqual(href); + }); +});