From d8ad27944e681e70065026b7f53030caa2eb9acb Mon Sep 17 00:00:00 2001 From: wahyu Date: Mon, 26 Feb 2024 16:40:47 +0700 Subject: [PATCH 01/14] menu state update --- .../Master/MasterRoles/DialogMenuRoles.js | 106 +++++++++++++++--- 1 file changed, 92 insertions(+), 14 deletions(-) diff --git a/src/views/Master/MasterRoles/DialogMenuRoles.js b/src/views/Master/MasterRoles/DialogMenuRoles.js index b066bc4..348f614 100644 --- a/src/views/Master/MasterRoles/DialogMenuRoles.js +++ b/src/views/Master/MasterRoles/DialogMenuRoles.js @@ -337,31 +337,104 @@ export default class DialogMenuRoles extends Component { this.setState({ stateMenu: copyStateMenu }) } - handleChangeCheckboxRead = (checked, index) => { + handleChangeCheckboxRead = (checked, index, menuItem = null, menuIdxList = []) => { let copyStateRead = [...this.state.stateRead]; copyStateRead[index] = checked; + let menu = this.state.menu; + let checkMenuParent = menu.map((state, index) => { + if (state.parent_id === menuItem.id) { + return state.id + } else { + return null + } + }).filter(index => index !== null); + let stateReadIdx = []; + menuIdxList.forEach((menu, index) => { + checkMenuParent.forEach((check, idx) => { + if (check === menu) { + stateReadIdx.push(index); + } + }); + }); + stateReadIdx.map((stateRead) => { + copyStateRead[stateRead] = checked + }) this.setState({ stateRead: copyStateRead }) } - handleChangeCheckboxCreate = (checked, index) => { + handleChangeCheckboxCreate = (checked, index, menuItem = null, menuIdxList = []) => { let copyStateCreate = [...this.state.stateCreate]; copyStateCreate[index] = checked; - + let menu = this.state.menu; + let checkMenuParent = menu.map((state, index) => { + if (state.parent_id === menuItem.id) { + return state.id + } else { + return null + } + }).filter(index => index !== null); + let stateCreateIdx = []; + menuIdxList.forEach((menu, index) => { + checkMenuParent.forEach((check, idx) => { + if (check === menu) { + stateCreateIdx.push(index); + } + }); + }); + stateCreateIdx.map((stateCreate) => { + copyStateCreate[stateCreate] = checked + }) this.setState({ stateCreate: copyStateCreate }) } - handleChangeCheckboxEdit = (checked, index) => { + handleChangeCheckboxEdit = (checked, index, menuItem = null, menuIdxList = []) => { let copyStateEdit = [...this.state.stateUpdate]; copyStateEdit[index] = checked; - + let menu = this.state.menu; + let checkMenuParent = menu.map((state, index) => { + if (state.parent_id === menuItem.id) { + return state.id + } else { + return null + } + }).filter(index => index !== null); + let stateEditIdx = []; + menuIdxList.forEach((menu, index) => { + checkMenuParent.forEach((check, idx) => { + if (check === menu) { + stateEditIdx.push(index); + } + }); + }); + stateEditIdx.map((stateEdit) => { + copyStateEdit[stateEdit] = checked + }) this.setState({ stateUpdate: copyStateEdit }) } - handleChangeCheckboxDelete = (checked, index) => { + handleChangeCheckboxDelete = (checked, index, menuItem = null, menuIdxList = []) => { let copyStateDelete = [...this.state.stateDelete]; copyStateDelete[index] = checked; - + let menu = this.state.menu; + let checkMenuParent = menu.map((state, index) => { + if (state.parent_id === menuItem.id) { + return state.id + } else { + return null + } + }).filter(index => index !== null); + let stateDeleteIdx = []; + menuIdxList.forEach((menu, index) => { + checkMenuParent.forEach((check, idx) => { + if (check === menu) { + stateDeleteIdx.push(index); + } + }); + }); + stateDeleteIdx.map((stateDelete) => { + copyStateDelete[stateDelete] = checked + }) this.setState({ stateDelete: copyStateDelete }) } @@ -419,7 +492,8 @@ export default class DialogMenuRoles extends Component { renderForm = () => { const { menu, stateRead, stateCreate, stateUpdate, stateDelete } = this.state; - + let menuIdxList = [] + let menuIdx = 0 const getChildren = (parentId) => { return menu.filter(item => item.parent_id === parentId); }; @@ -429,24 +503,28 @@ export default class DialogMenuRoles extends Component { const children = getChildren(parentId); return children.map((menuItem, index) => { + const currentIndex = menuIdx; // Capture current index + menuIdxList[currentIndex] = menuItem.id; + menuIdx++ const paddingLeft = depth * 20; const fontWeight = menuItem.parent_id === null ? 'bold' : 'normal'; return ( - + {menuItem.name} - this.handleChangeCheckboxRead(e.target.checked, index)} defaultChecked={stateRead[index]} /> - this.handleChangeCheckboxCreate(e.target.checked, index)} defaultChecked={stateCreate[index]} /> - this.handleChangeCheckboxEdit(e.target.checked, index)} defaultChecked={stateUpdate[index]} /> - this.handleChangeCheckboxDelete(e.target.checked, index)} defaultChecked={stateDelete[index]} /> + this.handleChangeCheckboxRead(e.target.checked, currentIndex, menuItem, menuIdxList)} defaultChecked={stateRead[currentIndex]} /> + this.handleChangeCheckboxCreate(e.target.checked, currentIndex, menuItem, menuIdxList)} defaultChecked={stateCreate[currentIndex]} /> + this.handleChangeCheckboxEdit(e.target.checked, currentIndex, menuItem, menuIdxList)} defaultChecked={stateUpdate[currentIndex]} /> + this.handleChangeCheckboxDelete(e.target.checked, currentIndex, menuItem, menuIdxList)} defaultChecked={stateDelete[currentIndex]} /> {renderMenu(menuItem.id, depth + 1)} {/* Recursively render children */} ); }); }; - + menuIdxList = [] + menuIdx = 0 // Render top-level menu items (parents) return ( From 9b1d2964abe971036c16465749cdf3222ca71dc8 Mon Sep 17 00:00:00 2001 From: wahyu Date: Tue, 27 Feb 2024 11:09:42 +0700 Subject: [PATCH 02/14] dynamic dashboard init --- package.json | 1 + src/components/wj/App.jsx | 270 +++++++++++++ src/components/wj/components/BarChart.jsx | 11 + src/components/wj/components/Blank.jsx | 3 + src/components/wj/components/BubbleChart.jsx | 9 + src/components/wj/components/BulletGraph.jsx | 22 ++ src/components/wj/components/ColumnChart.jsx | 11 + src/components/wj/components/Grid.jsx | 12 + src/components/wj/components/LineChart.jsx | 10 + src/components/wj/components/LinearGauge.jsx | 26 ++ src/components/wj/components/RadialGauge.jsx | 12 + src/components/wj/components/Tile.jsx | 14 + src/components/wj/index.css | 394 +++++++++++++++++++ src/components/wj/index.jsx | 10 + src/components/wj/license.js | 2 + src/components/wj/utils/DragDropTouch.js | 370 +++++++++++++++++ src/routes.js | 2 + 17 files changed, 1179 insertions(+) create mode 100644 src/components/wj/App.jsx create mode 100644 src/components/wj/components/BarChart.jsx create mode 100644 src/components/wj/components/Blank.jsx create mode 100644 src/components/wj/components/BubbleChart.jsx create mode 100644 src/components/wj/components/BulletGraph.jsx create mode 100644 src/components/wj/components/ColumnChart.jsx create mode 100644 src/components/wj/components/Grid.jsx create mode 100644 src/components/wj/components/LineChart.jsx create mode 100644 src/components/wj/components/LinearGauge.jsx create mode 100644 src/components/wj/components/RadialGauge.jsx create mode 100644 src/components/wj/components/Tile.jsx create mode 100644 src/components/wj/index.css create mode 100644 src/components/wj/index.jsx create mode 100644 src/components/wj/license.js create mode 100644 src/components/wj/utils/DragDropTouch.js diff --git a/package.json b/package.json index 964c241..81dbc9c 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@dabeng/react-orgchart": "^1.0.0", "@develoka/angka-rupiah-js": "^1.0.3", "@faker-js/faker": "^7.3.0", + "@grapecity/wijmo.react.all": "5.20213", "@iconify/icons-ant-design": "^1.0.6", "@iconify/icons-fa-solid": "^1.0.6", "@iconify/icons-fe": "^1.0.3", diff --git a/src/components/wj/App.jsx b/src/components/wj/App.jsx new file mode 100644 index 0000000..09b5099 --- /dev/null +++ b/src/components/wj/App.jsx @@ -0,0 +1,270 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcCore from '@grapecity/wijmo'; +import { Grid } from './components/Grid'; +import { RadialGauge } from './components/RadialGauge'; +import { LinearGauge } from './components/LinearGauge'; +import { BarChart } from './components/BarChart'; +import { ColumnChart } from './components/ColumnChart'; +import { LineChart } from './components/LineChart'; +import { BubbleChart } from './components/BubbleChart'; +import { BulletGraph } from './components/BulletGraph'; +import { Blank } from './components/Blank'; +import { Tile } from './components/Tile'; +// Wijmo and Material Design Lite +import '@grapecity/wijmo.styles/themes/material/wijmo.theme.material.indigo-amber.css'; +// Styles +import './index.css'; + +import './license' + +export default class App extends React.Component { + constructor() { + super(...arguments); + // Color palette + this.palette = ['#8e99f3', '#ffca28', '#5c6bc0', '#bbdefb']; + // Icons assets + this.icons = { + grid: [ + , + , + ], + barChart: [ + , + , + , + , + ], + columnChart: [ + , + , + , + , + ], + bubbleChart: [ + , + , + , + ], + lineChart: [ + , + , + , + , + ], + radialGauge: [ + , + , + , + ], + linearGauge: [ + , + , + , + ], + bulletGraph: [ + , + , + , + , + , + , + , + , + , + ], + blank: [ + , + ], + }; + // Tile names and types + this.tileCatalog = [ + { name: 'Grid', tile: Grid, icon: this.icons.grid }, + { name: 'Radial Gauge', tile: RadialGauge, icon: this.icons.radialGauge }, + { name: 'Linear Gauge', tile: LinearGauge, icon: this.icons.linearGauge }, + { name: 'Bar Chart', tile: BarChart, icon: this.icons.barChart }, + { name: 'Column Chart', tile: ColumnChart, icon: this.icons.columnChart }, + { name: 'Line Chart', tile: LineChart, icon: this.icons.lineChart }, + { name: 'Bubble Chart', tile: BubbleChart, icon: this.icons.bubbleChart }, + { name: 'Bullet Graph', tile: BulletGraph, icon: this.icons.bulletGraph }, + { name: 'Blank', tile: Blank, icon: this.icons.blank }, + ]; + this.key = 0; + this.state = { + isWideMenu: false, + tileCatalog: new wjcCore.CollectionView(this.tileCatalog), + tiles: this.getTiles(), + key: this.key, + data: this.getData(), + }; + } + // tiles currently in use + getTiles() { + return [ + { name: this.tileCatalog[1].name, key: this.key += 1 }, + { name: this.tileCatalog[2].name, key: this.key += 1 }, + { name: this.tileCatalog[5].name, key: this.key += 1 }, + { name: this.tileCatalog[7].name, key: this.key += 1 }, + { name: this.tileCatalog[0].name, key: this.key += 1 }, + ]; + } + // generate some data to show in the tiles + getData() { + let data = []; + const today = new Date(); + for (let i = 0; i < 12; i++) { + const sales = 100 + Math.random() * 800 + i * 50; + const expenses = 50 + Math.random() * 300 + i * 5; + data.push({ + id: i, + date: wjcCore.DateTime.addMonths(today, 12 - i), + sales: sales, + expenses: expenses, + profit: sales - expenses, + }); + } + return data; + } + // gets a tile content by name + getTileContent(name) { + const { data, tileCatalog } = this.state; + const arr = tileCatalog.items; + for (let i = 0; i < arr.length; i++) { + if (arr[i].name == name) { + return React.createElement(arr[i].tile, { + data: new wjcCore.CollectionView(data), + palette: this.palette + }); + } + } + throw '*** tile not found: ' + name; + } + // adds a tile to the dashboard + addTile(name) { + const { tiles, key: stateKey } = this.state; + const key = stateKey + 1; + this.setState({ tiles: [{ name, key }, ...tiles], key }); + } + // removes a tile from the dashboard + removeTile(tileIndex) { + const tiles = this.state.tiles.filter((item, index) => index != tileIndex); + this.setState({ tiles: tiles }); + } + // initialize component after it has been mounted + componentDidMount() { + // enable tile drag/drop + const panel = document.querySelector('.dashboard'); + this.enableItemReorder(panel); + } + // allow users to re-order elements within a panel element + // we work with the DOM elements and update the state when done. + enableItemReorder(panel) { + let dragSource = null; + let dropTarget = null; + // add drag/drop event listeners + panel.addEventListener('dragstart', (e) => { + const target = wjcCore.closest(e.target, '.tile'); + if (target && target.parentElement == panel) { + dragSource = target; + wjcCore.addClass(dragSource, 'drag-source'); + const dt = e.dataTransfer; + dt.effectAllowed = 'move'; + dt.setData('text', dragSource.innerHTML); + } + }); + panel.addEventListener('dragover', (e) => { + if (dragSource) { + let tile = wjcCore.closest(e.target, '.tile'); + if (tile == dragSource) { + tile = null; + } + if (dragSource && tile && tile != dragSource) { + e.preventDefault(); + e.dataTransfer.dropEffect = 'move'; + } + if (dropTarget != tile) { + wjcCore.removeClass(dropTarget, 'drag-over'); + dropTarget = tile; + wjcCore.addClass(dropTarget, 'drag-over'); + } + } + }); + panel.addEventListener('drop', (e) => { + if (dragSource && dropTarget) { + // finish drag/drop + e.stopPropagation(); + e.stopImmediatePropagation(); + e.preventDefault(); + // re-order HTML elements (optional here, we're updating the state later) + const srcIndex = getIndex(dragSource); + const dstIndex = getIndex(dropTarget); + const refChild = srcIndex > dstIndex ? dropTarget : dropTarget.nextElementSibling; + dragSource.parentElement.insertBefore(dragSource, refChild); + // focus and view on the tile that was dragged + dragSource.focus(); + // update state + let tiles = this.state.tiles.slice(); + tiles.splice(srcIndex, 1); + tiles.splice(dstIndex, 0, this.state.tiles[srcIndex]); + this.setState({ tiles: tiles }); + } + }); + panel.addEventListener('dragend', () => { + wjcCore.removeClass(dragSource, 'drag-source'); + wjcCore.removeClass(dropTarget, 'drag-over'); + dragSource = dropTarget = null; + }); + function getIndex(e) { + const p = e.parentElement; + for (let i = 0; i < p.children.length; i++) { + if (p.children[i] == e) + return i; + } + return -1; + } + } + // render the dashboard + render() { + const { tiles, isWideMenu } = this.state; + // animated toggle menu + const renderMenuToggle = (
this.setState({ isWideMenu: !isWideMenu })}> + + + + + +
); + // menu items + const renderMenuItems = ( + {this.tileCatalog.map((item) => (
this.addTile(item.name)}> + + {item.icon.map((entity, key) => ({entity}))} + +
{item.name}
+
))} +
); + // displayed when the dashboard is empty + const renderBlankTile = (
+ + + +
Click on an item on the menu bar to add the new tile to the dashboard.
+
); + // list of tiles + const renderTiles = ( + {tiles.map((item, index) => ())} + ); + const renderDashboard = tiles.length ? renderTiles : renderBlankTile; + return (
+
+ {renderMenuToggle} + {renderMenuItems} +
+
+
+
{renderDashboard}
+
+
); + } +} diff --git a/src/components/wj/components/BarChart.jsx b/src/components/wj/components/BarChart.jsx new file mode 100644 index 0000000..a9dc664 --- /dev/null +++ b/src/components/wj/components/BarChart.jsx @@ -0,0 +1,11 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcChart from '@grapecity/wijmo.chart'; +import * as wjChart from '@grapecity/wijmo.react.chart'; +export const BarChart = ({ data, palette }) => ( + + + + + ); diff --git a/src/components/wj/components/Blank.jsx b/src/components/wj/components/Blank.jsx new file mode 100644 index 0000000..28f67ca --- /dev/null +++ b/src/components/wj/components/Blank.jsx @@ -0,0 +1,3 @@ +// React +import * as React from 'react'; +export const Blank = () =>
This is an empty tile.
; diff --git a/src/components/wj/components/BubbleChart.jsx b/src/components/wj/components/BubbleChart.jsx new file mode 100644 index 0000000..ad8f98d --- /dev/null +++ b/src/components/wj/components/BubbleChart.jsx @@ -0,0 +1,9 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcChart from '@grapecity/wijmo.chart'; +import * as wjChart from '@grapecity/wijmo.react.chart'; +export const BubbleChart = ({ data, palette }) => ( + + + ); diff --git a/src/components/wj/components/BulletGraph.jsx b/src/components/wj/components/BulletGraph.jsx new file mode 100644 index 0000000..ed7af7a --- /dev/null +++ b/src/components/wj/components/BulletGraph.jsx @@ -0,0 +1,22 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcCore from '@grapecity/wijmo'; +import * as wjGauge from '@grapecity/wijmo.react.gauge'; +export const BulletGraph = ({ data }) => (
+ + + {data.items.map((item, index) => ( + + + + ))} + +
{wjcCore.Globalize.format(item.date, 'MMM yyyy')} + + + + + +
+
); diff --git a/src/components/wj/components/ColumnChart.jsx b/src/components/wj/components/ColumnChart.jsx new file mode 100644 index 0000000..5d8e495 --- /dev/null +++ b/src/components/wj/components/ColumnChart.jsx @@ -0,0 +1,11 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcChart from '@grapecity/wijmo.chart'; +import * as wjChart from '@grapecity/wijmo.react.chart'; +export const ColumnChart = ({ data, palette }) => ( + + + + + ); diff --git a/src/components/wj/components/Grid.jsx b/src/components/wj/components/Grid.jsx new file mode 100644 index 0000000..1d0caef --- /dev/null +++ b/src/components/wj/components/Grid.jsx @@ -0,0 +1,12 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcGrid from '@grapecity/wijmo.grid'; +import * as wjGrid from '@grapecity/wijmo.react.grid'; +export const Grid = ({ data, palette }) => ( + + + + + + ); diff --git a/src/components/wj/components/LineChart.jsx b/src/components/wj/components/LineChart.jsx new file mode 100644 index 0000000..6f93ab2 --- /dev/null +++ b/src/components/wj/components/LineChart.jsx @@ -0,0 +1,10 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcChart from '@grapecity/wijmo.chart'; +import * as wjChart from '@grapecity/wijmo.react.chart'; +export const LineChart = ({ data, palette }) => ( + + + + ); diff --git a/src/components/wj/components/LinearGauge.jsx b/src/components/wj/components/LinearGauge.jsx new file mode 100644 index 0000000..3a14ec3 --- /dev/null +++ b/src/components/wj/components/LinearGauge.jsx @@ -0,0 +1,26 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcCore from '@grapecity/wijmo'; +import * as wjGauge from '@grapecity/wijmo.react.gauge'; +export const LinearGauge = ({ data, palette }) => { + const lastItem = data.items[data.items.length - 1]; + return (
+
+

Sales: {wjcCore.Globalize.format(lastItem.sales, 'c')}

+ +
+ +
+

Expenses: {wjcCore.Globalize.format(lastItem.expenses, 'c')}

+ +
+ +
+

Profit: {wjcCore.Globalize.format(lastItem.profit, 'c')}

+ +
+ +

KPIs for {wjcCore.Globalize.format(lastItem.date, 'MMMM yyyy')}

+
); +}; diff --git a/src/components/wj/components/RadialGauge.jsx b/src/components/wj/components/RadialGauge.jsx new file mode 100644 index 0000000..00faeb9 --- /dev/null +++ b/src/components/wj/components/RadialGauge.jsx @@ -0,0 +1,12 @@ +// React +import * as React from 'react'; +// Wijmo +import * as wjcCore from '@grapecity/wijmo'; +import * as wjGauge from '@grapecity/wijmo.react.gauge'; +export const RadialGauge = ({ data, palette }) => { + const lastItem = data.items[data.items.length - 1]; + return ( + +

