fix: improve comments performance (#3816)

* fix: improve comments performance
* fix: discussion stores
This commit is contained in:
Mário Nunes
2024-08-06 16:53:03 +08:00
committed by GitHub
parent e595f4bd19
commit bbf6c9e3d0
7 changed files with 91 additions and 55 deletions

View File

@@ -50,7 +50,9 @@ export const CreateComment = (props: Props) => {
},
}}
>
{isLoggedIn ? (
{!isLoggedIn ? (
<LoginPrompt />
) : (
<>
<Textarea
value={comment}
@@ -83,22 +85,6 @@ export const CreateComment = (props: Props) => {
{comment.length}/{maxLength}
</Text>
</>
) : (
<Box sx={{ padding: [3, 4] }}>
<Text data-cy="comments-login-prompt">
Hi there!{' '}
<Link
to="/sign-in"
style={{
textDecoration: 'underline',
color: 'inherit',
}}
>
Login
</Link>{' '}
to leave a comment
</Text>
</Box>
)}
</Box>
</Flex>
@@ -121,3 +107,23 @@ export const CreateComment = (props: Props) => {
</Flex>
)
}
const LoginPrompt = () => {
return (
<Box sx={{ padding: [3, 4] }}>
<Text data-cy="comments-login-prompt">
Hi there!{' '}
<Link
to="/sign-in"
style={{
textDecoration: 'underline',
color: 'inherit',
}}
>
Login
</Link>{' '}
to leave a comment
</Text>
</Box>
)
}

View File

@@ -31,6 +31,7 @@ export const Default: Story = {
onMoreComments={() => null}
onSubmit={() => null}
onSubmitReply={() => Promise.resolve()}
isSubmitting={false}
isLoggedIn={false}
/>
)
@@ -51,6 +52,7 @@ export const NoComments: Story = {
onMoreComments={() => null}
onSubmit={() => null}
onSubmitReply={() => Promise.resolve()}
isSubmitting={false}
isLoggedIn={false}
/>
)
@@ -73,6 +75,7 @@ export const LoggedIn: Story = {
onMoreComments={() => null}
onSubmit={() => null}
onSubmitReply={() => Promise.resolve()}
isSubmitting={false}
isLoggedIn={true}
/>
)
@@ -95,6 +98,7 @@ export const Expandable: Story = {
onMoreComments={() => null}
onSubmit={() => null}
onSubmitReply={() => Promise.resolve()}
isSubmitting={false}
isLoggedIn={true}
/>
)
@@ -121,6 +125,7 @@ export const WithReplies: Story = {
onMoreComments={() => null}
onSubmit={() => null}
isLoggedIn={true}
isSubmitting={false}
onSubmitReply={async (commentId, comment) =>
alert(`reply to commentId: ${commentId} with comment: ${comment}`)
}

View File

@@ -21,6 +21,7 @@ export interface IProps {
onMoreComments: () => void
onSubmit: (comment: string) => void
onSubmitReply: (_id: string, reply: string) => Promise<void>
isSubmitting: boolean
supportReplies?: boolean
}
@@ -38,11 +39,12 @@ export const DiscussionContainer = (props: IProps) => {
onMoreComments,
onSubmit,
isLoggedIn,
isSubmitting,
supportReplies = false,
} = props
const [commentBeingRepliedTo, setCommentBeingRepliedTo] = useState<
null | string
string | null
>(null)
const structuredComments = useMemo(
() => transformToTree(comments),
@@ -51,7 +53,8 @@ export const DiscussionContainer = (props: IProps) => {
const handleSetCommentBeingRepliedTo = (commentId: string | null): void => {
if (commentId === commentBeingRepliedTo) {
return setCommentBeingRepliedTo(null)
setCommentBeingRepliedTo(null)
return
}
setCommentBeingRepliedTo(commentId)
}
@@ -85,6 +88,7 @@ export const DiscussionContainer = (props: IProps) => {
}}
>
<CreateComment
isLoading={isSubmitting}
maxLength={maxLength}
comment={comment}
onChange={onChange}

View File

@@ -1,4 +1,5 @@
import { useEffect, useState } from 'react'
import { observer } from 'mobx-react'
import { DiscussionContainer, Loader } from 'oa-components'
import { useCommonStores } from 'src/common/hooks/useCommonStores'
import { transformToUserComments } from 'src/common/transformToUserComments'
@@ -18,9 +19,9 @@ const LOADING_LABEL = 'Loading the awesome discussion'
interface IProps {
sourceType: IDiscussion['sourceType']
sourceId: string
setTotalCommentsCount: (number) => void
canHideComments?: boolean
setTotalCommentsCount: (number: number) => void
showComments?: boolean
canHideComments?: boolean
primaryContentId?: string | undefined
}
@@ -32,7 +33,7 @@ const getHighlightedCommentId = () => {
return filterOutResearchUpdate.replace('#comment:', '')
}
export const DiscussionWrapper = (props: IProps) => {
export const DiscussionWrapper = observer((props: IProps) => {
const {
canHideComments,
primaryContentId,
@@ -45,6 +46,7 @@ export const DiscussionWrapper = (props: IProps) => {
const [comment, setComment] = useState('')
const [discussion, setDiscussion] = useState<IDiscussion | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [isSubmitting, setIsSubmitting] = useState(false)
const { discussionStore } = useCommonStores().stores
const highlightedCommentId = getHighlightedCommentId()
@@ -86,6 +88,7 @@ export const DiscussionWrapper = (props: IProps) => {
const handleEdit = async (_id: string, comment: string) => {
if (!discussion) return
setIsSubmitting(true)
const updatedDiscussion = await discussionStore.editComment(
discussion,
_id,
@@ -96,6 +99,8 @@ export const DiscussionWrapper = (props: IProps) => {
if (updatedDiscussion) {
transformComments(updatedDiscussion)
}
setIsSubmitting(false)
}
const handleEditRequest = async () => {
@@ -105,6 +110,7 @@ export const DiscussionWrapper = (props: IProps) => {
const handleDelete = async (_id: string) => {
if (!discussion) return
setIsSubmitting(true)
const updatedDiscussion = await discussionStore.deleteComment(
discussion,
_id,
@@ -114,11 +120,15 @@ export const DiscussionWrapper = (props: IProps) => {
if (updatedDiscussion) {
transformComments(updatedDiscussion)
}
setIsSubmitting(false)
}
const onSubmit = async (comment: string) => {
if (!comment || !discussion) return
setIsSubmitting(true)
const updatedDiscussion = await discussionStore.addComment(
discussion,
comment,
@@ -131,11 +141,15 @@ export const DiscussionWrapper = (props: IProps) => {
if (updatedDiscussion) {
setComment('')
}
setIsSubmitting(false)
}
const handleSubmitReply = async (commentId: string, reply) => {
const handleSubmitReply = async (commentId: string, reply: string) => {
if (!discussion) return
setIsSubmitting(true)
const updatedDiscussion = await discussionStore.addComment(
discussion,
reply,
@@ -146,6 +160,8 @@ export const DiscussionWrapper = (props: IProps) => {
if (updatedDiscussion) {
transformComments(updatedDiscussion)
}
setIsSubmitting(false)
}
const discussionProps = {
@@ -161,6 +177,7 @@ export const DiscussionWrapper = (props: IProps) => {
highlightedCommentId,
onSubmit,
onSubmitReply: handleSubmitReply,
isSubmitting,
isLoggedIn: discussionStore?.activeUser
? !!discussionStore.activeUser
: false,
@@ -183,4 +200,4 @@ export const DiscussionWrapper = (props: IProps) => {
)}
</>
)
}
})

View File

@@ -1,10 +1,10 @@
import { useState } from 'react'
import React, { useMemo, useState } from 'react'
import { Button } from 'oa-components'
import { Box } from 'theme-ui'
interface IProps {
children
commentCount: number
children: React.ReactNode | React.ReactNode[]
showComments?: boolean
}
@@ -13,13 +13,9 @@ export const HideDiscussionContainer = ({
commentCount,
showComments,
}: IProps) => {
const [viewComments, setViewComments] = useState(showComments || false)
const [viewComments, setViewComments] = useState(() => showComments || false)
const onButtonClick = () => {
setViewComments(!viewComments)
}
const setButtonText = () => {
const buttonText = useMemo(() => {
if (!viewComments) {
switch (commentCount) {
case 0:
@@ -32,7 +28,7 @@ export const HideDiscussionContainer = ({
}
return 'Collapse Comments'
}
}, [viewComments])
return (
<Box
@@ -53,14 +49,14 @@ export const HideDiscussionContainer = ({
display: 'block',
marginBottom: viewComments ? 2 : 0,
}}
onClick={onButtonClick}
onClick={() => setViewComments((prev) => !prev)}
backgroundColor={viewComments ? '#c2daf0' : '#e2edf7'}
className={viewComments ? 'viewComments' : ''}
data-cy={`HideDiscussionContainer: button ${
!viewComments && 'open-comments'
}`}
>
<>{setButtonText()}</>
{buttonText}
</Button>
{viewComments && children}
</Box>

View File

@@ -74,7 +74,9 @@ export const updateDiscussionMetadata = async (
const researchRef = db.collection('research').doc(primaryContentId)
const research = toJS(await researchRef.get('server')) as IResearch.Item
if (!research || !research.updates) return
if (!research || !research.updates || research.updates.length === 0) {
return
}
const updates = research.updates.map((update) => {
return update._id === sourceId ? { ...update, commentCount } : update

View File

@@ -22,11 +22,11 @@ import type {
import type { DocReference } from '../databaseV2/DocReference'
import type { IRootStore } from '../RootStore'
const COLLECTION_NAME = 'discussions'
const DISCUSSIONS_COLLECTION = 'discussions'
export class DiscussionStore extends ModuleStore {
constructor(rootStore: IRootStore) {
super(rootStore, COLLECTION_NAME)
super(rootStore, DISCUSSIONS_COLLECTION)
}
public async fetchOrCreateDiscussionBySource(
@@ -37,7 +37,7 @@ export class DiscussionStore extends ModuleStore {
const foundDiscussion =
toJS(
await this.db
.collection<IDiscussion>(COLLECTION_NAME)
.collection<IDiscussion>(DISCUSSIONS_COLLECTION)
.getWhere('sourceId', '==', sourceId),
)[0] || null
@@ -74,7 +74,7 @@ export class DiscussionStore extends ModuleStore {
}
const dbRef = this.db
.collection<IDiscussion>(COLLECTION_NAME)
.collection<IDiscussion>(DISCUSSIONS_COLLECTION)
.doc(newDiscussion._id)
return await this._updateDiscussion(dbRef, newDiscussion)
@@ -91,7 +91,7 @@ export class DiscussionStore extends ModuleStore {
if (user && comment) {
const dbRef = this.db
.collection<IDiscussion>(COLLECTION_NAME)
.collection<IDiscussion>(DISCUSSIONS_COLLECTION)
.doc(discussion._id)
const currentDiscussion = toJS(await dbRef.get('server'))
@@ -120,7 +120,8 @@ export class DiscussionStore extends ModuleStore {
newComment,
)
await this._addNotifications(newComment, currentDiscussion)
// Do not await so it doesn't block adding a comment
this._addNotifications(newComment, currentDiscussion)
return this._updateDiscussion(dbRef, currentDiscussion)
}
@@ -143,7 +144,7 @@ export class DiscussionStore extends ModuleStore {
if (user && comment) {
const dbRef = this.db
.collection<IDiscussion>(COLLECTION_NAME)
.collection<IDiscussion>(DISCUSSIONS_COLLECTION)
.doc(discussion._id)
const currentDiscussion = toJS(await dbRef.get('server'))
@@ -185,7 +186,7 @@ export class DiscussionStore extends ModuleStore {
if (user) {
const dbRef = this.db
.collection<IDiscussion>(COLLECTION_NAME)
.collection<IDiscussion>(DISCUSSIONS_COLLECTION)
.doc(discussion._id)
const currentDiscussion = toJS(await dbRef.get('server'))
@@ -271,14 +272,16 @@ export class DiscussionStore extends ModuleStore {
)
if (update.collaborators) {
await update.collaborators.map((collaborator) => {
this.userNotificationsStore.triggerNotification(
'new_comment_discussion',
collaborator,
url,
research.title,
)
})
await Promise.all(
update.collaborators.map((collaborator) => {
this.userNotificationsStore.triggerNotification(
'new_comment_discussion',
collaborator,
url,
research.title,
)
}),
)
}
}
return
@@ -344,7 +347,10 @@ export class DiscussionStore extends ModuleStore {
discussion: IDiscussion,
): Promise<IDiscussionDB | null> {
await dbRef.set({ ...cloneDeep(discussion) })
await updateDiscussionMetadata(this.db, discussion)
// Do not await so it doesn't block adding a comment
updateDiscussionMetadata(this.db, discussion)
const updatedDiscussion = toJS(await dbRef.get('server'))
return updatedDiscussion ? updatedDiscussion : null
@@ -361,8 +367,8 @@ export class DiscussionStore extends ModuleStore {
)
return discussion
const dbRef = await this.db
.collection<IDiscussion>(COLLECTION_NAME)
const dbRef = this.db
.collection<IDiscussion>(DISCUSSIONS_COLLECTION)
.doc(discussion._id)
return await this._updateDiscussion(dbRef, {