diff --git a/package-lock.json b/package-lock.json index 5ef9c3e04a..ada30b07db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17456,21 +17456,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/src/actions/jobAnalytics/JobsHitsApplicationsActions.js b/src/actions/jobAnalytics/JobsHitsApplicationsActions.js new file mode 100644 index 0000000000..908a1121ba --- /dev/null +++ b/src/actions/jobAnalytics/JobsHitsApplicationsActions.js @@ -0,0 +1,26 @@ +import { JOBS_APPS_HITS_REQUEST, JOBS_APPS_HITS_REQUEST_SUCCESS, JOBS_APPS_HITS_REQUEST_FAILURE } from '../../constants/jobAnalytics/JobsApplicationsHitsConstants'; +import { ENDPOINTS } from '../../utils/URL'; + +export const fetchJobsHitsApplications = (queryParams, token) => async (dispatch) => { + dispatch({ type: JOBS_APPS_HITS_REQUEST }); + + try { + const response = await fetch(`${ENDPOINTS.JOB_HITS_AND_APPLICATIONS}?${queryParams}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Authorization': token + } + }); + + const data = await response.json(); + + if(!response.ok) { + throw new Error(data.error || 'Failed to fetch data'); + } + + dispatch({ type: JOBS_APPS_HITS_REQUEST_SUCCESS, payload: data }); + } catch (error) { + dispatch({ type: JOBS_APPS_HITS_REQUEST_FAILURE, payload: error.message }); + } +} diff --git a/src/components/JobAnalytics/JobsHitsApplicationsChart/JobsHitsApplicationsChart.jsx b/src/components/JobAnalytics/JobsHitsApplicationsChart/JobsHitsApplicationsChart.jsx new file mode 100644 index 0000000000..e5e150f315 --- /dev/null +++ b/src/components/JobAnalytics/JobsHitsApplicationsChart/JobsHitsApplicationsChart.jsx @@ -0,0 +1,231 @@ +import { Fragment, useEffect, useState } from 'react'; +import { fetchJobsHitsApplications } from '../../../actions/jobAnalytics/JobsHitsApplicationsActions'; +import { useDispatch, useSelector } from 'react-redux'; +import { BarChart, XAxis, YAxis, Tooltip, Legend, Bar, ResponsiveContainer, Brush } from 'recharts'; +import styles from './JobsHitsApplicationsChart.module.css'; +import Select from 'react-select'; +import DatePicker from 'react-datepicker'; + +export const JobsHitsApplicationsChart = () => { + const [startDate, setStartDate] = useState(null); + const [endDate, setEndDate] = useState(null); + const [selectedRoles, setSelectedRoles] = useState([]); + const [roleOptions, setRoleOptions] = useState([]); + const [roleAssigned, setRoleAssigned] = useState(false); + + const { loading, data, error } = useSelector(state => state.jobsHitsApplications); + const darkMode = useSelector(state => state.theme.darkMode); + const dispatch = useDispatch(); + const token = localStorage.getItem('token'); + + useEffect(() => { + const queryParams = new URLSearchParams(); + if (startDate) queryParams.append('startDate', startDate.toISOString()); + if (endDate) queryParams.append('endDate', endDate.toISOString()); + if (selectedRoles.length > 0) { + const roles = selectedRoles.map(role => role.value).join(','); + queryParams.append('roles', roles); + } + dispatch(fetchJobsHitsApplications(queryParams.toString(), token)); + }, [startDate, endDate, selectedRoles, dispatch, token]); + + useEffect(() => { + if (data && data.length > 0 && !roleAssigned) { + setRoleOptions( + data.map(item => { + return { + value: item.role, + label: item.role, + }; + }, setRoleAssigned(true)), + ); + } + }, [loading, error, data]); + + const CustomYAxisNames = ({ x, y, payload }) => { + const text = payload.value; + const extractedRole = text + .split('-') + .slice(0, 1)[0] + .trim(); + return ( + + + {text} + {extractedRole.length > 35 ? `${extractedRole.slice(0, 32)}...` : extractedRole} + + + ); + }; + + const handleStartDateChange = date => { + if (endDate && date > endDate) { + setEndDate(date); + } + setStartDate(date); + }; + + const handleEndDateChange = date => { + if (startDate && date < startDate) { + setStartDate(date); + } + setEndDate(date); + }; + + const handleResetDates = () => { + setStartDate(null); + setEndDate(null); + }; + + return ( + +
+

Role-wise Hits and Applications

+
+
+
+ {startDate || endDate ? ( + + ) : ( + + )} +
+
+ + +
+
+ + +
+
+ +
+
+ +