aboutsummaryrefslogtreecommitdiffstats
path: root/src/services
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-05-13 22:41:39 +0200
committerArmand Philippot <git@armandphilippot.com>2022-05-13 22:41:39 +0200
commitfe2252ced2bb895e26179640553b5a6c02957d54 (patch)
tree4da3258dc4cd1971f5c39ac2366bb43df776130c /src/services
parent5f3799ee75b3ac5cffe726023d8e5df129b919dd (diff)
chore: add Topic pages
Diffstat (limited to 'src/services')
-rw-r--r--src/services/graphql/topics.query.ts7
-rw-r--r--src/services/graphql/topics.ts135
2 files changed, 136 insertions, 6 deletions
diff --git a/src/services/graphql/topics.query.ts b/src/services/graphql/topics.query.ts
index 6cc525e..19be5d7 100644
--- a/src/services/graphql/topics.query.ts
+++ b/src/services/graphql/topics.query.ts
@@ -16,6 +16,13 @@ export const topicBySlugQuery = `query TopicBy($slug: ID!) {
}
}
}
+ author {
+ node {
+ gravatarUrl
+ name
+ url
+ }
+ }
commentCount
contentParts {
beforeMore
diff --git a/src/services/graphql/topics.ts b/src/services/graphql/topics.ts
index 0f59bad..3c92442 100644
--- a/src/services/graphql/topics.ts
+++ b/src/services/graphql/topics.ts
@@ -1,6 +1,20 @@
-import { RawTopicPreview, TotalItems } from '@ts/types/raw-data';
+import { PageLink, Slug, Topic } from '@ts/types/app';
+import {
+ RawArticle,
+ RawTopic,
+ RawTopicPreview,
+ TotalItems,
+} from '@ts/types/raw-data';
+import { getImageFromRawData } from '@utils/helpers/images';
+import { getPageLinkFromRawData } from '@utils/helpers/pages';
import { EdgesResponse, EdgesVars, fetchAPI, getAPIUrl } from './api';
-import { topicsListQuery, totalTopicsQuery } from './topics.query';
+import { getArticleFromRawData } from './articles';
+import {
+ topicBySlugQuery,
+ topicsListQuery,
+ topicsSlugQuery,
+ totalTopicsQuery,
+} from './topics.query';
/**
* Retrieve the total number of topics.
@@ -34,9 +48,118 @@ export const getTopicsPreview = async (
return response.topics;
};
-export const getAllTopicsLinks = async () => {
- const allTopics = [];
- const initialTopics = await getTopicsPreview({ first: 1 });
+/**
+ * Convert raw data to a Topic object.
+ *
+ * @param {RawTopic} data - The page raw data.
+ * @returns {Topic} The page data.
+ */
+export const getTopicFromRawData = (data: RawTopic): Topic => {
+ const {
+ acfTopics,
+ contentParts,
+ databaseId,
+ date,
+ featuredImage,
+ info,
+ modified,
+ slug,
+ title,
+ seo,
+ } = data;
+
+ /**
+ * Retrieve an array of related topics.
+ *
+ * @param posts - The topic posts.
+ * @returns {PageLink[]} An array of topics links.
+ */
+ const getRelatedThematics = (posts: RawArticle[]): PageLink[] => {
+ const thematics: PageLink[] = [];
+
+ posts.forEach((post) => {
+ if (post.acfPosts.postsInThematic) {
+ post.acfPosts.postsInThematic.forEach((thematic) =>
+ thematics.push(getPageLinkFromRawData(thematic))
+ );
+ }
+ });
+
+ const thematicsIds = thematics.map((thematic) => thematic.id);
+ const uniqueThematics = thematics.filter(
+ ({ id }, index) => !thematicsIds.includes(id, index + 1)
+ );
+ const sortThematicByName = (a: PageLink, b: PageLink) => {
+ var nameA = a.name.toUpperCase(); // ignore upper and lowercase
+ var nameB = b.name.toUpperCase(); // ignore upper and lowercase
+ if (nameA < nameB) {
+ return -1;
+ }
+ if (nameA > nameB) {
+ return 1;
+ }
+
+ // names must be equal
+ return 0;
+ };
+
+ return uniqueThematics.sort(sortThematicByName);
+ };
+
+ return {
+ content: contentParts.afterMore,
+ id: databaseId,
+ intro: contentParts.beforeMore,
+ meta: {
+ articles: acfTopics.postsInTopic.map((post) =>
+ getArticleFromRawData(post)
+ ),
+ cover: featuredImage?.node
+ ? getImageFromRawData(featuredImage.node)
+ : undefined,
+ dates: { publication: date, update: modified },
+ website: acfTopics.officialWebsite,
+ readingTime: info.readingTime,
+ seo: {
+ description: seo?.metaDesc || '',
+ title: seo?.title || '',
+ },
+ thematics: getRelatedThematics(acfTopics.postsInTopic),
+ wordsCount: info.wordsCount,
+ },
+ slug,
+ title,
+ };
+};
+
+/**
+ * Retrieve a Topic object by slug.
+ *
+ * @param {string} slug - The topic slug.
+ * @returns {Promise<Article>} The requested topic.
+ */
+export const getTopicBySlug = async (slug: string): Promise<Topic> => {
+ const response = await fetchAPI<RawTopic, typeof topicBySlugQuery>({
+ api: getAPIUrl(),
+ query: topicBySlugQuery,
+ variables: { slug },
+ });
+
+ return getTopicFromRawData(response.topic);
+};
+
+/**
+ * Retrieve all the topics slugs.
+ *
+ * @returns {Promise<string[]>} - An array of topics slugs.
+ */
+export const getAllTopicsSlugs = async (): Promise<string[]> => {
+ const totalTopics = await getTotalTopics();
+ const response = await fetchAPI<Slug, typeof topicsSlugQuery>({
+ api: getAPIUrl(),
+ query: topicsSlugQuery,
+ variables: { first: totalTopics },
+ });
- if (!initialTopics.pageInfo.hasNextPage) return initialTopics;
+ return response.topics.edges.map((edge) => edge.node.slug);
};