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