Browse Source

update endpoint

pull/2/head
wahyuun 1 year ago
parent
commit
2bf31bf161
  1. 9
      cypress.config.js
  2. 57
      cypress/e2e/addProject.cy.js
  3. 5
      cypress/fixtures/example.json
  4. 33
      cypress/support/commands.js
  5. 20
      cypress/support/e2e.js
  6. 1
      package.json
  7. 6
      src/appredux/modules/map/actions.js
  8. 2
      src/components/RoutingBarV2/index.js
  9. 17
      src/containers/DefaultLayout/DefaultLayout.js
  10. 1
      src/routes.js
  11. 51
      src/views/Dashboard/DashboardCustomer.js
  12. 19
      src/views/Dashboard/DashboardProject.js
  13. 4
      src/views/Master/MasterBroadcast/index.js
  14. 3
      src/views/Report/k3/index.js
  15. 6
      src/views/SimproV2/CreatedProyek/AsignHrProject.js
  16. 2
      src/views/SimproV2/CreatedProyek/DialogFormProyek.js
  17. 16
      src/views/SimproV2/CreatedProyek/DialogGantt.js
  18. 1
      src/views/SimproV2/CreatedProyek/DialogHierarchy.js
  19. 32
      src/views/SimproV2/CreatedProyek/FormAsignHr.js
  20. 49
      src/views/SimproV2/CreatedProyek/ImportActivity/index.js
  21. 145
      src/views/SimproV2/CreatedProyek/index.js
  22. 49
      src/views/SimproV2/Gantt/GanttFrame.js
  23. 25
      src/views/SimproV2/Gantt/index.js
  24. 2
      src/views/SimproV2/PanicButton/index.js
  25. 2
      src/views/SimproV2/Presence/index.js
  26. 2
      src/views/SimproV2/ResourceWorker/DialogForm.js

9
cypress.config.js

@ -0,0 +1,9 @@
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});

57
cypress/e2e/addProject.cy.js

@ -0,0 +1,57 @@
describe("Test a page", () => {
beforeEach(() => {
cy.login("admin", "1nt3gr4s14");
cy.url({ timeout: 20000 }).should("include", "/dashboard");
cy.visit("http://localhost:3000/#/projects");
});
it("Add project normal case", () => {
cy.intercept('GET', 'http://localhost/adw-backend/api/currency/list').as('getCurrency');
cy.intercept('GET', 'http://localhost/adw-backend/api/project-type/list').as('getType');
cy.intercept('GET', 'http://localhost/adw-backend/api/divisi/list').as('getDivisi');
cy.intercept('GET', 'http://localhost/adw-backend/api/project-phase/list').as('getPhase');
cy.intercept('GET', 'http://localhost/adw-backend/api/human-resource/list').as('getHr');
cy.get('[style="background: rgb(76, 175, 80); color: rgb(255, 255, 255);"]').click();
cy.get(':nth-child(2) > :nth-child(1) > .form-group > .form-control').type('Automated Test');
cy.get(':nth-child(2) > :nth-child(2) > .form-group > .form-control').type('AT');
cy.wait("@getType").then((xhr) => {
cy.get('#rc_select_1').type('template detail{enter}');
});
cy.wait("@getHr").then((xhr) => {
cy.get('#rc_select_2').type('admin adw{enter}');
});
cy.get(':nth-child(2) > .form-group > .ant-picker > .ant-picker-input > input').click();
cy.contains('td[title="2023-08-04"].ant-picker-cell', '4').click();
cy.get(':nth-child(5) > :nth-child(1) > .form-group > .form-control').type('Indramayu');
cy.get(':nth-child(5) > :nth-child(2) > .form-group > .form-control').type('Integrasia Utama');
cy.wait("@getCurrency").then((xhr) => {
cy.get('.col-md-4 > .ant-select > .ant-select-selector').click();
cy.get('[title="USD"] > .ant-select-item-option-content').click();
cy.get('.col-md-8 > .form-control').type(20000);
});
cy.get(':nth-child(6) > :nth-child(2) > .form-group > .form-control').type('Implement Automated Testing For Development');
cy.wait("@getDivisi").then((xhr) => {
cy.get('#rc_select_4').click();
cy.get('[title=" Construction"] > .ant-select-item-option-content').click();
});
cy.wait("@getPhase").then((xhr) => {
cy.get('#rc_select_5').click();
cy.get('.ant-select-item-option-content').contains('Inisiasi').click();
});
cy.get('#rc_select_6').click();
cy.get('.ant-select-item-option-content').contains('On budget').click();
cy.get('.btn-primary').click();
});
});

5
cypress/fixtures/example.json

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

33
cypress/support/commands.js

@ -0,0 +1,33 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
Cypress.Commands.add("login", (username, password) => {
// Implement your login logic here
// For example:
cy.visit("http://localhost:3000/#/login"); // Assuming your login page is at "/login"
cy.get("#exampleName").type(username);
cy.get("#examplePassword").type(password);
cy.get(".px-4").click();
});

20
cypress/support/e2e.js

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

1
package.json

@ -101,6 +101,7 @@
"@babel/core": "^7.14.5",
"babel-plugin-module-resolver": "^4.1.0",
"clean-webpack-plugin": "^3.0.0",
"cypress": "^12.17.2",
"react-scripts": "^3.0.1",
"webpack-sources": "1.0.1"
},

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

