wahyun
10 months ago
8 changed files with 985 additions and 984 deletions
@ -1,479 +1,480 @@
|
||||
import React, { useState, useEffect, useMemo } from 'react'; |
||||
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
||||
import { DownloadOutlined } from '@ant-design/icons'; |
||||
import axios from 'axios'; |
||||
import * as XLSX from 'xlsx'; |
||||
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||
import DialogForm from './DialogForm'; |
||||
import DialogFormSub from './DialogFormSub'; |
||||
import SubProyekComp from './SubProyekComp'; |
||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||
import { Pagination, Table, Button, Tooltip } from 'antd'; |
||||
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst'; |
||||
import { formatRupiah } from '../../../const/CustomFunc' |
||||
import moment from 'moment' |
||||
|
||||
const format = "DD-MM-YYYY"; |
||||
const data = [ |
||||
{ |
||||
key: 1, |
||||
name: 'John Brown', |
||||
age: 32, |
||||
address: 'New York No. 1 Lake Park', |
||||
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.', |
||||
}, |
||||
{ |
||||
key: 2, |
||||
name: 'Jim Green', |
||||
age: 42, |
||||
address: 'London No. 1 Lake Park', |
||||
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.', |
||||
}, |
||||
{ |
||||
key: 3, |
||||
name: 'Not Expandable', |
||||
age: 29, |
||||
address: 'Jiangsu No. 1 Lake Park', |
||||
description: 'This not expandable', |
||||
}, |
||||
{ |
||||
key: 4, |
||||
name: 'Joe Black', |
||||
age: 32, |
||||
address: 'Sidney No. 1 Lake Park', |
||||
description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.', |
||||
}, |
||||
]; |
||||
|
||||
const url = ""; |
||||
const proyek_id = localStorage.getItem('proyek_id'); |
||||
const role_id = localStorage.getItem('role_id'); |
||||
|
||||
const IndexRole = ({ params }) => { |
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
const [idTask, setidTask] = useState(0); |
||||
const [dataTable, setDatatable] = useState([]) |
||||
const [search, setSearch] = useState('') |
||||
const [currentPage, setCurrentPage] = useState(1) |
||||
const [totalPage, setTotalPage] = useState(0) |
||||
const [openDialog, setOpenDialog] = useState(false) |
||||
const [openDialogSub, setOpenDialogSub] = useState(false) |
||||
const [openDialogMap, setOpenDialogMap] = useState(false) |
||||
const [typeDialog, setTypeDialog] = useState('Save'); |
||||
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
||||
const [idDelete, setIdDelete] = useState(0) |
||||
const [alertDelete, setAlertDelete] = useState(false) |
||||
const [dataEdit, setDataEdit] = useState([]) |
||||
const [dataEditSub, setDataEditSub] = useState([]) |
||||
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||
const [dataExport, setDataExport] = useState([]) |
||||
const [allDataMenu, setAllDataMenu] = useState([]) |
||||
const pageName = params.name; |
||||
useEffect(() => { |
||||
getDataProyek(); |
||||
}, []) |
||||
|
||||
useEffect(() => { |
||||
getDataProyek(); |
||||
}, [search, rowsPerPage, currentPage]) |
||||
|
||||
useEffect(() => { |
||||
const cekData = dataExport || [] |
||||
if (cekData.length > 0) { |
||||
exportExcel() |
||||
} |
||||
}, [dataExport]) |
||||
|
||||
const handleSearch = e => { |
||||
const value = e.target.value |
||||
setSearch(value); |
||||
setCurrentPage(1) |
||||
}; |
||||
|
||||
const getDataProyek = async () => { |
||||
|
||||
|
||||
let start = 0; |
||||
|
||||
if (currentPage !== 1 && currentPage > 1) { |
||||
start = (currentPage * rowsPerPage) - rowsPerPage |
||||
} |
||||
|
||||
const payload = { |
||||
"columns": [ |
||||
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
||||
], |
||||
"joins": [ |
||||
{ "name": "subproyeks.m_proyek", "column_join": "proyek_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] }, |
||||
{ "name": "subproyeks.m_subproyek", "column_join": "parent_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] } |
||||
], |
||||
"orders": { "columns": ["id"], "ascending": true }, |
||||
"paging": { "start": 0, "length": 25 } |
||||
} |
||||
|
||||
|
||||
if (parseInt(role_id) !== 1) { |
||||
payload["columns"] = [ |
||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||
] |
||||
} |
||||
|
||||
|
||||
const URL = `${BASE_SIMPRO}/proyek/search-detail` |
||||
const result = await axios |
||||
.post(URL, payload, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
let dataRes = result.data.data || [] |
||||
let dataWithKey = getChildrenTree(dataRes) |
||||
setDatatable(dataWithKey); |
||||
setTotalPage(result.data.totalRecord); |
||||
} else { |
||||
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const getChildrenTree = (data) => ( |
||||
data.map((item, index) => { |
||||
let arrSubProyek = item.subproyeks |
||||
if (item.subproyeks && item.subproyeks.length > 0) { |
||||
return { |
||||
"key": Math.random(), |
||||
"subproyeks2": getChildrenTree(item.subproyeks), |
||||
...item |
||||
} |
||||
} |
||||
else if (item.plannings && item.plannings.length > 0) { |
||||
return { |
||||
"key": Math.random(), |
||||
"plannings2": getChildrenTree(item.plannings), |
||||
...item |
||||
} |
||||
} else { |
||||
return { |
||||
"key": Math.random(), |
||||
...item |
||||
} |
||||
} |
||||
}) |
||||
) |
||||
|
||||
const handleOpenDialog = (type) => { |
||||
setOpenDialog(true) |
||||
setTypeDialog(type) |
||||
} |
||||
|
||||
const handleOpenDialogSub = (type, param) => { |
||||
setidTask(param.id) |
||||
setOpenDialogSub(true) |
||||
setTypeDialogSub(type) |
||||
} |
||||
|
||||
const handleCloseDialog = (type, data) => { |
||||
if (type === "save") { |
||||
saveProyek(data); |
||||
} else if (type === "edit") { |
||||
editProyek(data); |
||||
} |
||||
setDataEdit([]) |
||||
setOpenDialog(false) |
||||
} |
||||
|
||||
const handleCloseDialogSub = (type, data) => { |
||||
setDataEditSub([]) |
||||
setOpenDialogSub(false) |
||||
if (type !== "cancel") { |
||||
getDataProyek() |
||||
} |
||||
} |
||||
|
||||
const handleCloseDialogMap = () => { |
||||
setOpenDialogMap(false) |
||||
} |
||||
|
||||
const toggleAddDialog = () => { |
||||
setOpenDialog(!openDialog) |
||||
} |
||||
|
||||
const toggleAddDialogSub = () => { |
||||
setOpenDialogSub(!openDialogSub) |
||||
} |
||||
|
||||
const toggleMapDialog = () => { |
||||
setOpenDialogMap(!openDialogMap) |
||||
} |
||||
|
||||
const onConfirmDelete = async () => { |
||||
let urlDel = PROYEK_DELETE(idDelete) |
||||
const result = await axios.delete(urlDel, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProyek() |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!'); |
||||
} else { |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const saveProyek = async (data) => { |
||||
const formData = data |
||||
|
||||
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProyek(); |
||||
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||
} |
||||
|
||||
} |
||||
|
||||
const editProyek = async (data) => { |
||||
|
||||
let urlEdit = PROYEK_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) { |
||||
getDataProyek(); |
||||
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
const handleEdit = (data) => { |
||||
setDataEdit(data) |
||||
handleOpenDialog('Edit'); |
||||
} |
||||
|
||||
const handleDelete = async (id) => { |
||||
await setAlertDelete(true) |
||||
await setIdDelete(id) |
||||
} |
||||
|
||||
const onShowSizeChange = (current, pageSize) => { |
||||
setRowsPerPage(pageSize) |
||||
} |
||||
|
||||
const onPagination = (current, pageSize) => { |
||||
setCurrentPage(current) |
||||
} |
||||
|
||||
const handleExportExcel = async () => { |
||||
|
||||
const payload = { |
||||
"paging": { "start": 0, "length": -1 }, |
||||
"joins": [], |
||||
"orders": { "columns": ["id"], "ascending": false } |
||||
} |
||||
|
||||
if (parseInt(role_id) !== 1) { |
||||
payload["columns"] = [ |
||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||
] |
||||
} |
||||
|
||||
|
||||
|
||||
const result = await axios |
||||
.post(PROYEK_SEARCH, payload, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
let resData = result.data.data; |
||||
const excelData = []; |
||||
resData.map((n, index) => { |
||||
let dataRow = { |
||||
"Nama Proyek": n.nama, |
||||
"Biaya": n.biaya, |
||||
"Color Progress": n.color_progress, |
||||
"Jumlah Pekerja": n.jumlah_pekerja, |
||||
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-", |
||||
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-", |
||||
} |
||||
excelData.push(dataRow) |
||||
}) |
||||
await setDataExport(excelData); |
||||
} else { |
||||
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const exportExcel = () => { |
||||
const dataExcel = dataExport || []; |
||||
const fileName = `Data ${pageName}.xlsx`; |
||||
const ws = XLSX.utils.json_to_sheet(dataExcel); |
||||
const wb = XLSX.utils.book_new(); |
||||
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); |
||||
|
||||
XLSX.writeFile(wb, fileName); |
||||
setDataExport([]) |
||||
} |
||||
|
||||
const cancelDelete = () => { |
||||
setAlertDelete(false) |
||||
setIdDelete(0) |
||||
} |
||||
|
||||
const renderProggress = (color) => { |
||||
if (color === "green") { |
||||
return "Aman" |
||||
} else if (color === "orange") { |
||||
return "Alert" |
||||
} else { |
||||
return "Critical" |
||||
} |
||||
} |
||||
|
||||
const renderFormatRupiah = (text, prefix) => { |
||||
if (text) { |
||||
return formatRupiah(text, prefix) |
||||
} else { |
||||
return "-" |
||||
} |
||||
} |
||||
|
||||
const RenderTable = useMemo(() => { |
||||
const columns = [ |
||||
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' }, |
||||
{ |
||||
title: 'Biaya', |
||||
dataIndex: 'biaya', |
||||
key: 'biaya', |
||||
render: (text, record) => { return renderFormatRupiah(text, "Rp") } |
||||
}, |
||||
{ title: 'SDM', dataIndex: 'jumlah_pekerja', key: 'jumlah_pekerja' }, |
||||
{ title: 'PM', dataIndex: 'pic', key: 'pic' }, |
||||
{ |
||||
title: 'Aktifitas Mulai', |
||||
dataIndex: 'mulai_proyek', |
||||
key: 'mulai_proyek', |
||||
render: (text, record) => <>{moment(text).format(format)}</>, |
||||
}, |
||||
{ |
||||
title: 'Aktifitas Selesai', |
||||
dataIndex: 'akhir_proyek', |
||||
key: 'akhir_proyek', |
||||
render: (text, record) => <>{moment(text).format(format)}</>, |
||||
}, |
||||
{ |
||||
title: 'Action', |
||||
dataIndex: '', |
||||
key: 'x', |
||||
render: (text, record) => <> |
||||
<Tooltip title="Tambah Sub"> |
||||
<Button size="small" type="link" style={{ color: 'green' }} onClick={() => handleOpenDialogSub('Save', text)}><i className="fa fa-plus"></i></Button> |
||||
</Tooltip> |
||||
<Tooltip title="Edit Proyek"> |
||||
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button> |
||||
</Tooltip> |
||||
<Tooltip title="Hapus Proyek"> |
||||
<Button size="small" type="link" style={{ color: 'red' }} onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button> |
||||
</Tooltip> |
||||
</>, |
||||
}, |
||||
]; |
||||
|
||||
return ( |
||||
<Table |
||||
size="small" |
||||
columns={columns} |
||||
expandable={{ |
||||
expandedRowRender: record => <SubProyekComp getDataProyek={getDataProyek} idParentTask={record.id} nameProyek={record.nama} data={record.subproyeks2} />, |
||||
rowExpandable: record => record.subproyeks2, |
||||
}} |
||||
dataSource={dataTable} |
||||
/> |
||||
) |
||||
}, [dataTable]) |
||||
|
||||
return ( |
||||
<div> |
||||
<NotificationContainer /> |
||||
<SweetAlert |
||||
show={alertDelete} |
||||
warning |
||||
showCancel |
||||
confirmBtnText="Delete" |
||||
confirmBtnBsStyle="danger" |
||||
title={`Apakah anda yakin?`} |
||||
onConfirm={onConfirmDelete} |
||||
onCancel={() => cancelDelete()} |
||||
focusCancelBtn |
||||
> |
||||
Data akan terhapus |
||||
</SweetAlert> |
||||
<DialogForm |
||||
openDialog={openDialog} |
||||
closeDialog={handleCloseDialog} |
||||
toggleDialog={() => toggleAddDialog} |
||||
typeDialog={typeDialog} |
||||
dataEdit={dataEdit} |
||||
clickOpenModal={clickOpenModal} |
||||
dataParent={allDataMenu} |
||||
/> |
||||
<DialogFormSub |
||||
openDialog={openDialogSub} |
||||
closeDialog={handleCloseDialogSub} |
||||
toggleDialog={() => toggleAddDialogSub} |
||||
typeDialog={typeDialogSub} |
||||
dataEdit={dataEditSub} |
||||
idTask={idTask} |
||||
idSubtask={0} |
||||
/> |
||||
<Card> |
||||
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||
<h4 className="capitalize">{pageName}</h4> |
||||
<Row> |
||||
<Col> |
||||
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} /> |
||||
</Col> |
||||
<Col> |
||||
<Tooltip title="Tambah Proyek"> |
||||
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button> |
||||
</Tooltip> |
||||
<Tooltip title="Export Excel"> |
||||
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button> |
||||
</Tooltip> |
||||
</Col> |
||||
</Row> |
||||
</CardHeader> |
||||
<CardBody> |
||||
|
||||
{RenderTable} |
||||
</CardBody> |
||||
</Card> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default IndexRole; |
||||
import React, { useState, useEffect, useMemo } from 'react'; |
||||
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
||||
import { DownloadOutlined } from '@ant-design/icons'; |
||||
import axios from 'axios'; |
||||
import * as XLSX from 'xlsx'; |
||||
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||
import DialogForm from './DialogForm'; |
||||
import DialogFormSub from './DialogFormSub'; |
||||
import SubProyekComp from './SubProyekComp'; |
||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||
import { Pagination, Table, Button, Tooltip } from 'antd'; |
||||
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst'; |
||||
import { formatRupiah } from '../../../const/CustomFunc' |
||||
import moment from 'moment' |
||||
|
||||
const format = "DD-MM-YYYY"; |
||||
const data = [ |
||||
{ |
||||
key: 1, |
||||
name: 'John Brown', |
||||
age: 32, |
||||
address: 'New York No. 1 Lake Park', |
||||
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.', |
||||
}, |
||||
{ |
||||
key: 2, |
||||
name: 'Jim Green', |
||||
age: 42, |
||||
address: 'London No. 1 Lake Park', |
||||
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.', |
||||
}, |
||||
{ |
||||
key: 3, |
||||
name: 'Not Expandable', |
||||
age: 29, |
||||
address: 'Jiangsu No. 1 Lake Park', |
||||
description: 'This not expandable', |
||||
}, |
||||
{ |
||||
key: 4, |
||||
name: 'Joe Black', |
||||
age: 32, |
||||
address: 'Sidney No. 1 Lake Park', |
||||
description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.', |
||||
}, |
||||
]; |
||||
|
||||
const url = ""; |
||||
const proyek_id = localStorage.getItem('proyek_id'); |
||||
const role_id = localStorage.getItem('role_id'); |
||||
const company_id = window.localStorage.getItem('company_id'); |
||||
|
||||
const IndexRole = ({ params }) => { |
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
const [idTask, setidTask] = useState(0); |
||||
const [dataTable, setDatatable] = useState([]) |
||||
const [search, setSearch] = useState('') |
||||
const [currentPage, setCurrentPage] = useState(1) |
||||
const [totalPage, setTotalPage] = useState(0) |
||||
const [openDialog, setOpenDialog] = useState(false) |
||||
const [openDialogSub, setOpenDialogSub] = useState(false) |
||||
const [openDialogMap, setOpenDialogMap] = useState(false) |
||||
const [typeDialog, setTypeDialog] = useState('Save'); |
||||
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
||||
const [idDelete, setIdDelete] = useState(0) |
||||
const [alertDelete, setAlertDelete] = useState(false) |
||||
const [dataEdit, setDataEdit] = useState([]) |
||||
const [dataEditSub, setDataEditSub] = useState([]) |
||||
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||
const [dataExport, setDataExport] = useState([]) |
||||
const [allDataMenu, setAllDataMenu] = useState([]) |
||||
const pageName = params.name; |
||||
useEffect(() => { |
||||
getDataProyek(); |
||||
}, []) |
||||
|
||||
useEffect(() => { |
||||
getDataProyek(); |
||||
}, [search, rowsPerPage, currentPage]) |
||||
|
||||
useEffect(() => { |
||||
const cekData = dataExport || [] |
||||
if (cekData.length > 0) { |
||||
exportExcel() |
||||
} |
||||
}, [dataExport]) |
||||
|
||||
const handleSearch = e => { |
||||
const value = e.target.value |
||||
setSearch(value); |
||||
setCurrentPage(1) |
||||
}; |
||||
|
||||
const getDataProyek = async () => { |
||||
|
||||
|
||||
let start = 0; |
||||
|
||||
if (currentPage !== 1 && currentPage > 1) { |
||||
start = (currentPage * rowsPerPage) - rowsPerPage |
||||
} |
||||
|
||||
const payload = { |
||||
"columns": [ |
||||
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
||||
], |
||||
"joins": [ |
||||
{ "name": "subproyeks.m_proyek", "column_join": "proyek_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] }, |
||||
{ "name": "subproyeks.m_subproyek", "column_join": "parent_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] } |
||||
], |
||||
"orders": { "columns": ["id"], "ascending": true }, |
||||
"paging": { "start": 0, "length": 25 } |
||||
} |
||||
|
||||
|
||||
if (parseInt(role_id) !== 1) { |
||||
payload["columns"] = [ |
||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||
] |
||||
} |
||||
|
||||
|
||||
const URL = `${BASE_SIMPRO}/proyek/search-detail` |
||||
const result = await axios |
||||
.post(URL, payload, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
let dataRes = result.data.data || [] |
||||
let dataWithKey = getChildrenTree(dataRes) |
||||
setDatatable(dataWithKey); |
||||
setTotalPage(result.data.totalRecord); |
||||
} else { |
||||
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const getChildrenTree = (data) => ( |
||||
data.map((item, index) => { |
||||
let arrSubProyek = item.subproyeks |
||||
if (item.subproyeks && item.subproyeks.length > 0) { |
||||
return { |
||||
"key": Math.random(), |
||||
"subproyeks2": getChildrenTree(item.subproyeks), |
||||
...item |
||||
} |
||||
} |
||||
else if (item.plannings && item.plannings.length > 0) { |
||||
return { |
||||
"key": Math.random(), |
||||
"plannings2": getChildrenTree(item.plannings), |
||||
...item |
||||
} |
||||
} else { |
||||
return { |
||||
"key": Math.random(), |
||||
...item |
||||
} |
||||
} |
||||
}) |
||||
) |
||||
|
||||
const handleOpenDialog = (type) => { |
||||
setOpenDialog(true) |
||||
setTypeDialog(type) |
||||
} |
||||
|
||||
const handleOpenDialogSub = (type, param) => { |
||||
setidTask(param.id) |
||||
setOpenDialogSub(true) |
||||
setTypeDialogSub(type) |
||||
} |
||||
|
||||
const handleCloseDialog = (type, data) => { |
||||
if (type === "save") { |
||||
saveProyek(data); |
||||
} else if (type === "edit") { |
||||
editProyek(data); |
||||
} |
||||
setDataEdit([]) |
||||
setOpenDialog(false) |
||||
} |
||||
|
||||
const handleCloseDialogSub = (type, data) => { |
||||
setDataEditSub([]) |
||||
setOpenDialogSub(false) |
||||
if (type !== "cancel") { |
||||
getDataProyek() |
||||
} |
||||
} |
||||
|
||||
const handleCloseDialogMap = () => { |
||||
setOpenDialogMap(false) |
||||
} |
||||
|
||||
const toggleAddDialog = () => { |
||||
setOpenDialog(!openDialog) |
||||
} |
||||
|
||||
const toggleAddDialogSub = () => { |
||||
setOpenDialogSub(!openDialogSub) |
||||
} |
||||
|
||||
const toggleMapDialog = () => { |
||||
setOpenDialogMap(!openDialogMap) |
||||
} |
||||
|
||||
const onConfirmDelete = async () => { |
||||
let urlDel = PROYEK_DELETE(idDelete, company_id); |
||||
const result = await axios.delete(urlDel, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProyek() |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!'); |
||||
} else { |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const saveProyek = async (data) => { |
||||
const formData = data |
||||
|
||||
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProyek(); |
||||
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||
} |
||||
|
||||
} |
||||
|
||||
const editProyek = async (data) => { |
||||
|
||||
let urlEdit = PROYEK_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) { |
||||
getDataProyek(); |
||||
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
const handleEdit = (data) => { |
||||
setDataEdit(data) |
||||
handleOpenDialog('Edit'); |
||||
} |
||||
|
||||
const handleDelete = async (id) => { |
||||
await setAlertDelete(true) |
||||
await setIdDelete(id) |
||||
} |
||||
|
||||
const onShowSizeChange = (current, pageSize) => { |
||||
setRowsPerPage(pageSize) |
||||
} |
||||
|
||||
const onPagination = (current, pageSize) => { |
||||
setCurrentPage(current) |
||||
} |
||||
|
||||
const handleExportExcel = async () => { |
||||
|
||||
const payload = { |
||||
"paging": { "start": 0, "length": -1 }, |
||||
"joins": [], |
||||
"orders": { "columns": ["id"], "ascending": false } |
||||
} |
||||
|
||||
if (parseInt(role_id) !== 1) { |
||||
payload["columns"] = [ |
||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||
] |
||||
} |
||||
|
||||
|
||||
|
||||
const result = await axios |
||||
.post(PROYEK_SEARCH, payload, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
let resData = result.data.data; |
||||
const excelData = []; |
||||
resData.map((n, index) => { |
||||
let dataRow = { |
||||
"Nama Proyek": n.nama, |
||||
"Biaya": n.biaya, |
||||
"Color Progress": n.color_progress, |
||||
"Jumlah Pekerja": n.jumlah_pekerja, |
||||
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-", |
||||
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-", |
||||
} |
||||
excelData.push(dataRow) |
||||
}) |
||||
await setDataExport(excelData); |
||||
} else { |
||||
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const exportExcel = () => { |
||||
const dataExcel = dataExport || []; |
||||
const fileName = `Data ${pageName}.xlsx`; |
||||
const ws = XLSX.utils.json_to_sheet(dataExcel); |
||||
const wb = XLSX.utils.book_new(); |
||||
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); |
||||
|
||||
XLSX.writeFile(wb, fileName); |
||||
setDataExport([]) |
||||
} |
||||
|
||||
const cancelDelete = () => { |
||||
setAlertDelete(false) |
||||
setIdDelete(0) |
||||
} |
||||
|
||||
const renderProggress = (color) => { |
||||
if (color === "green") { |
||||
return "Aman" |
||||
} else if (color === "orange") { |
||||
return "Alert" |
||||
} else { |
||||
return "Critical" |
||||
} |
||||
} |
||||
|
||||
const renderFormatRupiah = (text, prefix) => { |
||||
if (text) { |
||||
return formatRupiah(text, prefix) |
||||
} else { |
||||
return "-" |
||||
} |
||||
} |
||||
|
||||
const RenderTable = useMemo(() => { |
||||
const columns = [ |
||||
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' }, |
||||
{ |
||||
title: 'Biaya', |
||||
dataIndex: 'biaya', |
||||
key: 'biaya', |
||||
render: (text, record) => { return renderFormatRupiah(text, "Rp") } |
||||
}, |
||||
{ title: 'SDM', dataIndex: 'jumlah_pekerja', key: 'jumlah_pekerja' }, |
||||
{ title: 'PM', dataIndex: 'pic', key: 'pic' }, |
||||
{ |
||||
title: 'Aktifitas Mulai', |
||||
dataIndex: 'mulai_proyek', |
||||
key: 'mulai_proyek', |
||||
render: (text, record) => <>{moment(text).format(format)}</>, |
||||
}, |
||||
{ |
||||
title: 'Aktifitas Selesai', |
||||
dataIndex: 'akhir_proyek', |
||||
key: 'akhir_proyek', |
||||
render: (text, record) => <>{moment(text).format(format)}</>, |
||||
}, |
||||
{ |
||||
title: 'Action', |
||||
dataIndex: '', |
||||
key: 'x', |
||||
render: (text, record) => <> |
||||
<Tooltip title="Tambah Sub"> |
||||
<Button size="small" type="link" style={{ color: 'green' }} onClick={() => handleOpenDialogSub('Save', text)}><i className="fa fa-plus"></i></Button> |
||||
</Tooltip> |
||||
<Tooltip title="Edit Proyek"> |
||||
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button> |
||||
</Tooltip> |
||||
<Tooltip title="Hapus Proyek"> |
||||
<Button size="small" type="link" style={{ color: 'red' }} onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button> |
||||
</Tooltip> |
||||
</>, |
||||
}, |
||||
]; |
||||
|
||||
return ( |
||||
<Table |
||||
size="small" |
||||
columns={columns} |
||||
expandable={{ |
||||
expandedRowRender: record => <SubProyekComp getDataProyek={getDataProyek} idParentTask={record.id} nameProyek={record.nama} data={record.subproyeks2} />, |
||||
rowExpandable: record => record.subproyeks2, |
||||
}} |
||||
dataSource={dataTable} |
||||
/> |
||||
) |
||||
}, [dataTable]) |
||||
|
||||
return ( |
||||
<div> |
||||
<NotificationContainer /> |
||||
<SweetAlert |
||||
show={alertDelete} |
||||
warning |
||||
showCancel |
||||
confirmBtnText="Delete" |
||||
confirmBtnBsStyle="danger" |
||||
title={`Apakah anda yakin?`} |
||||
onConfirm={onConfirmDelete} |
||||
onCancel={() => cancelDelete()} |
||||
focusCancelBtn |
||||
> |
||||
Data akan terhapus |
||||
</SweetAlert> |
||||
<DialogForm |
||||
openDialog={openDialog} |
||||
closeDialog={handleCloseDialog} |
||||
toggleDialog={() => toggleAddDialog} |
||||
typeDialog={typeDialog} |
||||
dataEdit={dataEdit} |
||||
clickOpenModal={clickOpenModal} |
||||
dataParent={allDataMenu} |
||||
/> |
||||
<DialogFormSub |
||||
openDialog={openDialogSub} |
||||
closeDialog={handleCloseDialogSub} |
||||
toggleDialog={() => toggleAddDialogSub} |
||||
typeDialog={typeDialogSub} |
||||
dataEdit={dataEditSub} |
||||
idTask={idTask} |
||||
idSubtask={0} |
||||
/> |
||||
<Card> |
||||
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||
<h4 className="capitalize">{pageName}</h4> |
||||
<Row> |
||||
<Col> |
||||
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} /> |
||||
</Col> |
||||
<Col> |
||||
<Tooltip title="Tambah Proyek"> |
||||
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button> |
||||
</Tooltip> |
||||
<Tooltip title="Export Excel"> |
||||
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button> |
||||
</Tooltip> |
||||
</Col> |
||||
</Row> |
||||
</CardHeader> |
||||
<CardBody> |
||||
|
||||
{RenderTable} |
||||
</CardBody> |
||||
</Card> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default IndexRole; |
||||
|
@ -1,383 +1,384 @@
|
||||
import * as XLSX from 'xlsx'; |
||||
import DialogForm from './DialogForm'; |
||||
import React, { useState, useEffect, useMemo } from 'react'; |
||||
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||
import axios from "../../../const/interceptorApi"; |
||||
import moment from 'moment' |
||||
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst'; |
||||
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
||||
import { DownloadOutlined } from '@ant-design/icons'; |
||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||
import { Pagination, Table, Button, Tooltip } from 'antd'; |
||||
import { formatRupiah } from '../../../const/CustomFunc' |
||||
|
||||
const url = ""; |
||||
const proyek_id = localStorage.getItem('proyek_id'); |
||||
const role_id = localStorage.getItem('role_id'); |
||||
const format = "DD-MM-YYYY"; |
||||
|
||||
const Closing = ({ params, ...props }) => { |
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
|
||||
const [alertClose, setAlertClose] = useState(false) |
||||
const [alertDelete, setAlertDelete] = useState(false) |
||||
const [allDataMenu, setAllDataMenu] = useState([]) |
||||
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||
const [currentPage, setCurrentPage] = useState(1) |
||||
const [dataCharter, setDataCharter] = useState(null) |
||||
const [dataEdit, setDataEdit] = useState([]) |
||||
const [dataEditSub, setDataEditSub] = useState([]) |
||||
const [dataExport, setDataExport] = useState([]) |
||||
const [dataTable, setDatatable] = useState([]) |
||||
const [dataView, setDataView] = useState([]) |
||||
const [idDelete, setIdDelete] = useState(0) |
||||
const [idTask, setidTask] = useState(0); |
||||
const [openDialog, setOpenDialog] = useState(false) |
||||
const [openDialogMap, setOpenDialogMap] = useState(false) |
||||
const [openDialogResource, setOpenDialogResource] = useState(false) |
||||
const [openDialogViewDetail, setOpenDialogViewDetail] = useState(false) |
||||
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||
const [search, setSearch] = useState('') |
||||
const [totalPage, setTotalPage] = useState(0) |
||||
const [typeDialog, setTypeDialog] = useState('Save'); |
||||
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
||||
const [userProyek, setUserProyek] = useState([]); |
||||
const pageName = params.name; |
||||
|
||||
useEffect(() => { |
||||
getDataProyek() |
||||
}, []) |
||||
|
||||
const handleSearch = e => { |
||||
const value = e.target.value |
||||
setSearch(value); |
||||
setCurrentPage(1) |
||||
}; |
||||
|
||||
const getDataProyek = async () => { |
||||
|
||||
let start = 0; |
||||
|
||||
if (currentPage !== 1 && currentPage > 1) { |
||||
start = (currentPage * rowsPerPage) - rowsPerPage |
||||
} |
||||
|
||||
const payload = { |
||||
"columns": [ |
||||
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
||||
], |
||||
"joins": [ |
||||
{ "name": "m_users", "column_join": "pm_id", "column_results": ["name", "username"] }, |
||||
{ "name": "m_type_proyek", "column_join": "type_proyek_id", "column_results": ["name", "description"] }, |
||||
], |
||||
"orders": { "columns": ["id"], "ascending": true }, |
||||
"paging": { "start": 0, "length": 25 } |
||||
} |
||||
|
||||
|
||||
if (parseInt(role_id) !== 1) { |
||||
payload["columns"] = [ |
||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||
] |
||||
} |
||||
|
||||
const URL = `${BASE_SIMPRO}/proyek/search-detail` |
||||
const result = await axios |
||||
.post(URL, payload, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
let dataRes = result.data.data || [] |
||||
|
||||
setDatatable(dataRes); |
||||
setTotalPage(result.data.totalRecord); |
||||
} else { |
||||
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const handleOpenDialog = (id) => { |
||||
setOpenDialog(true) |
||||
setidTask(id) |
||||
} |
||||
|
||||
const handleOpenDialogResource = (data) => { |
||||
setOpenDialogResource(true) |
||||
setidTask(data.id) |
||||
setUserProyek(data.user_proyeks) |
||||
} |
||||
|
||||
const handleOpenDialogViewDetail = (data) => { |
||||
setOpenDialogViewDetail(true) |
||||
setidTask(data.id) |
||||
setDataView(data) |
||||
setDataCharter(data.project_charter ? data.project_charter : null) |
||||
} |
||||
|
||||
const handleCloseDialog = (type, payload) => { |
||||
if (type === "add") saveProyek(payload); |
||||
|
||||
if (type === "edit") editProyek(payload); |
||||
|
||||
setOpenDialog(false) |
||||
} |
||||
|
||||
const handleCloseDialogResource = (type, payload) => { |
||||
setOpenDialogResource(false) |
||||
} |
||||
|
||||
const handleCloseDialogView = (type, payload) => { |
||||
setOpenDialogViewDetail(false) |
||||
} |
||||
|
||||
|
||||
const toggleAddDialog = () => setOpenDialog(!openDialog) |
||||
|
||||
const toggleAddDialogResource = () => setOpenDialogResource(!openDialog) |
||||
const toggleAddDialogView = () => setOpenDialogViewDetail(!openDialogViewDetail) |
||||
|
||||
const onConfirmDelete = async () => { |
||||
let urlDel = PROYEK_DELETE(idDelete) |
||||
const result = await axios.delete(urlDel, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProyek() |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!'); |
||||
} else { |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const onConfirmClose = async () => { |
||||
setIdDelete(0) |
||||
setAlertClose(false) |
||||
NotificationManager.success(`Data proyek berhasil diclose`, 'Success!!'); |
||||
} |
||||
|
||||
const saveProyek = async (data) => { |
||||
const formData = data |
||||
|
||||
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProyek(); |
||||
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||
} |
||||
|
||||
} |
||||
|
||||
const editProyek = async (data) => { |
||||
let urlEdit = PROYEK_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) { |
||||
getDataProyek(); |
||||
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`); |
||||
} |
||||
} |
||||
|
||||
const handleDelete = async (id) => { |
||||
await setAlertDelete(true) |
||||
await setIdDelete(id) |
||||
} |
||||
|
||||
const handleCloseProject = async (id) => { |
||||
await setAlertClose(true) |
||||
await setIdDelete(id) |
||||
} |
||||
|
||||
const onShowSizeChange = (current, pageSize) => { |
||||
setRowsPerPage(pageSize) |
||||
} |
||||
|
||||
const onPagination = (current, pageSize) => { |
||||
setCurrentPage(current) |
||||
} |
||||
|
||||
const handleExportExcel = async () => { |
||||
|
||||
const payload = { |
||||
"paging": { "start": 0, "length": -1 }, |
||||
"joins": [], |
||||
"orders": { "columns": ["id"], "ascending": false } |
||||
} |
||||
|
||||
if (parseInt(role_id) !== 1) { |
||||
payload["columns"] = [ |
||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||
] |
||||
} |
||||
|
||||
const result = await axios |
||||
.post(PROYEK_SEARCH, payload, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
let resData = result.data.data; |
||||
const excelData = []; |
||||
resData.map((n, index) => { |
||||
let dataRow = { |
||||
"Nama Proyek": n.nama, |
||||
"Biaya": n.biaya, |
||||
"Color Progress": n.color_progress, |
||||
"Jumlah Pekerja": n.jumlah_pekerja, |
||||
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-", |
||||
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-", |
||||
} |
||||
excelData.push(dataRow) |
||||
}) |
||||
await setDataExport(excelData); |
||||
} else { |
||||
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const exportExcel = () => { |
||||
const dataExcel = dataExport || []; |
||||
const fileName = `Data ${pageName}.xlsx`; |
||||
const ws = XLSX.utils.json_to_sheet(dataExcel); |
||||
const wb = XLSX.utils.book_new(); |
||||
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); |
||||
|
||||
XLSX.writeFile(wb, fileName); |
||||
setDataExport([]) |
||||
} |
||||
|
||||
const cancelDelete = () => { |
||||
setAlertDelete(false) |
||||
setIdDelete(0) |
||||
} |
||||
|
||||
const cancelClose = () => { |
||||
setAlertClose(false) |
||||
setIdDelete(0) |
||||
} |
||||
|
||||
const renderFormatRupiah = (text, prefix) => { |
||||
if (text) { |
||||
return formatRupiah(text, prefix) |
||||
} else { |
||||
return "-" |
||||
} |
||||
} |
||||
|
||||
const handleClickGantt = (id) => { |
||||
props.history.push({ |
||||
pathname: '/gantt', |
||||
state: { proyek_id: id } |
||||
}) |
||||
} |
||||
|
||||
const RenderTable = useMemo(() => { |
||||
const columns = [ |
||||
{ |
||||
title: 'Action', |
||||
dataIndex: '', |
||||
key: 'x', |
||||
render: (text, record) => <> |
||||
<Tooltip title="Report"> |
||||
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleOpenDialog(text.id)}><i className="fa fa-print"></i></Button> |
||||
</Tooltip> |
||||
</>, |
||||
}, |
||||
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' }, |
||||
{ |
||||
title: 'Planning Cost', |
||||
dataIndex: 'rencana_biaya', |
||||
key: 'rencana_biaya', |
||||
render: (text, record) => { return renderFormatRupiah(text, "Rp") } |
||||
}, |
||||
{ |
||||
title: 'Project Type', |
||||
dataIndex: 'color_progress', |
||||
key: 'color_progress', |
||||
render: (text, record) => <>{record.join.m_type_proyek_name}</> |
||||
}, |
||||
{ |
||||
title: 'PM', dataIndex: 'pic', key: 'pic', |
||||
render: (text, record) => <>{record.join.m_users_name}</> |
||||
}, |
||||
{ |
||||
title: 'Time Project', |
||||
dataIndex: 'akhir_proyek', |
||||
key: 'akhir_proyek', |
||||
render: (text, record) => <>{moment(record.mulai_proyek).format(format)} - {moment(record.akhir_proyek).format(format)}</>, |
||||
}, |
||||
]; |
||||
|
||||
return ( |
||||
<Table |
||||
size="small" |
||||
columns={columns} |
||||
dataSource={dataTable} |
||||
/> |
||||
) |
||||
}, [dataTable]) |
||||
|
||||
const RenderDialogForm = useMemo(() => ( |
||||
<DialogForm |
||||
openDialog={openDialog} |
||||
closeDialog={handleCloseDialog} |
||||
toggleDialog={() => toggleAddDialog} |
||||
idTask={idTask} |
||||
/> |
||||
), [openDialog]) |
||||
|
||||
return ( |
||||
<div> |
||||
<NotificationContainer /> |
||||
<SweetAlert |
||||
show={alertClose} |
||||
warning |
||||
showCancel |
||||
confirmBtnText="Close" |
||||
confirmBtnBsStyle="danger" |
||||
title={`Are you sure?`} |
||||
onConfirm={onConfirmClose} |
||||
onCancel={() => cancelClose()} |
||||
focusCancelBtn |
||||
> |
||||
Close this project |
||||
</SweetAlert> |
||||
{RenderDialogForm} |
||||
<Card> |
||||
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||
<h4 className="capitalize">{pageName}</h4> |
||||
<Row> |
||||
<Col> |
||||
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} /> |
||||
</Col> |
||||
</Row> |
||||
</CardHeader> |
||||
<CardBody> |
||||
{RenderTable} |
||||
</CardBody> |
||||
</Card> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default Closing; |
||||
import * as XLSX from 'xlsx'; |
||||
import DialogForm from './DialogForm'; |
||||
import React, { useState, useEffect, useMemo } from 'react'; |
||||
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||
import axios from "../../../const/interceptorApi"; |
||||
import moment from 'moment' |
||||
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst'; |
||||
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
||||
import { DownloadOutlined } from '@ant-design/icons'; |
||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||
import { Pagination, Table, Button, Tooltip } from 'antd'; |
||||
import { formatRupiah } from '../../../const/CustomFunc' |
||||
|
||||
const url = ""; |
||||
const proyek_id = localStorage.getItem('proyek_id'); |
||||
const role_id = localStorage.getItem('role_id'); |
||||
const company_id = window.localStorage.getItem('company_id'); |
||||
const format = "DD-MM-YYYY"; |
||||
|
||||
const Closing = ({ params, ...props }) => { |
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
|
||||
const [alertClose, setAlertClose] = useState(false) |
||||
const [alertDelete, setAlertDelete] = useState(false) |
||||
const [allDataMenu, setAllDataMenu] = useState([]) |
||||
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||
const [currentPage, setCurrentPage] = useState(1) |
||||
const [dataCharter, setDataCharter] = useState(null) |
||||
const [dataEdit, setDataEdit] = useState([]) |
||||
const [dataEditSub, setDataEditSub] = useState([]) |
||||
const [dataExport, setDataExport] = useState([]) |
||||
const [dataTable, setDatatable] = useState([]) |
||||
const [dataView, setDataView] = useState([]) |
||||
const [idDelete, setIdDelete] = useState(0) |
||||
const [idTask, setidTask] = useState(0); |
||||
const [openDialog, setOpenDialog] = useState(false) |
||||
const [openDialogMap, setOpenDialogMap] = useState(false) |
||||
const [openDialogResource, setOpenDialogResource] = useState(false) |
||||
const [openDialogViewDetail, setOpenDialogViewDetail] = useState(false) |
||||
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||
const [search, setSearch] = useState('') |
||||
const [totalPage, setTotalPage] = useState(0) |
||||
const [typeDialog, setTypeDialog] = useState('Save'); |
||||
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
||||
const [userProyek, setUserProyek] = useState([]); |
||||
const pageName = params.name; |
||||
|
||||
useEffect(() => { |
||||
getDataProyek() |
||||
}, []) |
||||
|
||||
const handleSearch = e => { |
||||
const value = e.target.value |
||||
setSearch(value); |
||||
setCurrentPage(1) |
||||
}; |
||||
|
||||
const getDataProyek = async () => { |
||||
|
||||
let start = 0; |
||||
|
||||
if (currentPage !== 1 && currentPage > 1) { |
||||
start = (currentPage * rowsPerPage) - rowsPerPage |
||||
} |
||||
|
||||
const payload = { |
||||
"columns": [ |
||||
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
||||
], |
||||
"joins": [ |
||||
{ "name": "m_users", "column_join": "pm_id", "column_results": ["name", "username"] }, |
||||
{ "name": "m_type_proyek", "column_join": "type_proyek_id", "column_results": ["name", "description"] }, |
||||
], |
||||
"orders": { "columns": ["id"], "ascending": true }, |
||||
"paging": { "start": 0, "length": 25 } |
||||
} |
||||
|
||||
|
||||
if (parseInt(role_id) !== 1) { |
||||
payload["columns"] = [ |
||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||
] |
||||
} |
||||
|
||||
const URL = `${BASE_SIMPRO}/proyek/search-detail` |
||||
const result = await axios |
||||
.post(URL, payload, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
let dataRes = result.data.data || [] |
||||
|
||||
setDatatable(dataRes); |
||||
setTotalPage(result.data.totalRecord); |
||||
} else { |
||||
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const handleOpenDialog = (id) => { |
||||
setOpenDialog(true) |
||||
setidTask(id) |
||||
} |
||||
|
||||
const handleOpenDialogResource = (data) => { |
||||
setOpenDialogResource(true) |
||||
setidTask(data.id) |
||||
setUserProyek(data.user_proyeks) |
||||
} |
||||
|
||||
const handleOpenDialogViewDetail = (data) => { |
||||
setOpenDialogViewDetail(true) |
||||
setidTask(data.id) |
||||
setDataView(data) |
||||
setDataCharter(data.project_charter ? data.project_charter : null) |
||||
} |
||||
|
||||
const handleCloseDialog = (type, payload) => { |
||||
if (type === "add") saveProyek(payload); |
||||
|
||||
if (type === "edit") editProyek(payload); |
||||
|
||||
setOpenDialog(false) |
||||
} |
||||
|
||||
const handleCloseDialogResource = (type, payload) => { |
||||
setOpenDialogResource(false) |
||||
} |
||||
|
||||
const handleCloseDialogView = (type, payload) => { |
||||
setOpenDialogViewDetail(false) |
||||
} |
||||
|
||||
|
||||
const toggleAddDialog = () => setOpenDialog(!openDialog) |
||||
|
||||
const toggleAddDialogResource = () => setOpenDialogResource(!openDialog) |
||||
const toggleAddDialogView = () => setOpenDialogViewDetail(!openDialogViewDetail) |
||||
|
||||
const onConfirmDelete = async () => { |
||||
let urlDel = PROYEK_DELETE(idDelete, company_id) |
||||
const result = await axios.delete(urlDel, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProyek() |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!'); |
||||
} else { |
||||
setIdDelete(0) |
||||
setAlertDelete(false) |
||||
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!'); |
||||
} |
||||
} |
||||
|
||||
const onConfirmClose = async () => { |
||||
setIdDelete(0) |
||||
setAlertClose(false) |
||||
NotificationManager.success(`Data proyek berhasil diclose`, 'Success!!'); |
||||
} |
||||
|
||||
const saveProyek = async (data) => { |
||||
const formData = data |
||||
|
||||
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code === 200) { |
||||
getDataProyek(); |
||||
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||
} |
||||
|
||||
} |
||||
|
||||
const editProyek = async (data) => { |
||||
let urlEdit = PROYEK_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) { |
||||
getDataProyek(); |
||||
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!'); |
||||
} else { |
||||
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`); |
||||
} |
||||
} |
||||
|
||||
const handleDelete = async (id) => { |
||||
await setAlertDelete(true) |
||||
await setIdDelete(id) |
||||
} |
||||
|
||||
const handleCloseProject = async (id) => { |
||||
await setAlertClose(true) |
||||
await setIdDelete(id) |
||||
} |
||||
|
||||
const onShowSizeChange = (current, pageSize) => { |
||||
setRowsPerPage(pageSize) |
||||
} |
||||
|
||||
const onPagination = (current, pageSize) => { |
||||
setCurrentPage(current) |
||||
} |
||||
|
||||
const handleExportExcel = async () => { |
||||
|
||||
const payload = { |
||||
"paging": { "start": 0, "length": -1 }, |
||||
"joins": [], |
||||
"orders": { "columns": ["id"], "ascending": false } |
||||
} |
||||
|
||||
if (parseInt(role_id) !== 1) { |
||||
payload["columns"] = [ |
||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||
] |
||||
} |
||||
|
||||
const result = await axios |
||||
.post(PROYEK_SEARCH, payload, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.data && result.data.code == 200) { |
||||
let resData = result.data.data; |
||||
const excelData = []; |
||||
resData.map((n, index) => { |
||||
let dataRow = { |
||||
"Nama Proyek": n.nama, |
||||
"Biaya": n.biaya, |
||||
"Color Progress": n.color_progress, |
||||
"Jumlah Pekerja": n.jumlah_pekerja, |
||||
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-", |
||||
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-", |
||||
} |
||||
excelData.push(dataRow) |
||||
}) |
||||
await setDataExport(excelData); |
||||
} else { |
||||
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
||||
} |
||||
} |
||||
|
||||
const exportExcel = () => { |
||||
const dataExcel = dataExport || []; |
||||
const fileName = `Data ${pageName}.xlsx`; |
||||
const ws = XLSX.utils.json_to_sheet(dataExcel); |
||||
const wb = XLSX.utils.book_new(); |
||||
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); |
||||
|
||||
XLSX.writeFile(wb, fileName); |
||||
setDataExport([]) |
||||
} |
||||
|
||||
const cancelDelete = () => { |
||||
setAlertDelete(false) |
||||
setIdDelete(0) |
||||
} |
||||
|
||||
const cancelClose = () => { |
||||
setAlertClose(false) |
||||
setIdDelete(0) |
||||
} |
||||
|
||||
const renderFormatRupiah = (text, prefix) => { |
||||
if (text) { |
||||
return formatRupiah(text, prefix) |
||||
} else { |
||||
return "-" |
||||
} |
||||
} |
||||
|
||||
const handleClickGantt = (id) => { |
||||
props.history.push({ |
||||
pathname: '/gantt', |
||||
state: { proyek_id: id } |
||||
}) |
||||
} |
||||
|
||||
const RenderTable = useMemo(() => { |
||||
const columns = [ |
||||
{ |
||||
title: 'Action', |
||||
dataIndex: '', |
||||
key: 'x', |
||||
render: (text, record) => <> |
||||
<Tooltip title="Report"> |
||||
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleOpenDialog(text.id)}><i className="fa fa-print"></i></Button> |
||||
</Tooltip> |
||||
</>, |
||||
}, |
||||
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' }, |
||||
{ |
||||
title: 'Planning Cost', |
||||
dataIndex: 'rencana_biaya', |
||||
key: 'rencana_biaya', |
||||
render: (text, record) => { return renderFormatRupiah(text, "Rp") } |
||||
}, |
||||
{ |
||||
title: 'Project Type', |
||||
dataIndex: 'color_progress', |
||||
key: 'color_progress', |
||||
render: (text, record) => <>{record.join.m_type_proyek_name}</> |
||||
}, |
||||
{ |
||||
title: 'PM', dataIndex: 'pic', key: 'pic', |
||||
render: (text, record) => <>{record.join.m_users_name}</> |
||||
}, |
||||
{ |
||||
title: 'Time Project', |
||||
dataIndex: 'akhir_proyek', |
||||
key: 'akhir_proyek', |
||||
render: (text, record) => <>{moment(record.mulai_proyek).format(format)} - {moment(record.akhir_proyek).format(format)}</>, |
||||
}, |
||||
]; |
||||
|
||||
return ( |
||||
<Table |
||||
size="small" |
||||
columns={columns} |
||||
dataSource={dataTable} |
||||
/> |
||||
) |
||||
}, [dataTable]) |
||||
|
||||
const RenderDialogForm = useMemo(() => ( |
||||
<DialogForm |
||||
openDialog={openDialog} |
||||
closeDialog={handleCloseDialog} |
||||
toggleDialog={() => toggleAddDialog} |
||||
idTask={idTask} |
||||
/> |
||||
), [openDialog]) |
||||
|
||||
return ( |
||||
<div> |
||||
<NotificationContainer /> |
||||
<SweetAlert |
||||
show={alertClose} |
||||
warning |
||||
showCancel |
||||
confirmBtnText="Close" |
||||
confirmBtnBsStyle="danger" |
||||
title={`Are you sure?`} |
||||
onConfirm={onConfirmClose} |
||||
onCancel={() => cancelClose()} |
||||
focusCancelBtn |
||||
> |
||||
Close this project |
||||
</SweetAlert> |
||||
{RenderDialogForm} |
||||
<Card> |
||||
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||
<h4 className="capitalize">{pageName}</h4> |
||||
<Row> |
||||
<Col> |
||||
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} /> |
||||
</Col> |
||||
</Row> |
||||
</CardHeader> |
||||
<CardBody> |
||||
{RenderTable} |
||||
</CardBody> |
||||
</Card> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default Closing; |
||||
|
@ -1,96 +1,99 @@
|
||||
import React, { useEffect, useState } from 'react' |
||||
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; |
||||
import { Button, Form, FormGroup, Label, Input, Col, Row } from 'reactstrap'; |
||||
import axios from "../../../const/interceptorApi"; |
||||
import { DOCUMENT_ADD } from '../../../const/ApiConst'; |
||||
import 'antd/dist/antd.css'; |
||||
import { NotificationManager } from 'react-notifications'; |
||||
|
||||
const DialogRequest = ({ openDialog, closeDialog, toggleDialog, idTask, parentIdNewFolder }) => { |
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
const [id, setId] = useState(0) |
||||
const [file, setFile] = useState(null) |
||||
|
||||
|
||||
const handleCLearData = () => { |
||||
setId(0) |
||||
setFile(null) |
||||
} |
||||
|
||||
useEffect(() => { |
||||
handleCLearData() |
||||
}, [openDialog]) |
||||
|
||||
const handleSave = () => { |
||||
uploadDokumen() |
||||
handleCLearData() |
||||
} |
||||
|
||||
const uploadDokumen = async () => { |
||||
const formData = new FormData; |
||||
formData.append('dokumen', file, file.name); |
||||
|
||||
if (parentIdNewFolder > 0) { |
||||
formData.append('ref_id', parentIdNewFolder); // folder_id
|
||||
formData.append('type_dokumen', 'project-document-in-folder'); |
||||
} |
||||
else { |
||||
formData.append('ref_id', idTask); // proyek_id
|
||||
formData.append('type_dokumen', 'project-document-out-folder') |
||||
} |
||||
|
||||
const result = await axios |
||||
.post(DOCUMENT_ADD, formData, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
|
||||
if (result && result.status == 200) { |
||||
NotificationManager.success('Dokumen project berhasil diupload!!', 'Success'); |
||||
closeDialog('upload') |
||||
} else { |
||||
NotificationManager.error('Dokumen project gagal diupload!!', 'Failed'); |
||||
closeDialog('failed upload') |
||||
} |
||||
} |
||||
|
||||
const handleCancel = () => { |
||||
closeDialog('cancel') |
||||
handleCLearData() |
||||
} |
||||
|
||||
const renderForm = () => { |
||||
return ( |
||||
<Form> |
||||
<FormGroup> |
||||
<Label className="capitalize">Upload File</Label> |
||||
<Input type="file" onChange={(e) => setFile(e.target.files[0])} /> |
||||
</FormGroup> |
||||
</Form> |
||||
) |
||||
} |
||||
|
||||
|
||||
return ( |
||||
<> |
||||
<Modal isOpen={openDialog} toggle={toggleDialog}> |
||||
<ModalHeader className="capitalize" toggle={closeDialog}>Upload Project Document</ModalHeader> |
||||
<ModalBody> |
||||
{renderForm()} |
||||
</ModalBody> |
||||
<ModalFooter> |
||||
<Button color="primary" onClick={() => handleSave()}>Upload</Button>{' '} |
||||
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Cancel</Button> |
||||
</ModalFooter> |
||||
</Modal> |
||||
</> |
||||
) |
||||
|
||||
} |
||||
|
||||
export default DialogRequest; |
||||
import React, { useEffect, useState } from 'react' |
||||
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; |
||||
import { Button, Form, FormGroup, Label, Input, Col, Row } from 'reactstrap'; |
||||
import axios from "../../../const/interceptorApi"; |
||||
import { DOCUMENT_ADD } from '../../../const/ApiConst'; |
||||
import 'antd/dist/antd.css'; |
||||
import { NotificationManager } from 'react-notifications'; |
||||
|
||||
const DialogRequest = ({ openDialog, closeDialog, toggleDialog, idTask, parentIdNewFolder }) => { |
||||
const token = localStorage.getItem("token") |
||||
const HEADER = { |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
"Authorization": `Bearer ${token}` |
||||
} |
||||
} |
||||
const [id, setId] = useState(0) |
||||
const [file, setFile] = useState(null) |
||||
|
||||
|
||||
const handleCLearData = () => { |
||||
setId(0) |
||||
setFile(null) |
||||
} |
||||
|
||||
useEffect(() => { |
||||
handleCLearData() |
||||
}, [openDialog]) |
||||
|
||||
const handleSave = () => { |
||||
uploadDokumen() |
||||
handleCLearData() |
||||
} |
||||
|
||||
const uploadDokumen = async () => { |
||||
const configApp = JSON.parse(window.localStorage.getItem('configApp')); |
||||
|
||||
const formData = new FormData; |
||||
formData.append('dokumen', file, file.name); |
||||
formData.append('company_name',configApp.company_name); |
||||
|
||||
if (parentIdNewFolder > 0) { |
||||
formData.append('ref_id', parentIdNewFolder); // folder_id
|
||||
formData.append('type_dokumen', 'project-document-in-folder'); |
||||
} |
||||
else { |
||||
formData.append('ref_id', idTask); // proyek_id
|
||||
formData.append('type_dokumen', 'project-document-out-folder') |
||||
} |
||||
|
||||
const result = await axios |
||||
.post(DOCUMENT_ADD, formData, HEADER) |
||||
.then(res => res) |
||||
.catch((error) => error.response); |
||||
const notif = result.data.message; |
||||
if (result && result.status == 200) { |
||||
NotificationManager.success(notif, 'Success'); |
||||
closeDialog('upload') |
||||
} else { |
||||
NotificationManager.error(notif, 'Failed'); |
||||
closeDialog('failed upload') |
||||
} |
||||
} |
||||
|
||||
const handleCancel = () => { |
||||
closeDialog('cancel') |
||||
handleCLearData() |
||||
} |
||||
|
||||
const renderForm = () => { |
||||
return ( |
||||
<Form> |
||||
<FormGroup> |
||||
<Label className="capitalize">Upload File</Label> |
||||
<Input type="file" onChange={(e) => setFile(e.target.files[0])} /> |
||||
</FormGroup> |
||||
</Form> |
||||
) |
||||
} |
||||
|
||||
|
||||
return ( |
||||
<> |
||||
<Modal isOpen={openDialog} toggle={toggleDialog}> |
||||
<ModalHeader className="capitalize" toggle={closeDialog}>Upload Project Document</ModalHeader> |
||||
<ModalBody> |
||||
{renderForm()} |
||||
</ModalBody> |
||||
<ModalFooter> |
||||
<Button color="primary" onClick={() => handleSave()}>Upload</Button>{' '} |
||||
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Cancel</Button> |
||||
</ModalFooter> |
||||
</Modal> |
||||
</> |
||||
) |
||||
|
||||
} |
||||
|
||||
export default DialogRequest; |
||||
|
Loading…
Reference in new issue