Yusuf
2 years ago
20 changed files with 1503 additions and 833 deletions
@ -1,102 +1,104 @@
|
||||
import React from 'react'; |
||||
|
||||
const Absensi = React.lazy(() => import('./views/Master/MasterAbsensi')); |
||||
const BaseLayers = React.lazy(() => import('./views/BaseLayers')); |
||||
const Broadcast = React.lazy(() => import('./views/Master/MasterBroadcast')); |
||||
const ChecklistK3 = React.lazy(() => import('./views/SimproV2/ChecklistK3')); |
||||
const Closing = React.lazy(() => import('./views/SimproV2/Closing')); |
||||
const ConfigAlert = React.lazy(() => import('./views/Master/ConfigAlert')); |
||||
const ControlMonitoring = React.lazy(() => import('./views/Report/ControlMonitoring')); |
||||
const ControlMonitoringGantt = React.lazy(() => import('./views/ControlMonitoringGantt')); |
||||
const CreatedProyek = React.lazy(() => import('./views/SimproV2/CreatedProyek')); |
||||
const DashboardSimpro = React.lazy(() => import('./views/DashboardSimpro')); |
||||
const DashboardPMO = React.lazy(() => import('./views/DashboardPMO')); |
||||
const Divisi = React.lazy(() => import('./views/SimproV2/Divisi')); |
||||
const DivisiKaryawan = React.lazy(() => import('./views/Master/MasterTipeKaryawan')); |
||||
const Gantt = React.lazy(() => import('./views/SimproV2/Gantt')); |
||||
const Izin = React.lazy(() => import('./views/Master/MasterCuti')); |
||||
const K3 = React.lazy(() => import('./views/Report/k3')); |
||||
const LaporanAlert = React.lazy(() => import('./views/Report/alert')); |
||||
const LaporanTugas = React.lazy(() => import('./views/Master/MasterTask')); |
||||
const Layer = React.lazy(() => import('./views/Layers/Layer')); |
||||
const Layers = React.lazy(() => import('./views/Layers/Layers')); |
||||
const Lembur = React.lazy(() => import('./views/Master/MasterLembur')); |
||||
const MapConfig = React.lazy(() => import('./views/MapConfig')); |
||||
const Menu = React.lazy(() => import('./views/Master/MasterMenu')); |
||||
const OfficeHours = React.lazy(() => import('./views/Master/MasterOfficeHours')); |
||||
const Organization = React.lazy(() => import('./views/Master/MasterOrganization')); |
||||
const PanicButton = React.lazy(() => import('./views/SimproV2/PanicButton')); |
||||
const PlanningHarian = React.lazy(() => import('./views/SimproV2/PlanningHarian')); |
||||
const Presensi = React.lazy(() => import('./views/SimproV2/Presence')); |
||||
const ProjectRole = React.lazy(() => import('./views/Master/RoleProject')); |
||||
const ProjectType = React.lazy(() => import('./views/SimproV2/ProjectType')); |
||||
const Proyek = React.lazy(() => import('./views/Master/Proyek')); |
||||
const RateCost = React.lazy(() => import('./views/SimproV2/RateCost')); |
||||
const ResourceMaterial = React.lazy(() => import('./views/SimproV2/ResourceMaterial')); |
||||
const ResourceTools = React.lazy(() => import('./views/SimproV2/ResourceTools')); |
||||
const ResourceWorker = React.lazy(() => import('./views/SimproV2/ResourceWorker')); |
||||
const Roles = React.lazy(() => import('./views/Master/MasterRoles')); |
||||
const Satuan = React.lazy(() => import('./views/SimproV2/Satuan')); |
||||
const ScheduleShift = React.lazy(() => import('./views/SimproV2/ScheduleShift')); |
||||
const Shift = React.lazy(() => import('./views/SimproV2/Shift')); |
||||
const TestGantt = React.lazy(() => import('./views/testgantt')); |
||||
const UserAdmin = React.lazy(() => import('./views/Master/UserAdmin')); |
||||
const UserShift = React.lazy(() => import('./views/SimproV2/UserShift')); |
||||
const DashboardProject = React.lazy(() => import('./views/DashboardProject')); |
||||
const DashboardPMOV1 = React.lazy(() => import('./views/DashboardPMOV1')); |
||||
|
||||
const routes = [ |
||||
{ path: '/', exact: true, name: 'Home' }, |
||||
{ path: '/dashboardold', name: 'Dashboard', component: DashboardSimpro }, |
||||
{ path: '/dashboard', name: 'Dashboard', component: DashboardPMOV1 }, |
||||
|
||||
{ path: '/projects', exact: true, name: 'Projects', component: CreatedProyek }, |
||||
{ path: '/projects/:id/:project/gantt', exact: true, name: 'Gantt', component: Gantt }, |
||||
{ path: '/human-resource', exact: true, name: 'Human Resource', component: ResourceWorker }, |
||||
{ path: '/material-resource', exact: true, name: 'Material Resource', component: ResourceMaterial }, |
||||
{ path: '/tools-resource', exact: true, name: 'Tools Resource', component: ResourceTools }, |
||||
|
||||
{ path: '/control-monitoring', exact: true, name: 'Control Monitoring', component: ControlMonitoring }, |
||||
{ path: '/control-monitoring-gantt', exact: true, name: 'Control Monitoring Gantt', component: ControlMonitoringGantt }, |
||||
{ path: '/presensi-resource', exact: true, name: 'Presensi Resource', component: Presensi }, |
||||
{ path: '/absensi-resource', exact: true, name: 'Absensi Resource', component: Absensi }, |
||||
{ path: '/laporan-k3', exact: true, name: 'Laporan K3', component: K3 }, |
||||
{ path: '/broadcast', exact: true, name: 'Broadcast', component: Broadcast }, |
||||
{ path: '/panic-button', exact: true, name: 'Tombol Darurat', component: PanicButton }, |
||||
|
||||
{ path: '/closing', exact: true, name: 'Closing', component: Closing }, |
||||
|
||||
{ path: '/menu', exact: true, name: 'Menu', component: Menu }, |
||||
{ path: '/roles', exact: true, name: 'Roles', component: Roles }, |
||||
{ path: '/project-role', exact: true, name: 'Project Role', component: ProjectRole }, |
||||
{ path: '/project-type', exact: true, name: 'Project Type', component: ProjectType }, |
||||
{ path: '/divisi', exact: true, name: 'Divisi', component: Divisi }, |
||||
{ path: '/satuan', exact: true, name: 'Satuan', component: Satuan }, |
||||
{ path: '/config-alert', exact: true, name: 'Config Alert', component: ConfigAlert }, |
||||
|
||||
{ path: '/checklist-k3', exact: true, name: 'Checklist K3', component: ChecklistK3 }, |
||||
{ path: '/absensi', exact: true, name: 'Absensi', component: Absensi }, |
||||
{ path: '/divisi-karyawan', exact: true, name: 'Divisi Karyawan', component: DivisiKaryawan }, |
||||
{ path: '/izin', exact: true, name: 'Izin', component: Izin }, |
||||
{ path: '/laporan-alert', exact: true, name: 'Laporan Alert', component: LaporanAlert }, |
||||
{ path: '/laporan-tugas-karyawan', exact: true, name: 'Laporan Tugas Karyawan', component: LaporanTugas }, |
||||
{ path: '/lembur', exact: true, name: 'Lembur', component: Lembur }, |
||||
{ path: '/map/baselayers', exact: true, name: 'Base Layers', component: BaseLayers }, |
||||
{ path: '/map/config', exact: true, name: 'Config', component: MapConfig }, |
||||
{ path: '/map/layers', exact: true, name: 'Layers', component: Layers }, |
||||
{ path: '/map/layers/:id', exact: true, name: 'Layer Details', component: Layer }, |
||||
{ path: '/office-hours', exact: true, name: 'Jam Kerja', component: OfficeHours }, |
||||
{ path: '/organization', exact: true, name: 'Organisasi', component: Organization }, |
||||
{ path: '/planning-harian', exact: true, name: 'Planning Harian', component: PlanningHarian }, |
||||
{ path: '/presensi', exact: true, name: 'Presensi', component: Presensi }, |
||||
{ path: '/proyek', exact: true, name: 'Created Project', component: Proyek }, |
||||
{ path: '/proyek-gantt', exact: true, name: 'Gantt Chart Proyek', component: TestGantt }, |
||||
{ path: '/rate-cost', exact: true, name: 'Rate Cost', component: RateCost }, |
||||
{ path: '/schedule-shift', exact: true, name: 'Schedule Shift', component: ScheduleShift }, |
||||
{ path: '/user-admin', exact: true, name: 'User Admin', component: UserAdmin }, |
||||
{ path: '/user-shift', exact: true, name: 'Shift', component: UserShift }, |
||||
{ path: '/working-hour', exact: true, name: 'Working Hour', component: Shift }, |
||||
{ path: '/dashboard-project/:ID/:GANTTID', exact: true, name: 'Dashboard Project', component: DashboardProject }, |
||||
]; |
||||
|
||||
export default routes; |
||||
import React from 'react'; |
||||
|
||||
const Absensi = React.lazy(() => import('./views/Master/MasterAbsensi')); |
||||
const BaseLayers = React.lazy(() => import('./views/BaseLayers')); |
||||
const Broadcast = React.lazy(() => import('./views/Master/MasterBroadcast')); |
||||
const ChecklistK3 = React.lazy(() => import('./views/SimproV2/ChecklistK3')); |
||||
const Closing = React.lazy(() => import('./views/SimproV2/Closing')); |
||||
const ConfigAlert = React.lazy(() => import('./views/Master/ConfigAlert')); |
||||
const ControlMonitoring = React.lazy(() => import('./views/Report/ControlMonitoring')); |
||||
const ControlMonitoringGantt = React.lazy(() => import('./views/ControlMonitoringGantt')); |
||||
const CreatedProyek = React.lazy(() => import('./views/SimproV2/CreatedProyek')); |
||||
const DashboardSimpro = React.lazy(() => import('./views/DashboardSimpro')); |
||||
const DashboardPMO = React.lazy(() => import('./views/DashboardPMO')); |
||||
const Divisi = React.lazy(() => import('./views/SimproV2/Divisi')); |
||||
const DivisiKaryawan = React.lazy(() => import('./views/Master/MasterTipeKaryawan')); |
||||
const Gantt = React.lazy(() => import('./views/SimproV2/Gantt')); |
||||
const Izin = React.lazy(() => import('./views/Master/MasterCuti')); |
||||
const K3 = React.lazy(() => import('./views/Report/k3')); |
||||
const LaporanAlert = React.lazy(() => import('./views/Report/alert')); |
||||
const LaporanTugas = React.lazy(() => import('./views/Master/MasterTask')); |
||||
const Layer = React.lazy(() => import('./views/Layers/Layer')); |
||||
const Layers = React.lazy(() => import('./views/Layers/Layers')); |
||||
const Lembur = React.lazy(() => import('./views/Master/MasterLembur')); |
||||
const MapConfig = React.lazy(() => import('./views/MapConfig')); |
||||
const Menu = React.lazy(() => import('./views/Master/MasterMenu')); |
||||
const OfficeHours = React.lazy(() => import('./views/Master/MasterOfficeHours')); |
||||
const Organization = React.lazy(() => import('./views/Master/MasterOrganization')); |
||||
const PanicButton = React.lazy(() => import('./views/SimproV2/PanicButton')); |
||||
const PlanningHarian = React.lazy(() => import('./views/SimproV2/PlanningHarian')); |
||||
const Presensi = React.lazy(() => import('./views/SimproV2/Presence')); |
||||
const ProjectRole = React.lazy(() => import('./views/Master/RoleProject')); |
||||
const ProjectType = React.lazy(() => import('./views/SimproV2/ProjectType')); |
||||
const ProjectPhase = React.lazy(() => import('./views/Master/ProjectPhase')); |
||||
const Proyek = React.lazy(() => import('./views/Master/Proyek')); |
||||
const RateCost = React.lazy(() => import('./views/SimproV2/RateCost')); |
||||
const ResourceMaterial = React.lazy(() => import('./views/SimproV2/ResourceMaterial')); |
||||
const ResourceTools = React.lazy(() => import('./views/SimproV2/ResourceTools')); |
||||
const ResourceWorker = React.lazy(() => import('./views/SimproV2/ResourceWorker')); |
||||
const Roles = React.lazy(() => import('./views/Master/MasterRoles')); |
||||
const Satuan = React.lazy(() => import('./views/SimproV2/Satuan')); |
||||
const ScheduleShift = React.lazy(() => import('./views/SimproV2/ScheduleShift')); |
||||
const Shift = React.lazy(() => import('./views/SimproV2/Shift')); |
||||
const TestGantt = React.lazy(() => import('./views/testgantt')); |
||||
const UserAdmin = React.lazy(() => import('./views/Master/UserAdmin')); |
||||
const UserShift = React.lazy(() => import('./views/SimproV2/UserShift')); |
||||
const DashboardProject = React.lazy(() => import('./views/DashboardProject')); |
||||
const DashboardPMOV1 = React.lazy(() => import('./views/DashboardPMOV1')); |
||||
|
||||
const routes = [ |
||||
{ path: '/', exact: true, name: 'Home' }, |
||||
{ path: '/dashboardold', name: 'Dashboard', component: DashboardSimpro }, |
||||
{ path: '/dashboard', name: 'Dashboard', component: DashboardPMOV1 }, |
||||
|
||||
{ path: '/projects', exact: true, name: 'Projects', component: CreatedProyek }, |
||||
{ path: '/projects/:id/:project/gantt', exact: true, name: 'Gantt', component: Gantt }, |
||||
{ path: '/human-resource', exact: true, name: 'Human Resource', component: ResourceWorker }, |
||||
{ path: '/material-resource', exact: true, name: 'Material Resource', component: ResourceMaterial }, |
||||
{ path: '/tools-resource', exact: true, name: 'Tools Resource', component: ResourceTools }, |
||||
|
||||
{ path: '/control-monitoring', exact: true, name: 'Control Monitoring', component: ControlMonitoring }, |
||||
{ path: '/control-monitoring-gantt', exact: true, name: 'Control Monitoring Gantt', component: ControlMonitoringGantt }, |
||||
{ path: '/presensi-resource', exact: true, name: 'Presensi Resource', component: Presensi }, |
||||
{ path: '/absensi-resource', exact: true, name: 'Absensi Resource', component: Absensi }, |
||||
{ path: '/laporan-k3', exact: true, name: 'Laporan K3', component: K3 }, |
||||
{ path: '/broadcast', exact: true, name: 'Broadcast', component: Broadcast }, |
||||
{ path: '/panic-button', exact: true, name: 'Tombol Darurat', component: PanicButton }, |
||||
|
||||
{ path: '/closing', exact: true, name: 'Closing', component: Closing }, |
||||
|
||||
{ path: '/menu', exact: true, name: 'Menu', component: Menu }, |
||||
{ path: '/roles', exact: true, name: 'Roles', component: Roles }, |
||||
{ path: '/project-role', exact: true, name: 'Project Role', component: ProjectRole }, |
||||
{ path: '/project-type', exact: true, name: 'Project Type', component: ProjectType }, |
||||
{ path: '/project-phase', exact: true, name: 'Project Phase', component: ProjectPhase }, |
||||
{ path: '/divisi', exact: true, name: 'Divisi', component: Divisi }, |
||||
{ path: '/satuan', exact: true, name: 'Satuan', component: Satuan }, |
||||
{ path: '/config-alert', exact: true, name: 'Config Alert', component: ConfigAlert }, |
||||
|
||||
{ path: '/checklist-k3', exact: true, name: 'Checklist K3', component: ChecklistK3 }, |
||||
{ path: '/absensi', exact: true, name: 'Absensi', component: Absensi }, |
||||
{ path: '/divisi-karyawan', exact: true, name: 'Divisi Karyawan', component: DivisiKaryawan }, |
||||
{ path: '/izin', exact: true, name: 'Izin', component: Izin }, |
||||
{ path: '/laporan-alert', exact: true, name: 'Laporan Alert', component: LaporanAlert }, |
||||
{ path: '/laporan-tugas-karyawan', exact: true, name: 'Laporan Tugas Karyawan', component: LaporanTugas }, |
||||
{ path: '/lembur', exact: true, name: 'Lembur', component: Lembur }, |
||||
{ path: '/map/baselayers', exact: true, name: 'Base Layers', component: BaseLayers }, |
||||
{ path: '/map/config', exact: true, name: 'Config', component: MapConfig }, |
||||
{ path: '/map/layers', exact: true, name: 'Layers', component: Layers }, |
||||
{ path: '/map/layers/:id', exact: true, name: 'Layer Details', component: Layer }, |
||||
{ path: '/office-hours', exact: true, name: 'Jam Kerja', component: OfficeHours }, |
||||
{ path: '/organization', exact: true, name: 'Organisasi', component: Organization }, |
||||
{ path: '/planning-harian', exact: true, name: 'Planning Harian', component: PlanningHarian }, |
||||
{ path: '/presensi', exact: true, name: 'Presensi', component: Presensi }, |
||||
{ path: '/proyek', exact: true, name: 'Created Project', component: Proyek }, |
||||
{ path: '/proyek-gantt', exact: true, name: 'Gantt Chart Proyek', component: TestGantt }, |
||||
{ path: '/rate-cost', exact: true, name: 'Rate Cost', component: RateCost }, |
||||
{ path: '/schedule-shift', exact: true, name: 'Schedule Shift', component: ScheduleShift }, |
||||
{ path: '/user-admin', exact: true, name: 'User Admin', component: UserAdmin }, |
||||
{ path: '/user-shift', exact: true, name: 'Shift', component: UserShift }, |
||||
{ path: '/working-hour', exact: true, name: 'Working Hour', component: Shift }, |
||||
{ path: '/dashboard-project/:ID/:GANTTID', exact: true, name: 'Dashboard Project', component: DashboardProject }, |
||||
]; |
||||
|
||||
export default routes; |
||||
|
@ -1,114 +0,0 @@
|
||||
import '../../../node_modules/react-grid-layout/css/styles.css'; |
||||
import '../../../node_modules/react-resizable/css/styles.css'; |
||||
import './Dashboard.css'; |
||||
import PieChart from './PieChart'; |
||||
import { BASE_OSPRO } from '../../const/ApiConst'; |
||||
import ContentLoader from "react-content-loader" |
||||
import React, { useEffect, useState } from 'react'; |
||||
import axios from 'axios' |
||||
import moment from 'moment'; |
||||
import numeral from 'numeral'; |
||||
import { Table, Tree, Row, Col, Space, Card} from 'antd'; |
||||
import { Pie } from '@ant-design/plots'; |
||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||
import { formatRibuanDecimal, DATE_TIME_FORMAT } from '../../const/CustomFunc.js'; |
||||
import { Badge } from 'reactstrap'; |
||||
|
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}`, |
||||
"Access-Control-Allow-Origin": "*" |
||||
} |
||||
} |
||||
|
||||
const Dashboard = () => { |
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
|
||||
const [dataTable, setDataTable] = useState([]) |
||||
const getProjects = async () => { |
||||
const URL = `${BASE_OSPRO}/api/project/list` |
||||
const result = await axios.get(URL, HEADER).then(res => res).catch(err => err.response) |
||||
if (result.data.code !== 200) { |
||||
NotificationManager.error('Belum ada data proyek!', 'Failed'); |
||||
} |
||||
console.log("res ", result.data.data) |
||||
setDataTable(result.data.data); |
||||
} |
||||
|
||||
const columns = [ |
||||
{ |
||||
title: 'Project', |
||||
dataIndex: 'nama', |
||||
key: 'nama', |
||||
render: (text) => <a>{text}</a>, |
||||
}, |
||||
{ |
||||
title: 'Planned Interval', |
||||
dataIndex: 'plannedInterval', |
||||
key: 'plannedInterval', |
||||
}, |
||||
{ |
||||
title: 'Planned Cost', |
||||
dataIndex: 'plannedCost', |
||||
key: 'plannedCost', |
||||
render: (text) => <a>{ formatRibuanDecimal(text) }</a>, |
||||
}, |
||||
{ |
||||
title: 'Actual Cost', |
||||
dataIndex: 'actualCost', |
||||
key: 'actualCost', |
||||
render: (text) => <a>{ formatRibuanDecimal(text) }</a>, |
||||
}, |
||||
{ |
||||
title: 'Cost Variance', |
||||
dataIndex: 'costVariance', |
||||
key: 'costVariance', |
||||
render: (text) => <a>{ formatRibuanDecimal(text) }</a>, |
||||
}, |
||||
{ |
||||
title: 'Cost Health', |
||||
dataIndex: 'costHealth', |
||||
key: 'costHealth', |
||||
render: (text) => { |
||||
if(text == "on-budget") { |
||||
return <Badge color="success">On Budget</Badge> |
||||
} else if(text == "warning") { |
||||
return <Badge color="warning">Warning</Badge> |
||||
} else { |
||||
return <Badge color="danger">Danger</Badge> |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
title: 'Progress', |
||||
dataIndex: 'progress', |
||||
key: 'progress', |
||||
}, |
||||
]; |
||||
|
||||
useEffect(() => { |
||||
getProjects(); |
||||
}, []) |
||||
|
||||
|
||||
return ( |
||||
<> |
||||
<Row gutter={[16, 16]}> |
||||
<Col span={24}> |
||||
<Table columns={columns} dataSource={dataTable} /> |
||||
</Col> |
||||
</Row> |
||||
</> |
||||
|
||||
); |
||||
} |
||||
|
||||
export default Dashboard; |
@ -1,199 +1,206 @@
|
||||
import React, {useEffect, useState} from 'react'; |
||||
import { Row, Col, Select } from 'antd'; |
||||
import TableDashboard from './tableDashboard'; |
||||
import React, { useEffect, useState } from 'react'; |
||||
import { Row, Col, Select, Collapse } from 'antd'; |
||||
import { Column } from '@ant-design/plots'; |
||||
import TableDashboardV1 from './tableDashboardv1'; |
||||
import { BarChart, DoughnutChart } from './chartDashboard'; |
||||
import { ProjectTypeChart } from './chartDashboard'; |
||||
import { ProjectPhaseChart } from './projectPhaseChart'; |
||||
import axios from 'axios' |
||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||
import { BASE_OSPRO } from '../../const/ApiConst'; |
||||
import { formatRibuanDecimal } from '../../const/CustomFunc.js'; |
||||
|
||||
|
||||
const { Panel } = Collapse; |
||||
|
||||
function BoxDashboard({ value, title, secondaryTitle, icon, bgColor }) { |
||||
return ( |
||||
<div style={{ backgroundColor: bgColor }} className='box-dashboard-pm'> |
||||
<Row> |
||||
<Col span={7}> |
||||
<div className='box-icon'> |
||||
{icon} |
||||
</div> |
||||
</Col> |
||||
<Col span={17}> |
||||
<div className='box-content'> |
||||
<div style={{ fontSize: '1.4rem' }} className='text-box'>{value}</div> |
||||
<div style={{ fontSize: '0.7rem' }} className='text-box'>{title.toUpperCase()}</div> |
||||
<div style={{ fontSize: '0.6rem' }} className='text-box-secondary'>{secondaryTitle && secondaryTitle.toUpperCase()}</div> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
<> |
||||
<div style={{ backgroundColor: bgColor }} class='box-dashboard-pm'> |
||||
<Row> |
||||
<Col span={4}> |
||||
<div class='box-icon'> |
||||
{icon} |
||||
</div> |
||||
</Col> |
||||
<Col span={20}> |
||||
<div class='box-content'> |
||||
<div style={{ fontSize: '1.0rem' }} class='text-box'>{value}</div> |
||||
<div style={{ fontSize: '0.7rem' }} class='text-box'>{title.toUpperCase()}</div> |
||||
<div style={{ fontSize: '0.6rem' }} class='text-box-secondary'>{secondaryTitle && secondaryTitle.toUpperCase()}</div> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
// pardon this, i've no time
|
||||
function BoxDashboardNoIcon({ value, title, secondaryTitle, bgColor }) { |
||||
return ( |
||||
<> |
||||
<div style={{ backgroundColor: bgColor }} class='box-dashboard-pm'> |
||||
<Row> |
||||
<Col span={24}> |
||||
<div class='box-content'> |
||||
<div style={{ fontSize: '1.4rem' }} class='text-box'>{value}</div> |
||||
<div style={{ fontSize: '0.7rem' }} class='text-box'>{title.toUpperCase()}</div> |
||||
<div style={{ fontSize: '0.6rem' }} class='text-box-secondary'>{secondaryTitle && secondaryTitle.toUpperCase()}</div> |
||||
</div> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
</> |
||||
) |
||||
} |
||||
|
||||
const { Option } = Select; |
||||
|
||||
const DashbaoardPM = () => { |
||||
const [PROJECTCOUNT, SET_PROJECTCOUNT] = useState([]) |
||||
const [PROJECTBUDGETTOTAL, SET_PROJECTBUDGETTOTAL] = useState([]) |
||||
const [PROJECTMANPOWER, SET_PROJETMANPOWER] = useState([]) |
||||
const [PROJECTACTUALCOSTTOTAL, SET_PROJECTACTUALCOSTTOTAL] = useState([]) |
||||
const DashboardPM = () => { |
||||
const [PROJECTCOUNT, SET_PROJECTCOUNT] = useState(0) |
||||
const [PROJECTBUDGETTOTAL, SET_PROJECTBUDGETTOTAL] = useState(0) |
||||
const [PROJECTMANPOWER, SET_PROJETMANPOWER] = useState(0) |
||||
const [PROJECTACTUALCOSTTOTAL, SET_PROJECTACTUALCOSTTOTAL] = useState(0) |
||||
const [PROJECTCOSTTOTAL, SET_PROJECTCOSTTOTAL] = useState(0) |
||||
const [TOTALREVENUE, SET_TOTALREVENUE] = useState(0) |
||||
|
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
|
||||
const getProjects = async () => { |
||||
const getProjectInfos = async () => { |
||||
const URL = `${BASE_OSPRO}/api/project/list` |
||||
const result = await axios.get(URL, HEADER).then(res => res).catch(err => err.response) |
||||
if (result.data.code !== 200) { |
||||
NotificationManager.error('Belum ada data proyek!', 'Failed'); |
||||
} |
||||
console.log("res ", result.data.data) |
||||
// setDataTable(result.data.data);
|
||||
|
||||
SET_PROJECTCOUNT(result.data.totalRecord) |
||||
SET_PROJECTACTUALCOSTTOTAL(result.data.totalActualCost) |
||||
SET_PROJECTBUDGETTOTAL(result.data.totalPlannedCost) |
||||
result.data.totalActualCost != undefined ? SET_PROJECTCOSTTOTAL(result.data.totalActualCost) : SET_PROJECTCOSTTOTAL(0) |
||||
result.data.totalPlannedCost != undefined ? SET_PROJECTBUDGETTOTAL(result.data.totalPlannedCost) : SET_PROJECTBUDGETTOTAL(0) |
||||
result.data.totalRevenue != undefined ? SET_TOTALREVENUE(result.data.totalRevenue) : SET_TOTALREVENUE(0) |
||||
} |
||||
|
||||
useEffect(() => { |
||||
getProjects(); |
||||
getProjectInfos(); |
||||
}, []) |
||||
|
||||
return ( |
||||
<div> |
||||
<Row> |
||||
<Col span={4}><h6 style={{ textAlign: 'center' }}>PORTOFOLIO DASHBOARD</h6></Col> |
||||
{/* <Col span={5}> |
||||
<Select |
||||
style={{ width: '100%', padding: '0 5px' }} |
||||
showSearch |
||||
placeholder="Department" |
||||
optionFilterProp="children" |
||||
onChange={onChange} |
||||
onSearch={onSearch} |
||||
filterOption={(input, option) => |
||||
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
||||
} |
||||
> |
||||
<Option value="jack">Jack</Option> |
||||
<Option value="lucy">Lucy</Option> |
||||
<Option value="tom">Tom</Option> |
||||
</Select> |
||||
</Col> |
||||
<Col span={5}> |
||||
<Select |
||||
style={{ width: '100%', padding: '0 5px' }} |
||||
showSearch |
||||
placeholder="Project Type" |
||||
optionFilterProp="children" |
||||
onChange={onChange} |
||||
onSearch={onSearch} |
||||
filterOption={(input, option) => |
||||
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
||||
} |
||||
> |
||||
{['Manned guarding ', 'C&T', 'CMS ', 'ESS', 'RSO'].map(res => ( |
||||
<Option value={res}>{res}</Option> |
||||
))} |
||||
|
||||
</Select> |
||||
</Col> |
||||
<Col span={5}> |
||||
<Select |
||||
style={{ width: '100%', padding: '0 5px' }} |
||||
showSearch |
||||
placeholder="Project Owner" |
||||
optionFilterProp="children" |
||||
onChange={onChange} |
||||
onSearch={onSearch} |
||||
filterOption={(input, option) => |
||||
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
||||
} |
||||
> |
||||
<Option value="jack">Jack</Option> |
||||
<Option value="lucy">Lucy</Option> |
||||
<Option value="tom">Tom</Option> |
||||
</Select> |
||||
</Col> |
||||
<Col span={5}> |
||||
<Select |
||||
style={{ width: '100%', padding: '0 5px' }} |
||||
showSearch |
||||
placeholder="Governance Phase" |
||||
optionFilterProp="children" |
||||
onChange={onChange} |
||||
onSearch={onSearch} |
||||
filterOption={(input, option) => |
||||
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
||||
} |
||||
> |
||||
{['Initiation ', 'Excecution', 'Closing '].map(res => ( |
||||
<Option value={res}>{res}</Option> |
||||
))} |
||||
</Select> |
||||
</Col> */} |
||||
</Row> |
||||
|
||||
<div style={{ paddingTop: 0 }}> |
||||
<Row> |
||||
<Col span={4}> |
||||
<BoxDashboard |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-assignment zmdi-hc-3x"></i>} |
||||
value={PROJECTCOUNT} |
||||
bgColor="teal" |
||||
title="Project Count" /> |
||||
{/* <BoxDashboard |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-money-box zmdi-hc-3x"></i>} |
||||
value="19 M" |
||||
bgColor="#059669" |
||||
title="Project Cost" |
||||
secondaryTitle="(dollars)" /> */} |
||||
<> |
||||
<div> |
||||
<Row |
||||
gutter={{ |
||||
xs: 8, |
||||
sm: 16, |
||||
md: 24, |
||||
lg: 32, |
||||
}} |
||||
> |
||||
<Col span={6} style={{ margin: '' }}> |
||||
<BoxDashboard |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-money zmdi-hc-3x"></i>} |
||||
value={`${PROJECTBUDGETTOTAL} M`} |
||||
bgColor="#047857" |
||||
title="Budget Project Total"
|
||||
// secondaryTitle="(dollars)"
|
||||
/> |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-money zmdi-hc-4x"></i>} |
||||
value={`${formatRibuanDecimal(PROJECTBUDGETTOTAL)}`} |
||||
bgColor="#077857" |
||||
title="Budget" |
||||
/> |
||||
</Col> |
||||
<Col span={6} style={{ margin: '' }}> |
||||
<BoxDashboard |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-accounts-alt zmdi-hc-3x"></i>} |
||||
value="2000" |
||||
bgColor="#0284c7" |
||||
title="Project Manpower" |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-money zmdi-hc-4x"></i>} |
||||
value={`${formatRibuanDecimal(PROJECTCOSTTOTAL)}`} |
||||
bgColor="#077857" |
||||
title="Spent on Projects" |
||||
/> |
||||
</Col> |
||||
<Col span={6} style={{ margin: '' }}> |
||||
<BoxDashboard |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-account zmdi-hc-3x"></i>} |
||||
value="540" |
||||
bgColor="#0369a1" |
||||
title="Manpower Variance" |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-money zmdi-hc-4x"></i>} |
||||
value={`${formatRibuanDecimal(TOTALREVENUE)}`} |
||||
bgColor="#077857" |
||||
title="Revenue" |
||||
/> |
||||
</Col> |
||||
<Col span={6} style={{ margin: '' }}> |
||||
<BoxDashboard |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-alert-circle zmdi-hc-3x"></i>} |
||||
value="80" |
||||
bgColor="#b30000" |
||||
title="Active Car" /> |
||||
icon={<i style={{ color: '#fff' }} class="zmdi zmdi-accounts-alt zmdi-hc-4x"></i>} |
||||
value="-" |
||||
bgColor="#0287c7" |
||||
title="Manpowers" |
||||
/> |
||||
</Col> |
||||
<Col span={20}> |
||||
<div style={{ padding: '20px 0 20px 5px' }}> |
||||
<Row> |
||||
<Col span={12}> |
||||
<BarChart /> |
||||
</Col> |
||||
<Col span={12}> |
||||
<DoughnutChart /> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
<div style={{ paddingLeft: 5, }}> |
||||
<TableDashboardV1 /> |
||||
</div> |
||||
</Row> |
||||
<Row style={{ marginTop: '15px' }}> |
||||
<Col span={24} style={{ margin: '0px 0px 0px 0px' }}> |
||||
<Collapse> |
||||
<Panel key="1"> |
||||
<Row style={{ margin: '15px 10px 0px 0px' }}> |
||||
<Col span={8} > |
||||
<Row |
||||
gutter={{ |
||||
xs: 8, |
||||
sm: 16, |
||||
md: 24, |
||||
lg: 32, |
||||
}} |
||||
> |
||||
<Col span={12}> |
||||
<BoxDashboardNoIcon |
||||
value="-" |
||||
bgColor="#077857" |
||||
title="Active / Standby" |
||||
/> |
||||
</Col> |
||||
<Col span={12}> |
||||
<BoxDashboardNoIcon |
||||
value="-" |
||||
bgColor="#077857" |
||||
title="Need Maintenance" |
||||
/> |
||||
</Col> |
||||
</Row> |
||||
<Row |
||||
gutter={{ |
||||
xs: 8, |
||||
sm: 16, |
||||
md: 24, |
||||
lg: 32, |
||||
}} |
||||
> |
||||
<Col span={12}> |
||||
<BoxDashboardNoIcon |
||||
bgColor="#077857" |
||||
title="" |
||||
value={<i style={{ color: '#fff' }} class="zmdi zmdi-truck zmdi-hc-2x"></i>} |
||||
/> |
||||
</Col> |
||||
<Col span={12}> |
||||
<BoxDashboardNoIcon |
||||
value="-" |
||||
bgColor="#077857" |
||||
title="On Maintenance" |
||||
/> |
||||
</Col> |
||||
</Row> |
||||
</Col> |
||||
<Col span={8}> |
||||
<ProjectPhaseChart /> |
||||
</Col> |
||||
<Col span={8}> |
||||
<ProjectTypeChart /> |
||||
</Col> |
||||
</Row> |
||||
</Panel> |
||||
</Collapse> |
||||
</Col> |
||||
</Row> |
||||
<Row style={{ marginTop: '15px' }}> |
||||
<Col span={24}> |
||||
<TableDashboardV1 /> |
||||
</Col> |
||||
</Row> |
||||
</div> |
||||
</div> |
||||
</> |
||||
); |
||||
} |
||||
|
||||
export default DashbaoardPM; |
||||
export default DashboardPM; |
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
import React from 'react'; |
||||
import { Bar } from 'react-chartjs-2'; |
||||
import { faker } from '@faker-js/faker'; |
||||
|
||||
const options = { |
||||
indexAxis: 'y', |
||||
responsive: true, |
||||
}; |
||||
|
||||
const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; |
||||
|
||||
export const data = { |
||||
labels, |
||||
datasets: [ |
||||
{ |
||||
label: 'Dataset 1', |
||||
data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), |
||||
borderColor: 'rgb(255, 99, 132)', |
||||
backgroundColor: 'rgba(255, 99, 132, 0.5)', |
||||
}, |
||||
{ |
||||
label: 'Dataset 2', |
||||
data: labels.map(() => faker.datatype.number({ min: -1000, max: 1000 })), |
||||
borderColor: 'rgb(53, 162, 235)', |
||||
backgroundColor: 'rgba(53, 162, 235, 0.5)', |
||||
}, |
||||
], |
||||
}; |
||||
|
||||
export function ProjectPhaseChart() { |
||||
return <Bar options={options} data={data} />; |
||||
} |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,121 @@
|
||||
import React, { useEffect, useState } from 'react' |
||||
import {
|
||||
Modal, ModalHeader, ModalBody, ModalFooter, |
||||
Button, Form, FormGroup, Label, Input, Col, Row |
||||
} from 'reactstrap'; |
||||
import { DatePicker, Tooltip, Select } from 'antd'; |
||||
import { formatRupiah, formatNumber } from '../../../const/CustomFunc' |
||||
import moment from 'moment'; |
||||
import 'antd/dist/antd.css'; |
||||
const { Option } = Select |
||||
|
||||
const DialogForm = ({openDialog, closeDialog, toggleDialog, typeDialog, dataEdit}) => { |
||||
const [id, setId] = useState(0)
|
||||
const [projectType, setProjectType] = useState('') |
||||
const [uom, setUom] = useState('') |
||||
const [description, setDescription] = useState('') |
||||
const [unitPrice, setUnitPrice] = useState() |
||||
|
||||
|
||||
|
||||
|
||||
useEffect(()=> { |
||||
if(typeDialog==="Edit"){ |
||||
console.log("cel data Edit", dataEdit) |
||||
setId(dataEdit.id) |
||||
setDescription(dataEdit.description) |
||||
setUnitPrice(dataEdit.unit_price) |
||||
setUom(dataEdit.uom) |
||||
setProjectType(dataEdit.name) |
||||
|
||||
}else{ |
||||
setId(0) |
||||
} |
||||
},[dataEdit,openDialog]) |
||||
|
||||
const handleSave = () => { |
||||
let data = ''; |
||||
if(typeDialog==="Save"){ |
||||
data = { |
||||
name: projectType, |
||||
description |
||||
} |
||||
|
||||
closeDialog('save', data); |
||||
}else{ |
||||
data = { |
||||
id, |
||||
name: projectType,
|
||||
description |
||||
} |
||||
closeDialog('edit', data); |
||||
} |
||||
setId(0) |
||||
setDescription('') |
||||
|
||||
} |
||||
|
||||
const handleCancel = () => { |
||||
closeDialog('cancel', 'none') |
||||
setId(0) |
||||
|
||||
setDescription('') |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const renderForm = () => { |
||||
return( |
||||
<Form> |
||||
<Row> |
||||
<Col md={6}> |
||||
<FormGroup> |
||||
<Label className="capitalize">Project Type</Label> |
||||
<Input type="text" value={projectType} onChange={(e)=> setProjectType(e.target.value)} placeholder={`Input material name...`}/> |
||||
</FormGroup> |
||||
</Col> |
||||
<Col md={6}> |
||||
<FormGroup> |
||||
<Label className="capitalize">Description</Label> |
||||
<Input row="4" type="textarea" value={description} onChange={(e)=> setDescription(e.target.value)} placeholder={`Description ...`} /> |
||||
</FormGroup> |
||||
</Col> |
||||
</Row> |
||||
</Form> |
||||
) |
||||
} |
||||
|
||||
|
||||
return ( |
||||
<> |
||||
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}> |
||||
<ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog=="Save" ? `Add` : "Edit"} Resource</ModalHeader> |
||||
<ModalBody> |
||||
{renderForm()} |
||||
</ModalBody> |
||||
<ModalFooter> |
||||
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{' '} |
||||
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button> |
||||
</ModalFooter> |
||||
</Modal> |
||||
|
||||
{/* <DialogMap |
||||
openDialog={openDialogMap} |
||||
closeDialog={handleCloseDialogMap} |
||||
toggleDialog={() => toggleMapDialog} |
||||
dataEdit={dataEdit} |
||||
workArea_={workArea} |
||||
lat_={lat} |
||||
lon_={lon} |
||||
radius_={radius} |
||||
/> */} |
||||
</> |
||||
) |
||||
|
||||
} |
||||
|
||||
export default DialogForm; |
@ -0,0 +1,89 @@
|
||||
import React, { useEffect, useState } from 'react' |
||||
import {
|
||||
Modal, ModalHeader, ModalBody, ModalFooter, |
||||
Button, Form, FormGroup, Label, Input, Col, Row |
||||
} from 'reactstrap'; |
||||
|
||||
const DialogForm = ({openDialog, closeDialog, toggleDialog, typeDialog, dataEdit, idActivity, projectTypeId}) => { |
||||
|
||||
const [id, setId] = useState(0)
|
||||
const [activity, setActivity] = useState('') |
||||
|
||||
useEffect(()=> { |
||||
if(typeDialog==="edit"){ |
||||
setId(dataEdit.id) |
||||
setActivity(dataEdit.name_activity) |
||||
|
||||
}else{ |
||||
setId(0) |
||||
setActivity('') |
||||
} |
||||
},[dataEdit,openDialog]) |
||||
|
||||
const handleSave = () => { |
||||
let data = ''; |
||||
|
||||
if(typeDialog==="add"){ |
||||
data = { |
||||
name_activity: activity, |
||||
proyek_type_id:projectTypeId |
||||
} |
||||
|
||||
if(idActivity && idActivity > 0){ |
||||
data['parent_id'] = idActivity |
||||
} |
||||
console.log("cek cek cek") |
||||
closeDialog('save', data); |
||||
}else{ |
||||
data = { |
||||
id, |
||||
name_activity: activity, |
||||
proyek_type_id:projectTypeId |
||||
} |
||||
|
||||
if(idActivity && idActivity > 0){ |
||||
data['parent_id'] = idActivity |
||||
} |
||||
console.log("cek cek cek 2") |
||||
closeDialog('edit', data); |
||||
} |
||||
setId(0) |
||||
setActivity('') |
||||
} |
||||
|
||||
const handleCancel = () => { |
||||
closeDialog('cancel', 'none') |
||||
setId(0) |
||||
setActivity('') |
||||
} |
||||
|
||||
const renderForm = () => { |
||||
return( |
||||
<Form> |
||||
<FormGroup> |
||||
<Label className="capitalize">Activity</Label> |
||||
<Input row="4" type="textarea" value={activity} onChange={(e)=> setActivity(e.target.value)} placeholder={`Persiapan ...`} /> |
||||
</FormGroup> |
||||
</Form> |
||||
) |
||||
} |
||||
|
||||
|
||||
return ( |
||||
<> |
||||
<Modal isOpen={openDialog} toggle={toggleDialog}> |
||||
<ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog=="add" ? `Add` : "Edit"} Activity</ModalHeader> |
||||
<ModalBody> |
||||
{renderForm()} |
||||
</ModalBody> |
||||
<ModalFooter> |
||||
<Button className='capitalize' color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{' '} |
||||
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button> |
||||
</ModalFooter> |
||||
</Modal> |
||||
</> |
||||
) |
||||
|
||||
} |
||||
|
||||
export default DialogForm; |
@ -0,0 +1,217 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react' |
||||
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; |
||||
import { Button } from 'reactstrap'; |
||||
import { Table, Tooltip } from 'antd'; |
||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||
import 'antd/dist/antd.css'; |
||||
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||
import { TEMPLATE_GANTT_ADD, TEMPLATE_GANTT_DELETE, TEMPLATE_GANTT_EDIT, TEMPLATE_GANTT_TREE } from '../../../const/ApiConst'; |
||||
import axios from "../../../const/interceptorApi" |
||||
import DialogForm from './DialogFormInitial'; |
||||
|
||||
const DialogInitialGantt = ({ openDialog, closeDialog, toggleDialog, idTypeProject }) => { |
||||
const token = window.localStorage.getItem('token'); |
||||
const config = { |
||||
headers: |
||||
{ |
||||
Authorization: `Bearer ${token}`, |
||||
"Content-type": `application/json` |
||||
} |
||||
}; |
||||
|
||||
const [dataTable, setDataTable] = useState([]) |
||||
const [alertDelete, setAlertDelete] = useState(false) |
||||
const [idDelete, setIdDelete] = useState(0) |
||||
const [idActivity, setIdActivity] = useState(0) |
||||
const [openDialogForm, setOpenDialogForm] = useState(false) |
||||
const [typeDialog, setTypeDialog] = useState("add") |
||||
const [dataEdit, setDataEdit] = useState([]) |
||||
|
||||
useEffect(() => { |
||||
if (idTypeProject && idTypeProject > 0) { |
||||
getDataInitial(); |
||||
} |
||||
}, [idTypeProject]) |
||||
|
||||
const getDataInitial = async () => { |
||||
const url = TEMPLATE_GANTT_TREE(idTypeProject) |
||||
const result = await axios |
||||
.get(url, config) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
if (result && result.data && result.data.code == 200) { |
||||
setDataTable(result.data.data); |
||||
} else { |
||||
NotificationManager.error('Gagal mengambil data, Silahkan coba lagi!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const handleDelete = async (id) => { |
||||
await setIdDelete(id) |
||||
await setAlertDelete(true) |
||||
} |
||||
|
||||
const onConfirmDelete = async () => { |
||||
let url = TEMPLATE_GANTT_DELETE(idDelete); |
||||
|
||||
const result = await axios.delete(url, config) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataInitial() |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.success(`Activity berhasil dihapus!`, 'Success!!'); |
||||
} else { |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.error(`Activity gagal dihapus!}`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const cancelDelete = () => { |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
} |
||||
|
||||
const handleAdd = async () => { |
||||
setIdActivity(0) |
||||
await setTypeDialog("add") |
||||
setOpenDialogForm(true) |
||||
} |
||||
|
||||
const handleEdit = async (data) => { |
||||
await setDataEdit(data) |
||||
if (data.parent_id) { |
||||
await setIdActivity(data.parent_id); |
||||
} |
||||
await setTypeDialog("edit") |
||||
setOpenDialogForm(true) |
||||
} |
||||
|
||||
const handleAddWithParent = async (id) => { |
||||
setIdActivity(id) |
||||
await setTypeDialog("add") |
||||
setOpenDialogForm(true) |
||||
} |
||||
|
||||
const closeDialogForm = (type, data) => { |
||||
if (type == "save") { |
||||
saveActivity(data) |
||||
} else if (type == "edit") { |
||||
updateActivity(data) |
||||
} |
||||
setIdActivity(0) |
||||
setOpenDialogForm(false) |
||||
} |
||||
|
||||
const toggleDialogForm = () => { |
||||
if (openDialogForm) { |
||||
setIdActivity(0) |
||||
} |
||||
setOpenDialogForm(!openDialogForm); |
||||
} |
||||
|
||||
const saveActivity = async (data) => { |
||||
const result = await axios.post(TEMPLATE_GANTT_ADD, data, config) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataInitial() |
||||
NotificationManager.success(`Data activity berhasil ditambah`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const updateActivity = async (data) => { |
||||
const url = TEMPLATE_GANTT_EDIT(data.id) |
||||
const result = await axios.put(url, data, config) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataInitial() |
||||
NotificationManager.success(`Data activity berhasil diedit`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const renderTable = useMemo(() => { |
||||
const columns = [ |
||||
{ |
||||
title: 'Action', |
||||
dataIndex: '', |
||||
key: 'id', |
||||
className: "nowrap", |
||||
render: (text, record) => |
||||
<> |
||||
<Tooltip title="Delete Activity"> |
||||
<Button size="small" size={"sm"} color='danger' onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button> |
||||
</Tooltip>{" "}<Tooltip title="Add Activity"> |
||||
<Button size="small" size={"sm"} color='primary' onClick={() => handleAddWithParent(text.id)}><i className="fa fa-plus"></i></Button> |
||||
</Tooltip>{" "}<Tooltip title="Edit Activity"> |
||||
<Button size="small" size={"sm"} color='warning' onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button> |
||||
</Tooltip> |
||||
</> |
||||
, |
||||
}, |
||||
{ title: 'Nama Activity', dataIndex: 'name_activity', key: 'name_activity' }, |
||||
]; |
||||
|
||||
return ( |
||||
<Table |
||||
size="small" |
||||
columns={columns} |
||||
dataSource={dataTable} |
||||
pagination={{ position: ["bottomLeft"] }} |
||||
/> |
||||
) |
||||
}, [dataTable]) |
||||
|
||||
|
||||
return (<> |
||||
<NotificationContainer /> |
||||
<SweetAlert |
||||
show={alertDelete} |
||||
warning |
||||
showCancel |
||||
confirmBtnText="Delete" |
||||
confirmBtnBsStyle="danger" |
||||
title={`Are you sure?`} |
||||
onConfirm={onConfirmDelete} |
||||
onCancel={cancelDelete} |
||||
focusCancelBtn |
||||
> |
||||
Delete this data |
||||
</SweetAlert> |
||||
<DialogForm |
||||
openDialog={openDialogForm} |
||||
closeDialog={closeDialogForm} |
||||
toggleDialog={toggleDialogForm} |
||||
idActivity={idActivity} |
||||
typeDialog={typeDialog} |
||||
dataEdit={dataEdit} |
||||
projectTypeId={idTypeProject} |
||||
/> |
||||
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}> |
||||
{/* <ModalHeader className="capitalize" toggle={closeDialog}>Initial Gantt</ModalHeader> */} |
||||
<ModalHeader className="capitalize withBtn" toggle={closeDialog} style={{ width: "100%" }}> |
||||
<div>Template Gantt</div> <Button onClick={handleAdd} size='sm' color="primary"><i className='fa fa-plus'></i></Button> |
||||
</ModalHeader> |
||||
<ModalBody> |
||||
{renderTable} |
||||
</ModalBody> |
||||
<ModalFooter> |
||||
<Button className="capitalize" color="secondary" onClick={closeDialog}>Close</Button> |
||||
</ModalFooter> |
||||
</Modal> |
||||
</> |
||||
) |
||||
|
||||
} |
||||
|
||||
export default DialogInitialGantt; |
@ -0,0 +1,325 @@
|
||||
import * as XLSX from 'xlsx'; |
||||
import DialogForm from './DialogForm'; |
||||
import DialogInitialGantt from './DialogInitialGantt'; |
||||
import React, { useState, useEffect, useMemo } from 'react'; |
||||
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||
import axios from "../../../const/interceptorApi" |
||||
import moment from 'moment' |
||||
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||
import { PROJECT_PHASE_ADD, PROJECT_PHASE_EDIT, PROJECT_PHASE_DELETE, PROJECT_PHASE_SEARCH } from '../../../const/ApiConst'; |
||||
import { Pagination, Button, Tooltip, Table } from 'antd'; |
||||
|
||||
const token = window.localStorage.getItem('token'); |
||||
const config = { |
||||
headers: |
||||
{ |
||||
Authorization: `Bearer ${token}`, |
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", |
||||
"Access-Control-Allow-Origin": `*` |
||||
} |
||||
}; |
||||
|
||||
const ProjectPhase = ({ params }) => { |
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", |
||||
"Access-Control-Allow-Origin": "*", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
const pageName = params.name; |
||||
|
||||
const [alertDelete, setAlertDelete] = useState(false) |
||||
const [allDataMenu, setAllDataMenu] = useState([]) |
||||
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||
const [currentPage, setCurrentPage] = useState(1) |
||||
const [dataEdit, setDataEdit] = useState([]) |
||||
const [dataTable, setDatatable] = useState([]) |
||||
const [idDelete, setIdDelete] = useState(0) |
||||
const [idPhaseProject, setIdPhaseProject] = useState(0) |
||||
const [openDialog, setOpenDialog] = useState(false) |
||||
const [openDialogIG, setOpenDialogIG] = useState(false) |
||||
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||
const [search, setSearch] = useState('') |
||||
const [totalPage, setTotalPage] = useState(0) |
||||
const [typeDialog, setTypeDialog] = useState('Save') |
||||
|
||||
useEffect(() => { |
||||
getDataProjectPhase() |
||||
}, [currentPage, rowsPerPage, search]) |
||||
|
||||
const getDataProjectPhase = async () => { |
||||
let start = 0; |
||||
if (currentPage !== 1 && currentPage > 1) { |
||||
start = (currentPage * rowsPerPage) - rowsPerPage |
||||
} |
||||
|
||||
const payload = { |
||||
"columns": [ |
||||
{ |
||||
"name": "name", |
||||
"logic_operator": "like", |
||||
"value": search, |
||||
"operator": "AND" |
||||
} |
||||
], |
||||
"orders": { |
||||
"ascending": true, |
||||
"columns": [ |
||||
'id' |
||||
] |
||||
}, |
||||
"paging": { |
||||
"length": rowsPerPage, |
||||
"start": start |
||||
} |
||||
} |
||||
|
||||
const result = await axios |
||||
.post(PROJECT_PHASE_SEARCH, payload, config) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
setDatatable(result.data.data); |
||||
setTotalPage(result.data.totalRecord); |
||||
} else { |
||||
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const handleSearch = e => { |
||||
const value = e.target.value |
||||
setSearch(value); |
||||
setCurrentPage(1) |
||||
}; |
||||
|
||||
const handleOpenDialog = (type) => { |
||||
setOpenDialog(true) |
||||
setTypeDialog(type) |
||||
} |
||||
|
||||
const handleExportExcel = async () => { |
||||
let start = 0; |
||||
|
||||
const payload = { |
||||
"paging": { "start": start, "length": -1 }, |
||||
"columns": [ |
||||
{ "name": "name", "logic_operator": "ilike", "value": search, "operator": "AND" } |
||||
], |
||||
"joins": [], |
||||
"orders": { "columns": ["id"], "ascending": false } |
||||
} |
||||
|
||||
const result = await axios |
||||
.post(PROJECT_PHASE_SEARCH, payload) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
} |
||||
|
||||
const handleEdit = (data) => { |
||||
setDataEdit(data) |
||||
handleOpenDialog('Edit'); |
||||
} |
||||
|
||||
const handleDelete = async (id) => { |
||||
await setAlertDelete(true) |
||||
await setIdDelete(id) |
||||
} |
||||
|
||||
const handleCloseDialog = (type, data) => { |
||||
if (type === "save") { |
||||
saveProjectPhase(data); |
||||
} else if (type === "edit") { |
||||
editMaterialR(data); |
||||
} |
||||
setDataEdit([]) |
||||
setOpenDialog(false) |
||||
} |
||||
|
||||
const saveProjectPhase = async (data) => { |
||||
const formData = data |
||||
const result = await axios.post(PROJECT_PHASE_ADD, formData, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProjectPhase() |
||||
NotificationManager.success(`Data project type berhasil ditambah`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const editMaterialR = async (data) => { |
||||
let urlEdit = PROJECT_PHASE_EDIT(data.id) |
||||
const formData = data |
||||
|
||||
const result = await axios.put(urlEdit, formData, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProjectPhase(); |
||||
NotificationManager.success(`Data project phase berhasil diedit`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`Data project phase gagal di edit`, `Failed!!`); |
||||
} |
||||
} |
||||
|
||||
const toggleAddDialog = () => { |
||||
setOpenDialog(!openDialog) |
||||
} |
||||
|
||||
const handleDialogIg = (id) => { |
||||
setIdPhaseProject(id) |
||||
setOpenDialogIG(true) |
||||
} |
||||
|
||||
const closeDialogIG = () => { |
||||
setIdPhaseProject(0) |
||||
setOpenDialogIG(false) |
||||
} |
||||
|
||||
const toggleDialogIG = () => { |
||||
if (openDialogIG) { |
||||
setIdPhaseProject(0) |
||||
} |
||||
setOpenDialogIG(!openDialogIG); |
||||
} |
||||
|
||||
const onConfirmDelete = async () => { |
||||
let url = PROJECT_PHASE_DELETE(idDelete); |
||||
|
||||
const result = await axios.delete(url, config) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProjectPhase() |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.success(`Data project phase berhasil dihapus!`, 'Success!!'); |
||||
} else { |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.error(`Data project phase gagal dihapus!}`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const cancelDelete = () => { |
||||
setAlertDelete(false) |
||||
setIdDelete(0) |
||||
} |
||||
|
||||
const onShowSizeChange = (current, pageSize) => { |
||||
setRowsPerPage(pageSize) |
||||
} |
||||
|
||||
const onPagination = (current, pageSize) => { |
||||
setCurrentPage(current) |
||||
} |
||||
|
||||
const dataNotAvailable = () => { |
||||
if (dataTable.length === 0) { |
||||
return ( |
||||
<tr> |
||||
<td align="center" colSpan="3">Tidak ada data project phase</td> |
||||
</tr> |
||||
) |
||||
} |
||||
} |
||||
|
||||
const renderTable = useMemo(() => { |
||||
const columns = [ |
||||
{ |
||||
title: 'Action', |
||||
dataIndex: '', |
||||
key: 'x', |
||||
className: 'nowrap', |
||||
render: (text, record) => <> |
||||
<Tooltip title="Delete"> |
||||
<i className="fa fa-trash" style={{ color: 'red', marginRight: '10px', cursor: "pointer" }} onClick={() => handleDelete(text.id)}></i> |
||||
</Tooltip> |
||||
<Tooltip title="Edit"> |
||||
<i className="fa fa-edit" style={{ color: 'green', cursor: "pointer" }} onClick={() => handleEdit(text)}></i> |
||||
</Tooltip>{" "} |
||||
</>, |
||||
}, |
||||
{ title: 'Fase', dataIndex: 'name', key: 'name', className: "nowrap" }, |
||||
{ title: 'Warna', dataIndex: 'color', key: 'color' }, |
||||
]; |
||||
return ( |
||||
<Table |
||||
rowKey="id" |
||||
size="small" |
||||
columns={columns} |
||||
dataSource={dataTable} |
||||
pagination={false} |
||||
/> |
||||
) |
||||
}, [dataTable]) |
||||
|
||||
return ( |
||||
<div> |
||||
<NotificationContainer /> |
||||
<SweetAlert |
||||
show={alertDelete} |
||||
warning |
||||
showCancel |
||||
confirmBtnText="Delete" |
||||
confirmBtnBsStyle="danger" |
||||
title={`Are you sure?`} |
||||
onConfirm={onConfirmDelete} |
||||
onCancel={() => cancelDelete()} |
||||
focusCancelBtn |
||||
> |
||||
Delete this data |
||||
</SweetAlert> |
||||
<DialogForm |
||||
openDialog={openDialog} |
||||
closeDialog={handleCloseDialog} |
||||
toggleDialog={() => toggleAddDialog} |
||||
typeDialog={typeDialog} |
||||
dataEdit={dataEdit} |
||||
clickOpenModal={clickOpenModal} |
||||
dataParent={allDataMenu} |
||||
/> |
||||
<DialogInitialGantt |
||||
closeDialog={closeDialogIG} |
||||
openDialog={openDialogIG} |
||||
toggleDialog={toggleDialogIG} |
||||
idPhaseProject={idPhaseProject} |
||||
/> |
||||
<Card> |
||||
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||
<h4 className="capitalize">{pageName}</h4> |
||||
<Row> |
||||
<Col> |
||||
<Tooltip title="Add Material Resource"> |
||||
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button> |
||||
</Tooltip> |
||||
</Col> |
||||
</Row> |
||||
</CardHeader> |
||||
<CardBody> |
||||
{renderTable} |
||||
<Pagination |
||||
style={{ marginTop: "25px" }} |
||||
showSizeChanger |
||||
onShowSizeChange={onShowSizeChange} |
||||
onChange={onPagination} |
||||
defaultCurrent={currentPage} |
||||
pageSize={rowsPerPage} |
||||
total={totalPage} |
||||
pageSizeOptions={["10", "15", "20", "25", "30", "35", "40"]} |
||||
/> |
||||
</CardBody> |
||||
</Card> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default ProjectPhase; |
Loading…
Reference in new issue