Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions src/components/form/SignInForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import InputField from "./InputField";
import Button from "./Button";
import { zodResolver } from "@hookform/resolvers/zod";
import { loginFormData } from "../validation/login";
import { Link, useNavigate } from "react-router-dom";
import { Link, useNavigate, useLocation } from "react-router-dom";
import { toast } from "react-toastify";
import { GraphQLClient } from "graphql-request";
import { loginAction } from "../../redux/actions/login";
import { Token } from "../../utils/utils";
import { Token } from '../../utils/utils';

const googleIcn: string = require("../../assets/assets/googleIcon.jpg").default;

const MY_QUERY = `
{
Expand All @@ -38,6 +40,7 @@ const LoginForm = () => {
const [isLoading, setIsLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const navigate = useNavigate();
const location = useLocation();

const {
register,
Expand All @@ -47,6 +50,26 @@ const LoginForm = () => {
resolver: zodResolver(loginSchema),
});

const redirectAfterLogin = async () => {
const lastAttemptedRoute = localStorage.getItem('lastAttemptedRoute');
if (lastAttemptedRoute) {
localStorage.removeItem('lastAttemptedRoute');
navigate(lastAttemptedRoute);
} else {
await Token();
const role = localStorage.getItem("roleName") as string;
if (role === "applicant") {
navigate("/applicant");
} else if (role === "superAdmin") {
navigate("/admin");
} else {
const searchParams = new URLSearchParams(location.search);
const returnUrl = searchParams.get('returnUrl') || '/';
navigate(returnUrl);
}
}
}

const onSubmit = async (data: loginFormData) => {
setIsLoading(true);
try {
Expand All @@ -56,15 +79,7 @@ const LoginForm = () => {
const token = response?.data?.data?.login?.token;
if (token) {
localStorage.setItem("access_token", token);
await Token()
const role = localStorage.getItem("roleName") as string;
if(role === "applicant"){
navigate("/applicant")
}
else if (role === "superAdmin") {
navigate("/admin");
}
toast.success("Logged in successfully!");
await redirectAfterLogin();
} else {
toast.error(response?.data?.errors[0].message);
}
Expand Down Expand Up @@ -188,3 +203,4 @@ const LoginForm = () => {
};

export default LoginForm;

2 changes: 1 addition & 1 deletion src/pages/Applicant/ApplicantLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const ApplicantLayout = () => {
setExpanded={setSidebarExpanded}
/>
</div>
<main className="flex w-[100%] justify-center items-center flex-1">
<main className="flex w-[100%] justify-center items-center flex-1 dark:bg-dark-frame-bg">
<Outlet />
</main>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/JobPost/job.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ const Jobs = (props: any) => {
</li>
<li>
<Link
to={`/Job/Post/${item.id}`}
to={`/admin/Job/Post/${item.id}`}
className="text-sm hover:bg-gray-100 text-gray-700 dark:text-white dark:hover:bg-gray-500 block px-4 py-2"
>
View
Expand Down Expand Up @@ -477,7 +477,7 @@ const Jobs = (props: any) => {
Edit
</Link>
<Link
to={`/Job/Post/${item.id}`}
to={`/admin/Job/Post/${item.id}`}
className="text-white bg-green border border-solid border-green rounded-md px-2 text-xs"
>
View
Expand Down
98 changes: 65 additions & 33 deletions src/pages/JobPost/viewSingleJob.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,56 @@
import { useParams } from 'react-router';
import NavBar from '../../components/sidebar/navHeader';
import { BsFillPersonLinesFill } from 'react-icons/bs';
import React, { useEffect, useState } from 'react';
import { fetchSingleJobPost } from '../../redux/actions/fetchSingleJobPostAction';
import { useAppDispatch, useAppSelector } from '../../hooks/hooks';
import { connect } from 'react-redux';
import { useParams } from "react-router";
import NavBar from "../../components/sidebar/navHeader";
import { BsFillPersonLinesFill } from "react-icons/bs";
import React, { useEffect, useState } from "react";
import { fetchSingleJobPost } from "../../redux/actions/fetchSingleJobPostAction";
import { useAppDispatch, useAppSelector } from "../../hooks/hooks";
import { connect } from "react-redux";
import { FaLinkedin, FaTelegram, FaTwitter, FaWhatsapp, FaEnvelope } from "react-icons/fa";
import { FcGoogle } from 'react-icons/fc';

const SingleJobPostDetails = (props: any) => {
const { fetchSingleJobPostStates } = props;
console.log('fetchSingleJobPostStates:', fetchSingleJobPostStates);
const dispatch = useAppDispatch();
const params = useParams();
const [jobPostId, setjobPostId] = useState(params.id);

useEffect(() => {
dispatch(fetchSingleJobPost(jobPostId));
}, [jobPostId]);

const shareMessage = `Check out this job opportunity: ${fetchSingleJobPostStates?.data?.title}\n${window.location.href}`;

const shareOnTwitterDM = () => {
const url = `https://twitter.com/messages/compose?text=${encodeURIComponent(shareMessage)}`;
window.open(url, "_blank", "width=600,height=400");
};

