farhantock
10 months ago
20 changed files with 3749 additions and 1246 deletions
@ -1,247 +1,247 @@ |
|||||||
import React, { useEffect, useMemo, useState } from 'react'; |
import React, { useEffect, useMemo, useState } from 'react'; |
||||||
import Timeline from 'react-calendar-timeline' |
import Timeline from 'react-calendar-timeline' |
||||||
import 'react-calendar-timeline/lib/Timeline.css' |
import 'react-calendar-timeline/lib/Timeline.css' |
||||||
import moment from 'moment'; |
import moment from 'moment'; |
||||||
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH_DETAIL, GANTT_CONTROL_MONITORING_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../const/ApiConst'; |
import { BASE_SIMPRO, PROYEK_ADD, GANTT_CONTROL_MONITORING_SEARCH } from '../../const/ApiConst'; |
||||||
import axios from 'axios'; |
import axios from 'axios'; |
||||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||||
import { Button } from 'antd'; |
import { Button } from 'antd'; |
||||||
import { |
import { |
||||||
Container, Col, Row, UncontrolledTooltip, |
Container, Col, Row, UncontrolledTooltip, |
||||||
Card, |
Card, |
||||||
CardBody, |
CardBody, |
||||||
CardHeader, |
CardHeader, |
||||||
Table, |
Table, |
||||||
Modal, ModalHeader, ModalBody, ModalFooter |
Modal, ModalHeader, ModalBody, ModalFooter |
||||||
} from 'reactstrap'; |
} from 'reactstrap'; |
||||||
import GanttFull from './GanttDhtmlx2'; |
import GanttFull from './GanttDhtmlx2'; |
||||||
import DialogForm from '../Master/Proyek/DialogForm'; |
import DialogForm from '../Master/Proyek/DialogForm'; |
||||||
import DialogFormSub from '../Master/Proyek/DialogFormSub'; |
import DialogFormSub from '../Master/Proyek/DialogFormSub'; |
||||||
import Iframe from "@nicholasadamou/react-iframe"; |
import Iframe from "@nicholasadamou/react-iframe"; |
||||||
|
|
||||||
const getUrlParameter = (sParam) => { |
const getUrlParameter = (sParam) => { |
||||||
var sPageURL = window.location.search.substring(1), |
var sPageURL = window.location.search.substring(1), |
||||||
sURLVariables = sPageURL.split('&'), |
sURLVariables = sPageURL.split('&'), |
||||||
sParameterName, |
sParameterName, |
||||||
i; |
i; |
||||||
|
|
||||||
for (i = 0; i < sURLVariables.length; i++) { |
for (i = 0; i < sURLVariables.length; i++) { |
||||||
sParameterName = sURLVariables[i].split('='); |
sParameterName = sURLVariables[i].split('='); |
||||||
|
|
||||||
if (sParameterName[0] === sParam) { |
if (sParameterName[0] === sParam) { |
||||||
return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); |
return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); |
||||||
} |
} |
||||||
} |
} |
||||||
return false; |
return false; |
||||||
}; |
}; |
||||||
|
|
||||||
const GanttTimeLine = () => { |
const GanttTimeLine = () => { |
||||||
const token = localStorage.getItem("token") |
const token = localStorage.getItem("token") |
||||||
const HEADER = { |
const HEADER = { |
||||||
headers: { |
headers: { |
||||||
"Content-Type": "application/json", |
"Content-Type": "application/json", |
||||||
"Authorization": `Bearer ${token}` |
"Authorization": `Bearer ${token}` |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
const [proyekId, setProyekId] = useState(15); |
const [proyekId, setProyekId] = useState(15); |
||||||
const [dataGantt, setDataGantt] = useState([]); |
const [dataGantt, setDataGantt] = useState([]); |
||||||
const [prevProyekId, setPrevProyekId] = useState(0); |
const [prevProyekId, setPrevProyekId] = useState(0); |
||||||
const [dataGroupGantt, setDataGroupGantt] = useState([]); |
const [dataGroupGantt, setDataGroupGantt] = useState([]); |
||||||
const [maxDateGantt, setMaxDateGantt] = useState(null); |
const [maxDateGantt, setMaxDateGantt] = useState(null); |
||||||
const [minDateGantt, setMinDateGantt] = useState(null); |
const [minDateGantt, setMinDateGantt] = useState(null); |
||||||
const [dataAllTimeLine, setDataAllTimeLine] = useState([]); |
const [dataAllTimeLine, setDataAllTimeLine] = useState([]); |
||||||
const [prevDataAllTimeLine, setPrevDataAllTimeLine] = useState(null); |
const [prevDataAllTimeLine, setPrevDataAllTimeLine] = useState(null); |
||||||
|
|
||||||
const [idTask, setidTask] = useState(0); |
const [idTask, setidTask] = useState(0); |
||||||
const [dataTable, setDatatable] = useState([]) |
const [dataTable, setDatatable] = useState([]) |
||||||
const [search, setSearch] = useState('') |
const [search, setSearch] = useState('') |
||||||
const [currentPage, setCurrentPage] = useState(1) |
const [currentPage, setCurrentPage] = useState(1) |
||||||
const [totalPage, setTotalPage] = useState(0) |
const [totalPage, setTotalPage] = useState(0) |
||||||
const [openDialog, setOpenDialog] = useState(false) |
const [openDialog, setOpenDialog] = useState(false) |
||||||
const [openDialogSub, setOpenDialogSub] = useState(false) |
const [openDialogSub, setOpenDialogSub] = useState(false) |
||||||
const [typeDialog, setTypeDialog] = useState('Save'); |
const [typeDialog, setTypeDialog] = useState('Save'); |
||||||
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
||||||
const [idDelete, setIdDelete] = useState(0) |
const [idDelete, setIdDelete] = useState(0) |
||||||
const [alertDelete, setAlertDelete] = useState(false) |
const [alertDelete, setAlertDelete] = useState(false) |
||||||
const [dataEdit, setDataEdit] = useState([]) |
const [dataEdit, setDataEdit] = useState([]) |
||||||
const [dataEditSub, setDataEditSub] = useState([]) |
const [dataEditSub, setDataEditSub] = useState([]) |
||||||
const [rowsPerPage, setRowsPerPage] = useState(10) |
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||||
const [clickOpenModal, setClickOpenModal] = useState(false) |
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||||
const [dataExport, setDataExport] = useState([]) |
const [dataExport, setDataExport] = useState([]) |
||||||
const [allDataMenu, setAllDataMenu] = useState([]) |
const [allDataMenu, setAllDataMenu] = useState([]) |
||||||
const [idSubtask, setIdSubtask] = useState(0); |
const [idSubtask, setIdSubtask] = useState(0); |
||||||
|
|
||||||
const handleMappingDataGantt = (data) => { |
const handleMappingDataGantt = (data) => { |
||||||
const minDates = data.map(res => moment(res.mulai_proyek)), |
const minDates = data.map(res => moment(res.mulai_proyek)), |
||||||
minDate = moment.min(minDates) |
minDate = moment.min(minDates) |
||||||
const maxDates = data.map(res => moment(res.akhir_proyek)), |
const maxDates = data.map(res => moment(res.akhir_proyek)), |
||||||
maxDate = moment.max(maxDates) |
maxDate = moment.max(maxDates) |
||||||
|
|
||||||
let groups = [] |
let groups = [] |
||||||
let items = [] |
let items = [] |
||||||
data.map((res, idx) => { |
data.map((res, idx) => { |
||||||
let group = { |
let group = { |
||||||
id: res.id, |
id: res.id, |
||||||
title: res.nama, |
title: res.nama, |
||||||
stackItems: true, |
stackItems: true, |
||||||
height: 50 |
height: 50 |
||||||
} |
} |
||||||
let item = { |
let item = { |
||||||
id: res.id, |
id: res.id, |
||||||
group: res.id, |
group: res.id, |
||||||
title: res.pic, |
title: res.pic, |
||||||
start_time: moment(res.mulai_proyek), |
start_time: moment(res.mulai_proyek), |
||||||
end_time: moment(res.akhir_proyek), |
end_time: moment(res.akhir_proyek), |
||||||
} |
} |
||||||
groups.push(group) |
groups.push(group) |
||||||
items.push(item) |
items.push(item) |
||||||
}) |
}) |
||||||
setDataGantt(items) |
setDataGantt(items) |
||||||
setDataGroupGantt(groups) |
setDataGroupGantt(groups) |
||||||
setMaxDateGantt(maxDate) |
setMaxDateGantt(maxDate) |
||||||
setMinDateGantt(minDate) |
setMinDateGantt(minDate) |
||||||
} |
} |
||||||
|
|
||||||
const handleGetDataProyek = async () => { |
const handleGetDataProyek = async () => { |
||||||
|
|
||||||
const payload = { |
const payload = { |
||||||
"columns": [ |
"columns": [ |
||||||
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
||||||
], |
], |
||||||
"joins": [ |
"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_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"] } |
{ "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 }, |
"orders": { "columns": ["id"], "ascending": true }, |
||||||
"paging": { "start": 0, "length": 25 } |
"paging": { "start": 0, "length": 25 } |
||||||
} |
} |
||||||
|
|
||||||
const result = await axios |
const result = await axios |
||||||
.post(GANTT_CONTROL_MONITORING_SEARCH, payload, HEADER) |
.post(GANTT_CONTROL_MONITORING_SEARCH, payload, HEADER) |
||||||
.then(res => res) |
.then(res => res) |
||||||
.catch((error) => error.response); |
.catch((error) => error.response); |
||||||
|
|
||||||
|
|
||||||
if (result && result.data && result.data.code == 200) { |
if (result && result.data && result.data.code == 200) { |
||||||
const { data } = result.data |
const { data } = result.data |
||||||
setDataAllTimeLine(data) |
setDataAllTimeLine(data) |
||||||
setPrevDataAllTimeLine(data) |
setPrevDataAllTimeLine(data) |
||||||
handleMappingDataGantt(data) |
handleMappingDataGantt(data) |
||||||
|
|
||||||
} else { |
} else { |
||||||
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
useEffect(() => { |
useEffect(() => { |
||||||
let proyek_id = getUrlParameter('proyek_id'); |
let proyek_id = getUrlParameter('proyek_id'); |
||||||
if (proyek_id) { |
if (proyek_id) { |
||||||
setProyekId(proyek_id); |
setProyekId(proyek_id); |
||||||
} |
} |
||||||
handleGetDataProyek() |
handleGetDataProyek() |
||||||
}, []); |
}, []); |
||||||
|
|
||||||
const handleClickGroupGantt = param => { |
const handleClickGroupGantt = param => { |
||||||
const row = prevDataAllTimeLine.filter(res => res.id === param) |
const row = prevDataAllTimeLine.filter(res => res.id === param) |
||||||
if (row.length > 0) { |
if (row.length > 0) { |
||||||
const { subproyeks, proyek_id, parent_id } = row[0] |
const { subproyeks, proyek_id, parent_id } = row[0] |
||||||
setPrevProyekId(parent_id || proyek_id) |
setPrevProyekId(parent_id || proyek_id) |
||||||
handleMappingDataGantt(subproyeks) |
handleMappingDataGantt(subproyeks) |
||||||
setDataAllTimeLine(subproyeks) |
setDataAllTimeLine(subproyeks) |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
const handleOpenDialog = (type) => { |
const handleOpenDialog = (type) => { |
||||||
setOpenDialog(true) |
setOpenDialog(true) |
||||||
setTypeDialog(type) |
setTypeDialog(type) |
||||||
} |
} |
||||||
|
|
||||||
const handleOpenDialogSub = (type, param) => { |
const handleOpenDialogSub = (type, param) => { |
||||||
const { id, parent_id, proyek_id, parent } = param |
const { id, parent_id, proyek_id, parent } = param |
||||||
const idParent = parent == 0 ? 0 : parent == proyek_id ? id : parent_id |
const idParent = parent == 0 ? 0 : parent == proyek_id ? id : parent_id |
||||||
setidTask(proyek_id) |
setidTask(proyek_id) |
||||||
setIdSubtask(idParent) |
setIdSubtask(idParent) |
||||||
setOpenDialogSub(true) |
setOpenDialogSub(true) |
||||||
setTypeDialogSub(type) |
setTypeDialogSub(type) |
||||||
} |
} |
||||||
|
|
||||||
const handleCloseDialog = (type, data) => { |
const handleCloseDialog = (type, data) => { |
||||||
if (type === "save") { |
if (type === "save") { |
||||||
saveProyek(data); |
saveProyek(data); |
||||||
} |
} |
||||||
|
|
||||||
setDataEdit([]) |
setDataEdit([]) |
||||||
setOpenDialog(false) |
setOpenDialog(false) |
||||||
} |
} |
||||||
|
|
||||||
const handleCloseDialogSub = (type, data) => { |
const handleCloseDialogSub = (type, data) => { |
||||||
setDataEditSub([]) |
setDataEditSub([]) |
||||||
setOpenDialogSub(false) |
setOpenDialogSub(false) |
||||||
if (type !== "cancel") { |
if (type !== "cancel") { |
||||||
handleGetDataProyek() |
handleGetDataProyek() |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
const toggleAddDialog = () => { |
const toggleAddDialog = () => { |
||||||
setOpenDialog(!openDialog) |
setOpenDialog(!openDialog) |
||||||
} |
} |
||||||
|
|
||||||
const toggleAddDialogSub = () => { |
const toggleAddDialogSub = () => { |
||||||
setOpenDialogSub(!openDialogSub) |
setOpenDialogSub(!openDialogSub) |
||||||
} |
} |
||||||
|
|
||||||
const saveProyek = async (data) => { |
const saveProyek = async (data) => { |
||||||
const formData = data |
const formData = data |
||||||
|
|
||||||
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
||||||
.then(res => res) |
.then(res => res) |
||||||
.catch((error) => error.response); |
.catch((error) => error.response); |
||||||
|
|
||||||
if (result && result.data && result.data.code === 200) { |
if (result && result.data && result.data.code === 200) { |
||||||
handleGetDataProyek() |
handleGetDataProyek() |
||||||
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
||||||
} else { |
} else { |
||||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
const RenderGantt = useMemo(() => ( |
const RenderGantt = useMemo(() => ( |
||||||
<GanttFull |
<GanttFull |
||||||
handleOpenDialogSub={handleOpenDialogSub} |
handleOpenDialogSub={handleOpenDialogSub} |
||||||
data={dataAllTimeLine} |
data={dataAllTimeLine} |
||||||
startDate={minDateGantt ? minDateGantt.format("YYYY-MM-DD HH:mm:ss") : moment().add(-40, 'days').format("YYYY-MM-DD HH:mm:ss")} |
startDate={minDateGantt ? minDateGantt.format("YYYY-MM-DD HH:mm:ss") : moment().add(-40, 'days').format("YYYY-MM-DD HH:mm:ss")} |
||||||
endDate={maxDateGantt ? maxDateGantt.format("YYYY-MM-DD HH:mm:ss") : moment().add(40, 'days').format("YYYY-MM-DD HH:mm:ss")} |
endDate={maxDateGantt ? maxDateGantt.format("YYYY-MM-DD HH:mm:ss") : moment().add(40, 'days').format("YYYY-MM-DD HH:mm:ss")} |
||||||
/> |
/> |
||||||
), [dataAllTimeLine, maxDateGantt, minDateGantt]) |
), [dataAllTimeLine, maxDateGantt, minDateGantt]) |
||||||
|
|
||||||
return ( |
return ( |
||||||
<div> |
<div> |
||||||
{/* {RenderGantt} */} |
{/* {RenderGantt} */} |
||||||
{/* <iframe id="frame-embedd" src="http://localhost/jQueryGantt/gantt.html" |
{/* <iframe id="frame-embedd" src="http://localhost/jQueryGantt/gantt.html" |
||||||
style={{ |
style={{ |
||||||
width: '100%', |
width: '100%', |
||||||
height: '75vh', |
height: '75vh', |
||||||
}} |
}} |
||||||
scrolling="no"
|
scrolling="no" |
||||||
frameBorder="0" |
frameBorder="0" |
||||||
></iframe> */} |
></iframe> */} |
||||||
<Iframe |
<Iframe |
||||||
src={`http://siopas.co.id/simpro-gantt/gantt.html?proyek_id=${proyekId}&token=${localStorage.getItem('token')}`} |
src={`http://siopas.co.id/simpro-gantt/gantt.html?proyek_id=${proyekId}&token=${localStorage.getItem('token')}`} |
||||||
headers={{ |
headers={{ |
||||||
}} |
}} |
||||||
style={{ |
style={{ |
||||||
width: '100%', |
width: '100%', |
||||||
height: '75vh', |
height: '75vh', |
||||||
}} |
}} |
||||||
scrolling="no" |
scrolling="no" |
||||||
frameBorder="0" |
frameBorder="0" |
||||||
/> |
/> |
||||||
</div> |
</div> |
||||||
); |
); |
||||||
} |
} |
||||||
|
|
||||||
export default GanttTimeLine; |
export default GanttTimeLine; |
||||||
|
@ -1,479 +1,480 @@ |
|||||||
import React, { useState, useEffect, useMemo } from 'react'; |
import React, { useState, useEffect, useMemo } from 'react'; |
||||||
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
||||||
import { DownloadOutlined } from '@ant-design/icons'; |
import { DownloadOutlined } from '@ant-design/icons'; |
||||||
import axios from 'axios'; |
import axios from 'axios'; |
||||||
import * as XLSX from 'xlsx'; |
import * as XLSX from 'xlsx'; |
||||||
import SweetAlert from 'react-bootstrap-sweetalert'; |
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||||
import DialogForm from './DialogForm'; |
import DialogForm from './DialogForm'; |
||||||
import DialogFormSub from './DialogFormSub'; |
import DialogFormSub from './DialogFormSub'; |
||||||
import SubProyekComp from './SubProyekComp'; |
import SubProyekComp from './SubProyekComp'; |
||||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||||
import { Pagination, Table, Button, Tooltip } from 'antd'; |
import { Pagination, Table, Button, Tooltip } from 'antd'; |
||||||
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst'; |
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst'; |
||||||
import { formatRupiah } from '../../../const/CustomFunc' |
import { formatRupiah } from '../../../const/CustomFunc' |
||||||
import moment from 'moment' |
import moment from 'moment' |
||||||
|
|
||||||
const format = "DD-MM-YYYY"; |
const format = "DD-MM-YYYY"; |
||||||
const data = [ |
const data = [ |
||||||
{ |
{ |
||||||
key: 1, |
key: 1, |
||||||
name: 'John Brown', |
name: 'John Brown', |
||||||
age: 32, |
age: 32, |
||||||
address: 'New York No. 1 Lake Park', |
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.', |
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.', |
||||||
}, |
}, |
||||||
{ |
{ |
||||||
key: 2, |
key: 2, |
||||||
name: 'Jim Green', |
name: 'Jim Green', |
||||||
age: 42, |
age: 42, |
||||||
address: 'London No. 1 Lake Park', |
address: 'London No. 1 Lake Park', |
||||||
description: 'My name is Jim Green, I am 42 years old, living in 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, |
key: 3, |
||||||
name: 'Not Expandable', |
name: 'Not Expandable', |
||||||
age: 29, |
age: 29, |
||||||
address: 'Jiangsu No. 1 Lake Park', |
address: 'Jiangsu No. 1 Lake Park', |
||||||
description: 'This not expandable', |
description: 'This not expandable', |
||||||
}, |
}, |
||||||
{ |
{ |
||||||
key: 4, |
key: 4, |
||||||
name: 'Joe Black', |
name: 'Joe Black', |
||||||
age: 32, |
age: 32, |
||||||
address: 'Sidney No. 1 Lake Park', |
address: 'Sidney No. 1 Lake Park', |
||||||
description: 'My name is Joe Black, I am 32 years old, living in 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 url = ""; |
||||||
const proyek_id = localStorage.getItem('proyek_id'); |
const proyek_id = localStorage.getItem('proyek_id'); |
||||||
const role_id = localStorage.getItem('role_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 IndexRole = ({ params }) => { |
||||||
const HEADER = { |
const token = localStorage.getItem("token") |
||||||
headers: { |
const HEADER = { |
||||||
"Content-Type": "application/json", |
headers: { |
||||||
"Authorization": `Bearer ${token}` |
"Content-Type": "application/json", |
||||||
} |
"Authorization": `Bearer ${token}` |
||||||
} |
} |
||||||
const [idTask, setidTask] = useState(0); |
} |
||||||
const [dataTable, setDatatable] = useState([]) |
const [idTask, setidTask] = useState(0); |
||||||
const [search, setSearch] = useState('') |
const [dataTable, setDatatable] = useState([]) |
||||||
const [currentPage, setCurrentPage] = useState(1) |
const [search, setSearch] = useState('') |
||||||
const [totalPage, setTotalPage] = useState(0) |
const [currentPage, setCurrentPage] = useState(1) |
||||||
const [openDialog, setOpenDialog] = useState(false) |
const [totalPage, setTotalPage] = useState(0) |
||||||
const [openDialogSub, setOpenDialogSub] = useState(false) |
const [openDialog, setOpenDialog] = useState(false) |
||||||
const [openDialogMap, setOpenDialogMap] = useState(false) |
const [openDialogSub, setOpenDialogSub] = useState(false) |
||||||
const [typeDialog, setTypeDialog] = useState('Save'); |
const [openDialogMap, setOpenDialogMap] = useState(false) |
||||||
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
const [typeDialog, setTypeDialog] = useState('Save'); |
||||||
const [idDelete, setIdDelete] = useState(0) |
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
||||||
const [alertDelete, setAlertDelete] = useState(false) |
const [idDelete, setIdDelete] = useState(0) |
||||||
const [dataEdit, setDataEdit] = useState([]) |
const [alertDelete, setAlertDelete] = useState(false) |
||||||
const [dataEditSub, setDataEditSub] = useState([]) |
const [dataEdit, setDataEdit] = useState([]) |
||||||
const [rowsPerPage, setRowsPerPage] = useState(10) |
const [dataEditSub, setDataEditSub] = useState([]) |
||||||
const [clickOpenModal, setClickOpenModal] = useState(false) |
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||||
const [dataExport, setDataExport] = useState([]) |
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||||
const [allDataMenu, setAllDataMenu] = useState([]) |
const [dataExport, setDataExport] = useState([]) |
||||||
const pageName = params.name; |
const [allDataMenu, setAllDataMenu] = useState([]) |
||||||
useEffect(() => { |
const pageName = params.name; |
||||||
getDataProyek(); |
useEffect(() => { |
||||||
}, []) |
getDataProyek(); |
||||||
|
}, []) |
||||||
useEffect(() => { |
|
||||||
getDataProyek(); |
useEffect(() => { |
||||||
}, [search, rowsPerPage, currentPage]) |
getDataProyek(); |
||||||
|
}, [search, rowsPerPage, currentPage]) |
||||||
useEffect(() => { |
|
||||||
const cekData = dataExport || [] |
useEffect(() => { |
||||||
if (cekData.length > 0) { |
const cekData = dataExport || [] |
||||||
exportExcel() |
if (cekData.length > 0) { |
||||||
} |
exportExcel() |
||||||
}, [dataExport]) |
} |
||||||
|
}, [dataExport]) |
||||||
const handleSearch = e => { |
|
||||||
const value = e.target.value |
const handleSearch = e => { |
||||||
setSearch(value); |
const value = e.target.value |
||||||
setCurrentPage(1) |
setSearch(value); |
||||||
}; |
setCurrentPage(1) |
||||||
|
}; |
||||||
const getDataProyek = async () => { |
|
||||||
|
const getDataProyek = async () => { |
||||||
|
|
||||||
let start = 0; |
|
||||||
|
let start = 0; |
||||||
if (currentPage !== 1 && currentPage > 1) { |
|
||||||
start = (currentPage * rowsPerPage) - rowsPerPage |
if (currentPage !== 1 && currentPage > 1) { |
||||||
} |
start = (currentPage * rowsPerPage) - rowsPerPage |
||||||
|
} |
||||||
const payload = { |
|
||||||
"columns": [ |
const payload = { |
||||||
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
"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"] }, |
"joins": [ |
||||||
{ "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"] } |
{ "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 } |
"orders": { "columns": ["id"], "ascending": true }, |
||||||
} |
"paging": { "start": 0, "length": 25 } |
||||||
|
} |
||||||
|
|
||||||
if (parseInt(role_id) !== 1) { |
|
||||||
payload["columns"] = [ |
if (parseInt(role_id) !== 1) { |
||||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
payload["columns"] = [ |
||||||
] |
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||||
} |
] |
||||||
|
} |
||||||
|
|
||||||
const URL = `${BASE_SIMPRO}/proyek/search-detail` |
|
||||||
const result = await axios |
const URL = `${BASE_SIMPRO}/proyek/search-detail` |
||||||
.post(URL, payload, HEADER) |
const result = await axios |
||||||
.then(res => res) |
.post(URL, payload, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
if (result && result.data && result.data.code == 200) { |
|
||||||
let dataRes = result.data.data || [] |
if (result && result.data && result.data.code == 200) { |
||||||
let dataWithKey = getChildrenTree(dataRes) |
let dataRes = result.data.data || [] |
||||||
setDatatable(dataWithKey); |
let dataWithKey = getChildrenTree(dataRes) |
||||||
setTotalPage(result.data.totalRecord); |
setDatatable(dataWithKey); |
||||||
} else { |
setTotalPage(result.data.totalRecord); |
||||||
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
} else { |
||||||
} |
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||||
} |
} |
||||||
|
} |
||||||
const getChildrenTree = (data) => ( |
|
||||||
data.map((item, index) => { |
const getChildrenTree = (data) => ( |
||||||
let arrSubProyek = item.subproyeks |
data.map((item, index) => { |
||||||
if (item.subproyeks && item.subproyeks.length > 0) { |
let arrSubProyek = item.subproyeks |
||||||
return { |
if (item.subproyeks && item.subproyeks.length > 0) { |
||||||
"key": Math.random(), |
return { |
||||||
"subproyeks2": getChildrenTree(item.subproyeks), |
"key": Math.random(), |
||||||
...item |
"subproyeks2": getChildrenTree(item.subproyeks), |
||||||
} |
...item |
||||||
} |
} |
||||||
else if (item.plannings && item.plannings.length > 0) { |
} |
||||||
return { |
else if (item.plannings && item.plannings.length > 0) { |
||||||
"key": Math.random(), |
return { |
||||||
"plannings2": getChildrenTree(item.plannings), |
"key": Math.random(), |
||||||
...item |
"plannings2": getChildrenTree(item.plannings), |
||||||
} |
...item |
||||||
} else { |
} |
||||||
return { |
} else { |
||||||
"key": Math.random(), |
return { |
||||||
...item |
"key": Math.random(), |
||||||
} |
...item |
||||||
} |
} |
||||||
}) |
} |
||||||
) |
}) |
||||||
|
) |
||||||
const handleOpenDialog = (type) => { |
|
||||||
setOpenDialog(true) |
const handleOpenDialog = (type) => { |
||||||
setTypeDialog(type) |
setOpenDialog(true) |
||||||
} |
setTypeDialog(type) |
||||||
|
} |
||||||
const handleOpenDialogSub = (type, param) => { |
|
||||||
setidTask(param.id) |
const handleOpenDialogSub = (type, param) => { |
||||||
setOpenDialogSub(true) |
setidTask(param.id) |
||||||
setTypeDialogSub(type) |
setOpenDialogSub(true) |
||||||
} |
setTypeDialogSub(type) |
||||||
|
} |
||||||
const handleCloseDialog = (type, data) => { |
|
||||||
if (type === "save") { |
const handleCloseDialog = (type, data) => { |
||||||
saveProyek(data); |
if (type === "save") { |
||||||
} else if (type === "edit") { |
saveProyek(data); |
||||||
editProyek(data); |
} else if (type === "edit") { |
||||||
} |
editProyek(data); |
||||||
setDataEdit([]) |
} |
||||||
setOpenDialog(false) |
setDataEdit([]) |
||||||
} |
setOpenDialog(false) |
||||||
|
} |
||||||
const handleCloseDialogSub = (type, data) => { |
|
||||||
setDataEditSub([]) |
const handleCloseDialogSub = (type, data) => { |
||||||
setOpenDialogSub(false) |
setDataEditSub([]) |
||||||
if (type !== "cancel") { |
setOpenDialogSub(false) |
||||||
getDataProyek() |
if (type !== "cancel") { |
||||||
} |
getDataProyek() |
||||||
} |
} |
||||||
|
} |
||||||
const handleCloseDialogMap = () => { |
|
||||||
setOpenDialogMap(false) |
const handleCloseDialogMap = () => { |
||||||
} |
setOpenDialogMap(false) |
||||||
|
} |
||||||
const toggleAddDialog = () => { |
|
||||||
setOpenDialog(!openDialog) |
const toggleAddDialog = () => { |
||||||
} |
setOpenDialog(!openDialog) |
||||||
|
} |
||||||
const toggleAddDialogSub = () => { |
|
||||||
setOpenDialogSub(!openDialogSub) |
const toggleAddDialogSub = () => { |
||||||
} |
setOpenDialogSub(!openDialogSub) |
||||||
|
} |
||||||
const toggleMapDialog = () => { |
|
||||||
setOpenDialogMap(!openDialogMap) |
const toggleMapDialog = () => { |
||||||
} |
setOpenDialogMap(!openDialogMap) |
||||||
|
} |
||||||
const onConfirmDelete = async () => { |
|
||||||
let urlDel = PROYEK_DELETE(idDelete) |
const onConfirmDelete = async () => { |
||||||
const result = await axios.delete(urlDel, HEADER) |
let urlDel = PROYEK_DELETE(idDelete, company_id); |
||||||
.then(res => res) |
const result = await axios.delete(urlDel, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
if (result && result.data && result.data.code === 200) { |
|
||||||
getDataProyek() |
if (result && result.data && result.data.code === 200) { |
||||||
setIdDelete(0) |
getDataProyek() |
||||||
setAlertDelete(false) |
setIdDelete(0) |
||||||
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!'); |
setAlertDelete(false) |
||||||
} else { |
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!'); |
||||||
setIdDelete(0) |
} else { |
||||||
setAlertDelete(false) |
setIdDelete(0) |
||||||
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!'); |
setAlertDelete(false) |
||||||
} |
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!'); |
||||||
} |
} |
||||||
|
} |
||||||
const saveProyek = async (data) => { |
|
||||||
const formData = data |
const saveProyek = async (data) => { |
||||||
|
const formData = data |
||||||
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
|
||||||
.then(res => res) |
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
if (result && result.data && result.data.code === 200) { |
|
||||||
getDataProyek(); |
if (result && result.data && result.data.code === 200) { |
||||||
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
getDataProyek(); |
||||||
} else { |
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
||||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
} else { |
||||||
} |
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
} |
|
||||||
|
} |
||||||
const editProyek = async (data) => { |
|
||||||
|
const editProyek = async (data) => { |
||||||
let urlEdit = PROYEK_EDIT(data.id) |
|
||||||
const formData = data |
let urlEdit = PROYEK_EDIT(data.id) |
||||||
|
const formData = data |
||||||
const result = await axios.put(urlEdit, formData, HEADER) |
|
||||||
.then(res => res) |
const result = await axios.put(urlEdit, formData, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
if (result && result.data && result.data.code === 200) { |
|
||||||
getDataProyek(); |
if (result && result.data && result.data.code === 200) { |
||||||
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!'); |
getDataProyek(); |
||||||
} else { |
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!'); |
||||||
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`); |
} else { |
||||||
} |
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
|
} |
||||||
|
|
||||||
const handleEdit = (data) => { |
|
||||||
setDataEdit(data) |
const handleEdit = (data) => { |
||||||
handleOpenDialog('Edit'); |
setDataEdit(data) |
||||||
} |
handleOpenDialog('Edit'); |
||||||
|
} |
||||||
const handleDelete = async (id) => { |
|
||||||
await setAlertDelete(true) |
const handleDelete = async (id) => { |
||||||
await setIdDelete(id) |
await setAlertDelete(true) |
||||||
} |
await setIdDelete(id) |
||||||
|
} |
||||||
const onShowSizeChange = (current, pageSize) => { |
|
||||||
setRowsPerPage(pageSize) |
const onShowSizeChange = (current, pageSize) => { |
||||||
} |
setRowsPerPage(pageSize) |
||||||
|
} |
||||||
const onPagination = (current, pageSize) => { |
|
||||||
setCurrentPage(current) |
const onPagination = (current, pageSize) => { |
||||||
} |
setCurrentPage(current) |
||||||
|
} |
||||||
const handleExportExcel = async () => { |
|
||||||
|
const handleExportExcel = async () => { |
||||||
const payload = { |
|
||||||
"paging": { "start": 0, "length": -1 }, |
const payload = { |
||||||
"joins": [], |
"paging": { "start": 0, "length": -1 }, |
||||||
"orders": { "columns": ["id"], "ascending": false } |
"joins": [], |
||||||
} |
"orders": { "columns": ["id"], "ascending": false } |
||||||
|
} |
||||||
if (parseInt(role_id) !== 1) { |
|
||||||
payload["columns"] = [ |
if (parseInt(role_id) !== 1) { |
||||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
payload["columns"] = [ |
||||||
] |
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||||
} |
] |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
const result = await axios |
|
||||||
.post(PROYEK_SEARCH, payload, HEADER) |
const result = await axios |
||||||
.then(res => res) |
.post(PROYEK_SEARCH, payload, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
if (result && result.data && result.data.code == 200) { |
|
||||||
let resData = result.data.data; |
if (result && result.data && result.data.code == 200) { |
||||||
const excelData = []; |
let resData = result.data.data; |
||||||
resData.map((n, index) => { |
const excelData = []; |
||||||
let dataRow = { |
resData.map((n, index) => { |
||||||
"Nama Proyek": n.nama, |
let dataRow = { |
||||||
"Biaya": n.biaya, |
"Nama Proyek": n.nama, |
||||||
"Color Progress": n.color_progress, |
"Biaya": n.biaya, |
||||||
"Jumlah Pekerja": n.jumlah_pekerja, |
"Color Progress": n.color_progress, |
||||||
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-", |
"Jumlah Pekerja": n.jumlah_pekerja, |
||||||
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-", |
"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) |
} |
||||||
}) |
excelData.push(dataRow) |
||||||
await setDataExport(excelData); |
}) |
||||||
} else { |
await setDataExport(excelData); |
||||||
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
} else { |
||||||
} |
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
||||||
} |
} |
||||||
|
} |
||||||
const exportExcel = () => { |
|
||||||
const dataExcel = dataExport || []; |
const exportExcel = () => { |
||||||
const fileName = `Data ${pageName}.xlsx`; |
const dataExcel = dataExport || []; |
||||||
const ws = XLSX.utils.json_to_sheet(dataExcel); |
const fileName = `Data ${pageName}.xlsx`; |
||||||
const wb = XLSX.utils.book_new(); |
const ws = XLSX.utils.json_to_sheet(dataExcel); |
||||||
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); |
const wb = XLSX.utils.book_new(); |
||||||
|
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); |
||||||
XLSX.writeFile(wb, fileName); |
|
||||||
setDataExport([]) |
XLSX.writeFile(wb, fileName); |
||||||
} |
setDataExport([]) |
||||||
|
} |
||||||
const cancelDelete = () => { |
|
||||||
setAlertDelete(false) |
const cancelDelete = () => { |
||||||
setIdDelete(0) |
setAlertDelete(false) |
||||||
} |
setIdDelete(0) |
||||||
|
} |
||||||
const renderProggress = (color) => { |
|
||||||
if (color === "green") { |
const renderProggress = (color) => { |
||||||
return "Aman" |
if (color === "green") { |
||||||
} else if (color === "orange") { |
return "Aman" |
||||||
return "Alert" |
} else if (color === "orange") { |
||||||
} else { |
return "Alert" |
||||||
return "Critical" |
} else { |
||||||
} |
return "Critical" |
||||||
} |
} |
||||||
|
} |
||||||
const renderFormatRupiah = (text, prefix) => { |
|
||||||
if (text) { |
const renderFormatRupiah = (text, prefix) => { |
||||||
return formatRupiah(text, prefix) |
if (text) { |
||||||
} else { |
return formatRupiah(text, prefix) |
||||||
return "-" |
} else { |
||||||
} |
return "-" |
||||||
} |
} |
||||||
|
} |
||||||
const RenderTable = useMemo(() => { |
|
||||||
const columns = [ |
const RenderTable = useMemo(() => { |
||||||
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' }, |
const columns = [ |
||||||
{ |
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' }, |
||||||
title: 'Biaya', |
{ |
||||||
dataIndex: 'biaya', |
title: 'Biaya', |
||||||
key: 'biaya', |
dataIndex: 'biaya', |
||||||
render: (text, record) => { return renderFormatRupiah(text, "Rp") } |
key: 'biaya', |
||||||
}, |
render: (text, record) => { return renderFormatRupiah(text, "Rp") } |
||||||
{ title: 'SDM', dataIndex: 'jumlah_pekerja', key: 'jumlah_pekerja' }, |
}, |
||||||
{ title: 'PM', dataIndex: 'pic', key: 'pic' }, |
{ title: 'SDM', dataIndex: 'jumlah_pekerja', key: 'jumlah_pekerja' }, |
||||||
{ |
{ title: 'PM', dataIndex: 'pic', key: 'pic' }, |
||||||
title: 'Aktifitas Mulai', |
{ |
||||||
dataIndex: 'mulai_proyek', |
title: 'Aktifitas Mulai', |
||||||
key: 'mulai_proyek', |
dataIndex: 'mulai_proyek', |
||||||
render: (text, record) => <>{moment(text).format(format)}</>, |
key: 'mulai_proyek', |
||||||
}, |
render: (text, record) => <>{moment(text).format(format)}</>, |
||||||
{ |
}, |
||||||
title: 'Aktifitas Selesai', |
{ |
||||||
dataIndex: 'akhir_proyek', |
title: 'Aktifitas Selesai', |
||||||
key: 'akhir_proyek', |
dataIndex: 'akhir_proyek', |
||||||
render: (text, record) => <>{moment(text).format(format)}</>, |
key: 'akhir_proyek', |
||||||
}, |
render: (text, record) => <>{moment(text).format(format)}</>, |
||||||
{ |
}, |
||||||
title: 'Action', |
{ |
||||||
dataIndex: '', |
title: 'Action', |
||||||
key: 'x', |
dataIndex: '', |
||||||
render: (text, record) => <> |
key: 'x', |
||||||
<Tooltip title="Tambah Sub"> |
render: (text, record) => <> |
||||||
<Button size="small" type="link" style={{ color: 'green' }} onClick={() => handleOpenDialogSub('Save', text)}><i className="fa fa-plus"></i></Button> |
<Tooltip title="Tambah Sub"> |
||||||
</Tooltip> |
<Button size="small" type="link" style={{ color: 'green' }} onClick={() => handleOpenDialogSub('Save', text)}><i className="fa fa-plus"></i></Button> |
||||||
<Tooltip title="Edit Proyek"> |
</Tooltip> |
||||||
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button> |
<Tooltip title="Edit Proyek"> |
||||||
</Tooltip> |
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button> |
||||||
<Tooltip title="Hapus Proyek"> |
</Tooltip> |
||||||
<Button size="small" type="link" style={{ color: 'red' }} onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button> |
<Tooltip title="Hapus Proyek"> |
||||||
</Tooltip> |
<Button size="small" type="link" style={{ color: 'red' }} onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button> |
||||||
</>, |
</Tooltip> |
||||||
}, |
</>, |
||||||
]; |
}, |
||||||
|
]; |
||||||
return ( |
|
||||||
<Table |
return ( |
||||||
size="small" |
<Table |
||||||
columns={columns} |
size="small" |
||||||
expandable={{ |
columns={columns} |
||||||
expandedRowRender: record => <SubProyekComp getDataProyek={getDataProyek} idParentTask={record.id} nameProyek={record.nama} data={record.subproyeks2} />, |
expandable={{ |
||||||
rowExpandable: record => record.subproyeks2, |
expandedRowRender: record => <SubProyekComp getDataProyek={getDataProyek} idParentTask={record.id} nameProyek={record.nama} data={record.subproyeks2} />, |
||||||
}} |
rowExpandable: record => record.subproyeks2, |
||||||
dataSource={dataTable} |
}} |
||||||
/> |
dataSource={dataTable} |
||||||
) |
/> |
||||||
}, [dataTable]) |
) |
||||||
|
}, [dataTable]) |
||||||
return ( |
|
||||||
<div> |
return ( |
||||||
<NotificationContainer /> |
<div> |
||||||
<SweetAlert |
<NotificationContainer /> |
||||||
show={alertDelete} |
<SweetAlert |
||||||
warning |
show={alertDelete} |
||||||
showCancel |
warning |
||||||
confirmBtnText="Delete" |
showCancel |
||||||
confirmBtnBsStyle="danger" |
confirmBtnText="Delete" |
||||||
title={`Apakah anda yakin?`} |
confirmBtnBsStyle="danger" |
||||||
onConfirm={onConfirmDelete} |
title={`Apakah anda yakin?`} |
||||||
onCancel={() => cancelDelete()} |
onConfirm={onConfirmDelete} |
||||||
focusCancelBtn |
onCancel={() => cancelDelete()} |
||||||
> |
focusCancelBtn |
||||||
Data akan terhapus |
> |
||||||
</SweetAlert> |
Data akan terhapus |
||||||
<DialogForm |
</SweetAlert> |
||||||
openDialog={openDialog} |
<DialogForm |
||||||
closeDialog={handleCloseDialog} |
openDialog={openDialog} |
||||||
toggleDialog={() => toggleAddDialog} |
closeDialog={handleCloseDialog} |
||||||
typeDialog={typeDialog} |
toggleDialog={() => toggleAddDialog} |
||||||
dataEdit={dataEdit} |
typeDialog={typeDialog} |
||||||
clickOpenModal={clickOpenModal} |
dataEdit={dataEdit} |
||||||
dataParent={allDataMenu} |
clickOpenModal={clickOpenModal} |
||||||
/> |
dataParent={allDataMenu} |
||||||
<DialogFormSub |
/> |
||||||
openDialog={openDialogSub} |
<DialogFormSub |
||||||
closeDialog={handleCloseDialogSub} |
openDialog={openDialogSub} |
||||||
toggleDialog={() => toggleAddDialogSub} |
closeDialog={handleCloseDialogSub} |
||||||
typeDialog={typeDialogSub} |
toggleDialog={() => toggleAddDialogSub} |
||||||
dataEdit={dataEditSub} |
typeDialog={typeDialogSub} |
||||||
idTask={idTask} |
dataEdit={dataEditSub} |
||||||
idSubtask={0} |
idTask={idTask} |
||||||
/> |
idSubtask={0} |
||||||
<Card> |
/> |
||||||
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
<Card> |
||||||
<h4 className="capitalize">{pageName}</h4> |
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||||
<Row> |
<h4 className="capitalize">{pageName}</h4> |
||||||
<Col> |
<Row> |
||||||
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} /> |
<Col> |
||||||
</Col> |
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} /> |
||||||
<Col> |
</Col> |
||||||
<Tooltip title="Tambah Proyek"> |
<Col> |
||||||
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button> |
<Tooltip title="Tambah Proyek"> |
||||||
</Tooltip> |
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button> |
||||||
<Tooltip title="Export Excel"> |
</Tooltip> |
||||||
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button> |
<Tooltip title="Export Excel"> |
||||||
</Tooltip> |
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button> |
||||||
</Col> |
</Tooltip> |
||||||
</Row> |
</Col> |
||||||
</CardHeader> |
</Row> |
||||||
<CardBody> |
</CardHeader> |
||||||
|
<CardBody> |
||||||
{RenderTable} |
|
||||||
</CardBody> |
{RenderTable} |
||||||
</Card> |
</CardBody> |
||||||
</div> |
</Card> |
||||||
) |
</div> |
||||||
} |
) |
||||||
|
} |
||||||
export default IndexRole; |
|
||||||
|
export default IndexRole; |
||||||
|
@ -1,383 +1,384 @@ |
|||||||
import * as XLSX from 'xlsx'; |
import * as XLSX from 'xlsx'; |
||||||
import DialogForm from './DialogForm'; |
import DialogForm from './DialogForm'; |
||||||
import React, { useState, useEffect, useMemo } from 'react'; |
import React, { useState, useEffect, useMemo } from 'react'; |
||||||
import SweetAlert from 'react-bootstrap-sweetalert'; |
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||||
import axios from "../../../const/interceptorApi"; |
import axios from "../../../const/interceptorApi"; |
||||||
import moment from 'moment' |
import moment from 'moment' |
||||||
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst'; |
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst'; |
||||||
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; |
||||||
import { DownloadOutlined } from '@ant-design/icons'; |
import { DownloadOutlined } from '@ant-design/icons'; |
||||||
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
import { NotificationContainer, NotificationManager } from 'react-notifications'; |
||||||
import { Pagination, Table, Button, Tooltip } from 'antd'; |
import { Pagination, Table, Button, Tooltip } from 'antd'; |
||||||
import { formatRupiah } from '../../../const/CustomFunc' |
import { formatRupiah } from '../../../const/CustomFunc' |
||||||
|
|
||||||
const url = ""; |
const url = ""; |
||||||
const proyek_id = localStorage.getItem('proyek_id'); |
const proyek_id = localStorage.getItem('proyek_id'); |
||||||
const role_id = localStorage.getItem('role_id'); |
const role_id = localStorage.getItem('role_id'); |
||||||
const format = "DD-MM-YYYY"; |
const company_id = window.localStorage.getItem('company_id'); |
||||||
|
const format = "DD-MM-YYYY"; |
||||||
const Closing = ({ params, ...props }) => { |
|
||||||
const token = localStorage.getItem("token") |
const Closing = ({ params, ...props }) => { |
||||||
const HEADER = { |
const token = localStorage.getItem("token") |
||||||
headers: { |
const HEADER = { |
||||||
"Content-Type": "application/json", |
headers: { |
||||||
"Authorization": `Bearer ${token}` |
"Content-Type": "application/json", |
||||||
} |
"Authorization": `Bearer ${token}` |
||||||
} |
} |
||||||
|
} |
||||||
const [alertClose, setAlertClose] = useState(false) |
|
||||||
const [alertDelete, setAlertDelete] = useState(false) |
const [alertClose, setAlertClose] = useState(false) |
||||||
const [allDataMenu, setAllDataMenu] = useState([]) |
const [alertDelete, setAlertDelete] = useState(false) |
||||||
const [clickOpenModal, setClickOpenModal] = useState(false) |
const [allDataMenu, setAllDataMenu] = useState([]) |
||||||
const [currentPage, setCurrentPage] = useState(1) |
const [clickOpenModal, setClickOpenModal] = useState(false) |
||||||
const [dataCharter, setDataCharter] = useState(null) |
const [currentPage, setCurrentPage] = useState(1) |
||||||
const [dataEdit, setDataEdit] = useState([]) |
const [dataCharter, setDataCharter] = useState(null) |
||||||
const [dataEditSub, setDataEditSub] = useState([]) |
const [dataEdit, setDataEdit] = useState([]) |
||||||
const [dataExport, setDataExport] = useState([]) |
const [dataEditSub, setDataEditSub] = useState([]) |
||||||
const [dataTable, setDatatable] = useState([]) |
const [dataExport, setDataExport] = useState([]) |
||||||
const [dataView, setDataView] = useState([]) |
const [dataTable, setDatatable] = useState([]) |
||||||
const [idDelete, setIdDelete] = useState(0) |
const [dataView, setDataView] = useState([]) |
||||||
const [idTask, setidTask] = useState(0); |
const [idDelete, setIdDelete] = useState(0) |
||||||
const [openDialog, setOpenDialog] = useState(false) |
const [idTask, setidTask] = useState(0); |
||||||
const [openDialogMap, setOpenDialogMap] = useState(false) |
const [openDialog, setOpenDialog] = useState(false) |
||||||
const [openDialogResource, setOpenDialogResource] = useState(false) |
const [openDialogMap, setOpenDialogMap] = useState(false) |
||||||
const [openDialogViewDetail, setOpenDialogViewDetail] = useState(false) |
const [openDialogResource, setOpenDialogResource] = useState(false) |
||||||
const [rowsPerPage, setRowsPerPage] = useState(10) |
const [openDialogViewDetail, setOpenDialogViewDetail] = useState(false) |
||||||
const [search, setSearch] = useState('') |
const [rowsPerPage, setRowsPerPage] = useState(10) |
||||||
const [totalPage, setTotalPage] = useState(0) |
const [search, setSearch] = useState('') |
||||||
const [typeDialog, setTypeDialog] = useState('Save'); |
const [totalPage, setTotalPage] = useState(0) |
||||||
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
const [typeDialog, setTypeDialog] = useState('Save'); |
||||||
const [userProyek, setUserProyek] = useState([]); |
const [typeDialogSub, setTypeDialogSub] = useState('Save') |
||||||
const pageName = params.name; |
const [userProyek, setUserProyek] = useState([]); |
||||||
|
const pageName = params.name; |
||||||
useEffect(() => { |
|
||||||
getDataProyek() |
useEffect(() => { |
||||||
}, []) |
getDataProyek() |
||||||
|
}, []) |
||||||
const handleSearch = e => { |
|
||||||
const value = e.target.value |
const handleSearch = e => { |
||||||
setSearch(value); |
const value = e.target.value |
||||||
setCurrentPage(1) |
setSearch(value); |
||||||
}; |
setCurrentPage(1) |
||||||
|
}; |
||||||
const getDataProyek = async () => { |
|
||||||
|
const getDataProyek = async () => { |
||||||
let start = 0; |
|
||||||
|
let start = 0; |
||||||
if (currentPage !== 1 && currentPage > 1) { |
|
||||||
start = (currentPage * rowsPerPage) - rowsPerPage |
if (currentPage !== 1 && currentPage > 1) { |
||||||
} |
start = (currentPage * rowsPerPage) - rowsPerPage |
||||||
|
} |
||||||
const payload = { |
|
||||||
"columns": [ |
const payload = { |
||||||
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
"columns": [ |
||||||
], |
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" } |
||||||
"joins": [ |
], |
||||||
{ "name": "m_users", "column_join": "pm_id", "column_results": ["name", "username"] }, |
"joins": [ |
||||||
{ "name": "m_type_proyek", "column_join": "type_proyek_id", "column_results": ["name", "description"] }, |
{ "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 } |
"orders": { "columns": ["id"], "ascending": true }, |
||||||
} |
"paging": { "start": 0, "length": 25 } |
||||||
|
} |
||||||
|
|
||||||
if (parseInt(role_id) !== 1) { |
|
||||||
payload["columns"] = [ |
if (parseInt(role_id) !== 1) { |
||||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
payload["columns"] = [ |
||||||
] |
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||||
} |
] |
||||||
|
} |
||||||
const URL = `${BASE_SIMPRO}/proyek/search-detail` |
|
||||||
const result = await axios |
const URL = `${BASE_SIMPRO}/proyek/search-detail` |
||||||
.post(URL, payload, HEADER) |
const result = await axios |
||||||
.then(res => res) |
.post(URL, payload, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
if (result && result.data && result.data.code == 200) { |
|
||||||
let dataRes = result.data.data || [] |
if (result && result.data && result.data.code == 200) { |
||||||
|
let dataRes = result.data.data || [] |
||||||
setDatatable(dataRes); |
|
||||||
setTotalPage(result.data.totalRecord); |
setDatatable(dataRes); |
||||||
} else { |
setTotalPage(result.data.totalRecord); |
||||||
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
} else { |
||||||
} |
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||||
} |
} |
||||||
|
} |
||||||
const handleOpenDialog = (id) => { |
|
||||||
setOpenDialog(true) |
const handleOpenDialog = (id) => { |
||||||
setidTask(id) |
setOpenDialog(true) |
||||||
} |
setidTask(id) |
||||||
|
} |
||||||
const handleOpenDialogResource = (data) => { |
|
||||||
setOpenDialogResource(true) |
const handleOpenDialogResource = (data) => { |
||||||
setidTask(data.id) |
setOpenDialogResource(true) |
||||||
setUserProyek(data.user_proyeks) |
setidTask(data.id) |
||||||
} |
setUserProyek(data.user_proyeks) |
||||||
|
} |
||||||
const handleOpenDialogViewDetail = (data) => { |
|
||||||
setOpenDialogViewDetail(true) |
const handleOpenDialogViewDetail = (data) => { |
||||||
setidTask(data.id) |
setOpenDialogViewDetail(true) |
||||||
setDataView(data) |
setidTask(data.id) |
||||||
setDataCharter(data.project_charter ? data.project_charter : null) |
setDataView(data) |
||||||
} |
setDataCharter(data.project_charter ? data.project_charter : null) |
||||||
|
} |
||||||
const handleCloseDialog = (type, payload) => { |
|
||||||
if (type === "add") saveProyek(payload); |
const handleCloseDialog = (type, payload) => { |
||||||
|
if (type === "add") saveProyek(payload); |
||||||
if (type === "edit") editProyek(payload); |
|
||||||
|
if (type === "edit") editProyek(payload); |
||||||
setOpenDialog(false) |
|
||||||
} |
setOpenDialog(false) |
||||||
|
} |
||||||
const handleCloseDialogResource = (type, payload) => { |
|
||||||
setOpenDialogResource(false) |
const handleCloseDialogResource = (type, payload) => { |
||||||
} |
setOpenDialogResource(false) |
||||||
|
} |
||||||
const handleCloseDialogView = (type, payload) => { |
|
||||||
setOpenDialogViewDetail(false) |
const handleCloseDialogView = (type, payload) => { |
||||||
} |
setOpenDialogViewDetail(false) |
||||||
|
} |
||||||
|
|
||||||
const toggleAddDialog = () => setOpenDialog(!openDialog) |
|
||||||
|
const toggleAddDialog = () => setOpenDialog(!openDialog) |
||||||
const toggleAddDialogResource = () => setOpenDialogResource(!openDialog) |
|
||||||
const toggleAddDialogView = () => setOpenDialogViewDetail(!openDialogViewDetail) |
const toggleAddDialogResource = () => setOpenDialogResource(!openDialog) |
||||||
|
const toggleAddDialogView = () => setOpenDialogViewDetail(!openDialogViewDetail) |
||||||
const onConfirmDelete = async () => { |
|
||||||
let urlDel = PROYEK_DELETE(idDelete) |
const onConfirmDelete = async () => { |
||||||
const result = await axios.delete(urlDel, HEADER) |
let urlDel = PROYEK_DELETE(idDelete, company_id) |
||||||
.then(res => res) |
const result = await axios.delete(urlDel, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
if (result && result.data && result.data.code === 200) { |
.catch((error) => error.response); |
||||||
getDataProyek() |
if (result && result.data && result.data.code === 200) { |
||||||
setIdDelete(0) |
getDataProyek() |
||||||
setAlertDelete(false) |
setIdDelete(0) |
||||||
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!'); |
setAlertDelete(false) |
||||||
} else { |
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!'); |
||||||
setIdDelete(0) |
} else { |
||||||
setAlertDelete(false) |
setIdDelete(0) |
||||||
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!'); |
setAlertDelete(false) |
||||||
} |
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!'); |
||||||
} |
} |
||||||
|
} |
||||||
const onConfirmClose = async () => { |
|
||||||
setIdDelete(0) |
const onConfirmClose = async () => { |
||||||
setAlertClose(false) |
setIdDelete(0) |
||||||
NotificationManager.success(`Data proyek berhasil diclose`, 'Success!!'); |
setAlertClose(false) |
||||||
} |
NotificationManager.success(`Data proyek berhasil diclose`, 'Success!!'); |
||||||
|
} |
||||||
const saveProyek = async (data) => { |
|
||||||
const formData = data |
const saveProyek = async (data) => { |
||||||
|
const formData = data |
||||||
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
|
||||||
.then(res => res) |
const result = await axios.post(PROYEK_ADD, formData, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
if (result && result.data && result.data.code === 200) { |
|
||||||
getDataProyek(); |
if (result && result.data && result.data.code === 200) { |
||||||
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
getDataProyek(); |
||||||
} else { |
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!'); |
||||||
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
} else { |
||||||
} |
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
} |
|
||||||
|
} |
||||||
const editProyek = async (data) => { |
|
||||||
let urlEdit = PROYEK_EDIT(data.id) |
const editProyek = async (data) => { |
||||||
const formData = data |
let urlEdit = PROYEK_EDIT(data.id) |
||||||
|
const formData = data |
||||||
const result = await axios.put(urlEdit, formData, HEADER) |
|
||||||
.then(res => res) |
const result = await axios.put(urlEdit, formData, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
if (result && result.data && result.data.code === 200) { |
|
||||||
getDataProyek(); |
if (result && result.data && result.data.code === 200) { |
||||||
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!'); |
getDataProyek(); |
||||||
} else { |
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!'); |
||||||
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`); |
} else { |
||||||
} |
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`); |
||||||
} |
} |
||||||
|
} |
||||||
const handleDelete = async (id) => { |
|
||||||
await setAlertDelete(true) |
const handleDelete = async (id) => { |
||||||
await setIdDelete(id) |
await setAlertDelete(true) |
||||||
} |
await setIdDelete(id) |
||||||
|
} |
||||||
const handleCloseProject = async (id) => { |
|
||||||
await setAlertClose(true) |
const handleCloseProject = async (id) => { |
||||||
await setIdDelete(id) |
await setAlertClose(true) |
||||||
} |
await setIdDelete(id) |
||||||
|
} |
||||||
const onShowSizeChange = (current, pageSize) => { |
|
||||||
setRowsPerPage(pageSize) |
const onShowSizeChange = (current, pageSize) => { |
||||||
} |
setRowsPerPage(pageSize) |
||||||
|
} |
||||||
const onPagination = (current, pageSize) => { |
|
||||||
setCurrentPage(current) |
const onPagination = (current, pageSize) => { |
||||||
} |
setCurrentPage(current) |
||||||
|
} |
||||||
const handleExportExcel = async () => { |
|
||||||
|
const handleExportExcel = async () => { |
||||||
const payload = { |
|
||||||
"paging": { "start": 0, "length": -1 }, |
const payload = { |
||||||
"joins": [], |
"paging": { "start": 0, "length": -1 }, |
||||||
"orders": { "columns": ["id"], "ascending": false } |
"joins": [], |
||||||
} |
"orders": { "columns": ["id"], "ascending": false } |
||||||
|
} |
||||||
if (parseInt(role_id) !== 1) { |
|
||||||
payload["columns"] = [ |
if (parseInt(role_id) !== 1) { |
||||||
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
payload["columns"] = [ |
||||||
] |
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" } |
||||||
} |
] |
||||||
|
} |
||||||
const result = await axios |
|
||||||
.post(PROYEK_SEARCH, payload, HEADER) |
const result = await axios |
||||||
.then(res => res) |
.post(PROYEK_SEARCH, payload, HEADER) |
||||||
.catch((error) => error.response); |
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
if (result && result.data && result.data.code == 200) { |
|
||||||
let resData = result.data.data; |
if (result && result.data && result.data.code == 200) { |
||||||
const excelData = []; |
let resData = result.data.data; |
||||||
resData.map((n, index) => { |
const excelData = []; |
||||||
let dataRow = { |
resData.map((n, index) => { |
||||||
"Nama Proyek": n.nama, |
let dataRow = { |
||||||
"Biaya": n.biaya, |
"Nama Proyek": n.nama, |
||||||
"Color Progress": n.color_progress, |
"Biaya": n.biaya, |
||||||
"Jumlah Pekerja": n.jumlah_pekerja, |
"Color Progress": n.color_progress, |
||||||
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-", |
"Jumlah Pekerja": n.jumlah_pekerja, |
||||||
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-", |
"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) |
} |
||||||
}) |
excelData.push(dataRow) |
||||||
await setDataExport(excelData); |
}) |
||||||
} else { |
await setDataExport(excelData); |
||||||
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
} else { |
||||||
} |
NotificationManager.error('Gagal Export Data!!', 'Failed'); |
||||||
} |
} |
||||||
|
} |
||||||
const exportExcel = () => { |
|
||||||
const dataExcel = dataExport || []; |
const exportExcel = () => { |
||||||
const fileName = `Data ${pageName}.xlsx`; |
const dataExcel = dataExport || []; |
||||||
const ws = XLSX.utils.json_to_sheet(dataExcel); |
const fileName = `Data ${pageName}.xlsx`; |
||||||
const wb = XLSX.utils.book_new(); |
const ws = XLSX.utils.json_to_sheet(dataExcel); |
||||||
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); |
const wb = XLSX.utils.book_new(); |
||||||
|
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`); |
||||||
XLSX.writeFile(wb, fileName); |
|
||||||
setDataExport([]) |
XLSX.writeFile(wb, fileName); |
||||||
} |
setDataExport([]) |
||||||
|
} |
||||||
const cancelDelete = () => { |
|
||||||
setAlertDelete(false) |
const cancelDelete = () => { |
||||||
setIdDelete(0) |
setAlertDelete(false) |
||||||
} |
setIdDelete(0) |
||||||
|
} |
||||||
const cancelClose = () => { |
|
||||||
setAlertClose(false) |
const cancelClose = () => { |
||||||
setIdDelete(0) |
setAlertClose(false) |
||||||
} |
setIdDelete(0) |
||||||
|
} |
||||||
const renderFormatRupiah = (text, prefix) => { |
|
||||||
if (text) { |
const renderFormatRupiah = (text, prefix) => { |
||||||
return formatRupiah(text, prefix) |
if (text) { |
||||||
} else { |
return formatRupiah(text, prefix) |
||||||
return "-" |
} else { |
||||||
} |
return "-" |
||||||
} |
} |
||||||
|
} |
||||||
const handleClickGantt = (id) => { |
|
||||||
props.history.push({ |
const handleClickGantt = (id) => { |
||||||
pathname: '/gantt', |
props.history.push({ |
||||||
state: { proyek_id: id } |
pathname: '/gantt', |
||||||
}) |
state: { proyek_id: id } |
||||||
} |
}) |
||||||
|
} |
||||||
const RenderTable = useMemo(() => { |
|
||||||
const columns = [ |
const RenderTable = useMemo(() => { |
||||||
{ |
const columns = [ |
||||||
title: 'Action', |
{ |
||||||
dataIndex: '', |
title: 'Action', |
||||||
key: 'x', |
dataIndex: '', |
||||||
render: (text, record) => <> |
key: 'x', |
||||||
<Tooltip title="Report"> |
render: (text, record) => <> |
||||||
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleOpenDialog(text.id)}><i className="fa fa-print"></i></Button> |
<Tooltip title="Report"> |
||||||
</Tooltip> |
<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: 'Nama Proyek', dataIndex: 'nama', key: 'nama' }, |
||||||
title: 'Planning Cost', |
{ |
||||||
dataIndex: 'rencana_biaya', |
title: 'Planning Cost', |
||||||
key: 'rencana_biaya', |
dataIndex: 'rencana_biaya', |
||||||
render: (text, record) => { return renderFormatRupiah(text, "Rp") } |
key: 'rencana_biaya', |
||||||
}, |
render: (text, record) => { return renderFormatRupiah(text, "Rp") } |
||||||
{ |
}, |
||||||
title: 'Project Type', |
{ |
||||||
dataIndex: 'color_progress', |
title: 'Project Type', |
||||||
key: 'color_progress', |
dataIndex: 'color_progress', |
||||||
render: (text, record) => <>{record.join.m_type_proyek_name}</> |
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: 'PM', dataIndex: 'pic', key: 'pic', |
||||||
}, |
render: (text, record) => <>{record.join.m_users_name}</> |
||||||
{ |
}, |
||||||
title: 'Time Project', |
{ |
||||||
dataIndex: 'akhir_proyek', |
title: 'Time Project', |
||||||
key: 'akhir_proyek', |
dataIndex: 'akhir_proyek', |
||||||
render: (text, record) => <>{moment(record.mulai_proyek).format(format)} - {moment(record.akhir_proyek).format(format)}</>, |
key: 'akhir_proyek', |
||||||
}, |
render: (text, record) => <>{moment(record.mulai_proyek).format(format)} - {moment(record.akhir_proyek).format(format)}</>, |
||||||
]; |
}, |
||||||
|
]; |
||||||
return ( |
|
||||||
<Table |
return ( |
||||||
size="small" |
<Table |
||||||
columns={columns} |
size="small" |
||||||
dataSource={dataTable} |
columns={columns} |
||||||
/> |
dataSource={dataTable} |
||||||
) |
/> |
||||||
}, [dataTable]) |
) |
||||||
|
}, [dataTable]) |
||||||
const RenderDialogForm = useMemo(() => ( |
|
||||||
<DialogForm |
const RenderDialogForm = useMemo(() => ( |
||||||
openDialog={openDialog} |
<DialogForm |
||||||
closeDialog={handleCloseDialog} |
openDialog={openDialog} |
||||||
toggleDialog={() => toggleAddDialog} |
closeDialog={handleCloseDialog} |
||||||
idTask={idTask} |
toggleDialog={() => toggleAddDialog} |
||||||
/> |
idTask={idTask} |
||||||
), [openDialog]) |
/> |
||||||
|
), [openDialog]) |
||||||
return ( |
|
||||||
<div> |
return ( |
||||||
<NotificationContainer /> |
<div> |
||||||
<SweetAlert |
<NotificationContainer /> |
||||||
show={alertClose} |
<SweetAlert |
||||||
warning |
show={alertClose} |
||||||
showCancel |
warning |
||||||
confirmBtnText="Close" |
showCancel |
||||||
confirmBtnBsStyle="danger" |
confirmBtnText="Close" |
||||||
title={`Are you sure?`} |
confirmBtnBsStyle="danger" |
||||||
onConfirm={onConfirmClose} |
title={`Are you sure?`} |
||||||
onCancel={() => cancelClose()} |
onConfirm={onConfirmClose} |
||||||
focusCancelBtn |
onCancel={() => cancelClose()} |
||||||
> |
focusCancelBtn |
||||||
Close this project |
> |
||||||
</SweetAlert> |
Close this project |
||||||
{RenderDialogForm} |
</SweetAlert> |
||||||
<Card> |
{RenderDialogForm} |
||||||
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
<Card> |
||||||
<h4 className="capitalize">{pageName}</h4> |
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||||
<Row> |
<h4 className="capitalize">{pageName}</h4> |
||||||
<Col> |
<Row> |
||||||
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} /> |
<Col> |
||||||
</Col> |
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} /> |
||||||
</Row> |
</Col> |
||||||
</CardHeader> |
</Row> |
||||||
<CardBody> |
</CardHeader> |
||||||
{RenderTable} |
<CardBody> |
||||||
</CardBody> |
{RenderTable} |
||||||
</Card> |
</CardBody> |
||||||
</div> |
</Card> |
||||||
) |
</div> |
||||||
} |
) |
||||||
|
} |
||||||
export default Closing; |
|
||||||
|
export default Closing; |
||||||
|
@ -1,96 +1,99 @@ |
|||||||
import React, { useEffect, useState } from 'react' |
import React, { useEffect, useState } from 'react' |
||||||
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; |
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; |
||||||
import { Button, Form, FormGroup, Label, Input, Col, Row } from 'reactstrap'; |
import { Button, Form, FormGroup, Label, Input, Col, Row } from 'reactstrap'; |
||||||
import axios from "../../../const/interceptorApi"; |
import axios from "../../../const/interceptorApi"; |
||||||
import { DOCUMENT_ADD } from '../../../const/ApiConst'; |
import { DOCUMENT_ADD } from '../../../const/ApiConst'; |
||||||
import 'antd/dist/antd.css'; |
import 'antd/dist/antd.css'; |
||||||
import { NotificationManager } from 'react-notifications'; |
import { NotificationManager } from 'react-notifications'; |
||||||
|
|
||||||
const DialogRequest = ({ openDialog, closeDialog, toggleDialog, idTask, parentIdNewFolder }) => { |
const DialogRequest = ({ openDialog, closeDialog, toggleDialog, idTask, parentIdNewFolder }) => { |
||||||
const token = localStorage.getItem("token") |
const token = localStorage.getItem("token") |
||||||
const HEADER = { |
const HEADER = { |
||||||
headers: { |
headers: { |
||||||
"Content-Type": "application/json", |
"Content-Type": "application/json", |
||||||
"Authorization": `Bearer ${token}` |
"Authorization": `Bearer ${token}` |
||||||
} |
} |
||||||
} |
} |
||||||
const [id, setId] = useState(0) |
const [id, setId] = useState(0) |
||||||
const [file, setFile] = useState(null) |
const [file, setFile] = useState(null) |
||||||
|
|
||||||
|
|
||||||
const handleCLearData = () => { |
const handleCLearData = () => { |
||||||
setId(0) |
setId(0) |
||||||
setFile(null) |
setFile(null) |
||||||
} |
} |
||||||
|
|
||||||
useEffect(() => { |
useEffect(() => { |
||||||
handleCLearData() |
handleCLearData() |
||||||
}, [openDialog]) |
}, [openDialog]) |
||||||
|
|
||||||
const handleSave = () => { |
const handleSave = () => { |
||||||
uploadDokumen() |
uploadDokumen() |
||||||
handleCLearData() |
handleCLearData() |
||||||
} |
} |
||||||
|
|
||||||
const uploadDokumen = async () => { |
const uploadDokumen = async () => { |
||||||
const formData = new FormData; |
const configApp = JSON.parse(window.localStorage.getItem('configApp')); |
||||||
formData.append('dokumen', file, file.name); |
|
||||||
|
const formData = new FormData; |
||||||
if (parentIdNewFolder > 0) { |
formData.append('dokumen', file, file.name); |
||||||
formData.append('ref_id', parentIdNewFolder); // folder_id
|
formData.append('company_name',configApp.company_name); |
||||||
formData.append('type_dokumen', 'project-document-in-folder'); |
|
||||||
} |
if (parentIdNewFolder > 0) { |
||||||
else { |
formData.append('ref_id', parentIdNewFolder); // folder_id
|
||||||
formData.append('ref_id', idTask); // proyek_id
|
formData.append('type_dokumen', 'project-document-in-folder'); |
||||||
formData.append('type_dokumen', 'project-document-out-folder') |
} |
||||||
} |
else { |
||||||
|
formData.append('ref_id', idTask); // proyek_id
|
||||||
const result = await axios |
formData.append('type_dokumen', 'project-document-out-folder') |
||||||
.post(DOCUMENT_ADD, formData, HEADER) |
} |
||||||
.then(res => res) |
|
||||||
.catch((error) => error.response); |
const result = await axios |
||||||
|
.post(DOCUMENT_ADD, formData, HEADER) |
||||||
if (result && result.status == 200) { |
.then(res => res) |
||||||
NotificationManager.success('Dokumen project berhasil diupload!!', 'Success'); |
.catch((error) => error.response); |
||||||
closeDialog('upload') |
const notif = result.data.message; |
||||||
} else { |
if (result && result.status == 200) { |
||||||
NotificationManager.error('Dokumen project gagal diupload!!', 'Failed'); |
NotificationManager.success(notif, 'Success'); |
||||||
closeDialog('failed upload') |
closeDialog('upload') |
||||||
} |
} else { |
||||||
} |
NotificationManager.error(notif, 'Failed'); |
||||||
|
closeDialog('failed upload') |
||||||
const handleCancel = () => { |
} |
||||||
closeDialog('cancel') |
} |
||||||
handleCLearData() |
|
||||||
} |
const handleCancel = () => { |
||||||
|
closeDialog('cancel') |
||||||
const renderForm = () => { |
handleCLearData() |
||||||
return ( |
} |
||||||
<Form> |
|
||||||
<FormGroup> |
const renderForm = () => { |
||||||
<Label className="capitalize">Upload File</Label> |
return ( |
||||||
<Input type="file" onChange={(e) => setFile(e.target.files[0])} /> |
<Form> |
||||||
</FormGroup> |
<FormGroup> |
||||||
</Form> |
<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> |
return ( |
||||||
<ModalBody> |
<> |
||||||
{renderForm()} |
<Modal isOpen={openDialog} toggle={toggleDialog}> |
||||||
</ModalBody> |
<ModalHeader className="capitalize" toggle={closeDialog}>Upload Project Document</ModalHeader> |
||||||
<ModalFooter> |
<ModalBody> |
||||||
<Button color="primary" onClick={() => handleSave()}>Upload</Button>{' '} |
{renderForm()} |
||||||
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Cancel</Button> |
</ModalBody> |
||||||
</ModalFooter> |
<ModalFooter> |
||||||
</Modal> |
<Button color="primary" onClick={() => handleSave()}>Upload</Button>{' '} |
||||||
</> |
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Cancel</Button> |
||||||
) |
</ModalFooter> |
||||||
|
</Modal> |
||||||
} |
</> |
||||||
|
) |
||||||
export default DialogRequest; |
|
||||||
|
} |
||||||
|
|
||||||
|
export default DialogRequest; |
||||||
|
@ -0,0 +1,130 @@ |
|||||||
|
import React, { Fragment } from 'react' |
||||||
|
import './Kanban.css'; |
||||||
|
import { Card, Row, Col, Button, Avatar, Tooltip, Popover, Divider, Space, Menu, Dropdown } from 'antd'; |
||||||
|
import Task from './Task'; |
||||||
|
import { Droppable } from 'react-beautiful-dnd'; |
||||||
|
import styled from 'styled-components'
|
||||||
|
import {
|
||||||
|
AntDesignOutlined, |
||||||
|
UserOutlined, |
||||||
|
EditOutlined, |
||||||
|
DeleteOutlined, |
||||||
|
SettingOutlined, |
||||||
|
EllipsisOutlined, |
||||||
|
MoreOutlined |
||||||
|
} from '@ant-design/icons'; |
||||||
|
|
||||||
|
const Container = styled.div` |
||||||
|
margin: 8px; |
||||||
|
border: 1px solid lightgrey; |
||||||
|
border-radius: 2px; |
||||||
|
width: 220px; |
||||||
|
|
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
` |
||||||
|
|
||||||
|
const TaskList = styled.div` |
||||||
|
transition: background-color 0.2s ease; |
||||||
|
background-color: ${props => |
||||||
|
props.isDraggingOver ? 'skyblue' : 'white'} |
||||||
|
flex-grow: 1; |
||||||
|
min-height: 100px; |
||||||
|
` |
||||||
|
|
||||||
|
const Column = ({
|
||||||
|
column,
|
||||||
|
tasks,
|
||||||
|
index,
|
||||||
|
handleOpenDialogActivity,
|
||||||
|
handleOpenDialogChild,
|
||||||
|
handleDelete,
|
||||||
|
handleEditBoard,
|
||||||
|
loadingCard,
|
||||||
|
handleDeleteCard,
|
||||||
|
handleEditCard |
||||||
|
}) => { |
||||||
|
|
||||||
|
|
||||||
|
const menu = (column) => ( |
||||||
|
<Menu |
||||||
|
items={[ |
||||||
|
{ |
||||||
|
key: '3', |
||||||
|
label: ( |
||||||
|
<a rel="noopener noreferrer" > |
||||||
|
status is {column.status_progress} |
||||||
|
</a> |
||||||
|
), |
||||||
|
}, |
||||||
|
{ |
||||||
|
key: '1', |
||||||
|
label: ( |
||||||
|
<a rel="noopener noreferrer" onClick={() => handleEditBoard(column)} > |
||||||
|
<EditOutlined style={{marginRight: "5px"}} /> Edit |
||||||
|
</a> |
||||||
|
), |
||||||
|
}, |
||||||
|
{ |
||||||
|
key: '2', |
||||||
|
label: ( |
||||||
|
<a rel="noopener noreferrer" onClick={() => handleDelete(column.id)} > |
||||||
|
<DeleteOutlined style={{marginRight: "5px"}} /> Hapus |
||||||
|
</a> |
||||||
|
), |
||||||
|
}, |
||||||
|
]} |
||||||
|
/> |
||||||
|
); |
||||||
|
|
||||||
|
return ( |
||||||
|
<Col className="gutter-row" span={6}> |
||||||
|
<div className='board' style={{backgroundColor: column.header_color}}> |
||||||
|
<div className='title-board' style={{color: column.body_color}}> |
||||||
|
<b>{column.name_board}</b> |
||||||
|
{/* <a style={{color: column.body_color, marginRight: "7px", float: 'right'}} onClick={() => handleEditBoard(column)}><EditOutlined /></a> */} |
||||||
|
{/* <a style={{color: column.body_color, marginRight: "7px", float: 'right'}} onClick={() => handleDelete(column.id)}><DeleteOutlined /></a> */} |
||||||
|
<div style={{float: 'right', marginRight: "5px"}}> |
||||||
|
<Dropdown overlay={menu(column)}> |
||||||
|
<a onClick={(e) => e.preventDefault()}> |
||||||
|
<MoreOutlined style={{fontSize:"20px"}} /> |
||||||
|
</a> |
||||||
|
</Dropdown> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<Divider/> |
||||||
|
<div className='destination'> |
||||||
|
{ tasks.length === 0 &&
|
||||||
|
<p className='add-card' onClick={()=> handleOpenDialogActivity("Save", column.id)}>+ Add Activity</p> |
||||||
|
} |
||||||
|
<Droppable droppableId={column.key} type='TASK'> |
||||||
|
{(provided, snapshot) => ( |
||||||
|
<TaskList |
||||||
|
ref={provided.innerRef} |
||||||
|
{...provided.droppableProps} |
||||||
|
isDraggingOver={snapshot.isDraggingOver} |
||||||
|
> |
||||||
|
{tasks.map((task, index) => ( |
||||||
|
<Task
|
||||||
|
key={task.id}
|
||||||
|
task={task}
|
||||||
|
index={index}
|
||||||
|
bodyColor={column.body_color}
|
||||||
|
loadingCard={loadingCard}
|
||||||
|
handleDeleteCard={handleDeleteCard}
|
||||||
|
handleEditCard={handleEditCard} />
|
||||||
|
))} |
||||||
|
{provided.placeholder} |
||||||
|
</TaskList> |
||||||
|
)} |
||||||
|
</Droppable> |
||||||
|
{ tasks.length > 0 &&
|
||||||
|
<p className='add-card' onClick={()=> handleOpenDialogActivity("Save", column.id)}>+ Add Activity</p> |
||||||
|
} |
||||||
|
</div> |
||||||
|
</Col> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default Column; |
@ -0,0 +1,72 @@ |
|||||||
|
import React, { useEffect, useState } from 'react' |
||||||
|
import { |
||||||
|
ModalHeader, ModalBody, ModalFooter, |
||||||
|
Button, Form, FormGroup, Label, Input, Col, Row |
||||||
|
} from 'reactstrap'; |
||||||
|
import { DatePicker, Tooltip, Select, Modal } from 'antd'; |
||||||
|
import { formatRupiah, formatNumber } from '../../../const/CustomFunc' |
||||||
|
import moment from 'moment'; |
||||||
|
import 'antd/dist/antd.css'; |
||||||
|
const { Option } = Select |
||||||
|
|
||||||
|
const DialogCard = ({
|
||||||
|
openDialogChild, |
||||||
|
closeDialogChild, |
||||||
|
toggleDialogChild, |
||||||
|
typeDialogChild, |
||||||
|
task,
|
||||||
|
}) => { |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
|
||||||
|
}, [openDialogChild]) |
||||||
|
|
||||||
|
const handleCancel = () => { |
||||||
|
closeDialogChild('cancel', 'none') |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
{/* <Modal size="lg" isOpen={openDialogChild} toggle={toggleDialogChild} centered> |
||||||
|
<ModalHeader className="capitalize" toggle={closeDialogChild}></ModalHeader> |
||||||
|
<ModalBody> |
||||||
|
</ModalBody> |
||||||
|
<ModalFooter> |
||||||
|
<Button color="primary" onClick={() => handleSave()}>{typeDialogChild == "Edit" ? `Edit` : "Save"}</Button>{' '} |
||||||
|
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button> |
||||||
|
</ModalFooter> |
||||||
|
</Modal> */} |
||||||
|
<Modal title="Card" open={openDialogChild} onOk={handleCancel} onCancel={handleCancel}
|
||||||
|
footer={[ |
||||||
|
<Button key="back" onClick={handleCancel}> |
||||||
|
Close |
||||||
|
</Button> |
||||||
|
]} |
||||||
|
> |
||||||
|
<Row style={{padding: "20px"}}> |
||||||
|
<Col md={6} style={{fontWeight: "bold"}} >Activity</Col> |
||||||
|
<Col md={6}>{task.activity}</Col> |
||||||
|
</Row> |
||||||
|
<Row style={{padding: "20px"}}> |
||||||
|
<Col md={6} style={{fontWeight: "bold"}}>Start Date</Col> |
||||||
|
<Col md={6}>{moment(task.start_date).format('DD-MM-YYYY HH:mm')}</Col> |
||||||
|
</Row> |
||||||
|
<Row style={{padding: "20px"}}> |
||||||
|
<Col md={6} style={{fontWeight: "bold"}}>End Date</Col> |
||||||
|
<Col md={6}>{moment(task.end_date).format('DD-MM-YYYY HH:mm')}</Col> |
||||||
|
</Row> |
||||||
|
<Row style={{padding: "20px"}}> |
||||||
|
<Col md={6} style={{fontWeight: "bold"}}>Bobot Planning </Col> |
||||||
|
<Col md={6}>{task.bobot_planning}</Col> |
||||||
|
</Row> |
||||||
|
<Row style={{padding: "20px"}}> |
||||||
|
<Col md={6} style={{fontWeight: "bold"}}>Presentase Progress </Col> |
||||||
|
<Col md={6}>{task.persentase_progress}</Col> |
||||||
|
</Row> |
||||||
|
</Modal> |
||||||
|
</> |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
export default DialogCard; |
@ -0,0 +1,347 @@ |
|||||||
|
import React, { useEffect, useState } from 'react' |
||||||
|
import { |
||||||
|
Modal, ModalHeader, ModalBody, ModalFooter, |
||||||
|
Form, FormGroup, Label, Input, Col, Row |
||||||
|
} from 'reactstrap'; |
||||||
|
import { DatePicker, Tooltip, Drawer, Divider, Layout, Button, Space, Progress } from 'antd'; |
||||||
|
import { |
||||||
|
CloseOutlined, |
||||||
|
MinusOutlined,
|
||||||
|
PlusOutlined |
||||||
|
} from '@ant-design/icons'; |
||||||
|
import { formatRupiah, formatNumber } from '../../../const/CustomFunc' |
||||||
|
import moment from 'moment'; |
||||||
|
import Select from 'react-select'; |
||||||
|
import axios from "../../../const/interceptorApi"; |
||||||
|
import { BASE_SIMPRO_LUMEN } from '../../../const/ApiConst'; |
||||||
|
import { |
||||||
|
NotificationManager |
||||||
|
} from "react-notifications"; |
||||||
|
import 'antd/dist/antd.css'; |
||||||
|
// const { Option } = Select
|
||||||
|
|
||||||
|
const DialogFormActivity = ({
|
||||||
|
activityProject, |
||||||
|
openDialogActivity,
|
||||||
|
closeDialogActivity,
|
||||||
|
handleOpenDialogReport, |
||||||
|
toggleDialogActivity,
|
||||||
|
typeDialogActivity,
|
||||||
|
proyek_id,
|
||||||
|
version_gantt_id,
|
||||||
|
idBoard,
|
||||||
|
dataHr,
|
||||||
|
dataEditCard, |
||||||
|
userToActivityDelete, |
||||||
|
userToActivityAdd |
||||||
|
}) => { |
||||||
|
const [id, setId] = useState('') |
||||||
|
const [text, setText] = useState('') |
||||||
|
const [startDate, setStartDate] = useState('') |
||||||
|
const [progress, setProgress] = useState(0) |
||||||
|
const [volumePlan, setVolumePlan] = useState(0) |
||||||
|
const [endDate, setEndDate] = useState('') |
||||||
|
const [nativeeditorStatus, setNativeeditorStatus] = useState('') |
||||||
|
const [hr, setHr] = useState(null); |
||||||
|
const [hrTemporary, setHrTemporary] = useState(); |
||||||
|
const [hrTemporaryAdd, setHrTemporaryAdd] = useState([]); |
||||||
|
const [IdDeleteHrTemporary, setIdDeleteHrTemporary] = useState([]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
|
||||||
|
setText('') |
||||||
|
setStartDate('') |
||||||
|
setProgress(0) |
||||||
|
setEndDate('') |
||||||
|
setVolumePlan(0) |
||||||
|
setHr('') |
||||||
|
setHrTemporaryAdd([]) |
||||||
|
setHrTemporary([]) |
||||||
|
setIdDeleteHrTemporary([]) |
||||||
|
|
||||||
|
if (typeDialogActivity === "Edit") { |
||||||
|
|
||||||
|
setId(dataEditCard.id) |
||||||
|
setText(dataEditCard.activity) |
||||||
|
setProgress(dataEditCard.persentase_progress)
|
||||||
|
setStartDate(moment(dataEditCard.start_date)) |
||||||
|
setEndDate(moment(dataEditCard.end_date))
|
||||||
|
dataEditCard.assign_hr.map((item) => { |
||||||
|
item.value = item.id_hr |
||||||
|
item.label = item.name |
||||||
|
}) |
||||||
|
setVolumePlan(dataEditCard.jumlah_pekerjaan) |
||||||
|
setHr(dataEditCard.assign_hr) |
||||||
|
setHrTemporary(dataEditCard.assign_hr) |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
setId(0) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
dataHr.map((item) => { |
||||||
|
item.value = item.id |
||||||
|
item.label = item.name |
||||||
|
}) |
||||||
|
|
||||||
|
}, [openDialogActivity]) |
||||||
|
|
||||||
|
const handleCancel = () => { |
||||||
|
closeDialogActivity('cancel', 'none') |
||||||
|
setVolumePlan(0) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const handleSave = () => { |
||||||
|
let data = ''; |
||||||
|
|
||||||
|
if (!text || text === "") { |
||||||
|
alert("text cannot be empty!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (!startDate || startDate === "") { |
||||||
|
alert("startDate cannot be empty!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (!endDate || endDate === "") { |
||||||
|
alert("endDate cannot be empty!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (!hr || hr === "") { |
||||||
|
alert("hr cannot be empty!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (typeDialogActivity === "Save") { |
||||||
|
|
||||||
|
data = { |
||||||
|
"text" : text, |
||||||
|
"start_date": startDate, |
||||||
|
"jumlah_pekerjaan" : volumePlan, |
||||||
|
"end_date" : endDate, |
||||||
|
"proyek_id" : proyek_id, |
||||||
|
"version_gantt_id": version_gantt_id, |
||||||
|
"board_id" : idBoard, |
||||||
|
"parent_id" : activityProject |
||||||
|
} |
||||||
|
closeDialogActivity('save', data, hr, id); |
||||||
|
} else if (typeDialogActivity === "Edit") { |
||||||
|
|
||||||
|
hrTemporaryAdd.map((item)=> { |
||||||
|
let dataSaveHr = { |
||||||
|
"user_id": item.id, |
||||||
|
"role_proyek_id": item.proyek_role, |
||||||
|
"version_gantt_id": version_gantt_id, |
||||||
|
"proyek_id": proyek_id, |
||||||
|
"activity_id": id |
||||||
|
} |
||||||
|
userToActivityAdd(dataSaveHr) |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
IdDeleteHrTemporary.map((item)=>{ |
||||||
|
|
||||||
|
userToActivityDelete(item) |
||||||
|
|
||||||
|
}) |
||||||
|
|
||||||
|
setHrTemporaryAdd([]) |
||||||
|
setIdDeleteHrTemporary([]) |
||||||
|
setHrTemporary([]) |
||||||
|
|
||||||
|
progress == 100 ? |
||||||
|
data = { |
||||||
|
"text": text, |
||||||
|
"start_date": startDate, |
||||||
|
"jumlah_pekerjaan": volumePlan, |
||||||
|
"end_date": endDate, |
||||||
|
"proyek_id": proyek_id, |
||||||
|
"version_gantt_id": version_gantt_id, |
||||||
|
"board_id": idBoard, |
||||||
|
"progress": parseFloat(progress / 100).toFixed(2) |
||||||
|
} |
||||||
|
: |
||||||
|
data = { |
||||||
|
"text": text, |
||||||
|
"start_date": startDate, |
||||||
|
"jumlah_pekerjaan": volumePlan, |
||||||
|
"end_date": endDate, |
||||||
|
"proyek_id": proyek_id, |
||||||
|
"version_gantt_id": version_gantt_id, |
||||||
|
"board_id": idBoard, |
||||||
|
"progress": parseFloat(progress / 100).toFixed(2) |
||||||
|
} |
||||||
|
|
||||||
|
closeDialogActivity('edit', data, hr, id); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const onChangeHr = (newValue, actionMeta) => {
|
||||||
|
if (typeDialogActivity === "Edit") {
|
||||||
|
if (actionMeta.action === 'select-option') { |
||||||
|
const item = actionMeta.option |
||||||
|
// console.log("actionMeta", item);
|
||||||
|
// let dataSaveHr = {
|
||||||
|
// "user_id": item.id,
|
||||||
|
// "role_proyek_id": item.proyek_role,
|
||||||
|
// "version_gantt_id": version_gantt_id,
|
||||||
|
// "proyek_id": proyek_id,
|
||||||
|
// "activity_id": id
|
||||||
|
// }
|
||||||
|
// userToActivityAdd(dataSaveHr)
|
||||||
|
setHrTemporaryAdd([...hrTemporaryAdd, item]) |
||||||
|
} else if (actionMeta.action === 'remove-value') { |
||||||
|
const id = actionMeta.removedValue.id |
||||||
|
// userToActivityDelete(id)
|
||||||
|
for (let k in hrTemporary) {
|
||||||
|
if (hrTemporary[k].id == id) { |
||||||
|
setIdDeleteHrTemporary([...IdDeleteHrTemporary, id]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
}
|
||||||
|
} |
||||||
|
|
||||||
|
setHr(newValue) |
||||||
|
}; |
||||||
|
|
||||||
|
const increase = () => { |
||||||
|
let newPercent = progress + 10; |
||||||
|
if (newPercent > 100) { |
||||||
|
newPercent = 100; |
||||||
|
} |
||||||
|
setProgress(newPercent); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
const decline = () => { |
||||||
|
let newPercent = progress - 10; |
||||||
|
if (newPercent < 0) { |
||||||
|
newPercent = 0; |
||||||
|
} |
||||||
|
setProgress(newPercent); |
||||||
|
}; |
||||||
|
|
||||||
|
const renderForm = () => { |
||||||
|
return ( |
||||||
|
<Form> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Text</Label> |
||||||
|
<Input type="text" value={text} onChange={(e) => setText(e.target.value)} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Start Date</Label> |
||||||
|
<DatePicker style={{ width: "100%" }} value={startDate} onChange={(dateItem, dateString) => { |
||||||
|
dateItem.set({hour:0,minute:0,second:0}) |
||||||
|
setStartDate(dateItem)}}
|
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">End date</Label> |
||||||
|
<DatePicker style={{ width: "100%" }} value={endDate} onChange={(dateItem, dateString) => { |
||||||
|
dateItem.set({hour:23,minute:59,second:59}) |
||||||
|
setEndDate(dateItem)}} |
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
{/* <Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Duration</Label> |
||||||
|
<Input type="number" value={duration} onChange={(e) => setDuration(e.target.value)}/> |
||||||
|
</FormGroup> |
||||||
|
</Col> */} |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Presentase Progress</Label> |
||||||
|
{/* <Input type="number" value={progress} onChange={(e) => setProgress(e.target.value)}/> */} |
||||||
|
<Progress percent={Math.round(progress)} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Volume Plan</Label> |
||||||
|
<Input type="number" value={volumePlan} onChange={(e) => setVolumePlan(e.target.value)} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Human Resource</Label> |
||||||
|
{/* <Select |
||||||
|
showSearch |
||||||
|
filterOption={(inputValue, option) => |
||||||
|
option.children.toLowerCase().includes(inputValue.toLowerCase()) |
||||||
|
} |
||||||
|
value={hr} |
||||||
|
defaultValue={hr} |
||||||
|
onChange={onChangeHr} |
||||||
|
style={{ width: "100%" }} |
||||||
|
> |
||||||
|
{dataHr.map((res) => ( |
||||||
|
<Option key={res.id} value={res.id}> |
||||||
|
{res.name} |
||||||
|
</Option> |
||||||
|
))} |
||||||
|
</Select> */} |
||||||
|
<Select |
||||||
|
value={hr} |
||||||
|
defaultValue={hr} |
||||||
|
isClearable={false} |
||||||
|
isMulti |
||||||
|
name="colors" |
||||||
|
options={dataHr} |
||||||
|
className="basic-multi-select" |
||||||
|
classNamePrefix="select" |
||||||
|
onChange={onChangeHr} |
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Volume Actual : {Math.round(parseInt(progress) / 100 * volumePlan)}</Label> |
||||||
|
<div> |
||||||
|
<Button onClick={() => handleOpenDialogReport("Save")} type="primary">Detail Report</Button> |
||||||
|
</div> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Drawer title="Basic Drawer" placement="right" onClose={() => handleCancel()} open={openDialogActivity}> |
||||||
|
<div className='top'> |
||||||
|
<Space> |
||||||
|
<Button type='text' onClick={() => handleCancel()}><CloseOutlined /></Button> |
||||||
|
</Space> |
||||||
|
<Space style={{float:"right"}}> |
||||||
|
<Button onClick={() => handleCancel()}>Cancel</Button> |
||||||
|
<Button onClick={() => handleSave()} type="primary"> |
||||||
|
{typeDialogActivity == "Edit" ? `Edit` : "Add"} Activity |
||||||
|
</Button> |
||||||
|
</Space> |
||||||
|
<Divider /> |
||||||
|
</div> |
||||||
|
<div className='content' style={{alignContent:'center'}}> |
||||||
|
{renderForm()} |
||||||
|
</div> |
||||||
|
<div className='bottom' style={{float:'bottom'}}> |
||||||
|
</div> |
||||||
|
</Drawer> |
||||||
|
</> |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
export default DialogFormActivity; |
@ -0,0 +1,176 @@ |
|||||||
|
import React, { useEffect, useState } from 'react' |
||||||
|
import { |
||||||
|
Modal, ModalHeader, ModalBody, ModalFooter, |
||||||
|
Form, FormGroup, Label, Input, Col, Row, FormFeedback |
||||||
|
} from 'reactstrap'; |
||||||
|
import { DatePicker, Tooltip, Select, Drawer, Divider, Layout, Button, Space } from 'antd'; |
||||||
|
import 'antd/dist/antd.css'; |
||||||
|
import { |
||||||
|
CloseOutlined |
||||||
|
} from '@ant-design/icons'; |
||||||
|
const { Option } = Select |
||||||
|
const { Header, Footer, Sider, Content } = Layout; |
||||||
|
|
||||||
|
|
||||||
|
const DialogFormBoard = ({ openDialogBoard, closeDialogBoard, toggleDialogBoard, typeDialogBoard, dataEditBoard, proyek_id, version_gantt_id }) => { |
||||||
|
const [id, setId] = useState(0) |
||||||
|
const [nameBoard, setNameBoard] = useState('') |
||||||
|
const [statusProgress, setStatusProgress] = useState('none') |
||||||
|
const [headerColor, setHeaderColor] = useState('#000000') |
||||||
|
const [bodyColor, setBodyColor] = useState('#ffffff') |
||||||
|
|
||||||
|
// validation
|
||||||
|
const [nameBoardVal, setNameBoardVal] = useState(false) |
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
|
||||||
|
setNameBoard('') |
||||||
|
setStatusProgress('') |
||||||
|
setHeaderColor('#000000') |
||||||
|
setBodyColor('#ffffff') |
||||||
|
|
||||||
|
if (typeDialogBoard === "Edit") { |
||||||
|
setId(dataEditBoard.id) |
||||||
|
setNameBoard(dataEditBoard.name_board) |
||||||
|
setHeaderColor(dataEditBoard.header_color) |
||||||
|
setBodyColor(dataEditBoard.body_color) |
||||||
|
setStatusProgress(dataEditBoard.status_progress) |
||||||
|
} else { |
||||||
|
setId(0) |
||||||
|
} |
||||||
|
}, [dataEditBoard, openDialogBoard]) |
||||||
|
|
||||||
|
const handleCancel = () => { |
||||||
|
closeDialogBoard('cancel', 'none') |
||||||
|
} |
||||||
|
|
||||||
|
const handleSave = () => { |
||||||
|
let data = ''; |
||||||
|
|
||||||
|
if (!nameBoard || nameBoard === "") { |
||||||
|
alert("nameBoard cannot be empty!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (!statusProgress || statusProgress === "") { |
||||||
|
alert("statusProgress cannot be empty!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (typeDialogBoard === "Save") { |
||||||
|
data = { |
||||||
|
name_board: nameBoard, |
||||||
|
status_progress: statusProgress, |
||||||
|
header_color: headerColor, |
||||||
|
body_color: bodyColor, |
||||||
|
proyek_id: proyek_id, |
||||||
|
version_gantt_id: version_gantt_id |
||||||
|
} |
||||||
|
closeDialogBoard('save', data); |
||||||
|
} else if (typeDialogBoard === "Edit") { |
||||||
|
data = { |
||||||
|
id: id, |
||||||
|
name_board: nameBoard, |
||||||
|
status_progress: statusProgress, |
||||||
|
header_color: headerColor, |
||||||
|
body_color: bodyColor, |
||||||
|
proyek_id: proyek_id, |
||||||
|
version_gantt_id: version_gantt_id |
||||||
|
} |
||||||
|
closeDialogBoard('edit', data); |
||||||
|
} |
||||||
|
|
||||||
|
setNameBoard('') |
||||||
|
setStatusProgress('') |
||||||
|
setHeaderColor('#000000') |
||||||
|
setBodyColor('#ffffff') |
||||||
|
} |
||||||
|
|
||||||
|
const onChangeStatusProgress = (val) => { |
||||||
|
setStatusProgress(val) |
||||||
|
}; |
||||||
|
|
||||||
|
const renderForm = () => { |
||||||
|
return ( |
||||||
|
<Form> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Name Board</Label> |
||||||
|
<Input type="text" value={nameBoard} onChange={(e) => setNameBoard(e.target.value)} /> |
||||||
|
{/* <Input type="text" value={nameBoard} onChange={(e) => setNameBoard(e.target.value)} invalid={nameBoardVal} /> |
||||||
|
<FormFeedback> |
||||||
|
Required!
|
||||||
|
</FormFeedback> */} |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Status Progress</Label> |
||||||
|
{/* <Input type="text" value={statusProgress} onChange={(e) => setStatusProgress(e.target.value)}/> */} |
||||||
|
<Select |
||||||
|
showSearch |
||||||
|
filterOption={(inputValue, option) => |
||||||
|
option.children.toLowerCase().includes(inputValue.toLowerCase()) |
||||||
|
} |
||||||
|
value={statusProgress} |
||||||
|
defaultValue={statusProgress} |
||||||
|
onChange={onChangeStatusProgress} |
||||||
|
style={{ width: "100%" }} |
||||||
|
> |
||||||
|
<Option value="none">none</Option> |
||||||
|
<Option value="open">open</Option> |
||||||
|
<Option value="on-progress">on-progress</Option> |
||||||
|
<Option value="done">done</Option> |
||||||
|
</Select> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Header Color</Label> |
||||||
|
<Input type="color" value={headerColor} onChange={(e) => setHeaderColor(e.target.value)} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Text Header Color</Label> |
||||||
|
<Input type="color" value={bodyColor} onChange={(e) => setBodyColor(e.target.value)} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Drawer title="Basic Drawer" placement="right" onClose={() => handleCancel()} open={openDialogBoard}> |
||||||
|
<div className='top'> |
||||||
|
<Space> |
||||||
|
<Button type='text' onClick={() => handleCancel()}><CloseOutlined /></Button> |
||||||
|
</Space> |
||||||
|
<Space style={{ float: "right" }}> |
||||||
|
<Button onClick={() => handleCancel()}>Cancel</Button> |
||||||
|
<Button onClick={() => handleSave()} type="primary"> |
||||||
|
{typeDialogBoard == "Edit" ? `Edit` : "Add"} Board |
||||||
|
</Button> |
||||||
|
</Space> |
||||||
|
<Divider /> |
||||||
|
</div> |
||||||
|
<div className='content' style={{ alignContent: 'center' }}> |
||||||
|
{renderForm()} |
||||||
|
</div> |
||||||
|
<div className='bottom' style={{ float: 'bottom' }}> |
||||||
|
</div> |
||||||
|
</Drawer> |
||||||
|
</> |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
export default DialogFormBoard; |
@ -0,0 +1,69 @@ |
|||||||
|
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 DialogFormChild = ({ openDialogChild, closeDialogChild, toggleDialogChild, typeDialogChild }) => { |
||||||
|
const [activity, setActivity] = useState('') |
||||||
|
const [name, setName] = useState('') |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
|
||||||
|
}, [openDialogChild]) |
||||||
|
|
||||||
|
const handleCancel = () => { |
||||||
|
closeDialogChild('cancel', 'none') |
||||||
|
} |
||||||
|
|
||||||
|
const handleSave = () => { |
||||||
|
let data = ''; |
||||||
|
if (typeDialogChild === "Save") { |
||||||
|
data = { |
||||||
|
name,
|
||||||
|
} |
||||||
|
closeDialogChild('save', data); |
||||||
|
}
|
||||||
|
|
||||||
|
setActivity('') |
||||||
|
} |
||||||
|
|
||||||
|
const renderForm = () => { |
||||||
|
return ( |
||||||
|
<Form> |
||||||
|
<Row> |
||||||
|
<Col md={6}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Name</Label> |
||||||
|
<Input type="text" value={name} onChange={(e) => setName(e.target.value)}/> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Modal size="lg" isOpen={openDialogChild} toggle={toggleDialogChild}> |
||||||
|
<ModalHeader className="capitalize" toggle={closeDialogChild}>{typeDialogChild == "Edit" ? `Edit` : "Add"} Child</ModalHeader> |
||||||
|
<ModalBody> |
||||||
|
{renderForm()} |
||||||
|
</ModalBody> |
||||||
|
<ModalFooter> |
||||||
|
<Button color="primary" onClick={() => handleSave()}>{typeDialogChild == "Edit" ? `Edit` : "Save"}</Button>{' '} |
||||||
|
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button> |
||||||
|
</ModalFooter> |
||||||
|
</Modal> |
||||||
|
</> |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
export default DialogFormChild; |
@ -0,0 +1,438 @@ |
|||||||
|
import React, { useEffect, useState } from 'react' |
||||||
|
import { |
||||||
|
Modal, ModalHeader, ModalBody, ModalFooter, |
||||||
|
Form, FormGroup, Label, Input, Col, Row |
||||||
|
} from 'reactstrap'; |
||||||
|
import { DatePicker, Table, Drawer, Divider, Tooltip, Button, Space, Progress } from 'antd'; |
||||||
|
import { |
||||||
|
CloseOutlined, |
||||||
|
MinusOutlined, |
||||||
|
PlusOutlined |
||||||
|
} from '@ant-design/icons'; |
||||||
|
import { |
||||||
|
NotificationManager |
||||||
|
} from "react-notifications"; |
||||||
|
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||||
|
import { formatRupiah, formatNumber } from '../../../const/CustomFunc' |
||||||
|
import moment from 'moment'; |
||||||
|
import Select from 'react-select'; |
||||||
|
import 'antd/dist/antd.css'; |
||||||
|
import axios from "../../../const/interceptorApi"; |
||||||
|
import { BASE_SIMPRO_LUMEN } from '../../../const/ApiConst'; |
||||||
|
// const { Option } = Select
|
||||||
|
|
||||||
|
const DialogFormReport = ({ |
||||||
|
activityProject, |
||||||
|
openDialogReport, |
||||||
|
closeDialogReport, |
||||||
|
toggleDialogActivity, |
||||||
|
typeDialogReport, |
||||||
|
proyek_id, |
||||||
|
version_gantt_id, |
||||||
|
idBoard, |
||||||
|
dataHr, |
||||||
|
dataEditCard, |
||||||
|
userToActivityDelete, |
||||||
|
userToActivityAdd |
||||||
|
}) => { |
||||||
|
const [id, setId] = useState('') |
||||||
|
const [idDelete, setIdDelete] = useState('') |
||||||
|
const [alertDelete, setAlertDelete] = useState(false) |
||||||
|
const [text, setText] = useState('') |
||||||
|
const [description, setDescription] = useState('') |
||||||
|
const [startDate, setStartDate] = useState('') |
||||||
|
const [reportDate, setReportDate] = useState('') |
||||||
|
const [progress, setProgress] = useState(0) |
||||||
|
const [volumePlan, setVolumePlan] = useState(0) |
||||||
|
const [volumeActual, setVolumeActual] = useState(0) |
||||||
|
const [nativeeditorStatus, setNativeeditorStatus] = useState('') |
||||||
|
const [hr, setHr] = useState(null); |
||||||
|
const [hrTemporary, setHrTemporary] = useState(); |
||||||
|
const [hrTemporaryAdd, setHrTemporaryAdd] = useState([]); |
||||||
|
const [IdDeleteHrTemporary, setIdDeleteHrTemporary] = useState([]); |
||||||
|
const [reportActivity, setReportActivity] = useState([]) |
||||||
|
const token = localStorage.getItem("token"); |
||||||
|
|
||||||
|
const HEADER = { |
||||||
|
headers: { |
||||||
|
"Content-Type": "application/json", |
||||||
|
Authorization: `Bearer ${token}`, |
||||||
|
}, |
||||||
|
}; |
||||||
|
useEffect(() => { |
||||||
|
|
||||||
|
setText('') |
||||||
|
setStartDate('') |
||||||
|
setProgress(0) |
||||||
|
setVolumePlan(0) |
||||||
|
setHr('') |
||||||
|
setHrTemporaryAdd([]) |
||||||
|
setHrTemporary([]) |
||||||
|
setIdDeleteHrTemporary([]) |
||||||
|
if (dataEditCard.id) { |
||||||
|
handleGetReportActivity(dataEditCard.id) |
||||||
|
} |
||||||
|
|
||||||
|
if (typeDialogReport === "Edit") { |
||||||
|
|
||||||
|
setId(dataEditCard.id) |
||||||
|
setText(dataEditCard.activity) |
||||||
|
setProgress(dataEditCard.persentase_progress) |
||||||
|
setStartDate(moment(dataEditCard.start_date)) |
||||||
|
dataEditCard.assign_hr.map((item) => { |
||||||
|
item.value = item.id_hr |
||||||
|
item.label = item.name |
||||||
|
}) |
||||||
|
setVolumePlan(dataEditCard.jumlah_pekerjaan) |
||||||
|
setHr(dataEditCard.assign_hr) |
||||||
|
setHrTemporary(dataEditCard.assign_hr) |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
setId(0) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
dataHr.map((item) => { |
||||||
|
item.value = item.id |
||||||
|
item.label = item.name |
||||||
|
}) |
||||||
|
|
||||||
|
}, [openDialogReport]) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (dataEditCard.id) { |
||||||
|
handleGetReportActivity(dataEditCard.id) |
||||||
|
} |
||||||
|
}, [idDelete]) |
||||||
|
|
||||||
|
const handleCancel = () => { |
||||||
|
closeDialogReport('cancel', 'none') |
||||||
|
} |
||||||
|
|
||||||
|
const handleReport = () => { |
||||||
|
console.log('Button Triggered') |
||||||
|
} |
||||||
|
|
||||||
|
const handleGetReportActivity = async (id) => { |
||||||
|
const payload = { |
||||||
|
columns: [ |
||||||
|
{ |
||||||
|
name: "activity_id", |
||||||
|
logic_operator: "=", |
||||||
|
value: id, |
||||||
|
operator: "AND", |
||||||
|
} |
||||||
|
], |
||||||
|
}; |
||||||
|
|
||||||
|
const result = await axios |
||||||
|
.post(`${BASE_SIMPRO_LUMEN}/report-activity/search`, payload, HEADER) |
||||||
|
.then((res) => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code == 200) { |
||||||
|
let dataRes = result.data.data || []; |
||||||
|
dataRes.map((item) => { |
||||||
|
let formattedDate = moment(item.report_date, "YYYY-MM-DD HH:mm:ssZ").format('YYYY-MM-DD'); |
||||||
|
item.report_date = formattedDate; |
||||||
|
|
||||||
|
}) |
||||||
|
setReportActivity(dataRes) |
||||||
|
} else { |
||||||
|
NotificationManager.error("Gagal Mengambil Data!!", "Failed"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const handleDeleteReport = (id) => { |
||||||
|
setIdDelete(id) |
||||||
|
setAlertDelete(true) |
||||||
|
} |
||||||
|
|
||||||
|
const cancelDelete = () => { |
||||||
|
setAlertDelete(false) |
||||||
|
} |
||||||
|
|
||||||
|
const onConfirmDelete = async () => { |
||||||
|
let url = `${BASE_SIMPRO_LUMEN}/report-activity/delete/${idDelete}`; |
||||||
|
setAlertDelete(false) |
||||||
|
const result = await axios.delete(url, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
setIdDelete('') |
||||||
|
closeDialogReport("Delete") |
||||||
|
NotificationManager.success(`Data berhasil dihapus!`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setIdDelete('') |
||||||
|
NotificationManager.error(`Data gagal dihapus!}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const handleSave = () => { |
||||||
|
let data = ''; |
||||||
|
|
||||||
|
if (!reportDate || reportDate === "") { |
||||||
|
alert("reportDate cannot be empty!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (!hr || hr === "") { |
||||||
|
alert("hr cannot be empty!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (typeDialogReport === "Save") { |
||||||
|
|
||||||
|
data = { |
||||||
|
"activity_id": dataEditCard.id, |
||||||
|
"report_date": reportDate, |
||||||
|
"jumlah_pekerjaan": volumeActual, |
||||||
|
"description": description |
||||||
|
} |
||||||
|
setReportDate(''); |
||||||
|
setVolumeActual(0); |
||||||
|
setHr(null); |
||||||
|
setDescription(''); |
||||||
|
closeDialogReport('Save', data, hr); |
||||||
|
handleCancel() |
||||||
|
} else if (typeDialogReport === "Edit") { |
||||||
|
|
||||||
|
hrTemporaryAdd.map((item) => { |
||||||
|
let dataSaveHr = { |
||||||
|
"user_id": item.id, |
||||||
|
"role_proyek_id": item.proyek_role, |
||||||
|
"version_gantt_id": version_gantt_id, |
||||||
|
"proyek_id": proyek_id, |
||||||
|
"activity_id": id |
||||||
|
} |
||||||
|
userToActivityAdd(dataSaveHr) |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
IdDeleteHrTemporary.map((item) => { |
||||||
|
|
||||||
|
userToActivityDelete(item) |
||||||
|
|
||||||
|
}) |
||||||
|
|
||||||
|
setHrTemporaryAdd([]) |
||||||
|
setIdDeleteHrTemporary([]) |
||||||
|
setHrTemporary([]) |
||||||
|
|
||||||
|
progress == 100 ? |
||||||
|
data = { |
||||||
|
"text": text, |
||||||
|
"start_date": startDate, |
||||||
|
"jumlah_pekerjaan": volumePlan, |
||||||
|
"proyek_id": proyek_id, |
||||||
|
"version_gantt_id": version_gantt_id, |
||||||
|
"board_id": idBoard |
||||||
|
} |
||||||
|
: |
||||||
|
data = { |
||||||
|
"text": text, |
||||||
|
"start_date": startDate, |
||||||
|
"jumlah_pekerjaan": volumePlan, |
||||||
|
"proyek_id": proyek_id, |
||||||
|
"version_gantt_id": version_gantt_id, |
||||||
|
"board_id": idBoard |
||||||
|
} |
||||||
|
|
||||||
|
closeDialogReport('edit', data, hr, id); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const onChangeHr = (newValue, actionMeta) => { |
||||||
|
if (typeDialogReport === "Edit") { |
||||||
|
if (actionMeta.action === 'select-option') { |
||||||
|
const item = actionMeta.option |
||||||
|
// console.log("actionMeta", item);
|
||||||
|
// let dataSaveHr = {
|
||||||
|
// "user_id": item.id,
|
||||||
|
// "role_proyek_id": item.proyek_role,
|
||||||
|
// "version_gantt_id": version_gantt_id,
|
||||||
|
// "proyek_id": proyek_id,
|
||||||
|
// "activity_id": id
|
||||||
|
// }
|
||||||
|
// userToActivityAdd(dataSaveHr)
|
||||||
|
setHrTemporaryAdd([...hrTemporaryAdd, item]) |
||||||
|
} else if (actionMeta.action === 'remove-value') { |
||||||
|
const id = actionMeta.removedValue.id |
||||||
|
// userToActivityDelete(id)
|
||||||
|
for (let k in hrTemporary) { |
||||||
|
if (hrTemporary[k].id == id) { |
||||||
|
setIdDeleteHrTemporary([...IdDeleteHrTemporary, id]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
setHr(newValue) |
||||||
|
}; |
||||||
|
|
||||||
|
const increase = () => { |
||||||
|
let newPercent = progress + 10; |
||||||
|
if (newPercent > 100) { |
||||||
|
newPercent = 100; |
||||||
|
} |
||||||
|
setProgress(newPercent); |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
const decline = () => { |
||||||
|
let newPercent = progress - 10; |
||||||
|
if (newPercent < 0) { |
||||||
|
newPercent = 0; |
||||||
|
} |
||||||
|
setProgress(newPercent); |
||||||
|
}; |
||||||
|
|
||||||
|
const columns = [ |
||||||
|
{ |
||||||
|
title: 'Created By', |
||||||
|
dataIndex: 'created_by', |
||||||
|
key: 'created_by', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Report Date', |
||||||
|
dataIndex: 'report_date', |
||||||
|
key: 'report_date', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Actual', |
||||||
|
dataIndex: 'job_count_report', |
||||||
|
key: 'job_count_report', |
||||||
|
render: (text) => Math.round(text), |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Action', |
||||||
|
dataIndex: 'id', |
||||||
|
key: 'actions', |
||||||
|
render: (id) => ( |
||||||
|
<Tooltip title="Delete Report" placement="top"> |
||||||
|
<Button onClick={() => handleDeleteReport(id)} type="danger" style={{ backgroundColor:'transparent', color:'red', border:'none' }}> |
||||||
|
<i class="nav-icon icon-trash"></i> |
||||||
|
</Button> |
||||||
|
</Tooltip> |
||||||
|
), |
||||||
|
}, |
||||||
|
]; |
||||||
|
|
||||||
|
const renderForm = () => { |
||||||
|
return ( |
||||||
|
<Form> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Report Date</Label> |
||||||
|
<DatePicker style={{ width: "100%" }} value={reportDate} onChange={(dateItem, dateString) => { |
||||||
|
dateItem.set({ hour: 0, minute: 0, second: 0 }) |
||||||
|
setReportDate(dateItem) |
||||||
|
}} |
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
{/* <Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Duration</Label> |
||||||
|
<Input type="number" value={duration} onChange={(e) => setDuration(e.target.value)}/> |
||||||
|
</FormGroup> |
||||||
|
</Col> */} |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Volume Actual</Label> |
||||||
|
<Input type="number" value={volumeActual} onChange={(e) => setVolumeActual(e.target.value)} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Human Resource</Label> |
||||||
|
{/* <Select |
||||||
|
showSearch |
||||||
|
filterOption={(inputValue, option) => |
||||||
|
option.children.toLowerCase().includes(inputValue.toLowerCase()) |
||||||
|
} |
||||||
|
value={hr} |
||||||
|
defaultValue={hr} |
||||||
|
onChange={onChangeHr} |
||||||
|
style={{ width: "100%" }} |
||||||
|
> |
||||||
|
{dataHr.map((res) => ( |
||||||
|
<Option key={res.id} value={res.id}> |
||||||
|
{res.name} |
||||||
|
</Option> |
||||||
|
))} |
||||||
|
</Select> */} |
||||||
|
<Select |
||||||
|
value={hr} |
||||||
|
defaultValue={hr} |
||||||
|
isClearable={false} |
||||||
|
name="colors" |
||||||
|
options={dataHr} |
||||||
|
className="basic-multi-select" |
||||||
|
classNamePrefix="select" |
||||||
|
onChange={onChangeHr} |
||||||
|
/> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<Col md={12}> |
||||||
|
<FormGroup> |
||||||
|
<Label className="capitalize">Description</Label> |
||||||
|
<Input type="textarea" value={description} onChange={(e) => setDescription(e.target.value)} /> |
||||||
|
</FormGroup> |
||||||
|
</Col> |
||||||
|
<div> |
||||||
|
{reportActivity.length > 0 ? ( |
||||||
|
<Table dataSource={reportActivity} columns={columns} /> |
||||||
|
) : null} |
||||||
|
</div> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Drawer title="Basic Drawer" placement="right" onClose={() => handleCancel()} open={openDialogReport}> |
||||||
|
<SweetAlert |
||||||
|
show={alertDelete} |
||||||
|
warning |
||||||
|
showCancel |
||||||
|
confirmBtnText="Delete" |
||||||
|
confirmBtnBsStyle="danger" |
||||||
|
title={`Are you sure?`} |
||||||
|
onConfirm={onConfirmDelete} |
||||||
|
onCancel={() => cancelDelete()} |
||||||
|
focusCancelBtn |
||||||
|
> |
||||||
|
Delete this data |
||||||
|
</SweetAlert> |
||||||
|
<div className='top'> |
||||||
|
<Space> |
||||||
|
<Button type='text' onClick={() => handleCancel()}><CloseOutlined /></Button> |
||||||
|
</Space> |
||||||
|
<Space style={{ float: "right" }}> |
||||||
|
<Button onClick={() => handleCancel()}>Cancel</Button> |
||||||
|
<Button onClick={() => handleSave()} type="primary"> |
||||||
|
{typeDialogReport == "Edit" ? `Edit` : "Add"} Report |
||||||
|
</Button> |
||||||
|
</Space> |
||||||
|
<Divider /> |
||||||
|
</div> |
||||||
|
<div className='content' style={{ alignContent: 'center' }}> |
||||||
|
{renderForm()} |
||||||
|
</div> |
||||||
|
<div className='bottom' style={{ float: 'bottom' }}> |
||||||
|
</div> |
||||||
|
</Drawer> |
||||||
|
</> |
||||||
|
) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
export default DialogFormReport; |
@ -0,0 +1,136 @@ |
|||||||
|
.App { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.App-header { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
font-size: calc(10px + 1.5vmin); |
||||||
|
} |
||||||
|
|
||||||
|
.App-link { |
||||||
|
color: #61dafb; |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes App-logo-spin { |
||||||
|
from { |
||||||
|
transform: rotate(0deg); |
||||||
|
} |
||||||
|
to { |
||||||
|
transform: rotate(360deg); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.characters { |
||||||
|
list-style: none; |
||||||
|
padding-left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.characters li { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
border: solid 2px #d0d0d0; |
||||||
|
border-radius: .2em; |
||||||
|
padding: .5em .8em .5em .5em; |
||||||
|
margin-bottom: 1em; |
||||||
|
} |
||||||
|
|
||||||
|
/* .characters p { |
||||||
|
max-width: none; |
||||||
|
font-weight: bold; |
||||||
|
margin: 0; |
||||||
|
} */ |
||||||
|
|
||||||
|
.characters-thumb { |
||||||
|
overflow: hidden; |
||||||
|
flex-shrink: 0; |
||||||
|
width: 2em; |
||||||
|
height: 2em; |
||||||
|
background-color: #e8e8e8; |
||||||
|
padding: .5em; |
||||||
|
margin-right: .5em; |
||||||
|
} |
||||||
|
|
||||||
|
.characters-thumb img { |
||||||
|
display: block; |
||||||
|
width: 100%; |
||||||
|
height: auto; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/* body */ |
||||||
|
.body { |
||||||
|
background-color: #f4f4f4; |
||||||
|
border-radius: 10px; |
||||||
|
padding: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
.board { |
||||||
|
width: 19rem; |
||||||
|
height: 3rem; |
||||||
|
padding: 5px; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 8px; |
||||||
|
/* border: 0.5px solid silver; */ |
||||||
|
text-align: left; |
||||||
|
} |
||||||
|
|
||||||
|
.board-add{ |
||||||
|
width: 15rem; |
||||||
|
height: 3rem; |
||||||
|
padding: 5px; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 8px; |
||||||
|
/* border: 0.5px solid silver; */ |
||||||
|
text-align: left; |
||||||
|
cursor: pointer; |
||||||
|
background-color: #f4f4f4; |
||||||
|
} |
||||||
|
|
||||||
|
.board-add:hover { |
||||||
|
background-color: rgb(255, 255, 255); |
||||||
|
} |
||||||
|
|
||||||
|
.title-board-add { |
||||||
|
font-weight: normal; |
||||||
|
margin-top: 5px; |
||||||
|
margin-left: 10px; |
||||||
|
/* font-size: 20px; */ |
||||||
|
color: silver; |
||||||
|
} |
||||||
|
|
||||||
|
.title-board { |
||||||
|
font-weight: normal; |
||||||
|
margin-top: 5px; |
||||||
|
margin-left: 10px; |
||||||
|
/* font-size: 20px; */ |
||||||
|
/* color: rgb(81, 80, 80); */ |
||||||
|
} |
||||||
|
|
||||||
|
.board .title-option { |
||||||
|
float: right; |
||||||
|
} |
||||||
|
|
||||||
|
.board { |
||||||
|
border-radius: 8px; |
||||||
|
height: 3rem; |
||||||
|
width: 270px; |
||||||
|
} |
||||||
|
|
||||||
|
.cards { |
||||||
|
margin-bottom: 10px; |
||||||
|
border-radius: 8px; |
||||||
|
} |
||||||
|
/* border-top: 5px solid #65D3B3; */ |
||||||
|
|
||||||
|
.add-card { |
||||||
|
color: #f4f4f4; |
||||||
|
cursor: pointer; |
||||||
|
/* visibility: hidden; */ |
||||||
|
} |
||||||
|
|
||||||
|
.destination:hover .add-card{ |
||||||
|
color: silver; |
||||||
|
} |
@ -0,0 +1,206 @@ |
|||||||
|
import React, {Fragment, useState} from 'react' |
||||||
|
import './Kanban.css'; |
||||||
|
import { Draggable, DragDropContext, Droppable } from 'react-beautiful-dnd'; |
||||||
|
import styled from 'styled-components' |
||||||
|
import moment from 'moment'; |
||||||
|
import DialogCard from './DialogCard'; |
||||||
|
import { Card, Row, Col, Button, Avatar, Tooltip, Popover, Progress, Dropdown, Menu, Space } from 'antd'; |
||||||
|
import {
|
||||||
|
AntDesignOutlined, |
||||||
|
UserOutlined, |
||||||
|
EditOutlined, |
||||||
|
DeleteOutlined, |
||||||
|
EllipsisOutlined, |
||||||
|
DownOutlined, |
||||||
|
MoreOutlined, |
||||||
|
SmileOutlined |
||||||
|
} from '@ant-design/icons'; |
||||||
|
|
||||||
|
const Container = styled.div` |
||||||
|
border: 1px solid lightgrey; |
||||||
|
border-radius: 2px; |
||||||
|
padding: 8px; |
||||||
|
margin-bottom: 8px; |
||||||
|
transition: background-color 0.2s ease; |
||||||
|
background-color: ${props => |
||||||
|
props.isDragDisabled |
||||||
|
? 'lightgrey' |
||||||
|
: props.isDragging |
||||||
|
? 'lightgreen' |
||||||
|
: 'white'}; |
||||||
|
` |
||||||
|
|
||||||
|
const gridStyle = { |
||||||
|
// width: '25%',
|
||||||
|
// textAlign: 'center',
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
const Task = ({
|
||||||
|
task,
|
||||||
|
index,
|
||||||
|
stateKanban,
|
||||||
|
bodyColor,
|
||||||
|
loadingCard,
|
||||||
|
handleDeleteCard,
|
||||||
|
handleEditCard |
||||||
|
}) => { |
||||||
|
// const Task = ({ task, index, children, stateKanban , handleOpenDialogChild , handleDelete}) => {
|
||||||
|
const isDragDisabled = false |
||||||
|
|
||||||
|
const [openDialogChild, setOpenDialogChild] = useState(false) |
||||||
|
const [typeDialogChild, setTypeDialogChild] = useState('Save') |
||||||
|
const [clickOpenModalChild, setClickOpenModalChild] = useState(false) |
||||||
|
|
||||||
|
|
||||||
|
function onDragEnd(result) { |
||||||
|
const { destination, source, draggableId } = result |
||||||
|
|
||||||
|
|
||||||
|
if (!destination) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if ( |
||||||
|
destination.droppableId === source.droppableId && |
||||||
|
destination.index === source.index |
||||||
|
) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
const start = source.droppableId; |
||||||
|
const finish = destination.droppableId; |
||||||
|
|
||||||
|
if (start === finish) { |
||||||
|
const newTaskIds = stateKanban.columns[0].tasks[0].children; |
||||||
|
let newObj = stateKanban.columns[0].tasks[0].children.find(x => x.id === draggableId); |
||||||
|
newTaskIds.splice(source.index, 1) |
||||||
|
newTaskIds.splice(destination.index, 0, newObj) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const handleCloseDialogChild = (type, data) => { |
||||||
|
if (type === "save") { |
||||||
|
// saveItem(data);
|
||||||
|
}
|
||||||
|
setOpenDialogChild(false) |
||||||
|
} |
||||||
|
|
||||||
|
const toggleAddDialogChild = () => { |
||||||
|
setOpenDialogChild(!openDialogChild) |
||||||
|
} |
||||||
|
|
||||||
|
const handleOpenDialogChild = (type) => { |
||||||
|
setOpenDialogChild(true) |
||||||
|
setTypeDialogChild(type) |
||||||
|
} |
||||||
|
|
||||||
|
const menu = (task) => ( |
||||||
|
<Menu |
||||||
|
items={[ |
||||||
|
{ |
||||||
|
key: '1', |
||||||
|
label: ( |
||||||
|
<a rel="noopener noreferrer" onClick={()=>handleEditCard(task)}> |
||||||
|
<EditOutlined style={{marginRight: "5px"}} /> Edit |
||||||
|
</a> |
||||||
|
), |
||||||
|
}, |
||||||
|
{ |
||||||
|
key: '2', |
||||||
|
label: ( |
||||||
|
<a rel="noopener noreferrer" onClick={()=> handleDeleteCard(task.id)}> |
||||||
|
<DeleteOutlined style={{marginRight: "5px"}} /> Hapus |
||||||
|
</a> |
||||||
|
), |
||||||
|
}, |
||||||
|
]} |
||||||
|
/> |
||||||
|
); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<Fragment> |
||||||
|
<DialogCard |
||||||
|
openDialogChild={openDialogChild} |
||||||
|
closeDialogChild={handleCloseDialogChild} |
||||||
|
toggleDialogChild={() => toggleAddDialogChild} |
||||||
|
typeDialogChild={typeDialogChild} |
||||||
|
clickOpenModalChild={clickOpenModalChild} |
||||||
|
task={task}
|
||||||
|
/> |
||||||
|
<Draggable |
||||||
|
draggableId={task.id} |
||||||
|
index={index} |
||||||
|
isDragDisabled={isDragDisabled} |
||||||
|
> |
||||||
|
{(provided, snapshot) => ( |
||||||
|
<Card
|
||||||
|
className='cards' |
||||||
|
{...provided.draggableProps} |
||||||
|
{...provided.dragHandleProps} |
||||||
|
ref={provided.innerRef} |
||||||
|
isDragging={snapshot.isDragging} |
||||||
|
isDragDisabled={isDragDisabled} |
||||||
|
loading={loadingCard} |
||||||
|
onDoubleClick={()=> handleEditCard(task)} |
||||||
|
> |
||||||
|
<div className='contents' > |
||||||
|
<div style={{float: 'right'}}> |
||||||
|
<Dropdown overlay={menu(task)}> |
||||||
|
<a onClick={(e) => e.preventDefault()}> |
||||||
|
<MoreOutlined style={{fontSize:"20px"}} /> |
||||||
|
</a> |
||||||
|
</Dropdown> |
||||||
|
</div> |
||||||
|
<div><b>{task.activity}</b></div> |
||||||
|
</div> |
||||||
|
<div className='status' style={{marginTop: "15px"}}> |
||||||
|
<Progress percent={Math.round(task.persentase_progress)} /> |
||||||
|
</div> |
||||||
|
<div style={{marginTop: "20px"}}> |
||||||
|
<div style={{float: 'left'}}> |
||||||
|
<Avatar.Group> |
||||||
|
{ |
||||||
|
task.assign_hr.map( (item, index) => { |
||||||
|
if (index < 8) { |
||||||
|
return <Tooltip title={item.name} placement="top"> |
||||||
|
<Avatar |
||||||
|
style={{ |
||||||
|
backgroundColor: '#87d', |
||||||
|
}} |
||||||
|
icon={<UserOutlined />} size="small" |
||||||
|
/> |
||||||
|
</Tooltip> |
||||||
|
} else if(index == 8) { |
||||||
|
return <Avatar |
||||||
|
style={{ |
||||||
|
backgroundColor: '#f56a00', |
||||||
|
}} |
||||||
|
size="small"> |
||||||
|
{/* + {["1","1","1","1","1","1","1","1"].length - 3} */} |
||||||
|
+ {task.assign_hr.length - 8} |
||||||
|
</Avatar> |
||||||
|
} |
||||||
|
|
||||||
|
}) |
||||||
|
}
|
||||||
|
</Avatar.Group> |
||||||
|
</div> |
||||||
|
<div style={{float: 'right'}}> |
||||||
|
<p style={{color: "grey", fontSize: "12px", marginTop: "3px"}}>{moment(task.start_date).format('DD-MM-YYYY HH:mm')}</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</Card> |
||||||
|
)} |
||||||
|
</Draggable> |
||||||
|
</Fragment> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default Task; |
@ -0,0 +1,912 @@ |
|||||||
|
import React, { Fragment, useEffect, useMemo, useState } from 'react'; |
||||||
|
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; |
||||||
|
import { |
||||||
|
Row, |
||||||
|
Col, |
||||||
|
Button, |
||||||
|
Tooltip, |
||||||
|
Popover, |
||||||
|
Select |
||||||
|
} from 'antd'; |
||||||
|
import { Card, CardBody, CardHeader, Input } from "reactstrap"; |
||||||
|
|
||||||
|
import './Kanban.css'; |
||||||
|
import Column from './Column'; |
||||||
|
import styled from 'styled-components' |
||||||
|
import { |
||||||
|
PlusOutlined |
||||||
|
} from '@ant-design/icons'; |
||||||
|
import { BASE_SIMPRO_LUMEN, VERSION_GANTT_SEARCH, KANBAN_BOARD_LIST, KANBAN_BOARD_ADD, KANBAN_BOARD_DELETE, KANBAN_BOARD_EDIT, KANBAN_CARD_LIST, KANBAN_CARD_ADD, KANBAN_CARD_EDIT, USER_TO_ACTIVITY_ADD, HUMAN_RESOURCE_LIST, USER_TO_ACTIVITY_DELETE, PROYEK_SEARCH } from '../../../const/ApiConst'; |
||||||
|
import axios from "../../../const/interceptorApi"; |
||||||
|
import { |
||||||
|
NotificationContainer, |
||||||
|
NotificationManager |
||||||
|
} from "react-notifications"; |
||||||
|
import { array } from 'prop-types'; |
||||||
|
import DialogFormBoard from './DialogFormBoard'; |
||||||
|
import DialogFormActivity from './DialogFormActivity'; |
||||||
|
import DialogFormChild from './DialogFormChild'; |
||||||
|
import DialogFormReport from './DialogFormReport'; |
||||||
|
import SweetAlert from 'react-bootstrap-sweetalert'; |
||||||
|
import { useParams, useHistory } from "react-router-dom"; |
||||||
|
import moment from 'moment'; |
||||||
|
const Container = styled.div` |
||||||
|
display: flex; |
||||||
|
` |
||||||
|
|
||||||
|
const { Option } = Select; |
||||||
|
|
||||||
|
const finalSpaceCharacters = [ |
||||||
|
{ |
||||||
|
id: 'gary', |
||||||
|
name: 'Gary Goodspeed', |
||||||
|
thumb: '/images/gary.png' |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 'garyd', |
||||||
|
name: 'Gary Goodspeedg', |
||||||
|
thumb: '/images/gary.png' |
||||||
|
}, |
||||||
|
] |
||||||
|
|
||||||
|
const initialData = { |
||||||
|
columns: [ |
||||||
|
|
||||||
|
], |
||||||
|
} |
||||||
|
|
||||||
|
let hierarchy = []; |
||||||
|
hierarchy.push(JSON.parse(localStorage.getItem("hierarchy"))); |
||||||
|
const role_id = localStorage.getItem("role_id"); |
||||||
|
|
||||||
|
const Kanban = ({ params, ...props }) => { |
||||||
|
let history = useHistory(); |
||||||
|
const token = localStorage.getItem("token"); |
||||||
|
const sessionLogin = localStorage.getItem("user_id"); |
||||||
|
|
||||||
|
const HEADER = { |
||||||
|
headers: { |
||||||
|
"Content-Type": "application/json", |
||||||
|
Authorization: `Bearer ${token}`, |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
const { proyek_id, version_gantt_id } = useParams(); |
||||||
|
const [characters, updateCharacters] = useState(finalSpaceCharacters); |
||||||
|
const [stateKanban, setStateKanban] = useState(initialData); |
||||||
|
const [kanbanBoard, setKanbanBoard] = useState([]); |
||||||
|
const [kanbanCard, setKanbanCard] = useState([]); |
||||||
|
const [alertDelete, setAlertDelete] = useState(false) |
||||||
|
const [alertDeleteCard, setAlertDeleteCard] = useState(false) |
||||||
|
const [idDelete, setIdDelete] = useState(0) |
||||||
|
const [idDeleteCard, setIdDeleteCard] = useState(0) |
||||||
|
const [project, setProject] = useState(!proyek_id ? '' : proyek_id) |
||||||
|
const [versionGantt, setVersionGantt] = useState(!version_gantt_id ? 0 : version_gantt_id) |
||||||
|
//
|
||||||
|
const [openDialogBoard, setOpenDialogBoard] = useState(false) |
||||||
|
const [typeDialogBoard, setTypeDialogBoard] = useState('') |
||||||
|
const [clickOpenModalBoard, setClickOpenModalBoard] = useState(false) |
||||||
|
const [openDialogActivity, setOpenDialogActivity] = useState(false) |
||||||
|
const [openDialogReport, setOpenDialogReport] = useState(false) |
||||||
|
const [typeDialogActivity, setTypeDialogActivity] = useState('Save') |
||||||
|
// report
|
||||||
|
|
||||||
|
const [typeDialogReport, setTypeDialogReport] = useState('Save') |
||||||
|
const [clickOpenModalActivity, setClickOpenModalActivity] = useState(false) |
||||||
|
const [openDialogChild, setOpenDialogChild] = useState(false) |
||||||
|
const [typeDialogChild, setTypeDialogChild] = useState('Save') |
||||||
|
const [clickOpenModalChild, setClickOpenModalChild] = useState(false) |
||||||
|
const [open, setOpen] = useState(false); |
||||||
|
const [dataEditBoard, setDataEditBoard] = useState([]) |
||||||
|
const [dataEditCard, setDataEditCard] = useState([]) |
||||||
|
const [idBoard, setIdBoard] = useState(0) |
||||||
|
const [loadingCard, setLoadingCard] = useState(false) |
||||||
|
const [dataHr, setDataHr] = useState([]); |
||||||
|
const [dataProyek, setDataProyek] = useState([]) |
||||||
|
const [dataVersionGantt, setDataVersionGantt] = useState([]) |
||||||
|
const [optionProyek, setOptionProyek] = useState([]) |
||||||
|
const [optionGantt, setOptionGantt] = useState([]) |
||||||
|
const [activityProject, setActivityProject] = useState(null) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
handleGetDataHr() |
||||||
|
}, [project]) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
getDataProyek() |
||||||
|
if (project && versionGantt) { |
||||||
|
getDataGantt(parseInt(project)) |
||||||
|
getActivityProject() |
||||||
|
getDataKanbanBoard() |
||||||
|
} |
||||||
|
}, [project, versionGantt]) |
||||||
|
|
||||||
|
const getActivityProject = async () => { |
||||||
|
const url = `${BASE_SIMPRO_LUMEN}/activity/${versionGantt}/${project}/get` |
||||||
|
const result = await axios |
||||||
|
.get(url, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response) |
||||||
|
|
||||||
|
if (result && result.data.data.length > 0) { |
||||||
|
result.data.data.map((item) => { |
||||||
|
if (item.type_activity == "project") { |
||||||
|
setActivityProject(item.id) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getDataKanbanBoard = async () => { |
||||||
|
const url = `${KANBAN_BOARD_LIST}?start=0&length=-1&orderby=id&asc=true&column=version_gantt_id&value=${versionGantt}&logic==`; |
||||||
|
const result = await axios |
||||||
|
.get(url, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (!result || result.data.data.length == 0) { |
||||||
|
|
||||||
|
const data = [ |
||||||
|
{ |
||||||
|
name_board: 'TODO LIST', |
||||||
|
status_progress: 'open', |
||||||
|
header_color: "#9EE5FF", |
||||||
|
body_color: "#112A46", |
||||||
|
proyek_id: project, |
||||||
|
version_gantt_id: versionGantt |
||||||
|
}, |
||||||
|
{ |
||||||
|
name_board: 'DOING', |
||||||
|
status_progress: 'on-progress', |
||||||
|
header_color: "#D9D4FD", |
||||||
|
body_color: "#112A46", |
||||||
|
proyek_id: project, |
||||||
|
version_gantt_id: versionGantt |
||||||
|
}, |
||||||
|
{ |
||||||
|
name_board: 'TESTING', |
||||||
|
status_progress: 'none', |
||||||
|
header_color: "#FAD4FC", |
||||||
|
body_color: "#112A46", |
||||||
|
proyek_id: project, |
||||||
|
version_gantt_id: versionGantt |
||||||
|
}, |
||||||
|
{ |
||||||
|
name_board: 'DONE', |
||||||
|
status_progress: 'done', |
||||||
|
header_color: "#ADE7BF", |
||||||
|
body_color: "#112A46", |
||||||
|
proyek_id: project, |
||||||
|
version_gantt_id: versionGantt |
||||||
|
} |
||||||
|
]; |
||||||
|
for (let i = 0; i < data.length; i++) { |
||||||
|
const formData = data[i]; |
||||||
|
const result = await axios.post(KANBAN_BOARD_ADD, formData, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataKanbanBoard() |
||||||
|
NotificationManager.success(`Data berhasil ditambah`, 'Success!!'); |
||||||
|
} else { |
||||||
|
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (result && result.data && result.data.code == 200) { |
||||||
|
let countColumns = 0; |
||||||
|
const results = result.data.data; |
||||||
|
for (let i = results.length - 1; i >= 0; i--) { |
||||||
|
const res = results[i]; |
||||||
|
res.key = res.id.toString() |
||||||
|
res.tasks = [] |
||||||
|
await getDataKanbanCard(res.id).then(function (task) { |
||||||
|
if (task !== false) { |
||||||
|
task.map((e) => { |
||||||
|
e.id = e.id.toString() |
||||||
|
e.persentase_progress = e.persentase_progress ? e.persentase_progress : 0; |
||||||
|
res.tasks.push(e); |
||||||
|
}); |
||||||
|
} |
||||||
|
}) |
||||||
|
countColumns += 1; |
||||||
|
|
||||||
|
if (result.data.data.length === countColumns) { |
||||||
|
let newState = { |
||||||
|
...stateKanban, |
||||||
|
columns: [ |
||||||
|
...result.data.data, |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
|
setStateKanban(newState) |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
setLoadingCard(false) |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
} else { |
||||||
|
NotificationManager.error('Gagal Mengambil Data!!', 'Failed'); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const getDataProyek = async () => { |
||||||
|
let start = 0; |
||||||
|
|
||||||
|
const payload = { |
||||||
|
columns: [ |
||||||
|
{ |
||||||
|
name: "created_by", |
||||||
|
logic_operator: "IN", |
||||||
|
value: hierarchy, |
||||||
|
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: false }, |
||||||
|
}; |
||||||
|
|
||||||
|
if (parseInt(role_id) !== 1) { |
||||||
|
payload["columns"] = [ |
||||||
|
{ name: "id", logic_operator: "=", value: project, 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 dataRes = result.data.data || []; |
||||||
|
let dataTemp = [] |
||||||
|
dataRes.map(n => { |
||||||
|
if (n.id > 0 && n.nama.trim() !== "") { |
||||||
|
let obj = { |
||||||
|
key: n.id, |
||||||
|
value: n.id, |
||||||
|
label: n.nama.trim() |
||||||
|
} |
||||||
|
dataTemp.push(obj) |
||||||
|
} |
||||||
|
}) |
||||||
|
setOptionProyek(dataTemp); |
||||||
|
setDataProyek(dataRes); |
||||||
|
} else { |
||||||
|
NotificationManager.error("Gagal Mengambil Data!!", "Failed"); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const getDataGantt = async (id) => { |
||||||
|
const payload = { |
||||||
|
columns: [ |
||||||
|
{ |
||||||
|
name: "proyek_id", |
||||||
|
logic_operator: "=", |
||||||
|
value: id, |
||||||
|
operator: "AND", |
||||||
|
}, |
||||||
|
], |
||||||
|
}; |
||||||
|
const result = await axios |
||||||
|
.post(VERSION_GANTT_SEARCH, payload, HEADER) |
||||||
|
.then((res) => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.status == 200) { |
||||||
|
let dataRes = result.data.data || []; |
||||||
|
let dataTemp = [] |
||||||
|
dataRes.map(n => { |
||||||
|
if (n.id > 0 && n.name_version.trim() !== "") { |
||||||
|
let obj = { |
||||||
|
key: n.id, |
||||||
|
value: n.id, |
||||||
|
label: n.name_version |
||||||
|
} |
||||||
|
dataTemp.push(obj) |
||||||
|
} |
||||||
|
}) |
||||||
|
setOptionGantt(dataTemp); |
||||||
|
setDataVersionGantt(dataRes); |
||||||
|
|
||||||
|
} else { |
||||||
|
NotificationManager.error( |
||||||
|
`Data gantt project gagal terload silahkan coba lagi!`, |
||||||
|
"Failed!!" |
||||||
|
); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const getDataKanbanCard = async (id) => { |
||||||
|
const url = `${KANBAN_CARD_LIST}/${project}/${versionGantt}/${id}?session=${sessionLogin}`; |
||||||
|
const result = await axios |
||||||
|
.get(url, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
|
||||||
|
if (result.data.status === "empty") { |
||||||
|
return false |
||||||
|
} else { |
||||||
|
return result.data.data |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function handleOnDragEnd(result) { |
||||||
|
if (!result.destination) return; |
||||||
|
|
||||||
|
const items = Array.from(characters); |
||||||
|
const [reorderedItem] = items.splice(result.source.index, 1); |
||||||
|
items.splice(result.destination.index, 0, reorderedItem); |
||||||
|
|
||||||
|
updateCharacters(items); |
||||||
|
} |
||||||
|
|
||||||
|
const onChangeProject = (val) => { |
||||||
|
setProject(val); |
||||||
|
getDataGantt(val); |
||||||
|
setVersionGantt(''); |
||||||
|
}; |
||||||
|
|
||||||
|
const onChangeGantt = async (val) => { |
||||||
|
setVersionGantt(val); |
||||||
|
if (project) { |
||||||
|
history.push(`/kanban/${project}/${val}`); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
function onDragEnd(result) { |
||||||
|
const { destination, source, draggableId } = result |
||||||
|
|
||||||
|
|
||||||
|
if (!destination) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if ( |
||||||
|
destination.droppableId === source.droppableId && |
||||||
|
destination.index === source.index |
||||||
|
) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const start = source.droppableId; |
||||||
|
const finish = destination.droppableId; |
||||||
|
|
||||||
|
if (start != finish) { |
||||||
|
|
||||||
|
const data = { |
||||||
|
"kanban_board_id": destination.droppableId, |
||||||
|
} |
||||||
|
|
||||||
|
setLoadingCard(true) |
||||||
|
|
||||||
|
editActivity(data, draggableId) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const saveBoard = async (data) => { |
||||||
|
const formData = data |
||||||
|
|
||||||
|
const result = await axios.post(KANBAN_BOARD_ADD, formData, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
NotificationManager.success(`Data berhasil ditambah`, 'Success!!'); |
||||||
|
getDataKanbanBoard() |
||||||
|
} else { |
||||||
|
NotificationManager.error('Status Open Progress Done Hanya 1', 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const editBoard = async (data) => { |
||||||
|
let urlEdit = KANBAN_BOARD_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) { |
||||||
|
getDataKanbanBoard() |
||||||
|
NotificationManager.success(`Data berhasil diedit`, 'Success!!'); |
||||||
|
} else { |
||||||
|
NotificationManager.error(`Data gagal di edit`, `Failed!!`); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Board
|
||||||
|
|
||||||
|
const handleCloseDialogBoard = (type, data) => { |
||||||
|
if (type === "save") { |
||||||
|
saveBoard(data); |
||||||
|
} else if (type === "edit") { |
||||||
|
editBoard(data); |
||||||
|
} |
||||||
|
setOpenDialogBoard(false) |
||||||
|
} |
||||||
|
|
||||||
|
const toggleDialogBoard = () => { |
||||||
|
setOpenDialogBoard(!openDialogBoard) |
||||||
|
} |
||||||
|
|
||||||
|
const handleOpenDialogBoard = (type) => { |
||||||
|
setOpenDialogBoard(true) |
||||||
|
setTypeDialogBoard(type) |
||||||
|
} |
||||||
|
|
||||||
|
const saveReport = async (data, dataHrSelect) => { |
||||||
|
setLoadingCard(true) |
||||||
|
var formData = new FormData(); |
||||||
|
formData.set('report_date', moment(data.report_date).format("YYYY-MM-DD")); |
||||||
|
formData.set('job_count_report', data.jumlah_pekerjaan); |
||||||
|
formData.set('user_id', dataHrSelect.id); |
||||||
|
formData.set('gantt', true); |
||||||
|
formData.set('activity_id', data.activity_id); |
||||||
|
formData.set('description', data.description); |
||||||
|
const result = await axios |
||||||
|
.post(`${BASE_SIMPRO_LUMEN}/report-activity/add`, formData, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataKanbanBoard() |
||||||
|
NotificationManager.success(`Data berhasil ditambah`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setLoadingCard(false) |
||||||
|
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const saveCard = async (data, dataHrSelect) => { |
||||||
|
setLoadingCard(true) |
||||||
|
|
||||||
|
const formData = data |
||||||
|
const result = await axios.post(KANBAN_CARD_ADD, formData, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
dataHrSelect.map((item) => { |
||||||
|
let dataSaveHr = { |
||||||
|
"user_id": item.id, |
||||||
|
"role_proyek_id": item.proyek_role, |
||||||
|
"version_gantt_id": version_gantt_id, |
||||||
|
"proyek_id": proyek_id, |
||||||
|
"activity_id": result.data.tid |
||||||
|
} |
||||||
|
userToActivityAdd(dataSaveHr) |
||||||
|
}) |
||||||
|
NotificationManager.success(`Data berhasil ditambah`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setLoadingCard(false) |
||||||
|
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const editCard = async (data, id) => { |
||||||
|
setLoadingCard(true) |
||||||
|
const url = `${KANBAN_CARD_ADD}/${id}` |
||||||
|
const formData = data |
||||||
|
const result = await axios.put(url, formData, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataKanbanBoard() |
||||||
|
NotificationManager.success(`Data berhasil diubah`, 'Success!!'); |
||||||
|
} else { |
||||||
|
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const userToActivityAdd = async (data) => { |
||||||
|
setLoadingCard(true) |
||||||
|
|
||||||
|
const formData = data |
||||||
|
const result = await axios.post(USER_TO_ACTIVITY_ADD, formData, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataKanbanBoard() |
||||||
|
NotificationManager.success(`Data berhasil ditambah`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setLoadingCard(false) |
||||||
|
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const userToActivityDelete = async (id) => { |
||||||
|
setLoadingCard(true) |
||||||
|
|
||||||
|
const url = USER_TO_ACTIVITY_DELETE(id) |
||||||
|
const result = await axios.delete(url, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataKanbanBoard() |
||||||
|
NotificationManager.success(`Data berhasil dihapus`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setLoadingCard(false) |
||||||
|
NotificationManager.error(`${result.data.message}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
// Activity
|
||||||
|
|
||||||
|
const handleCloseDialogActivity = (type, data, dataHrSelect, id) => { |
||||||
|
if (type === "save") { |
||||||
|
saveCard(data, dataHrSelect) |
||||||
|
} else if (type == "edit") { |
||||||
|
editCard(data, id) |
||||||
|
} |
||||||
|
setOpenDialogActivity(false) |
||||||
|
} |
||||||
|
|
||||||
|
const toggleAddDialogActivity = () => { |
||||||
|
setOpenDialogActivity(!openDialogActivity) |
||||||
|
} |
||||||
|
|
||||||
|
const handleOpenDialogActivity = (type, idBoard) => { |
||||||
|
setOpenDialogActivity(true) |
||||||
|
setTypeDialogActivity(type) |
||||||
|
setIdBoard(idBoard) |
||||||
|
} |
||||||
|
|
||||||
|
// Report
|
||||||
|
|
||||||
|
const handleCloseDialogReport = (type, data, dataHrSelect) => { |
||||||
|
if (type === "Save") { |
||||||
|
saveReport(data, dataHrSelect) |
||||||
|
} else if(type === "Delete") { |
||||||
|
setLoadingCard(true); |
||||||
|
getDataKanbanBoard(); |
||||||
|
} else { |
||||||
|
setOpenDialogReport(false) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const handleOpenDialogReport = (type) => { |
||||||
|
setOpenDialogReport(true) |
||||||
|
setTypeDialogReport(type) |
||||||
|
} |
||||||
|
|
||||||
|
const editActivity = async (data, id) => { |
||||||
|
let urlEdit = KANBAN_CARD_EDIT(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) { |
||||||
|
getDataKanbanBoard() |
||||||
|
NotificationManager.success(`Data berhasil diedit`, 'Success!!'); |
||||||
|
} else { |
||||||
|
NotificationManager.error(`Data gagal di edit`, `Failed!!`); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Child
|
||||||
|
|
||||||
|
const handleCloseDialogChild = (type, data) => { |
||||||
|
if (type === "save") { |
||||||
|
// saveItem(data);
|
||||||
|
} |
||||||
|
setOpenDialogChild(false) |
||||||
|
} |
||||||
|
|
||||||
|
const toggleAddDialogChild = () => { |
||||||
|
setOpenDialogChild(!openDialogChild) |
||||||
|
} |
||||||
|
|
||||||
|
const handleOpenDialogChild = (type) => { |
||||||
|
setOpenDialogChild(true) |
||||||
|
setTypeDialogChild(type) |
||||||
|
} |
||||||
|
|
||||||
|
const onConfirmDelete = async () => { |
||||||
|
let url = KANBAN_BOARD_DELETE(idDelete); |
||||||
|
|
||||||
|
const result = await axios.delete(url, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
getDataKanbanBoard() |
||||||
|
setIdDelete(0) |
||||||
|
setAlertDelete(false) |
||||||
|
NotificationManager.success(`Data berhasil dihapus!`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setIdDelete(0) |
||||||
|
setAlertDelete(false) |
||||||
|
NotificationManager.error(`Data gagal dihapus!}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const cancelDelete = () => { |
||||||
|
setAlertDelete(false) |
||||||
|
} |
||||||
|
|
||||||
|
const handleDelete = async (id) => { |
||||||
|
await setAlertDelete(true) |
||||||
|
setIdDelete(id) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const handleEditBoard = (data) => { |
||||||
|
setDataEditBoard(data) |
||||||
|
handleOpenDialogBoard('Edit'); |
||||||
|
} |
||||||
|
|
||||||
|
const handleGetDataHr = async () => { |
||||||
|
let urlList = `${HUMAN_RESOURCE_LIST}/select?idProyek=${project}&sessionLogin=${sessionLogin}` |
||||||
|
const result = await axios |
||||||
|
.get(urlList, HEADER) |
||||||
|
.then((res) => res) |
||||||
|
.catch((err) => err.response); |
||||||
|
|
||||||
|
|
||||||
|
if (result.status === 200) { |
||||||
|
setDataHr(result.data) |
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
const handleDeleteCard = async (id) => { |
||||||
|
await setAlertDeleteCard(true) |
||||||
|
setIdDeleteCard(id) |
||||||
|
} |
||||||
|
|
||||||
|
const onConfirmDeleteCard = async () => { |
||||||
|
setAlertDeleteCard(false) |
||||||
|
setLoadingCard(true) |
||||||
|
|
||||||
|
const url = `${KANBAN_CARD_ADD}/${idDeleteCard}` |
||||||
|
|
||||||
|
const result = await axios.delete(url, HEADER) |
||||||
|
.then(res => res) |
||||||
|
.catch((error) => error.response); |
||||||
|
|
||||||
|
if (result && result.data && result.data.code === 200) { |
||||||
|
setIdDeleteCard(0) |
||||||
|
getDataKanbanBoard() |
||||||
|
NotificationManager.success(`Data berhasil dihapus!`, 'Success!!'); |
||||||
|
} else { |
||||||
|
setIdDeleteCard(0) |
||||||
|
NotificationManager.error(`Data gagal dihapus!}`, 'Failed!!'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const cancelDeleteCard = () => { |
||||||
|
setAlertDeleteCard(false) |
||||||
|
} |
||||||
|
|
||||||
|
const handleEditCard = (data) => { |
||||||
|
setDataEditCard(data) |
||||||
|
handleOpenDialogActivity('Edit'); |
||||||
|
} |
||||||
|
const setupSelectVersionGantt = () => { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
{dataVersionGantt.map((val, index) => { |
||||||
|
return ( |
||||||
|
<Option key={index} value={val.id}>{val.name_version}</Option> |
||||||
|
) |
||||||
|
})} |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
const setupSelectDataProyek = () => { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
{dataProyek.map((val, index) => { |
||||||
|
return ( |
||||||
|
<Option key={index} value={val.id}>{val.nama}</Option> |
||||||
|
) |
||||||
|
})} |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
const RenderStateKanban = useMemo(() => { |
||||||
|
return (<> |
||||||
|
{ |
||||||
|
stateKanban.columns.map((column) => { |
||||||
|
|
||||||
|
return <Column |
||||||
|
key={column.id} |
||||||
|
column={column} |
||||||
|
tasks={column.tasks} |
||||||
|
handleOpenDialogBoard={handleOpenDialogBoard} |
||||||
|
handleOpenDialogActivity={handleOpenDialogActivity} |
||||||
|
handleOpenDialogChild={handleOpenDialogChild} |
||||||
|
handleDelete={handleDelete} |
||||||
|
handleDeleteCard={handleDeleteCard} |
||||||
|
handleEditBoard={handleEditBoard} |
||||||
|
loadingCard={loadingCard} |
||||||
|
handleEditCard={handleEditCard} |
||||||
|
/> |
||||||
|
}) |
||||||
|
} |
||||||
|
</>) |
||||||
|
}, [stateKanban, loadingCard]) |
||||||
|
|
||||||
|
const RenderDialogFormActivity = useMemo( |
||||||
|
() => ( |
||||||
|
<DialogFormActivity |
||||||
|
activityProject={activityProject} |
||||||
|
openDialogActivity={openDialogActivity} |
||||||
|
closeDialogActivity={handleCloseDialogActivity} |
||||||
|
handleOpenDialogReport={handleOpenDialogReport} |
||||||
|
toggleDialogActivity={() => toggleAddDialogActivity} |
||||||
|
typeDialogActivity={typeDialogActivity} |
||||||
|
clickOpenModalActivity={clickOpenModalActivity} |
||||||
|
proyek_id={project} |
||||||
|
version_gantt_id={versionGantt} |
||||||
|
idBoard={idBoard} |
||||||
|
dataHr={dataHr} |
||||||
|
dataEditCard={dataEditCard} |
||||||
|
userToActivityAdd={userToActivityAdd} |
||||||
|
userToActivityDelete={userToActivityDelete} |
||||||
|
/> |
||||||
|
), |
||||||
|
[openDialogActivity] |
||||||
|
); |
||||||
|
const RenderDialogFormReport = useMemo( |
||||||
|
() => ( |
||||||
|
<DialogFormReport |
||||||
|
activityProject={activityProject} |
||||||
|
openDialogReport={openDialogReport} |
||||||
|
closeDialogReport={handleCloseDialogReport} |
||||||
|
typeDialogReport={typeDialogReport} |
||||||
|
clickOpenModalReport={clickOpenModalActivity} |
||||||
|
proyek_id={proyek_id} |
||||||
|
version_gantt_id={version_gantt_id} |
||||||
|
idBoard={idBoard} |
||||||
|
dataHr={dataHr} |
||||||
|
dataEditCard={dataEditCard} |
||||||
|
userToActivityAdd={userToActivityAdd} |
||||||
|
userToActivityDelete={userToActivityDelete} |
||||||
|
/> |
||||||
|
), |
||||||
|
[openDialogReport] |
||||||
|
); |
||||||
|
return ( |
||||||
|
<Fragment> |
||||||
|
<NotificationContainer /> |
||||||
|
<SweetAlert |
||||||
|
show={alertDelete} |
||||||
|
warning |
||||||
|
showCancel |
||||||
|
confirmBtnText="Delete" |
||||||
|
confirmBtnBsStyle="danger" |
||||||
|
title={`Are you sure?`} |
||||||
|
onConfirm={onConfirmDelete} |
||||||
|
onCancel={() => cancelDelete()} |
||||||
|
focusCancelBtn |
||||||
|
> |
||||||
|
Delete this data |
||||||
|
</SweetAlert> |
||||||
|
<SweetAlert |
||||||
|
show={alertDeleteCard} |
||||||
|
warning |
||||||
|
showCancel |
||||||
|
confirmBtnText="Delete" |
||||||
|
confirmBtnBsStyle="danger" |
||||||
|
title={`Are you sure?`} |
||||||
|
onConfirm={onConfirmDeleteCard} |
||||||
|
onCancel={() => cancelDeleteCard()} |
||||||
|
focusCancelBtn |
||||||
|
> |
||||||
|
Delete this data |
||||||
|
</SweetAlert> |
||||||
|
<DialogFormBoard |
||||||
|
openDialogBoard={openDialogBoard} |
||||||
|
closeDialogBoard={handleCloseDialogBoard} |
||||||
|
toggleDialogBoard={() => toggleDialogBoard} |
||||||
|
typeDialogBoard={typeDialogBoard} |
||||||
|
clickOpenModalBoard={clickOpenModalBoard} |
||||||
|
dataEditBoard={dataEditBoard} |
||||||
|
proyek_id={project} |
||||||
|
version_gantt_id={versionGantt} |
||||||
|
/> |
||||||
|
{RenderDialogFormActivity} |
||||||
|
{RenderDialogFormReport} |
||||||
|
<DialogFormChild |
||||||
|
openDialogChild={openDialogChild} |
||||||
|
closeDialogChild={handleCloseDialogChild} |
||||||
|
toggleDialogChild={() => toggleAddDialogChild} |
||||||
|
typeDialogChild={typeDialogChild} |
||||||
|
clickOpenModalChild={clickOpenModalChild} |
||||||
|
/> |
||||||
|
<div> |
||||||
|
<Card> |
||||||
|
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}> |
||||||
|
<h4 className="capitalize">Kanban</h4> |
||||||
|
<Row> |
||||||
|
<Col> |
||||||
|
<Select |
||||||
|
showSearch |
||||||
|
filterOption={(input, option) => ( |
||||||
|
option?.children ?? '').toLowerCase().includes(input.toLowerCase() |
||||||
|
)} |
||||||
|
defaultValue={proyek_id ? parseInt(proyek_id) : 'Pilih Project'} |
||||||
|
onChange={onChangeProject} |
||||||
|
style={{ |
||||||
|
width: 200, |
||||||
|
marginRight: 10 |
||||||
|
}} |
||||||
|
// options={optionProyek}
|
||||||
|
> |
||||||
|
{setupSelectDataProyek()} |
||||||
|
</Select> |
||||||
|
<Select |
||||||
|
showSearch |
||||||
|
filterOption={(input, option) => ( |
||||||
|
option?.children ?? '').toLowerCase().includes(input.toLowerCase() |
||||||
|
)} |
||||||
|
defaultValue={version_gantt_id ? parseInt(version_gantt_id) : 'Pilih Gantt'} |
||||||
|
onChange={onChangeGantt} |
||||||
|
style={{ |
||||||
|
width: 200, |
||||||
|
marginRight: 10 |
||||||
|
}} |
||||||
|
// option={optionGantt}
|
||||||
|
> |
||||||
|
{setupSelectVersionGantt()} |
||||||
|
</Select> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</CardHeader> |
||||||
|
</Card> |
||||||
|
{project != "" && versionGantt != 0 ? ( |
||||||
|
<> |
||||||
|
<Row gutter={16}> |
||||||
|
<Col className="gutter-row" span={6}> |
||||||
|
<div className='board-add' onClick={() => handleOpenDialogBoard("Save")} > |
||||||
|
<div className='title-board-add'> |
||||||
|
<div> |
||||||
|
+ Add Board |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row gutter={16} className='body'> |
||||||
|
<DragDropContext onDragEnd={onDragEnd}> |
||||||
|
{RenderStateKanban} |
||||||
|
</DragDropContext> |
||||||
|
</Row> |
||||||
|
</> |
||||||
|
) : ( |
||||||
|
<p style={{ textAlign: 'center' }}>Please select Project and Gantt Option</p> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
</Fragment> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export default Kanban; |
Loading…
Reference in new issue