Skip to content

Commit

Permalink
feat : redesigned job page (#374)
Browse files Browse the repository at this point in the history
* feat:redesigned job page

* added link tag to go to jobs page

* fix: added the latest jobs at recommndation section based on category

* added link tag for job card

* key issue fix

* small fix

* build fixed
  • Loading branch information
amanbairagi30 authored Sep 27, 2024
1 parent d81b889 commit 1d4aa59
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 32 deletions.
93 changes: 90 additions & 3 deletions src/actions/job.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ import {
JobPostSchemaType,
JobQuerySchema,
JobQuerySchemaType,
RecommendedJobSchema,
RecommendedJobSchemaType,
} from '@/lib/validators/jobs.validator';
import { getJobFilters } from '@/services/jobs.services';
import { ServerActionReturnType } from '@/types/api.types';
import { getAllJobsAdditonalType, getJobType } from '@/types/jobs.types';
import {
getAllJobsAdditonalType,
getAllRecommendedJobs,
getJobType,
} from '@/types/jobs.types';

type additional = {
isVerifiedJob: boolean;
Expand Down Expand Up @@ -93,6 +99,7 @@ export const getAllJobs = withServerActionAsyncCatcher<
},
select: {
id: true,
type: true,
title: true,
description: true,
companyName: true,
Expand All @@ -101,9 +108,9 @@ export const getAllJobs = withServerActionAsyncCatcher<
minExperience: true,
maxExperience: true,
skills: true,
type: true,
address: true,
workMode: true,
category: true,
minSalary: true,
maxSalary: true,
postedAt: true,
Expand All @@ -127,6 +134,84 @@ export const getAllJobs = withServerActionAsyncCatcher<
}).serialize();
});

export const getRecommendedJobs = withServerActionAsyncCatcher<
RecommendedJobSchemaType,
ServerActionReturnType<getAllRecommendedJobs>
>(async (data) => {
const result = RecommendedJobSchema.parse(data);
const { id, category } = result;

// fettching the latest three jobs excluding the current job and in the same category
const jobs = await prisma.job.findMany({
where: {
category: category,
id: { not: id },
},
orderBy: {
postedAt: 'desc',
},
take: 3,
select: {
id: true,
type: true,
title: true,
description: true,
companyName: true,
city: true,
address: true,
category: true,
workMode: true,
minSalary: true,
minExperience: true,
maxExperience: true,
maxSalary: true,
postedAt: true,
skills: true,
companyLogo: true,
},
});

if (jobs.length === 0) {
const fallbackJobs = await prisma.job.findMany({
where: {
id: { not: id },
},
orderBy: {
postedAt: 'desc',
},
take: 3, // Fallback to showing latest 3 jobs from other categories
select: {
id: true,
type: true,
title: true,
description: true,
companyName: true,
city: true,
address: true,
workMode: true,
minSalary: true,
skills: true,
maxSalary: true,
postedAt: true,
companyLogo: true,
minExperience: true,
maxExperience: true,
category: true,
},
});

return new SuccessResponse(
'No jobs found in this category, here are some recent jobs',
200,
{ jobs: fallbackJobs }
).serialize();
}

return new SuccessResponse('Recommended jobs fetched successfully', 200, {
jobs,
}).serialize();
});

export const getJobById = withServerActionAsyncCatcher<
JobByIdSchemaType,
ServerActionReturnType<getJobType>
Expand All @@ -142,9 +227,10 @@ export const getJobById = withServerActionAsyncCatcher<
companyName: true,
companyBio: true,
companyEmail: true,
type: true,
companyLogo: true,
category: true,
city: true,
type: true,
hasExperiencerange: true,
minExperience: true,
maxExperience: true,
Expand Down Expand Up @@ -190,6 +276,7 @@ export const getRecentJobs = async () => {
workMode: true,
minSalary: true,
maxSalary: true,
category: true,
minExperience: true,
maxExperience: true,
skills: true,
Expand Down
33 changes: 28 additions & 5 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
.paused {
animation-play-state: paused;
}

:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
Expand Down Expand Up @@ -66,9 +67,11 @@
* {
@apply border-border;
}

body {
@apply bg-background text-foreground;
}

button,
[role='button'],
a {
Expand All @@ -87,10 +90,12 @@
stroke-dashoffset: 0;
}
}

