/** * External dependencies */ import { EMPTY_ARRAY } from '@nab/utils'; import type { AlternativeIndex, Click, ClickVisibilityProps, ClicksPerSquare, ConfettiOption, ConfettiType, Dict, HeatmapDataStatus, HeatmapResolution, Maybe, ClickWithVisibility, Scroll, ScrollSummary, } from '@nab/types'; /** * Internal dependencies */ import type { State } from '../config'; import type { PageData, ProcessedAlternative, ProcessedResultsStatus, } from './config'; // ======== // RAW DATA // ======== const NO_STATUS: HeatmapDataStatus = { mode: 'missing' }; export function getRawResultStatus( state: State, alternative: AlternativeIndex ): HeatmapDataStatus { return state.data.byAlternative[ alternative ]?.raw.status ?? NO_STATUS; } export function getRawResultProgress( state: State, alternative: AlternativeIndex ): number { return state.data.byAlternative[ alternative ]?.raw.progress ?? 0; } export function getRawClicks( state: State, alternative: AlternativeIndex ): ReadonlyArray< Click > { return ( state.data.byAlternative[ alternative ]?.raw.results.clicks ?? EMPTY_ARRAY ); } export function getRawScrolls( state: State, alternative: AlternativeIndex ): ReadonlyArray< Scroll > { return ( state.data.byAlternative[ alternative ]?.raw.results.scrolls ?? EMPTY_ARRAY ); } const DEFAULT_ATTEMPTS = { clicks: { count: 0, length: 0 }, scrolls: { count: 0, length: 0 }, }; export function getLoadAttempts( state: State, alternative: AlternativeIndex ): ProcessedAlternative[ 'loadAttempts' ] { return ( state.data.byAlternative[ alternative ]?.loadAttempts ?? DEFAULT_ATTEMPTS ); } export function canRawDataBeProcessed( state: State, alternative: AlternativeIndex ): boolean { const status = state.data.byAlternative[ alternative ]?.raw.status.mode; return ( 'still-loading' === status || 'ready' === status || 'canceling' === status ); } // ============== // PROCESSED DATA // ============== export function hasProcessedResults( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): boolean { return !! state.data.byAlternative[ alternative ]?.byResolution[ resolution ].results; } export function getProcessedResultStatus( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): ProcessedResultsStatus { return ( state.data.byAlternative[ alternative ]?.byResolution[ resolution ] .status ?? 'missing' ); } export function getClicksInResolution( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): ReadonlyArray< ClickWithVisibility > { return ( state.data.byAlternative[ alternative ]?.byResolution[ resolution ] .results?.clicks ?? EMPTY_ARRAY ); } const DEFAULT_CLICKS_PER_SQUARE: ClicksPerSquare = { rows: 1, max: 1, value: [ 1 ], columns: 1, }; export function getClicksPerSquare( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): ClicksPerSquare { return ( state.data.byAlternative[ alternative ]?.byResolution[ resolution ] .results?.clicksPerSquare ?? DEFAULT_CLICKS_PER_SQUARE ); } export function getScrollsInResolution( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): ReadonlyArray< Scroll > { return ( state.data.byAlternative[ alternative ]?.byResolution[ resolution ] .results?.scrolls ?? EMPTY_ARRAY ); } const NO_SCROLL_SUMMARY: ScrollSummary = { rows: EMPTY_ARRAY, maxHits: 0, averageFold: 0, }; export function getScrollSummary( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): ScrollSummary { return ( state.data.byAlternative[ alternative ]?.byResolution[ resolution ] .results?.scrollSummary ?? NO_SCROLL_SUMMARY ); } // ================ // FILTERS AND MORE // ================ export function getConfettiFilterOptions( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): Partial< Record< ConfettiType, Dict< ConfettiOption > > > { return ( state.data.byAlternative[ alternative ]?.byResolution[ resolution ] .confettiFilterOptions ?? state.data.confettiFilterOptions ); } type Selector = string; export function getClickVisibilityProps( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): Maybe< Record< Selector, ClickVisibilityProps > > { return state.data.byAlternative[ alternative ]?.byResolution[ resolution ] .page.clickVisibilityProps; } export function getPageDimensions( state: State, alternative: AlternativeIndex, resolution: HeatmapResolution ): Maybe< PageData[ 'dimensions' ] > { return state.data.byAlternative[ alternative ]?.byResolution[ resolution ] .page.dimensions; }