const shareOnWhatsApp = () => {
const url = `https://api.whatsapp.com/send?text=${encodeURIComponent(shareMessage)}`;
window.open(url, "_blank", "width=600,height=400");
};

const shareOnTelegram = () => {
const url = `https://t.me/share/url?url=${encodeURIComponent(window.location.href)}`;
window.open(url, "_blank", "width=600,height=400");
};

const shareOnLinkedIn = () => {
const url = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(window.location.href)}`;
window.open(url, "_blank");
};

const shareOnGmail = () => {
const subject = encodeURIComponent("Interesting Job Opportunity");
const body = encodeURIComponent(shareMessage);
const url = `https://mail.google.com/mail/?view=cm&fs=1&to=&su=${subject}&body=${body}`;
window.open(url, "_blank");
}

return (
<>
<div className="h-screen flex flex-col items-center dark:bg-dark-frame-bg">
<div className="flex flex-col justify-start mt-24 items-start p-5 w-[95%] lg:w-1/2 md_:mx-auto overflow-hidden dark:bg-dark-bg">
<div className="min-h-screen flex flex-col items-center dark:bg-dark-frame-bg">
<div className="flex flex-col justify-start mt-24 items-start p-5 w-[95%] md_:mx-auto overflow-hidden dark:bg-dark-bg">
<h2 className="text-white font-bold my-5">
<BsFillPersonLinesFill className="float-left m-1" />
Job Post information
Expand All @@ -29,46 +60,47 @@ const SingleJobPostDetails = (props: any) => {
<>
<div className="flex flex-col">
<h3 className="text-white">Job title</h3>
<p className="text-gray-500 text-sm dark:text-gray-400">
{fetchSingleJobPostStates.data.title}
</p>
<p className="text-gray-500 text-sm dark:text-gray-400">{fetchSingleJobPostStates.data.title}</p>
</div>
<div className="flex flex-col">
<h3 className="text-white">Program</h3>
<p className="text-gray-500 text-sm dark:text-gray-400">
{fetchSingleJobPostStates.data.program.title}
</p>
<p className="text-gray-500 text-sm dark:text-gray-400">{fetchSingleJobPostStates.data.program.title}</p>
</div>
<div className="flex flex-col">
<h3 className="text-white">Cycle</h3>
<p className="text-gray-500 text-sm dark:text-gray-400">
{fetchSingleJobPostStates.data.cycle.name}
</p>
<p className="text-gray-500 text-sm dark:text-gray-400">{fetchSingleJobPostStates.data.cycle.name}</p>
</div>
<div className="flex flex-col">
<h3 className="text-white">Cohort</h3>
<p className="text-gray-500 text-sm dark:text-gray-400">
{fetchSingleJobPostStates.data.cohort.title}
</p>
<p className="text-gray-500 text-sm dark:text-gray-400">{fetchSingleJobPostStates.data.cohort.title}</p>
</div>
<div className="flex flex-col">
<h3 className="text-white">Program description</h3>
<p className="text-gray-500 text-sm dark:text-gray-400">
{fetchSingleJobPostStates.data.description}
</p>
<p className="text-gray-500 text-sm dark:text-gray-400">{fetchSingleJobPostStates.data.description}</p>
</div>
<div className="text-white">Share Job Post</div>
<div className="flex fle gap-4 mt-6">
<button onClick={shareOnTwitterDM} className="flex items-center gap-2 px-4 py-2 bg-blue-400 text-white rounded hover:bg-blue-500 transition-colors">
<FaTwitter />
</button>
<button onClick={shareOnWhatsApp} className="flex items-center gap-2 px-4 py-2 bg-green text-white rounded hover:bg-green-600 transition-colors">
<FaWhatsapp />
</button>
<button onClick={shareOnTelegram} className="flex items-center gap-2 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors">
<FaTelegram />
</button>
<button onClick={shareOnLinkedIn} className="flex items-center gap-2 px-4 py-2 bg-blue-800 text-white rounded hover:bg-blue-900 transition-colors">
<FaLinkedin />
</button>
<button onClick={shareOnGmail} className="flex items-center justify-center gap-2 px-4 py-2 bg-white text-gray-700 rounded hover:bg-gray-100 transition-colors">
<FcGoogle size={20} />
</button>
</div>
<button
type="submit"
className="flex justify-self-start self-start rounded w-15 px-5 py-2 mt-10 bg-green ml-2 sm:ml-80 text-white transition-colors hover:bg-dark-frame-bg hover:text-green hover:border hover:border-green"
>
Share Post
</button>
</>
)}
</div>
</div>
</div>