Profit for {wjcCore.Globalize.format(lastItem.date, 'MMMM yyyy')}

+
); +}; diff --git a/src/components/wj/components/Tile.jsx b/src/components/wj/components/Tile.jsx new file mode 100644 index 0000000..62cdcf5 --- /dev/null +++ b/src/components/wj/components/Tile.jsx @@ -0,0 +1,14 @@ +import * as React from 'react'; +export const Tile = ({ header, content, index, onRemove }) => (
+
+
{header}
+
+
onRemove(index)}> + + + +
+
+
+
{content}
+
); diff --git a/src/components/wj/index.css b/src/components/wj/index.css new file mode 100644 index 0000000..87262fc --- /dev/null +++ b/src/components/wj/index.css @@ -0,0 +1,394 @@ +/* app */ +*, *::before, *::after { + box-sizing: border-box; +} + +/* customize the browser's scrollbar: */ +*::-webkit-scrollbar { + width: 6px; + height: 6px; +} +*::-webkit-scrollbar-track { + border-radius: 0.25rem; + background: rgba(0, 0, 0, 0.1); +} +*::-webkit-scrollbar-thumb { + border-radius: 0.25rem; + background: rgba(0, 0, 0, 0.2); +} +*::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.4); +} +*::-webkit-scrollbar-thumb:active { + background: rgba(0, 0, 0, 0.9); +} + +html, +body { + height: 100%; +} + +body { + background-color: #f7faff; + font-size: 0.875rem; + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue', sans-serif; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; +} + +h3 { + font-size: 0.875rem; + font-weight: 500; + text-align: center; +} + +h4 { + font-size: 0.875rem; + font-size: 0.75rem; + font-weight: 400; + min-width: 7rem; +} + +.flex-row { + display: flex; + flex-direction: row; + align-items: center; + padding: 0 1rem; +} + +.button { + cursor: pointer; +} + +#app { + flex: 1 1 auto; + overflow: hidden; +} + +.container { + display: flex; + flex-direction: row; + height: 100%; + width: 100%; + max-width: 100%; + background: #f2f6fe; +} + +.hr { + width: 1px; + height: 100%; + position: relative; + background: #e4ecfb; + z-index: 1; +} +.hr::before { + content: ''; + display: block; + width: 1px; + height: 100%; + background-color: #f6f9fe; +} + +.blank { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + height: 100%; + justify-content: center; + text-align: center; +} + +.blank svg { + width: 3rem; + height: 3rem; + margin-bottom: 1rem; +} + +.content { + flex: 1 1 auto; + overflow: auto; + background-color: #f7faff; + width: 100%; + padding: 2rem; + box-sizing: border-box; +} +@media only screen and (max-width: 811px) { + .content { + padding: 0.25rem; + } +} + +.menu { + display: flex; + flex-direction: column; + font-size: 0.85rem; + justify-content: flex-start; + flex: 0 0 auto; + padding: 0; +} +@media only screen and (max-width: 840px), (max-height: 840px) { + .menu { + overflow: auto; + font: 0.75rem; + } +} +.menu.menu--open .menu-item-name { + display: block; +} + +.menu-toggle { + transition: all 500ms; + padding: 1rem; + text-align: center; + border-bottom: 1px solid #e6ecf1; + cursor: pointer; +} +.menu-toggle svg { + transition: all 250ms ease-out 50ms; + transform-origin: center center; + transform: scaleX(1); +} +.menu.menu--open .menu-toggle svg { + transform: scaleX(-1); +} + +.menu-item { + display: flex; + flex-direction: row; + align-items: center; + padding: 0.5rem 1rem; + cursor: pointer; + user-select: none; + position: relative; + text-align: left; +} +.menu-item:hover { + background: #f7faff; +} +.menu-item:hover:before { + content: ''; + display: inline-block; + width: 1rem; + height: 1rem; + bottom: 2rem; + left: 2.5rem; + position: absolute; + background: linear-gradient(#fff, #fff), linear-gradient(#fff, #fff), #0085c7; + background-position: center; + background-size: 50% 2px, 2px 50%; /*thickness = 2px, length = 50% (25px)*/ + background-repeat: no-repeat; + border-radius: 50%; + box-shadow: 0 1px 2px rgba(55, 63, 66, 0.07), 0 2px 4px rgba(55, 63, 66, 0.07), 0 4px 8px rgba(55, 63, 66, 0.07), + 0 8px 16px rgba(55, 63, 66, 0.07), 0 16px 24px rgba(55, 63, 66, 0.07), 0 24px 32px rgba(55, 63, 66, 0.07); +} +.menu-item-name { + margin: 0 0.5rem 0 1rem; + white-space: nowrap; + display: none; +} +@media only screen and (max-width: 840px), (max-height: 840px) { + .menu-toggle { + padding: 1rem 0; + } + .menu-item { + padding: 0.5rem; + } + .menu-item:hover:before { + bottom: 1rem; + left: 1rem; + } + .menu-item svg { + width: 32px; + height: 32px; + } +} + +/* dashboard and tiles */ +.dashboard { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: auto; + height: 100%; +} + +.table { + margin: 0; + table-layout: fixed; + width: 100%; +} + +.table td { + padding: 0.15rem 0.5rem; + font-size: 0.75rem; + white-space: nowrap; + width: 1.5rem; +} + +.table td:first-child { + width: 4rem; +} + +.table td:last-child { + width: auto; +} + +.tile { + display: flex; + flex-direction: column; + flex: 0 0 auto; + width: calc(25% - 1rem); + margin: 0.5rem; + height: 50vh; + max-height: calc(50% - 1rem); + overflow: hidden; + background: white; + page-break-inside: avoid; /* important when printing the dashboard */ + transition: all 250ms; + border-radius: 0.5rem; + box-sizing: border-box; + box-shadow: 0 1px 2px rgba(55, 63, 66, 0.07), 0 2px 4px rgba(55, 63, 66, 0.07), 0 4px 8px rgba(55, 63, 66, 0.07), + 0 8px 16px rgba(55, 63, 66, 0.07), 0 16px 24px rgba(55, 63, 66, 0.07), 0 24px 32px rgba(55, 63, 66, 0.07); +} +@media only screen and (max-width: 1599px) { + .tile { + width: calc(33.33% - 1rem); + } +} +@media only screen and (max-width: 1079px) { + .tile { + width: calc(50% - 1rem); + } +} +@media only screen and (max-width: 1023px) { + .tile { + width: calc(100% - 1rem); + } +} +@media only screen and (max-height: 800px) { + .tile { + max-height: 400px; + } +} +.tile:last-child { + flex: 1 1 auto; +} +.tile:hover { + border-color: #adb7bd; +} +.tile.drag-over { + border: 2px dashed #000; +} + +.tile .buttons { + transition: all 250ms; + opacity: 0; +} +@media (hover: none) and (pointer: coarse) { + .tile .buttons { + opacity: 1; + } +} +.tile:hover .buttons { + opacity: 1; +} +.tile .buttons > span { + padding: 0 0.5rem; + cursor: pointer; +} +.tile.drag-over { + border: 2px dashed #000; + background-color: rgba(0, 0, 0, 0.1); + transition: all 250ms; +} +.tile.drag-source { + opacity: 0.4; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); + background-color: rgba(145, 200, 248, 0.75); + transform: scale(0.9); + transition: all 250ms; +} + +.tile .tile-container { + border-bottom: 1px solid #e0e0e0; + padding: 0.75rem 1rem; + display: flex; + cursor: move; +} + +.tile .tile-header { + flex-grow: 1; + font-size: 1rem; + font-weight: 400; + padding: 0.125rem; + opacity: 0.75; +} + +.tile .tile-content { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + flex: 1 1 auto; + overflow: auto; + height: 100%; +} + +.tile .blank-tile { + height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +/* tile content */ + +.wj-flexgrid { + border: none; + height: 100%; +} + +.wj-flexgrid .wj-cell { + border-right: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + padding: 0.35rem 1rem; + font-size: 0.8125rem; +} + +.wj-flexchart { + background: transparent; + height: calc(100%); + width: 100%; + border: none; + padding: 1rem; + margin: 0; + overflow: hidden; +} +.wj-radialgauge { + width: 60%; + max-width: 300px; + padding: 1rem; + overflow: hidden; +} +.wj-radialgauge .wj-value { + font-size: 0.75rem; + font-weight: 500; +} + +.wj-lineargauge { + max-height: 1rem; + width: 100%; + overflow: hidden; +} + +.wj-gauge .wj-face path { + stroke: none; +} + +.wj-ranges { + opacity: 0.15; +} diff --git a/src/components/wj/index.jsx b/src/components/wj/index.jsx new file mode 100644 index 0000000..4f7df64 --- /dev/null +++ b/src/components/wj/index.jsx @@ -0,0 +1,10 @@ +import './license'; +// Wijmo and Material Design Lite +import '@grapecity/wijmo.styles/themes/material/wijmo.theme.material.indigo-amber.css'; +// Styles +import './index.css'; +//React +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './App'; +ReactDOM.render(React.createElement(App), document.getElementById('app')); diff --git a/src/components/wj/license.js b/src/components/wj/license.js new file mode 100644 index 0000000..5c66de4 --- /dev/null +++ b/src/components/wj/license.js @@ -0,0 +1,2 @@ +import { setLicenseKey } from '@grapecity/wijmo'; +setLicenseKey('GrapeCity,427351286422477#B0JoIIklkIs4nIzYXMyAjMiojIyVmdiwSZzxWYmpjIyNHZisnOiwmbBJye0ICRiwiI34TQvAVW7ZWbqNjeWZzRh9Ucl5UTuZVaCR7ZpB5UH9EVC3kaqJWZ0pnasJ7Q9I4bB3GR0F6aIt6NZ96MFN4aotEZrUXe4kHUlllerlGb9dDSPhEcFFmclJXd8syNEtENzMTOBNVYpFje6lDUlBlbkdmcNNGOrAHR9pXNSl6NpVkbCNWUxlkZ7o7QT3icHNGavFXdapWQDZ5KsN5N7dDcyRUW85ESFBlb4JUZq3GWlBldXBzU0hjW9wkb8cncopnSOBjNkJFdyNmSqB7YVlnNzpnb9BDSMllTSFDaNFjca54dtBXatlEdS5mVNV6dxIEN7RUNxYGSvU7KIdndPpENvlXW6hzbCh7RsZ7YLJzboNnU7ZERTRkVBNlN7RWSGhDVrdmZqZ4cq94aFpkbWZDMGBHdVZ5YwUTTIdlN0RnVvMDdFJzbQt6bolDM5NkdrsUO536LrNWSotmI0IyUiwiIDRTR4MjM9QjI0ICSiwSMyIjM9UTMwEjM0IicfJye35XX3JSSwIjUiojIDJCLi86bpNnblRHeFBCI4VWZoNFelxmRg2Wbql6ViojIOJyes4nI5kkTRJiOiMkIsIibvl6cuVGd8VEIgIXZ7VWaWRncvBXZSBybtpWaXJiOi8kI1xSfis4N8gkI0IyQiwiIu3Waz9WZ4hXRgAydvJVa4xWdNBybtpWaXJiOi8kI1xSfiQjR6QkI0IyQiwiIu3Waz9WZ4hXRgACUBx4TgAybtpWaXJiOi8kI1xSfiMzQwIkI0IyQiwiIlJ7bDBybtpWaXJiOi8kI1xSfiUFO7EkI0IyQiwiIu3Waz9WZ4hXRgACdyFGaDxWYpNmbh9WaGBybtpWaXJiOi8kI1tlOiQmcQJCLiETMwAzNwACOwcDMwIDMyIiOiQncDJCLi46bj9idlRWe4l6YlBXYydmLqwibj9SbvNmL9RXajVGchJ7ZuoCLt36YukHdpNWZwFmcn9iKsI7au26YukHdpNWZwFmcn9iKsAnau26YukHdpNWZwFmcn9iKiojIz5GRiwiI9RXaDVGchJ7RiojIh94QiwiI7cDNyIDN6gjMxUzMdI6N'); diff --git a/src/components/wj/utils/DragDropTouch.js b/src/components/wj/utils/DragDropTouch.js new file mode 100644 index 0000000..dfcdbe7 --- /dev/null +++ b/src/components/wj/utils/DragDropTouch.js @@ -0,0 +1,370 @@ +import * as wjcCore from '@grapecity/wijmo'; +/** + * Object used to hold the data that is being dragged during drag and drop operations. + * + * It may hold one or more data items of different types. For more information about + * drag and drop operations and data transfer objects, see + * HTML Drag and Drop API. + * + * This object is created automatically by the @see:DragDropTouch singleton and is + * accessible through the @see:dataTransfer property of all drag events. + */ +export class DataTransfer { + constructor() { + this._dropEffect = 'move'; + this._effectAllowed = 'all'; + this._data = {}; + } + /** + * Gets or sets the type of drag-and-drop operation currently selected. + * The value must be 'none', 'copy', 'link', or 'move'. + */ + get dropEffect() { + return this._dropEffect; + } + set dropEffect(value) { + this._dropEffect = wjcCore.asString(value); + } + /** + * Gets or sets the types of operations that are possible. + * Must be one of 'none', 'copy', 'copyLink', 'copyMove', 'link', + * 'linkMove', 'move', 'all' or 'uninitialized'. + */ + get effectAllowed() { + return this._effectAllowed; + } + set effectAllowed(value) { + this._effectAllowed = wjcCore.asString(value); + } + /** + * Gets an array of strings giving the formats that were set in the @see:dragstart event. + */ + get types() { + return Object.keys(this._data); + } + /** + * Removes the data associated with a given type. + * + * The type argument is optional. If the type is empty or not specified, the data + * associated with all types is removed. If data for the specified type does not exist, + * or the data transfer contains no data, this method will have no effect. + * + * @param type Type of data to remove. + */ + clearData(type) { + if (type != null) { + delete this._data[type]; + } + else { + this._data = null; + } + } + /** + * Retrieves the data for a given type, or an empty string if data for that type does + * not exist or the data transfer contains no data. + * + * @param type Type of data to retrieve. + */ + getData(type) { + return this._data[type] || ''; + } + /** + * Set the data for a given type. + * + * For a list of recommended drag types, please see + * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Recommended_Drag_Types. + * + * @param type Type of data to add. + * @param value Data to add. + */ + setData(type, value) { + this._data[type] = value; + } + /** + * Set the image to be used for dragging if a custom one is desired. + * + * @param img An image element to use as the drag feedback image. + * @param offsetX The horizontal offset within the image. + * @param offsetY The vertical offset within the image. + */ + setDragImage(img, offsetX, offsetY) { + var ddt = DragDropTouch._instance; + ddt._imgCustom = img; + ddt._imgOffset = new wjcCore.Point(offsetX, offsetY); + } +} +/** + * Defines a class that adds support for touch-based HTML5 drag/drop operations. + * + * The @see:DragDropTouch class listens to touch events and raises the + * appropriate HTML5 drag/drop events as if the events had been caused + * by mouse actions. + * + * The purpose of this class is to enable using existing, standard HTML5 + * drag/drop code on mobile devices running IOS or Android. + * + * To use, include the DragDropTouch.js file on the page. The class will + * automatically start monitoring touch events and will raise the HTML5 + * drag drop events (dragstart, dragenter, dragleave, drop, dragend) which + * should be handled by the application. + * + * For details and examples on HTML drag and drop, see + * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations. + */ +export class DragDropTouch { + /** + * Initializes the single instance of the @see:DragDropTouch class. + */ + constructor() { + this._lastClick = 0; + // enforce singleton pattern + wjcCore.assert(!DragDropTouch._instance, 'DragDropTouch instance already created.'); + // listen to touch events + if ('ontouchstart' in document) { + var d = document, ts = this._touchstart.bind(this), tm = this._touchmove.bind(this), te = this._touchend.bind(this); + d.addEventListener('touchstart', ts); + d.addEventListener('touchmove', tm); + d.addEventListener('touchend', te); + d.addEventListener('touchcancel', te); + } + } + /** + * Gets a reference to the @see:DragDropTouch singleton. + */ + static getInstance() { + return DragDropTouch._instance; + } + // ** event handlers + _touchstart(e) { + if (this._shouldHandle(e)) { + // raise double-click and prevent zooming + if (Date.now() - this._lastClick < DragDropTouch._DBLCLICK) { + if (this._dispatchEvent(e, 'dblclick', e.target)) { + e.preventDefault(); + this._reset(); + return; + } + } + // clear all variables + this._reset(); + // get nearest draggable element + var src = wjcCore.closest(e.target, '[draggable]'); + if (src) { + // give caller a chance to handle the hover/move events + if (!this._dispatchEvent(e, 'mousemove', e.target) && + !this._dispatchEvent(e, 'mousedown', e.target)) { + // get ready to start dragging + this._dragSource = src; + this._ptDown = this._getPoint(e); + this._lastTouch = e; + e.preventDefault(); + // show context menu if the user hasn't started dragging after a while + setTimeout(() => { + if (this._dragSource == src && this._img == null) { + if (this._dispatchEvent(e, 'contextmenu', src)) { + this._reset(); + } + } + }, DragDropTouch._CTXMENU); + } + } + } + } + _touchmove(e) { + if (this._shouldHandle(e)) { + // see if target wants to handle move + var target = this._getTarget(e); + if (this._dispatchEvent(e, 'mousemove', target)) { + this._lastTouch = e; + e.preventDefault(); + return; + } + // start dragging + if (this._dragSource && !this._img) { + var delta = this._getDelta(e); + if (delta > DragDropTouch._THRESHOLD) { + this._dispatchEvent(e, 'dragstart', this._dragSource); + this._createImage(e); + this._dispatchEvent(e, 'dragenter', target); + } + } + // continue dragging + if (this._img) { + this._lastTouch = e; + e.preventDefault(); // prevent scrolling + if (target != this._lastTarget) { + this._dispatchEvent(this._lastTouch, 'dragleave', this._lastTarget); + this._dispatchEvent(e, 'dragenter', target); + this._lastTarget = target; + } + this._moveImage(e); + this._dispatchEvent(e, 'dragover', target); + } + } + } + _touchend(e) { + if (this._shouldHandle(e)) { + // see if target wants to handle up + if (this._dispatchEvent(this._lastTouch, 'mouseup', e.target)) { + e.preventDefault(); + return; + } + // user clicked the element but didn't drag, so clear the source and simulate a click + if (!this._img) { + this._dragSource = null; + this._dispatchEvent(this._lastTouch, 'click', e.target); + this._lastClick = Date.now(); + } + // finish dragging + this._destroyImage(); + if (this._dragSource) { + if (e.type.indexOf('cancel') < 0) { + this._dispatchEvent(this._lastTouch, 'drop', this._lastTarget); + } + this._dispatchEvent(this._lastTouch, 'dragend', this._dragSource); + this._reset(); + } + } + } + // ** utilities + // ignore events that have been handled or that involve more than one touch + _shouldHandle(e) { + return e && + !e.defaultPrevented && + e.touches && e.touches.length < 2; + } + // clear all members + _reset() { + this._destroyImage(); + this._dragSource = null; + this._lastTouch = null; + this._lastTarget = null; + this._ptDown = null; + this._dataTransfer = new DataTransfer(); + } + // get point for a touch event + _getPoint(e, page) { + if (e && e.touches) { + e = e.touches[0]; + } + wjcCore.assert(e && ('clientX' in e), 'invalid event?'); + if (page == true) { + return new wjcCore.Point(e.pageX, e.pageY); + } + else { + return new wjcCore.Point(e.clientX, e.clientY); + } + } + // get distance between the current touch event and the first one + _getDelta(e) { + var p = this._getPoint(e); + return Math.abs(p.x - this._ptDown.x) + Math.abs(p.y - this._ptDown.y); + } + // get the element at a given touch event + _getTarget(e) { + var pt = this._getPoint(e), el = document.elementFromPoint(pt.x, pt.y); + while (el && getComputedStyle(el).pointerEvents == 'none') { + el = el.parentElement; + } + return el; + } + // create drag image from source element + _createImage(e) { + // just in case... + if (this._img) { + this._destroyImage(); + } + // create drag image from custom element or drag source + var src = this._imgCustom || this._dragSource; + this._img = src.cloneNode(true); + this._copyStyle(src, this._img); + this._img.style.top = this._img.style.left = '-9999px'; + // if creating from drag source, apply offset and opacity + if (!this._imgCustom) { + var rc = src.getBoundingClientRect(), pt = this._getPoint(e); + this._imgOffset = new wjcCore.Point(pt.x - rc.left, pt.y - rc.top); + this._img.style.opacity = DragDropTouch._OPACITY.toString(); + } + // add image to document + this._moveImage(e); + document.body.appendChild(this._img); + } + // dispose of drag image element + _destroyImage() { + if (this._img && this._img.parentElement) { + this._img.parentElement.removeChild(this._img); + } + this._img = null; + this._imgCustom = null; + } + // move the drag image element + _moveImage(e) { + requestAnimationFrame(() => { + var pt = this._getPoint(e, true); + wjcCore.setCss(this._img, { + position: 'absolute', + pointerEvents: 'none', + zIndex: 999999, + left: Math.round(pt.x - this._imgOffset.x), + top: Math.round(pt.y - this._imgOffset.y) + }); + }); + } + // copy properties from an object to another + _copyProps(dst, src, props) { + for (var i = 0; i < props.length; i++) { + var p = props[i]; + dst[p] = src[p]; + } + } + _copyStyle(src, dst) { + // remove potentially troublesome attributes + DragDropTouch._rmvAtts.forEach(function (att) { + dst.removeAttribute(att); + }); + // copy canvas content + if (src instanceof HTMLCanvasElement) { + var cSrc = src, cDst = dst; + cDst.width = cSrc.width; + cDst.height = cSrc.height; + cDst.getContext('2d').drawImage(cSrc, 0, 0); + } + // copy style + var cs = getComputedStyle(src); + for (var i = 0; i < cs.length; i++) { + var key = cs[i]; + dst.style[key] = cs[key]; + } + dst.style.pointerEvents = 'none'; + // and repeat for all children + for (var i = 0; i < src.children.length; i++) { + this._copyStyle(src.children[i], dst.children[i]); + } + } + _dispatchEvent(e, type, target) { + if (e && target) { + var evt = document.createEvent('Event'), t = e.touches ? e.touches[0] : e; + evt.initEvent(type, true, true); + evt.button = 0; + evt.which = evt.buttons = 1; + this._copyProps(evt, e, DragDropTouch._kbdProps); + this._copyProps(evt, t, DragDropTouch._ptProps); + evt.dataTransfer = this._dataTransfer; + target.dispatchEvent(evt); + return evt.defaultPrevented; + } + return false; + } +} +/*private*/ DragDropTouch._instance = new DragDropTouch(); // singleton +// constants +DragDropTouch._THRESHOLD = 5; // pixels to move before drag starts +DragDropTouch._OPACITY = 0.5; // drag image opacity +DragDropTouch._DBLCLICK = 500; // max ms between clicks in a double click +DragDropTouch._CTXMENU = 900; // ms to hold before raising 'contextmenu' event +// copy styles/attributes from drag source to drag image element +DragDropTouch._rmvAtts = 'id,class,style,draggable'.split(','); +// synthesize and dispatch an event +// returns true if the event has been handled (e.preventDefault == true) +DragDropTouch._kbdProps = 'altKey,ctrlKey,metaKey,shiftKey'.split(','); +DragDropTouch._ptProps = 'pageX,pageY,clientX,clientY,screenX,screenY'.split(','); diff --git a/src/routes.js b/src/routes.js index eb71b0f..1ede7b1 100644 --- a/src/routes.js +++ b/src/routes.js @@ -50,6 +50,7 @@ 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 DashboardDND = React.lazy(() => import('./components/wj/App')) const DashboardCustomer = React.lazy(() => import('./views/Dashboard/DashboardCustomer')); const DashboardProject = React.lazy(() => import('./views/Dashboard/DashboardProject')); const DashboardProjectCarousell = React.lazy(() => import('./views/Dashboard/DashboardProjectCarousell')); @@ -60,6 +61,7 @@ const DemoManagement = React.lazy(() => import('./views/SimproV2/Demo')) const routes = [ { path: '/', exact: true, name: 'Home' }, { path: '/dashboard', name: 'DashboardBOD', component: DashboardBOD }, + { path: '/dashboard-dnd', name: 'DashboardBOD', component: DashboardDND }, { path: '/dashboard-customer/:PROJECT_ID/:GANTT_ID/:SCURVE', name: 'DashboardCustomer', component: DashboardCustomer }, { 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 }, From 42e20239fb802dd185676618224916539ef6baa6 Mon Sep 17 00:00:00 2001 From: farhantock Date: Wed, 28 Feb 2024 16:34:56 +0700 Subject: [PATCH 03/14] resolve conflict --- .../Master/MasterRoles/DialogMenuRoles.js | 153 +++--------------- 1 file changed, 26 insertions(+), 127 deletions(-) diff --git a/src/views/Master/MasterRoles/DialogMenuRoles.js b/src/views/Master/MasterRoles/DialogMenuRoles.js index 348f614..a00128e 100644 --- a/src/views/Master/MasterRoles/DialogMenuRoles.js +++ b/src/views/Master/MasterRoles/DialogMenuRoles.js @@ -3,11 +3,8 @@ import { Modal, ModalHeader, ModalBody, ModalFooter, Row, Col, Table } from 'rea 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 { MENU_COMPANY_SEARCH } from '../../../const/ApiConst.js'; const token = window.localStorage.getItem('token'); - - const config = { headers: { @@ -15,7 +12,6 @@ const config = { "Content-type": `application/json` } }; - export default class DialogMenuRoles extends Component { constructor(props) { super(props) @@ -36,13 +32,13 @@ export default class DialogMenuRoles extends Component { stateUpdateAll: false, stateDeleteAll: false, allChecked: true, + company_id: props.company_id || null, } } async componentDidMount() { this.props.showDialog(this.showDialog); this.getAllMenu(); } - async componentDidUpdate() { if (this.state.isParentClick === true) { const { idRoles } = this.props @@ -54,43 +50,32 @@ export default class DialogMenuRoles extends Component { this.setState({ isParentClick: false, id: idRoles }); } } - - showDialog = () => { this.setState({ isParentClick: true }); } - getAllMenu = async () => { const payload = { "paging": { "start": 0, "length": -1 }, "columns": [ - { "name": "name", "logic_operator": "ilike", "value": "", "operator": "AND" } + { "name": "company_id", "logic_operator": "=", "value": this.state.company_id, "operator": "AND" } ], "joins": [ - { "name": "t_roles_menu", "column_join": "id", "column_results": ["create", "update", "delete", "read"] } + { "name": "t_roles_menu", "column_join": "menu_id", "column_results": ["create", "update", "delete", "read"] }, + { "name": "m_menu", "column_join": "menu_id", "column_results": ["name"] } ], "orders": { "columns": ["id"], "ascending": false } } - - - const result = await axios - .post(MENU_SEARCH, payload, config) + .post(MENU_COMPANY_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.setStateMenu(false); }); } else { } - } - - - setStateMenu = edit => { const stateMenu = []; this.state.menu.map((val) => { @@ -104,7 +89,6 @@ export default class DialogMenuRoles extends Component { }) }) } - setStateRead = edit => { const stateRead = []; this.state.menu.map((val) => { @@ -118,7 +102,6 @@ export default class DialogMenuRoles extends Component { }) }) } - setStateCreate = edit => { const stateCreate = []; this.state.menu.map((val) => { @@ -132,7 +115,6 @@ export default class DialogMenuRoles extends Component { }) }) } - setStateUpdate = edit => { const stateUpdate = []; this.state.menu.map((val) => { @@ -146,7 +128,6 @@ export default class DialogMenuRoles extends Component { }) }) } - setStateDelete = edit => { const stateDelete = []; this.state.menu.map((val) => { @@ -160,13 +141,10 @@ export default class DialogMenuRoles extends Component { }) }) } - checkMenuRoles = () => { let copyStateMenu = [...this.state.stateMenu]; - this.props.menuRoles.map((val, indexMenu) => { let index = this.getIndexDataMenu(val.menu_id); - if (index >= 0 || val.read === true || val.create === true || val.update === true || val.delete === true) { copyStateMenu[index] = true; } @@ -180,7 +158,6 @@ export default class DialogMenuRoles extends Component { } }) } - checkReadRoles = () => { let copyStateRead = [...this.state.stateRead]; this.props.menuRoles.map((val) => { @@ -191,7 +168,6 @@ export default class DialogMenuRoles extends Component { copyStateRead[index] = false; } }) - this.setState({ stateRead: [] }, () => { let check = copyStateRead.some(this.checkArray); if (check === false) { @@ -201,10 +177,8 @@ export default class DialogMenuRoles extends Component { } }) } - checkCreateRoles = () => { let copyStateCreate = [...this.state.stateCreate]; - this.props.menuRoles.map((val) => { let index = this.getIndexDataMenu(val.menu_id); if (val.create === true) { @@ -213,7 +187,6 @@ export default class DialogMenuRoles extends Component { copyStateCreate[index] = false; } }) - this.setState({ stateCreate: [] }, () => { let check = copyStateCreate.some(this.checkArray); if (check === false) { @@ -223,10 +196,8 @@ export default class DialogMenuRoles extends Component { } }) } - checkUpdateRoles = () => { let copyStateUpdate = [...this.state.stateUpdate]; - this.props.menuRoles.map((val) => { let index = this.getIndexDataMenu(val.menu_id); if (val.update === true) { @@ -235,7 +206,6 @@ export default class DialogMenuRoles extends Component { copyStateUpdate[index] = false; } }) - this.setState({ stateUpdate: [] }, () => { let check = copyStateUpdate.some(this.checkArray); if (check === false) { @@ -245,10 +215,8 @@ export default class DialogMenuRoles extends Component { } }) } - checkDeleteRoles = () => { let copyStateDelete = [...this.state.stateDelete]; - this.props.menuRoles.map((val) => { let index = this.getIndexDataMenu(val.menu_id); if (val.delete === true) { @@ -257,7 +225,6 @@ export default class DialogMenuRoles extends Component { copyStateDelete[index] = false; } }) - this.setState({ stateDelete: [] }, () => { let check = copyStateDelete.some(this.checkArray); if (check === false) { @@ -267,32 +234,26 @@ export default class DialogMenuRoles extends Component { } }) } - 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, @@ -303,9 +264,7 @@ export default class DialogMenuRoles extends Component { menu, id } = this.state - const arrayData = []; - menu.map((val, index) => { let data = { roles_id: id, @@ -315,35 +274,27 @@ export default class DialogMenuRoles extends Component { update: stateUpdate[index], delete: stateDelete[index], checked: stateMenu[index], - } arrayData.push(data); - - }) - console.log('arrayData', arrayData); - // this.props.closeDialog('save', arrayData); + this.props.closeDialog('save', arrayData); this.setState({ id: 0 }); } - handleCancel = () => { this.props.closeDialog('cancel', 'none') } - handleChangeCheckbox = (checked, index) => { let copyStateMenu = [...this.state.stateMenu]; copyStateMenu[index] = checked; - this.setState({ stateMenu: copyStateMenu }) } - handleChangeCheckboxRead = (checked, index, menuItem = null, menuIdxList = []) => { let copyStateRead = [...this.state.stateRead]; copyStateRead[index] = checked; let menu = this.state.menu; let checkMenuParent = menu.map((state, index) => { - if (state.parent_id === menuItem.id) { - return state.id + if (state.parent_menu_id === menuItem.menu_id) { + return state.menu_id } else { return null } @@ -359,17 +310,15 @@ export default class DialogMenuRoles extends Component { stateReadIdx.map((stateRead) => { copyStateRead[stateRead] = checked }) - this.setState({ stateRead: copyStateRead }) } - handleChangeCheckboxCreate = (checked, index, menuItem = null, menuIdxList = []) => { let copyStateCreate = [...this.state.stateCreate]; copyStateCreate[index] = checked; let menu = this.state.menu; let checkMenuParent = menu.map((state, index) => { - if (state.parent_id === menuItem.id) { - return state.id + if (state.parent_menu_id === menuItem.menu_id) { + return state.menu_id } else { return null } @@ -387,14 +336,13 @@ export default class DialogMenuRoles extends Component { }) this.setState({ stateCreate: copyStateCreate }) } - handleChangeCheckboxEdit = (checked, index, menuItem = null, menuIdxList = []) => { let copyStateEdit = [...this.state.stateUpdate]; copyStateEdit[index] = checked; let menu = this.state.menu; let checkMenuParent = menu.map((state, index) => { - if (state.parent_id === menuItem.id) { - return state.id + if (state.parent_menu_id === menuItem.menu_id) { + return state.menu_id } else { return null } @@ -412,14 +360,13 @@ export default class DialogMenuRoles extends Component { }) this.setState({ stateUpdate: copyStateEdit }) } - handleChangeCheckboxDelete = (checked, index, menuItem = null, menuIdxList = []) => { let copyStateDelete = [...this.state.stateDelete]; copyStateDelete[index] = checked; let menu = this.state.menu; let checkMenuParent = menu.map((state, index) => { - if (state.parent_id === menuItem.id) { - return state.id + if (state.parent_menu_id === menuItem.menu_id) { + return state.menu_id } else { return null } @@ -437,7 +384,6 @@ export default class DialogMenuRoles extends Component { }) this.setState({ stateDelete: copyStateDelete }) } - handleChangeCheckboxReadAll = (checked) => { let copyStateRead = [...this.state.stateRead]; copyStateRead.map((val, index) => { @@ -445,7 +391,6 @@ export default class DialogMenuRoles extends Component { }) this.setState({ stateRead: copyStateRead }) } - handleChangeCheckboxCreateAll = (checked, index) => { let copyStateCreate = [...this.state.stateCreate]; copyStateCreate.map((val, index) => { @@ -453,7 +398,6 @@ export default class DialogMenuRoles extends Component { }) this.setState({ stateCreate: copyStateCreate }) } - handleChangeCheckboxEditAll = (checked, index) => { let copyStateEdit = [...this.state.stateUpdate]; copyStateEdit.map((val, index) => { @@ -461,7 +405,6 @@ export default class DialogMenuRoles extends Component { }) this.setState({ stateUpdate: copyStateEdit }) } - handleChangeCheckboxDeleteAll = (checked, index) => { let copyStateDelete = [...this.state.stateDelete]; copyStateDelete.map((val, index) => { @@ -469,74 +412,44 @@ export default class DialogMenuRoles extends Component { }) this.setState({ stateDelete: copyStateDelete }) } - - // renderForm = () => { - // const { menu, stateRead, stateCreate, stateUpdate, stateDelete } = this.state - // console.log('menu', menu); - // return ( - // menu.map((val, index) => { - - // return ( - // - // {val.name} - // this.handleChangeCheckboxRead(e.target.checked, index)} defaultChecked={stateRead[index]} /> - // this.handleChangeCheckboxCreate(e.target.checked, index)} defaultChecked={stateCreate[index]} /> - // this.handleChangeCheckboxEdit(e.target.checked, index)} defaultChecked={stateUpdate[index]} /> - // this.handleChangeCheckboxDelete(e.target.checked, index)} defaultChecked={stateDelete[index]} /> - // - // ) - // }) - // ) - - // } - renderForm = () => { const { menu, stateRead, stateCreate, stateUpdate, stateDelete } = this.state; let menuIdxList = [] let menuIdx = 0 const getChildren = (parentId) => { - return menu.filter(item => item.parent_id === parentId); + return menu.filter(item => item.parent_menu_id === parentId); }; - - // Function to render menu items const renderMenu = (parentId, depth = 0) => { const children = getChildren(parentId); - return children.map((menuItem, index) => { - const currentIndex = menuIdx; // Capture current index - menuIdxList[currentIndex] = menuItem.id; + const currentIndex = menuIdx; + menuIdxList[currentIndex] = menuItem.menu_id; menuIdx++ - const paddingLeft = depth * 20; - const fontWeight = menuItem.parent_id === null ? 'bold' : 'normal'; - + const paddingLeft = depth * 30; return ( - + - {menuItem.name} + {menuItem.join_second_name} this.handleChangeCheckboxRead(e.target.checked, currentIndex, menuItem, menuIdxList)} defaultChecked={stateRead[currentIndex]} /> this.handleChangeCheckboxCreate(e.target.checked, currentIndex, menuItem, menuIdxList)} defaultChecked={stateCreate[currentIndex]} /> this.handleChangeCheckboxEdit(e.target.checked, currentIndex, menuItem, menuIdxList)} defaultChecked={stateUpdate[currentIndex]} /> this.handleChangeCheckboxDelete(e.target.checked, currentIndex, menuItem, menuIdxList)} defaultChecked={stateDelete[currentIndex]} /> - {renderMenu(menuItem.id, depth + 1)} {/* Recursively render children */} + {renderMenu(menuItem.menu_id, depth + 1)} ); }); }; menuIdxList = [] menuIdx = 0 - // Render top-level menu items (parents) return ( - {this.renderAll()} {/* Render the "All" row */} - {renderMenu(null)} {/* Render the menu items */} + {this.renderAll()} + {renderMenu(null)} ); }; - - renderAll = () => { - return ( All @@ -547,45 +460,32 @@ export default class DialogMenuRoles extends Component { ) } - - - - checkArray = (val) => { return val === false; } - handleAllChecked = (checked) => { this.setState({ allChecked: !this.state.allChecked }); if (checked === true) { - let check = this.state.stateMenu.some(this.checkArray); - if (check) { const stateMenu = []; this.state.menu.map((val) => { stateMenu.push(true); }) - this.setState({ stateMenu: [] }, () => { this.setState({ stateMenu: stateMenu }); }) } - - } else { - const stateMenu = []; this.state.menu.map((val) => { stateMenu.push(false); }) - this.setState({ stateMenu: [] }, () => { this.setState({ stateMenu: stateMenu }); }) } } - render() { return ( @@ -603,12 +503,11 @@ export default class DialogMenuRoles extends Component { Create - Edite + Edit Delete - @@ -624,4 +523,4 @@ export default class DialogMenuRoles extends Component { ) } -} +} \ No newline at end of file From 5d2e9f052f929f01d9cd4363a08b86954ed94854 Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:45:38 +0700 Subject: [PATCH 04/14] customfunc --- src/const/CustomFunc.js | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/const/CustomFunc.js b/src/const/CustomFunc.js index 808b6d4..bf29083 100644 --- a/src/const/CustomFunc.js +++ b/src/const/CustomFunc.js @@ -164,6 +164,46 @@ export const QUERY_BUILDER_FIELD_SALES = }, } +export const checkActMenup = (menuPath, actProp) => { + let foundObj; + let entireObj = JSON.parse(localStorage.getItem("menu_login")); + JSON.stringify(entireObj, (_, nestedValue) => { + if (nestedValue && nestedValue.url === menuPath) { + foundObj = nestedValue; + } + return nestedValue; + }); + + let output = false; + let actValue = actProp.trim().toLowerCase() + switch (actValue) { + case "create": + if (foundObj[actValue] === true) { + output = true; + } else { + output = false; + + } + case "read": + if (foundObj[actValue] === true) { + output = true; + } + case "update": + if (foundObj[actValue] === true) { + output = true; + } + case "delete": + if (foundObj[actValue] === true) { + output = true; + } + // default: + // output = false + } + + return output; + // return foundObj[actProp]; +}; + export const QUERY_BUILDER_FIELD_CUSTOMER = { "properties->name": { From 1ad73d642add306bf44825da0cbe1acb7644094c Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:46:28 +0700 Subject: [PATCH 05/14] roles --- src/views/Master/MasterRoles/index.js | 33 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/views/Master/MasterRoles/index.js b/src/views/Master/MasterRoles/index.js index 3ff0663..3d1137d 100644 --- a/src/views/Master/MasterRoles/index.js +++ b/src/views/Master/MasterRoles/index.js @@ -10,6 +10,7 @@ import { NotificationContainer, NotificationManager } from 'react-notifications' import { Pagination, Tooltip, Table } from 'antd'; import { ROLE_ADD, ROLE_SEARCH, ROLE_EDIT, ROLE_DELETE, ROLEMENU_ADD, ROLEMENU_SEARCH, ROLEMENU_DELETE_ROLE } from '../../../const/ApiConst.js'; import { withTranslation } from 'react-i18next'; +import { checkActMenup } from '../../../const/CustomFunc'; const LENGTH_DATA = 10 @@ -66,15 +67,30 @@ class index extends Component { className: 'nowrap', render: (text, record) => <> - this.handleMenuRoles(text.id)}> + { + checkActMenup('/roles', 'update') ? + this.handleMenuRoles(text.id)}> + : + null + } - this.handleDelete(text.id)}> + { + checkActMenup('/roles', 'delete') ? + this.handleDelete(text.id)}> + : + null + } - this.handleEdit(text)}> + { + checkActMenup('/roles', 'update') ? + this.handleEdit(text)}> + : + null + } , }, @@ -503,10 +519,17 @@ class index extends Component { - + { + checkActMenup('/roles', 'create') ? + + + : + null + } - + From 1e3560135cc676680f0ab131d5e925ff2ef81fff Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:46:56 +0700 Subject: [PATCH 06/14] menu --- src/views/Master/MenuCompany/index.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/views/Master/MenuCompany/index.js b/src/views/Master/MenuCompany/index.js index e3eb03b..e3e71a7 100644 --- a/src/views/Master/MenuCompany/index.js +++ b/src/views/Master/MenuCompany/index.js @@ -10,6 +10,8 @@ import { MENU_ADD, MENU_SEARCH, MENU_EDIT, MENU_DELETE, MENU_LIST, MENU_COMPANY_ import { NotificationContainer, NotificationManager } from 'react-notifications'; import { Pagination, Tooltip, Table } from 'antd'; import { useTranslation } from 'react-i18next'; +import { checkActMenup } from '../../../const/CustomFunc.js'; +import { useLocation } from "react-router-dom"; const token = window.localStorage.getItem('token'); const column = [ { name: "Nama" }, @@ -34,6 +36,7 @@ const Index = ({ params, ...props }) => { hierarchy = props.hierarchy; user_name = props.user_name; } + const location = useLocation() const [alertDelete, setAlertDelete] = useState(false) const [allDataMenu, setAllDataMenu] = useState([]) const [clickOpenModal, setClickOpenModal] = useState(false) @@ -340,10 +343,20 @@ const Index = ({ params, ...props }) => { key: 'x', render: (text, record) => <> - handleDelete(text.id)}> + { + checkActMenup(location.pathname, 'delete') ? + handleDelete(text.id)}> + : + null + } - handleEdit(text)}> + { + checkActMenup(location.pathname, 'update') ? + handleEdit(text)}> + : + null + } , }, From fe462877f049afc3ac3d1fc44d00c78aecc94395 Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:47:16 +0700 Subject: [PATCH 07/14] project phase --- src/views/Master/ProjectPhase/index.js | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/views/Master/ProjectPhase/index.js b/src/views/Master/ProjectPhase/index.js index 9effc9b..708e91a 100644 --- a/src/views/Master/ProjectPhase/index.js +++ b/src/views/Master/ProjectPhase/index.js @@ -9,6 +9,14 @@ import { NotificationContainer, NotificationManager } from 'react-notifications' import { PROJECT_PHASE_ADD, PROJECT_PHASE_EDIT, PROJECT_PHASE_DELETE, PROJECT_PHASE_SEARCH, COMPANY_MANAGEMENT_LIST, BASE_OSPRO } from '../../../const/ApiConst'; import { Pagination, Button, Tooltip, Table } from 'antd'; import { useTranslation } from 'react-i18next'; +import { + formatNumber, + formatRupiah, + formatThousand, + renderFormatRupiah, + checkActMenup, +} from "../../../const/CustomFunc"; +import { useLocation } from "react-router-dom"; const ProjectPhase = ({ params, ...props }) => { @@ -26,6 +34,7 @@ const ProjectPhase = ({ params, ...props }) => { user_name = props.user_name; } + const location = useLocation(); const HEADER = { headers: { "Content-Type": "application/json", @@ -350,10 +359,20 @@ const ProjectPhase = ({ params, ...props }) => { className: 'nowrap', render: (text, record) => <> - handleDelete(text.id)}> + { + checkActMenup(location.pathname, 'delete') ? + handleDelete(text.id)}> + : + null + } - handleEdit(text)}> + { + checkActMenup(location.pathname, 'update') ? + handleEdit(text)}> + : + null + } {" "} , }, @@ -429,7 +448,12 @@ const ProjectPhase = ({ params, ...props }) => { + { + checkActMenup(location.pathname, 'create') ? + : + null + } From 08428e7d696a7a5b08ca234755afbe87f3428786 Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:47:36 +0700 Subject: [PATCH 08/14] project role --- src/views/Master/RoleProject/index.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/views/Master/RoleProject/index.js b/src/views/Master/RoleProject/index.js index d5b095b..8ca9848 100644 --- a/src/views/Master/RoleProject/index.js +++ b/src/views/Master/RoleProject/index.js @@ -9,6 +9,7 @@ import { NotificationContainer, NotificationManager } from 'react-notifications' import { PROJECT_ROLE_ADD, PROJECT_ROLE_SEARCH, PROJECT_ROLE_EDIT, PROJECT_ROLE_DELETE } from '../../../const/ApiConst.js'; import { Pagination, Tooltip, Table } from 'antd'; import { withTranslation } from 'react-i18next'; +import { checkActMenup } from '../../../const/CustomFunc'; const LENGTH_DATA = 10 class index extends Component { constructor(props) { @@ -63,10 +64,20 @@ class index extends Component { className: 'nowrap', render: (text, record) => <> - this.handleDelete(text.id)}> + { + checkActMenup('/project-role', 'delete') ? + this.handleDelete(text.id)}> + : + null + } - this.handleEdit(text)}> + { + checkActMenup('/project-role', 'update') ? + this.handleEdit(text)}> + : + null + } , }, @@ -403,7 +414,13 @@ class index extends Component { - + { + checkActMenup('/roles', 'create') ? + + : + null + } From c1f8a08d6d9021f0d4765543bbc9d859e80ace1e Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:47:54 +0700 Subject: [PATCH 09/14] checklist 3 --- src/views/SimproV2/ChecklistK3/index.js | 30 ++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/views/SimproV2/ChecklistK3/index.js b/src/views/SimproV2/ChecklistK3/index.js index e0632b6..758f833 100644 --- a/src/views/SimproV2/ChecklistK3/index.js +++ b/src/views/SimproV2/ChecklistK3/index.js @@ -10,6 +10,14 @@ import { CHECKLIST_K3_ADD, CHECKLIST_K3_EDIT, CHECKLIST_K3_DELETE, CHECKLIST_K3_SEARCH, COMPANY_MANAGEMENT_LIST } from '../../../const/ApiConst'; import { useTranslation } from 'react-i18next'; +import { useLocation } from "react-router-dom"; +import { + formatNumber, + formatRupiah, + formatThousand, + renderFormatRupiah, + checkActMenup, +} from "../../../const/CustomFunc"; const token = window.localStorage.getItem('token'); const config = { @@ -34,6 +42,7 @@ const ChecklistK3 = ({ params, ...props }) => { hierarchy = props.hierarchy; user_name = props.user_name; } + const location = useLocation(); const HEADER = { headers: { "Content-Type": "application/json", @@ -363,7 +372,12 @@ const ChecklistK3 = ({ params, ...props }) => { - + { + checkActMenup(location.pathname, 'create') ? + + : + null + } @@ -390,10 +404,20 @@ const ChecklistK3 = ({ params, ...props }) => { - handleDelete(n.id)}> + { + checkActMenup(location.pathname, 'delete') ? + handleDelete(n.id)}> + : + null + } - handleEdit(n)}> + { + checkActMenup(location.pathname, 'edit') ? + handleEdit(n)}> + : + null + } {role_name === 'Super Admin' && From 9120cc187bfd2d13242ff7b0432b12a964368fc9 Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:48:16 +0700 Subject: [PATCH 10/14] project information --- src/views/SimproV2/CreatedProyek/index.js | 41 +++++++++++++++++------ 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/views/SimproV2/CreatedProyek/index.js b/src/views/SimproV2/CreatedProyek/index.js index 8a25b0e..d9c86b4 100644 --- a/src/views/SimproV2/CreatedProyek/index.js +++ b/src/views/SimproV2/CreatedProyek/index.js @@ -61,9 +61,6 @@ import { IMAGE_GET_BY_ID, IMAGE_DELETE, } from "../../../const/ApiConst"; -import { - formatThousand -} from "../../../const/CustomFunc"; import moment from "moment"; // import DialogFormResource from './DialogFormResource'; import DialogFormMaterial from "./DataRequestMaterial"; @@ -72,6 +69,13 @@ import DialogDocument from "./DialogDocument"; import DialogInitDocument from "./DialogInitDocument"; import DialogGantt from "./DialogGantt"; import DialogHierarchy from "./DialogHierarchy"; +import { + formatNumber, + formatRupiah, + formatThousand, + renderFormatRupiah, + checkActMenup, +} from "../../../const/CustomFunc"; // import DialogAsignHr from './AsignHrProject'; import AssignHrProject from "./AsignHrProject"; import AssignCustProject from "./AsignCustProject"; @@ -80,7 +84,7 @@ import ViewProject from "./ViewProject"; import ReportAnalysis from "./ReportAnalysis"; import { Icon } from "@iconify/react"; // import SubProyekComp from './SubProyekComp'; -import { Link, useHistory, withRouter } from "react-router-dom"; +import { Link, useHistory, withRouter, useLocation } from "react-router-dom"; import { t } from "i18next"; const url = ""; @@ -100,6 +104,7 @@ const CreatedProyek = ({ params, ...props }) => { hierarchy = props.hierarchy; user_name = props.user_name; } + const location = useLocation(); const history = useHistory(); const HEADER = { headers: { @@ -1727,10 +1732,17 @@ const CreatedProyek = ({ params, ...props }) => { content={popupMenu(text, record)} trigger="click" > + { + checkActMenup(location.pathname, 'read') ? + : + null + } + { + checkActMenup(location.pathname, 'update') ? { )} + : + null + } ), }, @@ -2106,12 +2121,18 @@ const CreatedProyek = ({ params, ...props }) => { {parseInt(role_id) == 44 ? null : ( // role kustomer - + { + checkActMenup(location.pathname, 'create') ? + + : + null + } )} From dedc56f2beae66d9ec1f90966977e2fe00765892 Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:48:29 +0700 Subject: [PATCH 11/14] divisi --- src/views/SimproV2/Divisi/index.js | 37 ++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/views/SimproV2/Divisi/index.js b/src/views/SimproV2/Divisi/index.js index 68b1825..d423c8f 100644 --- a/src/views/SimproV2/Divisi/index.js +++ b/src/views/SimproV2/Divisi/index.js @@ -8,6 +8,14 @@ import { DIVISI_LIST, DIVISI_ADD, DIVISI_EDIT, DIVISI_DELETE, DIVISI_SEARCH, COM import { NotificationContainer, NotificationManager } from 'react-notifications'; import { Pagination, Button, Tooltip, Table, Spin } from 'antd'; import { useTranslation } from 'react-i18next'; +import { useLocation } from "react-router-dom"; +import { + formatNumber, + formatRupiah, + formatThousand, + renderFormatRupiah, + checkActMenup, +} from "../../../const/CustomFunc"; const ProjectType = ({ params, ...props }) => { @@ -24,7 +32,7 @@ const ProjectType = ({ params, ...props }) => { hierarchy = props.hierarchy; user_name = props.user_name; } - + const location = useLocation(); const HEADER = { headers: { "Content-Type": "application/json", @@ -400,13 +408,29 @@ const ProjectType = ({ params, ...props }) => { render: (text, record) => <> - handleDelete(text.id)}> + { + checkActMenup(location.pathname, 'delete') ? + handleDelete(text.id)}> + : + null + } + - handleAddChild(text)}> + { + checkActMenup(location.pathname, 'create') ? + handleAddChild(text)}> + : + null + } - handleEdit(text)}> + { + checkActMenup(location.pathname, 'update') ? + handleEdit(text)}> + : + null + } , @@ -511,7 +535,12 @@ const ProjectType = ({ params, ...props }) => { + { + checkActMenup(location.pathname, 'create') ? + : + null + } From 9ad1234db2cef26c0459d5a46dcd3df50e91be83 Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:48:45 +0700 Subject: [PATCH 12/14] project type --- src/views/SimproV2/ProjectType/index.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/views/SimproV2/ProjectType/index.js b/src/views/SimproV2/ProjectType/index.js index 5d5b37c..0e23258 100644 --- a/src/views/SimproV2/ProjectType/index.js +++ b/src/views/SimproV2/ProjectType/index.js @@ -11,6 +11,8 @@ import { NotificationContainer, NotificationManager } from 'react-notifications' import { PROJECT_TYPE_ADD, PROJECT_TYPE_EDIT, PROJECT_TYPE_DELETE, PROJECT_TYPE_SEARCH, COMPANY_MANAGEMENT_LIST } from '../../../const/ApiConst'; import { Pagination, Button, Tooltip, Table } from 'antd'; import { useTranslation } from 'react-i18next'; +import { checkActMenup } from '../../../const/CustomFunc.js'; +import { useLocation } from "react-router-dom"; const ProjectType = ({ params, ...props }) => { @@ -27,6 +29,7 @@ const ProjectType = ({ params, ...props }) => { hierarchy = props.hierarchy; user_name = props.user_name; } + const location = useLocation() const HEADER = { headers: { "Content-Type": "application/json", @@ -353,10 +356,20 @@ const ProjectType = ({ params, ...props }) => { className: 'nowrap', render: (text, record) => <> - handleDelete(text.id)}> + { + checkActMenup(location.pathname, 'delete') ? + handleDelete(text.id)}> + : + null + } - handleEdit(text)}> + { + checkActMenup(location.pathname, 'update') ? + handleEdit(text)}> + : + null + } {" "} handleDialogIg(text.id)}> @@ -430,7 +443,12 @@ const ProjectType = ({ params, ...props }) => { + { + checkActMenup(location.pathname, 'create') ? + : + null + } From db8397684a42dcbf5902c82aa8e082e8346c5de8 Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:49:00 +0700 Subject: [PATCH 13/14] HR --- src/views/SimproV2/ResourceWorker/index.js | 36 +++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/views/SimproV2/ResourceWorker/index.js b/src/views/SimproV2/ResourceWorker/index.js index e042b07..9219541 100644 --- a/src/views/SimproV2/ResourceWorker/index.js +++ b/src/views/SimproV2/ResourceWorker/index.js @@ -8,11 +8,19 @@ import moment from 'moment' import { Card, CardBody, CardHeader, Col, Row, Input } from 'reactstrap'; import { DownloadOutlined } from '@ant-design/icons'; import { NotificationContainer, NotificationManager } from 'react-notifications'; +import { useLocation } from "react-router-dom"; import { Pagination, Table, Button, Tooltip, Spin } from 'antd'; import { USER_ADD, USER_SEARCH, USER_EDIT, USER_DELETE, ROLE_SEARCH, DIVISI_SEARCH, USER_SHIFT_ADD, COMPANY_MANAGEMENT_LIST } from '../../../const/ApiConst'; import { useTranslation } from 'react-i18next'; +import { + formatNumber, + formatRupiah, + formatThousand, + renderFormatRupiah, + checkActMenup, +} from "../../../const/CustomFunc"; const ResourceWorker = ({ params, ...props }) => { let role_id = 0, user_id = 0, isLogin = false, token = '', company_id = 0, all_project = null, role_name = '', hierarchy = [], user_name = ''; @@ -28,7 +36,7 @@ const ResourceWorker = ({ params, ...props }) => { hierarchy = props.hierarchy; user_name = props.user_name; } - + const location = useLocation(); const HEADER = { headers: { "Content-Type": "application/json", @@ -547,14 +555,29 @@ const ResourceWorker = ({ params, ...props }) => { key: 'x', render: (text, record) => <> - + { + checkActMenup(location.pathname, 'update') ? + handleEdit(text)} className="fa fa-edit"> + : + null + } - + { + checkActMenup(location.pathname, 'delete') ? + handleDelete(text.id)} className="fa fa-trash"> + : + null + } - + { + checkActMenup(location.pathname, 'update') ? + handleSetWorker(text)} className="fa fa-key"> + : + null + } , }, @@ -638,7 +661,12 @@ const ResourceWorker = ({ params, ...props }) => { + { + checkActMenup(location.pathname, 'create') ? + : + null + } From 03fd2fe6f2dbc60b6a360c1f95d9a6a7f45a4c70 Mon Sep 17 00:00:00 2001 From: khaidralirahman Date: Tue, 5 Mar 2024 14:49:24 +0700 Subject: [PATCH 14/14] UOM --- src/views/SimproV2/Satuan/index.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/views/SimproV2/Satuan/index.js b/src/views/SimproV2/Satuan/index.js index ab81794..89cfad8 100644 --- a/src/views/SimproV2/Satuan/index.js +++ b/src/views/SimproV2/Satuan/index.js @@ -8,6 +8,14 @@ import { NotificationContainer, NotificationManager } from 'react-notifications' import { Pagination, Button, Tooltip } from 'antd'; import { SATUAN_ADD, SATUAN_EDIT, SATUAN_DELETE, SATUAN_SEARCH, COMPANY_MANAGEMENT_LIST } from '../../../const/ApiConst'; import { useTranslation } from 'react-i18next'; +import { useLocation } from "react-router-dom"; +import { + formatNumber, + formatRupiah, + formatThousand, + renderFormatRupiah, + checkActMenup, +} from "../../../const/CustomFunc"; const Satuan = ({ params, ...props }) => { @@ -24,7 +32,7 @@ const Satuan = ({ params, ...props }) => { hierarchy = props.hierarchy; user_name = props.user_name; } - + const location = useLocation(); const HEADER = { headers: { "Content-Type": "application/json", @@ -352,7 +360,12 @@ const Satuan = ({ params, ...props }) => { + { + checkActMenup(location.pathname, 'create') ? + : + null + } @@ -380,11 +393,21 @@ const Satuan = ({ params, ...props }) => { - handleDelete(n.id)}> + { + checkActMenup(location.pathname, 'delete') ? + handleDelete(n.id)}> + : + null + } - handleEdit(n)}> + { + checkActMenup(location.pathname, 'update') ? + handleEdit(n)}> + : + null + } {role_name === 'Super Admin' &&