diff --git a/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Comment.jsx b/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Comment.jsx index b0b0f9d7e..96429ca0d 100644 --- a/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Comment.jsx +++ b/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Comment.jsx @@ -26,7 +26,7 @@ const commentUrl = `https://alpha.near.org/#/${APP_OWNER}/widget/QueryApi.Exampl if (!state.content && accountId && blockHeight !== "now") { const commentQuery = ` query CommentQuery { - dataplatform_near_feed_indexer_comments( + dataplatform_near_social_feed_comments( where: {_and: {account_id: {_eq: "${accountId}"}, block_height: {_eq: ${blockHeight}}}} ) { content @@ -57,7 +57,7 @@ query CommentQuery { fetchGraphQL(commentQuery, "CommentQuery", {}).then((result) => { if (result.status === 200) { if (result.body.data) { - const comments = result.body.data.dataplatform_near_feed_indexer_comments; + const comments = result.body.data.dataplatform_near_social_feed_comments; if (comments.length > 0) { const comment = comments[0]; let content = JSON.parse(comment.content); diff --git a/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Post.jsx b/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Post.jsx index 2138f9751..4e7673a31 100644 --- a/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Post.jsx +++ b/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Post.jsx @@ -23,10 +23,9 @@ const item = { // Load post if not contents and comments are not passed in if (!state.content || !state.comments || !state.likes) { - console.log("making call again"); const postsQuery = ` query IndexerQuery { - dataplatform_near_feed_indexer_posts( + dataplatform_near_social_feed_posts( order_by: {block_height: desc} where: {_and: {block_height: {_eq: ${blockHeight}}, account_id: {_eq: "${accountId}"}}} ) { @@ -64,7 +63,7 @@ query IndexerQuery { fetchGraphQL(postsQuery, "IndexerQuery", {}).then((result) => { if (result.status === 200) { if (result.body.data) { - const posts = result.body.data.dataplatform_near_feed_indexer_posts; + const posts = result.body.data.dataplatform_near_social_feed_posts; if (posts.length > 0) { const post = posts[0]; let content = JSON.parse(post.content); diff --git a/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.PostPage.jsx b/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.PostPage.jsx index b400f2166..27afc38bb 100644 --- a/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.PostPage.jsx +++ b/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.PostPage.jsx @@ -13,7 +13,7 @@ State.init({ }); const parentPostByComment = `query ParentPostByComment { - dataplatform_near_feed_indexer_comments( + dataplatform_near_social_feed_comments( where: {_and: {account_id: {_eq: "${accountId}"}, block_height: {_eq: ${commentBlockHeight}}}} ) { post { @@ -64,7 +64,7 @@ if (commentBlockHeight) { (result) => { if (result.status === 200) { if (result.body.data) { - const posts = result.body.data.dataplatform_near_feed_indexer_comments; + const posts = result.body.data.dataplatform_near_social_feed_comments; if (posts.length > 0) { const post = posts[0].post; let content = JSON.parse(post.content); diff --git a/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Posts.jsx b/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Posts.jsx new file mode 100644 index 000000000..43753e27f --- /dev/null +++ b/frontend/widgets/examples/feed/src/QueryApi.Examples.Feed.Posts.jsx @@ -0,0 +1,303 @@ +const APP_OWNER = props.APP_OWNER || "dataplatform.near"; +const GRAPHQL_ENDPOINT = + props.GRAPHQL_ENDPOINT || "https://near-queryapi.api.pagoda.co"; +const sortOption = props.postsOrderOption || "blockHeight"; // following, blockHeight +const LIMIT = 25; +let accountsFollowing = props.accountsFollowing + +if (context.accountId && !accountsFollowing) { + const graph = Social.keys(`${context.accountId}/graph/follow/*`, "final"); + if (graph !== null) { + accountsFollowing = Object.keys(graph[context.accountId].graph.follow || {}); + } +} + +State.init({ + selectedTab: Storage.privateGet("selectedTab") || "all", + posts: [], + postsCountLeft: 0, + initLoadPosts: false, + initLoadPostsAll: false +}); + +function fetchGraphQL(operationsDoc, operationName, variables) { + return asyncFetch( + `${GRAPHQL_ENDPOINT}/v1/graphql`, + { + method: "POST", + headers: { "x-hasura-role": "dataplatform_near" }, + body: JSON.stringify({ + query: operationsDoc, + variables: variables, + operationName: operationName, + }), + } + ); +} + +const createQuery = (sortOption, type) => { +let querySortOption = ""; +switch (sortOption) { + case "recentComments": + querySortOption = `{ last_comment_timestamp: desc_nulls_last },`; + break; + // More options... + default: + querySortOption = ""; +} + +let queryFilter = ""; +switch (type) { + case "following": + let queryAccountsString = accountsFollowing.map(account => `"${account}"`).join(", "); + queryFilter = `account_id: { _in: [${queryAccountsString}]}`; + break; + // More options... + default: + queryFilter = ""; +} + +const indexerQueries = ` + query GetPostsQuery($offset: Int) { + dataplatform_near_social_feed_posts(order_by: [${querySortOption} { block_height: desc }], offset: $offset, limit: ${LIMIT}) { + account_id + block_height + block_timestamp + content + receipt_id + accounts_liked + last_comment_timestamp + comments(order_by: {block_height: asc}) { + account_id + block_height + block_timestamp + content + } + } + dataplatform_near_social_feed_posts_aggregate(order_by: [${querySortOption} { block_height: desc }], offset: $offset){ + aggregate { + count + } + } +} +query GetFollowingPosts($offset: Int) { + dataplatform_near_social_feed_posts(where: {${queryFilter}}, order_by: [${querySortOption} { block_height: desc }], offset: $offset) { + account_id + block_height + block_timestamp + content + receipt_id + accounts_liked + last_comment_timestamp + comments(order_by: {block_height: asc}) { + account_id + block_height + block_timestamp + content + } + } + dataplatform_near_social_feed_posts_aggregate(where: {${queryFilter}}, order_by: [${querySortOption} { block_height: desc }], offset: $offset) { + aggregate { + count + } + } +} +`; +return indexerQueries +} + +const loadMorePosts = () => { + const queryName = state.selectedTab == "following" && accountsFollowing ? "GetFollowingPosts" : "GetPostsQuery" + const type = state.selectedTab == "following" && accountsFollowing ? "following" : "all" + + if(state.selectedTab == "following" && accountsSelected && accountsSelected.length == 0) { + console.log("user has no followers") + return + } + fetchGraphQL(createQuery(sortOption, type), queryName, { + offset: state.posts.length, + }).then((result) => { + if (result.status === 200 && result.body) { + if(result.body.errors) { + console.log('error:', result.body.errors) + return + } + let data = result.body.data; + if (data) { + const newPosts = data.dataplatform_near_social_feed_posts; + const postsCountLeft = + data.dataplatform_near_social_feed_posts_aggregate.aggregate.count; + if (newPosts.length > 0) { + State.update({ + posts: [...state.posts, ...newPosts], + postsCountLeft, + }); + } + } + } + }); +}; + +const previousSelectedTab = Storage.privateGet("selectedTab"); +if (previousSelectedTab && previousSelectedTab !== state.selectedTab) { + State.update({ + selectedTab: previousSelectedTab, + }); +} + +function selectTab(selectedTab) { + Storage.privateSet("selectedTab", selectedTab); + State.update({ + posts: [], + postsCountLeft: 0, + selectedTab + }); + loadMorePosts() +} + +const H2 = styled.h2` + font-size: 19px; + line-height: 22px; + color: #11181C; + margin: 0 0 24px; + padding: 0 24px; + + @media (max-width: 1200px) { + display: none; + } +`; + +const Content = styled.div` + @media (max-width: 1200px) { + > div:first-child { + border-top: none; + } + } +`; + +const ComposeWrapper = styled.div` + border-top: 1px solid #ECEEF0; +`; + +const FilterWrapper = styled.div` + border-top: 1px solid #ECEEF0; + padding: 24px 24px 0; + + @media (max-width: 1200px) { + padding: 12px; + } +`; + +const PillSelect = styled.div` + display: inline-flex; + align-items: center; + + @media (max-width: 600px) { + width: 100%; + + button { + flex: 1; + } + } +`; + +const PillSelectButton = styled.button` + display: block; + position: relative; + border: 1px solid #E6E8EB; + border-right: none; + padding: 3px 24px; + border-radius: 0; + font-size: 12px; + line-height: 18px; + color: ${(p) => (p.selected ? "#fff" : "#687076")}; + background: ${(p) => (p.selected ? "#006ADC !important" : "#FBFCFD")}; + font-weight: 600; + transition: all 200ms; + + &:hover { + background: #ECEDEE; + text-decoration: none; + } + + &:focus { + outline: none; + border-color: #006ADC !important; + box-shadow: 0 0 0 1px #006ADC; + z-index: 5; + } + + &:first-child { + border-radius: 6px 0 0 6px; + } + &:last-child { + border-radius: 0 6px 6px 0; + border-right: 1px solid #E6E8EB; + } +`; + +const FeedWrapper = styled.div` + .post { + padding-left: 24px; + padding-right: 24px; + + @media (max-width: 1200px) { + padding-left: 12px; + padding-right: 12px; + } + } +`; + +const hasMore = state.postsCountLeft != state.posts.length + +if(!state.initLoadPostsAll) { + loadMorePosts() + State.update({initLoadPostsAll: true}) +} + +if(state.initLoadPostsAll == true && !state.initLoadPosts && accountsFollowing) { + if (accountsFollowing.length > 0 && state.selectedTab == "following") { + selectTab("following") + } + State.update({initLoadPosts: true}) +} + +return ( + <> +