Skip to content

Commit

Permalink
Stats Chart: Add comparisons for chart tabs (#96602)
Browse files Browse the repository at this point in the history
* use highlight cards for chart tabs

* limit scope

* fix typo

* Apply previousData to StatsTabs for trend highlights

* flex wrap

* remove unecessary changes

* add previous data support

* flex base 250px

* previous data should always get aggregated

* previous data should always get aggregated

* mobile alignment for stats tabs

* alignments

* use highlight styling on aggregate

* more adjustments to sizes so that it could fit in the width easier

* Adjust Flexbox items layout

* use daysInRange for range calculation

* use daysInRange for range calculation

---------

Co-authored-by: Dognose <dognose24@gmail.com>
  • Loading branch information
kangzj and dognose24 authored Nov 24, 2024
1 parent 8f55f10 commit d301242
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 46 deletions.
66 changes: 57 additions & 9 deletions client/my-sites/stats/modernized-chart-tabs-styles.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
@use "sass:math";
@import "@wordpress/base-styles/breakpoints";
@import "@automattic/components/src/highlight-cards/variables";
@import "@automattic/components/src/styles/typography";

$custom-stats-tab-mobile-break: $break-small;
$custom-stats-tab-mobile-break: $break-medium;

.stats > .stats-content {
padding-top: $vertical-margin;
Expand All @@ -28,6 +29,9 @@ $custom-stats-tab-mobile-break: $break-small;

display: flex;
align-items: center;
justify-content: space-between;
flex-flow: row wrap;
gap: 24px;

@media (max-width: $custom-mobile-breakpoint) {
padding: 24px math.div($vertical-margin, 2) 16px;
Expand All @@ -44,17 +48,14 @@ $custom-stats-tab-mobile-break: $break-small;

// Adjust new stats-tabs styling beyond the mobile layout
.stats-tab {
flex: 1;
width: auto;
font-family: $font-sf-pro-text;
border: 0;

&:not(:first-child) {
margin-left: 16px;
}

// Keep the original mobile stats-tabs styles
@media (max-width: $custom-stats-tab-mobile-break) {
width: 100%;
flex: 1 1 100%;
max-width: initial;
float: none;
border-bottom: 1px solid var(--color-neutral-5);

Expand All @@ -67,6 +68,18 @@ $custom-stats-tab-mobile-break: $break-small;
}
}

// Keep the original mobile stats-tabs styles
@media (min-width: $custom-stats-tab-mobile-break) {
flex: 1 1 45%;
width: 45%;
}

@media (min-width: $break-xlarge) {
flex: 1 1 155px;
// For wrap layout of three items in a row.
max-width: 31%;
}

.gridicon {
@media (max-width: $custom-stats-tab-mobile-break) {
float: left;
Expand All @@ -84,8 +97,8 @@ $custom-stats-tab-mobile-break: $break-small;
padding: 10px 6px;

@media (max-width: $custom-stats-tab-mobile-break) {
display: flex;
flex-direction: row;
display: grid;
grid-template-columns: 2fr 2fr 3fr;
align-items: center;
justify-content: space-between;
}
Expand Down Expand Up @@ -184,6 +197,41 @@ $custom-stats-tab-mobile-break: $break-small;
}
}
}

// Apply highlight card styles to stats-tabs.
&.is-highlighted {
text-align: left;

.stats-tabs__highlight {
display: flex;
align-items: center;
justify-content: end;
}
// TODO: The relevant class names could be refactored to be more comprehensive.
.highlight-card-difference {
font-size: $font-body-small;
font-weight: 600;
line-height: 25px;
letter-spacing: -0.24px;
margin-left: 8px;
}
@media (min-width: $custom-stats-tab-mobile-break) {
& > a {
padding: 8px 16px;
}
.stats-tabs__highlight-value {
font-weight: 500;
font-size: $font-title-medium;
line-height: 40px;
// Prevent different heights of Flexbox items.
white-space: nowrap;
}
.stats-tabs__highlight {
display: flex;
justify-content: start;
}
}
}
}
}
}
29 changes: 28 additions & 1 deletion client/my-sites/stats/stats-chart-tabs/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import config from '@automattic/calypso-config';
import clsx from 'clsx';
import { localize } from 'i18n-calypso';
import { flowRight } from 'lodash';
import moment from 'moment';
import PropTypes from 'prop-types';
import { Component } from 'react';
import { connect } from 'react-redux';
Expand Down Expand Up @@ -96,7 +97,10 @@ class StatModuleChartTabs extends Component {
this.intervalId = setInterval( this.makeQuery, DEFAULT_HEARTBEAT );
}

makeQuery = () => this.props.requestChartCounts( this.props.query );
makeQuery = () => {
this.props.requestChartCounts( this.props.query );
this.props.queryComp && this.props.requestChartCounts( this.props.queryComp );
};

