From bfcb018f64c81c4ef81f3158f5d1a62ac2320c6c Mon Sep 17 00:00:00 2001 From: Pablo Assanelli Date: Tue, 26 Nov 2024 11:38:24 -0300 Subject: [PATCH] feature, Add support to show CTAs button on group tooltips --- .../polaris-viz/src/components/Grid/Grid.tsx | 17 +++ .../components/Grid/components/Tooltip.scss | 42 +++++- .../components/Grid/components/Tooltip.tsx | 65 ++++++++++ .../src/components/Grid/stories/data.tsx | 120 ++++++++++++++++++ .../polaris-viz/src/components/Grid/types.ts | 7 + .../components/Grid/utilities/constants.ts | 4 +- 6 files changed, 247 insertions(+), 8 deletions(-) diff --git a/packages/polaris-viz/src/components/Grid/Grid.tsx b/packages/polaris-viz/src/components/Grid/Grid.tsx index ab718a1cc..bb7a2e070 100644 --- a/packages/polaris-viz/src/components/Grid/Grid.tsx +++ b/packages/polaris-viz/src/components/Grid/Grid.tsx @@ -223,6 +223,23 @@ export function Grid(props: GridProps) { }; }; + const handleBodyClick = useCallback(() => { + setGroupSelected(null); + handleGroupHover(null); + }, [handleGroupHover]); + + useEffect(() => { + if (groupSelected) { + setTimeout(() => { + document.body.addEventListener('click', handleBodyClick); + }, 0); + + return () => { + document.body.removeEventListener('click', handleBodyClick); + }; + } + }, [groupSelected, handleBodyClick]); + const yTicks = useMemo(() => { return Array.from({length: gridDimensions.rows}, (_, index) => ({ value: gridDimensions.rows - 1 - index, diff --git a/packages/polaris-viz/src/components/Grid/components/Tooltip.scss b/packages/polaris-viz/src/components/Grid/components/Tooltip.scss index 86367db52..341ef1020 100644 --- a/packages/polaris-viz/src/components/Grid/components/Tooltip.scss +++ b/packages/polaris-viz/src/components/Grid/components/Tooltip.scss @@ -3,6 +3,36 @@ @import '../../../styles/common'; @import '../utilities/constants'; +.TooltipActions { + margin-top: 12px; +} + +.TooltipAction { + display: block; + text-decoration: none; + color: $color-gray-150; + font-size: 12px; + font-weight: 500; + line-height: 1.2; + margin: 0; + padding: 6px 12px; + text-align: center; + border-radius: 8px; + border: none; + box-shadow: 0 0 0.5px 0.5px rgba(0, 0, 0, 0.1), + 0 1px 2px 0 rgba(0, 0, 0, 0.25); + background: $color-white; +} + +.TooltipAction span { + box-sizing: border-box; + display: block; +} + +.TooltipAction:hover { + background: rgba(0, 0, 0, 0.025); +} + .GroupGoal { margin: 0; font-size: 11px; @@ -12,8 +42,8 @@ } .TooltipTitle { - font-weight: 700; - font-size: 12px; + font-weight: 600; + font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -25,13 +55,13 @@ -webkit-line-clamp: 3; overflow: hidden; text-overflow: ellipsis; - color: var(--p-color-bg-surface-inverse); + color: $color-gray-100; margin-bottom: 8px; } .TooltipMetricInformation { color: $color-gray-150; - font-weight: 600; + font-weight: 500; } .TooltipGoal { @@ -48,7 +78,7 @@ font-size: 12px; font-family: Inter, -apple-system, system-ui, 'San Francisco', 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif; - line-height: 1.2; + line-height: 1.3; padding: 12px; background: $color-white; border-radius: 12px; @@ -61,7 +91,7 @@ z-index: 1; top: 0; left: 0; - width: 250px; + width: 280px; outline: none; @container (max-width: #{$grid-small-breakpoint}) { display: none; diff --git a/packages/polaris-viz/src/components/Grid/components/Tooltip.tsx b/packages/polaris-viz/src/components/Grid/components/Tooltip.tsx index e43f5ec25..24f7102e8 100644 --- a/packages/polaris-viz/src/components/Grid/components/Tooltip.tsx +++ b/packages/polaris-viz/src/components/Grid/components/Tooltip.tsx @@ -1,3 +1,4 @@ +import {useEffect, useState, useRef} from 'react'; import {createPortal} from 'react-dom'; import type {CellGroup} from '../types'; @@ -15,6 +16,33 @@ interface TooltipProps { export function Tooltip({x, y, group}: TooltipProps) { const container = useRootContainer(TOOLTIP_ID); + const [actionsButtonsColumns, setActionsButtonsColumns] = useState(1); + const actionsContainerRef = useRef(null); + + useEffect(() => { + if (group?.actions?.length && actionsContainerRef.current) { + // This is a workaround to determine if the buttons should be displayed in one or two columns depending if the copy fits in one line + const buttonsWrapper = actionsContainerRef.current; + const actionsButtons = buttonsWrapper.querySelectorAll('a span'); + + const heights: Set = new Set(); + let areWrapping = false; + for (const button of actionsButtons) { + const wrapping = + parseFloat(window.getComputedStyle(button).height) / + parseFloat(window.getComputedStyle(button).lineHeight) > + 1; + if (wrapping) { + areWrapping = true; + } + heights.add(button.getBoundingClientRect().height); + } + + const haveSameHeight = heights.size === 1; + setActionsButtonsColumns(haveSameHeight && !areWrapping ? 2 : 1); + } + }, [group?.actions, actionsContainerRef.current]); + if (!group) { return null; } @@ -26,6 +54,9 @@ export function Tooltip({x, y, group}: TooltipProps) { transform: `translate(${x}px, ${y}px)`, }} aria-label={group.name} + onClick={(event) => { + event.stopPropagation(); + }} >
{group.name}
@@ -56,6 +87,40 @@ export function Tooltip({x, y, group}: TooltipProps) {

{group.goal}

)} + {group.actions?.length && ( +
+
+ {group.actions?.map((action, index) => { + const numActions = group.actions?.length || 0; + const oddNumActions = numActions % 2 !== 0; + const lastAction = index === numActions - 1; + const spanFullWidth = oddNumActions && lastAction; + return ( + + ); + })} +
+
+ )} , container, diff --git a/packages/polaris-viz/src/components/Grid/stories/data.tsx b/packages/polaris-viz/src/components/Grid/stories/data.tsx index 319b4dc60..8683debcf 100644 --- a/packages/polaris-viz/src/components/Grid/stories/data.tsx +++ b/packages/polaris-viz/src/components/Grid/stories/data.tsx @@ -33,6 +33,18 @@ export const CELL_GROUPS: CellGroup[] = [ '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)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, { id: 'at_risk', @@ -48,6 +60,18 @@ export const CELL_GROUPS: CellGroup[] = [ description: 'Customers without recent purchases, but with a strong history of orders and spend.', goal: 'Goal: move customers to Loyal or Needs Attention', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, { id: 'dormant', @@ -63,6 +87,18 @@ export const CELL_GROUPS: CellGroup[] = [ '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)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, { id: 'loyal', @@ -78,6 +114,18 @@ export const CELL_GROUPS: CellGroup[] = [ '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)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, { id: 'needs_attention', @@ -93,6 +141,18 @@ export const CELL_GROUPS: CellGroup[] = [ '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)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report long text', + url: '#', + target: '_blank', + }, + ], }, { id: 'almost_lost', @@ -108,6 +168,18 @@ export const CELL_GROUPS: CellGroup[] = [ '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)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, { id: 'promising', @@ -122,6 +194,18 @@ export const CELL_GROUPS: CellGroup[] = [ description: 'Customers with recent purchases, few orders, and low spend.', goal: 'Goal: move customers to Active.', metricInformation: '1,424 (10.9% of customer base)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, { id: 'active', @@ -137,6 +221,18 @@ export const CELL_GROUPS: CellGroup[] = [ '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)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, { id: 'new', @@ -152,6 +248,18 @@ export const CELL_GROUPS: CellGroup[] = [ '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)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, { id: 'champions', @@ -166,6 +274,18 @@ export const CELL_GROUPS: CellGroup[] = [ 'Customers with very recent purchases, many orders, and the most spend.', goal: null, metricInformation: '1,424 (10.9% of customer base)', + actions: [ + { + children: 'Preview segment', + url: '#', + target: '_blank', + }, + { + children: 'View report', + url: '#', + target: '_blank', + }, + ], }, ]; diff --git a/packages/polaris-viz/src/components/Grid/types.ts b/packages/polaris-viz/src/components/Grid/types.ts index 3713f8d6f..82d6f8b8c 100644 --- a/packages/polaris-viz/src/components/Grid/types.ts +++ b/packages/polaris-viz/src/components/Grid/types.ts @@ -18,6 +18,13 @@ export interface CellGroup { secondaryValue: string; value: string; metricInformation?: string; + actions?: GroupAction[]; +} + +export interface GroupAction { + children: string; + url?: string; + target?: '_blank' | '_self' | '_parent' | '_top'; } export interface TooltipInfo { diff --git a/packages/polaris-viz/src/components/Grid/utilities/constants.ts b/packages/polaris-viz/src/components/Grid/utilities/constants.ts index c4ce984f9..8ff4ba480 100644 --- a/packages/polaris-viz/src/components/Grid/utilities/constants.ts +++ b/packages/polaris-viz/src/components/Grid/utilities/constants.ts @@ -1,5 +1,5 @@ -export const TOOLTIP_WIDTH = 250; -export const TOOLTIP_HEIGHT = 155; +export const TOOLTIP_WIDTH = 280; +export const TOOLTIP_HEIGHT = 180; export const TOOLTIP_HORIZONTAL_OFFSET = 10; export const Y_LABEL_OFFSET = 25;