From 69437f607bad8b541e4e4402442ac8837844cde7 Mon Sep 17 00:00:00 2001 From: Wu Peirong Date: Tue, 11 Oct 2022 00:10:49 +0800 Subject: [PATCH] [resumes][fix] Fix star button delay --- apps/portal/src/pages/resumes/[resumeId].tsx | 59 +++++++++++++++---- apps/portal/src/server/router/index.ts | 2 +- .../router/resumes/resumes-resume-router.ts | 4 +- .../resumes/resumes-star-user-router.ts | 46 ++++++--------- 4 files changed, 69 insertions(+), 42 deletions(-) diff --git a/apps/portal/src/pages/resumes/[resumeId].tsx b/apps/portal/src/pages/resumes/[resumeId].tsx index 52d4f3b7..5d220f0a 100644 --- a/apps/portal/src/pages/resumes/[resumeId].tsx +++ b/apps/portal/src/pages/resumes/[resumeId].tsx @@ -4,7 +4,7 @@ import Error from 'next/error'; import Head from 'next/head'; import { useRouter } from 'next/router'; import { useSession } from 'next-auth/react'; -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { AcademicCapIcon, BriefcaseIcon, @@ -27,7 +27,6 @@ export default function ResumeReviewPage() { const { data: session } = useSession(); const router = useRouter(); const { resumeId } = router.query; - const trpcContext = trpc.useContext(); // Safe to assert resumeId type as string because query is only sent if so const detailsQuery = trpc.useQuery( ['resumes.resume.findOne', { resumeId: resumeId as string }], @@ -35,26 +34,62 @@ export default function ResumeReviewPage() { enabled: typeof resumeId === 'string', }, ); - const starMutation = trpc.useMutation('resumes.star.user.create_or_delete', { - onSuccess() { - trpcContext.invalidateQueries(['resumes.resume.findOne']); + const starMutation = trpc.useMutation('resumes.resume.star', { + onError() { + setStarDetails({ + isStarred: false, + numStars: starDetails.numStars - 1, + }); }, }); + const unstarMutation = trpc.useMutation('resumes.resume.unstar', { + onError() { + setStarDetails({ + isStarred: true, + numStars: starDetails.numStars + 1, + }); + }, + }); + const [starDetails, setStarDetails] = useState({ + isStarred: false, + numStars: 0, + }); useEffect(() => { - if (detailsQuery.data?.stars.length) { + if (starDetails.isStarred) { document.getElementById('star-button')?.focus(); } else { document.getElementById('star-button')?.blur(); } - }, [detailsQuery.data?.stars]); + }, [starDetails]); + + useEffect(() => { + if (detailsQuery?.data !== undefined) { + setStarDetails({ + isStarred: !!detailsQuery.data?.stars.length, + numStars: detailsQuery.data?._count.stars ?? 0, + }); + } + }, [detailsQuery.data]); const onStarButtonClick = () => { // Star button only rendered if resume exists // Star button only clickable if user exists - starMutation.mutate({ - resumeId: resumeId as string, + setStarDetails({ + isStarred: !starDetails.isStarred, + numStars: starDetails.isStarred + ? starDetails.numStars - 1 + : starDetails.numStars + 1, }); + if (starDetails.isStarred) { + unstarMutation.mutate({ + resumeId: resumeId as string, + }); + } else { + starMutation.mutate({ + resumeId: resumeId as string, + }); + } }; return ( @@ -78,7 +113,7 @@ export default function ResumeReviewPage() { diff --git a/apps/portal/src/server/router/index.ts b/apps/portal/src/server/router/index.ts index c018c3f7..8dd5e08c 100644 --- a/apps/portal/src/server/router/index.ts +++ b/apps/portal/src/server/router/index.ts @@ -28,7 +28,7 @@ export const appRouter = createRouter() .merge('companies.', companiesRouter) .merge('resumes.resume.', resumesRouter) .merge('resumes.resume.user.', resumesResumeUserRouter) - .merge('resumes.star.user.', resumesStarUserRouter) + .merge('resumes.resume.', resumesStarUserRouter) .merge('resumes.reviews.', resumeReviewsRouter) .merge('resumes.reviews.user.', resumesReviewsUserRouter) .merge('questions.answers.comments.', questionsAnswerCommentRouter) 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 177b076e..34d7d6f0 100644 --- a/apps/portal/src/server/router/resumes/resumes-resume-router.ts +++ b/apps/portal/src/server/router/resumes/resumes-resume-router.ts @@ -62,7 +62,9 @@ export const resumesRouter = createRouter() }, stars: { where: { - userId, + OR: { + userId, + }, }, }, user: { diff --git a/apps/portal/src/server/router/resumes/resumes-star-user-router.ts b/apps/portal/src/server/router/resumes/resumes-star-user-router.ts index 40daea7d..9e780858 100644 --- a/apps/portal/src/server/router/resumes/resumes-star-user-router.ts +++ b/apps/portal/src/server/router/resumes/resumes-star-user-router.ts @@ -2,22 +2,15 @@ import { z } from 'zod'; import { createProtectedRouter } from '../context'; -export const resumesStarUserRouter = createProtectedRouter().mutation( - 'create_or_delete', - { +export const resumesStarUserRouter = createProtectedRouter() + .mutation('unstar', { input: z.object({ resumeId: z.string(), }), async resolve({ ctx, input }) { const { resumeId } = input; - // Update_star will only be called if user is logged in - const userId = ctx.session!.user!.id; - - // Use the resumeId and resumeProfileId to check if star exists - const resumesStar = await ctx.prisma.resumesStar.findUnique({ - select: { - id: true, - }, + const userId = ctx.session.user.id; + return await ctx.prisma.resumesStar.delete({ where: { userId_resumeId: { resumeId, @@ -25,23 +18,20 @@ export const resumesStarUserRouter = createProtectedRouter().mutation( }, }, }); - - if (resumesStar === null) { - return await ctx.prisma.resumesStar.create({ - data: { - resumeId, - userId, - }, - }); - } - return await ctx.prisma.resumesStar.delete({ - where: { - userId_resumeId: { - resumeId, - userId, - }, + }, + }) + .mutation('star', { + input: z.object({ + resumeId: z.string(), + }), + async resolve({ ctx, input }) { + const { resumeId } = input; + const userId = ctx.session.user.id; + return await ctx.prisma.resumesStar.create({ + data: { + resumeId, + userId, }, }); }, - }, -); + });