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;