[questions][ui] add comments & commments page

pull/346/head
wlren 3 years ago
parent 2680f7fec6
commit 685f5483f6

@ -0,0 +1,38 @@
import { format } from 'date-fns';
import VotingButtons from './VotingButtons';
export type CommentListItemProps = {
authorImageUrl: string;
authorName: string;
content: string;
createdAt: Date;
upvoteCount: number;
};
export default function CommentListItem({
authorImageUrl,
authorName,
content,
createdAt,
upvoteCount,
}: CommentListItemProps) {
return (
<div className="flex gap-4 border bg-white p-2 ">
<VotingButtons size="sm" upvoteCount={upvoteCount} />
<div className="mt-1 flex flex-col gap-1">
<div className="flex items-center gap-2">
<img
alt={`${authorName} profile picture`}
className="h-8 w-8 rounded-full"
src={authorImageUrl}></img>
<h1 className="font-bold">{authorName}</h1>
<p className="pt-1 text-xs font-extralight">
Posted on: {format(createdAt, 'Pp')}
</p>
</div>
<p className="pl-1 pt-1">{content}</p>
</div>
</div>
);
}

@ -0,0 +1,38 @@
import { format } from 'date-fns';
import VotingButtons from '../VotingButtons';
export type FullAnswerCardProps = {
authorImageUrl: string;
authorName: string;
content: string;
createdAt: Date;
upvoteCount: number;
};
export default function FullAnswerCard({
authorImageUrl,
authorName,
content,
createdAt,
upvoteCount,
}: FullAnswerCardProps) {
return (
<article className="flex gap-4 rounded-md border border-slate-300 bg-white p-4">
<VotingButtons upvoteCount={upvoteCount}></VotingButtons>
<div className="mt-1 flex flex-col gap-1">
<div className="flex items-center gap-2">
<img
alt={`${authorName} profile picture`}
className="h-8 w-8 rounded-full"
src={authorImageUrl}></img>
<h1 className="font-bold">{authorName}</h1>
<p className="pt-1 text-xs font-extralight">
Posted on: {format(createdAt, 'Pp')}
</p>
</div>
<p className="pl-1 pt-1">{content}</p>
</div>
</article>
);
}

