Browse Source

finish dashboard BOD using API, add DashboardCustomer (dummy), add DashboardProject (dummy)

pull/2/head
ardhi 2 years ago
parent
commit
c7cab677d3
  1. 30
      src/components/BottomModal/BottomModal.css
  2. 173
      src/components/BottomModal/BottomModal.js
  3. 7
      src/components/BottomModal/package.json
  4. 361
      src/components/CardDashboard/CardDashboard.js
  5. 7
      src/components/CardDashboard/package.json
  6. 53
      src/const/ApiConst.js
  7. 4
      src/const/CustomFunc.js
  8. 13
      src/routes.js
  9. 1023
      src/views/Dashboard/DashboardBOD.js
  10. 244
      src/views/Dashboard/DashboardCustomer.js
  11. 323
      src/views/Dashboard/DashboardProject.js

30
src/components/BottomModal/BottomModal.css

@ -0,0 +1,30 @@
.bottommodal-window-button-container {
float: right;
right: 10px;
text-align: right;
}
.bottommodal-close,
.bottommodal-maximize,
.bottommodal-minimize {
cursor: pointer;
padding: 4px;
}
.bottommodal-header {
margin-bottom: -10px;
}
.bottommodal-title {
font-size: 16px;
font-weight: 750;
text-align: left;
margin-left: 20px;
color: #FFFFFF;
}
.bottommodal-close:hover,
.bottommodal-maximize:hover,
.bottommodal-minimize:hover {
color: #20a8d8;
}

173
src/components/BottomModal/BottomModal.js

@ -0,0 +1,173 @@
import React, { useMemo, useState } from 'react'
import { Resizable } from 're-resizable'
import './BottomModal.css'
import { Card, CardBody, CardHeader, Col, Row, Table } from 'reactstrap'
import Icon from '@iconify/react'
import closeCircleOutline from '@iconify/icons-ion/close-circle-outline';
import removeCircleOutline from '@iconify/icons-ion/remove-circle-outline';
import windowMaximaze from '@iconify/icons-mdi/window-maximize';
const BottomModal = ({title, tableHeader, tableData, closeModal}) => {
const [tableHeight, setTableHeight] = useState(150)
const [resizableWidth, setResizableWidth] = useState("100%")
const [resizableHeight, setResizableHeight] = useState(300)
const [maximizeTitle, setMaximizeTitle] = useState("maximize")
const setBottomTableWindow = (type) => {
if (type === 'min') {
// minimize
setResizableHeight(55);
setTableHeight(150)
}
else if (type === 'max') {
if (resizableHeight === '100vh') {
// restore
setResizableHeight(300)
setTableHeight(150)
setMaximizeTitle("maximize");
}
else {
// maximize
// setResizableHeight(600)
// setTableHeight(950)
setResizableHeight('100vh');
setTableHeight('90vh');
setMaximizeTitle("restore");
}
}
}
const renderTableRow = (item) => {
let row = [];
// looping through its object keys (item is an object)
Object.keys(item).map(key => {
// if (key !== 'id') {
row.push(<td>{item[key]}</td>)
// }
})
return row;
}
const RenderTable = useMemo(() => {
if (tableData && tableData.length > 0) {
return (
<Table size='sm'>
<thead style={{margin: 0, backgroundColor: '#888888', color: '#FFFFFF', fontSize: 12}}>
<tr>
<th>#</th>
{tableHeader && tableHeader.length > 0 &&
tableHeader.map((item, idx) => (
<th key={idx}>{item.title}</th>
))
}
</tr>
</thead>
<tbody style={{backgroundColor: '#EEEEEE'}}>
{tableData && tableData.length > 0 &&
tableData.map((item, index) => {
return (<tr key={index}>
{renderTableRow(item, tableHeader)}
</tr>)
})
}
</tbody>
</Table>
)
}
return (
// <Table>
// <tr>
// <td style={{ fontWeight: "bold" }} colSpan="4" align="center">No Data Available</td>
// </tr>
// </Table>
<div style={{justifyContent: 'center', textAlign: 'center', color: 'red', marginTop: 50, marginBottom: 50}}>
No Data Available
</div>
)
}, [tableData])
return (
<Resizable
style={{
position: "fixed",
width: "100%",
bottom: 0,
left: 0,
right: 0,
background: "#222222",
borderTopLeftRadius: 10,
borderTopRightRadius: 10,
zIndex: 9999
}}
size={{
width: resizableWidth,
height: resizableHeight
}}
maxHeight="100vh"
minWidth="100%"
enable={{ top: true, right: false, bottom: false, left: false, topRight: false, bottomRight: false, bottomLeft: false, topLeft: false }}
onResizeStop={(e, direction, ref, d) => {
setResizableWidth("100%");
setResizableHeight(resizableHeight + d.height);
if (e.screenY < 100) { // max
setResizableHeight('100vh');
setTableHeight(450)
}
else if (e.screenY < 150) {
setTableHeight(400)
}
else if (e.screenY < 200) {
setTableHeight(350)
}
else if (e.screenY < 250) {
setTableHeight(300)
}
else if (e.screenY < 300) {
setTableHeight(250)
}
else if (e.screenY < 400) {
setTableHeight(200)
}
else if (e.screenY < 600) {
setTableHeight(150) // default
}
else if (e.screenY >= 600) {
setBottomTableWindow('min');
}
}}
>
<div style={{ paddingTop: 10, position: "relative", height: "100%" }}>
<Row className="bottommodal-header">
<Col md={8}>
<p className="bottommodal-title">{title}</p>
</Col>
<Col md={4} className="bottommodal-window-button-container">
<span className="bottommodal-minimize" title="minimize"
onClick={() => setBottomTableWindow("min")}
>
<Icon icon={removeCircleOutline} width={30} height={30} color="#FFFFFF" />
</span>
<span className="bottommodal-maximize" title={maximizeTitle}
onClick={() => setBottomTableWindow("max")}
>
<Icon icon={windowMaximaze} width={30} height={30} color="#FFFFFF" />
</span>
<span className="bottommodal-close" title="close"
onClick={closeModal}
>
<Icon icon={closeCircleOutline} width={30} height={30} color="#FFFFFF" />
</span>
</Col>
</Row>
<Card style={{ margin: 10 }}>
<CardBody style={{ margin: 0, padding: 0, borderRadius: 5, backgroundColor: '#EEEEEE', overflowY: 'auto', height: resizableHeight === 300 ? 240 : 540 }}>
{RenderTable}
</CardBody>
</Card>
</div>
</Resizable>
)
}
export default BottomModal;

