video conferencing online

parent 40aaf3c7
...@@ -26,6 +26,14 @@ ...@@ -26,6 +26,14 @@
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
crossorigin="anonymous" crossorigin="anonymous"
></script> ></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<title>Smart Recruiter</title> <title>Smart Recruiter</title>
</head> </head>
<body> <body>
......
...@@ -14,6 +14,8 @@ import "./components.scss"; ...@@ -14,6 +14,8 @@ import "./components.scss";
import ProtectedRoutes from "./components/ProtectedRoute"; import ProtectedRoutes from "./components/ProtectedRoute";
import ApplicationsLayout from "./Layouts/ApplicationLayout"; import ApplicationsLayout from "./Layouts/ApplicationLayout";
import Applicant from "./views/Application"; import Applicant from "./views/Application";
import MeetingRoom from "./views/MeetingRoom";
import Organization from "./views/Organization.view";
function App() { function App() {
return ( return (
...@@ -23,9 +25,11 @@ function App() { ...@@ -23,9 +25,11 @@ function App() {
<Route element={<ProtectedRoutes />}> <Route element={<ProtectedRoutes />}>
<Route path="/home" element={<Home />} /> <Route path="/home" element={<Home />} />
<Route path="/settings" element={<Settings />} /> <Route path="/settings" element={<Settings />} />
<Route path="/organizations" element={<Organization />} />
<Route element={<ApplicationsLayout />}> <Route element={<ApplicationsLayout />}>
<Route path="/applications" element={<Applications />} /> <Route path="/applications" element={<Applications />} />
<Route path="/applicant" element={<Applicant />} /> <Route path="/applicant" element={<Applicant />} />
<Route path="/meeting" element={<MeetingRoom />} />
</Route> </Route>
</Route> </Route>
</Routes> </Routes>
......
...@@ -5,14 +5,18 @@ import NavBar from "../components/NavBar"; ...@@ -5,14 +5,18 @@ import NavBar from "../components/NavBar";
type OwnProps = { type OwnProps = {
title: string; title: string;
children?: JSX.Element | JSX.Element[]; children?: JSX.Element | JSX.Element[];
suffix?: JSX.Element;
}; };
const Layout = ({ title, children }: OwnProps) => { const Layout = ({ title, children, suffix }: OwnProps) => {
return ( return (
<> <>
<NavBar /> <NavBar />
<div className="container pb-5"> <div className="container pb-5">
<h4 className="mb-3">{title}</h4> <div className="layout-title-container">
<h4 className="mb-3">{title}</h4>
{suffix}
</div>
{children} {children}
</div> </div>
</> </>
......
...@@ -44,3 +44,14 @@ p { ...@@ -44,3 +44,14 @@ p {
margin-top: 10px; margin-top: 10px;
} }
} }
.layout-title-container {
display: flex;
flex-direction: row;
justify-content: space-between;
h4,
div {
flex: 1;
}
margin-bottom: 10px;
}
import { ACTIONS } from ".";
import { ApplicationPayloadType } from "../types";
export const updateApplication = (
payload: {
candidateId: string;
applicationId: string;
update: any;
},
success?: () => void
) => ({
type: ACTIONS.UPDATE_APPLICATION,
payload,
success,
});
export const updateApplicationAction = (
payload: {
applicationId: string;
update: any;
},
success?: () => void
) => ({
type: ACTIONS.UPDATE_APPLICATION_ACTION,
payload,
success,
});
export const createMeeting = (
payload: ApplicationPayloadType,
success?: (roomId: string | null) => void
) => ({
type: ACTIONS.CREATE_MEETING,
payload,
success,
});
export const endMeeting = (
payload: { application: ApplicationPayloadType; roomId: string },
success?: () => void
) => ({
type: ACTIONS.END_MEETING,
payload,
success,
});
...@@ -18,19 +18,6 @@ export const updateJob = (payload: JobType, success?: () => void) => ({ ...@@ -18,19 +18,6 @@ export const updateJob = (payload: JobType, success?: () => void) => ({
success, success,
}); });
export const updateApplication = (
payload: {
candidateId: string;
applicationId: string;
update: any;
},
success?: () => void
) => ({
type: ACTIONS.UPDATE_APPLICATION,
payload,
success,
});
export const setDialogBox = (payload: string | null) => ({ export const setDialogBox = (payload: string | null) => ({
type: ACTIONS.SET_DIALOG, type: ACTIONS.SET_DIALOG,
payload, payload,
......
...@@ -11,7 +11,6 @@ export enum ACTIONS { ...@@ -11,7 +11,6 @@ export enum ACTIONS {
UPDATE_ORG = "UPDATE_ORG", UPDATE_ORG = "UPDATE_ORG",
SET_APP_STATE = "SET_APP_STATE", SET_APP_STATE = "SET_APP_STATE",
SET_JOBS = "SET_JOBS", SET_JOBS = "SET_JOBS",
...@@ -19,5 +18,9 @@ export enum ACTIONS { ...@@ -19,5 +18,9 @@ export enum ACTIONS {
CREATE_JOB = "CREATE_JOB", CREATE_JOB = "CREATE_JOB",
UPDATE_JOB = "UPDATE_JOB", UPDATE_JOB = "UPDATE_JOB",
UPDATE_APPLICATION = "UPDATE_APPLICATION", UPDATE_APPLICATION = "UPDATE_APPLICATION",
UPDATE_APPLICATION_ACTION = "UPDATE_APPLICATION_ACTION",
SET_DIALOG = "SET_DIALOG", SET_DIALOG = "SET_DIALOG",
CREATE_MEETING = "CREATE_MEETING",
END_MEETING = "END_MEETING",
} }
...@@ -18,12 +18,20 @@ export default class CommonAPI { ...@@ -18,12 +18,20 @@ export default class CommonAPI {
static updateApplication = (payload: { static updateApplication = (payload: {
update: any; update: any;
applicationId: string; applicationId: string;
candidateId: string; candidateId?: string;
}) => request("<BASE_URL>/applications/update", "PUT", payload); }) => request("<BASE_URL>/applications/update", "PUT", payload);
static updateApplicationAction = (payload: {
update: any;
applicationId: string;
}) => request("<BASE_URL>/applications/update/action", "PUT", payload);
static analyseInterview = (payload: { static analyseInterview = (payload: {
startTime: number; startTime: number;
endTime: number; endTime: number;
applicationId: string; applicationId: string;
}) => request("<BASE_URL>/applications/analyse", "POST", payload); }) => request("<BASE_URL>/applications/analyse", "POST", payload);
static searchJobs = (key: string) =>
request("<BASE_URL>/jobs/search", "GET", { key });
} }
import { request } from "../lib/api";
const MEETINGS_URL = "https://api.videosdk.live/v2";
export let meetingToken: string;
export const getToken = async () => {
if (meetingToken) {
return meetingToken;
} else {
try {
const data: { token: string } = await MeetingsAPI.getToken();
meetingToken = data.token;
return data.token;
} catch (error) {}
}
};
export default class MeetingsAPI {
static getToken = (): Promise<any> =>
request("<BASE_URL>/auth/conference/key", "GET", {}, false, undefined);
static createRoom = async (customRoomId: string) =>
request(
`${MEETINGS_URL}/rooms`,
"POST",
{ customRoomId },
false,
undefined,
{ Authorization: await getToken() }
);
static endSession = async (roomId: string) =>
request(
`${MEETINGS_URL}/sessions/end`,
"POST",
{ roomId },
false,
undefined,
{ Authorization: await getToken() }
);
static deactivateRoom = async (roomId: string) =>
request(
`${MEETINGS_URL}/rooms/deactivate`,
"POST",
{ roomId },
false,
undefined,
{ Authorization: await getToken() }
);
static startRecord = async (roomId: string) =>
request(
`${MEETINGS_URL}/recordings/start`,
"POST",
{ roomId },
false,
undefined,
{ Authorization: await getToken() }
);
static getRecordings = async (roomId: string) =>
request(`${MEETINGS_URL}/recordings`, "GET", { roomId }, false, undefined, {
Authorization: await getToken(),
});
}
import { initializeApp } from "firebase/app"; import { initializeApp } from "firebase/app";
import { getStorage } from "firebase/storage"; import { getStorage } from "firebase/storage";
export const BASE_URL = "http://localhost:5000"; export const BASE_URL = "http://192.168.8.120:5000";
export const DEFAULT_CONTROLS = { export const DEFAULT_CONTROLS = {
standard: { standard: {
sd: 1.5, sd: 1.5,
...@@ -55,4 +55,5 @@ export const emotionsData = [ ...@@ -55,4 +55,5 @@ export const emotionsData = [
}, },
]; ];
export const OPEN_API_KEY = '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' export const OPEN_API_KEY =
\ No newline at end of file "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";
...@@ -21,7 +21,8 @@ export const request = ( ...@@ -21,7 +21,8 @@ export const request = (
method: AxiosRequestConfig["method"], method: AxiosRequestConfig["method"],
requestData?: AxiosRequestConfig["data"] | AxiosRequestConfig["params"], requestData?: AxiosRequestConfig["data"] | AxiosRequestConfig["params"],
isGuest?: boolean, isGuest?: boolean,
contentType?: string contentType?: string,
header?: AxiosRequestConfig["headers"]
) => ) =>
new Promise(async (resolve, reject) => { new Promise(async (resolve, reject) => {
const endpoint = url?.replace?.("<BASE_URL>", BASE_URL); const endpoint = url?.replace?.("<BASE_URL>", BASE_URL);
...@@ -33,6 +34,7 @@ export const request = ( ...@@ -33,6 +34,7 @@ export const request = (
const headers = { const headers = {
auth_token, auth_token,
"Content-Type": contentType || "application/json", "Content-Type": contentType || "application/json",
...(header||{}),
}; };
logger("REQUEST: ", method, endpoint, headers, requestData); logger("REQUEST: ", method, endpoint, headers, requestData);
......
import { import {
AddressType, AddressType,
ApplicationStatus,
CandidateType, CandidateType,
OrganizationType, OrganizationType,
Reducers, Reducers,
...@@ -52,7 +53,7 @@ export const getUserId = (state: Reducers): string => { ...@@ -52,7 +53,7 @@ export const getUserId = (state: Reducers): string => {
return profile._id as string; return profile._id as string;
}; };
export const getStatusColor = (status?: string) => { export const getStatusColor = (status?: ApplicationStatus) => {
const color = const color =
status === "Accepted" status === "Accepted"
? "text-bg-success" ? "text-bg-success"
...@@ -60,6 +61,8 @@ export const getStatusColor = (status?: string) => { ...@@ -60,6 +61,8 @@ export const getStatusColor = (status?: string) => {
? "text-bg-warning" ? "text-bg-warning"
: status === "Rejected" : status === "Rejected"
? "text-bg-danger" ? "text-bg-danger"
: status === "Analyse"
? "text-bg-info"
: "text-bg-primary"; : "text-bg-primary";
return color; return color;
}; };
......
import { put, takeLeading, call } from "redux-saga/effects";
import { ACTIONS } from "../actions";
import { APP_STATE, ApplicationPayloadType } from "../types";
import MeetingsAPI from "../apis/meetings";
import { getJobs } from "./common";
import CommonAPI from "../apis/common";
function* createMeeting({
payload,
success,
}: {
type: typeof ACTIONS.CREATE_MEETING;
payload: ApplicationPayloadType;
success?: (roomId: string | null) => void;
}) {
try {
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.LOADING },
});
const data: { roomId: string } = yield call(
MeetingsAPI.createRoom,
payload._id
);
yield call(updateApplicationAction, {
type: ACTIONS.UPDATE_APPLICATION_ACTION,
payload: {
applicationId: payload._id,
update: { interview: { ...payload.interview, link: data.roomId } },
},
});
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.SUCCESS },
});
success?.(data.roomId);
} catch (error) {
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.FAILED },
});
success?.(null);
}
}
export function* endMeeting({
payload,
success,
}: {
type: typeof ACTIONS.END_MEETING;
payload: { application: ApplicationPayloadType; roomId: string };
success?: () => void;
}) {
try {
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.LOADING },
});
// yield call(MeetingsAPI.endSession, payload.roomId);
// yield call(MeetingsAPI.deactivateRoom, payload.roomId);
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.SUCCESS },
});
success?.();
} catch (error) {
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.FAILED },
});
success?.();
}
}
export function* updateApplication({
payload,
success,
}: {
type: typeof ACTIONS.UPDATE_APPLICATION;
payload: { applicationId: string; update: any; candidateId?: string };
success?: () => void;
}) {
try {
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.LOADING },
});
const data: { success: boolean } = yield call(
CommonAPI.updateApplication,
payload
);
if (data.success) {
yield call(getJobs, { type: ACTIONS.GET_JOBS });
}
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.SUCCESS },
});
success?.();
} catch (error) {
success?.();
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.FAILED },
});
}
}
export function* updateApplicationAction({
payload,
success,
}: {
type: typeof ACTIONS.UPDATE_APPLICATION_ACTION;
payload: { applicationId: string; update: any };
success?: () => void;
}) {
try {
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.LOADING },
});
const data: { success: boolean } = yield call(
CommonAPI.updateApplicationAction,
payload
);
if (data.success) {
yield call(getJobs, { type: ACTIONS.GET_JOBS });
}
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.SUCCESS },
});
success?.();
} catch (error) {
success?.();
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.FAILED },
});
}
}
export default function* applicationSaga() {
yield takeLeading(ACTIONS.CREATE_MEETING, createMeeting);
yield takeLeading(ACTIONS.END_MEETING, endMeeting);
yield takeLeading(ACTIONS.UPDATE_APPLICATION, updateApplication);
yield takeLeading(ACTIONS.UPDATE_APPLICATION_ACTION, updateApplicationAction);
}
...@@ -3,7 +3,7 @@ import { ACTIONS } from "../actions"; ...@@ -3,7 +3,7 @@ import { ACTIONS } from "../actions";
import CommonAPI from "../apis/common"; import CommonAPI from "../apis/common";
import { APP_STATE, JobType, Reducers } from "../types"; import { APP_STATE, JobType, Reducers } from "../types";
function* getJobs({ export function* getJobs({
success, success,
}: { }: {
type: typeof ACTIONS.GET_JOBS; type: typeof ACTIONS.GET_JOBS;
...@@ -103,46 +103,8 @@ function* updateJob({ ...@@ -103,46 +103,8 @@ function* updateJob({
} }
} }
function* updateApplication({
payload,
success,
}: {
type: typeof ACTIONS.UPDATE_APPLICATION;
payload: { applicationId: string; update: any; candidateId: string };
success?: () => void;
}) {
try {
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.LOADING },
});
const data: { success: boolean } = yield call(
CommonAPI.updateApplication,
payload
);
if (data.success) {
yield call(getJobs, { type: ACTIONS.GET_JOBS });
}
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.SUCCESS },
});
success?.();
} catch (error) {
success?.();
yield put({
type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.FAILED },
});
}
}
export default function* authSaga() { export default function* authSaga() {
yield takeLeading(ACTIONS.GET_JOBS, getJobs); yield takeLeading(ACTIONS.GET_JOBS, getJobs);
yield takeLeading(ACTIONS.CREATE_JOB, createJob); yield takeLeading(ACTIONS.CREATE_JOB, createJob);
yield takeLeading(ACTIONS.UPDATE_JOB, updateJob); yield takeLeading(ACTIONS.UPDATE_JOB, updateJob);
yield takeLeading(ACTIONS.UPDATE_APPLICATION, updateApplication);
} }
...@@ -3,7 +3,8 @@ import { all } from "redux-saga/effects"; ...@@ -3,7 +3,8 @@ import { all } from "redux-saga/effects";
import Auth from "./auth"; import Auth from "./auth";
import User from "./user"; import User from "./user";
import Common from "./common"; import Common from "./common";
import Application from "./application";
export default function* rootSaga() { export default function* rootSaga() {
yield all([Auth(), User(), Common()]); yield all([Auth(), User(), Common(), Application()]);
} }
...@@ -3,7 +3,14 @@ import { ACTIONS } from "../actions"; ...@@ -3,7 +3,14 @@ import { ACTIONS } from "../actions";
import CommonAPI from "../apis/common"; import CommonAPI from "../apis/common";
import UserAPI from "../apis/user"; import UserAPI from "../apis/user";
import { getProfile } from "../lib/util"; import { getProfile } from "../lib/util";
import { APP_STATE, CandidateType, JobType, OrganizationType, Reducers } from "../types"; import {
APP_STATE,
CandidateType,
JobType,
OrganizationType,
Reducers,
} from "../types";
import { getJobs } from "./common";
function* updateCandidate({ function* updateCandidate({
payload, payload,
...@@ -125,11 +132,12 @@ function* applyForJob({ ...@@ -125,11 +132,12 @@ function* applyForJob({
} }
} }
yield call(getJobs, { type: ACTIONS.GET_JOBS });
yield put({ yield put({
type: ACTIONS.SET_APP_STATE, type: ACTIONS.SET_APP_STATE,
payload: { state: APP_STATE.SUCCESS }, payload: { state: APP_STATE.SUCCESS },
}); });
window.location.reload();
} catch (error) { } catch (error) {
yield put({ yield put({
type: ACTIONS.SET_APP_STATE, type: ACTIONS.SET_APP_STATE,
...@@ -138,8 +146,6 @@ function* applyForJob({ ...@@ -138,8 +146,6 @@ function* applyForJob({
} }
} }
export default function* authSaga() { export default function* authSaga() {
yield takeLeading(ACTIONS.UPDATE_CANDIDATE, updateCandidate); yield takeLeading(ACTIONS.UPDATE_CANDIDATE, updateCandidate);
yield takeLeading(ACTIONS.UPDATE_ORG, updateOrganization); yield takeLeading(ACTIONS.UPDATE_ORG, updateOrganization);
......
...@@ -144,10 +144,17 @@ export type JobType = { ...@@ -144,10 +144,17 @@ export type JobType = {
organization: string; organization: string;
}; };
export type ApplicationStatus =
| "Pending"
| "In progress"
| "Analyse"
| "Accepted"
| "Rejected";
export type ApplicationType = { export type ApplicationType = {
candidate: string; candidate: string;
job: string; job: string;
status: "Pending" | "Accepted" | "In progress" | "Rejected"; status: ApplicationStatus;
interview?: { interview?: {