import { makeListOf } from "@applicaster/zapp-react-native-utils/arrayUtils"; import { isFirstComponentGallery } from "@applicaster/zapp-react-native-utils/componentsUtils"; import { once } from "ramda"; const INITIAL_NUMBER_TO_LOAD = 3; // Infer the values of COMPONENT_LOADING_STATE as a type type ComponentLoadingState = (typeof COMPONENT_LOADING_STATE)[keyof typeof COMPONENT_LOADING_STATE]; export const COMPONENT_LOADING_STATE = { UNKNOWN: "UNKNOWN", LOADED_WITH_SUCCESS: "LOADED_WITH_SUCCESS", LOADED_WITH_FAILURE: "LOADED_WITH_FAILURE", } as const; // Function to get the number of loaded components const getNumberOfLoaded = (states: ComponentLoadingState[]): number => { return states.filter((value) => value !== COMPONENT_LOADING_STATE.UNKNOWN) .length; }; const getNumberOfComponentsWaitToLoadBeforePresent = ( componentsToRender: ZappUIComponent[] ): number => { // when Gallery is the first component, no need to wait the others if (isFirstComponentGallery(componentsToRender)) { return 1; } return Math.min(INITIAL_NUMBER_TO_LOAD, componentsToRender.length); }; export class ScreenRevealManager { public numberOfComponentsWaitToLoadBeforePresent: number; private renderingState: Array; private callback: Callback; /** * @param initialNumberToLoad how many components to wait for before revealing * the screen. Staggering exists so a screen full of network-backed components * does not load them all at once. A caller that has nothing to stagger - see * `disableIncrementalLoading` on the HOC - passes the full count here so the * reveal waits for exactly what gets rendered. Omitted, the count is derived * from the components themselves. */ constructor( componentsToRender: ZappUIComponent[], callback: Callback, initialNumberToLoad?: number ) { this.numberOfComponentsWaitToLoadBeforePresent = initialNumberToLoad == null ? getNumberOfComponentsWaitToLoadBeforePresent(componentsToRender) : // Clamped like the computed path: waiting for components that do not // exist would hold the screen behind its overlay until the timeout. Math.min(initialNumberToLoad, componentsToRender.length); this.renderingState = makeListOf( COMPONENT_LOADING_STATE.UNKNOWN, this.numberOfComponentsWaitToLoadBeforePresent ); this.callback = once(callback); } onLoadFinished = (index: number): void => { this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_SUCCESS; if ( getNumberOfLoaded(this.renderingState) >= this.numberOfComponentsWaitToLoadBeforePresent ) { this.setIsReadyToShow(); } }; onLoadFailed = (index: number): void => { this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_FAILURE; if ( getNumberOfLoaded(this.renderingState) >= this.numberOfComponentsWaitToLoadBeforePresent ) { this.setIsReadyToShow(); } }; setIsReadyToShow = (): void => { this.callback(); }; }