render() {
const {
Expand All @@ -106,6 +110,7 @@ class StatModuleChartTabs extends Component {
selectedPeriod,
isActiveTabLoading,
className,
countsComp,
showChartHeader = false,
} = this.props;
const classes = [
Expand Down Expand Up @@ -139,6 +144,7 @@ class StatModuleChartTabs extends Component {
</Chart>
<StatTabs
data={ this.props.counts }
previousData={ isNewDateFilteringEnabled ? countsComp : null }
tabs={ this.props.charts }
switchTab={ this.props.switchTab }
selectedTab={ this.props.chartTab }
Expand Down Expand Up @@ -193,6 +199,25 @@ const connectComponent = connect(
const queryKey = `${ date }-${ period }-${ quantity }-${ siteId }`;
const query = memoizedQuery( chartTab, date, period, quantity, siteId, chartStart );

let countsComp = null;
let queryComp = null;
if ( customRange ) {
const dateComp = moment( date )
.subtract( customRange.daysInRange, 'day' )
.format( 'YYYY-MM-DD' );
const chartStartComp = moment( chartStart )
.subtract( customRange.daysInRange, 'day' )
.format( 'YYYY-MM-DD' );
queryComp = memoizedQuery( chartTab, dateComp, period, quantity, siteId, chartStartComp );
countsComp = getCountRecords(
state,
siteId,
queryComp.date,
queryComp.period,
queryComp.quantity
);
}

const counts = getCountRecords( state, siteId, query.date, query.period, query.quantity );
const chartData = buildChartData( activeLegend, chartTab, counts, period, queryDate );
const loadingTabs = getLoadingTabs( state, siteId, query.date, query.period, query.quantity );
Expand All @@ -201,8 +226,10 @@ const connectComponent = connect(
return {
chartData,
counts,
countsComp,
isActiveTabLoading,
query,
queryComp,
queryKey,
siteId,
selectedPeriod: period,
Expand Down
2 changes: 1 addition & 1 deletion client/my-sites/stats/stats-chart-tabs/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ ul.module-tabs {
}

/* styles border around chart for new date filtering design */
&.is-date-filtering-enabled {
&.is-date-filtering-enabled {
background-color: var(--studio-white);
border: 1px solid var(--studio-gray-5);
border-radius: 4px;
Expand Down
80 changes: 47 additions & 33 deletions client/my-sites/stats/stats-tabs/index.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { TrendComparison } from '@automattic/components/src/highlight-cards/count-comparison-card';
import formatNumber from '@automattic/components/src/number-formatters/lib/format-number';
import clsx from 'clsx';
import { localize } from 'i18n-calypso';
import { find } from 'lodash';
Expand All @@ -11,65 +13,77 @@ class StatsTabs extends Component {
static displayName = 'StatsTabs';

static propTypes = {
activeKey: PropTypes.string,
children: PropTypes.node,
data: PropTypes.array,
previousData: PropTypes.array,
activeIndex: PropTypes.string,
selectedTab: PropTypes.string,
switchTab: PropTypes.func,
activeKey: PropTypes.string,
tabs: PropTypes.array,
switchTab: PropTypes.func,
selectedTab: PropTypes.string,
borderless: PropTypes.bool,
aggregate: PropTypes.bool,
};

formatData = ( data, aggregate = true ) => {
const { activeIndex, activeKey, tabs } = this.props;
let activeData = {};
if ( ! aggregate ) {
activeData = find( data, { [ activeKey ]: activeIndex } );
} else {
data?.map( ( day ) =>
tabs.map( ( tab ) => {
if ( isFinite( day[ tab.attr ] ) ) {
if ( ! ( tab.attr in activeData ) ) {
activeData[ tab.attr ] = 0;
}
activeData[ tab.attr ] = activeData[ tab.attr ] + day[ tab.attr ];
}
} )
);
}
return activeData;
};

render() {
const {
children,
data,
activeIndex,
activeKey,
tabs,
switchTab,
selectedTab,
borderless,
aggregate,
} = this.props;
const { children, data, previousData, tabs, switchTab, selectedTab, borderless, aggregate } =
this.props;

let statsTabs;

if ( data && ! children ) {
let activeData = {};
if ( ! aggregate ) {
activeData = find( data, { [ activeKey ]: activeIndex } );
} else {
// TODO: not major but we might want to cache the data.
data.map( ( day ) =>
tabs.map( ( tab ) => {
if ( isFinite( day[ tab.attr ] ) ) {
if ( ! ( tab.attr in activeData ) ) {
activeData[ tab.attr ] = 0;
}
activeData[ tab.attr ] = activeData[ tab.attr ] + day[ tab.attr ];
}
} )
);
}
const activeData = this.formatData( data, aggregate );
const activePreviousData = this.formatData( previousData );

statsTabs = tabs.map( ( tab ) => {
const hasData =
activeData && activeData[ tab.attr ] >= 0 && activeData[ tab.attr ] !== null;

const value = hasData ? activeData[ tab.attr ] : null;
const previousValue = activePreviousData && activePreviousData[ tab.attr ];

const tabOptions = {
attr: tab.attr,
icon: tab.icon,
className: tab.className,
className: clsx( tab.className, { 'is-highlighted': aggregate } ),
label: tab.label,
loading: ! hasData,
selected: selectedTab === tab.attr,
tabClick: switchTab,
value: hasData ? activeData[ tab.attr ] : null,
value,
format: tab.format,
};

return <StatTab key={ tabOptions.attr } { ...tabOptions } />;
return (
<StatTab key={ tabOptions.attr } { ...tabOptions }>
{ previousData && (
<div className="stats-tabs__highlight">
<span className="stats-tabs__highlight-value">{ formatNumber( value ) }</span>
<TrendComparison count={ value } previousCount={ previousValue } />
</div>
) }
</StatTab>
);
} );
}

Expand Down
2 changes: 0 additions & 2 deletions client/my-sites/stats/stats-tabs/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
$stats-tab-outer-padding: 10px;

.stats-tabs {
@include clear-fix;
background: var(--color-surface);
border-top: 1px solid var(--color-border-subtle);
list-style: none;
Expand Down Expand Up @@ -98,7 +97,6 @@ $stats-tab-outer-padding: 10px;

@include breakpoint-deprecated( ">480px" ) {
@include mobile-link-element;
@include clear-fix;
padding-bottom: $stats-tab-outer-padding;
-webkit-touch-callout: none;
}
Expand Down

0 comments on commit d301242

Please sign in to comment.