import React, { useMemo } from 'react'; import { __ } from '@wordpress/i18n'; import { Block } from '@/components/Blocks/Block'; import { BlockContent } from '@/components/Blocks/BlockContent'; import { BlockFooter } from '@/components/Blocks/BlockFooter'; import { BlockHeading } from '@/components/Blocks/BlockHeading'; import Icon from '@/utils/Icon'; import { VisitorFlowData } from '@/api/getVisitorFlowData'; import type { FlowDestinationRow, FlowDestinationType, FlowSourceRow, FlowSourceType, VisitorFlowPayload } from './types'; import { VisitorFlowLegend } from './VisitorFlowLegend'; import { VisitorFlowSankey } from './VisitorFlowSankey'; interface VisitorFlowDiagramBlockProps { data?: VisitorFlowData; isLoadingData?: boolean; fallbackPageUrl?: string; } /** * Maps the live backend visitor-flow payload into internal Sankey types. * * @param realData - Live REST API response. * @param fallbackPageUrl - Target page URL path from search params. * @return Internal Sankey payload structure. */ const transformRealDataToPayload = ( data: VisitorFlowData | undefined, fallbackPageUrl: string ): VisitorFlowPayload => { if ( ! data || ! data.target ) { return { pagePath: fallbackPageUrl || '/', totalSessions: 0, sequencedSessions: 0, sources: [], destinations: [] }; } const sources: FlowSourceRow[] = ( data.entries || []).map( ( entry, i ) => ({ id: `source-${ i }`, label: entry.name, type: ( 'page' === entry.type ? 'internal' : entry.type ) as FlowSourceType, sessions: entry.count }) ); const destinations: FlowDestinationRow[] = ( data.exits || []).map( ( exit, i ) => ({ id: `dest-${ i }`, label: exit.name, type: ( 'page' === exit.type ? 'internal' : exit.type ) as FlowDestinationType, sessions: exit.count }) ); const sequenced = sources.reduce( ( a, b ) => a + b.sessions, 0 ) + destinations.reduce( ( a, b ) => a + b.sessions, 0 ); return { pagePath: data.target.url || fallbackPageUrl || '/', totalSessions: data.target.total_visitors || 0, sequencedSessions: sequenced, sources, destinations }; }; /** * Renders a stable loading placeholder matching the visitor-flow layout. * * @return Visitor-flow loading skeleton. */ const VisitorFlowSkeleton = () => (
{__( 'No visitor flow data for this date range.', 'burst-statistics' )}