Browse Source

fix(dashboard): change view chart in dashboard BOD

pull/1/head
farhantock 4 months ago
parent
commit
a4186d5e41
  1. 41
      src/components/CardDashboard/CardDashboard.js
  2. 74
      src/views/Dashboard/Components/index.js
  3. 71
      src/views/Dashboard/DashboardBOD.js
  4. 4
      src/views/Dashboard/DashboardProject.js

41
src/components/CardDashboard/CardDashboard.js

@ -158,6 +158,35 @@ const optionsScheduleHealthPerDivision = {
indexAxis: 'x',
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
ticks: {
font: {
size: 9,
},
callback: function (value) {
const label = this.getLabelForValue(value);
const maxLabelLength = 5;
if (label.length <= maxLabelLength) {
return label;
}
const words = label.split(' ');
let lines = [];
let currentLine = '';
words.forEach(word => {
if ((currentLine + word).length <= maxLabelLength) {
currentLine += word + ' ';
} else {
lines.push(currentLine.trim());
currentLine = word + ' ';
}
});
lines.push(currentLine.trim());
return lines;
},
},
}
},
plugins: {
legend: {
display: true,
@ -175,7 +204,7 @@ const optionsScheduleHealthPerDivision = {
}
}
export const ContentLoaderChart = ({type}) => {
export const ContentLoaderChart = ({ type }) => {
if (type === 'vertical-bar') {
return (
<ContentLoader
@ -298,10 +327,10 @@ export const CardDashboard = ({ title, subtitle, chartType, chartData, chartOpti
</div>
<div style={styles.cardChartContainer}>
{ isReady ?
{isReady ?
chartData ? chart : <NoDataChart />
:
<ContentLoaderChart type={chartType}/>
<ContentLoaderChart type={chartType} />
}
</div>
@ -345,16 +374,16 @@ export const CardScheduleHealthPerDivision = ({ isReady, title, subtitle, mode,
</div>
<div style={{ position: 'relative', height: '20vh', margin: 'auto', paddingBottom: 10, justifyContent: 'center' }}>
{isReady ? chartData ? <Bar options={chartOption ? chartOption : optionsScheduleHealthPerDivision} data={chartData ? chartData : null} /> : <NoDataChart /> : <ContentLoaderChart type={chartType}/> }
{isReady ? chartData ? <Bar options={chartOption ? chartOption : optionsScheduleHealthPerDivision} data={chartData ? chartData : null} /> : <NoDataChart /> : <ContentLoaderChart type={chartType} />}
</div>
</div>
)
}
export const NoDataChart = ({message}) => {
export const NoDataChart = ({ message }) => {
return (
<div style={{textAlign: 'center', marginTop: 50, alignSelf: 'center', alignItems: 'center', justifyContent: 'center', color: 'red'}}>
<div style={{ textAlign: 'center', marginTop: 50, alignSelf: 'center', alignItems: 'center', justifyContent: 'center', color: 'red' }}>
{message ? message : "No Data Available"}
</div>
)

74
src/views/Dashboard/Components/index.js

@ -2,7 +2,7 @@ import React from 'react'
import moment from "moment"
import ContentLoader from "react-content-loader"
export const SingleTextLoader = ({width, height}) => (
export const SingleTextLoader = ({ width, height }) => (
<ContentLoader
speed={1}
width={width ? width : 200}
@ -19,111 +19,111 @@ export const ListLoader = () => (
// <div style={{color: 'grey', flex: 1, textAlign: 'center', marginTop: 50, marginBottom: 50}}>Loading overdue activities...</div>
<div>
<SingleTextLoader width={"100%"} height={50} />
<div style={{marginBottom: 5}}></div>
<div style={{ marginBottom: 5 }}></div>
<SingleTextLoader width={"100%"} height={50} />
<div style={{marginBottom: 5}}></div>
<div style={{ marginBottom: 5 }}></div>
<SingleTextLoader width={"100%"} height={50} />
<div style={{marginBottom: 5}}></div>
<div style={{ marginBottom: 5 }}></div>
<SingleTextLoader width={"100%"} height={50} />
<div style={{marginBottom: 5}}></div>
<div style={{ marginBottom: 5 }}></div>
<SingleTextLoader width={"100%"} height={50} />
</div>
)
export const Comment = ({name, comment, created_at}) => (
<div style={{backgroundColor: '#EEEEEE', border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2}}>
<div style={{fontWeight: 'bold'}}>{name}</div>
<div style={{color: '#E80053', fontWeight: 100, fontSize: 10}}>{created_at ? moment(created_at).format('D MMMM YYYY HH:mm:ss') : '-'}</div>
export const Comment = ({ name, comment, created_at }) => (
<div style={{ backgroundColor: '#EEEEEE', border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2 }}>
<div style={{ fontWeight: 'bold' }}>{name}</div>
<div style={{ color: '#E80053', fontWeight: 100, fontSize: 10 }}>{created_at ? moment(created_at).format('D MMMM YYYY HH:mm:ss') : '-'}</div>
<div>{comment}</div>
</div>
)
export const BehindTaskItem = ({name, message}) => (
<div style={{backgroundColor: '#EEEEEE', border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2}}>
<div style={{fontWeight: 'bold'}}>{name}</div>
<div style={{color: '#E80053'}}>{message}</div>
export const BehindTaskItem = ({ name, message }) => (
<div style={{ backgroundColor: '#EEEEEE', border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', padding: 5, marginBottom: 5, marginRight: 2, marginLeft: 2 }}>
<div style={{ fontWeight: 'bold' }}>{name}</div>
<div style={{ color: '#E80053' }}>{message}</div>
{/* <div style={{color: '#E80053', textAlign: 'right', fontWeight: 500, fontSize: 12}}>{division}</div> */}
</div>
)
export const ProgressPlanningBar = ({progress}) => {
export const ProgressPlanningBar = ({ progress }) => {
if (progress) {
if (progress > 30) {
return (
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{ backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10 }}>
<div style={{ backgroundColor: '#0000cc', width: `${progress}%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: progress < 100 ? 0 : 10, borderBottomRightRadius: progress < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500 }}>Planning : {progress}%</div>
</div>
)
}
else {
return (
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{ backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10 }}>
<div style={{ backgroundColor: '#0000cc', width: `${progress}%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: progress < 100 ? 0 : 10, borderBottomRightRadius: progress < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500, height: 30 }}></div>
<span style={{textAlign: 'center', width: '100%', float: 'left', marginTop: -25, color: '#4e4c4c', fontWeight: 500}}>Planning : {progress}%</span>
<span style={{ textAlign: 'center', width: '100%', float: 'left', marginTop: -25, color: '#4e4c4c', fontWeight: 500 }}>Planning : {progress}%</span>
</div>
)
}
}
else {
return (
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{ backgroundColor: '#0000cc', width: `0%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: 0 < 100 ? 0 : 10, borderBottomRightRadius: 0 < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500, height: 30 }}></div>
<span style={{textAlign: 'center', width: '100%', float: 'left', marginTop: -25, color: '#4e4c4c', fontWeight: 500}}>Planning : 0%</span>
</div>
)
return (
<div style={{ backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10 }}>
<div style={{ backgroundColor: '#0000cc', width: `0%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: 0 < 100 ? 0 : 10, borderBottomRightRadius: 0 < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500, height: 30 }}></div>
<span style={{ textAlign: 'center', width: '100%', float: 'left', marginTop: -25, color: '#4e4c4c', fontWeight: 500 }}>Planning : 0%</span>
</div>
)
}
}
export const ProgressActualBar = ({progress}) => {
export const ProgressActualBar = ({ progress }) => {
if (progress) {
if (progress > 30) {
return (
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{ backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10 }}>
<div style={{ backgroundColor: '#006600', width: `${progress}%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: progress < 100 ? 0 : 10, borderBottomRightRadius: progress < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500 }}>Actual : {progress}%</div>
</div>
)
}
else {
return (
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{ backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10 }}>
<div style={{ backgroundColor: '#006600', width: `${progress}%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: progress < 100 ? 0 : 10, borderBottomRightRadius: progress < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500, height: 30 }}></div>
<span style={{textAlign: 'center', width: '100%', float: 'left', marginTop: -25, color: '#4e4c4c', fontWeight: 500}}>Actual : {progress}%</span>
<span style={{ textAlign: 'center', width: '100%', float: 'left', marginTop: -25, color: '#4e4c4c', fontWeight: 500 }}>Actual : {progress}%</span>
</div>
)
}
}
else {
return (
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{ backgroundColor: '#006600', width: `0%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: 0 < 100 ? 0 : 10, borderBottomRightRadius: 0 < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500, height: 30 }}></div>
<span style={{textAlign: 'center', width: '100%', float: 'left', marginTop: -25, color: '#4e4c4c', fontWeight: 500}}>Actual : 0%</span>
</div>
)
<div style={{ backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10 }}>
<div style={{ backgroundColor: '#006600', width: `0%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: 0 < 100 ? 0 : 10, borderBottomRightRadius: 0 < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500, height: 30 }}></div>
<span style={{ textAlign: 'center', width: '100%', float: 'left', marginTop: -25, color: '#4e4c4c', fontWeight: 500 }}>Actual : 0%</span>
</div>
)
}
}
export const HealthByBudget = ({status}) => {
export const HealthByBudget = ({ status }) => {
let bgColor = '#52AC0B'; // on-budget
if (status && status !== '-') {
if (status === 'warning') bgColor = '#ED7014';
else if (status === 'overrun') bgColor = '#D0312D';
}
return (
<div style={{backgroundColor: bgColor, color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10, minHeight: 25}}>
<div style={{ backgroundColor: bgColor, color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10, minHeight: 25 }}>
<div style={{ textAlign: 'center', fontWeight: 500, fontSize: 12 }}>Health By Budget</div>
</div>
)
}
export const HealthBySchedule = ({status}) => {
export const HealthBySchedule = ({ status }) => {
// let bgColor = '#E80053'; // pink
let bgColor = '#52AC0B'; // green
if (status && status !== '-') {
if (status === 'warning') bgColor = '#ED7014';
else if (status === 'danger') bgColor = '#D0312D';
else if (status === 'behind-schedule') bgColor = '#D0312D';
}
return (
<div style={{backgroundColor: bgColor, color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10, minHeight: 25}}>
<div style={{ backgroundColor: bgColor, color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10, minHeight: 25 }}>
<div style={{ textAlign: 'center', fontWeight: 500, fontSize: 12 }}>Health By Schedule</div>
</div>
)

71
src/views/Dashboard/DashboardBOD.js

@ -242,7 +242,7 @@ const DashboardBOD = (props) => {
}
if (result.status == 200 && result.data.data) {
SET_PROJECT_SCHEDULE_HEALTH_PER_DIVISION(result.data.data[0]);
SET_PROJECT_SCHEDULE_HEALTH_PER_DIVISION(result.data.data);
}
SET_READY_PROJECT_SCHEDULE_BUDGET_HEALTH_PER_DIVISION(true);
}
@ -348,25 +348,6 @@ const DashboardBOD = (props) => {
if (result.data.data.length > 0) {
let tableData = [];
result.data.data.map((item, idx) => {
let statusHealthBySchedule = 'on-schedule';
let planningProgress = 0;
let actualProgress = 0;
let selisihProgress = 0;
if (item.scurve && item.scurve[0]) {
planningProgress = item.scurve[0].data.percentagePlan[item.scurve[0].data.percentagePlan.length - 1]
actualProgress = item.scurve[0].data.percentageReal[item.scurve[0].data.percentageReal.length - 1]
}
selisihProgress = planningProgress - actualProgress
if (selisihProgress > 0 && selisihProgress <= 5) {
statusHealthBySchedule = 'warning'
}
else if (selisihProgress > 5) {
statusHealthBySchedule = 'danger'
}
let outstanding_balance = 0;
if (item.invoice) {
outstanding_balance = item.invoice.invoiced - item.invoice.paid;
@ -394,7 +375,7 @@ const DashboardBOD = (props) => {
"cash_in": item.invoice?.paid ? toRupiah(item.invoice.paid) : '-',
"outstanding_balance": outstanding_balance,
"budget": <HealthByBudget status={item.budget_health} />,
"schedule": <HealthBySchedule status={statusHealthBySchedule} />
"schedule": <HealthBySchedule status={item.schedule_health} />
})
});
SET_DATA_DETAIL_EXPENDITURE(tableData);
@ -495,7 +476,12 @@ const DashboardBOD = (props) => {
y: {
ticks: {
autoSkip: false,
stepSize: 2
stepSize: 2,
// callback: function (value) {
// if (value === 0 || value === null || value === undefined) {
// return '';
// }
// }
}
}
},
@ -527,11 +513,11 @@ const DashboardBOD = (props) => {
label: '',
data: [
PROJECT_EXPENDITURE?.total_budget || 0,
PROJECT_EXPENDITURE?.total_expenditure || 1000000000,
PROJECT_EXPENDITURE?.total_invoice ? Math.floor(PROJECT_EXPENDITURE.total_invoice) : 1000000000,
PROJECT_EXPENDITURE?.total_paid_invoice || 1000000000,
PROJECT_EXPENDITURE?.total_paid_invoice || 1000000000,
PROJECT_EXPENDITURE?.total_paid_invoice || 1000000000
PROJECT_EXPENDITURE?.total_expenditure || 0,
PROJECT_EXPENDITURE?.total_invoice ? Math.floor(PROJECT_EXPENDITURE.total_invoice) : 0,
PROJECT_EXPENDITURE?.total_paid_invoice || 0,
PROJECT_EXPENDITURE?.total_paid_invoice || 0,
PROJECT_EXPENDITURE?.total_paid_invoice || 0
],
borderColor: [
PROJECT_EXPENDITURE_COLOR?.total_budget || '#480ca8',
@ -849,7 +835,36 @@ const DashboardBOD = (props) => {
font: {
size: 9,
},
}
maxRotation: 0,
minRotation: 0,
callback: function (value) {
const label = this.getLabelForValue(value);
const words = label.split(' ');
const maxWordLength = 7;
const splitLongWords = (word) => {
if (word.length <= maxWordLength) {
return [word];
}
const chunks = [];
for (let i = 0; i < word.length; i += maxWordLength) {
chunks.push(word.substring(i, i + maxWordLength));
}
return chunks;
};
const lines = [];
words.forEach(word => {
if (word.length > maxWordLength) {
lines.push(...splitLongWords(word));
} else {
lines.push(word);
}
});
return lines;
},
},
},
y: {
ticks: {

4
src/views/Dashboard/DashboardProject.js

@ -436,10 +436,10 @@ const DashboardProject = (props) => {
setActualProgress(actualProgress);
}
selisihProgress = planningProgress - actualProgress;
if (selisihProgress > 0 && selisihProgress <= 5) {
if (selisihProgress > 0 && selisihProgress <= 20) {
statusHealthBySchedule = "warning";
} else if (selisihProgress > 5) {
statusHealthBySchedule = "danger";
statusHealthBySchedule = "behind-schedule";
}
setHealthBySchedule(statusHealthBySchedule);
setIsReadySCurve(true);

Loading…
Cancel
Save