@ -122,9 +122,9 @@ export const getUserPoints = async () => {
feature.properties = {
"user_id": n.user_id,
"Name": n.name ? n.name : '-',
"Clock in time": n.clock_in ? moment(n.clock_in).format('YYYY-MM-DD HH:mm:ss') : '-',
"Clock in time": n.clock_in ? moment(n.clock_in).format('DD-MM-YYYY HH:mm:ss') : '-',
"Clock in location": n.clock_in_loc ? n.clock_in_loc : '-',
"Clock out time": n.clock_out ? moment(n.clock_out).format('YYYY-MM-DD HH:mm:ss') : '-',
"Clock out time": n.clock_out ? moment(n.clock_out).format('DD-MM-YYYY HH:mm:ss') : '-',
"Clock out location": n.clock_out_loc ? n.clock_out_loc : '-',
"image": n.image_selfie ? n.image_selfie : '',
"Projects": n.projects ? n.projects : null,
@ -133,7 +133,7 @@ export const getUserPoints = async () => {
feature.geometry = {
"type": "Point",
"coordinates": [n.clock_in_lng, n.clock_in_lat]
"coordinates": [n.wp_lon, n.wp_lat]
}
featureCollection.features.push(feature);

2
src/components/RoutingBarV2/index.js

@ -57,7 +57,7 @@ const RoutingBar = () => {
<div className="routingbar-range-picker">
<RangePicker
showTime={{ format: 'HH:mm' }}
format="YYYY-MM-DD HH:mm"
format="DD-MM-YYYY HH:mm"
placeholder={['Start Time', 'End Time']}
onChange={onChange}
onOk={onOk}

17
src/containers/DefaultLayout/DefaultLayout.js

@ -17,6 +17,7 @@ import {
AppBreadcrumb2 as AppBreadcrumb,
AppSidebarNav2 as AppSidebarNav,
} from '@coreui/react';
import LayoutHelper from '../../../node_modules/@coreui/react/lib/Shared/layout/layout';
import navigation from '../../_nav';
import routes from '../../routes';
import { emptyConstants } from '../../const/MapConst.js';
@ -44,6 +45,7 @@ class DefaultLayout extends Component {
routes2: routes,
finalRoutes: [],
breadrCrumbReady: false,
minimized: true
}
}
@ -70,7 +72,10 @@ class DefaultLayout extends Component {
}
}
toggleMinimized = () => {
this.setState((prevState) => ({ minimized: !prevState.minimized }));
LayoutHelper.sidebarToggle(!this.state.minimized);
};
setFinalRoutes = () => {
const { routes2 } = this.state;
@ -248,7 +253,7 @@ class DefaultLayout extends Component {
<div className="app">
<div className="app-body">
{!window.location.href.includes("dashboard-project") || renderSidebar ? (
<AppSidebar minimized={true} fixed display="lg">
<AppSidebar minimized={this.state.minimized} fixed display="lg">
{/* <div class="sidebar-header">
<Suspense fallback={this.loading()}>
<DefaultHeader history={this.props.history} onLogout={e => this.signOut(e)} />
@ -261,6 +266,7 @@ class DefaultLayout extends Component {
{this.getMenu()}
</Suspense>
<AppSidebarFooter />
{this.state.minimized ? null :
<UncontrolledDropdown direction="down">
<DropdownToggle nav>
<i className="nav-icon fa fa-user-circle"></i> {localStorage.getItem('user_name')}
@ -271,10 +277,11 @@ class DefaultLayout extends Component {
<DropdownItem href="#/settings"><i className="fa fa-user"></i>Profile</DropdownItem>
<DropdownItem onClick={e => this.signOut(e)}><i className="fa fa-sign-out"></i> Logout</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
<AppSidebarMinimizer />
</UncontrolledDropdown>}
<button className='sidebar-minimizer mt-auto' type='button' onClick={this.toggleMinimized}>
</button>
</AppSidebar>
) : null }
) : null}
<main className="main">
{this.state.breadrCrumbReady ? this.getAppBreadcrumb() : null}
<Container fluid>

1
src/routes.js

@ -54,6 +54,7 @@ const routes = [
// { path: '/dashboard', name: 'Dashboard', component: Dashboard},
{ path: '/dashboard', name: 'DashboardBOD', component: DashboardBOD },
{ path: '/dashboard-customer/:PROJECT_ID/:GANTT_ID', name: 'DashboardCustomer', component: DashboardCustomer },
{ 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/:SCURVE', exact: true, name: 'Dashboard Project', component: DashboardProject },
{ path: '/projects', exact: true, name: 'Projects', component: CreatedProyek },

51
src/views/Dashboard/DashboardCustomer.js

@ -33,7 +33,7 @@ const DashboardCustomer = () => {
Authorization: `Bearer ${token}`
}
}
const { PROJECT_ID, GANTT_ID } = useParams();
const { PROJECT_ID, GANTT_ID, SCURVE } = useParams();
const URL_GANTT = `https://adw-gantt.ospro.id/view-mode/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`;
const mapRef = useRef()
const [projectName, setProjectName] = useState("");
@ -61,6 +61,7 @@ const DashboardCustomer = () => {
const [healthBySchedule, setHealthBySchedule] = useState('-');
const [healthByBudget, setHealthByBudget] = useState('-');
const [reportDistribution, setReportDistribution] = useState([]);
const [calculationStatus, setCalculationStatus] = useState(false);
useEffect(() => {
getProjectDetail();
@ -79,6 +80,25 @@ const DashboardCustomer = () => {
}
}, [activeTabIdx]);
useEffect(() => {
// Add event listener for receiving messages from the iframe
window.addEventListener('message', handleIframeMessage);
// Clean up the event listener on component unmount
return () => {
window.removeEventListener('message', handleIframeMessage);
};
}, []);
const handleIframeMessage = (event) => {
if (event.data && event.data.action === 'getUrl') {
const childUrl = window.location.href;
// Send the URL back to the iframe
event.source.postMessage({ action: 'sendUrl', url: childUrl }, event.origin);
}
};
const getProjectDetail = async () => {
setIsReadyProjectDetail(false);
const URL = `${BASE_OSPRO}/api/project/detail/${PROJECT_ID}`;
@ -106,12 +126,13 @@ const DashboardCustomer = () => {
setActualStart(result.data.data.header?.start_date ? result.data.data.header.start_date : null)
setEstimatedFinish(result.data.data.header?.end_date ? result.data.data.header.end_date : null)
setIsReadyProjectDetail(true);
setCalculationStatus(result.data.data.calculation_status ? result.data.data.calculation_status : false)
}
}
const getSCurve = async () => {
setIsReadySCurve(false);
const URL = `${BASE_OSPRO}/api/project/get-s-curve`;
URL = `${BASE_OSPRO}/api/project/calculate-s-curve`;
const payload = {
"project_id": PROJECT_ID.toString(),
"period": "week",
@ -139,6 +160,20 @@ const DashboardCustomer = () => {
let planningProgress = result.data.data[0].data?.percentagePlan[result.data.data[0].data?.percentagePlan.length-1];
setPlanningProgress(planningProgress);
}
let now = new Date().toISOString().slice(0, 10);
let dates = result.data.data[0].data?.date;
let n = dates.findIndex(element => new Date(now) < new Date(element[0]));
if (n < 0) {
n = dates.length - 1;
}
if (result.data.data.length > 0 && result.data.data[0].data?.percentagePlan && result.data.data[0].data?.percentagePlan.length > 0) {
if(SCURVE && SCURVE == "1"){
planningProgress = result.data.data[0].data?.percentagePlan[result.data.data[0].data?.percentagePlan.length - 1];
} else {
planningProgress = result.data.data[0].data?.percentagePlan[n];
}
setPlanningProgress(planningProgress);
}
if (result.data.data.length > 0 && result.data.data[0].data?.percentageReal && result.data.data[0].data?.percentageReal.length > 0) {
let actualProgress = result.data.data[0].data?.percentageReal[result.data.data[0].data?.percentageReal.length-1];
setActualProgress(actualProgress);
@ -396,7 +431,13 @@ const DashboardCustomer = () => {
<div style={{ display: 'flex', flexDirection: 'row', marginBottom: 10 }}>
<div style={{ flex: 20, display: 'flex', flexDirection: 'column' }}>
<div style={{fontSize: 16, fontWeight: 'bold', marginBottom: 10}}>Project</div>
<div style={{fontSize: 14}}>{isReadyProjectDetail ? projectName : <SingleTextLoader />}</div>
<div style={{fontSize: 14}}>{isReadyProjectDetail
? projectName
? calculationStatus
? projectName + " - S-Curve Ready"
: projectName + " - S-Curve Loading"
: null
: <SingleTextLoader />}</div>
</div>
<div>
<i className="fa fa-check-square" style={{fontSize: 28}}></i>
@ -492,13 +533,13 @@ const DashboardCustomer = () => {
<div style={{backgroundColor: '#222222', padding: 10, marginBottom: 5}}>
<div style={{color: '#FFFFFF', textAlign: 'center', marginBottom: 10, fontWeight: 'bold'}}>Progress</div>
{isReadySCurve ?
<ProgressPlanningBar progress={planningProgress} />
<ProgressPlanningBar progress={planningProgress > 100 ? 100 : planningProgress} />
:
<SingleTextLoader width={"100%"} height={30} />
}
<div style={{marginTop: 10, marginBottom: 10}}></div>
{isReadySCurve ?
<ProgressActualBar progress={actualProgress} />
<ProgressActualBar progress={planningProgress > 100 ? parseFloat(actualProgress / planningProgress * 100).toFixed(2) : actualProgress} />
:
<SingleTextLoader width={"100%"} height={30} />
}

19
src/views/Dashboard/DashboardProject.js

@ -73,7 +73,7 @@ const DashboardProject = () => {
},
};
const { PROJECT_ID, GANTT_ID, SCURVE } = useParams();
const URL_GANTT = `http://localhost:8444/adw-gantt/view-mode/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`;
const URL_GANTT = `https://adw-gantt.ospro.id/view-mode/index.html?base_url=${BASE_OSPRO}/api&gantt_id=${GANTT_ID}&proyek_id=${PROJECT_ID}&token=${token}&ro=1`;
const mapRef = useRef();
const [projectName, setProjectName] = useState("");
const [projectManagerName, setProjectManagerName] = useState("");
@ -125,6 +125,7 @@ const DashboardProject = () => {
const [dataGanttParents, setDataGanttParents] = useState({});
const [isReadyGanttParents, setIsReadyGanttParents] = useState(false);
const [calculationStatus, setCalculationStatus] = useState(false);
const [isHierarchy, setIsHierarchy] = useState(false);
let history = useHistory();
useEffect(() => {
@ -185,6 +186,9 @@ const DashboardProject = () => {
try {
const response = await axios.get(url, HEADER);
setDataGantt(response);
if (response.data.data.hierarchy_ftth_id) {
setIsHierarchy(true);
}
setIsReadyGantt(true);
} catch (error) {
console.error("Failed to get gantt data:", error);
@ -331,7 +335,7 @@ const DashboardProject = () => {
const getSCurve = async () => {
setIsReadySCurve(false);
let URL = `${BASE_OSPRO}/api/project/get-s-curve`;
if (SCURVE && SCURVE == "1") {
if (SCURVE && SCURVE == "1" && isHierarchy) {
URL = `${BASE_OSPRO}/api/project/calculate-s-curve`;
}
@ -373,9 +377,7 @@ const DashboardProject = () => {
setActualToDate(
result.data.data[0].data.budget_control.acwp?.toString()
);
setBcwp(
result.data.data[0].data.budget_control.current_budget?.toString()
);
setBcwp(result.data.data[0].data.budget_control.bcwp?.toString());
// setRemToComplete(result.data.data[0].data.budget_control.rem_to_complete?.toString())
setAddCostToComplete(
result.data.data[0].data.budget_control.add_cost_to_complete?.toString()
@ -389,8 +391,9 @@ const DashboardProject = () => {
}
let now = new Date().toISOString().slice(0, 10);
let dates = result.data.data[0].data?.date;
let n =
dates.findIndex((element) => new Date(now) < new Date(element[0])) - 1;
let n = dates.findIndex(
(element) => new Date(now) < new Date(element[0])
);
if (n < 0) {
n = dates.length - 1;
}
@ -438,6 +441,8 @@ const DashboardProject = () => {
const URL = `${BASE_OSPRO}/api/project/get-overdue-activities`;
const payload = {
id: PROJECT_ID.toString(),
gantt: GANTT_ID.toString(),
scurve: SCURVE ? SCURVE.toString() : null,
till_date: moment(new Date()).format("YYYY-MM-DD"),
};
const result = await axios

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

@ -444,7 +444,7 @@ class index extends Component {
<td>{n.message_notif !== "" ? n.message_notif : "-"}</td>
<td>{n.description !== "" ? n.description : "-"}</td>
<td>{n.status_send !== "" ? n.status_send : "-"}</td>
<td>{n.created_date !== "" ? moment.utc(n.created_date).format("YYYY-MM-DD HH:mm:ss") : "-"}</td>
<td>{n.created_date !== "" ? moment.utc(n.created_date).format("DD-MM-YYYY HH:mm:ss") : "-"}</td>
</tr>
)
}) : <tr>
@ -569,7 +569,7 @@ class index extends Component {
</Input>
</div>
<div style={{}}>
<RangePicker size="default" allowClear={false} value={[this.state.startDate, this.state.endDate]} onChange={this.handleDatePicker} />{' '}
<RangePicker format={"DD-MM-YYYY"} size="default" allowClear={false} value={[this.state.startDate, this.state.endDate]} onChange={this.handleDatePicker} />{' '}
<Button color="primary" onClick={() => this.getDataPanicButton()}>{this.props.t('search')}</Button>
</div>
</div>

3
src/views/Report/k3/index.js

@ -103,6 +103,7 @@ class index extends Component {
getAllProyek = async () => {
const payload = {
"select": ["id", "nama"],
"paging": { "start": 0, "length": -1 },
"columns": [
{ "name": "nama", "logic_operator": "ilike", "value": "", "operator": "AND" }
@ -572,7 +573,7 @@ class index extends Component {
</Input>
</div>
<div style={{ width: "50%", marginTop: "3px" }}>
<RangePicker size="default" allowClear={false} value={[this.state.startDate, this.state.endDate]} onChange={this.handleDatePicker} />{' '}
<RangePicker format={"DD-MM-YYYY"} size="default" allowClear={false} value={[this.state.startDate, this.state.endDate]} onChange={this.handleDatePicker} />{' '}
<Button color="primary" onClick={() => this.getDataLaporanK3()}>{this.props.t('search')}</Button>
</div>
</div>

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

@ -34,9 +34,11 @@ const AssignHrProject = ({ openDialog, closeDialog, toggleDialog, idTask, toolsR
}, [openDialog]);
useEffect(() => {
getDataUser();
if (openDialog) {
getDataProjectRole();
}, [])
getDataUser();
}
}, [dataUserToProject])
const getDataAssignHr = async () => {
const payload = {

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

@ -511,6 +511,7 @@ const DialogFormProyek = ({
Start Date<span style={{ color: "red" }}>*</span>
</Label>
<DatePicker
format={"DD-MM-YYYY"}
style={{ width: "100%" }}
value={startDate}
onChange={handleDatePickerStart}
@ -530,6 +531,7 @@ const DialogFormProyek = ({
.format("YYYY-MM-DD");
return current && currentDate < customDate;
}}
format={"DD-MM-YYYY"}
style={{ width: "100%" }}
value={endDate}
onChange={handleDatePickerEnd}

16
src/views/SimproV2/CreatedProyek/DialogGantt.js

@ -13,7 +13,7 @@ import DialogUserGantt from './DialogUserGantt';
import { Link } from 'react-router-dom';
const DialogGantt = ({ openDialog, closeDialog, toggleDialog, idTask, proyekName, hierarchyId, hierarchyName }) => {
const DialogGantt = ({ openDialog, closeDialog, toggleDialog, idTask, proyekName, hierarchyId, hierarchyName, openDialogHierarchy }) => {
const token = localStorage.getItem("token")
const HEADER = {
headers: {
@ -31,21 +31,13 @@ const DialogGantt = ({ openDialog, closeDialog, toggleDialog, idTask, proyekName
const [humanResource, setHumanResource] = useState([])
useEffect(() => {
if (idTask > 0) {
if (openDialog && hierarchyId > 0 || idTask > 0 && !openDialogHierarchy) {
getdataGantt();
}
if (hierarchyId > 0) {
getdataGantt();
}
}, [hierarchyId, idTask, openDialog])
useEffect(() => {
if (!openDialog) {
setDataGantt([]);
} else {
}
}, [openDialog])
}, [hierarchyId, idTask, openDialog])
const getDataHumanResource = async () => {
const result = await axios
@ -77,12 +69,14 @@ const DialogGantt = ({ openDialog, closeDialog, toggleDialog, idTask, proyekName
let payload;
if (hierarchyId) {
payload = {
"select": ["id", "name_version", "calculation_type", "description", "created_at", "progress"],
"columns": [
{ "name": "hierarchy_ftth_id", "logic_operator": "=", "value": hierarchyId, "operator": "AND" }
]
}
} else {
payload = {
"select": ["id", "name_version", "calculation_type", "description", "created_at", "progress"],
"columns": [
{ "name": "proyek_id", "logic_operator": "=", "value": idTask, "operator": "AND" }
]

1
src/views/SimproV2/CreatedProyek/DialogHierarchy.js

@ -311,6 +311,7 @@ const DialogHierarchy = ({ openDialog, closeDialog, toggleDialog, idTask, proyek
hierarchyId={parentId}
hierarchyName={parentName}
idTask={idTask}
openDialogHierarchy={openDialog}
/>
<DialogFormGantt
idTask={idTask}

32
src/views/SimproV2/CreatedProyek/FormAsignHr.js

@ -22,6 +22,7 @@ const FormAsignHr = ({ openDialog, closeDialog, toggleDialog, idTask, dataEdit,
const [accrue, setAccrue] = useState("")
const [baseCalender, setBaseCalender] = useState("")
const [listHr, setListHr] = useState([])
const [isCustomer, setIsCustomer] = useState(false)
const handleClearData = () => {
setUser(null)
@ -29,6 +30,7 @@ const FormAsignHr = ({ openDialog, closeDialog, toggleDialog, idTask, dataEdit,
setProjectRole(null)
setGroupR("")
setMaxUsed("")
setIsCustomer(false)
setStandartRate("")
setUomStandartRate(null)
setOverTimeRate("")
@ -67,6 +69,7 @@ const FormAsignHr = ({ openDialog, closeDialog, toggleDialog, idTask, dataEdit,
setProjectRole(dataEdit.project_role)
setGroupR(dataEdit.group_r)
setMaxUsed(dataEdit.max_used ? formatNumber(dataEdit.max_used.toString()) : '')
setIsCustomer(dataEdit.is_customer)
setStandartRate(dataEdit.standart_rate ? formatNumber(dataEdit.standart_rate.toString()) : '')
setUomStandartRate(dataEdit.uom_standart_rate)
setOverTimeRate(dataEdit.overtime_rate ? formatNumber(dataEdit.overtime_rate.toString()) : '')
@ -91,6 +94,7 @@ const FormAsignHr = ({ openDialog, closeDialog, toggleDialog, idTask, dataEdit,
proyek_id: idTask,
user_id:user,
project_role:projectRole,
is_customer: isCustomer,
max_used:maxUsed.replaceAll(".", ""),
standart_rate:standartRate.replaceAll(".", ""),
uom_standart_rate:uomStandartRate,
@ -104,6 +108,7 @@ const FormAsignHr = ({ openDialog, closeDialog, toggleDialog, idTask, dataEdit,
proyek_id: idTask,
user_id:user,
project_role:projectRole,
is_customer: isCustomer,
max_used:maxUsed.replaceAll(".", ""),
standart_rate:standartRate.replaceAll(".", ""),
uom_standart_rate:uomStandartRate,
@ -157,6 +162,33 @@ const FormAsignHr = ({ openDialog, closeDialog, toggleDialog, idTask, dataEdit,
</FormGroup>
</Col>
</Row>
<Row>
<Col>
<FormGroup>
<Label>Customer</Label>
<div>
<Select
value={isCustomer}
defaultValue={false}
style={{
width: 235,
}}
onChange={(val) => setIsCustomer(val)}
options={[
{
value: true,
label: 'Yes',
},
{
value: false,
label: 'No',
}
]}
/>
</div>
</FormGroup>
</Col>
</Row>
<div style={{widht:"100%",display:"flex",flexDirection:"row",justifyContent:"space-between",alignItems:"center"}}>
<FormGroup style={{flexBasis:"49%"}}>
<Label>Standart Rate</Label>

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

@ -4,7 +4,7 @@ import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Button, Table, Form, Upload, Tooltip, Alert, Spin } from 'antd';
import { InboxOutlined, UploadOutlined } from '@ant-design/icons';
import {OutTable, ExcelRenderer} from 'react-excel-renderer';
import { OutTable, ExcelRenderer } from 'react-excel-renderer';
import './table.css';
import { BASE_OSPRO, ASSIGN_HR_PROJECT_SEARCH } from '../../../../const/ApiConst';
import { Prompt } from 'react-router-dom';
@ -137,7 +137,7 @@ const ImportActivity = ({ params }) => {
const fileHandler = (file) => {
setIsMovePage(true);
if(file.name.slice(file.name.lastIndexOf('.')+1) === "xlsx"){
if (file.name.slice(file.name.lastIndexOf('.') + 1) === "xlsx") {
// NotificationManager.info('Loading...',' ');
setTimeout(() => {
previewHandler(file);
@ -156,7 +156,7 @@ const ImportActivity = ({ params }) => {
let dataMapped = []
ExcelRenderer(fileObj, (err, resp) => {
if(err){
if (err) {
console.log(err)
errorHandler()
} else {
@ -167,7 +167,7 @@ const ImportActivity = ({ params }) => {
return el.length > 0;
});
for(let i = 5; i < rows.length; i++){
for (let i = 5; i < rows.length; i++) {
let extractedRow = {}
for (var prop in columnToIndexs) {
@ -175,14 +175,14 @@ const ImportActivity = ({ params }) => {
let columnData = rows[i][columnToIndexs[prop]]
// remove leading whitespace
if(typeof(columnData) == 'string') {
if (typeof (columnData) == 'string') {
columnData = columnData.trim().replace(/&nbsp;/g, '').replace(/<[^\/>][^>]*><\/[^>]+>/g, "")
}
if(["nik"].includes(prop)){
if(columnData){
if (["nik"].includes(prop)) {
if (columnData) {
let index = dataUserToProject.findIndex((x) => columnData == x.join_first_ktp_number);
if(index >= 0) {
if (index >= 0) {
columnData = dataUserToProject[index].join_first_ktp_number;
} else {
columnData = '';
@ -190,13 +190,30 @@ const ImportActivity = ({ params }) => {
}
}
if(prop == 'weight'){
if (prop == 'weight') {
if (columnData == null) {
columnData = 0;
}
columnData = columnData * 100
}
if (prop == 'duration') {
if (columnData == null) {
columnData = 0;
}
}
if (prop == 'level') {
if (columnData == null) {
columnData = 1;
}
}
if (prop == 'name') {
if (columnData == null) {
columnData = "New Activity";
}
}
extractedRow[prop] = columnData
}
@ -268,7 +285,7 @@ const ImportActivity = ({ params }) => {
key: 'name',
render: (text, record) => {
let prepend = ""
for(let i = 1; i < record.level; i++) {
for (let i = 1; i < record.level; i++) {
prepend = prepend + "--"
}
@ -329,7 +346,7 @@ const ImportActivity = ({ params }) => {
listType="text"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
maxCount={1}
beforeUpload={(file)=> fileHandler(file)}
beforeUpload={(file) => fileHandler(file)}
showUploadList={false}
>
<Button icon={<UploadOutlined />}>Import Excel</Button>
@ -338,11 +355,11 @@ const ImportActivity = ({ params }) => {
</Form.Item>
</Form>
</Col>
<Col span={2} style={{display: 'flex', justifyContent: 'flex-end'}}>
<Col span={2} style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button
style={{ marginLeft: "5px", marginRight: "10px" }}
disabled={dataTable.length > 0 ? false : true}
onClick={(e)=> saveHandler(e)}
onClick={(e) => saveHandler(e)}
>
<i className="fa fa-save" style={{ marginRight: "5px" }}></i> Save
</Button>
@ -397,7 +414,7 @@ const ImportActivity = ({ params }) => {
listType="text"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
maxCount={1}
beforeUpload={(file)=> fileHandler(file)}
beforeUpload={(file) => fileHandler(file)}
showUploadList={false}
>
<Button icon={<UploadOutlined />}>Import Excel</Button>
@ -406,11 +423,11 @@ const ImportActivity = ({ params }) => {
</Form.Item>
</Form>
</Col>
<Col span={2} style={{display: 'flex', justifyContent: 'flex-end'}}>
<Col span={2} style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button
style={{ marginLeft: "5px", marginRight: "10px" }}
disabled={dataTable.length > 0 ? false : true}
onClick={(e)=> saveHandler(e)}
onClick={(e) => saveHandler(e)}
>
<i className="fa fa-save" style={{ marginRight: "5px" }}></i> Save
</Button>

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

@ -19,7 +19,7 @@ import {
Tooltip,
Popover,
Skeleton,
Divider,
Spin,
} from "antd";
import {
PROJECT_APPROVAL_ADD,
@ -136,6 +136,7 @@ const CreatedProyek = ({ params, ...props }) => {
const [dataVersionGantt, setDataVersionGantt] = useState([]);
const [dataHierarchy, setDataHierarchy] = useState([]);
const [dataDetail, setDataDetail] = useState(null);
const [loading, setLoading] = useState(true);
const pageName = params.name;
@ -167,7 +168,7 @@ const CreatedProyek = ({ params, ...props }) => {
}, [openDialogProyek]);
useEffect(() => {
getDataProyek();
role_id !== "44" ? getDataProyek() : getDataProyekByCustomer();
}, [search, rowsPerPage, currentPage]);
useEffect(() => {
@ -230,6 +231,30 @@ const CreatedProyek = ({ params, ...props }) => {
}
};
const handleDashboard = async (text) => {
const URL = `${BASE_OSPRO}/api/project/detail/${text.id}`;
const result = await axios
.get(URL, HEADER)
.then((res) => res)
.catch((err) => err.response);
if (!result) {
NotificationManager.error(`Could not connect to internet.`, "Failed");
return;
}
if (result.status !== 200) {
NotificationManager.error(
`Get project detail failed, ${result.data.message}`,
"Failed"
);
return;
} else if (result.status == 200 && result.data.data) {
history.push(
`dashboard-customer/${text.id}/${result.data.gantt.last_gantt_id}/1`
);
}
};
const getDataProyek = async () => {
let start = 0;
@ -246,6 +271,80 @@ const CreatedProyek = ({ params, ...props }) => {
operator: "AND",
},
],
select: [
"id",
"nama",
"rencana_biaya",
"type_proyek_id",
"currency_symbol",
"mulai_proyek",
"akhir_proyek",
],
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"],
},
// { "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: false },
paging: { start: start, length: rowsPerPage },
};
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 dataRes = result.data.data || [];
setDatatable(dataRes);
setTotalPage(result.data.totalRecord);
setLoading(false);
} else {
setLoading(false);
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
};
const getDataProyekByCustomer = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = currentPage * rowsPerPage - rowsPerPage;
}
const payload = {
columns: [
{
name: "nama",
logic_operator: "ilike",
value: search,
operator: "AND",
},
],
select: [
"id",
"nama",
"rencana_biaya",
"type_proyek_id",
"currency_symbol",
"mulai_proyek",
"akhir_proyek",
],
joins: [
{
name: "m_users",
@ -257,11 +356,10 @@ const CreatedProyek = ({ params, ...props }) => {
column_join: "proyek_id",
column_results: ["type_proyek_id"],
},
// { "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"] }
],
user_id: { user_id: user_id },
orders: { columns: ["id"], ascending: false },
paging: { start: start, length: rowsPerPage },
user_id: { user_id: user_id }
};
if (parseInt(role_id) !== 1) {
@ -277,12 +375,12 @@ const CreatedProyek = ({ params, ...props }) => {
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data || [];
// const filteredData = dataRes.filter(
// (item) => item.join_first_role_id === parseInt(role_id)
// );
setDatatable(dataRes);
setTotalPage(result.data.totalRecord);
setLoading(false);
} else {
setLoading(false);
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
};
@ -304,6 +402,7 @@ const CreatedProyek = ({ params, ...props }) => {
const getdataGantt = async (idTask) => {
setLoadVersionGantt(true);
const payload = {
select: ["id", "name_version"],
columns: [
{
name: "proyek_id",
@ -591,7 +690,8 @@ const CreatedProyek = ({ params, ...props }) => {
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProyek();
role_id !== "44" ? getDataProyek() : getDataProyekByCustomer();
setIdDelete(0);
setAlertDelete(false);
NotificationManager.success(`Data proyek berhasil dihapus`, "Success!!");
@ -637,7 +737,7 @@ const CreatedProyek = ({ params, ...props }) => {
NotificationManager.success(`${result.data.message}`, "Success!!");
}
getDataProyek();
role_id !== "44" ? getDataProyek() : getDataProyekByCustomer();
} else {
NotificationManager.error(`${result.data.message}`, "Failed!!");
}
@ -718,7 +818,7 @@ const CreatedProyek = ({ params, ...props }) => {
const resultMilestone = await editMilestone(data.id, milestones);
const resultApproval = await editApproval(data.id, approval);
if (result && result.status === 200) {
getDataProyek();
role_id !== "44" ? getDataProyek() : getDataProyekByCustomer();
NotificationManager.success(`Data proyek berhasil Ubah`, "Success!!");
} else {
NotificationManager.error(`${result.data.message}`, "Failed!!");
@ -898,7 +998,7 @@ const CreatedProyek = ({ params, ...props }) => {
const data = resData.map((elt) => [
elt.nama,
`Rp. ${formatThousand(elt.rencana_biaya)}`,
elt.nama_type_proyek,
elt.join_second_name,
elt.join_first_name,
`${moment(elt.mulai_proyek).format(format)} - ${moment(
elt.akhir_proyek
@ -1112,7 +1212,21 @@ const CreatedProyek = ({ params, ...props }) => {
title: "Action",
dataIndex: "",
key: "x",
render: (text, record) => (
render: (text, record) =>
role_id == "44" ? (
<>
<Tooltip title="Dashboard Project">
<Button
size="small"
onClick={() => handleDashboard(text)}
type="link"
style={{ color: "green" }}
>
<i className="fa fa-line-chart"></i>
</Button>
</Tooltip>
</>
) : (
<>
<Popover
placement="rightTop"
@ -1165,7 +1279,7 @@ const CreatedProyek = ({ params, ...props }) => {
dataIndex: "color_progress",
key: "color_progress",
render: (text, record) => (
<>{record.nama_type_proyek ? record.nama_type_proyek : "-"}</>
<>{record.join_second_name ? record.join_second_name : "-"}</>
),
},
{
@ -1436,6 +1550,7 @@ const CreatedProyek = ({ params, ...props }) => {
/>
</Col>
<Col>
{role_id == "44" ? null : ( // role kustomer
<Tooltip title="Add Project">
<Button
style={{ background: "#4caf50", color: "#fff" }}
@ -1444,6 +1559,7 @@ const CreatedProyek = ({ params, ...props }) => {
<i className="fa fa-plus"></i>
</Button>
</Tooltip>
)}
<Tooltip title="Export Excel">
<Popover
// content={<a onClick={hide}>Close</a>}
@ -1486,7 +1602,10 @@ const CreatedProyek = ({ params, ...props }) => {
</Row>
</CardHeader>
<CardBody>
<Spin tip="Loading..." spinning={loading}>
{RenderTable}
</Spin>
<Pagination
style={{ marginTop: "25px" }}
showSizeChanger

49
src/views/SimproV2/Gantt/GanttFrame.js

@ -0,0 +1,49 @@
import React, { useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { BASE_SIMPRO_LUMEN } from '../../../const/ApiConst';
const GanttFrame = React.memo((props) => {
const history = useHistory();
const { versionGanttId, idProject, token, ro, timestamp } = props;
const iframeSrc = `https://adw-gantt.ospro.id/edit-mode/index.html?base_url=${BASE_SIMPRO_LUMEN}&gantt_id=${versionGanttId}&proyek_id=${idProject}&token=${token}&ro=${ro}&timestamp=${timestamp}`;
const [batchEntityData, setBatchEntityData] = useState(null);
useEffect(() => {
const handleMessage = (event) => {
if (event.data && event.data.batchEntity) {
setBatchEntityData(event.data.batchEntity);
}
};
window.addEventListener('message', handleMessage);
}, []);
useEffect(()=>{
const handleNavigation = (event) => {
if (batchEntityData && batchEntityData !== '') {
const message = 'You have unsaved changes. Are you sure you want to leave this page?';
return message;
}
};
history.block(handleNavigation);
}, [batchEntityData])
return (
<iframe
id="frame-gantt"
src={iframeSrc}
style={{
width: '100%',
height: '95vh',
}}
scrolling="no"
frameBorder="0"
allow="fullscreen"
></iframe>
);
});
export default GanttFrame;

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

@ -10,7 +10,7 @@ import axios from "../../../const/interceptorApi";
import { Fab, Action } from "react-tiny-fab";
import "react-tiny-fab/dist/styles.css";
import { useHistory } from "react-router-dom";
import GanttFrame from "./GanttFrame";
const token = localStorage.getItem("token");
const userId = parseInt(localStorage.getItem("user_id"));
const HEADER = {
@ -93,24 +93,19 @@ const Gantt = (props) => {
}
roCount = roCount + 1;
};
const RenderGantt = () => (
<iframe
id="frame-gantt"
src={`http://localhost:8444/adw-gantt/edit-mode/index.html?base_url=${BASE_SIMPRO_LUMEN}&gantt_id=${versionGanttId}&proyek_id=${idProject}&token=${token}&ro=${ro}&timestamp=${timestamp}`}
style={{
width: "100%",
height: "95vh",
}}
scrolling="no"
frameBorder="0"
allow="fullscreen"
></iframe>
);
return (
<>
<div style={{ margin: "-15px", marginBottom: "-30px" }}>
{ready && <RenderGantt />}
{ready && (
<GanttFrame
versionGanttId={versionGanttId}
idProject={idProject}
token={token}
ro={ro}
timestamp={timestamp}
/>
)}
</div>
</>
);

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

@ -364,7 +364,7 @@ class index extends Component {
</Input>
</div>
<div style={{ width: "50%" }}>
<RangePicker size="default" allowClear={false} value={[this.state.startDate, this.state.endDate]} onChange={this.handleDatePicker} />{' '}
<RangePicker format={"DD-MM-YYYY"} size="default" allowClear={false} value={[this.state.startDate, this.state.endDate]} onChange={this.handleDatePicker} />{' '}
<Button color="primary" onClick={() => this.getDataPanicButton()}>{this.props.t('search')}</Button>
</div>
</div>

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

@ -316,7 +316,7 @@ const Index = ({ params }) => {
</Input>
</div>
<div style={{ width: "50%", marginTop: "3px" }}>
<RangePicker size="default" allowClear={false} value={[startDate, endDate]} onChange={handleDatePicker} />{' '}
<RangePicker format="DD-MM-YYYY" size="default" allowClear={false} value={[startDate, endDate]} onChange={handleDatePicker} />{' '}
<Button color="primary" onClick={() => getDataPresence()}>{t('search')}</Button>
</div>
</div>

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

@ -270,7 +270,7 @@ const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdi
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('birthDate')}</Label>
<DatePicker style={{ width: "100%" }} value={birthDate} placeholder={t('inputBrithDate')} onChange={(date, dateString) => setBirthDate(date)} />
<DatePicker format={"DD-MM-YYYY"} style={{ width: "100%" }} value={birthDate} placeholder={t('inputBrithDate')} onChange={(date, dateString) => setBirthDate(date)} />
</FormGroup>
</Col>
</Row>

Loading…
Cancel
Save