Commit f28229a9 authored by Ramadevi Guduri's avatar Ramadevi Guduri

Merge branch 'master' of...

Merge branch 'master' of https://gitlab.mynisum.com/vsingamchetty/nisum-scorecard into scorecarduidesigns
parents 61c0029d a0cb4a13
...@@ -110,7 +110,7 @@ app.post("/getreportees",async (req, res) => { ...@@ -110,7 +110,7 @@ app.post("/getreportees",async (req, res) => {
], ],
}; };
aggre.push({ $match: orCondation }); aggre.push({ $match: orCondation });
aggre.push({$unset:"empIdString"});
query = Object.assign(query); query = Object.assign(query);
} }
aggre.push({ $sort: { [sortBy]: sortByOrder } }); aggre.push({ $sort: { [sortBy]: sortByOrder } });
...@@ -244,42 +244,67 @@ const calculateAverage = async(query) => { ...@@ -244,42 +244,67 @@ const calculateAverage = async(query) => {
{ {
"empId":41689, "empId":41689,
"fromDate":"2024-03-10", "fromDate":"2024-03-10",
"toDate":"2024-03-14" "toDate":"2024-03-14",
page:0
perPage:10,
} }
*/ */
app.post("/getActivities", async(req, res) => { app.post("/getActivities", async(req, res) => {
let { empId, fromDate, toDate, today } = req.body; let { empId,today } = req.body;
if (!empId || typeof empId == "string") { if (!empId || typeof empId == "string") {
res.status(401).json({ message: "Employee id is missing / EmpId should be string only" }); res.status(401).json({ message: "Employee id is missing / EmpId should be string only" });
return; return;
} else { } else {
let query = { let page = req.body.page ? parseInt(req.body.page) || 1 : 1;
empId: empId, let limit = req.body.perPage ? parseInt(req.body.perPage) || 10 : 10;
}; let skip = (page - 1) * limit || 0;
if (fromDate && toDate) {
fromDate = new Date(fromDate) //let query = { empId: empId};
toDate = new Date(toDate); let aggreGate = [ { $match:{empId: empId} } ];
toDate.setHours(23); let fromDate = moment().subtract(90, "days").toDate();
toDate.setMinutes(59); let toDate = moment().toDate()
toDate.setSeconds(59);
query["activities.recorded_date"] = { if (req.body.fromDate && req.body.toDate) {
$gte: new Date(fromDate), fromDate = new Date(req.body.fromDate);
$lte: new Date(toDate), toDate = new Date(req.body.toDate);
};
} else {
// If fromDate and toDate are not provided, fetch data for the last 90 days
query["activities.recorded_date"] = {
$gte: moment().subtract(90, "days").toDate(),
$lte: moment().toDate(),
};
} }
await db.collection("performance_master") toDate.setHours(23);
.findOne(query) toDate.setMinutes(59);
.then((results) => { toDate.setSeconds(59);
res.status(201).json(results); // query["activities.recorded_date"] = {$gte: new Date(fromDate),$lte: new Date(toDate) };
}) aggreGate.push({$match:{"activities.recorded_date": {$gte: new Date(fromDate),$lte: new Date(toDate) } } });
.catch((error) => { aggreGate.push({$unwind:"$activities" });
res.status(401).json({ message: "Error fetching data" }, error); aggreGate.push({ $sort: { "activities.recorded_date": -1 } });
});
let facet = {
data: [{ $skip: skip }, { $limit: limit }],
totalCount: [{ $count: "count" }],
};
aggreGate.push({ $facet: facet });
aggreGate.push({ $unwind: { path: "$totalCount" } });
db.collection("performance_master")
.aggregate(aggreGate)
.toArray()
.then((result) => {
if (result && result.length) {
let resData = { activities: [], totalCount: result[0].totalCount,"empId":empId };
if(result[0].data?.length){
result[0].data.forEach((item)=>{
resData["activities"].push(item.activities);
});
}
res.status(201).json(resData);
} else {
res.status(201).json({ activities: [], totalCount: { count: 0 },"empId":empId });
}
})
.catch((error) => res.status(401).send(error));
} }
}); });
\ No newline at end of file
import React, { useState } from "react"; import React, { useState } from "react";
import Table from "../table"; import Table from "../table";
import moment from "moment";
import ModalButton from "../modal/modalButton"; import ModalButton from "../modal/modalButton";
import { useSelector ,useDispatch} from "react-redux"; import { useSelector ,useDispatch} from "react-redux";
import { useEffect } from "react"; import { useEffect } from "react";
...@@ -8,6 +7,7 @@ import {useParams} from 'react-router' ...@@ -8,6 +7,7 @@ import {useParams} from 'react-router'
import { fetchReportees } from "../../redux/reducers/reporteesSlice"; import { fetchReportees } from "../../redux/reducers/reporteesSlice";
import { calculateDefaultScore,calculateInitiativeScore } from "../../redux/reducers/viewreporteeSlice"; import { calculateDefaultScore,calculateInitiativeScore } from "../../redux/reducers/viewreporteeSlice";
import Loading from "../loading Component/Loading"; import Loading from "../loading Component/Loading";
import {convertUTCToLocal} from '../../utils/commonFunctions';
function Accordion({ title, data ,handleAddActivity,open,handleAccordian}) { function Accordion({ title, data ,handleAddActivity,open,handleAccordian}) {
...@@ -41,7 +41,7 @@ function Accordion({ title, data ,handleAddActivity,open,handleAccordian}) { ...@@ -41,7 +41,7 @@ function Accordion({ title, data ,handleAddActivity,open,handleAccordian}) {
} }
const headers = [ const headers = [
{ title: "Activity Name", id: "aName"}, { title: "Activity Name", id: "aName"},
{ title: "Date", id: "recorded_date", render: (value) => moment(value).format('DD-MM-YYYY') }, { title: "Date", id: "recorded_date", render: (value) => convertUTCToLocal(value) },
{title: "Rated By", id: "ratedBy"}, {title: "Rated By", id: "ratedBy"},
{ title: "Score", id: "score", render: (value) => <div className="w-[35px] px-3 bg-blue-400 rounded-full text-white font-bold text-center p-[4px]">{value}</div> }, { title: "Score", id: "score", render: (value) => <div className="w-[35px] px-3 bg-blue-400 rounded-full text-white font-bold text-center p-[4px]">{value}</div> },
{ title: "Comments", id: "comments", render:(value)=><span className="listData" title={value}>{value}</span>}, { title: "Comments", id: "comments", render:(value)=><span className="listData" title={value}>{value}</span>},
......
import React, {useEffect, useState} from 'react'; import React, { useEffect, useState, useRef } from 'react';
import {useNavigate, Link } from 'react-router-dom'; import { useNavigate, Link } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import clearStore from '../../utils/clearStore'; import clearStore from '../../utils/clearStore';
function Header({isOpen}) { function Header({ isOpen }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const logoutRef = useRef()
const user = useSelector((state) => state.userDetails.user); const user = useSelector((state) => state.userDetails.user);
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
...@@ -13,25 +14,41 @@ function Header({isOpen}) { ...@@ -13,25 +14,41 @@ function Header({isOpen}) {
navigate('/'); navigate('/');
clearStore(dispatch) clearStore(dispatch)
} }
useEffect(()=>{ useEffect(() => {
if(open!==false) if (open !== false)
setOpen(isOpen) setOpen(isOpen)
},[isOpen]) }, [isOpen])
useEffect(() => {
// Function to disable the button when clicking anywhere on the document
const handleClickOutside = (event) => {
if (logoutRef.current && !logoutRef.current.contains(event.target)) {
setOpen(false);
}
};
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, []);
return ( return (
<div className="flex items-center justify-between py-5 px-10" onClick={() => setOpen(!open)}> <div className="flex items-center justify-between py-5 px-10" >
<Link to={"/dashboard"}><img src="/logo.png"/></Link> <Link to={"/dashboard"}><img src="/logo.png" /></Link>
<div className="flex items-center relative"> <div className="flex items-center relative">
<button className=" -mt-1 text-2xl flex" onClick={() => setOpen(!open)}> <button ref={logoutRef} className=" -mt-1 text-2xl flex" onClick={() => setOpen(!open)}>
<img src="/user.png" width="35px" height="35px" className="mt-2 pr-2" /> <img src="/user.png" width="35px" height="35px" className="mt-2 pr-2" />
<div className="flex flex-col"> <div className="flex flex-col items-start">
<p className="text-lg font-semibold">{user?.empName}</p> <p className="text-lg font-semibold">{user?.empName}</p>
<p className="text-xs">{user?.designation}</p> <p className="text-xs">{user?.designation}</p>
</div> </div>
</button> </button>
<button onClick={handleLogout} className={`${!open && "hidden"} absolute top-[40px] bg-white opacity-100 shadow-md px-5 py-1 bg-opacity-100 rounded border border-gray-400 right-0 hover:bg-blue-400 hover:text-white w-[-webkit-fill-available]`} style={{zIndex: 1}}> <button onClick={handleLogout} className={`${!open && "hidden"} absolute top-[40px] bg-white opacity-100 shadow-md px-5 py-1 bg-opacity-100 rounded border border-gray-400 right-0 hover:bg-blue-400 hover:text-white w-[-webkit-fill-available]`} style={{ zIndex: 1 }}>
Logout Logout
</button> </button>
</div> </div>
</div> </div>
......
...@@ -5,16 +5,19 @@ import { useSelector, useDispatch } from "react-redux"; ...@@ -5,16 +5,19 @@ import { useSelector, useDispatch } from "react-redux";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { scoreColor } from '../../utils/commonFunctions'; import { scoreColor } from '../../utils/commonFunctions';
import Loading from "../loading Component/Loading"; import Loading from "../loading Component/Loading";
import PaginationComponent from "../Pagenation/Pagenation";
function LeftSidebar() { function LeftSidebar() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [currPage, setCurrPage] = useState(1); const [currPage, setCurrPage] = useState(1);
const [inputValue, setInputValue] = useState(''); const [pagesCount, setPagesCount] = useState(1);
const { reportees, loading, viewReportee } = useSelector((state) => state.reportees); const [inputValue, setInputValue] = useState(null);
const { reportees, loading, viewReportee, totalCount } = useSelector((state) => state.reportees);
const userDetails = useSelector((state) => state.userDetails); const userDetails = useSelector((state) => state.userDetails);
useEffect(() => { useEffect(() => {
if(inputValue!==null){
const debounceTimeout = setTimeout(() => { const debounceTimeout = setTimeout(() => {
const data = { const data = {
reportees: userDetails.user.reportees, reportees: userDetails.user.reportees,
...@@ -24,14 +27,30 @@ function LeftSidebar() { ...@@ -24,14 +27,30 @@ function LeftSidebar() {
}; };
dispatch(fetchReportees(data)); dispatch(fetchReportees(data));
}, 1000); }, 1000);
return () => clearTimeout(debounceTimeout); return () => clearTimeout(debounceTimeout);
}
}, [inputValue]); }, [inputValue]);
const handleChange = (event) => { const handleChange = (event) => {
setInputValue(event.target.value); setInputValue(event.target.value);
}; };
useEffect(() => {
setPagesCount(Math.ceil((totalCount) / (10)))
}, [totalCount])
const handlePageChange = (currPage) => {
let data = {
reportees: userDetails.user.reportees,
page: currPage,
perPage: 10
}
setCurrPage(currPage)
dispatch(fetchReportees(data))
}
return ( return (
<div className=" w-[33%] flex flex-col px-[5px]"> <div className=" w-[33%] flex flex-col px-[5px]">
...@@ -40,7 +59,7 @@ function LeftSidebar() { ...@@ -40,7 +59,7 @@ function LeftSidebar() {
Reportees Reportees
</p> </p>
<input <input
placeholder="Search Reportees" placeholder="Search"
type="text" type="text"
className="p-2 mi-2 border rounded w-[160px]" className="p-2 mi-2 border rounded w-[160px]"
value={inputValue} value={inputValue}
...@@ -53,7 +72,7 @@ function LeftSidebar() { ...@@ -53,7 +72,7 @@ function LeftSidebar() {
{reportees?.map(({ empName, score, empId }) => ( {reportees?.map(({ empName, score, empId }) => (
<button onClick={() => dispatch(setViewReportee(empId))} <button onClick={() => dispatch(setViewReportee(empId))}
// to={`/viewreportee`} // to={`/viewreportee`}
className={`flex items-center hover:bg-blue-400 hover:text-white bg-${viewReportee.empId == empId ? "blue-400 text-white" : "white" className={`flex items-center hover:bg-blue-400 hover:text-white bg-${viewReportee?.empId == empId ? "blue-400 text-white" : "white"
} p-2 justify-between mb-1 w-full`} } p-2 justify-between mb-1 w-full`}
key={empId} key={empId}
> >
...@@ -67,7 +86,13 @@ function LeftSidebar() { ...@@ -67,7 +86,13 @@ function LeftSidebar() {
))} ))}
</div> </div>
} }
<div>
<PaginationComponent
currentPage={currPage}
totalPages={pagesCount}
onPageChange={handlePageChange}
/>
</div>
</div> </div>
); );
} }
......
...@@ -35,7 +35,7 @@ export default function MyModal({ visible, onClose, type, handleAddActivity }) { ...@@ -35,7 +35,7 @@ export default function MyModal({ visible, onClose, type, handleAddActivity }) {
const handleScoreChange = (value) => { const handleScoreChange = (value) => {
setActivityData({ ...activityData, score: value }) setActivityData({ ...activityData, score: Number(value) })
} }
const handlePerformance=(value)=> { const handlePerformance=(value)=> {
......
...@@ -114,7 +114,7 @@ function Dashboard() { ...@@ -114,7 +114,7 @@ function Dashboard() {
<div className="mb-2"> <div className="mb-2">
<div className="flex justify-end my-1 mr-2 items-center"> <div className="flex justify-end my-1 mr-2 items-center">
<label>Search Employee:</label> <label>Search Employee:</label>
<input placeholder="Enter value" value={inputValue} onChange={handleChange} type="text" className="p-1 px-2 border rounded ml-2"/> <input placeholder="Enter" value={inputValue} onChange={handleChange} type="text" className="p-1 px-2 border rounded ml-2"/>
</div> </div>
<Table headers={headers} data={reportees} loading={loading} maxHeight={88} /> <Table headers={headers} data={reportees} loading={loading} maxHeight={88} />
......
...@@ -3,7 +3,8 @@ import { useSelector, useDispatch } from "react-redux"; ...@@ -3,7 +3,8 @@ import { useSelector, useDispatch } from "react-redux";
import { useParams, useNavigate } from "react-router"; import { useParams, useNavigate } from "react-router";
import { base_url } from "../../utils/constants"; import { base_url } from "../../utils/constants";
import axios from 'axios'; import axios from 'axios';
import { fetchReportees } from "../../redux/reducers/reporteesSlice"; import { fetchReportees,setViewReportee } from "../../redux/reducers/reporteesSlice";
import {fetchReporteeActivities} from '../../redux/reducers/viewreporteeSlice'
import Accordion from "../../components/accordion"; import Accordion from "../../components/accordion";
import {scoreColor} from '../../utils/commonFunctions'; import {scoreColor} from '../../utils/commonFunctions';
...@@ -54,7 +55,7 @@ function Viewreportee() { ...@@ -54,7 +55,7 @@ function Viewreportee() {
page: 1, page: 1,
perPage: 10, perPage: 10,
}; };
dispatch(fetchReportees(data)); dispatch(fetchReportees(data))
} }
} }
...@@ -74,6 +75,17 @@ function Viewreportee() { ...@@ -74,6 +75,17 @@ function Viewreportee() {
} }
} }
useEffect(()=>{
if(reportees.length>0 && viewReportee !== null)
dispatch(fetchReporteeActivities({empId:viewReportee?.empId}))
},[reportees,viewReportee])
// useEffect(()=>{
// if(reportees.length){
// dispatch(setViewReportee(viewReportee?.empId))
// }
// },[reportees])
useEffect(() => { useEffect(() => {
...@@ -85,7 +97,7 @@ function Viewreportee() { ...@@ -85,7 +97,7 @@ function Viewreportee() {
} }
}, []); }, []);
if (viewReportee && reportees.length) if ( reportees.length && viewReportee)
return ( return (
<div className="p-4" > <div className="p-4" >
<div className="bg-white p-3 rounded-md"> <div className="bg-white p-3 rounded-md">
......
...@@ -10,7 +10,7 @@ const initialState = { ...@@ -10,7 +10,7 @@ const initialState = {
error: null, error: null,
}; };
export const fetchReports = createAsyncThunk("getReports", async (data) => { export const fetchReporteeActivities = createAsyncThunk("getReports", async (data) => {
return await axios return await axios
.post(`${base_url}/getActivities`, data) .post(`${base_url}/getActivities`, data)
.then((response) => response.data); .then((response) => response.data);
...@@ -47,13 +47,13 @@ const reportSlice = createSlice({ ...@@ -47,13 +47,13 @@ const reportSlice = createSlice({
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
builder.addCase(fetchReports.pending, (state) => { builder.addCase(fetchReporteeActivities.pending, (state) => {
return {...state,loading :true,error :"loading"} return {...state,loading :true,error :"loading"}
}); });
builder.addCase(fetchReports.fulfilled, (state, action) => { builder.addCase(fetchReporteeActivities.fulfilled, (state, action) => {
return {...state,loading :false,error :"",reports:action.payload?.activities} return {...state,loading :false,error :"",reports:action.payload?.activities}
}); });
builder.addCase(fetchReports.rejected, (state, action) => { builder.addCase(fetchReporteeActivities.rejected, (state, action) => {
return {...state,loading :false,error :action.error || "Something went wrong!",reports:null} return {...state,loading :false,error :action.error || "Something went wrong!",reports:null}
}); });
}, },
......
import moment from 'moment';
export const scoreColor = (value) => { export const scoreColor = (value) => {
if (value < 1) { if (value < 1) {
return 'bg-red-400'; return 'bg-red-400';
...@@ -18,7 +20,7 @@ export const scoreColor = (value) => { ...@@ -18,7 +20,7 @@ export const scoreColor = (value) => {
export const debounce = (func, delay) => { export const debounce = (func, delay) => {
let timeoutId; let timeoutId;
return function(...args) { return function(...args) {
clearTimeout(timeoutId); clearTimeout(timeoutId);
timeoutId = setTimeout(() => { timeoutId = setTimeout(() => {
...@@ -26,3 +28,10 @@ export const debounce = (func, delay) => { ...@@ -26,3 +28,10 @@ export const debounce = (func, delay) => {
}, delay); }, delay);
}; };
} }
export const convertUTCToLocal = (utcDate) => {
const utcDateObj = new Date(utcDate);
const localTimeMillis = utcDateObj.getTime() + utcDateObj.getTimezoneOffset() * 60 * 1000;
const localDateObj = new Date(localTimeMillis);
return moment(localDateObj).format('DD-MM-YYYY')
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment