Merge branch 'main' of https://git.marcoaiot.com/admin/marco.pms.web into Images_gallery_filter
This commit is contained in:
commit
4f45a805e1
10
index.html
10
index.html
@ -1,11 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" lang="en"
|
<html lang="en" lang="en" class="light-style layout-navbar-fixed layout-menu-fixed layout-compact" dir="ltr"
|
||||||
class="light-style layout-navbar-fixed layout-menu-fixed layout-compact"
|
data-theme="theme-default" data-assets-path="/assets/" data-template="vertical-menu-template" data-style="light">
|
||||||
dir="ltr"
|
|
||||||
data-theme="theme-default"
|
|
||||||
data-assets-path="/assets/"
|
|
||||||
data-template="vertical-menu-template"
|
|
||||||
data-style="light">
|
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
@ -30,6 +25,7 @@
|
|||||||
<!-- Core CSS -->
|
<!-- Core CSS -->
|
||||||
<link rel="stylesheet" href="/assets/vendor/css/core.css" class="template-customizer-core-css" />
|
<link rel="stylesheet" href="/assets/vendor/css/core.css" class="template-customizer-core-css" />
|
||||||
<link rel="stylesheet" href="/assets/vendor/css/theme-default.css" class="template-customizer-theme-css" />
|
<link rel="stylesheet" href="/assets/vendor/css/theme-default.css" class="template-customizer-theme-css" />
|
||||||
|
<link rel="stylesheet" href="/assets/css/core-extend.css" />
|
||||||
<link rel="stylesheet" href="/assets/css/default.css" />
|
<link rel="stylesheet" href="/assets/css/default.css" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />
|
<link rel="stylesheet" href="/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />
|
||||||
|
12
public/assets/css/core-extend.css
Normal file
12
public/assets/css/core-extend.css
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
:root,
|
||||||
|
[data-bs-theme="light"] {
|
||||||
|
--bs-nav-link-font-size: 0.7375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
--bs-nav-link-font-size: 0.7375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
padding: 0.5rem var(--bs-card-cap-padding-x);
|
||||||
|
}
|
@ -1,7 +1,3 @@
|
|||||||
/*
|
|
||||||
* demo.css
|
|
||||||
* File include item demo only specific css only
|
|
||||||
******************************************************************************/
|
|
||||||
#root {
|
#root {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@ -20,21 +16,28 @@
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu .app-brand.demo {
|
.menu .app-brand {
|
||||||
height: 64px;
|
height: 64px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-brand-logo.demo svg {
|
.app-brand-logo svg {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-brand-logo-sidebar {
|
.app-brand-logo-sidebar {
|
||||||
width: 70px;
|
width: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-brand-text.demo {
|
.app-brand-logo-login {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-brand-logo-border {
|
||||||
|
border: 1px solid #d5d5d5;
|
||||||
|
}
|
||||||
|
.app-brand-text {
|
||||||
font-size: 1.75rem;
|
font-size: 1.75rem;
|
||||||
letter-spacing: -0.5px;
|
letter-spacing: -0.5px;
|
||||||
/* text-transform: lowercase; */
|
/* text-transform: lowercase; */
|
||||||
@ -61,39 +64,6 @@
|
|||||||
* Content
|
* Content
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
.demo-blocks > * {
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-inline-spacing > * {
|
|
||||||
margin: 1rem 0.375rem 0 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ? .demo-vertical-spacing class is used to have vertical margins between elements. To remove margin-top from the first-child, use .demo-only-element class with .demo-vertical-spacing class. For example, we have used this class in forms-input-groups.html file. */
|
|
||||||
.demo-vertical-spacing > * {
|
|
||||||
margin-top: 1rem !important;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
.demo-vertical-spacing.demo-only-element > :first-child {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-vertical-spacing-lg > * {
|
|
||||||
margin-top: 1.875rem !important;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
.demo-vertical-spacing-lg.demo-only-element > :first-child {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-vertical-spacing-xl > * {
|
|
||||||
margin-top: 5rem !important;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
.demo-vertical-spacing-xl.demo-only-element > :first-child {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rtl-only {
|
.rtl-only {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
@ -104,30 +74,6 @@
|
|||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Layout demo
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
.layout-demo-wrapper {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-box-direction: normal;
|
|
||||||
-ms-flex-direction: column;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
.layout-demo-placeholder img {
|
|
||||||
width: 900px;
|
|
||||||
}
|
|
||||||
.layout-demo-info {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
.infra-activity-table-header {
|
.infra-activity-table-header {
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
text-transform: capitalize !important;
|
text-transform: capitalize !important;
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 43 KiB |
BIN
public/img/brand/marco1.png
Normal file
BIN
public/img/brand/marco1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@ -1,23 +1,3 @@
|
|||||||
/*
|
|
||||||
* demo.css
|
|
||||||
* File include item demo only specific css only
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
.menu .app-brand.demo {
|
|
||||||
height: 64px;
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-brand-logo.demo svg {
|
|
||||||
width: 22px;
|
|
||||||
height: 38px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-brand-text.demo {
|
|
||||||
font-size: 1.75rem;
|
|
||||||
letter-spacing: -0.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ! For .layout-navbar-fixed added fix padding top to .layout-page */
|
/* ! For .layout-navbar-fixed added fix padding top to .layout-page */
|
||||||
/* Detached navbar */
|
/* Detached navbar */
|
||||||
.layout-navbar-fixed
|
.layout-navbar-fixed
|
||||||
@ -43,43 +23,6 @@
|
|||||||
z-index: auto;
|
z-index: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Content
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
.demo-blocks > * {
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-inline-spacing > * {
|
|
||||||
margin: 1rem 0.375rem 0 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ? .demo-vertical-spacing class is used to have vertical margins between elements. To remove margin-top from the first-child, use .demo-only-element class with .demo-vertical-spacing class. For example, we have used this class in forms-input-groups.html file. */
|
|
||||||
.demo-vertical-spacing > * {
|
|
||||||
margin-top: 1rem !important;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
.demo-vertical-spacing.demo-only-element > :first-child {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-vertical-spacing-lg > * {
|
|
||||||
margin-top: 1.875rem !important;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
.demo-vertical-spacing-lg.demo-only-element > :first-child {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-vertical-spacing-xl > * {
|
|
||||||
margin-top: 5rem !important;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
.demo-vertical-spacing-xl.demo-only-element > :first-child {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rtl-only {
|
.rtl-only {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
@ -89,41 +32,3 @@
|
|||||||
[dir="rtl"] .rtl-only {
|
[dir="rtl"] .rtl-only {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dropdown buttons going out of small screens */
|
|
||||||
@media (max-width: 576px) {
|
|
||||||
#dropdown-variation-demo .btn-group .text-truncate {
|
|
||||||
width: 231px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#dropdown-variation-demo .btn-group .text-truncate::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 45%;
|
|
||||||
right: 0.65rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Layout demo
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
.layout-demo-wrapper {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-box-direction: normal;
|
|
||||||
-ms-flex-direction: column;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
.layout-demo-placeholder img {
|
|
||||||
width: 900px;
|
|
||||||
}
|
|
||||||
.layout-demo-info {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
@ -4,12 +4,15 @@ import { useProjects } from "../../hooks/useProjects";
|
|||||||
import { useDashboard_Data } from "../../hooks/useDashboard_Data";
|
import { useDashboard_Data } from "../../hooks/useDashboard_Data";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
const ProjectProgressChart = () => {
|
const ProjectProgressChart = ({
|
||||||
|
ShowAllProject = true,
|
||||||
|
DefaultRange = "15D",
|
||||||
|
}) => {
|
||||||
const selectedProject = useSelector(
|
const selectedProject = useSelector(
|
||||||
(store) => store.localVariables.projectId
|
(store) => store.localVariables.projectId
|
||||||
);
|
);
|
||||||
const { projects } = useProjects();
|
const { projects } = useProjects();
|
||||||
const [range, setRange] = useState("15D");
|
const [range, setRange] = useState(DefaultRange);
|
||||||
const [showAllEmployees, setShowAllEmployees] = useState(false);
|
const [showAllEmployees, setShowAllEmployees] = useState(false);
|
||||||
|
|
||||||
const getDaysFromRange = (range) => {
|
const getDaysFromRange = (range) => {
|
||||||
@ -69,7 +72,7 @@ const ProjectProgressChart = () => {
|
|||||||
);
|
);
|
||||||
const lineChartCategoriesDates = sortedDashboardData.map((d) =>
|
const lineChartCategoriesDates = sortedDashboardData.map((d) =>
|
||||||
new Date(d.date).toLocaleDateString("en-US", {
|
new Date(d.date).toLocaleDateString("en-US", {
|
||||||
weekday:"short",
|
weekday: "short",
|
||||||
month: "short",
|
month: "short",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
@ -82,7 +85,7 @@ const ProjectProgressChart = () => {
|
|||||||
: selectedProjectData?.name;
|
: selectedProjectData?.name;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card h-100">
|
<div className="card">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="d-flex flex-wrap justify-content-between align-items-start mb-2">
|
<div className="d-flex flex-wrap justify-content-between align-items-start mb-2">
|
||||||
{/* Left: Title */}
|
{/* Left: Title */}
|
||||||
@ -93,22 +96,24 @@ const ProjectProgressChart = () => {
|
|||||||
|
|
||||||
{/* Right: Checkbox and Project Name */}
|
{/* Right: Checkbox and Project Name */}
|
||||||
<div className="d-flex flex-column align-items-start align-items-md-end text-start text-md-end mt-1 mt-md-0">
|
<div className="d-flex flex-column align-items-start align-items-md-end text-start text-md-end mt-1 mt-md-0">
|
||||||
<div className="form-check form-switch mb-1 d-flex align-items-center">
|
{ShowAllProject == true && (
|
||||||
<input
|
<div className="form-check form-switch mb-1 d-flex align-items-center">
|
||||||
className="form-check-input"
|
<input
|
||||||
type="checkbox"
|
className="form-check-input"
|
||||||
role="switch"
|
type="checkbox"
|
||||||
id="showAllEmployees"
|
role="switch"
|
||||||
checked={showAllEmployees}
|
id="showAllEmployees"
|
||||||
onChange={(e) => setShowAllEmployees(e.target.checked)}
|
checked={showAllEmployees}
|
||||||
/>
|
onChange={(e) => setShowAllEmployees(e.target.checked)}
|
||||||
<label
|
/>
|
||||||
className="form-check-label ms-2"
|
<label
|
||||||
htmlFor="showAllEmployees"
|
className="form-check-label ms-2"
|
||||||
>
|
htmlFor="showAllEmployees"
|
||||||
All Projects
|
>
|
||||||
</label>
|
All Projects
|
||||||
</div>
|
</label>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{!showAllEmployees && selectedProjectName && (
|
{!showAllEmployees && selectedProjectName && (
|
||||||
<p className="text-muted mb-0 small">
|
<p className="text-muted mb-0 small">
|
||||||
<span className="card-subtitle">{selectedProjectName}</span>
|
<span className="card-subtitle">{selectedProjectName}</span>
|
||||||
|
@ -19,6 +19,10 @@ const NoteCardDirectory = ({
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
const [isActivProcess, setActiveProcessing] = useState(false);
|
const [isActivProcess, setActiveProcessing] = useState(false);
|
||||||
|
|
||||||
|
// State to manage hover status
|
||||||
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
const handleUpdateNote = async () => {
|
const handleUpdateNote = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -127,6 +131,8 @@ const NoteCardDirectory = ({
|
|||||||
background: `${noteItem.isActive ? "" : "#f8f6f6"}`,
|
background: `${noteItem.isActive ? "" : "#f8f6f6"}`,
|
||||||
}}
|
}}
|
||||||
key={noteItem.id}
|
key={noteItem.id}
|
||||||
|
onMouseEnter={() => setIsHovered(true)} // Set hover state to true on mouse enter
|
||||||
|
onMouseLeave={() => setIsHovered(false)} // Set hover state to false on mouse leave
|
||||||
>
|
>
|
||||||
<div className="d-flex justify-content-between align-items-center mb-1">
|
<div className="d-flex justify-content-between align-items-center mb-1">
|
||||||
<div className="d-flex align-items-center">
|
<div className="d-flex align-items-center">
|
||||||
@ -149,11 +155,15 @@ const NoteCardDirectory = ({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div
|
||||||
|
className={`absolute top-4 right-4 flex space-x-2 transition-opacity duration-300 ${
|
||||||
|
isHovered ? "opacity-100" : "opacity-0"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{noteItem.isActive ? (
|
{noteItem.isActive ? (
|
||||||
<>
|
<>
|
||||||
<i
|
<i
|
||||||
className="bx bxs-edit bx-sm me-1 text-primary cursor-pointer"
|
className="p-2 bg-blue-500 text-white rounded-full shadow-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-75"
|
||||||
onClick={() => setEditing(true)}
|
onClick={() => setEditing(true)}
|
||||||
></i>
|
></i>
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
const LayoutMenu = () => {
|
const LayoutMenu = () => {
|
||||||
return (
|
return (
|
||||||
<aside id="layout-menu" className="layout-menu menu-vertical menu bg-menu-theme">
|
<aside id="layout-menu" className="layout-menu menu-vertical menu bg-menu-theme">
|
||||||
<div className="app-brand demo">
|
<div className="app-brand">
|
||||||
<a href="index.html" className="app-brand-link">
|
<a href="index.html" className="app-brand-link">
|
||||||
<span className="app-brand-logo demo">
|
<span className="app-brand-logo">
|
||||||
<svg
|
<svg
|
||||||
width="25"
|
width="25"
|
||||||
viewBox="0 0 25 42"
|
viewBox="0 0 25 42"
|
||||||
@ -58,7 +58,7 @@ const LayoutMenu = () => {
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<span className="app-brand-text demo menu-text fw-bolder ms-2">Marco</span>
|
<span className="app-brand-text menu-text fw-bolder ms-2">Marco</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="javascript:void(0);" className="layout-menu-toggle menu-link text-large ms-auto d-block d-xl-none">
|
<a href="javascript:void(0);" className="layout-menu-toggle menu-link text-large ms-auto d-block d-xl-none">
|
||||||
|
@ -1,43 +1,31 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link, NavLink, useLocation, useNavigate } from "react-router-dom";
|
import { Link, NavLink, useLocation, useNavigate } from "react-router-dom";
|
||||||
import menuData from "../../data/menuData.json";
|
import menuData from "../../data/menuData.json";
|
||||||
import {getCachedProfileData} from "../../slices/apiDataManager";
|
import { getCachedProfileData } from "../../slices/apiDataManager";
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
// const logineUser = getCachedProfileData()
|
const navigate = useNavigate();
|
||||||
const navigate = useNavigate()
|
|
||||||
// const handleLogout = (e) => {
|
|
||||||
// e.preventDefault();
|
|
||||||
// // logout();
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const handleProfilePage = ()=>{
|
|
||||||
// navigate(`/employee/${profile?.employeeInfo?.id}?for=account`)
|
|
||||||
// }
|
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
id="layout-menu"
|
id="layout-menu"
|
||||||
className="layout-menu menu-vertical menu bg-menu-theme "
|
className="layout-menu menu-vertical menu bg-menu-theme "
|
||||||
>
|
>
|
||||||
<div className="app-brand demo">
|
<div className="app-brand" style={{ paddingLeft: "30px" }}>
|
||||||
<Link to="/dashboard" className="app-brand-link">
|
<Link to="/dashboard" className="app-brand-link">
|
||||||
<span className="app-brand-logo demo">
|
<span className="app-brand-logo rounded-circle app-brand-logo-border">
|
||||||
<img
|
<img
|
||||||
className="app-brand-logo-sidebar"
|
className="app-brand-logo-sidebar"
|
||||||
src="/img/brand/marco.png"
|
src="/img/brand/marco.png"
|
||||||
alt="logo"
|
alt="logo"
|
||||||
aria-label="logo image"
|
aria-label="logo image"
|
||||||
|
style={{ margin: "5px", paddingRight: "5px" }}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span className="app-brand-text demo menu-text fw-bold ms-2">
|
<span className="app-brand-text menu-text fw-bold ms-2">PMS</span>
|
||||||
PMS
|
|
||||||
</span>
|
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<a
|
<a className="layout-menu-toggle menu-link text-large ms-auto">
|
||||||
|
|
||||||
className="layout-menu-toggle menu-link text-large ms-auto"
|
|
||||||
>
|
|
||||||
<i className="bx bx-chevron-left bx-sm d-flex align-items-center justify-content-center"></i>
|
<i className="bx bx-chevron-left bx-sm d-flex align-items-center justify-content-center"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -56,87 +44,6 @@ const Sidebar = () => {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{/* <div className="dropdown py-sm-4 mt-sm-auto ms-auto ms-sm-0 flex-shrink-1 ps-5">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
className="d-flex align-items-center text-decoration-none dropdown-toggle"
|
|
||||||
id="dropdownUser1"
|
|
||||||
data-bs-toggle="dropdown"
|
|
||||||
aria-expanded="false"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="https://github.com/mdo.png"
|
|
||||||
alt="hugenerd"
|
|
||||||
width="28"
|
|
||||||
height="28"
|
|
||||||
className="rounded-circle"
|
|
||||||
/>
|
|
||||||
<span className="d-none d-sm-inline mx-1">{ logineUser?.employeeInfo?.firstName}</span>
|
|
||||||
</a>
|
|
||||||
<ul className="dropdown-menu dropdown-menu-end">
|
|
||||||
<li onClick={handleProfilePage}>
|
|
||||||
<a aria-label="go to profile" className="dropdown-item">
|
|
||||||
<div className="d-flex">
|
|
||||||
<div className="flex-shrink-0 me-3">
|
|
||||||
<div className="avatar avatar-online">
|
|
||||||
<img
|
|
||||||
src="../assets/img/avatars/00.jpg"
|
|
||||||
className="w-px-40 h-auto rounded-circle"
|
|
||||||
alt="avatar-image"
|
|
||||||
aria-label="Avatar Image"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex-grow-1">
|
|
||||||
<span className="fw-medium d-block">{ logineUser?.employeeInfo?.firstName}</span>
|
|
||||||
<small className="text-muted">Admin</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div className="dropdown-divider"></div>
|
|
||||||
</li>
|
|
||||||
<li onClick={handleProfilePage}>
|
|
||||||
<a aria-label="go to profile" className="dropdown-item" >
|
|
||||||
<i className="bx bx-user me-2"></i>
|
|
||||||
<span className="align-middle">My Profile</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a aria-label="go to setting" className="dropdown-item" href="#">
|
|
||||||
<i className="bx bx-cog me-2"></i>
|
|
||||||
<span className="align-middle">Settings</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a aria-label="go to billing" className="dropdown-item" href="#">
|
|
||||||
<span className="d-flex align-items-center align-middle">
|
|
||||||
<i className="flex-shrink-0 bx bx-credit-card me-2"></i>
|
|
||||||
<span className="flex-grow-1 align-middle ms-1">Billing</span>
|
|
||||||
<span className="flex-shrink-0 badge badge-center rounded-pill bg-danger w-px-20 h-px-20">
|
|
||||||
4
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div className="dropdown-divider"></div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
aria-label="click to log out"
|
|
||||||
className="dropdown-item"
|
|
||||||
href="/logout" // Optional: Add this for accessibility, but it won't actually redirect
|
|
||||||
onClick={handleLogout}
|
|
||||||
>
|
|
||||||
<i className="bx bx-power-off me-2"></i>
|
|
||||||
<span className="align-middle">Log Out</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div> */}
|
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,23 +1,96 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { getProjectStatusName } from "../../utils/projectStatus";
|
import { getProjectStatusName } from "../../utils/projectStatus";
|
||||||
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
|
import { MANAGE_PROJECT } from "../../utils/constants";
|
||||||
|
import { cacheData, getCachedData } from "../../slices/apiDataManager";
|
||||||
|
import ManageProjectInfo from "./ManageProjectInfo";
|
||||||
|
|
||||||
const AboutProject = ({ data }) => {
|
const AboutProject = ({ data }) => {
|
||||||
const [CurrentProject, setCurrentProject] = useState(data);
|
const [CurrentProject, setCurrentProject] = useState(data);
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentProject(data);
|
setCurrentProject(data);
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
|
const manageProject = useHasUserPermission(MANAGE_PROJECT);
|
||||||
|
|
||||||
|
const handleShow = () => setShowModal(true);
|
||||||
|
const handleClose = () => setShowModal(false);
|
||||||
|
const handleFormSubmit = (updatedProject, setLoading) => {
|
||||||
|
if (CurrentProject?.id) {
|
||||||
|
ProjectRepository.updateProject(CurrentProject.id, updatedProject)
|
||||||
|
.then((response) => {
|
||||||
|
const updatedProjectData = {
|
||||||
|
...CurrentProject,
|
||||||
|
...response.data,
|
||||||
|
building: CurrentProject.building,
|
||||||
|
};
|
||||||
|
setCurrentProject(updatedProject);
|
||||||
|
|
||||||
|
cacheData(`projectinfo-${CurrentProject.id}`, updatedProjectData);
|
||||||
|
const projects_list = getCachedData("projectslist");
|
||||||
|
if (projects_list) {
|
||||||
|
const updatedProjectsList = projects_list.map((project) =>
|
||||||
|
project.id === CurrentProject.id
|
||||||
|
? {
|
||||||
|
...project,
|
||||||
|
...response.data,
|
||||||
|
// tenant:project.tenant
|
||||||
|
}
|
||||||
|
: project
|
||||||
|
);
|
||||||
|
|
||||||
|
cacheData("projectslist", updatedProjectsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast("Project updated successfully.", "success");
|
||||||
|
setLoading(false);
|
||||||
|
setShowModal(false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
showToast(error.message, "error");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div
|
||||||
|
className={`modal fade ${showModal ? "show" : ""}`}
|
||||||
|
tabIndex="-1"
|
||||||
|
role="dialog"
|
||||||
|
style={{ display: showModal ? "block" : "none" }}
|
||||||
|
aria-hidden={!showModal}
|
||||||
|
>
|
||||||
|
<ManageProjectInfo
|
||||||
|
project={CurrentProject}
|
||||||
|
handleSubmitForm={handleFormSubmit}
|
||||||
|
onClose={handleClose}
|
||||||
|
></ManageProjectInfo>
|
||||||
|
</div>
|
||||||
{data && (
|
{data && (
|
||||||
<div className="card mb-6">
|
<div className="card mb-6">
|
||||||
|
<div class="card-header text-start">
|
||||||
|
<h6 class="card-action-title mb-0">
|
||||||
|
{" "}
|
||||||
|
<i className="fa fa-building rounded-circle text-primary"></i>
|
||||||
|
<span className="ms-2">Project Profile</span>
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<small className="card-text text-uppercase text-muted small">
|
<ul className="list-unstyled my-3 ps-2">
|
||||||
Profile
|
<li className="d-flex align-items-center mb-3">
|
||||||
</small>
|
<i className="bx bx-cog"></i>
|
||||||
<ul className="list-unstyled my-3">
|
<span className="fw-medium mx-2">Name:</span>{" "}
|
||||||
<li className="d-flex align-items-center mb-4">
|
<span>{data.name}</span>
|
||||||
|
</li>
|
||||||
|
<li className="d-flex align-items-center mb-3">
|
||||||
|
<i className="bx bx-fingerprint"></i>
|
||||||
|
<span className="fw-medium mx-2">Nick Name:</span>{" "}
|
||||||
|
<span> {data.shortName} </span>
|
||||||
|
</li>
|
||||||
|
<li className="d-flex align-items-center mb-3">
|
||||||
<i className="bx bx-check"></i>
|
<i className="bx bx-check"></i>
|
||||||
<span className="fw-medium mx-2">Start Date:</span>{" "}
|
<span className="fw-medium mx-2">Start Date:</span>{" "}
|
||||||
<span>
|
<span>
|
||||||
@ -26,7 +99,7 @@ const AboutProject = ({ data }) => {
|
|||||||
: "N/A"}
|
: "N/A"}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex align-items-center mb-4">
|
<li className="d-flex align-items-center mb-3">
|
||||||
<i className="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>
|
||||||
@ -35,17 +108,17 @@ const AboutProject = ({ data }) => {
|
|||||||
: "N/A"}
|
: "N/A"}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex align-items-center mb-2">
|
<li className="d-flex align-items-center mb-3">
|
||||||
<i className="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>{getProjectStatusName(data.projectStatusId)}</span>
|
<span>{getProjectStatusName(data.projectStatusId)}</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex align-items-center mb-4">
|
<li className="d-flex align-items-center mb-3">
|
||||||
<i className="bx bx-user"></i>
|
<i className="bx bx-user"></i>
|
||||||
<span className="fw-medium mx-2">Contact:</span>{" "}
|
<span className="fw-medium mx-2">Contact:</span>{" "}
|
||||||
<span>{data.contactPerson}</span>
|
<span>{data.contactPerson}</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex flex-column align-items-start mb-4">
|
<li className="d-flex flex-column align-items-start mb-3">
|
||||||
<div className="d-flex align-items-center">
|
<div className="d-flex align-items-center">
|
||||||
<i className="bx bx-flag"></i>
|
<i className="bx bx-flag"></i>
|
||||||
<span className="fw-medium mx-2">Address:</span>
|
<span className="fw-medium mx-2">Address:</span>
|
||||||
@ -57,6 +130,22 @@ const AboutProject = ({ data }) => {
|
|||||||
<div className="ms-4 text-start">{data.projectAddress}</div>
|
<div className="ms-4 text-start">{data.projectAddress}</div>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li className="d-flex justify-content-center mb-3">
|
||||||
|
{manageProject && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`btn btn-sm btn-primary ${
|
||||||
|
!manageProject && "d-none"
|
||||||
|
}`}
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#edit-project-modal"
|
||||||
|
onClick={handleShow}
|
||||||
|
>
|
||||||
|
Modify Details
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,6 +4,18 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
// const currentDate = new Date().toISOString().split("T")[0];
|
// const currentDate = new Date().toISOString().split("T")[0];
|
||||||
|
|
||||||
|
const ACTIVE_STATUS_ID = "b74da4c2-d07e-46f2-9919-e75e49b12731";
|
||||||
|
|
||||||
|
const DEFAULT_EMPTY_STATUS_ID = "00000000-0000-0000-0000-000000000000";
|
||||||
|
/**
|
||||||
|
|
||||||
|
* Formats a given date string into 'YYYY-MM-DD' format.
|
||||||
|
* If the date is invalid or not provided, it defaults to the current date.
|
||||||
|
* @param {string} date - The date string to format.
|
||||||
|
* @returns {string} The formatted date string.
|
||||||
|
*/
|
||||||
|
|
||||||
const currentDate = new Date().toLocaleDateString('en-CA');
|
const currentDate = new Date().toLocaleDateString('en-CA');
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
if (!date) {
|
if (!date) {
|
||||||
@ -29,7 +41,7 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
|
|||||||
shortName: z.string().optional(),
|
shortName: z.string().optional(),
|
||||||
contactPerson: z
|
contactPerson: z
|
||||||
.string()
|
.string()
|
||||||
.min( 1, {message: "Contact Person Name is required"} )
|
.min(1, { message: "Contact Person Name is required" })
|
||||||
.regex(/^[A-Za-z\s]+$/, {
|
.regex(/^[A-Za-z\s]+$/, {
|
||||||
message: "Contact Person must contain only letters",
|
message: "Contact Person must contain only letters",
|
||||||
}),
|
}),
|
||||||
@ -53,7 +65,7 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
|
|||||||
(data) => {
|
(data) => {
|
||||||
const start = new Date(data.startDate);
|
const start = new Date(data.startDate);
|
||||||
const end = new Date(data.endDate);
|
const end = new Date(data.endDate);
|
||||||
return end > start;
|
return end >= start;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ["endDate"], // attaches the error to the endDate field
|
path: ["endDate"], // attaches the error to the endDate field
|
||||||
@ -78,7 +90,12 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
|
|||||||
projectAddress: project?.projectAddress || "",
|
projectAddress: project?.projectAddress || "",
|
||||||
startDate: formatDate(project?.startDate) || currentDate,
|
startDate: formatDate(project?.startDate) || currentDate,
|
||||||
endDate: formatDate(project?.endDate) || currentDate,
|
endDate: formatDate(project?.endDate) || currentDate,
|
||||||
projectStatusId: String(project?.projectStatusId || "00000000-0000-0000-0000-000000000000"),
|
// projectStatusId: String(project?.projectStatusId || "00000000-0000-0000-0000-000000000000"),
|
||||||
|
projectStatusId: project?.projectStatusId && project.projectStatusId !== DEFAULT_EMPTY_STATUS_ID
|
||||||
|
|
||||||
|
? String(project.projectStatusId)
|
||||||
|
|
||||||
|
: ACTIVE_STATUS_ID,
|
||||||
},
|
},
|
||||||
mode: "onChange",
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
@ -88,24 +105,35 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
|
|||||||
reset(
|
reset(
|
||||||
project
|
project
|
||||||
? {
|
? {
|
||||||
id: project?.id || "",
|
id: project?.id || "",
|
||||||
name: project?.name || "",
|
name: project?.name || "",
|
||||||
shortName: project?.shortName || "",
|
shortName: project?.shortName || "",
|
||||||
contactPerson: project?.contactPerson || "",
|
contactPerson: project?.contactPerson || "",
|
||||||
projectAddress: project?.projectAddress || "",
|
projectAddress: project?.projectAddress || "",
|
||||||
startDate: formatDate(project?.startDate) || "",
|
startDate: formatDate(project?.startDate) || "",
|
||||||
endDate: formatDate(project?.endDate) || "",
|
endDate: formatDate(project?.endDate) || "",
|
||||||
projectStatusId: String(project.projectStatusId) || "00000000-0000-0000-0000-000000000000",
|
// projectStatusId: String(project.projectStatusId) || "00000000-0000-0000-0000-000000000000",
|
||||||
}
|
projectStatusId: project?.projectStatusId && project.projectStatusId !== DEFAULT_EMPTY_STATUS_ID
|
||||||
|
? String(project.projectStatusId)
|
||||||
|
: ACTIVE_STATUS_ID,
|
||||||
|
}
|
||||||
: {}
|
: {}
|
||||||
);
|
);
|
||||||
setAddressLength(project?.projectAddress?.length || 0);
|
setAddressLength(project?.projectAddress?.length || 0);
|
||||||
}, [project, reset]);
|
}, [project, reset]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
* Handles the form submission.
|
||||||
|
|
||||||
|
* @param {object} updatedProject - The project data from the form.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
const onSubmitForm = (updatedProject) => {
|
const onSubmitForm = (updatedProject) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
handleSubmitForm( updatedProject, setLoading,reset );
|
handleSubmitForm(updatedProject, setLoading, reset);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
reset({
|
reset({
|
||||||
@ -116,7 +144,10 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
|
|||||||
projectAddress: project?.projectAddress || "",
|
projectAddress: project?.projectAddress || "",
|
||||||
startDate: formatDate(project?.startDate) || currentDate,
|
startDate: formatDate(project?.startDate) || currentDate,
|
||||||
endDate: formatDate(project?.endDate) || currentDate,
|
endDate: formatDate(project?.endDate) || currentDate,
|
||||||
projectStatusId: String(project?.projectStatusId || "00000000-0000-0000-0000-000000000000"),
|
// projectStatusId: String(project?.projectStatusId || "00000000-0000-0000-0000-000000000000"),
|
||||||
|
projectStatusId: project?.projectStatusId && project.projectStatusId !== DEFAULT_EMPTY_STATUS_ID
|
||||||
|
? String(project.projectStatusId)
|
||||||
|
: ACTIVE_STATUS_ID,
|
||||||
});
|
});
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
@ -259,8 +290,9 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
|
|||||||
valueAsNumber: false,
|
valueAsNumber: false,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<option disabled>Status</option>
|
{/* <option disabled>Status</option>
|
||||||
<option value="b74da4c2-d07e-46f2-9919-e75e49b12731">Active</option>
|
<option value="b74da4c2-d07e-46f2-9919-e75e49b12731">Active</option> */}
|
||||||
|
<option value={ACTIVE_STATUS_ID}>Active</option>
|
||||||
<option value="603e994b-a27f-4e5d-a251-f3d69b0498ba">On Hold</option>
|
<option value="603e994b-a27f-4e5d-a251-f3d69b0498ba">On Hold</option>
|
||||||
|
|
||||||
<option value="cdad86aa-8a56-4ff4-b633-9c629057dfef">In Progress</option>
|
<option value="cdad86aa-8a56-4ff4-b633-9c629057dfef">In Progress</option>
|
||||||
@ -326,4 +358,4 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ManageProjectInfo;
|
export default ManageProjectInfo;
|
@ -1,33 +1,124 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {useEmployeesByProjectAllocated, useProjects} from "../../hooks/useProjects";
|
import {
|
||||||
|
useEmployeesByProjectAllocated,
|
||||||
|
useProjects,
|
||||||
|
} from "../../hooks/useProjects";
|
||||||
|
|
||||||
|
const ProjectOverview = ({ project }) => {
|
||||||
|
const { projects } = useProjects();
|
||||||
|
const getProgress = (planned, completed) => {
|
||||||
|
return (completed * 100) / planned + "%";
|
||||||
|
};
|
||||||
|
const getProgressInNumber = (planned, completed) => {
|
||||||
|
var number = (completed * 100) / planned;
|
||||||
|
return FormattedNumber(number);
|
||||||
|
};
|
||||||
|
|
||||||
|
const project_detail = projects.find((pro) => pro.id == project);
|
||||||
|
|
||||||
|
// Utility function to check if a number has a decimal part
|
||||||
|
const hasDecimal = (num) => {
|
||||||
|
// Convert to string and check for a decimal point
|
||||||
|
// Or, check if the number is not equal to its integer part
|
||||||
|
return num % 1 !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// FormattedNumber component to display numbers with conditional decimal places
|
||||||
|
function FormattedNumber(value, locale = "en-US") {
|
||||||
|
// Ensure the value is a number
|
||||||
|
const numericValue = parseFloat(value);
|
||||||
|
|
||||||
|
// Handle non-numeric values gracefully
|
||||||
|
if (isNaN(numericValue)) {
|
||||||
|
return <span>Invalid Number</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let options = {};
|
||||||
|
|
||||||
|
// Determine formatting options based on whether the number has a decimal part
|
||||||
|
if (hasDecimal(numericValue)) {
|
||||||
|
// If it has a decimal, format to exactly two decimal places
|
||||||
|
options = {
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// If it's a whole number, format to zero decimal places
|
||||||
|
options = {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Intl.NumberFormat for robust and locale-aware formatting
|
||||||
|
const formattedString = new Intl.NumberFormat(locale, options).format(
|
||||||
|
numericValue
|
||||||
|
);
|
||||||
|
|
||||||
|
return formattedString;
|
||||||
|
}
|
||||||
|
|
||||||
const ProjectOverview = ({project}) =>
|
|
||||||
{
|
|
||||||
const {projects} = useProjects()
|
|
||||||
const project_detail = projects.find( ( pro ) => pro.id == project )
|
|
||||||
return (
|
return (
|
||||||
<div className="card mb-6">
|
<div className="card mb-6">
|
||||||
|
<div className="card-header text-start">
|
||||||
|
<h6 className="card-action-title mb-0">
|
||||||
|
{" "}
|
||||||
|
<i className="fa fa-line-chart rounded-circle text-primary"></i>
|
||||||
|
<span className="ms-2">Project Statistics</span>
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<small className="card-text text-uppercase text-muted small">
|
|
||||||
Overview
|
|
||||||
</small>
|
|
||||||
<ul className="list-unstyled mb-0 mt-3 pt-1">
|
<ul className="list-unstyled mb-0 mt-3 pt-1">
|
||||||
<li className="d-flex align-items-center mb-4">
|
<li className="d-flex align-items-center mb-3">
|
||||||
<i className="bx bx-check"></i>
|
<i className="bx bx-check"></i>
|
||||||
<span className="fw-medium mx-2">Task Planned:</span>{" "}
|
<span className="fw-medium mx-2">Task Planned:</span>{" "}
|
||||||
<span>{project_detail?.plannedWork
|
<span>{project_detail?.plannedWork}</span>
|
||||||
}</span>
|
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex align-items-center mb-4">
|
<li className="d-flex align-items-center mb-3">
|
||||||
<i className="bx bx-star"></i>
|
<i className="bx bx-star"></i>
|
||||||
<span className="fw-medium mx-2">Task Completed:</span>{" "}
|
<span className="fw-medium mx-2">Task Completed:</span>{" "}
|
||||||
<span>{project_detail?.completedWork }</span>
|
<span>{project_detail?.completedWork}</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="d-flex align-items-center">
|
<li className="d-flex align-items-center mb-3">
|
||||||
<i className="bx bx-user"></i>
|
<i className="bx bx-user"></i>
|
||||||
<span className="fw-medium mx-2">Current team Size:</span>{" "}
|
<span className="fw-medium mx-2">Current team Size:</span>{" "}
|
||||||
<span>{project_detail?.teamSize}</span>
|
<span>{project_detail?.teamSize}</span>
|
||||||
</li>
|
</li>
|
||||||
|
<li className=" mb-3">
|
||||||
|
{project_detail && (
|
||||||
|
<>
|
||||||
|
<div className="d-flex text-end mb-2 mt-5">
|
||||||
|
<small className="text-body text-muted ">
|
||||||
|
{Math.floor(
|
||||||
|
getProgressInNumber(
|
||||||
|
project_detail.plannedWork,
|
||||||
|
project_detail.completedWork
|
||||||
|
)
|
||||||
|
) || 0}{" "}
|
||||||
|
% Completed
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="progress mb-4 rounded"
|
||||||
|
style={{ height: "8px" }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="progress-bar rounded"
|
||||||
|
role="progressbar"
|
||||||
|
style={{
|
||||||
|
width: getProgress(
|
||||||
|
project_detail.plannedWork,
|
||||||
|
project_detail.completedWork
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
aria-valuenow={project_detail.completedWork}
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax={project_detail.plannedWork}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,37 +2,40 @@ import React, { useEffect, useRef } from "react";
|
|||||||
|
|
||||||
const DateRangePicker = ({
|
const DateRangePicker = ({
|
||||||
onRangeChange,
|
onRangeChange,
|
||||||
DateDifference = 7,
|
DateDifference = 7,
|
||||||
endDateMode = "yesterday", // "today" or "yesterday"
|
endDateMode = "yesterday",
|
||||||
}) => {
|
}) => {
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const endDate = new Date();
|
const endDate = new Date();
|
||||||
if (endDateMode === "yesterday") {
|
if (endDateMode === "yesterday") {
|
||||||
endDate.setDate(endDate.getDate() - 1);
|
endDate.setDate(endDate.getDate() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const startDate = new Date();
|
endDate.setHours(0, 0, 0, 0);
|
||||||
startDate.setDate(endDate.getDate() - DateDifference);
|
|
||||||
|
const startDate = new Date(endDate);
|
||||||
|
startDate.setDate(endDate.getDate() - (DateDifference - 1));
|
||||||
|
startDate.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
const fp = flatpickr(inputRef.current, {
|
const fp = flatpickr(inputRef.current, {
|
||||||
mode: "range",
|
mode: "range",
|
||||||
dateFormat: "Y-m-d",
|
dateFormat: "Y-m-d",
|
||||||
altInput: true,
|
altInput: true,
|
||||||
altFormat: "d-m-Y",
|
altFormat: "d-m-Y",
|
||||||
defaultDate: [startDate, endDate],
|
defaultDate: [startDate, endDate],
|
||||||
static: true,
|
static: true,
|
||||||
clickOpens: true,
|
clickOpens: true,
|
||||||
onChange: (selectedDates, dateStr) => {
|
onChange: (selectedDates, dateStr) => {
|
||||||
const [startDate, endDate] = dateStr.split(" to ");
|
const [startDateString, endDateString] = dateStr.split(" to ");
|
||||||
onRangeChange?.({ startDate, endDate });
|
onRangeChange?.({ startDate: startDateString, endDate: endDateString });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
onRangeChange?.({
|
onRangeChange?.({
|
||||||
startDate: startDate.toLocaleDateString("en-CA"),
|
startDate: startDate.toLocaleDateString("en-CA"),
|
||||||
endDate: endDate.toLocaleDateString("en-CA"),
|
endDate: endDate.toLocaleDateString("en-CA"),
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -306,7 +306,7 @@ const DirectoryPageHeader = ({
|
|||||||
)}
|
)}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div className="dropdown-menu p-0" style={{ minWidth: "700px" }}>
|
<div className="dropdown-menu p-0" style={{ minWidth: "550px" }}>
|
||||||
{/* Scrollable Filter Content */}
|
{/* Scrollable Filter Content */}
|
||||||
<div
|
<div
|
||||||
className="p-3"
|
className="p-3"
|
||||||
@ -319,18 +319,19 @@ const DirectoryPageHeader = ({
|
|||||||
>
|
>
|
||||||
<div className="d-flex gap-3">
|
<div className="d-flex gap-3">
|
||||||
{/* Created By */}
|
{/* Created By */}
|
||||||
<div style={{ flex: 0.50, maxHeight: "260px", overflowY: "auto" }}>
|
<div style={{ flexBasis: "30%", maxHeight: "260px", overflowY: "auto" }}>
|
||||||
<div style={{ position: "sticky", top: 0, background: "#fff", zIndex: 1 }}>
|
<div style={{ position: "sticky", top: 0, background: "#fff", zIndex: 1 }}>
|
||||||
<p className="text-muted mb-2 pt-2">Created By</p>
|
<p className="text-muted mb-2 pt-2">Created By</p>
|
||||||
</div>
|
</div>
|
||||||
{allCreators.map((name, idx) => (
|
{allCreators.map((name, idx) => (
|
||||||
<div className="form-check mb-1" key={`creator-${idx}`}>
|
<div className="form-check mb-1" key={`creator-${idx}`}>
|
||||||
<input
|
<input
|
||||||
className="form-check-input"
|
className="form-check-input form-check-input-sm"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={`creator-${idx}`}
|
id={`creator-${idx}`}
|
||||||
checked={selectedCreators.includes(name)}
|
checked={selectedCreators.includes(name)}
|
||||||
onChange={() => handleToggleCreator(name)}
|
onChange={() => handleToggleCreator(name)}
|
||||||
|
style={{ width: "1rem", height: "1rem" }}
|
||||||
/>
|
/>
|
||||||
<label className="form-check-label text-nowrap" htmlFor={`creator-${idx}`}>
|
<label className="form-check-label text-nowrap" htmlFor={`creator-${idx}`}>
|
||||||
{name}
|
{name}
|
||||||
@ -340,18 +341,19 @@ const DirectoryPageHeader = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Organization */}
|
{/* Organization */}
|
||||||
<div style={{ flex: 1, maxHeight: "260px", overflowY: "auto",overflowX: "hidden", }}>
|
<div style={{ maxHeight: "260px", overflowY: "auto",overflowX: "hidden", }}>
|
||||||
<div style={{ position: "sticky", top: 0, background: "#fff", zIndex: 1 }}>
|
<div style={{ position: "sticky", top: 0, background: "#fff", zIndex: 1 }}>
|
||||||
<p className="text-muted mb-2 pt-2">Organization</p>
|
<p className="text-muted mb-2 pt-2">Organization</p>
|
||||||
</div>
|
</div>
|
||||||
{filteredOrganizations.map((org, idx) => (
|
{filteredOrganizations.map((org, idx) => (
|
||||||
<div className="form-check mb-1" key={`org-${idx}`}>
|
<div className="form-check mb-1" key={`org-${idx}`}>
|
||||||
<input
|
<input
|
||||||
className="form-check-input"
|
className="form-check-input form-check-input-sm"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={`org-${idx}`}
|
id={`org-${idx}`}
|
||||||
checked={selectedOrgs.includes(org)}
|
checked={selectedOrgs.includes(org)}
|
||||||
onChange={() => handleToggleOrg(org)}
|
onChange={() => handleToggleOrg(org)}
|
||||||
|
style={{ width: "1rem", height: "1rem" }}
|
||||||
/>
|
/>
|
||||||
<label className="form-check-label text-nowrap" htmlFor={`org-${idx}`}>
|
<label className="form-check-label text-nowrap" htmlFor={`org-${idx}`}>
|
||||||
{org}
|
{org}
|
||||||
@ -444,11 +446,12 @@ const DirectoryPageHeader = ({
|
|||||||
{filteredBuckets.map(({ id, name }) => (
|
{filteredBuckets.map(({ id, name }) => (
|
||||||
<div className="form-check me-3 mb-1" style={{ minWidth: "calc(50% - 15px)" }} key={id}>
|
<div className="form-check me-3 mb-1" style={{ minWidth: "calc(50% - 15px)" }} key={id}>
|
||||||
<input
|
<input
|
||||||
className="form-check-input"
|
className="form-check-input form-check-input-sm"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={`bucket-${id}`}
|
id={`bucket-${id}`}
|
||||||
checked={tempSelectedBucketIds.includes(id)}
|
checked={tempSelectedBucketIds.includes(id)}
|
||||||
onChange={() => handleTempBucketChange(id)}
|
onChange={() => handleTempBucketChange(id)}
|
||||||
|
style={{ width: "1rem", height: "1rem" }}
|
||||||
/>
|
/>
|
||||||
<label className="form-check-label text-nowrap text-small" htmlFor={`bucket-${id}`}>
|
<label className="form-check-label text-nowrap text-small" htmlFor={`bucket-${id}`}>
|
||||||
{name}
|
{name}
|
||||||
@ -463,11 +466,12 @@ const DirectoryPageHeader = ({
|
|||||||
{filteredCategories.map(({ id, name }) => (
|
{filteredCategories.map(({ id, name }) => (
|
||||||
<div className="form-check me-3 mb-1" style={{ minWidth: "calc(50% - 15px)" }} key={id}>
|
<div className="form-check me-3 mb-1" style={{ minWidth: "calc(50% - 15px)" }} key={id}>
|
||||||
<input
|
<input
|
||||||
className="form-check-input"
|
className="form-check-input form-check-input-sm"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={`cat-${id}`}
|
id={`cat-${id}`}
|
||||||
checked={tempSelectedCategoryIds.includes(id)}
|
checked={tempSelectedCategoryIds.includes(id)}
|
||||||
onChange={() => handleTempCategoryChange(id)}
|
onChange={() => handleTempCategoryChange(id)}
|
||||||
|
style={{ width: "1rem", height: "1rem" }}
|
||||||
/>
|
/>
|
||||||
<label className="form-check-label text-nowrap text-small" htmlFor={`cat-${id}`}>
|
<label className="form-check-label text-nowrap text-small" htmlFor={`cat-${id}`}>
|
||||||
{name}
|
{name}
|
||||||
|
@ -14,8 +14,12 @@ export const AuthWrapper = ({ children }) => {
|
|||||||
to="/"
|
to="/"
|
||||||
className="app-brand-link gap-2"
|
className="app-brand-link gap-2"
|
||||||
>
|
>
|
||||||
<span className="app-brand-logo demo">
|
<span className="app-brand-logo rounded-circle ">
|
||||||
<img src="/img/brand/marco.png" alt="marco-logo" />
|
<img
|
||||||
|
src="/img/brand/marco.png"
|
||||||
|
alt="marco-logo"
|
||||||
|
className="app-brand-logo-login"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
@ -52,7 +52,6 @@ const ChangePasswordPage = ({ onClose }) => {
|
|||||||
oldPassword: data.oldPassword,
|
oldPassword: data.oldPassword,
|
||||||
newPassword: data.newPassword,
|
newPassword: data.newPassword,
|
||||||
};
|
};
|
||||||
console.log(formData);
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await AuthRepository.changepassword(formData);
|
await AuthRepository.changepassword(formData);
|
||||||
showToast("Your Password changed Successfully", "success");
|
showToast("Your Password changed Successfully", "success");
|
||||||
@ -72,23 +71,20 @@ const ChangePasswordPage = ({ onClose }) => {
|
|||||||
role="dialog"
|
role="dialog"
|
||||||
style={{ display: "flex", backgroundColor: "rgba(0,0,0,0.5)" }}
|
style={{ display: "flex", backgroundColor: "rgba(0,0,0,0.5)" }}
|
||||||
>
|
>
|
||||||
<div
|
<div className="modal-dialog" role="document">
|
||||||
className="modal-dialog"
|
<div className="modal-header">
|
||||||
role="document"
|
{" "}
|
||||||
style={{
|
|
||||||
maxWidth: "600px",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="modal-content p-4 rounded shadow bg-white position-relative">
|
|
||||||
{/* Close Button */}
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn-close position-absolute"
|
class="btn-close"
|
||||||
style={{ top: "30px", right: "25px" }}
|
data-bs-dismiss="modal"
|
||||||
|
style={{ top: "40px", right: "15px" }}
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
onClick={onClose}
|
|
||||||
></button>
|
></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="modal-content p-10 rounded shadow bg-white position-relative">
|
||||||
|
{/* Close Button */}
|
||||||
|
|
||||||
<h5 className="mb-2">Change Password</h5>
|
<h5 className="mb-2">Change Password</h5>
|
||||||
<p className="mb-4" style={{ fontSize: "14px" }}>
|
<p className="mb-4" style={{ fontSize: "14px" }}>
|
||||||
@ -97,7 +93,7 @@ const ChangePasswordPage = ({ onClose }) => {
|
|||||||
|
|
||||||
<form onSubmit={handleSubmit(onChangePassword)}>
|
<form onSubmit={handleSubmit(onChangePassword)}>
|
||||||
{/* Old Password */}
|
{/* Old Password */}
|
||||||
<div className="mb-3">
|
<div className="mb-3 text-start">
|
||||||
<label className="form-label">Old Password</label>
|
<label className="form-label">Old Password</label>
|
||||||
<div className="input-group input-group-merge d-flex align-items-center border rounded px-2">
|
<div className="input-group input-group-merge d-flex align-items-center border rounded px-2">
|
||||||
<input
|
<input
|
||||||
@ -123,75 +119,75 @@ const ChangePasswordPage = ({ onClose }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="row">
|
{/* <div className="row"> */}
|
||||||
<div className="mb-3 col-md-6">
|
<div className="mb-3 text-start">
|
||||||
<label className="form-label">New Password</label>
|
<label className="form-label">New Password</label>
|
||||||
<div className="input-group input-group-merge d-flex align-items-center border rounded px-2">
|
<div className="input-group input-group-merge d-flex align-items-center border rounded px-2">
|
||||||
<input
|
<input
|
||||||
type={hideNewPass ? "password" : "text"}
|
type={hideNewPass ? "password" : "text"}
|
||||||
className="form-control form-control-sm border-0 shadow-none"
|
className="form-control form-control-sm border-0 shadow-none"
|
||||||
{...register("newPassword")}
|
{...register("newPassword")}
|
||||||
placeholder="············"
|
placeholder="············"
|
||||||
style={{ flex: 1 }}
|
style={{ flex: 1 }}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-link p-0 ms-2"
|
className="btn btn-link p-0 ms-2"
|
||||||
style={{ fontSize: "18px", color: "#6c757d" }}
|
style={{ fontSize: "18px", color: "#6c757d" }}
|
||||||
onClick={() => setHideNewPass(!hideNewPass)}
|
onClick={() => setHideNewPass(!hideNewPass)}
|
||||||
>
|
>
|
||||||
<i
|
<i className={`bx ${hideNewPass ? "bx-hide" : "bx-show"}`} />
|
||||||
className={`bx ${hideNewPass ? "bx-hide" : "bx-show"}`}
|
</button>
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{errors.newPassword && (
|
|
||||||
<div
|
|
||||||
className="danger-text text-start"
|
|
||||||
style={{ fontSize: "12px" }}
|
|
||||||
>
|
|
||||||
{errors.newPassword.message}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
{errors.newPassword && (
|
||||||
{/* Confirm Password */}
|
<div
|
||||||
<div className="mb-3 col-md-6">
|
className="danger-text text-start"
|
||||||
<label className="form-label">Confirm New Password</label>
|
style={{ fontSize: "12px" }}
|
||||||
<div className="input-group input-group-merge d-flex align-items-center border rounded px-2">
|
>
|
||||||
<input
|
{errors.newPassword.message}
|
||||||
type={hideConfirmPass ? "password" : "text"}
|
|
||||||
className="form-control form-control-sm border-0 shadow-none"
|
|
||||||
{...register("confirmPassword")}
|
|
||||||
placeholder="············"
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-link p-0 ms-2"
|
|
||||||
style={{ fontSize: "18px", color: "#6c757d" }}
|
|
||||||
onClick={() => setHideConfirmPass(!hideConfirmPass)}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className={`bx ${
|
|
||||||
hideConfirmPass ? "bx-hide" : "bx-show"
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
{errors.confirmPassword && (
|
)}
|
||||||
<div
|
|
||||||
className="danger-text text-start"
|
|
||||||
style={{ fontSize: "12px" }}
|
|
||||||
>
|
|
||||||
{errors.confirmPassword.message}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Confirm Password */}
|
||||||
|
<div className="mb-3 text-start">
|
||||||
|
<label className="form-label">Confirm New Password</label>
|
||||||
|
<div className="input-group input-group-merge d-flex align-items-center border rounded px-2">
|
||||||
|
<input
|
||||||
|
type={hideConfirmPass ? "password" : "text"}
|
||||||
|
className="form-control form-control-sm border-0 shadow-none"
|
||||||
|
{...register("confirmPassword")}
|
||||||
|
placeholder="············"
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-link p-0 ms-2"
|
||||||
|
style={{ fontSize: "18px", color: "#6c757d" }}
|
||||||
|
onClick={() => setHideConfirmPass(!hideConfirmPass)}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className={`bx ${hideConfirmPass ? "bx-hide" : "bx-show"}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{errors.confirmPassword && (
|
||||||
|
<div
|
||||||
|
className="danger-text text-start"
|
||||||
|
style={{ fontSize: "12px" }}
|
||||||
|
>
|
||||||
|
{errors.confirmPassword.message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{/* </div> */}
|
||||||
|
<div className="d-flex justify-content-center pt-2">
|
||||||
|
Your password must have at least 8 characters and include a lower
|
||||||
|
case latter, an uppercase letter, a number, and a special
|
||||||
|
character.
|
||||||
|
</div>
|
||||||
{/* Action Buttons */}
|
{/* Action Buttons */}
|
||||||
<div className="d-flex justify-content-end pt-2">
|
<div className="d-flex justify-content-center pt-2">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="btn btn-primary btn-sm me-2"
|
className="btn btn-primary btn-sm me-2"
|
||||||
@ -208,21 +204,6 @@ const ChangePasswordPage = ({ onClose }) => {
|
|||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3 text-start ">
|
|
||||||
<p className="p-0 m-0">Password must be:</p>
|
|
||||||
<p className="p-0 m-0">- at least 8 characters long</p>
|
|
||||||
<p className="p-0 m-0">
|
|
||||||
- must contain one uppercase, one lowercase letter, at least one
|
|
||||||
number, at least one special character
|
|
||||||
</p>
|
|
||||||
{/* <p className="p-0 m-0">
|
|
||||||
- must contain at least one lowercase letter
|
|
||||||
</p>
|
|
||||||
<p className="p-0 m-0">- must contain at least one number</p>
|
|
||||||
<p className="p-0 m-0">
|
|
||||||
- must contain at least one special character
|
|
||||||
</p> */}
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,11 @@ import ProjectInfra from "../../components/Project/ProjectInfra";
|
|||||||
import Loader from "../../components/common/Loader";
|
import Loader from "../../components/common/Loader";
|
||||||
import WorkPlan from "../../components/Project/WorkPlan";
|
import WorkPlan from "../../components/Project/WorkPlan";
|
||||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||||
import { cacheData, clearCacheKey, getCachedData } from "../../slices/apiDataManager";
|
import {
|
||||||
|
cacheData,
|
||||||
|
clearCacheKey,
|
||||||
|
getCachedData,
|
||||||
|
} from "../../slices/apiDataManager";
|
||||||
import ProjectRepository from "../../repositories/ProjectRepository";
|
import ProjectRepository from "../../repositories/ProjectRepository";
|
||||||
import { ActivityeRepository } from "../../repositories/MastersRepository";
|
import { ActivityeRepository } from "../../repositories/MastersRepository";
|
||||||
import "./ProjectDetails.css";
|
import "./ProjectDetails.css";
|
||||||
@ -24,6 +28,7 @@ import { setProjectId } from "../../slices/localVariablesSlice";
|
|||||||
import { ComingSoonPage } from "../Misc/ComingSoonPage";
|
import { ComingSoonPage } from "../Misc/ComingSoonPage";
|
||||||
import Directory from "../Directory/Directory";
|
import Directory from "../Directory/Directory";
|
||||||
import eventBus from "../../services/eventBus";
|
import eventBus from "../../services/eventBus";
|
||||||
|
import ProjectProgressChart from "../../components/Dashboard/ProjectProgressChart";
|
||||||
|
|
||||||
const ProjectDetails = () => {
|
const ProjectDetails = () => {
|
||||||
let { projectId } = useParams();
|
let { projectId } = useParams();
|
||||||
@ -75,18 +80,31 @@ const ProjectDetails = () => {
|
|||||||
switch (activePill) {
|
switch (activePill) {
|
||||||
case "profile": {
|
case "profile": {
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<>
|
||||||
<div className="col-xl-4 col-lg-5 col-md-5 mt-5">
|
<div className="row">
|
||||||
{/* About User */}
|
<div className="col-lg-4 col-md-5 mt-5">
|
||||||
<AboutProject data={projectDetails}></AboutProject>
|
{/* About User */}
|
||||||
{/* About User */}
|
<AboutProject data={projectDetails}></AboutProject>
|
||||||
|
<ProjectOverview project={projectId} />
|
||||||
|
{/* About User */}
|
||||||
|
</div>
|
||||||
|
<div className="col-lg-8 col-md-5 mt-5">
|
||||||
|
{/* Profile Overview */}
|
||||||
|
<ProjectProgressChart
|
||||||
|
ShowAllProject="false"
|
||||||
|
DefaultRange="1M"
|
||||||
|
/>
|
||||||
|
{/* Profile Overview */}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-xl-4 col-lg-5 col-md-5 mt-5">
|
<div className="row">
|
||||||
{/* Profile Overview */}
|
<div className="col-xl-4 col-lg-5 col-md-5 ">
|
||||||
<ProjectOverview project={projectId} />
|
{/* Profile Overview */}
|
||||||
{/* Profile Overview */}
|
{/* <ProjectOverview project={projectId} /> */}
|
||||||
|
{/* Profile Overview */}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case "teams": {
|
case "teams": {
|
||||||
@ -141,22 +159,22 @@ const ProjectDetails = () => {
|
|||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
(msg) => {
|
(msg) => {
|
||||||
if (msg.keyword === "Update_Project" && project.id === msg.response.id) {
|
if (msg.keyword === "Update_Project" && project.id === msg.response.id) {
|
||||||
clearCacheKey("projectInfo")
|
clearCacheKey("projectInfo");
|
||||||
ProjectRepository.getProjectByprojectId(projectId)
|
ProjectRepository.getProjectByprojectId(projectId)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
setProjectDetails(response.data);
|
setProjectDetails(response.data);
|
||||||
setProject(response.data);
|
setProject(response.data);
|
||||||
cacheData("projectInfo", { projectId, data: response.data });
|
cacheData("projectInfo", { projectId, data: response.data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
setError("Failed to fetch data.");
|
setError("Failed to fetch data.");
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[project,handleDataChange]
|
[project, handleDataChange]
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
eventBus.on("project", handler);
|
eventBus.on("project", handler);
|
||||||
@ -171,15 +189,15 @@ const ProjectDetails = () => {
|
|||||||
data={[
|
data={[
|
||||||
{ label: "Home", link: "/dashboard" },
|
{ label: "Home", link: "/dashboard" },
|
||||||
{ label: "Projects", link: "/projects" },
|
{ label: "Projects", link: "/projects" },
|
||||||
{ label: "Details", link: null },
|
{ label: `${project?.name ? project?.name : ""}`, link: null },
|
||||||
]}
|
]}
|
||||||
></Breadcrumb>
|
></Breadcrumb>
|
||||||
|
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{projectLoading && <p>Loading....</p>}
|
{projectLoading && <p>Loading....</p>}
|
||||||
{!projectLoading && project && (
|
{/* {!projectLoading && project && (
|
||||||
<ProjectBanner project_data={project}></ProjectBanner>
|
<ProjectBanner project_data={project}></ProjectBanner>
|
||||||
)}
|
)} */}
|
||||||
|
|
||||||
<ProjectNav
|
<ProjectNav
|
||||||
onPillClick={handlePillClick}
|
onPillClick={handlePillClick}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user