import Prismic, { Predicates } from 'prismic-javascript'; import { PrismicDocument, SearchResponse } from 'easy-prismic-react'; // import { getPrismicLocale } from '../utils/i18n'; import { IncomingMessage } from 'http'; import ResolvedApi, { QueryOptions } from 'prismic-javascript/d.ts/ResolvedApi'; import NextI18NextInstance from '../i18n'; import { BlogHomePageData, BlogPostData, BlogPostTag, HomePageData, ProductPageData, SharedConfiguration } from '../typings/entities'; import ApiSearchResponse from 'prismic-javascript/d.ts/ApiSearchResponse'; export type TContentTypes = | 'seo_configuration' | 'homepage' | 'product_landing' | 'blog_post' | 'blog_home' | 'blog_tag' | 'footer' | 'header' | 'shared_configuration'; const relatedProductsProperties = [ 'product_landing.product_illustration', 'product_landing.product_name', 'product_landing.product_shortname', 'product_landing.product_starting_price', 'product_landing.product_price_hover_text' ]; const homePageBlogPostProperties = [ 'blog_tag.name', 'blog_post.tag', 'blog_post.title', 'blog_post.description', 'blog_post.image' ]; export async function initApi(req: IncomingMessage): Promise<{ api: ResolvedApi; language: string }> { const api = await Prismic.getApi(process.env.PRISMIC_ENDPOINT, { req }); return { api, language: req ? (req as any).language : NextI18NextInstance.i18n.language }; } async function getContent(req: IncomingMessage, query: string[], queryOptions: QueryOptions = {}): Promise { const { api /**, language */ } = await initApi(req); // const locale = getPrismicLocale(language); // Force FR for now const response = await api.query(query, { ...queryOptions, lang: 'fr-fr' }); if (response?.results?.[0]) { return response; } throw new Error(); } function getContentByType(type: TContentTypes): string[] { return [ Prismic.Predicates.at('document.type', type) ]; } function getContentByUID(page: TContentTypes, uid: string): string[] { return [ Prismic.Predicates.at(`my.${page}.uid`, uid) ]; } export async function getSharedConfiguration(req: IncomingMessage): Promise> { const response = await getContent( req, getContentByType('shared_configuration'), { fetchLinks: [...relatedProductsProperties, 'blog_tag.name'] } ); return response.results[0]; } export async function getHomepage(req: IncomingMessage): Promise> { const response = await (getContent as any)( req, getContentByType('homepage'), { fetchLinks: relatedProductsProperties } ); return response.results[0]; } export async function getProductPage(req: IncomingMessage, slug: string): Promise> { const response = await getContent( req, getContentByUID('product_landing', slug), { fetchLinks: relatedProductsProperties } ); return response.results[0]; } export async function getBlogHomepage(req: IncomingMessage): Promise> { const response = await (getContent as any)( req, getContentByType('blog_home'), { fetchLinks: ['blog_post.image', 'blog_post.tag', 'blog_post.title', 'blog_post.description', 'blog_tag.name'] } ); return response.results[0]; } export const DEFAULT_POSTS_PER_PAGE = 8; interface GetBlogPostsParams { page?: number; ignoredPostId?: string; blogTagId?: string; postsPerPage?: number; } export async function getBlogPosts(req: IncomingMessage, { page, ignoredPostId, blogTagId, postsPerPage }: GetBlogPostsParams): Promise> { const predicates = [ ...getContentByType('blog_post'), Prismic.Predicates.not('document.id', ignoredPostId) ]; if (blogTagId) { predicates.push(Prismic.Predicates.at('my.blog_post.tag', blogTagId)); } return getContent( req, predicates, { page: page || 1, pageSize: postsPerPage || DEFAULT_POSTS_PER_PAGE, orderings: '[document.first_publication_date desc]', fetchLinks: ['blog_tag.name'], fetch: homePageBlogPostProperties } ); } export async function getBlogPost(req: IncomingMessage, slug: string): Promise> { const response = await getContent( req, getContentByUID('blog_post', slug), { fetchLinks: [ 'blog_tag.name', 'blog_post_author.full_name', 'blog_post_author.portrait', 'blog_post.title', 'blog_post.image', 'blog_post.tag' ] } ); return response.results[0]; } export async function getBlogTag(req: IncomingMessage, slug: string, fetchAdditionalProperties?: boolean): Promise> { const response = await getContent( req, getContentByUID('blog_tag', slug), fetchAdditionalProperties ? { fetchLinks: homePageBlogPostProperties } : undefined ); return response.results[0]; } export async function getProducts(req: IncomingMessage): Promise> { return getContent( req, getContentByType('product_landing'), { pageSize: 10 } ); } const TOTAL_RELATED_POSTS_DISPLAYED = 3; const MAX_COMMITMENT_LEVEL = 3; const SAME_COMMITMENT_AMOUNT = 2; const HIGHER_COMMITMENT_AMOUNT = TOTAL_RELATED_POSTS_DISPLAYED - SAME_COMMITMENT_AMOUNT; interface GetRelatedPostsOptions { ignoredPostId: string; commitmentLevel: number; blogTagId: string; } export async function getRelatedPosts(req: IncomingMessage, options: GetRelatedPostsOptions): Promise[]> { const { commitmentLevel, blogTagId, ignoredPostId } = options; const predicates = [ ...getContentByType('blog_post'), Prismic.Predicates.at('my.blog_post.tag', blogTagId), Prismic.Predicates.not('document.id', ignoredPostId) ]; const fetchOptions = { pageSize: TOTAL_RELATED_POSTS_DISPLAYED, orderings: '[document.first_publication_date desc]', fetchLinks: ['blog_tag.name'], fetch: homePageBlogPostProperties }; try { const sameCommitmentLevelReq = await getContent( req, [ ...predicates, Predicates.any('my.blog_post.commitment_level', [commitmentLevel]) ], fetchOptions ); if (commitmentLevel < MAX_COMMITMENT_LEVEL) { const higherCommitmentLevelReq = await getContent( req, [ ...predicates, Predicates.any('my.blog_post.commitment_level', [commitmentLevel + 1]) ], fetchOptions ); const sameRequirementPostsCount = sameCommitmentLevelReq.results.length; return [ ...sameCommitmentLevelReq.results.splice(0, SAME_COMMITMENT_AMOUNT), ...higherCommitmentLevelReq.results.splice( 0, sameRequirementPostsCount >= 2 ? HIGHER_COMMITMENT_AMOUNT : TOTAL_RELATED_POSTS_DISPLAYED - sameRequirementPostsCount ) ]; } return sameCommitmentLevelReq.results.splice(0, TOTAL_RELATED_POSTS_DISPLAYED); } catch (err) { const fallbackPosts = await getBlogPosts(req, { ignoredPostId, blogTagId, postsPerPage: 3, page: 1 }); return fallbackPosts.results; } }