UNPKG

@applicaster/zapp-react-native-ui-components

Version:

Applicaster Zapp React Native ui components for the Quick Brick App

199 lines (160 loc) • 5.51 kB
import { all, equals, path, prop, isEmpty, pluck, values } from "ramda"; import { useEffect, useMemo } from "react"; import { useDispatch } from "react-redux"; import { useLayoutPresets } from "@applicaster/zapp-react-native-redux/hooks/useLayoutPresets"; import { useZappPipesFeeds } from "@applicaster/zapp-react-native-redux/hooks/useZappPipesFeeds"; import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes"; import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils"; import { Categories } from "./logger"; import { createLogger } from "@applicaster/zapp-react-native-utils/logger"; import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation"; import { ZappPipesEntryContext, ZappPipesScreenContext, ZappPipesSearchContext, } from "@applicaster/zapp-react-native-ui-components/Contexts"; import { getInflatedDataSourceUrl, getSearchContext, } from "@applicaster/zapp-react-native-utils/reactHooks/feed/useInflatedUrl"; import { produce } from "immer"; // types reference declare type CurationEntry = { preset_name: string; feed_url: string }; type Feeds = Record<string, ZappPipesData>; type LayoutPresets = PresetsMapping["presets_mappings"]; const SMART_COMPONENT_TYPE = "quick-brick-smart-component"; const SOURCE_PATH = ["data", "source"]; const MAPPING_PATH = ["data", "mapping"]; const isSmartComponent = (component) => component.component_type === SMART_COMPONENT_TYPE; const logger = createLogger({ category: Categories.CURATION_API }); export const getTransformedPreset = ( preset: CurationEntry, componentId: ZappUIComponent["id"], index: number, layoutPresets: LayoutPresets ): ZappUIComponent | undefined => { const presetComponent = layoutPresets?.[preset?.preset_name]; if (!presetComponent) { logger.log_error("Preset missing or wrong data format", { entry: preset }); return; } const updatedPresetComponent = produce(presetComponent, (draft) => { draft.id = `${componentId}-${preset?.feed_url}-${index}`; draft.data.source = preset?.feed_url; if (draft.ui_components) { draft.ui_components.forEach((comp, uiIndex) => { comp.id = `${draft.id}-${uiIndex}`; }); } }); return updatedPresetComponent; }; export const enrichComponent = ( comp: ZappUIComponent, index: number, feeds: Feeds, layoutPresets: LayoutPresets, urlsMap: { [key: string]: string } ): ZappUIComponent[] | null => { if (!isSmartComponent(comp)) { return [comp]; } const presets = prop<string[]>(urlsMap[comp.id], feeds); if (presets && presets.data && presets.data.entry) { return presets.data.entry .map((preset: CurationEntry, _index) => getTransformedPreset(preset, comp.id, index + _index, layoutPresets) ) .filter(Boolean); } return null; }; export const getFinalComponents = ( enrichedComponents: Array<ZappUIComponent>, smartComponents: ZappUIComponent[], urls: string[], feeds: Feeds, components: ZappUIComponent[] ): ZappUIComponent[] => { if (isEmpty(smartComponents)) { return components; } if (all(isEmptyOrNil)(urls)) { return enrichedComponents; } if (isEmptyOrNil(feeds)) { return []; } if (all(equals(false))(values(pluck("loading", feeds)))) { return enrichedComponents; } else { return []; } }; export const useCurationAPI = ( components: Array<ZappUIComponent> ): ZappUIComponent[] => { const dispatch = useDispatch(); const smartComponents = useMemo( () => components?.filter?.(isSmartComponent) ?? [], [components] ); const { pathname } = useRoute(); const [entryContext] = ZappPipesEntryContext.useZappPipesContext(pathname); const [searchContext] = ZappPipesSearchContext.useZappPipesContext(); const [screenContext] = ZappPipesScreenContext.useZappPipesContext(); const urlsMap = useMemo<{ [key: string]: string }>(() => { const map = {}; smartComponents?.forEach?.((component) => { const url = path(SOURCE_PATH, component); const mapping = path(MAPPING_PATH, component); map[component.id] = mapping ? getInflatedDataSourceUrl({ source: url, contexts: { entry: entryContext, screen: screenContext, search: getSearchContext(searchContext, mapping), }, mapping, }) : url; }); return map; }, [smartComponents, entryContext, screenContext, searchContext]); const urls = useMemo<string[]>(() => Object.values(urlsMap), [urlsMap]); useEffect(() => { urls.forEach((url, index) => { if (url) { dispatch(loadPipesData(url, { clearCache: false })); } else { logger.log_error("Curation url is empty", { componentId: smartComponents?.[index]?.id, }); } }); }, [urls]); const feeds = useZappPipesFeeds(urls); const layoutPresets = useLayoutPresets(); const enrichedComponents = useMemo(() => { if (!components) return []; return components.reduce((acc, comp, index) => { const enrichedComp = enrichComponent( comp, index, feeds, layoutPresets, urlsMap ); return enrichedComp ? [...acc, ...enrichedComp] : acc; }, [] as Array<ZappUIComponent>); }, [components, feeds, layoutPresets, urlsMap]); return getFinalComponents( enrichedComponents, smartComponents, urls, feeds, components ); };