Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide low value comments by default and add option to "Show all comments" #215

Merged
merged 9 commits into from
Jan 30, 2024
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@
"store": "^2.0.12",
"strip-markdown": "^4.0.0",
"url-loader": "^4.1.1",
"use-local-storage": "^3.0.0",
"yup": "^0.32.9",
"zod": "^3.22.4"
}
Expand Down
16 changes: 13 additions & 3 deletions src/components/comments/CommentTree.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { FC, useMemo, useState } from 'react'
import { useSelectSpace } from 'src/rtk/app/hooks'
import { useFilterOutLowValuePosts, useSelectSpace } from 'src/rtk/app/hooks'
import { useAppDispatch } from 'src/rtk/app/store'
import { useSelectPost } from 'src/rtk/features/posts/postsHooks'
import { fetchPostReplyIds } from 'src/rtk/features/replies/repliesSlice'
Expand All @@ -13,19 +13,22 @@ import { useRepliesData } from './utils'
import ViewComment from './ViewComment'

type CommentsTreeProps = {
rootPostId: PostId
parentId: PostId
eventProps: CommentEventProps
directlyExpandReplies?: boolean
showAllReplies: boolean
}

type CommentByIdProps = {
commentId: PostId
eventProps: CommentEventProps
directlyExpandReplies?: boolean
showAllReplies: boolean
}

