import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import { useNavigate, useParams, useSearch } from '@tanstack/react-router'; import { __ } from '@wordpress/i18n'; import * as Select from '@radix-ui/react-select'; import Icon from '@/utils/Icon'; import DataTableBlock from '@/components/Statistics/DataTableBlock'; import OutgoingLinksOverlayTable from '@/components/OutgoingLinks/OutgoingLinksOverlayTable'; import { PageFilter } from '@/components/Filters/PageFilter'; import DateRange from '@/components/Statistics/DateRange'; import ErrorBoundary from '@/components/Common/ErrorBoundary'; import { FILTER_KEYS } from '@/config/filterConfig'; // Duration in ms, matched to the exit spring animation. const EXIT_DURATION_MS = 0; /** * Label and icon mapping for each datatable variant key. * Mirrors the config labels defined in DataTableBlock. */ const VARIANT_META: Record = { pages: { label: __( 'Pages', 'burst-statistics' ), icon: 'page' }, referrers: { label: __( 'Referrers', 'burst-statistics' ), icon: 'referrer' }, countries: { label: __( 'Locations', 'burst-statistics' ), icon: 'world' }, campaigns: { label: __( 'Campaigns', 'burst-statistics' ), icon: 'campaign' }, parameters: { label: __( 'Parameters', 'burst-statistics' ), icon: 'parameters' }, products: { label: __( 'Products', 'burst-statistics' ), icon: 'shopping-cart' }, subscription_products: { label: __( 'Plan performance', 'burst-statistics' ), icon: 'calendar-sync' }, search_terms: { label: __( 'Search terms', 'burst-statistics' ), icon: 'search' }, outgoing_links: { label: __( 'Outgoing links', 'burst-statistics' ), icon: 'external-link' } }; /** * DataTableOverlay — full-screen bottom sheet for exploring datatable data. * * Opened via the /table/$variant route. Shows a variant switcher, filters, * date range, and a full-height scrollable DataTableBlock. On close, the * user is returned to the source page with the current filter/date context * applied (Option B propagation). * * @return {JSX.Element} The overlay component. */ export const DataTableOverlay: React.FC = () => { const navigate = useNavigate(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const params = useParams({ strict: false }) as Record; const variant = ( params.variant as string ) || 'pages'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const search = useSearch({ strict: false }) as Record; const from = ( search.from as string ) || '/'; const allowed = ( search.allowed as string ) || ( variant || 'pages' ); const dataTableId = ( search.dataTableId as string ) || 'datatable'; const allowedConfigs = useMemo( () => allowed.split( ',' ).filter( Boolean ), [ allowed ] ); // Track the currently selected variant locally for instant switching. const [ selectedVariant, setSelectedVariant ] = useState( variant ); // Controls the exit animation before the actual navigation fires. const [ isVisible, setIsVisible ] = useState( true ); /** * Handle variant change from the dropdown. * * @param {string} newVariant - The newly selected variant key. */ const handleVariantChange = useCallback( ( newVariant: string ) => { setSelectedVariant( newVariant ); }, []); /** * Close the overlay and navigate back to the source page, carrying the * currently active filters and date range forward (Option B). */ const handleClose = useCallback( () => { setIsVisible( false ); const closeSearch: Record = {}; // Carry active filter values forward. FILTER_KEYS.forEach( ( key ) => { const value = search[ key ]; if ( value && '' !== value ) { closeSearch[ key ] = value; } }); // Carry date range forward. if ( search.startDate ) { closeSearch.startDate = search.startDate; } if ( search.endDate ) { closeSearch.endDate = search.endDate; } if ( search.range ) { closeSearch.range = search.range; } setTimeout( () => { navigate({ // eslint-disable-next-line @typescript-eslint/no-explicit-any to: from as any, // eslint-disable-next-line @typescript-eslint/no-explicit-any search: closeSearch as any }); }, EXIT_DURATION_MS ); }, [ navigate, from, search ]); // Close on Escape key. useEffect( () => { const handleKeyDown = ( e: KeyboardEvent ) => { if ( 'Escape' === e.key ) { handleClose(); } }; document.addEventListener( 'keydown', handleKeyDown ); return () => document.removeEventListener( 'keydown', handleKeyDown ); }, [ handleClose ]); // Prevent scroll on the body while overlay is open. useEffect( () => { document.body.style.overflow = 'hidden'; return () => { document.body.style.overflow = ''; }; }, []); // Build dropdown options from the allowed configs. const variantOptions = useMemo( () => { return allowedConfigs .filter( ( key ) => VARIANT_META[ key ]) .map( ( key ) => ({ key, ...VARIANT_META[ key ] }) ); }, [ allowedConfigs ]); const currentLabel = VARIANT_META[ selectedVariant ]?.label || selectedVariant; const showDropdown = 1 < variantOptions.length; return ( { isVisible && ( e.stopPropagation() } >
{/* Header: variant switcher, filters + date range, close button. */}
{/* Variant switcher. */}
{ showDropdown ? ( { currentLabel } { variantOptions.map( ( option ) => ( { option.label } ) )} ) : (

{ currentLabel }

)}
{/* Filters + date range. */}
{/* Close button. */}
{/* Table area — fills remaining space, scrollable. */}
{ 'outgoing_links' === selectedVariant ? ( ) : ( ) }
) }
); }; export default DataTableOverlay;