aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-11-06 18:08:04 +0100
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:15:27 +0100
commitc9c1c90b30e243563bb4f731da15b3fe657556d2 (patch)
tree8263c176b4096e2893b9d9319bfa7edb01fce188 /src/utils
parent2771de88f40a5f4ed7480bd8614532dda72deeda (diff)
refactor(components): replace Summary component with PostPreview
* rename component to PostPreview because Summary is an HTML element and it could lead to confusion * replace `title` and `titleLevel` with `heading` and `headingLvl` because `title` is a native attribute * rename `intro` prop to `excerpt` * extract `cover` from `meta` prop * rewrite meta type * extract meta logic into a new component
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/helpers/index.ts1
-rw-r--r--src/utils/helpers/pages.tsx (renamed from src/utils/helpers/pages.ts)36
-rw-r--r--src/utils/helpers/reading-time.test.ts31
-rw-r--r--src/utils/helpers/reading-time.ts46
4 files changed, 107 insertions, 7 deletions
diff --git a/src/utils/helpers/index.ts b/src/utils/helpers/index.ts
index 14487e6..f340a49 100644
--- a/src/utils/helpers/index.ts
+++ b/src/utils/helpers/index.ts
@@ -1,6 +1,7 @@
export * from './author';
export * from './images';
export * from './pages';
+export * from './reading-time';
export * from './rss';
export * from './schema-org';
export * from './strings';
diff --git a/src/utils/helpers/pages.ts b/src/utils/helpers/pages.tsx
index 84854cd..556b4fb 100644
--- a/src/utils/helpers/pages.ts
+++ b/src/utils/helpers/pages.tsx
@@ -1,4 +1,5 @@
-import type { LinksListItems, Post } from '../../components';
+import NextImage from 'next/image';
+import type { LinksListItems, PostData } from '../../components';
import { getArticleFromRawData } from '../../services/graphql';
import type {
Article,
@@ -72,13 +73,32 @@ export const getLinksListItems = (links: PageLink[]): LinksListItems[] =>
* Retrieve the posts list with the article URL.
*
* @param {Article[]} posts - An array of articles.
- * @returns {Post[]} An array of posts with full article URL.
+ * @returns {PostData[]} An array of posts with full article URL.
*/
-export const getPostsWithUrl = (posts: Article[]): Post[] =>
- posts.map((post) => {
+export const getPostsWithUrl = (posts: Article[]): PostData[] =>
+ posts.map(({ intro, meta, slug, title, ...post }) => {
return {
...post,
- url: `/article/${post.slug}`,
+ cover: meta.cover ? <NextImage {...meta.cover} /> : undefined,
+ excerpt: intro,
+ heading: title,
+ 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`,
+ },
+ },
+ url: `${ROUTES.ARTICLE}/${slug}`,
};
});
@@ -86,9 +106,11 @@ export const getPostsWithUrl = (posts: Article[]): Post[] =>
* Retrieve the posts list from raw data.
*
* @param {EdgesResponse<RawArticle>[]} rawData - The raw data.
- * @returns {Post[]} An array of posts.
+ * @returns {PostData[]} An array of posts.
*/
-export const getPostsList = (rawData: EdgesResponse<RawArticle>[]): Post[] => {
+export const getPostsList = (
+ rawData: EdgesResponse<RawArticle>[]
+): PostData[] => {
const articlesList: RawArticle[] = [];
rawData.forEach((articleData) => {
articleData.edges.forEach((edge) => {
diff --git a/src/utils/helpers/reading-time.test.ts b/src/utils/helpers/reading-time.test.ts
new file mode 100644
index 0000000..24181a6
--- /dev/null
+++ b/src/utils/helpers/reading-time.test.ts
@@ -0,0 +1,31 @@
+import { describe, it } from '@jest/globals';
+import { getReadingTimeFrom } from './reading-time';
+
+describe('reading-time', () => {
+ it('can transform a words count into a reading time in minutes', () => {
+ const wordsCount = 250;
+
+ // With the default settings, 250 words should be rounded to one minute.
+ expect(getReadingTimeFrom(wordsCount).inMinutes()).toBe(1);
+ });
+
+ it('can transform a words count into a reading time in minutes and seconds', () => {
+ const wordsCount = 1200;
+ const readingTime = getReadingTimeFrom(wordsCount).inMinutesAndSeconds();
+
+ expect(readingTime.minutes).toBeGreaterThan(1);
+ expect(readingTime.seconds).toBeGreaterThan(0);
+ });
+
+ it('can use a custom words per minute setting', () => {
+ const wordsCount = 100;
+ const wordsPerMinute = 100;
+ const readingTime = getReadingTimeFrom(
+ wordsCount,
+ wordsPerMinute
+ ).inMinutesAndSeconds();
+
+ expect(readingTime.minutes).toBe(1);
+ expect(readingTime.seconds).toBe(0);
+ });
+});
diff --git a/src/utils/helpers/reading-time.ts b/src/utils/helpers/reading-time.ts
new file mode 100644
index 0000000..6cdeba4
--- /dev/null
+++ b/src/utils/helpers/reading-time.ts
@@ -0,0 +1,46 @@
+export type GetReadingTimeReturn = {
+ /**
+ * The reading time rounded to minutes.
+ */
+ inMinutes: () => number;
+ /**
+ * The reading time in minutes and seconds.
+ */
+ inMinutesAndSeconds: () => {
+ minutes: number;
+ seconds: number;
+ };
+};
+
+/**
+ * Retrieve the reading time from a words count.
+ *
+ * @param {number} wordsCount - The number of words.
+ * @param {number} [wordsPerMinute] - How many words can we read per minute?
+ * @returns {GetReadingTimeReturn} Two methods to retrieve the reading time.
+ */
+export const getReadingTimeFrom = (
+ wordsCount: number,
+ wordsPerMinute = 245
+): GetReadingTimeReturn => {
+ const ONE_MINUTE_IN_SECONDS = 60;
+ const wordsPerSecond = wordsPerMinute / ONE_MINUTE_IN_SECONDS;
+ const estimatedTimeInSeconds = wordsCount / wordsPerSecond;
+
+ return {
+ inMinutes: () => Math.round(estimatedTimeInSeconds / ONE_MINUTE_IN_SECONDS),
+ inMinutesAndSeconds: () => {
+ const estimatedTimeInMinutes = Math.floor(
+ estimatedTimeInSeconds / ONE_MINUTE_IN_SECONDS
+ );
+
+ return {
+ minutes: estimatedTimeInMinutes,
+ seconds: Math.round(
+ estimatedTimeInSeconds -
+ estimatedTimeInMinutes * ONE_MINUTE_IN_SECONDS
+ ),
+ };
+ },
+ };
+};