Browse Source

Merge pull request 'staging' (#108) from staging into master

Reviewed-on: ordo/adw-frontend#108
pull/2/head
ibnu 1 year ago
parent
commit
58a1349ba2
  1. 7
      .env
  2. 49
      src/appredux/modules/map/actions.js
  3. BIN
      src/assets/img/map/pin_route_on_trip.png
  4. 1150
      src/const/ApiConst.js
  5. 2491
      src/views/Dashboard/DashboardProject.js
  6. 48
      src/views/MapMonitoring/index.js
  7. 34
      src/views/Master/MasterBroadcast/DialogDetail.js
  8. 20
      src/views/Master/MasterBroadcast/DialogForm.js
  9. 8
      src/views/Master/MasterBroadcast/index.js
  10. 294
      src/views/SimproV2/CreatedProyek/AsignCustProject.js
  11. 478
      src/views/SimproV2/CreatedProyek/DataRequestMaterial.js
  12. 173
      src/views/SimproV2/CreatedProyek/DialogAssignCust.js
  13. 3139
      src/views/SimproV2/CreatedProyek/index.js
  14. 217
      src/views/SimproV2/Gantt/index.js

7
.env

@ -1,3 +1,4 @@
PORT=3000
CHOKIDAR_USEPOLLING=true
GENERATE_SOURCEMAP=false
PORT=3000
CHOKIDAR_USEPOLLING=true
GENERATE_SOURCEMAP=false
SKIP_PREFLIGHT_CHECK=true

49
src/appredux/modules/map/actions.js

@ -158,11 +158,41 @@ export const getUserHistory = async (userId, dateString) => {
"features": []
}
// build waypoint line
let featureLine = {
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": []
}
}
userHistory.data.map((n, idx) => {
featureLine.geometry.coordinates.push([parseFloat(n.lon), parseFloat(n.lat)])
if (idx > startIdx && idx < endIdx) {
let featureOnTrip = {
"type": "Feature",
"properties": {
"type": "Working",
"wptime": n.wptime
},
"geometry": {
"type": "Point",
"coordinates": [parseFloat(n.lon), parseFloat(n.lat)]
}
}
featureCollection.features.push(featureOnTrip);
}
});
featureCollection.features.push(featureLine);
// set waypoint start
let featurePointStart = {
"type": "Feature",
"properties": {
"type": "start",
"type": "Start",
"wptime": userHistory.data[startIdx].wptime
},
"geometry": {
@ -176,7 +206,7 @@ export const getUserHistory = async (userId, dateString) => {
let featurePointEnd = {
"type": "Feature",
"properties": {
"type": "end",
"type": "End",
"wptime": userHistory.data[endIdx].wptime
},
"geometry": {
@ -186,21 +216,6 @@ export const getUserHistory = async (userId, dateString) => {
}
featureCollection.features.push(featurePointEnd);
// build waypoint line
let featureLine = {
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": []
}
}
userHistory.data.map(n => {
featureLine.geometry.coordinates.push([parseFloat(n.lon), parseFloat(n.lat)])
});
featureCollection.features.push(featureLine);
store.dispatch(setUserHistory(featureCollection));
store.dispatch(setIsSearchingRoute(false));
}

BIN
src/assets/img/map/pin_route_on_trip.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

1150
src/const/ApiConst.js

File diff suppressed because it is too large Load Diff

2491
src/views/Dashboard/DashboardProject.js

File diff suppressed because it is too large Load Diff

48
src/views/MapMonitoring/index.js

@ -17,11 +17,15 @@ import "react-toastify/dist/ReactToastify.css";
import './MapMonitoring.css';
import { BASE_SIMPRO_LUMEN_IMAGE } from '../../const/ApiConst';
import DEFAULT_USER_ICON from '../../assets/img/avatars/user.png';
import pinRouteStart from '../../assets/img/map/pin_route_green.png';
import pinRouteEnd from '../../assets/img/map/pin_route_red.png';
import pinRouteOnTrip from '../../assets/img/map/pin_route_on_trip.png';
import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/leaflet.markercluster.js'
import 'leaflet-control-geocoder/dist/Control.Geocoder.css'
import 'leaflet-control-geocoder/dist/Control.Geocoder.js'
import moment from 'moment';
const MapMonitoring = () => {
@ -81,8 +85,50 @@ const MapMonitoring = () => {
if (mymap) {
removeLayerByName('userHistoryLayer');
if (userHistory) {
var startIcon = new L.Icon({
iconSize: [60, 60],
iconAnchor: [30, 47],
popupAnchor: [1, -24],
iconUrl: pinRouteStart
});
var endIcon = new L.Icon({
iconSize: [60, 60],
iconAnchor: [30, 47],
popupAnchor: [1, -24],
iconUrl: pinRouteEnd
});
var onTripIcon = new L.Icon({
iconSize: [60, 60],
iconAnchor: [30, 47],
popupAnchor: [1, -24],
iconUrl: pinRouteOnTrip
});
let userHistoryLayer = L.geoJson(userHistory, {
name: 'userHistoryLayer'
name: 'userHistoryLayer',
onEachFeature: function(feature, layer) {
var popupText = `<b>Status: </b>${feature.properties.type}<br>
<b>Time: </b> ${feature.properties.wptime ? moment(feature.properties.wptime).format("DD-MM-YYYY HH:mm:ss") : '-'}`;
layer.bindPopup(popupText, {
closeButton: true,
// offset: L.point(0, -20)
});
layer.on('click', function() {
layer.openPopup();
});
},
pointToLayer: function(feature, latlng) {
var type = feature.properties.type;
if (type === 'Start') {
return L.marker(latlng, {icon: startIcon});
}
else if (type === "Working") {
return L.marker(latlng, {icon: onTripIcon});
}
else if (type === "End") {
return L.marker(latlng, {icon: endIcon});
}
},
});
userHistoryLayer.addTo(mymap);
mymap.fitBounds(userHistoryLayer.getBounds());

34
src/views/Master/MasterBroadcast/DialogDetail.js

@ -4,10 +4,17 @@ import moment from 'moment';
import { Button, Table, FormFeedback, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
import Select from 'react-select';
import axios from 'axios';
import { BASE_URL_GEOHR_API } from '../../../const/ApiConst';
import { BASE_SIMPRO_LUMEN, BASE_URL_GEOHR_API } from '../../../const/ApiConst';
import { Transfer } from 'antd';
import { withTranslation } from 'react-i18next';
const token = window.localStorage.getItem('token');
const config = {
headers:
{
Authorization: `Bearer ${token}`,
"Content-type": `application/json`
}
};
const ERROR_TITLE = "judul is required!"
const ERROR_MESSAGE = "message is required!"
const BASE_URL = "https://oslog.id/geohr-api/";
@ -42,26 +49,23 @@ class DialogDetail extends Component {
getDataDetail = async () => {
countError++;
let url = BASE_URL_GEOHR_API + `/broadcast-detail/search?broadcastId=${this.state.id}`;
let url = BASE_SIMPRO_LUMEN + `/broadcast/search`;
const payload = {
"paging": { "start": 0, "length": 25 },
"orders": { "columns": ["id"], "ascending": true },
"columns": [
{ "name": "status_send", "logic_operator": "ilike", "value": "", "operator": "AND" }
],
"joins": [
{ "name": "m_broadcast", "column_results": ["title_notif", "message_notif", "description", "status_send"], "column_join": "broadcast_id" }
{ "name": "id", "logic_operator": "=", "value": this.state.id, "operator": "AND" }
]
}
const result = await axios
.post(url, payload)
.post(url, payload, config)
.then(res => res)
.catch((error) => error.response);
console.log('cek data detail', result.data)
if (result && result.data && result.data.code === 200) {
if (result.data.data && result.data.data.broadcast_details) {
this.setState({ dataListDetail: result.data.data.broadcast_details })
if (result.data.data && result.data.data) {
this.setState({ dataListDetail: result.data.data })
}
} else {
if (countError < 6) {
@ -97,11 +101,11 @@ class DialogDetail extends Component {
{this.state.dataListDetail.map((val, index) => {
return (
<tr key={index}>
<td>{val.join.status_send === "" ? "-" : val.status_send}</td>
<td>{val.join.created_date === "" ? "-" : moment(val.created_date).format("YYYY-MM-DD HH:mm:ss")}</td>
<td>{val.join.broadcast_description === "" ? "-" : val.join.broadcast_description}</td>
<td>{val.join.broadcast_title_notif === "" ? "-" : val.join.broadcast_title_notif}</td>
<td>{val.join.broadcast_message_notif === "" ? "-" : val.join.broadcast_message_notif}</td>
<td>{val.status_send === "" ? "-" : val.status_send}</td>
<td>{val.created_at === "" ? "-" : moment(val.created_date).format("DD-MM-YYYY HH:mm:ss")}</td>
<td>{val.description === "" ? "-" : val.description}</td>
<td>{val.title_notif === "" ? "-" : val.title_notif}</td>
<td>{val.message_notif === "" ? "-" : val.message_notif}</td>
</tr>
)
})}

20
src/views/Master/MasterBroadcast/DialogForm.js

@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { Button, Form, FormFeedback, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
import Select from 'react-select';
import axios from 'axios';
import { BASE_URL_GEOHR_API2, ROLE_SEARCH, USER_WASPANG } from '../../../const/ApiConst';
import { BASE_URL_GEOHR_API2, ROLE_SEARCH, USER_WASPANG, USER_LIST } from '../../../const/ApiConst';
import { Transfer } from 'antd';
import { withTranslation } from 'react-i18next';
@ -137,7 +137,7 @@ class DialogForm extends Component {
if (penerima === "all") {
idSend = this.state.allEmployeeId;
send_to_type = "all";
} else if (penerima === "division") {
} else if (penerima === "organization") {
idSend = this.state.idOrganization;
send_to_type = "roles";
} else if (penerima === "karyawan") {
@ -145,9 +145,13 @@ class DialogForm extends Component {
send_to_type = "users";
}
if(Array.isArray(idSend)){
idSend = idSend.map(function (e) {
return e.toString()
});
} else {
idSend = idSend;
}
const data = {
title,
@ -186,7 +190,7 @@ class DialogForm extends Component {
}
setEmployeeOrganization = () => {
let arrEd = this.state.dataEmployee;
let arrEd = this.state.dataEmployee.data;
let cek = arrEd.filter(this.filterId)
this.setState({ idEmployeeDivision: cek })
@ -289,14 +293,14 @@ class DialogForm extends Component {
"ascending": false
}
}
//TODO should use search instead
const result = await axios
.post(USER_WASPANG, payload, config)
.get(USER_LIST, config)
.then(res => res)
.catch((error) => error.response);
console.log('test role', result)
if (result && result.data && result.code == "200") {
if (result && result.data && result.status == 200) {
this.setState({ dataEmployee: result.data }, () => {
this.setDataEmployee();
});
@ -307,12 +311,12 @@ class DialogForm extends Component {
setDataEmployee = () => {
const listEmployee = [];
const allIdEmployee = [];
this.state.dataEmployee.map((val, index) => {
this.state.dataEmployee.data.map((val, index) => {
allIdEmployee.push(val.id);
listEmployee.push({
key: val.id,
id: val.id,
title: val.join.m_users_name
title: val.name
});
})

8
src/views/Master/MasterBroadcast/index.js

@ -5,7 +5,7 @@ import React, { Component } from 'react';
import SweetAlert from 'react-bootstrap-sweetalert';
import axios from 'axios';
import moment from 'moment';
import { API_BROADCAST_SIMPRO, BASE_SIMPRO, BASE_URL_GEOHR_API2 } from '../../../const/ApiConst';
import { API_BROADCAST_SIMPRO, BASE_SIMPRO, BASE_SIMPRO_LUMEN, BASE_URL_GEOHR_API2 } from '../../../const/ApiConst';
import { Button, Card, CardBody, CardHeader, DropdownItem, DropdownMenu, DropdownToggle, Input, InputGroup, InputGroupButtonDropdown, Table, Row, Col } from 'reactstrap';
import { DatePicker, Pagination } from 'antd';
import { NotificationContainer, NotificationManager } from 'react-notifications';
@ -85,7 +85,7 @@ class index extends Component {
};
getDataBroadcast = async () => {
let url = BASE_SIMPRO + `/broadcast/search`;
let url = BASE_SIMPRO_LUMEN + `/broadcast/search`;
const { searchDetail } = this.state
let start = 0;
@ -180,7 +180,7 @@ class index extends Component {
}
saveBroadcast = async (type, data) => {
let url = BASE_SIMPRO + `/broadcast/add`;
let url = BASE_SIMPRO_LUMEN + `/broadcast/add`;
const param = {
"title_notif": data.title,
@ -205,7 +205,7 @@ class index extends Component {
"send_to_type": "users",
"message_notif": data.message,
"description": data.description,
"send_to_id": data.id.map((id, index) => id)
"send_to_id": data.send_to_type == "users" ? data.id.map((id, index) => id) : null
}
if (data.send_to_type === "all") {

294
src/views/SimproV2/CreatedProyek/AsignCustProject.js

@ -0,0 +1,294 @@
import React, { useEffect, useState, useMemo } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { Button, Form } from 'reactstrap';
import { Table, Tooltip } from 'antd';
import 'antd/dist/antd.css';
import moment from 'moment';
import { API_ADW, TOKEN_ADW, ASSIGN_HR_PROJECT_SEARCH, ASSIGN_HR_PROJECT_DELETE, USER_LIST, PROJECT_ROLE_SEARCH, ASSIGN_HR_PROJECT_ADD, ASSIGN_HR_PROJECT_EDIT } from '../../../const/ApiConst';
import axios from "../../../const/interceptorApi"
import { NotificationContainer, NotificationManager } from 'react-notifications';
import SweetAlert from 'react-bootstrap-sweetalert';
import FormAsignCust from './DialogAssignCust';
import { formatThousand } from '../../../const/CustomFunc';
const AssignHrProject = ({ openDialog, closeDialog, toggleDialog, idTask, toolsResource, proyekName }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [dataUserToProject, setdataUserToProject] = useState([])
const [alertDelete, setAlertDelete] = useState(false)
const [idDelete, setIdDelete] = useState(0)
const [openDialogFormTools, setOpenDialogFormTools] = useState(false)
const [dataEdit, setDataEdit] = useState(null)
const [listUser, setListUser] = useState([])
const [listRole, setListRole] = useState([])
useEffect(() => {
if (idTask > 0) {
getDataAssignHr();
}
}, [openDialog]);
useEffect(() => {
if (openDialog) {
getDataProjectRole();
getDataUser();
}
}, [dataUserToProject])
const getDataAssignHr = async () => {
const payload = {
"paging": {
"start": 0,
"length": -1
},
"columns": [
{ "name": "name", "logic_operator": "ilike", "value": "", "table_name": "m_users" },
{ "name": "proyek_id", "logic_operator": "=", "value": idTask }
],
"joins": [
{ "name": "m_users", "column_join": "user_id", "column_results": ["name"] },
{ "name": "m_role_proyek", "column_join": "project_role", "column_results": ["name"] },
],
"orders": {
"columns": [
"id"
],
"ascending": false
}
}
const URL = ASSIGN_HR_PROJECT_SEARCH
const result = await axios
.post(URL, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || []
const filteredData = dataRes.filter(item => item.is_customer === true);
setdataUserToProject(filteredData);
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
}
}
const getDataUser = async () => {
const HEADER_ADW = {
headers: {
"Authorization": `${TOKEN_ADW}`
}
}
const result = await axios
.get(USER_LIST, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.data.length != 0) {
let dataRes = result.data.data
setListUser(dataRes)
}
}
const getDataProjectRole = async () => {
const payload = {
"paging": {
"start": 0,
"length": -1
},
"columns": [
{ "name": "created_by", "logic_operator": "ilike", "value": "" },
],
"joins": [],
"orders": {
"columns": [
"id"
],
"ascending": false
}
}
const result = await axios
.post(PROJECT_ROLE_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || []
setListRole(dataRes);
} else {
}
}
const handleDelete = (id) => {
setIdDelete(id)
setAlertDelete(true)
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const onConfirmDelete = async () => {
let urlDel = ASSIGN_HR_PROJECT_DELETE(idDelete)
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataAssignHr()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data assign human resource berhasil dihapus`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data assign human resource gagal dihapus`, 'Failed!!');
}
}
const handleOpenDialogFormTools = () => {
setOpenDialogFormTools(true)
}
const handleCancel = () => {
closeDialog('cancel', 'none')
}
const RenderTable = useMemo(() => {
const columns = [
{
title: 'Action',
dataIndex: '',
key: 'x',
className: "nowrap",
render: (text, record) => <><Tooltip title="Delete Request Resource">
<Button size={"sm"} color='danger' onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button>
</Tooltip>{" "}</>,
},
{ title: 'Name Human Resource', dataIndex: 'join_first_name', key: 'join_first_name', className: "nowrap" },
{ title: 'Role Human Resource', dataIndex: 'join_second_name', key: 'join_second_name', className: "nowrap" },
{ title: 'Percentage Available User', dataIndex: 'max_used', key: 'max_used', className: "nowrap", render: (text, record) => record.max_used ? formatThousand(record.max_used) : '-' },
{ title: 'Standard Rate', dataIndex: 'standart_rate', key: 'standart_rate', className: "nowrap", render: (text, record) => record.standart_rate ? formatThousand(record.standart_rate) : '-' },
{ title: 'UOM Standard Rate', dataIndex: 'uom_standart_rate', key: 'uom_standart_rate', className: "nowrap" },
{ title: 'Overtime Rate', dataIndex: 'overtime_rate', key: 'overtime_rate', className: "nowrap", render: (text, record) => record.overtime_rate ? formatThousand(record.overtime_rate) : '-' },
{ title: 'UOM Overtime Rate', dataIndex: 'uom_overtime_rate', key: 'uom_overtime_rate', className: "nowrap" },
];
return (
<Table
size="small"
columns={columns}
dataSource={dataUserToProject}
pagination={{ position: ["bottomLeft"] }}
/>
)
}, [dataUserToProject])
const renderForm = () => {
return (
<div style={{"overflowX":"scroll"}}>
{RenderTable}
</div>
)
}
const handleCloseDialogFormTools = (type, data) => {
if(type=="add"){
addDataAssignHr(data);
}else if(type=="edit"){
editDataAssignHr(data);
}else{
setDataEdit(null)
setOpenDialogFormTools(false)
}
}
const addDataAssignHr = async (payload) => {
const result = await axios
.post(ASSIGN_HR_PROJECT_ADD, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
getDataAssignHr();
NotificationManager.success('assign human resource berhasil!!', 'Success');
setDataEdit(null)
setOpenDialogFormTools(false)
} else {
NotificationManager.error('assign human resource gagal!!', 'Failed');
}
}
const editDataAssignHr = async (payload) => {
let url = ASSIGN_HR_PROJECT_EDIT(payload.id)
const result = await axios
.put(url, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
getDataAssignHr();
NotificationManager.success('assign human resource berhasil diedit!!', 'Success');
setDataEdit(null)
setOpenDialogFormTools(false)
} else {
NotificationManager.error('assign human resource gagal diedit!!', 'Failed');
}
}
const toogleDialogFormTools = () => {
if (openDialogFormTools) {
setDataEdit(null)
}
setOpenDialogFormTools(!openDialogFormTools)
}
return (
<>
<NotificationContainer />
<SweetAlert
show={alertDelete}
warning
showCancel
confirmBtnText="Delete"
confirmBtnBsStyle="danger"
title={`Are you sure?`}
onConfirm={onConfirmDelete}
onCancel={() => cancelDelete()}
focusCancelBtn
>
Delete this data
</SweetAlert>
<Modal size="xl" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize withBtn" toggle={closeDialog}>
<div>Assign Customer - {proyekName}</div> <Button onClick={handleOpenDialogFormTools} size='sm' color="primary"><i className='fa fa-plus'></i></Button>
</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
</Modal>
<FormAsignCust
openDialog={openDialogFormTools}
closeDialog={handleCloseDialogFormTools}
toggleDialog={toogleDialogFormTools}
idTask={idTask}
dataEdit={dataEdit}
dataHr={listUser}
dataRole={listRole}
dataCurrentHr={dataUserToProject}
/>
</>
)
}
export default AssignHrProject;

478
src/views/SimproV2/CreatedProyek/DataRequestMaterial.js

@ -1,239 +1,239 @@
import React, { useEffect, useState, useMemo } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { Button } from 'reactstrap';
import { Table, Tooltip } from 'antd';
import 'antd/dist/antd.css';
import moment from 'moment';
import SweetAlert from 'react-bootstrap-sweetalert';
import { REQUEST_MATERIAL_SEARCH, REQUEST_MATERIAL_ADD, REQUEST_MATERIAL_DELETE, REQUEST_MATERIAL_EDIT } from '../../../const/ApiConst';
import axios from "../../../const/interceptorApi"
import { NotificationContainer, NotificationManager } from 'react-notifications';
import DialogRequest from './FormRequestMaterial';
import { renderLabelStatus } from '../../../const/CustomFunc';
const DialogFormMaterial = ({ openDialog, closeDialog, toggleDialog, idTask, materialResource, proyekName }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [dataResource, setDataResource] = useState([])
const [openDialogReq, setOpenDialogReq] = useState(false)
const [alertDelete, setAlertDelete] = useState(false)
const [idDelete, setIdDelete] = useState(0)
const [dataEdit, setDataEdit] = useState(null)
useEffect(() => {
if (idTask > 0) {
getDataRequestMaterial();
}
}, [idTask])
useEffect(() => {
if (!openDialog) {
setDataResource([]);
} else {
}
}, [openDialog])
const getDataRequestMaterial = async () => {
const payload = {
"columns": [
{ "name": "description", "logic_operator": "ilike", "value": "", "operator": "AND" },
{ "name": "proyek_id", "logic_operator": "=", "value": idTask, "operator": "AND" }
],
"joins": [],
"orders": { "columns": ["id"], "ascending": true },
"paging": { "start": 0, "length": 25 }
}
const result = await axios
.post(REQUEST_MATERIAL_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
console.log("result", result)
if (result && result.status == 200) {
setDataResource(result.data.data);
} else {
}
}
const handleCancel = () => {
setDataResource([]);
setDataEdit(null)
closeDialog('cancel', 'none')
}
const handleDelete = (id) => {
setIdDelete(id)
setAlertDelete(true)
}
const handleEdit = async (data) => {
await setDataEdit(data)
setOpenDialogReq(true)
}
const RenderTable = useMemo(() => {
const columns = [
{
title: 'Action',
dataIndex: '',
key: 'id',
className: "nowrap",
render: (text, record) => <>
{text.status == "fom" ? <><Tooltip title="Delete Request Resource">
<Button size="small" size={"sm"} color='danger' onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button>
</Tooltip>{" "}<Tooltip title="Edit Request Resource">
<Button size="small" size={"sm"} color='primary' onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button>
</Tooltip></> : "-"}
</>,
},
{ title: 'Status', dataIndex: 'status', key: 'status', render: (text, record) => renderLabelStatus(text) },
{ title: 'Description', dataIndex: 'description', key: 'description' },
{ title: 'Required Date', dataIndex: 'required_date', key: 'required_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{moment(text).format("D-M-YYYY")}</div>) },
{ title: 'QTY', dataIndex: 'qty', key: 'qty', render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? text : "-"}</div>) },
{ title: 'UOM', dataIndex: 'uom', key: 'uom', render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? text : "-"}</div>) },
{ title: 'QTY Received', dataIndex: 'qty_received', key: 'qty_received', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? text : "-"}</div>) },
{ title: 'FOM Date', dataIndex: 'fom_date', key: 'fom_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{moment(text).format("D-M-YYYY")}</div>) },
{ title: 'PR Date', dataIndex: 'pr_date', key: 'pr_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? moment(text).format("D-M-YYYY") : "-"}</div>) },
{ title: 'PO Date', dataIndex: 'po_date', key: 'po_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? moment(text).format("D-M-YYYY") : "-"}</div>) },
{ title: 'Received Date', dataIndex: 'received_date', key: 'received_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? moment(text).format("D-M-YYYY") : "-"}</div>) },
{ title: 'Delivery Date', dataIndex: 'delivery_date', key: 'delivery_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? moment(text).format("D-M-YYYY") : "-"}</div>) },
];
return (
<Table
size="small"
columns={columns}
rowKey={"id"}
dataSource={dataResource}
pagination={{ position: ["bottomLeft"] }}
/>
)
}, [dataResource])
const closeDialogReq = (type, data) => {
if (type == "add") {
saveRequestMaterial(data);
} else if (type == "edit") {
updateRequestMaterial(data);
} else {
setOpenDialogReq(false);
setDataEdit(null)
}
}
const toggleDialogReq = () => {
setOpenDialogReq(!openDialogReq)
}
const openDialogRequest = () => {
setOpenDialogReq(true)
}
const saveRequestMaterial = async (data) => {
const result = await axios
.post(REQUEST_MATERIAL_ADD, data, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
getDataRequestMaterial();
NotificationManager.success('Data request material berhasill ditambahkan!!', 'Success');
setOpenDialogReq(false);
setDataEdit(null)
} else {
NotificationManager.error('Data request material gagal ditambahkan!!', 'Failed');
}
}
const updateRequestMaterial = async (data) => {
let url = REQUEST_MATERIAL_EDIT(data.id)
const result = await axios
.put(url, data, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
getDataRequestMaterial();
NotificationManager.success('Data request material berhasill diedit!!', 'Success');
setOpenDialogReq(false);
setDataEdit(null)
} else {
NotificationManager.error('Data request material gagal diedit!!', 'Failed');
}
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const onConfirmDelete = async () => {
let urlDel = REQUEST_MATERIAL_DELETE(idDelete)
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataRequestMaterial()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data request material berhasil dihapus`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data request material gagal dihapus`, 'Failed!!');
}
}
return (
<>
<Modal size="xl" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize withBtn" toggle={closeDialog} style={{ width: "100%" }}>
<div>Request Material Resource - {proyekName}</div> <Button onClick={openDialogRequest} size='sm' color="primary"><i className='fa fa-plus'></i></Button>
</ModalHeader>
<ModalBody>
<div style={{ width: '100%', overflow: "auto" }}>
{RenderTable}
</div>
</ModalBody>
{/* <ModalFooter>
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button>
</ModalFooter> */}
</Modal>
<NotificationContainer />
<SweetAlert
show={alertDelete}
warning
showCancel
confirmBtnText="Delete"
confirmBtnBsStyle="danger"
title={`Are you sure?`}
onConfirm={onConfirmDelete}
onCancel={() => cancelDelete()}
focusCancelBtn
>
Delete this data
</SweetAlert>
<DialogRequest
openDialog={openDialogReq}
closeDialog={closeDialogReq}
toggleDialog={toggleDialogReq}
idTask={idTask}
dataEdit={dataEdit}
materialResource={materialResource}
/>
</>
)
}
export default DialogFormMaterial;
import React, { useEffect, useState, useMemo } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { Button } from 'reactstrap';
import { Table, Tooltip } from 'antd';
import 'antd/dist/antd.css';
import moment from 'moment';
import SweetAlert from 'react-bootstrap-sweetalert';
import { REQUEST_MATERIAL_SEARCH, REQUEST_MATERIAL_ADD, REQUEST_MATERIAL_DELETE, REQUEST_MATERIAL_EDIT } from '../../../const/ApiConst';
import axios from "../../../const/interceptorApi"
import { NotificationContainer, NotificationManager } from 'react-notifications';
import DialogRequest from './FormRequestMaterial';
import { renderLabelStatus } from '../../../const/CustomFunc';
const DialogFormMaterial = ({ openDialog, closeDialog, toggleDialog, idTask, materialResource, proyekName }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [dataResource, setDataResource] = useState([])
const [openDialogReq, setOpenDialogReq] = useState(false)
const [alertDelete, setAlertDelete] = useState(false)
const [idDelete, setIdDelete] = useState(0)
const [dataEdit, setDataEdit] = useState(null)
useEffect(() => {
if (idTask > 0) {
// getDataRequestMaterial();
}
}, [idTask])
useEffect(() => {
if (!openDialog) {
setDataResource([]);
} else {
}
}, [openDialog])
const getDataRequestMaterial = async () => {
const payload = {
"columns": [
{ "name": "description", "logic_operator": "ilike", "value": "", "operator": "AND" },
{ "name": "proyek_id", "logic_operator": "=", "value": idTask, "operator": "AND" }
],
"joins": [],
"orders": { "columns": ["id"], "ascending": true },
"paging": { "start": 0, "length": 25 }
}
const result = await axios
.post(REQUEST_MATERIAL_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
console.log("result", result)
if (result && result.status == 200) {
setDataResource(result.data.data);
} else {
}
}
const handleCancel = () => {
setDataResource([]);
setDataEdit(null)
closeDialog('cancel', 'none')
}
const handleDelete = (id) => {
setIdDelete(id)
setAlertDelete(true)
}
const handleEdit = async (data) => {
await setDataEdit(data)
setOpenDialogReq(true)
}
const RenderTable = useMemo(() => {
const columns = [
{
title: 'Action',
dataIndex: '',
key: 'id',
className: "nowrap",
render: (text, record) => <>
{text.status == "fom" ? <><Tooltip title="Delete Request Resource">
<Button size="small" size={"sm"} color='danger' onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button>
</Tooltip>{" "}<Tooltip title="Edit Request Resource">
<Button size="small" size={"sm"} color='primary' onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button>
</Tooltip></> : "-"}
</>,
},
{ title: 'Status', dataIndex: 'status', key: 'status', render: (text, record) => renderLabelStatus(text) },
{ title: 'Description', dataIndex: 'description', key: 'description' },
{ title: 'Required Date', dataIndex: 'required_date', key: 'required_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{moment(text).format("D-M-YYYY")}</div>) },
{ title: 'QTY', dataIndex: 'qty', key: 'qty', render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? text : "-"}</div>) },
{ title: 'UOM', dataIndex: 'uom', key: 'uom', render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? text : "-"}</div>) },
{ title: 'QTY Received', dataIndex: 'qty_received', key: 'qty_received', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? text : "-"}</div>) },
{ title: 'FOM Date', dataIndex: 'fom_date', key: 'fom_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{moment(text).format("D-M-YYYY")}</div>) },
{ title: 'PR Date', dataIndex: 'pr_date', key: 'pr_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? moment(text).format("D-M-YYYY") : "-"}</div>) },
{ title: 'PO Date', dataIndex: 'po_date', key: 'po_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? moment(text).format("D-M-YYYY") : "-"}</div>) },
{ title: 'Received Date', dataIndex: 'received_date', key: 'received_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? moment(text).format("D-M-YYYY") : "-"}</div>) },
{ title: 'Delivery Date', dataIndex: 'delivery_date', key: 'delivery_date', className: "nowrap", render: (text, record) => (<div style={{ whiteSpace: "nowrap" }}>{text ? moment(text).format("D-M-YYYY") : "-"}</div>) },
];
return (
<Table
size="small"
columns={columns}
rowKey={"id"}
dataSource={dataResource}
pagination={{ position: ["bottomLeft"] }}
/>
)
}, [dataResource])
const closeDialogReq = (type, data) => {
if (type == "add") {
saveRequestMaterial(data);
} else if (type == "edit") {
updateRequestMaterial(data);
} else {
setOpenDialogReq(false);
setDataEdit(null)
}
}
const toggleDialogReq = () => {
setOpenDialogReq(!openDialogReq)
}
const openDialogRequest = () => {
setOpenDialogReq(true)
}
const saveRequestMaterial = async (data) => {
const result = await axios
.post(REQUEST_MATERIAL_ADD, data, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
getDataRequestMaterial();
NotificationManager.success('Data request material berhasill ditambahkan!!', 'Success');
setOpenDialogReq(false);
setDataEdit(null)
} else {
NotificationManager.error('Data request material gagal ditambahkan!!', 'Failed');
}
}
const updateRequestMaterial = async (data) => {
let url = REQUEST_MATERIAL_EDIT(data.id)
const result = await axios
.put(url, data, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
getDataRequestMaterial();
NotificationManager.success('Data request material berhasill diedit!!', 'Success');
setOpenDialogReq(false);
setDataEdit(null)
} else {
NotificationManager.error('Data request material gagal diedit!!', 'Failed');
}
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const onConfirmDelete = async () => {
let urlDel = REQUEST_MATERIAL_DELETE(idDelete)
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataRequestMaterial()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data request material berhasil dihapus`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data request material gagal dihapus`, 'Failed!!');
}
}
return (
<>
<Modal size="xl" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize withBtn" toggle={closeDialog} style={{ width: "100%" }}>
<div>Request Material Resource - {proyekName}</div> <Button onClick={openDialogRequest} size='sm' color="primary"><i className='fa fa-plus'></i></Button>
</ModalHeader>
<ModalBody>
<div style={{ width: '100%', overflow: "auto" }}>
{RenderTable}
</div>
</ModalBody>
{/* <ModalFooter>
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button>
</ModalFooter> */}
</Modal>
<NotificationContainer />
<SweetAlert
show={alertDelete}
warning
showCancel
confirmBtnText="Delete"
confirmBtnBsStyle="danger"
title={`Are you sure?`}
onConfirm={onConfirmDelete}
onCancel={() => cancelDelete()}
focusCancelBtn
>
Delete this data
</SweetAlert>
<DialogRequest
openDialog={openDialogReq}
closeDialog={closeDialogReq}
toggleDialog={toggleDialogReq}
idTask={idTask}
dataEdit={dataEdit}
materialResource={materialResource}
/>
</>
)
}
export default DialogFormMaterial;

173
src/views/SimproV2/CreatedProyek/DialogAssignCust.js

@ -0,0 +1,173 @@
import React, { useEffect, useState } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { Button, Form } from 'reactstrap';
import axios from "../../../const/interceptorApi";
import { USER_VERSION_GANTT_ADDS, USER_VERSION_GANTT_SEARCH, USER_LIST} from '../../../const/ApiConst';
import { Transfer } from 'antd';
import 'antd/dist/antd.css';
const role_id = localStorage.getItem('role_id');
const DialogAssignCust = ({ openDialog, closeDialog, toggleDialog, idGantt}) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [id, setId] = useState(0)
const [targetKeys, setTargetKeys] = useState([])
const [assignCustomer, setAssignCustomer] = useState([])
const handleCLearData = () => {
setId(0)
setTargetKeys([])
}
useEffect(() => {
if(!openDialog){
handleCLearData()
} else {
getDataAssignCustomer();
}
}, [openDialog])
useEffect(() => {
if(idGantt && idGantt > 0){
getUserGantt()
}
}, [idGantt])
const getDataAssignCustomer = async () => {
const result = await axios
.get(USER_LIST, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.status == 200) {
let dataRes = result.data.data;
const filteredData = dataRes.filter(item => item.role_id === 44);
setTransferUser(filteredData);
} else {
}
}
const setTransferUser = (data) => {
const finalData = []
data.map((val, index) => {
let data = {
key: val.id,
title: val.name
}
finalData.push(data)
});
setAssignCustomer(finalData)
}
const getUserGantt = async () => {
const payload = {
"columns": [
{ "name": "version_gantt_id", "logic_operator": "=", "value": idGantt, "operator": "AND" }
]
}
const result = await axios
.post(USER_VERSION_GANTT_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if(result && result.status==200){
console.log("cek resource get user gantt",result.data.data)
setUserGantt(result.data.data);
}else{
}
}
const setUserGantt = (data) => {
let newTargetKeys = []
data.map((val,index)=> {
newTargetKeys.push(val.user_id)
});
setTargetKeys(newTargetKeys)
}
const handleSave = async () => {
await saveVersionGantt()
handleCLearData()
}
const saveVersionGantt= async () => {
const formData = {
user_id:targetKeys,
version_gantt_id:idGantt
}
const result = await axios
.post(USER_VERSION_GANTT_ADDS, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if(result && result.status==200){
closeDialog('success')
}else{
closeDialog('failed')
}
}
const handleCancel = () => {
closeDialog('cancel')
handleCLearData()
}
const handleChange = targetKeys => {
setTargetKeys(targetKeys)
};
const renderForm = () => {
return (
<div style={{
alignContent: "center",
justifyContent: "center !imporant",
paddingLeft: 20,
paddingRight: 20,
overflow: "auto"
}}>
<Transfer
showSearch
titles={['Available Customer', 'Granted to']}
dataSource={assignCustomer}
targetKeys={targetKeys}
onChange={handleChange}
render={item => item.title}
listStyle={{
width: 250,
height: 300,
}}
/>
</div>
)
}
return (
<>
<Modal size="lg" style={{maxWidth: '600px', width: '100%'}} isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>Add Customer</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>Save</Button>{' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Cancel</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogAssignCust;

3139
src/views/SimproV2/CreatedProyek/index.js

File diff suppressed because it is too large Load Diff

217
src/views/SimproV2/Gantt/index.js

@ -1,103 +1,114 @@
import React, { useEffect, useMemo, useState } from 'react';
import Timeline from 'react-calendar-timeline'
import 'react-calendar-timeline/lib/Timeline.css'
import { USER_VERSION_GANTT_SEARCH, BASE_SIMPRO_LUMEN, BASE_URL_GANTT } from '../../../const/ApiConst';
import axios from "../../../const/interceptorApi"
import { Fab, Action } from 'react-tiny-fab';
import 'react-tiny-fab/dist/styles.css';
import { useHistory } from "react-router-dom";
import GanttFrame from './GanttFrame';
const token = localStorage.getItem("token")
const userId = parseInt(localStorage.getItem("user_id"));
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
let roCount = 0;
const Gantt = (props) => {
const versionGanttId = props.match.params ? props.match.params.id : 0;
const idProject = props.match.params.project ? props.match.params.project : 0;
const timestamp = props.match.params.timestamp ? props.match.params.timestamp : 0;
const [ro, setRo] = useState(1)
const [listUserGant, setListUserGantt] = useState([])
const [ready, setReady] = useState(false)
let history = useHistory();
useEffect(() => {
document.getElementsByClassName("breadcrumb-item active").innerHTML = "Gantt Project";
getDataUserGantt();
}, []);
useEffect(() => {
cekPermission();
}, [listUserGant])
useEffect(() => {
}, [ro])
const getDataUserGantt = async () => {
const payload = {
"columns": [
{ "name": "version_gantt_id", "logic_operator": "=", "value": versionGanttId, "operator": "AND" }
]
}
const result = await axios
.post(USER_VERSION_GANTT_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.status == 200) {
setUserGantt(result.data.data);
} else {
cekPermission()
}
}
const setUserGantt = (data) => {
let newTargetKeys = []
data.map((val, index) => {
newTargetKeys.push(val.user_id)
});
setListUserGantt(newTargetKeys)
}
const handleRedirect = () => {
history.push("/dashboard-project/"+idProject+"/"+versionGanttId);
}
const cekPermission = () => {
let check = listUserGant.includes(userId)
if (check) {
setRo(0)
} else {
setRo(1)
}
if (roCount >= 1) {
setReady(true)
}
roCount = roCount + 1;
}
return (
<>
<div style={{ margin: "-15px", marginBottom: "-30px" }}>
{ready && (
<GanttFrame
versionGanttId={versionGanttId}
idProject={idProject}
token={token}
ro={ro}
timestamp={timestamp}
/>
)}
</div>
</>
);
}
export default Gantt;
import React, { useEffect, useMemo, useState } from "react";
import Timeline from "react-calendar-timeline";
import "react-calendar-timeline/lib/Timeline.css";
import {
USER_VERSION_GANTT_SEARCH,
BASE_SIMPRO_LUMEN,
BASE_URL_GANTT,
} from "../../../const/ApiConst";
import axios from "../../../const/interceptorApi";
import { Fab, Action } from "react-tiny-fab";
import "react-tiny-fab/dist/styles.css";
import { useHistory } from "react-router-dom";
import GanttFrame from "./GanttFrame";
const token = localStorage.getItem("token");
const userId = parseInt(localStorage.getItem("user_id"));
const HEADER = {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
};
let roCount = 0;
const Gantt = (props) => {
const versionGanttId = props.match.params ? props.match.params.id : 0;
const idProject = props.match.params.project ? props.match.params.project : 0;
const timestamp = props.match.params.timestamp
? props.match.params.timestamp
: 0;
const [ro, setRo] = useState(1);
const [listUserGant, setListUserGantt] = useState([]);
const [ready, setReady] = useState(false);
let history = useHistory();
useEffect(() => {
document.getElementsByClassName("breadcrumb-item active").innerHTML =
"Gantt Project";
getDataUserGantt();
}, []);
useEffect(() => {
cekPermission();
}, [listUserGant]);
useEffect(() => {}, [ro]);
const getDataUserGantt = async () => {
const payload = {
columns: [
{
name: "version_gantt_id",
logic_operator: "=",
value: versionGanttId,
operator: "AND",
},
],
};
const result = await axios
.post(USER_VERSION_GANTT_SEARCH, payload, HEADER)
.then((res) => res)
.catch((error) => error.response);
if (result && result.status == 200) {
setUserGantt(result.data.data);
} else {
cekPermission();
}
};
const setUserGantt = (data) => {
let newTargetKeys = [];
data.map((val, index) => {
newTargetKeys.push(val.user_id);
});
setListUserGantt(newTargetKeys);
};
const handleRedirect = () => {
history.push("/dashboard-project/" + idProject + "/" + versionGanttId);
};
const cekPermission = () => {
let check = listUserGant.includes(userId);
if (check) {
setRo(0);
} else {
setRo(1);
}
if (roCount >= 1) {
setReady(true);
}
roCount = roCount + 1;
};
return (
<>
<div style={{ margin: "-15px", marginBottom: "-30px" }}>
{ready && (
<GanttFrame
versionGanttId={versionGanttId}
idProject={idProject}
token={token}
ro={ro}
timestamp={timestamp}
/>
)}
</div>
</>
);
};
export default Gantt;

Loading…
Cancel
Save