From 637350e4d152de1346857d645bda8443900ec6f4 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Mon, 14 Feb 2022 13:57:06 +0100 Subject: fix: update comments list when a new comment is send The comments list was static before. If an user posted a comment, even after it was approved, the comments list was keeping the old state. --- src/components/Comment/Comment.tsx | 2 +- src/components/CommentsList/CommentsList.tsx | 27 +++++++++++-- src/pages/article/[slug].tsx | 19 ++++++--- src/services/graphql/queries.ts | 60 +++++++++++++++++++--------- src/ts/types/app.ts | 5 ++- src/ts/types/articles.ts | 3 +- src/ts/types/comments.ts | 8 ++++ src/utils/helpers/format.ts | 14 +++---- 8 files changed, 99 insertions(+), 39 deletions(-) diff --git a/src/components/Comment/Comment.tsx b/src/components/Comment/Comment.tsx index 4835f8c..ab1dffc 100644 --- a/src/components/Comment/Comment.tsx +++ b/src/components/Comment/Comment.tsx @@ -121,7 +121,7 @@ const Comment = ({ return ( diff --git a/src/components/CommentsList/CommentsList.tsx b/src/components/CommentsList/CommentsList.tsx index 6630a03..1e7c3e7 100644 --- a/src/components/CommentsList/CommentsList.tsx +++ b/src/components/CommentsList/CommentsList.tsx @@ -1,6 +1,9 @@ import Comment from '@components/Comment/Comment'; +import Spinner from '@components/Spinner/Spinner'; +import { getCommentsByPostId } from '@services/graphql/queries'; import { Comment as CommentData } from '@ts/types/comments'; import { useIntl } from 'react-intl'; +import useSWR from 'swr'; import styles from './CommentsList.module.scss'; const CommentsList = ({ @@ -11,11 +14,29 @@ const CommentsList = ({ comments: CommentData[]; }) => { const intl = useIntl(); + const { data, error } = useSWR( + '/api/comments', + () => getCommentsByPostId(articleId), + { fallbackData: comments } + ); const getCommentsList = () => { - return comments.map((comment) => { + if (error) { + return intl.formatMessage({ + defaultMessage: 'Failed to load.', + description: 'CommentsList: failed to load', + }); + } + + if (!data) return ; + + return data.map((comment) => { return ( - + ); }); }; @@ -28,7 +49,7 @@ const CommentsList = ({ description: 'CommentsList: Comments section title', })} - {comments.length > 0 ? ( + {data && data.length > 0 ? (
    {getCommentsList()}
) : (

diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx index 7bde448..a0255fa 100644 --- a/src/pages/article/[slug].tsx +++ b/src/pages/article/[slug].tsx @@ -6,7 +6,11 @@ import PostHeader from '@components/PostHeader/PostHeader'; import Sidebar from '@components/Sidebar/Sidebar'; import Spinner from '@components/Spinner/Spinner'; import { Sharing, ToC } from '@components/Widgets'; -import { getAllPostsSlug, getPostBySlug } from '@services/graphql/queries'; +import { + getAllPostsSlug, + getCommentsByPostId, + getPostBySlug, +} from '@services/graphql/queries'; import styles from '@styles/pages/Page.module.scss'; import { NextPageWithLayout } from '@ts/types/app'; import { ArticleMeta, ArticleProps } from '@ts/types/articles'; @@ -25,7 +29,10 @@ import { useIntl } from 'react-intl'; import { Blog, BlogPosting, Graph, WebPage } from 'schema-dts'; import '@utils/plugins/prism-color-scheme'; -const SingleArticle: NextPageWithLayout = ({ post }) => { +const SingleArticle: NextPageWithLayout = ({ + comments, + post, +}) => { const intl = useIntl(); const router = useRouter(); @@ -47,7 +54,7 @@ const SingleArticle: NextPageWithLayout = ({ post }) => { const { author, - comments, + commentCount, content, databaseId, dates, @@ -62,7 +69,7 @@ const SingleArticle: NextPageWithLayout = ({ post }) => { const meta: ArticleMeta = { author, - commentCount: comments.length, + commentCount: commentCount || undefined, dates, readingTime: info.readingTime, thematics, @@ -105,7 +112,7 @@ const SingleArticle: NextPageWithLayout = ({ post }) => { description: intro, articleBody: content, author: { '@id': `${settings.url}/#branding` }, - commentCount: comments.length, + commentCount: commentCount || undefined, copyrightYear: publicationDate.getFullYear(), creator: { '@id': `${settings.url}/#branding` }, dateCreated: publicationDate.toISOString(), @@ -220,11 +227,13 @@ export const getStaticProps: GetStaticProps = async ( const translation = await loadTranslation(locale); const { slug } = context.params as PostParams; const post = await getPostBySlug(slug); + const comments = await getCommentsByPostId(post.databaseId); const breadcrumbTitle = post.title; return { props: { breadcrumbTitle, + comments, post, translation, }, diff --git a/src/services/graphql/queries.ts b/src/services/graphql/queries.ts index a9b3141..688d3f2 100644 --- a/src/services/graphql/queries.ts +++ b/src/services/graphql/queries.ts @@ -1,6 +1,7 @@ import { Slug } from '@ts/types/app'; import { Article, PostBy, TotalArticles } from '@ts/types/articles'; import { AllPostsSlug, PostsList, RawPostsList } from '@ts/types/blog'; +import { Comment, CommentsByPostId } from '@ts/types/comments'; import { AllTopics, AllTopicsSlug, @@ -18,6 +19,8 @@ import { getFormattedPostPreview, getFormattedTopic, getFormattedThematic, + getFormattedComments, + buildCommentsTree, } from '@utils/helpers/format'; import { gql } from 'graphql-request'; import { fetchApi } from './api'; @@ -188,24 +191,6 @@ export const getPostBySlug = async (slug: string): Promise

=> { } } commentCount - comments(where: { order: ASC, orderby: COMMENT_DATE }) { - nodes { - approved - author { - node { - gravatarUrl - name - url - } - } - commentId - content - date - id - parentDatabaseId - parentId - } - } contentParts { afterMore beforeMore @@ -242,7 +227,6 @@ export const getPostBySlug = async (slug: string): Promise
=> { opengraphTitle opengraphType opengraphUrl - readingTime } title } @@ -254,6 +238,44 @@ export const getPostBySlug = async (slug: string): Promise
=> { return getFormattedPost(response.postBy); }; +//============================================================================== +// Comments query +//============================================================================== + +export const getCommentsByPostId = async (id: number): Promise => { + const query = gql` + query MyQuery($id: Int) { + postBy(postId: $id) { + comments(where: { order: ASC, orderby: COMMENT_DATE }) { + nodes { + approved + author { + node { + gravatarUrl + id + name + url + } + } + commentId + content + date + parentDatabaseId + } + } + } + } + `; + + const variables = { id }; + const response = await fetchApi(query, variables); + const formattedComments = getFormattedComments( + response.postBy.comments.nodes + ); + + return buildCommentsTree(formattedComments); +}; + //============================================================================== // Topic query //============================================================================== diff --git a/src/ts/types/app.ts b/src/ts/types/app.ts index 3edc8a0..8e087fd 100644 --- a/src/ts/types/app.ts +++ b/src/ts/types/app.ts @@ -3,7 +3,7 @@ import { AppProps } from 'next/app'; import { ReactElement, ReactNode } from 'react'; import { PostBy, TotalArticles } from './articles'; import { AllPostsSlug, RawPostsList } from './blog'; -import { CommentData, CreateComment } from './comments'; +import { CommentData, CommentsByPostId, CreateComment } from './comments'; import { ContactData, SendEmail } from './contact'; import { AllTopics, @@ -34,6 +34,8 @@ export type VariablesType = T extends PostBy | TopicBy | ThematicBy ? Slug : T extends RawPostsList ? CursorPagination + : T extends CommentsByPostId + ? { id: number } : T extends CreateComment ? CommentData : T extends SendEmail @@ -46,6 +48,7 @@ export type RequestType = | AllTopicsSlug | AllThematics | AllThematicsSlug + | CommentsByPostId | CreateComment | PostBy | RawPostsList diff --git a/src/ts/types/articles.ts b/src/ts/types/articles.ts index 75e5a1a..ea90207 100644 --- a/src/ts/types/articles.ts +++ b/src/ts/types/articles.ts @@ -35,7 +35,6 @@ export type ArticleMeta = { export type Article = { author: ArticleAuthor; commentCount: number | null; - comments: Comment[]; content: string; databaseId: number; dates: Dates; @@ -55,7 +54,6 @@ export type RawArticle = Pick< > & { acfPosts: RawACFPosts; author: { node: ArticleAuthor }; - comments: CommentsNode; contentParts: ContentParts; date: string; featuredImage: RawCover; @@ -91,6 +89,7 @@ export type PostBy = { }; export type ArticleProps = { + comments: Comment[]; post: Article; }; diff --git a/src/ts/types/comments.ts b/src/ts/types/comments.ts index 75e7d23..36bd98c 100644 --- a/src/ts/types/comments.ts +++ b/src/ts/types/comments.ts @@ -2,6 +2,14 @@ // Comments query //============================================================================== +export type CommentsByPostId = { + postBy: { + comments: { + nodes: RawComment[]; + }; + }; +}; + export type CommentAuthor = { gravatarUrl: string; name: string; diff --git a/src/utils/helpers/format.ts b/src/utils/helpers/format.ts index 817daaf..9c6f266 100644 --- a/src/utils/helpers/format.ts +++ b/src/utils/helpers/format.ts @@ -189,14 +189,16 @@ export const buildCommentsTree = (comments: Comment[]) => { const commentsTree: Comment[] = []; comments.forEach( - (comment) => (hashTable[comment.id] = { ...comment, replies: [] }) + (comment) => (hashTable[comment.commentId] = { ...comment, replies: [] }) ); comments.forEach((comment) => { - if (!comment.parentId) { - commentsTree.push(hashTable[comment.id]); + if (!comment.parentDatabaseId) { + commentsTree.push(hashTable[comment.commentId]); } else { - hashTable[comment.parentId].replies.push(hashTable[comment.id]); + hashTable[comment.parentDatabaseId].replies.push( + hashTable[comment.commentId] + ); } }); @@ -226,7 +228,6 @@ export const getFormattedPost = (rawPost: RawArticle): Article => { acfPosts, author, commentCount, - comments, contentParts, databaseId, date, @@ -243,8 +244,6 @@ export const getFormattedPost = (rawPost: RawArticle): Article => { update: modified, }; - const formattedComments = getFormattedComments(comments.nodes); - const commentsTree = buildCommentsTree(formattedComments); const topics = acfPosts.postsInTopic ? getFormattedTopicsPreview(acfPosts.postsInTopic) : []; @@ -252,7 +251,6 @@ export const getFormattedPost = (rawPost: RawArticle): Article => { const formattedPost: Article = { author: author.node, commentCount, - comments: commentsTree, content: contentParts.afterMore, databaseId, dates, -- cgit v1.2.3