// @ts-check import { getHeaderDataQuery } from './graphql/getHeaderDataQuery.mjs'; import { getItemsHeaderMediaQuery } from './graphql/getItemsHeaderMediaQuery.mjs'; /** * Returns the header data for the header with the given ID. Returns a new header object with the header media for the * child items. * * @param {{ * channelToken: string; * headerItemId: string; * graphql: (args: any) => Promise; * }} args * @returns {Promise} */ export const getHeaderData = async ({ channelToken, headerItemId, graphql }) => { /** @type {import('./graphql/getHeaderDataQuery.mjs').HeaderDataQueryResponse} */ const headerDataRes = await graphql({ query: getHeaderDataQuery, variables: { channelToken, id: headerItemId, }, }); if (headerDataRes.errors) { console.warn('WARNING: Error while getting header data', headerDataRes.errors); } if (!headerDataRes.data) { return; } const headerData = headerDataRes.data.getItem; if (!headerData) { console.warn('WARNING: No header data'); return; } /** All header children without related images items */ const headerChildren = headerData.fields.level1Items; const headerChildItemsIds = getAllIds(headerChildren); /** Image assets related to `headerChildren` */ const headerChildItemsImages = await getHeaderChildItemsImages(headerChildItemsIds, graphql, channelToken); if (!headerChildItemsImages) { console.warn('WARNING: Could not get header child items images'); return headerData; } /** Header children with adjusted fields */ const headerChildrenWithImages = addImagesToItems(headerChildren, headerChildItemsImages); const headerDataWithNestedChildrenAndTheirImages = { ...headerData, fields: { ...headerData.fields, level1Items: headerChildrenWithImages, }, }; return headerDataWithNestedChildrenAndTheirImages; }; /** * Returns all the IDs of the child items of the given level items. Uses recurency to get the IDs of the child items of * the child items and so on. * * @param {Partial<{ id: string; fields: { headerChildItems: any } }>[]} levelItems * @param {Partial} headerChildItemsImages */ const addImagesToItems = (levelItems, headerChildItemsImages) => { const itemsWithImages = levelItems.map((item) => { const childItem = headerChildItemsImages?.getItems?.items?.find((childItem) => childItem && item ? childItem.id === item.id : false ); const childItemHeaderMedia = childItem?.fields?.headerMedia; const childItemListPageMedia = childItem?.fields?.fieldListPageMedia; const childItemMediaFile = childItem?.fields?.mediaFile; if (item?.fields?.headerChildItems) { item.fields.headerChildItems = addImagesToItems(item.fields.headerChildItems, headerChildItemsImages); } return { ...item, fields: { ...item?.fields, /** Assets of type ProductPage, ProductCategoryPage, ArticlePage, Link contains this property */ headerMedia: childItemHeaderMedia, /** Assets of type ProductPage, ProductCategoryPage, ArticlePage, Link contains this property */ fieldListPageMedia: childItemListPageMedia, /** Assets of type Link contains this property */ mediaFile: childItemMediaFile, }, }; }); return itemsWithImages; }; /** * Loops through all nested items and extracts their IDs * * @param {Partial< * ({ [key: string]: any } & { id: string; fields?: { [key: string]: any } & { headerChildItems?: any[] } })[] * >} items * @returns {string[]} */ const getAllIds = (items) => { // Loop through all items and extract their IDs const ids = items.flatMap((item) => [item?.id, ...getAllIds(item?.fields?.headerChildItems ?? [])]); // Filter out any falsy values (empty strings, etc.) return ids.filter(Boolean); }; /** * Returns the header media for the child items in the header (images etc.) * * @param {string[]} headerChildItemsIds * @param {any} graphql * @param {string} channelToken */ const getHeaderChildItemsImages = async (headerChildItemsIds, graphql, channelToken) => { if (headerChildItemsIds?.length === 0 || !headerChildItemsIds) { return; } /** @type {import('./graphql/getItemsHeaderMediaQuery.mjs').HeaderMediaQueryRes} */ const headerChildItemsImages = await graphql({ query: getItemsHeaderMediaQuery, variables: { channelToken, idsFilter: composeIdsFilter(headerChildItemsIds), }, }); return headerChildItemsImages.data; }; /** * Returns an array of objects with the id of the item and the value of the id. This is used to filter the items in the * graphql query. * * @param {string[]} ids * @returns */ const composeIdsFilter = (ids) => { return ids.map((id) => ({ id: { op: 'IS', value: id, }, })); };