|
|
@ -20,10 +20,10 @@ const { TextArea } = Input; |
|
|
|
|
|
|
|
|
|
|
|
const styles = { |
|
|
|
const styles = { |
|
|
|
cardContainer: { backgroundColor: '#F8F8F8', margin: 2, paddingLeft: 20, paddingRight: 20, paddingTop: 10 }, |
|
|
|
cardContainer: { backgroundColor: '#F8F8F8', margin: 2, paddingLeft: 20, paddingRight: 20, paddingTop: 10 }, |
|
|
|
cardHeaderContainer: { display: 'flex', flexDirection: 'row', marginBottom: 10 }, |
|
|
|
cardHeaderContainer: { display: 'flex', flexDirection: 'row', marginBottom: 10 }, |
|
|
|
cardChartContainer: { position: 'relative', height: '21vh', margin: 'auto', paddingBottom: 10, justifyContent: 'center' }, |
|
|
|
cardChartContainer: { position: 'relative', height: '21vh', margin: 'auto', paddingBottom: 10, justifyContent: 'center' }, |
|
|
|
cardTitle: { color: '#444444', fontSize: 16, fontWeight: 'bold' }, |
|
|
|
cardTitle: { color: '#444444', fontSize: 16, fontWeight: 'bold' }, |
|
|
|
cardSubtitle: { color: '#888888', fontSize: 12 } |
|
|
|
cardSubtitle: { color: '#888888', fontSize: 12 } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const center = { |
|
|
|
const center = { |
|
|
@ -32,13 +32,13 @@ const center = { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const DashboardProject = () => { |
|
|
|
const DashboardProject = () => { |
|
|
|
const token = localStorage.getItem("token") |
|
|
|
const token = localStorage.getItem("token") |
|
|
|
const HEADER = { |
|
|
|
const HEADER = { |
|
|
|
headers: { |
|
|
|
headers: { |
|
|
|
"Content-Type": "application/json", |
|
|
|
"Content-Type": "application/json", |
|
|
|
"Authorization": `Bearer ${token}` |
|
|
|
"Authorization": `Bearer ${token}` |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
const { PROJECT_ID, GANTT_ID } = useParams(); |
|
|
|
const { PROJECT_ID, GANTT_ID } = useParams(); |
|
|
|
const URL_GANTT = `https://adw-gantt.ospro.id/view-mode/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`; |
|
|
|
const URL_GANTT = `https://adw-gantt.ospro.id/view-mode/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`; |
|
|
|
const mapRef = useRef() |
|
|
|
const mapRef = useRef() |
|
|
@ -80,7 +80,7 @@ const DashboardProject = () => { |
|
|
|
const [healthBySchedule, setHealthBySchedule] = useState('-') |
|
|
|
const [healthBySchedule, setHealthBySchedule] = useState('-') |
|
|
|
const [healthByBudget, setHealthByBudget] = useState('-') |
|
|
|
const [healthByBudget, setHealthByBudget] = useState('-') |
|
|
|
const [reportDistribution, setReportDistribution] = useState([]); |
|
|
|
const [reportDistribution, setReportDistribution] = useState([]); |
|
|
|
let history = useHistory(); |
|
|
|
let history = useHistory(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
@ -101,17 +101,17 @@ const DashboardProject = () => { |
|
|
|
}, [activeTabIdx]); |
|
|
|
}, [activeTabIdx]); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
let deviation = 0; |
|
|
|
let deviation = 0; |
|
|
|
if(plannedCost && totalCost){ |
|
|
|
if (plannedCost && totalCost) { |
|
|
|
deviation = plannedCost - totalCost; |
|
|
|
deviation = plannedCost - totalCost; |
|
|
|
} |
|
|
|
} |
|
|
|
setRemToComplete(deviation.toString()) |
|
|
|
setRemToComplete(deviation.toString()) |
|
|
|
|
|
|
|
|
|
|
|
}, [plannedCost, totalCost]); |
|
|
|
}, [plannedCost, totalCost]); |
|
|
|
|
|
|
|
|
|
|
|
const handleRedirect = () => { |
|
|
|
const handleRedirect = () => { |
|
|
|
history.push("/projects/"+GANTT_ID+"/"+PROJECT_ID+"/gantt"); |
|
|
|
history.push("/projects/" + GANTT_ID + "/" + PROJECT_ID + "/gantt"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const getProjectDetail = async () => { |
|
|
|
const getProjectDetail = async () => { |
|
|
|
setIsReadyProjectDetail(false); |
|
|
|
setIsReadyProjectDetail(false); |
|
|
@ -121,17 +121,17 @@ const DashboardProject = () => { |
|
|
|
if (!result) { |
|
|
|
if (!result) { |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
setIsReadyProjectDetail(true); |
|
|
|
setIsReadyProjectDetail(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
if (result.status !== 200) { |
|
|
|
NotificationManager.error(`Get project detail failed, ${result.data.message}`, "Failed"); |
|
|
|
NotificationManager.error(`Get project detail failed, ${result.data.message}`, "Failed"); |
|
|
|
setIsReadyProjectDetail(true); |
|
|
|
setIsReadyProjectDetail(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
console.log(result.data.data); |
|
|
|
console.log(result.data.data); |
|
|
|
// setComments(result.data.data);
|
|
|
|
// setComments(result.data.data);
|
|
|
|
setProjectName(result.data.data.nama ? result.data.data.nama : '-'); |
|
|
|
setProjectName(result.data.data.nama ? result.data.data.nama : '-'); |
|
|
|
setProjectManagerName(result.data.data.projectManager ? result.data.data.projectManager : '-'); |
|
|
|
setProjectManagerName(result.data.data.projectManager ? result.data.data.projectManager : '-'); |
|
|
|
setCustomerName(result.data.data.company ? result.data.data.company : '-') |
|
|
|
setCustomerName(result.data.data.company ? result.data.data.company : '-') |
|
|
@ -145,7 +145,7 @@ const DashboardProject = () => { |
|
|
|
if (result.data.data.kode_sortname && result.data.data.kode_sortname !== '') { |
|
|
|
if (result.data.data.kode_sortname && result.data.data.kode_sortname !== '') { |
|
|
|
getIntegrationInvoice(result.data.data.kode_sortname) |
|
|
|
getIntegrationInvoice(result.data.data.kode_sortname) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const getSCurve = async () => { |
|
|
|
const getSCurve = async () => { |
|
|
@ -157,18 +157,17 @@ const DashboardProject = () => { |
|
|
|
// "end_date": moment(new Date()).format('YYYY-MM-DD')
|
|
|
|
// "end_date": moment(new Date()).format('YYYY-MM-DD')
|
|
|
|
} |
|
|
|
} |
|
|
|
const result = await axios.post(URL, payload, HEADER).then(res => res).catch(err => err.response) |
|
|
|
const result = await axios.post(URL, payload, HEADER).then(res => res).catch(err => err.response) |
|
|
|
console.log('getSCurve', result); |
|
|
|
|
|
|
|
if (!result) { |
|
|
|
if (!result) { |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
setIsReadySCurve(true); |
|
|
|
setIsReadySCurve(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
if (result.status !== 200) { |
|
|
|
NotificationManager.error(`Get S Curve failed, ${result.data.message}`, "Failed"); |
|
|
|
NotificationManager.error(`Get S Curve failed, ${result.data.message}`, "Failed"); |
|
|
|
setIsReadySCurve(true); |
|
|
|
setIsReadySCurve(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
let selisihProgress = 0; |
|
|
|
let selisihProgress = 0; |
|
|
|
let planningProgress = 0; |
|
|
|
let planningProgress = 0; |
|
|
@ -184,11 +183,11 @@ const DashboardProject = () => { |
|
|
|
setCostDeviation(result.data.data[0].data.budget_control.cost_deviation?.toString()) |
|
|
|
setCostDeviation(result.data.data[0].data.budget_control.cost_deviation?.toString()) |
|
|
|
} |
|
|
|
} |
|
|
|
if (result.data.data.length > 0 && result.data.data[0].data?.percentagePlan && result.data.data[0].data?.percentagePlan.length > 0) { |
|
|
|
if (result.data.data.length > 0 && result.data.data[0].data?.percentagePlan && result.data.data[0].data?.percentagePlan.length > 0) { |
|
|
|
planningProgress = result.data.data[0].data?.percentagePlan[result.data.data[0].data?.percentagePlan.length-1]; |
|
|
|
planningProgress = result.data.data[0].data?.percentagePlan[result.data.data[0].data?.percentagePlan.length - 1]; |
|
|
|
setPlanningProgress(planningProgress); |
|
|
|
setPlanningProgress(planningProgress); |
|
|
|
} |
|
|
|
} |
|
|
|
if (result.data.data.length > 0 && result.data.data[0].data?.percentageReal && result.data.data[0].data?.percentageReal.length > 0) { |
|
|
|
if (result.data.data.length > 0 && result.data.data[0].data?.percentageReal && result.data.data[0].data?.percentageReal.length > 0) { |
|
|
|
actualProgress = result.data.data[0].data?.percentageReal[result.data.data[0].data?.percentageReal.length-1]; |
|
|
|
actualProgress = result.data.data[0].data?.percentageReal[result.data.data[0].data?.percentageReal.length - 1]; |
|
|
|
setActualProgress(actualProgress); |
|
|
|
setActualProgress(actualProgress); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -202,7 +201,7 @@ const DashboardProject = () => { |
|
|
|
|
|
|
|
|
|
|
|
setHealthBySchedule(statusHealthBySchedule) |
|
|
|
setHealthBySchedule(statusHealthBySchedule) |
|
|
|
setIsReadySCurve(true); |
|
|
|
setIsReadySCurve(true); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const getOverdueActivities = async () => { |
|
|
|
const getOverdueActivities = async () => { |
|
|
@ -217,21 +216,21 @@ const DashboardProject = () => { |
|
|
|
if (!result) { |
|
|
|
if (!result) { |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
setIsReadyOverdueActivities(true); |
|
|
|
setIsReadyOverdueActivities(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
if (result.status !== 200) { |
|
|
|
NotificationManager.error(`Get Overdue Activities failed, ${result.data.message}`, "Failed"); |
|
|
|
NotificationManager.error(`Get Overdue Activities failed, ${result.data.message}`, "Failed"); |
|
|
|
setIsReadyOverdueActivities(true); |
|
|
|
setIsReadyOverdueActivities(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
if (result.data.data.overdueActivities) { |
|
|
|
if (result.data.data.overdueActivities) { |
|
|
|
setOverdueActivities(result.data.data.overdueActivities) |
|
|
|
setOverdueActivities(result.data.data.overdueActivities) |
|
|
|
} |
|
|
|
} |
|
|
|
setHealthByBudget(result.data.data.budget_health) |
|
|
|
setHealthByBudget(result.data.data.budget_health) |
|
|
|
setIsReadyOverdueActivities(true); |
|
|
|
setIsReadyOverdueActivities(true); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const getIntegrationInvoice = async (kode_sortname) => { |
|
|
|
const getIntegrationInvoice = async (kode_sortname) => { |
|
|
@ -245,16 +244,15 @@ const DashboardProject = () => { |
|
|
|
if (!result) { |
|
|
|
if (!result) { |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
setIsReadyIntegrationInvoice(true); |
|
|
|
setIsReadyIntegrationInvoice(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
if (result.status !== 200) { |
|
|
|
NotificationManager.error(`Get integration invoice failed, ${result.data.message}`, "Failed"); |
|
|
|
NotificationManager.error(`Get integration invoice failed, ${result.data.message}`, "Failed"); |
|
|
|
setIsReadyIntegrationInvoice(true); |
|
|
|
setIsReadyIntegrationInvoice(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
// console.log()
|
|
|
|
|
|
|
|
if (result.data.data.data) { |
|
|
|
if (result.data.data.data) { |
|
|
|
let total_invoice = result.data.data.data.total_invoice_amount; |
|
|
|
let total_invoice = result.data.data.data.total_invoice_amount; |
|
|
|
let cash_in = result.data.data.data.total_invoice_paid_amount; |
|
|
|
let cash_in = result.data.data.data.total_invoice_paid_amount; |
|
|
@ -262,12 +260,12 @@ const DashboardProject = () => { |
|
|
|
let outstanding_balance = total_invoice - cash_in; |
|
|
|
let outstanding_balance = total_invoice - cash_in; |
|
|
|
setTotalInvoice(total_invoice ? total_invoice.toString() : null); |
|
|
|
setTotalInvoice(total_invoice ? total_invoice.toString() : null); |
|
|
|
setCashIn(cash_in ? cash_in.toString() : null) |
|
|
|
setCashIn(cash_in ? cash_in.toString() : null) |
|
|
|
total_cost = total_cost.toString().split('.')[0] |
|
|
|
total_cost = total_cost.toString().split('.')[0] |
|
|
|
setTotalCost(total_cost? total_cost.toString() : null) |
|
|
|
setTotalCost(total_cost ? total_cost.toString() : null) |
|
|
|
setOutstandingBalance(outstanding_balance ? outstanding_balance.toString() : null); |
|
|
|
setOutstandingBalance(outstanding_balance ? outstanding_balance.toString() : null); |
|
|
|
} |
|
|
|
} |
|
|
|
setIsReadyIntegrationInvoice(true); |
|
|
|
setIsReadyIntegrationInvoice(true); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const getReportDistribution = async () => { |
|
|
|
const getReportDistribution = async () => { |
|
|
@ -283,66 +281,66 @@ const DashboardProject = () => { |
|
|
|
if (!result) { |
|
|
|
if (!result) { |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
setIsReadyReportDistribution(true); |
|
|
|
setIsReadyReportDistribution(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
if (result.status !== 200) { |
|
|
|
NotificationManager.error(`Get report distribution failed, ${result.data.message}`, "Failed"); |
|
|
|
NotificationManager.error(`Get report distribution failed, ${result.data.message}`, "Failed"); |
|
|
|
setIsReadyReportDistribution(true); |
|
|
|
setIsReadyReportDistribution(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
setReportDistribution(result.data.data); |
|
|
|
setReportDistribution(result.data.data); |
|
|
|
setIsReadyReportDistribution(true); |
|
|
|
setIsReadyReportDistribution(true); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const getComments = async () => { |
|
|
|
const getComments = async () => { |
|
|
|
setIsReadyComments(false); |
|
|
|
setIsReadyComments(false); |
|
|
|
const URL = `${BASE_OSPRO}/api/project-comment/search`; |
|
|
|
const URL = `${BASE_OSPRO}/api/project-comment/search`; |
|
|
|
const payload = { |
|
|
|
const payload = { |
|
|
|
columns: [ |
|
|
|
columns: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
name: "project_id", |
|
|
|
name: "project_id", |
|
|
|
logic_operator: "=", |
|
|
|
logic_operator: "=", |
|
|
|
value: PROJECT_ID.toString(), |
|
|
|
value: PROJECT_ID.toString(), |
|
|
|
operator: "AND", |
|
|
|
operator: "AND", |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "gantt_id", |
|
|
|
|
|
|
|
logic_operator: "=", |
|
|
|
|
|
|
|
value: GANTT_ID.toString(), |
|
|
|
|
|
|
|
operator: "AND", |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
joins: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
name: "gantt_id", |
|
|
|
name: "m_users", |
|
|
|
logic_operator: "=", |
|
|
|
column_join: "sender_id", |
|
|
|
value: GANTT_ID.toString(), |
|
|
|
column_results: ["name", "username"], |
|
|
|
operator: "AND", |
|
|
|
} |
|
|
|
} |
|
|
|
], |
|
|
|
], |
|
|
|
orders: { columns: ["created_at"], ascending: false }, |
|
|
|
joins: [ |
|
|
|
paging: { start: 0, length: -1 }, |
|
|
|
{ |
|
|
|
}; |
|
|
|
name: "m_users", |
|
|
|
|
|
|
|
column_join: "sender_id", |
|
|
|
|
|
|
|
column_results: ["name", "username"], |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
orders: { columns: ["created_at"], ascending: false }, |
|
|
|
|
|
|
|
paging: { start: 0, length: -1 }, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const result = await axios.post(URL, payload, HEADER).then(res => res).catch(err => err.response) |
|
|
|
const result = await axios.post(URL, payload, HEADER).then(res => res).catch(err => err.response) |
|
|
|
console.log('getComments', result); |
|
|
|
console.log('getComments', result); |
|
|
|
if (!result) { |
|
|
|
if (!result) { |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
setIsReadyComments(true); |
|
|
|
setIsReadyComments(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
if (result.status !== 200) { |
|
|
|
NotificationManager.error(`Get comments failed, ${result.data.message}`, "Failed"); |
|
|
|
NotificationManager.error(`Get comments failed, ${result.data.message}`, "Failed"); |
|
|
|
setIsReadyComments(true); |
|
|
|
setIsReadyComments(true); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
else if (result.status == 200 && result.data.data) { |
|
|
|
setComments(result.data.data); |
|
|
|
setComments(result.data.data); |
|
|
|
setIsReadyComments(true); |
|
|
|
setIsReadyComments(true); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleSendComment = async () => { |
|
|
|
const handleSendComment = async () => { |
|
|
@ -365,14 +363,14 @@ const DashboardProject = () => { |
|
|
|
if (!result) { |
|
|
|
if (!result) { |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
NotificationManager.error(`Could not connect to internet.`, "Failed"); |
|
|
|
setIsSendingComment(false); |
|
|
|
setIsSendingComment(false); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (result.status !== 200) { |
|
|
|
if (result.status !== 200) { |
|
|
|
NotificationManager.error(`Post comment failed, ${result.data.message}`, "Failed"); |
|
|
|
NotificationManager.error(`Post comment failed, ${result.data.message}`, "Failed"); |
|
|
|
setIsSendingComment(false); |
|
|
|
setIsSendingComment(false); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (result.status === 200) { |
|
|
|
else if (result.status === 200) { |
|
|
|
NotificationManager.success(`Post comment success`, "Success"); |
|
|
|
NotificationManager.success(`Post comment success`, "Success"); |
|
|
|
resetInputComment(); |
|
|
|
resetInputComment(); |
|
|
@ -392,7 +390,7 @@ const DashboardProject = () => { |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
setMymap(mymap); |
|
|
|
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); |
|
|
|
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(() => { |
|
|
|
useEffect(() => { |
|
|
@ -406,36 +404,36 @@ const DashboardProject = () => { |
|
|
|
}, [mymap, reportDistribution]) |
|
|
|
}, [mymap, reportDistribution]) |
|
|
|
|
|
|
|
|
|
|
|
const RenderGantt = useMemo(() => ( |
|
|
|
const RenderGantt = useMemo(() => ( |
|
|
|
<iframe |
|
|
|
<iframe |
|
|
|
id="frame-gantt" |
|
|
|
id="frame-gantt" |
|
|
|
src={URL_GANTT} |
|
|
|
src={URL_GANTT} |
|
|
|
style={{ |
|
|
|
style={{ |
|
|
|
width: '100%', |
|
|
|
width: '100%', |
|
|
|
height: '100%', |
|
|
|
height: '100%', |
|
|
|
}} |
|
|
|
}} |
|
|
|
scrolling="no" |
|
|
|
scrolling="no" |
|
|
|
frameBorder="0" |
|
|
|
frameBorder="0" |
|
|
|
allow="fullscreen" |
|
|
|
allow="fullscreen" |
|
|
|
></iframe> |
|
|
|
></iframe> |
|
|
|
), [activeTabIdx]) |
|
|
|
), [activeTabIdx]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const RenderComments = useMemo(() => { |
|
|
|
const RenderComments = useMemo(() => { |
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<> |
|
|
|
<> |
|
|
|
<div style={{padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2}}> |
|
|
|
<div style={{ padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2 }}> |
|
|
|
<TextArea value={comment} onChange={(e) => setComment(e.target.value)} rows={3} placeholder="Write comment here" disabled={isSendingComment} /> |
|
|
|
<TextArea value={comment} onChange={(e) => setComment(e.target.value)} rows={3} placeholder="Write comment here" disabled={isSendingComment} /> |
|
|
|
<div style={{float: 'right', marginTop: -40, marginRight: 10}}> |
|
|
|
<div style={{ float: 'right', marginTop: -40, marginRight: 10 }}> |
|
|
|
<Button title='Send' type="primary" shape="circle" icon={<SendOutlined />} size={20} onClick={handleSendComment} disabled={isSendingComment} /> |
|
|
|
<Button title='Send' type="primary" shape="circle" icon={<SendOutlined />} size={20} onClick={handleSendComment} disabled={isSendingComment} /> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
{!isReadyComments && <ListLoader />} |
|
|
|
|
|
|
|
{isReadyComments && comments && comments.length < 1 && <div style={{ flex: 1, textAlign: 'center', color: '#E80053', marginTop: 50, marginBottom: 50 }}>No comments found.</div>} |
|
|
|
|
|
|
|
{comments && comments.length > 0 && comments.map((item, idx) => |
|
|
|
|
|
|
|
<Comment key={idx} name={item.join_first_name} comment={item.comment} created_at={item.created_at} /> |
|
|
|
|
|
|
|
)} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
{!isReadyComments && <ListLoader />} |
|
|
|
|
|
|
|
{isReadyComments && comments && comments.length < 1 && <div style={{flex: 1, textAlign: 'center', color: '#E80053', marginTop: 50, marginBottom: 50}}>No comments found.</div>} |
|
|
|
|
|
|
|
{comments && comments.length > 0 && comments.map((item, idx) => |
|
|
|
|
|
|
|
<Comment key={idx} name={item.join_first_name} comment={item.comment} created_at={item.created_at} /> |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</> |
|
|
|
</> |
|
|
|
) |
|
|
|
) |
|
|
|
}, [comment, comments, isSendingComment, isReadyComments]) |
|
|
|
}, [comment, comments, isSendingComment, isReadyComments]) |
|
|
@ -444,7 +442,7 @@ const DashboardProject = () => { |
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
{!isReadyOverdueActivities && <ListLoader />} |
|
|
|
{!isReadyOverdueActivities && <ListLoader />} |
|
|
|
{isReadyOverdueActivities && overdueActivities && overdueActivities.length < 1 && <div style={{flex: 1, textAlign: 'center', color: '#E80053', marginTop: 50, marginBottom: 50}}>No overdue activity found.</div>} |
|
|
|
{isReadyOverdueActivities && overdueActivities && overdueActivities.length < 1 && <div style={{ flex: 1, textAlign: 'center', color: '#E80053', marginTop: 50, marginBottom: 50 }}>No overdue activity found.</div>} |
|
|
|
{isReadyOverdueActivities && overdueActivities && overdueActivities.length > 0 && overdueActivities.map((item, idx) => { |
|
|
|
{isReadyOverdueActivities && overdueActivities && overdueActivities.length > 0 && overdueActivities.map((item, idx) => { |
|
|
|
let end_date = null; |
|
|
|
let end_date = null; |
|
|
|
let today = null; |
|
|
|
let today = null; |
|
|
@ -462,58 +460,58 @@ const DashboardProject = () => { |
|
|
|
) |
|
|
|
) |
|
|
|
}, [overdueActivities, isReadyOverdueActivities]) |
|
|
|
}, [overdueActivities, isReadyOverdueActivities]) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div style={{ marginLeft: -25, marginRight: -25 }}> |
|
|
|
<div style={{ marginLeft: -25, marginRight: -25 }}> |
|
|
|
<NotificationContainer /> |
|
|
|
<NotificationContainer /> |
|
|
|
<Fab |
|
|
|
<Fab |
|
|
|
icon={<i className="fa fa-bars"/>} |
|
|
|
icon={<i className="fa fa-bars" />} |
|
|
|
alwaysShowTitle={true} |
|
|
|
alwaysShowTitle={true} |
|
|
|
> |
|
|
|
> |
|
|
|
<Action |
|
|
|
<Action |
|
|
|
text="Gantt Chart" |
|
|
|
text="Gantt Chart" |
|
|
|
onClick={() => handleRedirect()} |
|
|
|
onClick={() => handleRedirect()} |
|
|
|
> |
|
|
|
> |
|
|
|
<i className="fa fa-gears" /> |
|
|
|
<i className="fa fa-gears" /> |
|
|
|
</Action> |
|
|
|
</Action> |
|
|
|
</Fab> |
|
|
|
</Fab> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={18}> |
|
|
|
<Col span={18}> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={8}> |
|
|
|
<Col span={8}> |
|
|
|
<div style={{border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2}}> |
|
|
|
<div style={{ border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'row', marginBottom: 10 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'row', marginBottom: 10 }}> |
|
|
|
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}> |
|
|
|
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}> |
|
|
|
<div style={{fontSize: 16, fontWeight: 'bold', marginBottom: 10}}>Project</div> |
|
|
|
<div style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 10 }}>Project</div> |
|
|
|
<div style={{fontSize: 14}}>{isReadyProjectDetail ? projectName : <SingleTextLoader />}</div> |
|
|
|
<div style={{ fontSize: 14 }}>{isReadyProjectDetail ? projectName : <SingleTextLoader />}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<i className="fa fa-check-square" style={{fontSize: 28}}></i> |
|
|
|
<i className="fa fa-check-square" style={{ fontSize: 28 }}></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
<Col span={8}> |
|
|
|
<Col span={8}> |
|
|
|
<div style={{border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2}}> |
|
|
|
<div style={{ border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'row', marginBottom: 10 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'row', marginBottom: 10 }}> |
|
|
|
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}> |
|
|
|
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}> |
|
|
|
<div style={{fontSize: 16, fontWeight: 'bold', marginBottom: 10}}>Project Manager</div> |
|
|
|
<div style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 10 }}>Project Manager</div> |
|
|
|
<div style={{fontSize: 14}}>{isReadyProjectDetail ? projectManagerName : <SingleTextLoader />}</div> |
|
|
|
<div style={{ fontSize: 14 }}>{isReadyProjectDetail ? projectManagerName : <SingleTextLoader />}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<i className="fa fa-user" style={{fontSize: 28}}></i> |
|
|
|
<i className="fa fa-user" style={{ fontSize: 28 }}></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
<Col span={8}> |
|
|
|
<Col span={8}> |
|
|
|
<div style={{border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2}}> |
|
|
|
<div style={{ border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'row', marginBottom: 10 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'row', marginBottom: 10 }}> |
|
|
|
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}> |
|
|
|
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}> |
|
|
|
<div style={{fontSize: 16, fontWeight: 'bold', marginBottom: 10}}>Customer</div> |
|
|
|
<div style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 10 }}>Customer</div> |
|
|
|
<div style={{fontSize: 14}}>{isReadyProjectDetail ? customerName : <SingleTextLoader />}</div> |
|
|
|
<div style={{ fontSize: 14 }}>{isReadyProjectDetail ? customerName : <SingleTextLoader />}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<i className="fa fa-home" style={{fontSize: 28}}></i> |
|
|
|
<i className="fa fa-home" style={{ fontSize: 28 }}></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@ -521,15 +519,15 @@ const DashboardProject = () => { |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={8}> |
|
|
|
<Col span={8}> |
|
|
|
<div style={{border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2}}> |
|
|
|
<div style={{ border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'column', marginBottom: 10 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'column', marginBottom: 10 }}> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<div style={{fontSize: 16, fontWeight: 'bold', marginBottom: 10}}>Schedule</div> |
|
|
|
<div style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 10 }}>Schedule</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<Row> |
|
|
|
<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, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Planned Start</Col> |
|
|
|
<Col span={12} style={{fontSize: 11}}> |
|
|
|
<Col span={12} style={{ fontSize: 11 }}> |
|
|
|
{isReadyProjectDetail ? |
|
|
|
{isReadyProjectDetail ? |
|
|
|
plannedStart ? moment(plannedStart).format('D MMMM YYYY') : '-' |
|
|
|
plannedStart ? moment(plannedStart).format('D MMMM YYYY') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
@ -537,8 +535,8 @@ const DashboardProject = () => { |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<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, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Actual Start</Col> |
|
|
|
<Col span={12} style={{fontSize: 11}}> |
|
|
|
<Col span={12} style={{ fontSize: 11 }}> |
|
|
|
{isReadyProjectDetail ? |
|
|
|
{isReadyProjectDetail ? |
|
|
|
actualStart ? moment(actualStart).format('D MMMM YYYY') : '-' |
|
|
|
actualStart ? moment(actualStart).format('D MMMM YYYY') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
@ -546,8 +544,8 @@ const DashboardProject = () => { |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<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, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Planned Finish</Col> |
|
|
|
<Col span={12} style={{fontSize: 11}}> |
|
|
|
<Col span={12} style={{ fontSize: 11 }}> |
|
|
|
{isReadyProjectDetail ? |
|
|
|
{isReadyProjectDetail ? |
|
|
|
plannedFinish ? moment(plannedFinish).format('D MMMM YYYY') : '-' |
|
|
|
plannedFinish ? moment(plannedFinish).format('D MMMM YYYY') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
@ -555,8 +553,8 @@ const DashboardProject = () => { |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<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, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Estimated Finish</Col> |
|
|
|
<Col span={12} style={{fontSize: 11}}> |
|
|
|
<Col span={12} style={{ fontSize: 11 }}> |
|
|
|
{isReadyProjectDetail ? |
|
|
|
{isReadyProjectDetail ? |
|
|
|
estimatedFinish ? moment(estimatedFinish).format('D MMMM YYYY') : '-' |
|
|
|
estimatedFinish ? moment(estimatedFinish).format('D MMMM YYYY') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
@ -568,22 +566,22 @@ const DashboardProject = () => { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
<Col span={16}> |
|
|
|
<Col span={16}> |
|
|
|
<div style={{border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2}}> |
|
|
|
<div style={{ border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 10, margin: 2 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'column', marginBottom: 10 }}> |
|
|
|
<div style={{ display: 'flex', flexDirection: 'column', marginBottom: 10 }}> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<div style={{fontSize: 16, fontWeight: 'bold', marginBottom: 10}}>Financials</div> |
|
|
|
<div style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 10 }}>Financials</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={7} style={{fontSize: 11, fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Current Budget</Col> |
|
|
|
<Col span={7} style={{ fontSize: 11, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Current Budget</Col> |
|
|
|
<Col span={5} style={{fontSize: 11}}> |
|
|
|
<Col span={5} style={{ fontSize: 11 }}> |
|
|
|
{isReadyProjectDetail ? |
|
|
|
{isReadyProjectDetail ? |
|
|
|
plannedCost ? renderFormatRupiah(plannedCost , 'Rp.') : '-' |
|
|
|
plannedCost ? renderFormatRupiah(plannedCost, 'Rp.') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
} |
|
|
|
} |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
<Col span={7} style={{fontSize: 11, fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Add Cost to Complete</Col> |
|
|
|
<Col span={7} style={{ fontSize: 11, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Add Cost to Complete</Col> |
|
|
|
<Col span={5} style={{fontSize: 11}}> |
|
|
|
<Col span={5} style={{ fontSize: 11 }}> |
|
|
|
{isReadySCurve ? |
|
|
|
{isReadySCurve ? |
|
|
|
addCostToComplete ? renderFormatRupiah(addCostToComplete, 'Rp.') : '-' |
|
|
|
addCostToComplete ? renderFormatRupiah(addCostToComplete, 'Rp.') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
@ -591,40 +589,43 @@ const DashboardProject = () => { |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={7} style={{fontSize: 11, fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Actual to Date</Col> |
|
|
|
<Col span={7} style={{ fontSize: 11, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Actual to Date</Col> |
|
|
|
<Col span={5} style={{fontSize: 11}}> |
|
|
|
<Col span={5} style={{ fontSize: 11 }}> |
|
|
|
{isReadyIntegrationInvoice ? |
|
|
|
{isReadyIntegrationInvoice ? |
|
|
|
totalCost ? renderFormatRupiah(totalCost, 'Rp.') : '-' |
|
|
|
totalCost ? renderFormatRupiah(totalCost, 'Rp.') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
} |
|
|
|
} |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
<Col span={7} style={{fontSize: 11, fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Est. at Completion</Col> |
|
|
|
<Col span={7} style={{ fontSize: 11, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Est. at Completion</Col> |
|
|
|
<Col span={5} style={{fontSize: 11}}> |
|
|
|
<Col span={5} style={{ fontSize: 11 }}> |
|
|
|
{isReadySCurve ? |
|
|
|
{isReadySCurve ? |
|
|
|
plannedCost > bcwp ? renderFormatRupiah(plannedCost, 'Rp.') : renderFormatRupiah(bcwp, 'Rp.') |
|
|
|
plannedCost !== null && bcwp !== null ? |
|
|
|
|
|
|
|
plannedCost > bcwp ? renderFormatRupiah(plannedCost, 'Rp.') : renderFormatRupiah(bcwp, 'Rp.') |
|
|
|
|
|
|
|
: '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={7} style={{fontSize: 11, fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>BCWP (cost vs perform)</Col> |
|
|
|
<Col span={7} style={{ fontSize: 11, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>BCWP (cost vs perform)</Col> |
|
|
|
<Col span={5} style={{fontSize: 11}}> |
|
|
|
<Col span={5} style={{ fontSize: 11 }}> |
|
|
|
{isReadySCurve ? |
|
|
|
{isReadySCurve ? |
|
|
|
bcwp ? renderFormatRupiah(bcwp, 'Rp.') : '-' |
|
|
|
bcwp ? renderFormatRupiah(bcwp, 'Rp.') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
} |
|
|
|
} |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
<Col span={7} style={{fontSize: 11, fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Cost Deviation</Col> |
|
|
|
<Col span={7} style={{ fontSize: 11, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Cost Deviation</Col> |
|
|
|
<Col span={5} style={{fontSize: 11}}> |
|
|
|
<Col span={5} style={{ fontSize: 11 }}> |
|
|
|
{isReadyProjectDetail && isReadyIntegrationInvoice ? |
|
|
|
{isReadyProjectDetail && isReadyIntegrationInvoice ? |
|
|
|
totalCost > plannedCost ? renderFormatRupiah( (totalCost-plannedCost).toString(), 'Rp.') : 'Rp. 0' |
|
|
|
totalCost > plannedCost ? renderFormatRupiah((totalCost - plannedCost).toString(), 'Rp.') : 'Rp. 0' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
} |
|
|
|
} |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={7} style={{fontSize: 11, fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Rem. to Complete</Col> |
|
|
|
<Col span={7} style={{ fontSize: 11, fontWeight: 'bold' }}><i className="fa fa-calendar" style={{ marginRight: 8 }}></i>Rem. to Complete</Col> |
|
|
|
<Col span={5} style={{fontSize: 11}}> |
|
|
|
<Col span={5} style={{ fontSize: 11 }}> |
|
|
|
{isReadyProjectDetail && isReadyIntegrationInvoice ? |
|
|
|
{isReadyProjectDetail && isReadyIntegrationInvoice ? |
|
|
|
remToComplete ? renderFormatRupiah(remToComplete, 'Rp.') : '-' |
|
|
|
remToComplete ? renderFormatRupiah(remToComplete, 'Rp.') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
@ -636,128 +637,128 @@ const DashboardProject = () => { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<div style={{margin: 2, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD'}}> |
|
|
|
<div style={{ margin: 2, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD' }}> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={12}> |
|
|
|
<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> |
|
|
|
<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> |
|
|
|
<Col span={12}> |
|
|
|
<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> |
|
|
|
<div style={{ backgroundColor: activeTabIdx === 1 ? '#FFFFFF' : '#D9D9D9', padding: 8, fontWeight: 'bold', cursor: 'pointer', color: activeTabIdx === 1 ? '#000000' : '#4E4C4C' }} onClick={() => setActiveTabIdx(1)}>Maps</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={24}> |
|
|
|
<Col span={24}> |
|
|
|
<div style={{maxHeight: '55vh'}}> |
|
|
|
<div style={{ maxHeight: '55vh' }}> |
|
|
|
{/* { activeTabIdx === 0 && <div style={{height: '52vh', width: '100%'}}>{RenderGantt}</div> } |
|
|
|
{/* { activeTabIdx === 0 && <div style={{height: '52vh', width: '100%'}}>{RenderGantt}</div> } |
|
|
|
{ activeTabIdx === 1 && <div id="map-area" style={{height: '52vh'}} ref={mapRef}></div> } */} |
|
|
|
{ activeTabIdx === 1 && <div id="map-area" style={{height: '52vh'}} ref={mapRef}></div> } */} |
|
|
|
<div style={{height: '56vh', width: '100%', display: activeTabIdx === 0 ? 'block' : 'none'}}>{RenderGantt}</div> |
|
|
|
<div style={{ height: '56vh', width: '100%', display: activeTabIdx === 0 ? 'block' : 'none' }}>{RenderGantt}</div> |
|
|
|
{ activeTabIdx === 1 && <div id="map-area" style={{height: '56vh'}} ref={mapRef}></div> } |
|
|
|
{activeTabIdx === 1 && <div id="map-area" style={{ height: '56vh' }} ref={mapRef}></div>} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
<Col span={6}> |
|
|
|
<Col span={6}> |
|
|
|
<div style={{margin: 2}}> |
|
|
|
<div style={{ margin: 2 }}> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={24}> |
|
|
|
<Col span={24}> |
|
|
|
<div style={{backgroundColor: '#222222', padding: 10, marginBottom: 5}}> |
|
|
|
<div style={{ backgroundColor: '#222222', padding: 10, marginBottom: 5 }}> |
|
|
|
<div style={{color: '#FFFFFF', textAlign: 'center', marginBottom: 10, fontWeight: 'bold'}}>Progress</div> |
|
|
|
<div style={{ color: '#FFFFFF', textAlign: 'center', marginBottom: 10, fontWeight: 'bold' }}>Progress</div> |
|
|
|
{isReadySCurve ? |
|
|
|
{isReadySCurve ? |
|
|
|
<ProgressPlanningBar progress={planningProgress} /> |
|
|
|
<ProgressPlanningBar progress={planningProgress} /> |
|
|
|
: |
|
|
|
: |
|
|
|
<SingleTextLoader width={"100%"} height={30} /> |
|
|
|
<SingleTextLoader width={"100%"} height={30} /> |
|
|
|
} |
|
|
|
} |
|
|
|
<div style={{marginTop: 10, marginBottom: 10}}></div> |
|
|
|
<div style={{ marginTop: 10, marginBottom: 10 }}></div> |
|
|
|
{isReadySCurve ? |
|
|
|
{isReadySCurve ? |
|
|
|
<ProgressActualBar progress={actualProgress} /> |
|
|
|
<ProgressActualBar progress={actualProgress} /> |
|
|
|
: |
|
|
|
: |
|
|
|
<SingleTextLoader width={"100%"} height={30} /> |
|
|
|
<SingleTextLoader width={"100%"} height={30} /> |
|
|
|
} |
|
|
|
} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={12}> |
|
|
|
<Col span={12}> |
|
|
|
<div style={{backgroundColor: '#FFFFFF', padding: 10, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', marginBottom: 5, marginRight: 2}}> |
|
|
|
<div style={{ backgroundColor: '#FFFFFF', padding: 10, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', marginBottom: 5, marginRight: 2 }}> |
|
|
|
<div style={{color: '#000000', textAlign: 'center', marginBottom: 10, fontWeight: 'bold', fontSize: 12}}>Health By Budget</div> |
|
|
|
<div style={{ color: '#000000', textAlign: 'center', marginBottom: 10, fontWeight: 'bold', fontSize: 12 }}>Health By Budget</div> |
|
|
|
{isReadyOverdueActivities ? <HealthByBudget status={healthByBudget} /> : <SingleTextLoader width={"100%"} height={30} /> } |
|
|
|
{isReadyOverdueActivities ? <HealthByBudget status={healthByBudget} /> : <SingleTextLoader width={"100%"} height={30} />} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
<Col span={12}> |
|
|
|
<Col span={12}> |
|
|
|
<div style={{backgroundColor: '#FFFFFF', padding: 10, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', marginBottom: 5, marginLeft: 2}}> |
|
|
|
<div style={{ backgroundColor: '#FFFFFF', padding: 10, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', marginBottom: 5, marginLeft: 2 }}> |
|
|
|
<div style={{color: '#000000', textAlign: 'center', marginBottom: 10, fontWeight: 'bold', fontSize: 12}}>Health By Schedule</div> |
|
|
|
<div style={{ color: '#000000', textAlign: 'center', marginBottom: 10, fontWeight: 'bold', fontSize: 12 }}>Health By Schedule</div> |
|
|
|
{isReadySCurve ? <HealthBySchedule status={healthBySchedule} /> : <SingleTextLoader width={"100%"} height={30} /> } |
|
|
|
{isReadySCurve ? <HealthBySchedule status={healthBySchedule} /> : <SingleTextLoader width={"100%"} height={30} />} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={24}> |
|
|
|
<Col span={24}> |
|
|
|
<div style={{backgroundColor: '#FFFFFF', padding: 10, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', marginBottom: 5, marginRight: 2}}> |
|
|
|
<div style={{ backgroundColor: '#FFFFFF', padding: 10, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', marginBottom: 5, marginRight: 2 }}> |
|
|
|
{/* <div style={{color: '#000000', textAlign: 'center', marginBottom: 10, fontWeight: 'bold', fontSize: 12}}>Health By Schedule</div> |
|
|
|
{/* <div style={{color: '#000000', textAlign: 'center', marginBottom: 10, fontWeight: 'bold', fontSize: 12}}>Health By Schedule</div> |
|
|
|
<div style={{backgroundColor: '#52AC0B', color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10}}> |
|
|
|
<div style={{backgroundColor: '#52AC0B', color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10}}> |
|
|
|
<div style={{textAlign: 'center', fontWeight: 500, fontSize: 12}}>On Budget</div> |
|
|
|
<div style={{textAlign: 'center', fontWeight: 500, fontSize: 12}}>On Budget</div> |
|
|
|
</div> */} |
|
|
|
</div> */} |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={12}>Total Invoice</Col> |
|
|
|
<Col span={12}>Total Invoice</Col> |
|
|
|
<Col span={12} style={{textAlign: 'right'}}> |
|
|
|
<Col span={12} style={{ textAlign: 'right' }}> |
|
|
|
{isReadyIntegrationInvoice ? |
|
|
|
{isReadyIntegrationInvoice ? |
|
|
|
totalInvoice ? renderFormatRupiah(totalInvoice, 'Rp.') : '-' |
|
|
|
totalInvoice ? renderFormatRupiah(totalInvoice, 'Rp.') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
} |
|
|
|
} |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={12}>Cash In</Col> |
|
|
|
<Col span={12}>Cash In</Col> |
|
|
|
<Col span={12} style={{textAlign: 'right'}}> |
|
|
|
<Col span={12} style={{ textAlign: 'right' }}> |
|
|
|
{isReadyIntegrationInvoice ? |
|
|
|
{isReadyIntegrationInvoice ? |
|
|
|
cashIn ? renderFormatRupiah(cashIn, 'Rp.') : '-' |
|
|
|
cashIn ? renderFormatRupiah(cashIn, 'Rp.') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
} |
|
|
|
} |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={24}><hr style={{margin: 2}}/></Col> |
|
|
|
<Col span={24}><hr style={{ margin: 2 }} /></Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={12}>Outstanding Balance</Col> |
|
|
|
<Col span={12}>Outstanding Balance</Col> |
|
|
|
<Col span={12} style={{textAlign: 'right', color: '#E80053', fontWeight: 500}}> |
|
|
|
<Col span={12} style={{ textAlign: 'right', color: '#E80053', fontWeight: 500 }}> |
|
|
|
{isReadyIntegrationInvoice ? |
|
|
|
{isReadyIntegrationInvoice ? |
|
|
|
outstandingBalance ? renderFormatRupiah(outstandingBalance, 'Rp.') : '-' |
|
|
|
outstandingBalance ? renderFormatRupiah(outstandingBalance, 'Rp.') : '-' |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
: <SingleTextLoader width={100} height={10} /> |
|
|
|
} |
|
|
|
} |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<Row> |
|
|
|
<Row> |
|
|
|
<Col span={24}> |
|
|
|
<Col span={24}> |
|
|
|
<div style={{border: 'solid', borderWidth: 1, borderColor: '#DDDDDD'}}> |
|
|
|
<div style={{ border: 'solid', borderWidth: 1, borderColor: '#DDDDDD' }}> |
|
|
|
{/* <div style={{display: 'flex', alignItems: 'center'}}> |
|
|
|
{/* <div style={{display: 'flex', alignItems: 'center'}}> |
|
|
|
<div style={{flex: 1, margin: 'auto', cursor: 'pointer', textAlign: 'center', backgroundColor: activeTabCommentIdx === 0 ? '#FFFFFF' : '#D9D9D9', color: activeTabCommentIdx === 0 ? '#000000' : '#FFFFFF', fontWeight: 500, padding: 2}} onClick={() => setActiveTabCommentIdx(0)}>Behind Task</div> |
|
|
|
<div style={{flex: 1, margin: 'auto', cursor: 'pointer', textAlign: 'center', backgroundColor: activeTabCommentIdx === 0 ? '#FFFFFF' : '#D9D9D9', color: activeTabCommentIdx === 0 ? '#000000' : '#FFFFFF', fontWeight: 500, padding: 2}} onClick={() => setActiveTabCommentIdx(0)}>Behind Task</div> |
|
|
|
<div style={{flex: 1, margin: 'auto', cursor: 'pointer', textAlign: 'center', backgroundColor: activeTabCommentIdx === 1 ? '#FFFFFF' : '#D9D9D9', color: activeTabCommentIdx === 1 ? '#000000' : '#FFFFFF', fontWeight: 500, padding: 2, fontSize: 12}} onClick={() => setActiveTabCommentIdx(1)}>Comment From Customer</div> |
|
|
|
<div style={{flex: 1, margin: 'auto', cursor: 'pointer', textAlign: 'center', backgroundColor: activeTabCommentIdx === 1 ? '#FFFFFF' : '#D9D9D9', color: activeTabCommentIdx === 1 ? '#000000' : '#FFFFFF', fontWeight: 500, padding: 2, fontSize: 12}} onClick={() => setActiveTabCommentIdx(1)}>Comment From Customer</div> |
|
|
|
</div> */} |
|
|
|
</div> */} |
|
|
|
<Row style={{alignItems: 'center', marginBottom: 5}}> |
|
|
|
<Row style={{ alignItems: 'center', marginBottom: 5 }}> |
|
|
|
<Col span={12}> |
|
|
|
<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> |
|
|
|
<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> |
|
|
|
<Col span={12}> |
|
|
|
<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> |
|
|
|
<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> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
<div className='custom-scroll' style={{maxHeight: '37vh', overflow: 'auto'}}> |
|
|
|
<div className='custom-scroll' style={{ maxHeight: '37vh', overflow: 'auto' }}> |
|
|
|
{activeTabCommentIdx === 0 && RenderBehindTasks} |
|
|
|
{activeTabCommentIdx === 0 && RenderBehindTasks} |
|
|
|
{activeTabCommentIdx === 1 && RenderComments} |
|
|
|
{activeTabCommentIdx === 1 && RenderComments} |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</Col> |
|
|
|
</Col> |
|
|
|
</Row> |
|
|
|
</Row> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export default DashboardProject; |
|
|
|
export default DashboardProject; |
|
|
|