Browse Source

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

Reviewed-on: ibnu/generic-ospro-frontend#56
pull/2/head
farhantock 11 months ago
parent
commit
d33bc88c61
  1. 3
      public/index.html
  2. 28
      src/App.js
  3. 68
      src/const/ApiConst.js
  4. 5
      src/const/en.json
  5. 5
      src/const/id.json
  6. 49
      src/containers/DefaultLayout/DefaultHeader.js
  7. 61
      src/containers/DefaultLayout/DefaultLayout.js
  8. 10
      src/routes.js
  9. 494
      src/views/ControlMonitoringGantt/index.js
  10. 1725
      src/views/Master/MasterCompany/DialogForm.js
  11. 86
      src/views/Master/MasterCompany/index.js
  12. 430
      src/views/Master/MasterRoles/DialogMenuRoles.js
  13. 9
      src/views/Master/MasterRoles/index.js
  14. 26
      src/views/Master/MenuCompany/DialogMasterMenu.js
  15. 3
      src/views/Master/MenuCompany/index.js
  16. 959
      src/views/Master/Proyek/index.js
  17. 1
      src/views/Pages/Login/Login.js
  18. 33
      src/views/Pages/Page403/Page403.js
  19. 9
      src/views/Pages/Page403/Page403.test.js
  20. 6
      src/views/Pages/Page403/package.json
  21. 35
      src/views/Pages/Page404/Page404.js
  22. 9
      src/views/Pages/Page404/Page404.test.js
  23. 6
      src/views/Pages/Page404/package.json
  24. 35
      src/views/Pages/Page500/Page500.js
  25. 9
      src/views/Pages/Page500/Page500.test.js
  26. 6
      src/views/Pages/Page500/package.json
  27. 68
      src/views/Pages/Register/Register.js
  28. 9
      src/views/Pages/Register/Register.test.js
  29. 6
      src/views/Pages/Register/package.json
  30. 767
      src/views/SimproV2/Closing/index.js
  31. 2
      src/views/SimproV2/CreatedProyek/AsignCustProject.js
  32. 22
      src/views/SimproV2/CreatedProyek/DialogDocument.js
  33. 195
      src/views/SimproV2/CreatedProyek/FormDocument.js
  34. 16
      src/views/SimproV2/CreatedProyek/ImportActivity/index.js
  35. 265
      src/views/SimproV2/CreatedProyek/ReportAnalysis.js
  36. 6
      src/views/SimproV2/CreatedProyek/index.js
  37. 201
      src/views/SimproV2/Demo/DialogForm.js
  38. 367
      src/views/SimproV2/Demo/index.js
  39. 34
      src/views/SimproV2/Divisi/DialogForm.js
  40. 180
      src/views/SimproV2/Divisi/index.js
  41. 130
      src/views/SimproV2/Kanban/Column.js
  42. 72
      src/views/SimproV2/Kanban/DialogCard.js
  43. 347
      src/views/SimproV2/Kanban/DialogFormActivity.js
  44. 176
      src/views/SimproV2/Kanban/DialogFormBoard.js
  45. 69
      src/views/SimproV2/Kanban/DialogFormChild.js
  46. 438
      src/views/SimproV2/Kanban/DialogFormReport.js
  47. 136
      src/views/SimproV2/Kanban/Kanban.css
  48. 206
      src/views/SimproV2/Kanban/Task.js
  49. 912
      src/views/SimproV2/Kanban/index.js
  50. 6
      src/views/SimproV2/Profile/index.js
  51. 4
      src/views/SimproV2/ResourceWorker/DialogForm.js
  52. 278
      src/views/SimproV2/Satuan/DialogForm.js
  53. 2
      src/views/SimproV2/Satuan/index.js
  54. 148
      src/views/SimproV2/Settings/DialogForm.js
  55. 86
      src/views/SimproV2/Settings/index.js
  56. 46
      src/views/Users/User.js
  57. 15
      src/views/Users/User.test.js
  58. 78
      src/views/Users/Users.js
  59. 10
      src/views/Users/Users.test.js
  60. 31
      src/views/Users/UsersData.js
  61. 6
      src/views/Users/package.json

3
public/index.html

@ -14,7 +14,7 @@
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/OSPRO.ico">
<link rel="shortcut icon" href="">
<!-- <link rel="shortcut icon" href="%PUBLIC_URL%/favicon_bmd_denpasar.ico"> -->
<link rel="stylesheet" href="https://unpkg.com/@coreui/icons@1.0.0/css/all.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
@ -35,7 +35,6 @@
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-118965717-3"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}

28
src/App.js

