├── Client
├── src
│ ├── index.css
│ ├── assets
│ │ ├── icons
│ │ │ ├── error.png
│ │ │ ├── teamIcon.png
│ │ │ ├── profileIcon.png
│ │ │ ├── templeteIcon.png
│ │ │ ├── careerPageIcon.png
│ │ │ ├── home.svg
│ │ │ ├── down.svg
│ │ │ ├── reports.svg
│ │ │ ├── show_more.svg
│ │ │ ├── asd.svg
│ │ │ ├── jobs.svg
│ │ │ ├── delete.svg
│ │ │ ├── employees.svg
│ │ │ ├── settings.svg
│ │ │ ├── notification.svg
│ │ │ ├── candidates.svg
│ │ │ └── share.svg
│ │ └── illustrations
│ │ │ ├── 404.png
│ │ │ ├── job.png
│ │ │ ├── dep_1.jpg
│ │ │ ├── dep_2.jpg
│ │ │ ├── dep_3.jpg
│ │ │ └── done.png
│ ├── Components
│ │ ├── Common
│ │ │ ├── ProtectedRoute.jsx
│ │ │ ├── MainButton.jsx
│ │ │ ├── InputText.jsx
│ │ │ └── GoBackButton.jsx
│ │ ├── ProfileSetup
│ │ │ ├── ProfileSetup.jsx
│ │ │ ├── SucessModel.jsx
│ │ │ ├── ProfileP1.jsx
│ │ │ └── Profile_Social3.jsx
│ │ ├── Dashboard
│ │ │ ├── ProfileCreation
│ │ │ │ └── NavigationTab.jsx
│ │ │ └── CreateJob
│ │ │ │ ├── TopRcruitementCycle.jsx
│ │ │ │ ├── CreatedJobElement.jsx
│ │ │ │ ├── AppliedApplicantProfile.jsx
│ │ │ │ ├── CreateJobHeadaer.jsx
│ │ │ │ └── FIlterProfiles.jsx
│ │ ├── HiredCandidatePage
│ │ │ └── MainPage.jsx
│ │ └── RecruitmentStage
│ │ │ ├── DeleteCandidateProfileButton.jsx
│ │ │ ├── SwitchStatus.jsx
│ │ │ ├── ReccomendidCandidateCard.jsx
│ │ │ ├── WithdrawnDetailsCard.jsx
│ │ │ ├── WithdrawnCandidateCard.jsx
│ │ │ └── ReccomendedCandidateDetailsCard.jsx
│ ├── Pages
│ │ ├── Dashboard
│ │ │ ├── ProfileCreation
│ │ │ │ ├── Profile-Office.jsx
│ │ │ │ ├── Profile-Sucess.jsx
│ │ │ │ ├── ProfileSocial.jsx
│ │ │ │ ├── ProfileTeam_Members.jsx
│ │ │ │ └── ProfileCreation.jsx
│ │ │ └── NotPageFound404.jsx
│ │ ├── HiredCandidates
│ │ │ ├── HiredCandidate.jsx
│ │ │ └── HiredCandidatesDetails.jsx
│ │ ├── RecruitmentCycle
│ │ │ ├── RejectedCandidates.jsx
│ │ │ ├── InterviewingCandidate.jsx
│ │ │ ├── WithdrawnCandidate.jsx
│ │ │ ├── HiredCandidates.jsx
│ │ │ ├── ReccomendedCandidates.jsx
│ │ │ ├── AppliedCandidateDetails.jsx
│ │ │ ├── WithdrawnDetails.jsx
│ │ │ └── ReccomendedCandidatesDetails.jsx
│ │ ├── Employees
│ │ │ ├── MainPageOfEmployees.jsx
│ │ │ └── AddNewEmployee.jsx
│ │ ├── CreateJob
│ │ │ └── CreateJob.jsx
│ │ ├── Settings
│ │ │ └── MainPageOfSetting.jsx
│ │ ├── EndUser
│ │ │ ├── PostedJobDescription.jsx
│ │ │ └── postedJobs.jsx
│ │ └── Auth
│ │ │ └── ForgetPassword.jsx
│ ├── App
│ │ └── Store.js
│ ├── main.jsx
│ ├── Features
│ │ ├── Dashboard
│ │ │ └── Organization_Details_Slice.js
│ │ └── JobCycle
│ │ │ └── storeAllCandidatesDetails.js
│ └── App.css
├── public
│ └── logo.png
├── postcss.config.cjs
├── vite.config.js
├── .gitignore
├── tailwind.config.cjs
├── package.json
└── index.html
├── Server
├── Routes
│ ├── Report.js
│ ├── SettingRouter.js
│ ├── ProfileCreation.js
│ ├── UserRoute.js
│ ├── Jobs.js
│ └── RecruitmentCycle.js
├── Controllers
│ ├── Recruitment Cycle
│ │ ├── HiredEmail.js
│ │ ├── GetCandidateDetails.js
│ │ ├── ShowActiveCandidateDetails.js
│ │ ├── ShowInterviewingCandidate.js
│ │ ├── GetReccomendedCandidateDetails.js
│ │ ├── GetWithdrawnCandidateDetails.js
│ │ ├── GetComments.js
│ │ ├── GetHiredCandidate.js
│ │ ├── GetRejectedCandidate.js
│ │ ├── UpdateWithdrawnReason.js
│ │ ├── GetWithdrawnCandidate.js
│ │ ├── SaveInterviewDateAndTime.js
│ │ ├── HandleComments.js
│ │ ├── GetReccomendedCandidates.js
│ │ ├── PatchComments.js
│ │ ├── DeleteCandidateProfile.js
│ │ ├── UpdateStatus.js
│ │ ├── SubmitFeedbacl.js
│ │ ├── SendInterviewEmail.js
│ │ ├── SentHiredEmail.js
│ │ ├── SentDeclinedEmail.js
│ │ └── FilterCandidates.js
│ ├── Jobs
│ │ ├── GetAllPostedJobs.js
│ │ ├── GetSelectedJobDescription.js
│ │ ├── FilterShowClosedJobs.js
│ │ ├── Filter-ShowActiveJobs.js
│ │ ├── GetJobs.js
│ │ ├── GetOrganizationPostedJob.js
│ │ └── PostJob.js
│ ├── Dashboard
│ │ ├── GetProfilePic.js
│ │ └── Home.js
│ ├── Settings
│ │ ├── UpdateProfileSettings.js
│ │ └── UpdateProfilePicture.js
│ ├── UserController
│ │ ├── VerifyMail.js
│ │ ├── UpdatePassword.js
│ │ ├── verifyForgetpwd.js
│ │ └── Login.js
│ ├── Setup Profile
│ │ └── Profile_Setup.js
│ └── Report Stats
│ │ └── MainPage.js
├── vercel.json
├── Config
│ ├── Cloudnary.js
│ ├── Database.js
│ └── Multer.js
├── .gitignore
├── Middleware
│ ├── VerifyToken.js
│ └── AuthMiddleware.js
├── Models
│ ├── Comment.js
│ ├── User_Model.js
│ ├── Organization_Model.js
│ ├── JobModel.js
│ └── Candidate.js
├── package.json
└── index.js
├── .gitignore
└── README.md
/Client/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/Client/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/public/logo.png
--------------------------------------------------------------------------------
/Client/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/icons/error.png
--------------------------------------------------------------------------------
/Client/src/assets/icons/teamIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/icons/teamIcon.png
--------------------------------------------------------------------------------
/Client/src/assets/icons/profileIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/icons/profileIcon.png
--------------------------------------------------------------------------------
/Client/src/assets/illustrations/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/illustrations/404.png
--------------------------------------------------------------------------------
/Client/src/assets/illustrations/job.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/illustrations/job.png
--------------------------------------------------------------------------------
/Client/src/assets/icons/templeteIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/icons/templeteIcon.png
--------------------------------------------------------------------------------
/Client/src/assets/illustrations/dep_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/illustrations/dep_1.jpg
--------------------------------------------------------------------------------
/Client/src/assets/illustrations/dep_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/illustrations/dep_2.jpg
--------------------------------------------------------------------------------
/Client/src/assets/illustrations/dep_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/illustrations/dep_3.jpg
--------------------------------------------------------------------------------
/Client/src/assets/illustrations/done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/illustrations/done.png
--------------------------------------------------------------------------------
/Client/src/assets/icons/careerPageIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hamza-Sajid/Smart-Cruiter-FYP/HEAD/Client/src/assets/icons/careerPageIcon.png
--------------------------------------------------------------------------------
/Client/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/Server/Routes/Report.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const StatMainPage = require('../Controllers/Report Stats/MainPage');
3 |
4 | const RouterReport = express.Router();
5 |
6 | RouterReport.post("/main", StatMainPage)
7 |
8 | module.exports = RouterReport;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/HiredEmail.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const app = express();
3 |
4 |
5 | const HiredEmail = async (req, res, next) => {
6 |
7 | const { email } = req.body;
8 |
9 |
10 |
11 | }
12 |
13 | module.exports = HiredEmail;
--------------------------------------------------------------------------------
/Server/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "builds": [
4 | {
5 | "src": "index.js",
6 | "use": "@vercel/node"
7 | }
8 | ],
9 | "routes": [
10 | {
11 | "src": "/(.*)",
12 | "dest": "index.js"
13 | }
14 | ]
15 | }
--------------------------------------------------------------------------------
/Server/Config/Cloudnary.js:
--------------------------------------------------------------------------------
1 | const Cloudinary = require('cloudinary');
2 |
3 | const cloud = Cloudinary.config({
4 |
5 | cloud_name: process.env.CLOUDNAME,
6 | api_key: process.env.APIKEY,
7 | api_secret: process.env.APISECRET
8 |
9 | });
10 |
11 |
12 | module.exports = cloud;
--------------------------------------------------------------------------------
/Client/src/Components/Common/ProtectedRoute.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Navigate, Outlet } from "react-router-dom";
3 |
4 | function ProtectedRoute() {
5 | const isLogin = localStorage.getItem("token");
6 | return isLogin ? : ;
7 | }
8 |
9 | export default ProtectedRoute;
10 |
--------------------------------------------------------------------------------
/Client/src/Components/Common/MainButton.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function MainButton({ value }) {
4 | return (
5 |
11 | );
12 | }
13 |
14 | export default MainButton;
15 |
--------------------------------------------------------------------------------
/Server/Config/Database.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose")
2 | const connection = async () => {
3 | try {
4 | const connect = await mongoose.connect(process.env.MONGOURL);
5 | console.log("Database connected");
6 | }
7 |
8 | catch (e) {
9 | console.log("DB Error: " + e);
10 | }
11 | }
12 |
13 | module.exports = connection;
--------------------------------------------------------------------------------
/Client/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .env
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | pnpm-debug.log*
10 | lerna-debug.log*
11 |
12 | node_modules
13 | dist
14 | dist-ssr
15 | *.local
16 |
17 | # Editor directories and files
18 | .vscode/*
19 | !.vscode/extensions.json
20 | .idea
21 | .DS_Store
22 | *.suo
23 | *.ntvs*
24 | *.njsproj
25 | *.sln
26 | *.sw?
27 |
--------------------------------------------------------------------------------
/Server/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .env
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | pnpm-debug.log*
10 | lerna-debug.log*
11 | .env
12 | node_modules
13 | dist
14 | dist-ssr
15 | *.local
16 |
17 | # Editor directories and files
18 | .vscode/*
19 | !.vscode/extensions.json
20 | .idea
21 | .DS_Store
22 | *.suo
23 | *.ntvs*
24 | *.njsproj
25 | *.sln
26 | *.sw?
27 |
--------------------------------------------------------------------------------
/Server/Config/Multer.js:
--------------------------------------------------------------------------------
1 |
2 | const multer = require('multer')
3 |
4 | const data = multer({
5 | storage: multer.diskStorage({}),
6 | fileFilter: (req, file, cb) => {
7 | if (!file.mimetype.match(/jpg|jpeg|png/)) {
8 | cb(new Error("file is not in supported format"), false);
9 | return
10 | }
11 | cb(null, true)
12 | }
13 | })
14 |
15 | module.exports = data;
--------------------------------------------------------------------------------
/Client/src/Pages/Dashboard/ProfileCreation/Profile-Office.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Profile_Office2 from "../../../Components/ProfileSetup/Profile_Office2";
3 | export default function Profile_Office() {
4 | return (
5 |
6 |
7 |
Profile Creation
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/Client/src/Pages/Dashboard/ProfileCreation/Profile-Sucess.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import SucessModel from "../../../Components/ProfileSetup/SucessModel";
3 |
4 | function Profile_Sucess() {
5 | return (
6 |
7 |
8 |
Profile Creation
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default Profile_Sucess;
16 |
--------------------------------------------------------------------------------
/Client/src/Pages/Dashboard/ProfileCreation/ProfileSocial.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Profile_Social3 from "../../../Components/ProfileSetup/Profile_Social3";
3 |
4 | function ProfileSocial() {
5 | return (
6 |
7 |
8 |
Profile Creation
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default ProfileSocial;
16 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/home.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Client/src/Components/Common/InputText.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function InputText({ type, palceholder, value, label, onChange }) {
4 | return (
5 | <>
6 |
7 |
14 | >
15 | );
16 | }
17 |
18 | export default InputText;
19 |
--------------------------------------------------------------------------------
/Client/src/Pages/Dashboard/ProfileCreation/ProfileTeam_Members.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ProfileAddTeam from "../../../Components/ProfileSetup/ProfileAddTeam";
3 |
4 | function ProfileTeam_Members() {
5 | return (
6 |
7 |
8 |
Profile Creation
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default ProfileTeam_Members;
16 |
--------------------------------------------------------------------------------
/Client/src/App/Store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from '@reduxjs/toolkit'
2 | import OrganizationDetailsReducer from '../Features/Dashboard/Organization_Details_Slice'
3 | import OrganizationDetails from '../Features/JobCycle/storeAllCandidatesDetails'
4 | export const store = configureStore({
5 | reducer: { OrganizationDetailsReducer, }
6 |
7 | // reducer: {
8 |
9 |
10 | // organizationReducer: OrganizationDetailsReducer,
11 | // candidatesReducer: OrganizationDetails,
12 |
13 | // }
14 | })
--------------------------------------------------------------------------------
/Server/Middleware/VerifyToken.js:
--------------------------------------------------------------------------------
1 | const userModel = require("../Models/User_Model");
2 |
3 | const VerifyToken = async (req, res, next) => {
4 |
5 |
6 | try {
7 | const findUser = await userModel.findById({ _id: req.body.userID })
8 | if (findUser) {
9 | res.send(findUser)
10 | }
11 | else {
12 | res.send("INVALID TOKEN");
13 | }
14 | } catch (error) {
15 | console.log(error);
16 | }
17 |
18 |
19 | }
20 |
21 | module.exports = VerifyToken;
--------------------------------------------------------------------------------
/Server/Controllers/Jobs/GetAllPostedJobs.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Job = require('../../Models/JobModel');
3 |
4 | const app = express();
5 |
6 |
7 | const GetAllPostedJobs = async (req, res, next) => {
8 |
9 | const fetchAllPostedJobs = await Job.find();
10 |
11 | if (fetchAllPostedJobs) {
12 | return res.status(200).json({ fetchAllPostedJobs })
13 | }
14 | else {
15 | return res.status(400).json({ message: "No job found" })
16 | }
17 | }
18 |
19 | module.exports = GetAllPostedJobs;
--------------------------------------------------------------------------------
/Client/src/assets/icons/down.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/reports.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Client/src/Pages/Dashboard/NotPageFound404.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import NotFound from "../../assets/illustrations/404.png";
3 | function NotPageFound404() {
4 | return (
5 |
6 |
7 |

8 |
9 |
10 |
Enter valid address!
11 |
12 |
13 | );
14 | }
15 |
16 | export default NotPageFound404;
17 |
--------------------------------------------------------------------------------
/Server/Controllers/Jobs/GetSelectedJobDescription.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Job = require("../../Models/JobModel");
3 | const app = express();
4 |
5 |
6 | const GetSelectedJobDescription = async (req, res, next) => {
7 |
8 | const { id } = req.body;
9 |
10 | const jobs = await Job.find({ _id: id });
11 | if (jobs) {
12 | return res.status(200).json({ jobs })
13 | }
14 | else {
15 | return res.status(400).json({ message: 'an error has been occured' })
16 | }
17 |
18 | }
19 |
20 | module.exports = GetSelectedJobDescription;
--------------------------------------------------------------------------------
/Server/Controllers/Jobs/FilterShowClosedJobs.js:
--------------------------------------------------------------------------------
1 | const Job = require("../../Models/JobModel");
2 |
3 | const FilterShowClosedJobs = async (req, res) => {
4 | const id = req.body;
5 |
6 | if (!id) {
7 | return res.status(440).json({ message: "No id found" });
8 | }
9 |
10 | const jobs = await Job.find({ org_id: id.id, job_status: 'Closed' });
11 |
12 | if (jobs) {
13 | return res.status(200).json({ jobs })
14 | }
15 | else {
16 | return res.status(404).json({ message: "No user found" })
17 | }
18 | }
19 | module.exports = FilterShowClosedJobs;
--------------------------------------------------------------------------------
/Client/src/Pages/Dashboard/ProfileCreation/ProfileCreation.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Link, Outlet } from "react-router-dom";
3 | import NavigationTab from "../../../Components/Dashboard/ProfileCreation/NavigationTab";
4 | import ProfileP1 from "../../../Components/ProfileSetup/ProfileP1";
5 |
6 | function ProfileCreation() {
7 | return (
8 |
9 |
Profile Creation
10 |
11 |
12 | );
13 | }
14 |
15 | export default ProfileCreation;
16 |
--------------------------------------------------------------------------------
/Server/Controllers/Jobs/Filter-ShowActiveJobs.js:
--------------------------------------------------------------------------------
1 | const Job = require("../../Models/JobModel");
2 |
3 | const showActiveJobs = async (req, res, next) => {
4 |
5 | const id = req.body;
6 |
7 | if (!id) {
8 | return res.status(440).json({ message: "No id found" });
9 | }
10 |
11 | const jobs = await Job.find({ org_id: id.id, job_status: 'Active' });
12 |
13 | if (jobs) {
14 | return res.status(200).json({ jobs })
15 | }
16 | else {
17 | return res.status(404).json({ message: "No user found" })
18 | }
19 |
20 | }
21 |
22 | module.exports = showActiveJobs;
--------------------------------------------------------------------------------
/Server/Controllers/Dashboard/GetProfilePic.js:
--------------------------------------------------------------------------------
1 | const OrganizationModal = require("../../Models/Organization_Model");
2 |
3 | const GetProfilePicture = async (req, res) => {
4 |
5 | const organization_id = req.body.organization_id
6 |
7 | const organizaion = await OrganizationModal.findById(organization_id);
8 | if (organizaion) {
9 | const { logo } = organizaion;
10 | return res.status(200).json(logo)
11 | }
12 | else {
13 | res.status(404).json({ message: "No organization found , enter valid organization" });
14 | }
15 | }
16 |
17 | module.exports = GetProfilePicture;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/GetCandidateDetails.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Candidate = require('../../Models/Candidate');
3 | const app = express();
4 |
5 | const GetCandidateDetails = async (req, res, next) => {
6 | const { id } = req.body;
7 |
8 | const candidate_details = await Candidate.findById(id);
9 |
10 | if (candidate_details) {
11 | return res.status(200).json({ candidate_details })
12 | }
13 |
14 | else {
15 | return res.status(404).json({ message: "No candidate found with this id" })
16 | }
17 | }
18 |
19 | module.exports = GetCandidateDetails;
--------------------------------------------------------------------------------
/Client/tailwind.config.cjs:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./index.html",
5 | "./src/**/*.{js,ts,jsx,tsx}",
6 | ],
7 | plugins: [require("daisyui")],
8 | theme: {
9 | extend: {
10 | colors: {
11 | 'primarytext': '333232',
12 | 'primary': '#0063B2',
13 | 'lighttext': '#C3C3C4',
14 | 'secondrytext': '#888888',
15 | 'secondry': '#2687F0',
16 | 'background': '#FAFAFC',
17 |
18 | }
19 |
20 | },
21 | daisyui: {
22 | // themes: ["light", "dark", "cupcake"],
23 | themes: false,
24 | },
25 | }
26 | }
--------------------------------------------------------------------------------
/Server/Controllers/Jobs/GetJobs.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Job = require("../../Models/JobModel");
3 | const app = express();
4 |
5 |
6 | const GetJob = async (req, res, next) => {
7 |
8 | const { id } = req.body;
9 | console.log(id);
10 | if (!id) {
11 | return res.status(440).json({ message: "on id found" });
12 | }
13 | const jobs = await Job.find({ org_id: id });
14 | if (jobs) {
15 | return res.status(200).json({ jobs })
16 | }
17 | else {
18 | return res.status(400).json({ message: 'an error has been occured' })
19 | }
20 |
21 | }
22 |
23 | module.exports = GetJob;
--------------------------------------------------------------------------------
/Client/src/assets/icons/show_more.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Server/Controllers/Dashboard/Home.js:
--------------------------------------------------------------------------------
1 | const OrganizationModal = require("../../Models/Organization_Model");
2 |
3 | const Home = async (req, res, next) => {
4 | console.log(req.body)
5 | const { organization_id } = req.body.data;
6 | console.log(' I am going to run');
7 | console.log(organization_id);
8 | const organizaion = await OrganizationModal.findById(organization_id);
9 | console.log(organizaion);
10 | if (organizaion) {
11 | return res.status(200).json({ organizaion })
12 | }
13 | else {
14 | res.status(404).json({ message: "No organization found , enter valid organization" });
15 | }
16 | }
17 |
18 | module.exports = Home;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/ShowActiveCandidateDetails.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const Candidate = require('../../Models/Candidate.js')
4 |
5 | const showActiveCandidateDetails = async (req, res, next) => {
6 | const { user_id } = req.body;
7 | if (!user_id) {
8 | return res.status(400).json({ message: "Enter valid user_id" })
9 | }
10 | const findUser = await Candidate.findById(user_id);
11 | if (findUser) {
12 | return res.status(200).json(findUser)
13 | }
14 | else {
15 | return res.status(500).json({ message: "Invalid User ID" })
16 |
17 | }
18 | }
19 |
20 | module.exports = showActiveCandidateDetails;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/ShowInterviewingCandidate.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Candidate = require('../../Models/Candidate');
3 |
4 | const ShowInterviewingCandidate = async (req, res, next) => {
5 |
6 |
7 | const { id } = req.body.id;
8 |
9 | const findInterviewingCandidates = await Candidate.find({
10 | recruitmentCycle: 'Interviewing',
11 | jobID: id
12 | },)
13 |
14 | if (findInterviewingCandidates) {
15 |
16 | res.status(200).json(findInterviewingCandidates)
17 |
18 | }
19 | else {
20 |
21 | res.status(400).json({ message: "No candidate found" })
22 | }
23 | }
24 |
25 | module.exports = ShowInterviewingCandidate;
--------------------------------------------------------------------------------
/Client/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App";
4 | import { ChakraProvider } from "@chakra-ui/react";
5 | import { BrowserRouter } from "react-router-dom";
6 | import { store } from "./App/Store";
7 | import { Provider } from "react-redux";
8 | import { Analytics } from "@vercel/analytics/react";
9 |
10 | import "./index.css";
11 |
12 | ReactDOM.createRoot(document.getElementById("root")).render(
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/GetReccomendedCandidateDetails.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Candidate = require("../../Models/Candidate");
3 | const app = express();
4 |
5 | const GetReccomendedCandidatesDetails = async (req, res, next) => {
6 | const { id } = req.body;
7 | try {
8 | const getUser = await Candidate.findById(id);
9 | if (getUser) {
10 | return res.status(200).json(getUser);
11 | } else {
12 | return res.status(404).json({ message: "No user found" });
13 | }
14 | } catch (error) {
15 | return res.status(500).json({ message: "Something unexpected happend" });
16 | }
17 | };
18 |
19 | module.exports = GetReccomendedCandidatesDetails;
20 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/GetWithdrawnCandidateDetails.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Candidate = require('../../Models/Candidate');
3 | const app = express();
4 | const GetWithdrawnCandidateDetails = async (req, res, next) => {
5 |
6 |
7 | const { id } = req.body;
8 |
9 | try {
10 | const getUser = await Candidate.findById(id);
11 |
12 | if (getUser) {
13 | return res.status(200).json(getUser);
14 | } else {
15 | return res.status(404).json({ message: "No user found" });
16 | }
17 | } catch (error) {
18 | return res.status(500).json({ message: "Something unexpected happend" });
19 | }
20 |
21 | }
22 |
23 | module.exports = GetWithdrawnCandidateDetails;
--------------------------------------------------------------------------------
/Server/Controllers/Settings/UpdateProfileSettings.js:
--------------------------------------------------------------------------------
1 | const { find } = require("../../Models/Organization_Model");
2 | const OrganizationModal = require("../../Models/Organization_Model");
3 |
4 | const UpdateProfileSettings = async (req, res) => {
5 | console.log("i am running")
6 | console.log(req.body.org_id)
7 |
8 |
9 | const { org_id } = req.body;
10 | const { inputValue } = req.body;
11 | // console.log(inputValue)
12 | const findOrganization = await OrganizationModal.findById(org_id);
13 |
14 | // if (findOrganization) {
15 |
16 |
17 | // }
18 |
19 | // else {
20 | // res.status(404).json({ message: "Organization is not found" })
21 | // }
22 |
23 |
24 | }
25 |
26 | module.exports = UpdateProfileSettings;
--------------------------------------------------------------------------------
/Server/Controllers/Jobs/GetOrganizationPostedJob.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Candidate = require('../../Models/Candidate');
3 | const app = express();
4 |
5 |
6 | const GetOrganizationPostedJobApplicants = async (req, res, next) => {
7 |
8 |
9 | const { job_id } = req.body;
10 | if (!job_id) {
11 | return res.status(404).json({ message: "ID not found" });
12 | }
13 | const findApplicants = await Candidate.find(
14 | {
15 | jobID: job_id,
16 | })
17 |
18 | if (findApplicants) {
19 | return res.status(200).json(findApplicants)
20 | }
21 | else return res.status(400).json({ message: "nothing found" });
22 | }
23 |
24 |
25 | module.exports = GetOrganizationPostedJobApplicants;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/GetComments.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const CandidateRemarks = require('../../Models/Comment.js');
3 | const GetComments = async (req, res, next) => {
4 |
5 | const { id } = req.body;
6 |
7 |
8 | // Use the `findOne()` method to find a candidate with the given `user_id`
9 | CandidateRemarks.findOne({ CandidateID: id }, (err, candidate) => {
10 | if (err) {
11 | return res.status(400).json({ message: "No candidate found " })
12 | }
13 |
14 | if (!candidate) {
15 | return res.status(500).json({ message: "Server error" })
16 |
17 | }
18 |
19 | return res.status(200).json(candidate)
20 | });
21 |
22 | }
23 | module.exports = GetComments;
--------------------------------------------------------------------------------
/Client/src/Pages/HiredCandidates/HiredCandidate.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
3 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
4 | import MainPage from "../../Components/HiredCandidatePage/MainPage";
5 |
6 | function HiredCandidate() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 | }
22 |
23 | export default HiredCandidate;
24 |
--------------------------------------------------------------------------------
/Server/Models/Comment.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const CandidateComments = new mongoose.Schema({
4 |
5 |
6 | CandidateID: {
7 | type: String,
8 | required: true
9 | },
10 | Applied: {
11 | type: String,
12 | },
13 | Interviewing: {
14 | type: String,
15 | },
16 | Reccomended: {
17 | type: String,
18 | },
19 | Applied: {
20 | type: String,
21 | },
22 | Hired: {
23 | type: String,
24 | },
25 | Rejected: {
26 | type: String,
27 | },
28 | Initialized: {
29 | type: Boolean,
30 | default: false,
31 | }
32 | })
33 |
34 | const CandidateRemarks = mongoose.model("Comment", CandidateComments)
35 |
36 | module.exports = CandidateRemarks;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/GetHiredCandidate.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Candidate = require("../../Models/Candidate");
3 | const app = express();
4 |
5 | const GetHiredCandidate = async (req, res, next) => {
6 | const { id } = req.body;
7 |
8 | try {
9 | const getUser = await Candidate.find(
10 | {
11 | jobID: id,
12 | recruitmentCycle: 'Hired'
13 | }
14 | );
15 | if (getUser) {
16 | return res.status(200).json(getUser);
17 | } else {
18 | return res.status(404).json({ message: "No user found" });
19 | }
20 | } catch (error) {
21 | return res.status(500).json({ message: "Something unexpected happend" });
22 | }
23 | };
24 |
25 | module.exports = GetHiredCandidate;
26 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/GetRejectedCandidate.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Candidate = require("../../Models/Candidate");
3 | const app = express();
4 |
5 | const GetRejectedCandidates = async (req, res, next) => {
6 | const { id } = req.body;
7 |
8 | try {
9 | const getUser = await Candidate.find(
10 | {
11 | jobID: id,
12 | recruitmentCycle: 'Rejected'
13 | }
14 | );
15 | if (getUser) {
16 | return res.status(200).json(getUser);
17 | } else {
18 | return res.status(404).json({ message: "No user found" });
19 | }
20 | } catch (error) {
21 | return res.status(500).json({ message: "Something unexpected happend" });
22 | }
23 | };
24 |
25 | module.exports = GetRejectedCandidates;
26 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/UpdateWithdrawnReason.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Candidate = require('../../Models/Candidate');
3 |
4 | const app = express();
5 | const UpdateWithdrawnReason = async (req, res, next) => {
6 |
7 | const { id, description } = req.body;
8 | Candidate.findByIdAndUpdate(id, { withdrawn_reason: description }, { new: true })
9 | .then(updatedItem => {
10 | if (updatedItem) {
11 | return res.status(200).json({ message: ('Updated') });
12 | } else {
13 | return res.status(404).json({ message: ('Invalid ID') });
14 | }
15 | })
16 | .catch(error => {
17 | return res.status(404).json({ message: ('Something went wrong') });
18 | });
19 |
20 | }
21 |
22 | module.exports = UpdateWithdrawnReason;
--------------------------------------------------------------------------------
/Server/Middleware/AuthMiddleware.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jsonwebtoken');
2 | const secretKey = 'mysecretkey'; // replace with your secret key
3 |
4 | function AuthMiddleware(req, res, next) {
5 | var authHeader = req.headers.authorization;
6 | if (authHeader && authHeader.startsWith('Bearer ')) {
7 | // check if the header starts with "Bearer " prefix
8 | const token = authHeader.split(' ')[1]; // split the header and get the token part
9 | authHeader = token;
10 | }
11 | jwt.verify(authHeader, process.env.KEY, (error, data) => {
12 | if (error) {
13 | return res.status(400).send({ message: "invalid token" })
14 | }
15 |
16 | else {
17 | req.body.userID = data.id;
18 | next();
19 | }
20 | })
21 | }
22 |
23 | module.exports = AuthMiddleware;
24 |
--------------------------------------------------------------------------------
/Client/src/Pages/HiredCandidates/HiredCandidatesDetails.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
3 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
4 | import MainAreaOfHiredCandidateDetails from "../../Components/HiredCandidatePage/MainAreaOfHiredCandidateDetails";
5 |
6 | function HiredCandidateDetails() {
7 | return (
8 |
19 | );
20 | }
21 |
22 | export default HiredCandidateDetails;
23 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/GetWithdrawnCandidate.js:
--------------------------------------------------------------------------------
1 |
2 | const express = require("express");
3 | const Candidate = require("../../Models/Candidate");
4 | const app = express();
5 |
6 | const GetWithdrawnCandidate = async (req, res, next) => {
7 | const { id } = req.body;
8 |
9 | try {
10 | const getUser = await Candidate.find(
11 | {
12 | jobID: id,
13 | recruitmentCycle: 'Withdrawn'
14 | }
15 | );
16 |
17 | if (getUser) {
18 | return res.status(200).json(getUser);
19 | } else {
20 | return res.status(404).json({ message: "No user found" });
21 | }
22 | } catch (error) {
23 | return res.status(500).json({ message: "Something unexpected happend" });
24 | }
25 | };
26 |
27 | module.exports = GetWithdrawnCandidate;
28 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/asd.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Server/Controllers/Settings/UpdateProfilePicture.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const app = express();
3 | const Cloudinary = require("cloudinary");
4 | const cloud = require("../../Config/Cloudnary.js");
5 | const OrganizationModal = require("../../Models/Organization_Model");
6 |
7 | const UpdateProfilePicture = async (req, res, next) => {
8 | // // -> Storing selected image to cloud
9 |
10 | const file = req.file;
11 | const userId = req.body.userId;
12 | if (file && userId) {
13 | const findOrganization = await OrganizationModal.findById(userId);
14 | const img = await Cloudinary.v2.uploader.upload(req.file.path);
15 | const { url } = img;
16 | findOrganization.logo = url;
17 | await findOrganization.save();
18 | res.send("done")
19 | }
20 | };
21 |
22 | module.exports = UpdateProfilePicture;
23 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/SaveInterviewDateAndTime.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Candidate = require('../../Models/Candidate');
3 |
4 | const SaveInterviewDateAndTime = async (req, res, next) => {
5 |
6 | const { value, time, id } = req.body;
7 | const date = new Date(value);
8 | const month = date.getMonth() + 1;
9 | const year = date.getFullYear();
10 | const day = date.getDate();
11 |
12 |
13 |
14 | const addData = await Candidate.findByIdAndUpdate(id, {
15 | interviewDate: `${day} - ${month} - ${year}`,
16 | interviewTime: `${time}`
17 | })
18 |
19 | if (addData === null) {
20 | return res.status(500).json({ message: "Something went wrong" });
21 | } else {
22 | return res.status(200).json({ message: "Added" });
23 | }
24 |
25 |
26 |
27 | }
28 |
29 | module.exports = SaveInterviewDateAndTime;
--------------------------------------------------------------------------------
/Server/Routes/SettingRouter.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const UpdateProfilePicture = require("../Controllers/Settings/UpdateProfilePicture");
3 | const multer = require('multer');
4 | const UpdateProfileSettings = require("../Controllers/Settings/UpdateProfileSettings");
5 |
6 |
7 |
8 |
9 | const SettingRouter = express.Router();
10 |
11 | // Set up Multer middleware
12 | const storage = multer.diskStorage({
13 | destination: function (req, file, cb) {
14 | cb(null, 'uploads/');
15 | },
16 | filename: function (req, file, cb) {
17 | cb(null, file.originalname);
18 | },
19 | });
20 | const upload = multer({ storage });
21 |
22 |
23 |
24 | SettingRouter.post("/updateProfile", upload.single('file'), UpdateProfilePicture)
25 | SettingRouter.post("/updateProfileData", upload.single('file'), UpdateProfileSettings)
26 |
27 | module.exports = SettingRouter;
--------------------------------------------------------------------------------
/Client/src/Components/ProfileSetup/ProfileSetup.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useNavigate } from "react-router-dom";
3 | import Home from "../../assets/illustrations/home.svg";
4 | function ProfileSetup() {
5 | const navigate = useNavigate();
6 | return (
7 |
8 |
9 | Start setting up your company account
10 |
11 |
12 |

13 |
14 |
21 |
22 |
23 | );
24 | }
25 |
26 | export default ProfileSetup;
27 |
--------------------------------------------------------------------------------
/Server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "dev": "node Server",
9 | "start": "nodemon index.js"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "axios": "^1.3.0",
16 | "bcrypt": "^5.1.0",
17 | "body-parser": "^1.20.2",
18 | "cloudinary": "^1.34.0",
19 | "cors": "^2.8.5",
20 | "dotenv": "^16.0.3",
21 | "ejs": "^3.1.8",
22 | "express": "^4.18.2",
23 | "express-fileupload": "^1.4.0",
24 | "jsonwebtoken": "^9.0.0",
25 | "mongoose": "^6.9.0",
26 | "morgan": "^1.10.0",
27 | "multer": "^1.4.3",
28 | "ngrok": "^4.3.3",
29 | "nodemailer": "^6.9.1"
30 | },
31 | "devDependencies": {
32 | "nodemon": "^2.0.20"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/HandleComments.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const CandidateRemarks = require('../../Models/Comment.js');
3 | const HandleComments = async (req, res, next) => {
4 | const { Applied, Interviewing, Reccomended, Hired, Rejected } = req.body.comment;
5 | const { id } = req.body;
6 |
7 | if (!id) {
8 | return res.status(400).json({ message: "invalid input data" })
9 | }
10 | const madeComment = await new CandidateRemarks({
11 | CandidateID: id,
12 | Applied: Applied,
13 | Interviewing: Interviewing, Reccomended: Reccomended, Hired, Rejected, Initialized: true
14 | });
15 | try {
16 | await madeComment.save();
17 | } catch (error) {
18 | return res.status(500).json({ message: "Server error occured" });
19 | }
20 | return res.status(200).json(madeComment)
21 |
22 |
23 | }
24 |
25 | module.exports = HandleComments;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/GetReccomendedCandidates.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Candidate = require("../../Models/Candidate");
3 | const app = express();
4 |
5 | const GetReccomendedCandidates = async (req, res, next) => {
6 | //find ID where the id is == candidate
7 |
8 | // -> go check all candidate which have the same job id:
9 | const { id } = req.body;
10 |
11 | try {
12 | const getUser = await Candidate.find({
13 | jobID: id,
14 | recruitmentCycle: "Reccomended",
15 | });
16 |
17 | if (getUser) {
18 | return res.status(200).json(getUser);
19 | } else {
20 | return res.status(404).json({ message: "No user found" });
21 | }
22 | } catch (error) {
23 | return res.status(500).json({ message: "Something unexpected happend" });
24 | }
25 | };
26 |
27 | module.exports = GetReccomendedCandidates;
28 |
--------------------------------------------------------------------------------
/Server/Controllers/UserController/VerifyMail.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const userModel = require("../../Models/User_Model");
3 | const app = express();
4 |
5 | const VerifyMail = async (req, res, next) => {
6 | const id = req.query.id;
7 |
8 | if (!id) {
9 | return res.status(400).json({ error: "ID is required!" });
10 | }
11 | const findUser = await userModel.findByIdAndUpdate(id, { isVerified: true });
12 | try {
13 | await findUser.save();
14 | const html = `
15 | Verified
16 | Email verification completed, you can login now.
Go to Home
17 | `;
18 | res.send(html);
19 | } catch (e) {
20 | res.send("Eroor :_ " + e);
21 | }
22 | };
23 |
24 | module.exports = VerifyMail;
25 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/jobs.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/Client/src/Features/Dashboard/Organization_Details_Slice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit'
2 |
3 | const initialState = {
4 | apiData: null,
5 | loading: false,
6 | error: null,
7 | }
8 |
9 | export const OrganizationDetails = createSlice({
10 | name: 'organization_details',
11 | initialState,
12 | reducers: {
13 | fetchOrganizationDataStart(state) {
14 | state.loading = true;
15 | state.error = null;
16 | },
17 | fetchOrganizationDataSuccess(state, action) {
18 | state.loading = false;
19 | state.apiData = action.payload;
20 | },
21 | fetchOrganizationDataFailure(state, action) {
22 | state.loading = false;
23 | state.error = action.payload;
24 | },
25 | },
26 | })
27 |
28 | export const { fetchOrganizationDataStart, fetchOrganizationDataSuccess, fetchOrganizationDataFailure } = OrganizationDetails.actions
29 |
30 | export default OrganizationDetails.reducer
--------------------------------------------------------------------------------
/Server/Controllers/UserController/UpdatePassword.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const userModel = require("../../Models/User_Model");
3 | const bcrypt = require("bcrypt");
4 |
5 | const app = express();
6 |
7 | const updatePassword = async (req, res, next) => {
8 |
9 | const { password, id } = req.body;
10 | console.log(password, id);
11 | if (!password) {
12 | return res.status(400).json({ error: "Must fill new-password field." });
13 | }
14 |
15 | const saltRounds = 10;
16 | const hashedPassword = await bcrypt.hash(password, saltRounds);
17 |
18 | try {
19 | const findUser = await userModel.findOneAndUpdate(
20 | { _id: id },
21 | { password: hashedPassword }
22 | );
23 | await findUser.save();
24 | return res.status(200).json({ error: "Password updated" });
25 | } catch (error) {
26 | return res.status(500).json({ error: "Server error, something went wrong" });
27 | }
28 | };
29 |
30 | module.exports = updatePassword;
31 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/delete.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/employees.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Client/src/Features/JobCycle/storeAllCandidatesDetails.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 | const initialState = {
3 | canidatesData: null,
4 | loading: false,
5 | error: null,
6 | filterBS: null
7 | }
8 |
9 | export const storeAllCandidatesDetails = createSlice({
10 | name: 'StoreCandidatesDetails',
11 | initialState,
12 | reducers: {
13 | startFetchingCandidatesData(state) {
14 | state.loading = true;
15 | state.error = null;
16 | },
17 |
18 | sucessOnFetchingCandidatesData(state, action) {
19 | state.loading = false;
20 | state.canidatesData = action.payload
21 | },
22 |
23 | errorFetchingCandidatesData(state, action) {
24 | state.loading = false,
25 | state.error = action.payload;
26 |
27 | },
28 |
29 | filterOnBS(state, action) {
30 | return state.filterBS = "Hamza"
31 | }
32 | }
33 | })
34 |
35 | export const { filterOnBS, startFetchingCandidatesData, sucessOnFetchingCandidatesData, errorFetchingCandidatesData } = storeAllCandidatesDetails.actions;
36 | export default storeAllCandidatesDetails.reducer;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/PatchComments.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const CandidateRemarks = require("../../Models/Comment.js");
3 | const PatchComments = async (req, res, next) => {
4 | const { Applied, Interviewing, Reccomended, Hired, Rejected } = req.body.comment;
5 | const commentID = req.body.id;
6 | // Update the document by ID
7 | CandidateRemarks.findOneAndUpdate(
8 | { CandidateID: commentID }, // Corrected line
9 | {
10 | Applied: Applied,
11 | Interviewing: Interviewing,
12 | Reccomended: Reccomended,
13 | Hired: Hired,
14 | Rejected: Rejected,
15 | },
16 | { new: true })
17 | .then((updatedDoc) => {
18 | if (updatedDoc) {
19 | return res.status(200).json({ message: "Update successful" });
20 | } else {
21 |
22 | return res.status(400).json({ message: "Candidate not found or an error occurred" });
23 | }
24 | })
25 | .catch((error) => {
26 | return res.status(500).json({ message: "Server error" });
27 | });
28 | };
29 |
30 | module.exports = PatchComments;
31 |
--------------------------------------------------------------------------------
/Server/Models/User_Model.js:
--------------------------------------------------------------------------------
1 | const mongo = require('mongoose');
2 |
3 | const userSchema = new mongo.Schema({
4 | f_name: {
5 | type: String,
6 | required: [true, "First name is must"]
7 | },
8 |
9 | username: {
10 | type: String,
11 | required: [true, "Last name is must"],
12 | unique: true
13 | },
14 |
15 | email: {
16 | type: String,
17 | required: [true, 'Email is required'],
18 | unique: true
19 | },
20 |
21 | company_name: {
22 | type: String,
23 | required: [true, 'Company name is must']
24 | },
25 |
26 | password: {
27 | type: String,
28 | required: [true, 'password is required']
29 | },
30 | isVerified: {
31 | type: Boolean, default: false
32 | },
33 | passwordResetToken: {
34 | type: String,
35 | },
36 | org_registered: {
37 | type: Boolean, default: false
38 | },
39 | org_id: {
40 | type: String, default: '0'
41 | }
42 | // passwordResetExpires: {
43 | // type: Date,
44 | // }
45 |
46 | })
47 |
48 |
49 | const userModel = mongo.model('user', userSchema)
50 |
51 | module.exports = userModel;
--------------------------------------------------------------------------------
/Server/Controllers/Jobs/PostJob.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Job = require('../../Models/JobModel');
3 | const app = express();
4 | const PostJobRouter = async (req, res, next) => {
5 |
6 | const { form, description, org_details } = req.body;
7 |
8 | // console.log(form, description, org_details);
9 |
10 | const Postjob = await new Job({
11 | jobPosition: form.postition,
12 | officeLocation: form.office_location,
13 | department: form.department,
14 | jobType: form.job_type,
15 | numberOfSeats: form.no_of_seats,
16 | salaryRangeFrom: form.salary_range_from,
17 | salaryRangeUpto: form.salary_range_upto,
18 | job_description: description,
19 | city: org_details[0],
20 | country: org_details[1],
21 | org_name: org_details[2],
22 | org_id: org_details[3]
23 | })
24 | try {
25 | await Postjob.save();
26 |
27 |
28 | } catch (error) {
29 | console.log(error)
30 | return res
31 | .status(500)
32 | .json({ error: "An error occurred while saving the user." });
33 |
34 | }
35 | return res.status(200).json({ message: "Job posted!" })
36 |
37 |
38 | }
39 |
40 |
41 | module.exports = PostJobRouter;
--------------------------------------------------------------------------------
/Client/src/assets/icons/settings.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Client/src/Components/ProfileSetup/SucessModel.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import SucessImg from "../../assets/illustrations/profile_success.svg";
3 | import { AiFillHome } from "react-icons/ai";
4 | import { useNavigate } from "react-router-dom";
5 |
6 | function SucessModel() {
7 | const navigate = useNavigate();
8 | return (
9 |
10 | {" "}
11 |
12 | {/* THIS MENUE MAIN INPUT CONTENT */}
13 |
14 |
15 | Congratulations Profile Setup Complete
16 |
17 |
18 |

24 |
25 |
26 | {/* NEXT BUTTON CODE */}
27 |
34 |
35 |
36 | );
37 | }
38 |
39 | export default SucessModel;
40 |
--------------------------------------------------------------------------------
/Client/src/Pages/RecruitmentCycle/RejectedCandidates.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { FiSend } from "react-icons/fi";
3 | import { useParams } from "react-router-dom";
4 | import TopRcruitementCycle from "../../Components/Dashboard/CreateJob/TopRcruitementCycle";
5 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
6 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
7 | import RejectedCandidateCard from "../../Components/RecruitmentStage/RejectedCandidatesCard";
8 |
9 | function RejectedCandidates() {
10 | const { id } = useParams();
11 |
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Declined Candidates List
25 |
26 |
27 |
28 |
29 |
30 | );
31 | }
32 |
33 | export default RejectedCandidates;
34 |
--------------------------------------------------------------------------------
/Client/src/Pages/RecruitmentCycle/InterviewingCandidate.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useParams } from "react-router-dom";
3 | import TopRcruitementCycle from "../../Components/Dashboard/CreateJob/TopRcruitementCycle";
4 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
5 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
6 | import InterviewingCandidateListCard from "../../Components/RecruitmentStage/InterviewingCandidateListCard";
7 |
8 | function InterviewingCandidate() {
9 | const params = useParams();
10 |
11 | return (
12 | <>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Interviewing Candidates List
24 |
25 |
26 |
27 |
28 |
29 |
30 | >
31 | );
32 | }
33 |
34 | export default InterviewingCandidate;
35 |
--------------------------------------------------------------------------------
/Client/src/Pages/Employees/MainPageOfEmployees.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
4 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
5 | import Illustration from "../../assets/illustrations/no_user.svg";
6 | function MainPageOfEmployees() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Your Employees
18 |
19 |
22 |
23 |
24 |
25 |