7
src/components/BottomModal/package.json

@ -0,0 +1,7 @@
{
"name": "BottomModal",
"version": "0.0.0",
"private": true,
"main": "./BottomModal.js"
}

361
src/components/CardDashboard/CardDashboard.js

@ -0,0 +1,361 @@
import React, { useEffect, useState } from 'react';
import {
Chart as ChartJS,
CategoryScale,
LineController,
LineElement,
LinearScale,
BarController,
BarElement,
PieController,
Title,
Tooltip,
Legend,
ArcElement
} from 'chart.js';
// import Chart from 'chart.js/auto';
import { Chart, Bar, Line, Pie } from 'react-chartjs-2';
import ChartDataLabels from 'chartjs-plugin-datalabels';
import ContentLoader from 'react-content-loader';
ChartJS.register(
CategoryScale,
LineController,
LineElement,
LinearScale,
BarController,
BarElement,
PieController,
Title,
Tooltip,
Legend,
ArcElement,
ChartDataLabels
);
const styles = {
cardContainer: { backgroundColor: '#F8F8F8', margin: 2, paddingLeft: 20, paddingRight: 20, paddingTop: 10, height: '30vh' },
cardHeaderContainer: { display: 'flex', flexDirection: 'row', marginBottom: 10 },
cardChartContainer: { position: 'relative', height: '20vh', margin: 'auto', paddingBottom: 10, justifyContent: 'center' },
cardTitle: { color: '#444444', fontSize: 14, fontWeight: 'bold' },
cardSubtitle: { color: '#888888', fontSize: 12 }
}
const verticalBarChartOption = {
elements: {
bar: {
borderWidth: 2,
},
},
indexAxis: 'x',
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'right',
labels: {
boxWidth: 10
}
},
datalabels: {
color: '#FFFFFF'
}
},
// scales: {
// yAxes: [{
// afterFit: function(scaleInstance) {
// scaleInstance.width = 100; // sets the width to 100px
// }
// }]
// }
}
const horizontalBarChartOption = {
indexAxis: 'y',
elements: {
bar: {
borderWidth: 2,
},
},
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
datalabels: {
color: '#FFFFFF'
}
}
}
const pieChartOption = {
elements: {
pie: {
borderWidth: 2,
},
},
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'right',
labels: {
boxWidth: 10
}
},
datalabels: {
color: '#FFFFFF'
}
}
}
const lineChartOption = {
elements: {
line: {
borderWidth: 2,
},
},
responsive: false,
plugins: {
datalabels: {
color: '#FFFFFF'
}
}
}
const optionsExpenditure = {
indexAxis: 'y',
elements: {
bar: {
borderWidth: 2,
},
},
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
position: 'right',
labels: {
boxWidth: 10
}
},
datalabels: {
color: '#FFFFFF'
}
},
};
const optionsScheduleHealthPerDivision = {
elements: {
bar: {
borderWidth: 2,
},
},
indexAxis: 'x',
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'top',
labels: {
boxWidth: 10,
font: {
size: 10
}
}
},
datalabels: {
color: '#FFFFFF'
}
}
}
export const ContentLoaderChart = ({type}) => {
if (type === 'vertical-bar') {
return (
<ContentLoader
speed={2}
width="100%"
height="100%"
viewBox="0 0 500 200"
backgroundColor="#f3f3f3"
foregroundColor="#ecebeb"
>
{/* <rect x="6" y="88" rx="4" ry="4" width="18" height="105" />
<rect x="36" y="64" rx="4" ry="4" width="18" height="129" />
<rect x="64" y="130" rx="4" ry="4" width="18" height="62" />
<rect x="91" y="87" rx="4" ry="4" width="18" height="105" />
<rect x="118" y="107" rx="4" ry="4" width="18" height="85" />
<rect x="147" y="92" rx="4" ry="4" width="18" height="100" />
<rect x="176" y="120" rx="4" ry="4" width="18" height="72" />
<rect x="207" y="54" rx="4" ry="4" width="18" height="138" />
<rect x="267" y="94" rx="4" ry="4" width="18" height="98" />
<rect x="235" y="56" rx="4" ry="4" width="18" height="136" />
<rect x="298" y="68" rx="4" ry="4" width="18" height="124" />
<rect x="330" y="77" rx="4" ry="4" width="18" height="114" />
<rect x="360" y="106" rx="4" ry="4" width="18" height="84" />
<rect x="388" y="155" rx="4" ry="4" width="18" height="35" />
<rect x="417" y="108" rx="4" ry="4" width="18" height="81" />
<rect x="450" y="82" rx="4" ry="4" width="18" height="107" /> */}
{/* <rect x="13" y="47" rx="4" ry="4" width="39" height="140" />
<rect x="61" y="9" rx="4" ry="4" width="39" height="178" />
<rect x="112" y="28" rx="4" ry="4" width="39" height="160" />
<rect x="186" y="45" rx="4" ry="4" width="39" height="140" />
<rect x="234" y="7" rx="4" ry="4" width="39" height="178" />
<rect x="284" y="27" rx="4" ry="4" width="39" height="160" />
<rect x="358" y="45" rx="4" ry="4" width="39" height="140" />
<rect x="406" y="7" rx="4" ry="4" width="39" height="178" />
<rect x="456" y="27" rx="4" ry="4" width="39" height="160" /> */}
<rect x="13" y="87" rx="4" ry="4" width="39" height="106" />
<rect x="61" y="21" rx="4" ry="4" width="39" height="171" />
<rect x="112" y="61" rx="4" ry="4" width="39" height="131" />
<rect x="185" y="87" rx="4" ry="4" width="39" height="106" />
<rect x="233" y="21" rx="4" ry="4" width="39" height="171" />
<rect x="284" y="61" rx="4" ry="4" width="39" height="131" />
<rect x="354" y="88" rx="4" ry="4" width="39" height="106" />
<rect x="402" y="22" rx="4" ry="4" width="39" height="171" />
<rect x="453" y="62" rx="4" ry="4" width="39" height="131" />
</ContentLoader>
)
}
else if (type === 'pie') {
return (
<ContentLoader
speed={2}
width="100%"
height="100%"
viewBox="0 0 200 100"
backgroundColor="#f3f3f3"
foregroundColor="#ecebeb"
>
<circle cx="45" cy="41" r="39" />
<rect x="98" y="15" rx="8" ry="8" width="82" height="13" />
<rect x="98" y="35" rx="8" ry="8" width="82" height="13" />
<rect x="98" y="56" rx="8" ry="8" width="82" height="13" />
</ContentLoader>
)
}
else {
return (
<ContentLoader
speed={2}
width="100%"
height="100%"
viewBox="0 0 200 100"
backgroundColor="#f3f3f3"
foregroundColor="#ecebeb"
>
<rect x="0" y="0" rx="10" ry="10" width="25%" height="20" />
<rect x="0" y="25" rx="10" ry="10" width="75%" height="20" />
<rect x="0" y="50" rx="10" ry="10" width="100%" height="20" />
<rect x="0" y="75" rx="10" ry="10" width="45%" height="20" />
</ContentLoader>
)
}
}
// export const FullCard =
export const CardDashboard = ({ title, subtitle, chartType, chartData, chartOption, isReady }) => {
let chart = null;
if (chartType === 'vertical-bar') {
chart = <Bar
options={chartOption ? chartOption : verticalBarChartOption}
data={chartData ? chartData : null}
/>
}
else if (chartType === 'horizontal-bar') {
chart = <Bar
options={chartOption ? chartOption : horizontalBarChartOption}
data={chartData ? chartData : null}
/>
}
else if (chartType === 'pie') {
chart = <Pie
options={chartOption ? chartOption : pieChartOption}
data={chartData ? chartData : null}
/>
}
else if (chartType === 'line') {
chart = <Line
options={chartOption ? chartOption : lineChartOption}
data={chartData ? chartData : null}
/>
}
return (
<div style={styles.cardContainer}>
<div style={styles.cardHeaderContainer}>
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}>
<div style={styles.cardTitle}>{title}</div>
<div style={styles.cardSubtitle}>{subtitle}</div>
</div>
</div>
<div style={styles.cardChartContainer}>
{ isReady ?
chartData ? chart : <NoDataChart />
:
<ContentLoaderChart type={chartType}/>
}
</div>
</div>
)
}
// export const CardExpenditure = ({ title, subtitle, chartData, chartOption }) => {
// return (
// <div style={styles.cardContainer}>
// <div style={styles.cardHeaderContainer}>
// <div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}>
// <div style={styles.cardTitle}>{title}</div>
// <div style={styles.cardSubtitle}>{subtitle}</div>
// </div>
// <div style={{ flex: 6, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
// <div style={{ backgroundColor: '#DDDDDD', color: '#4C4747', borderRadius: 5, padding: 4, fontWeight: 500, cursor: 'pointer', fontSize: 12, textAlign: 'center', lineHeight: 'normal' }}>Detailed View</div>
// </div>
// </div>
// <div style={styles.cardChartContainer}>
// <Bar options={chartOption ? chartOption : optionsExpenditure} data={chartData ? chartData : null} />
// </div>
// </div>
// )
// }
export const CardScheduleHealthPerDivision = ({ isReady, title, subtitle, mode, changeMode, chartData, chartOption, chartType }) => {
return (
<div style={{ backgroundColor: '#F8F8F8', margin: 2, paddingLeft: 20, paddingRight: 20, paddingTop: 10, height: '30vh' }}>
<div style={{ display: 'flex', flexDirection: 'row', marginBottom: 10 }}>
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}>
<div style={styles.cardTitle}>{title}</div>
<div style={styles.cardSubtitle}>{subtitle}</div>
</div>
<div style={{ flex: 6, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
<div style={{ width: '100%', textAlign: 'center', height: 24, fontSize: 12, verticalAlign: 'middle', cursor: 'pointer', color: '#FFFFFF', backgroundColor: mode === 'budget' ? '#52AC0B' : '#777777' }} onClick={() => changeMode('budget')}>Budget</div>
<div style={{ width: '100%', textAlign: 'center', height: 24, fontSize: 12, verticalAlign: 'middle', cursor: 'pointer', color: '#FFFFFF', backgroundColor: mode === 'schedule' ? '#52AC0B' : '#777777' }} onClick={() => changeMode('schedule')}>Schedule</div>
</div>
</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}/> }
</div>
</div>
)
}
export const NoDataChart = ({message}) => {
return (
<div style={{textAlign: 'center', marginTop: 50, alignSelf: 'center', alignItems: 'center', justifyContent: 'center', color: 'red'}}>
{message ? message : "No Data Available"}
</div>
)
}

