aboutsummaryrefslogtreecommitdiffstats
path: root/src/services/graphql/comments.ts
blob: 86b6a35db5330ed1667d89bba77e5ccb41587ab1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { Comment } 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 { 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.
 *
 * @param {FetchCommentsInput} variables - An object of variables.
 * @returns {Promise<RawComment[]>} The raw comments.
 */
export const fetchComments = async (
  variables: FetchCommentsInput
): Promise<RawComment[]> => {
  const response = await fetchAPI<RawComment, typeof commentsQuery>({
    query: commentsQuery,
    variables,
  });

  return response.comments.nodes;
};

/**
 * Create a comments tree with replies.
 *
 * @param {Comment[]} comments - A flatten comments list.
 * @returns {Comment[]} An array of comments with replies.
 */
export const buildCommentsTree = (comments: Comment[]): Comment[] => {
  type CommentsHashTable = {
    [key: string]: Comment;
  };

  const hashTable: CommentsHashTable = Object.create(null);
  const commentsTree: Comment[] = [];

  comments.forEach(
    (comment) => (hashTable[comment.id] = { ...comment, replies: [] })
  );

  comments.forEach((comment) => {
    if (!comment.parentId) {
      commentsTree.push(hashTable[comment.id]);
    } else {
      hashTable[comment.parentId].replies.push(hashTable[comment.id]);
    }
  });

  return commentsTree;
};

/**
 * Convert a comment from RawComment to Comment type.
 *
 * @param {RawComment} comment - A raw comment.
 * @returns {Comment} A formatted comment.
 */
export const getCommentFromRawData = (comment: RawComment): Comment => {
  const { author, databaseId, date, parentDatabaseId, ...data } = comment;

  return {
    id: databaseId,
    meta: {
      author: getAuthorFromRawData(author.node, 'comment'),
      date,
    },
    parentId: parentDatabaseId,
    replies: [],
    ...data,
  };
};

/**
 * Retrieve a comments list by post id.
 *
 * @param {number} id - A post id.
 * @returns {Promise<Comment[]>} The comments list.
 */
export const getPostComments = async (id: number): Promise<Comment[]> => {
  const rawComments = await fetchComments({ contentId: id });
  const comments = rawComments.map((comment) => getCommentFromRawData(comment));

  return buildCommentsTree(comments);
};

/**
 * Send a comment using GraphQL API.
 *
 * @param {SendCommentVars} data - The comment data.
 * @returns {Promise<SentEmail>} The mutation response.
 */
export const sendComment = async (
  data: SendCommentInput
): Promise<SentComment> => {
  const response = await fetchAPI<SentComment, typeof sendCommentMutation>({
    query: sendCommentMutation,
    variables: { ...data },
  });

  return response.createComment;
};