Browse Source

dashboard project types & project-phase

pull/2/head
Yusuf 2 years ago
parent
commit
a69c0df10d
  1. 1
      package.json
  2. 33
      src/scss/_custom.scss
  3. 28
      src/views/DashboardPMOV1/chartDashboard.js
  4. 7
      src/views/DashboardPMOV1/index.js
  5. 75
      src/views/Master/ProjectPhase/DialogForm.js
  6. 217
      src/views/Master/ProjectPhase/DialogInitialGantt.js
  7. 46
      src/views/Master/ProjectPhase/InputColor.js
  8. 40
      src/views/Master/ProjectPhase/index.js
  9. 41
      src/views/Master/ProjectPhase/styles.css

1
package.json

@ -54,6 +54,7 @@
"numeral": "^2.0.6", "numeral": "^2.0.6",
"ol": "^5.3.3", "ol": "^5.3.3",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"rc-color-picker": "^1.2.6",
"react": "^16.14.0", "react": "^16.14.0",
"react-app-polyfill": "^1.0.1", "react-app-polyfill": "^1.0.1",
"react-awesome-query-builder": "^4.3.0", "react-awesome-query-builder": "^4.3.0",

33
src/scss/_custom.scss

@ -127,3 +127,36 @@
.chat-body { .chat-body {
padding: 6px 10px padding: 6px 10px
} }
.rc-color-picker-panel {
border: 1px solid #ccc;
}
.rc-color-picker-panel-inner {
border: none;
box-shadow: none;
}
.rc-color-picker-panel-board-hsv {
border-radius: 12px;
outline: none;
}
.rc-color-picker-panel-board-value {
border: none;
border-radius: 12px;
}
.rc-color-picker-panel-board-saturation {
border: none;
border-radius: 12px;
}
.rc-color-picker-panel-ribbon {
border-radius: 12px;
}
.rc-color-picker-panel-wrap-preview {
border-radius: 12px;
}
.rc-color-picker-panel-preview span {
border-radius: 12px;
}
.rc-color-picker-panel-preview input {
border-radius: 12px;
}

