Browse Source

add file

pull/1/head
wahyuun 12 months ago
parent
commit
c3417b1352
  1. 977
      src/views/Dashboard/DashboardProjectCarousell.js

977
src/views/Dashboard/DashboardProjectCarousell.js

@ -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:
'&copy; <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…
Cancel
Save