Skip to content

Commit

Permalink
Merge pull request #46 from Kashyap1ankit/fix/hero
Browse files Browse the repository at this point in the history
added approval sytem
  • Loading branch information
Kashyap1ankit authored Nov 25, 2024
2 parents 25683a0 + ab62d6c commit f4a99c7
Show file tree
Hide file tree
Showing 15 changed files with 329 additions and 22 deletions.
87 changes: 87 additions & 0 deletions app/actions/posts/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export async function CreateJob(postdata: createJobSchemaType) {
salary_disclosed: postdata.salary_disclosed,
salary_max: postdata.salary_max,
salary_min: postdata.salary_min,
approved: false,
author: {
connect: {
id: response.userId,
Expand Down Expand Up @@ -76,6 +77,66 @@ export async function GetAllPost() {
createdAt: "desc",
},

where: {
approved: false,
},

select: {
id: true,
apply_link: true,
company: true,
company_logo: true,
company_website: true,
experience_level: true,
job_type: true,
location: true,
position: true,
role_description: true,
salary_disclosed: true,
salary_max: true,
salary_min: true,
approved: true,
author: {
select: {
id: true,
avatar: true,
username: true,
role: true,
},
},
createdAt: true,
},
});

if (!allPosts) throw new Error("No Posts Found");

return {
status: 200,
message: "Succesfylly Fetched all Posts",
data: allPosts,
};
} catch (error) {
return {
status: 404,
message: (error as Error).message,
data: [],
};
}
}

//Get All approved jobs posting