28
src/views/DashboardPMOV1/chartDashboard.js

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { Doughnut } from 'react-chartjs-2'; import { Doughnut } from 'react-chartjs-2';
import { faker } from '@faker-js/faker';
const options = { const options = {
title: { title: {
@ -9,12 +8,16 @@ const options = {
}, },
}; };
const data = { export const ProjectTypeChart = ({ projectTypes, projectsByType }) => {
labels: ['Pengadaan Barang dan Jasa','Kontruksi', 'FTTH'], let total = []
datasets: [
{ for (var j = 0; j < projectTypes.length; j++) {
label: '# of Votes', total.push(projectsByType[j].total)
data: [1, 1, 2], }
let dataSets = [{
label: "#",
data: total,
backgroundColor: [ backgroundColor: [
'rgba(255, 99, 132, 0.2)', 'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)', 'rgba(54, 162, 235, 0.2)',
@ -29,10 +32,13 @@ const data = {
'rgba(153, 102, 255, 1)', 'rgba(153, 102, 255, 1)',
], ],
borderWidth: 1, borderWidth: 1,
}, }]
],
}; const data = {
labels: projectTypes,
datasets: dataSets,
};
export const ProjectTypeChart = () => {
return <Doughnut data={data} options={options} />; return <Doughnut data={data} options={options} />;
} }

7
src/views/DashboardPMOV1/index.js

@ -64,6 +64,9 @@ const DashboardPM = () => {
const [PROJECTPHASES, SET_PROJECTPHASES] = useState([]) const [PROJECTPHASES, SET_PROJECTPHASES] = useState([])
const [PROJECTSBYPHASE, SET_PROJECTSBYPHASE] = useState([]) const [PROJECTSBYPHASE, SET_PROJECTSBYPHASE] = useState([])
const [PROJECTTYPES, SET_PROJECTTYPES] = useState([])
const [PROJECTSBYTYPE, SET_PROJECTSBYTYPE] = useState([])
const token = localStorage.getItem("token") const token = localStorage.getItem("token")
const HEADER = { const HEADER = {
headers: { headers: {
@ -83,6 +86,8 @@ const DashboardPM = () => {
result.data.manpowers != undefined ? SET_MANPOWERS(result.data.manpowers) : SET_MANPOWERS(0) result.data.manpowers != undefined ? SET_MANPOWERS(result.data.manpowers) : SET_MANPOWERS(0)
result.data.projectPhases != undefined ? SET_PROJECTPHASES(result.data.projectPhases) : SET_PROJECTPHASES([]) result.data.projectPhases != undefined ? SET_PROJECTPHASES(result.data.projectPhases) : SET_PROJECTPHASES([])
result.data.projectsByPhase != undefined ? SET_PROJECTSBYPHASE(result.data.projectsByPhase) : SET_PROJECTSBYPHASE([]) result.data.projectsByPhase != undefined ? SET_PROJECTSBYPHASE(result.data.projectsByPhase) : SET_PROJECTSBYPHASE([])
result.data.projectTypes != undefined ? SET_PROJECTTYPES(result.data.projectTypes) : SET_PROJECTTYPES([])
result.data.projectsByType != undefined ? SET_PROJECTSBYTYPE(result.data.projectsByType) : SET_PROJECTSBYTYPE([])
} }
@ -205,7 +210,7 @@ const DashboardPM = () => {
<ProjectPhaseChart projectPhases={PROJECTPHASES} projectsByPhase={PROJECTSBYPHASE} /> <ProjectPhaseChart projectPhases={PROJECTPHASES} projectsByPhase={PROJECTSBYPHASE} />
</Col> </Col>
<Col span={8}> <Col span={8}>
<ProjectTypeChart /> <ProjectTypeChart projectTypes={PROJECTTYPES} projectsByType={PROJECTSBYTYPE} />
</Col> </Col>
</Row> </Row>
</Panel> </Panel>

75
src/views/Master/ProjectPhase/DialogForm.js

@ -3,85 +3,67 @@ import {
Modal, ModalHeader, ModalBody, ModalFooter, Modal, ModalHeader, ModalBody, ModalFooter,
Button, Form, FormGroup, Label, Input, Col, Row Button, Form, FormGroup, Label, Input, Col, Row
} from 'reactstrap'; } from 'reactstrap';
import { DatePicker, Tooltip, Select } from 'antd';
import { formatRupiah, formatNumber } from '../../../const/CustomFunc'
import moment from 'moment';
import 'antd/dist/antd.css'; import 'antd/dist/antd.css';
const { Option } = Select import InputColor from "./InputColor";
import "./styles.css";
import "rc-color-picker/assets/index.css";
const DialogForm = ({openDialog, closeDialog, toggleDialog, typeDialog, dataEdit}) => { const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit }) => {
const [id, setId] = useState(0) const [id, setId] = useState(0)
const [projectType, setProjectType] = useState('') const [projectType, setProjectType] = useState('')
const [uom, setUom] = useState('') const [color, setColor] = useState('')
const [description, setDescription] = useState('')
const [unitPrice, setUnitPrice] = useState()
useEffect(() => {
if (typeDialog === "Edit") {
useEffect(()=> {
if(typeDialog==="Edit"){
console.log("cel data Edit", dataEdit) console.log("cel data Edit", dataEdit)
setId(dataEdit.id) setId(dataEdit.id)
setDescription(dataEdit.description)
setUnitPrice(dataEdit.unit_price)
setUom(dataEdit.uom)
setProjectType(dataEdit.name) setProjectType(dataEdit.name)
setColor(dataEdit.color)
}else{ } else {
setId(0) setId(0)
setColor('')
setProjectType('')
} }
},[dataEdit,openDialog]) }, [dataEdit, openDialog])
const handleSave = () => { const handleSave = () => {
let data = ''; let data = '';
if(typeDialog==="Save"){ if (typeDialog === "Save") {
data = { data = {
name: projectType, name: projectType,
description color
} }
closeDialog('save', data); closeDialog('save', data);
}else{ } else {
data = { data = {
id, id,
name: projectType, name: projectType,
description color
} }
closeDialog('edit', data); closeDialog('edit', data);
} }
setId(0) setId(0)
setDescription('')
} }
const handleCancel = () => { const handleCancel = () => {
closeDialog('cancel', 'none') closeDialog('cancel', 'none')
setId(0) setId(0)
setDescription('')
} }
const renderForm = () => { const renderForm = () => {
return( return (
<Form> <Form>
<Row> <Row>
<Col md={6}> <Col md={6}>
<FormGroup> <FormGroup>
<Label className="capitalize">Project Type</Label> <Label className="capitalize">Phase</Label>
<Input type="text" value={projectType} onChange={(e)=> setProjectType(e.target.value)} placeholder={`Input material name...`}/> <Input type="text" value={projectType} onChange={(e) => setProjectType(e.target.value)} />
</FormGroup> </FormGroup>
</Col> </Col>
<Col md={6}> <Col md={6}>
<FormGroup> <FormGroup>
<Label className="capitalize">Description</Label> <Label className="capitalize">Warna</Label>
<Input row="4" type="textarea" value={description} onChange={(e)=> setDescription(e.target.value)} placeholder={`Description ...`} /> <InputColor value={color} onChange={(e) => setColor(e.color)} />
</FormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
@ -89,11 +71,10 @@ const DialogForm = ({openDialog, closeDialog, toggleDialog, typeDialog, dataEdit
) )
} }
return ( return (
<> <>
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}> <Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog=="Save" ? `Add` : "Edit"} Resource</ModalHeader> <ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog == "Save" ? `Add` : "Edit"} data</ModalHeader>
<ModalBody> <ModalBody>
{renderForm()} {renderForm()}
</ModalBody> </ModalBody>
@ -102,20 +83,8 @@ const DialogForm = ({openDialog, closeDialog, toggleDialog, typeDialog, dataEdit
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button> <Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button>
</ModalFooter> </ModalFooter>
</Modal> </Modal>
{/* <DialogMap
openDialog={openDialogMap}
closeDialog={handleCloseDialogMap}
toggleDialog={() => toggleMapDialog}
dataEdit={dataEdit}
workArea_={workArea}
lat_={lat}
lon_={lon}
radius_={radius}
/> */}
</> </>
) )
} }
export default DialogForm; export default DialogForm;

217
src/views/Master/ProjectPhase/DialogInitialGantt.js

@ -1,217 +0,0 @@
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;

46
src/views/Master/ProjectPhase/InputColor.js

@ -0,0 +1,46 @@
import React from "react";
import Input from "antd/lib/input";
import Button from "antd/lib/button";
import Dropdown from "antd/lib/dropdown";
import { Panel } from 'rc-color-picker'
import "antd/dist/antd.css";
import "./styles.css";
export default function InputColor(props) {
const { color, onChange } = props;
const [internalColor, setInternalColor] = React.useState(color);
const handleChange = (color) => {
setInternalColor(color.color);
if (onChange) {
onChange(color);
}
};
const overlay = (
<div>
<Panel
color={internalColor}
enableAlpha={false}
onChange={handleChange}
/>
</div>
);
return (
<>
<Input
value={internalColor || ""}
onChange={(e) => setInternalColor(e.target.value)}
suffix={
<Dropdown trigger={["click"]} overlay={overlay}>
<Button style={{ background: internalColor }}> </Button>
</Dropdown>
}
/>
</>
);
}

40
src/views/Master/ProjectPhase/index.js

@ -1,13 +1,12 @@
import * as XLSX from 'xlsx'; import * as XLSX from 'xlsx';
import DialogForm from './DialogForm'; import DialogForm from './DialogForm';
import DialogInitialGantt from './DialogInitialGantt';
import React, { useState, useEffect, useMemo } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import SweetAlert from 'react-bootstrap-sweetalert'; import SweetAlert from 'react-bootstrap-sweetalert';
import axios from "../../../const/interceptorApi" import axios from "../../../const/interceptorApi"
import moment from 'moment' import moment from 'moment'
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap';
import { NotificationContainer, NotificationManager } from 'react-notifications'; import { NotificationContainer, NotificationManager } from 'react-notifications';
import { PROJECT_PHASE_ADD, PROJECT_PHASE_EDIT, PROJECT_PHASE_DELETE, PROJECT_PHASE_SEARCH } from '../../../const/ApiConst'; import { PROJECT_PHASE_ADD, PROJECT_PHASE_EDIT, PROJECT_PHASE_DELETE, PROJECT_PHASE_SEARCH, BASE_OSPRO } from '../../../const/ApiConst';
import { Pagination, Button, Tooltip, Table } from 'antd'; import { Pagination, Button, Tooltip, Table } from 'antd';
const token = window.localStorage.getItem('token'); const token = window.localStorage.getItem('token');
@ -16,18 +15,23 @@ const config = {
{ {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Access-Control-Allow-Origin": `*`
} }
}; };
const ProjectPhase = ({ params }) => { const ProjectPhase = ({ params }) => {
const token = localStorage.getItem("token") const token = localStorage.getItem("token")
const HEADER = { /*const HEADER = {
headers: { headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
"Authorization": `Bearer ${token}` "Authorization": `Bearer ${token}`
} }
}*/
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
} }
const pageName = params.name; const pageName = params.name;
@ -77,10 +81,15 @@ const ProjectPhase = ({ params }) => {
} }
} }
const result = await axios /*const result = await axios
.post(PROJECT_PHASE_SEARCH, payload, config) .post(PROJECT_PHASE_SEARCH, payload, config)
.then(res => res) .then(res => res)
.catch((error) => error.response); .catch((error) => error.response);*/
//const result = await axios.post(PROJECT_PHASE_SEARCH, payload, HEADER).then(res => res).catch(err => err.response)
const URL = `${BASE_OSPRO}/api/project-phase/list`
const result = await axios.get(URL, HEADER).then(res => res).catch(err => err.response)
console.log(result)
if (result && result.data && result.data.code == 200) { if (result && result.data && result.data.code == 200) {
setDatatable(result.data.data); setDatatable(result.data.data);
@ -249,7 +258,16 @@ const ProjectPhase = ({ params }) => {
</>, </>,
}, },
{ title: 'Fase', dataIndex: 'name', key: 'name', className: "nowrap" }, { title: 'Fase', dataIndex: 'name', key: 'name', className: "nowrap" },
{ title: 'Warna', dataIndex: 'color', key: 'color' }, {
title: 'Warna',
dataIndex: 'color',
key: 'color',
render: (text) => <>
<Tooltip title={text}>
<i className="fa fa-square" style={{ color: text }} ></i>
</Tooltip>
</>,
},
]; ];
return ( return (
<Table <Table
@ -287,18 +305,12 @@ const ProjectPhase = ({ params }) => {
clickOpenModal={clickOpenModal} clickOpenModal={clickOpenModal}
dataParent={allDataMenu} dataParent={allDataMenu}
/> />
<DialogInitialGantt
closeDialog={closeDialogIG}
openDialog={openDialogIG}
toggleDialog={toggleDialogIG}
idPhaseProject={idPhaseProject}
/>
<Card> <Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> <CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4> <h4 className="capitalize">{pageName}</h4>
<Row> <Row>
<Col> <Col>
<Tooltip title="Add Material Resource"> <Tooltip title="Add new data">
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button> <Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button>
</Tooltip> </Tooltip>
</Col> </Col>

41
src/views/Master/ProjectPhase/styles.css

@ -0,0 +1,41 @@
.App {
font-family: sans-serif;
padding: 20px;
}
h2 {
margin-top: 40px;
}
.rc-color-picker-panel {
border: 1px solid #ccc;
}
.rc-color-picker-panel-inner {
border: none;
box-shadow: none;
}
.rc-color-picker-panel-board-hsv {
border-radius: 12px;
outline: none;
}
.rc-color-picker-panel-board-value {
border: none;
border-radius: 12px;
}
.rc-color-picker-panel-board-saturation {
border: none;
border-radius: 12px;
}
.rc-color-picker-panel-ribbon {
border-radius: 12px;
}
.rc-color-picker-panel-wrap-preview {
border-radius: 12px;
}
.rc-color-picker-panel-preview span {
border-radius: 12px;
}
.rc-color-picker-panel-preview input {
border-radius: 12px;
}
Loading…
Cancel
Save