31 |
32 | Currently no active employee
33 |
34 |
35 |
36 | );
37 | }
38 |
39 | export default MainPageOfEmployees;
40 |
--------------------------------------------------------------------------------
/Server/Controllers/UserController/verifyForgetpwd.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const userModel = require("../../Models/User_Model");
3 | const app = express();
4 |
5 | const verifyForgetPwd = async (req, res, next) => {
6 |
7 | const { params, inputCode } = req.body;
8 |
9 | console.log("This is the otp code")
10 | console.log(params, inputCode);
11 | //to remove space and , from code (as input is coming from an array[])
12 | let newVal = inputCode.toString();
13 | newVal = newVal.split(" ").pop()
14 | newVal = newVal.replace(/,/g, '');
15 |
16 |
17 |
18 | try {
19 | console.log(newVal, params)
20 | const user = await userModel.findOneAndUpdate(
21 | {
22 | $and: [{ email: params }, { passwordResetToken: newVal }],
23 | },
24 | { passwordResetToken: null }
25 | );
26 | if (!user) {
27 | console.log('invalid otp');
28 | return res.status(404).json({ error: "Invalid otp_code" });
29 | }
30 |
31 | res.status(200).json({ id: user._id })
32 | } catch (error) {
33 | return res.status(500).json({ error: "Something went wrong" });
34 | }
35 | //this params will shared to the next route with req.data method.
36 | req.data = {
37 | params: params,
38 | };
39 | next();
40 | };
41 |
42 | module.exports = verifyForgetPwd;
43 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/DeleteCandidateProfile.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Candidate = require('../../Models/Candidate');
3 |
4 | const DeleteCandidateProfile = async (req, res, next) => {
5 |
6 | const { id } = req.body;
7 |
8 | console.log(id);
9 | try {
10 | const candidate = await Candidate.findByIdAndDelete({ _id: id });
11 | console.log(candidate);
12 | if (!candidate) {
13 | return res.status(404).json({ message: 'Candidate not found' });
14 | }
15 |
16 | await Candidate.findByIdAndDelete(req.params.id);
17 |
18 | return res.status(200).json({ message: 'Candidate deleted successfully' });
19 | } catch (err) {
20 | console.error(err.message);
21 | return res.status(500).json({ message: 'Server error' });
22 | }
23 | };
24 |
25 | // const { id } = req.body;
26 | // console.log(id);
27 | // const findUser = await Candidate.findByIdAndRemove(id);
28 |
29 | // if (findUser) {
30 | // try {
31 | // findUser.save();
32 |
33 | // } catch (error) {
34 | // return res.status(500).json({ message: "Server Error" })
35 | // }
36 |
37 | // return res.status(200).json({ message: "User delete successfully" })
38 | // }
39 | // else {
40 | // return res.status(404).json({ message: "No user found" })
41 | // }
42 |
43 |
44 |
45 |
46 | module.exports = DeleteCandidateProfile;
--------------------------------------------------------------------------------
/Client/src/Components/Common/GoBackButton.jsx:
--------------------------------------------------------------------------------
1 | import { Breadcrumb, BreadcrumbItem, BreadcrumbLink } from "@chakra-ui/react";
2 | import React from "react";
3 | import { FiArrowLeft } from "react-icons/fi";
4 | import { useNavigate } from "react-router-dom";
5 |
6 | function GoBackButton({ name, location }) {
7 | const navigate = useNavigate();
8 | return (
9 |
10 |
11 |
{
16 | navigate(-1);
17 | }}
18 | >
19 |
20 |
21 |
22 |
23 |
24 | {
26 | navigate(-1);
27 | }}
28 | >
29 | {location}
30 |
31 |
32 |
33 |
34 |
35 | {name}
36 | {/* {candidateDetails?.firstName} */}
37 |
38 |
39 |
40 |
41 |
42 | );
43 | }
44 |
45 | export default GoBackButton;
46 |
--------------------------------------------------------------------------------
/Client/src/Pages/RecruitmentCycle/WithdrawnCandidate.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { FiSend } from "react-icons/fi";
3 | import { useParams } from "react-router-dom";
4 | import TopRcruitementCycle from "../../Components/Dashboard/CreateJob/TopRcruitementCycle";
5 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
6 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
7 | import RejectedCandidateCard from "../../Components/RecruitmentStage/RejectedCandidatesCard";
8 | import WithdrawnCandidateCard from "../../Components/RecruitmentStage/WithdrawnCandidateCard";
9 |
10 | function WithdrawnCandidate() {
11 | const { id } = useParams();
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
Withdrawn Candidates List
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
34 | export default WithdrawnCandidate;
35 |
--------------------------------------------------------------------------------
/Client/src/Pages/RecruitmentCycle/HiredCandidates.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { FiSend } from "react-icons/fi";
3 | import { useParams } from "react-router-dom";
4 | import TopRcruitementCycle from "../../Components/Dashboard/CreateJob/TopRcruitementCycle";
5 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
6 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
7 | import HiredCandidateCard from "../../Components/RecruitmentStage/HiredCandidateCard";
8 | import ReccomendidCandidateCard from "../../Components/RecruitmentStage/ReccomendidCandidateCard";
9 |
10 | function HiredCandidates() {
11 | const { id } = useParams();
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
Hired Candidates List
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 |
36 | export default HiredCandidates;
37 |
--------------------------------------------------------------------------------
/Client/src/Pages/RecruitmentCycle/ReccomendedCandidates.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useParams } from "react-router-dom";
3 | import TopRcruitementCycle from "../../Components/Dashboard/CreateJob/TopRcruitementCycle";
4 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
5 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
6 | import InterviewingCandidateListCard from "../../Components/RecruitmentStage/InterviewingCandidateListCard";
7 | import ReccomendidCandidateCard from "../../Components/RecruitmentStage/ReccomendidCandidateCard";
8 |
9 | function ReccomendedCandidates() {
10 | const { id } = useParams();
11 |
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Reccomended Candidates List
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 |
35 | export default ReccomendedCandidates;
36 |
--------------------------------------------------------------------------------
/Server/Routes/ProfileCreation.js:
--------------------------------------------------------------------------------
1 | // -> IMPORTS
2 | const ProfileRouter = require('../Controllers/Setup Profile/Profile_Setup');
3 | const multer = require('multer')
4 | // -> INITIALIZATIONS
5 | const express = require('express');
6 | const AuthMiddleware = require('../Middleware/AuthMiddleware');
7 | const VerifyToken = require('../Middleware/VerifyToken');
8 | const ProfileSetup = express.Router();
9 |
10 | //* ** MULTER CONFIGURATION ** */
11 |
12 | const storage = multer.diskStorage({
13 | destination: function (req, file, cb) {
14 | //so it will store the images in the public directory
15 | cb(null, "Models");
16 | },
17 | filename: function (req, file, cb) {
18 | cb(null, new Date().toISOString() + file.originalname);
19 | }
20 | });
21 |
22 | const multerFilter = (req, file, cb) => {
23 | if (
24 | file.mimetype === "image/png" ||
25 | file.mimetype === "image/jpg" ||
26 | file.mimetype === "image/jpeg"
27 | ) {
28 | cb(null, true);
29 | } else {
30 | cb(null, false);
31 | }
32 | };
33 |
34 | const upload = multer({ storage: storage, multerFilter });
35 |
36 | // *******************************************************************
37 |
38 |
39 | // -> MAIN CODE
40 |
41 | //1st Time Profile Setup Route
42 | ProfileSetup.post("/setup", AuthMiddleware, ProfileRouter);
43 |
44 | ProfileSetup.post("/", (req, res) => {
45 | res.send("welcome")
46 | })
47 | // -> EXPORT
48 | module.exports = ProfileSetup;
49 |
--------------------------------------------------------------------------------
/Client/src/Pages/RecruitmentCycle/AppliedCandidateDetails.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useParams } from "react-router-dom";
3 | import { ToastContainer, toast } from "react-toastify";
4 | import TopRcruitementCycle from "../../Components/Dashboard/CreateJob/TopRcruitementCycle";
5 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
6 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
7 | import SwitchStatus from "../../Components/RecruitmentStage/SwitchStatus";
8 | import AppliedApplicantProfile from "./AppliedApplicantProfile";
9 |
10 | function AppliedCandidateDetails() {
11 | const { id } = useParams();
12 |
13 | const notify = () => toast("Wow so easy !");
14 |
15 | return (
16 | <>
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 | >
35 | );
36 | }
37 |
38 | export default AppliedCandidateDetails;
39 |
--------------------------------------------------------------------------------
/Client/src/Pages/RecruitmentCycle/WithdrawnDetails.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useParams } from "react-router-dom";
3 | import TopRcruitementCycle from "../../Components/Dashboard/CreateJob/TopRcruitementCycle";
4 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
5 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
6 | import SwitchStatus from "../../Components/RecruitmentStage/SwitchStatus";
7 | import WithdrawnCandidateCard from "../../Components/RecruitmentStage/WithdrawnCandidateCard";
8 | import WithdrawnDetailsCard from "../../Components/RecruitmentStage/WithdrawnDetailsCard";
9 |
10 | function WithdrawnDetails() {
11 | const { id } = useParams();
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {/* */}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | );
36 | }
37 |
38 | export default WithdrawnDetails;
39 |
--------------------------------------------------------------------------------
/Client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "smart-cruiter",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@chakra-ui/react": "^2.6.1",
13 | "@reduxjs/toolkit": "^1.9.3",
14 | "@smastrom/react-rating": "^1.3.1",
15 | "@vercel/analytics": "^1.0.1",
16 | "axios": "^1.3.1",
17 | "chart.js": "^4.3.0",
18 | "daisyui": "^2.49.0",
19 | "formik": "^2.2.9",
20 | "framer-motion": "^10.12.10",
21 | "js-alert": "^2.0.0",
22 | "react": "^18.2.0",
23 | "react-animated-rating": "^1.0.5",
24 | "react-calendar": "^4.2.1",
25 | "react-confetti": "^6.1.0",
26 | "react-country-region-selector": "^3.6.1",
27 | "react-datepicker": "^4.11.0",
28 | "react-dom": "^18.2.0",
29 | "react-icons": "^4.7.1",
30 | "react-quill": "^2.0.0",
31 | "react-redux": "^8.0.5",
32 | "react-router-dom": "^6.8.0",
33 | "react-simple-star-rating": "^5.1.7",
34 | "react-spinners": "^0.13.8",
35 | "react-time-picker": "^6.1.0",
36 | "react-toastify": "^9.1.2",
37 | "react-use-file-upload": "^0.9.5",
38 | "recharts": "^2.6.2",
39 | "yup": "^0.32.11"
40 | },
41 | "devDependencies": {
42 | "@types/react": "^18.0.26",
43 | "@types/react-dom": "^18.0.9",
44 | "@vitejs/plugin-react": "^3.0.0",
45 | "autoprefixer": "^10.4.13",
46 | "postcss": "^8.4.21",
47 | "tailwindcss": "^3.2.4",
48 | "vite": "^4.0.0"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Server/index.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | require("dotenv").config();
3 | const ngrok = require('ngrok');
4 |
5 | // const fileUpload = require('express-fileupload')
6 | var bodyParser = require('body-parser')
7 | const mongoose = require('mongoose');
8 | const cors = require("cors");
9 | const connection = require("./Config/Database.js");
10 | const UserRouter = require("./Routes/UserRoute");
11 | const ProfileRouter = require("./Routes/ProfileCreation");
12 | const JobRouter = require('./Routes/Jobs');
13 | const RecruitmentRouter = require('./Routes/RecruitmentCycle.js');
14 | const ReportRouter = require('./Routes/Report.js');
15 | const RouterReport = require('./Routes/Report.js');
16 | const SettingRouter = require('./Routes/SettingRouter.js');
17 |
18 | // -----| Configration |-----
19 | const app = express();
20 | app.use(cors());
21 | mongoose.set('strictQuery', false);
22 | app.use(express.urlencoded({ extended: true }))
23 | // app.use(fileUpload())
24 | app.use(express.json());
25 | app.use(bodyParser.json());
26 |
27 | connection();
28 |
29 |
30 |
31 | //Routes
32 |
33 |
34 | app.use('/', UserRouter);
35 | app.use("/profile", ProfileRouter)
36 | app.use("/job", JobRouter)
37 | app.use('/details', RecruitmentRouter)
38 | app.use("/report", RouterReport)
39 | app.use("/settings", SettingRouter);
40 |
41 | // Create a new ngrok tunnel.
42 | //
43 |
44 |
45 |
46 | //-----| App listening |------
47 | const port = process.env.PORT || 8080;
48 |
49 |
50 |
51 | app.listen(port, () => {
52 | console.log("server is running on port :" + port)
53 | })
54 |
55 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/UpdateStatus.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Candidate = require("../../Models/Candidate");
3 | const Job = require("../../Models/JobModel");
4 | const app = express();
5 | const UpdateStatus = async (req, res, next) => {
6 | const { status, id } = req.body;
7 | if (!status) {
8 | return res.status(300).json({ message: "Status value is empty" });
9 | }
10 | try {
11 | const updatedCandidate = await Candidate.findByIdAndUpdate(
12 | id,
13 | { recruitmentCycle: status },
14 | { new: true }
15 | );
16 |
17 | if (updatedCandidate) {
18 | if (status == "Declined") {
19 | const findJob = await Job.findById(updatedCandidate.jobID);
20 | findJob.report_status.rejected += 1;
21 | await findJob.save();
22 | }
23 | else if (status == "Hired") {
24 | const findJob = await Job.findById(updatedCandidate.jobID);
25 | findJob.report_status.hired += 1;
26 | await findJob.save();
27 | }
28 |
29 | return res.status(200).json({ message: "Update successful" });
30 | } else {
31 | return res
32 | .status(400)
33 | .json({ message: "Candidate not found or an error occurred" });
34 | }
35 | } catch (error) {
36 | console.error("Error updating candidate:", error);
37 | return res.status(500).json({ message: "Server error occurred" });
38 | }
39 | };
40 |
41 | module.exports = UpdateStatus;
42 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/notification.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/candidates.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/SubmitFeedbacl.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Candidate = require("../../Models/Candidate");
3 | const app = express();
4 |
5 | const SubmitFeedback = async (req, res, next) => {
6 |
7 |
8 | const { id, startRating } = req.body;
9 |
10 | //now i want to enfore that if user by mistake put wrong value he should be able to put new value again
11 |
12 | var user = await Candidate.findById(id);
13 | if (user) {
14 | if (user.feedback_form == null || user.feedback_form == "") {
15 | user.feedback_form = [
16 | startRating.first,
17 | startRating.second,
18 | startRating.third,
19 | startRating.fourth,
20 | startRating.fifth,
21 | ];
22 |
23 | await user.save();
24 | return res.status(200).json({ message: "Saved" });
25 | } else {
26 | //so else part is dealing that if there is alrady any value
27 | // in object of -> feedback_form
28 | // than 1st i will clean that value and than add the new value
29 |
30 | let abc = user.feedback_form;
31 |
32 | abc = null;
33 | user.feedback_form = abc;
34 |
35 | user.feedback_form = [
36 | startRating.first,
37 | startRating.second,
38 | startRating.third,
39 | startRating.fourth,
40 | startRating.fifth,
41 | ];
42 | await user.save();
43 | return res.status(200).json({ message: "Saved" });
44 | }
45 | } else {
46 | return res.status(500).json({ message: "Something went wrong" });
47 | }
48 | };
49 |
50 | module.exports = SubmitFeedback;
51 |
--------------------------------------------------------------------------------
/Server/Routes/UserRoute.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const GetProfilePicture = require('../Controllers/Dashboard/GetProfilePic.js');
3 | const Home = require('../Controllers/Dashboard/Home.js');
4 | const forget_password = require('../Controllers/UserController/ForgetPassword.js');
5 | const login = require('../Controllers/UserController/Login.js');
6 | const register = require('../Controllers/UserController/Register.js');
7 | const updatePassword = require('../Controllers/UserController/UpdatePassword.js');
8 | const verifyForgetPwd = require('../Controllers/UserController/verifyForgetpwd.js');
9 | const VerifyMail = require('../Controllers/UserController/VerifyMail.js');
10 | const AuthMiddleware = require('../Middleware/AuthMiddleware.js');
11 | const VerifyToken = require('../Middleware/VerifyToken.js');
12 |
13 | const UserRouter = express.Router();
14 |
15 |
16 |
17 | //Login Route
18 | UserRouter.post("/login", login);
19 |
20 |
21 |
22 |
23 | // -> Register
24 |
25 | UserRouter.post("/register", register)
26 |
27 | // -> Verify Email
28 |
29 | UserRouter.get("/verify", VerifyMail)
30 |
31 |
32 | // -> Forget Password
33 | UserRouter.post("/forget-password", forget_password)
34 |
35 | // -> Verify Forget Password by verifying token
36 | UserRouter.post("/verify-forget-pwd", verifyForgetPwd)
37 |
38 | //-> Making a new password
39 | UserRouter.post("/new-password", updatePassword)
40 |
41 |
42 |
43 |
44 |
45 | //-> ## DASHBOARD HOME ROUTES ##
46 |
47 | //I left Auth Middleware intentionally to increase devlopment speed
48 | // Will implement it while deploying it on any hosting platform
49 | UserRouter.post("/home", AuthMiddleware, VerifyToken)
50 | UserRouter.post("/dashboard", Home)
51 | UserRouter.post("/getProfilePic", GetProfilePicture)
52 | module.exports = UserRouter;
--------------------------------------------------------------------------------
/Server/Routes/Jobs.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const ApplyForJob = require('../Controllers/Jobs/ApplyForJob');
3 | const GetAllPostedJobs = require('../Controllers/Jobs/GetAllPostedJobs');
4 | const GetJob = require('../Controllers/Jobs/GetJobs');
5 | const GetSelectedJobDescription = require('../Controllers/Jobs/GetSelectedJobDescription');
6 | const PostJobRouter = require('../Controllers/Jobs/PostJob');
7 | const multer = require('multer');
8 | const GetOrganizationPostedJobApplicants = require('../Controllers/Jobs/GetOrganizationPostedJob');
9 | const FilterShowActiveJobs = require('../Controllers/Jobs/Filter-ShowActiveJobs');
10 | const FilterShowClosedJobs = require('../Controllers/Jobs/FilterShowClosedJobs');
11 |
12 |
13 | const JobRouter = express.Router();
14 |
15 | JobRouter.post("/post", PostJobRouter)
16 | JobRouter.post("/get-jobs", GetJob);
17 | JobRouter.post("/get-jobs/active", FilterShowActiveJobs);
18 | JobRouter.post("/get-jobs/closed", FilterShowClosedJobs);
19 | JobRouter.post("/get-jobs/details", GetSelectedJobDescription);
20 | JobRouter.get("/get-all-jobs", GetAllPostedJobs)
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | //* ~~~~~~~~FILE - UPLOAD - API ~~~~~~~~~~ **/
34 | const storage = multer.diskStorage({
35 | destination: function (req, file, cb) {
36 | cb(null, 'uploads/');
37 | },
38 | filename: function (req, file, cb) {
39 | cb(null, Date.now() + '-' + file.originalname);
40 | }
41 | });
42 | const upload = multer({ storage: storage });
43 | // The correct method was to use upload.array() but it was giving error
44 | // so for time being i am gona use .any method
45 |
46 | JobRouter.post("/apply-to-job", upload.any('profile', 'resume'), ApplyForJob)
47 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48 |
49 |
50 |
51 |
52 |
53 |
54 | module.exports = JobRouter;
--------------------------------------------------------------------------------
/Client/src/Pages/RecruitmentCycle/ReccomendedCandidatesDetails.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import TopRcruitementCycle from "../../Components/Dashboard/CreateJob/TopRcruitementCycle";
3 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
4 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
5 | import SwitchStatus from "../../Components/RecruitmentStage/SwitchStatus";
6 | import GoBackButton from "../../Components/Common/GoBackButton";
7 | import ReccomendedCandidateDetailsCard from "../../Components/RecruitmentStage/ReccomendedCandidateDetailsCard";
8 | import { useParams } from "react-router-dom";
9 | function ReccomendedCandidatesDetails() {
10 | const { id } = useParams();
11 | const [user, SetUser] = useState();
12 |
13 | const [candidateID, setCandidateID] = useState();
14 |
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
40 |
41 |
42 |
43 | );
44 | }
45 |
46 | export default ReccomendedCandidatesDetails;
47 |
--------------------------------------------------------------------------------
/Client/src/Pages/CreateJob/CreateJob.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { useSelector } from "react-redux";
4 | import { Link, useNavigate } from "react-router-dom";
5 | import CreatedJobElement from "../../Components/Dashboard/CreateJob/CreatedJobElement";
6 | import CreateJobHeadaer from "../../Components/Dashboard/CreateJob/CreateJobHeadaer";
7 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
8 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
9 | function CreateJob() {
10 | const [data, setData] = useState();
11 | useEffect(() => {
12 | const fetchData = async () => {
13 | // axios POST request
14 | const options = {
15 | url: "https://smart-cruiter-fyp-production.up.railway.app/job/get-jobs",
16 | method: "POST",
17 | headers: {
18 | Accept: "application/json",
19 | "Content-Type": "application/json;charset=UTF-8",
20 | },
21 | data: { id: localStorage.getItem("organization_id") },
22 | };
23 |
24 | axios(options).then((response) => {
25 | // console.log(response);
26 |
27 | setData(response.data.jobs);
28 | });
29 | };
30 |
31 | fetchData();
32 | }, []);
33 |
34 | return (
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | );
52 | }
53 |
54 | export default CreateJob;
55 |
--------------------------------------------------------------------------------
/Client/src/Components/Dashboard/ProfileCreation/NavigationTab.jsx:
--------------------------------------------------------------------------------
1 | import { background } from "@chakra-ui/react";
2 | import React from "react";
3 |
4 | function NavigationTab({
5 | first_value,
6 | second_value,
7 | third_value,
8 | fourth_value,
9 | active,
10 | text,
11 | }) {
12 | return (
13 |
14 |
15 |
19 | {text == 1 ? 1 : null}
20 |
21 |
{first_value}
22 |
23 |
24 |
25 |
{second_value}
26 |
27 |
31 | {text == 2 ? 2 : null}
32 |
33 |
34 |
35 |
36 |
40 | {text == 3 ? 3 : null}
41 |
42 |
{third_value}
43 |
44 |
45 |
46 |
{fourth_value}
47 |
48 |
52 | {text == 4 ? 4 : null}
53 |
54 |
55 |
56 | );
57 | }
58 |
59 | export default NavigationTab;
60 |
--------------------------------------------------------------------------------
/Client/src/Components/Dashboard/CreateJob/TopRcruitementCycle.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useEffect } from "react";
3 | import { NavLink, useNavigate } from "react-router-dom";
4 |
5 | function TopRcruitementCycle({ id }) {
6 | // const [ids, setID] = useState();
7 | // useEffect(() => {
8 | // setID(id);
9 | // }, [id]);
10 |
11 | const NavLinkStyles = ({ isActive }) => {
12 | return {
13 | background: isActive ? "#0063B2" : "#2687F0",
14 | color: "white",
15 | padding: "0.75rem",
16 | borderRadius: "0.5rem",
17 | fontFamily: "Poppins , sans-serif",
18 | fontWeight: 300,
19 | fontSize: "14px",
20 | lineHeight: "28px",
21 | };
22 | };
23 |
24 | // console.log(id);
25 | return (
26 |
27 |
28 | {/* */}
31 |
32 |
33 | Applied Candidates
34 |
35 |
36 |
37 | Interviewing
38 |
39 |
40 |
41 | Reccomended
42 |
43 |
44 |
45 | Hired
46 |
47 |
48 |
49 | Declined
50 |
51 |
52 |
53 | Withdrawn
54 |
55 |
56 |
57 | );
58 | }
59 |
60 | export default TopRcruitementCycle;
61 |
--------------------------------------------------------------------------------
/Server/Models/Organization_Model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 |
4 | const OrganizationSchema = new mongoose.Schema({
5 |
6 | username: {
7 | type: String,
8 | required: [true, 'Email is required'],
9 | unique: true
10 | },
11 |
12 |
13 | organization_name: {
14 |
15 | type: String,
16 | required: [true, 'Name is required'],
17 |
18 | },
19 | phoneNo: {
20 | type: Number,
21 | required: [true, 'Phone No is required'],
22 | },
23 | website: {
24 | type: String,
25 | required: [true, 'Website URL is required'],
26 | },
27 | logo: {
28 | type: String,
29 | required: true
30 | },
31 | departments: {
32 | type: [String],
33 | min: 1,
34 |
35 | },
36 | office_address: {
37 | type: String,
38 | required: [true, 'Address is required'],
39 | },
40 | office_city: {
41 | type: String,
42 | required: [true, 'Office City is required'],
43 | },
44 | office_country: {
45 | type: String,
46 | required: [true, 'Office Country is required'],
47 | },
48 |
49 | fb_url: {
50 | type: String,
51 | required: [true, 'FB URL is required'],
52 | },
53 | linkedIn_url: {
54 | type: String,
55 | required: [true, 'LinkedIn URL is required'],
56 | },
57 | insta_url: {
58 | type: String,
59 | required: [true, 'Insta URL is required'],
60 | },
61 | yt_url: {
62 | type: String,
63 | required: [true, 'YT URL is required'],
64 | },
65 | // team_members: [
66 |
67 | // {
68 | // name: String,
69 | // email: String,
70 | // role: String
71 | // }
72 | // ]
73 | team_members: [{
74 |
75 | name: { type: String, required: true },
76 | email: { type: String, required: true, max: 20 },
77 | role: { type: String, required: true }
78 |
79 | }]
80 |
81 | })
82 |
83 |
84 | const OrganizationModal = mongoose.model('organization', OrganizationSchema);
85 |
86 | module.exports = OrganizationModal;
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Smart Cruiter
3 | ### Live Link : https://smart-cruiter-fyp-mqjf.vercel.app
4 | An applicant tracking management system, help organization in their hiring process with futures like:
5 |
6 | 1-) Job creation
7 |
8 | 2-) Managing applicants (applied, recommended, hired , declined, withdrawn)
9 |
10 | 3-) You can set up an online interview
11 |
12 | 4-) Send rejection or accepting emails to hundreds of candidates in a single click
13 |
14 | 5-) Manage the record of applicants with great data visualization
15 |
16 | 6-) Job details and application form for end-user
17 |
18 |
19 |
20 | ## Tech Stack
21 |
22 | **Client:** React, Redux Toolkit, TailwindCSS, DaisyUI
23 |
24 | **Server:** Node, Express
25 |
26 | **Database:** MongoDB Atlas
27 |
28 | **Deployment:** Vercel
29 |
30 |
31 |
32 | ## Screenshots
33 |
34 | 
35 | 
36 | 
37 | 
38 |
39 |
40 |
41 | ## Installation
42 |
43 | To install dependencies use npm
44 |
45 | ```bash
46 | npm install
47 | ```
48 | Backend / Server start command:
49 | ```bash
50 | npm run start
51 | Nodemon index
52 | ```
53 |
54 | Frontend / Client start command:
55 | ```bash
56 | npm run dev
57 | ```
58 |
59 | ## Need Detailed Assistance/Help?
60 | I'm available as a freelance MERN developer on [Fiverr](https://www.fiverr.com/mrhamzasajid/build-web-applications-with-mern-stack-reactjs-nodejs?context_referrer=seller_page&ref_ctx_id=e16faa02db8d4fd0bddae79455778a9c&pckg_id=1&pos=3&seller_online=true&imp_id=9d7c1f8d-2382-4e0d-8525-78ada752dfcc#), if you want to convert your idea to code or struggling with bugs in your system feel free to contact me https://www.fiverr.com/mrhamzasajid
61 |
62 |
--------------------------------------------------------------------------------
/Server/Controllers/UserController/Login.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const bcrypt = require("bcrypt");
4 | const jwt = require("jsonwebtoken");
5 | const userModel = require("../../Models/User_Model.js");
6 |
7 | const secret = process.env.KEY;
8 |
9 | const login = async (req, res, next) => {
10 | const { email, password } = req.body;
11 |
12 | if (!email || !password) {
13 | return res.status(400).json({ error: "All fields are required." });
14 | }
15 | try {
16 |
17 |
18 | const findUser = await userModel.findOne({ email: email });
19 | if (!findUser) {
20 | return res.status(404).json({
21 | error: "No such user found",
22 | });
23 | }
24 |
25 | // **************************************
26 | // -> INITIAL LOGIC || JUST BLAZING-UP
27 | // **************************************
28 | // const checkStatus = await userModel.findOne({ isVerified: false });
29 | // if (checkStatus) {
30 | // console.log(checkStatus);
31 | // return res.status(403).json({
32 | // error: "Email isn't verified, kindly first verify your email address",
33 | // });
34 | // }
35 |
36 | const checkStatus = findUser.isVerified;
37 | if (checkStatus == false) {
38 | return res.status(403).json({
39 | error: "Email isn't verified, kindly first verify your email address",
40 | });
41 | }
42 |
43 |
44 |
45 | // Compare the passwords
46 | const unhashed = await bcrypt.compare(password, findUser.password);
47 | if (!unhashed) {
48 | return res.status(401).json({
49 | error: "Incorrect password",
50 | });
51 | }
52 | //putting user id in pyaload so find user uniquely
53 | const payload = {
54 | id: findUser._id,
55 | };
56 | const token = jwt.sign(payload, process.env.KEY, { expiresIn: "96h" });
57 | return res.status(200).json({
58 | message: "Login successful",
59 | token: token,
60 | });
61 | }
62 |
63 | catch (e) {
64 | res.send("Something un-expected happend! " + e)
65 | }
66 | };
67 | module.exports = login;
68 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/SendInterviewEmail.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const app = express();
3 | const nodemailer = require('nodemailer');
4 |
5 |
6 |
7 | const SendInterviewEmail = async (req, res, next) => {
8 |
9 | // const { to, subject, body } = req.body;
10 |
11 | const { discription } = req.body;
12 | const { emailDetails } = req.body
13 | const { to } = emailDetails;
14 | const { subject } = emailDetails;
15 |
16 |
17 | if (!to || !subject || !discription) {
18 | return res.status(206).json({ message: "Complete all required fields" })
19 | }
20 |
21 |
22 |
23 | const sendMail = async () => {
24 |
25 | const htmlCode = `
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
Interview Invitation
38 |
39 |
40 |
41 |
42 |
43 | ${discription
44 | }
45 |
46 |
47 |
48 |
49 |
50 |
51 | Powered By : Smart-Cruiter
52 |
53 |
54 |
55 |
56 | `
57 | try {
58 |
59 | const transporter = nodemailer.createTransport({
60 | host: 'smtp.gmail.com',
61 | port: 587,
62 | secure: false,
63 | auth: {
64 | user: process.env.MAILUSER,
65 | pass: process.env.MAILPASS,
66 | },
67 | });
68 |
69 | const mailOptions = {
70 | from: process.env.MAILUSER,
71 | to: to,
72 | subject: subject,
73 | html: htmlCode,
74 | };
75 |
76 | transporter.sendMail(mailOptions, (error, info) => {
77 | if (error) {
78 |
79 | return res.status(500).json({ message: "Something went wrong" })
80 | } else {
81 | return res.status(200).json({ message: "email sent succesfully" })
82 |
83 | }
84 | });
85 |
86 | } catch (error) {
87 | return res.status(500).json({ message: "Something went wrong" })
88 | }
89 | }
90 |
91 | sendMail();
92 |
93 |
94 | }
95 |
96 | module.exports = SendInterviewEmail;
--------------------------------------------------------------------------------
/Client/src/Pages/Employees/AddNewEmployee.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
3 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
4 | import ProfilePic from "../../assets/icons/profileIcon.png";
5 | function AddNewEmployee() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Add employee information
19 |
20 |
21 |