@ -11,29 +11,10 @@ const loading = () => <div className="animated fadeIn pt-3 text-center">Loading.
const DefaultLayout = React.lazy(() => import('./containers/DefaultLayout'));
const Login = React.lazy(() => import('./views/Pages/Login'));
const Register = React.lazy(() => import('./views/Pages/Register'));
const Page403 = React.lazy(() => import('./views/Pages/Page403'));
const Page404 = React.lazy(() => import('./views/Pages/Page404'));
const Page500 = React.lazy(() => import('./views/Pages/Page500'));
const SiopasMap = React.lazy(() => import('./views/Map'));
class App extends Component {
componentDidMount() {
try {
const storedData = localStorage.getItem('configApp');
if (storedData !== null) {
const data = JSON.parse(storedData);
const htmlTitle = data.html_title || 'OSPRO';
document.title = htmlTitle;
} else {
document.title = 'OSPRO';
}
} catch (error) {
document.title = 'OSPRO';
}
}
render() {
return (
@ -42,14 +23,7 @@ class App extends Component {
<React.Suspense fallback={loading()}>
<Switch>
<Route exact path="/login" name="Login Page" render={props => <Login {...props} />} />
{/* <Route exact path="/home" name="Home" render={props => <DefaultLayout {...props}/>} /> */}
<Route exact path="/register" name="Register Page" render={props => <Register {...props} />} />
<Route exact path="/404" name="Page 404" render={props => <Page404 {...props} />} />
<Route exact path="/403" name="Page 403" render={props => <Page403 {...props} />} />
<Route exact path="/500" name="Page 500" render={props => <Page500 {...props} />} />
<Route exact path="/map/view" name="Map" render={props => <SiopasMap {...props} />} />
{/*<Route exact path="/layerswitcher" name="Layer Switcher" render={props => <LayerSwitcherExample {...props}/>} />*/}
{/*<Route exact path="/muidt" name="Mui Datatable Example" render={props => <MuiDatatablesExample {...props}/>} />*/}
<Route path="/" name="Home" render={props => <DefaultLayout {...props} />} />
</Switch>
</React.Suspense>

68
src/const/ApiConst.js

@ -122,6 +122,9 @@ export let BASE_OSPRO = "http://localhost:8444/generic-ospro-backend";
export let BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
export let BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`;
export let BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`;
export let BASE_SIMPRO_LUMEN_FILE_COMPANY = (file, company_name)=>{
return `${BASE_OSPRO}/assets/${company_name}/file/project/${file}`;
}
// switch (APP_MODE) {
// case 'KIT':
@ -277,10 +280,26 @@ export const USER_SYNC = `${BASE_SIMPRO_LUMEN}/human-resource/sync`;
export const USER_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/human-resource/update/${id}`;
};
export const USER_GET_ID = (id) => {
return `${BASE_SIMPRO_LUMEN}/human-resource/edit/${id}`;
};
export const USER_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/human-resource/delete/${id}`;
};
export const HUMAN_RESOURCE_LIST = `${BASE_SIMPRO_LUMEN}/human-resource`
export const USER_TO_ACTIVITY_ADD = `${BASE_SIMPRO_LUMEN}/user-to-activity/add`
export const USER_TO_ACTIVITY_DELETE = (id) => { return `${BASE_SIMPRO_LUMEN}/user-to-activity/delete/${id}` }
export const REFFERAL_ADD = `${BASE_SIMPRO_LUMEN}/refferal-code/add`;
export const REFFERAL_SEARCH = `${BASE_SIMPRO_LUMEN}/refferal-code/search`;
export const REFFERAL_GET_ID = (id) => {
return `${BASE_SIMPRO_LUMEN}/refferal-code/edit/${id}`;
};
export const REFFERAL_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/refferal-code/update/${id}`;
};
export const ABSENSI_ADD = `${BASE_SIMPRO_LUMEN}/permit/add`;
export const ABSENSI_SEARCH = `${BASE_SIMPRO_LUMEN}/permit/search`;
export const ABSENSI_EDIT = (id) => {
@ -307,11 +326,11 @@ export const DOCUMENT_SEARCH = `${BASE_SIMPRO_LUMEN}/document-project/search`;
export const DOCUMENT_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/document-project/update/${id}`;
};
export const DOCUMENT_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/document-project/delete/${id}`;
export const DOCUMENT_DELETE = (id, company_id) => {
return `${BASE_SIMPRO_LUMEN}/document-project/delete/${id}/${company_id}`;
};
export const DOCUMENT_DOWNLOAD = (id) => {
return `${BASE_SIMPRO_LUMEN}/document-project/download/${id}`;
export const DOCUMENT_DOWNLOAD = (id, company_id) => {
return `${BASE_SIMPRO_LUMEN}/document-project/download/${id}/${company_id}`;
};
export const ROLE_ADD = `${BASE_SIMPRO_LUMEN}/role/add`;
@ -423,8 +442,8 @@ export const PROYEK_GET_ID = (id) => {
export const PROYEK_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/project/update/${id}`;
};
export const PROYEK_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/project/delete/${id}`;
export const PROYEK_DELETE = (id, company_id) => {
return `${BASE_SIMPRO_LUMEN}/project/delete/${id}/${company_id}`;
};
export const PROJECT_ROLE_ADD = `${BASE_SIMPRO_LUMEN}/project-role/add`;
@ -576,6 +595,15 @@ export const DIVISI_DELETE = (id) => {
};
export const DIVISI_LIST = `${BASE_SIMPRO_LUMEN}/divisi/list`;
export const KANBAN_BOARD_LIST = `${BASE_SIMPRO_LUMEN}/kanban-board/list`
export const KANBAN_BOARD_ADD = `${BASE_SIMPRO_LUMEN}/kanban-board/add`
export const KANBAN_BOARD_EDIT = (id) => { return `${BASE_SIMPRO_LUMEN}/kanban-board/update/${id}` }
export const KANBAN_BOARD_DELETE = (id) => { return `${BASE_SIMPRO_LUMEN}/kanban-board/delete/${id}` }
export const KANBAN_CARD_LIST = `${BASE_SIMPRO_LUMEN}/kanban-card/get-data`
export const KANBAN_CARD_ADD = `${BASE_SIMPRO_LUMEN}/task`
export const KANBAN_CARD_EDIT = (id) => { return `${BASE_SIMPRO_LUMEN}/kanban-card/update/${id}` }
export const SHIFT_ADD = `${BASE_SIMPRO_LUMEN}/shift/add`;
export const SHIFT_SEARCH = `${BASE_SIMPRO_LUMEN}/shift/search`;
export const SHIFT_EDIT = (id) => {
@ -700,8 +728,8 @@ export const ASSIGN_HR_PROJECT_SEARCH = `${BASE_SIMPRO_LUMEN}/user-to-proyek/sea
export const ASSIGN_HR_PROJECT_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/user-to-proyek/update/${id}`;
};
export const ASSIGN_HR_PROJECT_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/user-to-proyek/delete/${id}`;
export const ASSIGN_HR_PROJECT_DELETE = (id, company_id) => {
return `${BASE_SIMPRO_LUMEN}/user-to-proyek/delete/${id}/${company_id}`;
};
export const ASSIGN_HR_PROJECT_LIST = `${BASE_SIMPRO_LUMEN}/user-to-proyek/list`;
@ -771,9 +799,12 @@ export const HIERARCHY_FTTH_COUNT_TREE = (id) => {
export const WAYPOINT_SEARCH = `${BASE_SIMPRO_LUMEN}/waypoint/search`;
export const IMAGE_UPLOAD = `${BASE_SIMPRO_LUMEN}/image/upload`;
export const IMAGE_DELETE = (id, category) => {
return `${BASE_SIMPRO_LUMEN}/image/delete/${id}/${category}`;
export const IMAGE_MULTIPLE_UPLOAD = `${BASE_SIMPRO_LUMEN}/image/multiple-upload`;
export const IMAGE_MULTIPLE_DELETE = (id, category, company_id) => {
return `${BASE_SIMPRO_LUMEN}/image/multiple-delete/${id}/${category}/${company_id}`;
}
export const IMAGE_DELETE = (id, category, company_id) => {
return `${BASE_SIMPRO_LUMEN}/image/delete/${id}/${category}/${company_id}`;
}
@ -803,3 +834,18 @@ export const MENU_COMPANY_EDIT = (id) => {
export const MENU_COMPANY_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/menu-company/delete/${id}`;
};
export const DEMO_MANAGEMENT_ADD = `${BASE_SIMPRO_LUMEN}/demo-management/add`;
export const DEMO_MANAGEMENT_SEARCH = `${BASE_SIMPRO_LUMEN}/demo-management/search`;
export const DEMO_MANAGEMENT_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/demo-management/update/${id}`;
};
export const DEMO_MANAGEMENT_GET_ID = (id) => {
return `${BASE_SIMPRO_LUMEN}/demo-management/edit/${id}`;
};
export const DEMO_MANAGEMENT_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/demo-management/delete/${id}`;
};
export const DEMO_MANAGEMENT_LIST = `${BASE_SIMPRO_LUMEN}/demo-management/list`;

5
src/const/en.json

@ -34,6 +34,7 @@
"description": "Description",
"division": "Division",
"divisionAdd": "Add Division",
"demoAdd": "Add Demo",
"employeeType": "Employee Type",
"edit": "Edit",
"export": "Export",
@ -66,6 +67,8 @@
"inputEmail": "Input Email",
"inputNoPhone": "Input Phone Number",
"inputNik": "Input NIK (KTP)",
"inputMessage": "Input Message",
"inputRole": "Input Role",
"image": "Image",
"imageCheck": "Selfie Presence",
"locIn": "Location In",
@ -100,6 +103,7 @@
"presenceIn": "Presence In",
"presenceOut": "Presence Out",
"panicButton": "Panic Button",
"phoneNumber": "Phone Number",
"price": "Price",
"qty": "QTY",
"qtyReceived": "QTY Received",
@ -114,6 +118,7 @@
"search": "Search",
"save": "Save",
"saveSend": "Save & Send",
"searchDemo": "Search Data Demo",
"searchType": "Search Project Type",
"searchPhase": "Search Project Phase",
"searchDivision": "Search Division",

5
src/const/id.json

@ -34,6 +34,7 @@
"description": "Deskripsi",
"division": "Divisi",
"divisionAdd": "Tambah Divisi",
"demoAdd": "Tambah Demo",
"edit": "Ubah",
"export": "Ekspor",
"exportExcel": "Ekspor Excel",
@ -66,6 +67,8 @@
"inputEmail": "Masukan Email",
"inputNoPhone": "Masukan No Telp",
"inputNik": "Masukan NIK (KTP)",
"inputMessage": "Masukan Pesan",
"inputRole": "Masukan Peran",
"image": "Gambar",
"imageCheck": "Lihat Selfie Presensi",
"locIn": "Lokasi Masuk",
@ -100,6 +103,7 @@
"presenceIn": "Waktu Masuk",
"presenceOut": "Waktu Pulang",
"panicButton": "Tombol Panik",
"phoneNumber": "No Telepon",
"price": "Harga",
"qty": "Kuantitas",
"qtyReceived": "Kuantitas Diterima",
@ -116,6 +120,7 @@
"search": "Cari",
"searchType": "Cari Tipe Proyek",
"searchPhase": "Cari Fase Proyek",
"searchDemo": "Cari Data Demo",
"searchDivision": "Cari Divisi",
"searchUom": "Cari Satuan",
"searchChecklistK3": "Cari Ceklis K3",

49
src/containers/DefaultLayout/DefaultHeader.js

@ -3,23 +3,17 @@ import { NavLink } from 'react-router-dom';
import { Badge, Nav, NavItem } from 'reactstrap';
import PropTypes from 'prop-types';
import { Menu, Dropdown } from 'antd'
import { ALERTUSER_SEARCH, ALERT_SEARCH, ALERTUSER_STATUSVIEW, ALERT_STATUSVIEW, APP_MODE } from '../../const/ApiConst';
import { ALERTUSER_SEARCH, ALERT_SEARCH, ALERTUSER_STATUSVIEW, ALERT_STATUSVIEW, APP_MODE, BASE_SIMPRO_LUMEN_IMAGE } from '../../const/ApiConst';
import { AppAsideToggler, AppNavbarBrand, AppSidebarToggler } from '@coreui/react';
import logo_ospro from '../../assets/img/OSPRO.png'
import axios from 'axios';
import './Default.css'
const token = window.localStorage.getItem('token');
const propTypes = {
children: PropTypes.node,
};
const config = {
headers:
{
Authorization: `Bearer ${token}`,
"Content-type": `application/json`
}
};
const defaultProps = {};
@ -42,8 +36,32 @@ class DefaultHeader extends Component {
componentDidMount() {
this.getHeaderMenu();
const token = window.localStorage.getItem('token');
const role = window.localStorage.getItem('role_name');
if (role !== 'Super Admin') {
this.setState({
configApp: JSON.parse(window.localStorage.getItem('configApp')),
});
}
this.setState({
config: {
headers: {
Authorization: `Bearer ${token}`,
'Content-type': `application/json`,
},
},
});
}
getLogoHeaderContent = () => {
const { configApp } = this.state;
const logoHeaderContent = configApp && configApp.logo_header ? configApp.logo_header.content : null;
return logoHeaderContent
? `${BASE_SIMPRO_LUMEN_IMAGE}/${logoHeaderContent}`
: logo_ospro;
};
componentDidUpdate(prevProps, prevState) {
if (this.state.listReadNotif !== prevState.listReadNotif) {
if (this.state.listReadNotif.length > 0) {
@ -107,7 +125,7 @@ class DefaultHeader extends Component {
}
const result = await axios
.post(url, payload, config)
.post(url, payload, this.state.config)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
@ -178,14 +196,14 @@ class DefaultHeader extends Component {
if (parseInt(localStorage.getItem('role_id')) === 1) {
data.map((val, index) => {
let url = ALERT_STATUSVIEW(val)
promises.push(axios.put(url, payload, config)
promises.push(axios.put(url, payload, this.state.config)
.then(res => result.push(res)));
});
} else {
data.map((val, index) => {
let url = ALERTUSER_STATUSVIEW(val)
promises.push(axios.put(url, payload, config)
promises.push(axios.put(url, payload, this.state.config)
.then(res => result.push(res)))
});
}
@ -199,11 +217,14 @@ class DefaultHeader extends Component {
getLogo = () => {
return (
<div style={{ width: '10%', display: 'flex', justifyContent: 'center' }}>
<img style={{ width: '100%', height: '100%' }} src={logo_ospro} />
<img
style={{ width: '100%', height: '100%' }}
src={this.getLogoHeaderContent()}
/>
</div>
)
}
// logo_ospro
getHeaderMenu = () => {
const { fullname, u_group } = this.state;
if (u_group == 'kominfo') {

61
src/containers/DefaultLayout/DefaultLayout.js

@ -3,7 +3,7 @@ import { Redirect, Route, Switch, withRouter } from 'react-router-dom';
import * as router from 'react-router-dom';
import { Button, Container, UncontrolledDropdown, DropdownItem, DropdownMenu, DropdownToggle, Nav, NavItem } from 'reactstrap';
import axios from 'axios';
import { ALERTUSER_SEARCH, ALERT_SEARCH, MENU_SEARCH, ROLEMENU_SEARCH, ALERTUSER_STATUSVIEW, ALERT_STATUSVIEW, MENU_MANAGEMENT, CONTROL_MONITORING_SEARCH } from '../../const/ApiConst';
import { BASE_SIMPRO_LUMEN_IMAGE, MENU_MANAGEMENT } from '../../const/ApiConst';
import { handleChangeLng } from "../../utils/LangUtils";
import {
AppAside,
@ -63,8 +63,6 @@ class DefaultLayout extends Component {
company_id: company_id
};
}
async componentDidMount() {
const menu = localStorage.getItem("menu_login")
if (menu) this.setMenu(JSON.parse(menu))
@ -72,6 +70,53 @@ class DefaultLayout extends Component {
if (!localStorage.getItem("token")) {
this.signOut();
}
window.myData = "Data dari komponen React";
try {
const storedData = localStorage.getItem('configApp');
if (storedData !== null) {
const data = JSON.parse(storedData);
const faviconContent = data && data.favicon_image ? `${BASE_SIMPRO_LUMEN_IMAGE}/${data.favicon_image.content}` : null;
const htmlTitle = data.html_title || 'OSPRO';
document.title = htmlTitle;
if (faviconContent) {
this.setFavicon(faviconContent);
}
} else {
document.title = 'OSPRO';
}
} catch (error) {
document.title = 'OSPRO';
}
}
setFavicon = (faviconContent) => {
const existingFavicon = document.querySelector("link[rel='icon']");
if (existingFavicon) {
document.head.removeChild(existingFavicon);
}
const faviconElement = document.createElement('link');
faviconElement.rel = 'icon';
const fileExtension = faviconContent ? faviconContent.split('.').pop().toLowerCase() : '';
switch (fileExtension) {
case 'svg':
faviconElement.type = 'image/svg+xml';
break;
case 'ico':
faviconElement.type = 'image/x-icon';
break;
default:
faviconElement.type = 'image/png';
}
console.log('faviconElement.type', faviconElement.type);
console.log('faviconContent', faviconContent);
faviconElement.href = faviconContent || `${process.env.PUBLIC_URL}/OSPRO.ico`;
document.head.appendChild(faviconElement);
}
componentDidUpdate(prevProps, prevState) {
@ -120,6 +165,7 @@ class DefaultLayout extends Component {
await localStorage.removeItem("role_id");
await localStorage.removeItem("company_id");
document.getElementById('title').innerText = 'OSPRO';
this.setFavicon(`${process.env.PUBLIC_URL}/OSPRO.ico`);
await window.localStorage.clear();
this.props.history.replace('/login')
}
@ -269,9 +315,12 @@ class DefaultLayout extends Component {
return (
<div className="app">
{/* <AppHeader fixed>
<DefaultHeader />
</AppHeader> */}
{!window.location.href.includes("false-header") && (
<AppHeader fixed>
<DefaultHeader />
</AppHeader>
)
}
<div className="app-body">
{!window.location.href.includes("dashboard-project") || renderSidebar ? (
<AppSidebar minimized={this.state.minimized} fixed display="lg">

10
src/routes.js

@ -47,6 +47,7 @@ const Shift = React.lazy(() => import('./views/SimproV2/Shift'));
const TestGantt = React.lazy(() => import('./views/testgantt'));
const UserAdmin = React.lazy(() => import('./views/Master/UserAdmin'));
const UserShift = React.lazy(() => import('./views/SimproV2/UserShift'));
const Kanban = React.lazy(() => import('./views/SimproV2/Kanban'));
// const DashboardProject = React.lazy(() => import('./views/DashboardProject'));
const DashboardBOD = React.lazy(() => import('./views/Dashboard/DashboardBOD'));
const DashboardCustomer = React.lazy(() => import('./views/Dashboard/DashboardCustomer'));
@ -55,11 +56,12 @@ const DashboardProjectCarousell = React.lazy(() => import('./views/Dashboard/Das
const MapMonitoring = React.lazy(() => import('./views/MapMonitoring'));
const Settings = React.lazy(() => import('./views/SimproV2/Settings'));
const CompanyManagement = React.lazy(() => import('./views/Master/MasterCompany'))
const DemoManagement = React.lazy(() => import('./views/SimproV2/Demo'))
const routes = [
{ path: '/', exact: true, name: 'Home' },
{ path: '/dashboard', name: 'DashboardBOD', component: DashboardBOD },
{ path: '/dashboard-customer/:PROJECT_ID/:GANTT_ID/:SCURVE', name: 'DashboardCustomer', component: DashboardCustomer },
{ path: '/dashboard-project/:PROJECT_ID/:GANTT_ID', exact: true, name: 'Dashboard Project', component: DashboardProject },
{ path: '/dashboard-project/:PROJECT_ID/:GANTT_ID/:Header', exact: true, name: 'Dashboard Project', component: DashboardProject },
{ path: '/dashboard-perproject', exact: true, name: 'Dashboard Project Carousell', component: DashboardProjectCarousell },
{ path: '/dashboard-project/:PROJECT_ID/:GANTT_ID/:SCURVE', exact: true, name: 'Dashboard Project', component: DashboardProject },
{ path: '/projects', exact: true, name: 'Projects', component: CreatedProyek },
@ -70,7 +72,6 @@ const routes = [
{ path: '/human-resource', exact: true, name: 'Human Resource', component: ResourceWorker },
{ path: '/material-resource', exact: true, name: 'Material Resource', component: ResourceMaterial },
{ path: '/tools-resource', exact: true, name: 'Tools Resource', component: ResourceTools },
{ path: '/control-monitoring', exact: true, name: 'Control Monitoring', component: ControlMonitoring },
{ path: '/control-monitoring-gantt', exact: true, name: 'Control Monitoring Gantt', component: ControlMonitoringGantt },
{ path: '/presensi-resource', exact: true, name: 'Presensi Resource', component: Presensi },
@ -78,9 +79,9 @@ const routes = [
{ path: '/laporan-k3', exact: true, name: 'Laporan K3', component: K3 },
{ path: '/broadcast', exact: true, name: 'Broadcast', component: Broadcast },
{ path: '/panic-button', exact: true, name: 'Tombol Darurat', component: PanicButton },
{ path: '/kanban', exact: true, name: 'Kanban', component: Kanban },
{ path: '/kanban/:proyek_id/:version_gantt_id', exact: true, name: 'Kanban', component: Kanban },
{ path: '/closing', exact: true, name: 'Closing', component: Closing },
{ path: '/menu', exact: true, name: 'Menu', component: Menu },
{ path: '/roles', exact: true, name: 'Roles', component: Roles },
{ path: '/project-role', exact: true, name: 'Project Role', component: ProjectRole },
@ -119,6 +120,7 @@ const routes = [
// { path: '/dashboard-project/:ID/:GANTTID', exact: true, name: 'Dashboard Project', component: DashboardProject },
{ path: '/settings', exact: true, name: 'Settings', component: Settings },
{ path: '/company-management', exact: true, name: 'Company Management', component: CompanyManagement },
{ path: '/demo-management', exact: true, name: 'Demo Management', component: DemoManagement },
];
export default routes;

494
src/views/ControlMonitoringGantt/index.js

@ -1,247 +1,247 @@
import React, { useEffect, useMemo, useState } from 'react';
import Timeline from 'react-calendar-timeline'
import 'react-calendar-timeline/lib/Timeline.css'
import moment from 'moment';
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH_DETAIL, GANTT_CONTROL_MONITORING_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../const/ApiConst';
import axios from 'axios';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Button } from 'antd';
import {
Container, Col, Row, UncontrolledTooltip,
Card,
CardBody,
CardHeader,
Table,
Modal, ModalHeader, ModalBody, ModalFooter
} from 'reactstrap';
import GanttFull from './GanttDhtmlx2';
import DialogForm from '../Master/Proyek/DialogForm';
import DialogFormSub from '../Master/Proyek/DialogFormSub';
import Iframe from "@nicholasadamou/react-iframe";
const getUrlParameter = (sParam) => {
var sPageURL = window.location.search.substring(1),
sURLVariables = sPageURL.split('&'),
sParameterName,
i;
for (i = 0; i < sURLVariables.length; i++) {
sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
}
}
return false;
};
const GanttTimeLine = () => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [proyekId, setProyekId] = useState(15);
const [dataGantt, setDataGantt] = useState([]);
const [prevProyekId, setPrevProyekId] = useState(0);
const [dataGroupGantt, setDataGroupGantt] = useState([]);
const [maxDateGantt, setMaxDateGantt] = useState(null);
const [minDateGantt, setMinDateGantt] = useState(null);
const [dataAllTimeLine, setDataAllTimeLine] = useState([]);
const [prevDataAllTimeLine, setPrevDataAllTimeLine] = useState(null);
const [idTask, setidTask] = useState(0);
const [dataTable, setDatatable] = useState([])
const [search, setSearch] = useState('')
const [currentPage, setCurrentPage] = useState(1)
const [totalPage, setTotalPage] = useState(0)
const [openDialog, setOpenDialog] = useState(false)
const [openDialogSub, setOpenDialogSub] = useState(false)
const [typeDialog, setTypeDialog] = useState('Save');
const [typeDialogSub, setTypeDialogSub] = useState('Save')
const [idDelete, setIdDelete] = useState(0)
const [alertDelete, setAlertDelete] = useState(false)
const [dataEdit, setDataEdit] = useState([])
const [dataEditSub, setDataEditSub] = useState([])
const [rowsPerPage, setRowsPerPage] = useState(10)
const [clickOpenModal, setClickOpenModal] = useState(false)
const [dataExport, setDataExport] = useState([])
const [allDataMenu, setAllDataMenu] = useState([])
const [idSubtask, setIdSubtask] = useState(0);
const handleMappingDataGantt = (data) => {
const minDates = data.map(res => moment(res.mulai_proyek)),
minDate = moment.min(minDates)
const maxDates = data.map(res => moment(res.akhir_proyek)),
maxDate = moment.max(maxDates)
let groups = []
let items = []
data.map((res, idx) => {
let group = {
id: res.id,
title: res.nama,
stackItems: true,
height: 50
}
let item = {
id: res.id,
group: res.id,
title: res.pic,
start_time: moment(res.mulai_proyek),
end_time: moment(res.akhir_proyek),
}
groups.push(group)
items.push(item)
})
setDataGantt(items)
setDataGroupGantt(groups)
setMaxDateGantt(maxDate)
setMinDateGantt(minDate)
}
const handleGetDataProyek = async () => {
const payload = {
"columns": [
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" }
],
"joins": [
{ "name": "subproyeks.m_proyek", "column_join": "proyek_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] },
{ "name": "subproyeks.m_subproyek", "column_join": "parent_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] }
],
"orders": { "columns": ["id"], "ascending": true },
"paging": { "start": 0, "length": 25 }
}
const result = await axios
.post(GANTT_CONTROL_MONITORING_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
const { data } = result.data
setDataAllTimeLine(data)
setPrevDataAllTimeLine(data)
handleMappingDataGantt(data)
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
useEffect(() => {
let proyek_id = getUrlParameter('proyek_id');
if (proyek_id) {
setProyekId(proyek_id);
}
handleGetDataProyek()
}, []);
const handleClickGroupGantt = param => {
const row = prevDataAllTimeLine.filter(res => res.id === param)
if (row.length > 0) {
const { subproyeks, proyek_id, parent_id } = row[0]
setPrevProyekId(parent_id || proyek_id)
handleMappingDataGantt(subproyeks)
setDataAllTimeLine(subproyeks)
}
}
const handleOpenDialog = (type) => {
setOpenDialog(true)
setTypeDialog(type)
}
const handleOpenDialogSub = (type, param) => {
const { id, parent_id, proyek_id, parent } = param
const idParent = parent == 0 ? 0 : parent == proyek_id ? id : parent_id
setidTask(proyek_id)
setIdSubtask(idParent)
setOpenDialogSub(true)
setTypeDialogSub(type)
}
const handleCloseDialog = (type, data) => {
if (type === "save") {
saveProyek(data);
}
setDataEdit([])
setOpenDialog(false)
}
const handleCloseDialogSub = (type, data) => {
setDataEditSub([])
setOpenDialogSub(false)
if (type !== "cancel") {
handleGetDataProyek()
}
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
const toggleAddDialogSub = () => {
setOpenDialogSub(!openDialogSub)
}
const saveProyek = async (data) => {
const formData = data
const result = await axios.post(PROYEK_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
handleGetDataProyek()
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!');
} else {
NotificationManager.error(`${result.data.message}`, 'Failed!!');
}
}
const RenderGantt = useMemo(() => (
<GanttFull
handleOpenDialogSub={handleOpenDialogSub}
data={dataAllTimeLine}
startDate={minDateGantt ? minDateGantt.format("YYYY-MM-DD HH:mm:ss") : moment().add(-40, 'days').format("YYYY-MM-DD HH:mm:ss")}
endDate={maxDateGantt ? maxDateGantt.format("YYYY-MM-DD HH:mm:ss") : moment().add(40, 'days').format("YYYY-MM-DD HH:mm:ss")}
/>
), [dataAllTimeLine, maxDateGantt, minDateGantt])
return (
<div>
{/* {RenderGantt} */}
{/* <iframe id="frame-embedd" src="http://localhost/jQueryGantt/gantt.html"
style={{
width: '100%',
height: '75vh',
}}
scrolling="no"
frameBorder="0"
></iframe> */}
<Iframe
src={`http://siopas.co.id/simpro-gantt/gantt.html?proyek_id=${proyekId}&token=${localStorage.getItem('token')}`}
headers={{
}}
style={{
width: '100%',
height: '75vh',
}}
scrolling="no"
frameBorder="0"
/>
</div>
);
}
export default GanttTimeLine;
import React, { useEffect, useMemo, useState } from 'react';
import Timeline from 'react-calendar-timeline'
import 'react-calendar-timeline/lib/Timeline.css'
import moment from 'moment';
import { BASE_SIMPRO, PROYEK_ADD, GANTT_CONTROL_MONITORING_SEARCH } from '../../const/ApiConst';
import axios from 'axios';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Button } from 'antd';
import {
Container, Col, Row, UncontrolledTooltip,
Card,
CardBody,
CardHeader,
Table,
Modal, ModalHeader, ModalBody, ModalFooter
} from 'reactstrap';
import GanttFull from './GanttDhtmlx2';
import DialogForm from '../Master/Proyek/DialogForm';
import DialogFormSub from '../Master/Proyek/DialogFormSub';
import Iframe from "@nicholasadamou/react-iframe";
const getUrlParameter = (sParam) => {
var sPageURL = window.location.search.substring(1),
sURLVariables = sPageURL.split('&'),
sParameterName,
i;
for (i = 0; i < sURLVariables.length; i++) {
sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
}
}
return false;
};
const GanttTimeLine = () => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [proyekId, setProyekId] = useState(15);
const [dataGantt, setDataGantt] = useState([]);
const [prevProyekId, setPrevProyekId] = useState(0);
const [dataGroupGantt, setDataGroupGantt] = useState([]);
const [maxDateGantt, setMaxDateGantt] = useState(null);
const [minDateGantt, setMinDateGantt] = useState(null);
const [dataAllTimeLine, setDataAllTimeLine] = useState([]);
const [prevDataAllTimeLine, setPrevDataAllTimeLine] = useState(null);
const [idTask, setidTask] = useState(0);
const [dataTable, setDatatable] = useState([])
const [search, setSearch] = useState('')
const [currentPage, setCurrentPage] = useState(1)
const [totalPage, setTotalPage] = useState(0)
const [openDialog, setOpenDialog] = useState(false)
const [openDialogSub, setOpenDialogSub] = useState(false)
const [typeDialog, setTypeDialog] = useState('Save');
const [typeDialogSub, setTypeDialogSub] = useState('Save')
const [idDelete, setIdDelete] = useState(0)
const [alertDelete, setAlertDelete] = useState(false)
const [dataEdit, setDataEdit] = useState([])
const [dataEditSub, setDataEditSub] = useState([])
const [rowsPerPage, setRowsPerPage] = useState(10)
const [clickOpenModal, setClickOpenModal] = useState(false)
const [dataExport, setDataExport] = useState([])
const [allDataMenu, setAllDataMenu] = useState([])
const [idSubtask, setIdSubtask] = useState(0);
const handleMappingDataGantt = (data) => {
const minDates = data.map(res => moment(res.mulai_proyek)),
minDate = moment.min(minDates)
const maxDates = data.map(res => moment(res.akhir_proyek)),
maxDate = moment.max(maxDates)
let groups = []
let items = []
data.map((res, idx) => {
let group = {
id: res.id,
title: res.nama,
stackItems: true,
height: 50
}
let item = {
id: res.id,
group: res.id,
title: res.pic,
start_time: moment(res.mulai_proyek),
end_time: moment(res.akhir_proyek),
}
groups.push(group)
items.push(item)
})
setDataGantt(items)
setDataGroupGantt(groups)
setMaxDateGantt(maxDate)
setMinDateGantt(minDate)
}
const handleGetDataProyek = async () => {
const payload = {
"columns": [
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" }
],
"joins": [
{ "name": "subproyeks.m_proyek", "column_join": "proyek_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] },
{ "name": "subproyeks.m_subproyek", "column_join": "parent_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] }
],
"orders": { "columns": ["id"], "ascending": true },
"paging": { "start": 0, "length": 25 }
}
const result = await axios
.post(GANTT_CONTROL_MONITORING_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
const { data } = result.data
setDataAllTimeLine(data)
setPrevDataAllTimeLine(data)
handleMappingDataGantt(data)
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
useEffect(() => {
let proyek_id = getUrlParameter('proyek_id');
if (proyek_id) {
setProyekId(proyek_id);
}
handleGetDataProyek()
}, []);
const handleClickGroupGantt = param => {
const row = prevDataAllTimeLine.filter(res => res.id === param)
if (row.length > 0) {
const { subproyeks, proyek_id, parent_id } = row[0]
setPrevProyekId(parent_id || proyek_id)
handleMappingDataGantt(subproyeks)
setDataAllTimeLine(subproyeks)
}
}
const handleOpenDialog = (type) => {
setOpenDialog(true)
setTypeDialog(type)
}
const handleOpenDialogSub = (type, param) => {
const { id, parent_id, proyek_id, parent } = param
const idParent = parent == 0 ? 0 : parent == proyek_id ? id : parent_id
setidTask(proyek_id)
setIdSubtask(idParent)
setOpenDialogSub(true)
setTypeDialogSub(type)
}
const handleCloseDialog = (type, data) => {
if (type === "save") {
saveProyek(data);
}
setDataEdit([])
setOpenDialog(false)
}
const handleCloseDialogSub = (type, data) => {
setDataEditSub([])
setOpenDialogSub(false)
if (type !== "cancel") {
handleGetDataProyek()
}
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
const toggleAddDialogSub = () => {
setOpenDialogSub(!openDialogSub)
}
const saveProyek = async (data) => {
const formData = data
const result = await axios.post(PROYEK_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
handleGetDataProyek()
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!');
} else {
NotificationManager.error(`${result.data.message}`, 'Failed!!');
}
}
const RenderGantt = useMemo(() => (
<GanttFull
handleOpenDialogSub={handleOpenDialogSub}
data={dataAllTimeLine}
startDate={minDateGantt ? minDateGantt.format("YYYY-MM-DD HH:mm:ss") : moment().add(-40, 'days').format("YYYY-MM-DD HH:mm:ss")}
endDate={maxDateGantt ? maxDateGantt.format("YYYY-MM-DD HH:mm:ss") : moment().add(40, 'days').format("YYYY-MM-DD HH:mm:ss")}
/>
), [dataAllTimeLine, maxDateGantt, minDateGantt])
return (
<div>
{/* {RenderGantt} */}
{/* <iframe id="frame-embedd" src="http://localhost/jQueryGantt/gantt.html"
style={{
width: '100%',
height: '75vh',
}}
scrolling="no"
frameBorder="0"
></iframe> */}
<Iframe
src={`http://siopas.co.id/simpro-gantt/gantt.html?proyek_id=${proyekId}&token=${localStorage.getItem('token')}`}
headers={{
}}
style={{
width: '100%',
height: '75vh',
}}
scrolling="no"
frameBorder="0"
/>
</div>
);
}
export default GanttTimeLine;

1725
src/views/Master/MasterCompany/DialogForm.js

File diff suppressed because it is too large Load Diff

86
src/views/Master/MasterCompany/index.js

@ -6,7 +6,7 @@ import DialogForm from './DialogForm'
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Table, Button, Tooltip, Spin } from 'antd';
import {
COMPANY_MANAGEMENT_SEARCH, COMPANY_MANAGEMENT_ADD, COMPANY_MANAGEMENT_EDIT, COMPANY_MANAGEMENT_DELETE, IMAGE_UPLOAD, IMAGE_GET_BY_ID, IMAGE_DELETE
COMPANY_MANAGEMENT_SEARCH, COMPANY_MANAGEMENT_ADD, COMPANY_MANAGEMENT_EDIT, COMPANY_MANAGEMENT_DELETE, IMAGE_UPLOAD, IMAGE_MULTIPLE_UPLOAD, IMAGE_MULTIPLE_DELETE, IMAGE_GET_BY_ID, IMAGE_DELETE, IMAGE_SEARCH
} from '../../../const/ApiConst';
import { useTranslation } from 'react-i18next';
const token = window.localStorage.getItem('token');
@ -47,12 +47,13 @@ const MasterCompany = ({ params }) => {
const [companyName, setCompanyName] = useState('')
const [imageHeader, setProjectImageHeader] = useState(null);
const [imageLogin, setProjectImageLogin] = useState(null);
const [imageSlider, setProjectImageSlider] = useState([]);
const [imageFavIcon, setProjectImageFavicon] = useState(null);
const [lastIdCompany,setLastCompanyId] = useState('');
const [loading, setLoading] = useState(true);
const pageName = params.name;
const { t } = useTranslation();
const configApp = JSON.parse(window.localStorage.getItem('configApp'));
useEffect(() => {
setLoading(true)
getDataCompany()
@ -163,6 +164,24 @@ const MasterCompany = ({ params }) => {
}
}
const getProjectImageSlider = async (id) => {
const payload = {
"columns": [
{ "name": "category", "logic_operator": "=", "value": "company_slider_login", "operator": "and" },
{ "name": "ref_id", "logic_operator": "=", "value": parseInt(id), "operator": "and" }
]
}
const result = await axios
.post(IMAGE_SEARCH, payload, config)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
const sourceData = result.data.data;
setProjectImageSlider(sourceData);
}
}
const handleSearch = e => {
const value = e.target.value
setSearch(value);
@ -178,6 +197,7 @@ const MasterCompany = ({ params }) => {
const handleEdit = async (data) => {
setDataEdit(data);
await getProjectImageHeader(data.id);
await getProjectImageSlider(data.id);
await getProjectImageLogin(data.id);
await getProjectImageFavicon(data.id);
handleOpenDialog('Edit');
@ -213,9 +233,24 @@ const MasterCompany = ({ params }) => {
setProjectImageHeader(null)
setProjectImageLogin(null)
setProjectImageFavicon(null)
setProjectImageSlider([])
setOpenDialog(false)
}
const packFiles = (id, files) => {
const data = new FormData();
for (let i = 0; i < files.length; i++) {
data.append('files[]', files[i]);
}
data.append('ref_id', id);
data.append('category', 'company_slider_login');
return data;
};
const saveCompany = async (data) => {
const formData = data
const result = await axios.post(COMPANY_MANAGEMENT_ADD, formData, HEADER)
@ -226,6 +261,7 @@ const MasterCompany = ({ params }) => {
const logoHeader = data.imageHeader;
const logoLogin = data.imageLogin;
const favIcon = data.imageFavicon;
const slider = data.imageSlider;
if (logoHeader) {
await saveImageHeader(
result.data.data.id,
@ -244,6 +280,10 @@ const MasterCompany = ({ params }) => {
favIcon
);
}
if(slider) {
const dataPack = packFiles(result.data.data.id,slider)
await saveSliderLogin(dataPack)
}
getDataCompany();
setLoading(false)
NotificationManager.success(`Data company berhasil ditambah`, 'Success!!');
@ -259,6 +299,7 @@ const MasterCompany = ({ params }) => {
const logoHeader = data.imageHeader;
const logoLogin = data.imageLogin;
const favIcon = data.imageFavicon;
const slider = data.imageSlider;
const formData = data
const result = await axios.put(urlEdit, formData, HEADER)
@ -291,6 +332,13 @@ const MasterCompany = ({ params }) => {
favIcon
);
}
if(slider) {
await deleteImageSlider(
data.id
);
const dataPack = packFiles(data.id,slider)
await saveSliderLogin(dataPack)
}
if (result && result.data && result.data.code === 200) {
getDataCompany();
setLoading(false)
@ -306,6 +354,7 @@ const MasterCompany = ({ params }) => {
formData.append('ref_id', id);
formData.append('category', 'company_logo_header');
formData.append('files', data);
formData.append('company_name',configApp.company_name);
await axios
.post(IMAGE_UPLOAD, formData, HEADER_MULTIPART)
@ -319,6 +368,7 @@ const MasterCompany = ({ params }) => {
formData.append('ref_id', id);
formData.append('category', 'company_logo_login');
formData.append('files', data);
formData.append('company_name',configApp.company_name);
await axios
.post(IMAGE_UPLOAD, formData, HEADER_MULTIPART)
@ -332,6 +382,7 @@ const MasterCompany = ({ params }) => {
formData.append('ref_id', id);
formData.append('category', 'company_favicon');
formData.append('files', data);
formData.append('company_name',configApp.company_name);
await axios
.post(IMAGE_UPLOAD, formData, HEADER_MULTIPART)
@ -339,9 +390,19 @@ const MasterCompany = ({ params }) => {
.catch((error) => error.response);
return "berhasil";
};
const saveSliderLogin = async (data) => {
data.company_name = configApp.company_name;
await axios
.post(IMAGE_MULTIPLE_UPLOAD, data, HEADER_MULTIPART)
.then(res => res)
.catch((error) => error.response);
return "berhasil";
};
// Delete Image Function
const deleteImageHeader = async (id) => {
const URL = IMAGE_DELETE(id, 'company_logo_header');
const URL = IMAGE_DELETE(id, 'company_logo_header', company_id);
await axios
.delete(URL, HEADER)
.then(res => res)
@ -350,7 +411,7 @@ const MasterCompany = ({ params }) => {
};
const deleteImageLogin = async (id) => {
const URL = IMAGE_DELETE(id, 'company_logo_login');
const URL = IMAGE_DELETE(id, 'company_logo_login', company_id);
await axios
.delete(URL, HEADER)
.then(res => res)
@ -359,7 +420,16 @@ const MasterCompany = ({ params }) => {
};
const deleteImageFavicon = async (id) => {
const URL = IMAGE_DELETE(id, 'company_favicon');
const URL = IMAGE_DELETE(id, 'company_favicon', company_id);
await axios
.delete(URL, HEADER)
.then(res => res)
.catch((error) => error.response);
return "berhasil";
};
const deleteImageSlider = async (id) => {
const URL = IMAGE_MULTIPLE_DELETE(id, 'company_slider_login', company_id);
await axios
.delete(URL, HEADER)
.then(res => res)
@ -383,6 +453,7 @@ const MasterCompany = ({ params }) => {
deleteImageHeader(idDelete)
deleteImageLogin(idDelete)
deleteImageFavicon(idDelete)
deleteImageSlider(idDelete)
setIdDelete(0)
setAlertDelete(false)
setLoading(false)
@ -465,6 +536,7 @@ const MasterCompany = ({ params }) => {
companyNameProp={companyName}
imageHeader={imageHeader}
imageFavIcon={imageFavIcon}
imageSlider={imageSlider}
imageLogin={imageLogin}
lastIdCompany={lastIdCompany}
/>
@ -473,10 +545,10 @@ const MasterCompany = ({ params }) => {
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4>
<Row>
<Col>
<Col md={7}>
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder='Search Company' />
</Col>
<Col>
<Col md={5}>
<Tooltip title='Add Company'>
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button>
</Tooltip>

430
src/views/Master/MasterRoles/DialogMenuRoles.js

@ -4,10 +4,19 @@ import { Button, Form, FormGroup, Label, Input } from 'reactstrap';
import 'antd/dist/antd.css';
import axios from 'axios';
import { MENU_SEARCH } from '../../../const/ApiConst.js';
import { withTranslation, WithTranslation } from 'react-i18next';
const BASE_URL = "http://siopas.co.id/custom-php/api/geohr/";
class DialogMenuRoles extends Component {
const token = window.localStorage.getItem('token');
const config = {
headers:
{
Authorization: `Bearer ${token}`,
"Content-type": `application/json`
}
};
export default class DialogMenuRoles extends Component {
constructor(props) {
super(props)
this.state = {
@ -16,24 +25,39 @@ class DialogMenuRoles extends Component {
description: "",
openDialog: false,
isParentClick: false,
menu: [],
stateMenu: [],
menu:[],
stateRead: [],
stateCreate: [],
stateUpdate: [],
stateDelete: [],
stateReadAll: false,
stateCreateAll: false,
stateUpdateAll: false,
stateDeleteAll: false,
allChecked: true,
company_id: props.company_id || null,
role_name: props.role_name || '',
token: props.token || '',
config: {
headers: {
Authorization: `Bearer ${props.token || ''}`,
"Content-type": "application/json",
}
}
}
}
async componentDidMount() {
this.getAllMenu()
this.props.showDialog(this.showDialog);
this.getAllMenu();
}
async componentDidUpdate() {
if (this.state.isParentClick === true) {
const { idRoles } = this.props
this.setStateMenu(true);
this.setStateRead(true);
this.setStateUpdate(true);
this.setStateCreate(true);
this.setStateDelete(true);
this.setState({ isParentClick: false, id: idRoles });
}
}
showDialog = () => {
this.setState({ isParentClick: true });
}
getAllMenu = async () => {
@ -42,30 +66,30 @@ class DialogMenuRoles extends Component {
"columns": [
{ "name": "name", "logic_operator": "ilike", "value": "", "operator": "AND" }
],
"joins": [],
"joins": [
{ "name": "t_roles_menu", "column_join": "id", "column_results": ["create", "update", "delete", "read"] }
],
"orders": { "columns": ["id"], "ascending": false }
}
const result = await axios
.post(MENU_SEARCH, payload, this.state.config)
.post(MENU_SEARCH, payload, config)
.then(res => res)
.catch((error) => error.response);
// console.log('78', result);
if (result && result.data && result.data.code == 200) {
this.setState({ menu: result.data.data });
this.setState({ menu: result.data.data }, () => {
this.setStateMenu(false);
});
} else {
}
}
async componentDidUpdate() {
if (this.state.isParentClick === true) {
const { idRoles } = this.props
this.setStateMenu(true);
this.setState({ isParentClick: false, id: idRoles });
}
}
showDialog = () => {
this.setState({ isParentClick: true });
}
setStateMenu = edit => {
const stateMenu = [];
@ -81,11 +105,69 @@ class DialogMenuRoles extends Component {
})
}
setStateRead = edit => {
const stateRead = [];
this.state.menu.map((val) => {
stateRead.push(false);
})
this.setState({ stateRead: [] }, () => {
this.setState({ stateRead: stateRead }, () => {
if (edit) {
this.checkReadRoles();
}
})
})
}
setStateCreate = edit => {
const stateCreate = [];
this.state.menu.map((val) => {
stateCreate.push(false);
})
this.setState({ stateCreate: [] }, () => {
this.setState({ stateCreate: stateCreate }, () => {
if (edit) {
this.checkCreateRoles();
}
})
})
}
setStateUpdate = edit => {
const stateUpdate = [];
this.state.menu.map((val) => {
stateUpdate.push(false);
})
this.setState({ stateUpdate: [] }, () => {
this.setState({ stateUpdate: stateUpdate }, () => {
if (edit) {
this.checkUpdateRoles();
}
})
})
}
setStateDelete = edit => {
const stateDelete = [];
this.state.menu.map((val) => {
stateDelete.push(false);
})
this.setState({ stateDelete: [] }, () => {
this.setState({ stateDelete: stateDelete }, () => {
if (edit) {
this.checkDeleteRoles();
}
})
})
}
checkMenuRoles = () => {
let copyStateMenu = [...this.state.stateMenu];
this.props.menuRoles.map((val, indexMenu) => {
let index = this.getIndexDataMenu(val.menu_id);
if (index >= 0) {
if (index >= 0 || val.read === true || val.create === true || val.update === true || val.delete === true) {
copyStateMenu[index] = true;
}
})
@ -99,15 +181,125 @@ class DialogMenuRoles extends Component {
})
}
checkReadRoles = () => {
let copyStateRead = [...this.state.stateRead];
this.props.menuRoles.map((val) => {
let index = this.getIndexDataMenu(val.menu_id);
if (val.read === true) {
copyStateRead[index] = true;
} else {
copyStateRead[index] = false;
}
})
this.setState({ stateRead: [] }, () => {
let check = copyStateRead.some(this.checkArray);
if (check === false) {
this.setState({ allChecked: true, stateRead: copyStateRead, })
} else {
this.setState({ allChecked: false, stateRead: copyStateRead, })
}
})
}
checkCreateRoles = () => {
let copyStateCreate = [...this.state.stateCreate];
this.props.menuRoles.map((val) => {
let index = this.getIndexDataMenu(val.menu_id);
if (val.create === true) {
copyStateCreate[index] = true;
} else {
copyStateCreate[index] = false;
}
})
this.setState({ stateCreate: [] }, () => {
let check = copyStateCreate.some(this.checkArray);
if (check === false) {
this.setState({ allChecked: true, stateCreate: copyStateCreate, })
} else {
this.setState({ allChecked: false, stateCreate: copyStateCreate, })
}
})
}
checkUpdateRoles = () => {
let copyStateUpdate = [...this.state.stateUpdate];
this.props.menuRoles.map((val) => {
let index = this.getIndexDataMenu(val.menu_id);
if (val.update === true) {
copyStateUpdate[index] = true;
} else {
copyStateUpdate[index] = false;
}
})
this.setState({ stateUpdate: [] }, () => {
let check = copyStateUpdate.some(this.checkArray);
if (check === false) {
this.setState({ allChecked: true, stateUpdate: copyStateUpdate, })
} else {
this.setState({ allChecked: false, stateUpdate: copyStateUpdate, })
}
})
}
checkDeleteRoles = () => {
let copyStateDelete = [...this.state.stateDelete];
this.props.menuRoles.map((val) => {
let index = this.getIndexDataMenu(val.menu_id);
if (val.delete === true) {
copyStateDelete[index] = true;
} else {
copyStateDelete[index] = false;
}
})
this.setState({ stateDelete: [] }, () => {
let check = copyStateDelete.some(this.checkArray);
if (check === false) {
this.setState({ allChecked: true, stateDelete: copyStateDelete, })
} else {
this.setState({ allChecked: false, stateDelete: copyStateDelete, })
}
})
}
getIndexDataMenu = (id) => {
let index = this.state.menu.findIndex(obj => obj.id === id);
return index
}
getIndexDataCreate = (id) => {
let index = this.state.stateCreate.findIndex(obj => obj.id === id);
return index
}
getIndexDataDelete = (id) => {
let index = this.state.stateDelete.findIndex(obj => obj.id === id);
return index
}
getIndexDataRead = (id) => {
let index = this.state.stateRead.findIndex(obj => obj.id === id);
return index
}
getIndexDataUpdate = (id) => {
let index = this.state.stateUpdate.findIndex(obj => obj.id === id);
return index
}
handleSave = () => {
const {
stateMenu,
stateCreate,
stateDelete,
stateRead,
stateUpdate,
menu,
id
} = this.state
@ -118,11 +310,19 @@ class DialogMenuRoles extends Component {
let data = {
roles_id: id,
menu_id: val.id,
checked: stateMenu[index]
read: stateRead[index],
create: stateCreate[index],
update: stateUpdate[index],
delete: stateDelete[index],
checked: stateMenu[index],
}
arrayData.push(data);
})
this.props.closeDialog('save', arrayData);
console.log('arrayData', arrayData);
// this.props.closeDialog('save', arrayData);
this.setState({ id: 0 });
}
@ -133,23 +333,146 @@ class DialogMenuRoles extends Component {
handleChangeCheckbox = (checked, index) => {
let copyStateMenu = [...this.state.stateMenu];
copyStateMenu[index] = checked;
this.setState({ stateMenu: copyStateMenu })
}
handleChangeCheckboxRead = (checked, index) => {
let copyStateRead = [...this.state.stateRead];
copyStateRead[index] = checked;
this.setState({ stateRead: copyStateRead })
}
handleChangeCheckboxCreate = (checked, index) => {
let copyStateCreate = [...this.state.stateCreate];
copyStateCreate[index] = checked;
this.setState({ stateCreate: copyStateCreate })
}
handleChangeCheckboxEdit = (checked, index) => {
let copyStateEdit = [...this.state.stateUpdate];
copyStateEdit[index] = checked;
this.setState({ stateUpdate: copyStateEdit })
}
handleChangeCheckboxDelete = (checked, index) => {
let copyStateDelete = [...this.state.stateDelete];
copyStateDelete[index] = checked;
this.setState({ stateDelete: copyStateDelete })
}
handleChangeCheckboxReadAll = (checked) => {
let copyStateRead = [...this.state.stateRead];
copyStateRead.map((val, index) => {
copyStateRead[index] = checked;
})
this.setState({ stateRead: copyStateRead })
}
handleChangeCheckboxCreateAll = (checked, index) => {
let copyStateCreate = [...this.state.stateCreate];
copyStateCreate.map((val, index) => {
copyStateCreate[index] = checked;
})
this.setState({ stateCreate: copyStateCreate })
}
handleChangeCheckboxEditAll = (checked, index) => {
let copyStateEdit = [...this.state.stateUpdate];
copyStateEdit.map((val, index) => {
copyStateEdit[index] = checked;
})
this.setState({ stateUpdate: copyStateEdit })
}
handleChangeCheckboxDeleteAll = (checked, index) => {
let copyStateDelete = [...this.state.stateDelete];
copyStateDelete.map((val, index) => {
copyStateDelete[index] = checked;
})
this.setState({ stateDelete: copyStateDelete })
}
// renderForm = () => {
// const { menu, stateRead, stateCreate, stateUpdate, stateDelete } = this.state
// console.log('menu', menu);
// return (
// menu.map((val, index) => {
// return (
// <tr key={index}>
// <td>{val.name}</td>
// <td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxRead(e.target.checked, index)} defaultChecked={stateRead[index]} /></td>
// <td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxCreate(e.target.checked, index)} defaultChecked={stateCreate[index]} /></td>
// <td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxEdit(e.target.checked, index)} defaultChecked={stateUpdate[index]} /></td>
// <td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxDelete(e.target.checked, index)} defaultChecked={stateDelete[index]} /></td>
// </tr>
// )
// })
// )
// }
renderForm = () => {
const { menu, stateMenu } = this.state
return (
menu.map((val, index) => {
const { menu, stateRead, stateCreate, stateUpdate, stateDelete } = this.state;
const getChildren = (parentId) => {
return menu.filter(item => item.parent_id === parentId);
};
// Function to render menu items
const renderMenu = (parentId, depth = 0) => {
const children = getChildren(parentId);
return children.map((menuItem, index) => {
const paddingLeft = depth * 20;
const fontWeight = menuItem.parent_id === null ? 'bold' : 'normal';
return (
<tr key={index}>
<td>{val.name}</td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckbox(e.target.checked, index)} defaultChecked={stateMenu[index]} /></td>
</tr>
)
})
<React.Fragment key={index}>
<tr >
<td style={{ paddingLeft: paddingLeft }}>{menuItem.name}</td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxRead(e.target.checked, index)} defaultChecked={stateRead[index]} /></td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxCreate(e.target.checked, index)} defaultChecked={stateCreate[index]} /></td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxEdit(e.target.checked, index)} defaultChecked={stateUpdate[index]} /></td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxDelete(e.target.checked, index)} defaultChecked={stateDelete[index]} /></td>
</tr>
{renderMenu(menuItem.id, depth + 1)} {/* Recursively render children */}
</React.Fragment>
);
});
};
// Render top-level menu items (parents)
return (
<React.Fragment>
{this.renderAll()} {/* Render the "All" row */}
{renderMenu(null)} {/* Render the menu items */}
</React.Fragment>
);
};
renderAll = () => {
return (
<tr>
<td>All</td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxReadAll(e.target.checked)} defaultChecked={this.state.stateReadAll} /></td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxCreateAll(e.target.checked)} defaultChecked={this.state.stateCreateAll} /></td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxEditAll(e.target.checked)} defaultChecked={this.state.stateUpdateAll} /></td>
<td><input type="checkbox" onClick={(e) => this.handleChangeCheckboxDeleteAll(e.target.checked)} defaultChecked={this.state.stateDeleteAll} /></td>
</tr>
)
}
checkArray = (val) => {
return val === false;
}
@ -157,6 +480,7 @@ class DialogMenuRoles extends Component {
handleAllChecked = (checked) => {
this.setState({ allChecked: !this.state.allChecked });
if (checked === true) {
let check = this.state.stateMenu.some(this.checkArray);
if (check) {
@ -172,6 +496,7 @@ class DialogMenuRoles extends Component {
} else {
const stateMenu = [];
this.state.menu.map((val) => {
stateMenu.push(false);
@ -185,8 +510,8 @@ class DialogMenuRoles extends Component {
render() {
return (
<Modal scrollable={true} isOpen={this.props.openDialog} toggle={this.props.toggleDialog}>
<ModalHeader toggle={this.props.closeDialog}>{this.props.t('menuRoles')}</ModalHeader>
<Modal size="xl" scrollable={true} isOpen={this.props.openDialog} toggle={this.props.toggleDialog}>
<ModalHeader toggle={this.props.closeDialog}>Roles Menu</ModalHeader>
<ModalBody>
<Form>
<Table>
@ -194,26 +519,31 @@ class DialogMenuRoles extends Component {
<tr>
<th>Menu</th>
<th>
T/F
View
</th>
<th>
Create
</th>
<th>
Edite
</th>
<th>
Delete
</th>
</tr>
</thead>
<tbody>
<tr>
<td>All</td>
<td><input type="checkbox" onChange={(e) => this.handleAllChecked(e.target.checked)} checked={this.state.allChecked} /></td>
</tr>
{this.renderForm()}
</tbody>
</Table>
</Form>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => this.handleSave()}>{this.props.t('save')}</Button>{' '}
<Button color="secondary" onClick={() => this.handleCancel()}>{this.props.t('cancel')}</Button>
<Button id="roleSaveButton" className="roleSaveButton" name="roleSaveButton" color="primary" onClick={() => this.handleSave()}>Save</Button>{' '}
<Button id="roleCancelButton" className="roleCancelButton" name="roleCancelButton" color="secondary" onClick={() => this.handleCancel()}>Cancel</Button>
</ModalFooter>
</Modal>
)
}
}
export default withTranslation()(DialogMenuRoles);

9
src/views/Master/MasterRoles/index.js

@ -307,7 +307,7 @@ class index extends Component {
"columns": [
{ "name": "role_id", "logic_operator": "=", "value": `${id}`, "operator": "AND" }
],
"joins": [],
"joins": [{ "name": "m_menu", "column_join": "menu_id", "column_results": ["parent_id", "name"] }],
"orders": { "columns": ["id"], "ascending": false }
}
@ -476,7 +476,7 @@ class index extends Component {
dataHs={this.state.dataIdHo}
company_id={this.state.company_id}
role_name={this.state.role_name}
token={this.state.token}
token={this.state.token}
/>
<DialogMenuRoles
openDialog={dialogMenuForm}
@ -484,9 +484,10 @@ class index extends Component {
idRoles={this.state.idRoles}
showDialog={showDialog => this.showMenuRolesDialog = showDialog}
menuRoles={this.state.menuRoles}
company_id={this.state.company_id}
company_id={this.state.company_id}
role_name={this.state.role_name}
token={this.state.token}
role_id={this.state.role_id}
token={this.state.token}
/>
<Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>

26
src/views/Master/MenuCompany/DialogMasterMenu.js

@ -36,7 +36,8 @@ const Index = ({ params, openDialog, toggleDialog, closeDialog }) => {
const [tooltipTambah, setTooltipTambah] = useState(false)
const [totalPage, setTotalPage] = useState(0)
const [typeDialog, setTypeDialog] = useState('Save')
const [loading, SetLoading] = useState(false)
const [loading, setLoading] = useState(false)
const [openDialogMasterMenu, setOpenDialogFormMenu] = useState(false)
const { t } = useTranslation()
// const pageName = params.name;
@ -84,7 +85,7 @@ const Index = ({ params, openDialog, toggleDialog, closeDialog }) => {
}
const getDataMenu = async () => {
SetLoading(true)
setLoading(true)
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
@ -114,17 +115,17 @@ const Index = ({ params, openDialog, toggleDialog, closeDialog }) => {
if (result && result.data && result.data.code == 200) {
setDatatable(result.data.data);
setTotalPage(result.data.totalRecord);
SetLoading(false)
setLoading(false)
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
SetLoading(false)
setLoading(false)
}
}
const handleOpenDialog = async (type) => {
await setTypeDialog(type)
getDataAllMenu();
// setOpenDialog(true)
setOpenDialogFormMenu(true)
}
const handleCloseDialog = (type, data) => {
@ -134,19 +135,16 @@ const Index = ({ params, openDialog, toggleDialog, closeDialog }) => {
editMenu(data);
}
setDataEdit([])
// setOpenDialog(false)
setOpenDialogFormMenu(false)
}
const toggleAddDialog = () => {
// setOpenDialog(!openDialog)
setOpenDialogFormMenu(!openDialog)
}
const handleCancel = () => {
closeDialog('cancel', 'none')
// setDatatable([]);
// setBaseUrl([]);
// setAvailableBaseUrl(false);
// setLoading(false);
setLoading(false);
}
@ -334,15 +332,15 @@ const Index = ({ params, openDialog, toggleDialog, closeDialog }) => {
>
{t('deleteMsg')}
</SweetAlert>
{/* <DialogForm
openDialog={openDialog}
<DialogForm
openDialog={openDialogMasterMenu}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
typeDialog={typeDialog}
dataEdit={dataEdit}
clickOpenModal={clickOpenModal}
dataMenu={allDataMenu}
/> */}
/>
<Modal size="xl" fullscreen="xl" scrollable={true} isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize withBtn" toggle={closeDialog} style={{ width: "100%" }}>
MASTER MENU

3
src/views/Master/MenuCompany/index.js

@ -414,9 +414,6 @@ const Index = ({ params, ...props }) => {
<Button id="TooltipMasterMenu" color="warning" onClick={() => handleOpenDialogMasterMenu()}><i className="fa fa-table"></i></Button>
</Tooltip>
}
<Tooltip title={t('menuAdd')}>
<Button style={{ marginLeft: "5px" }} id="TooltipTambah" color="success" onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button>
</Tooltip>
<Tooltip title={t('exportExcel')}>
<Button style={{ marginLeft: "5px" }} id="TooltipExport" color="primary" onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button>
</Tooltip>

959
src/views/Master/Proyek/index.js

@ -1,479 +1,480 @@
import React, { useState, useEffect, useMemo } from 'react';
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap';
import { DownloadOutlined } from '@ant-design/icons';
import axios from 'axios';
import * as XLSX from 'xlsx';
import SweetAlert from 'react-bootstrap-sweetalert';
import DialogForm from './DialogForm';
import DialogFormSub from './DialogFormSub';
import SubProyekComp from './SubProyekComp';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Table, Button, Tooltip } from 'antd';
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst';
import { formatRupiah } from '../../../const/CustomFunc'
import moment from 'moment'
const format = "DD-MM-YYYY";
const data = [
{
key: 1,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
},
{
key: 2,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
},
{
key: 3,
name: 'Not Expandable',
age: 29,
address: 'Jiangsu No. 1 Lake Park',
description: 'This not expandable',
},
{
key: 4,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
},
];
const url = "";
const proyek_id = localStorage.getItem('proyek_id');
const role_id = localStorage.getItem('role_id');
const IndexRole = ({ params }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [idTask, setidTask] = useState(0);
const [dataTable, setDatatable] = useState([])
const [search, setSearch] = useState('')
const [currentPage, setCurrentPage] = useState(1)
const [totalPage, setTotalPage] = useState(0)
const [openDialog, setOpenDialog] = useState(false)
const [openDialogSub, setOpenDialogSub] = useState(false)
const [openDialogMap, setOpenDialogMap] = useState(false)
const [typeDialog, setTypeDialog] = useState('Save');
const [typeDialogSub, setTypeDialogSub] = useState('Save')
const [idDelete, setIdDelete] = useState(0)
const [alertDelete, setAlertDelete] = useState(false)
const [dataEdit, setDataEdit] = useState([])
const [dataEditSub, setDataEditSub] = useState([])
const [rowsPerPage, setRowsPerPage] = useState(10)
const [clickOpenModal, setClickOpenModal] = useState(false)
const [dataExport, setDataExport] = useState([])
const [allDataMenu, setAllDataMenu] = useState([])
const pageName = params.name;
useEffect(() => {
getDataProyek();
}, [])
useEffect(() => {
getDataProyek();
}, [search, rowsPerPage, currentPage])
useEffect(() => {
const cekData = dataExport || []
if (cekData.length > 0) {
exportExcel()
}
}, [dataExport])
const handleSearch = e => {
const value = e.target.value
setSearch(value);
setCurrentPage(1)
};
const getDataProyek = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = (currentPage * rowsPerPage) - rowsPerPage
}
const payload = {
"columns": [
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" }
],
"joins": [
{ "name": "subproyeks.m_proyek", "column_join": "proyek_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] },
{ "name": "subproyeks.m_subproyek", "column_join": "parent_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] }
],
"orders": { "columns": ["id"], "ascending": true },
"paging": { "start": 0, "length": 25 }
}
if (parseInt(role_id) !== 1) {
payload["columns"] = [
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" }
]
}
const URL = `${BASE_SIMPRO}/proyek/search-detail`
const result = await axios
.post(URL, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || []
let dataWithKey = getChildrenTree(dataRes)
setDatatable(dataWithKey);
setTotalPage(result.data.totalRecord);
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
}
}
const getChildrenTree = (data) => (
data.map((item, index) => {
let arrSubProyek = item.subproyeks
if (item.subproyeks && item.subproyeks.length > 0) {
return {
"key": Math.random(),
"subproyeks2": getChildrenTree(item.subproyeks),
...item
}
}
else if (item.plannings && item.plannings.length > 0) {
return {
"key": Math.random(),
"plannings2": getChildrenTree(item.plannings),
...item
}
} else {
return {
"key": Math.random(),
...item
}
}
})
)
const handleOpenDialog = (type) => {
setOpenDialog(true)
setTypeDialog(type)
}
const handleOpenDialogSub = (type, param) => {
setidTask(param.id)
setOpenDialogSub(true)
setTypeDialogSub(type)
}
const handleCloseDialog = (type, data) => {
if (type === "save") {
saveProyek(data);
} else if (type === "edit") {
editProyek(data);
}
setDataEdit([])
setOpenDialog(false)
}
const handleCloseDialogSub = (type, data) => {
setDataEditSub([])
setOpenDialogSub(false)
if (type !== "cancel") {
getDataProyek()
}
}
const handleCloseDialogMap = () => {
setOpenDialogMap(false)
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
const toggleAddDialogSub = () => {
setOpenDialogSub(!openDialogSub)
}
const toggleMapDialog = () => {
setOpenDialogMap(!openDialogMap)
}
const onConfirmDelete = async () => {
let urlDel = PROYEK_DELETE(idDelete)
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!');
}
}
const saveProyek = async (data) => {
const formData = data
const result = await axios.post(PROYEK_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!');
} else {
NotificationManager.error(`${result.data.message}`, 'Failed!!');
}
}
const editProyek = async (data) => {
let urlEdit = PROYEK_EDIT(data.id)
const formData = data
const result = await axios.put(urlEdit, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!');
} else {
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`);
}
}
const handleEdit = (data) => {
setDataEdit(data)
handleOpenDialog('Edit');
}
const handleDelete = async (id) => {
await setAlertDelete(true)
await setIdDelete(id)
}
const onShowSizeChange = (current, pageSize) => {
setRowsPerPage(pageSize)
}
const onPagination = (current, pageSize) => {
setCurrentPage(current)
}
const handleExportExcel = async () => {
const payload = {
"paging": { "start": 0, "length": -1 },
"joins": [],
"orders": { "columns": ["id"], "ascending": false }
}
if (parseInt(role_id) !== 1) {
payload["columns"] = [
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" }
]
}
const result = await axios
.post(PROYEK_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let resData = result.data.data;
const excelData = [];
resData.map((n, index) => {
let dataRow = {
"Nama Proyek": n.nama,
"Biaya": n.biaya,
"Color Progress": n.color_progress,
"Jumlah Pekerja": n.jumlah_pekerja,
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-",
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-",
}
excelData.push(dataRow)
})
await setDataExport(excelData);
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
const exportExcel = () => {
const dataExcel = dataExport || [];
const fileName = `Data ${pageName}.xlsx`;
const ws = XLSX.utils.json_to_sheet(dataExcel);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`);
XLSX.writeFile(wb, fileName);
setDataExport([])
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const renderProggress = (color) => {
if (color === "green") {
return "Aman"
} else if (color === "orange") {
return "Alert"
} else {
return "Critical"
}
}
const renderFormatRupiah = (text, prefix) => {
if (text) {
return formatRupiah(text, prefix)
} else {
return "-"
}
}
const RenderTable = useMemo(() => {
const columns = [
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' },
{
title: 'Biaya',
dataIndex: 'biaya',
key: 'biaya',
render: (text, record) => { return renderFormatRupiah(text, "Rp") }
},
{ title: 'SDM', dataIndex: 'jumlah_pekerja', key: 'jumlah_pekerja' },
{ title: 'PM', dataIndex: 'pic', key: 'pic' },
{
title: 'Aktifitas Mulai',
dataIndex: 'mulai_proyek',
key: 'mulai_proyek',
render: (text, record) => <>{moment(text).format(format)}</>,
},
{
title: 'Aktifitas Selesai',
dataIndex: 'akhir_proyek',
key: 'akhir_proyek',
render: (text, record) => <>{moment(text).format(format)}</>,
},
{
title: 'Action',
dataIndex: '',
key: 'x',
render: (text, record) => <>
<Tooltip title="Tambah Sub">
<Button size="small" type="link" style={{ color: 'green' }} onClick={() => handleOpenDialogSub('Save', text)}><i className="fa fa-plus"></i></Button>
</Tooltip>
<Tooltip title="Edit Proyek">
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button>
</Tooltip>
<Tooltip title="Hapus Proyek">
<Button size="small" type="link" style={{ color: 'red' }} onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button>
</Tooltip>
</>,
},
];
return (
<Table
size="small"
columns={columns}
expandable={{
expandedRowRender: record => <SubProyekComp getDataProyek={getDataProyek} idParentTask={record.id} nameProyek={record.nama} data={record.subproyeks2} />,
rowExpandable: record => record.subproyeks2,
}}
dataSource={dataTable}
/>
)
}, [dataTable])
return (
<div>
<NotificationContainer />
<SweetAlert
show={alertDelete}
warning
showCancel
confirmBtnText="Delete"
confirmBtnBsStyle="danger"
title={`Apakah anda yakin?`}
onConfirm={onConfirmDelete}
onCancel={() => cancelDelete()}
focusCancelBtn
>
Data akan terhapus
</SweetAlert>
<DialogForm
openDialog={openDialog}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
typeDialog={typeDialog}
dataEdit={dataEdit}
clickOpenModal={clickOpenModal}
dataParent={allDataMenu}
/>
<DialogFormSub
openDialog={openDialogSub}
closeDialog={handleCloseDialogSub}
toggleDialog={() => toggleAddDialogSub}
typeDialog={typeDialogSub}
dataEdit={dataEditSub}
idTask={idTask}
idSubtask={0}
/>
<Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4>
<Row>
<Col>
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} />
</Col>
<Col>
<Tooltip title="Tambah Proyek">
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button>
</Tooltip>
<Tooltip title="Export Excel">
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button>
</Tooltip>
</Col>
</Row>
</CardHeader>
<CardBody>
{RenderTable}
</CardBody>
</Card>
</div>
)
}
export default IndexRole;
import React, { useState, useEffect, useMemo } from 'react';
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap';
import { DownloadOutlined } from '@ant-design/icons';
import axios from 'axios';
import * as XLSX from 'xlsx';
import SweetAlert from 'react-bootstrap-sweetalert';
import DialogForm from './DialogForm';
import DialogFormSub from './DialogFormSub';
import SubProyekComp from './SubProyekComp';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Table, Button, Tooltip } from 'antd';
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst';
import { formatRupiah } from '../../../const/CustomFunc'
import moment from 'moment'
const format = "DD-MM-YYYY";
const data = [
{
key: 1,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
},
{
key: 2,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
},
{
key: 3,
name: 'Not Expandable',
age: 29,
address: 'Jiangsu No. 1 Lake Park',
description: 'This not expandable',
},
{
key: 4,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
},
];
const url = "";
const proyek_id = localStorage.getItem('proyek_id');
const role_id = localStorage.getItem('role_id');
const company_id = window.localStorage.getItem('company_id');
const IndexRole = ({ params }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [idTask, setidTask] = useState(0);
const [dataTable, setDatatable] = useState([])
const [search, setSearch] = useState('')
const [currentPage, setCurrentPage] = useState(1)
const [totalPage, setTotalPage] = useState(0)
const [openDialog, setOpenDialog] = useState(false)
const [openDialogSub, setOpenDialogSub] = useState(false)
const [openDialogMap, setOpenDialogMap] = useState(false)
const [typeDialog, setTypeDialog] = useState('Save');
const [typeDialogSub, setTypeDialogSub] = useState('Save')
const [idDelete, setIdDelete] = useState(0)
const [alertDelete, setAlertDelete] = useState(false)
const [dataEdit, setDataEdit] = useState([])
const [dataEditSub, setDataEditSub] = useState([])
const [rowsPerPage, setRowsPerPage] = useState(10)
const [clickOpenModal, setClickOpenModal] = useState(false)
const [dataExport, setDataExport] = useState([])
const [allDataMenu, setAllDataMenu] = useState([])
const pageName = params.name;
useEffect(() => {
getDataProyek();
}, [])
useEffect(() => {
getDataProyek();
}, [search, rowsPerPage, currentPage])
useEffect(() => {
const cekData = dataExport || []
if (cekData.length > 0) {
exportExcel()
}
}, [dataExport])
const handleSearch = e => {
const value = e.target.value
setSearch(value);
setCurrentPage(1)
};
const getDataProyek = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = (currentPage * rowsPerPage) - rowsPerPage
}
const payload = {
"columns": [
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" }
],
"joins": [
{ "name": "subproyeks.m_proyek", "column_join": "proyek_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] },
{ "name": "subproyeks.m_subproyek", "column_join": "parent_id", "column_results": ["nama", "biaya", "color_progress", "jumlah_pekerja", "pic", "mulai_proyek", "akhir_proyek", "biaya_actual", "persentase_progress_plan", "persentase_progress_actual"] }
],
"orders": { "columns": ["id"], "ascending": true },
"paging": { "start": 0, "length": 25 }
}
if (parseInt(role_id) !== 1) {
payload["columns"] = [
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" }
]
}
const URL = `${BASE_SIMPRO}/proyek/search-detail`
const result = await axios
.post(URL, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || []
let dataWithKey = getChildrenTree(dataRes)
setDatatable(dataWithKey);
setTotalPage(result.data.totalRecord);
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
}
}
const getChildrenTree = (data) => (
data.map((item, index) => {
let arrSubProyek = item.subproyeks
if (item.subproyeks && item.subproyeks.length > 0) {
return {
"key": Math.random(),
"subproyeks2": getChildrenTree(item.subproyeks),
...item
}
}
else if (item.plannings && item.plannings.length > 0) {
return {
"key": Math.random(),
"plannings2": getChildrenTree(item.plannings),
...item
}
} else {
return {
"key": Math.random(),
...item
}
}
})
)
const handleOpenDialog = (type) => {
setOpenDialog(true)
setTypeDialog(type)
}
const handleOpenDialogSub = (type, param) => {
setidTask(param.id)
setOpenDialogSub(true)
setTypeDialogSub(type)
}
const handleCloseDialog = (type, data) => {
if (type === "save") {
saveProyek(data);
} else if (type === "edit") {
editProyek(data);
}
setDataEdit([])
setOpenDialog(false)
}
const handleCloseDialogSub = (type, data) => {
setDataEditSub([])
setOpenDialogSub(false)
if (type !== "cancel") {
getDataProyek()
}
}
const handleCloseDialogMap = () => {
setOpenDialogMap(false)
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
const toggleAddDialogSub = () => {
setOpenDialogSub(!openDialogSub)
}
const toggleMapDialog = () => {
setOpenDialogMap(!openDialogMap)
}
const onConfirmDelete = async () => {
let urlDel = PROYEK_DELETE(idDelete, company_id);
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!');
}
}
const saveProyek = async (data) => {
const formData = data
const result = await axios.post(PROYEK_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!');
} else {
NotificationManager.error(`${result.data.message}`, 'Failed!!');
}
}
const editProyek = async (data) => {
let urlEdit = PROYEK_EDIT(data.id)
const formData = data
const result = await axios.put(urlEdit, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!');
} else {
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`);
}
}
const handleEdit = (data) => {
setDataEdit(data)
handleOpenDialog('Edit');
}
const handleDelete = async (id) => {
await setAlertDelete(true)
await setIdDelete(id)
}
const onShowSizeChange = (current, pageSize) => {
setRowsPerPage(pageSize)
}
const onPagination = (current, pageSize) => {
setCurrentPage(current)
}
const handleExportExcel = async () => {
const payload = {
"paging": { "start": 0, "length": -1 },
"joins": [],
"orders": { "columns": ["id"], "ascending": false }
}
if (parseInt(role_id) !== 1) {
payload["columns"] = [
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" }
]
}
const result = await axios
.post(PROYEK_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let resData = result.data.data;
const excelData = [];
resData.map((n, index) => {
let dataRow = {
"Nama Proyek": n.nama,
"Biaya": n.biaya,
"Color Progress": n.color_progress,
"Jumlah Pekerja": n.jumlah_pekerja,
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-",
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-",
}
excelData.push(dataRow)
})
await setDataExport(excelData);
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
const exportExcel = () => {
const dataExcel = dataExport || [];
const fileName = `Data ${pageName}.xlsx`;
const ws = XLSX.utils.json_to_sheet(dataExcel);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`);
XLSX.writeFile(wb, fileName);
setDataExport([])
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const renderProggress = (color) => {
if (color === "green") {
return "Aman"
} else if (color === "orange") {
return "Alert"
} else {
return "Critical"
}
}
const renderFormatRupiah = (text, prefix) => {
if (text) {
return formatRupiah(text, prefix)
} else {
return "-"
}
}
const RenderTable = useMemo(() => {
const columns = [
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' },
{
title: 'Biaya',
dataIndex: 'biaya',
key: 'biaya',
render: (text, record) => { return renderFormatRupiah(text, "Rp") }
},
{ title: 'SDM', dataIndex: 'jumlah_pekerja', key: 'jumlah_pekerja' },
{ title: 'PM', dataIndex: 'pic', key: 'pic' },
{
title: 'Aktifitas Mulai',
dataIndex: 'mulai_proyek',
key: 'mulai_proyek',
render: (text, record) => <>{moment(text).format(format)}</>,
},
{
title: 'Aktifitas Selesai',
dataIndex: 'akhir_proyek',
key: 'akhir_proyek',
render: (text, record) => <>{moment(text).format(format)}</>,
},
{
title: 'Action',
dataIndex: '',
key: 'x',
render: (text, record) => <>
<Tooltip title="Tambah Sub">
<Button size="small" type="link" style={{ color: 'green' }} onClick={() => handleOpenDialogSub('Save', text)}><i className="fa fa-plus"></i></Button>
</Tooltip>
<Tooltip title="Edit Proyek">
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleEdit(text)}><i className="fa fa-edit"></i></Button>
</Tooltip>
<Tooltip title="Hapus Proyek">
<Button size="small" type="link" style={{ color: 'red' }} onClick={() => handleDelete(text.id)}><i className="fa fa-trash"></i></Button>
</Tooltip>
</>,
},
];
return (
<Table
size="small"
columns={columns}
expandable={{
expandedRowRender: record => <SubProyekComp getDataProyek={getDataProyek} idParentTask={record.id} nameProyek={record.nama} data={record.subproyeks2} />,
rowExpandable: record => record.subproyeks2,
}}
dataSource={dataTable}
/>
)
}, [dataTable])
return (
<div>
<NotificationContainer />
<SweetAlert
show={alertDelete}
warning
showCancel
confirmBtnText="Delete"
confirmBtnBsStyle="danger"
title={`Apakah anda yakin?`}
onConfirm={onConfirmDelete}
onCancel={() => cancelDelete()}
focusCancelBtn
>
Data akan terhapus
</SweetAlert>
<DialogForm
openDialog={openDialog}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
typeDialog={typeDialog}
dataEdit={dataEdit}
clickOpenModal={clickOpenModal}
dataParent={allDataMenu}
/>
<DialogFormSub
openDialog={openDialogSub}
closeDialog={handleCloseDialogSub}
toggleDialog={() => toggleAddDialogSub}
typeDialog={typeDialogSub}
dataEdit={dataEditSub}
idTask={idTask}
idSubtask={0}
/>
<Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4>
<Row>
<Col>
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} />
</Col>
<Col>
<Tooltip title="Tambah Proyek">
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button>
</Tooltip>
<Tooltip title="Export Excel">
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button>
</Tooltip>
</Col>
</Row>
</CardHeader>
<CardBody>
{RenderTable}
</CardBody>
</Card>
</div>
)
}
export default IndexRole;

1
src/views/Pages/Login/Login.js

@ -64,7 +64,6 @@ class Login extends Component {
if (storedData !== null) {
const data = JSON.parse(storedData);
const htmlTitle = data.html_title || 'OSPRO';
console.log('htmlTitle', htmlTitle);
document.getElementById('title').innerText = htmlTitle;
} else {
document.title = 'OSPRO';

33
src/views/Pages/Page403/Page403.js

@ -1,33 +0,0 @@
import React, { Component } from 'react';
import { Button, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row } from 'reactstrap';
class Page403 extends Component {
logOut = () => {
window.localStorage.clear();
this.props.history.push('/login')
}
render() {
return (
<div className="app flex-row align-items-center">
<Container>
<Row className="justify-content-center">
<Col md="6">
<div className="clearfix">
<h1 className="float-left display-3 mr-4">403</h1>
<h4 className="pt-3">Oops! <br></br>Kamu pergi ke halaman yang terlarang!</h4>
<p className="text-muted float-left">Halaman tidak bisa di akses!</p>
</div>
<div style={{alignItems:'center'}}>
<Button size="sm" color="warning" onClick={() => this.logOut()}>Back To Login</Button>
</div>
</Col>
</Row>
</Container>
</div>
);
}
}
export default Page403;

9
src/views/Pages/Page403/Page403.test.js

@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Page404 from './Page403';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Page403 />, div);
ReactDOM.unmountComponentAtNode(div);
});

6
src/views/Pages/Page403/package.json

@ -1,6 +0,0 @@
{
"name": "Page403",
"version": "0.0.0",
"private": true,
"main": "./Page403.js"
}

35
src/views/Pages/Page404/Page404.js

@ -1,35 +0,0 @@
import React, { Component } from 'react';
import { Button, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row } from 'reactstrap';
class Page404 extends Component {
render() {
return (
<div className="app flex-row align-items-center">
<Container>
<Row className="justify-content-center">
<Col md="6">
<div className="clearfix">
<h1 className="float-left display-3 mr-4">404</h1>
<h4 className="pt-3">Oops! You're lost.</h4>
<p className="text-muted float-left">The page you are looking for was not found.</p>
</div>
<InputGroup className="input-prepend">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="fa fa-search"></i>
</InputGroupText>
</InputGroupAddon>
<Input size="16" type="text" placeholder="What are you looking for?" />
<InputGroupAddon addonType="append">
<Button color="info">Search</Button>
</InputGroupAddon>
</InputGroup>
</Col>
</Row>
</Container>
</div>
);
}
}
export default Page404;

9
src/views/Pages/Page404/Page404.test.js

@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Page404 from './Page404';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Page404 />, div);
ReactDOM.unmountComponentAtNode(div);
});

6
src/views/Pages/Page404/package.json

@ -1,6 +0,0 @@
{
"name": "Page404",
"version": "0.0.0",
"private": true,
"main": "./Page404.js"
}

35
src/views/Pages/Page500/Page500.js

@ -1,35 +0,0 @@
import React, { Component } from 'react';
import { Button, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row } from 'reactstrap';
class Page500 extends Component {
render() {
return (
<div className="app flex-row align-items-center">
<Container>
<Row className="justify-content-center">
<Col md="6">
<span className="clearfix">
<h1 className="float-left display-3 mr-4">500</h1>
<h4 className="pt-3">Houston, we have a problem!</h4>
<p className="text-muted float-left">The page you are looking for is temporarily unavailable.</p>
</span>
<InputGroup className="input-prepend">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="fa fa-search"></i>
</InputGroupText>
</InputGroupAddon>
<Input size="16" type="text" placeholder="What are you looking for?" />
<InputGroupAddon addonType="append">
<Button color="info">Search</Button>
</InputGroupAddon>
</InputGroup>
</Col>
</Row>
</Container>
</div>
);
}
}
export default Page500;

9
src/views/Pages/Page500/Page500.test.js

@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Page500 from './Page500';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Page500 />, div);
ReactDOM.unmountComponentAtNode(div);
});

6
src/views/Pages/Page500/package.json

@ -1,6 +0,0 @@
{
"name": "Page500",
"version": "0.0.0",
"private": true,
"main": "./Page500.js"
}

68
src/views/Pages/Register/Register.js

@ -1,68 +0,0 @@
import React, { Component } from 'react';
import { Button, Card, CardBody, CardFooter, Col, Container, Form, Input, InputGroup, InputGroupAddon, InputGroupText, Row } from 'reactstrap';
class Register extends Component {
render() {
return (
<div className="app flex-row align-items-center">
<Container>
<Row className="justify-content-center">
<Col md="9" lg="7" xl="6">
<Card className="mx-4">
<CardBody className="p-4">
<Form>
<h1>Register</h1>
<p className="text-muted">Create your account</p>
<InputGroup className="mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="icon-user"></i>
</InputGroupText>
</InputGroupAddon>
<Input type="text" placeholder="Username" autoComplete="username" />
</InputGroup>
<InputGroup className="mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>@</InputGroupText>
</InputGroupAddon>
<Input type="text" placeholder="Email" autoComplete="email" />
</InputGroup>
<InputGroup className="mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="icon-lock"></i>
</InputGroupText>
</InputGroupAddon>
<Input type="password" placeholder="Password" autoComplete="new-password" />
</InputGroup>
<InputGroup className="mb-4">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="icon-lock"></i>
</InputGroupText>
</InputGroupAddon>
<Input type="password" placeholder="Repeat password" autoComplete="new-password" />
</InputGroup>
<Button color="success" block>Create Account</Button>
</Form>
</CardBody>
<CardFooter className="p-4">
<Row>
<Col xs="12" sm="6">
<Button className="btn-facebook mb-1" block><span>facebook</span></Button>
</Col>
<Col xs="12" sm="6">
<Button className="btn-twitter mb-1" block><span>twitter</span></Button>
</Col>
</Row>
</CardFooter>
</Card>
</Col>
</Row>
</Container>
</div>
);
}
}
export default Register;

9
src/views/Pages/Register/Register.test.js

@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Register from './Register';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Register />, div);
ReactDOM.unmountComponentAtNode(div);
});

6
src/views/Pages/Register/package.json

@ -1,6 +0,0 @@
{
"name": "Register",
"version": "0.0.0",
"private": true,
"main": "./Register.js"
}

767
src/views/SimproV2/Closing/index.js

@ -1,383 +1,384 @@
import * as XLSX from 'xlsx';
import DialogForm from './DialogForm';
import React, { useState, useEffect, useMemo } from 'react';
import SweetAlert from 'react-bootstrap-sweetalert';
import axios from "../../../const/interceptorApi";
import moment from 'moment'
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst';
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap';
import { DownloadOutlined } from '@ant-design/icons';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Table, Button, Tooltip } from 'antd';
import { formatRupiah } from '../../../const/CustomFunc'
const url = "";
const proyek_id = localStorage.getItem('proyek_id');
const role_id = localStorage.getItem('role_id');
const format = "DD-MM-YYYY";
const Closing = ({ params, ...props }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [alertClose, setAlertClose] = useState(false)
const [alertDelete, setAlertDelete] = useState(false)
const [allDataMenu, setAllDataMenu] = useState([])
const [clickOpenModal, setClickOpenModal] = useState(false)
const [currentPage, setCurrentPage] = useState(1)
const [dataCharter, setDataCharter] = useState(null)
const [dataEdit, setDataEdit] = useState([])
const [dataEditSub, setDataEditSub] = useState([])
const [dataExport, setDataExport] = useState([])
const [dataTable, setDatatable] = useState([])
const [dataView, setDataView] = useState([])
const [idDelete, setIdDelete] = useState(0)
const [idTask, setidTask] = useState(0);
const [openDialog, setOpenDialog] = useState(false)
const [openDialogMap, setOpenDialogMap] = useState(false)
const [openDialogResource, setOpenDialogResource] = useState(false)
const [openDialogViewDetail, setOpenDialogViewDetail] = useState(false)
const [rowsPerPage, setRowsPerPage] = useState(10)
const [search, setSearch] = useState('')
const [totalPage, setTotalPage] = useState(0)
const [typeDialog, setTypeDialog] = useState('Save');
const [typeDialogSub, setTypeDialogSub] = useState('Save')
const [userProyek, setUserProyek] = useState([]);
const pageName = params.name;
useEffect(() => {
getDataProyek()
}, [])
const handleSearch = e => {
const value = e.target.value
setSearch(value);
setCurrentPage(1)
};
const getDataProyek = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = (currentPage * rowsPerPage) - rowsPerPage
}
const payload = {
"columns": [
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" }
],
"joins": [
{ "name": "m_users", "column_join": "pm_id", "column_results": ["name", "username"] },
{ "name": "m_type_proyek", "column_join": "type_proyek_id", "column_results": ["name", "description"] },
],
"orders": { "columns": ["id"], "ascending": true },
"paging": { "start": 0, "length": 25 }
}
if (parseInt(role_id) !== 1) {
payload["columns"] = [
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" }
]
}
const URL = `${BASE_SIMPRO}/proyek/search-detail`
const result = await axios
.post(URL, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || []
setDatatable(dataRes);
setTotalPage(result.data.totalRecord);
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
}
}
const handleOpenDialog = (id) => {
setOpenDialog(true)
setidTask(id)
}
const handleOpenDialogResource = (data) => {
setOpenDialogResource(true)
setidTask(data.id)
setUserProyek(data.user_proyeks)
}
const handleOpenDialogViewDetail = (data) => {
setOpenDialogViewDetail(true)
setidTask(data.id)
setDataView(data)
setDataCharter(data.project_charter ? data.project_charter : null)
}
const handleCloseDialog = (type, payload) => {
if (type === "add") saveProyek(payload);
if (type === "edit") editProyek(payload);
setOpenDialog(false)
}
const handleCloseDialogResource = (type, payload) => {
setOpenDialogResource(false)
}
const handleCloseDialogView = (type, payload) => {
setOpenDialogViewDetail(false)
}
const toggleAddDialog = () => setOpenDialog(!openDialog)
const toggleAddDialogResource = () => setOpenDialogResource(!openDialog)
const toggleAddDialogView = () => setOpenDialogViewDetail(!openDialogViewDetail)
const onConfirmDelete = async () => {
let urlDel = PROYEK_DELETE(idDelete)
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!');
}
}
const onConfirmClose = async () => {
setIdDelete(0)
setAlertClose(false)
NotificationManager.success(`Data proyek berhasil diclose`, 'Success!!');
}
const saveProyek = async (data) => {
const formData = data
const result = await axios.post(PROYEK_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!');
} else {
NotificationManager.error(`${result.data.message}`, 'Failed!!');
}
}
const editProyek = async (data) => {
let urlEdit = PROYEK_EDIT(data.id)
const formData = data
const result = await axios.put(urlEdit, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!');
} else {
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`);
}
}
const handleDelete = async (id) => {
await setAlertDelete(true)
await setIdDelete(id)
}
const handleCloseProject = async (id) => {
await setAlertClose(true)
await setIdDelete(id)
}
const onShowSizeChange = (current, pageSize) => {
setRowsPerPage(pageSize)
}
const onPagination = (current, pageSize) => {
setCurrentPage(current)
}
const handleExportExcel = async () => {
const payload = {
"paging": { "start": 0, "length": -1 },
"joins": [],
"orders": { "columns": ["id"], "ascending": false }
}
if (parseInt(role_id) !== 1) {
payload["columns"] = [
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" }
]
}
const result = await axios
.post(PROYEK_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let resData = result.data.data;
const excelData = [];
resData.map((n, index) => {
let dataRow = {
"Nama Proyek": n.nama,
"Biaya": n.biaya,
"Color Progress": n.color_progress,
"Jumlah Pekerja": n.jumlah_pekerja,
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-",
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-",
}
excelData.push(dataRow)
})
await setDataExport(excelData);
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
const exportExcel = () => {
const dataExcel = dataExport || [];
const fileName = `Data ${pageName}.xlsx`;
const ws = XLSX.utils.json_to_sheet(dataExcel);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`);
XLSX.writeFile(wb, fileName);
setDataExport([])
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const cancelClose = () => {
setAlertClose(false)
setIdDelete(0)
}
const renderFormatRupiah = (text, prefix) => {
if (text) {
return formatRupiah(text, prefix)
} else {
return "-"
}
}
const handleClickGantt = (id) => {
props.history.push({
pathname: '/gantt',
state: { proyek_id: id }
})
}
const RenderTable = useMemo(() => {
const columns = [
{
title: 'Action',
dataIndex: '',
key: 'x',
render: (text, record) => <>
<Tooltip title="Report">
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleOpenDialog(text.id)}><i className="fa fa-print"></i></Button>
</Tooltip>
</>,
},
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' },
{
title: 'Planning Cost',
dataIndex: 'rencana_biaya',
key: 'rencana_biaya',
render: (text, record) => { return renderFormatRupiah(text, "Rp") }
},
{
title: 'Project Type',
dataIndex: 'color_progress',
key: 'color_progress',
render: (text, record) => <>{record.join.m_type_proyek_name}</>
},
{
title: 'PM', dataIndex: 'pic', key: 'pic',
render: (text, record) => <>{record.join.m_users_name}</>
},
{
title: 'Time Project',
dataIndex: 'akhir_proyek',
key: 'akhir_proyek',
render: (text, record) => <>{moment(record.mulai_proyek).format(format)} - {moment(record.akhir_proyek).format(format)}</>,
},
];
return (
<Table
size="small"
columns={columns}
dataSource={dataTable}
/>
)
}, [dataTable])
const RenderDialogForm = useMemo(() => (
<DialogForm
openDialog={openDialog}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
idTask={idTask}
/>
), [openDialog])
return (
<div>
<NotificationContainer />
<SweetAlert
show={alertClose}
warning
showCancel
confirmBtnText="Close"
confirmBtnBsStyle="danger"
title={`Are you sure?`}
onConfirm={onConfirmClose}
onCancel={() => cancelClose()}
focusCancelBtn
>
Close this project
</SweetAlert>
{RenderDialogForm}
<Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4>
<Row>
<Col>
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} />
</Col>
</Row>
</CardHeader>
<CardBody>
{RenderTable}
</CardBody>
</Card>
</div>
)
}
export default Closing;
import * as XLSX from 'xlsx';
import DialogForm from './DialogForm';
import React, { useState, useEffect, useMemo } from 'react';
import SweetAlert from 'react-bootstrap-sweetalert';
import axios from "../../../const/interceptorApi";
import moment from 'moment'
import { BASE_SIMPRO, PROYEK_ADD, PROYEK_SEARCH, PROYEK_EDIT, PROYEK_DELETE } from '../../../const/ApiConst';
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap';
import { DownloadOutlined } from '@ant-design/icons';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Table, Button, Tooltip } from 'antd';
import { formatRupiah } from '../../../const/CustomFunc'
const url = "";
const proyek_id = localStorage.getItem('proyek_id');
const role_id = localStorage.getItem('role_id');
const company_id = window.localStorage.getItem('company_id');
const format = "DD-MM-YYYY";
const Closing = ({ params, ...props }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [alertClose, setAlertClose] = useState(false)
const [alertDelete, setAlertDelete] = useState(false)
const [allDataMenu, setAllDataMenu] = useState([])
const [clickOpenModal, setClickOpenModal] = useState(false)
const [currentPage, setCurrentPage] = useState(1)
const [dataCharter, setDataCharter] = useState(null)
const [dataEdit, setDataEdit] = useState([])
const [dataEditSub, setDataEditSub] = useState([])
const [dataExport, setDataExport] = useState([])
const [dataTable, setDatatable] = useState([])
const [dataView, setDataView] = useState([])
const [idDelete, setIdDelete] = useState(0)
const [idTask, setidTask] = useState(0);
const [openDialog, setOpenDialog] = useState(false)
const [openDialogMap, setOpenDialogMap] = useState(false)
const [openDialogResource, setOpenDialogResource] = useState(false)
const [openDialogViewDetail, setOpenDialogViewDetail] = useState(false)
const [rowsPerPage, setRowsPerPage] = useState(10)
const [search, setSearch] = useState('')
const [totalPage, setTotalPage] = useState(0)
const [typeDialog, setTypeDialog] = useState('Save');
const [typeDialogSub, setTypeDialogSub] = useState('Save')
const [userProyek, setUserProyek] = useState([]);
const pageName = params.name;
useEffect(() => {
getDataProyek()
}, [])
const handleSearch = e => {
const value = e.target.value
setSearch(value);
setCurrentPage(1)
};
const getDataProyek = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = (currentPage * rowsPerPage) - rowsPerPage
}
const payload = {
"columns": [
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" }
],
"joins": [
{ "name": "m_users", "column_join": "pm_id", "column_results": ["name", "username"] },
{ "name": "m_type_proyek", "column_join": "type_proyek_id", "column_results": ["name", "description"] },
],
"orders": { "columns": ["id"], "ascending": true },
"paging": { "start": 0, "length": 25 }
}
if (parseInt(role_id) !== 1) {
payload["columns"] = [
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" }
]
}
const URL = `${BASE_SIMPRO}/proyek/search-detail`
const result = await axios
.post(URL, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || []
setDatatable(dataRes);
setTotalPage(result.data.totalRecord);
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
}
}
const handleOpenDialog = (id) => {
setOpenDialog(true)
setidTask(id)
}
const handleOpenDialogResource = (data) => {
setOpenDialogResource(true)
setidTask(data.id)
setUserProyek(data.user_proyeks)
}
const handleOpenDialogViewDetail = (data) => {
setOpenDialogViewDetail(true)
setidTask(data.id)
setDataView(data)
setDataCharter(data.project_charter ? data.project_charter : null)
}
const handleCloseDialog = (type, payload) => {
if (type === "add") saveProyek(payload);
if (type === "edit") editProyek(payload);
setOpenDialog(false)
}
const handleCloseDialogResource = (type, payload) => {
setOpenDialogResource(false)
}
const handleCloseDialogView = (type, payload) => {
setOpenDialogViewDetail(false)
}
const toggleAddDialog = () => setOpenDialog(!openDialog)
const toggleAddDialogResource = () => setOpenDialogResource(!openDialog)
const toggleAddDialogView = () => setOpenDialogViewDetail(!openDialogViewDetail)
const onConfirmDelete = async () => {
let urlDel = PROYEK_DELETE(idDelete, company_id)
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data proyek berhasil dihapus`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data proyek gagal dihapus`, 'Failed!!');
}
}
const onConfirmClose = async () => {
setIdDelete(0)
setAlertClose(false)
NotificationManager.success(`Data proyek berhasil diclose`, 'Success!!');
}
const saveProyek = async (data) => {
const formData = data
const result = await axios.post(PROYEK_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
NotificationManager.success(`Data proyek berhasil ditambah`, 'Success!!');
} else {
NotificationManager.error(`${result.data.message}`, 'Failed!!');
}
}
const editProyek = async (data) => {
let urlEdit = PROYEK_EDIT(data.id)
const formData = data
const result = await axios.put(urlEdit, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
NotificationManager.success(`Data proyek berhasil diedit`, 'Success!!');
} else {
NotificationManager.error(`Data proyek gagal di edit`, `Failed!!`);
}
}
const handleDelete = async (id) => {
await setAlertDelete(true)
await setIdDelete(id)
}
const handleCloseProject = async (id) => {
await setAlertClose(true)
await setIdDelete(id)
}
const onShowSizeChange = (current, pageSize) => {
setRowsPerPage(pageSize)
}
const onPagination = (current, pageSize) => {
setCurrentPage(current)
}
const handleExportExcel = async () => {
const payload = {
"paging": { "start": 0, "length": -1 },
"joins": [],
"orders": { "columns": ["id"], "ascending": false }
}
if (parseInt(role_id) !== 1) {
payload["columns"] = [
{ "name": "id", "logic_operator": "=", "value": proyek_id, "operator": "AND" }
]
}
const result = await axios
.post(PROYEK_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let resData = result.data.data;
const excelData = [];
resData.map((n, index) => {
let dataRow = {
"Nama Proyek": n.nama,
"Biaya": n.biaya,
"Color Progress": n.color_progress,
"Jumlah Pekerja": n.jumlah_pekerja,
"Tanggal Mulai": n.mulai_proyek ? moment(n.mulai_proyek).format(format) : "-",
"Tanggal Selesai": n.akhir_proyek ? moment(n.akhir_proyek).format(format) : "-",
}
excelData.push(dataRow)
})
await setDataExport(excelData);
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
const exportExcel = () => {
const dataExcel = dataExport || [];
const fileName = `Data ${pageName}.xlsx`;
const ws = XLSX.utils.json_to_sheet(dataExcel);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`);
XLSX.writeFile(wb, fileName);
setDataExport([])
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const cancelClose = () => {
setAlertClose(false)
setIdDelete(0)
}
const renderFormatRupiah = (text, prefix) => {
if (text) {
return formatRupiah(text, prefix)
} else {
return "-"
}
}
const handleClickGantt = (id) => {
props.history.push({
pathname: '/gantt',
state: { proyek_id: id }
})
}
const RenderTable = useMemo(() => {
const columns = [
{
title: 'Action',
dataIndex: '',
key: 'x',
render: (text, record) => <>
<Tooltip title="Report">
<Button size="small" type="link" style={{ color: 'orange' }} onClick={() => handleOpenDialog(text.id)}><i className="fa fa-print"></i></Button>
</Tooltip>
</>,
},
{ title: 'Nama Proyek', dataIndex: 'nama', key: 'nama' },
{
title: 'Planning Cost',
dataIndex: 'rencana_biaya',
key: 'rencana_biaya',
render: (text, record) => { return renderFormatRupiah(text, "Rp") }
},
{
title: 'Project Type',
dataIndex: 'color_progress',
key: 'color_progress',
render: (text, record) => <>{record.join.m_type_proyek_name}</>
},
{
title: 'PM', dataIndex: 'pic', key: 'pic',
render: (text, record) => <>{record.join.m_users_name}</>
},
{
title: 'Time Project',
dataIndex: 'akhir_proyek',
key: 'akhir_proyek',
render: (text, record) => <>{moment(record.mulai_proyek).format(format)} - {moment(record.akhir_proyek).format(format)}</>,
},
];
return (
<Table
size="small"
columns={columns}
dataSource={dataTable}
/>
)
}, [dataTable])
const RenderDialogForm = useMemo(() => (
<DialogForm
openDialog={openDialog}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
idTask={idTask}
/>
), [openDialog])
return (
<div>
<NotificationContainer />
<SweetAlert
show={alertClose}
warning
showCancel
confirmBtnText="Close"
confirmBtnBsStyle="danger"
title={`Are you sure?`}
onConfirm={onConfirmClose}
onCancel={() => cancelClose()}
focusCancelBtn
>
Close this project
</SweetAlert>
{RenderDialogForm}
<Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4>
<Row>
<Col>
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={`Cari nama proyek`} />
</Col>
</Row>
</CardHeader>
<CardBody>
{RenderTable}
</CardBody>
</Card>
</div>
)
}
export default Closing;

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

@ -84,7 +84,7 @@ const AssignCustProject = ({ openDialog, closeDialog, toggleDialog, idTask, proy
}
const onConfirmDelete = async () => {
let urlDel = ASSIGN_HR_PROJECT_DELETE(idDelete)
let urlDel = ASSIGN_HR_PROJECT_DELETE(idDelete, company_id)
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);

22
src/views/SimproV2/CreatedProyek/DialogDocument.js

@ -5,7 +5,7 @@ import { Table, Tooltip, Popover, Spin } from 'antd';
import 'antd/dist/antd.css';
import moment from 'moment';
import SweetAlert from 'react-bootstrap-sweetalert';
import { DOCUMENT_DOWNLOAD, DOCUMENT_GET, BASE_SIMPRO_LUMEN_FILE, REQUEST_MATERIAL_EDIT, DOCUMENT_DELETE, DOCUMENT_SEARCH, FOLDER_DOCUMENT_PROYEK_GET_TREE, FOLDER_DOCUMENT_PROYEK_DELETE } from '../../../const/ApiConst';
import { DOCUMENT_DOWNLOAD, DOCUMENT_GET, BASE_SIMPRO_LUMEN_FILE_COMPANY, REQUEST_MATERIAL_EDIT, DOCUMENT_DELETE, DOCUMENT_SEARCH, FOLDER_DOCUMENT_PROYEK_GET_TREE, FOLDER_DOCUMENT_PROYEK_DELETE } from '../../../const/ApiConst';
import axios from "../../../const/interceptorApi"
import { NotificationContainer, NotificationManager } from 'react-notifications';
import DialogRequest from './FormDocument';
@ -18,13 +18,6 @@ const DialogDocument = ({ openDialog, closeDialog, toggleDialog, idTask, proyekN
"Authorization": `Bearer ${token}`
}
}
const config = {
headers:
{
Authorization: `Bearer ${token}`,
"Content-type": `application/json`
}
};
const [dataDocument, setDataDocument] = useState([])
const [openDialogReq, setOpenDialogReq] = useState(false)
const [openDialogNewFolder, setOpenDialogNewFolder] = useState(false)
@ -34,6 +27,7 @@ const DialogDocument = ({ openDialog, closeDialog, toggleDialog, idTask, proyekN
const [dataEdit, setDataEdit] = useState(null)
const [parentIdNewFolder, setParentIdNewFolder] = useState(0)
const [loading, setLoading] = useState(true);
const company_id = window.localStorage.getItem('company_id');
useEffect(() => {
if (idTask > 0) {
@ -58,7 +52,7 @@ const DialogDocument = ({ openDialog, closeDialog, toggleDialog, idTask, proyekN
const getDataDocument = async () => {
const url = FOLDER_DOCUMENT_PROYEK_GET_TREE(idTask)
const result = await axios
.get(url, config)
.get(url, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
@ -86,7 +80,7 @@ const DialogDocument = ({ openDialog, closeDialog, toggleDialog, idTask, proyekN
}
const handleDownload = (id, file) => {
fetch(DOCUMENT_DOWNLOAD(id), {
fetch(DOCUMENT_DOWNLOAD(id, company_id), {
headers: new Headers({
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
@ -101,14 +95,12 @@ const DialogDocument = ({ openDialog, closeDialog, toggleDialog, idTask, proyekN
a.click();
a.remove();
});
//window.location.href = response.url;
});
// const urlDownload = DOCUMENT_DOWNLOAD(id);
// window.open(urlDownload);
}
const handleShow = (file) => {
const urlShow = `${BASE_SIMPRO_LUMEN_FILE}/${file}`
const configApp = JSON.parse(window.localStorage.getItem('configApp'));
const urlShow = `${BASE_SIMPRO_LUMEN_FILE_COMPANY(file, configApp.company_name)}`
window.open(urlShow);
}
@ -215,7 +207,7 @@ const DialogDocument = ({ openDialog, closeDialog, toggleDialog, idTask, proyekN
}
const onConfirmDelete = async () => {
let urlDel = DOCUMENT_DELETE(idDelete)
let urlDel = DOCUMENT_DELETE(idDelete, company_id)
const result = await axios.delete(urlDel, HEADER)
.then(res => res)
.catch((error) => error.response);

195
src/views/SimproV2/CreatedProyek/FormDocument.js

@ -1,96 +1,99 @@
import React, { useEffect, useState } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { Button, Form, FormGroup, Label, Input, Col, Row } from 'reactstrap';
import axios from "../../../const/interceptorApi";
import { DOCUMENT_ADD } from '../../../const/ApiConst';
import 'antd/dist/antd.css';
import { NotificationManager } from 'react-notifications';
const DialogRequest = ({ openDialog, closeDialog, toggleDialog, idTask, parentIdNewFolder }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [id, setId] = useState(0)
const [file, setFile] = useState(null)
const handleCLearData = () => {
setId(0)
setFile(null)
}
useEffect(() => {
handleCLearData()
}, [openDialog])
const handleSave = () => {
uploadDokumen()
handleCLearData()
}
const uploadDokumen = async () => {
const formData = new FormData;
formData.append('dokumen', file, file.name);
if (parentIdNewFolder > 0) {
formData.append('ref_id', parentIdNewFolder); // folder_id
formData.append('type_dokumen', 'project-document-in-folder');
}
else {
formData.append('ref_id', idTask); // proyek_id
formData.append('type_dokumen', 'project-document-out-folder')
}
const result = await axios
.post(DOCUMENT_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.status == 200) {
NotificationManager.success('Dokumen project berhasil diupload!!', 'Success');
closeDialog('upload')
} else {
NotificationManager.error('Dokumen project gagal diupload!!', 'Failed');
closeDialog('failed upload')
}
}
const handleCancel = () => {
closeDialog('cancel')
handleCLearData()
}
const renderForm = () => {
return (
<Form>
<FormGroup>
<Label className="capitalize">Upload File</Label>
<Input type="file" onChange={(e) => setFile(e.target.files[0])} />
</FormGroup>
</Form>
)
}
return (
<>
<Modal isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>Upload Project Document</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>Upload</Button>{' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Cancel</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogRequest;
import React, { useEffect, useState } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { Button, Form, FormGroup, Label, Input, Col, Row } from 'reactstrap';
import axios from "../../../const/interceptorApi";
import { DOCUMENT_ADD } from '../../../const/ApiConst';
import 'antd/dist/antd.css';
import { NotificationManager } from 'react-notifications';
const DialogRequest = ({ openDialog, closeDialog, toggleDialog, idTask, parentIdNewFolder }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const [id, setId] = useState(0)
const [file, setFile] = useState(null)
const handleCLearData = () => {
setId(0)
setFile(null)
}
useEffect(() => {
handleCLearData()
}, [openDialog])
const handleSave = () => {
uploadDokumen()
handleCLearData()
}
const uploadDokumen = async () => {
const configApp = JSON.parse(window.localStorage.getItem('configApp'));
const formData = new FormData;
formData.append('dokumen', file, file.name);
formData.append('company_name',configApp.company_name);
if (parentIdNewFolder > 0) {
formData.append('ref_id', parentIdNewFolder); // folder_id
formData.append('type_dokumen', 'project-document-in-folder');
}
else {
formData.append('ref_id', idTask); // proyek_id
formData.append('type_dokumen', 'project-document-out-folder')
}
const result = await axios
.post(DOCUMENT_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
const notif = result.data.message;
if (result && result.status == 200) {
NotificationManager.success(notif, 'Success');
closeDialog('upload')
} else {
NotificationManager.error(notif, 'Failed');
closeDialog('failed upload')
}
}
const handleCancel = () => {
closeDialog('cancel')
handleCLearData()
}
const renderForm = () => {
return (
<Form>
<FormGroup>
<Label className="capitalize">Upload File</Label>
<Input type="file" onChange={(e) => setFile(e.target.files[0])} />
</FormGroup>
</Form>
)
}
return (
<>
<Modal isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>Upload Project Document</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>Upload</Button>{' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Cancel</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogRequest;

16
src/views/SimproV2/CreatedProyek/ImportActivity/index.js

@ -93,6 +93,7 @@ const ImportActivity = ({ params }) => {
//
const [isMovePage, setIsMovePage] = useState(false);
const [isPreview, setIsPreview] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
getDataAssignHr();
@ -130,7 +131,9 @@ const ImportActivity = ({ params }) => {
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || []
setdataUserToProject(dataRes);
setLoading(false)
} else {
setLoading(false)
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
}
}
@ -144,6 +147,7 @@ const ImportActivity = ({ params }) => {
setIsMovePage(false);
}, 5000);
} else {
setLoading(false)
NotificationManager.error('file harus dalam format .xlsx', 'Failed');
}
// else{
@ -219,8 +223,9 @@ const ImportActivity = ({ params }) => {
}
dataMapped.push(extractedRow)
setLoading(false)
}
setLoading(false)
setDatatable(dataMapped)
}
});
@ -250,8 +255,11 @@ const ImportActivity = ({ params }) => {
const timestamp = Date.now();
const newTimestamp = timestamp + 60000;
window.location = urlSplitted[0] + '//' + urlSplitted[2] + `/#/projects/` + ganttId + '/' + result.data.projectId + '/' + newTimestamp + '/gantt'
}
setLoading(false)
}else{
setLoading(false)
}
setLoading(false)
setIsMovePage(true);
setIsPreview(true);
}
@ -369,7 +377,7 @@ const ImportActivity = ({ params }) => {
<h4 className="capitalize">Data Preview</h4>
</CardHeader>
<CardBody>
<Spin tip="Loading...">
<Spin tip="Loading..." spinning={loading}>
<Table
rowClassName={(record, index) => index % 2 == 0 ? 'table-row-light' : 'table-row-dark'}
dataSource={dataTable}

265
src/views/SimproV2/CreatedProyek/ReportAnalysis.js

@ -1,4 +1,4 @@
import React, {useState, useEffect} from 'react'
import React, { useState, useEffect } from 'react'
import {
Modal,
ModalHeader,
@ -73,67 +73,76 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
};
const columns = [
{title: "Gantt", dataIndex: "name_version", key: "name_version"},
{title: "Baseline Start", dataIndex: "planned_start", key: "planned_start",
{ title: "Gantt", dataIndex: "name_version", key: "name_version" },
{
title: "Baseline Start", dataIndex: "planned_start", key: "planned_start",
render: (text, record) => (
<>
{record.planned_start ? moment(record.planned_start).format("DD-MM-YY") : ''}
</>
),
<>
{record.planned_start ? moment(record.planned_start).format("DD-MM-YY") : ''}
</>
),
},
{title: "Baseline Finish", dataIndex: "planned_end", key: "planned_end",
{
title: "Baseline Finish", dataIndex: "planned_end", key: "planned_end",
render: (text, record) => (
<>
{record.planned_end ? moment(record.planned_end).format("DD-MM-YY") : ''}
</>
),
<>
{record.planned_end ? moment(record.planned_end).format("DD-MM-YY") : ''}
</>
),
},
{title: "Early Start", dataIndex: "start_date", key: "start_date",
{
title: "Early Start", dataIndex: "start_date", key: "start_date",
render: (text, record) => (
<>
{moment(record.start_date).format("DD-MM-YY")}
</>
),
<>
{moment(record.start_date).format("DD-MM-YY")}
</>
),
},
{title: "Early Finish", dataIndex: "end_date", key: "end_date",
{
title: "Early Finish", dataIndex: "end_date", key: "end_date",
render: (text, record) => (
<>
{moment(record.end_date).format("DD-MM-YY")}
</>
),
<>
{moment(record.end_date).format("DD-MM-YY")}
</>
),
},
{title: "Actual Start", dataIndex: "actual_start", key: "actual_start",
{
title: "Actual Start", dataIndex: "actual_start", key: "actual_start",
render: (text, record) => (
<>
{record.actual_start ? moment(record.actual_start).format("DD-MM-YY") : ""}
</>
),
<>
{record.actual_start ? moment(record.actual_start).format("DD-MM-YY") : ""}
</>
),
},
{title: "Actual Finish", dataIndex: "actual_end", key: "actual_end",
{
title: "Actual Finish", dataIndex: "actual_end", key: "actual_end",
render: (text, record) => (
<>
{record.actual_end ? moment(record.actual_end).format("DD-MM-YY") : ""}
</>
),
<>
{record.actual_end ? moment(record.actual_end).format("DD-MM-YY") : ""}
</>
),
},
{title: "Assign HR", dataIndex: "user_name", key: "user_name", width: "8%",
ellipsis:{
showTitle: true
},
render: (text) =>
<Tooltip placement="topLeft" title={text}>
{text}
</Tooltip>
{
title: "Assign HR", dataIndex: "user_name", key: "user_name", width: "8%",
ellipsis: {
showTitle: true
},
render: (text) =>
<Tooltip placement="topLeft" title={text}>
{text}
</Tooltip>
},
{title: "Volume Plan", dataIndex: "qty_planning", key: "qty_planning",
render: (text, record) =>
<>
{text ? text : 0}
</>
{
title: "Volume Plan", dataIndex: "qty_planning", key: "qty_planning",
render: (text, record) =>
<>
{text ? text : 0}
</>
},
{title: "Volume Actual", dataIndex: "qty", key: "qty"},
{title: "Progress Plan (%)", dataIndex: "persentase_progress", key: "persentase_progress",
render: (text, record) => {
{ title: "Volume Actual", dataIndex: "qty", key: "qty" },
{
title: "Progress Plan (%)", dataIndex: "persentase_progress", key: "persentase_progress",
render: (text, record) => {
const startDate = moment(record.start_date);
const duration = record.duration;
@ -148,7 +157,7 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
);
},
},
{title: "Progress Actual (%)", dataIndex: "persentase_progress", key: "persentase_progress", width: "8%"},
{ title: "Progress Actual (%)", dataIndex: "persentase_progress", key: "persentase_progress", width: "8%" },
{
title: 'Action',
dataIndex: '',
@ -165,59 +174,67 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
]
const columnActivityToHr = [
{title: "Activity", dataIndex: "join_second_name", key: "join_second_name"},
{title: "Gantt", dataIndex: "join_fourth_name_version", key: "join_fourth_name_version"},
{title: "Baseline Start", dataIndex: "join_second_planned_start", key: "join_second_planned_start",
{ title: "Activity", dataIndex: "join_second_name", key: "join_second_name" },
{ title: "Gantt", dataIndex: "join_fourth_name_version", key: "join_fourth_name_version" },
{
title: "Baseline Start", dataIndex: "join_second_planned_start", key: "join_second_planned_start",
render: (text, record) => (
<>
{moment(record.join_second_planned_start).format("DD-MM-YY")}
</>
),
<>
{moment(record.join_second_planned_start).format("DD-MM-YY")}
</>
),
},
{title: "Baseline Finish", dataIndex: "join_second_planned_end", key: "join_second_planned_end",
{
title: "Baseline Finish", dataIndex: "join_second_planned_end", key: "join_second_planned_end",
render: (text, record) => (
<>
{moment(record.join_second_planned_end).format("DD-MM-YY")}
</>
),
<>
{moment(record.join_second_planned_end).format("DD-MM-YY")}
</>
),
},
{title: "Early Start", dataIndex: "join_second_start_date", key: "join_second_start_date",
{
title: "Early Start", dataIndex: "join_second_start_date", key: "join_second_start_date",
render: (text, record) => (
<>
{moment(record.join_second_start_date).format("DD-MM-YY")}
</>
),
<>
{moment(record.join_second_start_date).format("DD-MM-YY")}
</>
),
},
{title: "Early Finish", dataIndex: "join_second_end_date", key: "join_second_end_date",
{
title: "Early Finish", dataIndex: "join_second_end_date", key: "join_second_end_date",
render: (text, record) => (
<>
{moment(record.join_second_end_date).format("DD-MM-YY")}
</>
),
<>
{moment(record.join_second_end_date).format("DD-MM-YY")}
</>
),
},
{title: "Actual Start", dataIndex: "join_second_actual_start", key: "join_second_actual_start",
{
title: "Actual Start", dataIndex: "join_second_actual_start", key: "join_second_actual_start",
render: (text, record) => (
<>
{record.join_second_actual_start ? moment(record.join_second_actual_start).format("DD-MM-YY") : ""}
</>
),
<>
{record.join_second_actual_start ? moment(record.join_second_actual_start).format("DD-MM-YY") : ""}
</>
),
},
{title: "Actual Finish", dataIndex: "join_second_actual_end", key: "join_second_actual_end",
{
title: "Actual Finish", dataIndex: "join_second_actual_end", key: "join_second_actual_end",
render: (text, record) => (
<>
{record.join_second_actual_end ? moment(record.join_second_actual_end).format("DD-MM-YY") : ""}
</>
),
<>
{record.join_second_actual_end ? moment(record.join_second_actual_end).format("DD-MM-YY") : ""}
</>
),
},
{title: "Volume Plan", dataIndex: "join_third_qty_planning", key: "join_third_qty_planning",
render: (text, record) =>
<>
{text ? text : 0}
</>
{
title: "Volume Plan", dataIndex: "join_third_qty_planning", key: "join_third_qty_planning",
render: (text, record) =>
<>
{text ? text : 0}
</>
},
{title: "Volume Actual", dataIndex: "volume_actual", key: "volume_actual"},
{title: "Progress Plan (%)", dataIndex: "join_second_persentase_progress", key: "persentase_progress",
render: (text, record) => {
{ title: "Volume Actual", dataIndex: "volume_actual", key: "volume_actual" },
{
title: "Progress Plan (%)", dataIndex: "join_second_persentase_progress", key: "persentase_progress",
render: (text, record) => {
const startDate = moment(record.join_second_start_date);
const duration = record.join_second_duration;
@ -232,20 +249,20 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
);
},
},
{title: "Progress Actual (%)", dataIndex: "join_second_persentase_progress", key: "persentase_progress"},
{ title: "Progress Actual (%)", dataIndex: "join_second_persentase_progress", key: "persentase_progress" },
{
title: 'Action',
dataIndex: '',
key: 'id',
className: "nowrap",
render: (text, record) =>
<>
<Tooltip title="Detail Activity">
<Button size={"sm"} color='primary' onClick={() => handleDetail(text)}><i className="fa fa-eye"></i></Button>
</Tooltip>{" "}
</>
,
},
title: 'Action',
dataIndex: '',
key: 'id',
className: "nowrap",
render: (text, record) =>
<>
<Tooltip title="Detail Activity">
<Button size={"sm"} color='primary' onClick={() => handleDetail(text)}><i className="fa fa-eye"></i></Button>
</Tooltip>{" "}
</>
,
},
]
useEffect(() => {
@ -297,10 +314,10 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
if (status == "Save") {
// getdataGantt()
NotificationManager.success(`Gantt berhasil dibuat!`, 'Success!!');
}else if (status == "Edit") {
} else if (status == "Edit") {
// getdataGantt()
NotificationManager.success(`Gantt berhasil dibubah!`, 'Failed!!');
}else if (status == "failed") {
} else if (status == "failed") {
NotificationManager.error(`Gantt gagal dibuat!`, 'Failed!!');
}
setDataDetail(null)
@ -338,7 +355,21 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || [];
setHrList(dataRes);
let groupedData = {};
dataRes.forEach(data => {
if (groupedData[data.join_first_name]) {
groupedData[data.join_first_name].join_first_id = Math.min(groupedData[data.join_first_name].join_first_id, data.join_first_id);
} else {
groupedData[data.join_first_name] = {
join_first_id: data.join_first_id,
join_first_name: data.join_first_name
};
}
});
let dataFiltered = Object.values(groupedData);
setHrList(dataFiltered);
} else {
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
@ -382,21 +413,21 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
name1: "m_activity",
name: "assign_material_to_activity",
column_join: "id",
column_self:"activity_id",
column_results: ["id", "qty_planning"]
column_self: "activity_id",
column_results: ["qty_planning"]
},
{
name1: "m_activity",
name: "m_version_gantt",
column_join: "version_gantt_id",
column_self:"id",
column_self: "id",
column_results: ["name_version"]
},
{
name1: "m_activity",
name: "report_activity_material",
column_join: "id",
column_self:"activity_id",
column_self: "activity_id",
},
],
orders: { columns: ["id"], ascending: false },
@ -411,7 +442,7 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || [];
dataRes.forEach(element => {
element.join_third_persentase_progress ? sum += parseInt(element.join_third_persentase_progress) : sum += 0;
element.join_third_persentase_progress ? sum += parseInt(element.join_third_persentase_progress) : sum += 0;
});
setAvgActivityHr(sum / dataRes.length);
setDataTableActivityToHr(dataRes);
@ -485,9 +516,9 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
let dataRes = result.data.data || [];
dataRes.forEach(element => {
element.persentase_progress ? sum += parseInt(element.persentase_progress) : sum += 0;
element.qty_planning ? sumPlan += parseInt(element.qty_planning) : sumPlan += 0;
element.qty ? sumAct += parseInt(element.qty) : sumAct += 0;
element.persentase_progress ? sum += parseInt(element.persentase_progress) : sum += 0;
element.qty_planning ? sumPlan += parseInt(element.qty_planning) : sumPlan += 0;
element.qty ? sumAct += parseInt(element.qty) : sumAct += 0;
});
setAvgActivity(sum / dataRes.length);
setSumVolPlan(sumPlan);
@ -536,9 +567,9 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
<Select showSearch value={search} onChange={(val) => setSearch(val)} placeholder="Select Activity" filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
} style={{ width: 200 }}>
{groupedActivity && groupedActivity.map((res, index) => (
{groupedActivity && groupedActivity.map((res, index) => (
<Option key={index} value={res.name}>{`${res.name}`}</Option>
))}
))}
</Select>
</Col>
</Row>
@ -573,9 +604,9 @@ const ReportAnalysis = ({ openDialog, closeDialog, toggleDialog, projectId }) =>
<Select showSearch value={selectedHr} onChange={(val) => setSelectedHr(val)} placeholder="Select Human Resource" filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
} style={{ width: 200 }}>
{hrList && hrList.map(res => (
{hrList && hrList.map(res => (
<Option key={res.join_first_id} value={res.join_first_id}>{`${res.join_first_name}`}</Option>
))}
))}
</Select>
</Col>
</Row>

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

@ -968,7 +968,7 @@ const CreatedProyek = ({ params, ...props }) => {
};
const onConfirmDelete = async () => {
let urlDel = PROYEK_DELETE(idDelete);
let urlDel = PROYEK_DELETE(idDelete, company_id);
const result = await axios
.delete(urlDel, HEADER)
.then((res) => res)
@ -1189,8 +1189,8 @@ const CreatedProyek = ({ params, ...props }) => {
};
const deleteImage = async (id) => {
const URL = IMAGE_DELETE(id, 'project_structure_organization');
const company_id = localStorage.getItem("company_id");
const URL = IMAGE_DELETE(id, 'project_structure_organization', company_id);
await axios
.delete(URL, HEADER)
.then(res => res)

201
src/views/SimproV2/Demo/DialogForm.js

@ -0,0 +1,201 @@
import React, { useEffect, useState } from 'react'
import {
Modal, ModalHeader, ModalBody, ModalFooter,
Button, Form, FormGroup, Label, Input, Col, Row
} from 'reactstrap';
import { Select } from 'antd';
import 'antd/dist/antd.css';
import { useTranslation } from 'react-i18next';
import "rc-color-picker/assets/index.css";
const { Option } = Select
const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit }) => {
const [id, setId] = useState(0)
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [message, setMessage] = useState('')
const [phoneNumber, setPhoneNumber] = useState('')
const [role, setRole] = useState(null)
const [status, setStatus] = useState('')
const { t } = useTranslation()
useEffect(() => {
if (typeDialog === "Edit") {
setId(dataEdit.id)
setName(dataEdit.name)
setEmail(dataEdit.email)
setMessage(dataEdit.message)
setPhoneNumber(dataEdit.number_phone)
setStatus(dataEdit.status)
setRole(dataEdit.role)
} else {
setId(0)
setName('')
setEmail('')
setMessage('')
setStatus('')
setRole('')
setPhoneNumber('')
}
}, [dataEdit, openDialog])
const validation = () => {
if (!name || name === "") {
alert("Name cannot be empty!");
return true;
}
}
const handleSave = () => {
let data = '';
const err = validation();
if (!err) {
if (typeDialog === "Save") {
data = {
name,
email,
message,
number_phone: phoneNumber,
role,
status
}
closeDialog('save', data);
} else {
data = {
id,
name,
email,
message,
number_phone: phoneNumber,
role,
status
}
closeDialog('edit', data);
}
setId(0)
setName('')
}
}
const handleCancel = () => {
closeDialog('cancel', 'none')
setId(0)
setName('')
}
const onChangeStatus = (val) => {
setStatus(val)
}
const renderForm = () => {
return (
<Form>
<Row>
<Col md={12}>
<span style={{ color: "red" }}>*</span> Wajib diisi.
</Col>
</Row>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('name')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder={t('inputName')}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('email')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder={t('inputEmail')}
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('phoneNumber')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={phoneNumber}
onChange={(e) => setName(e.target.value)}
placeholder={t('inputNoPhone')}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('role')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={role}
onChange={(e) => setRole(e.target.value)}
placeholder={t('inputRole')}
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col md={12}>
<FormGroup>
<Label className="capitalize">
{t('status')}<span style={{ color: "red" }}>*</span>
</Label>
<Select
showSearch
filterOption={(inputValue, option) =>
option.children.toLowerCase().includes(inputValue.toLowerCase())
}
value={status}
defaultValue={status}
onChange={onChangeStatus}
style={{ width: "100%" }}
>
<Option value="New Request">New Request</Option>
<Option value="Presentation">Presentation</Option>
<Option value="Live Demo">Live Demo</Option>
<Option value="Trial">Trial</Option>
<Option value="Go-Live">Go-Live</Option>
<Option value="Postpone">Postpone</Option>
</Select>
</FormGroup>
</Col>
</Row>
<Row>
<Col md={12}>
<FormGroup>
<Label className="capitalize">{t('message')}</Label>
<Input row="4" type="textarea" value={message} onChange={(e) => setMessage(e.target.value)} placeholder={t('inputMessage')} />
</FormGroup>
</Col>
</Row>
</Form>
)
}
return (
<>
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog == "Save" ? `Add` : "Edit"} {t('Demo')}</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>{t('cancel')}</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogForm;

367
src/views/SimproV2/Demo/index.js

@ -0,0 +1,367 @@
import * as XLSX from 'xlsx';
import DialogForm from './DialogForm';
import React, { useState, useEffect } from 'react';
import SweetAlert from 'react-bootstrap-sweetalert';
import axios from "../../../const/interceptorApi"
import { Card, CardBody, CardHeader, Col, Row, Input, Table } from 'reactstrap';
import { DEMO_MANAGEMENT_EDIT, DEMO_MANAGEMENT_SEARCH, DEMO_MANAGEMENT_LIST, DEMO_MANAGEMENT_GET_ID, DEMO_MANAGEMENT_ADD, DEMO_MANAGEMENT_DELETE } from '../../../const/ApiConst';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Button, Tooltip } from 'antd';
import { useTranslation } from 'react-i18next';
const ProjectType = ({ params, ...props }) => {
let role_id = 0, user_id = 0, isLogin = false, token = '', company_id = 0, all_project = null, role_name = '', hierarchy = [], user_name = '';
if (props && props.role_id && props.user_id) {
role_id = props.role_id;
user_id = props.user_id;
token = props.token;
isLogin = props.isLogin;
company_id = props.company_id;
all_project = props.all_project;
role_name = props.role_name;
isLogin = props.isLogin;
hierarchy = props.hierarchy;
user_name = props.user_name;
}
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const pageName = params.name;
const [alertDelete, setAlertDelete] = useState(false)
const [allDataMenu, setAllDataMenu] = useState([])
const [clickOpenModal, setClickOpenModal] = useState(false)
const [currentPage, setCurrentPage] = useState(1)
const [dataEdit, setDataEdit] = useState([])
const [dataExport, setDataExport] = useState([])
const [dataTable, setDatatable] = useState([])
const [idDelete, setIdDelete] = useState(0)
const [openDialog, setOpenDialog] = useState(false)
const [rowsPerPage, setRowsPerPage] = useState(10)
const [search, setSearch] = useState("")
const [totalPage, setTotalPage] = useState(0)
const [typeDialog, setTypeDialog] = useState('Save')
const [dataDemo, setDataDemo] = useState([])
const [listCompany, setListCompany] = useState([])
const { t } = useTranslation()
const column = [
{ name: t('name') },
{ name: t('email') },
{ name: t('roles') },
{ name: t('phoneNumber') },
{ name: t('status') },
{ name: t('message') },
].filter(column => column && column.name);
useEffect(() => {
getDataDemo();
}, [currentPage, rowsPerPage, search])
useEffect(() => {
const cekData = dataExport || []
if (cekData.length > 0) {
exportExcel()
}
}, [dataExport])
const getDataDemo = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = currentPage * rowsPerPage - rowsPerPage;
}
const payload = {
group_column: {
"operator": "AND",
"group_operator": "OR",
"where": [
{
"name": "name",
"logic_operator": "~*",
"value": search,
}
]
},
columns: [],
"orders": {
"ascending": true,
"columns": [
'id'
]
},
"paging": {
"length": rowsPerPage,
"start": start
},
'joins': []
}
const result = await axios
.post(DEMO_MANAGEMENT_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
setDatatable(result.data.data);
setTotalPage(result.data.totalRecord);
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
}
}
const handleExportExcel = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = (currentPage * rowsPerPage) - rowsPerPage
}
const payload = {
group_column: {
"operator": "AND",
"group_operator": "OR",
"where": [
{
"name": "name",
"logic_operator": "~*",
"value": search,
}
]
},
"columns": [],
"orders": {
"ascending": true,
"columns": [
'id'
]
},
"paging": {
"length": rowsPerPage,
"start": start
},
'joins': []
}
const result = await axios
.post(DEMO_MANAGEMENT_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let resData = result.data.data;
const excelData = [];
resData.map((val, index) => {
let dataRow = {};
dataRow["Nama"] = val.name;
dataRow["Email"] = val.email;
dataRow["Role"] = val.role;
dataRow["No Telepon"] = val.number_phone;
dataRow["Status"] = val.message;
dataRow["Message"] = val.message;
excelData.push(dataRow)
})
await setDataExport(excelData)
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
const exportExcel = () => {
const dataExcel = dataExport || [];
const fileName = `Data ${pageName}.xlsx`;
const ws = XLSX.utils.json_to_sheet(dataExcel);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`);
XLSX.writeFile(wb, fileName);
setDataExport([])
}
const handleSearch = e => {
const value = e.target.value
setSearch(value);
setCurrentPage(1)
};
const handleOpenDialog = (type) => {
setOpenDialog(true)
setTypeDialog(type)
}
const handleEdit = (data) => {
setDataEdit(data)
handleOpenDialog('Edit');
}
const handleDelete = async (id) => {
await setAlertDelete(true)
await setIdDelete(id)
}
const handleCloseDialog = (type, data) => {
if (type === "save") {
saveDemo(data);
} else if (type === "edit") {
editMaterialR(data);
}
setDataEdit([])
setOpenDialog(false)
}
const saveDemo = async (data) => {
const formData = data
const result = await axios.post(DEMO_MANAGEMENT_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataDemo()
NotificationManager.success(`Data berhasil ditambahkan`, 'Success!!');
} else {
NotificationManager.error(`Data gagal ditambahkan`, 'Failed!!');
}
}
const editMaterialR = async (data) => {
let urlEdit = DEMO_MANAGEMENT_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) {
getDataDemo();
NotificationManager.success(`Data berhasil diubah`, 'Success!!');
} else {
NotificationManager.error(`Data gagal diubah`, `Failed!!`);
}
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
const onConfirmDelete = async () => {
let url = DEMO_MANAGEMENT_DELETE(idDelete);
const result = await axios.delete(url, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataDemo()
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)
setIdDelete(0)
}
const onShowSizeChange = (current, pageSize) => {
setRowsPerPage(pageSize)
}
const onPagination = (current, pageSize) => {
setCurrentPage(current)
}
const dataNotAvailable = () => {
if (dataTable.length === 0) {
return (
<tr>
<td align="center" colSpan="7">{t('noData')}</td>
</tr>
)
}
}
return (
<div>
<NotificationContainer />
<SweetAlert
show={alertDelete}
warning
showCancel
confirmBtnText="Delete"
confirmBtnBsStyle="danger"
title={t('deleteConfirm')}
onConfirm={onConfirmDelete}
onCancel={cancelDelete}
focusCancelBtn
>
{t('deleteMsg')}
</SweetAlert>
<DialogForm
openDialog={openDialog}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
typeDialog={typeDialog}
dataEdit={dataEdit}
clickOpenModal={clickOpenModal}
dataParent={allDataMenu}
/>
<Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4>
<Row>
<Col>
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={t('searchDemo')} />
</Col>
<Col>
<Tooltip title={t('demoAdd')}>
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button>
</Tooltip>
<Tooltip title={t('exportExcel')}>
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button>
</Tooltip>
</Col>
</Row>
</CardHeader>
<CardBody>
<Table responsive striped hover>
<thead>
<tr>
<th>Aksi</th>
{column.map((i, index) => {
return (
<th key={index} scope="row">{i.name}</th>
)
})}
</tr>
</thead>
<tbody>
{dataNotAvailable()}
{dataTable.map((n, index) => {
return (
<tr key={n.id}>
<td className='nowrap'>
<Tooltip title={t('delete')}>
<i id="TooltipDelete" className="fa fa-trash" style={{ color: 'red', marginRight: 10, cursor: "pointer" }} onClick={() => handleDelete(n.id)}></i>
</Tooltip>
<Tooltip title={t('edit')}>
<i id="TooltipEdit" className="fa fa-edit" style={{ color: 'green', cursor: "pointer" }} onClick={() => handleEdit(n)}></i>
</Tooltip>
</td>
<td>{n.name}</td>
<td>{n.email}</td>
<td>{n.role}</td>
<td>{n.number_phone}</td>
<td>{n.status}</td>
<td>{n.message}</td>
</tr>
)
})}
</tbody>
</Table>
</CardBody>
</Card>
</div>
)
}
export default ProjectType;

34
src/views/SimproV2/Divisi/DialogForm.js

@ -30,10 +30,18 @@ const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdi
setName(dataEdit.name)
setParent(dataEdit.parent)
setColor(dataEdit.color)
setParent(dataEdit.parent);
setSelectedCompany(dataEdit.company_id);
} else if (typeDialog === "addChild") {
setParent(dataEdit.id);
setColor(dataEdit.color)
setSelectedCompany(dataEdit.company_id);
} else {
setId(0)
setColor('')
setDescription('')
setParent(null)
setSelectedCompany(null)
}
}, [dataEdit, openDialog])
@ -43,15 +51,16 @@ const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdi
return true;
}
}
const handleSave = () => {
let data = '';
const err = validation();
if (!err) {
if (role_name === 'Super Admin') {
company_id = selectedCompany
}
if (typeDialog === "Save") {
if (role_name === 'Super Admin') {
company_id = selectedCompany
}
data = {
name,
description,
@ -60,10 +69,18 @@ const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdi
company_id: company_id
}
closeDialog('save', data);
} else {
if (role_name === 'Super Admin') {
company_id = selectedCompany
}
} else if (typeDialog === "addChild") {
data = {
parent: parent,
name: name,
description,
color,
company_id: company_id
};
closeDialog('save', data);
} else if (typeDialog === "Edit") {
data = {
id,
name,
@ -82,6 +99,7 @@ const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdi
setSelectedCompany(null)
}
}
const handleCancel = () => {
closeDialog('cancel', 'none')
setId(0)
@ -125,7 +143,7 @@ const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdi
filterOption={(input, option) => option.children.toLowerCase().includes(input.toLowerCase())}
>
{dataDivisions.map((res, idx) => (
<Option key={res['id']} value={res['id']}>{res['displayName']}</Option>
<Option key={res['id']} value={res['id']}>{res['name']}</Option>
))}
</Select>
</FormGroup>

180
src/views/SimproV2/Divisi/index.js

@ -1,12 +1,12 @@
import * as XLSX from 'xlsx';
import DialogForm from './DialogForm';
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import SweetAlert from 'react-bootstrap-sweetalert';
import axios from "../../../const/interceptorApi"
import { Card, CardBody, CardHeader, Col, Row, Input, Table } from 'reactstrap';
import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap';
import { DIVISI_LIST, DIVISI_ADD, DIVISI_EDIT, DIVISI_DELETE, DIVISI_SEARCH, COMPANY_MANAGEMENT_LIST } from '../../../const/ApiConst';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Button, Tooltip } from 'antd';
import { Pagination, Button, Tooltip, Table, Spin } from 'antd';
import { useTranslation } from 'react-i18next';
@ -48,6 +48,7 @@ const ProjectType = ({ params, ...props }) => {
const [typeDialog, setTypeDialog] = useState('Save')
const [dataDivisions, setDataDivisions] = useState([])
const [listCompany, setListCompany] = useState([])
const [loading, setLoading] = useState(true)
const { t } = useTranslation()
const column = [
role_name === 'Super Admin' ? { name: t('company') } : null,
@ -56,7 +57,7 @@ const ProjectType = ({ params, ...props }) => {
{ name: t('color') },
].filter(column => column && column.name);
useEffect(() => {
getDataProjectType();
getDataDivisi();
}, [currentPage, rowsPerPage, search])
useEffect(() => {
@ -93,20 +94,19 @@ const ProjectType = ({ params, ...props }) => {
}
]
},
columns: [],
"columns": [],
"orders": {
"ascending": true,
"columns": [
'name'
'id'
]
},
"paging": {
"length": 0,
"start": -1
"length": -1,
"start": 0
},
'joins': []
}
if (role_name !== "Super Admin") {
payload.columns.push(
{ "name": "company_id", "logic_operator": "=", "value": company_id, "operator": "AND" },
@ -122,6 +122,7 @@ const ProjectType = ({ params, ...props }) => {
{ name: "company_name", logic_operator: "~*", value: search, table_name: "m_company" }
)
}
const listDivions = await axios
.post(DIVISI_SEARCH, payload, HEADER)
.then(res => res)
@ -139,7 +140,7 @@ const ProjectType = ({ params, ...props }) => {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
}
}
const getDataProjectType = async () => {
const getDataDivisi = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = currentPage * rowsPerPage - rowsPerPage;
@ -156,11 +157,11 @@ const ProjectType = ({ params, ...props }) => {
}
]
},
columns: [],
"columns": [],
"orders": {
"ascending": true,
"columns": [
'name'
'id'
]
},
"paging": {
@ -169,7 +170,6 @@ const ProjectType = ({ params, ...props }) => {
},
'joins': []
}
if (role_name !== "Super Admin") {
payload.columns.push(
{ "name": "company_id", "logic_operator": "=", "value": company_id, "operator": "AND" },
@ -185,6 +185,7 @@ const ProjectType = ({ params, ...props }) => {
{ name: "company_name", logic_operator: "~*", value: search, table_name: "m_company" }
)
}
const result = await axios
.post(DIVISI_SEARCH, payload, HEADER)
.then(res => res)
@ -194,8 +195,10 @@ const ProjectType = ({ params, ...props }) => {
let dataRes = result.data.data || [];
setDatatable(dataRes);
setTotalPage(result.data.totalRecord);
setLoading(false)
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
setLoading(false)
}
}
const handleExportExcel = async () => {
@ -315,7 +318,7 @@ const ProjectType = ({ params, ...props }) => {
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProjectType()
getDataDivisi()
NotificationManager.success(`Data berhasil ditambahkan`, 'Success!!');
} else {
NotificationManager.error(`Data gagal ditambahkan`, 'Failed!!');
@ -329,7 +332,7 @@ const ProjectType = ({ params, ...props }) => {
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProjectType();
getDataDivisi();
NotificationManager.success(`Data berhasil diubah`, 'Success!!');
} else {
NotificationManager.error(`Data gagal diubah`, `Failed!!`);
@ -347,7 +350,7 @@ const ProjectType = ({ params, ...props }) => {
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProjectType()
getDataDivisi()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data berhasil dihapus!`, 'Success!!');
@ -381,6 +384,95 @@ const ProjectType = ({ params, ...props }) => {
}
}
const handleAddChild = (data) => {
setDataEdit(data)
handleOpenDialog('addChild');
}
const renderTable = useMemo(() => {
const columns = [
{
title: 'Action',
dataIndex: '',
key: 'id',
className: "nowrap",
render: (text, record) =>
<>
<Tooltip title="Hapus">
<i id="TooltipDelete" className="fa fa-trash" style={{ color: 'red', marginRight: 10, cursor: "pointer" }} onClick={() => handleDelete(text.id)}></i>
</Tooltip>
<Tooltip title="Add">
<i id="TooltipEdit" className="cil-level-down fa-sm" style={{ color: 'blue', marginRight: 10, cursor: "pointer" }} onClick={() => handleAddChild(text)}></i>
</Tooltip>
<Tooltip title="Edit">
<i id="TooltipEdit" className="fa fa-edit" style={{ color: 'green', cursor: "pointer" }} onClick={() => handleEdit(text)}></i>
</Tooltip>
</>
,
},
...(role_name === 'Super Admin' ? [
{
title: t('company'),
dataIndex: "join_first_company_name",
key: "join_first_company_name",
render: (text, record) => (
<span>{record.join_first_company_name}</span>
)
}] : []),
{ title: 'Nama', dataIndex: 'name', key: 'name' },
{ title: 'Nama', dataIndex: 'name', key: 'name' },
{ title: 'Deskripsi', dataIndex: 'description', key: 'description' },
{
title: 'Color',
dataIndex: 'color',
key: 'color',
render: (text) => {
if (text != null) {
return (
<Tooltip title={text}>
<span className="fa fa-square" style={{ color: text }}></span>
</Tooltip>
);
} else {
return (
<small style={{ color: "grey", fontStyle: "italic" }}>No color set</small>
);
}
}
}
];
return (
<Spin tip="Loading..." spinning={loading}>
<Table
size="small"
columns={columns}
expandable={{
expandIcon: ({ expanded, onExpand, record }) =>
record.children && record.children.length > 0 ?
expanded ? (
<Tooltip title="Add">
<i id="TooltipEdit" className="fa fa-chevron-down fa-sm" style={{ color: 'grey', marginRight: 10, cursor: "pointer" }} onClick={e => onExpand(record, e)}></i>
</Tooltip>
) : (
<i id="TooltipEdit" className="fa fa-chevron-right fa-sm" style={{ color: 'grey', marginRight: 10, cursor: "pointer" }} onClick={e => onExpand(record, e)}></i>
)
: (
<i id="TooltipEdit" className="fa fa-chevron-right fa-sm" style={{ color: 'white', marginRight: 10, cursor: "pointer" }} onClick={e => onExpand(record, e)}></i>
)
}}
dataSource={dataTable}
pagination={false}
>
</Table>
</Spin>
)
}, [dataTable, loading])
return (
<div>
<NotificationContainer />
@ -428,51 +520,17 @@ const ProjectType = ({ params, ...props }) => {
</Row>
</CardHeader>
<CardBody>
<Table responsive striped hover>
<thead>
<tr>
<th>Aksi</th>
{column.map((i, index) => {
return (
<th key={index} scope="row">{i.name}</th>
)
})}
</tr>
</thead>
<tbody>
{dataNotAvailable()}
{dataTable.map((n, index) => {
return (
<tr key={n.id}>
<td className='nowrap'>
<Tooltip title={t('delete')}>
<i id="TooltipDelete" className="fa fa-trash" style={{ color: 'red', marginRight: 10, cursor: "pointer" }} onClick={() => handleDelete(n.id)}></i>
</Tooltip>
<Tooltip title={t('edit')}>
<i id="TooltipEdit" className="fa fa-edit" style={{ color: 'green', cursor: "pointer" }} onClick={() => handleEdit(n)}></i>
</Tooltip>
</td>
{role_name === 'Super Admin' &&
(
<td>{n.join_first_company_name}</td>
)
}
<td>{n.name}</td>
<td>{n.description ?? '-'}</td>
{n.color != null ? (
<td>
<Tooltip title={n.color}>
<span className="fa fa-square" style={{ color: n.color }}></span>
</Tooltip>
</td>
) : (
<td><small style={{ color: "grey", fontStyle: "italic" }}>No color set</small></td>
)}
</tr>
)
})}
</tbody>
</Table>
{renderTable}
<Pagination
style={{ marginTop: "25px" }}
showSizeChanger
onShowSizeChange={onShowSizeChange}
onChange={onPagination}
current={currentPage}
pageSize={rowsPerPage}
total={totalPage}
pageSizeOptions={["10", "15", "20", "25", "30", "35", "40"]}
/>
</CardBody>
</Card>
</div>

130
src/views/SimproV2/Kanban/Column.js

@ -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;

72
src/views/SimproV2/Kanban/DialogCard.js

@ -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;

347
src/views/SimproV2/Kanban/DialogFormActivity.js

@ -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;

176
src/views/SimproV2/Kanban/DialogFormBoard.js

@ -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;

69
src/views/SimproV2/Kanban/DialogFormChild.js

@ -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;

438
src/views/SimproV2/Kanban/DialogFormReport.js

@ -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;

136
src/views/SimproV2/Kanban/Kanban.css

@ -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;
}

206
src/views/SimproV2/Kanban/Task.js

@ -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;

912
src/views/SimproV2/Kanban/index.js

@ -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;

6
src/views/SimproV2/Profile/index.js

@ -8,7 +8,7 @@ import { Pagination, Tooltip } from 'antd';
import { USER_EDIT, SATUAN_ADD, SATUAN_EDIT, SATUAN_DELETE, SATUAN_SEARCH } from '../../../const/ApiConst';
import profile from '../../../assets/img/profile.png'
import DialogForm from './DialogForm'
import { ROLE_SEARCH, BASE_OSPRO } from '../../../const/ApiConst'
import { ROLE_SEARCH, USER_GET_ID } from '../../../const/ApiConst'
@ -120,9 +120,7 @@ const Profile = ({ params }) => {
const getDataProfileUser = async () => {
const id = localStorage.getItem("user_id")
const url = `${BASE_OSPRO}/api/human-resource/edit/${id}`
const url = USER_GET_ID(id);
const result = await axios
.get(url, config)
.then((res) => res)

4
src/views/SimproV2/ResourceWorker/DialogForm.js

@ -135,6 +135,7 @@ const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdi
username,
password,
email,
company_id: parseInt(company_id)
}
closeDialog('edit', data);
@ -215,8 +216,7 @@ const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdi
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('nik')} <span style={{ color: "red" }}>*</span></Label>
{/* <Input type="text" value={ktpNumber} onChange={(e) => setKtpNumber(e.target.value.replace(/[^0-9]/g, ''))} placeholder={`Input NIK (KTP)...`} maxLength="16" /> */}
<Input type="text" value={ktpNumber} onChange={(e) => setKtpNumber(e.target.value.replace(/[^0-9]/g, ''))} placeholder={t('inputNik')} maxLength="16" />
<Input type="text" value={ktpNumber} onChange={(e) => setKtpNumber(e.target.value)} placeholder={'KTP/ID Card'} maxLength="16" />
</FormGroup>
</Col>
<Col md={6}>

278
src/views/SimproV2/Satuan/DialogForm.js

@ -1,139 +1,139 @@
import React, { useEffect, useState } from 'react'
import {
Modal, ModalHeader, ModalBody, ModalFooter,
Button, Form, FormGroup, Label, Input, Col, Row
} from 'reactstrap';
import { Select } from 'antd';
import 'antd/dist/antd.css';
import { useTranslation } from 'react-i18next';
const { Option } = Select;
const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit, company_id, listCompany, role_name }) => {
const [id, setId] = useState(0)
const [name, setName] = useState('')
const [description, setDescription] = useState('')
const [selectedCompany, setSelectedCompany] = useState(null)
const { t } = useTranslation()
useEffect(() => {
if (typeDialog === "Edit") {
setId(dataEdit.id)
setDescription(dataEdit.description)
setName(dataEdit.name)
setSelectedCompany(dataEdit.company_id);
} else {
setId(0)
}
}, [dataEdit, openDialog])
const handleSave = () => {
let data = '';
if (typeDialog === "Save") {
if (role_name === 'Super Admin') {
company_id = selectedCompany
}
data = {
name: name,
description: description,
company_id: company_id
}
closeDialog('save', data);
} else {
if (role_name === 'Super Admin') {
company_id = selectedCompany
}
data = {
id,
name: name,
description: description,
company_id: company_id
}
closeDialog('edit', data);
}
setId(0)
setDescription('')
setSelectedCompany(null)
}
const handleCancel = () => {
closeDialog('cancel', 'none')
setId(0)
setDescription('')
setSelectedCompany(null)
}
const onChangeCompany = (val) => {
setSelectedCompany(val);
};
const renderForm = () => {
return (
<Form>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('name')}</Label>
<Input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder={t('inputName')} />
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">Description</Label>
<Input row="4" type="textarea" value={description} onChange={(e) => setDescription(e.target.value)} placeholder={t('inputDescription')} />
</FormGroup>
</Col>
</Row>
{role_name === 'Super Admin' &&
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">
{t('company')}<span style={{ color: "red" }}>*</span>
</Label>
<Select
showSearch
filterOption={(inputValue, option) =>
option.children.toLowerCase().includes(inputValue.toLowerCase())
}
value={selectedCompany}
defaultValue={selectedCompany}
onChange={onChangeCompany}
style={{ width: "100%" }}
>
{listCompany.map((res) => (
<Option key={res.id} value={res.id}>
{res.company_name}
</Option>
))}
</Select>
</FormGroup>
</Col>
</Row>
}
</Form>
)
}
return (
<>
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog == "Save" ? `Add` : "Edit"} {'uom'}</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>{t('cancel')}</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogForm;
import React, { useEffect, useState } from 'react'
import {
Modal, ModalHeader, ModalBody, ModalFooter,
Button, Form, FormGroup, Label, Input, Col, Row
} from 'reactstrap';
import { Select } from 'antd';
import 'antd/dist/antd.css';
import { useTranslation } from 'react-i18next';
const { Option } = Select;
const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit, company_id, listCompany, role_name }) => {
const [id, setId] = useState(0)
const [name, setName] = useState('')
const [description, setDescription] = useState('')
const [selectedCompany, setSelectedCompany] = useState(null)
const { t } = useTranslation()
useEffect(() => {
if (typeDialog === "Edit") {
setId(dataEdit.id)
setDescription(dataEdit.description)
setName(dataEdit.name)
setSelectedCompany(dataEdit.company_id);
} else {
setId(0)
}
}, [dataEdit, openDialog])
const handleSave = () => {
let data = '';
if (typeDialog === "Save") {
if (role_name === 'Super Admin') {
company_id = parseInt(selectedCompany)
}
data = {
name: name,
description: description,
company_id: parseInt(company_id)
}
closeDialog('save', data);
} else {
if (role_name === 'Super Admin') {
company_id = parseInt(selectedCompany)
}
data = {
id,
name: name,
description: description,
company_id: parseInt(company_id)
}
closeDialog('edit', data);
}
setId(0)
setDescription('')
setSelectedCompany(null)
}
const handleCancel = () => {
closeDialog('cancel', 'none')
setId(0)
setDescription('')
setSelectedCompany(null)
}
const onChangeCompany = (val) => {
setSelectedCompany(val);
};
const renderForm = () => {
return (
<Form>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('name')}</Label>
<Input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder={t('inputName')} />
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">Description</Label>
<Input row="4" type="textarea" value={description} onChange={(e) => setDescription(e.target.value)} placeholder={t('inputDescription')} />
</FormGroup>
</Col>
</Row>
{role_name === 'Super Admin' &&
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">
{t('company')}<span style={{ color: "red" }}>*</span>
</Label>
<Select
showSearch
filterOption={(inputValue, option) =>
option.children.toLowerCase().includes(inputValue.toLowerCase())
}
value={selectedCompany}
defaultValue={selectedCompany}
onChange={onChangeCompany}
style={{ width: "100%" }}
>
{listCompany.map((res) => (
<Option key={res.id} value={res.id}>
{res.company_name}
</Option>
))}
</Select>
</FormGroup>
</Col>
</Row>
}
</Form>
)
}
return (
<>
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog == "Save" ? `Add` : "Edit"} {'uom'}</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>{t('cancel')}</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogForm;

2
src/views/SimproV2/Satuan/index.js

@ -116,7 +116,7 @@ const Satuan = ({ params, ...props }) => {
if (role_name !== "Super Admin") {
payload.columns.push(
{ "name": "company_id", "logic_operator": "=", "value": company_id, "operator": "AND" },
{ "name": "company_id", "logic_operator": "=", "value": parseInt(company_id), "operator": "AND" },
)
} else {
payload.columns.push(

148
src/views/SimproV2/Settings/DialogForm.js

@ -26,6 +26,8 @@ const DialogForm = ({
addressProp,
emailProp,
userNameProp,
refferalCode,
userProfile
}) => {
const token = window.localStorage.getItem('token');
const [typeDialog, setTypeDialog] = useState(typeDialogProp)
@ -38,15 +40,15 @@ const DialogForm = ({
const [birthdayDate, setBirthdaydate] = useState(birthdayDateProp)
const [idNumber, setIdnumber] = useState(idNumberProp)
const [email, setEmail] = useState(emailProp)
const [password, setPassword] = useState('')
const [refferal, setRefferalCode] = useState('')
const [oldPassword, setOldPassword] = useState('')
const [newPassword, setNewPassword] = useState('')
const [newPasswordConfirm, setNewPasswordConfirm] = useState('')
const [activeTab, setActiveTab] = useState('tab1')
console.log('typeDialogProp',typeDialogProp)
const handleSave = () => {
let data = '';
if (typeDialog === "Personal") {
if (typeDialog === "Personal" && typeDialogProp !== "Refferal") {
data = {
name: name,
phone_number: noHp,
@ -59,14 +61,22 @@ const DialogForm = ({
data.birth_date = birthdayDate;
}
closeDialog('profile', data)
} else if (typeDialog === "Account") {
} else if (typeDialog === "Account" && typeDialogProp !== "Refferal") {
data = {
username: userName,
email: email,
password: newPassword,
}
closeDialog('profile', data)
}
} else {
data = {
code: refferal,
user_id: userProfile.id,
username: userProfile.username,
ktp_number: userProfile.ktp_number
}
closeDialog('refferal_code', data)
}
}
const handleCancel = () => {
@ -85,6 +95,19 @@ const DialogForm = ({
)
}
function generateRandomString(length) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
function generateReferralCode() {
const newReferralCode = generateRandomString(6);
setRefferalCode(newReferralCode);
}
const renderForm = () => {
return (
@ -197,45 +220,46 @@ const DialogForm = ({
}
return (
<>
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>
Update {typeDialog == "Personal" ? `Personal` : "Account"} Data
</ModalHeader>
<ModalBody>
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>
Update {typeDialog == "Personal" ? `Personal` : "Account"} Data
</ModalHeader>
<ModalBody>
{typeDialogProp !== 'Refferal' ? (
<>
<Nav tabs>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab1");
setTypeDialog("Personal");
}}
active={activeTab === "tab1"}
>
Personal
</NavLink>
</NavItem>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab2");
setTypeDialog("Account");
}}
active={activeTab === "tab2"}
>
Account
</NavLink>
</NavItem>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab3");
setTypeDialog("Setting");
}}
active={activeTab === "tab3"}
>
Setting
</NavLink>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab1");
setTypeDialog("Personal");
}}
active={activeTab === "tab1"}
>
Personal
</NavLink>
</NavItem>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab2");
setTypeDialog("Account");
}}
active={activeTab === "tab2"}
>
Account
</NavLink>
</NavItem>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab3");
setTypeDialog("Setting");
}}
active={activeTab === "tab3"}
>
Setting
</NavLink>
</NavItem>
</Nav>
<TabContent activeTab={activeTab}>
@ -249,13 +273,37 @@ const DialogForm = ({
{renderFormSetting()}
</TabPane>
</TabContent>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>{typeDialog == "Profile" ? `Profile` : "Save"}</Button> {' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button>
</ModalFooter>
</Modal>
</>
</>
):(
<Form>
<Row>
<Col md={12}>
<span style={{ color: "red" }}>*</span> Wajib diisi.
</Col>
</Row>
<Row>
<Col md={12}>
<FormGroup>
<Label className="capitalize">Refferal Code</Label>
<Row>
<Col md={8}>
<Input maxLength={16} type="text" value={refferal || refferalCode} onChange={(e) => setRefferalCode(e.target.value)} placeholder={'Input refferal code'} />
</Col>
<Col md={4}>
<Button color="primary" onClick={generateReferralCode}>Generate</Button>
</Col>
</Row>
</FormGroup>
</Col>
</Row>
</Form >
)}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>{typeDialogProp !== 'Refferal' ? typeDialog == "Profile" ? `Profile` : "Save" : "Generate Code"}</Button> {' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button>
</ModalFooter>
</Modal>
)

86
src/views/SimproV2/Settings/index.js

@ -5,14 +5,11 @@ import axios from "../../../const/interceptorApi"
import { Card, CardBody, CardHeader, Col, Row, Input, Table, Button } from 'reactstrap';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Tooltip } from 'antd';
import { USER_EDIT, SATUAN_ADD, SATUAN_EDIT, SATUAN_DELETE, SATUAN_SEARCH } from '../../../const/ApiConst';
import { USER_EDIT, USER_GET_ID, REFFERAL_GET_ID, REFFERAL_ADD, REFFERAL_EDIT } from '../../../const/ApiConst';
import profile from '../../../assets/img/profile.png'
import DialogForm from './DialogForm'
import { ROLE_SEARCH, BASE_OSPRO } from '../../../const/ApiConst'
const Setting = ({ params }) => {
const token = localStorage.getItem("token")
const config = {
@ -21,17 +18,13 @@ const Setting = ({ params }) => {
"Authorization": `Bearer ${token}`
}
}
const pageName = params.name;
const [openDialog, setOpenDialog] = useState(false)
const [typeDialog, setTypeDialog] = useState('Personal')
const [id, setId] = useState(0)
const [roleList, setRoleList] = useState([])
const [userProfile, setUserprofile] = useState(null)
const [refferal, setReferralCode] = useState(null)
const [userName, setUserName] = useState("")
const [name, setName] = useState('')
const [noHp, setNohp] = useState("")
@ -44,7 +37,7 @@ const Setting = ({ params }) => {
const [role, setRole] = useState("")
const [email, setEmail] = useState("")
const [employeeType, setEmployeeType] = useState("")
const [isCopied, setIsCopied] = useState(false);
useEffect(() => {
getDataProfileUser();
@ -68,7 +61,7 @@ const Setting = ({ params }) => {
setEmployeeType(userProfile?.employee_type);
}
}, [userProfile])
}, [userProfile, typeDialog])
const handleOpenDialog = (type) => {
setOpenDialog(true)
@ -78,12 +71,13 @@ const Setting = ({ params }) => {
const handleCloseDialog = (type, data) => {
if (type === "profile") {
saveProfile(data);
} else if(type === "refferal_code") {
updateRefferal(data);
}
setOpenDialog(false)
}
const saveProfile = async (data) => {
let urlEdit = USER_EDIT(id)
const formData = data
@ -99,6 +93,20 @@ const Setting = ({ params }) => {
}
}
const updateRefferal = async (data) => {
let urlEdit = REFFERAL_EDIT(id)
const formData = data
const result = await axios.put(urlEdit, formData, config)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataRefferal(data.user_id, data.username, data.ktp_number);
NotificationManager.success(`Code refferal berhasil diedit`, 'Success!!');
} else {
NotificationManager.error(`Code refferal gagal di edit`, `Failed!!`);
}
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
@ -121,10 +129,7 @@ const Setting = ({ params }) => {
const getDataProfileUser = async () => {
const id = localStorage.getItem("user_id")
const url = `${BASE_OSPRO}/api/human-resource/edit/${id}`
const url = USER_GET_ID(id);
const result = await axios
.get(url, config)
.then((res) => res)
@ -132,11 +137,49 @@ const Setting = ({ params }) => {
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data;
setUserprofile(dataRes);
await getDataRefferal(id, dataRes.username, dataRes.ktp_number);
} else {
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
};
const getDataRefferal = async (user_id, username, ktp_number) => {
const url = REFFERAL_GET_ID(user_id);
const result = await axios
.get(url, config)
.then((res) => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data;
setReferralCode(dataRes);
} else {
saveRefferalCode(user_id, username, ktp_number);
};
}
const saveRefferalCode = async (user_id, username, ktp_number) => {
const formData = {
'id': parseInt(user_id),
'code': username + ktp_number.substring(0, 4),
'amount': 0
}
const result = await axios
.post(REFFERAL_ADD, formData, config)
.then((res) => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
await getDataRefferal(user_id, username, ktp_number);
}
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
}, (err) => {
console.error('Gagal menyalin teks ke clipboard: ', err);
});
}
return (
@ -158,6 +201,8 @@ const Setting = ({ params }) => {
addressProp={address}
emailProp={email}
userNameProp={userName}
refferalCode={refferal?.code}
userProfile={userProfile}
/>
<Card>
@ -233,6 +278,15 @@ const Setting = ({ params }) => {
<td><b>Tanggal Lahir &nbsp; </b></td>
<td>: &nbsp; {birthdayDate}</td>
</tr>
<tr>
<td><b>Referral Code &nbsp; </b></td>
<td>: &nbsp; {refferal?.code} <small style={{ color:'blue', cursor: 'pointer' }} onClick={() => copyToClipboard(refferal?.code)}>{isCopied ? 'Copied' : 'Copy'}</small></td>
<td>
<Tooltip title='Custom Refferal Code'>
<Button color="success" onClick={() => handleOpenDialog('Refferal')}>Custom Refferal Code</Button>
</Tooltip>
</td>
</tr>
</tbody>
<br />
</Col>

46
src/views/Users/User.js

@ -1,46 +0,0 @@
import React, { Component } from 'react';
import { Card, CardBody, CardHeader, Col, Row, Table } from 'reactstrap';
import usersData from './UsersData'
class User extends Component {
render() {
const user = usersData.find(user => user.id.toString() === this.props.match.params.id)
const userDetails = user ? Object.entries(user) : [['id', (<span><i className="text-muted icon-ban"></i> Not found</span>)]]
return (
<div className="animated fadeIn">
<Row>
<Col lg={6}>
<Card>
<CardHeader>
<strong><i className="icon-info pr-1"></i>User id: {this.props.match.params.id}</strong>
</CardHeader>
<CardBody>
<Table responsive striped hover>
<tbody>
{
userDetails.map(([key, value]) => {
return (
<tr key={key}>
<td>{`${key}:`}</td>
<td><strong>{value}</strong></td>
</tr>
)
})
}
</tbody>
</Table>
</CardBody>
</Card>
</Col>
</Row>
</div>
)
}
}
export default User;

15
src/views/Users/User.test.js

@ -1,15 +0,0 @@
import React from 'react';
import {MemoryRouter} from 'react-router-dom';
import { mount } from 'enzyme'
import User from './User';
it('renders without crashing', () => {
const wrapper = mount(
<MemoryRouter>
<User match={{params: {id: "1"}, isExact: true, path: "/users/:id", name: "User details"}}/>
</MemoryRouter>
);
expect(wrapper.containsMatchingElement(<strong>Samppa Nori</strong>)).toEqual(true)
wrapper.unmount()
});

78
src/views/Users/Users.js

@ -1,78 +0,0 @@
import React, { Component } from 'react'
import DataTable from '../../components/DataTableEditDialog'
import { API_LIST_DATA_USERS, API_INSERT_DATA_USERS, API_UPDATE_DATA_USERS, API_DELETE_DATA_USERS } from '../../const/ApiConst'
const columns = [{
dataField: 'id',
alias: "Id",
showInput: false,
type: "number",
state: 0
}, {
dataField: 'fullname',
alias: "Fullname",
showInput: true,
type: "text",
state: ""
}, {
dataField: 'username',
alias: "Username",
showInput: true,
type: "text",
state: ""
}, {
dataField: 'password',
alias: "Password",
showInput: true,
type: "password",
state: ""
}, {
dataField: 'created_time',
alias: "Created Time",
showInput: false,
type: "text",
state: ""
}, {
dataField: 'modified_time',
alias: "Modified Time",
showInput: false,
type: "text",
state: ""
}, {
dataField: 'created_by',
alias: "Created By",
showInput: false,
type: "text",
state: "admin"
}];
class Users extends Component {
constructor(props) {
super(props)
this.state = {
columns: null,
dataTable: []
}
}
componentDidMount() {
}
render() {
let dataTable = this.state.dataTable
return (
<div>
<DataTable
title="User"
columns={columns}
urlParamGet={API_LIST_DATA_USERS}
urlParamInsert={API_INSERT_DATA_USERS}
urlParamUpdate={API_UPDATE_DATA_USERS}
urlParamDelete={API_DELETE_DATA_USERS}
/>
</div>
)
}
}
export default Users;

10
src/views/Users/Users.test.js

@ -1,10 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { MemoryRouter } from 'react-router-dom';
import Users from './Users';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<MemoryRouter><Users /></MemoryRouter>, div);
ReactDOM.unmountComponentAtNode(div);
});

31
src/views/Users/UsersData.js

@ -1,31 +0,0 @@
const usersData = [
{id: 0, name: 'John Doe', registered: '2018/01/01', role: 'Guest', status: 'Pending'},
{id: 1, name: 'Samppa Nori', registered: '2018/01/01', role: 'Member', status: 'Active'},
{id: 2, name: 'Estavan Lykos', registered: '2018/02/01', role: 'Staff', status: 'Banned'},
{id: 3, name: 'Chetan Mohamed', registered: '2018/02/01', role: 'Admin', status: 'Inactive'},
{id: 4, name: 'Derick Maximinus', registered: '2018/03/01', role: 'Member', status: 'Pending'},
{id: 5, name: 'Friderik Dávid', registered: '2018/01/21', role: 'Staff', status: 'Active'},
{id: 6, name: 'Yiorgos Avraamu', registered: '2018/01/01', role: 'Member', status: 'Active'},
{id: 7, name: 'Avram Tarasios', registered: '2018/02/01', role: 'Staff', status: 'Banned'},
{id: 8, name: 'Quintin Ed', registered: '2018/02/01', role: 'Admin', status: 'Inactive'},
{id: 9, name: 'Enéas Kwadwo', registered: '2018/03/01', role: 'Member', status: 'Pending'},
{id: 10, name: 'Agapetus Tadeáš', registered: '2018/01/21', role: 'Staff', status: 'Active'},
{id: 11, name: 'Carwyn Fachtna', registered: '2018/01/01', role: 'Member', status: 'Active'},
{id: 12, name: 'Nehemiah Tatius', registered: '2018/02/01', role: 'Staff', status: 'Banned'},
{id: 13, name: 'Ebbe Gemariah', registered: '2018/02/01', role: 'Admin', status: 'Inactive'},
{id: 14, name: 'Eustorgios Amulius', registered: '2018/03/01', role: 'Member', status: 'Pending'},
{id: 15, name: 'Leopold Gáspár', registered: '2018/01/21', role: 'Staff', status: 'Active'},
{id: 16, name: 'Pompeius René', registered: '2018/01/01', role: 'Member', status: 'Active'},
{id: 17, name: 'Paĉjo Jadon', registered: '2018/02/01', role: 'Staff', status: 'Banned'},
{id: 18, name: 'Micheal Mercurius', registered: '2018/02/01', role: 'Admin', status: 'Inactive'},
{id: 19, name: 'Ganesha Dubhghall', registered: '2018/03/01', role: 'Member', status: 'Pending'},
{id: 20, name: 'Hiroto Šimun', registered: '2018/01/21', role: 'Staff', status: 'Active'},
{id: 21, name: 'Vishnu Serghei', registered: '2018/01/01', role: 'Member', status: 'Active'},
{id: 22, name: 'Zbyněk Phoibos', registered: '2018/02/01', role: 'Staff', status: 'Banned'},
{id: 23, name: 'Einar Randall', registered: '2018/02/01', role: 'Admin', status: 'Inactive'},
{id: 24, name: 'Félix Troels', registered: '2018/03/21', role: 'Staff', status: 'Active'},
{id: 25, name: 'Aulus Agmundr', registered: '2018/01/01', role: 'Member', status: 'Pending'},
{id: 42, name: 'Ford Prefex', registered: '2001/05/21', role: 'Alien', status: 'Don\'t panic!'}
]
export default usersData

6
src/views/Users/package.json

@ -1,6 +0,0 @@
{
"name": "Users",
"version": "0.0.0",
"private": true,
"main": "./Users.js"
}
Loading…
Cancel
Save