diff --git a/functions/graphql/types/post.js b/functions/graphql/types/post.js index c9328f8..06020f6 100644 --- a/functions/graphql/types/post.js +++ b/functions/graphql/types/post.js @@ -37,7 +37,7 @@ const Story = objectType({ definition(t) { t.implements('PostBase'); t.nonNull.string('type', { - resolve: () => 'story' + resolve: () => 'Story' }); t.nonNull.string('cover_image'); t.nonNull.int('comments_count'); @@ -49,7 +49,7 @@ const Bounty = objectType({ definition(t) { t.implements('PostBase'); t.nonNull.string('type', { - resolve: () => 'bounty' + resolve: () => 'Bounty' }); t.nonNull.string('cover_image'); t.nonNull.string('deadline'); @@ -63,7 +63,8 @@ const Question = objectType({ definition(t) { t.implements('PostBase'); t.nonNull.string('type', { - resolve: () => 'question' + resolve: () => 'Question', + }); t.nonNull.string('cover_image'); t.nonNull.string('deadline'); diff --git a/src/features/Posts/Components/PostCard/PostCard.tsx b/src/features/Posts/Components/PostCard/PostCard.tsx index 740a8d6..bf0802e 100644 --- a/src/features/Posts/Components/PostCard/PostCard.tsx +++ b/src/features/Posts/Components/PostCard/PostCard.tsx @@ -1,4 +1,4 @@ -import { Post } from "src/features/Posts/types" +import { Post, isStory, isBounty, isQuestion } from "src/features/Posts/types" import BountyCard from "./BountyCard" import QuestionCard from "./QuestionCard" import StoryCard from "./StoryCard" @@ -8,13 +8,13 @@ type Props = { } export default function PostCard({ post }: Props) { - if (post.type === 'story') + if (isStory(post)) return - if (post.type === 'bounty') + if (isBounty(post)) return - if (post.type === 'question') + if (isQuestion(post)) return return null diff --git a/src/features/Posts/Components/PostsList/PostsList.tsx b/src/features/Posts/Components/PostsList/PostsList.tsx index 0e0bdfb..52a119f 100644 --- a/src/features/Posts/Components/PostsList/PostsList.tsx +++ b/src/features/Posts/Components/PostsList/PostsList.tsx @@ -1,4 +1,5 @@ import { Post } from "src/features/Posts/types" +import { useFeedQuery } from "src/graphql" import PostCard from "../PostCard/PostCard" interface Props { @@ -6,10 +7,13 @@ interface Props { } export default function PostsList(props: Props) { + + const { data, loading } = useFeedQuery() + if (loading) return

Loading

return (
{ - props.posts.map(post => ) + data?.getFeed.map(post => ) }
) diff --git a/src/features/Posts/pages/FeedPage/feed.graphql b/src/features/Posts/pages/FeedPage/feed.graphql index 6d0629a..d012632 100644 --- a/src/features/Posts/pages/FeedPage/feed.graphql +++ b/src/features/Posts/pages/FeedPage/feed.graphql @@ -1,4 +1,4 @@ -query FeedQuery { +query Feed { getFeed { ... on Story { id diff --git a/src/features/Posts/pages/PostDetailsPage/postDetails.graphql b/src/features/Posts/pages/PostDetailsPage/postDetails.graphql index 360d1d1..db4ee2d 100644 --- a/src/features/Posts/pages/PostDetailsPage/postDetails.graphql +++ b/src/features/Posts/pages/PostDetailsPage/postDetails.graphql @@ -1,4 +1,4 @@ -query PostDetailsQuery($postId: Int!) { +query PostDetails($postId: Int!) { getPostById(id: $postId) { ... on Story { id diff --git a/src/features/Posts/types/posts.interface.ts b/src/features/Posts/types/posts.interface.ts index 868b6f4..5f4e9cb 100644 --- a/src/features/Posts/types/posts.interface.ts +++ b/src/features/Posts/types/posts.interface.ts @@ -7,7 +7,7 @@ export type User = { } export type Author = User & { - join_date: string + join_date?: string } export type PostBase = { @@ -18,28 +18,38 @@ export type PostBase = { excerpt: string tags: Tag[] votes_count: number + type: string } export type Story = PostBase & { - type: 'story' cover_image: string; comments_count: number } +export function isStory(post: Post): post is Story { + return post.type === 'Story' +} + export type Bounty = PostBase & { - type: 'bounty' cover_image: string; reward_amount: number deadline: string applicants_count: number } +export function isBounty(post: Post): post is Bounty { + return post.type === 'Bounty' +} + export type Question = PostBase & { - type: 'question' answers_count: number comments: PostComment[] } +export function isQuestion(post: Post): post is Question { + return post.type === 'Question' +} + export type PostComment = { id: number; author: Author diff --git a/src/graphql/index.tsx b/src/graphql/index.tsx index ab965bc..e354914 100644 --- a/src/graphql/index.tsx +++ b/src/graphql/index.tsx @@ -254,17 +254,17 @@ export type SearchProjectsQueryVariables = Exact<{ export type SearchProjectsQuery = { __typename?: 'Query', searchProjects: Array<{ __typename?: 'Project', id: number, thumbnail_image: string, title: string, category: { __typename?: 'Category', title: string, id: number } }> }; -export type FeedQueryQueryVariables = Exact<{ [key: string]: never; }>; +export type FeedQueryVariables = Exact<{ [key: string]: never; }>; -export type FeedQueryQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> }> }; +export type FeedQuery = { __typename?: 'Query', getFeed: Array<{ __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> }> }; -export type PostDetailsQueryQueryVariables = Exact<{ +export type PostDetailsQueryVariables = Exact<{ postId: Scalars['Int']; }>; -export type PostDetailsQueryQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } }; +export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, answers_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, image: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } }; export type CategoryPageQueryVariables = Exact<{ categoryId: Scalars['Int']; @@ -390,8 +390,8 @@ export function useSearchProjectsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt export type SearchProjectsQueryHookResult = ReturnType; export type SearchProjectsLazyQueryHookResult = ReturnType; export type SearchProjectsQueryResult = Apollo.QueryResult; -export const FeedQueryDocument = gql` - query FeedQuery { +export const FeedDocument = gql` + query Feed { getFeed { ... on Story { id @@ -469,33 +469,33 @@ export const FeedQueryDocument = gql` `; /** - * __useFeedQueryQuery__ + * __useFeedQuery__ * - * To run a query within a React component, call `useFeedQueryQuery` and pass it any options that fit your needs. - * When your component renders, `useFeedQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * To run a query within a React component, call `useFeedQuery` and pass it any options that fit your needs. + * When your component renders, `useFeedQuery` returns an object from Apollo Client that contains loading, error, and data properties * you can use to render your UI. * * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * * @example - * const { data, loading, error } = useFeedQueryQuery({ + * const { data, loading, error } = useFeedQuery({ * variables: { * }, * }); */ -export function useFeedQueryQuery(baseOptions?: Apollo.QueryHookOptions) { +export function useFeedQuery(baseOptions?: Apollo.QueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(FeedQueryDocument, options); + return Apollo.useQuery(FeedDocument, options); } -export function useFeedQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { +export function useFeedLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(FeedQueryDocument, options); + return Apollo.useLazyQuery(FeedDocument, options); } -export type FeedQueryQueryHookResult = ReturnType; -export type FeedQueryLazyQueryHookResult = ReturnType; -export type FeedQueryQueryResult = Apollo.QueryResult; -export const PostDetailsQueryDocument = gql` - query PostDetailsQuery($postId: Int!) { +export type FeedQueryHookResult = ReturnType; +export type FeedLazyQueryHookResult = ReturnType; +export type FeedQueryResult = Apollo.QueryResult; +export const PostDetailsDocument = gql` + query PostDetails($postId: Int!) { getPostById(id: $postId) { ... on Story { id @@ -573,32 +573,32 @@ export const PostDetailsQueryDocument = gql` `; /** - * __usePostDetailsQueryQuery__ + * __usePostDetailsQuery__ * - * To run a query within a React component, call `usePostDetailsQueryQuery` and pass it any options that fit your needs. - * When your component renders, `usePostDetailsQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties + * To run a query within a React component, call `usePostDetailsQuery` and pass it any options that fit your needs. + * When your component renders, `usePostDetailsQuery` returns an object from Apollo Client that contains loading, error, and data properties * you can use to render your UI. * * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * * @example - * const { data, loading, error } = usePostDetailsQueryQuery({ + * const { data, loading, error } = usePostDetailsQuery({ * variables: { * postId: // value for 'postId' * }, * }); */ -export function usePostDetailsQueryQuery(baseOptions: Apollo.QueryHookOptions) { +export function usePostDetailsQuery(baseOptions: Apollo.QueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(PostDetailsQueryDocument, options); + return Apollo.useQuery(PostDetailsDocument, options); } -export function usePostDetailsQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { +export function usePostDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(PostDetailsQueryDocument, options); + return Apollo.useLazyQuery(PostDetailsDocument, options); } -export type PostDetailsQueryQueryHookResult = ReturnType; -export type PostDetailsQueryLazyQueryHookResult = ReturnType; -export type PostDetailsQueryQueryResult = Apollo.QueryResult; +export type PostDetailsQueryHookResult = ReturnType; +export type PostDetailsLazyQueryHookResult = ReturnType; +export type PostDetailsQueryResult = Apollo.QueryResult; export const CategoryPageDocument = gql` query CategoryPage($categoryId: Int!) { projectsByCategory(category_id: $categoryId) { diff --git a/src/mocks/data/posts.ts b/src/mocks/data/posts.ts index e6c0882..6aae6b7 100644 --- a/src/mocks/data/posts.ts +++ b/src/mocks/data/posts.ts @@ -14,14 +14,14 @@ const date = dayjs().subtract(5, 'hour').toString(); export let posts = { stories: [ { - id: 1, + id: 4, title: 'Digital Editor, Mars Review of Books', cover_image: getCoverImage(), comments_count: 31, date, votes_count: 120, excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...', - type: "story", + type: "Story", tags: [ { id: 1, title: "lnurl" }, { id: 2, title: "webln" }, @@ -32,8 +32,8 @@ export let posts = { ] as Story[], bounties: [ { - type: "bounty", - id: 1, + type: "Bounty", + id: 2, title: 'Digital Editor, Mars Review of Books', cover_image: getCoverImage(), applicants_count: 31, @@ -52,8 +52,8 @@ export let posts = { ] as Bounty[], questions: [ { - type: "question", - id: 1, + type: "Question", + id: 3, title: 'Digital Editor, Mars Review of Books', answers_count: 31, date, diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index ca8a180..5b19143 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1,6 +1,6 @@ import { graphql } from 'msw' -import { allCategories, getCategory, getProject, hottestProjects, newProjects, projectsByCategory, searchProjects } from './resolvers' +import { allCategories, getCategory, getFeed, getPostById, getProject, hottestProjects, newProjects, projectsByCategory, searchProjects } from './resolvers' import { NavCategoriesQuery, ExploreProjectsQuery, @@ -13,7 +13,10 @@ import { HottestProjectsQuery, HottestProjectsQueryVariables, AllCategoriesQuery, - AllCategoriesQueryVariables + AllCategoriesQueryVariables, + FeedQuery, + PostDetailsQuery, + PostDetailsQueryVariables, } from 'src/graphql' const delay = (ms = 1000) => new Promise((res) => setTimeout(res, ms)) @@ -96,4 +99,25 @@ export const handlers = [ ) }), + graphql.query('Feed', async (req, res, ctx) => { + await delay() + + return res( + ctx.data({ + getFeed: getFeed() + }) + ) + }), + + graphql.query('PostDetails', async (req, res, ctx) => { + await delay() + const { postId } = req.variables + + return res( + ctx.data({ + getPostById: getPostById(postId) + }) + ) + }), + ] \ No newline at end of file diff --git a/src/mocks/resolvers.ts b/src/mocks/resolvers.ts index 2542758..b432d25 100644 --- a/src/mocks/resolvers.ts +++ b/src/mocks/resolvers.ts @@ -1,5 +1,6 @@ import ASSETS from "src/assets"; import { MOCK_DATA } from "./data"; +import { Query } from 'src/graphql' export function getCategory(id: number) { @@ -39,5 +40,22 @@ export function searchProjects(search: string) { export function hottestProjects() { return MOCK_DATA.projects.sort((p1, p2) => p2.votes_count - p1.votes_count).slice(0, 20) +} +export function getFeed(): Query['getFeed'] { + return MOCK_DATA.feed as any; +} + +export function getPostById(postId: number): Query['getPostById'] { + for (const key in MOCK_DATA.posts) { + if (Object.prototype.hasOwnProperty.call(MOCK_DATA.posts, key)) { + const t = key as keyof typeof MOCK_DATA.posts + for (const p of MOCK_DATA.posts[t]) { + if (p.id === postId) return p as any; + } + + } + } + + throw new Error("Post doesn't exist") } \ No newline at end of file