/** * WordPress dependencies */ import { useSelect, useDispatch } from '@safe-wordpress/data'; import { useEffect } from '@safe-wordpress/element'; /** * External dependencies */ import { store as NAB_DATA } from '@nab/data'; import type { ExperimentId } from '@nab/types'; export type ResultsProviderProps = { readonly experimentId: ExperimentId; readonly isPublicView: boolean; readonly isReadOnlyActive: boolean; readonly children: JSX.Element | JSX.Element[]; }; export const ResultsProvider = ( { experimentId, isPublicView, isReadOnlyActive, children, }: ResultsProviderProps ): JSX.Element | null => { const isReady = useIsReady( experimentId ); useLoadEffect( experimentId, isPublicView, isReadOnlyActive ); useTimeGroupingEffect( experimentId ); return isReady ? <>{ children } : null; }; // ===== // HOOKS // ===== const useIsReady = ( experimentId: ExperimentId ) => { const isLoaded = useIsLoaded( experimentId ); const activeExperiment = useSelect( ( select ) => select( NAB_DATA ).getPageAttribute( 'editor/activeExperiment' ), [] ); return isLoaded && activeExperiment === experimentId; }; const useIsLoaded = ( experimentId: ExperimentId ) => useSelect( ( select ) => select( NAB_DATA ).hasFinishedResolution( 'getExperiment', [ experimentId, ] ), [ experimentId ] ); const useLoadEffect = ( experimentId: ExperimentId, isPublicView: boolean, isReadOnlyActive: boolean ) => { const isLoaded = useIsLoaded( experimentId ); const { setPageAttribute } = useDispatch( NAB_DATA ); useSelect( ( select ) => { select( NAB_DATA ).getExperiment( experimentId ); select( NAB_DATA ).getExperimentResults( experimentId ); }, [ experimentId ] ); useEffect( () => { if ( ! isLoaded ) { return; } void setPageAttribute( 'editor/activeExperiment', experimentId ); void setPageAttribute( 'results/isPublicView', isPublicView ); void setPageAttribute( 'results/isReadOnlyActive', isReadOnlyActive ); }, [ isLoaded, experimentId, isPublicView, isReadOnlyActive, setPageAttribute, ] ); }; const TODAY = new Date(); const DAYS_IN_MONTH = 30; const DAYS_IN_WEEK = 7; const MIN_SAMPLE_SIZE = 6; function useTimeGroupingEffect( experimentId: ExperimentId ) { const experiment = useSelect( ( select ) => select( NAB_DATA ).getExperiment( experimentId ), [ experimentId ] ); const { setPageAttribute } = useDispatch( NAB_DATA ); const days = getDurationInDays( experiment?.startDate ? new Date( experiment.startDate ) : TODAY, experiment?.endDate ? new Date( experiment.endDate ) : TODAY ); const timeGrouping = // eslint-disable-next-line no-nested-ternary days / DAYS_IN_MONTH > MIN_SAMPLE_SIZE ? 'monthly' : days / DAYS_IN_WEEK > MIN_SAMPLE_SIZE ? 'weekly' : 'daily'; useEffect( () => { void setPageAttribute( 'results/timeGrouping', timeGrouping ); }, [ timeGrouping, setPageAttribute ] ); } // ======= // HELPERS // ======= function getDurationInDays( startDate: Date, endDate: Date ): number { const millisecondsPerDay = 1000 * 60 * 60 * 24; return Math.max( 1, Math.ceil( ( endDate.getTime() - startDate.getTime() ) / millisecondsPerDay ) ); }