export async function GetAllApprovedPost() {
try {
const allPosts = await prisma.post.findMany({
where: {
approved: true,
},

orderBy: {
createdAt: "desc",
},

select: {
id: true,
apply_link: true,
Expand Down Expand Up @@ -261,3 +322,29 @@ export async function UploadImage(data: FormData) {
};
}
}

//Approve job

export async function ApproveJob(id: string) {
try {
await prisma.post.update({
where: {
id,
},

data: {
approved: true,
},
});

return {
status: 200,
message: "Job has been approved",
};
} catch (error) {
return {
status: 400,
message: (error as Error).message,
};
}
}
5 changes: 5 additions & 0 deletions app/admin/manage/posts/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import PendingPostsComp from "@/components/Admin/Manage/PendingTab";

export default function AdminManagePostPage() {
return <PendingPostsComp />;
}
4 changes: 2 additions & 2 deletions components/Admin/AdminComp.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import { useEffect } from "react";
import { GetAllPost } from "@/app/actions/posts/jobs";
import { GetAllApprovedPost } from "@/app/actions/posts/jobs";
import { toast } from "sonner";
import { GetAllPostResponseType } from "@/types/types";
import { useRecoilState, useRecoilValue } from "recoil";
Expand Down Expand Up @@ -35,7 +35,7 @@ export default function AllJobsComp() {
const getAllJobs = async () => {
setLoading(true);
try {
const response: GetAllPostResponseType = await GetAllPost();
const response: GetAllPostResponseType = await GetAllApprovedPost();
if (response.status !== 200) throw new Error(response.message);
setAllJobs(response.data);
} catch (error) {
Expand Down
22 changes: 20 additions & 2 deletions components/Admin/AdminSideBarComp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function AdminSideBarComp() {

useEffect(() => {
if (pathname.includes("/admin")) setActiveTab("admin");
if (pathname.includes("/admin/manage/posts")) setActiveTab("manage");
if (pathname.includes("/admin/users/all")) setActiveTab("users");
}, []);

Expand All @@ -35,7 +36,24 @@ export default function AdminSideBarComp() {
: ""
}`}
>
All Posts
Live Posts
</p>
</Link>

<Link
href={`/admin/manage/posts`}
onClick={() => setActiveTab("manage")}
className="min-w-40 text-center"
aria-label="admin-user"
>
<p
className={`mt-8 text-gray-400 duration-500 ${
activeTab === "manage"
? "w-fit w-full rounded-full bg-secondaryBorder p-2 font-kanit text-sideBarColor"
: ""
}`}
>
Pending Posts
</p>
</Link>

Expand All @@ -52,7 +70,7 @@ export default function AdminSideBarComp() {
: ""
}`}
>
All Users
Registered Users
</p>
</Link>
</>
Expand Down
167 changes: 167 additions & 0 deletions components/Admin/Manage/PendingTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
"use client";
import { useEffect, useState } from "react";
import { ApproveJob, GetAllPost } from "@/app/actions/posts/jobs";
import { toast } from "sonner";
import { ApprovedJobLisitingType, GetAllPostResponseType } from "@/types/types";
import { useRecoilState, useRecoilValue } from "recoil";
import { joblistingError, universalLoader } from "@/store/store";

import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";

import { poppins } from "@/utils/fonts/font";
import Link from "next/link";

import Image from "next/image";
import Loader from "@/app/loading";
import { CircleCheck } from "lucide-react";
import { SendNotification } from "@/app/actions/notification";
import { DeletePostComp } from "@/components/Job/MoreDialog";

export default function PendingPostsComp() {
const [allJobs, setAllJobs] = useState<ApprovedJobLisitingType[] | []>([]);
const [loading, setLoading] = useRecoilState(universalLoader);
const errorNoPost = useRecoilValue(joblistingError);

useEffect(() => {
const getAllJobs = async () => {
setLoading(true);
try {
const response: GetAllPostResponseType = await GetAllPost();
if (response.status !== 200) throw new Error(response.message);
setAllJobs(response.data);
} catch (error) {
toast((error as Error).message || "Error Occured");
} finally {
setLoading(false);
}
};

getAllJobs();
}, []);

async function handleApproveJob(id: string, company: string) {
try {
const response = await ApproveJob(id);
if (response.status !== 200) throw new Error(response.message);

setAllJobs((prev) => {
const filteredArray = prev.filter((e) => e.id !== id);
return filteredArray;
});

toast.success("Job Approved", {
style: {
backgroundColor: "#65a30d",
color: "white",
borderColor: "#65a30d",
},
});

await SendNotification(company);
} catch (error) {
toast.error((error as Error).message);
}
}

return (
<>
{errorNoPost || allJobs.length <= 0 ? (
<div className="flex h-screen max-h-screen w-full items-center justify-center text-white">
<p>No Post found</p>
</div>
) : (
<div className="no-scrollbar h-screen max-h-screen gap-8 overflow-y-scroll bg-transparent py-6 md:flex md:flex-col">
{loading ? (
<Loader />
) : (
<>
<Table>
<TableHeader className="">
<TableRow
className={`${poppins.className} bg-gray-700 font-bold text-white hover:bg-gray-700`}
>
<TableHead className="rounded-tl-md text-white">
Id
</TableHead>
<TableHead className="text-white">Company</TableHead>
<TableHead className="text-white">Role</TableHead>
<TableHead className="text-white">Posted By</TableHead>
<TableHead className="text-white">CreatedAt</TableHead>
<TableHead className="rounded-tr-md text-white">
Action
</TableHead>
</TableRow>
</TableHeader>
<TableBody
className={`${poppins.className} bg-primaryBorder font-bold text-gray-400 text-white`}
>
{allJobs.map((post) => (
<TableRow
key={post.id}
className="cursor-pointer hover:bg-primaryBorder"
>
<TableCell className="font-medium">
#{post.id.slice(0, 5)}
</TableCell>
<TableCell>
<Link
href={post.company_website || "/jobs"}
aria-label="company_website"
target="_blank"
className="hover:text-blue-500"
>
{post.company}
</Link>
</TableCell>
<TableCell>{post.position}</TableCell>
<TableCell>
<Link
href={`/user/${post.author.id}/profile` || "/jobs"}
aria-label="company_website"
target="_blank"
className="hover:text-blue-500"
>
<Image
src={post.author.avatar || "/Images/avatar.png"}
width={500}
height={500}
alt="avatar"
aria-label="user-avatar"
className="w-12 rounded-full"
/>
</Link>
</TableCell>
<TableCell>
{post.createdAt.toLocaleDateString()}
</TableCell>
<TableCell className="flex gap-2">
<CircleCheck
className="text-green-500"
onClick={() =>
handleApproveJob(post.id, post.company)
}
/>
<DeletePostComp
postId={post.id}
authorId={post.author.id}
cross={true}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</>
)}
</div>
)}
</>
);
}
4 changes: 0 additions & 4 deletions components/GetNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,15 @@ export default function GetNotification() {
async function subscribeUser(registration: ServiceWorkerRegistration) {
try {
if (!("Notification" in window)) {
console.log("notification error");
throw new Error("This browser does not support notifications");
}

const permission = await Notification.requestPermission();
if (permission !== "granted") {
console.log("permission eror");
throw new Error("Notification permission denied");
}

if (!("PushManager" in window)) {
console.log("pushmanager eror");
throw new Error("Push messaging is not supported");
}

Expand All @@ -104,7 +101,6 @@ export default function GetNotification() {

const subcriptionObject =
await registration.pushManager.subscribe(option);
console.log("subs model", subcriptionObject);

const response = await addNotificationSubscription(
JSON.stringify(subcriptionObject),
Expand Down
2 changes: 1 addition & 1 deletion components/Job/Create/CreateForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default function CreateForm() {
data.company_logo = uploadedImageUrl.secure_url;
const response = await CreateJob(data);
if (response.status !== 200) throw new Error(response.message);
toast.success("Successfully created", {
toast.success("Successfully created ! Now wait for admin approval", {
style: {
backgroundColor: "#65a30d",
color: "white",
Expand Down
4 changes: 2 additions & 2 deletions components/Job/JobSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
import { JobLisitingType } from "@/types/types";
import { ApprovedJobLisitingType } from "@/types/types";
import { fraunces, poppins, roboto_slab } from "@/utils/fonts/font";
import { BriefcaseBusiness, Pin, X } from "lucide-react";
import { useState } from "react";
Expand Down Expand Up @@ -36,7 +36,7 @@ export default function JobSheetComp({
salary_max,
experience_level,
apply_link,
}: JobLisitingType) {
}: ApprovedJobLisitingType) {
const [applySheet, setApplySheet] = useState(false);
return (
<div id={id}>
Expand Down
Loading

0 comments on commit f4a99c7

Please sign in to comment.