Skip to content

Commit

Permalink
Merge pull request #1764 from Shopify/jorge/grid-grey-out-groups
Browse files Browse the repository at this point in the history
Add disabled groups
  • Loading branch information
mollerjorge authored Dec 2, 2024
2 parents 21981f1 + beccc58 commit 725784d
Show file tree
Hide file tree
Showing 9 changed files with 274 additions and 25 deletions.
10 changes: 9 additions & 1 deletion packages/polaris-viz/src/components/Grid/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
SMALL_CONTAINER_WIDTH,
SMALL_CONTAINER_HEIGHT,
DEFAULT_BOUNDS,
DISABLED_GROUP_COLOR,
DISABLED_TEXT_COLOR,
} from './utilities/constants';
import type {
CellGroup,
Expand Down Expand Up @@ -143,7 +145,7 @@ export function Grid(props: GridProps) {

const handleGroupHover = useCallback(
(group: CellGroup | null) => {
if (!isSmallContainer) {
if (!isSmallContainer && group?.value !== null) {
if (group) {
const activeGroups = getActiveGroups(group);
setHoveredGroups(activeGroups);
Expand Down Expand Up @@ -211,6 +213,12 @@ export function Grid(props: GridProps) {
]);

const getColors = (group: CellGroup | null) => {
if (group?.value === null) {
return {
bgColor: DISABLED_GROUP_COLOR,
textColor: DISABLED_TEXT_COLOR,
};
}
if (group) {
return {
bgColor: group.bgColor || DEFAULT_GROUP_COLOR,
Expand Down
42 changes: 31 additions & 11 deletions packages/polaris-viz/src/components/Grid/components/Background.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface BackgroundProps {
height: number;
fill: string;
opacity: number;
isDisabled?: boolean;
}

export const Background = ({
Expand All @@ -16,18 +17,37 @@ export const Background = ({
height,
fill,
opacity,
isDisabled,
}: BackgroundProps) => {
const adjustedWidth = Math.max(0, width - BACKGROUND_GAP);
const adjustedHeight = Math.max(0, height - BACKGROUND_GAP);

return (
<rect
x={x + BACKGROUND_GAP / 2}
y={y + BACKGROUND_GAP / 2}
width={Math.max(0, width - BACKGROUND_GAP)}
height={Math.max(0, height - BACKGROUND_GAP)}
fill={fill}
strokeWidth="4"
rx="4"
ry="4"
opacity={opacity}
/>
<g>
<rect
x={x + BACKGROUND_GAP / 2}
y={y + BACKGROUND_GAP / 2}
width={adjustedWidth}
height={adjustedHeight}
fill={fill}
rx="4"
ry="4"
opacity={opacity}
/>
{isDisabled && (
<rect
x={x + BACKGROUND_GAP / 2 + 1}
y={y + BACKGROUND_GAP / 2 + 1}
width={adjustedWidth - 2}
height={adjustedHeight - 2}
fill="none"
stroke="#E3E3E3"
strokeWidth="1"
strokeDasharray="4 4"
rx="3"
ry="3"
/>
)}
</g>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
}

.GroupCellContainerSelected {
// stylelint-disable declaration-no-important
outline: 2px solid $color-blue-100 !important;
outline-offset: -1px;
border-radius: 4px;
// stylelint-enable declaration-no-important
&:not([data-disabled='true']) {
outline: 2px solid $color-blue-100;
outline-offset: -1px;
border-radius: 4px;
}
}

@keyframes FadeInScale {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,11 @@ export const GroupCell: React.FC<GroupCellProps> = ({
style={{opacity}}
role="button"
data-testid="group-cell"
data-disabled={group.value === null}
onClick={() => {
handleSelectGroup(group);
if (group.value !== null) {
handleSelectGroup(group);
}
}}
onMouseEnter={() => {
if (!groupSelected) {
Expand Down Expand Up @@ -139,6 +142,7 @@ export const GroupCell: React.FC<GroupCellProps> = ({
height={groupHeight}
fill={getColors(group).bgColor}
opacity={opacity}
isDisabled={group.value === null}
/>

<GroupInfo
Expand Down
26 changes: 21 additions & 5 deletions packages/polaris-viz/src/components/Grid/components/GroupInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface GroupInfoProps {
getColors: (group: any) => {textColor: string};
opacity: number;
mainFontSize: number;
groupValue: string;
groupValue: string | null;
showNameAndSecondaryValue: boolean;
secondaryFontSize: number;
groupSecondaryValue: string;
Expand Down Expand Up @@ -58,6 +58,26 @@ export const GroupInfo: React.FC<GroupInfoProps> = ({
[characterWidths, dimensions],
);

const truncatedGroupName = showNameAndSecondaryValue
? getTruncatedText(group.name, groupWidth * GROUP_NAME_WIDTH_MULTIPLIER)
: '';

if (groupValue === null) {
return (
<text
x={groupX + groupNameOffset}
y={groupY + groupNameOffset}
textAnchor="start"
dominantBaseline="hanging"
fontSize={LABEL_FONT_SIZE}
fill={getColors(group).textColor}
opacity={opacity}
>
{truncatedGroupName}
</text>
);
}

const valueAndSecondaryValue = showNameAndSecondaryValue
? `${groupValue}${VALUES_DIVIDER}${groupSecondaryValue}`
: groupValue;
Expand All @@ -70,10 +90,6 @@ export const GroupInfo: React.FC<GroupInfoProps> = ({
const truncatedSecondaryValue =
truncatedValueAndSecondaryValue.split(VALUES_DIVIDER)[1];

const truncatedGroupName = showNameAndSecondaryValue
? getTruncatedText(group.name, groupWidth * GROUP_NAME_WIDTH_MULTIPLIER)
: '';

const textYOffset = showNameAndSecondaryValue
? TEXT_Y_OFFSET_WITH_SECONDARY
: 0;
Expand Down
153 changes: 152 additions & 1 deletion packages/polaris-viz/src/components/Grid/stories/data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const CELL_GROUPS: CellGroup[] = [
start: {row: 0, col: 0},
end: {row: 0, col: 1},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
value: '0',
bgColor: '#B1C3F7',
color: '#000000',
name: 'Previously loyal',
Expand Down Expand Up @@ -169,6 +169,157 @@ export const CELL_GROUPS: CellGroup[] = [
},
];

export const MISSING_CELL_GROUPS: CellGroup[] = [
{
id: 'previously_loyal',
start: {row: 0, col: 0},
end: {row: 0, col: 1},
secondaryValue: getRandomPercentage(),
value: null,
bgColor: '#B1C3F7',
color: '#000000',
name: 'Previously loyal',
connectedGroups: ['loyal'],
description:
'Customers without recent purchases, but with a very strong history of orders and spend.',
goal: 'Goal: move customers to Loyal',
metricInformation: '1,424 (10.9% of customer base)',
},
{
id: 'at_risk',
start: {row: 1, col: 0},
end: {row: 2, col: 1},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
bgColor: '#CBD7F9',
color: '#000000',
name: 'At risk',
metricInformation: '1,424 (10.9% of customer base)',
connectedGroups: ['needs_attention', 'loyal'],
description:
'Customers without recent purchases, but with a strong history of orders and spend.',
goal: 'Goal: move customers to Loyal or Needs Attention',
},
{
id: 'dormant',
start: {row: 3, col: 0},
end: {row: 4, col: 1},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
bgColor: '#E5EBFC',
color: '#000000',
name: 'Dormant',
connectedGroups: ['almost_lost'],
description:
'Customers without recent orders, with infrequent orders, and with low spend.',
goal: 'Goal: move customers to Almost lost',
metricInformation: '1,424 (10.9% of customer base)',
},
{
id: 'loyal',
start: {row: 0, col: 2},
end: {row: 1, col: 3},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
bgColor: '#0B2062',
color: '#FFFFFF',
name: 'Loyal',
connectedGroups: ['champions'],
description:
'Customers without recent purchases, but with a very strong history of orders and spend.',
goal: 'Goal: move customers to Loyal',
metricInformation: '1,424 (10.9% of customer base)',
},
{
id: 'needs_attention',
start: {row: 2, col: 2},
end: {row: 2, col: 2},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
bgColor: '#3E69EA',
color: '#FFFFFF',
name: 'Needs attention',
connectedGroups: ['loyal', 'active'],
description:
'Customers who buy less recently, order sometimes and spend moderately with your store.',
goal: 'Goal: move customers to Loyal or Potential',
metricInformation: '1,424 (10.9% of customer base)',
},
{
id: 'almost_lost',
start: {row: 3, col: 2},
end: {row: 4, col: 2},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
bgColor: '#7594F0',
color: '#000000',
name: 'Almost lost',
connectedGroups: ['active', 'promising'],
description:
'Customers without recent purchases, fewer orders, and with lower spend.',
goal: 'Goal: move customers to Active or Promising',
metricInformation: '1,424 (10.9% of customer base)',
},
{
id: 'promising',
start: {row: 4, col: 3},
end: {row: 4, col: 3},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
bgColor: '#194BE3',
color: '#FFFFFF',
name: 'Promising',
connectedGroups: ['active'],
description: 'Customers with recent purchases, few orders, and low spend.',
goal: 'Goal: move customers to Active.',
metricInformation: '1,424 (10.9% of customer base)',
},
{
id: 'active',
start: {row: 2, col: 3},
end: {row: 3, col: 4},
secondaryValue: getRandomPercentage(),
value: null,
bgColor: '#0D297C',
color: '#FFFFFF',
name: 'Active',
connectedGroups: ['loyal', 'champions'],
description:
'Customers with recent purchases, some orders, and moderate spend.',
goal: 'Goal: move customers to Champions or Loyal',
metricInformation: '1,424 (10.9% of customer base)',
},
{
id: 'new',
start: {row: 4, col: 4},
end: {row: 4, col: 4},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
bgColor: '#133AAF',
color: '#FFFFFF',
name: 'New',
connectedGroups: ['active'],
description:
'Clients ayant effectué des achats très récemment, ayant passé peu de commandes et ayant dépensé peu dargent.',
goal: 'Goal: move customers to Active',
metricInformation: '1,424 (10.9% of customer base)',
},
{
id: 'champions',
start: {row: 0, col: 4},
end: {row: 1, col: 4},
secondaryValue: getRandomPercentage(),
value: getRandomValue(),
bgColor: '#081848',
color: '#FFFFFF',
name: 'Champions',
description:
'Customers with very recent purchases, many orders, and the most spend.',
goal: null,
metricInformation: '1,424 (10.9% of customer base)',
},
];

export const RANDOM_CELL_GROUPS: CellGroup[] = [
{
id: 'revenue',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type {Story} from '@storybook/react';

import {Grid} from '../../Grid';
import type {GridProps} from '../../Grid';
import {MISSING_CELL_GROUPS} from '../data';
import {META} from '../meta';

export default {
...META,
title: `${META.title}/Playground`,
decorators: [],
};

function GridCard(args: GridProps) {
return (
<div
style={{
height: 400,
width: 800,
background: 'white',
borderRadius: '8px',
padding: 10,
}}
>
<Grid {...args} />
</div>
);
}

const Template: Story<GridProps> = (args: GridProps) => {
return (
<div style={{display: 'flex', gap: '20px'}}>
<GridCard {...args} />
</div>
);
};

export const FilteredGroups = Template.bind({});

FilteredGroups.args = {
cellGroups: MISSING_CELL_GROUPS,
xAxisOptions: {
label: 'Recency',
},
yAxisOptions: {
label: 'Frequency',
},
};
2 changes: 1 addition & 1 deletion packages/polaris-viz/src/components/Grid/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface CellGroup {
goal: string | null;
connectedGroups?: string[];
secondaryValue: string;
value: string;
value: string | null;
metricInformation?: string;
}

Expand Down
Loading

0 comments on commit 725784d

Please sign in to comment.