Yusuf
2 years ago
20 changed files with 1503 additions and 833 deletions
@ -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; |
|
@ -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