Commit f6fff81e authored by Venkaiah Naidu Singamchetty's avatar Venkaiah Naidu Singamchetty

Merge branch 'R-branch' into 'master'

R branch

See merge request !99
parents e9c516aa 1a7c084e
......@@ -6,15 +6,23 @@ import Viewreportee from './pages/viewReportee';
import './App.css';
import PageNotFound from './pages/pagenotfound/PageNotFound';
import Exporttable from './pages/reportexport'
import AdminProfile from './pages/adminProfile';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />}/>
<Route path="/dashboard" element={<Layout><Dashboard/></Layout>}/>
{/* profile page */}
<Route path="/dashboard" element={<Layout><AdminProfile/></Layout>}/>
{/* reportees page */}
<Route path="/myreportees" element={<Layout><Dashboard/></Layout>}/>
{/*adding activities*/}
<Route path="/viewreportee" element={<Layout><Viewreportee/></Layout>}/>
{/* fetch reports */}
<Route path="/reportees" element={<Layout><Exporttable/></Layout>}/>
<Route path="/*" element={<PageNotFound/>}/>
</Routes>
</BrowserRouter>
......
import React from "react";
function AdminProfileIcon() {
return (
<svg
className="size-4"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" />
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" />
</svg>
);
}
export default AdminProfileIcon;
// 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 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
const menus = [
{title: "Dashboard", path: '/dashboard', selectPaths: ['dashboard', 'viewreportee'], icon: <DashboardIcon/> },
{title: "Reports", path: '/reportees', selectPaths:['reportees'], icon: <ReportsIcon />}
{ 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 /> },
]
function Sidebar() {
......@@ -15,23 +61,23 @@ function Sidebar() {
const selected = url.split('/').at(-1)
return (
<div className="w-[20%] flex items-center flex-col overflow-auto" style={{ height: `calc(${windowHeight}px - 87px)` }}>
<div className="w-[20%] flex bg-blue-700 text-white 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"
className="hs-accordion-group mt-1 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>
<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`}
to={menu.path}
>
<p className="flex items-center">{menu.icon} <span className="ps-2"> {menu.title}</span></p>
</Link>
</li>
))
}
......
......@@ -59,10 +59,10 @@ function Table({headers, data,loading, handleSorting }) {
if(loading) return <Loading/>
else
return (
<div className={` overflow-auto sm:rounded-lg p-4 bg-gray-100`}>
<table className="w-full text-sm text-left rtl:text-right text-gray-500 bg-transparent justify-center border-separate border-spacing-y-2">
<thead className="text-xs text-gray-700 uppercase bg-gray-50">
<tr className="mb-2">
<div className={` overflow-auto sm:rounded-lg p-4 `}>
<table className="w-full text-sm text-left rtl:text-right bg-transparent justify-center ">
<thead className=" uppercase bg-white font-extrabold">
<tr className="mb-2 border-2 border-black-200">
{headers?.map((item,index) => (
<th key={index} scope="col" className={`px-6 py-4 w-[${item.width}]`} >
{ item.renderHeader ? item.renderHeader(item.title) : item.isSorting ?
......@@ -80,7 +80,7 @@ function Table({headers, data,loading, handleSorting }) {
(data?.length)?<tbody >
{
data?.map((item, index) => (
<tr key={item.id} className="bg-white hover:bg-gray-300 " >
<tr key={item.id} className="bg-[#eef5ff] font-medium hover:bg-white " >
{
headers?.map(({render, id}) => (
<td className="px-6 py-2 " >
......
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchUser } from "../../redux/reducers/userSlice";
import { scoreColor } from "../../utils/commonFunctions";
import Tabs from "./tabs";
const AdminProfile = () => {
const dispatch = useDispatch();
const { user, error, loading } = useSelector((state) => state.userDetails); // Get user data from Redux store
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div className="p-4" >
<div className="bg-white p-3 rounded-md">
<div className="flex justify-between">
{user && (<>
<div className="flex items-center">
<div>
<p className="font-medium mb-2">
Employee Name
</p>
<p className="font-medium mb-2">
Employee Id
</p>
<p className="font-medium">
Email Id
</p>
</div>
<div>
<p className="mb-2"><span className="font-medium">:</span> {user.empName}</p>
<p className="mb-2"><span className="font-medium">:</span> {user.empId}</p>
<p><span className="font-medium">:</span> {user.empEmail}</p>
</div>
</div>
<div className="flex items-center">
<div>
<p className="font-medium mb-2">
Designation
</p>
<p className="font-medium mb-2">
Role
</p>
<p className="font-medium">
Project
</p>
</div>
<div>
<p className="mb-2"><span className="font-medium">:</span> {user.designation}</p>
<p className="mb-2"><span className="font-medium">:</span> {user.techStack}</p>
<p><span className="font-medium">:</span> {user.project}</p>
</div>
</div>
<div className="flex flex-col justify-center items-center">
<div className={`w-[40px] h-[40px] rounded-full flex items-center text-white justify-center ${scoreColor(user.score)}`}>
<span className="text-lg font-bold">{user.score}</span>
</div>
<div className="">
<span className="text-blue-400 font-semibold">Total Score</span>
</div>
</div>
</>
)}
</div>
</div>
<div className="mt-1">
< Tabs />
</div>
</div>
);
};
export default AdminProfile;
import React, { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { fetchProfileReporteeActivities } from "../../redux/reducers/profileSlice";
import Table from "../../components/table/index";
import { convertUTCToLocal } from "../../utils/commonFunctions";
import Loading from "../../components/loading Component/Loading";
const Tabs = () => {
const [index, setIndex] = useState(0);
const dispatch = useDispatch();
const { loading, error, dutiesReports, initiativeReports } =useSelector((state) => state.reports);
const { user } = useSelector((state) => state.userDetails);
const fetchActivities = (type) => {
const data = {
empId: user?.empId,
types: [type],
page: 1,
perPage: 5,
};
dispatch(fetchProfileReporteeActivities(data));
};
useEffect(() => {
fetchActivities("duties");
}, []);
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>
),
},
];
return (
<>
<div className="text-sm font-medium text-center text-gray-500 border-b border-gray-200 dark:text-gray-400 ">
<ul className="flex flex-wrap -mb-px">
<li className="me-2" onClick={() => {}}>
<button
onClick={() => {
setIndex(0);
fetchActivities("duties");
}}
className={`inline-block p-4 border-b-2 border-blue-600 ${index === 0
? 'text-blue-600'
: 'border-transparent hover:text-blue-300 hover:border-blue-300'
}`}
>
Duties
</button>
</li>
<li className="me-2">
<button
onClick={() => {
setIndex(index + 1);
fetchActivities("initiative");
}}
className={`inline-block p-4 border-b-2 border-blue-600 ${index >0
? 'text-blue-600'
: 'border-transparent hover:text-blue-300 hover:border-blue-300'
}`}
>
Initiatives
</button>
</li>
</ul>
</div>
<div className="">
{index === 0 ? (
<div>
<Table headers={headers}
loading={loading}
data={dutiesReports} />
</div>
) : (
<div>
<Table
headers={headers}
loading={loading}
data={initiativeReports} />
</div>
)}
</div>
</>
);
};
export default Tabs;
......@@ -63,6 +63,7 @@ function Dashboard() {
}, [userDetails]);
useEffect(() => {
if(inputValue!==null){
const debounceTimeout = setTimeout(() => {
const data = {
......
......@@ -6,6 +6,7 @@ import { loginUser } from "../../redux/reducers/userSlice";
import {useDispatch,useSelector} from 'react-redux'
function Home() {
const inputRef = useRef(null);
const navigate = useNavigate();
const dispatch=useDispatch()
......@@ -16,6 +17,7 @@ function Home() {
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true)
if(id!==null){
......@@ -35,10 +37,12 @@ function Home() {
};
useEffect(()=>{
setLoading(false)
inputRef.current.focus();
},[])
useEffect(()=>{
if (userDetails?.user!=null)
navigate("/dashboard")
else
......@@ -46,6 +50,7 @@ function Home() {
},[userDetails])
return (
<div className="container py-10 px-10 mx-0 min-w-full h-screen flex items-center justify-center bg-blue-100 ">
<div className="">
<h1 className="text-4xl font-extrabold leading-none tracking-tight md:text-5xl lg:text-6xl text-purple-900 mb-10 ">SCORE CARD</h1>
......
......@@ -17,7 +17,7 @@ function Layout({children}) {
<Header isOpen={isOpen} />
<div className="flex pt-[85px]">
<Sidebar/>
<div className="bg-[#E9EDEE] w-full overflow-auto" style={{ height: `calc(${windowHeight}px - 87px)` }}>
<div className="bg-[#fafafb] w-full overflow-auto" style={{ height: `calc(${windowHeight}px - 87px)` }}>
{children}
</div>
{url.includes('/viewreportee') && <LeftSidebar/>}
......
......@@ -3,7 +3,7 @@ import React, { memo } from 'react';
const PageNotFound = memo(() => {
return (
<div className="w-full h-full ">
<p className="text-center align-middle pt-14 pb-14 text-red-500 text-3xl font-bold">Page Not Found</p>
<p className="text-center align-middle pt-14 pb-14 text-red-500 text-3xl font-bold">Page Not Found54</p>
</div>
);
});
......
export const styles = {
genarateReportContainer: "overflow-auto sm:rounded-lg p-4 bg-[#E9EDEE] ",
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",
......
......@@ -9,6 +9,7 @@ import {scoreColor} from '../../utils/commonFunctions';
function Viewreportee() {
const dispatch = useDispatch();
const navigate = useNavigate();
const {reportees, viewReportee,currPage, reporteeId } = useSelector((state) => state.reportees);
......@@ -100,14 +101,7 @@ function Viewreportee() {
<div className="p-4" >
<div className="bg-white p-3 rounded-md">
<div className="flex justify-between">
{/* <div className="my-1">
<p>
<span className="font-medium">Employee Name: </span> {viewReportee?.empName}
</p>
<p>
<span className="font-medium">Designation: </span> {viewReportee?.designation}
</p>
</div> */}
<div className="flex items-center">
<div>
<p className="font-medium mb-2">
......@@ -171,4 +165,5 @@ function Viewreportee() {
}
export default Viewreportee;
// // actions.js
// export const FETCH_EMPLOYEE_REQUEST = 'FETCH_EMPLOYEE_REQUEST';
// export const FETCH_EMPLOYEE_SUCCESS = 'FETCH_EMPLOYEE_SUCCESS';
// export const FETCH_EMPLOYEE_FAILURE = 'FETCH_EMPLOYEE_FAILURE';
// // actions.js
// export const fetchEmployeeRequest = () => ({
// type: FETCH_EMPLOYEE_REQUEST
// });
// export const fetchEmployeeSuccess = (data) => ({
// type: FETCH_EMPLOYEE_SUCCESS,
// payload: data
// });
// export const fetchEmployeeFailure = (error) => ({
// type: FETCH_EMPLOYEE_FAILURE,
// payload: error
// });
\ No newline at end of file
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axiosApi from '../../api/axiosConfig'
const initialState = {
reports:null,
dutiesReports: null,
initiativeReports: null,
loading: false,
error: null,
};
export const fetchProfileReporteeActivities = createAsyncThunk("getReports", async (data) => {
return await axiosApi
.post(`/getActivities`, data)
.then((response) => {return {data:response.data?.activities, type:data.types}});
});
const profileSlice = createSlice({
name: "reportees",
initialState,
reducers: {
resetActivities:() => {
return initialState
},
},
extraReducers: (builder) => {
builder.addCase(fetchProfileReporteeActivities.pending, (state) => {
return {...state,loading :true,error :"loading"}
});
builder.addCase(fetchProfileReporteeActivities.fulfilled, (state, action) => {
const {data, type} = action.payload;
return {...state,loading :false,error :"", [`${type[0]}Reports`]: data}
});
builder.addCase(fetchProfileReporteeActivities.rejected, (state, action) => {
return {...state,loading :false,error :action.error || "Something went wrong!",reports:null}
});
},
});
export const {resetActivities} = profileSlice.actions;
export default profileSlice.reducer;
......@@ -2,11 +2,13 @@ import {resetUser} from '../redux/reducers/userSlice';
import {resetReportees} from '../redux/reducers/reporteesSlice';
import { resetReports } from '../redux/reducers/viewreporteeSlice';
import {resetReporteesTableData} from '../redux/reducers/exporttableslice';
import { resetActivities } from '../redux/reducers/profileSlice';
const clearStore = (dispatch) => {
dispatch(resetUser());
dispatch(resetReportees());
dispatch(resetReports())
dispatch(resetReporteesTableData())
dispatch(resetActivities())
};
export default clearStore;
\ 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