feat: add the post details routes, added skeleton to trending card

This commit is contained in:
MTG2000
2022-04-20 10:22:54 +03:00
parent 75186e7492
commit 5c81dc2a7e
13 changed files with 103 additions and 98 deletions

24
package-lock.json generated
View File

@@ -24,6 +24,7 @@
"apollo-server": "^3.5.0",
"apollo-server-lambda": "^3.5.0",
"axios": "^0.24.0",
"chance": "^1.1.8",
"dayjs": "^1.11.1",
"env-cmd": "^10.1.0",
"framer-motion": "^5.3.0",
@@ -68,6 +69,7 @@
"@storybook/node-logger": "^6.3.12",
"@storybook/preset-create-react-app": "^3.2.0",
"@storybook/react": "^6.3.12",
"@types/chance": "^1.1.3",
"@types/lodash.debounce": "^4.0.6",
"@types/lodash.throttle": "^4.1.6",
"@types/marked": "^4.0.3",
@@ -9385,6 +9387,12 @@
"@types/responselike": "*"
}
},
"node_modules/@types/chance": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@types/chance/-/chance-1.1.3.tgz",
"integrity": "sha512-X6c6ghhe4/sQh4XzcZWSFaTAUOda38GQHmq9BUanYkOE/EO7ZrkazwKmtsj3xzTjkLWmwULE++23g3d3CCWaWw==",
"dev": true
},
"node_modules/@types/chrome": {
"version": "0.0.74",
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.74.tgz",
@@ -13368,6 +13376,11 @@
"node": ">=4"
}
},
"node_modules/chance": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/chance/-/chance-1.1.8.tgz",
"integrity": "sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg=="
},
"node_modules/change-case": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz",
@@ -67850,6 +67863,12 @@
"@types/responselike": "*"
}
},
"@types/chance": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@types/chance/-/chance-1.1.3.tgz",
"integrity": "sha512-X6c6ghhe4/sQh4XzcZWSFaTAUOda38GQHmq9BUanYkOE/EO7ZrkazwKmtsj3xzTjkLWmwULE++23g3d3CCWaWw==",
"dev": true
},
"@types/chrome": {
"version": "0.0.74",
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.74.tgz",
@@ -71111,6 +71130,11 @@
"supports-color": "^5.3.0"
}
},
"chance": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/chance/-/chance-1.1.8.tgz",
"integrity": "sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg=="
},
"change-case": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz",

View File

@@ -19,6 +19,7 @@
"apollo-server": "^3.5.0",
"apollo-server-lambda": "^3.5.0",
"axios": "^0.24.0",
"chance": "^1.1.8",
"dayjs": "^1.11.1",
"env-cmd": "^10.1.0",
"framer-motion": "^5.3.0",
@@ -118,6 +119,7 @@
"@storybook/node-logger": "^6.3.12",
"@storybook/preset-create-react-app": "^3.2.0",
"@storybook/react": "^6.3.12",
"@types/chance": "^1.1.3",
"@types/lodash.debounce": "^4.0.6",
"@types/lodash.throttle": "^4.1.6",
"@types/marked": "^4.0.3",

View File

