From fd41501a851570fd2d44d0033c1f8168695eb81a Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Tue, 23 Apr 2024 19:08:01 +0700 Subject: [PATCH 1/4] Change reply ids fetcher to use squid --- src/components/posts/view-post/PostPage.tsx | 9 ++++---- src/graphql/apis/index.ts | 14 ++++++++++++ src/graphql/queries.ts | 16 +++++++++++++ src/rtk/features/replies/repliesSlice.ts | 25 +++++++++++++++++++-- 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/components/posts/view-post/PostPage.tsx b/src/components/posts/view-post/PostPage.tsx index 6e5297a7f..d9f25fd81 100644 --- a/src/components/posts/view-post/PostPage.tsx +++ b/src/components/posts/view-post/PostPage.tsx @@ -32,11 +32,11 @@ import { useIsPostBlocked } from 'src/rtk/features/moderation/hooks' import { fetchPost, fetchPosts, selectPost } from 'src/rtk/features/posts/postsSlice' import { fetchPostsViewCount } from 'src/rtk/features/posts/postsViewCountSlice' import { useFetchMyReactionsByPostId } from 'src/rtk/features/reactions/myPostReactionsHooks' +import { fetchPostReplyIds, selectReplyIds } from 'src/rtk/features/replies/repliesSlice' import { asCommentStruct, DataSourceTypes, HasStatusCode, - idToBn, PostData, PostWithSomeDetails, } from 'src/types' @@ -288,16 +288,15 @@ export async function loadPostOnNextReq({ asPath, } = context - const { blockchain } = subsocial - const slugStr = slug as string const postId = getPostIdFromSlug(slugStr) if (!postId) return return404(context) async function getPost() { - const replyIds = await blockchain.getReplyIdsByPostId(idToBn(postId!)) - const ids = replyIds.concat(postId!) + await dispatch(fetchPostReplyIds({ id: postId!, api: subsocial })) + const replyIds = selectReplyIds(reduxStore.getState(), postId!) + const ids = [postId!, ...(replyIds?.replyIds ?? [])] await dispatch( fetchPosts({ api: subsocial, diff --git a/src/graphql/apis/index.ts b/src/graphql/apis/index.ts index 1f17d6cb4..e91a94851 100644 --- a/src/graphql/apis/index.ts +++ b/src/graphql/apis/index.ts @@ -417,3 +417,17 @@ export async function getLastestPostIdsInSpace( const posts = res.data.posts ?? [] return posts.map(post => post.id) } + +export async function getReplyIdsByParentId(client: GqlClient, variables: { parentId: string }) { + try { + const posts = await client.query<{ posts: { id: string }[] }, { parentId: string }>({ + query: q.GET_REPLY_IDS_BY_PARENT_ID, + variables, + }) + return posts.data.posts.map(post => post.id) + } catch (err) { + console.log(variables) + console.log(err) + return [] + } +} diff --git a/src/graphql/queries.ts b/src/graphql/queries.ts index 7e9010e8f..1a24c0f0a 100644 --- a/src/graphql/queries.ts +++ b/src/graphql/queries.ts @@ -835,3 +835,19 @@ export const GET_LASTEST_POST_IDS_IN_SPACE = gql` } } ` + +// Replies + +export const GET_REPLY_IDS_BY_PARENT_ID = gql` + query GetReplyIdsByParentId($parentId: String!) { + posts( + orderBy: createdAtTime_ASC + where: { + parentPost: { id_eq: $parentId } + OR: { rootPost: { id_eq: $parentId }, parentPost: { id_isNull: true } } + } + ) { + id + } + } +` diff --git a/src/rtk/features/replies/repliesSlice.ts b/src/rtk/features/replies/repliesSlice.ts index 0fa025a8f..6eb835532 100644 --- a/src/rtk/features/replies/repliesSlice.ts +++ b/src/rtk/features/replies/repliesSlice.ts @@ -1,13 +1,17 @@ import { createAsyncThunk, createEntityAdapter, createSlice } from '@reduxjs/toolkit' +import { SubsocialApi } from '@subsocial/api' import { idToBn, isEmptyArray } from '@subsocial/utils' +import { getReplyIdsByParentId } from 'src/graphql/apis' import { CommonFetchProps, createSelectUnknownIds, SelectManyArgs, SelectOneArgs, ThunkApiConfig, + validateDataSource, } from 'src/rtk/app/helpers' import { RootState } from 'src/rtk/app/rootReducer' +import { createFetchDataFn } from 'src/rtk/app/wrappers' import { AccountId, DataSourceTypes, PostId, PostWithSomeDetails } from 'src/types' import { fetchPosts } from '../posts/postsSlice' @@ -72,12 +76,26 @@ export function selectManyReplyIds( // return selectManyPostReplies(state, { ids: [ parentId ]})[parentId] || [] // } +const getReplyIds = createFetchDataFn([])({ + chain: async ({ api, parentId }: { api: SubsocialApi; parentId: string }) => { + return api.blockchain.getReplyIdsByPostId(idToBn(parentId)) + }, + squid: async ({ parentId }: { parentId: string }, client) => { + if (!parentId) return [] + const ids = await getReplyIdsByParentId(client, { + parentId, + }) + return ids + }, +}) + export const fetchPostReplyIds = createAsyncThunk< ReplyIdsByPostId[], FetchManyPostRepliesArgs, ThunkApiConfig >('replyIds/fetchMany', async (args, { getState, dispatch }) => { - const { id: parentId, myAddress, api, reload } = args + const { id: parentId, myAddress, api, reload, dataSource: _dataSource } = args + const dataSource = validateDataSource(_dataSource) if (!reload) { const parentIds = selectUnknownParentIds(getState(), [parentId]) @@ -87,7 +105,10 @@ export const fetchPostReplyIds = createAsyncThunk< } } - const replyIds = await api.blockchain.getReplyIdsByPostId(idToBn(parentId)) + const replyIds = await getReplyIds(dataSource, { + chain: { api, parentId }, + squid: { parentId }, + }) await Promise.allSettled([ dispatch( From 514fa97d437ad17598ba261b5f005a1241865ec3 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Tue, 23 Apr 2024 19:32:38 +0700 Subject: [PATCH 2/4] Add fallback for post and space page to chain fetching --- src/components/posts/editor/ModalEditor.tsx | 2 +- src/components/posts/editor/index.tsx | 2 +- src/components/posts/view-post/PostPage.tsx | 16 ++++++++++++++-- .../spaces/helpers/loadSpaceOnNextReq.ts | 18 ++++++++++++++---- src/components/urls/goToPage.ts | 2 +- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/components/posts/editor/ModalEditor.tsx b/src/components/posts/editor/ModalEditor.tsx index 614b2e919..d35a79595 100644 --- a/src/components/posts/editor/ModalEditor.tsx +++ b/src/components/posts/editor/ModalEditor.tsx @@ -161,7 +161,7 @@ export const PostEditorModalBody = ({ const url = postUrl({ id: spaceId! }, postData) router - .push('/[spaceId]/[slug]', url + '?source=chain') + .push('/[spaceId]/[slug]', url) .catch(err => log.error(`Failed to redirect to a post page. ${err}`)) } diff --git a/src/components/posts/editor/index.tsx b/src/components/posts/editor/index.tsx index 8052102ca..5314f6908 100644 --- a/src/components/posts/editor/index.tsx +++ b/src/components/posts/editor/index.tsx @@ -132,7 +132,7 @@ function EditPostForm(props: PostFormProps) { const url = postUrl({ id: spaceForPost! }, postData) router - .push('/[spaceId]/[slug]', url + '?source=chain') + .push('/[spaceId]/[slug]', url) .catch(err => log.error(`Failed to redirect to a post page. ${err}`)) } diff --git a/src/components/posts/view-post/PostPage.tsx b/src/components/posts/view-post/PostPage.tsx index d9f25fd81..72211d69d 100644 --- a/src/components/posts/view-post/PostPage.tsx +++ b/src/components/posts/view-post/PostPage.tsx @@ -283,7 +283,7 @@ export async function loadPostOnNextReq({ reduxStore, }: NextContextWithRedux): Promise { const { - query: { slug, source }, + query: { slug }, res, asPath, } = context @@ -303,9 +303,21 @@ export async function loadPostOnNextReq({ ids, reload: true, eagerLoadHandles: true, - dataSource: source === 'chain' ? DataSourceTypes.CHAIN : DataSourceTypes.SQUID, + dataSource: DataSourceTypes.SQUID, }), ) + const postData = selectPost(reduxStore.getState(), { id: postId! }) + if (!postData) { + await dispatch( + fetchPosts({ + api: subsocial, + ids: [postId!], + reload: true, + eagerLoadHandles: true, + dataSource: DataSourceTypes.CHAIN, + }), + ) + } } await Promise.all([getPost(), dispatch(fetchBlockedResources({ appId }))]) const postData = selectPost(reduxStore.getState(), { id: postId }) diff --git a/src/components/spaces/helpers/loadSpaceOnNextReq.ts b/src/components/spaces/helpers/loadSpaceOnNextReq.ts index 2df51e8fa..3492840b9 100644 --- a/src/components/spaces/helpers/loadSpaceOnNextReq.ts +++ b/src/components/spaces/helpers/loadSpaceOnNextReq.ts @@ -12,7 +12,7 @@ export async function loadSpaceOnNextReq( ): Promise { const { context, subsocial, dispatch, reduxStore } = props const { query, res } = context - const { spaceId, source } = query + const { spaceId } = query const idOrHandle = spaceId as string try { @@ -29,13 +29,23 @@ export async function loadSpaceOnNextReq( id: idStr, reload: true, eagerLoadHandles: true, - dataSource: source === 'chain' ? DataSourceTypes.CHAIN : DataSourceTypes.SQUID, + dataSource: DataSourceTypes.SQUID, }), ) - const spaceData = selectSpace(reduxStore.getState(), { id: idStr }) + let spaceData = selectSpace(reduxStore.getState(), { id: idStr }) if (!spaceData) { - return return404(context) + await dispatch( + fetchSpace({ + api: subsocial, + id: idStr, + reload: true, + eagerLoadHandles: true, + dataSource: DataSourceTypes.CHAIN, + }), + ) + spaceData = selectSpace(reduxStore.getState(), { id: idStr }) + if (!spaceData) return return404(context) } const maybeHandle = idStr !== idOrHandle ? idOrHandle : undefined diff --git a/src/components/urls/goToPage.ts b/src/components/urls/goToPage.ts index e1fcbc0c3..a47da40df 100644 --- a/src/components/urls/goToPage.ts +++ b/src/components/urls/goToPage.ts @@ -7,7 +7,7 @@ import { createNewPostLinkProps } from '../spaces/helpers' const log = newLogger('Go to page') export function goToSpacePage(spaceId: AnyId, isFirstSpace?: boolean) { - const params = `?source=chain${isFirstSpace ? '&isFirst' : ''}` + const params = `?${isFirstSpace ? 'isFirst' : ''}` Router.push('/[spaceId]', `/${spaceId.toString()}${params}`).catch(err => log.error('Failed to redirect to "View Space" page:', err), From e0925c7f6cd9754cbfb77fee4b2efa60346560f5 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Tue, 23 Apr 2024 19:48:53 +0700 Subject: [PATCH 3/4] Use squid to fetch space data in edit space --- .../spaces/withLoadSpaceFromUrl.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components/spaces/withLoadSpaceFromUrl.tsx b/src/components/spaces/withLoadSpaceFromUrl.tsx index 63461db41..45ddca8d9 100644 --- a/src/components/spaces/withLoadSpaceFromUrl.tsx +++ b/src/components/spaces/withLoadSpaceFromUrl.tsx @@ -2,8 +2,10 @@ import { isFunction } from '@polkadot/util' import { newLogger } from '@subsocial/utils' import { useRouter } from 'next/router' import React, { useState } from 'react' +import { useDispatch, useStore } from 'react-redux' import { useFetchMyPermissionsBySpaceId } from 'src/rtk/features/permissions/mySpacePermissionsHooks' -import { SpaceData } from 'src/types' +import { fetchSpace, selectSpace } from 'src/rtk/features/spaces/spacesSlice' +import { DataSourceTypes, SpaceData } from 'src/types' import useSubsocialEffect from '../api/useSubsocialEffect' import { getSpaceId } from '../substrate' import { Loading } from '../utils' @@ -35,6 +37,8 @@ export function withLoadSpaceFromUrl( const [isLoaded, setIsLoaded] = useState(!idOrHandle) const [loadedData, setLoadedData] = useState({}) useFetchMyPermissionsBySpaceId(loadedData.space?.id) + const dispatch = useDispatch() + const store = useStore() useSubsocialEffect( ({ subsocial }) => { @@ -45,7 +49,19 @@ export function withLoadSpaceFromUrl( if (isMounted && id) { setIsLoaded(false) - const space = await subsocial.findSpace({ id }) + await dispatch(fetchSpace({ api: subsocial, id: id.toString() })) + let space = selectSpace(store.getState(), { id: id.toString() }) + + if (!space) { + await dispatch( + fetchSpace({ + api: subsocial, + id: id.toString(), + dataSource: DataSourceTypes.CHAIN, + }), + ) + space = selectSpace(store.getState(), { id: id.toString() }) + } setLoadedData({ space }) } From 0e881f33ff05e0f131ae8851838875a0705a0543 Mon Sep 17 00:00:00 2001 From: teodorus-nathaniel Date: Tue, 23 Apr 2024 19:51:34 +0700 Subject: [PATCH 4/4] Remove logs --- src/graphql/apis/index.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/graphql/apis/index.ts b/src/graphql/apis/index.ts index e91a94851..b5fee1b95 100644 --- a/src/graphql/apis/index.ts +++ b/src/graphql/apis/index.ts @@ -419,15 +419,9 @@ export async function getLastestPostIdsInSpace( } export async function getReplyIdsByParentId(client: GqlClient, variables: { parentId: string }) { - try { - const posts = await client.query<{ posts: { id: string }[] }, { parentId: string }>({ - query: q.GET_REPLY_IDS_BY_PARENT_ID, - variables, - }) - return posts.data.posts.map(post => post.id) - } catch (err) { - console.log(variables) - console.log(err) - return [] - } + const posts = await client.query<{ posts: { id: string }[] }, { parentId: string }>({ + query: q.GET_REPLY_IDS_BY_PARENT_ID, + variables, + }) + return posts.data.posts.map(post => post.id) }