Skip to content

Commit

Permalink
feat:added usequery
Browse files Browse the repository at this point in the history
  • Loading branch information
Paribesh01 committed Nov 2, 2024
1 parent 8815369 commit dd41924
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 100 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
20 changes: 18 additions & 2 deletions src/actions/job.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,25 @@ export const getRecommendedJobs = withServerActionAsyncCatcher<
ServerActionReturnType<getAllRecommendedJobs>
>(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,
Expand Down
109 changes: 62 additions & 47 deletions src/app/jobs/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="container max-w-8xl h-fit mx-auto my-8">
<section className="flex h-fit py-4">
<Link
href="/jobs"
className="flex border-2 border-transparent cursor-pointer h-fit p-2 rounded-full px-4 transition-all duration-450 ease-linear hover:border-2 hover:bg-[#F1F5F9] dark:hover:bg-[#0F172A] items-center gap-2"
>
<ArrowLeft size={18} />
<p className="text-xs">Back to All Jobs</p>
</Link>
</section>
<main className="grid grid-cols-1 lg:grid-cols-6 gap-8">
{/* the particular job details */}
<Job job={jobDetail} />

{/* job recommendations */}
<aside className="col-span-1 rounded-md lg:col-span-2">
<div className="sticky top-4">
<h2 className="text-xl font-semibold mb-4">Recommended for you</h2>
<main className="my-2 flex flex-col gap-4">
{recommendedJobs &&
recommendedJobs.map((job, index) => {
return <JobCard key={`recommended_job_${index}`} job={job} />;
})}
</main>
</div>
</aside>
</main>
</div>
<HydrationBoundary state={dehydrate(queryClient)}>
<div className="container max-w-8xl h-fit mx-auto my-8">
<section className="flex h-fit py-4">
<Link
href="/jobs"
className="flex border-2 border-transparent cursor-pointer h-fit p-2 rounded-full px-4 transition-all duration-450 ease-linear hover:border-2 hover:bg-[#F1F5F9] dark:hover:bg-[#0F172A] items-center gap-2"
>
<ArrowLeft size={18} />
<p className="text-xs">Back to All Jobs</p>
</Link>
</section>
<main className="grid grid-cols-1 lg:grid-cols-6 gap-8">
{/* the particular job details */}

<Job />

{/* job recommendations */}
<aside className="col-span-1 rounded-md lg:col-span-2">
<div className="sticky top-4">
<h2 className="text-xl font-semibold mb-4">
Recommended for you
</h2>
<RecommendJobs jobId={params.id} />
</div>
</aside>
</main>
</div>
</HydrationBoundary>
);
};

Expand Down
66 changes: 42 additions & 24 deletions src/app/jobs/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 (
<div className="container grid sm:gap-6 gap-4 mt-12">
<div className="grid gap-2">
<h1 className="text-3xl sm:text-4xl font-bold">Explore Jobs</h1>
<p className="text-sm font-medium text-slate-500 dark:text-slate-400">
Explore thousands of remote and onsite jobs that match your skills and
aspirations.
</p>
</div>
<div className="flex gap-6">
<div className="hidden sm:block border h-fit rounded-lg w-[310px] ">
<JobFilters searchParams={parsedSearchParams} />
<HydrationBoundary state={dehydrate(queryClient)}>
<div className="container grid sm:gap-6 gap-4 mt-12">
<div className="grid gap-2">
<h1 className="text-3xl sm:text-4xl font-bold">Explore Jobs</h1>
<p className="text-sm font-medium text-slate-500 dark:text-slate-400">
Explore thousands of remote and onsite jobs that match your skills
and aspirations.
</p>
</div>
<div className="grow">
<JobsHeader searchParams={parsedSearchParams} />
<Suspense
key={JSON.stringify(parsedSearchParams)}
fallback={
<div className="flex justify-center items-center h-full gap-5 ">
<Loader />
</div>
}
>
<AllJobs searchParams={parsedSearchParams} />
</Suspense>
<div className="flex gap-6">
<div className="hidden sm:block border h-fit rounded-lg w-[310px] ">
<JobFilters searchParams={parsedSearchParams} />
</div>
<div className="grow">
<JobsHeader searchParams={parsedSearchParams} />
<Suspense
key={JSON.stringify(parsedSearchParams)}
fallback={
<div className="flex justify-center items-center h-full gap-5 ">
<Loader />
</div>
}
>
<AllJobs
userbookmarks={UserBookmarks.data}
searchParams={parsedSearchParams}
/>
</Suspense>
</div>
</div>
</div>
</div>
</HydrationBoundary>
);
};

Expand Down
34 changes: 34 additions & 0 deletions src/components/RecommendJobs.tsx
Original file line number Diff line number Diff line change
@@ -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 <div>Error </div>;
}
const recommendedJobs = data?.additional?.jobs;

return (
<main className="my-2 flex flex-col gap-4">
{recommendedJobs &&
recommendedJobs.map((job, index) => {
return (
<JobCard
isBookmarked={false}
key={`recommended_job_${index}`}
job={job}
/>
);
})}
</main>
);
};
28 changes: 16 additions & 12 deletions src/components/all-jobs.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 <div>Error {jobs.message}</div>;
const { data } = useQuery({
queryKey: ['jobs', searchParams],
queryFn: () => getAllJobs(searchParams),
staleTime: 1000 * 60 * 5,
});
if (!data?.status || !data?.additional) {
return <div>Error {data?.message}</div>;
}
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 (
<div className="bg-background py-4 grid gap-3 w-full">
{jobs.additional.jobs.length > 0 ? (
{jobsLength > 0 ? (
jobs.additional?.jobs.map((job, index) => (
<JobCard
job={job}
Expand Down
21 changes: 19 additions & 2 deletions src/components/job.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
'use client';
import { JobType } from '@/types/jobs.types';
import Icon from './ui/icon';
import { formatSalary } from '@/lib/utils';
import { Button } from './ui/button';
Expand All @@ -8,11 +7,29 @@ import { Briefcase, MapPin } from 'lucide-react';
import Link from 'next/link';
import Linkify from 'linkify-react';
import { ShareJobDialog } from './ShareJobDialog';
import { useParams } from 'next/navigation';
import { useQuery } from '@tanstack/react-query';
import { getJobById } from '@/actions/job.action';
const options = {
defaultProtocol: 'https',
target: '_blank',
};
export const Job = ({ job }: { job: JobType }) => {
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 <div>Error </div>;
}
const job = data?.additional?.job;
if (!job) {
return <div>Error</div>;
}

return (
<aside className="col-span-1 flex flex-col gap-6 lg:col-span-4 ">
<section className="grid gap-5 border-2 shadow-sm p-6 w-full bg-gradient-to-b from-[#F1F5F9] to-white dark:from-darkBgSecondary dark:to-darkBgTertiary rounded-lg">
Expand Down
1 change: 0 additions & 1 deletion src/lib/validators/jobs.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ export const JobByIdSchema = z.object({

export const RecommendedJobSchema = z.object({
id: z.string().min(1, 'Job id is required'),
category: z.string().min(1, 'Job category is required'),
});

export const deleteJobByIdSchema = z.object({
Expand Down
Loading

0 comments on commit dd41924

Please sign in to comment.