farhantock
12 months ago
3 changed files with 993 additions and 8 deletions
@ -0,0 +1,977 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react"; |
||||
import axios from "axios"; |
||||
import { Row, Col, Button, Input,Spin } from "antd"; |
||||
import { |
||||
CardDashboard, |
||||
CardExpenditure, |
||||
CardScheduleHealthPerDivision, |
||||
} from "../../components/CardDashboard/CardDashboard"; |
||||
import L from "leaflet"; |
||||
import "../../assets/css/customscroll.css"; |
||||
import moment from "moment"; |
||||
import { renderFormatRupiah } from "../../const/CustomFunc"; |
||||
import { BASE_OSPRO, BASE_OSPRO_FE, VERSION_GANTT_SEARCH } from "../../const/ApiConst"; |
||||
import { SendOutlined } from "@ant-design/icons"; |
||||
import { |
||||
NotificationContainer, |
||||
NotificationManager, |
||||
} from "react-notifications"; |
||||
import { |
||||
Carousel, |
||||
CarouselItem, |
||||
CarouselControl, |
||||
CarouselIndicators, |
||||
CarouselCaption, |
||||
} from 'reactstrap'; |
||||
import ContentLoader from "react-content-loader"; |
||||
import { |
||||
BehindTaskItem, |
||||
Comment, |
||||
HealthByBudget, |
||||
HealthBySchedule, |
||||
ListLoader, |
||||
PopupContent, |
||||
ProgressActualBar, |
||||
ProgressPlanningBar, |
||||
SingleTextLoader, |
||||
} from "./Components"; |
||||
import { Fab, Action } from "react-tiny-fab"; |
||||
import "react-tiny-fab/dist/styles.css"; |
||||
import { useHistory, useLocation, useParams } from "react-router-dom"; |
||||
|
||||
const { TextArea } = Input; |
||||
|
||||
const styles = { |
||||
cardContainer: { |
||||
backgroundColor: "#F8F8F8", |
||||
margin: 2, |
||||
paddingLeft: 20, |
||||
paddingRight: 20, |
||||
paddingTop: 10, |
||||
}, |
||||
cardHeaderContainer: { |
||||
display: "flex", |
||||
flexDirection: "row", |
||||
marginBottom: 10, |
||||
}, |
||||
cardChartContainer: { |
||||
position: "relative", |
||||
height: "21vh", |
||||
margin: "auto", |
||||
paddingBottom: 10, |
||||
justifyContent: "center", |
||||
}, |
||||
cardTitle: { color: "#444444", fontSize: 16, fontWeight: "bold" }, |
||||
cardSubtitle: { color: "#888888", fontSize: 12 }, |
||||
}; |
||||
const center = { |
||||
lat: -6.2, |
||||
lng: 106.816666, |
||||
}; |
||||
|
||||
const DashboardProject = (args) => { |
||||
const token = localStorage.getItem("token"); |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
Authorization: `Bearer ${token}`, |
||||
}, |
||||
}; |
||||
const { PROJECT_ID } = useParams(); |
||||
const mapRef = useRef(); |
||||
const [mymap, setMymap] = useState(null); |
||||
const [activeTabIdx, setActiveTabIdx] = useState(0); |
||||
const [activeTabCommentIdx, setActiveTabCommentIdx] = useState(0); |
||||
const [planningProgress, setPlanningProgress] = useState(0); |
||||
const [actualProgress, setActualProgress] = useState(0); |
||||
const [isReadyComments, setIsReadyComments] = useState(false); |
||||
const [isSendingComment, setIsSendingComment] = useState(false); |
||||
const [isReadyProjectDetail, setIsReadyProjectDetail] = useState(false); |
||||
const [isReadySCurve, setIsReadySCurve] = useState(false); |
||||
const [isReadyGantt, setIsReadyGantt] = useState(false); |
||||
const [reportDistribution, setReportDistribution] = useState([]); |
||||
const [isReadyOverdueActivities, setIsReadyOverdueActivities] = |
||||
useState(false); |
||||
const [healthBySchedule, setHealthBySchedule] = useState("-"); |
||||
const [allDataMaster, sourceData] = useState([]); |
||||
const [isHierarchy, setIsHierarchy] = useState(false); |
||||
let history = useHistory(); |
||||
// Carousell
|
||||
const [activeIndex, setActiveIndex] = useState(0); |
||||
const [animating, setAnimating] = useState(false); |
||||
const [loading, setLoading] = useState(true); |
||||
|
||||
|
||||
useEffect(() => { |
||||
setLoading(true); |
||||
getAllData(); |
||||
},[]); |
||||
|
||||
useEffect(() => { |
||||
if (activeTabIdx === 1) { |
||||
initMap(); |
||||
} |
||||
}, [activeTabIdx]); |
||||
|
||||
const getAllData = async () => { |
||||
setIsReadyProjectDetail(false); |
||||
setIsReadySCurve(false) |
||||
setIsReadySCurve(false); |
||||
const URL = `${BASE_OSPRO}/api/project-carausell`; |
||||
const result = await axios |
||||
.get(URL, HEADER) |
||||
.then((res) => res) |
||||
.catch((err) => err.response); |
||||
if (!result) { |
||||
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
||||
setIsReadyProjectDetail(true); |
||||
setIsReadySCurve(true); |
||||
setLoading(false); |
||||
return; |
||||
} |
||||
|
||||
if (result.status !== 200) { |
||||
NotificationManager.error( |
||||
`Get project detail failed, ${result.data.message}`, |
||||
"Failed" |
||||
); |
||||
setIsReadyProjectDetail(true); |
||||
setIsReadySCurve(true); |
||||
setLoading(false); |
||||
return; |
||||
} else if (result.status == 200 && result.data.data) { |
||||
const dataResault = result.data.data; |
||||
console.log("Resault Data",dataResault); |
||||
sourceData(dataResault); |
||||
setIsReadyGantt(true); |
||||
setIsReadyProjectDetail(true); |
||||
// // SCurve
|
||||
// let statusHealthBySchedule = "on-schedule";
|
||||
// let selisihProgress = 0;
|
||||
// dataResault.map((item, idx) => {
|
||||
// item.SCurve.map((itemSCurve, idx) => {
|
||||
// let planningProgress = 0;
|
||||
// let actualProgress = 0;
|
||||
// let now = new Date().toISOString().slice(0, 10);
|
||||
// let dates = itemSCurve.data?.date;
|
||||
// let n = dates.findIndex(
|
||||
// (element) => new Date(now) < new Date(element)
|
||||
// );
|
||||
// if (
|
||||
// itemSCurve.length > 0 &&
|
||||
// itemSCurve.data?.percentagePlan &&
|
||||
// itemSCurve.data?.percentagePlan.length > 0
|
||||
// ) {
|
||||
// planningProgress = itemSCurve.data?.percentagePlan[n];
|
||||
// if (n < 0) {
|
||||
// planningProgress = 100;
|
||||
// }
|
||||
// setPlanningProgress(planningProgress);
|
||||
// }
|
||||
// if (
|
||||
// itemSCurve.length > 0 &&
|
||||
// itemSCurve.data?.percentageReal &&
|
||||
// itemSCurve.data?.percentageReal.length > 0
|
||||
// ) {
|
||||
// actualProgress =
|
||||
// itemSCurve.data?.percentageReal[
|
||||
// itemSCurve.data?.percentageReal.length - 1
|
||||
// ];
|
||||
// setActualProgress(actualProgress);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
// selisihProgress = planningProgress - actualProgress;
|
||||
// if (selisihProgress > 0 && selisihProgress <= 5) {
|
||||
// statusHealthBySchedule = "warning";
|
||||
// } else if (selisihProgress > 5) {
|
||||
// statusHealthBySchedule = "danger";
|
||||
// }
|
||||
// setHealthBySchedule(statusHealthBySchedule);
|
||||
setIsReadySCurve(true); |
||||
// setHierarchy
|
||||
setIsHierarchy(true); |
||||
// Get Overdue
|
||||
setIsReadyOverdueActivities(true); |
||||
// Distribution
|
||||
setReportDistribution(dataResault); |
||||
// loading
|
||||
setLoading(false); |
||||
|
||||
} |
||||
}; |
||||
|
||||
const initMap = () => { |
||||
let mymap = L.map("map-area", { |
||||
center: center, |
||||
zoom: 13, |
||||
}); |
||||
|
||||
setMymap(mymap); |
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { |
||||
attribution: |
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', |
||||
}).addTo(mymap); |
||||
}; |
||||
|
||||
useEffect(() => { |
||||
if (mymap) { |
||||
reportDistribution.map((item, idx) => { |
||||
if (item.report_distribution.length > 0) { |
||||
item.report_distribution.map((itemDistribution, idx) => { |
||||
L.marker([itemDistribution.lat, itemDistribution.lon]) |
||||
.addTo(mymap) |
||||
.bindPopup(PopupContent(itemDistribution)); |
||||
}) |
||||
} |
||||
}); |
||||
} |
||||
}, [mymap, reportDistribution]); |
||||
|
||||
useEffect(() => { |
||||
// Add event listener for receiving messages from the iframe
|
||||
window.addEventListener("message", handleIframeMessage); |
||||
|
||||
// Clean up the event listener on component unmount
|
||||
return () => { |
||||
window.removeEventListener("message", handleIframeMessage); |
||||
}; |
||||
}, []); |
||||
|
||||
const handleIframeMessage = (event) => { |
||||
if (event.data && event.data.action === "getUrl") { |
||||
const childUrl = window.location.href; |
||||
|
||||
// Send the URL back to the iframe
|
||||
event.source.postMessage( |
||||
{ action: "sendUrl", url: childUrl, isHierarchy: isHierarchy }, |
||||
event.origin |
||||
); |
||||
} |
||||
}; |
||||
|
||||
const next = () => { |
||||
if (animating) return; |
||||
const nextIndex = activeIndex === allDataMaster.length - 1 ? 0 : activeIndex + 1; |
||||
setActiveIndex(nextIndex); |
||||
}; |
||||
|
||||
const previous = () => { |
||||
if (animating) return; |
||||
const nextIndex = activeIndex === 0 ? allDataMaster.length - 1 : activeIndex - 1; |
||||
setActiveIndex(nextIndex); |
||||
}; |
||||
|
||||
const goToIndex = (newIndex) => { |
||||
if (animating) return; |
||||
setActiveIndex(newIndex); |
||||
}; |
||||
|
||||
const slides = allDataMaster.map((item, index) => { |
||||
let URL_GANTT = ""; |
||||
let version_gantt = ""; |
||||
item.project.gantt.map((itemGantt, index) => { |
||||
URL_GANTT = `http://localhost:8444/adw-gantt/view-mode/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${itemGantt.gantt_id}&proyek_id=${itemGantt.proyek_id}&token=${token}&ro=1`; |
||||
version_gantt = itemGantt.name_version |
||||
}); |
||||
const today = moment(); |
||||
const assignedList = item.assigned |
||||
.filter((itemAssigned) => |
||||
today.isBetween(moment(itemAssigned.start_date), moment(itemAssigned.end_date)) |
||||
) |
||||
.map((itemMap) => itemMap.user_id); |
||||
// SCurve
|
||||
let statusHealthBySchedule = "on-schedule"; |
||||
let selisihProgress = 0; |
||||
let SetplanningProgress = 0; |
||||
let SetactualProgress = 0; |
||||
let now = new Date().toISOString().slice(0, 10); |
||||
let dates = item.SCurve[0].data?.date; |
||||
let n = dates.findIndex( |
||||
(element) => new Date(now) < new Date(element) |
||||
); |
||||
if ( |
||||
item.SCurve[0].length > 0 && |
||||
item.SCurve[0].data?.percentagePlan && |
||||
item.SCurve[0].data?.percentagePlan.length > 0 |
||||
) { |
||||
SetplanningProgress = item.SCurve[0].data?.percentagePlan[n]; |
||||
if (n < 0) { |
||||
SetplanningProgress = 100; |
||||
} |
||||
} |
||||
if ( |
||||
item.SCurve[0].length > 0 && |
||||
item.SCurve[0].data?.percentageReal && |
||||
item.SCurve[0].data?.percentageReal.length > 0 |
||||
) { |
||||
SetactualProgress = |
||||
item.SCurve[0].data?.percentageReal[ |
||||
item.SCurve[0].data?.percentageReal.length - 1 |
||||
]; |
||||
} |
||||
|
||||
selisihProgress = SetplanningProgress - SetactualProgress; |
||||
if (selisihProgress > 0 && selisihProgress <= 5) { |
||||
statusHealthBySchedule = "warning"; |
||||
} else if (selisihProgress > 5) { |
||||
statusHealthBySchedule = "danger"; |
||||
} |
||||
return ( |
||||
<CarouselItem |
||||
onExiting={() => setAnimating(true)} |
||||
onExited={() => setAnimating(false)} |
||||
key={parseInt(item.key)}> |
||||
<Row> |
||||
<Col span={18}> |
||||
<Row> |
||||
<Col span={8}> |
||||
<div |
||||
style={{ |
||||
border: "solid", |
||||
borderWidth: 1, |
||||
borderColor: "#DDDDDD", |
||||
padding: 10, |
||||
margin: 2, |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
display: "flex", |
||||
flexDirection: "row", |
||||
marginBottom: 10, |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
flex: 20, |
||||
display: "flex", |
||||
flexDirection: "column", |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
fontSize: 16, |
||||
fontWeight: "bold", |
||||
marginBottom: 10, |
||||
}} |
||||
> |
||||
Project |
||||
</div> |
||||
<div style={{ fontSize: 14 }}> |
||||
{isReadyProjectDetail && |
||||
isReadyGantt ? ( |
||||
(() => { |
||||
let parentNames = ""; |
||||
if (item.hierarchy.length > 0) |
||||
{ |
||||
for ( let i = item.hierarchy.length - 1; i >= 0; i--) { |
||||
parentNames += " - "; |
||||
parentNames += item.hierarchy[i].name; |
||||
} |
||||
} |
||||
return item.project.nama + |
||||
parentNames + |
||||
" - " + |
||||
version_gantt |
||||
})() |
||||
) : ( |
||||
<SingleTextLoader /> |
||||
)} |
||||
</div> |
||||
</div> |
||||
<div> |
||||
<i |
||||
className="fa fa-check-square" |
||||
style={{ fontSize: 28 }} |
||||
></i> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</Col> |
||||
<Col span={8}> |
||||
<div |
||||
style={{ |
||||
border: "solid", |
||||
borderWidth: 1, |
||||
borderColor: "#DDDDDD", |
||||
padding: 10, |
||||
margin: 2, |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
display: "flex", |
||||
flexDirection: "row", |
||||
marginBottom: 10, |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
flex: 20, |
||||
display: "flex", |
||||
flexDirection: "column", |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
fontSize: 16, |
||||
fontWeight: "bold", |
||||
marginBottom: 10, |
||||
}} |
||||
> |
||||
Project Manager |
||||
</div> |
||||
<div style={{ fontSize: 14 }}> |
||||
{isReadyProjectDetail ? ( |
||||
item.project_manager |
||||
) : ( |
||||
<SingleTextLoader /> |
||||
)} |
||||
</div> |
||||
</div> |
||||
<div> |
||||
<i className="fa fa-user" style={{ fontSize: 28 }}></i> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</Col> |
||||
<Col span={8}> |
||||
<div |
||||
style={{ |
||||
border: "solid", |
||||
borderWidth: 1, |
||||
borderColor: "#DDDDDD", |
||||
padding: 10, |
||||
margin: 2, |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
display: "flex", |
||||
flexDirection: "row", |
||||
marginBottom: 10, |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
flex: 20, |
||||
display: "flex", |
||||
flexDirection: "column", |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
fontSize: 16, |
||||
fontWeight: "bold", |
||||
marginBottom: 10, |
||||
}} |
||||
> |
||||
Customer |
||||
</div> |
||||
<div style={{ fontSize: 14 }}> |
||||
{isReadyProjectDetail ? ( |
||||
item.project.company |
||||
) : ( |
||||
<SingleTextLoader /> |
||||
)} |
||||
</div> |
||||
</div> |
||||
<div> |
||||
<i className="fa fa-home" style={{ fontSize: 28 }}></i> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col span={10}> |
||||
<div |
||||
style={{ |
||||
border: "solid", |
||||
borderWidth: 1, |
||||
borderColor: "#DDDDDD", |
||||
padding: 10, |
||||
margin: 2, |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
display: "flex", |
||||
flexDirection: "column", |
||||
marginBottom: 10, |
||||
}} |
||||
> |
||||
<div> |
||||
<div |
||||
style={{ |
||||
fontSize: 16, |
||||
fontWeight: "bold", |
||||
marginBottom: 10, |
||||
}} |
||||
> |
||||
Schedule |
||||
</div> |
||||
</div> |
||||
<div> |
||||
<Row> |
||||
<Col |
||||
span={12} |
||||
style={{ fontSize: 11, fontWeight: "bold" }} |
||||
> |
||||
<i |
||||
className="fa fa-calendar" |
||||
style={{ marginRight: 8 }} |
||||
></i> |
||||
Planned Start |
||||
</Col> |
||||
<Col span={12} style={{ fontSize: 11 }}> |
||||
{isReadyProjectDetail ? ( |
||||
item.activity.planned_start ? ( |
||||
moment(item.activity.planned_start).format("D MMMM YYYY") |
||||
) : ( |
||||
"-" |
||||
) |
||||
) : ( |
||||
<SingleTextLoader width={100} height={10} /> |
||||
)} |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col |
||||
span={12} |
||||
style={{ fontSize: 11, fontWeight: "bold" }} |
||||
> |
||||
<i |
||||
className="fa fa-calendar" |
||||
style={{ marginRight: 8 }} |
||||
></i> |
||||
Actual Start |
||||
</Col> |
||||
<Col span={12} style={{ fontSize: 11 }}> |
||||
{isReadyProjectDetail ? ( |
||||
item.activity.start_date ? ( |
||||
moment(item.activity.start_date).format("D MMMM YYYY") |
||||
) : ( |
||||
"-" |
||||
) |
||||
) : ( |
||||
<SingleTextLoader width={100} height={10} /> |
||||
)} |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col |
||||
span={12} |
||||
style={{ fontSize: 11, fontWeight: "bold" }} |
||||
> |
||||
<i |
||||
className="fa fa-calendar" |
||||
style={{ marginRight: 8 }} |
||||
></i> |
||||
Planned Finish |
||||
</Col> |
||||
<Col span={12} style={{ fontSize: 11 }}> |
||||
{isReadyProjectDetail ? ( |
||||
item.activity.planned_end ? ( |
||||
moment(item.activity.planned_end).format("D MMMM YYYY") |
||||
) : ( |
||||
"-" |
||||
) |
||||
) : ( |
||||
<SingleTextLoader width={100} height={10} /> |
||||
)} |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col |
||||
span={12} |
||||
style={{ fontSize: 11, fontWeight: "bold" }} |
||||
> |
||||
<i |
||||
className="fa fa-calendar" |
||||
style={{ marginRight: 8 }} |
||||
></i> |
||||
Estimated Finish |
||||
</Col> |
||||
<Col span={12} style={{ fontSize: 11 }}> |
||||
{isReadyProjectDetail ? ( |
||||
item.activity.end_date ? ( |
||||
moment(item.activity.end_date).format("D MMMM YYYY") |
||||
) : ( |
||||
"-" |
||||
) |
||||
) : ( |
||||
<SingleTextLoader width={100} height={10} /> |
||||
)} |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<div |
||||
style={{ |
||||
margin: 2, |
||||
border: "solid", |
||||
borderWidth: 1, |
||||
borderColor: "#DDDDDD", |
||||
}} |
||||
> |
||||
<Row> |
||||
<Col span={12}> |
||||
<div |
||||
style={{ |
||||
backgroundColor: activeTabIdx === 0 ? "#FFFFFF" : "#D9D9D9", |
||||
padding: 8, |
||||
fontWeight: "bold", |
||||
cursor: "pointer", |
||||
color: activeTabIdx === 0 ? "#000000" : "#4E4C4C", |
||||
}} |
||||
onClick={() => setActiveTabIdx(0)} |
||||
> |
||||
S Curve |
||||
</div> |
||||
</Col> |
||||
<Col span={12}> |
||||
<div |
||||
style={{ |
||||
backgroundColor: activeTabIdx === 1 ? "#FFFFFF" : "#D9D9D9", |
||||
padding: 8, |
||||
fontWeight: "bold", |
||||
cursor: "pointer", |
||||
color: activeTabIdx === 1 ? "#000000" : "#4E4C4C", |
||||
}} |
||||
onClick={() => setActiveTabIdx(1)} |
||||
> |
||||
Maps |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col span={24}> |
||||
<div style={{ maxHeight: "55vh" }}> |
||||
<div |
||||
style={{ |
||||
height: "56vh", |
||||
width: "100%", |
||||
display: activeTabIdx === 0 ? "block" : "none", |
||||
}} |
||||
> |
||||
<iframe |
||||
id="frame-gantt" |
||||
src={URL_GANTT} |
||||
style={{ |
||||
width: "100%", |
||||
height: "100%", |
||||
}} |
||||
scrolling="no" |
||||
frameBorder="0" |
||||
allow="fullscreen" |
||||
></iframe> |
||||
</div> |
||||
{activeTabIdx === 1 && ( |
||||
<div |
||||
id="map-area" |
||||
style={{ height: "56vh" }} |
||||
ref={mapRef} |
||||
></div> |
||||
)} |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
</Col> |
||||
<Col span={6}> |
||||
<div style={{ margin: 2 }}> |
||||
<Row> |
||||
<Col span={24}> |
||||
<div |
||||
style={{ |
||||
backgroundColor: "#222222", |
||||
padding: 10, |
||||
marginBottom: 5, |
||||
}} |
||||
> |
||||
<div |
||||
style={{ |
||||
color: "#FFFFFF", |
||||
textAlign: "center", |
||||
marginBottom: 10, |
||||
fontWeight: "bold", |
||||
}} |
||||
> |
||||
Progress |
||||
</div> |
||||
{isReadySCurve ? ( |
||||
<ProgressPlanningBar |
||||
progress={SetplanningProgress > 100 ? 100 : SetplanningProgress} |
||||
/> |
||||
) : ( |
||||
<SingleTextLoader width={"100%"} height={30} /> |
||||
)} |
||||
<div style={{ marginTop: 10, marginBottom: 10 }}></div> |
||||
{isReadySCurve ? ( |
||||
<ProgressActualBar |
||||
progress={ |
||||
SetplanningProgress > 100 || SetactualProgress > 100 |
||||
? parseFloat( |
||||
(SetactualProgress / SetplanningProgress) * 100 |
||||
).toFixed(0) |
||||
: SetactualProgress |
||||
} |
||||
/> |
||||
) : ( |
||||
<SingleTextLoader width={"100%"} height={30} /> |
||||
)} |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col span={12}> |
||||
<div |
||||
style={{ |
||||
background: "#FFF", |
||||
padding: 10, |
||||
border: "1px solid #DDD", |
||||
marginRight: 2, |
||||
}} |
||||
> |
||||
{isReadyOverdueActivities && ( |
||||
<HealthByBudget status={item.project.budget_health} /> |
||||
)} |
||||
{isReadySCurve && ( |
||||
<HealthBySchedule status={statusHealthBySchedule} /> |
||||
)} |
||||
</div> |
||||
</Col> |
||||
<Col span={12}> |
||||
<Row style={{ height: "50%" }}> |
||||
<Col span={24}> |
||||
<div |
||||
style={{ |
||||
display: "flex", |
||||
alignItems: "center", |
||||
justifyContent: "center", |
||||
height: "100%", |
||||
background: "#FFF", |
||||
padding: 10, |
||||
border: "1px solid #DDD", |
||||
marginBottom: 5, |
||||
marginRight: 2, |
||||
}} |
||||
> |
||||
Manpower : {item.manpower} |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<Row style={{ height: "50%" }}> |
||||
<Col span={12}> |
||||
<div |
||||
style={{ |
||||
display: "flex", |
||||
alignItems: "center", |
||||
justifyContent: "center", |
||||
height: "100%", |
||||
background: "#FFF", |
||||
padding: 10, |
||||
border: "1px solid #DDD", |
||||
marginBottom: 5, |
||||
marginRight: 2, |
||||
}} |
||||
> |
||||
Assigned: {item.assigned && assignedList.length} |
||||
</div> |
||||
</Col> |
||||
<Col span={12}> |
||||
<div |
||||
style={{ |
||||
display: "flex", |
||||
alignItems: "center", |
||||
justifyContent: "center", |
||||
height: "100%", |
||||
background: "#FFF", |
||||
padding: 10, |
||||
border: "1px solid #DDD", |
||||
marginBottom: 5, |
||||
marginRight: 2, |
||||
}} |
||||
> |
||||
Actual : {item.actual} |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
</Col> |
||||
</Row> |
||||
<Row> |
||||
<Col span={24}> |
||||
<div |
||||
style={{ |
||||
border: "solid", |
||||
borderWidth: 1, |
||||
borderColor: "#DDDDDD", |
||||
}} |
||||
> |
||||
<Row style={{ alignItems: "center", marginBottom: 5 }}> |
||||
<Col span={12}> |
||||
<div |
||||
style={{ |
||||
backgroundColor: |
||||
activeTabCommentIdx === 0 ? "#FFFFFF" : "#D9D9D9", |
||||
fontWeight: 500, |
||||
textAlign: "center", |
||||
fontSize: 12, |
||||
padding: 2, |
||||
cursor: "pointer", |
||||
color: |
||||
activeTabCommentIdx === 0 ? "#000000" : "#4E4C4C", |
||||
}} |
||||
onClick={() => setActiveTabCommentIdx(0)} |
||||
> |
||||
Behind Task |
||||
</div> |
||||
</Col> |
||||
<Col span={12}> |
||||
<div |
||||
style={{ |
||||
backgroundColor: |
||||
activeTabCommentIdx === 1 ? "#FFFFFF" : "#D9D9D9", |
||||
fontWeight: 500, |
||||
textAlign: "center", |
||||
fontSize: 12, |
||||
padding: 2, |
||||
cursor: "pointer", |
||||
color: |
||||
activeTabCommentIdx === 1 ? "#000000" : "#4E4C4C", |
||||
}} |
||||
onClick={() => setActiveTabCommentIdx(1)} |
||||
> |
||||
Comment From Customer |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<div |
||||
className="custom-scroll" |
||||
style={{ maxHeight: "37vh", overflow: "auto" }} |
||||
> |
||||
{activeTabCommentIdx === 0 && ( |
||||
<div> |
||||
{isReadyOverdueActivities && item.overdueActivities != [] && item.overdueActivities.length > 0 ? ( |
||||
item.overdueActivities.map((overdueItem, idx) => { |
||||
let end_date; |
||||
let planned_end; |
||||
let diffDays = 0; |
||||
let message = ""; |
||||
|
||||
if (overdueItem.end_date && overdueItem.end_date !== null) { |
||||
end_date = moment(overdueItem.end_date); |
||||
planned_end = moment(overdueItem.planned_end); |
||||
diffDays = end_date.diff(planned_end, "days"); |
||||
|
||||
if (isNaN(diffDays)) { |
||||
return null; |
||||
} else { |
||||
if (diffDays > 0) { |
||||
message = `Overdue by ${diffDays + 1} days`; |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return <BehindTaskItem key={idx} name={overdueItem.name} message={message} />; |
||||
}) |
||||
) : ( |
||||
<div |
||||
style={{ |
||||
flex: 1, |
||||
textAlign: "center", |
||||
color: "#E80053", |
||||
marginTop: 50, |
||||
marginBottom: 50, |
||||
}} |
||||
> |
||||
No overdue activity found. |
||||
</div> |
||||
)} |
||||
</div> |
||||
)} |
||||
{activeTabCommentIdx === 1 &&( |
||||
<div> |
||||
{item.project_comment && item.project_comment != [] ? ( |
||||
item.project_comment.map((commentItem, idx) => { |
||||
|
||||
return <Comment |
||||
key={idx} |
||||
name={""} |
||||
comment={commentItem.comment} |
||||
created_at={commentItem.created_at} |
||||
/> |
||||
}) |
||||
) : ( |
||||
<div |
||||
style={{ |
||||
flex: 1, |
||||
textAlign: "center", |
||||
color: "#E80053", |
||||
marginTop: 50, |
||||
marginBottom: 50, |
||||
}} |
||||
> |
||||
No comments found. |
||||
</div> |
||||
)} |
||||
</div> |
||||
)} |
||||
</div> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
<CarouselCaption/> |
||||
</CarouselItem> |
||||
); |
||||
}); |
||||
|
||||
return ( |
||||
<div style={{ marginLeft: -25, marginRight: -25 }}> |
||||
<NotificationContainer /> |
||||
<Row> |
||||
<Col span={24}> |
||||
<Spin tip="Loading..." spinning={loading} style={{ marginTop:120 }}> |
||||
<Carousel |
||||
activeIndex={activeIndex} |
||||
next={next} |
||||
previous={previous} |
||||
{...args} |
||||
> |
||||
<CarouselIndicators |
||||
items={allDataMaster} |
||||
activeIndex={activeIndex} |
||||
onClickHandler={goToIndex} |
||||
/> |
||||
{slides} |
||||
|
||||
<CarouselControl |
||||
direction="prev" |
||||
directionText="Previous" |
||||
onClickHandler={previous} |
||||
/> |
||||
<CarouselControl |
||||
direction="next" |
||||
directionText="Next" |
||||
onClickHandler={next} |
||||
/> |
||||
</Carousel > |
||||
</Spin> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
export default DashboardProject; |
Loading…
Reference in new issue