import React, { useEffect } from "react"; import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux"; import { reactHooksLogger } from "../logger"; import { shouldDispatchData, useIsInitialRender } from "../utils"; import { useInflatedUrl } from "./useInflatedUrl"; import { useLoadPipesDataDispatch } from "./useLoadPipesDataDispatch"; const logger = reactHooksLogger.addSubsystem("useFeedLoader"); type Props = { feedUrl: string | null; mapping?: ZappTypeMapping; pipesOptions?: { clearCache?: boolean; loadLocalFavourites?: boolean; silentRefresh?: boolean; method?: "get" | "post"; bodyParams?: Record; skipLoading?: boolean; }; }; export type ReloadDataFunction = ( silentRefresh?: boolean, callback?: (data: any, error?: any) => void ) => void; type FeedLoaderResponse = PipesDataObject & { loadNext?: () => void; reloadData?: ReloadDataFunction; }; export const useFeedLoader = ({ feedUrl, mapping, pipesOptions = {}, }: Props): FeedLoaderResponse => { const isInitialRender = useIsInitialRender(); const callableFeedUrl = useInflatedUrl({ feedUrl, mapping }); const currentFeed = useZappPipesFeed(callableFeedUrl); const loadPipesDataDispatcher = useLoadPipesDataDispatch(); const reloadData = React.useCallback( (silentRefresh = true, callback) => { loadPipesDataDispatcher( callableFeedUrl, { clearCache: true, silentRefresh, callback, }, { withResolvers: true, } ); }, [callableFeedUrl] ); const loadNext: FeedLoaderResponse["loadNext"] = React.useCallback(() => { if (callableFeedUrl) { const nextFeed = currentFeed?.data?.next; loadPipesDataDispatcher( nextFeed, { silentRefresh: true, parentFeed: callableFeedUrl, }, { withResolvers: true, } ); } }, [callableFeedUrl, currentFeed?.data?.next]); useEffect(() => { if ( shouldDispatchData(callableFeedUrl, currentFeed, pipesOptions.clearCache) ) { if (callableFeedUrl && !pipesOptions.skipLoading) { loadPipesDataDispatcher( callableFeedUrl, { ...pipesOptions, clearCache: true, }, { withResolvers: true, withScreenRouteMapping: true, } ); } else if (!callableFeedUrl) { logger.info({ message: "Feed is not defined or not inflated, skipping loading. \nMake sure you have correct feedUrl and mapping.", jsOnly: true, }); } else { logger.info({ message: "Loading skipped as per pipesOptions.skipLoading configuration.", data: { url: callableFeedUrl }, jsOnly: true, }); } } else { logger.info({ message: "Feed already exists, skipping loading. \nCall reloadData() if you want to refresh data.", data: { url: callableFeedUrl }, jsOnly: true, }); } }, []); // Reload feed when feedUrl changes, unless skipLoading is true useEffect(() => { if (!isInitialRender && callableFeedUrl && !pipesOptions.skipLoading) { loadPipesDataDispatcher(callableFeedUrl, pipesOptions, { withResolvers: true, }); } }, [callableFeedUrl, isInitialRender, pipesOptions.skipLoading]); return React.useMemo(() => { if (!callableFeedUrl || !feedUrl) { return { error: new Error("No Feed url provided"), loading: false, url: "", // empty string when no data data: null, }; } if (!currentFeed) { return { loading: true, url: callableFeedUrl || feedUrl, data: null, }; } return { error: currentFeed?.error, loading: currentFeed?.loading, url: currentFeed?.url, data: currentFeed?.data, reloadData, loadNext, }; }, [ callableFeedUrl, currentFeed?.data, currentFeed?.error, currentFeed?.loading, reloadData, loadNext, ]); };