[resumes][feat] fetch comments from database (#320)
* [resumes][feat] Add resume-comments type * [resumes][feat] Add resume-comments type * [resumes][feat] Filter comments * [resumes][feat] Add comments render * [resumes][refactor] rename variables * [resumes][refactor] update invalidateQueries * [resumes][refactor] Use resumeId in [resumeId].tsx * [resumes][fix] fix invalidateQuery Co-authored-by: Terence Ho <>pull/326/head
parent
b37aae2154
commit
d9880dbff1
@ -0,0 +1,18 @@
|
||||
import CommentBody from './CommentBody';
|
||||
import CommentCard from './CommentCard';
|
||||
|
||||
import type { ResumeComment } from '~/types/resume-comments';
|
||||
|
||||
type CommentProps = {
|
||||
comment: ResumeComment;
|
||||
userId?: string;
|
||||
};
|
||||
|
||||
export default function Comment({ comment, userId }: CommentProps) {
|
||||
const isCommentOwner = userId === comment.user.userId;
|
||||
return (
|
||||
<CommentCard isCommentOwner={isCommentOwner}>
|
||||
<CommentBody comment={comment} isCommentOwner={isCommentOwner} />
|
||||
</CommentCard>
|
||||
);
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
import {
|
||||
ArrowDownCircleIcon,
|
||||
ArrowUpCircleIcon,
|
||||
} from '@heroicons/react/20/solid';
|
||||
import { FaceSmileIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
import type { ResumeComment } from '~/types/resume-comments';
|
||||
|
||||
type CommentBodyProps = {
|
||||
comment: ResumeComment;
|
||||
isCommentOwner?: boolean;
|
||||
};
|
||||
|
||||
export default function CommentBody({
|
||||
comment,
|
||||
isCommentOwner,
|
||||
}: CommentBodyProps) {
|
||||
return (
|
||||
<div className="flex w-full flex-row space-x-2 p-1 align-top">
|
||||
{comment.user.image ? (
|
||||
<img
|
||||
alt={comment.user.name ?? 'Reviewer'}
|
||||
className="mt-1 h-8 w-8 rounded-full"
|
||||
src={comment.user.image!}
|
||||
/>
|
||||
) : (
|
||||
<FaceSmileIcon className="h-8 w-8 rounded-full" />
|
||||
)}
|
||||
|
||||
<div className="flex w-full flex-col space-y-1">
|
||||
{/* Name and creation time */}
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="font-medium">
|
||||
{comment.user.name ?? 'Reviewer ABC'}
|
||||
</div>
|
||||
<div className="text-xs text-gray-600">
|
||||
{comment.createdAt.toLocaleString('en-US', {
|
||||
dateStyle: 'medium',
|
||||
timeStyle: 'short',
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="text-sm">{comment.description}</div>
|
||||
|
||||
{/* Upvote and edit */}
|
||||
<div className="flex flex-row space-x-1 pt-1 align-middle">
|
||||
{/* TODO: Implement upvote */}
|
||||
<ArrowUpCircleIcon className="h-4 w-4 fill-gray-400" />
|
||||
<div className="text-xs">{comment.numVotes}</div>
|
||||
<ArrowDownCircleIcon className="h-4 w-4 fill-gray-400" />
|
||||
|
||||
{/* TODO: Implement edit */}
|
||||
{isCommentOwner ? (
|
||||
<div className="text-primary-800 hover:text-primary-400 px-1 text-xs">
|
||||
Edit
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
type CommentCardProps = {
|
||||
children: ReactNode;
|
||||
isCommentOwner?: boolean;
|
||||
};
|
||||
|
||||
export default function CommentCard({
|
||||
isCommentOwner,
|
||||
children,
|
||||
}: CommentCardProps) {
|
||||
// Used two different <div> to allow customisation of owner comments
|
||||
return isCommentOwner ? (
|
||||
<div className="border-primary-300 float-right w-3/4 rounded-md border-2 bg-white p-2 drop-shadow-md">
|
||||
{children}
|
||||
</div>
|
||||
) : (
|
||||
<div className="border-primary-300 float-left w-3/4 rounded-md border-2 bg-white p-2 drop-shadow-md">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import type { ResumesSection } from '@prisma/client';
|
||||
|
||||
/**
|
||||
* Returned by `resumeReviewsRouter` (query for 'resumes.reviews.list') and received as prop by `Comment` in `CommentsList`
|
||||
* frontend-friendly representation of the query
|
||||
*/
|
||||
export type ResumeComment = {
|
||||
createdAt: Date;
|
||||
description: string;
|
||||
hasVoted: boolean;
|
||||
id: string;
|
||||
numVotes: number;
|
||||
resumeId: string;
|
||||
section: ResumesSection;
|
||||
updatedAt: Date;
|
||||
user: {
|
||||
image: string?;
|
||||
name: string?;
|
||||
userId: string;
|
||||
};
|
||||
};
|
Loading…
Reference in new issue