import type TBLClassicPage from '../classic/TBLClassicPage'; import type TBLClassicUnitController from '../classic/TBLClassicUnitController'; import type { TBLClassicListener } from '../classic/TBLClassicListener'; import { useEffect, useReducer, useRef } from 'react'; interface UseCreateUnitProps { tblClassicPage: TBLClassicPage; placement: string; mode: string; placementType: number; tblClassicListener: TBLClassicListener; } /** * useCreateUnit hook: Builds a Taboola unit once on mount * * @param {TBLClassicPage} params.tblClassicPage - Configuration parameters for creating a Taboola unit * @param {string} params.placement - The placement name for the Taboola unit * @param {string} params.mode - The mode of the placement * @param {number} params.placementType - The type of the placement * @param {TBLClassicListener} [params.tblClassicListener] - Optional listener for unit events * * @description * Controls how organic clicks are handled: * - `true` (default): SDK handles opening the click URL for non-organic content * - `false`: Prevents SDK from handling click URL, allowing custom handling * * @returns {Promise} A promise that resolves to a created TBLClassicUnit * * @example * const tblClassicUnitController = useCreateUnit({ * tblClassicPage: tblClassicPage, * placement: 'below-article', * mode: 'thumbnails-and-video', * placementType: PlacementType.FEED, * shouldTaboolaHandleOrganicClicks: false * }); */ export function useCreateUnit({ tblClassicPage, placement, mode, placementType, tblClassicListener, }: UseCreateUnitProps): { tblClassicUnitController: TBLClassicUnitController | null; } { const [, forceUpdate] = useReducer((x: number) => x + 1, 0); // Ref to hold the unit controller const tblClassicUnitController = useRef(null); useEffect(() => { let isMounted = true; async function loadUnit() { try { console.log('[TBLSOS] [useCreateUnit.loadUnit] Starting unit creation', { pageId: tblClassicPage.pageId, placement, mode, placementType, hasListener: !!tblClassicListener }); const createdUnit = await tblClassicPage.buildUnit(placement, mode, placementType, tblClassicListener); console.log('[TBLSOS] [useCreateUnit.loadUnit] buildUnit returned', { unitId: createdUnit?.unitId, isUnitNull: createdUnit === null || createdUnit === undefined, isMounted }); if (isMounted && createdUnit) { console.log('[useCreateUnit] loadUnit: Unit created', { unitId: createdUnit.unitId }); tblClassicUnitController.current = createdUnit; forceUpdate(); console.log('[TBLSOS] [useCreateUnit.loadUnit] Unit assigned to ref', { unitId: createdUnit.unitId }); } else { console.log('[TBLSOS] [useCreateUnit.loadUnit] Unit NOT assigned', { isMounted, isCreatedUnitNull: !createdUnit }); } } catch (error) { console.error('[TBLSOS] [useCreateUnit.loadUnit] ERROR occurred during unit creation:', error); console.error('[TBLSOS] [useCreateUnit.loadUnit] Error details:', error instanceof Error ? error.message : String(error)); console.error('[TBLSOS] [useCreateUnit.loadUnit] Error stack:', error instanceof Error ? error.stack : 'No stack trace'); } } loadUnit(); return () => { console.log('[TBLSOS] [useCreateUnit.cleanup] Cleaning up unit', { unitId: tblClassicUnitController.current?.unitId }); isMounted = false; if (tblClassicUnitController.current) { tblClassicUnitController.current = null; } }; // We want to run this effect once on mount/unmount // eslint-disable-next-line react-hooks/exhaustive-deps }, []); console.log('[TBLSOS] [useCreateUnit.return] Returning controller', { isControllerNull: tblClassicUnitController.current === null, unitId: tblClassicUnitController.current?.unitId }); return { tblClassicUnitController: tblClassicUnitController.current }; }