diff --git a/apps/portal/src/components/resumes/comments/ResumeCommentListItem.tsx b/apps/portal/src/components/resumes/comments/ResumeCommentListItem.tsx
index 28f6a224..d5890ac6 100644
--- a/apps/portal/src/components/resumes/comments/ResumeCommentListItem.tsx
+++ b/apps/portal/src/components/resumes/comments/ResumeCommentListItem.tsx
@@ -13,6 +13,7 @@ import { Button, TextArea } from '@tih/ui';
import { trpc } from '~/utils/trpc';
+import ResumeUserBadges from './ResumeUserBadges';
import ResumeExpandableText from '../shared/ResumeExpandableText';
import type { ResumeComment } from '~/types/resume-comments';
@@ -152,13 +153,15 @@ export default function ResumeCommentListItem({
{/* Name and creation time */}
-
+
{comment.user.name ?? 'Reviewer ABC'}
-
+
-
+
{isCommentOwner ? '(Me)' : ''}
-
+
+
+
diff --git a/apps/portal/src/components/resumes/comments/ResumeUserBadges.tsx b/apps/portal/src/components/resumes/comments/ResumeUserBadges.tsx
new file mode 100644
index 00000000..9a7de7f8
--- /dev/null
+++ b/apps/portal/src/components/resumes/comments/ResumeUserBadges.tsx
@@ -0,0 +1,61 @@
+import { Badge } from '@tih/ui';
+
+import { trpc } from '~/utils/trpc';
+
+type Props = {
+ userId: string;
+};
+
+type BadgeInfo = {
+ description: string;
+ id: string;
+ isValid: (userId: string) => boolean;
+ label: string;
+};
+
+const badges: Array = [
+ {
+ description: 'User has reviewed over 50 resumes',
+ id: 'VeteranReviewer',
+ isValid: (userId: string) => {
+ const userReviewedResumesCountQuery = trpc.useQuery([
+ 'resumes.resume.findUserReviewedResumeCount',
+ { userId },
+ ]);
+
+ return (
+ userReviewedResumesCountQuery.data != null &&
+ userReviewedResumesCountQuery.data >= 5
+ );
+ },
+ label: 'Veteran',
+ },
+ {
+ description: 'User has reviewed over 50 resumes',
+ id: 'NoviceReviewer',
+ isValid: (userId: string) => {
+ const userReviewedResumesCountQuery = trpc.useQuery([
+ 'resumes.resume.findUserReviewedResumeCount',
+ { userId },
+ ]);
+
+ return (
+ userReviewedResumesCountQuery.data != null &&
+ userReviewedResumesCountQuery.data >= 2
+ );
+ },
+ label: 'Veteran',
+ },
+];
+
+export default function ResumeUserBadges({ userId }: Props) {
+ return (
+ <>
+ {badges
+ .filter((badge) => badge.isValid(userId))
+ .map((badge) => (
+
+ ))}
+ >
+ );
+}
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 00c9f13b..44d253b0 100644
--- a/apps/portal/src/server/router/resumes/resumes-resume-router.ts
+++ b/apps/portal/src/server/router/resumes/resumes-resume-router.ts
@@ -138,4 +138,32 @@ export const resumesRouter = createRouter()
},
});
},
+ })
+ .query('findUserReviewedResumeCount', {
+ input: z.object({
+ userId: z.string(),
+ }),
+ async resolve({ ctx, input }) {
+ return await ctx.prisma.resumesResume.count({
+ where: {
+ comments: {
+ some: {
+ userId: input.userId,
+ },
+ },
+ },
+ });
+ },
+ })
+ .query('findUserStarredResumeCount', {
+ input: z.object({
+ userId: z.string(),
+ }),
+ async resolve({ ctx, input }) {
+ return await ctx.prisma.resumesResume.findMany({
+ where: {
+ userId: input.userId,
+ },
+ });
+ },
});