import { useEffect, useMemo, Fragment } from 'react'; import type { ReactNode } from 'react'; import type { NavigationRegistry, FunctionRegistry, LogAnalytics, } from './types'; import { RenderList } from './ContentItem/list'; import { RenderSection } from './ContentItem/section'; import { ContentFormRenderer } from './FormElements'; import { useShallow } from 'zustand/shallow'; import { contentModel, type ContentViewItem } from './store/contentModel'; import Resync from 'resync-javascript'; import { useResync } from './hooks/useResync'; /** * Resync Content View Component * Renders dynamic content blocks in React Native apps */ interface ResyncContentBlockProps { name: string; loadingComponent?: React.ReactNode; errorComponent?: React.ReactNode; emptyComponent?: React.ReactNode; // Enhanced props for dynamic function handling functionRegistry?: FunctionRegistry; navigationRegistry?: NavigationRegistry; logAnalytics?: LogAnalytics; isCampaign?: boolean; } // const MadeByView = () => ( // { // Linking.canOpenURL('https://getresync.com').then((supported) => { // if (supported) { // Linking.openURL('https://getresync.com'); // } // }); // }} // style={{ // alignSelf: 'flex-end', // marginRight: 10, // }} // > // // Made with Resync // // // ); export const ResyncContentBlock = ({ name, loadingComponent, errorComponent, emptyComponent, functionRegistry, navigationRegistry, logAnalytics, }: ResyncContentBlockProps): ReactNode => { const { loaded, isLoading, loadFailed } = useResync(); // Get per-instance content state const contentViews = contentModel(useShallow((state) => state.contentViews)); const content = contentViews[name]; // store state useEffect(() => { if (!loaded || loadFailed || isLoading) { return; } if (name) { contentModel.getState().loadContentView(name, { functionRegistry, navigationRegistry, logAnalytics, }); } }, [ functionRegistry, navigationRegistry, logAnalytics, name, loaded, loadFailed, isLoading, ]); if (isLoading && loadingComponent) { return loadingComponent; } if (!name) { return null; } // Render error state if (!content || loadFailed) { if (errorComponent) { return errorComponent; } return null; } if (emptyComponent && content.content?.contents?.length === 0) { return emptyComponent; } return ; }; const RenderContentItem = ({ contentItem, }: { contentItem: ContentViewItem; }): ReactNode => { // Get root level content items (those without parentItemId) and sort by order const { content } = contentItem; const rootContentItems = useMemo(() => { if (content) { // filter out hidden items and sort by order return content?.contents ?.filter((item_) => item_.isVisible && !item_.parentItemId) .sort((a, b) => a.order - b.order); } return []; }, [content]); useEffect(() => { if (content && content.event) { Resync.logEvent({ eventId: content?.event?.eventId, }); } }, [content]); if (!content || rootContentItems.length === 0) { return null; } return ( {rootContentItems.map((item) => { if (item.type === 'list') { return ( {/* */} ); } if (item.type === 'form') { return ( {/* */} ); } if (item.type === 'section') { return ( {/* */} ); } return null; })} ); }; export default ResyncContentBlock;