@keyframes scroll {
0% {
transform: translateX(0);
}

100% {
transform: translateX(-100%);
}
Expand All @@ -112,11 +117,13 @@
rgba(0, 0, 0, 0)
);
}

.itemLeft img {
height: 100%;
width: 100%;
border-radius: 10px;
}

.itemRight img {
height: 100%;
width: 100%;
Expand Down Expand Up @@ -229,6 +236,7 @@
right: max(calc(100px * 8), calc(100% + 100px));
}
}

.scroll-container {
overflow: hidden;
white-space: nowrap;
Expand All @@ -255,6 +263,7 @@
0% {
transform: translateX(0%);
}

100% {
transform: translateX(-50%);
}
Expand All @@ -271,11 +280,13 @@
0% {
transform: translateX(0%);
}

100% {
transform: translateX(-50%);
}
}
}

.loader {
border: 8px solid #f3f3f3;
border-radius: 50%;
Expand All @@ -289,6 +300,7 @@
0% {
transform: rotate(0deg);
}

100% {
transform: rotate(360deg);
}
Expand All @@ -303,15 +315,20 @@

.ql-container.ql-snow {
border: none !important;
max-height: 56rem; /* Set a fixed height */
overflow-y: hidden; /* Hide vertical overflow */
overflow-x: auto; /* Allow horizontal scrolling */
max-height: 56rem;
/* Set a fixed height */
overflow-y: hidden;
/* Hide vertical overflow */
overflow-x: auto;
/* Allow horizontal scrolling */
}

.ql-editor {
min-height: 10px;
overflow-y: hidden; /* Prevent height increase */
white-space: nowrap; /* Ensure long lines don't wrap */
overflow-y: hidden;
/* Prevent height increase */
white-space: nowrap;
/* Ensure long lines don't wrap */
}

.ql-editor.ql-blank::before {
Expand All @@ -337,8 +354,11 @@

/* Ensure long content does not wrap within the editor */
.job-description-editor .ql-editor {

white-space: nowrap !important;
overflow-x: hidden !important; /* Allow horizontal scrolling */
overflow-y: hidden !important; /* Hide vertical overflow */

}

.pac-container {
Expand All @@ -350,15 +370,18 @@
font-family: '__Inter_36bd41', '__Inter_Fallback', sans-serif !important;
font-size: 14px !important;
}

.pac-item {
color: #fff !important;
border: none;
font-size: 14px;
}

.pac-item:hover {
background-color: hsl(0, 0%, 14.9%) !important;
cursor: pointer;
}

.pac-item-query {
color: white;
font-weight: bold;
Expand Down
45 changes: 42 additions & 3 deletions src/app/jobs/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { getJobById } from '@/actions/job.action';
import { getJobById, getRecommendedJobs } from '@/actions/job.action';
import { Job } from '@/components/job';
import JobCard from '@/components/job-card';
import { JobByIdSchemaType } from '@/lib/validators/jobs.validator';
import { ArrowLeft } from 'lucide-react';
import Link from 'next/link';
import { redirect } from 'next/navigation';

const page = async ({ params }: { params: JobByIdSchemaType }) => {
Expand All @@ -15,9 +18,45 @@ const page = async ({ params }: { params: JobByIdSchemaType }) => {
return redirect('/jobs');
}

const curatedJobs = await getRecommendedJobs({
id: jobDetail.id,
category: jobDetail.category,
});

if (!curatedJobs.status) {
return;
}

const recommendedJobs = curatedJobs.additional?.jobs;

return (
<div className="container my-8">
<Job job={jobDetail} />
<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">
<h1 className="text-xl font-semibold mb-4">Recommended for you</h1>
<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>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/infinitescroll.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export function LogoMarquee() {
</div>
))}
</Marquee>
<div className="pointer-events-none absolute inset-y-0 left-0 w-1/3 bg-gradient-to-r dark:from-neutral-950"></div>
<div className="pointer-events-none absolute inset-y-0 right-0 w-1/3 bg-gradient-to-l dark:from-neutral-950"></div>
<div className="pointer-events-none absolute inset-y-0 left-0 w-1/3 bg-gradient-to-r dark:from-background"></div>
<div className="pointer-events-none absolute inset-y-0 right-0 w-1/3 bg-gradient-to-l dark:from-background"></div>
</div>
</div>
);
Expand Down
Loading

0 comments on commit 1d4aa59

Please sign in to comment.