import * as React from "react"; import {} from "react-native"; import { useState, useContext, useRef, useEffect } from "react"; import { getDefaultRegisteredComponents } from "../../constants/builder-registered-components"; import { TARGET } from "../../constants/target"; import ComponentsContext from "../../context/components.context"; import type { BuilderContextInterface, BuilderRenderState, RegisteredComponents, } from "../../context/types"; import { evaluate } from "../../functions/evaluate/evaluate"; import { serializeIncludingFunctions } from "../../functions/register-component"; import { logger } from "../../helpers/logger"; import type { ComponentInfo } from "../../types/components"; import type { Dictionary } from "../../types/typescript"; import Blocks from "../blocks/blocks"; import { getUpdateVariantVisibilityScript } from "../content-variants/helpers"; import DynamicDiv from "../dynamic-div"; import InlinedScript from "../inlined-script"; import EnableEditor from "./components/enable-editor"; import ContentStyles from "./components/styles"; import { getContentInitialValue, getRootStateInitialValue, } from "./content.helpers"; import type { ContentProps } from "./content.types"; import { wrapComponentRef } from "./wrap-component-ref"; import { ScrollView } from "react-native"; function ContentComponent(props: ContentProps) { const [scriptStr, setScriptStr] = useState(() => getUpdateVariantVisibilityScript({ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain variationId: props.content?.testVariationId!, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain contentId: props.content?.id!, }) ); function contentSetState(newRootState: BuilderRenderState) { setBuilderContextSignal((PREVIOUS_VALUE) => ({ ...PREVIOUS_VALUE, rootState: newRootState, })); } const [registeredComponents, setRegisteredComponents] = useState(() => [ ...getDefaultRegisteredComponents(), ...(props.customComponents || []), ].reduce( (acc, { component, ...info }) => ({ ...acc, [info.name]: { component: component, ...serializeIncludingFunctions(info), }, }), {} ) ); const [builderContextSignal, setBuilderContextSignal] = useState(() => ({ strictStyleMode: props.strictStyleMode, content: getContentInitialValue({ content: props.content, data: props.data, }), localState: undefined, rootState: getRootStateInitialValue({ content: props.content, data: props.data, locale: props.locale, }), rootSetState: contentSetState, context: props.context || {}, canTrack: props.canTrack, apiKey: props.apiKey, apiVersion: props.apiVersion, componentInfos: [ ...getDefaultRegisteredComponents(), ...(props.customComponents || []), ].reduce>( (acc, { component: _, ...info }) => ({ ...acc, [info.name]: serializeIncludingFunctions(info), }), {} ), inheritedStyles: {}, BlocksWrapper: props.blocksWrapper || ScrollView, BlocksWrapperProps: props.blocksWrapperProps || {}, nonce: props.nonce || "", model: props.model, })); const hasInitialized = useRef(false); if (!hasInitialized.current) { if (!props.apiKey) { logger.error( "No API key provided to `Content` component. This can cause issues. Please provide an API key using the `apiKey` prop." ); } // run any dynamic JS code attached to content const jsCode = builderContextSignal.content?.data?.jsCode; if (jsCode) { evaluate({ code: jsCode, context: props.context || {}, localState: undefined, rootState: builderContextSignal.rootState, rootSetState: (newState) => { setBuilderContextSignal((PREVIOUS_VALUE) => ({ ...PREVIOUS_VALUE, rootState: newState, })); }, isExpression: false, }); } hasInitialized.current = true; } useEffect(() => { const updateContentAndRootState = () => { const nextId = props.content?.id; const currentId = builderContextSignal.content?.id; if (nextId && nextId !== currentId) { // Update content and root state to reflect the new entry builderContextSignal.content = getContentInitialValue({ content: props.content, data: props.data, }); builderContextSignal.rootState = getRootStateInitialValue({ content: props.content, data: props.data, locale: props.locale, }); // Update AB-test visibility script setScriptStr( getUpdateVariantVisibilityScript({ variationId: props.content?.testVariationId || "", contentId: nextId, }) ); } }; }, [props.content, props.data, props.locale]); return ( {props.isSsrAbTest ? ( ) : null} {TARGET !== "reactNative" ? ( ) : null} ); } export default ContentComponent;