@@ -9,6 +9,7 @@ import CategoryPage from "src/features/Projects/pages/CategoryPage/CategoryPage"
import { useWrapperSetup } from "./utils/Wrapper";
import HottestPage from "src/features/Projects/pages/HottestPage/HottestPage";
import FeedPage from "./features/Posts/pages/FeedPage/FeedPage";
import PostDetailsPage from "./features/Posts/pages/PostDetailsPage/PostDetailsPage";
function App() {
const { isWalletConnected } = useAppSelector(state => ({
@@ -40,6 +41,7 @@ function App() {
<Routes>
<Route path="/hottest" element={<HottestPage />} />
<Route path="/category/:id" element={<CategoryPage />} />
<Route path="/blog/post/:type/:id" element={<PostDetailsPage />} />
<Route path="/blog" element={<FeedPage />} />
<Route path="/" element={<ExplorePage />} />
</Routes>

View File

@@ -30,8 +30,7 @@ export default function BountyCard({ bounty }: Props) {
<Header author={bounty.author} date={bounty.date} />
<div className="flex flex-col gap-8 md:gap-0 md:flex-row justify-between">
<div>
<Link to={'#'}>
<Link to={`/blog/post/Bounty/${bounty.id}`}>
<h2 className="text-h5 font-bolder mt-16 flex items-center gap-8">
<span><Badge color="none" size="sm" className="bg-yellow-500 text-black">Bounty</Badge> {bounty.title}</span>
</h2>

View File

@@ -27,7 +27,7 @@ export default function QuestionCard({ question }: Props) {
<div className="p-24">
<Header author={question.author} date={question.date} />
<div className="flex justify-between">
<Link to={'#'}>
<Link to={`/blog/post/Question/${question.id}`}>
<h2 className="text-h5 font-bolder mt-16">{question.title}</h2>
</Link>
</div>
@@ -59,7 +59,7 @@ export default function QuestionCard({ question }: Props) {
</div>
<div className="flex">
<Link to='#' className="text-black font-medium p-8 hover:bg-gray-100 rounded">
<Link to={`/blog/post/Question/${question.id}`} className="text-black font-medium p-8 hover:bg-gray-100 rounded">
See all {question.answers_count} comments
</Link>
</div>

View File

@@ -25,7 +25,7 @@ export default function StoryCard({ story }: Props) {
<img src={story.cover_image} className='h-[200px] w-full object-cover' alt="" />
<div className="p-24">
<Header author={story.author} date={story.date} />
<Link to={'#'}>
<Link to={`/blog/post/Story/${story.id}`}>
<h2 className="text-h5 font-bolder mt-16">{story.title}</h2>
</Link>
<p className="text-body4 text-gray-600 mt-8">{story.excerpt}</p>

View File

@@ -1,32 +1,37 @@
import Skeleton from 'react-loading-skeleton'
import { Link } from 'react-router-dom'
import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'
import { useTrendingPostsQuery } from 'src/graphql'
import { random } from 'src/utils/helperFunctions'
export default function TrendingCard() {
const trendingPosts = useTrendingPostsQuery()
if (trendingPosts.loading)
return <></>
console.log(trendingPosts.data?.getTrendingPosts);
return (
<div className="bg-white rounded-8 border p-16">
<h3 className="text-body2 font-bolder mb-16">Trending on BOLT.FUN</h3>
<ul className='flex flex-col gap-16'>
{trendingPosts.data?.getTrendingPosts.map(post => {
console.log(post);
return <Link key={post.id} to={`/post-details-page/${post.id}`} className="border-b pb-4 last-of-type:border-b-0">
<li className="flex items-start gap-8">
<Avatar width={24} src={post.author.image} />
<p className="text-body5 font-medium">{post.title}</p>
{
trendingPosts.loading ?
Array(4).fill(0).map((_, idx) => <li key={idx} className="flex items-start gap-8">
<Skeleton circle width={24} height={24} />
<p className="text-body5 font-medium flex-grow"><Skeleton width={'80%'} />
<Skeleton width={`${random(30, 65)}%`} /></p>
</li>
</Link>
}
)}
)
:
trendingPosts.data?.getTrendingPosts.map(post => {
return <Link key={post.id} to={`/post-details-page/${post.id}`} className="border-b pb-4 last-of-type:border-b-0">
<li className="flex items-start gap-8">
<Avatar width={24} src={post.author.image} />
<p className="text-body5 font-medium">{post.title}</p>
</li>
</Link>
}
)}
</ul>
</div>
)

View File

@@ -55,20 +55,16 @@ export default function BountyPageContent({ bounty }: Props) {
<div className="border bg-white rounded-8 p-24 mt-16">
<h4 className="text-body2 font-bolder">Applicants</h4>
<ul className="flex flex-col gap-16 mt-16">
<li>
<Header author={bounty.author} size='sm' date={bounty.date} />
<div className="bg-gray-100 mt-10 p-16 rounded-8">
<p className="text-body5 font-medium mb-8">Work Plan</p>
<p className="text-body5 text-gray-600">I will create the widget using nextjs, react and typescript. and also convert it into a npm package.</p>
</div>
</li>
<li>
<Header author={bounty.author} size='sm' date={bounty.date} />
<div className="bg-gray-100 mt-10 p-16 rounded-8">
<p className="text-body5 font-medium mb-8">Work Plan</p>
<p className="text-body5 text-gray-600">I will create the widget using nextjs, react and typescript. and also convert it into a npm package.</p>
</div>
</li>
{bounty.applications.map(application =>
<li key={application.id}>
<Header author={application.author} size='sm' date={application.date} />
<div className="bg-gray-100 mt-10 p-16 rounded-8">
<p className="text-body5 font-medium mb-8">Work Plan</p>
<p className="text-body5 text-gray-600"> {application.workplan}</p>
</div>
</li>
)}
</ul>
</div>
</div>

View File

@@ -1,16 +1,11 @@
import Header from "src/features/Posts/Components/PostCard/Header/Header"
import { isBounty, isQuestion, isStory, Post } from "src/features/Posts/types"
import { marked } from 'marked';
import styles from './styles.module.css'
import Badge from "src/Components/Badge/Badge";
import { BiComment } from "react-icons/bi";
import { RiFlashlightLine } from "react-icons/ri";
import StoryPageContent from "./StoryPageContent";
import BountyPageContent from "./BountyPageContent";
import { PostDetailsQuery } from "src/graphql";
interface Props {
post: Post
post: PostDetailsQuery['getPostById']
}
export default function PageContent({ post }: Props) {

View File

@@ -1,5 +1,5 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { ModifyArgs } from 'src/utils/storybook/utils';
import PostDetailsPage from './PostDetailsPage';
export default {
@@ -8,6 +8,14 @@ export default {
argTypes: {
backgroundColor: { control: 'color' },
},
parameters: {
modifyArgs: {
router: {
routePath: "/:type/:id",
currentPath: "/Story/1"
}
} as ModifyArgs
}
} as ComponentMeta<typeof PostDetailsPage>;

View File

@@ -1,8 +1,7 @@
import { useFeedQuery } from 'src/graphql'
import { MOCK_DATA } from 'src/mocks/data'
import { useAppSelector, useInfiniteQuery } from 'src/utils/hooks'
import PostsList from '../../Components/PostsList/PostsList'
import { useParams } from 'react-router-dom'
import { usePostDetailsQuery } from 'src/graphql'
import { useAppSelector, } from 'src/utils/hooks'
import TrendingCard from '../../Components/TrendingCard/TrendingCard'
import AuthorCard from './Components/AuthorCard/AuthorCard'
import PageContent from './Components/PageContent/PageContent'
@@ -12,18 +11,27 @@ import styles from './styles.module.css'
export default function PostDetailsPage() {
// const feedQuery = useFeedQuery({
// variables: {
// take: 10,
// skip: 0
// },
// })
// const { fetchMore, isFetchingMore } = useInfiniteQuery(feedQuery, 'getFeed')
const post = MOCK_DATA.posts.stories[0]
const { type, id } = useParams()
const postDetailsQuery = usePostDetailsQuery({
variables: {
id: Number(id!),
type: type as any
},
skip: isNaN(Number(id))
})
const { navHeight } = useAppSelector((state) => ({
navHeight: state.ui.navHeight
}));
if (postDetailsQuery.loading)
return <h2>Loading</h2>
const post = postDetailsQuery.data?.getPostById;
if (!post)
return <h2>404</h2>
return (
<div
className={`page-container grid pt-16 w-full gap-32 ${styles.grid}`}

View File

@@ -3,9 +3,12 @@ import dayjs from "dayjs";
import { Bounty, Post, Question, Story } from "src/features/Posts/types";
import { randomItem } from "src/utils/helperFunctions";
import { getAvatarImage, getCoverImage } from "./utils";
import chance, { Chance } from 'chance'
const date = dayjs().subtract(5, 'hour').toString();
const getAuthor = () => ({
id: 12,
name: "John Doe",
@@ -102,7 +105,7 @@ export let posts = {
author: getAuthor(),
deadline: "25 May",
reward_amount: 200_000,
applications: getApplications(),
applications: getApplications(2),
}
] as Bounty[],
@@ -145,8 +148,10 @@ posts.questions = posts.questions.map(b => ({ ...b, __typename: "Question" }))
posts.stories = posts.stories.map(b => ({ ...b, __typename: "Story" }))
const feedRandomer = new Chance('feed')
export const feed: Post[] = Array(30).fill(0).map((_, idx) => {
const post = randomItem(posts.bounties[0], posts.questions[0], posts.stories[0]) as Post;
const post = feedRandomer.pickone([posts.bounties[0], posts.questions[0], posts.stories[0]])
return { ...post, id: idx + 1, title: `${post.type} Title ${idx + 1}` }
})

View File

@@ -1,6 +1,8 @@
import { MOCK_DATA } from "./data";
import { Post, Query, QueryGetFeedArgs, QueryGetPostByIdArgs } from 'src/graphql'
import { Author } from "src/features/Posts/types";
import { Chance } from "chance";
const chance = new Chance()
export function getCategory(id: number) {
@@ -55,46 +57,5 @@ export function getPostById(args: QueryGetPostByIdArgs): Query['getPostById'] {
}
export function getTrendingPosts(): Query['getTrendingPosts'] {
return [
{
id: 1,
title: 'How to collect donations within lightning network?',
author: {
id: 2,
name: "John Doe",
image: "https://i.pravatar.cc/150?img=2"
} as Author,
__typename: "Question"
},
{
id: 2,
title: 'How to implement the RSMC part of Lightning network?',
author: {
id: 2,
name: "John Doe",
image: "https://i.pravatar.cc/150?img=2"
} as Author,
__typename: "Question"
},
{
id: 3,
title: 'c-lightning public node data on explorers',
author: {
id: 2,
name: "John Doe",
image: "https://i.pravatar.cc/150?img=2"
} as Author,
__typename: "Story"
},
{
id: 4,
title: 'How to find all nodes and connections in LN?',
author: {
id: 2,
name: "John Doe",
image: "https://i.pravatar.cc/150?img=2"
} as Author,
__typename: "Question"
},
] as Post[];
return chance.pickset(MOCK_DATA.feed, 5);
}