feat: connect feed filters apis with ui, change filters list style

This commit is contained in:
MTG2000
2022-05-20 15:32:38 +03:00
parent 86e832e04b
commit 80c9e31467
46 changed files with 445 additions and 250 deletions

View File

@@ -39,7 +39,7 @@ function App() {
return <div id="app" className='w-full overflow-hidden'>
return <div id="app" className='w-full'>
<Navbar />
<Suspense fallback={<LoadingPage />}>
<Routes>

View File

@@ -199,20 +199,36 @@ export default function VoteButton({
key={increment.id}
className={styles.vote_counter}
>+{increment.value}</span>)}
{sparks.map(spark =>
<div
key={spark.id}
className={styles.spark}
<div className="relative z-50">
<MdLocalFireDepartment className={styles.spark}
style={{
"--offsetX": spark.offsetX,
"--offsetY": spark.offsetY,
"--animationSpeed": spark.animationSpeed,
"--scale": spark.scale,
"animationName": spark.animation,
"color": spark.color
} as any}
><MdLocalFireDepartment className='' /></div>)
}
opacity: 1,
scale: 1,
top: 0,
left: 0,
color: 'green'
}}
/>
{sparks.map(spark =>
<div
key={spark.id}
className={styles.spark}
style={{
"--offsetX": spark.offsetX,
"--offsetY": spark.offsetY,
"--animationSpeed": spark.animationSpeed,
"--scale": spark.scale,
"animationName": spark.animation,
"color": spark.color
} as any}
><MdLocalFireDepartment className='' /></div>)
}
</div>
<div
className={styles.spark}
><MdLocalFireDepartment className='' /></div>
</button>
)

View File

@@ -136,6 +136,7 @@
transform: scale(var(--scale));
opacity: 0;
will-change: transform;
z-index: 3000;
animation-name: fly-spark-1;
animation-duration: calc(var(--animationSpeed) * 1s);

View File

@@ -18,7 +18,7 @@ export default function HackathonsPage() {
take: 10,
skip: 0,
sortBy: sortByFilter,
category: topicsFilter
topic: Number(topicsFilter)
},
})
const { fetchMore, isFetchingMore } = useInfiniteQuery(feedQuery, 'getFeed')

View File