@ -1,39 +1,45 @@
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { ArrowSmallLeftIcon } from '@heroicons/react/24/outline'; import { ArrowSmallLeftIcon } from '@heroicons/react/24/outline';
import { Button, Collapsible, Select, TextArea } from '@tih/ui'; import { Button, Select, TextArea } from '@tih/ui';
import AnswerCard from '~/components/questions/card/AnswerCard'; import FullAnswerCard from '~/components/questions/card/FullAnswerCard';
import FullQuestionCard from '~/components/questions/card/FullQuestionCard'; import CommentListItem from '~/components/questions/CommentListItem';
import { SAMPLE_QUESTION } from '~/utils/questions/constants'; import {
SAMPLE_ANSWER,
SAMPLE_ANSWER_COMMENT,
SAMPLE_QUESTION,
} from '~/utils/questions/constants';
import { useFormRegister } from '~/utils/questions/useFormRegister'; import { useFormRegister } from '~/utils/questions/useFormRegister';
export type AnswerData = { export type AnswerCommentData = {
answerContent: string; commentContent: string;
}; };
export default function QuestionPage() { export default function QuestionPage() {
const router = useRouter(); const router = useRouter();
const { const {
register: formRegister, register: comRegister,
handleSubmit, handleSubmit: handleCommentSubmit,
formState: { isDirty, isValid }, formState: { isDirty: isCommentDirty, isValid: isCommentValid },
} = useForm<AnswerData>({ mode: 'onChange' }); } = useForm<AnswerCommentData>({ mode: 'onChange' });
const register = useFormRegister(formRegister); const commentRegister = useFormRegister(comRegister);
const question = SAMPLE_QUESTION;
const question = SAMPLE_QUESTION;
const comment = SAMPLE_ANSWER_COMMENT;
const handleBackNavigation = () => { const handleBackNavigation = () => {
router.back(); router.back();
}; };
const handleSubmitAnswer = (data: AnswerData) => { const handleSubmitComment = (data: AnswerCommentData) => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(data); console.log(data);
}; };
return ( return (
<div className="flex"> <div className="flex w-full flex-1 items-stretch pb-4">
<div className="flex items-baseline gap-2 py-4 pl-4"> <div className="flex items-baseline gap-2 py-4 pl-4">
<Button <Button
addonPosition="start" addonPosition="start"
@ -43,71 +49,66 @@ export default function QuestionPage() {
variant="secondary" variant="secondary"
onClick={handleBackNavigation}></Button> onClick={handleBackNavigation}></Button>
</div> </div>
<div className="flex flex-col items-center overflow-y-auto py-4 px-5"> <div className="flex w-full justify-center overflow-y-auto py-4 px-5">
<div className="flex max-w-7xl flex-col gap-2"> <div className="flex max-w-7xl flex-1 flex-col gap-2">
<FullQuestionCard {...question} showVoteButtons={true} /> <FullAnswerCard {...SAMPLE_ANSWER} />
<div className="mx-2"> <div className="mx-2">
<Collapsible label="256 comments"> <form
<div>Comment placeholder</div> className="mb-2"
</Collapsible> onSubmit={handleCommentSubmit(handleSubmitComment)}>
</div> <TextArea
<form onSubmit={handleSubmit(handleSubmitAnswer)}> {...commentRegister('commentContent', {
<TextArea minLength: 1,
{...register('answerContent', { minLength: 1, required: true })} required: true,
label="Contribute your answer" })}
required={true} label="Post a comment"
resize="vertical" required={true}
rows={5} resize="vertical"
/> rows={2}
<div className="mt-2 flex justify-end">
<Button
disabled={!isDirty || !isValid}
label="Contribute"
type="submit"
variant="primary"
/> />
</div> <div className="my-3 flex justify-between">
</form> <div className="flex items-baseline gap-2">
<div className="my-2 flex items-baseline justify-between"> <span aria-hidden={true} className="text-sm">
<p>{question.answerCount} answers</p> Sort by:
<div className="flex items-baseline gap-2"> </span>
<span aria-hidden={true} className="text-sm"> <Select
Sort by: display="inline"
</span> isLabelHidden={true}
<Select label="Sort by"
display="inline" options={[
isLabelHidden={true} {
label="Sort by" label: 'Most recent',
options={[ value: 'most-recent',
{ },
label: 'Most recent', {
value: 'most-recent', label: 'Most upvotes',
}, value: 'most-upvotes',
{ },
label: 'Most upvotes', ]}
value: 'most-upvotes', value="most-recent"
}, onChange={(value) => {
]} // eslint-disable-next-line no-console
value="most-recent" console.log(value);
onChange={(value) => { }}></Select>
// eslint-disable-next-line no-console </div>
console.log(value);
}}></Select> <Button
</div> disabled={!isCommentDirty || !isCommentValid}
</div> label="Post"
type="submit"
variant="primary"
/>
</div>
</form>
{Array.from({ length: question.answerCount }).map((_, index) => ( {Array.from({ length: question.commentCount }).map((_, index) => (
<AnswerCard <CommentListItem
// eslint-disable-next-line react/no-array-index-key // eslint-disable-next-line react/no-array-index-key
key={index} key={index}
authorImageUrl="https://avatars.githubusercontent.com/u/66356390?v=4" {...comment}
authorName="James Smith" />
content="Hello" ))}
createdAt={new Date()} </div>
href={`${router.asPath}/answer/1/1`}
upvoteCount={10}
/>
))}
</div> </div>
</div> </div>
</div> </div>

@ -5,24 +5,41 @@ import { Button, Collapsible, Select, TextArea } from '@tih/ui';
import AnswerCard from '~/components/questions/card/AnswerCard'; import AnswerCard from '~/components/questions/card/AnswerCard';
import FullQuestionCard from '~/components/questions/card/FullQuestionCard'; import FullQuestionCard from '~/components/questions/card/FullQuestionCard';
import CommentListItem from '~/components/questions/CommentListItem';
import { SAMPLE_QUESTION } from '~/utils/questions/constants'; import {
SAMPLE_ANSWER,
SAMPLE_QUESTION,
SAMPLE_QUESTION_COMMENT,
} from '~/utils/questions/constants';
import { useFormRegister } from '~/utils/questions/useFormRegister'; import { useFormRegister } from '~/utils/questions/useFormRegister';
export type AnswerQuestionData = { export type AnswerQuestionData = {
answerContent: string; answerContent: string;
}; };
export type QuestionCommentData = {
commentContent: string;
};
export default function QuestionPage() { export default function QuestionPage() {
const router = useRouter(); const router = useRouter();
const { const {
register: formRegister, register: ansRegister,
handleSubmit, handleSubmit,
formState: { isDirty, isValid }, formState: { isDirty, isValid },
} = useForm<AnswerQuestionData>({ mode: 'onChange' }); } = useForm<AnswerQuestionData>({ mode: 'onChange' });
const register = useFormRegister(formRegister); const answerRegister = useFormRegister(ansRegister);
const question = SAMPLE_QUESTION;
const {
register: comRegister,
handleSubmit: handleCommentSubmit,
formState: { isDirty: isCommentDirty, isValid: isCommentValid },
} = useForm<QuestionCommentData>({ mode: 'onChange' });
const commentRegister = useFormRegister(comRegister);
const question = SAMPLE_QUESTION;
const comment = SAMPLE_QUESTION_COMMENT;
const handleBackNavigation = () => { const handleBackNavigation = () => {
router.back(); router.back();
}; };
@ -32,8 +49,13 @@ export default function QuestionPage() {
console.log(data); console.log(data);
}; };
const handleSubmitComment = (data: QuestionCommentData) => {
// eslint-disable-next-line no-console
console.log(data);
};
return ( return (
<div className="flex"> <div className="flex w-full flex-1 items-stretch pb-4">
<div className="flex items-baseline gap-2 py-4 pl-4"> <div className="flex items-baseline gap-2 py-4 pl-4">
<Button <Button
addonPosition="start" addonPosition="start"
@ -43,23 +65,107 @@ export default function QuestionPage() {
variant="secondary" variant="secondary"
onClick={handleBackNavigation}></Button> onClick={handleBackNavigation}></Button>
</div> </div>
<div className="flex flex-col items-center overflow-y-auto py-4 px-5"> <div className="flex w-full justify-center overflow-y-auto py-4 px-5">
<div className="flex max-w-7xl flex-col gap-2"> <div className="flex max-w-7xl flex-1 flex-col gap-2">
<FullQuestionCard {...question} showVoteButtons={true} /> <FullQuestionCard {...question} showVoteButtons={true} />
<div className="mx-2"> <div className="mx-2">
<Collapsible label="256 comments"> <Collapsible label={`${question.commentCount} comment(s)`}>
<div>Comment placeholder</div> <form
className="mb-2"
onSubmit={handleCommentSubmit(handleSubmitComment)}>
<TextArea
{...commentRegister('commentContent', {
minLength: 1,
required: true,
})}
label="Post a comment"
required={true}
resize="vertical"
rows={2}
/>
<div className="my-3 flex justify-between">
<div className="flex items-baseline gap-2">
<span aria-hidden={true} className="text-sm">
Sort by:
</span>
<Select
display="inline"
isLabelHidden={true}
label="Sort by"
options={[
{
label: 'Most recent',
value: 'most-recent',
},
{
label: 'Most upvotes',
value: 'most-upvotes',
},
]}
value="most-recent"
onChange={(value) => {
// eslint-disable-next-line no-console
console.log(value);
}}></Select>
</div>
<Button
disabled={!isCommentDirty || !isCommentValid}
label="Post"
type="submit"
variant="primary"
/>
</div>
</form>
{Array.from({ length: question.commentCount }).map((_, index) => (
<CommentListItem
// eslint-disable-next-line react/no-array-index-key
key={index}
{...comment}
/>
))}
</Collapsible> </Collapsible>
</div> </div>
<form onSubmit={handleSubmit(handleSubmitAnswer)}> <form onSubmit={handleSubmit(handleSubmitAnswer)}>
<TextArea <TextArea
{...register('answerContent', { minLength: 1, required: true })} {...answerRegister('answerContent', {
minLength: 1,
required: true,
})}
label="Contribute your answer" label="Contribute your answer"
required={true} required={true}
resize="vertical" resize="vertical"
rows={5} rows={5}
/> />
<div className="mt-2 flex justify-end"> <div className="mt-3 mb-1 flex justify-between">
<div className="flex items-baseline justify-start gap-2">
<p>{question.answerCount} answers</p>
<div className="flex items-baseline gap-2">
<span aria-hidden={true} className="text-sm">
Sort by:
</span>
<Select
display="inline"
isLabelHidden={true}
label="Sort by"
options={[
{
label: 'Most recent',
value: 'most-recent',
},
{
label: 'Most upvotes',
value: 'most-upvotes',
},
]}
value="most-recent"
onChange={(value) => {
// eslint-disable-next-line no-console
console.log(value);
}}></Select>
</div>
</div>
<Button <Button
disabled={!isDirty || !isValid} disabled={!isDirty || !isValid}
label="Contribute" label="Contribute"
@ -68,44 +174,13 @@ export default function QuestionPage() {
/> />
</div> </div>
</form> </form>
<div className="my-2 flex items-baseline justify-between">
<p>{question.answerCount} answers</p>
<div className="flex items-baseline gap-2">
<span aria-hidden={true} className="text-sm">
Sort by:
</span>
<Select
display="inline"
isLabelHidden={true}
label="Sort by"
options={[
{
label: 'Most recent',
value: 'most-recent',
},
{
label: 'Most upvotes',
value: 'most-upvotes',
},
]}
value="most-recent"
onChange={(value) => {
// eslint-disable-next-line no-console
console.log(value);
}}></Select>
</div>
</div>
{Array.from({ length: question.answerCount }).map((_, index) => ( {Array.from({ length: question.answerCount }).map((_, index) => (
<AnswerCard <AnswerCard
// eslint-disable-next-line react/no-array-index-key // eslint-disable-next-line react/no-array-index-key
key={index} key={index}
authorImageUrl="https://avatars.githubusercontent.com/u/66356390?v=4" {...SAMPLE_ANSWER}
authorName="James Smith"
content="Hello"
createdAt={new Date()}
href={`${router.asPath}/answer/1/1`} href={`${router.asPath}/answer/1/1`}
upvoteCount={10}
/> />
))} ))}
</div> </div>

Loading…
Cancel
Save