</div>
</>
);
};
Expand Down
11 changes: 10 additions & 1 deletion src/pages/PrivateRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { Navigate } from "react-router-dom";
import { Navigate, useLocation } from "react-router-dom";
import { Token } from "../utils/utils";
import { useEffect } from "react";

const PrivateRoute = ({ children }) => {
const access_token = Token();
const location = useLocation();
const user =
//@ts-ignore
access_token !== null && access_token !== undefined && access_token !== '';

useEffect(() => {
if(!user){
localStorage.setItem('lastAttemptedRoute', location.pathname);
}
}, [user, location])
return user ? children : <Navigate to="/login" />;
};


export default PrivateRoute;
63 changes: 63 additions & 0 deletions src/pages/ShareApplication.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useParams } from 'react-router';
import NavBar from '../components/sidebar/navHeader';
import React, { useEffect } from 'react';
import { fetchSingleJobPost } from '../redux/actions/fetchSingleJobPostAction';
import { connect, useDispatch } from 'react-redux';
import { useAppSelector } from 'hooks/hooks';
import { Link } from 'react-router-dom';

type Props = {};

const ShareApplication = (props: any) => {
const { fetchSingleJobPostStates, updateJobPostStates } = props;
const dispatch = useDispatch();
const { id } = useParams();
useEffect(() => {
dispatch(fetchSingleJobPost(id));
}, [id]);
return (
<div className="flex flex-col h-screen absolute w-[100%]">
<div className="flex flex-row">
<div className="w-full">
<div>
<div className="bg-light-bg dark:bg-dark-frame-bg min-h-screen overflow-y-hidden overflow-x-hidden flex justify-center ">
<div className="flex flex-col w-[60%] dark:bg-dark-tertiary mt-[7rem] mb-[5rem] rounded-lg p-5 md:ml-0 md:w-[90%] ">
<div className="flex justify-center">
<p className="text-white font-semibold underline font-size-10">{fetchSingleJobPostStates?.data?.title}</p>
</div>
<div className="flex justify-start width-[80%] ml-3 mt-5">
<p className="text-white font-sans">{fetchSingleJobPostStates?.data?.description}</p>
</div>
<div className="flex flex-col justify-start width-[80%] ml-5 mt-5 ">
<p className="text-white font-semibold">Here are the requirements:</p>
<ul className="list-disc ml-5">
{fetchSingleJobPostStates?.data?.program?.requirements.map(
(item: any) => (
<li className="text-white font-sans">{item}</li>
),
)}
</ul>
</div>
<div className="flex justify-center mt-5">
<Link to={`/jobPost/${id}/apply`}>
<button className="flex bg-primary dark:bg-[#56C870] rounded-md py-2 px-4 text-white font-medium cursor-pointer">Apply</button>
</Link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};

// export default ShareApplication;

const mapState = (state: any) => ({
fetchSingleJobPostStates: state.fetchSingleJobPost,
});

export default connect(mapState, {
fetchSingleJobPost,
})(ShareApplication);
Loading
Loading