22 |
23 |
26 |
31 |
32 |
35 |
40 |
41 |
44 |
52 |
53 |
56 |
57 |
58 |
59 | );
60 | }
61 |
62 | export default AddNewEmployee;
63 |
--------------------------------------------------------------------------------
/Client/src/App.css:
--------------------------------------------------------------------------------
1 |
2 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap');
3 |
4 | @import url('https://fonts.googleapis.com/css2?family=Lato:wght@700&display=swap');
5 |
6 | @import url('https://fonts.googleapis.com/css2?family=Montserrat&display=swap');
7 |
8 | /* DIV SHADOWS - BOX_SHADOWS */
9 | .shadows{
10 | background: #FFFFFF;
11 | /* Shadow/Div-Shadow */
12 | box-shadow: 0px 1px 3px -1px rgba(0, 0, 0, 0.3), 0px 2px 5px -1px rgba(50, 50, 93, 0.25);
13 | border-radius: 5px;}
14 |
15 | .modalShadow{
16 | box-shadow: 0px 2px 8px rgba(99, 99, 99, 0.2);
17 | border-radius: 5px;
18 | }
19 |
20 | /* FONTS */
21 | .heading1
22 | {
23 | font-family: 'Poppins', sans-serif;
24 | font-weight: 500;
25 | font-size: 48px;
26 | line-height: 28px;
27 | color: #333232;
28 | }
29 | .heading2
30 | {
31 | font-family: 'Poppins', sans-serif;
32 | font-weight: 500;
33 | font-size: 32px;
34 | line-height: 28px;
35 | color: #333232;
36 | }
37 |
38 | .heading2b
39 | {
40 | font-family: 'Poppins', sans-serif;
41 | font-weight: 500;
42 | font-size: 26px;
43 | line-height: 28px;
44 | color: #333232;
45 | }
46 |
47 | .heading3
48 | {
49 | font-family: 'Poppins';
50 | font-style: normal;
51 | font-weight: 300;
52 | font-size: 20px;
53 | line-height: 28px;
54 | color: #333232;
55 | }
56 | .heading4
57 | {
58 | font-family: 'Poppins', sans-serif;
59 | font-weight: 300;
60 | font-size: 16px;
61 | line-height: 28px;
62 | color: #333232;
63 | }
64 | .line1
65 | {
66 | font-family: 'Poppins', sans-serif;
67 | font-weight: 400;
68 | font-size: 16px;
69 | line-height: 28px;
70 | }
71 |
72 |
73 |
74 | .line2
75 | {
76 | font-family: 'Poppins', sans-serif;
77 | font-weight: 300;
78 | font-size: 14px;
79 | line-height: 28px;
80 | }
81 |
82 | .btnfont
83 | {
84 | font-family: 'Poppins', sans-serif;
85 | font-weight: 500;
86 | font-size: 24px;
87 | line-height: 28px;
88 | }
89 |
90 |
91 | .navMenuFont
92 | {
93 | font-family: 'Poppins', sans-serif;
94 | font-style: normal;
95 | font-weight: 300;
96 | font-size: 17px;
97 | line-height: 28px;
98 | color: #333232;
99 | }
100 |
101 | .topNavigationBoxShadow{
102 | box-shadow: 0px 1px 4px rgba(74, 188, 227, 0.25);
103 |
104 | }
105 |
106 |
107 | /* COLORS */
108 |
109 | .secondryColor
110 | {
111 | background: #2687F0;
112 | }
113 |
114 | .tertaryColor
115 | {
116 | background: #E3F3FF;
117 | }
--------------------------------------------------------------------------------
/Client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
15 |
19 |
20 |
21 |
22 |
23 |
27 |
31 |
35 |
36 |
37 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Smart Cruiter
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Client/src/Pages/Settings/MainPageOfSetting.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import LeftMenuBar from "../../Components/Dashboard/LeftMenuBar";
3 | import TopNavigationBar from "../../Components/Dashboard/TopNavigationBar";
4 | import ProfileIcon from "../../assets/icons/profileIcon.png";
5 | import TeamIcon from "../../assets/icons/teamIcon.png";
6 | import TempleteIcon from "../../assets/icons/templeteIcon.png";
7 | import CareerPage from "../../assets/icons/careerPageIcon.png";
8 | import { Link } from "react-router-dom";
9 | function MainPageOfSetting() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |

24 |
25 |
26 | Edit Profile
27 |
28 |
29 |
30 |
31 | {/* //2nd value */}
32 |
33 |
34 |

35 |
36 |
37 | Team Members
38 |
39 |
40 |
41 | {/* 3rd value */}
42 |
43 |
44 |

45 |
46 |
47 | Templetes
48 |
49 |
50 |
51 | {/* 4th value */}
52 | {/*
53 |
54 |

55 |
56 |
57 | Career Page
58 |
59 |
*/}
60 |
61 |
62 |
63 | );
64 | }
65 |
66 | export default MainPageOfSetting;
67 |
--------------------------------------------------------------------------------
/Client/src/Pages/EndUser/PostedJobDescription.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React from "react";
3 | import { useState } from "react";
4 | import { useEffect } from "react";
5 | import { useNavigate, useParams } from "react-router-dom";
6 |
7 | function PostedJobDescription() {
8 | const { id } = useParams();
9 | const [details, setDetails] = useState();
10 | const fetchJobDescription = () => {
11 | // axios POST request
12 | const options = {
13 | url: "https://smart-cruiter-fyp-production.up.railway.app/job/get-jobs/details",
14 | method: "POST",
15 | headers: {
16 | Accept: "application/json",
17 | "Content-Type": "application/json;charset=UTF-8",
18 | },
19 | data: { id: id },
20 | };
21 |
22 | axios(options).then((response) => {
23 | setDetails(response.data.jobs[0]);
24 | });
25 | };
26 | useEffect(() => {
27 | fetchJobDescription();
28 | }, [0]);
29 | console.log(details);
30 | const navigate = useNavigate();
31 | const handle = () => {
32 | const { org_id, _id } = details;
33 |
34 | navigate(`/portal/job/apply/${_id}`, {
35 | state: { orgID: org_id },
36 | });
37 | };
38 | return (
39 |
40 |
41 | {/*

*/}
47 |
48 |
49 | {details?.jobPosition}
50 |
51 |
52 |
53 |
58 |
Job Description
59 |
60 |
61 | Pay : {details?.salaryRangeFrom} ~~ to ~~ {details?.salaryRangeUpto}
62 |
63 |
64 | Totall No Of Jobs : {details?.numberOfSeats}
65 |
66 | Company : {details?.org_name}
67 |
68 |
72 |
75 |
76 |
77 | );
78 | }
79 |
80 | export default PostedJobDescription;
81 |
--------------------------------------------------------------------------------
/Client/src/Components/Dashboard/CreateJob/CreatedJobElement.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect } from "react";
3 | import { useState } from "react";
4 | import { Link, useNavigate } from "react-router-dom";
5 | import DeleteIcon from "../../../assets/icons/delete.svg";
6 | import SocialIcon from "../../../assets/icons/share.svg";
7 | function CreatedJobElement({ data, setData }) {
8 | const navigate = useNavigate();
9 | const handleJob = (id) => {
10 | navigate(`/JobDetails/${id}`);
11 | };
12 | // console.log(data);
13 | return (
14 |
15 | {data?.map((e, index) => {
16 | return (
17 |
handleJob(e._id)}
20 | title="Job"
21 | className="bg-white hover:bg-gray-100 hover:border hover:border-solid hover:border-gray-300 flex flex-wrap items-center w-80 pl-4 pr-4 pt-2 modalShadow cursor-pointer "
22 | >
23 | {/*
*/}
24 |
25 |
{e.jobPosition}
26 |
32 |
33 |
34 | {/* PART TO HANDLE DATA */}
35 |
36 |
37 |
Totall Candidates
38 |
{e.applicants_no}
39 |
40 |
41 |
42 |
Active Candidates
43 |
0
44 |
45 |
46 |
47 | {/* PART TO SHOW SHARE JOB-ID AND SHARE BUTTONS */}
48 |
49 |
50 |
51 |
JOB-ID: {index}
52 |
53 |
54 |
55 |

56 |

57 |
58 |
59 | {/* */}
60 |
61 | );
62 | })}
63 |
64 | );
65 | }
66 |
67 | export default CreatedJobElement;
68 |
--------------------------------------------------------------------------------
/Client/src/assets/icons/share.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Server/Models/JobModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const jobSchema = new mongoose.Schema({
4 | jobPosition: {
5 | type: String,
6 | required: true,
7 | },
8 | officeLocation: {
9 | type: String,
10 | required: true,
11 | },
12 | department: {
13 | type: String,
14 | required: true,
15 | },
16 |
17 | jobType: {
18 | type: String,
19 | enum: ["Full Time", "Part Time", "Remote Based", "Project Based", "Hourly"],
20 | required: true,
21 | },
22 | numberOfSeats: {
23 | type: Number,
24 | min: 1,
25 | required: true,
26 | },
27 | salaryRangeFrom: {
28 | type: Number,
29 | required: true,
30 | },
31 | salaryRangeUpto: {
32 | type: Number,
33 | required: true,
34 | },
35 | job_description: {
36 | type: String,
37 | required: true,
38 | },
39 | city: {
40 | type: String,
41 | required: true,
42 | },
43 | country: {
44 | type: String,
45 | required: true,
46 | },
47 | org_name: {
48 | type: String,
49 | required: true,
50 | },
51 | org_id: {
52 | type: String,
53 | required: true,
54 | },
55 | applicants_no: {
56 | type: Number,
57 | required: true,
58 | default: 0
59 | },
60 |
61 | job_status: {
62 | type: String,
63 | enum: ["Active", "Closed"],
64 | default: 'Active'
65 | },
66 | report_status: {
67 | type: {
68 | applied: Number,
69 | hired: Number,
70 | rejected: Number,
71 | withdrawn: Number,
72 | },
73 | default: {
74 | applied: 0,
75 | hired: 0,
76 | rejected: 0,
77 | withdraw: 0,
78 | },
79 | },
80 | report_experience: {
81 | type: {
82 | nill: Number,
83 | oneyear: Number,
84 | two_to_three: Number,
85 | four_to_five: Number,
86 | five_plus: Number,
87 | },
88 | default: {
89 | nill: 0,
90 | oneyear: 0,
91 | two_to_three: 0,
92 | four_to_five: 0,
93 | five_plus: 0,
94 | },
95 | },
96 | report_educational_level: {
97 | type: [String]
98 | },
99 | report_city: {
100 | type: [String]
101 | },
102 | report_university: {
103 | type: [String]
104 | },
105 | report_male_vs_female: {
106 | type: {
107 | male: Number,
108 | female: Number,
109 | },
110 | default: {
111 | male: 0,
112 | female: 0,
113 |
114 | },
115 | },
116 |
117 |
118 |
119 |
120 | });
121 |
122 | const Job = mongoose.model("Job", jobSchema);
123 |
124 | module.exports = Job;
125 |
--------------------------------------------------------------------------------
/Server/Models/Candidate.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const CandidateSchema = new mongoose.Schema({
4 | firstName: {
5 | type: String,
6 | required: true,
7 | },
8 |
9 | lastName: {
10 | type: String,
11 | required: true,
12 | },
13 | dob: {
14 | type: String,
15 | require: true
16 | },
17 | gender: {
18 | type: String,
19 | enum: ["Male", "Female"],
20 | required: true,
21 | },
22 | address: {
23 | type: String,
24 | required: true,
25 | },
26 |
27 | city: {
28 | type: String,
29 | required: true,
30 | },
31 |
32 | zipCode: {
33 | type: Number,
34 | required: true,
35 | },
36 |
37 | institute: [{
38 | type: String,
39 | required: true,
40 | }],
41 |
42 | level: [{
43 | type: String,
44 | required: true,
45 | }],
46 |
47 | session: [{
48 | type: Array,
49 | required: true
50 | }],
51 | majors: [{
52 | type: String,
53 | required: true,
54 | }],
55 |
56 |
57 | title: [{
58 | type: String,
59 | required: true,
60 | }],
61 | duration: [{
62 | type: Number,
63 | required: true,
64 | }],
65 | companyName: [{
66 | type: String,
67 | required: true,
68 | }],
69 | emailAddress: [{
70 | type: String,
71 | required: true,
72 | }],
73 | phoneNo: {
74 | type: Number,
75 | required: true,
76 | },
77 | linkedinProfile: {
78 | type: String,
79 | required: true,
80 | },
81 | gitHubProfile: {
82 | type: String,
83 | required: true,
84 | },
85 |
86 | profilePic: {
87 | type: String,
88 | required: true,
89 | },
90 |
91 |
92 | ResumeURL: {
93 | type: String,
94 | required: true,
95 | }
96 |
97 | ,
98 |
99 | jobID: {
100 | type: String,
101 | required: true,
102 | }
103 | ,
104 | orgID: {
105 | type: String,
106 | required: true,
107 | },
108 | recruitmentCycle: {
109 | type: String,
110 | enum: ["Applied", "Interviewing", "Reccomended", "Hired", "Withdrawn"],
111 | default: "Applied"
112 | },
113 | interviewDate: {
114 | type: String,
115 | default: 'nill'
116 | },
117 | interviewTime: {
118 | type: String,
119 | default: 'nill'
120 | },
121 | rating: {
122 | type: Number,
123 | default: 0
124 | },
125 | interview_link: {
126 | type: String,
127 | default: 'http:zoom.meet.com/783'
128 | },
129 | feedback_form: {
130 | type: [Number],
131 | default: [0]
132 | },
133 |
134 | withdrawn_reason: {
135 | type: String,
136 | default: "Try again!"
137 | }
138 | })
139 |
140 |
141 | const Candidate = mongoose.model("Candidate", CandidateSchema);
142 |
143 | module.exports = Candidate;
144 |
--------------------------------------------------------------------------------
/Client/src/Components/Dashboard/CreateJob/AppliedApplicantProfile.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import ShowMoreIcon from "../../../assets/icons/show_more.svg";
4 | function AppliedApplicantProfile({ id }) {
5 | // const [candidates, setCandidates] = useState();
6 | // useEffect(() => {
7 | // const fetchData = () => {
8 | // // axios POST request
9 | // const options = {
10 | // url: "http://localhost:3000/job/get-posted-job-details",
11 | // method: "POST",
12 | // headers: {
13 | // Accept: "application/json",
14 | // "Content-Type": "application/json;charset=UTF-8",
15 | // },
16 | // data: {
17 | // job_id: id,
18 | // },
19 | // };
20 |
21 | // axios(options).then((response) => {
22 | // setCandidates(response.data);
23 | // });
24 | // };
25 |
26 | // fetchData();
27 | // }, [0]);
28 | // console.log(candidates);
29 |
30 | return (
31 |
32 |
33 | {/* CANIDATE PROFILE PICTURE */}
34 |
35 |
36 |

42 |
43 | {/* EDUCATION , CITY AND EXPERINCE STAT UI */}
44 |
45 | {/* NAME FIELD */}
46 |
47 |
Alex Bhaati
48 |
49 |
50 |
51 |
52 |
Experience
53 |
54 |
55 |
1/Year
56 |
57 |
58 | {/* EDUCATION STAT */}
59 |
60 |
61 |
Education
62 |
63 |
64 |
Data Science
65 |
66 |
67 | {/* CITY STAT */}
68 |
69 |
70 |
City
71 |
72 |
73 |
Attock
74 |
75 |
76 |
77 |
80 |
81 |

87 |
88 |
89 |
90 |
91 |
92 | );
93 | }
94 |
95 | export default AppliedApplicantProfile;
96 |
--------------------------------------------------------------------------------
/Client/src/Components/HiredCandidatePage/MainPage.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 |
5 | function MainPage() {
6 | const [createdJobs, setCreatedJobs] = useState();
7 |
8 | useEffect(() => {
9 | const fetchData = () => {
10 | // axios POST request
11 | const options = {
12 | url: "https://smart-cruiter-fyp-production.up.railway.app/job/get-jobs",
13 | method: "POST",
14 | headers: {
15 | Accept: "application/json",
16 | "Content-Type": "application/json;charset=UTF-8",
17 | },
18 | data: { id: localStorage.getItem("organization_id") },
19 | };
20 |
21 | axios(options).then((response) => {
22 | setCreatedJobs(response.data.jobs);
23 | });
24 | };
25 |
26 | fetchData();
27 | }, [0]);
28 |
29 | const navigate = useNavigate();
30 | return (
31 |
32 |
33 | Hired Candidate Details
34 |
35 |
36 | {createdJobs?.map((element, index) => {
37 | return (
38 |
navigate(`details/${element._id}`)}
40 | key={index}
41 | className="cursor-pointer bg-white border border-solid border-gray-200 shadow-md rounded-lg w-80 h-72 pb-2
42 | hover:bg-gray-50
43 | "
44 | >
45 |
46 |
47 |
48 | {element.jobPosition}
49 |
50 |
51 |
52 |
53 | {element.department}
54 |
55 |
56 |
57 |
58 |
59 | {element.department == "HR" ? (
60 |

65 | ) : element.department == "IT" ? (
66 |

71 | ) : (
72 |

77 | )}
78 |
79 |
80 | {element.applicants_no} Applied
81 |
82 |
83 |
84 | );
85 | })}
86 |
87 |
88 | );
89 | }
90 |
91 | export default MainPage;
92 |
--------------------------------------------------------------------------------
/Client/src/Pages/EndUser/postedJobs.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 | import Banner from "../../assets/illustrations/job.png";
5 | function PostedJobs() {
6 | const [data, setData] = useState();
7 |
8 | useEffect(() => {
9 | const fetchData = async () => {
10 | const response = await axios.get(
11 | "https://smart-cruiter-fyp-production.up.railway.app/job/get-all-jobs"
12 | );
13 | setData(response.data.fetchAllPostedJobs);
14 | };
15 |
16 | fetchData();
17 | }, [0]);
18 |
19 | const navigate = useNavigate();
20 | const handleMe = (id) => {};
21 | // console.log(data);
22 | return (
23 |
24 |
25 |
26 |
Find Your
27 | Dream
28 | Job
29 | ,
30 |
31 | Simply fill form and
32 |
33 |
39 | Get Hired
40 |
41 |
42 |
43 |

48 |
49 |
50 |
51 |
52 | All posted jobs
53 |
54 |
55 |
56 | {data?.map((e, index) => {
57 | return (
58 | <>
59 |
62 | handleMe(navigate(`/portal/job/description/${e._id}`))
63 | }
64 | className="cursor-pointer w-52 rounded-lg text-center flex items-center h-52 bg-white bg-opacity-20 shadow-sm shadow-gray-900
65 | hover:bg-gray-700 hover:border hover:border-solid border-gray-800 "
66 | >
67 |
68 | {e.jobPosition}
69 |
70 | {/*
*/}
73 |
74 | >
75 | );
76 | })}
77 |
78 |
79 |
80 |
83 |
84 | );
85 | }
86 |
87 | export default PostedJobs;
88 |
--------------------------------------------------------------------------------
/Server/Routes/RecruitmentCycle.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const GetOrganizationPostedJobApplicants = require('../Controllers/Jobs/GetOrganizationPostedJob');
3 | const DeleteCandidateProfile = require('../Controllers/Recruitment Cycle/DeleteCandidateProfile');
4 | const FilterCandidates = require('../Controllers/Recruitment Cycle/FilterCandidates');
5 | const GetCandidateDetails = require('../Controllers/Recruitment Cycle/GetCandidateDetails');
6 | const GetComments = require('../Controllers/Recruitment Cycle/GetComments');
7 | const GetHiredCandidate = require('../Controllers/Recruitment Cycle/GetHiredCandidate');
8 | const GetReccomendedCandidatesDetails = require('../Controllers/Recruitment Cycle/GetReccomendedCandidateDetails');
9 | const GetReccomendedCandidates = require('../Controllers/Recruitment Cycle/GetReccomendedCandidates');
10 | const GetWithdrawnCandidate = require('../Controllers/Recruitment Cycle/GetWithdrawnCandidate');
11 | const GetWithdrawnCandidateDetails = require('../Controllers/Recruitment Cycle/GetWithdrawnCandidateDetails');
12 | const HandleComments = require('../Controllers/Recruitment Cycle/HandleComments');
13 | const PatchComments = require('../Controllers/Recruitment Cycle/PatchComments');
14 | const SaveInterviewDateAndTime = require('../Controllers/Recruitment Cycle/SaveInterviewDateAndTime');
15 | const SendInterviewEmail = require('../Controllers/Recruitment Cycle/SendInterviewEmail');
16 | const SentHiredEmail = require('../Controllers/Recruitment Cycle/SentHiredEmail');
17 | const showActiveCandidateDetails = require('../Controllers/Recruitment Cycle/ShowActiveCandidateDetails');
18 | const ShowInterviewingCandidate = require('../Controllers/Recruitment Cycle/ShowInterviewingCandidate');
19 | const SubmitFeedback = require('../Controllers/Recruitment Cycle/SubmitFeedbacl');
20 | const UpdateStatus = require('../Controllers/Recruitment Cycle/UpdateStatus');
21 | const UpdateWithdrawnReason = require('../Controllers/Recruitment Cycle/UpdateWithdrawnReason');
22 |
23 | const RecruitmentRouter = express.Router();
24 |
25 |
26 | RecruitmentRouter.post("/active/applied", GetOrganizationPostedJobApplicants)
27 | RecruitmentRouter.post("/active/user", showActiveCandidateDetails);
28 | RecruitmentRouter.post("/active/user/filter", FilterCandidates);
29 | RecruitmentRouter.delete("/active/user/delete", DeleteCandidateProfile);
30 | RecruitmentRouter.post("/active/user/add/comments", HandleComments);
31 | RecruitmentRouter.patch("/active/user/patch/comments", PatchComments);
32 | RecruitmentRouter.post("/active/user/get/comments", GetComments);
33 | RecruitmentRouter.post("/active/user/updateStatus", UpdateStatus)
34 | RecruitmentRouter.post("/active/interviewing", ShowInterviewingCandidate);
35 | RecruitmentRouter.post("/active/interviewing/details", GetCandidateDetails);
36 | RecruitmentRouter.post("/active/interviewing/details/sendInterviewEmail", SendInterviewEmail);
37 | RecruitmentRouter.post("/active/interviewing/details/dateandtime", SaveInterviewDateAndTime);
38 | RecruitmentRouter.post("/active/interviewing/details/savefeedback", SubmitFeedback);
39 | RecruitmentRouter.post("/active/reccomended", GetReccomendedCandidates);
40 | RecruitmentRouter.post("/active/reccomended/details", GetReccomendedCandidatesDetails);
41 | RecruitmentRouter.post("/active/hired", GetHiredCandidate);
42 | RecruitmentRouter.post("/active/hired/sendEmail", SentHiredEmail);
43 |
44 | RecruitmentRouter.post("/active/rejected", GetReccomendedCandidates);
45 | RecruitmentRouter.post("/active/withdrawn", GetWithdrawnCandidate);
46 |
47 | RecruitmentRouter.post("/active/withdrawn/details", GetWithdrawnCandidateDetails);
48 | RecruitmentRouter.post("/active/withdrawn/details/updateReason", UpdateWithdrawnReason);
49 |
50 |
51 | module.exports = RecruitmentRouter
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/SentHiredEmail.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Job = require('../../Models/JobModel');
3 | const app = express();
4 | const nodemailer = require("nodemailer");
5 |
6 | const SentHiredEmail = async (req, res, next) => {
7 |
8 | var org_name, job_title;
9 |
10 | const { email_to } = req.body;
11 | const { jobInfo } = req.body;
12 |
13 |
14 | // ************************
15 |
16 | // STEP : 1 FIND JOB
17 |
18 | // ************************
19 | const id = jobInfo.job_id;
20 |
21 | if (jobInfo == null) {
22 | res.status(404).json({ message: "ID isn't found in this request" })
23 | }
24 | const findJob = await Job.findById(id);
25 |
26 | if (findJob) {
27 | org_name = findJob.org_name,
28 | job_title = findJob.jobPosition
29 | }
30 | else {
31 | res.status(404).json({ message: "No job found with this ID" })
32 | }
33 |
34 | // *********************************
35 |
36 | // STEP : 2 GET ALL EMAIL - LIST , Email Body and Subject
37 |
38 | // AND SENT EMAIL
39 |
40 | // *********************************
41 |
42 | const { emailTitle, description } = req.body;
43 |
44 | const SendHireMail = async () => {
45 |
46 | const htmlCode = `
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ${description}
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | `
68 | try {
69 |
70 | const transporter = nodemailer.createTransport({
71 | host: 'smtp.gmail.com',
72 | port: 587,
73 | secure: false,
74 | auth: {
75 | user: process.env.MAILUSER,
76 | pass: process.env.MAILPASS,
77 | },
78 | });
79 |
80 | const mailOptions = {
81 | from: process.env.MAILUSER,
82 | to: [email_to],
83 | subject: emailTitle,
84 | html: htmlCode,
85 | };
86 |
87 | transporter.sendMail(mailOptions, (error, info) => {
88 | if (error) {
89 | // console.log(error);
90 | return res.status(500).json({ message: "An error occured" })
91 | } else {
92 | return res.status(200).json({ message: "Email Sent" })
93 | // console.log(`Email sent: ${info.response}`);
94 | }
95 | });
96 |
97 | } catch (error) {
98 | return res.status(500).json({ message: "Something goes unexpected , please try again" })
99 | // console.log("Error -> " + error);
100 | }
101 | }
102 |
103 |
104 | SendHireMail();
105 |
106 | }
107 |
108 | module.exports = SentHiredEmail;
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/SentDeclinedEmail.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const Job = require('../../Models/JobModel');
3 | const app = express();
4 | const nodemailer = require("nodemailer");
5 |
6 | const SentDeclinedEmail = async (req, res, next) => {
7 |
8 | var org_name, job_title;
9 |
10 | const { email_to } = req.body;
11 | const { jobInfo } = req.body;
12 |
13 |
14 | // ************************
15 |
16 | // STEP : 1 FIND JOB
17 |
18 | // ************************
19 | const id = jobInfo.job_id;
20 |
21 | if (jobInfo == null) {
22 | res.status(404).json({ message: "ID isn't found in this request" })
23 | }
24 | const findJob = await Job.findById(id);
25 |
26 | if (findJob) {
27 | org_name = findJob.org_name,
28 | job_title = findJob.jobPosition
29 | }
30 | else {
31 | res.status(404).json({ message: "No job found with this ID" })
32 | }
33 |
34 | // *********************************
35 |
36 | // STEP : 2 GET ALL EMAIL - LIST , Email Body and Subject
37 |
38 | // AND SENT EMAIL
39 |
40 | // *********************************
41 |
42 | const { emailTitle, description } = req.body;
43 |
44 | const SendHireMail = async () => {
45 |
46 | const htmlCode = `
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ${description}
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | `
68 | try {
69 |
70 | const transporter = nodemailer.createTransport({
71 | host: 'smtp.gmail.com',
72 | port: 587,
73 | secure: false,
74 | auth: {
75 | user: process.env.MAILUSER,
76 | pass: process.env.MAILPASS,
77 | },
78 | });
79 |
80 | const mailOptions = {
81 | from: process.env.MAILUSER,
82 | to: [email_to],
83 | subject: emailTitle,
84 | html: htmlCode,
85 | };
86 |
87 | transporter.sendMail(mailOptions, (error, info) => {
88 | if (error) {
89 | // console.log(error);
90 | return res.status(500).json({ message: "An error occured" })
91 | } else {
92 | return res.status(200).json({ message: "Email Sent" })
93 | // console.log(`Email sent: ${info.response}`);
94 | }
95 | });
96 |
97 | } catch (error) {
98 | return res.status(500).json({ message: "Something goes unexpected , please try again" })
99 | // console.log("Error -> " + error);
100 | }
101 | }
102 |
103 |
104 | SendHireMail();
105 |
106 | }
107 |
108 | module.exports = SentDeclinedEmail;
--------------------------------------------------------------------------------
/Client/src/Pages/Auth/ForgetPassword.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import { useFormik } from "formik";
3 | import React, { useState } from "react";
4 | import { useNavigate } from "react-router-dom";
5 | import { object, string } from "yup";
6 | import MainButton from "../../Components/Common/MainButton";
7 |
8 | function ForgetPassword() {
9 | const [error, Seterror] = useState();
10 |
11 | const navigate = useNavigate();
12 | const emailValue = {
13 | email: "",
14 | };
15 | const emailSchema = object({
16 | email: string().email("*Follow format").required("*Email is must"),
17 | });
18 |
19 | // -> handle login api call
20 | const handleLogin = async (inputData) => {
21 | console.log(" i am going to run");
22 | const options = {
23 | url: "https://smart-cruiter-fyp-production.up.railway.app/forget-password",
24 | method: "POST",
25 | headers: {
26 | Accept: "application/json",
27 | "Content-Type": "application/json;charset=UTF-8",
28 | },
29 | data: inputData,
30 | };
31 |
32 | axios(options)
33 | .then((response) => {
34 | if (response.status == 200) {
35 | console.log(200);
36 |
37 | navigate("/verifyotp?email=" + inputData.email);
38 | }
39 | })
40 | .catch(function (error) {
41 | if (error.response.status == 400) {
42 | Seterror("Email address is required");
43 | } else if (error.response.status == 404) {
44 | Seterror("Email address not found");
45 | } else if (error.response.status == 401) {
46 | Seterror("Email address is not activated");
47 | } else {
48 | Seterror("Error processing password reset request");
49 | }
50 | });
51 | };
52 | const formik = useFormik({
53 | initialValues: emailValue,
54 | validationSchema: emailSchema,
55 | onSubmit: (e) => {
56 | handleLogin(e);
57 | // e.preventDefault();
58 | // console.log(e);
59 | },
60 | });
61 | // console.log(error);
62 | return (
63 |
64 |
65 |

72 |
73 | Trouble Logging In
74 |
75 |
76 |
77 | Enter your email and we’ll send you a link to get back into your
78 | account.
79 |
80 |
81 |
104 |
105 |
106 | Return to Login
107 |
108 |
109 |
110 | );
111 | }
112 |
113 | export default ForgetPassword;
114 |
--------------------------------------------------------------------------------
/Client/src/Components/RecruitmentStage/DeleteCandidateProfileButton.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React from "react";
3 | import { useState } from "react";
4 | import { TiUserDelete } from "react-icons/ti";
5 | import { useNavigate } from "react-router-dom";
6 |
7 | function DeleteCandidateProfileButton({ id }) {
8 | const [showModal, setShowModal] = useState(false);
9 |
10 | const navigate = useNavigate();
11 |
12 | const handleDeleteButton = async () => {
13 | // axios POST request
14 | const options = {
15 | url: "https://smart-cruiter-fyp-production.up.railway.app/details/active/user/delete",
16 | method: "DELETE",
17 | headers: {
18 | Accept: "application/json",
19 | "Content-Type": "application/json;charset=UTF-8",
20 | },
21 | data: {
22 | id: id,
23 | },
24 | };
25 |
26 | axios(options)
27 | .then((response) => {
28 | if (response.status == 200) {
29 | setShowModal(false);
30 | navigate("/jobs");
31 | }
32 | })
33 | .then((e) => {
34 | console.log(e);
35 | });
36 | };
37 |
38 | return (
39 |
40 | {/* ///////////// */}
41 |
42 | <>
43 | {showModal ? (
44 | <>
45 |
46 |
47 | {/*content*/}
48 |
49 | {/*header*/}
50 |
51 |
52 | Are you sure to delete this candidate?
53 |
54 |
55 | {/*body*/}
56 |
57 | {/*footer*/}
58 |
59 |
66 |
76 |
77 |
78 |
79 |
80 |
81 | >
82 | ) : null}
83 | >
84 |
85 | {/* ////////////////////////////////////// */}
86 |
87 |
93 |
94 |
Delete
95 |
96 | );
97 | }
98 |
99 | export default DeleteCandidateProfileButton;
100 |
--------------------------------------------------------------------------------
/Client/src/Components/Dashboard/CreateJob/CreateJobHeadaer.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React from "react";
3 | import { useState } from "react";
4 | import { Link } from "react-router-dom";
5 | import DownImg from "../../../assets/icons/down.svg";
6 | function CreateJobHeadaer({ setData }) {
7 | const [jobStatus, SetJobStatus] = useState(false);
8 | const [departmentStatus, SetDepartmentStatus] = useState(false);
9 |
10 | const filterShowClosedJobs = () => {
11 | // axios POST request
12 | const options = {
13 | url: "https://smart-cruiter-fyp-production.up.railway.app/job/get-jobs/closed",
14 | method: "POST",
15 | headers: {
16 | Accept: "application/json",
17 | "Content-Type": "application/json;charset=UTF-8",
18 | },
19 | data: { id: localStorage.getItem("organization_id") },
20 | };
21 |
22 | axios(options).then((response) => {
23 | // console.log(response);
24 | setData(response.data.jobs);
25 | });
26 | };
27 | const filterShowActiveJobs = () => {
28 | // axios POST request
29 | const options = {
30 | url: "https://smart-cruiter-fyp-production.up.railway.app/job/get-jobs/active",
31 | method: "POST",
32 | headers: {
33 | Accept: "application/json",
34 | "Content-Type": "application/json;charset=UTF-8",
35 | },
36 | data: { id: localStorage.getItem("organization_id") },
37 | };
38 |
39 | axios(options).then((response) => {
40 | // console.log(response);
41 | setData(response.data.jobs);
42 | });
43 | };
44 |
45 | return (
46 |
47 | {/* --> Main Create Job Button */}
48 |
49 |
50 |
51 |
57 |
58 |
59 |
60 | {/* 2nd flex div */}
61 |
62 |
63 | {/* ==> Job Status Button */}
64 |
71 | {jobStatus == true ? (
72 |
85 | ) : null}
86 |
87 | {/*
*/}
94 |
95 | {/* {departmentStatus == true ? (
96 |
97 |
101 | -
102 | IT
103 |
104 | -
105 | HR
106 |
107 | -
108 | Markeeting
109 |
110 |
111 |
112 | ) : null} */}
113 |
114 |
115 | );
116 | }
117 |
118 | export default CreateJobHeadaer;
119 |
--------------------------------------------------------------------------------
/Server/Controllers/Setup Profile/Profile_Setup.js:
--------------------------------------------------------------------------------
1 | const { json } = require('express');
2 | const express = require('express');
3 | const app = express();
4 | const Cloudinary = require('cloudinary');
5 | const cloud = require("../../Config/Cloudnary.js");
6 |
7 | const OrganizationModal = require('../../Models/Organization_Model.js');
8 | const userModel = require('../../Models/User_Model.js');
9 | const { findOneAndUpdate } = require('../../Models/Organization_Model.js');
10 | const ProfileRouter = async (req, res, next) => {
11 | // --> ORGANIZATION DEATILS EXTRACTION
12 |
13 | const org_name = req.body.detailed_data.name;
14 |
15 | const phone = req.body.detailed_data.phone;
16 |
17 | const website_link = req.body.detailed_data.website_link;
18 | const logo = req.body.detailed_data.logo_url;
19 | const departments = req.body.detailed_data.departments;
20 | const address = req.body.detailed_data.address;
21 | const city = req.body.detailed_data.city;
22 | const country = req.body.detailed_data.country;
23 | const region = req.body.detailed_data.region;
24 | const fb_link = req.body.detailed_data.fb_link;
25 | const insta_link = req.body.detailed_data.insta_link;
26 | const yt_link = req.body.detailed_data.yt_link;
27 | const linkedIn_link = req.body.detailed_data.linkedin_link;
28 |
29 | // // --> EXTRACTING TEAM DATA
30 |
31 |
32 |
33 | const { name, email, role } = req.body.team_details;
34 | const data = [{ name, email, role }];
35 | // console.log(data);
36 | var departments2 = [departments]
37 | departments2 = departments2[0].list
38 |
39 | // // -> to get the image url path
40 | // console.log(req.file.path)
41 |
42 | // // -> Storing selected image to cloud
43 |
44 | // const img = await Cloudinary.v2.uploader.upload(req.file.path);
45 | // const img_url = img.secure_url;
46 |
47 | // -> so 1st check is there is valid reg user which is trying to setup org account
48 | const checkUser = await userModel.findById(req.body.userID)
49 | console.log(checkUser)
50 | if (checkUser.org_registered == false) {
51 |
52 | console.log('1st time hai');
53 |
54 | const org = await new OrganizationModal({
55 | "username": checkUser.username,
56 | "password": "Hamza123",
57 | "organization_name": org_name,
58 | "phoneNo": phone,
59 | "website": website_link,
60 | "logo": "Temp_URL",
61 | "departments": departments2,
62 |
63 | "office_address": address,
64 | "office_city": city,
65 | "office_country": country,
66 | "fb_url": fb_link,
67 | "linkedIn_url": linkedIn_link,
68 | "insta_url": insta_link,
69 | "yt_url": insta_link,
70 | "team_members": data
71 | })
72 |
73 |
74 |
75 | // findOneAndUpdate
76 |
77 | try {
78 |
79 | //Now 1st i have to get the acutall id value from _id with this code
80 |
81 | var user_id = org._id;
82 | user_id = user_id.toString();
83 | console.log(user_id)
84 | const profile = await userModel.findOneAndUpdate(
85 | { _id: req.body.userID }, // replace with the organization ID
86 | { $set: { org_registered: true, org_id: user_id } }, // use $set operator to update the field
87 | { new: true }, // return the updated document
88 | );
89 | await org.save()
90 | await profile.save();
91 | console.log(profile)
92 |
93 |
94 | return res.status(200).json({ message: "user saved" });
95 |
96 | } catch (error) {
97 | // console.log(error)
98 | return res.status(500).json(error)
99 | }
100 |
101 |
102 | }
103 |
104 | //1st Make Sure Is Organization is already registered or not
105 | else if (checkUser.org_registered == true) {
106 | // console.log('2nd time hai');
107 | // console.log('already organizaion is REGISTERED :-> STATUS = ' + checkUser.org_registered);
108 | return res.status(400).json({ message: "Already Organization Setup Or Fill Employee All Details" })
109 | }
110 |
111 |
112 | return res.status(404).json({ message: "Invalid username" })
113 | }
114 |
115 |
116 |
117 | module.exports = ProfileRouter;
--------------------------------------------------------------------------------
/Client/src/Components/RecruitmentStage/SwitchStatus.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { AiFillHeart } from "react-icons/ai";
3 | import DeleteCandidateProfileButton from "./DeleteCandidateProfileButton";
4 | import CandidateNotes from "./CandidateNotes";
5 | import { ToastContainer, toast } from "react-toastify";
6 | import "react-toastify/dist/ReactToastify.css";
7 | import { useState } from "react";
8 | import axios from "axios";
9 | import { useNavigate } from "react-router-dom";
10 |
11 | function SwitchStatus({ id }) {
12 | const [status, setStatus] = useState();
13 | const [alert, setAlert] = useState();
14 |
15 | const navigate = useNavigate();
16 | const notify = () =>
17 | toast.success("Candidate Status Updated", {
18 | position: "top-center",
19 | autoClose: 1000,
20 | hideProgressBar: false,
21 | closeOnClick: true,
22 | pauseOnHover: true,
23 | draggable: true,
24 | progress: undefined,
25 | theme: "light",
26 | });
27 |
28 | const handleStatus = () => {
29 | // axios POST request
30 | const options = {
31 | url: "https://smart-cruiter-fyp-production.up.railway.app/details/active/user/updateStatus",
32 | method: "POST",
33 | headers: {
34 | Accept: "application/json",
35 | "Content-Type": "application/json;charset=UTF-8",
36 | },
37 | data: { id, status },
38 | };
39 |
40 | axios(options)
41 | .then((response) => {
42 | if (response.status == 200) {
43 | notify();
44 | setTimeout(() => {
45 | navigate(-1);
46 | }, 1000);
47 | } else if (response.status == 300) {
48 | alert("Select any value of interview stage");
49 | } else {
50 | alert("something went wrong , refresh page and try again");
51 | }
52 | })
53 | .catch((e) => {
54 | alert("Something went wrong");
55 | });
56 | };
57 |
58 | return (
59 |
60 |
72 |
73 |
74 |
Switch Status
75 |
90 |
91 |
100 |
101 |
102 |
103 | {/* NOTES BUTTON CODE */}
104 |
105 |
106 | {/* LIKE BUTTON CODE */}
107 | {/*
*/}
115 |
116 | {/* DELETE BUTTON CODE */}
117 |
118 |
119 |
120 |
121 |
122 | );
123 | }
124 |
125 | export default SwitchStatus;
126 |
--------------------------------------------------------------------------------
/Client/src/Components/ProfileSetup/ProfileP1.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useState } from "react";
3 | import { Link, Outlet, useNavigate } from "react-router-dom";
4 | import NavigationTab from "../Dashboard/ProfileCreation/NavigationTab";
5 |
6 | function ProfileP1() {
7 | const navigate = useNavigate();
8 |
9 | const [selectedImage, setSelectedImage] = useState();
10 |
11 | // --> To Handle Input Fields
12 | const [profileData, SetProfileData] = useState({
13 | name: "",
14 | phone_no: "",
15 | website: "",
16 | });
17 |
18 | console.log(selectedImage);
19 | return (
20 |
130 | );
131 | }
132 |
133 | export default ProfileP1;
134 |
--------------------------------------------------------------------------------
/Server/Controllers/Recruitment Cycle/FilterCandidates.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const Candidate = require("../../Models/Candidate");
3 |
4 | const FilterCandidates = async (req, res, next) => {
5 | console.log("running now");
6 |
7 | const { filter_value } = req.body;
8 | const BSCandidates = await Candidate.find();
9 |
10 | if (filter_value == "MALE") {
11 | const result = BSCandidates.filter((level) => level.gender == "Male");
12 | return res.status(200).json(result);
13 | } else if (filter_value == "FEMALE") {
14 | const result = BSCandidates.filter((level) => level.gender == "Female");
15 | return res.status(200).json(result);
16 | }
17 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 |
20 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21 | // -> FILTER ON YEARS OF EXPERIENCE
22 | // **there is some issue with experience resolve it back
23 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 |
25 | if (filter_value === "Experience" || filter_value.startsWith("Experience")) {
26 | //1st Trim the req.body value because i will be sending input in this format Experience:1
27 | const str = filter_value;
28 | const value = str.split(":")[1].trim();
29 | //Now checking that city_value in DB
30 | console.log('I AM RUNNING');
31 | console.log(filter_value);
32 | console.log(value);
33 | if (value == 0) {
34 | const result = BSCandidates.filter((level) => level.duration <= 1);
35 | return res.status(200).json(result);
36 | } else if (value == 25) {
37 | const result = BSCandidates.filter(
38 | (level) => level.duration >= 1 && level.duration <= 3
39 | );
40 | return res.status(200).json(result);
41 | } else if (value == 50) {
42 | const result = BSCandidates.filter(
43 | (level) => level.duration >= 3 && level.duration <= 5
44 | );
45 | return res.status(200).json(result);
46 | } else if (value == 75) {
47 | const result = BSCandidates.filter(
48 | (level) => level.duration >= 5 && level.duration <= 8
49 | );
50 | return res.status(200).json(result);
51 | } else if (value == 100) {
52 | const result = BSCandidates.filter((level) => level.duration >= 8);
53 | return res.status(200).json(result);
54 | } else {
55 | return res.status(404).json({ message: "No user from this city exsist" });
56 | }
57 | }
58 |
59 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60 | // -> FILTER ON BASIS OF CITY NAME
61 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
62 |
63 | if (filter_value === "City" || filter_value.startsWith("City")) {
64 | //1st Trim the req.body value because i will be sending input in this format City : city_name
65 | const str = filter_value;
66 | const value = str.split(":")[1].trim();
67 | //Now checking that city_value in DB
68 | const result = BSCandidates.filter((level) => level.city == value);
69 | if (result) {
70 | return res.status(200).json(result);
71 | } else {
72 | return res.status(404).json({ message: "No user from this city exsist" });
73 | }
74 | }
75 |
76 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77 | // -> FILTER ON BASIS OF EDUCATIONAL QUALIFICATION
78 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79 | else if (filter_value == "BS") {
80 | const result = BSCandidates.filter((level) => level.level.length == 1);
81 |
82 | return res.status(200).json(result);
83 | } else if (filter_value == "MS") {
84 | const result = BSCandidates.filter((level) => level.level.length == 2);
85 |
86 | return res.status(200).json(result);
87 | } else if (filter_value == "PHD") {
88 | const result = BSCandidates.filter((level) => level.level.length == 3);
89 |
90 | return res.status(200).json(result);
91 | }
92 |
93 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
94 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
95 | else {
96 | return res.status(404).json({ message: "No candidate found" });
97 | }
98 | };
99 |
100 | module.exports = FilterCandidates;
101 |
--------------------------------------------------------------------------------
/Client/src/Components/RecruitmentStage/ReccomendidCandidateCard.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 | import NoUserSVG from "../../assets/illustrations/no_user.svg";
5 |
6 | function ReccomendidCandidateCard({ id }) {
7 | const [candidate, setCandidate] = useState();
8 | useEffect(() => {
9 | const getCandidates = () => {
10 | const options = {
11 | url: "https://smart-cruiter-fyp-production.up.railway.app/details/active/reccomended",
12 | method: "POST",
13 | headers: {
14 | Accept: "application/json",
15 | "Content-Type": "application/json;charset=UTF-8",
16 | },
17 | data: { id },
18 | };
19 |
20 | axios(options).then((response) => {
21 | if (response.status == 200) {
22 | setCandidate(response.data);
23 | } else {
24 | alert("something went wrong , try again");
25 | }
26 | });
27 | };
28 |
29 | getCandidates();
30 | }, [0]);
31 |
32 | const navigate = useNavigate();
33 |
34 | return (
35 |
36 | {candidate?.length !== 0 ? (
37 | candidate?.map((e, index) => {
38 | var educationLevelLastValue = e?.level.slice(-1)[0];
39 |
40 | return (
41 |
44 | navigate(`/JobDetails/reccomended/details/${e._id}`)
45 | }
46 | className="w-4/5 mt-6 block m-auto bg-white h-auto p-5 shadow-md rounded-md hover:bg-gray-50 hover:border border-solid border-gray-300 cursor-pointer "
47 | >
48 |
49 |
50 |

56 |
57 | {/* 2nd Profile Info */}
58 |
59 |
60 | {e.firstName + " " + e.lastName}
61 |
62 |
63 |
64 |
65 |
66 |
Experience
67 | {e.duration}
68 |
69 |
70 |
71 |
72 |
73 |
Education
74 | {educationLevelLastValue}
75 |
76 |
77 |
78 |
79 |
80 |
City
81 | {e.city}
82 |
83 |
84 |
85 |
86 |
87 |
88 | Interview Date
89 |
90 | {e.interviewDate}
91 |
92 |
93 |
94 |
95 |
96 | {/*
97 |
{e.}%
98 | */}
99 |
100 |
101 | );
102 | })
103 | ) : (
104 | // *********************************************
105 | // CODE FOR IF THERE ARE NOT RECCOMENDED USER
106 | // *********************************************
107 |
108 |

109 |
110 |
111 | Currently no Interviewing User
112 |
113 |
114 | )}
115 |
116 | );
117 | }
118 |
119 | export default ReccomendidCandidateCard;
120 |
--------------------------------------------------------------------------------
/Client/src/Components/ProfileSetup/Profile_Social3.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import NavigationTab from "../Dashboard/ProfileCreation/NavigationTab";
3 | import {
4 | FaFacebookF,
5 | FaLinkedinIn,
6 | FaInstagram,
7 | FaYoutube,
8 | } from "react-icons/fa";
9 | import { useNavigate, useLocation } from "react-router-dom";
10 | import { useState } from "react";
11 |
12 | function Profile_Social3() {
13 | const location = useLocation();
14 | // const { basicInfo, image } = location.state;
15 | console.log(location.state);
16 |
17 | // => A new object which can handle old + new value to pass to the next component using useNavigate()
18 | const [socialDetails, setSocialDetails] = useState({
19 | facebook_url: "",
20 | insta_url: "",
21 | linkedin_url: "asd",
22 | yt_url: "dsa",
23 | });
24 | console.log(socialDetails);
25 |
26 | //An data object to pass it to the next Route
27 | const Office_Profile = {
28 | office_details: location.state,
29 | social_links: socialDetails,
30 | };
31 | const navigate = useNavigate();
32 | return (
33 |
34 | {" "}
35 |
36 |
44 | {/* THIS MENUE MAIN INPUT CONTENT */}
45 |
46 |
Add Social Link's
47 |
48 | {/* HANDLING SOCIAL INPUT */}
49 |
50 |
87 |
88 | {/* HERE IS THE 2ND LINES OF SOCIAL LINK UI CODE */}
89 |
90 |
127 |
128 |
137 |
138 |
139 | );
140 | }
141 |
142 | export default Profile_Social3;
143 |
--------------------------------------------------------------------------------
/Client/src/Components/RecruitmentStage/WithdrawnDetailsCard.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect } from "react";
3 | import { useState } from "react";
4 | import ReactQuill from "react-quill";
5 | import { toast, ToastContainer } from "react-toastify";
6 | import SwitchStatus from "./SwitchStatus";
7 |
8 | function WithdrawnDetailsCard({ id }) {
9 | const [userDetails, setUserDetails] = useState();
10 | const [description, setDescription] = useState();
11 |
12 | const notify = () =>
13 | toast.success("Updated", {
14 | position: "top-center",
15 | autoClose: 1000,
16 | hideProgressBar: false,
17 | closeOnClick: true,
18 | pauseOnHover: true,
19 | draggable: true,
20 | progress: undefined,
21 | theme: "light",
22 | });
23 |
24 | useEffect(() => {
25 | // axios POST request
26 | const options = {
27 | url: "https://smart-cruiter-fyp-production.up.railway.app/details/active/withdrawn/details",
28 | method: "POST",
29 | headers: {
30 | Accept: "application/json",
31 | "Content-Type": "application/json;charset=UTF-8",
32 | },
33 | data: { id },
34 | };
35 |
36 | axios(options)
37 | .then((response) => {
38 | if (response.status == 200) {
39 | setUserDetails(response.data);
40 | setDescription(response.data.withdrawn_reason);
41 | } else {
42 | alert("Something went wrong, refresh page and try again");
43 | }
44 | })
45 | .catch((e) => {
46 | alert("Something went wrong, refresh page and try again");
47 | });
48 | }, [0]);
49 |
50 | const handleTextValue = () => {
51 | // axios POST request
52 | const options = {
53 | url: "https://smart-cruiter-fyp-production.up.railway.app/details/active/withdrawn/details/updateReason",
54 | method: "POST",
55 | headers: {
56 | Accept: "application/json",
57 | "Content-Type": "application/json;charset=UTF-8",
58 | },
59 | data: { id, description },
60 | };
61 |
62 | axios(options)
63 | .then((response) => {
64 | if (response.status == 200) {
65 | notify();
66 | console.log(response);
67 | } else {
68 | alert("Something went wrong, refresh page and try again");
69 | }
70 | })
71 | .catch((e) => {
72 | alert("Something went wrong, refresh page and try again");
73 | });
74 | };
75 |
76 | return (
77 |
78 |
Withdrawn Candidate
79 |
80 |
92 |
93 |
94 |
95 |

103 |
104 |
105 | {userDetails?.firstName + " " + userDetails?.lastName}
106 |
107 |
108 |
109 |
110 |
113 |
114 | {/* **********************************
115 | MODAL UI CODE
116 | ********************************** */}
117 |
118 |
119 |
120 |
121 |
127 |
132 |
133 |
134 | {/* *****************************
135 | ***************************** */}
136 |
137 |
138 |
139 |
140 |
Widthdrawn Reason
141 |
142 |
147 |
148 |
154 |
155 |
156 | );
157 | }
158 |
159 | export default WithdrawnDetailsCard;
160 |
--------------------------------------------------------------------------------
/Client/src/Components/RecruitmentStage/WithdrawnCandidateCard.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { BsFillInfoCircleFill } from "react-icons/bs";
4 | import { motion } from "framer-motion";
5 | import { FiSend } from "react-icons/fi";
6 | import ReactQuill from "react-quill";
7 | import { useNavigate } from "react-router-dom";
8 | import NoUserSVG from "../../assets/illustrations/no_user.svg";
9 | import OkSVG from "../../assets/illustrations/done.svg";
10 | import { BeatLoader } from "react-spinners";
11 | function WithdrawnCandidateCard({ id }) {
12 | // const { width, height } = useWindowSize();
13 |
14 | const [candidate, setCandidate] = useState();
15 |
16 | useEffect(() => {
17 | const getCandidates = async () => {
18 | const options = {
19 | url: "https://smart-cruiter-fyp-production.up.railway.app/details/active/withdrawn",
20 | method: "POST",
21 | headers: {
22 | Accept: "application/json",
23 | "Content-Type": "application/json;charset=UTF-8",
24 | },
25 | data: { id },
26 | };
27 |
28 | axios(options)
29 | .then((response) => {
30 | console.log(response);
31 | if (response.status == 200) {
32 | setCandidate(response.data);
33 | } else {
34 | alert("something went wrong , try again");
35 | }
36 | })
37 | .catch((e) => {
38 | alert("something went wrong , try again");
39 | });
40 | };
41 |
42 | getCandidates();
43 | }, [0]);
44 |
45 | const navigate = useNavigate();
46 |
47 | return (
48 |
49 | {candidate?.length !== 0 ? (
50 | candidate?.map((e, index) => {
51 | var educationLevelLastValue = e?.level.slice(-1)[0];
52 |
53 | return (
54 |
{
57 | navigate(`/JobDetails/withdrawn/details/${e._id}`);
58 | }}
59 | className="w-4/5 mb-6 block m-auto bg-white h-auto p-5 shadow-md rounded-md hover:bg-gray-50 hover:border border-solid border-gray-300 cursor-pointer "
60 | >
61 |
62 |
63 |

69 |
70 | {/* 2nd Profile Info */}
71 |
72 |
73 | {e.firstName + " " + e.lastName}
74 |
75 |
76 |
77 |
78 |
79 |
Experience
80 | {e.duration}
81 |
82 |
83 |
84 |
85 |
86 |
Education
87 | {educationLevelLastValue}
88 |
89 |
90 |
91 |
92 |
93 |
City
94 | {e.city}
95 |
96 |
97 |
98 |
99 |
100 |
101 | Interview Date
102 |
103 | {e.interviewDate}
104 |
105 |
106 |
107 |
108 |
109 | {/*
110 |
{e.}%
111 | */}
112 |
113 |
114 | );
115 | })
116 | ) : (
117 | // *********************************************
118 | // CODE FOR IF THERE ARE NOT RECCOMENDED USER
119 | // *********************************************
120 |
121 |

122 |
123 |
124 | Currently no Withdrawn Candidate
125 |
126 |
127 | )}
128 |
129 | );
130 | }
131 |
132 | export default WithdrawnCandidateCard;
133 |
--------------------------------------------------------------------------------
/Server/Controllers/Report Stats/MainPage.js:
--------------------------------------------------------------------------------
1 | const Job = require("../../Models/JobModel");
2 |
3 | const StatMainPage = async (req, res) => {
4 | const id = req.body.id;
5 | if (!id) {
6 | res.status(440).json({ message: "No id found" })
7 | }
8 |
9 |
10 |
11 | const findTotallJobs = await Job.find({ org_id: id });
12 |
13 | //Totall jobs posted
14 | const totallJobsPosted = findTotallJobs.length;
15 |
16 | // Counting totall number of candidates applied till now
17 | const applicantsCount = findTotallJobs.map((job) => job.applicants_no);
18 | const totallApplicants = applicantsCount.reduce((a, b) => a + b, 0)
19 |
20 |
21 | // Getting the applied , rejected , hired stats
22 |
23 | const reportForJobStats = findTotallJobs.map((job) => job.report_status);
24 |
25 |
26 | // Initialize the sum variables
27 | var hiredSum = 0;
28 | var appliedSum = 0;
29 |
30 | // Loop through the array
31 | for (var i = 0; i < reportForJobStats.length; i++) {
32 | // Access the object at index i
33 | var obj = reportForJobStats[i];
34 |
35 | // Extract the values for 'hired' and 'applied' keys
36 | var hiredValue = obj.hired;
37 | var appliedValue = obj.applied;
38 |
39 | // Add the values to the sum variables
40 | hiredSum += hiredValue;
41 | appliedSum += appliedValue;
42 | }
43 |
44 |
45 | // Output the sum values
46 | // console.log("Sum of 'hired' key values:", hiredSum);
47 | // console.log("Sum of 'applied' key values:", appliedSum);
48 |
49 |
50 | // *************************************************
51 | // NOW EXTRACTING EDUCATIONAL QUALIFICATION
52 | // *************************************************
53 |
54 | const reportForEducationalStatus = findTotallJobs.map((job) => job.report_educational_level);
55 |
56 |
57 | // const array = [[], ['Ph.D', 'Ph.D', 'BS', 'BS']];
58 |
59 | // Flatten the array
60 | const flattenedArray = reportForEducationalStatus.flat();
61 |
62 | // Count the occurrences of each value
63 | const countMap = flattenedArray.reduce((acc, value) => {
64 | if (acc[value]) {
65 | acc[value] += 1;
66 | } else {
67 | acc[value] = 1;
68 | }
69 | return acc;
70 | }, {});
71 |
72 | // Log the counts
73 | // console.log('Number of occurrences for each value:');
74 | // console.log(countMap);
75 |
76 |
77 | // *************************************************
78 | // NOW EXTRACTING CITIES OF APPLICANTS
79 | // *************************************************
80 |
81 |
82 | const reportForCities = findTotallJobs.map((job) => job.report_city);
83 |
84 | // Flatten the array
85 | const flattenedArray2 = reportForCities.flat();
86 |
87 | // Create an object to store unique values and their counts
88 | const citiesList = {};
89 |
90 | // Count the occurrences of each value
91 | flattenedArray2.forEach(value => {
92 | if (citiesList[value]) {
93 | citiesList[value] += 1;
94 | } else {
95 | citiesList[value] = 1;
96 | }
97 | });
98 |
99 | // Log the unique values and their counts
100 | // for (const value in citiesList) {
101 | // console.log(`${value}: ${citiesList[value]}`);
102 | // }
103 |
104 |
105 |
106 | // *************************************************
107 | // NOW EXTRACTING UNIVERSITIES LIST OF APPLICANTS
108 | // *************************************************
109 |
110 |
111 | const reportForUniversities = findTotallJobs.map((job) => job.report_university);
112 |
113 | // Flatten the array
114 | const flattenedArray3 = reportForUniversities.flat();
115 |
116 | // Create an object to store unique values and their counts
117 | const UniversitiesList = {};
118 |
119 | // Count the occurrences of each value
120 | flattenedArray3.forEach(value => {
121 | if (UniversitiesList[value]) {
122 | UniversitiesList[value] += 1;
123 | } else {
124 | UniversitiesList[value] = 1;
125 | }
126 | });
127 |
128 | // Log the unique values and their counts
129 | // for (const value in UniversitiesList) {
130 | // console.log(`${value}: ${UniversitiesList[value]}`);
131 | // }
132 |
133 |
134 | // *************************************************
135 | // NOW EXTRACTING APPLICANTS MALE VS FEMALE RATIO %
136 | // *************************************************
137 |
138 | const reportForMaleVSFemale = findTotallJobs.map((job) => job.report_male_vs_female);
139 |
140 |
141 | const GenderRatio = reportForMaleVSFemale.reduce((accumulator, currentValue) => {
142 | return {
143 | male: accumulator.male + currentValue.male,
144 | female: accumulator.female + currentValue.female
145 | };
146 | }, { male: 0, female: 0 });
147 |
148 |
149 | const total = GenderRatio.male + GenderRatio.female;
150 |
151 | const malePercentage = (GenderRatio.male / total) * 100;
152 | const femalePercentage = (GenderRatio.female / total) * 100;
153 | const GenderPercentage = {
154 | Male: malePercentage,
155 | Female: femalePercentage
156 | }
157 |
158 |
159 | res.send({ hiredSum, appliedSum, totallApplicants, totallJobsPosted, countMap, citiesList, UniversitiesList, GenderPercentage })
160 |
161 | }
162 |
163 | module.exports = StatMainPage;
--------------------------------------------------------------------------------
/Client/src/Components/RecruitmentStage/ReccomendedCandidateDetailsCard.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect } from "react";
3 | import { useState } from "react";
4 |
5 | import {
6 | FcAssistant,
7 | FcDataSheet,
8 | FcGraduationCap,
9 | FcHome,
10 | FcInvite,
11 | } from "react-icons/fc";
12 |
13 | function ReccomendedCandidateDetailsCard({ id, user, SetUser, setID }) {
14 | useEffect(() => {
15 | const getCanidateDetails = () => {
16 | // axios POST request
17 | const options = {
18 | url: "https://smart-cruiter-fyp-production.up.railway.app/details/active/reccomended/details",
19 | method: "POST",
20 | headers: {
21 | Accept: "application/json",
22 | "Content-Type": "application/json;charset=UTF-8",
23 | },
24 | data: { id },
25 | };
26 |
27 | axios(options)
28 | .then((response) => {
29 | SetUser(response.data);
30 | setID(response.data._id);
31 | })
32 | .catch((e) => {
33 | console.log(e);
34 | });
35 | };
36 |
37 | getCanidateDetails();
38 | }, [0]);
39 |
40 | var educationLevelLastValue = user?.level.slice(-1)[0];
41 |
42 | const calculateFeebackPercentage = (feedback) => {
43 | let rating = 0;
44 | for (let i = 0; i < feedback?.length; i++) {
45 | if (feedback[i] == 0) {
46 | rating += 0;
47 | } else {
48 | rating += feedback[i] * 4;
49 | }
50 | }
51 | return rating;
52 | };
53 | const rating = calculateFeebackPercentage(user?.feedback_form);
54 |
55 | return (
56 |
57 | {/* ****************************************************
58 | THIS IS 1ST DIV SHOWING PROFILE PICTURE AND RATING
59 | **************************************************** */}
60 |
61 |

68 |
74 |
75 |
76 |
77 |
78 |
84 |
91 |
92 |
93 |
94 |
Interview Rating
95 |
96 |
99 |
Details Here
100 |
101 |
102 | {/* ****************************************************
103 | THIS IS 2nd DIV SHOWING CANDIDATE DETAILS
104 | **************************************************** */}
105 |
106 |
107 | {user?.firstName + " " + user?.lastName}
108 |
109 |
110 |
111 |
112 |
113 | City :
114 |
115 |
{user?.city}
116 |
117 |
118 |
119 |
120 | DoB
121 | :
122 |
123 |
{user?.dob}
124 |
125 |
126 |
127 |
128 | {" "}
129 | Last Degree :{" "}
130 |
131 |
{educationLevelLastValue}
132 |
133 |
134 |
135 |
136 | {" "}
137 | Interview Date :{" "}
138 |
139 |
{user?.interviewDate}
140 |
141 |
142 |
143 |
144 | Email :{" "}
145 |
146 |
{user?.emailAddress}
147 |
148 |
149 |
150 |
151 | );
152 | }
153 |
154 | export default ReccomendedCandidateDetailsCard;
155 |
--------------------------------------------------------------------------------
/Client/src/Components/Dashboard/CreateJob/FIlterProfiles.jsx:
--------------------------------------------------------------------------------
1 | import React, { useRef, useState } from "react";
2 | import { Checkbox } from "@chakra-ui/react";
3 |
4 | import { BsPlusCircle } from "react-icons/bs";
5 | import axios from "axios";
6 | import { useEffect } from "react";
7 |
8 | function FilterProfiles({ can, setCan }) {
9 | const [city, setCity] = useState();
10 | const [slider, setSlider] = useState(0);
11 | const city_name = useRef();
12 | const filterCandidates = async (filter) => {
13 | // axios POST request
14 | const options = {
15 | url: "https://smart-cruiter-fyp-production.up.railway.app/details/active/user/filter",
16 | method: "POST",
17 | headers: {
18 | Accept: "application/json",
19 | "Content-Type": "application/json;charset=UTF-8",
20 | },
21 | data: {
22 | filter_value: filter,
23 | },
24 | };
25 |
26 | axios(options)
27 | .then((response) => {
28 | setCan(response.data);
29 | })
30 | .catch((e) => {
31 | console.log(e);
32 | });
33 | };
34 |
35 | return (
36 |
37 |
Filter Profile
38 |
39 |
40 |
41 | Education
42 |
43 |
44 | {/* Education check boxes */}
45 |
46 | filterCandidates("BS")}
53 | >
54 | BS
55 |
56 |
57 | filterCandidates("MS")}
64 | >
65 | MS
66 |
67 |
68 | filterCandidates("PHD")}
76 | >
77 | Ph.D
78 |
79 |
80 | {/* EXPERIANCE UI */}
81 |
Experience
82 |
83 |
{
85 | setSlider(e.target.value); // get value as :25
86 | filterCandidates("Experience:" + slider); //experience : 3s
87 | }}
88 | value={slider}
89 | type="range"
90 | min="0"
91 | max="100"
92 | className="range"
93 | step="25"
94 | />
95 |
96 | 0|1
97 | 1|3
98 | 3|5
99 | 5|8
100 | 8+
101 |
{" "}
102 |
103 |
104 | {/* CITY INPUT UI */}
105 |
106 |
City
107 |
108 | (city_name.current = e.target.value)}
114 | />
115 |
122 |
123 | {/* INSERTED TAGS LIST */}
124 | {city !== null ? (
125 |
126 |
filterCandidates("City:" + city)}
128 | className="cursor-pointer line1 bg-gray-800 p-2 rounded-lg text-white ml-3"
129 | >
130 | {city}
131 |
132 |
133 | ) : undefined}
134 |
135 | {/* GENDER SELECTION UI */}
136 |
137 | Gender
138 |
139 |
140 | filterCandidates("MALE")}
147 | >
148 | Male
149 |
150 |
151 | filterCandidates("FEMALE")}
158 | >
159 | Female
160 |
161 |
162 |
163 |
164 | );
165 | }
166 |
167 | export default FilterProfiles;
168 |
--------------------------------------------------------------------------------