[resumes][refactor] prefix comments section with Resume

pull/363/head
Terence Ho 3 years ago
parent 701ccce5ae
commit e7bcd18cc5

@ -1,35 +0,0 @@
import { useSession } from 'next-auth/react';
import { Spinner } from '@tih/ui';
import Comment from './comment/Comment';
import type { ResumeComment } from '~/types/resume-comments';
type Props = Readonly<{
comments: Array<ResumeComment>;
isLoading: boolean;
}>;
export default function CommentListItems({ comments, isLoading }: Props) {
const { data: session } = useSession();
if (isLoading) {
return (
<div className="col-span-10 pt-4">
<Spinner display="block" size="lg" />
</div>
);
}
return (
<div className="m-2 flow-root h-[calc(100vh-20rem)] w-full flex-col space-y-3 overflow-y-auto">
{comments.map((comment) => (
<Comment
key={comment.id}
comment={comment}
userId={session?.user?.id}
/>
))}
</div>
);
}

@ -1,54 +0,0 @@
import { useSession } from 'next-auth/react';
import { useState } from 'react';
import { Tabs } from '@tih/ui';
import { Button } from '@tih/ui';
import { trpc } from '~/utils/trpc';
import CommentListItems from './CommentListItems';
import { COMMENTS_SECTIONS } from './constants';
import ResumeSignInButton from '../shared/ResumeSignInButton';
type CommentsListProps = Readonly<{
resumeId: string;
setShowCommentsForm: (show: boolean) => void;
}>;
export default function CommentsList({
resumeId,
setShowCommentsForm,
}: CommentsListProps) {
const { data: sessionData } = useSession();
const [tab, setTab] = useState(COMMENTS_SECTIONS[0].value);
const commentsQuery = trpc.useQuery(['resumes.reviews.list', { resumeId }]);
const renderButton = () => {
if (sessionData === null) {
return <ResumeSignInButton text="to join discussion" />;
}
return (
<Button
display="block"
label="Add your review"
variant="tertiary"
onClick={() => setShowCommentsForm(true)}
/>
);
};
return (
<div className="space-y-3">
{renderButton()}
<Tabs
label="comments"
tabs={COMMENTS_SECTIONS}
value={tab}
onChange={(value) => setTab(value)}
/>
<CommentListItems
comments={commentsQuery.data?.filter((c) => c.section === tab) ?? []}
isLoading={commentsQuery.isFetching}
/>
</div>
);
}

