From 4f18395360564dc08404e16557f66ae8f135cd05 Mon Sep 17 00:00:00 2001 From: Paribesh Nepal Date: Tue, 22 Oct 2024 01:12:00 +0530 Subject: [PATCH 1/6] fix: deleted jobs were showing --- .../20241021191938_somfadf/migration.sql | 18 ++++++++++++++++++ prisma/seed.ts | 14 +++++++++++++- src/actions/job.action.ts | 12 ++++++++++-- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 prisma/migrations/20241021191938_somfadf/migration.sql diff --git a/prisma/migrations/20241021191938_somfadf/migration.sql b/prisma/migrations/20241021191938_somfadf/migration.sql new file mode 100644 index 00000000..21f638de --- /dev/null +++ b/prisma/migrations/20241021191938_somfadf/migration.sql @@ -0,0 +1,18 @@ +-- CreateEnum +CREATE TYPE "ProjectStack" AS ENUM ('GO', 'PYTHON', 'MERN', 'NEXTJS', 'AI_GPT_APIS', 'SPRINGBOOT', 'OTHERS'); + +-- DropForeignKey +ALTER TABLE "Experience" DROP CONSTRAINT "Experience_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "Project" DROP CONSTRAINT "Project_userId_fkey"; + +-- AlterTable +ALTER TABLE "Project" ADD COLUMN "projectThumbnail" TEXT, +ADD COLUMN "stack" "ProjectStack" NOT NULL DEFAULT 'OTHERS'; + +-- AddForeignKey +ALTER TABLE "Experience" ADD CONSTRAINT "Experience_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Project" ADD CONSTRAINT "Project_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/seed.ts b/prisma/seed.ts index 27d6685a..5aa0b4a8 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -13,7 +13,7 @@ const prisma = new PrismaClient(); const users = [ { id: '1', name: 'Jack', email: 'user@gmail.com' }, - { id: '2', name: 'Admin', email: 'admin@gmail.com', role: Role.ADMIN , onBoard : true }, + { id: '2', name: 'Admin', email: 'admin@gmail.com', role: Role.ADMIN, onBoard: true }, { id: '3', name: 'Hr', email: 'hr@gmail.com', role: Role.HR }, ]; @@ -63,6 +63,7 @@ let jobs = [ minSalary: null, maxSalary: null, isVerifiedJob: false, + }, { id: '3', @@ -86,6 +87,7 @@ let jobs = [ minSalary: 90000, maxSalary: 120000, isVerifiedJob: true, + deleted: true }, { id: '4', @@ -134,6 +136,7 @@ let jobs = [ minSalary: 110000, maxSalary: 150000, isVerifiedJob: true, + deleted: true }, { id: '6', @@ -159,6 +162,7 @@ let jobs = [ minSalary: 80000, maxSalary: 100000, isVerifiedJob: false, + }, { id: '7', @@ -183,6 +187,8 @@ let jobs = [ minSalary: 70000, maxSalary: 90000, isVerifiedJob: false, + delted: true + }, { id: '8', @@ -207,6 +213,8 @@ let jobs = [ minSalary: null, maxSalary: null, isVerifiedJob: true, + deleted: true + }, { id: '9', @@ -229,6 +237,7 @@ let jobs = [ minSalary: 100000, maxSalary: 130000, isVerifiedJob: true, + }, { id: '10', @@ -253,6 +262,7 @@ let jobs = [ minSalary: 75000, maxSalary: 95000, isVerifiedJob: false, + }, { id: '11', @@ -274,6 +284,7 @@ let jobs = [ minSalary: 25000, maxSalary: 50000, isVerifiedJob: true, + }, { id: '12', @@ -298,6 +309,7 @@ let jobs = [ minSalary: null, maxSalary: null, isVerifiedJob: true, + delted: false }, ]; diff --git a/src/actions/job.action.ts b/src/actions/job.action.ts index 4948a62a..fb1120fb 100644 --- a/src/actions/job.action.ts +++ b/src/actions/job.action.ts @@ -135,6 +135,7 @@ export const getAllJobs = withSession< ? { ...filterQueries } : { isVerifiedJob: true, + deleted: false, ...filterQueries, expired: false, }), @@ -195,6 +196,7 @@ export const getRecommendedJobs = withServerActionAsyncCatcher< id: { not: id }, isVerifiedJob: true, expired: false, + deleted: false, }, orderBy: { postedAt: 'desc', @@ -227,6 +229,7 @@ export const getRecommendedJobs = withServerActionAsyncCatcher< where: { id: { not: id }, expired: false, + deleted: false, }, orderBy: { postedAt: 'desc', @@ -273,7 +276,7 @@ export const getJobById = withServerActionAsyncCatcher< const result = JobByIdSchema.parse(data); const { id } = result; const job = await prisma.job.findFirst({ - where: { id, expired: false }, + where: { id, expired: false, deleted: false }, select: { id: true, title: true, @@ -308,8 +311,12 @@ export const getJobById = withServerActionAsyncCatcher< export const getCityFilters = async () => { const response = await prisma.job.findMany({ - select: { + where: { + isVerifiedJob: true, expired: false, + deleted: false, + }, + select: { city: true, }, }); @@ -324,6 +331,7 @@ export const getRecentJobs = async () => { const recentJobs = await prisma.job.findMany({ where: { isVerifiedJob: true, + deleted: false, expired: false, }, orderBy: { From dd419244ca98c7ecc03daf26b6979713a6f260f1 Mon Sep 17 00:00:00 2001 From: Paribesh Nepal Date: Sun, 3 Nov 2024 04:40:34 +0530 Subject: [PATCH 2/6] feat:added usequery --- package.json | 1 + src/actions/job.action.ts | 20 ++++- src/app/jobs/[id]/page.tsx | 109 +++++++++++++++------------ src/app/jobs/page.tsx | 66 ++++++++++------ src/components/RecommendJobs.tsx | 34 +++++++++ src/components/all-jobs.tsx | 28 ++++--- src/components/job.tsx | 21 +++++- src/lib/validators/jobs.validator.ts | 1 - src/providers/providers.tsx | 29 ++++--- src/providers/queryClient.ts | 20 +++++ 10 files changed, 229 insertions(+), 100 deletions(-) create mode 100644 src/components/RecommendJobs.tsx create mode 100644 src/providers/queryClient.ts diff --git a/package.json b/package.json index 2a7f56c0..f96da66f 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-toast": "^1.2.1", "@t3-oss/env-nextjs": "^0.11.1", + "@tanstack/react-query": "^5.59.17", "@types/lodash": "^4.17.7", "@types/uuid": "^10.0.0", "@uidotdev/usehooks": "^2.4.1", diff --git a/src/actions/job.action.ts b/src/actions/job.action.ts index b3b15ade..ec8494be 100644 --- a/src/actions/job.action.ts +++ b/src/actions/job.action.ts @@ -188,9 +188,25 @@ export const getRecommendedJobs = withServerActionAsyncCatcher< ServerActionReturnType >(async (data) => { const result = RecommendedJobSchema.parse(data); - const { id, category } = result; + const { id } = result; + + const job = await prisma.job.findUnique({ + where: { id }, // Ensure params.id is available + select: { + id: true, + category: true, + // Add any other fields you need from the job + }, + }); + + if (!job) { + throw new Error('Job not found'); + } + + // Use the category from the fetched job + const { category } = job; - // fettching the latest three jobs excluding the current job and in the same category + // Fetch the latest three jobs excluding the current job and in the same category const jobs = await prisma.job.findMany({ where: { category: category, diff --git a/src/app/jobs/[id]/page.tsx b/src/app/jobs/[id]/page.tsx index e34810b3..887b4d45 100644 --- a/src/app/jobs/[id]/page.tsx +++ b/src/app/jobs/[id]/page.tsx @@ -1,62 +1,77 @@ import { getJobById, getRecommendedJobs } from '@/actions/job.action'; import { Job } from '@/components/job'; -import JobCard from '@/components/job-card-rec'; import { JobByIdSchemaType } from '@/lib/validators/jobs.validator'; +import { HydrationBoundary, dehydrate } from '@tanstack/react-query'; import { ArrowLeft } from 'lucide-react'; import Link from 'next/link'; -import { redirect } from 'next/navigation'; +import getQueryClient from '../../../providers/queryClient'; +import { RecommendJobs } from '@/components/RecommendJobs'; const page = async ({ params }: { params: JobByIdSchemaType }) => { - const job = await getJobById(params); - if (!job.status) { - return; - } - - const jobDetail = job.additional?.job; - if (!jobDetail) { - return redirect('/jobs'); - } - - const curatedJobs = await getRecommendedJobs({ - id: jobDetail.id, - category: jobDetail.category, + const queryClient = getQueryClient(); + + await queryClient.prefetchQuery({ + queryKey: ['jobs', params], + queryFn: () => getJobById({ id: params.id }), + staleTime: 1000 * 60 * 5, + }); + + await queryClient.prefetchQuery({ + queryKey: ['RecommendedJobs', params], + queryFn: () => getRecommendedJobs({ id: params.id }), + staleTime: 1000 * 60 * 5, }); - if (!curatedJobs.status) { - return; - } + // const job = await getJobById(params); + // if (!job.status) { + // return; + // } + + // const jobDetail = job.additional?.job; + // if (!jobDetail) { + // return redirect('/jobs'); + // } - const recommendedJobs = curatedJobs.additional?.jobs; + // const curatedJobs = await getRecommendedJobs({ + // id: jobDetail.id, + // category: jobDetail.category, + // }); + + // if (!curatedJobs.status) { + // return; + // } + + // const recommendedJobs = curatedJobs.additional?.jobs; return ( -
-
- - -

Back to All Jobs

- -
-
- {/* the particular job details */} - - - {/* job recommendations */} - -
-
+ +
+
+ + +

Back to All Jobs

+ +
+
+ {/* the particular job details */} + + + + {/* job recommendations */} + +
+
+
); }; diff --git a/src/app/jobs/page.tsx b/src/app/jobs/page.tsx index 3dfd3077..924c1115 100644 --- a/src/app/jobs/page.tsx +++ b/src/app/jobs/page.tsx @@ -8,6 +8,9 @@ import { } from '@/lib/validators/jobs.validator'; import { redirect } from 'next/navigation'; import { Suspense } from 'react'; +import getQueryClient from '../../providers/queryClient'; +import { GetUserBookmarksId, getAllJobs } from '@/actions/job.action'; +import { HydrationBoundary, dehydrate } from '@tanstack/react-query'; const page = async ({ searchParams }: { searchParams: JobQuerySchemaType }) => { const parsedData = JobQuerySchema.safeParse(searchParams); @@ -16,34 +19,49 @@ const page = async ({ searchParams }: { searchParams: JobQuerySchemaType }) => { redirect('/jobs'); } const parsedSearchParams = parsedData.data; + + const queryClient = getQueryClient(); + + await queryClient.prefetchQuery({ + queryKey: ['jobs', parsedSearchParams], + queryFn: () => getAllJobs(parsedSearchParams), + staleTime: 1000 * 60 * 5, + }); + const UserBookmarks = await GetUserBookmarksId(); + return ( -
-
-

Explore Jobs

-

- Explore thousands of remote and onsite jobs that match your skills and - aspirations. -

-
-
-
- + +
+
+

Explore Jobs

+

+ Explore thousands of remote and onsite jobs that match your skills + and aspirations. +

-
- - - -
- } - > - - +
+
+ +
+
+ + + +
+ } + > + + +
-
+ ); }; diff --git a/src/components/RecommendJobs.tsx b/src/components/RecommendJobs.tsx new file mode 100644 index 00000000..573999b1 --- /dev/null +++ b/src/components/RecommendJobs.tsx @@ -0,0 +1,34 @@ +'use client'; +import { getRecommendedJobs } from '@/actions/job.action'; +import { useQuery } from '@tanstack/react-query'; +import JobCard from './Jobcard'; +import { useParams } from 'next/navigation'; + +export const RecommendJobs = ({ jobId }: { jobId: string }) => { + const params = useParams(); + const { data } = useQuery({ + queryKey: ['RecommendedJobs', params], + queryFn: () => getRecommendedJobs({ id: jobId }), + staleTime: 1000 * 60 * 5, + }); + + if (!data?.status) { + return
Error
; + } + const recommendedJobs = data?.additional?.jobs; + + return ( +
+ {recommendedJobs && + recommendedJobs.map((job, index) => { + return ( + + ); + })} +
+ ); +}; diff --git a/src/components/all-jobs.tsx b/src/components/all-jobs.tsx index 4a5f8f2c..45827afd 100644 --- a/src/components/all-jobs.tsx +++ b/src/components/all-jobs.tsx @@ -1,4 +1,5 @@ -import { getAllJobs, GetUserBookmarksId } from '@/actions/job.action'; +'use client'; +import { getAllJobs } from '@/actions/job.action'; import { DEFAULT_PAGE, JOBS_PER_PAGE } from '@/config/app.config'; import { Card, CardContent, CardHeader, CardTitle } from './ui/card'; import { JobQuerySchemaType } from '@/lib/validators/jobs.validator'; @@ -10,31 +11,34 @@ import { Pagination, PaginationContent, PaginationItem } from './ui/pagination'; import { PaginationPages } from './ui/paginator'; import JobCard from './Jobcard'; import APP_PATHS from '@/config/path.config'; +import { useQuery } from '@tanstack/react-query'; type PaginatorProps = { searchParams: JobQuerySchemaType; + userbookmarks: { jobId: string }[] | null; }; -const AllJobs = async ({ searchParams }: PaginatorProps) => { - const [jobs, getUserBookmarks] = await Promise.all([ - await getAllJobs(searchParams), - await GetUserBookmarksId(), - ]); +const AllJobs = ({ searchParams, userbookmarks }: PaginatorProps) => { + const userbookmarkArr: { jobId: string }[] | null = userbookmarks; - const userbookmarkArr: { jobId: string }[] | null = getUserBookmarks.data; - - if (!jobs.status || !jobs.additional) { - return
Error {jobs.message}
; + const { data } = useQuery({ + queryKey: ['jobs', searchParams], + queryFn: () => getAllJobs(searchParams), + staleTime: 1000 * 60 * 5, + }); + if (!data?.status || !data?.additional) { + return
Error {data?.message}
; } + const jobs = data; const totalPages = Math.ceil((jobs.additional?.totalJobs || 0) / JOBS_PER_PAGE) || DEFAULT_PAGE; const currentPage = parseInt(searchParams.page?.toString()) || DEFAULT_PAGE; - + const jobsLength = jobs.additional?.jobs.length || 0; // Defaults to 0 if undefined return (
- {jobs.additional.jobs.length > 0 ? ( + {jobsLength > 0 ? ( jobs.additional?.jobs.map((job, index) => ( { +export const Job = () => { + const params = useParams(); + const id: any = params.id; + const { data } = useQuery({ + queryKey: ['jobs', { id }], + queryFn: () => getJobById({ id }), + staleTime: 1000 * 60 * 5, + }); + if (!data?.status) { + return
Error
; + } + const job = data?.additional?.job; + if (!job) { + return
Error
; + } + return (
diff --git a/src/components/RecentJobs.tsx b/src/components/RecentJobs.tsx index d4a476c6..e892db04 100644 --- a/src/components/RecentJobs.tsx +++ b/src/components/RecentJobs.tsx @@ -1,13 +1,32 @@ +'use client'; import { getRecentJobs, GetUserBookmarksId } from '@/actions/job.action'; import JobCard from './Jobcard'; +import { useQuery } from '@tanstack/react-query'; +import { useSession } from 'next-auth/react'; -export default async function RecentJobs() { - const [recentJobs, getUserBookmarks] = await Promise.all([ - await getRecentJobs(), - await GetUserBookmarksId(), - ]); +export default function RecentJobs() { + // const [recentJobs, getUserBookmarks] = await Promise.all([ + // await getRecentJobs(), + // await GetUserBookmarksId(), + // ]); + const session = useSession(); - const userbookmarkArr: { jobId: string }[] | null = getUserBookmarks.data; + const { data } = useQuery({ + queryKey: ['recentJobs'], + queryFn: () => getRecentJobs(), + staleTime: 1000 * 60 * 5, + }); + const bookmarks = useQuery({ + queryKey: ['UserBookmarksId', session?.data?.user?.id], + queryFn: () => GetUserBookmarksId(), + }); + if (!data?.status || !data?.additional) { + return
Error {data?.message}
; + } + const recentJobs = data; + + const userbookmarkArr: { jobId: string }[] | null = + bookmarks.data?.data || null; if (!recentJobs.status) { return
{recentJobs.message}
; diff --git a/src/components/all-jobs.tsx b/src/components/all-jobs.tsx index 45827afd..50e51909 100644 --- a/src/components/all-jobs.tsx +++ b/src/components/all-jobs.tsx @@ -1,5 +1,5 @@ 'use client'; -import { getAllJobs } from '@/actions/job.action'; +import { GetUserBookmarksId, getAllJobs } from '@/actions/job.action'; import { DEFAULT_PAGE, JOBS_PER_PAGE } from '@/config/app.config'; import { Card, CardContent, CardHeader, CardTitle } from './ui/card'; import { JobQuerySchemaType } from '@/lib/validators/jobs.validator'; @@ -12,14 +12,20 @@ import { PaginationPages } from './ui/paginator'; import JobCard from './Jobcard'; import APP_PATHS from '@/config/path.config'; import { useQuery } from '@tanstack/react-query'; +import { useSession } from 'next-auth/react'; type PaginatorProps = { searchParams: JobQuerySchemaType; - userbookmarks: { jobId: string }[] | null; }; -const AllJobs = ({ searchParams, userbookmarks }: PaginatorProps) => { - const userbookmarkArr: { jobId: string }[] | null = userbookmarks; +const AllJobs = ({ searchParams }: PaginatorProps) => { + // const userbookmarkArr: { jobId: string }[] | null = userbookmarks; + const session = useSession(); + + const userbookmark = useQuery({ + queryKey: ['UserBookmarksId', session?.data?.user?.id], + queryFn: () => GetUserBookmarksId(), + }); const { data } = useQuery({ queryKey: ['jobs', searchParams], @@ -30,6 +36,8 @@ const AllJobs = ({ searchParams, userbookmarks }: PaginatorProps) => { return
Error {data?.message}
; } const jobs = data; + const userbookmarkArr: { jobId: string }[] | null = + userbookmark.data?.data || null; const totalPages = Math.ceil((jobs.additional?.totalJobs || 0) / JOBS_PER_PAGE) || diff --git a/src/components/job-landing.tsx b/src/components/job-landing.tsx index c931bfb8..a417ecba 100644 --- a/src/components/job-landing.tsx +++ b/src/components/job-landing.tsx @@ -3,6 +3,10 @@ import relativeTime from 'dayjs/plugin/relativeTime'; import { ChevronRight } from 'lucide-react'; import RecentJobs from './RecentJobs'; import Link from 'next/link'; +import getQueryClient from '@/providers/queryClient'; +import { GetUserBookmarksId, getRecentJobs } from '@/actions/job.action'; +import { HydrationBoundary, dehydrate } from '@tanstack/react-query'; +import { getServerSession } from 'next-auth'; dayjs.extend(relativeTime); export const calculateTimeSincePosted = (postedAt: Date): string => { @@ -13,30 +17,47 @@ export const getFirstLetterCaps = (str: string): string => { return str.charAt(0).toUpperCase(); }; -export const JobLanding = () => { +export const JobLanding = async () => { + const session = await getServerSession(); + const queryClient = getQueryClient(); + + await queryClient.prefetchQuery({ + queryKey: ['recentJobs'], + queryFn: () => getRecentJobs(), + staleTime: 1000 * 60 * 5, + }); + await queryClient.prefetchQuery({ + queryKey: ['UserBookmarksId', session?.user?.id], + queryFn: () => GetUserBookmarksId(), + }); + return ( -
-
-

Recently Added jobs

-

- Stay ahead with newly added jobs -

-
- -
- + +
+
+

+ Recently Added jobs +

+

+ Stay ahead with newly added jobs +

+
+ +
+ +
-
+ ); }; From abfd631c12e247afa49ea6fd88bd81df8fa7a496 Mon Sep 17 00:00:00 2001 From: Paribesh Nepal Date: Sun, 3 Nov 2024 15:43:15 +0530 Subject: [PATCH 6/6] fix:minor change --- src/actions/job.action.ts | 7 ++----- src/components/RecentJobs.tsx | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/actions/job.action.ts b/src/actions/job.action.ts index ec8494be..c98ae38c 100644 --- a/src/actions/job.action.ts +++ b/src/actions/job.action.ts @@ -191,11 +191,10 @@ export const getRecommendedJobs = withServerActionAsyncCatcher< const { id } = result; const job = await prisma.job.findUnique({ - where: { id }, // Ensure params.id is available + where: { id }, select: { id: true, category: true, - // Add any other fields you need from the job }, }); @@ -203,10 +202,8 @@ export const getRecommendedJobs = withServerActionAsyncCatcher< throw new Error('Job not found'); } - // Use the category from the fetched job const { category } = job; - // Fetch the latest three jobs excluding the current job and in the same category const jobs = await prisma.job.findMany({ where: { category: category, @@ -252,7 +249,7 @@ export const getRecommendedJobs = withServerActionAsyncCatcher< orderBy: { postedAt: 'desc', }, - take: 3, // Fallback to showing latest 3 jobs from other categories + take: 3, select: { id: true, type: true, diff --git a/src/components/RecentJobs.tsx b/src/components/RecentJobs.tsx index e892db04..28a44374 100644 --- a/src/components/RecentJobs.tsx +++ b/src/components/RecentJobs.tsx @@ -5,10 +5,6 @@ import { useQuery } from '@tanstack/react-query'; import { useSession } from 'next-auth/react'; export default function RecentJobs() { - // const [recentJobs, getUserBookmarks] = await Promise.all([ - // await getRecentJobs(), - // await GetUserBookmarksId(), - // ]); const session = useSession(); const { data } = useQuery({