wahyun
10 months ago
9 changed files with 2486 additions and 0 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