/* eslint-disable camelcase,@typescript-eslint/no-non-null-assertion */ /* eslint-env browser */ import React, { ComponentProps, useEffect, useReducer } from 'react' import { parseHostname } from '@ta-interaktiv/parse-hostname' import { GoogleTagManager } from '@ta-interaktiv/react-gtm' import { ArticleId } from '@ta-interaktiv/types' import { getTitle, isPremium, getCategory, getSubCategory, getPublishingDate, getAuthors } from '@ta-interaktiv/api-access' export interface Props extends Partial { /** Article ID of the link article in * the CD. If not available it will assume that content is being loaded in an * iframe. So, yes, you can use this component without adding the * `articleId` attribute. Make sure that you also pass an article ID when * passing in the statistics configuration and GTM ID directly, otherwise * WEMF won't track! */ articleId?: string /** Google Tag Manager ID. If this isn't * passed in, the component will fetch the necessary data from the Newsnet * API. */ gtmId: string } const domain = parseHostname().publicationName /** * Create a type based on the GTM Component props, that only contains the information * that we need to get from the APIs */ type ReducedGoogleTagManagerProps = Omit< ComponentProps, 'gtmId' | 'event' | 'article_id' | 'article_length' > /** * A list of all the properties we load from the APIs, and whether they have * been loaded. */ type HasLoadedList = { [key in keyof ReducedGoogleTagManagerProps]: boolean } type Action = { type: 'SET_VALUE' payload: string | number meta: keyof ReducedGoogleTagManagerProps } interface ReducerState { hasLoaded: HasLoadedList values: ReducedGoogleTagManagerProps } const reducer = (state: ReducerState, action: Action) => { switch (action.type) { case 'SET_VALUE': return { hasLoaded: { ...state.hasLoaded, [action.meta]: true }, values: { ...state.values, [action.meta]: action.payload } } } return state } /** * Create the dispatch object * @param value * @param key */ const setValue: ( value: string | number, key: keyof ReducedGoogleTagManagerProps ) => Action = (value, key) => ({ type: 'SET_VALUE', payload: value, meta: key }) const defaultValues: ReducedGoogleTagManagerProps = { article_title: '', article_type: 'interactive-standalone', pagetype: 'content', category: '', subcategory: '', premium: 0, publish_date: '', author_name: '' } const defaultLoadingValues = Object.keys(defaultValues).reduce( (previousValue, currentValue) => { previousValue[currentValue as keyof HasLoadedList] = false return previousValue }, {} as HasLoadedList ) /** * Component to track visits to a website, accessing the Newsnet API for all * tracking information. Currently supports GTM. */ export function Tracking({ gtmId, articleId }: Props) { const [state, dispatch] = useReducer(reducer, { hasLoaded: defaultLoadingValues, values: defaultValues }) useEffect(() => { if (articleId) { try { // Title getTitle(domain, articleId).then(title => dispatch(setValue(title ?? '', 'article_title')) ) // Article Type dispatch(setValue('interactive-standalone', 'article_type')) // Page type needs to be set to content when an article ID is available dispatch(setValue('content', 'pagetype')) // Category getCategory(domain, articleId).then(category => dispatch(setValue(category ?? '', 'category')) ) // Sub Category getSubCategory(domain, articleId).then(subcategory => dispatch(setValue(subcategory ?? '', 'subcategory')) ) // Premium isPremium(domain, articleId).then(isPremium => dispatch(setValue(isPremium ? 1 : 0, 'premium')) ) // Publish Date getPublishingDate(domain, articleId).then(date => dispatch(setValue(date ?? '', 'publish_date')) ) // Author name getAuthors(domain, articleId).then((authorList: any) => dispatch(setValue(authorList.join(', '), 'author_name')) ) } catch (e) { console.debug( '[Tracking] Could not set up tracking due to an Error.', e ) } } else { // Title dispatch(setValue(window.document.title, 'article_title')) // Article Type dispatch(setValue('interactive-embeddable', 'article_type')) // Page Type dispatch(setValue('embeddable', 'pagetype')) // Category dispatch(setValue('', 'category')) // Sub category dispatch(setValue('', 'subcategory')) // Premium dispatch(setValue(0, 'premium')) // Publish Date dispatch(setValue('', 'publish_date')) // Author name dispatch(setValue('', 'author_name')) } }, [articleId]) if (!gtmId) { return null } // When we have loaded all the properties, render the GTM component if (Object.values(state.hasLoaded).every(val => val)) { return ( ) } return null }