change class= to className=
This commit is contained in:
parent
984efe207b
commit
5995c74ae6
10
index.html
10
index.html
@ -84,8 +84,8 @@
|
|||||||
<script src="/assets/vendor/libs/bootstrap-select/bootstrap-select.js"></script>
|
<script src="/assets/vendor/libs/bootstrap-select/bootstrap-select.js"></script>
|
||||||
<script src="/assets/vendor/libs/select2/select2.js"></script>
|
<script src="/assets/vendor/libs/select2/select2.js"></script>
|
||||||
<script src="/assets/vendor/libs/apex-charts/apexcharts.js"></script>
|
<script src="/assets/vendor/libs/apex-charts/apexcharts.js"></script>
|
||||||
<script src="/assets/vendor/libs/jquery-timepicker/jquery-timepicker.js" ></script>
|
<!-- <script src="/assets/vendor/libs/jquery-timepicker/jquery-timepicker.js" ></script> -->
|
||||||
<script src="/assets/vendor/libs/flatpickr/flatpickr.js" ></script>
|
<script src="/assets/vendor/libs/flatpickr/flatpickr.js"></script>
|
||||||
<!-- Main JS -->
|
<!-- Main JS -->
|
||||||
<script src="/assets/js/main.js"></script>
|
<script src="/assets/js/main.js"></script>
|
||||||
|
|
||||||
@ -94,15 +94,15 @@
|
|||||||
<script src="/assets/js/dashboards-analytics.js"></script>
|
<script src="/assets/js/dashboards-analytics.js"></script>
|
||||||
|
|
||||||
<!-- component -->
|
<!-- component -->
|
||||||
<script src="./public/js/timppick.js"></script>
|
<!-- <script src="./public/js/timppick.js"></script> -->
|
||||||
|
|
||||||
<script src="/assets/vendor/libs/sweetalert2/sweetalert2.js" ></script>
|
<script src="/assets/vendor/libs/sweetalert2/sweetalert2.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js"></script>
|
<!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script> -->
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script> -->
|
||||||
|
|
||||||
<!-- Flatpickr JS -->
|
<!-- Flatpickr JS -->
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
@ -6,9 +6,8 @@ import { z } from "zod";
|
|||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
import { TasksRepository } from "../../repositories/TaskRepository";
|
import { TasksRepository } from "../../repositories/TaskRepository";
|
||||||
|
|
||||||
export const ReportTask = ({ report,closeModal,refetch }) => {
|
export const ReportTask = ({ report, closeModal, refetch }) => {
|
||||||
const [ loading, setloading ] = useState( false );
|
const [loading, setloading] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
completedTask: z
|
completedTask: z
|
||||||
@ -32,21 +31,18 @@ export const ReportTask = ({ report,closeModal,refetch }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = async (data) => {
|
const onSubmit = async (data) => {
|
||||||
try
|
try {
|
||||||
{
|
setloading(true);
|
||||||
setloading(true)
|
const reportData = {
|
||||||
const reportData = {
|
...data,
|
||||||
...data,
|
|
||||||
id: report?.id,
|
id: report?.id,
|
||||||
reportedDate: new Date().toISOString(),
|
reportedDate: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let response = await TasksRepository.reportTsak( reportData )
|
|
||||||
showToast( "succesfully", "success" )
|
|
||||||
refetch()
|
|
||||||
closeModal()
|
|
||||||
|
|
||||||
|
let response = await TasksRepository.reportTsak(reportData);
|
||||||
|
showToast("succesfully", "success");
|
||||||
|
refetch();
|
||||||
|
closeModal();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast("Somthing wrog", "error");
|
showToast("Somthing wrog", "error");
|
||||||
}
|
}
|
||||||
@ -56,125 +52,135 @@ export const ReportTask = ({ report,closeModal,refetch }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div
|
||||||
|
className="modal-dialog modal-md modal-simple report-task-modal"
|
||||||
|
role="document"
|
||||||
|
>
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-body px-1">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn-close"
|
||||||
|
onClick={handleClose}
|
||||||
|
aria-label="Close"
|
||||||
|
></button>
|
||||||
|
|
||||||
|
<div className="container m-0">
|
||||||
<div className="modal-dialog modal-md modal-simple report-task-modal" role="document">
|
<div className="d-flex justify-content-between">
|
||||||
<div className="modal-content">
|
<figure className="text-start p-0 m-0">
|
||||||
<div className="modal-body px-1">
|
<blockquote className="blockquote">
|
||||||
<button
|
<small>
|
||||||
type="button"
|
{" "}
|
||||||
className="btn-close"
|
Assigned Date : {formatDate(report?.assignmentDate)}
|
||||||
|
</small>
|
||||||
onClick={handleClose}
|
|
||||||
aria-label="Close"
|
|
||||||
></button>
|
|
||||||
|
|
||||||
<div className="container m-0">
|
|
||||||
<div className="d-flex justify-content-between">
|
|
||||||
|
|
||||||
<figure class="text-start p-0 m-0">
|
|
||||||
<blockquote class="blockquote">
|
|
||||||
<small> Assigned Date : {formatDate(report?.assignmentDate)}</small>
|
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</figure>
|
</figure>
|
||||||
<figure class="text-end p-0 m-0">
|
<figure className="text-end p-0 m-0">
|
||||||
<blockquote class="blockquote">
|
<blockquote className="blockquote">
|
||||||
<small>Assigned By</small>
|
<small>Assigned By</small>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<figcaption className="blockquote-footer mb-0">
|
<figcaption className="blockquote-footer mb-0">
|
||||||
{/* <div className="d-flex avatar avatar-xs">
|
{/* <div className="d-flex avatar avatar-xs">
|
||||||
<span className="avatar-initial rounded-circle bg-label-primary">
|
<span className="avatar-initial rounded-circle bg-label-primary">
|
||||||
{report?.assignedBy?.firstName.slice(0, 1)}
|
{report?.assignedBy?.firstName.slice(0, 1)}
|
||||||
</span> */}
|
</span> */}
|
||||||
<cite title="Source Title m-0">{` ${report?.assignedBy.firstName} ${report?.assignedBy.lastName}`}</cite>
|
<cite title="Source Title m-0">{` ${report?.assignedBy.firstName} ${report?.assignedBy.lastName}`}</cite>
|
||||||
{/* </div> */}
|
{/* </div> */}
|
||||||
</figcaption>
|
</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="d-flex p-0 m-0">
|
<div className="d-flex p-0 m-0">
|
||||||
<div className="flex-shrink-0 mt-1 mx-sm-0 px-2 mx-auto">
|
<div className="flex-shrink-0 mt-1 mx-sm-0 px-2 mx-auto">
|
||||||
<i class="bx bx-buildings"></i>
|
<i className="bx bx-buildings"></i>
|
||||||
</div>
|
|
||||||
<p class="lead">{report?.workItem?.workArea?.floor?.building?.name}</p>
|
|
||||||
<p class="lead ms-12">{report?.workItem?.workArea?.floor?.floorName}</p>
|
|
||||||
</div>
|
|
||||||
<dl class="row text-start ms-3">
|
|
||||||
<dt class="col-sm-6">
|
|
||||||
Work Area : {report?.workItem?.workArea?.areaName}
|
|
||||||
</dt>
|
|
||||||
<dd class="col-sm-6">
|
|
||||||
<small> {report?.workItem?.activityMaster.activityName}</small>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<dl class="row text-start ms-3">
|
|
||||||
<dt class="col-sm-4">Team</dt>
|
|
||||||
|
|
||||||
<dd class="col-sm-4 d-flex align-items-center avatar-group justify-content-start">
|
|
||||||
{report?.teamMembers.map((member) => (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
data-bs-toggle="tooltip"
|
|
||||||
data-bs-html="true"
|
|
||||||
data-popup="tooltip-custom"
|
|
||||||
data-bs-placement="top"
|
|
||||||
title={`${member.firstName} ${member.lastName}`}
|
|
||||||
className="avatar avatar-xs"
|
|
||||||
>
|
|
||||||
{/* <img src="..." alt="Avatar" class="rounded-circle pull-up" /> */}
|
|
||||||
<span className="avatar-initial rounded-circle bg-label-primary">
|
|
||||||
{member?.firstName.slice(0, 1)}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
<p className="lead">
|
||||||
))}
|
{report?.workItem?.workArea?.floor?.building?.name}
|
||||||
</dd>
|
</p>
|
||||||
<dt class="col-sm-4 text-start">Planned : {report?.plannedTask}</dt>
|
<p className="lead ms-12">
|
||||||
</dl>
|
{report?.workItem?.workArea?.floor?.floorName}
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
</p>
|
||||||
<div className="row p-0">
|
</div>
|
||||||
<div className="col-4">
|
<dl className="row text-start ms-3">
|
||||||
<input
|
<dt className="col-sm-6">
|
||||||
{...register("completedTask", { valueAsNumber: true })}
|
Work Area : {report?.workItem?.workArea?.areaName}
|
||||||
id="smallInput"
|
</dt>
|
||||||
className="form-control form-control-sm"
|
<dd className="col-sm-6">
|
||||||
type="number"
|
<small> {report?.workItem?.activityMaster.activityName}</small>
|
||||||
placeholder="Completed Work"
|
</dd>
|
||||||
/>
|
</dl>
|
||||||
{errors.completedTask && (
|
<dl className="row text-start ms-3">
|
||||||
<div className="text-danger">{errors.completedTask.message}</div>
|
<dt className="col-sm-4">Team</dt>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="col-8">
|
|
||||||
<textarea
|
|
||||||
{...register("comment")}
|
|
||||||
className="form-control"
|
|
||||||
id="exampleFormControlTextarea1"
|
|
||||||
rows="1"
|
|
||||||
placeholder="Enter comment"
|
|
||||||
/>
|
|
||||||
{errors.comment && (
|
|
||||||
<div className="text-danger">{errors.comment.message}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-12 text-center my-2">
|
<dd className="col-sm-4 d-flex align-items-center avatar-group justify-content-start">
|
||||||
<button type="submit" className="btn btn-sm btn-primary me-3">
|
{report?.teamMembers.map((member) => (
|
||||||
{loading ? "Please wait":"Submit Report"}
|
<>
|
||||||
</button>
|
<div
|
||||||
<button
|
data-bs-toggle="tooltip"
|
||||||
type="button"
|
data-bs-html="true"
|
||||||
className="btn btn-sm btn-label-secondary"
|
data-popup="tooltip-custom"
|
||||||
onClick={handleClose}
|
data-bs-placement="top"
|
||||||
>
|
title={`${member.firstName} ${member.lastName}`}
|
||||||
Cancel
|
className="avatar avatar-xs"
|
||||||
</button>
|
>
|
||||||
</div>
|
{/* <img src="..." alt="Avatar" className="rounded-circle pull-up" /> */}
|
||||||
</form>
|
<span className="avatar-initial rounded-circle bg-label-primary">
|
||||||
|
{member?.firstName.slice(0, 1)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</dd>
|
||||||
|
<dt className="col-sm-4 text-start">
|
||||||
|
Planned : {report?.plannedTask}
|
||||||
|
</dt>
|
||||||
|
</dl>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<div className="row p-0">
|
||||||
|
<div className="col-4">
|
||||||
|
<input
|
||||||
|
{...register("completedTask", { valueAsNumber: true })}
|
||||||
|
id="smallInput"
|
||||||
|
className="form-control form-control-sm"
|
||||||
|
type="number"
|
||||||
|
placeholder="Completed Work"
|
||||||
|
/>
|
||||||
|
{errors.completedTask && (
|
||||||
|
<div className="text-danger">
|
||||||
|
{errors.completedTask.message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="col-8">
|
||||||
|
<textarea
|
||||||
|
{...register("comment")}
|
||||||
|
className="form-control"
|
||||||
|
id="exampleFormControlTextarea1"
|
||||||
|
rows="1"
|
||||||
|
placeholder="Enter comment"
|
||||||
|
/>
|
||||||
|
{errors.comment && (
|
||||||
|
<div className="text-danger">{errors.comment.message}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-12 text-center my-2">
|
||||||
|
<button type="submit" className="btn btn-sm btn-primary me-3">
|
||||||
|
{loading ? "Please wait" : "Submit Report"}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-sm btn-label-secondary"
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,62 +1,54 @@
|
|||||||
import React, {useEffect, useState} from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import {useProfile} from "../../hooks/useProfile";
|
import { useProfile } from "../../hooks/useProfile";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {TasksRepository} from "../../repositories/TaskRepository";
|
import { TasksRepository } from "../../repositories/TaskRepository";
|
||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
|
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
comment: z.string().min(1, "Comment cannot be empty"),
|
comment: z.string().min(1, "Comment cannot be empty"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const ReportTaskComments = ({ commentsData, closeModal }) => {
|
||||||
|
const [loading, setloading] = useState(false);
|
||||||
|
const { profile } = useProfile();
|
||||||
|
const [comments, setComment] = useState([]);
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
reset,
|
||||||
|
} = useForm({
|
||||||
|
resolver: zodResolver(schema),
|
||||||
});
|
});
|
||||||
|
|
||||||
const ReportTaskComments = ( {commentsData, closeModal} ) =>
|
useEffect(() => {
|
||||||
{
|
setComment(commentsData?.comments);
|
||||||
const [loading,setloading]=useState(false)
|
}, [commentsData]);
|
||||||
const {profile} = useProfile()
|
const isLoggedUser = (usrId) => profile?.employeeInfo.id;
|
||||||
const [comments,setComment] = useState([])
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors },reset
|
|
||||||
} = useForm({
|
|
||||||
resolver: zodResolver(schema),
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect( () =>
|
const onSubmit = async (data) => {
|
||||||
{
|
|
||||||
setComment(commentsData?.comments
|
|
||||||
)
|
|
||||||
}, [commentsData] )
|
|
||||||
const isLoggedUser = ( usrId ) => profile?.employeeInfo.id;
|
|
||||||
|
|
||||||
const onSubmit = async(data) =>
|
|
||||||
{
|
|
||||||
let sendComment = {
|
let sendComment = {
|
||||||
...data,
|
...data,
|
||||||
taskAllocationId: commentsData?.id,
|
taskAllocationId: commentsData?.id,
|
||||||
commentDate: new Date().toISOString(),
|
commentDate: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
|
||||||
}
|
try {
|
||||||
|
setloading(true);
|
||||||
try
|
|
||||||
{
|
|
||||||
setloading(true)
|
|
||||||
// const resp = await TasksRepository.taskComments( sendComment );
|
// const resp = await TasksRepository.taskComments( sendComment );
|
||||||
// console.timeLog( resp )
|
// console.timeLog( resp )
|
||||||
reset()
|
reset();
|
||||||
setloading(false)
|
setloading(false);
|
||||||
showToast( "Successfully Sent", "success" )
|
showToast("Successfully Sent", "success");
|
||||||
closeModal()
|
closeModal();
|
||||||
} catch ( err )
|
} catch (err) {
|
||||||
{
|
setloading(false);
|
||||||
setloading(false)
|
showToast(error.response.data?.message || "Something wrong", "error");
|
||||||
showToast(error.response.data?.message || "Something wrong","error")
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="modal-dialog modal-md modal-simple report-task-comments-modal"
|
className="modal-dialog modal-md modal-simple report-task-comments-modal"
|
||||||
@ -71,39 +63,49 @@ const ReportTaskComments = ( {commentsData, closeModal} ) =>
|
|||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
></button>
|
></button>
|
||||||
<div className="container ">
|
<div className="container ">
|
||||||
|
{comments &&
|
||||||
{
|
comments.map((data) => (
|
||||||
comments && comments.map( ( data ) =>
|
|
||||||
(
|
|
||||||
<div className="text-start" key={data.id}>
|
<div className="text-start" key={data.id}>
|
||||||
<div class={`li-wrapper d-flex justify-content-${isLoggedUser(data?.employee?.id) ? "end":"start"} align-items-start`}>
|
<div
|
||||||
<div class="avatar avatar-xs me-1">
|
className={`li-wrapper d-flex justify-content-${
|
||||||
<span class="avatar-initial rounded-circle bg-label-success">
|
isLoggedUser(data?.employee?.id) ? "end" : "start"
|
||||||
M
|
} align-items-start`}
|
||||||
</span>
|
>
|
||||||
</div>
|
<div className="avatar avatar-xs me-1">
|
||||||
<div class="text-start py-0">
|
<span className="avatar-initial rounded-circle bg-label-success">
|
||||||
<p class="mb-0">
|
M
|
||||||
<strong>{ `${data?.employee?.firstName} ${data?.employee?.lastName}`}</strong>
|
</span>
|
||||||
</p>
|
</div>
|
||||||
<small style={{fontSize: "10px"}}>{ moment(data?.commentDate).fromNow()}</small>
|
<div className="text-start py-0">
|
||||||
</div>
|
<p className="mb-0">
|
||||||
|
<strong>{`${data?.employee?.firstName} ${data?.employee?.lastName}`}</strong>
|
||||||
|
</p>
|
||||||
|
<small style={{ fontSize: "10px" }}>
|
||||||
|
{moment(data?.commentDate).fromNow()}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className={`ms-${ isLoggedUser( data?.employee?.id ) ? "0 text-end me-6" : "6 " } mt-1`}>{ data?.comment
|
<p
|
||||||
}</p>
|
className={`ms-${
|
||||||
|
isLoggedUser(data?.employee?.id)
|
||||||
|
? "0 text-end me-6"
|
||||||
|
: "6 "
|
||||||
|
} mt-1`}
|
||||||
|
>
|
||||||
|
{data?.comment}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
))
|
))}
|
||||||
}
|
|
||||||
{/* by other users */}
|
{/* by other users */}
|
||||||
{/* <div className="text-start">
|
{/* <div className="text-start">
|
||||||
<div class="li-wrapper d-flex justify-content-start align-items-start">
|
<div className="li-wrapper d-flex justify-content-start align-items-start">
|
||||||
<div class="avatar avatar-xs me-1">
|
<div className="avatar avatar-xs me-1">
|
||||||
<span class="avatar-initial rounded-circle bg-label-success">
|
<span className="avatar-initial rounded-circle bg-label-success">
|
||||||
M
|
M
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-start py-0">
|
<div className="text-start py-0">
|
||||||
<p class="mb-0">
|
<p className="mb-0">
|
||||||
<strong>Mahajan</strong>
|
<strong>Mahajan</strong>
|
||||||
</p>
|
</p>
|
||||||
<small style={{ fontSize: "10px" }}>2 hour ago</small>
|
<small style={{ fontSize: "10px" }}>2 hour ago</small>
|
||||||
@ -114,14 +116,14 @@ const ReportTaskComments = ( {commentsData, closeModal} ) =>
|
|||||||
|
|
||||||
{/* by login usrer */}
|
{/* by login usrer */}
|
||||||
{/* <div className="text-start">
|
{/* <div className="text-start">
|
||||||
<div class="li-wrapper d-flex justify-content-end align-items-start">
|
<div className="li-wrapper d-flex justify-content-end align-items-start">
|
||||||
<div class="avatar avatar-xs me-1">
|
<div className="avatar avatar-xs me-1">
|
||||||
<span class="avatar-initial rounded-circle bg-label-success">
|
<span className="avatar-initial rounded-circle bg-label-success">
|
||||||
M
|
M
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-start py-0">
|
<div className"text-start py-0">
|
||||||
<p class="mb-0">
|
<p className="mb-0">
|
||||||
<strong>Pramod Mahajan</strong>
|
<strong>Pramod Mahajan</strong>
|
||||||
</p>
|
</p>
|
||||||
<small style={{ fontSize: "10px" }}>2 hour ago</small>
|
<small style={{ fontSize: "10px" }}>2 hour ago</small>
|
||||||
@ -129,25 +131,31 @@ const ReportTaskComments = ( {commentsData, closeModal} ) =>
|
|||||||
</div>
|
</div>
|
||||||
<p className="ms-6 mt-1">Stylized implementation of HTML’s element for abbreviations and acronyms to show the expanded version on hover. Abbreviations have a default underline and gain a help cursor to provide additional context on hov </p>
|
<p className="ms-6 mt-1">Stylized implementation of HTML’s element for abbreviations and acronyms to show the expanded version on hover. Abbreviations have a default underline and gain a help cursor to provide additional context on hov </p>
|
||||||
</div> */}
|
</div> */}
|
||||||
<form onSubmit={handleSubmit( onSubmit )}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<textarea
|
<textarea
|
||||||
{...register("comment")}
|
{...register("comment")}
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="exampleFormControlTextarea1"
|
id="exampleFormControlTextarea1"
|
||||||
rows="1"
|
rows="1"
|
||||||
placeholder="Enter comment"
|
placeholder="Enter comment"
|
||||||
/>
|
/>
|
||||||
{errors.comment && (
|
{errors.comment && (
|
||||||
<div className="danger-text">{errors.comment.message}</div>
|
<div className="danger-text">{errors.comment.message}</div>
|
||||||
)}
|
)}
|
||||||
<div class="text-end my-1">
|
<div className="text-end my-1">
|
||||||
|
<button
|
||||||
<button type="button" class="btn btn-sm btn-secondary" onClick={closeModal} data-bs-dismiss="modal">Close</button>
|
type="button"
|
||||||
<button type="submit" class="btn btn-sm btn-primary ms-2">{ loading ? "Sending...":"Comment"}</button>
|
className="btn btn-sm btn-secondary"
|
||||||
</div>
|
onClick={closeModal}
|
||||||
|
data-bs-dismiss="modal"
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
<button type="submit" className="btn btn-sm btn-primary ms-2">
|
||||||
|
{loading ? "Sending..." : "Comment"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,135 +1,172 @@
|
|||||||
import React from 'react'
|
import React from "react";
|
||||||
|
|
||||||
const DemoTable = () => {
|
const DemoTable = () => {
|
||||||
return (
|
return (
|
||||||
<div class="content-wrapper">
|
<div className="content-wrapper">
|
||||||
|
<div className="container-xxl flex-grow-1 container-p-y">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-datatable table-responsive">
|
||||||
|
<table className="datatables-basic table border-top">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
<th>id</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Salary</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="offcanvas offcanvas-end" id="add-new-record">
|
||||||
|
<div className="offcanvas-header border-bottom">
|
||||||
|
<h5 className="offcanvas-title" id="exampleModalLabel">
|
||||||
|
New Record
|
||||||
|
</h5>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn-close text-reset"
|
||||||
|
data-bs-dismiss="offcanvas"
|
||||||
|
aria-label="Close"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
<div className="offcanvas-body flex-grow-1">
|
||||||
|
<form
|
||||||
|
className="add-new-record pt-0 row g-2"
|
||||||
|
id="form-add-new-record"
|
||||||
|
onsubmit="return false"
|
||||||
|
>
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<label className="form-label" for="basicFullname">
|
||||||
|
Full Name
|
||||||
|
</label>
|
||||||
|
<div className="input-group input-group-merge">
|
||||||
|
<span id="basicFullname2" className="input-group-text">
|
||||||
|
<i className="bx bx-user"></i>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="basicFullname"
|
||||||
|
className="form-control dt-full-name"
|
||||||
|
name="basicFullname"
|
||||||
|
placeholder="John Doe"
|
||||||
|
aria-label="John Doe"
|
||||||
|
aria-describedby="basicFullname2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<label className="form-label" for="basicPost">
|
||||||
|
Post
|
||||||
|
</label>
|
||||||
|
<div className="input-group input-group-merge">
|
||||||
|
<span id="basicPost2" className="input-group-text">
|
||||||
|
<i className="bx bxs-briefcase"></i>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="basicPost"
|
||||||
|
name="basicPost"
|
||||||
|
className="form-control dt-post"
|
||||||
|
placeholder="Web Developer"
|
||||||
|
aria-label="Web Developer"
|
||||||
|
aria-describedby="basicPost2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<label className="form-label" for="basicEmail">
|
||||||
|
Email
|
||||||
|
</label>
|
||||||
|
<div className="input-group input-group-merge">
|
||||||
|
<span className="input-group-text">
|
||||||
|
<i className="bx bx-envelope"></i>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="basicEmail"
|
||||||
|
name="basicEmail"
|
||||||
|
className="form-control dt-email"
|
||||||
|
placeholder="john.doe@example.com"
|
||||||
|
aria-label="john.doe@example.com"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-text">
|
||||||
|
You can use letters, numbers & periods
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<label className="form-label" for="basicDate">
|
||||||
|
Joining Date
|
||||||
|
</label>
|
||||||
|
<div className="input-group input-group-merge">
|
||||||
|
<span id="basicDate2" className="input-group-text">
|
||||||
|
<i className="bx bx-calendar"></i>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control dt-date"
|
||||||
|
id="basicDate"
|
||||||
|
name="basicDate"
|
||||||
|
aria-describedby="basicDate2"
|
||||||
|
placeholder="MM/DD/YYYY"
|
||||||
|
aria-label="MM/DD/YYYY"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<label className="form-label" for="basicSalary">
|
||||||
|
Salary
|
||||||
|
</label>
|
||||||
|
<div className="input-group input-group-merge">
|
||||||
|
<span id="basicSalary2" className="input-group-text">
|
||||||
|
<i className="bx bx-dollar"></i>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
id="basicSalary"
|
||||||
|
name="basicSalary"
|
||||||
|
className="form-control dt-salary"
|
||||||
|
placeholder="12000"
|
||||||
|
aria-label="12000"
|
||||||
|
aria-describedby="basicSalary2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="btn btn-primary data-submit me-sm-4 me-1"
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="reset"
|
||||||
|
className="btn btn-outline-secondary"
|
||||||
|
data-bs-dismiss="offcanvas"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="container-xxl flex-grow-1 container-p-y">
|
<hr className="my-12" />
|
||||||
<div class="card">
|
|
||||||
<div class="card-datatable table-responsive">
|
<hr className="my-12" />
|
||||||
<table class="datatables-basic table border-top">
|
|
||||||
<thead>
|
<hr className="my-12" />
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
<th></th>
|
|
||||||
<th>id</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th>Date</th>
|
|
||||||
<th>Salary</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Action</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="offcanvas offcanvas-end" id="add-new-record">
|
|
||||||
<div class="offcanvas-header border-bottom">
|
|
||||||
<h5 class="offcanvas-title" id="exampleModalLabel">New Record</h5>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn-close text-reset"
|
|
||||||
data-bs-dismiss="offcanvas"
|
|
||||||
aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="offcanvas-body flex-grow-1">
|
|
||||||
<form class="add-new-record pt-0 row g-2" id="form-add-new-record" onsubmit="return false">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<label class="form-label" for="basicFullname">Full Name</label>
|
|
||||||
<div class="input-group input-group-merge">
|
|
||||||
<span id="basicFullname2" class="input-group-text"><i class="bx bx-user"></i></span>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="basicFullname"
|
|
||||||
class="form-control dt-full-name"
|
|
||||||
name="basicFullname"
|
|
||||||
placeholder="John Doe"
|
|
||||||
aria-label="John Doe"
|
|
||||||
aria-describedby="basicFullname2" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<label class="form-label" for="basicPost">Post</label>
|
|
||||||
<div class="input-group input-group-merge">
|
|
||||||
<span id="basicPost2" class="input-group-text"><i class="bx bxs-briefcase"></i></span>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="basicPost"
|
|
||||||
name="basicPost"
|
|
||||||
class="form-control dt-post"
|
|
||||||
placeholder="Web Developer"
|
|
||||||
aria-label="Web Developer"
|
|
||||||
aria-describedby="basicPost2" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<label class="form-label" for="basicEmail">Email</label>
|
|
||||||
<div class="input-group input-group-merge">
|
|
||||||
<span class="input-group-text"><i class="bx bx-envelope"></i></span>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="basicEmail"
|
|
||||||
name="basicEmail"
|
|
||||||
class="form-control dt-email"
|
|
||||||
placeholder="john.doe@example.com"
|
|
||||||
aria-label="john.doe@example.com" />
|
|
||||||
</div>
|
|
||||||
<div class="form-text">You can use letters, numbers & periods</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<label class="form-label" for="basicDate">Joining Date</label>
|
|
||||||
<div class="input-group input-group-merge">
|
|
||||||
<span id="basicDate2" class="input-group-text"><i class="bx bx-calendar"></i></span>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control dt-date"
|
|
||||||
id="basicDate"
|
|
||||||
name="basicDate"
|
|
||||||
aria-describedby="basicDate2"
|
|
||||||
placeholder="MM/DD/YYYY"
|
|
||||||
aria-label="MM/DD/YYYY" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<label class="form-label" for="basicSalary">Salary</label>
|
|
||||||
<div class="input-group input-group-merge">
|
|
||||||
<span id="basicSalary2" class="input-group-text"><i class="bx bx-dollar"></i></span>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
id="basicSalary"
|
|
||||||
name="basicSalary"
|
|
||||||
class="form-control dt-salary"
|
|
||||||
placeholder="12000"
|
|
||||||
aria-label="12000"
|
|
||||||
aria-describedby="basicSalary2" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<button type="submit" class="btn btn-primary data-submit me-sm-4 me-1">Submit</button>
|
|
||||||
<button type="reset" class="btn btn-outline-secondary" data-bs-dismiss="offcanvas">Cancel</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-12" />
|
<div className="content-backdrop fade"></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DemoTable;
|
||||||
|
|
||||||
<hr class="my-12" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<hr class="my-12" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content-backdrop fade"></div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DemoTable
|
|
||||||
|
@ -11,7 +11,7 @@ import { Link, useNavigate, useParams } from "react-router-dom";
|
|||||||
import { formatDate } from "../../utils/dateUtils";
|
import { formatDate } from "../../utils/dateUtils";
|
||||||
import { useEmployeeProfile } from "../../hooks/useEmployees";
|
import { useEmployeeProfile } from "../../hooks/useEmployees";
|
||||||
import { clearCacheKey, getCachedData } from "../../slices/apiDataManager";
|
import { clearCacheKey, getCachedData } from "../../slices/apiDataManager";
|
||||||
import {clearApiCacheKey} from "../../slices/apiCacheSlice";
|
import { clearApiCacheKey } from "../../slices/apiCacheSlice";
|
||||||
|
|
||||||
const mobileNumberRegex = /^[7-9]\d{9}$/;
|
const mobileNumberRegex = /^[7-9]\d{9}$/;
|
||||||
|
|
||||||
@ -24,66 +24,78 @@ const ManageEmployee = () => {
|
|||||||
error,
|
error,
|
||||||
loading: empLoading,
|
loading: empLoading,
|
||||||
} = useEmployeeProfile(employeeId);
|
} = useEmployeeProfile(employeeId);
|
||||||
dispatch( changeMaster( "Job Role" ) );
|
dispatch(changeMaster("Job Role"));
|
||||||
const [disabledEmail,setDisabledEmail] = useState(false)
|
const [disabledEmail, setDisabledEmail] = useState(false);
|
||||||
const { data: job_role, loading } = useMaster();
|
const { data: job_role, loading } = useMaster();
|
||||||
const [isloading, setLoading] = useState(false);
|
const [isloading, setLoading] = useState(false);
|
||||||
const navigation = useNavigate();
|
const navigation = useNavigate();
|
||||||
const [currentEmployee, setCurrentEmployee] = useState();
|
const [currentEmployee, setCurrentEmployee] = useState();
|
||||||
|
|
||||||
|
const userSchema = z.object({
|
||||||
const userSchema = z
|
...(employeeId ? { Id: z.number().optional() } : {}),
|
||||||
.object({
|
FirstName: z.string().min(1, { message: "First Name is required" }),
|
||||||
...(employeeId ? { Id: z.number().optional() } : {}),
|
MiddleName: z.string().optional(),
|
||||||
FirstName: z.string().min(1, { message: "First Name is required" }),
|
LastName: z.string().min(1, { message: "Last Name is required" }),
|
||||||
MiddleName: z.string().optional(),
|
Email: z.string().optional(),
|
||||||
LastName: z.string().min(1, { message: "Last Name is required" }),
|
CurrentAddress: z
|
||||||
Email: z.string().optional(),
|
.string()
|
||||||
CurrentAddress: z
|
.min(1, { message: "Current Address is required" })
|
||||||
.string()
|
.max(150, { message: "Address cannot exceed 150 characters" }),
|
||||||
.min(1, { message: "Current Address is required" }).max(150, { message: "Address cannot exceed 150 characters" }),
|
BirthDate: z
|
||||||
BirthDate: z.string().min(1, { message: "Birth Date is required" }).refine((date, ctx) => {
|
.string()
|
||||||
return new Date(date) <= new Date();
|
.min(1, { message: "Birth Date is required" })
|
||||||
}, {
|
.refine(
|
||||||
message: "Birth date cannot be in the future",
|
(date, ctx) => {
|
||||||
}),
|
return new Date(date) <= new Date();
|
||||||
JoiningDate: z.string().min(1, { message: "Joining Date is required" }).refine((date, ctx) => {
|
},
|
||||||
return new Date(date) <= new Date();
|
{
|
||||||
}, {
|
message: "Birth date cannot be in the future",
|
||||||
message: "Joining date cannot be in the future",
|
}
|
||||||
}),
|
),
|
||||||
EmergencyPhoneNumber: z
|
JoiningDate: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, { message: "Phone Number is required" })
|
.min(1, { message: "Joining Date is required" })
|
||||||
.regex(mobileNumberRegex, { message: "Invalid phone number " }),
|
.refine(
|
||||||
EmergencyContactPerson: z
|
(date, ctx) => {
|
||||||
.string()
|
return new Date(date) <= new Date();
|
||||||
.min(1, { message: "Emergency Contact Person is required" }),
|
},
|
||||||
AadharNumber: z.string()
|
{
|
||||||
|
message: "Joining date cannot be in the future",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
EmergencyPhoneNumber: z
|
||||||
|
.string()
|
||||||
|
.min(1, { message: "Phone Number is required" })
|
||||||
|
.regex(mobileNumberRegex, { message: "Invalid phone number " }),
|
||||||
|
EmergencyContactPerson: z
|
||||||
|
.string()
|
||||||
|
.min(1, { message: "Emergency Contact Person is required" }),
|
||||||
|
AadharNumber: z
|
||||||
|
.string()
|
||||||
.regex(/^\d{12}$/, "Aadhar card must be exactly 12 digits long")
|
.regex(/^\d{12}$/, "Aadhar card must be exactly 12 digits long")
|
||||||
.nonempty("Aadhar card is required"),
|
.nonempty("Aadhar card is required"),
|
||||||
Gender: z
|
Gender: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, { message: "Gender is required" })
|
.min(1, { message: "Gender is required" })
|
||||||
.refine((val) => val !== "Select Gender", {
|
.refine((val) => val !== "Select Gender", {
|
||||||
message: "Please select a gender",
|
message: "Please select a gender",
|
||||||
}),
|
}),
|
||||||
PanNumber: z
|
PanNumber: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.refine((val) => !val || /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(val), {
|
.refine((val) => !val || /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(val), {
|
||||||
message: "Invalid PAN number",
|
message: "Invalid PAN number",
|
||||||
}),
|
}),
|
||||||
PeramnentAddress: z
|
PeramnentAddress: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, { message: "Permanent Address is required" }).max(150, { message: "Address cannot exceed 150 characters" }),
|
.min(1, { message: "Permanent Address is required" })
|
||||||
PhoneNumber: z
|
.max(150, { message: "Address cannot exceed 150 characters" }),
|
||||||
.string()
|
PhoneNumber: z
|
||||||
.min(1, { message: "Phone Number is required" })
|
.string()
|
||||||
.regex(mobileNumberRegex, { message: "Invalid phone number " }),
|
.min(1, { message: "Phone Number is required" })
|
||||||
JobRoleId: z.string().min(1, { message: "Role is required" }),
|
.regex(mobileNumberRegex, { message: "Invalid phone number " }),
|
||||||
})
|
JobRoleId: z.string().min(1, { message: "Role is required" }),
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@ -140,11 +152,10 @@ const ManageEmployee = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EmployeeRepository.manageEmployee(formDataToSend)
|
EmployeeRepository.manageEmployee(formDataToSend)
|
||||||
.then( ( response ) =>
|
.then((response) => {
|
||||||
{
|
showToast("Employee details updated successfully.", "success");
|
||||||
showToast("Employee details updated successfully.", "success" );
|
clearCacheKey("employeeListByProject");
|
||||||
clearCacheKey("employeeListByProject")
|
clearCacheKey("allEmployeeList");
|
||||||
clearCacheKey( "allEmployeeList" )
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
navigation("/employees");
|
navigation("/employees");
|
||||||
})
|
})
|
||||||
@ -198,10 +209,18 @@ const ManageEmployee = () => {
|
|||||||
{employee ? "Update Employee" : "Create Employee"}
|
{employee ? "Update Employee" : "Create Employee"}
|
||||||
</h6>
|
</h6>
|
||||||
|
|
||||||
<span className="cursor-pointer fs-6" data-htm="true" data-bs-toggle="tooltip"
|
<span
|
||||||
data-bs-offset="0,6"
|
className="cursor-pointer fs-6"
|
||||||
data-bs-placement="top"
|
data-htm="true"
|
||||||
data-bs-html="true" title="Move Back" onClick={()=>navigation("/employees")}><i class='bx bxs-chevron-left'></i> Back</span>
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-offset="0,6"
|
||||||
|
data-bs-placement="top"
|
||||||
|
data-bs-html="true"
|
||||||
|
title="Move Back"
|
||||||
|
onClick={() => navigation("/employees")}
|
||||||
|
>
|
||||||
|
<i className="bx bxs-chevron-left"></i> Back
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
{!currentEmployee && empLoading && (
|
{!currentEmployee && empLoading && (
|
||||||
@ -289,8 +308,6 @@ const ManageEmployee = () => {
|
|||||||
{errors.Email.message}
|
{errors.Email.message}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-6">
|
<div className="col-sm-6">
|
||||||
<div className="form-text text-start">Phone Number</div>
|
<div className="form-text text-start">Phone Number</div>
|
||||||
@ -444,7 +461,9 @@ const ManageEmployee = () => {
|
|||||||
Select Role
|
Select Role
|
||||||
</option>
|
</option>
|
||||||
{job_role?.map((item) => (
|
{job_role?.map((item) => (
|
||||||
<option value={item?.id} key={item.id}>{item?.name} </option>
|
<option value={item?.id} key={item.id}>
|
||||||
|
{item?.name}{" "}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -525,7 +544,14 @@ const ManageEmployee = () => {
|
|||||||
id="PanNumber"
|
id="PanNumber"
|
||||||
placeholder="PAN Number"
|
placeholder="PAN Number"
|
||||||
/>
|
/>
|
||||||
{errors.PanNumber && <div className="danger-text text-start" style={{fontSize:"12px"}}>{errors.PanNumber.message}</div>}
|
{errors.PanNumber && (
|
||||||
|
<div
|
||||||
|
className="danger-text text-start"
|
||||||
|
style={{ fontSize: "12px" }}
|
||||||
|
>
|
||||||
|
{errors.PanNumber.message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React,{useState} from "react";
|
import React, { useState } from "react";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { ProjectStatus } from "../../utils/projectStatus";
|
import { ProjectStatus } from "../../utils/projectStatus";
|
||||||
const AboutProject = ( {data} ) =>
|
const AboutProject = ({ data }) => {
|
||||||
{
|
const [CurrentProject, setCurrentProject] = useState(data);
|
||||||
const [CurrentProject,setCurrentProject] = useState(data)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -24,7 +23,7 @@ const AboutProject = ( {data} ) =>
|
|||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex align-items-center mb-4">
|
<li className="d-flex align-items-center mb-4">
|
||||||
<i class="bx bx-stop-circle"></i>{" "}
|
<i className="bx bx-stop-circle"></i>{" "}
|
||||||
<span className="fw-medium mx-2">End Date:</span>{" "}
|
<span className="fw-medium mx-2">End Date:</span>{" "}
|
||||||
<span>
|
<span>
|
||||||
{data.endDate
|
{data.endDate
|
||||||
@ -33,7 +32,7 @@ const AboutProject = ( {data} ) =>
|
|||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex align-items-center mb-2">
|
<li className="d-flex align-items-center mb-2">
|
||||||
<i class="bx bx-trophy"></i>
|
<i className="bx bx-trophy"></i>
|
||||||
<span className="fw-medium mx-2">Status:</span>{" "}
|
<span className="fw-medium mx-2">Status:</span>{" "}
|
||||||
<span>{ProjectStatus(data.projectStatusId)}</span>
|
<span>{ProjectStatus(data.projectStatusId)}</span>
|
||||||
</li>
|
</li>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState,useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { changeMaster } from "../../slices/localVariablesSlice";
|
import { changeMaster } from "../../slices/localVariablesSlice";
|
||||||
import useMaster from "../../hooks/masterHook/useMaster";
|
import useMaster from "../../hooks/masterHook/useMaster";
|
||||||
@ -6,254 +6,289 @@ import { employee } from "../../data/masters";
|
|||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { getCachedData } from "../../slices/apiDataManager";
|
import { getCachedData } from "../../slices/apiDataManager";
|
||||||
import {useModal} from "../../ModalContext";
|
import { useModal } from "../../ModalContext";
|
||||||
import {useProjects} from "../../hooks/useProjects";
|
import { useProjects } from "../../hooks/useProjects";
|
||||||
import {useEmployeesAllOrByProjectId} from "../../hooks/useEmployees";
|
import { useEmployeesAllOrByProjectId } from "../../hooks/useEmployees";
|
||||||
import {TasksRepository} from "../../repositories/ProjectRepository";
|
import { TasksRepository } from "../../repositories/ProjectRepository";
|
||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
|
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
selectedEmployees: z.array( z.number() ).min( 1, {message: "At least one employee must be selected"} ),
|
selectedEmployees: z
|
||||||
description: z.string().min( 1, {message: "description required"} ),
|
.array(z.number())
|
||||||
|
.min(1, { message: "At least one employee must be selected" }),
|
||||||
})
|
description: z.string().min(1, { message: "description required" }),
|
||||||
|
|
||||||
|
|
||||||
const AssignRoleModel = ( {assignData,onClose}) => {
|
|
||||||
const [ plannedTask, setPlannedTask ] = useState()
|
|
||||||
const { openModal, closeModal } = useModal()
|
|
||||||
const selectedProject = useSelector((store)=>store.localVariables.projectId)
|
|
||||||
const {employees} = useEmployeesAllOrByProjectId( selectedProject )
|
|
||||||
|
|
||||||
const dispatch = useDispatch()
|
|
||||||
const {data,loading} = useMaster()
|
|
||||||
const jobRoleData = getCachedData("Job Role")
|
|
||||||
|
|
||||||
|
|
||||||
const [selectedRole, setSelectedRole] = useState("all");
|
|
||||||
const [selectedEmployees, setSelectedEmployees] = useState([]);
|
|
||||||
|
|
||||||
|
|
||||||
const { handleSubmit, control, setValue, watch, formState: { errors } } = useForm({
|
|
||||||
defaultValues: {
|
|
||||||
selectedEmployees: [],
|
|
||||||
description:""
|
|
||||||
},
|
|
||||||
resolver: (data) => {
|
|
||||||
const validation = schema.safeParse(data);
|
|
||||||
if (validation.success) return { values: data, errors: {} };
|
|
||||||
return { values: {}, errors: validation.error.formErrors.fieldErrors };
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleRoleChange = (event) => {
|
const AssignRoleModel = ({ assignData, onClose }) => {
|
||||||
setSelectedRole(event.plannedTask.value);
|
const [plannedTask, setPlannedTask] = useState();
|
||||||
};
|
const { openModal, closeModal } = useModal();
|
||||||
|
const selectedProject = useSelector(
|
||||||
|
(store) => store.localVariables.projectId
|
||||||
|
);
|
||||||
|
const { employees } = useEmployeesAllOrByProjectId(selectedProject);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const { data, loading } = useMaster();
|
||||||
|
const jobRoleData = getCachedData("Job Role");
|
||||||
|
|
||||||
const filteredEmployees = selectedRole === "all"
|
const [selectedRole, setSelectedRole] = useState("all");
|
||||||
? employees
|
const [selectedEmployees, setSelectedEmployees] = useState([]);
|
||||||
: employees.filter((emp) => emp.JobRoleId.toString() === selectedRole);
|
|
||||||
|
|
||||||
|
const {
|
||||||
// not need currently for this fun
|
handleSubmit,
|
||||||
const handleEmployeeSelection = (employeeId,field) => {
|
control,
|
||||||
|
setValue,
|
||||||
|
watch,
|
||||||
setSelectedEmployees((prevSelected) => {
|
formState: { errors },
|
||||||
let updatedSelection;
|
} = useForm({
|
||||||
if (!prevSelected.includes(employeeId)) {
|
defaultValues: {
|
||||||
updatedSelection = [...prevSelected, employeeId];
|
selectedEmployees: [],
|
||||||
} else {
|
description: "",
|
||||||
updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
},
|
||||||
}
|
resolver: (data) => {
|
||||||
field.onChange(updatedSelection);
|
const validation = schema.safeParse(data);
|
||||||
return updatedSelection;
|
if (validation.success) return { values: data, errors: {} };
|
||||||
|
return { values: {}, errors: validation.error.formErrors.fieldErrors };
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
|
const handleRoleChange = (event) => {
|
||||||
const removeEmployee = (employeeId) => {
|
setSelectedRole(event.plannedTask.value);
|
||||||
setSelectedEmployees((prevSelected) => {
|
|
||||||
const updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
|
||||||
setValue("selectedEmployees", updatedSelection); // Ensure form state is updated
|
|
||||||
return updatedSelection;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const onSubmit = async(data) => {
|
|
||||||
const formattedData = {
|
|
||||||
taskTeam: data.selectedEmployees,
|
|
||||||
plannedTask: parseInt( plannedTask, 10 ),
|
|
||||||
description: data.description,
|
|
||||||
assignmentDate: new Date().toISOString(),
|
|
||||||
workItemId:assignData?.workItem?.workItem.id
|
|
||||||
};
|
};
|
||||||
try
|
|
||||||
{
|
|
||||||
let response = await TasksRepository.assignTask( formattedData );
|
|
||||||
console.log( response )
|
|
||||||
showToast( "Task Successfully Assigend", "success" )
|
|
||||||
closeModal()
|
|
||||||
} catch ( error )
|
|
||||||
{
|
|
||||||
showToast("something wrong","error")
|
|
||||||
|
|
||||||
}
|
const filteredEmployees =
|
||||||
|
selectedRole === "all"
|
||||||
|
? employees
|
||||||
|
: employees.filter((emp) => emp.JobRoleId.toString() === selectedRole);
|
||||||
|
|
||||||
};
|
// not need currently for this fun
|
||||||
useEffect(()=>{
|
const handleEmployeeSelection = (employeeId, field) => {
|
||||||
dispatch(changeMaster("Job Role"))
|
setSelectedEmployees((prevSelected) => {
|
||||||
return ()=> setSelectedRole("all")
|
let updatedSelection;
|
||||||
},[dispatch])
|
if (!prevSelected.includes(employeeId)) {
|
||||||
|
updatedSelection = [...prevSelected, employeeId];
|
||||||
|
} else {
|
||||||
|
updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
||||||
|
}
|
||||||
|
field.onChange(updatedSelection);
|
||||||
|
return updatedSelection;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeEmployee = (employeeId) => {
|
||||||
|
setSelectedEmployees((prevSelected) => {
|
||||||
|
const updatedSelection = prevSelected.filter((id) => id !== employeeId);
|
||||||
|
setValue("selectedEmployees", updatedSelection); // Ensure form state is updated
|
||||||
|
return updatedSelection;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (<>
|
const onSubmit = async (data) => {
|
||||||
|
const formattedData = {
|
||||||
|
taskTeam: data.selectedEmployees,
|
||||||
|
plannedTask: parseInt(plannedTask, 10),
|
||||||
|
description: data.description,
|
||||||
|
assignmentDate: new Date().toISOString(),
|
||||||
|
workItemId: assignData?.workItem?.workItem.id,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
let response = await TasksRepository.assignTask(formattedData);
|
||||||
|
console.log(response);
|
||||||
|
showToast("Task Successfully Assigend", "success");
|
||||||
|
closeModal();
|
||||||
|
} catch (error) {
|
||||||
|
showToast("something wrong", "error");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(changeMaster("Job Role"));
|
||||||
|
return () => setSelectedRole("all");
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
<div className="container my-1">
|
return (
|
||||||
<div className="mb-2">
|
<>
|
||||||
<div className="bs-stepper wizard-numbered d-flex justify-content-center align-items-center flex-wrap">
|
<div className="container my-1">
|
||||||
{[
|
<div className="mb-2">
|
||||||
assignData?.building?.name,
|
<div className="bs-stepper wizard-numbered d-flex justify-content-center align-items-center flex-wrap">
|
||||||
assignData?.floor?.floorName,
|
{[
|
||||||
assignData?.workArea?.areaName,
|
assignData?.building?.name,
|
||||||
assignData?.workItem?.workItem?.activityMaster?.activityName
|
assignData?.floor?.floorName,
|
||||||
].map((item, index, array) => (
|
assignData?.workArea?.areaName,
|
||||||
<div key={index} className="col d-flex justify-content-center align-items-center">
|
assignData?.workItem?.workItem?.activityMaster?.activityName,
|
||||||
<div className="bs-stepper-header p-1 text-center">
|
].map((item, index, array) => (
|
||||||
<span className="fs-5">{item}</span>
|
<div
|
||||||
|
key={index}
|
||||||
{/* Arrow between items */}
|
className="col d-flex justify-content-center align-items-center"
|
||||||
{index < array.length - 1 && (
|
|
||||||
<div className="line">
|
|
||||||
<i className="icon-base bx bx-chevron-right scaleX-n1-rtl"></i>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
|
||||||
<div className="row mb-1">
|
|
||||||
<div className="col-sm-4">
|
|
||||||
<div className="form-text text-start">Select Role</div>
|
|
||||||
<div className="input-group input-group-merge">
|
|
||||||
<select
|
|
||||||
className="form-select form-select-sm"
|
|
||||||
id="Role"
|
|
||||||
value={selectedRole}
|
|
||||||
onChange={handleRoleChange}
|
|
||||||
aria-label=""
|
|
||||||
>
|
>
|
||||||
{loading && data ? "Loading..." : (
|
<div className="bs-stepper-header p-1 text-center">
|
||||||
<>
|
<span className="fs-5">{item}</span>
|
||||||
<option value="all">All</option>
|
|
||||||
{ jobRoleData?.map((item) => (
|
|
||||||
<option key={item.id} value={item.id}>
|
|
||||||
{item.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="divider text-start">
|
|
||||||
<div class="divider-text">Employee</div>
|
|
||||||
</div>
|
|
||||||
{selectedRole !== "" && (
|
|
||||||
<div className="row mb-2">
|
|
||||||
<div className="col-sm-12">
|
|
||||||
<div className="row">
|
|
||||||
{filteredEmployees.map((emp) => {
|
|
||||||
const jobRole = jobRoleData?.find((role) => role.id === emp.jobRoleId);
|
|
||||||
|
|
||||||
return (
|
{/* Arrow between items */}
|
||||||
<div key={emp.id} className="col-6 col-sm-4 col-md-4 col-lg-3 mb-1">
|
{index < array.length - 1 && (
|
||||||
<div className="form-check text-start p-0">
|
<div className="line">
|
||||||
<div className="li-wrapper d-flex justify-content-start align-items-start">
|
<i className="icon-base bx bx-chevron-right scaleX-n1-rtl"></i>
|
||||||
<Controller
|
|
||||||
name="selectedEmployees"
|
|
||||||
control={control}
|
|
||||||
render={({ field }) => (
|
|
||||||
<input
|
|
||||||
{...field}
|
|
||||||
className="form-check-input mx-2"
|
|
||||||
type="checkbox"
|
|
||||||
id={`employee-${emp.id}`}
|
|
||||||
value={emp.id}
|
|
||||||
checked={field.value.includes(emp.id)} // Ensure the checkbox reflects the current form state
|
|
||||||
onChange={() => {
|
|
||||||
handleEmployeeSelection( emp.id, field )
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<div className="list-content">
|
|
||||||
<h6 className="mb-0">{emp.firstName
|
|
||||||
} {emp.lastName}</h6>
|
|
||||||
<small className="text-muted">
|
|
||||||
{loading && (<p className="skeleton para" style={{height:"7px"}}></p>)}
|
|
||||||
{data && !loading && (jobRole ? jobRole.name : 'Unknown Role')}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
)}
|
||||||
})}
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<div className="row mb-1">
|
||||||
|
<div className="col-sm-4">
|
||||||
|
<div className="form-text text-start">Select Role</div>
|
||||||
|
<div className="input-group input-group-merge">
|
||||||
|
<select
|
||||||
|
className="form-select form-select-sm"
|
||||||
|
id="Role"
|
||||||
|
value={selectedRole}
|
||||||
|
onChange={handleRoleChange}
|
||||||
|
aria-label=""
|
||||||
|
>
|
||||||
|
{loading && data ? (
|
||||||
|
"Loading..."
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<option value="all">All</option>
|
||||||
|
{jobRoleData?.map((item) => (
|
||||||
|
<option key={item.id} value={item.id}>
|
||||||
|
{item.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="divider text-start">
|
||||||
)}
|
<div className="divider-text">Employee</div>
|
||||||
|
|
||||||
|
|
||||||
{selectedEmployees.length > 0 && (
|
|
||||||
<div className="mt-1">
|
|
||||||
<div className="text-start px-2">
|
|
||||||
{selectedEmployees.map((empId) => {
|
|
||||||
const emp = employees.find((emp) => emp.id === empId);
|
|
||||||
return (
|
|
||||||
<span key={empId} className="badge bg-label-primary d-inline-flex align-items-center gap-2 me-1 p-2 mb-2">
|
|
||||||
{emp.firstName
|
|
||||||
} {emp.lastName}
|
|
||||||
<p
|
|
||||||
type="button"
|
|
||||||
className=" btn-close-white p-0 m-0"
|
|
||||||
aria-label="Close"
|
|
||||||
onClick={() => {
|
|
||||||
removeEmployee(empId);
|
|
||||||
setValue("selectedEmployees", selectedEmployees.filter(id => id !== empId));
|
|
||||||
}}
|
|
||||||
><i className="icon-base bx bx-x icon-md "></i></p>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{selectedRole !== "" && (
|
||||||
)}
|
<div className="row mb-2">
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<div className="row">
|
||||||
|
{filteredEmployees.map((emp) => {
|
||||||
|
const jobRole = jobRoleData?.find(
|
||||||
|
(role) => role.id === emp.jobRoleId
|
||||||
|
);
|
||||||
|
|
||||||
<div class="col-md text-start mx-0 px-0">
|
return (
|
||||||
<div class="form-check form-check-inline mt-4 px-1">
|
<div
|
||||||
<label className="form-text fs-6" for="inlineCheckbox1">Pending Work</label>
|
key={emp.id}
|
||||||
<label className="form-check-label ms-2" for="inlineCheckbox1">{ assignData?.workItem?.workItem?.plannedWork - assignData?.workItem?.workItem?.completedWork}</label>
|
className="col-6 col-sm-4 col-md-4 col-lg-3 mb-1"
|
||||||
</div>
|
>
|
||||||
<div className="form-check form-check-inline col-sm-2 col">
|
<div className="form-check text-start p-0">
|
||||||
<label for="defaultFormControlInput" className="form-label">Target</label>
|
<div className="li-wrapper d-flex justify-content-start align-items-start">
|
||||||
<input type="text" className="form-control form-control-sm " value={plannedTask} onChange={(e)=>setPlannedTask(e.target.value)} id="defaultFormControlInput" aria-describedby="defaultFormControlHelp" />
|
<Controller
|
||||||
</div>
|
name="selectedEmployees"
|
||||||
</div>
|
control={control}
|
||||||
{errors.selectedEmployees && (
|
render={({ field }) => (
|
||||||
<div className="danger-text mt-1">
|
<input
|
||||||
<p>{errors.selectedEmployees[0]}</p>
|
{...field}
|
||||||
</div>
|
className="form-check-input mx-2"
|
||||||
)}
|
type="checkbox"
|
||||||
|
id={`employee-${emp.id}`}
|
||||||
|
value={emp.id}
|
||||||
|
checked={field.value.includes(emp.id)} // Ensure the checkbox reflects the current form state
|
||||||
|
onChange={() => {
|
||||||
|
handleEmployeeSelection(emp.id, field);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="list-content">
|
||||||
|
<h6 className="mb-0">
|
||||||
|
{emp.firstName} {emp.lastName}
|
||||||
|
</h6>
|
||||||
|
<small className="text-muted">
|
||||||
|
{loading && (
|
||||||
|
<p
|
||||||
|
className="skeleton para"
|
||||||
|
style={{ height: "7px" }}
|
||||||
|
></p>
|
||||||
|
)}
|
||||||
|
{data &&
|
||||||
|
!loading &&
|
||||||
|
(jobRole ? jobRole.name : "Unknown Role")}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<label for="exampleFormControlTextarea1" className="form-label">Description</label>
|
{selectedEmployees.length > 0 && (
|
||||||
|
<div className="mt-1">
|
||||||
|
<div className="text-start px-2">
|
||||||
|
{selectedEmployees.map((empId) => {
|
||||||
|
const emp = employees.find((emp) => emp.id === empId);
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={empId}
|
||||||
|
className="badge bg-label-primary d-inline-flex align-items-center gap-2 me-1 p-2 mb-2"
|
||||||
|
>
|
||||||
|
{emp.firstName} {emp.lastName}
|
||||||
|
<p
|
||||||
|
type="button"
|
||||||
|
className=" btn-close-white p-0 m-0"
|
||||||
|
aria-label="Close"
|
||||||
|
onClick={() => {
|
||||||
|
removeEmployee(empId);
|
||||||
|
setValue(
|
||||||
|
"selectedEmployees",
|
||||||
|
selectedEmployees.filter((id) => id !== empId)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i className="icon-base bx bx-x icon-md "></i>
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="col-md text-start mx-0 px-0">
|
||||||
|
<div className="form-check form-check-inline mt-4 px-1">
|
||||||
|
<label className="form-text fs-6" for="inlineCheckbox1">
|
||||||
|
Pending Work
|
||||||
|
</label>
|
||||||
|
<label className="form-check-label ms-2" for="inlineCheckbox1">
|
||||||
|
{assignData?.workItem?.workItem?.plannedWork -
|
||||||
|
assignData?.workItem?.workItem?.completedWork}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-check form-check-inline col-sm-2 col">
|
||||||
|
<label for="defaultFormControlInput" className="form-label">
|
||||||
|
Target
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control form-control-sm "
|
||||||
|
value={plannedTask}
|
||||||
|
onChange={(e) => setPlannedTask(e.target.value)}
|
||||||
|
id="defaultFormControlInput"
|
||||||
|
aria-describedby="defaultFormControlHelp"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{errors.selectedEmployees && (
|
||||||
|
<div className="danger-text mt-1">
|
||||||
|
<p>{errors.selectedEmployees[0]}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<label for="exampleFormControlTextarea1" className="form-label">
|
||||||
|
Description
|
||||||
|
</label>
|
||||||
<Controller
|
<Controller
|
||||||
name="description"
|
name="description"
|
||||||
control={control}
|
control={control}
|
||||||
@ -265,22 +300,27 @@ useEffect(()=>{
|
|||||||
rows="3"
|
rows="3"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{errors.description && ( <div>{errors.description.message }</div>)}
|
{errors.description && <div>{errors.description.message}</div>}
|
||||||
|
|
||||||
<div className="col-12 d-flex justify-content-center align-items-center gap-sm-6 gap-8 text-center mt-1">
|
<div className="col-12 d-flex justify-content-center align-items-center gap-sm-6 gap-8 text-center mt-1">
|
||||||
<button type="submit" className="btn btn-sm btn-primary ">Submit</button>
|
<button type="submit" className="btn btn-sm btn-primary ">
|
||||||
<button type="reset" className="btn btn-sm btn-label-secondary" data-bs-dismiss="modal" aria-label="Close" onClick={closeModal}>
|
Submit
|
||||||
Cancel
|
</button>
|
||||||
</button>
|
<button
|
||||||
|
type="reset"
|
||||||
|
className="btn btn-sm btn-label-secondary"
|
||||||
|
data-bs-dismiss="modal"
|
||||||
|
aria-label="Close"
|
||||||
|
onClick={closeModal}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default AssignRoleModel
|
export default AssignRoleModel;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState,useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useModal } from "../../../ModalContext";
|
import { useModal } from "../../../ModalContext";
|
||||||
import AssignRoleModel from "../AssignRole";
|
import AssignRoleModel from "../AssignRole";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
@ -6,8 +6,8 @@ import GlobalModel from "../../common/GlobalModel";
|
|||||||
|
|
||||||
const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
|
const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const [ itemName, setItemName ] = useState( "" );
|
const [itemName, setItemName] = useState("");
|
||||||
const [NewWorkItem,setNewWorkItem] = useState()
|
const [NewWorkItem, setNewWorkItem] = useState();
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
|
||||||
const openModal = () => setIsModalOpen(true);
|
const openModal = () => setIsModalOpen(true);
|
||||||
@ -17,7 +17,6 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleAssignTask = () => {
|
const handleAssignTask = () => {
|
||||||
|
|
||||||
setItemName("");
|
setItemName("");
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,8 +28,7 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setNewWorkItem(workItem);
|
||||||
setNewWorkItem(workItem)
|
|
||||||
}, [workItem]); // This hook will run whenever the workItem prop changes
|
}, [workItem]); // This hook will run whenever the workItem prop changes
|
||||||
|
|
||||||
let assigndata = {
|
let assigndata = {
|
||||||
@ -40,7 +38,7 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
|
|||||||
workItem,
|
workItem,
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasWorkItem = NewWorkItem && NewWorkItem
|
const hasWorkItem = NewWorkItem && NewWorkItem;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -57,21 +55,32 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
|
|||||||
<td className="text-start table-cell-small">
|
<td className="text-start table-cell-small">
|
||||||
<i className="bx bx-right-arrow-alt"></i>
|
<i className="bx bx-right-arrow-alt"></i>
|
||||||
<span className="fw-medium">
|
<span className="fw-medium">
|
||||||
{hasWorkItem ? ( NewWorkItem?.workItem?.activityMaster?.activityName || workItem.activityMaster?.activityName ) :"NA"
|
{hasWorkItem
|
||||||
}
|
? NewWorkItem?.workItem?.activityMaster?.activityName ||
|
||||||
|
workItem.activityMaster?.activityName
|
||||||
|
: "NA"}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
{/* for mobile view */}
|
{/* for mobile view */}
|
||||||
<td className="text-center d-sm-none d-sm-table-cell">
|
<td className="text-center d-sm-none d-sm-table-cell">
|
||||||
{hasWorkItem ? (NewWorkItem?.workItem?.completedWork || workItem?.completedWork) :"NA" }/{" "}
|
{hasWorkItem
|
||||||
{ hasWorkItem ? (NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork) : "NA"}
|
? NewWorkItem?.workItem?.completedWork || workItem?.completedWork
|
||||||
|
: "NA"}
|
||||||
|
/{" "}
|
||||||
|
{hasWorkItem
|
||||||
|
? NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork
|
||||||
|
: "NA"}
|
||||||
</td>
|
</td>
|
||||||
{/* for greather than mobile view ************* */}
|
{/* for greather than mobile view ************* */}
|
||||||
<td className="text-center d-none d-md-table-cell">
|
<td className="text-center d-none d-md-table-cell">
|
||||||
{hasWorkItem ? (NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork): "NA"}
|
{hasWorkItem
|
||||||
|
? NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork
|
||||||
|
: "NA"}
|
||||||
</td>
|
</td>
|
||||||
<td className="text-center d-none d-md-table-cell">
|
<td className="text-center d-none d-md-table-cell">
|
||||||
{hasWorkItem ? (NewWorkItem?.workItem?.completedWork || workItem?.completedWork) : "NA"}
|
{hasWorkItem
|
||||||
|
? NewWorkItem?.workItem?.completedWork || workItem?.completedWork
|
||||||
|
: "NA"}
|
||||||
</td>
|
</td>
|
||||||
{/* ************************************************ */}
|
{/* ************************************************ */}
|
||||||
<td className="text-center" style={{ width: "15%" }}>
|
<td className="text-center" style={{ width: "15%" }}>
|
||||||
@ -81,17 +90,23 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
|
|||||||
role="progressbar"
|
role="progressbar"
|
||||||
style={{
|
style={{
|
||||||
width: getProgress(
|
width: getProgress(
|
||||||
(NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork),
|
NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork,
|
||||||
(NewWorkItem?.workItem?.completedWork || workItem?.completedWork)
|
NewWorkItem?.workItem?.completedWork ||
|
||||||
|
workItem?.completedWork
|
||||||
),
|
),
|
||||||
height: "10px",
|
height: "10px",
|
||||||
}}
|
}}
|
||||||
aria-valuenow={
|
aria-valuenow={
|
||||||
hasWorkItem ? (NewWorkItem?.workItem?.completedWork || workItem?.completedWork) : 0
|
hasWorkItem
|
||||||
|
? NewWorkItem?.workItem?.completedWork ||
|
||||||
|
workItem?.completedWork
|
||||||
|
: 0
|
||||||
}
|
}
|
||||||
aria-valuemin="0"
|
aria-valuemin="0"
|
||||||
aria-valuemax={
|
aria-valuemax={
|
||||||
hasWorkItem ? (NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork) : 0
|
hasWorkItem
|
||||||
|
? NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork
|
||||||
|
: 0
|
||||||
}
|
}
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,33 +2,33 @@ import React from "react";
|
|||||||
|
|
||||||
const Loader = () => {
|
const Loader = () => {
|
||||||
return (
|
return (
|
||||||
<div class="demo-inline-spacing">
|
<div className="demo-inline-spacing">
|
||||||
<div class="spinner-grow" role="status">
|
<div className="spinner-grow" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner-grow text-primary" role="status">
|
<div className="spinner-grow text-primary" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner-grow text-secondary" role="status">
|
<div className="spinner-grow text-secondary" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner-grow text-success" role="status">
|
<div className="spinner-grow text-success" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner-grow text-danger" role="status">
|
<div className="spinner-grow text-danger" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner-grow text-warning" role="status">
|
<div className="spinner-grow text-warning" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner-grow text-info" role="status">
|
<div className="spinner-grow text-info" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner-grow text-light" role="status">
|
<div className="spinner-grow text-light" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="spinner-grow text-dark" role="status">
|
<div className="spinner-grow text-dark" role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span className="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -3,18 +3,18 @@ import axios from "axios";
|
|||||||
|
|
||||||
const API_URL = "http://localhost:5000/mastersdata";
|
const API_URL = "http://localhost:5000/mastersdata";
|
||||||
|
|
||||||
|
const DeleteMaster = ({ master, onClose }) => {
|
||||||
const DeleteMaster = ({ master,onClose}) => {
|
|
||||||
const [loader, setLoader] = useState(false);
|
const [loader, setLoader] = useState(false);
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
const handleDelete = () => {
|
const index = mastersdata[master?.masterType]?.findIndex(
|
||||||
const index = mastersdata[master?.masterType]?.findIndex(item => String(item?.id) === String(master?.item?.id));
|
(item) => String(item?.id) === String(master?.item?.id)
|
||||||
console.log(index)
|
);
|
||||||
|
console.log(index);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
mastersdata[master?.masterType].splice(index, 1);
|
mastersdata[master?.masterType].splice(index, 1);
|
||||||
}
|
}
|
||||||
onClose()
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -27,8 +27,8 @@ const DeleteMaster = ({ master,onClose}) => {
|
|||||||
onClick={handleDelete}
|
onClick={handleDelete}
|
||||||
>
|
>
|
||||||
{loader ? (
|
{loader ? (
|
||||||
<div class="spinner-border text-primary" role="status">
|
<div className="spinner-border text-primary" role="status">
|
||||||
<span class="sr-only">Loading...</span>
|
<span className="sr-only">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
"Delete"
|
"Delete"
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { cacheData, getCachedData, getCachedProfileData } from "../../slices/apiDataManager";
|
import {
|
||||||
|
cacheData,
|
||||||
|
getCachedData,
|
||||||
|
getCachedProfileData,
|
||||||
|
} from "../../slices/apiDataManager";
|
||||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||||
import AttendanceLog from "../../components/Activities/AttendcesLogs";
|
import AttendanceLog from "../../components/Activities/AttendcesLogs";
|
||||||
import Attendance from "../../components/Activities/Attendance";
|
import Attendance from "../../components/Activities/Attendance";
|
||||||
@ -10,30 +14,28 @@ import Regularization from "../../components/Activities/Regularization";
|
|||||||
import { useAttendace } from "../../hooks/useAttendance";
|
import { useAttendace } from "../../hooks/useAttendance";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { setProjectId } from "../../slices/localVariablesSlice";
|
import { setProjectId } from "../../slices/localVariablesSlice";
|
||||||
import {markCurrentAttendance} from "../../slices/apiSlice/attendanceAllSlice";
|
import { markCurrentAttendance } from "../../slices/apiSlice/attendanceAllSlice";
|
||||||
import { hasUserPermission } from "../../utils/authUtils";
|
import { hasUserPermission } from "../../utils/authUtils";
|
||||||
import {useHasUserPermission} from "../../hooks/useHasUserPermission";
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
import {REGULARIZE_ATTENDANCE} from "../../utils/constants";
|
import { REGULARIZE_ATTENDANCE } from "../../utils/constants";
|
||||||
|
|
||||||
const AttendancePage = () =>
|
const AttendancePage = () => {
|
||||||
{
|
const loginUser = getCachedProfileData();
|
||||||
const loginUser = getCachedProfileData()
|
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
||||||
var selectedProject = useSelector( ( store ) => store.localVariables.projectId )
|
const { projects, loading: projectLoading } = useProjects();
|
||||||
const {projects,loading:projectLoading} = useProjects()
|
const { attendance, loading: attLoading } = useAttendace(selectedProject);
|
||||||
const {attendance,loading:attLoading} = useAttendace(selectedProject)
|
const [attendances, setAttendances] = useState();
|
||||||
const[attendances,setAttendances] = useState()
|
|
||||||
const [empRoles, setEmpRoles] = useState(null);
|
const [empRoles, setEmpRoles] = useState(null);
|
||||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||||
const [ modelConfig, setModelConfig ] = useState();
|
const [modelConfig, setModelConfig] = useState();
|
||||||
const DoRegularized = useHasUserPermission(REGULARIZE_ATTENDANCE)
|
const DoRegularized = useHasUserPermission(REGULARIZE_ATTENDANCE);
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
time: "",
|
time: "",
|
||||||
description: "",
|
description: "",
|
||||||
date: new Date().toLocaleDateString(),
|
date: new Date().toLocaleDateString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const getRole = (roleId) => {
|
const getRole = (roleId) => {
|
||||||
if (!empRoles) return "Unassigned";
|
if (!empRoles) return "Unassigned";
|
||||||
@ -46,130 +48,142 @@ const AttendancePage = () =>
|
|||||||
setIsCreateModalOpen(true);
|
setIsCreateModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleModalData = (employee) => {
|
||||||
const handleModalData =(employee)=>{
|
|
||||||
setModelConfig(employee);
|
setModelConfig(employee);
|
||||||
}
|
};
|
||||||
|
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
setModelConfig(null);
|
setModelConfig(null);
|
||||||
setIsCreateModalOpen(false);
|
setIsCreateModalOpen(false);
|
||||||
const modalElement = document.getElementById("check-Out-modal");
|
const modalElement = document.getElementById("check-Out-modal");
|
||||||
if (modalElement) {
|
if (modalElement) {
|
||||||
modalElement.classList.remove('show');
|
modalElement.classList.remove("show");
|
||||||
modalElement.style.display = 'none';
|
modalElement.style.display = "none";
|
||||||
document.body.classList.remove('modal-open');
|
document.body.classList.remove("modal-open");
|
||||||
document.querySelector('.modal-backdrop').remove();
|
document.querySelector(".modal-backdrop").remove();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSubmit = (formData) => {
|
||||||
const handleSubmit = ( formData ) =>{
|
dispatch(markCurrentAttendance(formData))
|
||||||
dispatch( markCurrentAttendance( formData ) ).then( ( action ) =>
|
.then((action) => {
|
||||||
{
|
const updatedAttendance = attendances.map((item) =>
|
||||||
const updatedAttendance = attendances.map(item =>
|
item.employeeId === action.payload.employeeId
|
||||||
item.employeeId === action.payload.employeeId
|
? { ...item, ...action.payload }
|
||||||
? { ...item, ...action.payload }
|
: item
|
||||||
: item
|
);
|
||||||
);
|
cacheData("Attendance", {
|
||||||
cacheData("Attendance", { data: updatedAttendance, projectId: selectedProject })
|
data: updatedAttendance,
|
||||||
setAttendances(updatedAttendance)
|
projectId: selectedProject,
|
||||||
showToast("Attedance Marked Successfully","success")
|
});
|
||||||
})
|
setAttendances(updatedAttendance);
|
||||||
.catch( ( error ) =>
|
showToast("Attedance Marked Successfully", "success");
|
||||||
{
|
})
|
||||||
showToast(error.message,"error")
|
.catch((error) => {
|
||||||
});
|
showToast(error.message, "error");
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modelConfig !== null) {
|
if (modelConfig !== null) {
|
||||||
openModel();
|
openModel();
|
||||||
}
|
}
|
||||||
}, [modelConfig,isCreateModalOpen]);
|
}, [modelConfig, isCreateModalOpen]);
|
||||||
useEffect(()=>{
|
useEffect(() => {
|
||||||
setAttendances(attendance)
|
setAttendances(attendance);
|
||||||
},[attendance])
|
}, [attendance]);
|
||||||
useEffect( () =>
|
useEffect(() => {
|
||||||
{
|
dispatch(setProjectId(projects[0]?.id));
|
||||||
dispatch(setProjectId(projects[0]?.id))
|
}, [projects]);
|
||||||
},[projects])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isCreateModalOpen && modelConfig && (
|
{isCreateModalOpen && modelConfig && (
|
||||||
<div
|
<div
|
||||||
className="modal fade show"
|
className="modal fade show"
|
||||||
style={{ display: "block" }}
|
style={{ display: "block" }}
|
||||||
id="check-Out-modal"
|
id="check-Out-modal"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
<AttendanceModel modelConfig={modelConfig} closeModal={closeModal} handleSubmitForm={handleSubmit}/>
|
<AttendanceModel
|
||||||
|
modelConfig={modelConfig}
|
||||||
|
closeModal={closeModal}
|
||||||
|
handleSubmitForm={handleSubmit}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="container-xxl flex-grow-1 container-p-y">
|
<div className="container-xxl flex-grow-1 container-p-y">
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
data={[
|
data={[
|
||||||
{ label: "Home", link: "/dashboard" },
|
{ label: "Home", link: "/dashboard" },
|
||||||
{ label: "Attendance", link: null },
|
{ label: "Attendance", link: null },
|
||||||
]}
|
]}
|
||||||
></Breadcrumb>
|
></Breadcrumb>
|
||||||
<div class="nav-align-top nav-tabs-shadow">
|
<div className="nav-align-top nav-tabs-shadow">
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul className="nav nav-tabs" role="tablist">
|
||||||
<div
|
<div
|
||||||
className="dataTables_length text-start py-2 px-2"
|
className="dataTables_length text-start py-2 px-2"
|
||||||
id="DataTables_Table_0_length"
|
id="DataTables_Table_0_length"
|
||||||
>
|
>
|
||||||
{
|
{loginUser && loginUser?.projects.length > 1 && (
|
||||||
((loginUser && loginUser?.projects.length > 1) ) && (<label>
|
<label>
|
||||||
<select
|
<select
|
||||||
name="DataTables_Table_0_length"
|
name="DataTables_Table_0_length"
|
||||||
aria-controls="DataTables_Table_0"
|
aria-controls="DataTables_Table_0"
|
||||||
className="form-select form-select-sm"
|
className="form-select form-select-sm"
|
||||||
value={selectedProject}
|
value={selectedProject}
|
||||||
onChange={(e)=>dispatch(setProjectId(e.target.value))}
|
onChange={(e) => dispatch(setProjectId(e.target.value))}
|
||||||
aria-label=""
|
aria-label=""
|
||||||
|
>
|
||||||
|
{!projectLoading &&
|
||||||
|
projects
|
||||||
|
?.filter((project) =>
|
||||||
|
loginUser?.projects?.map(Number).includes(project.id)
|
||||||
|
)
|
||||||
|
.map((project) => (
|
||||||
|
<option value={project.id}>{project.name}</option>
|
||||||
|
))}
|
||||||
|
{projectLoading && (
|
||||||
|
<option value="Loading..." disabled>
|
||||||
|
Loading...
|
||||||
|
</option>
|
||||||
|
)}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
<ul className="nav nav-tabs" role="tablist">
|
||||||
|
<li className="nav-item">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="nav-link active"
|
||||||
|
role="tab"
|
||||||
|
data-bs-toggle="tab"
|
||||||
|
data-bs-target="#navs-top-home"
|
||||||
|
aria-controls="navs-top-home"
|
||||||
|
aria-selected="true"
|
||||||
>
|
>
|
||||||
{!projectLoading && projects?.filter(project =>
|
All
|
||||||
loginUser?.projects?.map(Number).includes(project.id)).map((project)=>(
|
</button>
|
||||||
<option value={project.id}>{project.name}</option>
|
</li>
|
||||||
))}
|
<li className="nav-item">
|
||||||
{projectLoading && <option value="Loading..." disabled>Loading...</option> }
|
<button
|
||||||
</select>
|
type="button"
|
||||||
</label>)
|
className="nav-link"
|
||||||
}
|
role="tab"
|
||||||
</div>
|
data-bs-toggle="tab"
|
||||||
</ul>
|
data-bs-target="#navs-top-profile"
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
aria-controls="navs-top-profile"
|
||||||
<li class="nav-item">
|
aria-selected="false"
|
||||||
<button
|
>
|
||||||
type="button"
|
Logs
|
||||||
class="nav-link active"
|
</button>
|
||||||
role="tab"
|
</li>
|
||||||
data-bs-toggle="tab"
|
|
||||||
data-bs-target="#navs-top-home"
|
|
||||||
aria-controls="navs-top-home"
|
|
||||||
aria-selected="true">
|
|
||||||
All
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="nav-link"
|
|
||||||
role="tab"
|
|
||||||
data-bs-toggle="tab"
|
|
||||||
data-bs-target="#navs-top-profile"
|
|
||||||
aria-controls="navs-top-profile"
|
|
||||||
aria-selected="false">
|
|
||||||
Logs
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li className={`nav-item ${!DoRegularized && 'd-none'}`}>
|
<li className={`nav-item ${!DoRegularized && "d-none"}`}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="nav-link "
|
className="nav-link "
|
||||||
@ -177,43 +191,55 @@ const AttendancePage = () =>
|
|||||||
data-bs-toggle="tab"
|
data-bs-toggle="tab"
|
||||||
data-bs-target="#navs-top-messages"
|
data-bs-target="#navs-top-messages"
|
||||||
aria-controls="navs-top-messages"
|
aria-controls="navs-top-messages"
|
||||||
aria-selected="false">
|
aria-selected="false"
|
||||||
|
>
|
||||||
Regularization
|
Regularization
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
</ul>
|
||||||
</ul>
|
<div className="tab-content attedanceTabs py-2">
|
||||||
<div class="tab-content attedanceTabs py-2">
|
{projectLoading && <span>Loading..</span>}
|
||||||
{projectLoading && (<span>Loading..</span>)}
|
{!projectLoading && !attendances && <span>Not Found</span>}
|
||||||
{(!projectLoading && !attendances) && <span>Not Found</span>}
|
{projects && projects.length > 0 && (
|
||||||
{ (projects && projects.length > 0 ) && (
|
<>
|
||||||
<>
|
<div
|
||||||
<div className="tab-pane fade show active py-0" id="navs-top-home" role="tabpanel" key={projects.id}>
|
className="tab-pane fade show active py-0"
|
||||||
|
id="navs-top-home"
|
||||||
<Attendance attendance={attendances} handleModalData={handleModalData} getRole={getRole} />
|
role="tabpanel"
|
||||||
</div>
|
key={projects.id}
|
||||||
<div class="tab-pane fade" id="navs-top-profile" role="tabpanel">
|
>
|
||||||
|
<Attendance
|
||||||
<AttendanceLog
|
attendance={attendances}
|
||||||
attendance={attendances}
|
handleModalData={handleModalData}
|
||||||
handleModalData={handleModalData}
|
getRole={getRole}
|
||||||
projectId={selectedProject}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<div className="tab-pane fade" id="navs-top-messages" role="tabpanel">
|
className="tab-pane fade"
|
||||||
<Regularization
|
id="navs-top-profile"
|
||||||
attendance={attendances}
|
role="tabpanel"
|
||||||
handleRequest ={handleSubmit}
|
>
|
||||||
/>
|
<AttendanceLog
|
||||||
</div>
|
attendance={attendances}
|
||||||
</>
|
handleModalData={handleModalData}
|
||||||
)}
|
projectId={selectedProject}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="tab-pane fade"
|
||||||
|
id="navs-top-messages"
|
||||||
|
role="tabpanel"
|
||||||
|
>
|
||||||
|
<Regularization
|
||||||
|
attendance={attendances}
|
||||||
|
handleRequest={handleSubmit}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -6,10 +6,10 @@ import { useProjects } from "../../hooks/useProjects";
|
|||||||
import { setProjectId } from "../../slices/localVariablesSlice";
|
import { setProjectId } from "../../slices/localVariablesSlice";
|
||||||
import { useProfile } from "../../hooks/useProfile";
|
import { useProfile } from "../../hooks/useProfile";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import {formatDate} from "../../utils/dateUtils";
|
import { formatDate } from "../../utils/dateUtils";
|
||||||
import GlobalModel from "../../components/common/GlobalModel";
|
import GlobalModel from "../../components/common/GlobalModel";
|
||||||
import AssignRoleModel from "../../components/Project/AssignRole";
|
import AssignRoleModel from "../../components/Project/AssignRole";
|
||||||
import {ReportTask} from "../../components/Activities/ReportTask";
|
import { ReportTask } from "../../components/Activities/ReportTask";
|
||||||
import ReportTaskComments from "../../components/Activities/ReportTaskComments";
|
import ReportTaskComments from "../../components/Activities/ReportTaskComments";
|
||||||
|
|
||||||
const DailyTask = () => {
|
const DailyTask = () => {
|
||||||
@ -22,59 +22,63 @@ const DailyTask = () => {
|
|||||||
const selectedProject = useSelector(
|
const selectedProject = useSelector(
|
||||||
(store) => store.localVariables.projectId
|
(store) => store.localVariables.projectId
|
||||||
);
|
);
|
||||||
const dispatch = useDispatch( selectedProject );
|
const dispatch = useDispatch(selectedProject);
|
||||||
const {
|
const {
|
||||||
TaskList,
|
TaskList,
|
||||||
loading: task_loading,
|
loading: task_loading,
|
||||||
error: task_error,
|
error: task_error,
|
||||||
refetch
|
refetch,
|
||||||
} = useTaskList(selectedProject);
|
} = useTaskList(selectedProject);
|
||||||
const [TaskLists, setTaskLists] = useState([]);
|
const [TaskLists, setTaskLists] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTaskLists(TaskList);
|
setTaskLists(TaskList);
|
||||||
}, [ TaskList, selectedProject ] );
|
}, [TaskList, selectedProject]);
|
||||||
|
|
||||||
const [ selectedTask, selectTask ] = useState( null )
|
const [selectedTask, selectTask] = useState(null);
|
||||||
const [comments,setComment] = useState(null)
|
const [comments, setComment] = useState(null);
|
||||||
|
|
||||||
const [ isModalOpen, setIsModalOpen ] = useState( false );
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [ isModalOpenComment, setIsModalOpenComment ] = useState( false )
|
const [isModalOpenComment, setIsModalOpenComment] = useState(false);
|
||||||
|
|
||||||
const openModal = () => setIsModalOpen(true);
|
const openModal = () => setIsModalOpen(true);
|
||||||
const closeModal = () => setIsModalOpen( false );
|
const closeModal = () => setIsModalOpen(false);
|
||||||
|
|
||||||
const openComment = () =>setIsModalOpenComment(true)
|
const openComment = () => setIsModalOpenComment(true);
|
||||||
const closeCommentModal =()=>setIsModalOpenComment(false)
|
const closeCommentModal = () => setIsModalOpenComment(false);
|
||||||
const handletask = (task) =>
|
const handletask = (task) => {
|
||||||
{
|
selectTask(task);
|
||||||
selectTask(task)
|
openModal();
|
||||||
openModal()
|
};
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`modal fade ${isModalOpen ? 'show' : ''}`}
|
className={`modal fade ${isModalOpen ? "show" : ""}`}
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
style={{ display: isModalOpen ? 'block' : 'none' }}
|
style={{ display: isModalOpen ? "block" : "none" }}
|
||||||
aria-hidden={!isModalOpen}
|
aria-hidden={!isModalOpen}
|
||||||
>
|
>
|
||||||
<ReportTask report={selectedTask} closeModal={ closeModal} refetch={refetch} />
|
<ReportTask
|
||||||
|
report={selectedTask}
|
||||||
|
closeModal={closeModal}
|
||||||
|
refetch={refetch}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`modal fade ${isModalOpenComment ? 'show' : ''}`}
|
className={`modal fade ${isModalOpenComment ? "show" : ""}`}
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
style={{ display: isModalOpenComment ? 'block' : 'none' }}
|
style={{ display: isModalOpenComment ? "block" : "none" }}
|
||||||
aria-hidden={!isModalOpenComment}
|
aria-hidden={!isModalOpenComment}
|
||||||
>
|
>
|
||||||
<ReportTaskComments commentsData={comments} closeModal={ closeCommentModal} />
|
<ReportTaskComments
|
||||||
|
commentsData={comments}
|
||||||
|
closeModal={closeCommentModal}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div className="container-xxl flex-grow-1 container-p-y">
|
<div className="container-xxl flex-grow-1 container-p-y">
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
data={[
|
data={[
|
||||||
@ -147,67 +151,75 @@ const DailyTask = () => {
|
|||||||
return (
|
return (
|
||||||
<React.Fragment key={index}>
|
<React.Fragment key={index}>
|
||||||
{/* Main Row */}
|
{/* Main Row */}
|
||||||
<tr >
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div className="d-flex justify-content-center align-items-center" data-bs-toggle="collapse"
|
<div
|
||||||
data-bs-target={`#${accordionId}`}
|
className="d-flex justify-content-center align-items-center"
|
||||||
aria-expanded="false"
|
data-bs-toggle="collapse"
|
||||||
|
data-bs-target={`#${accordionId}`}
|
||||||
|
aria-expanded="false"
|
||||||
aria-controls={accordionId}
|
aria-controls={accordionId}
|
||||||
>
|
>
|
||||||
<div className="d-flex flex-column">
|
<div className="d-flex flex-column">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
className="text-heading text-truncate"
|
className="text-heading text-truncate"
|
||||||
|
|
||||||
>
|
>
|
||||||
<i class='bx bx-chevron-right'></i>
|
<i className="bx bx-chevron-right"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="flex-wrap">
|
<td className="flex-wrap">
|
||||||
{task.workItem.activityMaster.activityName || "No Activity Name"}
|
{task.workItem.activityMaster.activityName ||
|
||||||
|
"No Activity Name"}
|
||||||
</td>
|
</td>
|
||||||
<td>{task.plannedTask || "NA"}</td>
|
<td>{task.plannedTask || "NA"}</td>
|
||||||
<td>{task.completedTask}</td>
|
<td>{task.completedTask}</td>
|
||||||
<td>{formatDate( task.assignmentDate )}</td>
|
<td>{formatDate(task.assignmentDate)}</td>
|
||||||
<td className="text-center">
|
<td className="text-center">
|
||||||
<div class="d-flex align-items-center avatar-group justify-content-center">
|
<div className="d-flex align-items-center avatar-group justify-content-center">
|
||||||
{task.teamMembers.map( ( member ) => (
|
{task.teamMembers.map((member) => (
|
||||||
|
<div
|
||||||
<div key={member.id} data-bs-toggle="tooltip" data-bs-html="true" data-popup="tooltip-custom" data-bs-placement="top" title={`${member.firstName} ${member.lastName}`} className="avatar avatar-xs">
|
key={member.id}
|
||||||
{/* <img src="..." alt="Avatar" class="rounded-circle pull-up" /> */}
|
data-bs-toggle="tooltip"
|
||||||
<span className="avatar-initial rounded-circle bg-label-primary">{member?.firstName.slice(0,1) }</span>
|
data-bs-html="true"
|
||||||
</div>
|
data-popup="tooltip-custom"
|
||||||
))}
|
data-bs-placement="top"
|
||||||
|
title={`${member.firstName} ${member.lastName}`}
|
||||||
|
className="avatar avatar-xs"
|
||||||
|
>
|
||||||
|
{/* <img src="..." alt="Avatar" className="rounded-circle pull-up" /> */}
|
||||||
|
<span className="avatar-initial rounded-circle bg-label-primary">
|
||||||
|
{member?.firstName.slice(0, 1)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="text-center">
|
<td className="text-center">
|
||||||
<div className="d-flex justify-content-center">
|
<div className="d-flex justify-content-center">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-xs btn-primary"
|
className="btn btn-xs btn-primary"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
{
|
selectTask(task);
|
||||||
selectTask( task )
|
openModal();
|
||||||
openModal()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Report
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-xs btn-primary ms-2"
|
|
||||||
onClick={() =>
|
|
||||||
{
|
|
||||||
setComment( task )
|
|
||||||
openComment()
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Comment
|
Report
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-xs btn-primary ms-2"
|
||||||
|
onClick={() => {
|
||||||
|
setComment(task);
|
||||||
|
openComment();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Comment
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ const LoginPage = () => {
|
|||||||
aria-describedby="password"
|
aria-describedby="password"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="input-group-text cursor-pointer"
|
className="input-group-text cursor-pointer"
|
||||||
onClick={() => setHidepass(!hidepass)}
|
onClick={() => setHidepass(!hidepass)}
|
||||||
>
|
>
|
||||||
{hidepass ? (
|
{hidepass ? (
|
||||||
|
@ -118,7 +118,7 @@ const ResetPasswordPage = () => {
|
|||||||
aria-describedby="password"
|
aria-describedby="password"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="input-group-text lcursor-pointer"
|
className="input-group-text lcursor-pointer"
|
||||||
onClick={() => setHidepass(!hidepass)}
|
onClick={() => setHidepass(!hidepass)}
|
||||||
>
|
>
|
||||||
{hidepass ? (
|
{hidepass ? (
|
||||||
@ -129,13 +129,13 @@ const ResetPasswordPage = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{errors.password && (
|
{errors.password && (
|
||||||
<div
|
<div
|
||||||
className="danger-text text-start"
|
className="danger-text text-start"
|
||||||
style={{ fontSize: "12px" }}
|
style={{ fontSize: "12px" }}
|
||||||
>
|
>
|
||||||
{errors.password.message}
|
{errors.password.message}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
{" "}
|
{" "}
|
||||||
<label htmlFor="email" className="form-label">
|
<label htmlFor="email" className="form-label">
|
||||||
@ -144,7 +144,7 @@ const ResetPasswordPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className=" input-group input-group-merge">
|
<div className=" input-group input-group-merge">
|
||||||
<input
|
<input
|
||||||
type={hidepass ? "password" : "text"}
|
type={hidepass ? "password" : "text"}
|
||||||
autoComplete="true"
|
autoComplete="true"
|
||||||
id="password"
|
id="password"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
@ -154,7 +154,7 @@ const ResetPasswordPage = () => {
|
|||||||
aria-describedby="password"
|
aria-describedby="password"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="input-group-text cursor-pointer"
|
className="input-group-text cursor-pointer"
|
||||||
onClick={() => setHidepass(!hidepass)}
|
onClick={() => setHidepass(!hidepass)}
|
||||||
>
|
>
|
||||||
{hidepass ? (
|
{hidepass ? (
|
||||||
@ -165,13 +165,13 @@ const ResetPasswordPage = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{errors.confirmPassword && (
|
{errors.confirmPassword && (
|
||||||
<div
|
<div
|
||||||
className="danger-text text-start"
|
className="danger-text text-start"
|
||||||
style={{ fontSize: "12px" }}
|
style={{ fontSize: "12px" }}
|
||||||
>
|
>
|
||||||
{errors.confirmPassword.message}
|
{errors.confirmPassword.message}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-3 text-start ">
|
<div className="mb-3 text-start ">
|
||||||
|
@ -44,32 +44,40 @@ axiosClient.interceptors.response.use(
|
|||||||
originalRequest._toastShown = true;
|
originalRequest._toastShown = true;
|
||||||
|
|
||||||
if (error.code === "ERR_CONNECTION_REFUSED") {
|
if (error.code === "ERR_CONNECTION_REFUSED") {
|
||||||
console.error("Connection refused. Please ensure the server is running.");
|
console.error(
|
||||||
showToast("Unable to connect to the server. Please try again later.", "error");
|
"Connection refused. Please ensure the server is running."
|
||||||
|
);
|
||||||
|
showToast(
|
||||||
|
"Unable to connect to the server. Please try again later.",
|
||||||
|
"error"
|
||||||
|
);
|
||||||
} else if (error.code === "ERR_NETWORK") {
|
} else if (error.code === "ERR_NETWORK") {
|
||||||
console.error("Network error: Unable to reach the server.");
|
console.error("Network error: Unable to reach the server.");
|
||||||
showToast("Server is unreachable. Try again later!", "error");
|
showToast("Server is unreachable. Try again later!", "error");
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
} else if (error.code === "ECONNABORTED") {
|
} else if (error.code === "ECONNABORTED") {
|
||||||
console.error("Request timed out.");
|
console.error("Request timed out.");
|
||||||
showToast("The request took too long. Please try again later.", "error");
|
showToast(
|
||||||
|
"The request took too long. Please try again later.",
|
||||||
|
"error"
|
||||||
|
);
|
||||||
} else if (error.response) {
|
} else if (error.response) {
|
||||||
showToast(error.response.data.message,"error")
|
showToast(error.response.data.message, "error");
|
||||||
|
|
||||||
if (error.response.status === 401 && !originalRequest._retry) {
|
if (error.response.status === 401 && !originalRequest._retry) {
|
||||||
originalRequest._retry = true;
|
originalRequest._retry = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// debugger;
|
// debugger;
|
||||||
// Get the refresh token from secure storage
|
// Get the refresh token from secure storage
|
||||||
const refreshToken = localStorage.getItem("refreshToken");
|
const refreshToken = localStorage.getItem("refreshToken");
|
||||||
|
|
||||||
if (!refreshToken) {
|
if (!refreshToken) {
|
||||||
// Redirect to login if refresh token is not available
|
// Redirect to login if refresh token is not available
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
// Make a request to refresh the access token
|
// Make a request to refresh the access token
|
||||||
const response = await axiosClient.post("/api/Auth/refresh-token", {
|
const response = await axiosClient.post("/api/Auth/refresh-token", {
|
||||||
token: localStorage.getItem("jwtToken"),
|
token: localStorage.getItem("jwtToken"),
|
||||||
refreshToken,
|
refreshToken,
|
||||||
@ -82,17 +90,19 @@ axiosClient.interceptors.response.use(
|
|||||||
// Retry the original request with the new token
|
// Retry the original request with the new token
|
||||||
originalRequest.headers["Authorization"] = `Bearer ${token}`;
|
originalRequest.headers["Authorization"] = `Bearer ${token}`;
|
||||||
|
|
||||||
// Retry the original request
|
// Retry the original request
|
||||||
return axiosClient(originalRequest);
|
return axiosClient(originalRequest);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Redirect to login if token refresh fails
|
// Redirect to login if token refresh fails
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
{
|
showToast(
|
||||||
|
error.response.data?.message ||
|
||||||
showToast(error.response.data?.message || "An error occurred. Please try again.", "error");
|
"An error occurred. Please try again.",
|
||||||
|
"error"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error("An unknown error occurred:", error.message);
|
console.error("An unknown error occurred:", error.message);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user