7
src/components/CardDashboard/package.json

@ -0,0 +1,7 @@
{
"name": "CardDashboard",
"version": "0.0.0",
"private": true,
"main": "./CardDashboard.js"
}

53
src/const/ApiConst.js

@ -111,41 +111,44 @@ export const BASE_SIMPRO_LUMENNIAGA = "https://ospro-api.odm-iu.com/api";
export const BASE_INTEGRATION_V1 = "http://ospro-api.adyawinsa.com:9083"; export const BASE_INTEGRATION_V1 = "http://ospro-api.adyawinsa.com:9083";
export const TOKEN_ADW = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIxMjAyIiwiZXhwIjoxNjkxODMwNDkzfQ.DvBQIOZsdFndWsliPCZT65Y6G5Xx4vWBKz8Rhe7rvRA"; export const TOKEN_ADW = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIxMjAyIiwiZXhwIjoxNjkxODMwNDkzfQ.DvBQIOZsdFndWsliPCZT65Y6G5Xx4vWBKz8Rhe7rvRA";
export let BASE_OSPRO = "https://ospro-api.ospro.id"; // export let BASE_OSPRO = "https://ospro-api.ospro.id";
export let BASE_OSPRO = "https://adw-api.ospro.id";
// export let BASE_OSPRO = "http://192.168.1.123:8444"; // local
// export let BASE_OSPRO = "http://103.73.125.81:8444"; // ip public adw
export let BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`; export let BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
export let BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`; export let BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`;
export let BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`; export let BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`;
switch (APP_MODE) { // switch (APP_MODE) {
case 'KIT': // case 'KIT':
BASE_OSPRO = "https://kit-api.oslogdev.com" // BASE_OSPRO = "https://kit-api.oslogdev.com"
//for KIT server // //for KIT server
// BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`; // // BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
// BASE_SIMPRO_LUMEN_IMAGE = `${BASE_SIMPRO_LUMEN}/assets/image`; // // BASE_SIMPRO_LUMEN_IMAGE = `${BASE_SIMPRO_LUMEN}/assets/image`;
// BASE_SIMPRO_LUMEN_FILE = `${BASE_SIMPRO_LUMEN}/assets/file/project`; // // BASE_SIMPRO_LUMEN_FILE = `${BASE_SIMPRO_LUMEN}/assets/file/project`;
break;
case 'ADW':
BASE_OSPRO = "https://adw-api.ospro.id"
BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`; // break;
BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`; // case 'ADW':
BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`; // // BASE_OSPRO = "https://adw-api.ospro.id"
// BASE_OSPRO = "http://103.73.125.81:8444";
break; // BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
case 'IU': // BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`;
BASE_OSPRO = "https://api-iu.ospro.id" // BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`;
BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`; // break;
BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`; // case 'IU':
BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`; // BASE_OSPRO = "https://api-iu.ospro.id"
break; // BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
default: // BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`;
BASE_OSPRO = "https://ospro-api.ospro.id" // BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`;
} // break;
// default:
// BASE_OSPRO = "https://ospro-api.ospro.id"
// }
export const USERROLE_ADD = `${BASE_SIMPRO}/user-role/add` export const USERROLE_ADD = `${BASE_SIMPRO}/user-role/add`
export const USERROLE_SEARCH = `${BASE_SIMPRO}/user-role/search` export const USERROLE_SEARCH = `${BASE_SIMPRO}/user-role/search`

