Skip to content

Commit

Permalink
created the bookmark functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Kashyap1ankit committed Oct 19, 2024
1 parent aee51e6 commit fabfeda
Show file tree
Hide file tree
Showing 12 changed files with 424 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
-- AlterEnum
ALTER TYPE "Role" ADD VALUE 'HR';

-- DropForeignKey
ALTER TABLE "Job" DROP CONSTRAINT "Job_userId_fkey";

Expand Down
14 changes: 14 additions & 0 deletions prisma/migrations/20241019104716_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- CreateTable
CREATE TABLE "Bookmark" (
"id" TEXT NOT NULL,
"jobId" TEXT NOT NULL,
"userId" TEXT NOT NULL,

CONSTRAINT "Bookmark_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Bookmark" ADD CONSTRAINT "Bookmark_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "Job"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Bookmark" ADD CONSTRAINT "Bookmark_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
12 changes: 11 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ model User {
oauthId String?
blockedByAdmin DateTime?
bookmark Bookmark[]
}

enum OauthProvider {
Expand Down Expand Up @@ -76,6 +77,15 @@ model Job {
postedAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id],onDelete: Cascade)
bookmark Bookmark[]
}

model Bookmark {
id String @id @default(uuid())
jobId String
userId String
job Job @relation(fields: [jobId],references: [id],onDelete: Cascade)
user User @relation(fields: [userId],references: [id],onDelete: Cascade)
}

enum Currency {
Expand Down
159 changes: 159 additions & 0 deletions src/actions/job.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
getAllRecommendedJobs,
getJobType,
} from '@/types/jobs.types';
import { revalidatePath } from 'next/cache';

type additional = {
isVerifiedJob: boolean;
Expand Down Expand Up @@ -383,3 +384,161 @@ export async function updateExpiredJobs() {
},
});
}

export async function toggleBookmarkAction(userId: string, jobId: string) {
try {
if (!userId || !jobId) throw new Error('User or Post is missing');

const checkForUser = await prisma.user.findFirst({
where: { id: userId },
});

if (!checkForUser)
throw new ErrorHandler(
'User with this email does not exist',
'BAD_REQUEST'
);

const checkForBookmark = await prisma.bookmark.findFirst({
where: {
jobId: jobId,
userId: userId,
},
});

if (checkForBookmark) {
const deletedBookmark = await prisma.bookmark.delete({
where: {
id: checkForBookmark.id,
},
});

return {
status: 201,
message: 'Bookmakr Deleted Successfully',
data: deletedBookmark,
};
}

const createNewBookmark = await prisma.bookmark.create({
data: {
jobId: jobId,
userId: userId,
},
});

return {
status: 200,
message: 'Bookmarked Successfully',
data: createNewBookmark,
};
} catch (error) {
return {
status: 404,
message: (error as Error).message,
data: null,
};
}
}

export async function CheckForBookmark(jobId: string) {
try {
const auth = await getServerSession(authOptions);
if (!auth || !auth?.user?.id)
throw new ErrorHandler('Not Authrised', 'UNAUTHORIZED');

if (!jobId) throw new Error('Post is missing');

const userId = auth.user.id;

const checkForUser = await prisma.user.findFirst({
where: { id: userId },
});

if (!checkForUser)
throw new ErrorHandler(
'User with this email does not exist',
'BAD_REQUEST'
);

const isBookmarked = await prisma.bookmark.findFirst({
where: {
jobId: jobId,
userId: userId,
},
});
if (!isBookmarked) throw new Error('Post is not Bookmarked');

return {
status: 200,
message: 'Post is Bookmarked',
};
} catch (error) {
return {
status: 404,
message: (error as Error).message,
};
}
}
const reloadBookmarkPage = () => {
revalidatePath('/jobs');
};