@@ -12,7 +12,7 @@ interface Props {
export default function CommentCard({ comment, onReply }: Props) {
return (
<div className="border rounded-12 p-24">
<Header author={comment.author} date={comment.created_at} />
<Header author={comment.author} date={comment.createdAt} />
<p className="text-body4 mt-16">
{comment.body}
</p>

View File

@@ -4,7 +4,7 @@ import { Author } from "src/features/Posts/types";
export interface Comment {
id: number
author: Author
created_at: string
createdAt: string
body: string
votes_count: number
parentId: number | null

View File

@@ -12,7 +12,7 @@ export type BountyCardType = Pick<Bounty,
| 'type'
| 'title'
| 'cover_image'
| 'date'
| 'createdAt'
| 'author'
| 'excerpt'
| 'votes_count'
@@ -33,7 +33,7 @@ export default function BountyCard({ bounty }: Props) {
<div className="bg-white rounded-12 overflow-hidden border">
<img src={bounty.cover_image} className='h-[200px] w-full object-cover bg-gray-100' alt="" />
<div className="p-24">
<Header author={bounty.author} date={bounty.date} />
<Header author={bounty.author} date={bounty.createdAt} />
<div className="flex flex-col gap-8 md:gap-0 md:flex-row justify-between">
<div>
<Link to={`/blog/post/Bounty/${bounty.id}`}>

View File

@@ -6,7 +6,7 @@ interface Props {
author: {
id: number,
name: string,
image: string
avatar: string
}
date: string;
size?: 'sm' | 'md' | 'lg';
@@ -27,21 +27,25 @@ const nameSize: UnionToObjectKeys<Props, 'size'> = {
export default function Header({
size = 'md',
showTimeAgo = true,
showTimeAgo = false,
...props }: Props) {
const passedTime = dayjs().diff(props.date, 'hour');
const dateToShow = passedTime < 24 ?
`${dayjs().diff(props.date, 'hour')}h ago`
:
dayjs(props.date).format('MMMM DD');
const dateToShow = () => {
const passedTime = dayjs().diff(props.date, 'hour');
if (passedTime === 0) return 'now';
if (passedTime < 24) return `${dayjs().diff(props.date, 'hour')}h ago`
return dayjs(props.date).format('MMMM DD');
}
return (
<div className='flex gap-8'>
<Avatar width={avatarSize[size]} src={props.author.image} />
<Avatar width={avatarSize[size]} src={props.author.avatar} />
<div>
<p className={`${nameSize[size]} text-black font-medium`}>{props.author.name}</p>
<p className={`text-body6 text-gray-600`}>{dateToShow}</p>
<p className={`text-body6 text-gray-600`}>{dateToShow()}</p>
</div>
{/* {showTimeAgo && <p className={`${nameSize[size]} text-gray-500 ml-auto `}>
{dayjs().diff(props.date, 'hour') < 24 ? `${dayjs().diff(props.date, 'hour')}h ago` : undefined}

View File

@@ -11,7 +11,7 @@ export type QuestionCardType = Pick<Question,
| 'id'
| 'type'
| 'title'
| 'date'
| 'createdAt'
| 'author'
| 'excerpt'
| 'votes_count'
@@ -22,7 +22,7 @@ export type QuestionCardType = Pick<Question,
| 'id'
| 'author'
| 'body'
| 'created_at'
| 'createdAt'
>>
};
interface Props {
@@ -33,7 +33,7 @@ export default function QuestionCard({ question }: Props) {
<div className="bg-white rounded-12 overflow-hidden border">
{/* <img src={question.cover_image} className='h-[200px] w-full object-cover' alt="" /> */}
<div className="p-24">
<Header author={question.author} date={question.date} />
<Header author={question.author} date={question.createdAt} />
<div className="flex justify-between">
<Link to={`/blog/post/Question/${question.id}`}>
<h2 className="text-h5 font-bolder mt-16">{question.title}</h2>
@@ -61,7 +61,7 @@ export default function QuestionCard({ question }: Props) {
<div className="flex p-16 mt-16 flex-col gap-10 bg-gray-50">
<div className="flex flex-col gap-10">
{question.comments.slice(0, 2).map(comment => <div key={comment.id} className="border-b last-of-type:border-b-0 pb-8 " >
<Header author={comment.author} size='sm' date={comment.created_at} />
<Header author={comment.author} size='sm' date={comment.createdAt} />
<p className="text-body5 text-gray-600 mt-8">{trimText(comment.body, 80)}</p>
</div>)}
</div>

View File

@@ -10,7 +10,7 @@ export type StoryCardType = Pick<Story,
| 'type'
| 'title'
| 'cover_image'
| 'date'
| 'createdAt'
| 'author'
| 'excerpt'
| 'votes_count'
@@ -25,7 +25,7 @@ export default function StoryCard({ story }: Props) {
<div className="bg-white rounded-12 overflow-hidden border">
<img src={story.cover_image} className='h-[200px] w-full object-cover' alt="" />
<div className="p-24">
<Header author={story.author} date={story.date} />
<Header author={story.author} date={story.createdAt} />
<Link to={`/blog/post/Story/${story.id}`}>
<h2 className="text-h5 font-bolder mt-16">{story.title}</h2>
</Link>

View File

@@ -26,7 +26,7 @@ export default function TrendingCard() {
trendingPosts.data?.getTrendingPosts.map(post => {
return <Link key={post.id} to={`/blog/post/${post.__typename}/${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} />
<Avatar width={24} src={post.author.avatar} />
<p className="text-body5 font-medium">{post.title}</p>
</li>
</Link>

View File

@@ -5,7 +5,7 @@ query TrendingPosts {
title
author {
id
image
avatar
}
}
... on Bounty {
@@ -13,7 +13,7 @@ query TrendingPosts {
title
author {
id
image
avatar
}
}
@@ -22,7 +22,7 @@ query TrendingPosts {
title
author {
id
image
avatar
}
}
}

View File

@@ -4,7 +4,7 @@ import { useFeedQuery } from 'src/graphql'
import { useAppSelector, useInfiniteQuery } from 'src/utils/hooks'
import PostsList from '../../Components/PostsList/PostsList'
import TrendingCard from '../../Components/TrendingCard/TrendingCard'
import PopularCategories from './PopularCategories/PopularCategories'
import PopularTopicsFilter from './PopularTopicsFilter/PopularTopicsFilter'
import SortBy from './SortBy/SortBy'
import styles from './styles.module.scss'
@@ -12,15 +12,15 @@ import styles from './styles.module.scss'
export default function FeedPage() {
const [sortByFilter, setSortByFilter] = useState('all')
const [categoryFilter, setCategoryFilter] = useState('all')
const [topicFilter, setTopicFilter] = useState<number | null>(null)
const feedQuery = useFeedQuery({
variables: {
take: 10,
take: 3,
skip: 0,
sortBy: sortByFilter,
category: categoryFilter
topic: topicFilter
},
})
const { fetchMore, isFetchingMore } = useInfiniteQuery(feedQuery, 'getFeed')
@@ -42,9 +42,9 @@ export default function FeedPage() {
<SortBy
filterChanged={setSortByFilter}
/>
<hr className="my-24 bg-gray-100" />
<PopularCategories
filterChanged={setCategoryFilter}
<div className="my-24"></div>
<PopularTopicsFilter
filterChanged={setTopicFilter}
/>
</div>
</aside>

View File

@@ -1,20 +0,0 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import PopularCategories from './PopularCategories';
export default {
title: 'Posts/Feed Page/Components/PopularCategories',
component: PopularCategories,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof PopularCategories>;
const Template: ComponentStory<typeof PopularCategories> = (args) => <div className="max-w-[326px]"><PopularCategories {...args as any} ></PopularCategories></div>
export const Default = Template.bind({});
Default.args = {
}

View File

@@ -1,54 +0,0 @@
import React, { useState } from 'react'
const filters = [
{
text: "🔥 All",
value: 'all'
}, {
text: "Lightning Network",
value: 'lightning-network'
}, {
text: "Bitcoin",
value: 'bitcoin'
}, {
text: "Cybersecurity",
value: 'cybersecurity'
}, {
text: "Bounties",
value: 'bounties'
}, {
text: "Grants",
value: 'Grants'
},
]
interface Props {
filterChanged?: (newFilter: string) => void
}
export default function PopularCategories({ filterChanged }: Props) {
const [selected, setSelected] = useState(filters[0].value);
const filterClicked = (newValue: string) => {
if (selected === newValue)
return
setSelected(newValue);
filterChanged?.(newValue);
}
return (
<div className=''>
<p className="text-body2 font-bolder text-black mb-16">Popular Categories</p>
<ul>
{filters.map((f, idx) => <li
key={f.value}
className={`p-12 rounded-8 cursor-pointer font-bold ${f.value === selected && 'bg-gray-100'}`}
onClick={() => filterClicked(f.value)}
>
{f.text}
</li>)}
</ul>
</div>
)
}

View File

@@ -0,0 +1,20 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import PopularTopicsFilter from './PopularTopicsFilter';
export default {
title: 'Posts/Feed Page/Components/Popular Topics Filter',
component: PopularTopicsFilter,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof PopularTopicsFilter>;
const Template: ComponentStory<typeof PopularTopicsFilter> = (args) => <div className="max-w-[326px]"><PopularTopicsFilter {...args as any} ></PopularTopicsFilter></div>
export const Default = Template.bind({});
Default.args = {
}

View File

@@ -0,0 +1,74 @@
import React, { useState } from 'react'
import Skeleton from 'react-loading-skeleton';
import { usePopularTopicsQuery } from 'src/graphql';
const filters = [
{
text: "🔥 All",
value: 0
}, {
text: "Lightning Network",
value: 1
}, {
text: "Bitcoin",
value: 2
}, {
text: "Cybersecurity",
value: 3
}, {
text: "Bounties",
value: 4
}, {
text: "Grants",
value: 5
},
]
interface Props {
filterChanged?: (newFilter: number) => void
}
export default function PopularTopicsFilter({ filterChanged }: Props) {
const [selected, setSelected] = useState(filters[0].value);
const topicsQuery = usePopularTopicsQuery();
const filterClicked = (newValue: number) => {
if (selected === newValue)
return
setSelected(newValue);
filterChanged?.(newValue);
}
return (
<div className='bg-white border rounded-12 p-16'>
<p className="text-body2 font-bolder text-black mb-16">Topics</p>
<ul className=' flex flex-col gap-16'>
{topicsQuery.loading ?
Array(4).fill(0).map((_, idx) => <li
key={idx}
className={`flex items-start rounded-8 font-bold`}
>
<span className='bg-gray-50 rounded-8 w-40 h-40 text-center py-8'> </span>
<span className="self-center px-16"><Skeleton width={'10ch'} />
</span>
</li>
)
:
topicsQuery.data?.popularTopics.map((f, idx) => <li
key={f.id}
className={`flex items-start rounded-8 cursor-pointer font-bold ${f.id === selected && 'bg-gray-50'}`}
onClick={() => filterClicked(f.id)}
>
<span className='bg-gray-50 rounded-8 w-40 h-40 text-center py-8'>{f.icon}</span>
<span className="self-center px-16">
{f.title}
</span>
</li>)}
</ul>
</div>
)
}

View File

@@ -0,0 +1,7 @@
query PopularTopics {
popularTopics {
id
title
icon
}
}

View File

@@ -29,7 +29,7 @@ export default function SortBy({ filterChanged }: Props) {
}
return (
<div className=''>
<div className='bg-white border rounded-12 p-16'>
<p className="text-body2 font-bolder text-black mb-16">Sort By</p>
<ul>
{filters.map((f, idx) => <li

View File

@@ -1,13 +1,13 @@
query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
getFeed(take: $take, skip: $skip, sortBy: $sortBy, category: $category) {
query Feed($take: Int, $skip: Int, $sortBy: String, $topic: Int) {
getFeed(take: $take, skip: $skip, sortBy: $sortBy, topic: $topic) {
... on Story {
id
title
date
createdAt
author {
id
name
image
avatar
}
excerpt
tags {
@@ -22,11 +22,11 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
... on Bounty {
id
title
date
createdAt
author {
id
name
image
avatar
}
excerpt
tags {
@@ -43,11 +43,11 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
... on Question {
id
title
date
createdAt
author {
id
name
image
avatar
}
excerpt
tags {
@@ -59,12 +59,12 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
answers_count
comments {
id
created_at
createdAt
body
author {
id
name
image
avatar
}
}
}

View File

@@ -11,7 +11,7 @@ export default function AuthorCard({ author }: Props) {
return (
<div className="bg-white p-16 border rounded-8">
<div className='flex gap-8'>
<Avatar width={48} src={author.image} />
<Avatar width={48} src={author.avatar} />
<div>
<p className={`'text-body4' text-black font-medium`}>{author.name}</p>
<p className={`text-body6 text-gray-600`}>Joined on {dayjs(author.join_date).format('MMMM DD, YYYY')}</p>

View File

@@ -9,6 +9,8 @@ import Button from "src/Components/Button/Button";
import { FiGithub, FiShare2 } from "react-icons/fi";
import BountyApplicants from "./BountyApplicants";
import VoteButton from "src/Components/VoteButton/VoteButton";
import { RiFlashlightLine } from "react-icons/ri";
import { numberFormatter } from "src/utils/helperFunctions";
interface Props {
@@ -21,14 +23,16 @@ export default function BountyPageContent({ bounty }: Props) {
{/* Header */}
<div className="flex flex-col gap-24">
<Header size="lg" showTimeAgo={false} author={bounty.author} date={bounty.date} />
<Header size="lg" showTimeAgo={false} author={bounty.author} date={bounty.createdAt} />
<h1 className="text-h2 font-bolder">{bounty.title} <Badge color="none" size="sm" className="bg-warning-500 text-black">Bounty</Badge></h1>
<div className="">
<span className="text-body4 text-gray-600 font-bolder">Reward: </span>
<span className="text-body4 text-purple-500 font-medium">{bounty.reward_amount} sats</span>
</div>
<div className="flex gap-24 items-center">
<VoteButton initVotes={bounty.votes_count} />
<div className="text-black font-medium">
<RiFlashlightLine /> <span className="align-middle text-body5">{numberFormatter(bounty.votes_count)} votes</span>
</div>
<div className="text-black font-medium">
<BiComment /> <span className="align-middle text-body5">32 Comments</span>
</div>

View File

@@ -1,10 +1,12 @@
import { BsBookmark } from "react-icons/bs"
import { MdIosShare, MdLocalFireDepartment } from "react-icons/md"
import { MdIosShare } from "react-icons/md"
import VoteButton from "src/Components/VoteButton/VoteButton"
interface Props {
votes_count: number
}
export default function PostActions() {
export default function PostActions(props: Props) {
const actions = [
{
@@ -19,7 +21,7 @@ export default function PostActions() {
return (
<ul className="bg-white rounded-12 p-16 border flex justify-around md:flex-col gap-32">
<VoteButton initVotes={123} direction='vertical' fillType="upDown" />
<VoteButton initVotes={props.votes_count} direction='vertical' fillType="upDown" />
{actions.map((action, idx) => <li
className={`py-8 px-20 text-body5 flex flex-col justify-center items-center cursor-pointer rounded-8
${'text-gray-500 hover:bg-gray-50 active:bg-gray-100'}`}>

View File

@@ -6,6 +6,7 @@ import Badge from "src/Components/Badge/Badge";
import { BiComment } from "react-icons/bi";
import { RiFlashlightLine } from "react-icons/ri";
import { CommentsSection } from "src/features/Posts/Components/Comments";
import { numberFormatter } from "src/utils/helperFunctions";
interface Props {
@@ -17,7 +18,7 @@ export default function QuestionPageContent({ question }: Props) {
<>
<div id="content" className="bg-white p-32 border rounded-16">
<div className="flex flex-col gap-24">
<Header size="lg" showTimeAgo={false} author={question.author} date={question.date} />
<Header size="lg" showTimeAgo={false} author={question.author} date={question.createdAt} />
<h1 className="text-h2 font-bolder">{question.title}</h1>
<div className="flex gap-8">
{question.tags.map(tag => <Badge key={tag.id} size='sm'>
@@ -26,7 +27,7 @@ export default function QuestionPageContent({ question }: Props) {
</div>
<div className="flex gap-24">
<div className="text-black font-medium">
<RiFlashlightLine /> <span className="align-middle text-body5">{question.votes_count} votes</span>
<RiFlashlightLine /> <span className="align-middle text-body5">{numberFormatter(question.votes_count)} votes</span>
</div>
<div className="text-black font-medium">
<BiComment /> <span className="align-middle text-body5">32 Comments</span>
@@ -38,9 +39,9 @@ export default function QuestionPageContent({ question }: Props) {
</div>
</div>
<div id="comments" className="mt-10">
{/* <div id="comments" className="mt-10">
<CommentsSection comments={question.comments} />
</div>
</div> */}
</>
)
}

View File

@@ -6,6 +6,7 @@ import Badge from "src/Components/Badge/Badge";
import { BiComment } from "react-icons/bi";
import { RiFlashlightLine } from "react-icons/ri";
import { CommentsSection } from "src/features/Posts/Components/Comments";
import { numberFormatter } from "src/utils/helperFunctions";
interface Props {
@@ -17,16 +18,16 @@ export default function StoryPageContent({ story }: Props) {
<>
<div id="content" className="bg-white p-32 border rounded-16">
<div className="flex flex-col gap-24">
<Header size="lg" showTimeAgo={false} author={story.author} date={story.date} />
<Header size="lg" showTimeAgo={false} author={story.author} date={story.createdAt} />
<h1 className="text-h2 font-bolder">{story.title}</h1>
<div className="flex gap-8">
{story.tags.length > 0 && <div className="flex gap-8">
{story.tags.map(tag => <Badge key={tag.id} size='sm'>
{tag.title}
</Badge>)}
</div>
</div>}
<div className="flex gap-24">
<div className="text-black font-medium">
<RiFlashlightLine /> <span className="align-middle text-body5">{story.votes_count} votes</span>
<RiFlashlightLine /> <span className="align-middle text-body5">{numberFormatter(story.votes_count)} votes</span>
</div>
<div className="text-black font-medium">
<BiComment /> <span className="align-middle text-body5">{story.comments_count} Comments</span>
@@ -37,9 +38,9 @@ export default function StoryPageContent({ story }: Props) {
<div className={`mt-42 ${styles.body}`} dangerouslySetInnerHTML={{ __html: marked.parse(story.body) }}>
</div>
</div>
<div id="comments" className="mt-10 comments_col">
{/* <div id="comments" className="mt-10 comments_col">
<CommentsSection comments={story.comments} />
</div>
</div> */}
</>
)
}

View File

@@ -44,7 +44,7 @@ export default function PostDetailsPage() {
top: `${navHeight + 16}px`,
maxHeight: `calc(100vh - ${navHeight}px - 16px)`,
}}>
<PostActions />
<PostActions votes_count={post.votes_count} />
</div>
</aside>

View File

@@ -3,11 +3,11 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
... on Story {
id
title
date
createdAt
author {
id
name
image
avatar
}
body
tags {
@@ -20,25 +20,25 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
comments_count
comments {
id
created_at
createdAt
body
votes_count
parentId
author {
id
name
image
avatar
}
}
}
... on Bounty {
id
title
date
createdAt
author {
id
name
image
avatar
}
body
tags {
@@ -58,18 +58,18 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
author {
id
name
image
avatar
}
}
}
... on Question {
id
title
date
createdAt
author {
id
name
image
avatar
}
body
tags {
@@ -81,14 +81,14 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
answers_count
comments {
id
created_at
createdAt
body
votes_count
parentId
author {
id
name
image
avatar
}
}
}

View File

@@ -4,7 +4,7 @@ import { Tag } from "src/utils/interfaces"
export type User = {
id: number
name: string
image: string
avatar: string
}
export type Author = User & {
@@ -14,7 +14,7 @@ export type Author = User & {
export type PostBase1 = {
id: number
title: string
date: string
createdAt: string
author: Author
excerpt: string
tags: Tag[]

View File

@@ -4,14 +4,16 @@ import ProjectsSection from "./ProjectsSection/ProjectsSection";
export default function ExplorePage() {
return (
<>
<div className="px-32">
<Header />
</div>
<div className="page-container">
<Header />
{/* <div className="my-40 px-32">
<Categories />
</div> */}
<ProjectsSection />
</>
<div className="w-full overflow-hidden">
<ProjectsSection />
</div>
</div>
)
}

View File

@@ -6,10 +6,10 @@ export default function ProjectsRowSkeleton() {
return (
<div className='mb-48'>
<h3 className="font-bolder text-body3 mb-24 px-32">
<h3 className="font-bolder text-body3 mb-24">
<Skeleton width='10ch' />
</h3>
<div className="p-32 flex gap-20">
<div className=" flex gap-20">
{Array(5).fill(0).map((_, idx) => (
<ProjectCardMiniSkeleton key={idx} />
))}

View File

@@ -83,13 +83,13 @@ export default function ProjectsRow({ title, categoryId, projects }: Props) {
return (
<div className='mb-48'>
<h3 className="font-bolder text-body3 mb-24 px-32">
<h3 className="font-bolder text-body3 mb-24">
<span className="align-middle">{title}</span>
{categoryId > 0 && <Link to={`/category/${categoryId}`}>
<MdDoubleArrow className='text-gray-200 ml-8 hover:cursor-pointer transform scale-y-110 scale-x-125 origin-left' />
</Link>}
</h3>
<div className="px-32">
<div className="">
<Carousel
showDots={false}
autoPlay={false}

View File

@@ -13,6 +13,8 @@ export type Scalars = {
Boolean: boolean;
Int: number;
Float: number;
/** Date custom scalar type */
Date: any;
};
export type Award = {
@@ -31,7 +33,7 @@ export type Bounty = PostBase & {
author: User;
body: Scalars['String'];
cover_image: Scalars['String'];
date: Scalars['String'];
createdAt: Scalars['Date'];
deadline: Scalars['String'];
excerpt: Scalars['String'];
id: Scalars['Int'];
@@ -73,6 +75,7 @@ export type Mutation = {
__typename?: 'Mutation';
confirmVote: Vote;
vote: Vote;
vote2: Vote2;
};
@@ -87,6 +90,13 @@ export type MutationVoteArgs = {
project_id: Scalars['Int'];
};
export type MutationVote2Args = {
amount_in_sat: Scalars['Int'];
item_id: Scalars['Int'];
item_type: Vote_Item_Type;
};
export enum Post_Type {
Bounty = 'Bounty',
Question = 'Question',
@@ -96,12 +106,10 @@ export enum Post_Type {
export type Post = Bounty | Question | Story;
export type PostBase = {
author: User;
body: Scalars['String'];
date: Scalars['String'];
createdAt: Scalars['Date'];
excerpt: Scalars['String'];
id: Scalars['Int'];
tags: Array<Tag>;
title: Scalars['String'];
votes_count: Scalars['Int'];
};
@@ -110,7 +118,7 @@ export type PostComment = {
__typename?: 'PostComment';
author: User;
body: Scalars['String'];
created_at: Scalars['String'];
createdAt: Scalars['Date'];
id: Scalars['Int'];
parentId: Maybe<Scalars['Int']>;
votes_count: Scalars['Int'];
@@ -137,6 +145,7 @@ export type Query = {
__typename?: 'Query';
allCategories: Array<Category>;
allProjects: Array<Project>;
allTopics: Array<Topic>;
getCategory: Category;
getFeed: Array<Post>;
getLnurlDetailsForProject: LnurlDetails;
@@ -145,6 +154,7 @@ export type Query = {
getTrendingPosts: Array<Post>;
hottestProjects: Array<Project>;
newProjects: Array<Project>;
popularTopics: Array<Topic>;
projectsByCategory: Array<Project>;
searchProjects: Array<Project>;
};
@@ -162,10 +172,10 @@ export type QueryGetCategoryArgs = {
export type QueryGetFeedArgs = {
category?: InputMaybe<Scalars['String']>;
skip?: InputMaybe<Scalars['Int']>;
sortBy?: InputMaybe<Scalars['String']>;
take?: InputMaybe<Scalars['Int']>;
topic?: InputMaybe<Scalars['Int']>;
};
@@ -216,7 +226,7 @@ export type Question = PostBase & {
author: User;
body: Scalars['String'];
comments: Array<PostComment>;
date: Scalars['String'];
createdAt: Scalars['Date'];
excerpt: Scalars['String'];
id: Scalars['Int'];
tags: Array<Tag>;
@@ -232,11 +242,12 @@ export type Story = PostBase & {
comments: Array<PostComment>;
comments_count: Scalars['Int'];
cover_image: Scalars['String'];
date: Scalars['String'];
createdAt: Scalars['Date'];
excerpt: Scalars['String'];
id: Scalars['Int'];
tags: Array<Tag>;
title: Scalars['String'];
topic: Topic;
type: Scalars['String'];
votes_count: Scalars['Int'];
};
@@ -247,13 +258,29 @@ export type Tag = {
title: Scalars['String'];
};
export type Topic = {
__typename?: 'Topic';
icon: Scalars['String'];
id: Scalars['Int'];
title: Scalars['String'];
};
export type User = {
__typename?: 'User';
avatar: Scalars['String'];
id: Scalars['Int'];
image: Scalars['String'];
name: Scalars['String'];
};
export enum Vote_Item_Type {
Bounty = 'Bounty',
Comment = 'Comment',
Project = 'Project',
Question = 'Question',
Story = 'Story',
User = 'User'
}
export type Vote = {
__typename?: 'Vote';
amount_in_sat: Scalars['Int'];
@@ -264,6 +291,17 @@ export type Vote = {
project: Project;
};
export type Vote2 = {
__typename?: 'Vote2';
amount_in_sat: Scalars['Int'];
id: Scalars['Int'];
item_id: Scalars['Int'];
item_type: Vote_Item_Type;
paid: Scalars['Boolean'];
payment_hash: Scalars['String'];
payment_request: Scalars['String'];
};
export type NavCategoriesQueryVariables = Exact<{ [key: string]: never; }>;
@@ -279,17 +317,22 @@ export type SearchProjectsQuery = { __typename?: 'Query', searchProjects: Array<
export type TrendingPostsQueryVariables = Exact<{ [key: string]: never; }>;
export type TrendingPostsQuery = { __typename?: 'Query', getTrendingPosts: Array<{ __typename?: 'Bounty', id: number, title: string, author: { __typename?: 'User', id: number, image: string } } | { __typename?: 'Question', id: number, title: string, author: { __typename?: 'User', id: number, image: string } } | { __typename?: 'Story', id: number, title: string, author: { __typename?: 'User', id: number, image: string } }> };
export type TrendingPostsQuery = { __typename?: 'Query', getTrendingPosts: Array<{ __typename?: 'Bounty', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } } | { __typename?: 'Question', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } } | { __typename?: 'Story', id: number, title: string, author: { __typename?: 'User', id: number, avatar: string } }> };
export type PopularTopicsQueryVariables = Exact<{ [key: string]: never; }>;
export type PopularTopicsQuery = { __typename?: 'Query', popularTopics: Array<{ __typename?: 'Topic', id: number, title: string, icon: string }> };
export type FeedQueryVariables = Exact<{
take: InputMaybe<Scalars['Int']>;
skip: InputMaybe<Scalars['Int']>;
sortBy: InputMaybe<Scalars['String']>;
category: InputMaybe<Scalars['String']>;
topic: InputMaybe<Scalars['Int']>;
}>;
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, 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, created_at: 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, createdAt: any, 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, avatar: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, answers_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, author: { __typename?: 'User', id: number, name: string, avatar: string } }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, excerpt: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }> }> };
export type PostDetailsQueryVariables = Exact<{
id: Scalars['Int'];
@@ -297,7 +340,7 @@ export type PostDetailsQueryVariables = Exact<{
}>;
export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, date: string, body: 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 }>, applications: Array<{ __typename?: 'BountyApplication', id: number, date: string, workplan: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Question', id: number, title: string, date: string, body: string, votes_count: number, type: string, 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, created_at: string, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'User', id: number, name: string, image: string } }> } | { __typename?: 'Story', id: number, title: string, date: string, body: 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 }>, comments: Array<{ __typename?: 'PostComment', id: number, created_at: string, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'User', id: number, name: string, image: string } }> } };
export type PostDetailsQuery = { __typename?: 'Query', getPostById: { __typename?: 'Bounty', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string, deadline: string, reward_amount: number, applicants_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, applications: Array<{ __typename?: 'BountyApplication', id: number, date: string, workplan: string, author: { __typename?: 'User', id: number, name: string, avatar: string } }> } | { __typename?: 'Question', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, answers_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'User', id: number, name: string, avatar: string } }> } | { __typename?: 'Story', id: number, title: string, createdAt: any, body: string, votes_count: number, type: string, cover_image: string, comments_count: number, author: { __typename?: 'User', id: number, name: string, avatar: string }, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, comments: Array<{ __typename?: 'PostComment', id: number, createdAt: any, body: string, votes_count: number, parentId: number | null, author: { __typename?: 'User', id: number, name: string, avatar: string } }> } };
export type CategoryPageQueryVariables = Exact<{
categoryId: Scalars['Int'];
@@ -431,7 +474,7 @@ export const TrendingPostsDocument = gql`
title
author {
id
image
avatar
}
}
... on Bounty {
@@ -439,7 +482,7 @@ export const TrendingPostsDocument = gql`
title
author {
id
image
avatar
}
}
... on Question {
@@ -447,7 +490,7 @@ export const TrendingPostsDocument = gql`
title
author {
id
image
avatar
}
}
}
@@ -480,17 +523,53 @@ export function useTrendingPostsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpti
export type TrendingPostsQueryHookResult = ReturnType<typeof useTrendingPostsQuery>;
export type TrendingPostsLazyQueryHookResult = ReturnType<typeof useTrendingPostsLazyQuery>;
export type TrendingPostsQueryResult = Apollo.QueryResult<TrendingPostsQuery, TrendingPostsQueryVariables>;
export const PopularTopicsDocument = gql`
query PopularTopics {
popularTopics {
id
title
icon
}
}
`;
/**
* __usePopularTopicsQuery__
*
* To run a query within a React component, call `usePopularTopicsQuery` and pass it any options that fit your needs.
* When your component renders, `usePopularTopicsQuery` 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 } = usePopularTopicsQuery({
* variables: {
* },
* });
*/
export function usePopularTopicsQuery(baseOptions?: Apollo.QueryHookOptions<PopularTopicsQuery, PopularTopicsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<PopularTopicsQuery, PopularTopicsQueryVariables>(PopularTopicsDocument, options);
}
export function usePopularTopicsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PopularTopicsQuery, PopularTopicsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<PopularTopicsQuery, PopularTopicsQueryVariables>(PopularTopicsDocument, options);
}
export type PopularTopicsQueryHookResult = ReturnType<typeof usePopularTopicsQuery>;
export type PopularTopicsLazyQueryHookResult = ReturnType<typeof usePopularTopicsLazyQuery>;
export type PopularTopicsQueryResult = Apollo.QueryResult<PopularTopicsQuery, PopularTopicsQueryVariables>;
export const FeedDocument = gql`
query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
getFeed(take: $take, skip: $skip, sortBy: $sortBy, category: $category) {
query Feed($take: Int, $skip: Int, $sortBy: String, $topic: Int) {
getFeed(take: $take, skip: $skip, sortBy: $sortBy, topic: $topic) {
... on Story {
id
title
date
createdAt
author {
id
name
image
avatar
}
excerpt
tags {
@@ -505,11 +584,11 @@ export const FeedDocument = gql`
... on Bounty {
id
title
date
createdAt
author {
id
name
image
avatar
}
excerpt
tags {
@@ -526,11 +605,11 @@ export const FeedDocument = gql`
... on Question {
id
title
date
createdAt
author {
id
name
image
avatar
}
excerpt
tags {
@@ -542,12 +621,12 @@ export const FeedDocument = gql`
answers_count
comments {
id
created_at
createdAt
body
author {
id
name
image
avatar
}
}
}
@@ -570,7 +649,7 @@ export const FeedDocument = gql`
* take: // value for 'take'
* skip: // value for 'skip'
* sortBy: // value for 'sortBy'
* category: // value for 'category'
* topic: // value for 'topic'
* },
* });
*/
@@ -591,11 +670,11 @@ export const PostDetailsDocument = gql`
... on Story {
id
title
date
createdAt
author {
id
name
image
avatar
}
body
tags {
@@ -608,25 +687,25 @@ export const PostDetailsDocument = gql`
comments_count
comments {
id
created_at
createdAt
body
votes_count
parentId
author {
id
name
image
avatar
}
}
}
... on Bounty {
id
title
date
createdAt
author {
id
name
image
avatar
}
body
tags {
@@ -646,18 +725,18 @@ export const PostDetailsDocument = gql`
author {
id
name
image
avatar
}
}
}
... on Question {
id
title
date
createdAt
author {
id
name
image
avatar
}
body
tags {
@@ -669,14 +748,14 @@ export const PostDetailsDocument = gql`
answers_count
comments {
id
created_at
createdAt
body
votes_count
parentId
author {
id
name
image
avatar
}
}
}

View File

@@ -1,7 +1,7 @@
import { random, randomItem, randomItems } from "src/utils/helperFunctions"
import { getCoverImage } from "./utils"
const topics = [
export const topics = [
{
id: 1,
title: '🎨 Design'

View File

@@ -4,13 +4,14 @@ import { Bounty, Post, Question, Story } from "src/features/Posts/types";
import { random, randomItem } from "src/utils/helperFunctions";
import { getAvatarImage, getCoverImage } from "./utils";
import { Chance } from 'chance'
import { topics } from "./hackathon";
const getDate = () => dayjs().subtract(random(5, 48), 'hour').toString();
const getAuthor = () => ({
id: 12,
name: "John Doe",
image: getAvatarImage(),
avatar: getAvatarImage(),
join_date: getDate()
})
@@ -23,7 +24,7 @@ export const generatePostComments = (cnt: number = 1): Story['comments'] => {
const comment = {
id: i + 1,
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nisi, at ut sit id. Vulputate aliquet aliquam penatibus ac, et dictum est etiam. Sagittis odio dui sed viverra donec rutrum iaculis vitae morbi.",
created_at: getDate(),
createdAt: getDate(),
author: getAuthor(),
votes_count: 123,
parentId
@@ -85,7 +86,7 @@ export let posts = {
body: postBody,
cover_image: getCoverImage(),
comments_count: 3,
date: getDate(),
createdAt: getDate(),
votes_count: 120,
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
type: "Story",
@@ -96,6 +97,7 @@ export let posts = {
],
author: getAuthor(),
comments: generatePostComments(3),
topic: randomItem(...topics)
},
] as Story[],
@@ -107,7 +109,7 @@ export let posts = {
body: postBody,
cover_image: getCoverImage(),
applicants_count: 31,
date: getDate(),
createdAt: getDate(),
votes_count: 120,
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
tags: [
@@ -129,7 +131,7 @@ export let posts = {
title: 'Digital Editor, Mars Review of Books',
body: postBody,
answers_count: 3,
date: getDate(),
createdAt: getDate(),
votes_count: 70,
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
tags: [

View File

@@ -106,7 +106,7 @@ export const handlers = [
const { take, skip } = req.variables;
return res(
ctx.data({
getFeed: getFeed({ take, skip })
getFeed: getFeed({ take, skip, })
})
)
}),

View File

@@ -11,9 +11,8 @@ body {
}
.page-container {
width: 98%;
width: calc(min(100% - 64px, 1440px));
margin: 0 auto;
max-width: 1440px;
}
svg {

View File

@@ -50,7 +50,7 @@ export const apolloClient = new ApolloClient({
typePolicies: {
Query: {
fields: {
getFeed: offsetLimitPagination(['sortBy', 'category'])
getFeed: offsetLimitPagination(['sortBy', 'topic'])
},
},
},