@ -5,7 +5,7 @@ import { Button, Dialog, TextArea } from '@tih/ui';
import { trpc } from '~/utils/trpc'; import { trpc } from '~/utils/trpc';
type CommentsFormProps = Readonly<{ type ResumeCommentsFormProps = Readonly<{
resumeId: string; resumeId: string;
setShowCommentsForm: (show: boolean) => void; setShowCommentsForm: (show: boolean) => void;
}>; }>;
@ -20,10 +20,10 @@ type IFormInput = {
type InputKeys = keyof IFormInput; type InputKeys = keyof IFormInput;
export default function CommentsForm({ export default function ResumeCommentsForm({
resumeId, resumeId,
setShowCommentsForm, setShowCommentsForm,
}: CommentsFormProps) { }: ResumeCommentsFormProps) {
const [showDialog, setShowDialog] = useState(false); const [showDialog, setShowDialog] = useState(false);
const { const {
register, register,

@ -0,0 +1,69 @@
import { useSession } from 'next-auth/react';
import { useState } from 'react';
import { Spinner, Tabs } from '@tih/ui';
import { Button } from '@tih/ui';
import { trpc } from '~/utils/trpc';
import ResumeCommentListItem from './comment/ResumeCommentListItem';
import { RESUME_COMMENTS_SECTIONS } from './resumeCommentConstants';
import ResumeSignInButton from '../shared/ResumeSignInButton';
type ResumeCommentsListProps = Readonly<{
resumeId: string;
setShowCommentsForm: (show: boolean) => void;
}>;
export default function ResumeCommentsList({
resumeId,
setShowCommentsForm,
}: ResumeCommentsListProps) {
const { data: sessionData } = useSession();
const [tab, setTab] = useState(RESUME_COMMENTS_SECTIONS[0].value);
const commentsQuery = trpc.useQuery(['resumes.reviews.list', { resumeId }]);
const renderButton = () => {
if (sessionData === null) {
return <ResumeSignInButton text="to join discussion" />;
}
return (
<Button
display="block"
label="Add your review"
variant="tertiary"
onClick={() => setShowCommentsForm(true)}
/>
);
};
return (
<div className="space-y-3">
{renderButton()}
<Tabs
label="comments"
tabs={RESUME_COMMENTS_SECTIONS}
value={tab}
onChange={(value) => setTab(value)}
/>
{commentsQuery.isFetching ? (
<div className="col-span-10 pt-4">
<Spinner display="block" size="lg" />
</div>
) : (
<div className="m-2 flow-root h-[calc(100vh-20rem)] w-full flex-col space-y-3 overflow-y-auto">
{(commentsQuery.data?.filter((c) => c.section === tab) ?? []).map(
(comment) => (
<ResumeCommentListItem
key={comment.id}
comment={comment}
userId={sessionData?.user?.id}
/>
),
)}
</div>
)}
</div>
);
}

@ -1,13 +1,15 @@
import { useState } from 'react'; import { useState } from 'react';
import CommentsForm from './CommentsForm'; import ResumeCommentsForm from './ResumeCommentsForm';
import CommentsList from './CommentsList'; import ResumeCommentsList from './ResumeCommentsList';
type ICommentsSectionProps = { type CommentsSectionProps = {
resumeId: string; resumeId: string;
}; };
export default function CommentsSection({ resumeId }: ICommentsSectionProps) { export default function ResumeCommentsSection({
resumeId,
}: CommentsSectionProps) {
const [showCommentsForm, setShowCommentsForm] = useState(false); const [showCommentsForm, setShowCommentsForm] = useState(false);
return ( return (
@ -23,12 +25,12 @@ export default function CommentsSection({ resumeId }: ICommentsSectionProps) {
</div> </div>
</div> </div>
{showCommentsForm ? ( {showCommentsForm ? (
<CommentsForm <ResumeCommentsForm
resumeId={resumeId} resumeId={resumeId}
setShowCommentsForm={setShowCommentsForm} setShowCommentsForm={setShowCommentsForm}
/> />
) : ( ) : (
<CommentsList <ResumeCommentsList
resumeId={resumeId} resumeId={resumeId}
setShowCommentsForm={setShowCommentsForm} setShowCommentsForm={setShowCommentsForm}
/> />

@ -1,18 +0,0 @@
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>
<CommentBody comment={comment} isCommentOwner={isCommentOwner} />
</CommentCard>
);
}

@ -4,19 +4,19 @@ import {
} from '@heroicons/react/20/solid'; } from '@heroicons/react/20/solid';
import { FaceSmileIcon } from '@heroicons/react/24/outline'; import { FaceSmileIcon } from '@heroicons/react/24/outline';
import CommentDescription from './CommentDescription'; import ResumeExpandableText from '../../shared/ResumeExpandableText';
import type { ResumeComment } from '~/types/resume-comments'; import type { ResumeComment } from '~/types/resume-comments';
type CommentBodyProps = { type ResumeCommentBodyProps = {
comment: ResumeComment; comment: ResumeComment;
isCommentOwner?: boolean; isCommentOwner?: boolean;
}; };
export default function CommentBody({ export default function ResumeCommentBody({
comment, comment,
isCommentOwner, isCommentOwner,
}: CommentBodyProps) { }: ResumeCommentBodyProps) {
return ( return (
<div className="flex w-full flex-row space-x-2 p-1 align-top"> <div className="flex w-full flex-row space-x-2 p-1 align-top">
{comment.user.image ? ( {comment.user.image ? (
@ -51,7 +51,7 @@ export default function CommentBody({
</div> </div>
{/* Description */} {/* Description */}
<CommentDescription>{comment.description}</CommentDescription> <ResumeExpandableText>{comment.description}</ResumeExpandableText>
{/* Upvote and edit */} {/* Upvote and edit */}
<div className="flex flex-row space-x-1 pt-1 align-middle"> <div className="flex flex-row space-x-1 pt-1 align-middle">

@ -1,10 +1,12 @@
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
type CommentCardProps = { type ResumeCommentCardProps = {
children: ReactNode; children: ReactNode;
}; };
export default function CommentCard({ children }: CommentCardProps) { export default function ResumeCommentCard({
children,
}: ResumeCommentCardProps) {
return ( return (
<div className="border-primary-300 w-3/4 rounded-md border-2 bg-white p-2 drop-shadow-md"> <div className="border-primary-300 w-3/4 rounded-md border-2 bg-white p-2 drop-shadow-md">
{children} {children}

@ -0,0 +1,21 @@
import ResumeCommentBody from './ResumeCommentBody';
import ResumeCommentCard from './ResumeCommentCard';
import type { ResumeComment } from '~/types/resume-comments';
type ResumeCommentListItemProps = {
comment: ResumeComment;
userId?: string;
};
export default function ResumeCommentListItem({
comment,
userId,
}: ResumeCommentListItemProps) {
const isCommentOwner = userId === comment.user.userId;
return (
<ResumeCommentCard>
<ResumeCommentBody comment={comment} isCommentOwner={isCommentOwner} />
</ResumeCommentCard>
);
}

@ -1,6 +1,6 @@
import { ResumesSection } from '@prisma/client'; import { ResumesSection } from '@prisma/client';
export const COMMENTS_SECTIONS = [ export const RESUME_COMMENTS_SECTIONS = [
{ {
label: 'General', label: 'General',
value: ResumesSection.GENERAL, value: ResumesSection.GENERAL,

@ -2,13 +2,13 @@ import clsx from 'clsx';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { useLayoutEffect, useRef, useState } from 'react'; import { useLayoutEffect, useRef, useState } from 'react';
type CommentDescriptionProps = Readonly<{ type ResumeExpandableTextProps = Readonly<{
children: ReactNode; children: ReactNode;
}>; }>;
export default function CommentDescription({ export default function ResumeExpandableText({
children, children,
}: CommentDescriptionProps) { }: ResumeExpandableTextProps) {
const ref = useRef<HTMLSpanElement>(null); const ref = useRef<HTMLSpanElement>(null);
const [descriptionExpanded, setDescriptionExpanded] = useState(false); const [descriptionExpanded, setDescriptionExpanded] = useState(false);
const [descriptionOverflow, setDescriptionOverflow] = useState(false); const [descriptionOverflow, setDescriptionOverflow] = useState(false);

@ -15,7 +15,7 @@ import {
} from '@heroicons/react/20/solid'; } from '@heroicons/react/20/solid';
import { Spinner } from '@tih/ui'; import { Spinner } from '@tih/ui';
import CommentsSection from '~/components/resumes/comments/CommentsSection'; import ResumeCommentsSection from '~/components/resumes/comments/ResumeCommentsSection';
import ResumePdf from '~/components/resumes/ResumePdf'; import ResumePdf from '~/components/resumes/ResumePdf';
import { trpc } from '~/utils/trpc'; import { trpc } from '~/utils/trpc';
@ -178,7 +178,7 @@ export default function ResumeReviewPage() {
<ResumePdf url={detailsQuery.data.url} /> <ResumePdf url={detailsQuery.data.url} />
</div> </div>
<div className="mx-8 grow"> <div className="mx-8 grow">
<CommentsSection resumeId={resumeId as string} /> <ResumeCommentsSection resumeId={resumeId as string} />
</div> </div>
</div> </div>
</main> </main>

Loading…
Cancel
Save