feat: comment card component, update post comments api fields

This commit is contained in:
MTG2000
2022-04-25 19:02:58 +03:00
parent 123374d844
commit 2b0d2c174c
12 changed files with 144 additions and 64 deletions

View File

@@ -72,8 +72,10 @@ export interface NexusGenObjects {
PostComment: { // root type
author: NexusGenRootTypes['User']; // User!
body: string; // String!
date: string; // String!
created_at: string; // String!
id: number; // Int!
parentId: number; // Int!
votes_count: number; // Int!
}
Project: { // root type
cover_image: string; // String!
@@ -195,8 +197,10 @@ export interface NexusGenFieldTypes {
PostComment: { // field return type
author: NexusGenRootTypes['User']; // User!
body: string; // String!
date: string; // String!
created_at: string; // String!
id: number; // Int!
parentId: number; // Int!
votes_count: number; // Int!
}
Project: { // field return type
awards: NexusGenRootTypes['Award'][]; // [Award!]!
@@ -335,8 +339,10 @@ export interface NexusGenFieldTypeNames {
PostComment: { // field return type name
author: 'User'
body: 'String'
date: 'String'
created_at: 'String'
id: 'Int'
parentId: 'Int'
votes_count: 'Int'
}
Project: { // field return type name
awards: 'Award'

View File

@@ -78,8 +78,10 @@ interface PostBase {
type PostComment {
author: User!
body: String!
date: String!
created_at: String!
id: Int!
parentId: Int!
votes_count: Int!
}
type Project {

View File

@@ -102,11 +102,13 @@ const PostComment = objectType({
name: 'PostComment',
definition(t) {
t.nonNull.int('id');
t.nonNull.string('date');
t.nonNull.string('created_at');
t.nonNull.string('body');
t.nonNull.field('author', {
type: "User"
});
t.nonNull.int('parentId');
t.nonNull.int('votes_count');
}
})

View File

@@ -0,0 +1,22 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { MOCK_DATA } from 'src/mocks/data';
import CommentCard from './CommentCard';
export default {
title: 'Posts/Components/CommentCard',
component: CommentCard,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof CommentCard>;
const Template: ComponentStory<typeof CommentCard> = (args) => <div className="max-w-[70ch]"><CommentCard {...args} ></CommentCard></div>
export const Default = Template.bind({});
Default.args = {
comment: MOCK_DATA.posts.stories[0].comments[0]
}

View File

@@ -0,0 +1,32 @@
import { BiComment } from "react-icons/bi";
import Button from "src/Components/Button/Button";
import VotesCount from "src/Components/VotesCount/VotesCount";
import { Author } from "../../types"
import Header from "../PostCard/Header/Header";
interface Comment {
author: Author
created_at: string
body: string;
votes_count: number
}
interface Props {
comment: Comment
}
export default function CommentCard({ comment }: Props) {
return (
<div className="border rounded-12 p-24">
<Header author={comment.author} date={comment.created_at} />
<p className="text-body4 mt-16">
{comment.body}
</p>
<div className="flex gap-24 mt-16 items-center">
<VotesCount count={comment.votes_count} />
<button className="text-gray-600 font-medium hover:bg-gray-100 py-8 px-12 rounded-8">
<BiComment /> <span className="align-middle text-body5">Reply</span>
</button>
</div>
</div>
)
}

View File

@@ -30,16 +30,22 @@ export default function Header({
showTimeAgo = true,
...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');
return (
<div className='flex gap-8'>
<Avatar width={avatarSize[size]} src={props.author.image} />
<div>
<p className={`${nameSize[size]} text-black font-medium`}>{props.author.name}</p>
<p className={`text-body6 text-gray-600`}>{dayjs(props.date).format('MMMM DD')}</p>
<p className={`text-body6 text-gray-600`}>{dateToShow}</p>
</div>
{showTimeAgo && <p className={`${nameSize[size]} text-gray-500 ml-auto `}>
{/* {showTimeAgo && <p className={`${nameSize[size]} text-gray-500 ml-auto `}>
{dayjs().diff(props.date, 'hour') < 24 ? `${dayjs().diff(props.date, 'hour')}h ago` : undefined}
</p>}
</p>} */}
</div>
)
}

View File

@@ -4,6 +4,7 @@ import Header from "../Header/Header"
import { FiUsers } from "react-icons/fi"
import Badge from "src/Components/Badge/Badge"
import { Link } from "react-router-dom"
import { trimText } from "src/utils/helperFunctions"
export type QuestionCardType = Pick<Question,
| 'id'
@@ -15,8 +16,14 @@ export type QuestionCardType = Pick<Question,
| 'votes_count'
| "tags"
| "answers_count"
| "comments"
>;
> & {
comments: Array<Pick<Question['comments'][number],
| 'id'
| 'author'
| 'body'
| 'created_at'
>>
};
interface Props {
question: QuestionCardType
}
@@ -52,9 +59,9 @@ 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.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.date} />
<p className="text-body5 text-gray-600 mt-8">{comment.body}</p>
{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} />
<p className="text-body5 text-gray-600 mt-8">{trimText(comment.body, 80)}</p>
</div>)}
</div>

View File

@@ -59,7 +59,7 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
answers_count
comments {
id
date
created_at
body
author {
id

View File

@@ -20,7 +20,7 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
comments_count
comments {
id
date
created_at
body
author {
id
@@ -79,7 +79,7 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
answers_count
comments {
id
date
created_at
body
author {
id

View File

@@ -5,7 +5,7 @@ export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
const defaultOptions = {}
const defaultOptions = {} as const;
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: string;
@@ -110,8 +110,10 @@ export type PostComment = {
__typename?: 'PostComment';
author: User;
body: Scalars['String'];
date: Scalars['String'];
created_at: Scalars['String'];
id: Scalars['Int'];
parentId: Scalars['Int'];
votes_count: Scalars['Int'];
};
export type Project = {
@@ -265,7 +267,7 @@ export type Vote = {
export type NavCategoriesQueryVariables = Exact<{ [key: string]: never; }>;
export type NavCategoriesQuery = { __typename?: 'Query', allCategories: Array<{ __typename?: 'Category', id: number, title: string, icon: string | null | undefined, votes_sum: number }> };
export type NavCategoriesQuery = { __typename?: 'Query', allCategories: Array<{ __typename?: 'Category', id: number, title: string, icon: string | null, votes_sum: number }> };
export type SearchProjectsQueryVariables = Exact<{
search: Scalars['String'];
@@ -287,7 +289,7 @@ export type FeedQueryVariables = Exact<{
}>;
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, 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, 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 PostDetailsQueryVariables = Exact<{
id: Scalars['Int'];
@@ -295,14 +297,14 @@ 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, date: string, body: string, 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, date: string, body: string, author: { __typename?: 'User', id: number, name: string, image: string } }> } };
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, 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, author: { __typename?: 'User', id: number, name: string, image: string } }> } };
export type CategoryPageQueryVariables = Exact<{
categoryId: Scalars['Int'];
}>;
export type CategoryPageQuery = { __typename?: 'Query', projectsByCategory: Array<{ __typename?: 'Project', id: number, thumbnail_image: string, title: string, votes_count: number, category: { __typename?: 'Category', title: string, id: number } }>, getCategory: { __typename?: 'Category', id: number, title: string, cover_image: string | null | undefined, apps_count: number } };
export type CategoryPageQuery = { __typename?: 'Query', projectsByCategory: Array<{ __typename?: 'Project', id: number, thumbnail_image: string, title: string, votes_count: number, category: { __typename?: 'Category', title: string, id: number } }>, getCategory: { __typename?: 'Category', id: number, title: string, cover_image: string | null, apps_count: number } };
export type AllCategoriesQueryVariables = Exact<{ [key: string]: never; }>;
@@ -324,7 +326,7 @@ export type ProjectDetailsQueryVariables = Exact<{
}>;
export type ProjectDetailsQuery = { __typename?: 'Query', getProject: { __typename?: 'Project', id: number, title: string, description: string, cover_image: string, thumbnail_image: string, screenshots: Array<string>, website: string, lightning_address: string | null | undefined, lnurl_callback_url: string | null | undefined, votes_count: number, category: { __typename?: 'Category', id: number, title: string }, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } };
export type ProjectDetailsQuery = { __typename?: 'Query', getProject: { __typename?: 'Project', id: number, title: string, description: string, cover_image: string, thumbnail_image: string, screenshots: Array<string>, website: string, lightning_address: string | null, lnurl_callback_url: string | null, votes_count: number, category: { __typename?: 'Category', id: number, title: string }, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } };
export type VoteMutationVariables = Exact<{
projectId: Scalars['Int'];
@@ -540,7 +542,7 @@ export const FeedDocument = gql`
answers_count
comments {
id
date
created_at
body
author {
id
@@ -606,7 +608,7 @@ export const PostDetailsDocument = gql`
comments_count
comments {
id
date
created_at
body
author {
id
@@ -665,7 +667,7 @@ export const PostDetailsDocument = gql`
answers_count
comments {
id
date
created_at
body
author {
id

View File

@@ -1,32 +1,45 @@
import dayjs from "dayjs";
import { Bounty, Post, Question, Story } from "src/features/Posts/types";
import { randomItem } from "src/utils/helperFunctions";
import { random, randomItem } from "src/utils/helperFunctions";
import { getAvatarImage, getCoverImage } from "./utils";
import chance, { Chance } from 'chance'
const date = dayjs().subtract(5, 'hour').toString();
import { Chance } from 'chance'
const getDate = () => dayjs().subtract(random(5, 48), 'hour').toString();
const getAuthor = () => ({
id: 12,
name: "John Doe",
image: getAvatarImage(),
join_date: date
join_date: getDate()
})
const getPostComments = (cnt: number = 1): Story['comments'] => Array(cnt).fill(0).map((_, idx) => ({
id: idx + 1,
body: "This is a comment " + idx + 1,
date,
author: getAuthor()
}))
const getPostComments = (cnt: number = 1): Story['comments'] => {
let comments = [];
const rootCommentsIds: any[] = []
for (let i = 0; i < cnt; i++) {
const parentId = Math.random() < .4 ? 0 : rootCommentsIds.length ? randomItem(...rootCommentsIds) : 0;
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(),
author: getAuthor(),
votes_count: 123,
parentId
}
comments.push(comment);
if (!parentId)
rootCommentsIds.push(comment.id);
}
return comments;
}
const getApplications = (cnt: number = 1): Bounty['applications'] => Array(cnt).fill(0).map((_, idx) => ({
id: idx + 1,
workplan: "I Plan to build this using React, Ts, Redux, and Storybook.",
date,
date: getDate(),
author: getAuthor(),
}))
@@ -72,7 +85,7 @@ export let posts = {
body: postBody,
cover_image: getCoverImage(),
comments_count: 31,
date,
date: getDate(),
votes_count: 120,
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
type: "Story",
@@ -94,7 +107,7 @@ export let posts = {
body: postBody,
cover_image: getCoverImage(),
applicants_count: 31,
date,
date: getDate(),
votes_count: 120,
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
tags: [
@@ -116,7 +129,7 @@ export let posts = {
title: 'Digital Editor, Mars Review of Books',
body: postBody,
answers_count: 31,
date,
date: getDate(),
votes_count: 70,
excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...',
tags: [
@@ -124,20 +137,7 @@ export let posts = {
{ id: 2, title: "webln" },
],
author: getAuthor(),
comments: [
{
id: 1,
author: getAuthor(),
date,
body: 'Naw, Im 42 and know people who started in their 50s, you got this!'
},
{
id: 2,
author: getAuthor(),
date,
body: 'Naw, Im 42 and know people who started in their 50s, you got this!'
},
]
comments: getPostComments(3)
},
] as Question[]
}
@@ -154,8 +154,11 @@ export const feed: Post[] = Array(30).fill(0).map((_, idx) => {
const post = feedRandomer.pickone([posts.bounties[0], posts.questions[0], posts.stories[0]])
return {
...post, id: idx + 1, title: feedRandomer.sentence({
...post,
id: idx + 1,
title: feedRandomer.sentence({
words: feedRandomer.integer({ min: 4, max: 7 })
})
}),
date: getDate(),
}
})

View File

@@ -52,11 +52,9 @@ export function lazyModal<T extends ComponentType<any>>
<C direction={!LoadingComponent && direction} {...props} />
</Suspense>
// type ThenArg<T> = T extends PromiseLike<infer U> ? U : T
// type y = ThenArg<ReturnType<typeof x>>
// type yy = ComponentProps<y['default']>
return { LazyComponent, preload };
}
export function trimText(text: string, length: number) {
return text.slice(0, length) + (text.length > length ? "..." : "")
}