|
|
|
@ -31,34 +31,15 @@ import {
|
|
|
|
|
import { Fab, Action } from "react-tiny-fab"; |
|
|
|
|
import "react-tiny-fab/dist/styles.css"; |
|
|
|
|
import { useHistory, useLocation, useParams } from "react-router-dom"; |
|
|
|
|
import { Icon } from '@iconify/react'; |
|
|
|
|
import arrowLeft from '@iconify/icons-ion/ios-arrow-back'; |
|
|
|
|
|
|
|
|
|
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 = (props) => { |
|
|
|
|
let role_id = 0, user_id = 0, isLogin = false, token = '', all_project = null, role_name = '', hierarchy = [], user_name = ''; |
|
|
|
|
if (props && props.role_id && props.user_id) { |
|
|
|
@ -72,12 +53,14 @@ const DashboardProject = (props) => {
|
|
|
|
|
hierarchy = props.hierarchy; |
|
|
|
|
user_name = props.user_name; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const HEADER = { |
|
|
|
|
headers: { |
|
|
|
|
"Content-Type": "application/json", |
|
|
|
|
Authorization: `Bearer ${token}`, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const { PROJECT_ID, GANTT_ID, SCURVE } = useParams(); |
|
|
|
|
const URL_GANTT = `https://project-gantt.ospro.id/view-mode/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1&role_name=${role_name}`; |
|
|
|
|
// const URL_GANTT = `http://localhost:8444/generic-ospro-gantt/view-mode/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1&role_name=${role_name}`;
|
|
|
|
@ -97,6 +80,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
const [activeTabIdx, setActiveTabIdx] = useState(0); |
|
|
|
|
const [activeTabCommentIdx, setActiveTabCommentIdx] = useState(0); |
|
|
|
|
const [planningProgress, setPlanningProgress] = useState(0); |
|
|
|
|
const [planningProgressToDay, setPlanningProgressToDay] = useState(0); |
|
|
|
|
const [actualProgress, setActualProgress] = useState(0); |
|
|
|
|
const [currentBudget, setCurrentBudget] = useState(null); |
|
|
|
|
const [addCostToComplete, setAddCostToComplete] = useState(null); |
|
|
|
@ -134,6 +118,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
const [isReadyGanttParents, setIsReadyGanttParents] = useState(false); |
|
|
|
|
const [calculationStatus, setCalculationStatus] = useState(false); |
|
|
|
|
const [isHierarchy, setIsHierarchy] = useState(null); |
|
|
|
|
const [dashboardGantt, setDashboardStatus] = useState(false); |
|
|
|
|
let history = useHistory(); |
|
|
|
|
useEffect(() => { |
|
|
|
|
getProjectDetail(); |
|
|
|
@ -142,9 +127,11 @@ const DashboardProject = (props) => {
|
|
|
|
|
getComments(); |
|
|
|
|
getGantt(); |
|
|
|
|
getGanttParents(); |
|
|
|
|
getQueryParams(); |
|
|
|
|
return () => { |
|
|
|
|
}; |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (isHierarchy != null) { |
|
|
|
|
getSCurve(); |
|
|
|
@ -154,11 +141,13 @@ const DashboardProject = (props) => {
|
|
|
|
|
window.removeEventListener("message", handleIframeMessage); |
|
|
|
|
}; |
|
|
|
|
}, [isHierarchy]); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (activeTabIdx === 1) { |
|
|
|
|
initMap(); |
|
|
|
|
} |
|
|
|
|
}, [activeTabIdx]); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
async function fetchData() { |
|
|
|
|
await Promise.all([ |
|
|
|
@ -169,6 +158,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
} |
|
|
|
|
fetchData(); |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
let deviation = 0; |
|
|
|
|
if (plannedCost && totalCost) { |
|
|
|
@ -176,9 +166,11 @@ const DashboardProject = (props) => {
|
|
|
|
|
} |
|
|
|
|
setRemToComplete(deviation.toString()); |
|
|
|
|
}, [plannedCost, totalCost]); |
|
|
|
|
|
|
|
|
|
const handleRedirect = () => { |
|
|
|
|
history.push("/projects/" + GANTT_ID + "/" + PROJECT_ID + "/gantt"); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getManpower = async () => { |
|
|
|
|
const url = `${BASE_OSPRO}/api/project/manpower/${PROJECT_ID}`; |
|
|
|
|
try { |
|
|
|
@ -187,6 +179,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
} catch (error) { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getGantt = async () => { |
|
|
|
|
setIsReadyGantt(false); |
|
|
|
|
const url = `${BASE_OSPRO}/api/version-gantt/edit/${GANTT_ID}`; |
|
|
|
@ -203,6 +196,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
setIsReadyGantt(true); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getGanttParents = async () => { |
|
|
|
|
setIsReadyGanttParents(false); |
|
|
|
|
const url = `${BASE_OSPRO}/api/hierarchy-ftths/tree-gantt/${GANTT_ID}`; |
|
|
|
@ -214,6 +208,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
setIsReadyGanttParents(true); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getAssignedHR = async () => { |
|
|
|
|
const url = `${BASE_OSPRO}/api/project/manpower/assigned/${GANTT_ID}`; |
|
|
|
|
try { |
|
|
|
@ -229,6 +224,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
} catch (error) { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getActualHR = async () => { |
|
|
|
|
const dateStart = moment().startOf("day").toDate(); |
|
|
|
|
const dateEnd = moment().endOf("day").toDate(); |
|
|
|
@ -268,6 +264,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
console.error("Failed to get actual HR:", error); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getProjectDetail = async () => { |
|
|
|
|
setIsReadyProjectDetail(false); |
|
|
|
|
let URL = `${BASE_OSPRO}/api/project/detail/${PROJECT_ID}`; |
|
|
|
@ -352,6 +349,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getSCurve = async () => { |
|
|
|
|
setIsReadySCurve(false); |
|
|
|
|
let URL = `${BASE_OSPRO}/api/project/get-s-curve`; |
|
|
|
@ -384,6 +382,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
let selisihProgress = 0; |
|
|
|
|
let planningProgress = 0; |
|
|
|
|
let actualProgress = 0; |
|
|
|
|
let progressPlanToDay = 0; |
|
|
|
|
let statusHealthBySchedule = "behind-schedule"; |
|
|
|
|
if ( |
|
|
|
|
result.data.data.length > 0 && |
|
|
|
@ -423,6 +422,14 @@ const DashboardProject = (props) => {
|
|
|
|
|
planningProgress = result.data.data[0].data?.percentagePlan[n]; |
|
|
|
|
setPlanningProgress(planningProgress); |
|
|
|
|
} |
|
|
|
|
if ( |
|
|
|
|
result.data.data.length > 0 && |
|
|
|
|
result.data.data[0].data?.progressPlanToDay && |
|
|
|
|
result.data.data[0].data?.progressPlanToDay != null |
|
|
|
|
) { |
|
|
|
|
progressPlanToDay = result.data.data[0].data?.progressPlanToDay; |
|
|
|
|
setPlanningProgressToDay(+(Math.round(progressPlanToDay + "e+2") + "e-2")); |
|
|
|
|
} |
|
|
|
|
if ( |
|
|
|
|
result.data.data.length > 0 && |
|
|
|
|
result.data.data[0].data?.percentageReal && |
|
|
|
@ -444,6 +451,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
setIsReadySCurve(true); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getOverdueActivities = async () => { |
|
|
|
|
setIsReadyOverdueActivities(false); |
|
|
|
|
const URL = `${BASE_OSPRO}/api/project/get-overdue-activities`; |
|
|
|
@ -477,6 +485,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
setIsReadyOverdueActivities(true); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getIntegrationInvoice = async (kode_sortname, id, gantt_id = null) => { |
|
|
|
|
setIsReadyIntegrationInvoice(false); |
|
|
|
|
const URL = `${BASE_OSPRO}/api/project/get-integration-invoice`; |
|
|
|
@ -520,6 +529,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
setIsReadyIntegrationInvoice(true); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getReportDistribution = async () => { |
|
|
|
|
setIsReadyReportDistribution(false); |
|
|
|
|
const URL = `${BASE_OSPRO}/api/project/get-report-distribution`; |
|
|
|
@ -552,6 +562,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
setIsReadyReportDistribution(true); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getComments = async () => { |
|
|
|
|
setIsReadyComments(false); |
|
|
|
|
const URL = `${BASE_OSPRO}/api/project-comment/search`; |
|
|
|
@ -580,6 +591,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
orders: { columns: ["created_at"], ascending: false }, |
|
|
|
|
paging: { start: 0, length: -1 }, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const result = await axios |
|
|
|
|
.post(URL, payload, HEADER) |
|
|
|
|
.then((res) => res) |
|
|
|
@ -601,6 +613,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
setIsReadyComments(true); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const handleSendComment = async () => { |
|
|
|
|
setIsSendingComment(true); |
|
|
|
|
if (comment === "") { |
|
|
|
@ -640,10 +653,23 @@ const DashboardProject = (props) => {
|
|
|
|
|
getComments(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const resetInputComment = () => { |
|
|
|
|
setComment(""); |
|
|
|
|
setIsSendingComment(false); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getQueryParams = () => { |
|
|
|
|
const searchParams = new URLSearchParams(props.location.search); |
|
|
|
|
const dashboardGantt = searchParams.get('dashboardGantt'); |
|
|
|
|
setDashboardStatus(dashboardGantt); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const handleBack = async () => { |
|
|
|
|
const domainUrl = window.location.origin; |
|
|
|
|
!SCURVE ? (dashboardGantt ? window.parent.location.reload() : window.location.replace(`${domainUrl}/#/projects/${GANTT_ID}/${PROJECT_ID}/gantt`)) : window.history.go(-1); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const initMap = () => { |
|
|
|
|
let mymap = L.map("map-area", { |
|
|
|
|
center: center, |
|
|
|
@ -655,6 +681,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', |
|
|
|
|
}).addTo(mymap); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (mymap) { |
|
|
|
|
if (reportDistribution.length > 0) { |
|
|
|
@ -666,6 +693,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, [mymap, reportDistribution]); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
// Add event listener for receiving messages from the iframe
|
|
|
|
|
window.addEventListener("message", handleIframeMessage); |
|
|
|
@ -674,6 +702,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
window.removeEventListener("message", handleIframeMessage); |
|
|
|
|
}; |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
const handleIframeMessage = (event) => { |
|
|
|
|
if (event.data && event.data.action === "getUrl") { |
|
|
|
|
const childUrl = window.location.href; |
|
|
|
@ -684,6 +713,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const RenderGantt = useMemo( |
|
|
|
|
() => ( |
|
|
|
|
<iframe |
|
|
|
@ -700,6 +730,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
), |
|
|
|
|
[activeTabIdx] |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const RenderComments = useMemo(() => { |
|
|
|
|
return ( |
|
|
|
|
<> |
|
|
|
@ -803,12 +834,25 @@ const DashboardProject = (props) => {
|
|
|
|
|
); |
|
|
|
|
}, [overdueActivities, isReadyOverdueActivities]); |
|
|
|
|
return ( |
|
|
|
|
<div style={{ marginLeft: -25, marginRight: -25 }}> |
|
|
|
|
<div style={{ marginLeft: dashboardGantt ? -80 : -25, marginRight: -25 }}> |
|
|
|
|
<NotificationContainer /> |
|
|
|
|
<Row> |
|
|
|
|
<Col span={18}> |
|
|
|
|
<Row> |
|
|
|
|
<Col span={8}> |
|
|
|
|
<Col span={2}> |
|
|
|
|
<Button |
|
|
|
|
style={{ |
|
|
|
|
height: "100%", |
|
|
|
|
width: "100%", |
|
|
|
|
fontSize: "18px" |
|
|
|
|
}} |
|
|
|
|
onClick={handleBack} |
|
|
|
|
type="primary" |
|
|
|
|
> |
|
|
|
|
<Icon icon={arrowLeft} style={{ fontSize: "20px" }} /> Back |
|
|
|
|
</Button> |
|
|
|
|
</Col> |
|
|
|
|
<Col span={6}> |
|
|
|
|
<div |
|
|
|
|
style={{ |
|
|
|
|
border: "solid", |
|
|
|
@ -857,14 +901,14 @@ const DashboardProject = (props) => {
|
|
|
|
|
} |
|
|
|
|
return SCURVE && SCURVE == "1" |
|
|
|
|
? projectName |
|
|
|
|
? calculationStatus |
|
|
|
|
? projectName + " - S-Curve Ready" |
|
|
|
|
: projectName + " - S-Curve Loading" |
|
|
|
|
: null |
|
|
|
|
: projectName + |
|
|
|
|
parentNames + |
|
|
|
|
" - " + |
|
|
|
|
dataGantt.data.data.name_version; |
|
|
|
|
// ? calculationStatus
|
|
|
|
|
// ? projectName + " - S-Curve Ready"
|
|
|
|
|
// : projectName + " - S-Curve Loading"
|
|
|
|
|
// : null
|
|
|
|
|
: projectName |
|
|
|
|
// + parentNames +
|
|
|
|
|
// " - " +
|
|
|
|
|
// dataGantt.data.data.name_version;
|
|
|
|
|
})() |
|
|
|
|
) : ( |
|
|
|
|
<SingleTextLoader /> |
|
|
|
@ -1415,7 +1459,7 @@ const DashboardProject = (props) => {
|
|
|
|
|
</div> |
|
|
|
|
{isReadySCurve ? ( |
|
|
|
|
<ProgressPlanningBar |
|
|
|
|
progress={planningProgress > 100 ? 100 : planningProgress} |
|
|
|
|
progress={planningProgressToDay > 100 ? 100 : planningProgressToDay} |
|
|
|
|
/> |
|
|
|
|
) : ( |
|
|
|
|
<SingleTextLoader width={"100%"} height={30} /> |
|
|
|
|