diff options
Diffstat (limited to 'src/utils/helpers')
| -rw-r--r-- | src/utils/helpers/author.ts | 31 | ||||
| -rw-r--r-- | src/utils/helpers/graphql.ts | 64 | ||||
| -rw-r--r-- | src/utils/helpers/images.ts | 17 | ||||
| -rw-r--r-- | src/utils/helpers/index.ts | 3 | ||||
| -rw-r--r-- | src/utils/helpers/pages.tsx | 83 | ||||
| -rw-r--r-- | src/utils/helpers/rss.ts | 25 | ||||
| -rw-r--r-- | src/utils/helpers/server/projects.ts | 38 |
7 files changed, 100 insertions, 161 deletions
diff --git a/src/utils/helpers/author.ts b/src/utils/helpers/author.ts deleted file mode 100644 index a5e9bc6..0000000 --- a/src/utils/helpers/author.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { type Author, type ContentKind, type RawAuthor } from '../../types'; - -/** - * Convert author raw data to regular data. - * - * @param {RawAuthor<ContentKind>} data - The author raw data. - * @param {ContentKind} kind - The author kind. Either `page` or `comment`. - * @param {number} [avatarSize] - The author avatar size. - * @returns {Author<ContentKind>} The author data. - */ -export const getAuthorFromRawData = ( - data: RawAuthor<typeof kind>, - kind: ContentKind, - avatarSize: number = 80 -): Author<typeof kind> => { - const { name, description, gravatarUrl, url } = data; - - return { - name, - avatar: gravatarUrl - ? { - alt: `${name} avatar`, - height: avatarSize, - src: gravatarUrl, - width: avatarSize, - } - : undefined, - description, - website: url, - }; -}; diff --git a/src/utils/helpers/graphql.ts b/src/utils/helpers/graphql.ts new file mode 100644 index 0000000..e07b151 --- /dev/null +++ b/src/utils/helpers/graphql.ts @@ -0,0 +1,64 @@ +import type { Nullable } from '../../types'; +import { CONFIG } from '../config'; + +/** + * Retrieve the API url from settings. + * + * @returns {string} The API url. + */ +export const getGraphQLUrl = (): string => { + if (!CONFIG.api.url) throw new Error('You forgot to define the API url.'); + + return CONFIG.api.url; +}; + +export type GraphQLData<T> = Record<string, Nullable<T>>; + +type GraphQLResponse<T extends GraphQLData<unknown>> = { + data: T; + errors?: { message: string }[]; +}; + +export type FetchGraphQLConfig = { + query: string; + url: string; + variables?: Record<string, unknown>; +}; + +/** + * Retrieve GraphQL data using fetch. + * + * @template T - The expected data type. + * @param {FetchGraphQLConfig} config - A configuration object. + * @returns {Promise<T>} The data. + */ +export const fetchGraphQL = async < + T extends GraphQLData<unknown> = GraphQLData<unknown>, +>({ + query, + url, + variables, +}: FetchGraphQLConfig): Promise<T> => { + const response = await fetch(url, { + method: 'POST', + headers: { + 'content-type': 'application/json;charset=UTF-8', + }, + body: JSON.stringify({ + query, + variables, + }), + }); + + const { data, errors }: GraphQLResponse<T> = await response.json(); + + if (!response.ok) { + const error = new Error( + errors?.map((e) => e.message).join('\n') ?? 'Network response was not OK' + ); + + return Promise.reject(error); + } + + return data; +}; diff --git a/src/utils/helpers/images.ts b/src/utils/helpers/images.ts deleted file mode 100644 index 6e0c2c5..0000000 --- a/src/utils/helpers/images.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { type Image, type RawCover } from '../../types'; - -/** - * Retrieve an Image object from raw data. - * - * @param image - The cover raw data. - * @returns {Image} - An Image object. - */ -export const getImageFromRawData = (image: RawCover): Image => { - return { - alt: image.altText, - height: image.mediaDetails.height, - src: image.sourceUrl, - title: image.title, - width: image.mediaDetails.width, - }; -}; diff --git a/src/utils/helpers/index.ts b/src/utils/helpers/index.ts index 92f9424..94fde45 100644 --- a/src/utils/helpers/index.ts +++ b/src/utils/helpers/index.ts @@ -1,5 +1,4 @@ -export * from './author'; -export * from './images'; +export * from './graphql'; export * from './pages'; export * from './reading-time'; export * from './refs'; diff --git a/src/utils/helpers/pages.tsx b/src/utils/helpers/pages.tsx index 7b6bdca..9e015db 100644 --- a/src/utils/helpers/pages.tsx +++ b/src/utils/helpers/pages.tsx @@ -1,43 +1,7 @@ import NextImage from 'next/image'; import type { LinksWidgetItemData, PostData } from '../../components'; -import { getArticleFromRawData } from '../../services/graphql'; -import type { - Article, - EdgesResponse, - PageLink, - RawArticle, - RawThematicPreview, - RawTopicPreview, -} from '../../types'; +import type { ArticlePreview, PageLink } from '../../types'; import { ROUTES } from '../constants'; -import { getImageFromRawData } from './images'; - -/** - * Convert raw data to a Link object. - * - * @param data - An object. - * @param {number} data.databaseId - The data id. - * @param {number} [data.logo] - The data logo. - * @param {string} data.slug - The data slug. - * @param {string} data.title - The data name. - * @returns {PageLink} The link data (id, slug and title). - */ -export const getPageLinkFromRawData = ( - data: RawThematicPreview | RawTopicPreview, - kind: 'thematic' | 'topic' -): PageLink => { - const { databaseId, featuredImage, slug, title } = data; - const baseUrl = `${ - kind === 'thematic' ? ROUTES.THEMATICS.INDEX : ROUTES.TOPICS - }/`; - - return { - id: databaseId, - logo: featuredImage ? getImageFromRawData(featuredImage.node) : undefined, - name: title, - url: `${baseUrl}${slug}`, - }; -}; /** * Method to sort PageLink objects by name. @@ -73,55 +37,28 @@ export const getLinksItemData = (links: PageLink[]): LinksWidgetItemData[] => /** * Retrieve the posts list with the article URL. * - * @param {Article[]} posts - An array of articles. + * @param {ArticlePreview[]} posts - An array of articles. * @returns {PostData[]} An array of posts with full article URL. */ -export const getPostsWithUrl = (posts: Article[]): PostData[] => - posts.map(({ intro, meta, slug, title, ...post }) => { +export const getPostsWithUrl = (posts: ArticlePreview[]): PostData[] => + posts.map(({ id, intro, meta, slug, title, ...post }) => { return { ...post, cover: meta.cover ? <NextImage {...meta.cover} /> : undefined, excerpt: intro, heading: title, + id, meta: { publicationDate: meta.dates.publication, updateDate: meta.dates.update, wordsCount: meta.wordsCount, - author: meta.author?.name, thematics: meta.thematics, - topics: meta.topics, - comments: - meta.commentsCount === undefined - ? undefined - : { - count: meta.commentsCount, - postHeading: title, - url: `${ROUTES.ARTICLE}/${slug}#comments`, - }, + comments: { + count: meta.commentsCount ?? 0, + postHeading: title, + url: `${ROUTES.ARTICLE}/${slug}#comments`, + }, }, url: `${ROUTES.ARTICLE}/${slug}`, }; }); - -/** - * Retrieve the posts list from raw data. - * - * @param {EdgesResponse<RawArticle>[]} rawData - The raw data. - * @returns {PostData[]} An array of posts. - */ -export const getPostsList = async ( - rawData: EdgesResponse<RawArticle>[] -): Promise<PostData[]> => { - const articlesList: RawArticle[] = []; - rawData.forEach((articleData) => { - articleData.edges.forEach((edge) => { - articlesList.push(edge.node); - }); - }); - - return getPostsWithUrl( - await Promise.all( - articlesList.map(async (article) => getArticleFromRawData(article)) - ) - ); -}; diff --git a/src/utils/helpers/rss.ts b/src/utils/helpers/rss.ts index d9c3b1e..82fa1ee 100644 --- a/src/utils/helpers/rss.ts +++ b/src/utils/helpers/rss.ts @@ -1,28 +1,25 @@ import { Feed } from 'feed'; import { - getArticleFromRawData, - getArticles, - getTotalArticles, + convertPostPreviewToArticlePreview, + fetchPostsList, + fetchPostsCount, } from '../../services/graphql'; -import type { Article } from '../../types'; +import type { ArticlePreview } from '../../types'; import { CONFIG } from '../config'; import { ROUTES } from '../constants'; /** * Retrieve the data for all the articles. * - * @returns {Promise<Article[]>} - All the articles. + * @returns {Promise<ArticlePreview[]>} - All the articles. */ -const getAllArticles = async (): Promise<Article[]> => { - const totalArticles = await getTotalArticles(); - const rawArticles = await getArticles({ first: totalArticles }); - const articles: Article[] = []; +const getAllArticles = async (): Promise<ArticlePreview[]> => { + const totalPosts = await fetchPostsCount(); + const posts = await fetchPostsList({ first: totalPosts }); - rawArticles.edges.forEach(async (edge) => { - articles.push(await getArticleFromRawData(edge.node)); - }); - - return articles; + return posts.edges.map((edge) => + convertPostPreviewToArticlePreview(edge.node) + ); }; /** diff --git a/src/utils/helpers/server/projects.ts b/src/utils/helpers/server/projects.ts index ed73da8..c1a3d10 100644 --- a/src/utils/helpers/server/projects.ts +++ b/src/utils/helpers/server/projects.ts @@ -1,10 +1,6 @@ import { readdirSync } from 'fs'; import path from 'path'; -import { - type MDXProjectMeta, - type ProjectCard, - type ProjectPreview, -} from '../../../types'; +import type { MDXProjectMeta, Project, ProjectPreview } from '../../../types'; /** * Retrieve all the projects filename. @@ -24,9 +20,7 @@ export const getProjectFilenames = (): string[] => { * @param {string} filename - The project filename. * @returns {Promise<ProjectPreview>} */ -export const getProjectData = async ( - filename: string -): Promise<ProjectPreview> => { +export const getProjectData = async (filename: string): Promise<Project> => { try { const { meta, @@ -53,7 +47,7 @@ export const getProjectData = async ( }, }, slug: filename, - title: title, + title, }; } catch (err) { console.error(err); @@ -65,28 +59,24 @@ export const getProjectData = async ( * Retrieve all the projects data using filenames. * * @param {string[]} filenames - The filenames without extension. - * @returns {Promise<ProjectCard[]>} - An array of projects data. + * @returns {Promise<ProjectPreview[]>} - An array of projects data. */ export const getProjectsData = async ( filenames: string[] -): Promise<ProjectCard[]> => { - return Promise.all( - filenames.map(async (filename) => { - const { id, meta, slug, title } = await getProjectData(filename); - const { cover, dates, tagline, technologies } = meta; - return { id, meta: { cover, dates, tagline, technologies }, slug, title }; - }) - ); -}; +): Promise<ProjectPreview[]> => + Promise.all(filenames.map(async (filename) => getProjectData(filename))); /** * Method to sort an array of projects by publication date. * - * @param {ProjectCard} a - A single project. - * @param {ProjectCard} b - A single project. + * @param {ProjectPreview} a - A single project. + * @param {ProjectPreview} b - A single project. * @returns The result used by Array.sort() method: 1 || -1 || 0. */ -const sortProjectsByPublicationDate = (a: ProjectCard, b: ProjectCard) => { +const sortProjectsByPublicationDate = ( + a: ProjectPreview, + b: ProjectPreview +) => { if (a.meta.dates.publication < b.meta.dates.publication) return 1; if (a.meta.dates.publication > b.meta.dates.publication) return -1; return 0; @@ -95,9 +85,9 @@ const sortProjectsByPublicationDate = (a: ProjectCard, b: ProjectCard) => { /** * Retrieve all projects in content folder sorted by publication date. * - * @returns {Promise<ProjectCard[]>} An array of projects. + * @returns {Promise<ProjectPreview[]>} An array of projects. */ -export const getProjectsCard = async (): Promise<ProjectCard[]> => { +export const getProjectsCard = async (): Promise<ProjectPreview[]> => { const filenames = getProjectFilenames(); const projects = await getProjectsData(filenames); |
