diff --git a/projects/packages/premium-analytics/changelog/update-pa-authors-widget-followups b/projects/packages/premium-analytics/changelog/update-pa-authors-widget-followups new file mode 100644 index 000000000000..646dba78a74e --- /dev/null +++ b/projects/packages/premium-analytics/changelog/update-pa-authors-widget-followups @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Authors widget: localize the untracked-authors label; center the chart empty state. diff --git a/projects/packages/premium-analytics/packages/widgets-toolkit/src/components/chart-empty-state/chart-empty-state.module.scss b/projects/packages/premium-analytics/packages/widgets-toolkit/src/components/chart-empty-state/chart-empty-state.module.scss index 60786aa66322..10fbdf09e800 100644 --- a/projects/packages/premium-analytics/packages/widgets-toolkit/src/components/chart-empty-state/chart-empty-state.module.scss +++ b/projects/packages/premium-analytics/packages/widgets-toolkit/src/components/chart-empty-state/chart-empty-state.module.scss @@ -4,6 +4,7 @@ justify-content: center; height: 100%; width: 100%; + margin-inline: auto; gap: var(--wpds-dimension-gap-lg); } diff --git a/projects/packages/premium-analytics/widgets/authors/__tests__/build-top-authors-data.test.ts b/projects/packages/premium-analytics/widgets/authors/__tests__/build-top-authors-data.test.ts index a434168f7c83..d38b4fa20678 100644 --- a/projects/packages/premium-analytics/widgets/authors/__tests__/build-top-authors-data.test.ts +++ b/projects/packages/premium-analytics/widgets/authors/__tests__/build-top-authors-data.test.ts @@ -116,4 +116,13 @@ describe( 'buildTopAuthorsData', () => { const bob = result.find( author => author.label === 'Bob' ); expect( bob ).toMatchObject( { previousValue: 0, delta: 100 } ); } ); + + it( 'localizes the untracked-authors sentinel produced by the sanitizer', () => { + const result = buildTopAuthorsData( + makeReport( [ { label: 'Untracked Authors', views: 5 } ] ), + undefined + ); + + expect( result[ 0 ].label ).toBe( 'Untracked authors' ); + } ); } ); diff --git a/projects/packages/premium-analytics/widgets/authors/build-top-authors-data.ts b/projects/packages/premium-analytics/widgets/authors/build-top-authors-data.ts index dcbc3be93d3a..7ed83681c84d 100644 --- a/projects/packages/premium-analytics/widgets/authors/build-top-authors-data.ts +++ b/projects/packages/premium-analytics/widgets/authors/build-top-authors-data.ts @@ -8,17 +8,26 @@ import { import { __ } from '@wordpress/i18n'; import type { StatsNormalizedReport, StatsTopAuthorsItem } from '@jetpack-premium-analytics/data'; +// The Stats sanitizer substitutes this untranslated sentinel for authors with +// no name (see `sanitizeStatsTopAuthorsResponse`), so match it here to surface a +// localized label. +const UNTRACKED_AUTHORS_SENTINEL = 'Untracked Authors'; + /** - * Resolve a display label for an author, falling back to a translated - * "Untracked authors" label when the API provides none. + * Resolve a display label for an author, translating the untracked-authors + * sentinel (and any empty label) into a localized string. * * @param author - The top-authors item. * @return The author's display label. */ function getAuthorLabel( author: StatsTopAuthorsItem ) { - return typeof author.label === 'string' && author.label - ? author.label - : __( 'Untracked authors', 'jetpack-premium-analytics' ); + const label = typeof author.label === 'string' ? author.label : ''; + + if ( ! label || label === UNTRACKED_AUTHORS_SENTINEL ) { + return __( 'Untracked authors', 'jetpack-premium-analytics' ); + } + + return label; } /** diff --git a/projects/packages/premium-analytics/widgets/authors/render.tsx b/projects/packages/premium-analytics/widgets/authors/render.tsx index 1994b63af1a6..421b52c5e9f4 100644 --- a/projects/packages/premium-analytics/widgets/authors/render.tsx +++ b/projects/packages/premium-analytics/widgets/authors/render.tsx @@ -11,6 +11,7 @@ import { useWidgetRootContext, type LeaderboardChartData, type LegendLabels, + type ReportParamsFieldAttributes, } from '@jetpack-premium-analytics/widgets-toolkit'; import { __ } from '@wordpress/i18n'; import { postAuthor } from '@wordpress/icons'; @@ -19,16 +20,17 @@ import { useMemo } from 'react'; * Internal dependencies */ import { buildTopAuthorsData } from './build-top-authors-data'; +import type { AuthorsAttributes } from './widget'; import type { WidgetRenderProps } from '@wordpress/widget-primitives'; import type { ComponentProps } from 'react'; const DEFAULT_MAX = 7; -type AuthorsAttributes = NonNullable< ComponentProps< typeof WidgetRoot >[ 'attributes' ] > & { - max?: string | number; -}; +// Report params are usually URL-driven (WidgetRoot's fallback), but callers may +// also pass them via `attributes`. Compose the render-only shape to cover both. +type AuthorsRenderAttributes = AuthorsAttributes & Partial< ReportParamsFieldAttributes >; -type AuthorsRenderProps = WidgetRenderProps< AuthorsAttributes > & { +type AuthorsRenderProps = WidgetRenderProps< AuthorsRenderAttributes > & { setError?: ComponentProps< typeof WidgetRoot >[ 'setError' ]; }; @@ -169,9 +171,11 @@ function AuthorsReport( { max }: { max: number } ) { /** * Authors widget render entry point. * - * WidgetRoot provides the analytics query client, chart theme, and the report - * params consumed by the inner leaderboard — resolved from the dashboard date - * range via context, the same way the other Stats widgets read them. + * Passes host `attributes` into `WidgetRoot`, which resolves the report params: + * the dashboard leaves `reportParams` out of `attributes`, so it falls back to + * the date-range URL search params the picker writes to; Storybook injects + * `attributes.reportParams` directly. The widget's own `max` is forwarded to + * the inner component. * * @param props - Render props. * @param props.attributes - Widget attributes. diff --git a/projects/packages/premium-analytics/widgets/authors/widget.ts b/projects/packages/premium-analytics/widgets/authors/widget.ts index 0d631efd86f3..a133ab04da2c 100644 --- a/projects/packages/premium-analytics/widgets/authors/widget.ts +++ b/projects/packages/premium-analytics/widgets/authors/widget.ts @@ -4,6 +4,18 @@ import { __ } from '@wordpress/i18n'; import { postAuthor } from '@wordpress/icons'; +/** + * Configurable attributes for the Authors widget. Mirrors the `attributes` + * declared on the widget definition below; the host passes the selected values + * through to `render.tsx`. + */ +export type AuthorsAttributes = { + /** + * Maximum number of authors to display. + */ + max?: number; +}; + /** * Widget type definition. */ @@ -20,7 +32,7 @@ export default { ], example: { attributes: { - max: '7', + max: 7, }, }, };