farhantock
10 months ago
20 changed files with 3749 additions and 1246 deletions
@ -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