Commit 335206ad authored by Shiva Komirishetti's avatar Shiva Komirishetti

Merge branch 'initailSetup' into 'master'

Initail setup

See merge request !100
parents 6bd4d717 e4414a66
......@@ -5,7 +5,7 @@ let dbConnection
module.exports = {
connectToDb : (cb)=>{
// MongoClient.connect('mongodb://localhost:27017/ecommerse')
// MongoClient.connect('mongodb://localhost:27017/nisum-scorecard')
MongoClient.connect('mongodb+srv://vsingamchetty:user1234@cluster0.ch8kwyt.mongodb.net/nisumscorecard?connectTimeoutMS=30000&socketTimeoutMS=30000')
// mongodb+srv://vsingamchetty:user1234@cluster0.ch8kwyt.mongodb.net/
.then((client)=>{
......
......@@ -62,7 +62,6 @@ app.post('/login', async (req, res) => {
}
});
//to get activities to display
app.get("/activities", async(req, res) => {
await db.collection("activities_master")
......@@ -133,13 +132,13 @@ app.post("/getreportees",async (req, res) => {
.catch((error) => res.status(401).send(error));
});
//Example of post Data
/*
{
"empId":10000,
"data":{
"aName":"Approval of timesheet",
"aId":"D001",
"type":"duties",
"ratedBy":"Name",
"score":3,
......@@ -156,7 +155,7 @@ app.post('/createActivity',async (req, res) => {
let { data } = req.body;
//data validation
if (!_.get(data, "aName", "") || !_.get(data, "type", "") || !_.get(data, "score", "") || !_.get(data,"comments","") ||!_.get(data,"ratedBy","") ) {
if (!_.get(data, "aName", "") || !_.get(data, "aId", "") || !_.get(data, "type", "") || !_.get(data, "score", "") || !_.get(data,"comments","") ||!_.get(data,"ratedBy","") ) {
res.status(401).json({ "error": "Invalid Activity data" });
return;
}
......@@ -372,17 +371,6 @@ app.post("/getActivities-avg", async(req, res) => {
}
});
aggreGate.push({
$project:{
"type":"$_id",
"avgScore":1
}
});
aggreGate.push({
$unset:"_id"
});
db.collection("performance_master")
.aggregate(aggreGate)
......@@ -393,3 +381,194 @@ app.post("/getActivities-avg", async(req, res) => {
.catch((error) => res.status(401).send(error));
}
});
// -------------------------------------------------------------
const checkEmpIdExists = async (req, res, next) => {
try {
const empId = req.body.empId;
const empEdit = req.body?.empEdit;
const reportingTo = req.body.reportingTo;
const existingEmployee = await db.collection('employees').findOne({ empId: empId });
if (existingEmployee && !empEdit) {
return res.status(400).json({ error: "Employee already exists" });
}
else if(!existingEmployee){
await db.collection('employees').updateOne({ empId: reportingTo }, { $push: { reportees: empId } });
next();
}
else{
db.collection('employees').updateOne({empId:existingEmployee.reportingTo},{ $pull: { reportees: { $eq: empId } } });
await db.collection('employees').updateOne({ empId: reportingTo }, { $push: { reportees: empId } });
next();
}
} catch (error) {
console.error('Error checking or updating employee data:', error);
res.status(500).json({ error: "Internal server error" });
}
};
const checkEmpIdActivityExists = async (req, res, next) => {
try {
const empId = req.body.empId;
const existingEmployee = await db.collection('performance_master').findOne({ empId: empId });
if (!existingEmployee) {
return res.status(400).json({ error: "Employee doesn't have any activity" });
}
else{
next();
}
} catch (error) {
res.status(500).json({ error: "Internal server error" });
}
};
// Add employee details API endpoint
// {
// "empId": 41716,
// "empName": "Prashanth vagalaboina",
// "designation": "Software Engineer",
// "reportingTo": 16020,
// "score": 0,
// "project": "prologies",
// "reportees": [],
// "empEmail": "pvagalaboina@nisum.com",
// "techStack": "Frontend",
// "createdBy": 41111,
// "roleId": 1,
// "status": 1,
// "updatedBy": 41111
// }
app.post('/addEmployee', checkEmpIdExists, async (req, res) => {
try {
const empData = req.body;
// Insert data into MongoDB
const result = await db.collection('employees').insertOne(empData);
res.status(201).json({ message: 'Data added successfully', insertedId: result.insertedId });
} catch (err) {
console.error('Error adding data:', err);
res.status(500).json({ message: 'Internal server error' });
}
});
// Update employee details API endpoint
// Mandatory(*) fields are Editable in UI
// {
// "empId": 41716,
// * "empName": "Prashanth vagalaboina",
// * "designation": "Software Engineer",
// * "reportingTo": 16020,
// "score": 0,
// * "project": "prologies",
// "reportees": [],
// "empEmail": "pvagalaboina@nisum.com",
// * "techStack": "Frontend",
// "createdBy": 41111,
// * "roleId": 1,
// * "status": 1,
// * "updatedBy": 41111,
// "empEdit" : "true"
// }
app.put('/updateEmployee', checkEmpIdExists, async (req, res) => {
try {
const { empId, empName, project, roleId, designation, status, reportingTo, techStack, updatedBy } = req.body;
// Update employee details
const result = await db.collection('employees').updateOne(
{ empId: empId },
{
$set: {
empName,
project,
roleId,
designation,
status,
reportingTo,
techStack,
updatedBy
}
}
);
if (result.modifiedCount === 1) {
res.status(200).json({ message: 'Employee details updated successfully' });
} else {
res.status(404).json({ message: 'Employee not found' });
}
} catch (err) {
console.error('Error updating employee details:', err);
res.status(500).json({ message: 'Internal server error' });
}
});
// Employee role and status check API endpoint
// {
// "category": "emp_roles" or "emp_status"
// }
app.post('/getmaster-data',(req, res) => {
let emp = req.body.category;
let collection = ""
if(emp === "emp_roles")
collection ="emp_roles";
if(emp === "emp_status")
collection = "emp_status";
db.collection(collection).find({}).toArray()
.then(result => {
res.status(201).json(result);
})
.catch(error => res.status(500).json({ error: "Could not fetch the Role / Status of Employee" }));
});
// Delete Activity details API endpoint
// {
// "empId": 41716,
// "ObjectId": "660ba3ab707f841402133801"
// }
app.put('/deleteActivity', checkEmpIdActivityExists, async (req, res) => {
try {
const empId = req.body.empId;
const Id = req.body.ObjectId;
const result = await db.collection('performance_master').updateOne({empId:empId},{ $pull: { activities: { _id: new ObjectId(Id) } } });
console.log(result);
if (result.modifiedCount === 1) {
res.status(200).json({ message: 'Employee activity deleted successfully' });
}
} catch (err) {
console.error('Error updating employee details:', err);
res.status(500).json({ message: 'Internal server error' });
}
});
// Add MasterActivity details API endpoint
// {
// "atype": "duties",
// "aName": "submission test",
// "appreciate": "true",
// "depreciate": "false"
// }
app.post('/addMasterActivity', async (req, res) => {
try {
const empActivityMasterData = req.body;
// Insert data into MongoDB
const result = await db.collection('activities_master').insertOne(empActivityMasterData);
res.status(201).json({ message: 'Data added successfully', insertedId: result.insertedId });
} catch (err) {
console.error('Error adding data:', err);
res.status(500).json({ message: 'Internal server error' });
}
});
// Delete Master Activity details API endpoint
// {
// "ObjectId": "660ba3ab707f841402133801"
// }
app.put('/deleteMasterActivity', async (req, res) => {
const aId = req.body.ObjectId;
await db.collection('activities_master').deleteOne({_id: new ObjectId(aId)}).then((result) => {
res.send(result);}).catch((error) => res.status(401).send(error));
});
\ No newline at end of file
......@@ -7,6 +7,8 @@ import './App.css';
import PageNotFound from './pages/pagenotfound/PageNotFound';
import Exporttable from './pages/reportexport'
import AdminProfile from './pages/adminProfile';
import Adminreports from './pages/adminreports';
import Admin from './pages/admin';
function App() {
return (
......@@ -21,7 +23,8 @@ function App() {
<Route path="/viewreportee" element={<Layout><Viewreportee/></Layout>}/>
{/* fetch reports */}
<Route path="/reportees" element={<Layout><Exporttable/></Layout>}/>
<Route path="/adminreportees" element={<Layout><Adminreports/></Layout>}/>
<Route path="/Admin" element={<Layout><Admin/></Layout>}/>
<Route path="/*" element={<PageNotFound/>}/>
</Routes>
......
import React, { useState } from "react";
import MyCreateModal from "./createMyModel";
export default function CreateActivityButton({handleRefresh}) {
const [showMyModal, setShowMyModal] = useState(false);
return (
<div className="bg-blue-400 bg-opacity-30 mr-4" onClick={(e) => e.stopPropagation()}>
<button
className="bg-blue-400 text-white px-2 py-2 rounded hover:scale-95 transition text-sm"
onClick={()=>setShowMyModal(true)}
>
Create Activity
</button>
{showMyModal?<MyCreateModal setShowMyModal={setShowMyModal} handleRefresh={handleRefresh}/>:null}
</div>
);
}
\ No newline at end of file
import React, { useEffect, useState, useCallback } from "react";
import axios from "axios";
import { base_url } from "../../utils/constants";
import { fetchData } from "../../pages/admin";
const MyCreateModal = ({ setShowMyModal,handleRefresh}) => {
const [formData, setFormData] = useState({
atype: "",
aName: "",
appreciate: "",
depreciate: "",
});
const [enableSubmit, setEnableSubmit] = useState(false);
const handleInputChange = useCallback(
(event) => {
const { name, value } = event.target;
setFormData({ ...formData, [name]: value });
},
[formData]
);
const handleRadioChange = useCallback(
(event) => {
const { name, value } = event.target;
setFormData({ ...formData, [name]: value === "true" });
},
[formData]
);
useEffect(() => {
const { atype, aName, appreciate, depreciate } = formData;
if (
atype !== "" &&
aName !== "" &&
(appreciate === true || appreciate === false) &&
(depreciate === true || depreciate === false)
) {
// All conditions met
setEnableSubmit(true);
} else {
setEnableSubmit(false);
}
}, [formData]);
const handleSubmit = async (event) => {
event.preventDefault();
try {
// console.log(formData.atype);
await axios.post(`${base_url}/addMasterActivity`, formData)
.then((res)=>fetchData())
setShowMyModal(false);
setFormData({
atype: "",
aName: "",
appreciate: "",
depreciate: "",
});
handleRefresh()
} catch (error) {
console.error("Error submitting form data:", error);
}
};
return (
<div className="absolute w-full h-full inset-0 bg-black bg-opacity-25 backdrop-blur-sm flex items-center justify-center">
<div className="bg-white rounded-md lg:w-4/12 sm:w-100">
<div className="text-white py-3 pl-2 bg-blue-500 rounded-md text-start">
atype Type
</div>
<div>
<form
onSubmit={handleSubmit}
className="p-2 max-w-sm mx-auto text-[12px]"
>
<div className="flex items-center my-5">
<label htmlFor="atype">
SELECT atype<span className="text-[15px]">*</span>:{" "}
</label>
<select
id="atype"
name="atype"
value={formData.atype}
onChange={handleInputChange}
className="bg-gray-50 ml-2 w-6/12 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5"
>
<option value="">Select</option>
<option value="duties">Duties</option>
<option value="initiative">Initiative</option>
</select>
</div>
<div className="flex items-center">
<label className="font-medium mr-2">
atype Name<span className="text-[15px]">*</span>:
</label>
<input
type="text"
placeholder="Enter atype name"
name="aName"
value={formData.aName}
onChange={handleInputChange}
className="border border-gray-300 rounded p-2"
/>
</div>
<div className="flex items-center mb-1">
<label htmlFor="appreciate" className="font-medium">
Appreciate<span className="text-[15px]">*</span>:
</label>
<label htmlFor="appreciateTrue" className="font-medium ms-2">
True{" "}
</label>
<input
id="appreciateTrue"
type="radio"
value="true"
name="appreciate"
checked={formData.appreciate === true}
onChange={handleRadioChange}
className="w-4 h-4 m-3 text-blue-600 bg-gray-100 border-gray-300"
/>
<label htmlFor="appreciateFalse" className="font-medium">
False{" "}
</label>
<input
id="appreciateFalse"
type="radio"
value="false"
name="appreciate"
checked={formData.appreciate === false}
onChange={handleRadioChange}
className="w-4 h-4 m-3 text-blue-600 bg-gray-100 border-gray-300"
/>
</div>
<div className="flex items-center mb-1">
<label htmlFor="depreciate" className="font-medium">
Depreciate<span className="text-[15px]">*</span>:
</label>
<label htmlFor="depreciateTrue" className="font-medium ms-2">
True{" "}
</label>
<input
id="depreciateTrue"
type="radio"
value="true"
name="depreciate"
checked={formData.depreciate === true}
onChange={handleRadioChange}
className="w-4 h-4 m-3 text-blue-600 bg-gray-100 border-gray-300"
/>
<label htmlFor="depreciateFalse" className="font-medium">
False{" "}
</label>
<input
id="depreciateFalse"
type="radio"
value="false"
name="depreciate"
checked={formData.depreciate === false}
onChange={handleRadioChange}
className="w-4 h-4 m-3 text-blue-600 bg-gray-100 border-gray-300"
/>
</div>
<div className="flex items-center justify-end mb-3">
<button className="px-3 py-2 rounded-md bg-gray-700 text-white"
onClick={()=>setShowMyModal(false)}
>
Cancel
</button>
<button
type="submit"
className={`px-3 py-2 ml-5 rounded-md ${
enableSubmit
? "bg-blue-500 text-white"
: "bg-gray-400 text-white"
}`}
disabled={!enableSubmit}
title="Please fill all fields to submit"
>
Submit
</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default MyCreateModal;
\ No newline at end of file
// import React from "react";
// import { Link, useParams } from "react-router-dom";
// import SetWindowSize from '../../utils/SetWindowSize';
// import DashboardIcon from '../../assets/icons/dashboardIcon';
// import ReportsIcon from '../../assets/icons/reportsIcon';
// const menus = [
// {title: "Dashboard", path: '/dashboard', selectPaths: ['dashboard', 'viewreportee'], icon: <DashboardIcon/> },
// {title: "Reports", path: '/reportees', selectPaths:['reportees'], icon: <ReportsIcon />}
// ]
// function Sidebar() {
// const url = window.location.href;
// const [windowWidth, windowHeight] = SetWindowSize();
// const selected = url.split('/').at(-1)
// return (
// <div className="w-[20%] flex items-center flex-col overflow-auto" style={{ height: `calc(${windowHeight}px - 87px)` }}>
// <nav
// className="hs-accordion-group p-6 w-full flex flex-col flex-wrap"
// data-hs-accordion-always-open
// >
// <ul className="space-y-1.5">
// {
// menus.map((menu) => (
// <li key={menu.path}>
// <Link
// className={`flex items-center ${menu.selectPaths.includes(selected) && 'bg-gray-100'} gap-x-3.5 py-2 px-2.5 text-sm text-slate-700 rounded-lg hover:bg-gray-100 `}
// to={menu.path}
// >
// <span>{menu.icon}</span>
// {menu.title}
// </Link>
// </li>
// ))
// }
// </ul>
// </nav>
// </div>
// );
// }
// export default Sidebar;
import React from "react";
import { Link, useParams } from "react-router-dom";
import { useSelector } from 'react-redux'
import SetWindowSize from '../../utils/SetWindowSize';
import DashboardIcon from '../../assets/icons/dashboardIcon';
import ReportsIcon from '../../assets/icons/reportsIcon';
import AdminProfileIcon from '../../assets/icons/adminProfileIcon'; // Assuming you have an icon for Admin Profile
import Admin from "../../pages/admin";
const menus = [
{ title: "Dashboard", path: '/dashboard', selectPaths: ['dashboard'], icon: <DashboardIcon /> },
{ title: "My Reportees", path: '/myreportees', selectPaths: ['myreportees', 'viewreportee'], icon: <ReportsIcon /> },
{ title: "Reports", path: '/reportees', selectPaths:['reportees'], icon: <ReportsIcon /> },
{ title: "Dashboard", path: '/dashboard', selectPaths: ['dashboard'], icon: <DashboardIcon />, role:[2, 3] },
{ title: "My Reportees", path: '/myreportees', selectPaths: ['myreportees', 'viewreportee'], icon: <ReportsIcon />, role:[2] },
{ title: "Reports", path: '/reportees', selectPaths:['reportees'], icon: <ReportsIcon />, role:[2] },
{ title: "Activity List", path: '/admin', selectPaths:['admin'], icon: <ReportsIcon />, role:[1] },
{ title: "Reports", path: '/adminreportees', selectPaths:['adminreportees'], icon: <ReportsIcon />, role:[1] },
]
function Sidebar() {
const userDetails = useSelector((state) => state.userDetails?.user);
const url = window.location.href;
const [windowWidth, windowHeight] = SetWindowSize();
const selected = url.split('/').at(-1)
const selected = url.split('/').at(-1);
const roleId = userDetails.roleId ?? 0
return (
<div className="w-[20%] flex bg-blue-700 text-white items-center flex-col overflow-auto" style={{ height: `calc(${windowHeight}px - 87px)` }}>
......@@ -68,7 +31,9 @@ function Sidebar() {
>
<ul className="space-y-1.5">
{
menus.map((menu) => (
menus.map((menu) => {
if(menu.role.includes(roleId)) {
return (
<li key={menu.path}>
<Link
className={`flex ${menu.selectPaths.includes(selected) && 'bg-blue-500 ' } gap-x-3.5 py-2 lg:px-5 min-sm:px-4 text-sm text-slate-700 hover:bg-blue-500 text-white`}
......@@ -78,7 +43,9 @@ function Sidebar() {
</Link>
</li>
))
)
}
})
}
</ul>
......
......@@ -83,7 +83,7 @@ function Table({headers, data,loading, handleSorting }) {
<tr key={item.id} className="bg-[#eef5ff] font-medium hover:bg-white " >
{
headers?.map(({render, id}) => (
<td className="px-6 py-2 " >
<td className="px-6 py-2 capitalize" >
{render ? render(item[id]) : item[id] === "" ? "NA" : item[id] }
</td>
))
......
import React, { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux"; // Import useDispatch
import CreateActivityButton from '../../components/modal/createActivityButton';
import Table from '../../components/table';
import Loading from "../../components/loading Component/Loading";
import { styles } from './styles.js';
import { convertToString } from "../../utils/commonFunctions";
import axiosApi from '../../api/axiosConfig'
// Define fetchData function
export const fetchData = async () => {
try {
const response = await axiosApi.get(`/activities`);
//setActivitiesList(response.data)
return response.data;
} catch (error) {
console.error('Error fetching data:', error);
throw error; // Rethrow the error for handling by the caller if needed
}
};
const Admin = () => {
const [activitiesList, setActivitiesList] = useState([]);
const [refresh,setRefresh]=useState(true)
const { loading } = useSelector((state) => state.reportees);
const dispatch = useDispatch(); // Initialize useDispatch
const handleRefresh=()=>{
setRefresh(!refresh)
}
useEffect(() => {
// Call fetchData when the component mounts
fetchData().then((res)=>setActivitiesList(res))
}, [refresh]);
const handleDelete = async (_id) => {
try {
//console.log("Deleting activity with id:", _id);
await axiosApi.put(`/deleteMasterActivity`, { ObjectId: _id });
setRefresh(!refresh)
// console.log("Deleted successfully");
} catch (error) {
// console.error("Error deleting activity:", _id);
// console.error("Error:", error);
}
};
const headers = [
{ title: "Activity Type", id: "atype" },
{ title: "Activity Name", id: "aName" },
{ title: "Appreciate", id: "appreciate", render: (value) => convertToString(value) },
{ title: "Depreciate", id: "depreciate", render: (value) => convertToString(value) },
{
title: "Actions",
id: "_id",
render: (id) => (
<button
className="bg-red-400 text-white rounded-md px-1 py-1 flex items-center justify-center w-[40px]"
onClick={() => {
if (id) {
handleDelete(id);
//console.log(id)
} else {
// console.error("Item or item._id is undefined");
}
}}
>
X
</button>
)
},
];
if (loading) return <Loading />;
return (
<div>
<div className={styles.createActivityContainer}>
<div className={styles.textBlueHeading}>
ACTIVITY LIST
</div>
<div className="flex" style={{ justifyContent: 'flex-end', marginBottom: "10px" }}>
<CreateActivityButton handleRefresh={handleRefresh} />
</div>
<Table headers={headers} loading={loading} data={activitiesList} />
</div>
</div>
);
};
export default Admin;
export const styles = {
createActivityContainer: "overflow-auto sm:rounded-lg p-4 bg-[#E9EDEE] ",
textBlueHeading: "text-blue-800 py-3 pl-2 text-center fond-bold text-2xl",
};
\ No newline at end of file
import React, { useEffect, useState } from "react";
import axiosApi from '../../api/axiosConfig';
import { useDispatch, useSelector } from "react-redux";
import { fetchReportesActivitiesData, resetReporteesTableData, resetActivitiesData } from "../../redux/reducers/exporttableslice";
import { fetchReportees } from "../../redux/reducers/reporteesSlice";
import { convertUTCToLocal } from "../../utils/commonFunctions";
import Table from "../../components/table";
import DownloadIcon from '../../assets/icons/downloadIcon';
import jsPDF from 'jspdf';
import 'jspdf-autotable';
import {styles} from './styles';
function Adminreports() {
const dispatch = useDispatch();
const { user } = useSelector((state) => state.userDetails);
const { activitiesData } = useSelector((state) => state.totalreportees);
const { reportees, loading, totalCount, currPage, pagesCount } = useSelector(
(state) => state.reportees
);
const [selectedEmployee, setSelectedEmployee] = useState(0);
const [fromDate, setFromDate] = useState("");
const [toDate, setToDate] = useState("");
const [inputValue, setInputValue] = useState('');
const [pdfLoading, setPdfLoading] = useState(false);
const [selectedDate, setSelectedDate] = useState(null);
const [employees, setEmployees] = useState(null)
useEffect(() => {
if(selectedEmployee && fromDate && toDate) {
let data = {
empId: Number(selectedEmployee),
fromDate: fromDate,
toDate: toDate,
};
dispatch(fetchReportesActivitiesData(data));
}
},[selectedEmployee, fromDate, toDate])
const calculateDateRange = (monthsAgo) => {
const toDate = new Date().toISOString().split("T")[0];
const fromDate = new Date();
fromDate.setMonth(fromDate.getMonth() - monthsAgo);
const fromDateFormatted = fromDate.toISOString().split("T")[0];
return { fromDate: fromDateFormatted, toDate };
};
const handleDropdownChange = (event) => {
const selectedValue = event.target.value;
let fromDate, toDate;
if (selectedValue === "Past 1 month") {
({ fromDate, toDate } = calculateDateRange(1));
} else if (selectedValue === "Past 3 months") {
({ fromDate, toDate } = calculateDateRange(3));
} else if (selectedValue === "Past 6 months") {
({ fromDate, toDate } = calculateDateRange(6));
} else if (selectedValue === "Past 1 year") {
({ fromDate, toDate } = calculateDateRange(12));
}
if(selectedValue!=="")
setSelectedDate(selectedValue)
setFromDate(fromDate);
setToDate(toDate);
};
useEffect(() => {
// if (user) {
// let data = {
// reportees: user.reportees,
// page: 1,
// perPage: 100000000, //user.reportees.length,
// getMasterData: true
// };
// dispatch(fetchReportees(data));
// }
// return(() => {
// dispatch(resetReporteesTableData())
// })
const getEmployees = async () => {
try {
const res = await axiosApi.get(`/employees`);
const data = res?.data.filter((emp) => emp.roleId !== 1)
setEmployees(data)
} catch (error) {
// console.error("Error:", error);
}
}
getEmployees()
}, []);
const handleReportieDelete = async (id) => {
try {
await axiosApi.put(`/deleteActivity`, { ObjectId: id, empId: Number(selectedEmployee) });
dispatch(fetchReportesActivitiesData({ empId: Number(selectedEmployee), fromDate, toDate }));
} catch (error) {
// console.error("Error deleting activity:", id);
// console.error("Error:", error);
}
};
const headers = [
{ title: "Activity Name", id: "aName" },
{
title: "Date",
id: "recorded_date",
render: (value) => convertUTCToLocal(value),
},
{ 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: "Comments",
id: "comments",
render: (value) => (
<span className="listData" title={value}>
{value}
</span>
),
},
{
title: "Actions",
id: "_id",
render: (id) => (
<button
className="bg-red-400 text-white rounded-md px-1 py-1 flex items-center justify-center w-[40px]"
onClick={() => {
if (id && selectedEmployee) {
handleReportieDelete(id,selectedEmployee);
} else {
// console.error("Item or item._id is undefined");
}
}}
>
X
</button>
)
},
];
const periodOptions = ['Past 1 month', 'Past 3 months', 'Past 6 months', 'Past 1 year']
// Function to convert table to PDF
const convertTableToPDF = (data) => {
const doc = new jsPDF({
orientation: 'portrait',
format: 'a4'
});
const headerParams = {
align: 'justify',
fillStyle: 'FD'
}
const tableData = data.map(item => [item.aName, item.ratedBy, item.score, item.comments]);
// Add header to the PDF
doc.text('Score card reports', 15, 10, headerParams);
doc.autoTable({
head: [['Activity Name', 'Rated By', 'Score', 'Comments']], // Extract header row
body: tableData, // Extract data rows
startY: 20, // Start y-position of the table
theme: 'striped', // Table theme: 'plain', 'grid', 'striped', 'striped' (default is 'striped')
styles: { overflow: 'linebreak' }, // Styles for table cells
columnStyles: { 2: { fontStyle: 'bold' } }, // Styles for specific columns
});
// Save PDF
doc.save('ActivitiesList.pdf');
};
const getPdfList = async (type) => {
try{
setPdfLoading(true);
let data = {
empId: Number(selectedEmployee),
fromDate: fromDate,
toDate: toDate,
};
const response = await axiosApi.post(`/getActivities`, data).then((res) => res.data.activities);
if(response.length > 0) convertTableToPDF(response);
} catch {
setPdfLoading(false);
} finally {
setPdfLoading(false);
}
}
const getName = (id) => {
const user = reportees.find((item) => item?.empId === Number(id));
return user ? user.empName : '';
}
const handleSelectedName=(value)=>{
if(value!=="")
setSelectedEmployee(value)
}
return (
<div>
<div className={styles.genarateReportContainer}>
<div className={styles.textBlueHeading}>
REPORTS
</div>
<div>
<form className={styles.formContainer}>
<div className={styles.flexContainer}>
<div className={styles.flexItemsCenter}>
<div className={styles.flexItemsCenter}>
<label htmlFor="countries" className="font-semibold">
SELECT EMPLOYEE:{" "}
</label>
<select
onChange={(e) => handleSelectedName(e.target.value)}
// value={selectedEmployee}
className={styles.selectEmployeeDropdown}
>
<option id="" value="">
Select
</option>
{employees &&
employees.map((reportee) => (
<option
className="text-pretty"
key={reportee?.empId}
id={reportee?.empId}
value={reportee?.empId}
>
{reportee?.empName}
</option>
))}
</select>
</div>
<div className={styles.flexItemsCenter}>
<label htmlFor="countries" className="font-semibold ml-4">
SELECT PERIOD:
</label>
<select
onChange={handleDropdownChange}
className={styles.selectEmployeeDropdown && styles.selectDropdown}
>
<option value="">
Select
</option>
{
periodOptions.map((option) => (
<option value={option}>
{option}
</option>
))
}
</select>
</div>
</div>
<div className="flex">
<button
onClick={getPdfList}
disabled={activitiesData?.length === 0}
type="button"
className={styles.downloadButton}
>
<span>{pdfLoading ? "Downloading... " : "Download "} </span>
<DownloadIcon />
{ pdfLoading && <div className="loading ml-2 "></div>}
</button>
</div>
</div>
</form>
</div>
<div className={`mb-4 ${activitiesData?.length === 0 && "hidden"}`}>
<p>Showing <span className="font-semibold">{getName(selectedEmployee)}</span> reports from <span className="font-semibold">{selectedDate}</span> </p>
</div>
<Table headers={headers} loading={loading} data={activitiesData} />
</div>
</div>
);
}
export default Adminreports;
export const styles = {
genarateReportContainer: "overflow-auto sm:rounded-lg p-4 bg-gray-50 ",
textBlueHeading: "text-blue-800 py-3 pl-2 text-center fond-bold text-2xl",
formContainer: "p-2 text-[12px] mb-4",
flexContainer: "flex items-center justify-between",
flexItemsCenter: "flex items-center",
selectEmployeeDropdown:
"bg-gray-50 text-balance rounded-lg rounded-md ml-2 border border-gray-300 text-gray-900 text-sm focus:ring-blue-500 focus:border-blue-500 block p-2.5 ",
selectDropdown:"bg-gray-50 text-balance rounded-lg ml-2 border border-gray-300 text-gray-900 text-sm focus:ring-blue-500 focus:border-blue-500 block p-2.5 w-[235px]",
downloadButton:
"px-3 py-2 ml-5 min-w-[100px] disabled:bg-gray-400 h-[40px] bg-blue-500 font-semibold text-white rounded-md flex items-center justify-center",
Norecords: "text-center align-middle pt-14 pb-14 text-blue-500 font-bold",
};
\ No newline at end of file
......@@ -40,13 +40,18 @@ function Home() {
setLoading(false)
inputRef.current.focus();
},[])
useEffect(()=>{
},[]);
if (userDetails?.user!=null)
navigate("/dashboard")
useEffect(()=>{
if (userDetails?.user!=null){
if(userDetails?.user.roleId === 1)
navigate("/admin")
else
navigate("/dashboard")
}
else {
navigate("/")
}
},[userDetails])
return (
......
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
export const fetchUsers = createAsyncThunk("user/fetchUsers", async () => {
try {
const response = await axios.get("/addMasterActivity");
return response.data;
} catch (error) {
throw error;
}
});
export const addActivity = createAsyncThunk("user/addUser", async (values) => {
try {
const response = await axios.post(
"/addMasterActivity",
{
type: values.type,
aId: values.aId,
aId: values.aId,
appreciate: values.appreciate,
depreciate:values.depreciate,
},
{
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
);
return response.data;
} catch (error) {
throw error;
}
});
const activitiesSlice= createSlice({
name: "activities",
initialState: {
loading: false,
user: [],
error: "",
isSuccess: "",
},
extraReducers: (builder) => {
builder.addCase(fetchUsers.pending, (state) => {
state.loading = true;
});
builder.addCase(fetchUsers.fulfilled, (state, action) => {
state.loading = false;
state.user = action.payload;
state.error = "";
});
builder.addCase(fetchUsers.rejected, (state, action) => {
state.loading = false;
state.user = [];
state.error = action.error.message;
});
builder.addCase(addActivity.pending, (state) => {
state.loading = true;
state.error = "";
});
builder.addCase(addActivity.fulfilled, (state, action) => {
state.loading = false;
state.user = [];
state.isSuccess = action.payload;
});
builder.addCase(addActivity.rejected, (state, action) => {
state.loading = false;
state.user = [];
state.error = action.error.message;
});
},
});
export default activitiesSlice.reducer;
......@@ -3,12 +3,14 @@ import reporteesReducer from './reporteesSlice';
import userReducer from './userSlice';
import reportReducer from './viewreporteeSlice';
import exporttableReducer from './exporttableslice';
import activitiesReducer from './activitiesSlice'
const rootReducer = combineReducers({
userDetails: userReducer,
reportees: reporteesReducer,
reports: reportReducer,
totalreportees: exporttableReducer
totalreportees: exporttableReducer,
activities: activitiesReducer,
});
export default rootReducer;
\ No newline at end of file
......@@ -35,3 +35,8 @@ export const convertUTCToLocal = (utcDate) => {
const localDateObj = new Date(localTimeMillis);
return moment(localDateObj).format('DD-MM-YYYY')
}
export const convertToString = (value) =>{
return String(value);
}
\ 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