diff options
Diffstat (limited to 'src/services/graphql/comments.ts')
| -rw-r--r-- | src/services/graphql/comments.ts | 144 |
1 files changed, 104 insertions, 40 deletions
diff --git a/src/services/graphql/comments.ts b/src/services/graphql/comments.ts index 86b6a35..41f80b3 100644 --- a/src/services/graphql/comments.ts +++ b/src/services/graphql/comments.ts @@ -1,46 +1,61 @@ -import { Comment } from '@ts/types/app'; +import { SingleComment } from '@ts/types/app'; import { GraphQLEdgesInput } from '@ts/types/graphql/generics'; import { SendCommentInput, SentComment } from '@ts/types/graphql/mutations'; import { ContentId } from '@ts/types/graphql/queries'; -import { RawComment } from '@ts/types/raw-data'; +import { RawComment, RawCommentsPage } from '@ts/types/raw-data'; import { getAuthorFromRawData } from '@utils/helpers/author'; import { fetchAPI } from './api'; import { sendCommentMutation } from './comments.mutation'; import { commentsQuery } from './comments.query'; -type FetchCommentsInput = ContentId & - Pick<GraphQLEdgesInput, 'after' | 'first'>; - /** - * Retrieve the comments list from GraphQL. + * Convert a comment from RawComment type to SingleComment type. * - * @param {FetchCommentsInput} variables - An object of variables. - * @returns {Promise<RawComment[]>} The raw comments. + * @param {RawComment} comment - A raw comment. + * @returns {SingleComment} A formatted comment. */ -export const fetchComments = async ( - variables: FetchCommentsInput -): Promise<RawComment[]> => { - const response = await fetchAPI<RawComment, typeof commentsQuery>({ - query: commentsQuery, - variables, - }); +export const getCommentFromRawData = (comment: RawComment): SingleComment => { + const { author, databaseId, date, parentDatabaseId, ...data } = comment; - return response.comments.nodes; + return { + id: databaseId, + meta: { + author: getAuthorFromRawData(author.node, 'comment'), + date, + }, + parentId: parentDatabaseId === 0 ? undefined : parentDatabaseId, + replies: [], + ...data, + }; +}; + +/** + * Convert an array of RawComment type to an array of SingleComment type. + * + * @param {RawComment[]} comments - The raw comments. + * @returns {SingleComment[]} The formatted comments. + */ +export const getCommentsFromRawData = ( + comments: RawComment[] +): SingleComment[] => { + return comments.map((comment) => getCommentFromRawData(comment)); }; /** * Create a comments tree with replies. * - * @param {Comment[]} comments - A flatten comments list. - * @returns {Comment[]} An array of comments with replies. + * @param {SingleComment[]} comments - A flatten comments list. + * @returns {SingleComment[]} An array of comments with replies. */ -export const buildCommentsTree = (comments: Comment[]): Comment[] => { +export const buildCommentsTree = ( + comments: SingleComment[] +): SingleComment[] => { type CommentsHashTable = { - [key: string]: Comment; + [key: string]: SingleComment; }; const hashTable: CommentsHashTable = Object.create(null); - const commentsTree: Comment[] = []; + const commentsTree: SingleComment[] = []; comments.forEach( (comment) => (hashTable[comment.id] = { ...comment, replies: [] }) @@ -57,36 +72,85 @@ export const buildCommentsTree = (comments: Comment[]): Comment[] => { return commentsTree; }; +type FetchCommentsInput = ContentId & + Pick<GraphQLEdgesInput, 'after' | 'first'>; + /** - * Convert a comment from RawComment to Comment type. + * Retrieve a raw comments page from GraphQL. * - * @param {RawComment} comment - A raw comment. - * @returns {Comment} A formatted comment. + * @param {FetchCommentsInput} variables - An object of variables. + * @returns {Promise<RawCommentsPage>} A raw comments page. */ -export const getCommentFromRawData = (comment: RawComment): Comment => { - const { author, databaseId, date, parentDatabaseId, ...data } = comment; +export const fetchRawComments = async ( + variables: FetchCommentsInput +): Promise<RawCommentsPage> => { + const response = await fetchAPI<RawComment, typeof commentsQuery>({ + query: commentsQuery, + variables, + }); return { - id: databaseId, - meta: { - author: getAuthorFromRawData(author.node, 'comment'), - date, - }, - parentId: parentDatabaseId, - replies: [], - ...data, + comments: response.comments.edges.map((edge) => edge.node), + hasNextPage: response.comments.pageInfo.hasNextPage, + endCursor: response.comments.pageInfo.endCursor, }; }; /** - * Retrieve a comments list by post id. + * Fetch recursively all the comments on a post. + * + * @param {FetchCommentsInput} variables - An object of query variables. + * @param {RawCommentsPage[]} pages - An accumulator to keep track of pages. + * @returns {Promise<RawCommentsPage[]>} The raw comments pages. + */ +export const fetchAllRawCommentsPages = async ( + variables: FetchCommentsInput, + pages: RawCommentsPage[] = [] +): Promise<RawCommentsPage[]> => { + return fetchRawComments(variables).then((page) => { + pages.push(page); + + if (page.hasNextPage) { + return fetchAllRawCommentsPages( + { ...variables, after: page.endCursor }, + pages + ); + } else { + return pages; + } + }); +}; + +/** + * Method to compare two comments dates and sort them from older to newest. + * + * @param {SingleComment} a - A comment. + * @param {SingleComment} b - Another comment. + * @returns {number} The difference between dates. + */ +export const compareCommentsDate = ( + a: SingleComment, + b: SingleComment +): number => { + return +new Date(a.meta.date) - +new Date(b.meta.date); +}; + +/** + * Retrieve all the comments on a post. * * @param {number} id - A post id. - * @returns {Promise<Comment[]>} The comments list. + * @returns {Promise<SingleComment[]>} The comments list. */ -export const getPostComments = async (id: number): Promise<Comment[]> => { - const rawComments = await fetchComments({ contentId: id }); - const comments = rawComments.map((comment) => getCommentFromRawData(comment)); +export const getAllComments = async ({ + contentId, +}: { + contentId: number; +}): Promise<SingleComment[]> => { + const pages = await fetchAllRawCommentsPages({ contentId }); + const comments = pages + .map((page) => getCommentsFromRawData(page.comments)) + .flat() + .sort(compareCommentsDate); return buildCommentsTree(comments); }; @@ -95,7 +159,7 @@ export const getPostComments = async (id: number): Promise<Comment[]> => { * Send a comment using GraphQL API. * * @param {SendCommentVars} data - The comment data. - * @returns {Promise<SentEmail>} The mutation response. + * @returns {Promise<SentComment>} The mutation response. */ export const sendComment = async ( data: SendCommentInput |
