Commit 223aa5fb authored by Your Name's avatar Your Name

Latest pull

parent 59c0b16b
This diff is collapsed.
......@@ -2,6 +2,7 @@ import {BrowserRouter, Routes, Route} from 'react-router-dom';
import Home from "./pages/home";
import Dashboard from './pages/dashboard';
import Layout from './pages/layout';
import Reports from './pages/reports';
import './App.css';
function App() {
......@@ -10,6 +11,7 @@ function App() {
<Routes>
<Route path='/' element={<Home />}/>
<Route path=":id/dashboard" element={<Layout><Dashboard/></Layout>}/>
<Route path=":id/reports" element={<Layout><Reports/></Layout>}/>
</Routes>
</BrowserRouter>
);
......
import React from 'react';
import {Link} from 'react-router-dom';
import {useNavigate} from 'react-router-dom';
import { useDispatch } from 'react-redux';
import clearStore from '../../utils/clearStore';
function Header() {
const dispatch = useDispatch();
const navigate = useNavigate()
const handleLogout = () => {
navigate('/');
clearStore(dispatch)
}
return (
<div className="flex items-center justify-between py-5 px-10">
<img src="/logo.png"/>
<div className="flex items-center">
<img src="/power-button.png" width="30px" height="30px"/>
<button className="ml-2 -mt-1 text-2xl" >
<Link to="/">
Logout
</Link>
<button className="ml-2 -mt-1 text-2xl" onClick={handleLogout}>
Logout
</button>
</div>
</div>
......
import axios from "axios";
import React, { useMemo, useEffect, useState, useCallback } from "react";
import { base_url } from "../../utils/constants";
export default function MyModal({ visible, onClose ,type}) {
const [activitiesList, setActivitiesList] = useState([])
const [enableSubmit,setEnableSubmit]=useState(false)
const [scoreType,setScoreType]=useState(1)
const [activityData,setActivityData]=useState({aName:"",aId:"",type:type,score:0,comments:""})
const getActivitysList= async()=>{
const activities=await axios.get(`${base_url}/activities`)
const response= await activities.data.filter((item)=>item.type==type)
setActivitiesList(response)
}
const handleActivityName = (e) => {
setActivityData({...activityData,aName:e.target.value,aId:e.target.options[e.target.selectedIndex].id})
}
const handleScoreChange=(value)=>{
setActivityData({...activityData,score:(scoreType)*(value)})
}
function handlePerformance (value){
setScoreType(value)
}
const handleComments=(e)=>{
setActivityData({...activityData,comments:e.target.value})
}
const handleSubmit=(e)=>{
onClose()
console.log(activityData)
}
useEffect(()=>{handleScoreChange(activityData.score)},[scoreType])
useEffect(() => {
if (activityData.aName !== "" && activityData.aId !== "" && activityData.comments !== "" && activityData.score != 0 || -0) {
setEnableSubmit(true);
} else {
setEnableSubmit(false);
}
}, [activityData]);
useEffect(()=>{
if (visible===false){
setActivityData({aName:"",aId:"",type:type,score:0,comments:""})
}else{
getActivitysList();
}
},[visible,type])
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="bg-white rounded lg:w-4/12 sm:w-100">
<div className=" text-white py-3 pl-2 bg-blue-500">Default Activity</div>
<div>
<div>
<form className=" p-2 max-w-sm mx-auto">
<div className="flex items-center my-5">
<label htmlFor="countries">Select Activity: </label>
<select className="bg-gray-50 ml-2 w-7/12 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" onChange={(e)=>handleActivityName(e)}>
<option id="" value="" className="text-[16px]">Select</option>
{
activitiesList && activitiesList.map((activity)=><option className="text-[16px] w-7/12" key={activity.aId} id={activity.aId} value={activity.aName}>{activity.aName}</option>)
}
</select>
</div>
<div className="flex items-center mb-4 ">
<label htmlFor="appreciate" className=" text-sm font-medium text-gray-900 dark:text-gray-300">Appreciation:</label>
<input id="appreciate" type="radio" value="appreciate" name="performance" className="w-4 h-4 m-3 text-blue-600 bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600" onChange={()=>handlePerformance(1)}/>
<label htmlFor="depreciate" className="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">Depreciation:</label>
<input id="depreciate" type="radio" value="depreciate" name="performance" className="w-4 h-4 m-3 text-blue-600 bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600" onChange={()=>handlePerformance(-1)} />
</div>
<div className="flex ">
<span>Score</span>
<select className="border w-1/5" onChange={(e)=>handleScoreChange(e.target.value)}>
<option value={0}>Select</option>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
<option value={4}>4</option>
<option value={5}>5</option>
</select>
</div>
<div className="flex items-center my-5">
<label htmlFor="comments" className="block w-3/12 mb-20 text-sm font-medium text-gray-900 dark:text-white">Comments :</label>
<textarea id="comments" rows="4" className="block ml-2 p-2.5 w-9/12 text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="activity comments" onChange={(e)=>handleComments(e)}></textarea>
</div>
<div className="flex items-center justify-end mb-3">
<button onClick={onClose} className="px-3 py-2 bg-gray-700 text-white rounded">Cancel</button>
{
enableSubmit?<button type="button" className="px-3 py-2 ml-5 bg-green-700 text-white rounded" onClick={handleSubmit}>Submit</button>:
<button type="button" className="px-3 py-2 ml-5 bg-gray-400 text-white rounded" disabled={!enableSubmit} title="Please fill all fileds to submit">Submit</button>
}
</div>
</form>
</div>
</div>
</div>
</div>
);
}
\ No newline at end of file
import React, { useState } from "react";
import MyModal from "./index";
export default function ModalButton({type}) {
const [showMyModal, setShowMyModal] = useState(false);
const handleOnClose = () => setShowMyModal(false);
return (
<div className="bg-blue-400 bg-opacity-30">
{/* // <div className="max-w-3xl mx-auto">
// <div className="text-center py-3"> */}
<button
onClick={() => setShowMyModal(true)}
className="bg-red-400 text-white px-3 py-2 rounded hover:scale-95 transition text-xl">
Add Activity
</button>
{/* // </div>
// <p className="text-lg">
// </p>
// </div> */}
<MyModal onClose={handleOnClose} visible={showMyModal} type={type}/>
</div>
);
}
\ No newline at end of file
import React from "react";
import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
function Sidebar() {
const user = useSelector((state) => state.userDetails.user);
const reportees = useSelector((state) => state.reportees.reportees);
const url = window.location.href
return (
<div className="w-[30%] flex items-center flex-col">
<div className="w-[30%] flex items-center flex-col px-4">
<div>
<img src="/user.png" width="130px" height="130px" />
</div>
......@@ -12,6 +17,23 @@ function Sidebar() {
<p className="text-lg font-semibold">{user.empName}</p>
<p>{user.designation}</p>
</div>
{
url.includes('/reports') && <div className="mt-5 border-t-2 border-gray-300 w-[-webkit-fill-available] flex flex-col ">
<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-[50vh] overflow-auto">
{
reportees?.map(({empName, score, empId}) => (
<div className="flex items-center bg-white p-2 justify-between mb-1" key={empId}>
<img src="/man.png" width="18px" height="18px" />
<p className="w-[80%]">{empName}</p>
<p className="w-[10%] bg-blue-200 rounded-sm text-center">{score}</p>
</div>
))
}
</div>
</div>
}
</div>
);
}
......
import React from "react";
import {Link} from 'react-router-dom';
function Table({headers, data, isView}) {
return (
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<div className="relative overflow-x-auto shadow-md sm:rounded-lg p-3">
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 bg-transparent justify-center">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400 ">
<tr>
{headers.map((item) => (
<th scope="col" class="px-6 py-3 font-bold">
<th scope="col" className="px-6 py-3" >
{item.title}
</th>
))}
......@@ -16,9 +17,9 @@ function Table({headers, data, isView}) {
<tbody>
{
data?.map((item, index) => (
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
<tr className="bg-white border-b-8 dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
{headers?.map((field) => (
field.id !== "action" ? <td class="px-6 py-4">{item[field.id]}</td> : <td class="px-6 py-4"><button>View</button></td>
field.id !== "action" ?<td className="px-6 py-4 listData" >{field.id==="empName"?<span className="flex items-center"><img className="pr-2" src="/user.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>
))}
</tr>
......
......@@ -15,3 +15,6 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.listData:nth-child(4) {
padding-left: 35px;
}
\ No newline at end of file
......@@ -10,7 +10,7 @@ function Dashboard() {
const reportees = useSelector((state) => state.reportees.reportees);
const userDetails = useSelector((state) => state.userDetails);
const { id } = useParams();
const reporteIds = userDetails.user.reportees || {};
const reporteIds = userDetails.user.reportees || [];
useEffect(() => {
if (reporteIds.length > 0) {
......@@ -25,11 +25,12 @@ function Dashboard() {
}, [reporteIds]);
useEffect(() => {
if(id !== undefined ||null)
dispatch(fetchUser(id));
}, []);
}, [id]);
const headers = [
{title: "Name", id:"empName"},
{title: "Employee Name", id:"empName"},
{title: "Emp.Id", id: "empId"},
{title: "Designation", id: 'designation'},
{title: "score", id:"score"},
......@@ -38,7 +39,7 @@ function Dashboard() {
]
return (
<div>
<Table headers={headers} data={reportees.data} isView={true}/>
<Table headers={headers} data={reportees} isView={true}/>
</div>
)
}
......
import React, {useState, useEffect} from 'react';
import { useSelector,useDispatch } from 'react-redux';
import { useParams } from 'react-router';
import { fetchReports } from "../../redux/reducers/reportSlice";
import ModalButton from '../../components/modal/modalButton';
function Reports() {
const {id} = useParams();
const dispatch = useDispatch();
const reportees = useSelector((state) => state.reportees.reportees);
const [empDetails, setEmpDetails] = useState(null);
const { report, loading, error}=useSelector((state)=>state.reports)
/*Example post data
{
"empId":41689,
"fromDate":"2024-03-10",
"toDate":"2024-03-11"
}
*/
useEffect(() => {
if(id) {
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>This Perots
<ModalButton type={"default"}/>
</div>
)
}
export default Reports
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { base_url } from "../../utils/constants";
import axios from "axios";
const initialState = {
reports: [],
loading: false,
error: null,
};
export const fetchReports = createAsyncThunk("getReports", async (data) => {
return await axios
.post(`${base_url}/getActivities`, data)
.then((response) => response.data);
});
const reportSlice = createSlice({
name: "reportees",
initialState,
reducers: {
resetReports:() => {
return initialState
}
},
extraReducers: (builder) => {
builder.addCase(fetchReports.pending, (state) => {
state.loading = true;
state.error = "pending";
});
builder.addCase(fetchReports.fulfilled, (state, action) => {
state.loading = false;
state.reports = action.payload?.activities;
state.error = "";
});
builder.addCase(fetchReports.rejected, (state, action) => {
state.loading = false;
state.reports = [];
state.error = action.error || "Something went wrong!";
});
},
});
export const {resetReports} = reportSlice.actions;
export default reportSlice.reducer;
......@@ -15,9 +15,13 @@ export const fetchReportees = createAsyncThunk("getReportees", async (data) => {
});
const reporteesSlice = createSlice({
name: "counter",
name: "reportees",
initialState,
reducers: {},
reducers: {
resetReportees:() => {
return initialState
}
},
extraReducers: (builder) => {
builder.addCase(fetchReportees.pending, (state) => {
state.loading = true;
......@@ -25,7 +29,7 @@ const reporteesSlice = createSlice({
});
builder.addCase(fetchReportees.fulfilled, (state, action) => {
state.loading = false;
state.reportees = action.payload;
state.reportees = action.payload.data;
state.error = "";
});
builder.addCase(fetchReportees.rejected, (state, action) => {
......@@ -36,6 +40,6 @@ const reporteesSlice = createSlice({
},
});
export const {} = reporteesSlice.actions;
export const {resetReportees} = reporteesSlice.actions;
export default reporteesSlice.reducer;
import { combineReducers } from 'redux';
import reporteesReducer from './reporteesSlice';
import userReducer from './userSlice';
import reportReducer from './reportSlice';
const rootReducer = combineReducers({
userDetails: userReducer,
reportees: reporteesReducer
reportees: reporteesReducer,
reports: reportReducer
});
export default rootReducer;
\ No newline at end of file
......@@ -15,9 +15,13 @@ export const fetchUser = createAsyncThunk("getUser", async (id) => {
});
const userSlice = createSlice({
name: "counter",
name: "user",
initialState,
reducers: {},
reducers: {
resetUser:() => {
return initialState
}
},
extraReducers: (builder) => {
// fetch user
builder.addCase(fetchUser.pending, (state) => {
......@@ -37,6 +41,6 @@ const userSlice = createSlice({
},
});
export const {} = userSlice.actions;
export const {resetUser} = userSlice.actions;
export default userSlice.reducer;
import {resetUser} from '../redux/reducers/userSlice';
import {resetReportees} from '../redux/reducers/reporteesSlice';
const clearStore = (dispatch) => {
dispatch(resetUser());
dispatch(resetReportees());
};
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