export async function GetBookmarkByUserId() {
try {
const auth = await getServerSession(authOptions);

if (!auth || !auth?.user?.id)
throw new ErrorHandler('Not Authrised', 'UNAUTHORIZED');

const userId = auth.user.id;

const getUserBookmarks = await prisma.bookmark.findMany({
where: {
userId: userId,
},

select: {
job: {
select: {
id: true,
type: true,
title: true,
description: true,
companyName: true,
city: true,
companyBio: true,
hasExperiencerange: true,
minExperience: true,
maxExperience: true,
hasExpiryDate: true,
expiryDate: true,
skills: true,
address: true,
workMode: true,
category: true,
minSalary: true,
maxSalary: true,
postedAt: true,
companyLogo: true,
},
},
},
});

if (!getUserBookmarks || getUserBookmarks.length === 0)
throw new Error('No Bookmarked Job found');
reloadBookmarkPage();
return {
status: 200,
message: 'Bookmarks fetched ',
data: getUserBookmarks,
};
} catch (error) {
return {
status: 404,
message: (error as Error).message,
data: null,
};
}
}
4 changes: 4 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,7 @@ html {
html {
scroll-behavior: smooth;
}

.no-scrollbar::-webkit-scrollbar {
display: none;
}
64 changes: 64 additions & 0 deletions src/app/profile/bookmarks/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use client';

import { GetBookmarkByUserId } from '@/actions/job.action';
import BookmarkCardSkeleton from '@/components/BookmarkCardSkeletion';
import JobCard from '@/components/Jobcard';

import { JobType } from '@/types/jobs.types';
import { useEffect, useState } from 'react';

export default function BookmarkPage() {
const [loading, setLoading] = useState(true);
const [errorNoPost, setErrorNoPost] = useState(false);
const [bookmarkedJobs, setBookmarkedJobs] = useState<
{
job: JobType;
}[]
>();

useEffect(() => {
const getBookmark = async () => {
setLoading(true);
try {
const response = await GetBookmarkByUserId();
if (response.status !== 200 || !response.data) {
return setErrorNoPost(true);
}
setBookmarkedJobs(response.data);
} finally {
setLoading(false);
}
};
getBookmark();
}, []);

return (
<div className="md:container flex flex-col w-full">
<div className="flex justify-between items-center">
<span>Bookmarks</span>
</div>

{loading ? (
<div className="space-y-4 w-full">
{[1, 2, 3, 4, 5].map((e: number) => (
<BookmarkCardSkeleton key={e} />
))}
</div>
) : (
<>
{errorNoPost ? (
<div className="w-full h-screen flex items-center justify-center text-white">
<p>No Bookmarks found</p>
</div>
) : (
<div className="h-full overflow-y-scroll no-scrollbar flex flex-col gap-8 my-3">
{bookmarkedJobs?.map(({ job }, index) => {
return <JobCard job={job} key={index} className="w-full" />;
})}
</div>
)}
</>
)}
</div>
);
}
2 changes: 1 addition & 1 deletion src/app/profile/edit/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const EditProfilePage = () => {
const router = useRouter();
const session = useSession();
useEffect(() => {
if (session.status !== 'loading' && session.status === 'unauthenticated')
if (session.status === 'unauthenticated')
router.push(`${APP_PATHS.SIGNIN}?redirectTo=/profile`);
}, [session.status, router]);
const user = session.data?.user;
Expand Down
4 changes: 2 additions & 2 deletions src/app/profile/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ const ProfileLayout = ({ children }: { children: React.ReactNode }) => {
useEffect(() => {
if (session.status !== 'loading' && session.status === 'unauthenticated')
router.push(`${APP_PATHS.SIGNIN}?redirectTo=/profile`);
}, [session.status]);
}, [session.status, router]);
return (
<div className="container flex max-md:flex-col md:gap-5 w-full relative">
<Sidebar />
<div className="flex px-2 w-full overflow-y-auto md:max-h-[73vh] lg:h-full md:border md:rounded-xl md:pt-6 ">
<div className="flex px-2 w-full overflow-y-auto md:max-h-[73vh] lg:h-full md:border md:rounded-xl md:pt-6 no-scrollbar">
{children}
</div>
</div>
Expand Down
28 changes: 28 additions & 0 deletions src/components/BookmarkCardSkeletion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Card, CardContent } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';

export default function BookmarkCardSkeleton() {
return (
<Card className=" border shadow-sm ">
<CardContent className="p-6">
<div className="flex flex-col sm:flex-row items-start gap-4">
<Skeleton className="w-12 h-12 rounded-full " />
<div className="flex-1 space-y-2">
<Skeleton className="w-48 h-6 " />
<Skeleton className="w-32 h-4 " />
<div className="flex flex-wrap gap-4">
<Skeleton className="w-20 h-6 " />
<Skeleton className="w-20 h-6 " />
<Skeleton className="w-32 h-6 " />
</div>
<div className="flex flex-wrap gap-2">
{[1, 2, 3, 4, 5, 6].map((skill) => (
<Skeleton key={skill} className="w-16 h-4 " />
))}
</div>
</div>
</div>
</CardContent>
</Card>
);
}
Loading

0 comments on commit fabfeda

Please sign in to comment.