table-modal-changes-done

parent 7e20fe14
......@@ -9,7 +9,6 @@
"version": "0.1.0",
"dependencies": {
"@reduxjs/toolkit": "^2.2.1",
"@tailwindcss/ui": "^0.7.2",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
......@@ -25,7 +24,6 @@
"react-redux": "^9.1.0",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"react-tailwindcss-datepicker": "^1.6.6",
"redux-persist": "^6.0.0",
"redux-thunk": "^3.1.0",
"web-vitals": "^2.1.4"
......@@ -3783,41 +3781,6 @@
"url": "https://github.com/sponsors/gregberge"
}
},
"node_modules/@tailwindcss/ui": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/@tailwindcss/ui/-/ui-0.7.2.tgz",
"integrity": "sha512-7HuFoWUMfVdY8EWEIS2FSJBCj+iEWL4JfljVE6Wd5qLrQrCzH10tuE0S6697jPm7dt8ZUEslFWlJtAsU76A5Nw==",
"dependencies": {
"@tailwindcss/custom-forms": "^0.2.1",
"@tailwindcss/typography": "^0.2.0",
"hex-rgb": "^4.1.0",
"postcss-selector-parser": "^6.0.2"
},
"peerDependencies": {
"tailwindcss": "^1.8.3"
}
},
"node_modules/@tailwindcss/ui/node_modules/@tailwindcss/custom-forms": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/custom-forms/-/custom-forms-0.2.1.tgz",
"integrity": "sha512-XdP5XY6kxo3x5o50mWUyoYWxOPV16baagLoZ5uM41gh6IhXzhz/vJYzqrTb/lN58maGIKlpkxgVsQUNSsbAS3Q==",
"dependencies": {
"lodash": "^4.17.11",
"mini-svg-data-uri": "^1.0.3",
"traverse": "^0.6.6"
},
"peerDependencies": {
"tailwindcss": "^1.0"
}
},
"node_modules/@tailwindcss/ui/node_modules/@tailwindcss/typography": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.2.0.tgz",
"integrity": "sha512-aPgMH+CjQiScLZculoDNOQUrrK2ktkbl3D6uCLYp1jgYRlNDrMONu9nMu8LfwAeetYNpVNeIGx7WzHSu0kvECg==",
"peerDependencies": {
"tailwindcss": "^1.5.0"
}
},
"node_modules/@testing-library/dom": {
"version": "9.3.4",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz",
......@@ -7102,12 +7065,6 @@
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/dayjs": {
"version": "1.11.10",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
"integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==",
"peer": true
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
......@@ -9411,17 +9368,6 @@
"he": "bin/he"
}
},
"node_modules/hex-rgb": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz",
"integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==",
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
......@@ -12946,14 +12892,6 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/mini-svg-data-uri": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
"integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
"bin": {
"mini-svg-data-uri": "cli.js"
}
},
"node_modules/minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
......@@ -15579,15 +15517,6 @@
}
}
},
"node_modules/react-tailwindcss-datepicker": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/react-tailwindcss-datepicker/-/react-tailwindcss-datepicker-1.6.6.tgz",
"integrity": "sha512-kHSUonRO86PoYQQWPqpaSw2JeEn9OafdLsLBG85zO5Sfs23Ku8Ixt/YO+Is3TCBcFeOKnZgzhGLmP3NAXVlFkA==",
"peerDependencies": {
"dayjs": "^1.11.6",
"react": "^17.0.2 || ^18.2.0"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
......@@ -17433,17 +17362,6 @@
"node": ">=8"
}
},
"node_modules/traverse": {
"version": "0.6.8",
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz",
"integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/tryer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
......
......@@ -121,7 +121,7 @@ app.post("/getreportees", (req, res) => {
}
*/
app.post('/createActivity',(req,res)=>{
const empId = req.body.empId || null;
const empId = req.body.empId;
if(!empId){
res.status(401).json({"message":"Employee id is missing"});
return
......
......@@ -4,21 +4,32 @@ import moment from "moment";
import ModalButton from "../modal/modalButton";
import { useSelector ,useDispatch} from "react-redux";
import { useEffect } from "react";
import { fetchReportees } from "../../redux/reducers/reporteesSlice";
import { calculateDefaultScore,calculateInitiativeScore } from "../../redux/reducers/reportSlice";
function Accordion({ title, data ,handleAddActivity}) {
function Accordion({ title, data ,handleAddActivity,open,handleAccordian}) {
const dispatch=useDispatch()
const [open, setOpen] = useState(false);
// const [open, setOpen] = useState(false);
const { reports,defaultAvgScore,initiativeAvgScore } = useSelector((state) => state.reports);
const userDetails = useSelector((state) => state.userDetails);
useEffect(()=>{
const data = {
reportees: userDetails.user.reportees,
sort: { type: "empId", order: 1 },
page: 1,
perPage: 10,
}
dispatch(fetchReportees(data));
dispatch(calculateDefaultScore(reports))
dispatch(calculateInitiativeScore(reports))
},[reports])
function handleClick(){
handleAccordian(title)
}
const headers = [
{ title: "Name", id: "aName", width: "30%" },
{ title: "Date", id: "recorded_date", width: "20%", render: (value) => moment(value).format('DD-MM-YYYY') },
......@@ -29,23 +40,14 @@ function Accordion({ title, data ,handleAddActivity}) {
<div className="px-4">
<button
onClick={() => setOpen(!open)}
onClick={handleClick}
type="button"
className="flex items-center w-full py-2 mt-4 font-medium rtl:text-right bg-white text-gray-500 border border-[#B7B7B7] focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 gap-3"
data-accordion-target="#accordion-collapse-body-2"
aria-expanded="false"
aria-controls="accordion-collapse-body-2"
>
<div className="w-1/2 text-start">{title}</div>
<div className="w-1/2">Average Score :{title === "Default Activities:" ? defaultAvgScore : initiativeAvgScore}</div>
<svg
data-accordion-icon
className="w-3 h-3 rotate-180 shrink-0"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 10 6"
>
className="flex items-center rounded-lg w-full py-2 px-2 mt-4 font-medium rtl:text-right bg-white text-gray-500 border border-[#B7B7B7] focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 gap-3" data-accordion-target="#accordion-collapse-body-2" aria-expanded="false" aria-controls="accordion-collapse-body-2" >
<div className="w-1/2 text-start ms-2">{title}</div>
<div className="w-1/2 flex justify-between">Average Score :{title === "Default Activities:" ? defaultAvgScore : initiativeAvgScore}
<ModalButton type={`${title === "Default" ? "default" : "initiative"}`} handleAddActivity={handleAddActivity}/>
</div>
<svg data-accordion-icon className="w-3 h-3 rotate-180 shrink-0" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
<path
stroke="currentColor"
stroke-linecap="round"
......@@ -59,10 +61,7 @@ function Accordion({ title, data ,handleAddActivity}) {
className={`${!open && "hidden"} mt-2`}
aria-labelledby="accordion-collapse-heading-2"
>
<Table headers={headers} data={data} maxHeight={30}/>
<div className="justify-end mr-4 flex align-items-center justify-items-center">
<ModalButton type={`${title === "Default Activities:" ? "default" : "initiative"}`} handleAddActivity={handleAddActivity}/>
</div>
<Table headers={headers} data={data} maxHeight={10}/>
</div>
</div>
);
......
......@@ -10,7 +10,7 @@ export default function MyModal({ visible, onClose ,type,handleAddActivity}) {
const [activityData,setActivityData]=useState({aName:"",aId:"",type:type,score:0,comments:""})
const [activityType,setActivtyType]=useState("")
const getActivitysList= async()=>{
const getActivitysList= async(type)=>{
const activities=await axios.get(`${base_url}/activities`)
const response= await activities.data.filter((item)=>item.type==type)
setActivitiesList(response)
......@@ -56,7 +56,7 @@ export default function MyModal({ visible, onClose ,type,handleAddActivity}) {
if (visible===false){
setActivityData({aName:"",aId:"",type:type,score:0,comments:""})
}else{
getActivitysList();
getActivitysList(type);
}
},[visible,type])
......@@ -64,9 +64,9 @@ export default function MyModal({ visible, onClose ,type,handleAddActivity}) {
if (!visible) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-25 backdrop-blur-sm flex items-center justify-center">
<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 lg:w-4/12 sm:w-100">
<div className=" text-white py-3 pl-2 bg-blue-500">{activityType} Activity</div>
<div className=" text-white py-3 pl-2 bg-blue-500 ">{activityType} Activity</div>
<div>
<div>
<form className=" p-2 max-w-sm mx-auto">
......@@ -114,9 +114,7 @@ export default function MyModal({ visible, onClose ,type,handleAddActivity}) {
</form>
</div>
</div>
</div>
</div>
</div>
......
......@@ -9,7 +9,7 @@ export default function ModalButton({type,handleAddActivity}) {
<div className="bg-blue-400 bg-opacity-30">
<button
onClick={() => setShowMyModal(true)}
className="bg-red-400 text-white px-3 py-2 rounded hover:scale-95 transition text-xl">
className="bg-blue-400 text-white px-2 py-1 rounded hover:scale-95 transition text-sm">
Add Activity
</button>
<MyModal onClose={handleOnClose} visible={showMyModal} handleAddActivity={handleAddActivity} type={type}/>
......
......@@ -2,7 +2,7 @@ import React from "react";
function Table({headers, data, maxHeight}) {
return (
<div className={`relative overflow-x-auto sm:rounded-lg p-4 max-h-[${maxHeight}vh]`}>
<div className={` 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 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 ">
<tr className="mb-2">
......@@ -19,7 +19,7 @@ function Table({headers, data, maxHeight}) {
<tr className="bg-white dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
{
headers?.map(({render, id}) => (
<td className="px-6 py-4 listData" >{render ? render(item[id]) : item[id] }</td>
<td className="px-6 py-4 listData" >{render ? render(item[id]) : item[id] === "" ? "NA" : item[id] }</td>
))
}
</tr>
......
......@@ -12,7 +12,7 @@ function Home() {
return (
<div className="container py-10 px-10 mx-0 min-w-full h-screen flex items-center justify-center bg-blue-100 ">
<div class="">
<h1 class="mb-4 text-4xl font-extrabold leading-none tracking-tight md:text-5xl lg:text-6xl text-purple-900 mb-10 ">SCORE CARD</h1>
<h1 class="text-4xl font-extrabold leading-none tracking-tight md:text-5xl lg:text-6xl text-purple-900 mb-10 ">SCORE CARD</h1>
<div className="max-w-sm p-10 bg-white border border-gray-400 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700 ">
<label
for="email"
......
......@@ -9,11 +9,13 @@ import DateRangePicker from "../../components/DateRangePicker";
function Reports() {
const { id } = useParams();
const empId=Number(id)
const empId = Number(id)
const dispatch = useDispatch();
const reportees = useSelector((state) => state.reportees.reportees);
const [empDetails, setEmpDetails] = useState(null);
const { reports} = useSelector((state) => state.reports);
const { reports } = useSelector((state) => state.reports);
const [open, setOpen] = useState({"accordianOne":true,"accordianTwo":false});
/*Example post data
{
......@@ -23,96 +25,105 @@ function Reports() {
}
*/
const activities = useMemo(() => {
if(reports !== undefined) {
const filtered = Object.groupBy(reports, ({ type }) => type);
return filtered;
if (reports !== undefined) {
const filtered = Object.groupBy(reports, ({ type }) => type);
return filtered;
}
}, [reports]);
const handleAccordian=(value)=>{
switch (value){
case "Default":
setOpen({...open,"accordianOne":!open["accordianOne"], "accordianTwo": !open["accordianTwo"]})
break;
case "Initiative":
setOpen({...open,"accordianOne":!open["accordianOne"], "accordianTwo": !open["accordianTwo"]})
break;
default:
setOpen({"accordianOne":true,"accordianTwo":false})
}
}
const getReports=(startDate=null, endDate=null)=>{
const data={"empId":empId,"fromDate":startDate,"toDate":endDate}
const getReports = (startDate = null, endDate = null) => {
const data = { "empId": empId, "fromDate": startDate, "toDate": endDate }
dispatch(fetchReports(data))
}
const handleAddActivity=(activityData)=>{
if(id){
let newData={
"empId":empId,
"data":activityData
const handleAddActivity = (activityData) => {
if (id) {
let newData = {
"empId": empId,
"data": activityData
}
axios.post(`${base_url}/createActivity`, newData)
.then((result) => {
getReports()
})
} else {
alert("Please login")
}
axios.post(`${base_url}/createActivity`,newData)
.then((result)=>{
getReports()
})
}else{
alert("Please login")
}
}
useEffect(() => {
if(id!==undefined|| null) {
const emp = reportees?.filter((item) => item.empId === Number(id));
setEmpDetails(emp[0]);
const data = {
"empId":Number(id),
"fromDate":"2024-03-10",
"toDate":"2024-03-15"
}
dispatch(fetchReports(data))
}
return (() => {
setEmpDetails(null)
})
},[id]);
useEffect(() => {
if (id !== undefined || null) {
const emp = reportees?.filter((item) => item.empId === Number(id));
setEmpDetails(emp[0]);
const data = {
"empId": Number(id),
"fromDate": "2024-03-10",
"toDate": "2024-03-15"
}
dispatch(fetchReports(data))
}
return (() => {
setEmpDetails(null)
})
}, [id]);
return (
<div className="p-4">
<div className="flex bg-white p-3">
<div className="w-[25%]">
<img src="/generic-male-avatar-rectangular.jpg" width="100px" height="100px" />
<div>
<p className="text-lg font-medium mt-1">{empDetails?.empName}</p>
<p>{empDetails?.designation}</p>
</div>
</div>
<div className="flex flex-col w-[85%]">
<div className="flex py-4">
<p className="w-[23%]">
<span className="font-medium">Email Id: </span>{empDetails?.empEmail}
<div className=" bg-white p-3">
<div className="flex">
{/* <img src="/generic-male-avatar-rectangular.jpg" width="100px" height="100px" /> */}
<div className="w-1/2">
<p>
<span className="font-medium">Employee Name : </span> {empDetails?.empName}
</p>
<p className="w-[23%]">
<span className="font-medium">Emp.Id: </span>
{empDetails?.empId}
<p>
<span className="font-medium">Designation : </span> {empDetails?.designation}
</p>
<p className="w-[23%]">
<span className="font-medium">Experience: </span>Null
</p>
<p className="w-[23%]">
<span className="font-medium">Scorecard: </span>
{empDetails?.score}
<p>
<span className="font-medium">Email Id: </span> {empDetails?.empEmail}
</p>
</div>
<div className="flex">
<p className="w-[23%]">
<span className="font-medium">Joining Date: </span>Null
<div className="w-1/2">
<p>
<span className="font-medium">Employee Id: </span> {empDetails?.empId}
</p>
<p>
<span className="font-medium">Average Score : </span> {empDetails?.score}
</p>
<p className="w-[23%]">
<span className="font-medium">Technologies Know: </span>Null
<p>
<span className="font-medium">Allocated To : </span> {empDetails?.project}
</p>
</div>
</div>
</div>
<div className="max-h-[60vh] overflow-auto">
<div className="container mx-auto mt-4 flex justify-end pe-4">
<DateRangePicker getReports={getReports}/>
</div>
<Accordion title="Default Activities:" data={activities?.default} handleAddActivity={handleAddActivity}/>
<Accordion title="Initiatives:" data={activities?.initiative} handleAddActivity={handleAddActivity}/>
<div className="max-h-[70vh] overflow-auto">
<div className="container mx-auto mt-4 flex justify-end pe-4">
<DateRangePicker getReports={getReports} />
</div>
<div className="max-h-[50vh] overflow-auto">
<Accordion title="Default" open={open.accordianOne} handleAccordian={handleAccordian} data={activities?.default} handleAddActivity={handleAddActivity} />
</div>
<div className="max-h-[50vh] overflow-auto">
<Accordion title="Initiative" open={open.accordianTwo} handleAccordian={handleAccordian} data={activities?.initiative} handleAddActivity={handleAddActivity} />
</div>
</div>
</div>
);
}
export default Reports;
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