4
src/const/CustomFunc.js

@ -345,3 +345,7 @@ export const formatRibuanDecimal = (n) => {
let parts=n.toString().split("."); let parts=n.toString().split(".");
return "Rp. " + parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".") + (parts[1] ? "," + parts[1] : ""); return "Rp. " + parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".") + (parts[1] ? "," + parts[1] : "");
} }
export const capitalizeFirstLetter = (string) => {
return string.charAt(0).toUpperCase() + string.slice(1);
}

13
src/routes.js

@ -42,14 +42,17 @@ const Shift = React.lazy(() => import('./views/SimproV2/Shift'));
const TestGantt = React.lazy(() => import('./views/testgantt')); const TestGantt = React.lazy(() => import('./views/testgantt'));
const UserAdmin = React.lazy(() => import('./views/Master/UserAdmin')); const UserAdmin = React.lazy(() => import('./views/Master/UserAdmin'));
const UserShift = React.lazy(() => import('./views/SimproV2/UserShift')); const UserShift = React.lazy(() => import('./views/SimproV2/UserShift'));
const DashboardProject = React.lazy(() => import('./views/DashboardProject')); // const DashboardProject = React.lazy(() => import('./views/DashboardProject'));
const DashboardBOD = React.lazy(() => import('./views/Dashboard/DashboardBOD')); const DashboardBOD = React.lazy(() => import('./views/Dashboard/DashboardBOD'));
const DashboardCustomer = React.lazy(() => import('./views/Dashboard/DashboardCustomer'));
const DashboardProject = React.lazy(() => import('./views/Dashboard/DashboardProject'));
const routes = [ const routes = [
{ path: '/', exact: true, name: 'Home' }, { path: '/', exact: true, name: 'Home' },
{ path: '/dashboard', name: 'Dashboard', component: Dashboard}, // { path: '/dashboard', name: 'Dashboard', component: Dashboard},
{ path: '/dashboard-bod', name: 'DashboardBOD', component: DashboardBOD}, { path: '/dashboard', name: 'DashboardBOD', component: DashboardBOD},
{ path: '/dashboard-customer/:PROJECT_ID/:GANTT_ID', name: 'DashboardCustomer', component: DashboardCustomer},
{ path: '/dashboard-project/:PROJECT_ID/:GANTT_ID', exact: true, name: 'Dashboard Project', component: DashboardProject },
{ path: '/projects', exact: true, name: 'Projects', component: CreatedProyek }, { path: '/projects', exact: true, name: 'Projects', component: CreatedProyek },
{ path: '/projects/:id/:project/gantt', exact: true, name: 'Gantt', component: Gantt }, { path: '/projects/:id/:project/gantt', exact: true, name: 'Gantt', component: Gantt },
{ path: '/human-resource', exact: true, name: 'Human Resource', component: ResourceWorker }, { path: '/human-resource', exact: true, name: 'Human Resource', component: ResourceWorker },
@ -97,7 +100,7 @@ const routes = [
{ path: '/user-admin', exact: true, name: 'User Admin', component: UserAdmin }, { path: '/user-admin', exact: true, name: 'User Admin', component: UserAdmin },
{ path: '/user-shift', exact: true, name: 'Shift', component: UserShift }, { path: '/user-shift', exact: true, name: 'Shift', component: UserShift },
{ path: '/working-hour', exact: true, name: 'Working Hour', component: Shift }, { path: '/working-hour', exact: true, name: 'Working Hour', component: Shift },
{ path: '/dashboard-project/:ID/:GANTTID', exact: true, name: 'Dashboard Project', component: DashboardProject }, // { path: '/dashboard-project/:ID/:GANTTID', exact: true, name: 'Dashboard Project', component: DashboardProject },
]; ];
export default routes; export default routes;

1023
src/views/Dashboard/DashboardBOD.js

File diff suppressed because it is too large Load Diff

244
src/views/Dashboard/DashboardCustomer.js

@ -0,0 +1,244 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import axios from 'axios'
import { Row, Col } from 'antd';
import { CardDashboard, CardExpenditure, CardScheduleHealthPerDivision } from '../../components/CardDashboard/CardDashboard';
import L from 'leaflet';
import { useParams } from 'react-router-dom';
import '../../assets/css/customscroll.css'
import moment from 'moment';
import { BASE_OSPRO } from '../../const/ApiConst';
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.200000,
lng: 106.816666
}
const DashboardCustomer = () => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const { PROJECT_ID, GANTT_ID } = useParams();
// const URL_GANTT = `http://103.73.125.81:8446/index.html?base_url=http://103.73.125.81:8444/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`;
const URL_GANTT = `http://103.73.125.81:8446/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`;
const mapRef = useRef()
const [projectName, setProjectName] = useState("Project Tower ABC");
const [customerName, setCustomerName] = useState("Jaya Gedung Group");
const [plannedStart, setPlannedStart] = useState("2019-03-04")
const [plannedFinish, setPlannedFinish] = useState("2020-05-28")
const [actualStart, setActualStart] = useState("2019-03-04")
const [actualFinish, setActualFinish] = useState("2020-05-28")
const [estimatedFinish, setEstimatedFinish] = useState("2020-05-28")
const [mymap, setMymap] = useState(null);
const [activeTabIdx, setActiveTabIdx] = useState(0);
const [activeTabCommentIdx, setActiveTabCommentIdx] = useState(0);
const [planningProgress, setPlanningProgress] = useState(79);
const [actualProgress, setActualProgress] = useState(50);
useEffect(() => {
console.log('URL_GANTT', URL_GANTT);
return () => {
console.log('unmount RenderMap');
}
}, [])
useEffect(() => {
if (activeTabIdx === 1) {
initMap();
}
}, [activeTabIdx]);
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);
}
const RenderGantt = useMemo(() => (
<iframe
id="frame-gantt"
src={URL_GANTT}
style={{
width: '100%',
height: '100%',
}}
scrolling="no"
frameBorder="0"
allow="fullscreen"
></iframe>
), [activeTabIdx])
const Comment = ({name, division, 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>{division}</div>
<div style={{color: '#E80053', textAlign: 'right', fontWeight: 500, fontSize: 12}}>{message}</div>
</div>
)
return (
<div style={{ marginLeft: -25, marginRight: -25 }}>
<Row>
<Col span={18}>
<Row>
<Col span={12}>
{/* <div style={styles.cardContainer}>
<div style={styles.cardHeaderContainer}>
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}>
<div style={styles.cardTitle}>Project</div>
<div style={styles.cardSubtitle}>Project Tower ABC</div>
</div>
<div style={{ flex: 6, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<i className="fa fa-check-square" style={{fontSize: 28}}></i>
</div>
</div>
</div> */}
<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}}>{projectName}</div>
</div>
<div>
<i className="fa fa-check-square" style={{fontSize: 28}}></i>
</div>
</div>
</div>
</Col>
<Col span={12}>
<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}}>{customerName}</div>
</div>
<div>
<i className="fa fa-home" style={{fontSize: 28}}></i>
</div>
</div>
</div>
</Col>
</Row>
<Row>
<Col span={24}>
<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={4} style={{fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Planned Start</Col>
<Col span={4}>{plannedStart ? moment(plannedStart).format('D MMMM YYYY') : '-'}</Col>
<Col span={4} style={{fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Planned Finish</Col>
<Col span={4}>{plannedFinish ? moment(plannedFinish).format('D MMMM YYYY') : '-'}</Col>
<Col span={4} style={{fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Actual Finish</Col>
<Col span={4}>{actualFinish ? moment(actualFinish).format('D MMMM YYYY') : '-'}</Col>
</Row>
<Row>
<Col span={4} style={{fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Actual Start</Col>
<Col span={4}>{actualStart ? moment(actualStart).format('D MMMM YYYY') : '-'}</Col>
<Col span={4} style={{fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Estimated Finish</Col>
<Col span={4}>{estimatedFinish ? moment(estimatedFinish).format('D MMMM YYYY') : '-'}</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: '57vh'}}>
{ activeTabIdx === 0 && <div style={{height: '56vh', width: '100%'}}>{RenderGantt}</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>
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{backgroundColor: '#7209B7', width: `${planningProgress}%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: planningProgress < 100 ? 0 : 10, borderBottomRightRadius: planningProgress < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500}}>Planning : {planningProgress}%</div>
</div>
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{backgroundColor: '#0059C9', width: `${actualProgress}%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: actualProgress < 100 ? 0 : 10, borderBottomRightRadius: actualProgress < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500}}>{actualProgress && actualProgress < 50 ? `${actualProgress}%` : `Actual : ${actualProgress}%` }</div>
</div>
</div>
</Col>
</Row>
<Row>
<Col span={24}>
<div style={{backgroundColor: '#FFFFFF', padding: 10, border: 'solid', borderWidth: 1, borderColor: '#DDDDDD', marginBottom: 5}}>
<div style={{color: '#000000', textAlign: 'center', marginBottom: 10, fontWeight: 'bold'}}>Health By Schedule</div>
<div style={{backgroundColor: '#E80053', color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10}}>
<div style={{textAlign: 'center', fontWeight: 500}}>Behind Schedule</div>
</div>
</div>
</Col>
</Row>
<Row>
<Col span={24}>
<div style={{border: 'solid', borderWidth: 1, borderColor: '#DDDDDD'}}>
{/* <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 === 1 ? '#FFFFFF' : '#D9D9D9', color: activeTabCommentIdx === 1 ? '#000000' : '#FFFFFF', fontWeight: 500, padding: 2, fontSize: 12}} onClick={() => setActiveTabCommentIdx(1)}>Comment From Customer</div>
</div> */}
<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: '52vh', overflow: 'auto'}}>
<Comment name="Dani" division="Interior Office" message="Overdue by 3 days"/>
<Comment name="Roland" division="Interior Office" message="Overdue by 3 days"/>
<Comment name="John" division="Interior Office" message="Overdue by 3 days"/>
<Comment name="Logan" division="Interior Office" message="Overdue by 3 days"/>
<Comment name="Doe" division="Interior Office" message="Overdue by 3 days"/>
</div>
</div>
</Col>
</Row>
</div>
</Col>
</Row>
</div>
);
}
export default DashboardCustomer;

323
src/views/Dashboard/DashboardProject.js

@ -0,0 +1,323 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import axios from 'axios'
import { Row, Col } from 'antd';
import { CardDashboard, CardExpenditure, CardScheduleHealthPerDivision } from '../../components/CardDashboard/CardDashboard';
import L from 'leaflet';
import { useParams } from 'react-router-dom';
import '../../assets/css/customscroll.css'
import moment from 'moment';
import { renderFormatRupiah } from '../../const/CustomFunc';
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.200000,
lng: 106.816666
}
const DashboardProject = () => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const { PROJECT_ID, GANTT_ID } = useParams();
const URL_GANTT = `http://103.73.125.81:8446/index.html?base_url=http://103.73.125.81:8444/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`;
const mapRef = useRef()
const [projectName, setProjectName] = useState("Project Tower ABC");
const [projectManagerName, setProjectManagerName] = useState("John Doe");
const [customerName, setCustomerName] = useState("Jaya Gedung Group");
const [plannedStart, setPlannedStart] = useState("2019-03-04")
const [plannedFinish, setPlannedFinish] = useState("2020-05-28")
const [actualStart, setActualStart] = useState("2019-03-04")
const [actualFinish, setActualFinish] = useState("2020-05-28")
const [estimatedFinish, setEstimatedFinish] = useState("2020-05-28")
const [mymap, setMymap] = useState(null);
const [activeTabIdx, setActiveTabIdx] = useState(0);
const [activeTabCommentIdx, setActiveTabCommentIdx] = useState(0);
const [planningProgress, setPlanningProgress] = useState(79);
const [actualProgress, setActualProgress] = useState(43);
const [currentBudget, setCurrentBudget] = useState("168011727772");
const [addCostToComplete, setAddCostToComplete] = useState("0");
const [actualToDate, setactualToDate] = useState("43256751714");
const [estAtCompletion, setEstAtCompletion] = useState("168011727772");
const [bcwp, setBcwp] = useState("26658794618");
const [costDeviation, setCostDeviation] = useState("0");
const [remToComplete, setRemToComplete] = useState("124754976058");
const [totalInvoice, setTotalInvoice] = useState("10000000000");
const [cashIn, setCashIn] = useState("8000000000");
const [outstandingBalance, setOutstandingBalance] = useState("2000000000");
useEffect(() => {
console.log('URL_GANTT', URL_GANTT);
return () => {
console.log('unmount RenderMap');
}
}, [])
useEffect(() => {
if (activeTabIdx === 1) {
initMap();
}
}, [activeTabIdx]);
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);
}
const RenderGantt = useMemo(() => (
<iframe
id="frame-gantt"
src={URL_GANTT}
style={{
width: '100%',
height: '100%',
}}
scrolling="no"
frameBorder="0"
allow="fullscreen"
></iframe>
), [activeTabIdx])
const Comment = ({name, division, 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>{division}</div>
<div style={{color: '#E80053', textAlign: 'right', fontWeight: 500, fontSize: 12}}>{message}</div>
</div>
)
return (
<div style={{ marginLeft: -25, marginRight: -25 }}>
<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}}>{projectName}</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}}>{projectManagerName}</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}}>{customerName}</div>
</div>
<div>
<i className="fa fa-home" style={{fontSize: 28}}></i>
</div>
</div>
</div>
</Col>
</Row>
<Row>
<Col span={8}>
<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}}>{plannedStart ? moment(plannedStart).format('D MMMM YYYY') : '-'}</Col>
</Row>
<Row>
<Col span={12} style={{fontSize: 11, fontWeight: 'bold'}}><i className="fa fa-calendar" style={{marginRight:8}}></i>Acutal Start</Col>
<Col span={12} style={{fontSize: 11}}>{plannedStart ? moment(actualStart).format('D MMMM YYYY') : '-'}</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}}>{plannedStart ? moment(plannedFinish).format('D MMMM YYYY') : '-'}</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}}>{plannedStart ? moment(estimatedFinish).format('D MMMM YYYY') : '-'}</Col>
</Row>
</div>
</div>
</div>
</Col>
<Col span={16}>
<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}}>Financials</div>
</div>
<div>
<Row>
<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}}>{currentBudget ? renderFormatRupiah(currentBudget, 'Rp.') : '-' }</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}}>{addCostToComplete ? renderFormatRupiah(addCostToComplete, 'Rp.') : '-' }</Col>
</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={5} style={{fontSize: 11}}>{actualToDate ? renderFormatRupiah(actualToDate, 'Rp.') : '-' }</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}}>{estAtCompletion ? renderFormatRupiah(estAtCompletion, 'Rp.') : '-' }</Col>
</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={5} style={{fontSize: 11}}>{bcwp ? renderFormatRupiah(bcwp, 'Rp.') : '-' }</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}}>{costDeviation ? renderFormatRupiah(costDeviation, 'Rp.') : '-' }</Col>
</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={5} style={{fontSize: 11}}>{remToComplete ? renderFormatRupiah(remToComplete, 'Rp.') : '-' }</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'}}>
{ activeTabIdx === 0 && <div style={{height: '52vh', width: '100%'}}>{RenderGantt}</div> }
{ activeTabIdx === 1 && <div id="map-area" style={{height: '52vh'}} 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>
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{backgroundColor: '#7209B7', width: `${planningProgress}%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: planningProgress < 100 ? 0 : 10, borderBottomRightRadius: planningProgress < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500}}>Planning : {planningProgress}%</div>
</div>
<div style={{backgroundColor: '#DDDDDD', color: '#FFFFFF', borderRadius: 10, marginBottom: 10}}>
<div style={{backgroundColor: '#0059C9', width: `${actualProgress}%`, padding: 5, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, borderTopRightRadius: actualProgress < 100 ? 0 : 10, borderBottomRightRadius: actualProgress < 100 ? 0 : 10, textAlign: 'center', fontWeight: 500}}>Actual : {actualProgress}%</div>
</div>
</div>
</Col>
</Row>
<Row>
<Col span={12}>
<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={{backgroundColor: '#52AC0B', color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10}}>
<div style={{textAlign: 'center', fontWeight: 500, fontSize: 12}}>On Budget</div>
</div>
</div>
</Col>
<Col span={12}>
<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={{backgroundColor: '#E80053', color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10}}>
<div style={{textAlign: 'center', fontWeight: 500, fontSize: 12}}>Behind Schedule</div>
</div>
</div>
</Col>
</Row>
<Row>
<Col span={24}>
<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={{backgroundColor: '#52AC0B', color: '#FFFFFF', padding: 5, borderRadius: 10, marginBottom: 10}}>
<div style={{textAlign: 'center', fontWeight: 500, fontSize: 12}}>On Budget</div>
</div> */}
<Row>
<Col span={12}>Total Invoice</Col>
<Col span={12} style={{textAlign: 'right'}}>{totalInvoice ? renderFormatRupiah(totalInvoice, 'Rp.') : '-' }</Col>
</Row>
<Row>
<Col span={12}>Cash In</Col>
<Col span={12} style={{textAlign: 'right'}}>{cashIn ? renderFormatRupiah(cashIn, 'Rp.') : '-' }</Col>
</Row>
<Row>
<Col span={24}><hr style={{margin: 2}}/></Col>
</Row>
<Row>
<Col span={12}>Outstanding Balance</Col>
<Col span={12} style={{textAlign: 'right', color: '#E80053', fontWeight: 500}}>{outstandingBalance ? renderFormatRupiah(outstandingBalance, 'Rp.') : '-' }</Col>
</Row>
</div>
</Col>
</Row>
<Row>
<Col span={24}>
<div style={{border: 'solid', borderWidth: 1, borderColor: '#DDDDDD'}}>
{/* <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 === 1 ? '#FFFFFF' : '#D9D9D9', color: activeTabCommentIdx === 1 ? '#000000' : '#FFFFFF', fontWeight: 500, padding: 2, fontSize: 12}} onClick={() => setActiveTabCommentIdx(1)}>Comment From Customer</div>
</div> */}
<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'}}>
<Comment name="Dani" division="Interior Office" message="Overdue by 3 days"/>
<Comment name="Roland" division="Interior Office" message="Overdue by 3 days"/>
<Comment name="John" division="Interior Office" message="Overdue by 3 days"/>
<Comment name="Logan" division="Interior Office" message="Overdue by 3 days"/>
<Comment name="Doe" division="Interior Office" message="Overdue by 3 days"/>
</div>
</div>
</Col>
</Row>
</div>
</Col>
</Row>
</div>
);
}
export default DashboardProject;
Loading…
Cancel
Save