const CommentById = React.memo(
({ commentId: id, eventProps, directlyExpandReplies }: CommentByIdProps) => {
({ commentId: id, eventProps, directlyExpandReplies, showAllReplies }: CommentByIdProps) => {
const comment = useSelectPost(id)

const rootPostId = comment ? asCommentStruct(comment.post.struct).rootPostId : undefined
Expand All @@ -36,6 +39,7 @@ const CommentById = React.memo(

return (
<ViewComment
showAllReplies={showAllReplies}
withShowReplies={directlyExpandReplies}
rootPost={rootPost}
space={space}
Expand All @@ -50,6 +54,8 @@ export const ViewCommentsTree: FC<CommentsTreeProps> = ({
parentId,
eventProps,
directlyExpandReplies,
showAllReplies,
rootPostId,
}) => {
const dispatch = useAppDispatch()
const myAddress = useMyAddress()
Expand All @@ -62,6 +68,9 @@ export const ViewCommentsTree: FC<CommentsTreeProps> = ({
return replyIds.slice().reverse()
}, [replyIds])

const filteredIds = useFilterOutLowValuePosts(rootPostId, reversedReplyIds)
const usedIds = showAllReplies ? reversedReplyIds : filteredIds

useSubsocialEffect(
({ subsocial }) => {
if (!repliesCount) return setLoading(false)
Expand Down Expand Up @@ -90,13 +99,14 @@ export const ViewCommentsTree: FC<CommentsTreeProps> = ({

return (
<DataList
dataSource={reversedReplyIds}
dataSource={usedIds}
getKey={replyId => replyId}
className='mt-2.5'
listClassName='GapSmall d-flex flex-column'
renderItem={replyId => (
<CommentById
directlyExpandReplies={directlyExpandReplies}
showAllReplies={showAllReplies}
commentId={replyId}
eventProps={eventProps}
/>
Expand Down
32 changes: 29 additions & 3 deletions src/components/comments/CommentsSection.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Checkbox } from 'antd'
import clsx from 'clsx'
import { FC } from 'react'
import { useIsMyAddressWhitelisted } from 'src/config/constants'
import { PostWithSomeDetails, SpaceStruct } from 'src/types'
import useLocalStorage from 'use-local-storage'
import { useIsMyAddress } from '../auth/MyAccountsContext'
import { Pluralize } from '../utils/Plularize'
import Section from '../utils/Section'
Expand Down Expand Up @@ -28,21 +31,44 @@ export const CommentSection: FC<CommentSectionProps> = ({
const { id, repliesCount, ownerId } = struct
const isPostAuthor = useIsMyAddress(ownerId)

const isWhitelisted = useIsMyAddressWhitelisted()
let [showAllComments, setShowAllComments] = useLocalStorage<boolean>('showAllComments', false, {
parser: str => str === 'true',
serializer: bool => String(bool),
})

if (!isWhitelisted) {
showAllComments = true
}

return (
<Section
id={hashId}
className={clsx('DfCommentSection', {
TopBorder: withBorder,
})}
>
<h3>
<Pluralize count={repliesCount || 0} singularText='comment' />
</h3>
<div className='d-flex GapNormal justify-content-between align-items-center'>
<h3>
<Pluralize count={repliesCount || 0} singularText='comment' />
</h3>
{isWhitelisted && (
<Checkbox
checked={showAllComments}
style={{ marginRight: '-8px' }}
onChange={e => setShowAllComments(e.target.checked)}
>
<span className='ColorMuted'>Show all comments</span>
</Checkbox>
)}
</div>
<NewComment post={struct} asStub eventProps={{ eventSource, level: 0, isPostAuthor }} />
<ViewCommentsTree
rootPostId={id}
eventProps={{ eventSource, level: 1, isPostAuthor }}
parentId={id}
directlyExpandReplies
showAllReplies={showAllComments}
/>
</Section>
)
Expand Down
6 changes: 5 additions & 1 deletion src/components/comments/ViewComment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Props = {
comment: PostWithSomeDetails
withShowReplies?: boolean
eventProps: CommentEventProps
showAllReplies: boolean
}

export const InnerViewComment: FC<Props> = props => {
Expand All @@ -46,6 +47,7 @@ export const InnerViewComment: FC<Props> = props => {
comment: commentDetails,
withShowReplies = false,
eventProps,
showAllReplies,
} = props

const { post: comment } = commentDetails
Expand Down Expand Up @@ -187,8 +189,10 @@ export const InnerViewComment: FC<Props> = props => {
{hasReplies && (
<div className='pb-2'>
{!withShowReplies && <ViewRepliesLink />}
{showReplies && (
{showReplies && rootPost?.id && (
<ViewCommentsTree
rootPostId={rootPost.id}
showAllReplies={showAllReplies}
eventProps={{ ...eventProps, level: eventProps.level + 1 }}
parentId={commentStruct.id}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/creators/TopUsersCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default function TopUsersCard({ ...props }: TopUsersCardProps) {
<>
<div className='d-flex justify-content-between align-items-center'>
<div className='d-flex align-items-center FontWeightSemibold GapMini'>
<span className='FontSemilarge'>Top users (this week)</span>
<span className='FontSemilarge'>Weekly Top Users</span>
</div>
{isMobile && seeMoreButton}
</div>
Expand Down
28 changes: 19 additions & 9 deletions src/components/main/HomePageFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,16 @@ const commonFilterOption = [{ label: 'Latest', value: 'latest' }]
// ]
// : []

export const postFilterOpt = [
{ label: 'Featured Posts', value: 'suggested' },
type Filter = { label: string; value: string; icon?: string }
export const postFilterOpt: Filter[] = [
{ label: 'Featured Posts', icon: '✅', value: 'suggested' },
{ label: 'Hot Posts', icon: '🔥', value: 'hot' },
{ label: 'All Posts', value: 'latest' },
{ label: 'Hot Posts', value: 'hot' },
// removed most liked and commented
// ...offchainPostFilterOpt,
]

export const commentFilterOpt = enableGraphQl
export const commentFilterOpt: Filter[] = enableGraphQl
? [
...commonFilterOption,
{ label: 'Most liked', value: 'liked' },
Expand All @@ -53,13 +54,13 @@ export const commentFilterOpt = enableGraphQl
// ]
// : []

export const spaceFilterOpt = [
{ label: 'Featured Creators', value: 'suggested' },
export const spaceFilterOpt: Filter[] = [
{ label: 'Featured Creators', icon: '✅', value: 'suggested' },
{ label: 'Creators Staking', value: 'creators' },
// ...offchainSpaceFilterOpt,
]

export const dateFilterOpt = [
export const dateFilterOpt: Filter[] = [
{ label: '1 day', value: 'day' },
{ label: '7 days', value: 'week' },
{ label: '30 days', value: 'month' },
Expand Down Expand Up @@ -124,7 +125,15 @@ export const Filters = (props: Props) => {
{!isMobile ? (
<Col className={needDateFilter ? style.DfCol : 'ant-col-24'}>
<Radio.Group
options={filters}
options={filters.map(({ label, value, icon }) => ({
label: (
<span>
<span className='mr-1'>{icon}</span>
{label}
</span>
),
value,
}))}
onChange={onChangeWrap(onFilterChange)}
value={type}
optionType={'button'}
Expand All @@ -137,9 +146,10 @@ export const Filters = (props: Props) => {
onChange={onFilterChange}
className={clsx('w-100', style.FilterSelect)}
>
{filters.map(({ label, value }) => (
{filters.map(({ label, value, icon }) => (
<Select.Option key={value} value={value}>
{label}
{icon && <span className='ml-1'>{icon}</span>}
</Select.Option>
))}
</Select>
Expand Down
31 changes: 31 additions & 0 deletions src/components/utils/datahub/posts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import gql from 'graphql-tag'
import { LowValueIds } from 'src/rtk/features/replies/lowValueIdsSlice'
import { datahubQueryRequest } from './utils'

// QUERIES
Expand Down Expand Up @@ -36,3 +37,33 @@ export async function getHotPosts(variables: { offset: number; limit: number })

return res.data.activeStakingRankedPostIdsByActiveStakingActivity
}

const GET_LOW_VALUE_IDS = gql`
query GetLowValueIds($rootPostId: String!) {
findPosts(where: { rootPostPersistentId: $rootPostId, lowValue: true }) {
data {
persistentId
}
}
}
`
export async function getLowValueIds(rootPostId: string): Promise<LowValueIds> {
const res = await datahubQueryRequest<
{
findPosts: {
data: {
persistentId: string
}[]
}
},
{ rootPostId: string }
>({
query: GET_LOW_VALUE_IDS,
variables: { rootPostId },
})

return {
rootPostId,
lowValueIds: res.data.findPosts.data.map(post => post.persistentId),
}
}
4 changes: 4 additions & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const WHITELISTED_FOR_NEW_FEATURES = [
'3q8uTV4HTCd4M8tP4fTKrGdopfKxAfLGfNdsmLbLP7hYj7JM',
'3tPAVaHYAFRfUVpNP1DAq4E3BxTPanzkGN4uukn3b4ZAefkj',
'3pjRboNv5rSDoy3thDse1KgaWtfVh3x2rrHqrabxjT7dJQdJ',
// filippo
'3sVFfCTpfWE5aqodJT5tpcK13uY9HMJNMDKDQYNpzPKmqVwA',
// jay TheKus
'3pYyydiZfeTL7iVxcYqw9bVyPbFXdVHSomUNzg4SpdycD5tg',
]
export function useIsMyAddressWhitelisted() {
const myAddress = useMyAddress()
Expand Down
8 changes: 7 additions & 1 deletion src/layout/SideMenuItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import React from 'react'
import { FaDiscord } from 'react-icons/fa'
import { FiTwitter } from 'react-icons/fi'
import { IoFlashOutline } from 'react-icons/io5'
import { MdOutlineLeaderboard } from 'react-icons/md'
import { accountUrl } from 'src/components/urls'
import { SubIcon } from 'src/components/utils'
import config from 'src/config'
Expand Down Expand Up @@ -57,8 +58,13 @@ export const DefaultMenu: MenuItem[] = [
// icon: <BlockOutlined />,
// },
{
name: 'Statistics',
name: 'Leaderboard',
page: ['/leaderboard'],
icon: <SubIcon Icon={MdOutlineLeaderboard} />,
},
{
name: 'Statistics',
page: ['/stats'],
icon: <LineChartOutlined />,
},
Divider,
Expand Down
2 changes: 2 additions & 0 deletions src/rtk/app/rootReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import posts from '../features/posts/postsSlice'
import followedAccountIds from '../features/profiles/followedAccountIdsSlice'
import profileSpaces from '../features/profiles/profilesSlice'
import myPostReactions from '../features/reactions/myPostReactionsSlice'
import lowValueIds from '../features/replies/lowValueIdsSlice'
import replyIds from '../features/replies/repliesSlice'
import sellerConfig from '../features/sellerConfig/sellerConfigSlice'
import followedSpaceIds from '../features/spaceIds/followedSpaceIdsSlice'
Expand Down Expand Up @@ -77,6 +78,7 @@ const rootReducer = combineReducers({
generalStatistics,
leaderboard,
postScores,
lowValueIds,
})

export type RootState = ReturnType<typeof rootReducer>
Expand Down
37 changes: 37 additions & 0 deletions src/rtk/features/replies/lowValueIdsSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'
import { getLowValueIds } from 'src/components/utils/datahub/posts'
import { RootState } from 'src/rtk/app/rootReducer'
import { createSimpleFetchWrapper } from 'src/rtk/app/wrappers'

export type LowValueIds = {
rootPostId: string
lowValueIds: string[]
}

const sliceName = 'lowValueIds'

const adapter = createEntityAdapter<LowValueIds>({
selectId: data => data.rootPostId,
})
const selectors = adapter.getSelectors<RootState>(state => state.lowValueIds)

export const selectLowValueIds = selectors.selectById

export const fetchLowValueIds = createSimpleFetchWrapper<{ rootPostId: string }, LowValueIds>({
sliceName,
fetchData: async function ({ rootPostId }) {
return await getLowValueIds(rootPostId)
},
getCachedData: (state, { rootPostId }) => selectLowValueIds(state, rootPostId),
saveToCacheAction: data => slice.actions.setIsPostLowValue(data),
})

const slice = createSlice({
name: sliceName,
initialState: adapter.getInitialState(),
reducers: {
setIsPostLowValue: adapter.upsertOne,
},
})

export default slice.reducer
12 changes: 12 additions & 0 deletions src/rtk/features/replies/repliesHooks.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useMemo } from 'react'
import { useActions } from 'src/rtk/app/helpers'
import { useAppSelector } from 'src/rtk/app/store'
import { PostData, PostId, PostStruct } from 'src/types'
import { upsertContent } from '../contents/contentsSlice'
import { useCreateReloadPosts } from '../posts/postsHooks'
import { removePost, upsertPost } from '../posts/postsSlice'
import { selectLowValueIds } from './lowValueIdsSlice'
import { ReplyIdsByPostId, selectReplyIdsEntities, upsertReplyIdsByPostId } from './repliesSlice'

type RemoveReplyParams = {
Expand Down Expand Up @@ -106,3 +108,13 @@ export const useCreateUpsertReply = () => {
upsertReply(replyData)
}
}

export function useFilterOutLowValuePosts(rootPostId: string, postIds: string[]) {
const lowValueState = useAppSelector(state => selectLowValueIds(state, rootPostId))
return useMemo(() => {
const lowValueSet = new Set(lowValueState?.lowValueIds ?? [])
return postIds.filter(postId => {
return !lowValueSet.has(postId)
})
}, [postIds, lowValueState])
}
Loading
Loading