From 0666c991513882fdb68690da5738d3dddfadc06c Mon Sep 17 00:00:00 2001 From: Keane Chan <e0425601@u.nus.edu> Date: Sat, 15 Oct 2022 12:41:38 +0800 Subject: [PATCH] [resumes][feat] add isStarredByUser field to Resumes (#381) --- .../resumes/browse/ResumeListItem.tsx | 18 +++---------- .../resumes/browse/ResumeListItems.tsx | 4 +-- apps/portal/src/pages/resumes/[resumeId].tsx | 3 --- .../resumes/resumes-comments-user-router.ts | 2 +- .../router/resumes/resumes-resume-router.ts | 9 +++++++ .../resumes/resumes-resume-user-router.ts | 27 +++++++------------ apps/portal/src/types/resume.d.ts | 1 + 7 files changed, 26 insertions(+), 38 deletions(-) diff --git a/apps/portal/src/components/resumes/browse/ResumeListItem.tsx b/apps/portal/src/components/resumes/browse/ResumeListItem.tsx index 0d0a2756..b314376a 100644 --- a/apps/portal/src/components/resumes/browse/ResumeListItem.tsx +++ b/apps/portal/src/components/resumes/browse/ResumeListItem.tsx @@ -1,17 +1,14 @@ import formatDistanceToNow from 'date-fns/formatDistanceToNow'; import Link from 'next/link'; -import { useSession } from 'next-auth/react'; import type { UrlObject } from 'url'; -import { ChevronRightIcon } from '@heroicons/react/20/solid'; import { AcademicCapIcon, BriefcaseIcon, + ChevronRightIcon, StarIcon as ColouredStarIcon, } from '@heroicons/react/20/solid'; import { ChatBubbleLeftIcon, StarIcon } from '@heroicons/react/24/outline'; -import { trpc } from '~/utils/trpc'; - import type { Resume } from '~/types/resume'; type Props = Readonly<{ @@ -19,16 +16,7 @@ type Props = Readonly<{ resumeInfo: Resume; }>; -export default function BrowseListItem({ href, resumeInfo }: Props) { - const { data: sessionData } = useSession(); - - // Find out if user has starred this particular resume - const resumeId = resumeInfo.id; - const isStarredQuery = trpc.useQuery([ - 'resumes.resume.user.isResumeStarred', - { resumeId }, - ]); - +export default function ResumeListItem({ href, resumeInfo }: Props) { return ( <Link href={href}> <div className="grid grid-cols-8 gap-4 border-b border-slate-200 p-4 hover:bg-slate-100"> @@ -56,7 +44,7 @@ export default function BrowseListItem({ href, resumeInfo }: Props) { {resumeInfo.numComments} comments </div> <div className="flex gap-2"> - {isStarredQuery.data && sessionData?.user ? ( + {resumeInfo.isStarredByUser ? ( <ColouredStarIcon className="w-4 text-yellow-400" /> ) : ( <StarIcon className="w-4" /> diff --git a/apps/portal/src/components/resumes/browse/ResumeListItems.tsx b/apps/portal/src/components/resumes/browse/ResumeListItems.tsx index 1216e36b..07f61770 100644 --- a/apps/portal/src/components/resumes/browse/ResumeListItems.tsx +++ b/apps/portal/src/components/resumes/browse/ResumeListItems.tsx @@ -1,6 +1,6 @@ import { Spinner } from '@tih/ui'; -import ResumseListItem from './ResumeListItem'; +import ResumeListItem from './ResumeListItem'; import type { Resume } from '~/types/resume'; @@ -22,7 +22,7 @@ export default function ResumeListItems({ isLoading, resumes }: Props) { <ul role="list"> {resumes.map((resumeObj: Resume) => ( <li key={resumeObj.id}> - <ResumseListItem + <ResumeListItem href={`/resumes/${resumeObj.id}`} resumeInfo={resumeObj} /> diff --git a/apps/portal/src/pages/resumes/[resumeId].tsx b/apps/portal/src/pages/resumes/[resumeId].tsx index 611f0204..79fbd077 100644 --- a/apps/portal/src/pages/resumes/[resumeId].tsx +++ b/apps/portal/src/pages/resumes/[resumeId].tsx @@ -49,7 +49,6 @@ export default function ResumeReviewPage() { utils.invalidateQueries(['resumes.resume.findOne']); }, }); - const userIsOwner = session?.user?.id != null && session.user.id === detailsQuery.data?.userId; @@ -61,8 +60,6 @@ export default function ResumeReviewPage() { return; } - // Star button only rendered if resume exists - // Star button only clickable if user exists if (detailsQuery.data?.stars.length) { unstarMutation.mutate({ resumeId: resumeId as string, diff --git a/apps/portal/src/server/router/resumes/resumes-comments-user-router.ts b/apps/portal/src/server/router/resumes/resumes-comments-user-router.ts index 479c9390..0e083222 100644 --- a/apps/portal/src/server/router/resumes/resumes-comments-user-router.ts +++ b/apps/portal/src/server/router/resumes/resumes-comments-user-router.ts @@ -22,7 +22,7 @@ export const resumesCommentsUserRouter = createProtectedRouter().mutation( skills: z.string(), }), async resolve({ ctx, input }) { - const userId = ctx.session?.user?.id; + const userId = ctx.session.user.id; const { resumeId, education, experience, general, projects, skills } = input; diff --git a/apps/portal/src/server/router/resumes/resumes-resume-router.ts b/apps/portal/src/server/router/resumes/resumes-resume-router.ts index 34d7d6f0..4f5c33d8 100644 --- a/apps/portal/src/server/router/resumes/resumes-resume-router.ts +++ b/apps/portal/src/server/router/resumes/resumes-resume-router.ts @@ -7,6 +7,7 @@ import type { Resume } from '~/types/resume'; export const resumesRouter = createRouter() .query('findAll', { async resolve({ ctx }) { + const userId = ctx.session?.user?.id; const resumesData = await ctx.prisma.resumesResume.findMany({ include: { _count: { @@ -15,6 +16,13 @@ export const resumesRouter = createRouter() stars: true, }, }, + stars: { + where: { + OR: { + userId, + }, + }, + }, user: { select: { name: true, @@ -31,6 +39,7 @@ export const resumesRouter = createRouter() createdAt: r.createdAt, experience: r.experience, id: r.id, + isStarredByUser: r.stars.length > 0, location: r.location, numComments: r._count.comments, numStars: r._count.stars, diff --git a/apps/portal/src/server/router/resumes/resumes-resume-user-router.ts b/apps/portal/src/server/router/resumes/resumes-resume-user-router.ts index 366385ad..a61aa3ac 100644 --- a/apps/portal/src/server/router/resumes/resumes-resume-user-router.ts +++ b/apps/portal/src/server/router/resumes/resumes-resume-user-router.ts @@ -17,7 +17,7 @@ export const resumesResumeUserRouter = createProtectedRouter() url: z.string(), }), async resolve({ ctx, input }) { - const userId = ctx.session?.user.id; + const userId = ctx.session.user.id; return await ctx.prisma.resumesResume.upsert({ create: { @@ -46,7 +46,7 @@ export const resumesResumeUserRouter = createProtectedRouter() }) .query('findUserStarred', { async resolve({ ctx }) { - const userId = ctx.session?.user?.id; + const userId = ctx.session.user.id; const resumeStarsData = await ctx.prisma.resumesStar.findMany({ include: { resume: { @@ -78,6 +78,7 @@ export const resumesResumeUserRouter = createProtectedRouter() createdAt: rs.resume.createdAt, experience: rs.resume.experience, id: rs.resume.id, + isStarredByUser: true, location: rs.resume.location, numComments: rs.resume._count.comments, numStars: rs.resume._count.stars, @@ -92,7 +93,7 @@ export const resumesResumeUserRouter = createProtectedRouter() }) .query('findUserCreated', { async resolve({ ctx }) { - const userId = ctx.session?.user?.id; + const userId = ctx.session.user.id; const resumesData = await ctx.prisma.resumesResume.findMany({ include: { _count: { @@ -101,6 +102,11 @@ export const resumesResumeUserRouter = createProtectedRouter() stars: true, }, }, + stars: { + where: { + userId, + }, + }, user: { select: { name: true, @@ -120,6 +126,7 @@ export const resumesResumeUserRouter = createProtectedRouter() createdAt: r.createdAt, experience: r.experience, id: r.id, + isStarredByUser: r.stars.length > 0, location: r.location, numComments: r._count.comments, numStars: r._count.stars, @@ -131,18 +138,4 @@ export const resumesResumeUserRouter = createProtectedRouter() return resume; }); }, - }) - .query('isResumeStarred', { - input: z.object({ - resumeId: z.string(), - }), - async resolve({ ctx, input }) { - const userId = ctx.session?.user?.id; - const { resumeId } = input; - return await ctx.prisma.resumesStar.findUnique({ - where: { - userId_resumeId: { resumeId, userId }, - }, - }); - }, }); diff --git a/apps/portal/src/types/resume.d.ts b/apps/portal/src/types/resume.d.ts index 5b2a33a9..39e782bb 100644 --- a/apps/portal/src/types/resume.d.ts +++ b/apps/portal/src/types/resume.d.ts @@ -3,6 +3,7 @@ export type Resume = { createdAt: Date; experience: string; id: string; + isStarredByUser: boolean; location: string; numComments: number; numStars: number;