apps/web/src/lib/recentArticles.ts

1import { EDITORIAL_TYPES } from '@local/config'
2import { getPublishedSanityClient } from '@local/sanity/client'
3import { sanityFetch } from '@local/sanity/utils/fetch'
4import {
5	RESOURCE_DATE_RAW_GROQ,
6	RESOURCE_DATETIME_GROQ,
7} from '@local/sanity/utils/query'
8
9export const ARTICLE_TYPES = EDITORIAL_TYPES.filter(
10	(type) =>
11		!['video', 'report', 'research', 'data', 'testimonials'].includes(type),
12)
13
14export const RECENT_ARTICLES_QUERY = `*[
15	_type in $types && defined(fullSlug) && defined(title) &&
16	(${RESOURCE_DATETIME_GROQ}) <= dateTime(now()) &&
17	($topic == "" || title match $topic || excerpt match $topic || topics[]->title match $topic)
18] | order((${RESOURCE_DATETIME_GROQ}) desc, _id asc) [0...8] {
19	title, "url": fullSlug, excerpt,
20	"publishedAt": ${RESOURCE_DATE_RAW_GROQ},
21	"topics": topics[]->title
22}`
23
24type RecentArticle = {
25	title: string
26	url: string
27	excerpt: string | null
28	publishedAt: string
29	topics: string[] | null
30}
31
32/** Sort the complete matching published catalogue before limiting results. */
33export async function fetchRecentArticles(
34	topic: string,
35): Promise<RecentArticle[]> {
36	return sanityFetch<RecentArticle[]>(
37		getPublishedSanityClient(),
38		RECENT_ARTICLES_QUERY,
39		{ types: ARTICLE_TYPES, topic: topic.trim().slice(0, 120) },
40		{ tag: 'media' },
41	)
42}
43