Skip to content

Commit

Permalink
refactor: major refactor of Chip.js (#488)
Browse files Browse the repository at this point in the history
  • Loading branch information
martinkrulltott authored Nov 27, 2019
1 parent 9969e61 commit 188f651
Showing 1 changed file with 120 additions and 110 deletions.
230 changes: 120 additions & 110 deletions packages/app/src/components/Layout/Chip.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,29 @@ import {
getDisplayNameByVisType,
getAxisName,
} from '@dhis2/analytics';
import PropTypes from 'prop-types';

import Menu from './Menu';
import Tooltip from './Tooltip';
import { setDataTransfer } from '../../modules/dnd';
import { sGetDimensions } from '../../reducers/dimensions';
import { sGetUiItemsByDimension, sGetUiType } from '../../reducers/ui';
import DynamicDimensionIcon from '../../assets/DynamicDimensionIcon';
import { sGetMetadata } from '../../reducers/metadata';
import { styles } from './styles/Chip.style';

const TOOLTIP_ENTER_DELAY = 500;

const emptyItems = [];
const LockIconWrapper = (
<div style={styles.lockIconWrapper}>
<LockIcon style={styles.lockIcon} />
</div>
);

const WarningIconWrapper = (
<div style={styles.warningIconWrapper}>
<WarningIcon style={styles.warningIcon} />
</div>
);

class Chip extends React.Component {
state = {
Expand All @@ -34,6 +44,16 @@ class Chip extends React.Component {

timeout = null;

isLocked = getLockedDimensionAxis(
this.props.type,
this.props.dimensionId
).includes(this.props.axisId);

maxNumberOfItemsPerAxis = getMaxNumberOfItemsPerAxis(
this.props.type,
this.props.axisId
);

handleMouseOver = () => {
if (this.timeout === null) {
this.timeout = setTimeout(
Expand Down Expand Up @@ -62,13 +82,39 @@ class Chip extends React.Component {
this.handleMouseOut();
};

getDragStartHandler = source => e => {
getDragStartHandler = () => event => {
this.handleMouseOut();

setDataTransfer(e, source);
setDataTransfer(event, this.props.axisId);
};

getAnchorEl = () => document.getElementById(this.id);

getWrapperStyles = () => ({
...styles.chipWrapper,
...(!this.props.items.length ? styles.chipEmpty : {}),
});

renderChipLabel = () => {
const numberOfItems = this.props.items.length;

const getItemsLabel =
!!this.maxNumberOfItemsPerAxis &&
numberOfItems > this.maxNumberOfItemsPerAxis
? i18n.t(`{{total}} of {{maxNumberOfItemsPerAxis}} selected`, {
total: numberOfItems,
maxNumberOfItemsPerAxis: this.maxNumberOfItemsPerAxis,
})
: i18n.t('{{total}} selected', {
total: numberOfItems,
});

return `${this.props.dimensionName}${
this.props.items.length > 0 ? `: ${getItemsLabel}` : ''
}`;
};

getIconByDimension = () => {
renderChipIcon = () => {
const fixedDimension = FIXED_DIMENSIONS[this.props.dimensionId];

if (fixedDimension) {
Expand All @@ -79,128 +125,92 @@ class Chip extends React.Component {
return <DynamicDimensionIcon style={styles.dynamicDimensionIcon} />;
};

// TODO refactor this very long function
renderChip = () => {
const axisId = this.props.axisId;
const visType = this.props.type;
const numberOfItems = this.props.items.length;

const isLocked = getLockedDimensionAxis(
visType,
this.props.dimensionId
).includes(axisId);
renderMenu = () => (
<div style={styles.chipRight}>
<Menu
dimensionId={this.props.dimensionId}
currentAxisId={this.props.axisId}
visType={this.props.type}
numberOfDimensionItems={this.props.items.length}
/>
</div>
);

renderTooltip = () => {
const activeItemIds = !!this.maxNumberOfItemsPerAxis
? this.props.items.slice(0, this.maxNumberOfItemsPerAxis)
: this.props.items;

const lockedMessage = isLocked
const lockedLabel = this.isLocked
? i18n.t(
`{{dimensionName}} is locked to {{axisName}} for {{visTypeName}}`,
{
dimensionName: this.props.dimensionName,
axisName: getAxisName(axisId),
visTypeName: getDisplayNameByVisType(visType),
axisName: getAxisName(this.props.axisId),
visTypeName: getDisplayNameByVisType(this.props.type),
}
)
: null;

const maxNumberOfItemsPerAxis = getMaxNumberOfItemsPerAxis(
visType,
axisId
return (
<Tooltip
dimensionId={this.props.dimensionId}
itemIds={activeItemIds}
lockedLabel={lockedLabel}
displayLimitedAmount={
this.props.items.length > activeItemIds.length
}
open={this.state.tooltipOpen}
anchorEl={this.getAnchorEl()}
/>
);
};

const hasMaxNumberOfItemsRule = !!maxNumberOfItemsPerAxis;

const itemsLabel =
hasMaxNumberOfItemsRule && numberOfItems > maxNumberOfItemsPerAxis
? i18n.t(`{{total}} of {{maxNumberOfItemsPerAxis}} selected`, {
total: numberOfItems,
maxNumberOfItemsPerAxis,
})
: i18n.t('{{total}} selected', {
total: numberOfItems,
});

const activeItemIds = hasMaxNumberOfItemsRule
? this.props.items.slice(0, maxNumberOfItemsPerAxis)
: this.props.items;

const chipLabel = `${this.props.dimensionName}${
numberOfItems > 0 ? `: ${itemsLabel}` : ''
}`;
const anchorEl = document.getElementById(this.id);
const icon = this.getIconByDimension();
const wrapperStyle = {
...styles.chipWrapper,
...(!numberOfItems ? styles.chipEmpty : {}),
};
const warningIcon = hasTooManyItemsPerAxis(
visType,
axisId,
numberOfItems
) ? (
<div style={styles.warningIconWrapper}>
<WarningIcon style={styles.warningIcon} />
</div>
) : null;

const lockIcon = isLocked ? (
<div style={styles.lockIconWrapper}>
<LockIcon style={styles.lockIcon} />
</div>
) : null;

return (
render = () => (
<div
style={this.getWrapperStyles()}
data-dimensionid={this.props.dimensionId}
draggable={!this.isLocked}
onDragStart={this.getDragStartHandler()}
>
<div
style={wrapperStyle}
data-dimensionid={this.props.dimensionId}
draggable={!isLocked}
onDragStart={this.getDragStartHandler(this.props.axisId)}
id={this.id}
style={styles.chipLeft}
onClick={this.handleClick}
onMouseOver={this.handleMouseOver}
onMouseOut={this.handleMouseOut}
>
<div
id={this.id}
style={styles.chipLeft}
onClick={this.handleClick}
onMouseOver={this.handleMouseOver}
onMouseOut={this.handleMouseOut}
>
<div style={styles.iconWrapper}>{icon}</div>
{chipLabel}
{warningIcon}
{lockIcon}
</div>
{!isLocked && (
<div style={styles.chipRight}>
<Menu
dimensionId={this.props.dimensionId}
currentAxisId={this.props.axisId}
visType={this.props.type}
numberOfDimensionItems={this.props.items.length}
/>
</div>
)}
{anchorEl && (
<Tooltip
dimensionId={this.props.dimensionId}
itemIds={activeItemIds}
lockedLabel={lockedMessage}
displayLimitedAmount={
this.props.items.length > activeItemIds.length
}
open={this.state.tooltipOpen}
anchorEl={anchorEl}
/>
)}
<div style={styles.iconWrapper}>{this.renderChipIcon()}</div>
{this.renderChipLabel()}
{hasTooManyItemsPerAxis(
this.props.type,
this.props.axisId,
this.props.items.length
) && WarningIconWrapper}
{this.isLocked && LockIconWrapper}
</div>
);
};

render() {
return this.props.dimensionId ? this.renderChip() : '';
}
{!this.isLocked && this.renderMenu()}
{this.getAnchorEl() && this.renderTooltip()}
</div>
);
}

Chip.propTypes = {
axisId: PropTypes.string.isRequired,
dimensionId: PropTypes.string.isRequired,
dimensionName: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
onClick: PropTypes.func,
items: PropTypes.array,
};

Chip.defaultProps = {
onClick: Function.prototype,
items: [],
};

const mapStateToProps = (state, ownProps) => ({
dimensionName: (sGetDimensions(state)[ownProps.dimensionId] || {}).name,
items: sGetUiItemsByDimension(state, ownProps.dimensionId) || emptyItems,
metadata: sGetMetadata(state),
items: sGetUiItemsByDimension(state, ownProps.dimensionId) || [],
type: sGetUiType(state),
});

Expand Down

0 comments on commit 188f651

Please sign in to comment.