Commit 859b581b authored by Shiva Komirishetti's avatar Shiva Komirishetti

layout changes and redux persist changes

parent eee13f7c
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"react-router-dom": "^6.22.3", "react-router-dom": "^6.22.3",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-tailwindcss-datepicker": "^1.6.6", "react-tailwindcss-datepicker": "^1.6.6",
"redux-persist": "^6.0.0",
"redux-thunk": "^3.1.0", "redux-thunk": "^3.1.0",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
...@@ -15647,6 +15648,14 @@ ...@@ -15647,6 +15648,14 @@
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
}, },
"node_modules/redux-persist": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz",
"integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==",
"peerDependencies": {
"redux": ">4.0.0"
}
},
"node_modules/redux-thunk": { "node_modules/redux-thunk": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^2.2.1", "@reduxjs/toolkit": "^2.2.1",
"@tailwindcss/ui": "^0.7.2",
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
...@@ -20,7 +19,7 @@ ...@@ -20,7 +19,7 @@
"react-redux": "^9.1.0", "react-redux": "^9.1.0",
"react-router-dom": "^6.22.3", "react-router-dom": "^6.22.3",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-tailwindcss-datepicker": "^1.6.6", "redux-persist": "^6.0.0",
"redux-thunk": "^3.1.0", "redux-thunk": "^3.1.0",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
......
...@@ -17,8 +17,7 @@ const DateRangePicker = ({getReports}) => { ...@@ -17,8 +17,7 @@ const DateRangePicker = ({getReports}) => {
} }
useEffect(()=>{ useEffect(()=>{
console.log(value.startDate) getReports(value.startDate?value.startDate:null,value.endDate?value.endDate:null )
getReports({startDate:value.startDate?value.startDate:null,endDate:value.endDate?value.endDate:null} )
},[value]) },[value])
return ( return (
......
import React, { useState } from "react"; import React, { useState } from "react";
import AccordionTable from "./accordionTable"; 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";
...@@ -20,8 +21,8 @@ function Accordion({ title, data ,handleAddActivity}) { ...@@ -20,8 +21,8 @@ function Accordion({ title, data ,handleAddActivity}) {
const headers = [ const headers = [
{ title: "Name", id: "aName", width: "30%" }, { title: "Name", id: "aName", width: "30%" },
{ title: "Date", id: "recorded_date", width: "20%" }, { title: "Date", id: "recorded_date", width: "20%", render: (value) => moment(value).format('DD-MM-YYYY') },
{ title: "Score", id: "score", width: "10%" }, { title: "Score", id: "score", width: "10%", render: (value) => <div className="w-[35px] bg-blue-200 rounded-md text-center p-[4px]">{value}</div> },
{ title: "Comments", id: "comments", width: "40%" }, { title: "Comments", id: "comments", width: "40%" },
]; ];
return ( return (
...@@ -58,7 +59,7 @@ function Accordion({ title, data ,handleAddActivity}) { ...@@ -58,7 +59,7 @@ function Accordion({ title, data ,handleAddActivity}) {
className={`${!open && "hidden"} mt-2`} className={`${!open && "hidden"} mt-2`}
aria-labelledby="accordion-collapse-heading-2" aria-labelledby="accordion-collapse-heading-2"
> >
<AccordionTable headers={headers} data={data} /> <Table headers={headers} data={data} maxHeight={30}/>
<div className="justify-end mr-4 flex align-items-center justify-items-center"> <div className="justify-end mr-4 flex align-items-center justify-items-center">
<ModalButton type={`${title === "Default Activities:" ? "default" : "initiative"}`} handleAddActivity={handleAddActivity}/> <ModalButton type={`${title === "Default Activities:" ? "default" : "initiative"}`} handleAddActivity={handleAddActivity}/>
</div> </div>
......
import React from 'react'; import React, {useState} 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';
...@@ -6,7 +6,8 @@ import clearStore from '../../utils/clearStore'; ...@@ -6,7 +6,8 @@ import clearStore from '../../utils/clearStore';
function Header() { function Header() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const userDetails = useSelector((state) => state.userDetails.user); const user = useSelector((state) => state.userDetails.user);
const [open, setOpen] = useState(false)
const handleLogout = () => { const handleLogout = () => {
navigate('/'); navigate('/');
...@@ -16,13 +17,15 @@ function Header() { ...@@ -16,13 +17,15 @@ function Header() {
return ( return (
<div className="flex items-center justify-between py-5 px-10"> <div className="flex items-center justify-between py-5 px-10">
<img src="/logo.png"/> <img src="/logo.png"/>
<div className="w-[23%]"> <div className="flex items-center relative">
<Link to={`/${userDetails?.empId}/dashboard`}><button className="pr-10 hover:text-blue-400">Home</button></Link> <button className=" -mt-1 text-2xl flex" onClick={() => setOpen(!open)}>
<Link><button className="hover:text-blue-400">Reports</button></Link> <img src="/user.png" width="35px" height="35px" className="mt-2 pr-2" />
<div className="flex flex-col">
<p className="text-lg font-semibold">{user.empName}</p>
<p className="text-xs">{user.designation}</p>
</div> </div>
<div className="flex items-center"> </button>
<img src="/power-button.png" width="30px" height="30px"/> <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 className="ml-2 -mt-1 text-2xl" onClick={handleLogout}>
Logout Logout
</button> </button>
</div> </div>
......
import React from "react";
import { Link } from "react-router-dom";
import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
function LeftSidebar() {
const reportees = useSelector((state) => state.reportees.reportees);
const {id} = useParams()
return (
<div className="mt-2 w-[30%] flex flex-col px-[5px]">
<p className="text-xl text-blue-400 font-semibold pl-4 mt-3">
My Reportees
</p>
<div className="p-2 bg-[#E9EDEE] mt-4 max-h-[80vh] overflow-auto">
{reportees?.map(({ empName, score, empId }) => (
<Link
to={`/${empId}/reports`}
className={`flex items-center bg-${
Number(id) === empId ? "indigo-400" : "white"
} p-2 justify-between mb-1 w-full`}
key={empId}
>
<img src="/man.png" width="18px" height="18px" />
<p className="w-[80%] text-left">{empName}</p>
<p className="w-[10%] bg-blue-200 rounded-sm text-center">
{score}
</p>
</Link>
))}
</div>
</div>
);
}
export default LeftSidebar;
import React from "react"; import React from "react";
import {Link} from 'react-router-dom'; import { Link } from "react-router-dom";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
function Sidebar() { function Sidebar() {
const user = useSelector((state) => state.userDetails.user); const user = useSelector((state) => state.userDetails.user);
const reportees = useSelector((state) => state.reportees.reportees);
const url = window.location.href;
const {id} = useParams()
return ( return (
<div className="w-[30%] flex items-center flex-col px-4"> <div className="w-[20%] flex items-center flex-col">
<div> <nav
<img src="/generic-male-avatar-rectangular.jpg" width="130px" height="130px" /> class="hs-accordion-group p-6 w-full flex flex-col flex-wrap"
</div> data-hs-accordion-always-open
<div className="flex items-center flex-col mt-5"> >
<p className="text-lg font-semibold">{user.empName}</p> <ul class="space-y-1.5">
<p>{user.designation}</p> <li>
</div> <Link
{ class={`flex items-center gap-x-3.5 py-2 px-2.5 bg-gray-100 text-sm text-slate-700 rounded-lg hover:bg-gray-100 dark:bg-gray-900 dark:text-white dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600`}
url.includes('/reports') && <div className="mt-5 border-t-2 border-gray-300 w-[-webkit-fill-available] flex flex-col "> to={`/${user?.empId}/dashboard`}
<p className="text-xl text-blue-400 font-semibold pl-4 mt-3">My Project Allocations</p> >
<div className="p-2 bg-[#E9EDEE] mt-4 max-h-[49vh] overflow-auto"> <svg
{ class="size-4"
reportees?.map(({empName, score, empId}) => ( xmlns="http://www.w3.org/2000/svg"
<Link to={`/${empId}/reports`} className={`flex items-center bg-${Number(id) === empId ? "indigo-400" : "white"} p-2 justify-between mb-1 w-full`} key={empId}> width="24"
<img src="/man.png" width="18px" height="18px" /> height="24"
<p className="w-[80%] text-left">{empName}</p> viewBox="0 0 24 24"
<p className="w-[10%] bg-blue-200 rounded-sm text-center">{score}</p> fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" />
</svg>
Dashboard
</Link> </Link>
)) </li>
} <li>
</div> <Link
</div> class={`flex items-center gap-x-3.5 py-2 px-2.5 text-sm text-slate-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-900 dark:text-slate-400 dark:hover:text-slate-300 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600`}
} >
<svg
class="size-4"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="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>
Reports
</Link>
</li>
</ul>
</nav>
</div> </div>
); );
} }
......
import React from "react"; import React from "react";
import {Link} from 'react-router-dom';
function Table({headers, data, isView}) { function Table({headers, data, maxHeight}) {
return ( return (
<div className="relative overflow-x-auto sm:rounded-lg p-3"> <div className={`relative overflow-x-auto sm:rounded-lg p-4 max-h-[${maxHeight}vh]`}>
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 bg-transparent justify-center"> <table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 bg-transparent justify-center border-separate border-spacing-y-2">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400 "> <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400 ">
<tr> <tr className="mb-2">
{headers.map((item) => ( {headers.map((item) => (
<th scope="col" className="px-6 py-3" > <th scope="col" className={`px-6 py-4 w-[${item.width}]`} >
{item.title} {item.title}
</th> </th>
))} ))}
...@@ -17,11 +16,12 @@ function Table({headers, data, isView}) { ...@@ -17,11 +16,12 @@ function Table({headers, data, isView}) {
<tbody> <tbody>
{ {
data?.map((item, index) => ( data?.map((item, index) => (
<tr className="bg-white border-b-8 dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600"> <tr className="bg-white dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
{headers?.map((field) => ( {
field.id !== "action" ?<td className="px-6 py-4 listData" >{field.id==="empName"?<span className="flex items-center"><img className="pr-2" src="/man.png" width="30px" height="30px"/>{item[field.id]}</span> :item[field.id]}</td> : <td className="px-6 py-3 border-l-2"><Link to={`/${item.empId}/reports`}><button type="button" className="bg-blue-400 text-white rounded-md px-3 py-1">View</button></Link></td> headers?.map(({render, id}) => (
))} <td className="px-6 py-4 listData" >{render ? render(item[id]) : item[id] }</td>
))
}
</tr> </tr>
)) ))
} }
......
...@@ -15,6 +15,6 @@ code { ...@@ -15,6 +15,6 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;
} }
.listData:nth-child(4) { /* .listData:nth-child(4) {
padding-left: 35px; padding-left: 35px;
} } */
\ No newline at end of file \ No newline at end of file
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useParams } from "react-router-dom"; import { useParams, Link } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { fetchReportees } from "../../redux/reducers/reporteesSlice"; import { fetchReportees } from "../../redux/reducers/reporteesSlice";
import { fetchUser } from "../../redux/reducers/userSlice"; import { fetchUser } from "../../redux/reducers/userSlice";
...@@ -30,16 +30,38 @@ function Dashboard() { ...@@ -30,16 +30,38 @@ function Dashboard() {
}, [id]); }, [id]);
const headers = [ const headers = [
{title: "Employee Name", id:"empName"}, {
{title: "Emp.Id", id: "empId"}, title: "Employee Name",
{title: "Designation", id: 'designation'}, id:"empName",
{title: "score", id:"score"}, render: (value) => <span className="flex items-center"><img className="pr-2" src="/man.png" width="30px" height="30px"/>{value}</span>
{title: "Action", id:"action"}, },
{
title: "Emp.Id",
id: "empId"
},
{
title: "Designation",
id: 'designation'
},
{
title: "score",
id:"score",
render: (value) => <div className="bg-blue-200 rounded-md text-center p-[4px]">{value}</div>
},
{
title: "Email",
id: 'empEmail'
},
{
title: "Action",
id:"empId",
render: (value) => <Link to={`/${value}/reports`}><button className="bg-blue-400 text-white rounded-md px-3 py-1">View</button></Link>
},
] ]
return ( return (
<div> <div>
<Table headers={headers} data={reportees} isView={true}/> <Table headers={headers} data={reportees} maxHeight={88}/>
</div> </div>
) )
} }
......
import React from 'react' import React from 'react'
import Header from '../../components/header'; import Header from '../../components/header';
import Sidebar from '../../components/sidebar'; import Sidebar from '../../components/sidebar';
import LeftSidebar from '../../components/leftSidebar';
function Layout({children}) { function Layout({children}) {
const url = window.location.href;
return ( return (
<div> <div>
<Header/> <Header/>
...@@ -11,6 +13,7 @@ function Layout({children}) { ...@@ -11,6 +13,7 @@ function Layout({children}) {
<div className="bg-[#E9EDEE] w-full" style={{height:"88vh"}}> <div className="bg-[#E9EDEE] w-full" style={{height:"88vh"}}>
{children} {children}
</div> </div>
{url.includes('/reports') && <LeftSidebar/>}
</div> </div>
</div> </div>
) )
......
...@@ -31,7 +31,7 @@ function Reports() { ...@@ -31,7 +31,7 @@ function Reports() {
const getReports=({startDate, endDate})=>{ const getReports=(startDate=null, endDate=null)=>{
const data={"empId":empId,"fromDate":startDate,"toDate":endDate} const data={"empId":empId,"fromDate":startDate,"toDate":endDate}
dispatch(fetchReports(data)) dispatch(fetchReports(data))
} }
...@@ -82,7 +82,7 @@ function Reports() { ...@@ -82,7 +82,7 @@ function Reports() {
<div className="flex flex-col w-[85%]"> <div className="flex flex-col w-[85%]">
<div className="flex py-4"> <div className="flex py-4">
<p className="w-[23%]"> <p className="w-[23%]">
<span className="font-medium">Email Id: </span>Null <span className="font-medium">Email Id: </span>{empDetails?.empEmail}
</p> </p>
<p className="w-[23%]"> <p className="w-[23%]">
<span className="font-medium">Emp.Id: </span> <span className="font-medium">Emp.Id: </span>
......
...@@ -25,13 +25,13 @@ const reportSlice = createSlice({ ...@@ -25,13 +25,13 @@ const reportSlice = createSlice({
}, },
calculateDefaultScore:(state, action)=>{ calculateDefaultScore:(state, action)=>{
const defaultItems = action.payload?.filter(item => item.type === "default"); const defaultItems = action.payload?.filter(item => item.type === "default");
const totalDefaultScore = defaultItems.reduce((acc, curr) => acc+ curr.score, 0); const totalDefaultScore = defaultItems?.reduce((acc, curr) => acc+ curr.score, 0);
const defaultAvgScore = totalDefaultScore > 0 ? totalDefaultScore / defaultItems.length : 0; const defaultAvgScore = totalDefaultScore > 0 ? totalDefaultScore / defaultItems.length : 0;
return {...state,defaultAvgScore :defaultAvgScore.toFixed(1)} return {...state,defaultAvgScore :defaultAvgScore.toFixed(1)}
}, },
calculateInitiativeScore:(state,action)=>{ calculateInitiativeScore:(state,action)=>{
const defaultItems = action.payload?.filter(item => item.type === "initiative"); const defaultItems = action.payload?.filter(item => item.type === "initiative");
const totalDefaultScore = defaultItems.reduce((acc, curr) => acc+ curr.score, 0); const totalDefaultScore = defaultItems?.reduce((acc, curr) => acc+ curr.score, 0);
const defaultAvgScore = totalDefaultScore > 0 ? totalDefaultScore / defaultItems.length : 0; const defaultAvgScore = totalDefaultScore > 0 ? totalDefaultScore / defaultItems.length : 0;
return {...state,initiativeAvgScore :defaultAvgScore.toFixed(1)} return {...state,initiativeAvgScore :defaultAvgScore.toFixed(1)}
}, },
......
import { configureStore } from '@reduxjs/toolkit'; import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducers/rootReducer'; import rootReducer from './reducers/rootReducer';
import sessionStorage from 'redux-persist/es/storage/session'
import { persistReducer, persistStore } from 'redux-persist';
const persistConfig={
key: "root",
storage:sessionStorage,
}
const persistState=persistReducer(persistConfig, rootReducer)
const store = configureStore({ const store = configureStore({
reducer: rootReducer, reducer: persistState,
}); });
export const persistor = persistStore(store);
export default store; export default store;
\ 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