desain dashboard, outlet, perusahaan, agen
This commit is contained in:
parent
7f080c735f
commit
d3705835bb
@ -1 +1,2 @@
|
|||||||
NEXT_PUBLIC_API_URL='https://api-silos-kpr.basys.co.id'
|
//NEXT_PUBLIC_API_URL='https://api-silos-kpr.basys.co.id'
|
||||||
|
NEXT_PUBLIC_API_URL='https://digital-attendance-api.basys.co.id'
|
168
package-lock.json
generated
168
package-lock.json
generated
@ -10,6 +10,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.3.0",
|
"@ant-design/icons": "^5.3.0",
|
||||||
"antd": "^5.12.5",
|
"antd": "^5.12.5",
|
||||||
|
"aos": "^3.0.0-beta.6",
|
||||||
|
"apexcharts": "^3.49.1",
|
||||||
"cookies-next": "^4.1.1",
|
"cookies-next": "^4.1.1",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"docxtemplater": "^3.40.0",
|
"docxtemplater": "^3.40.0",
|
||||||
@ -22,16 +24,15 @@
|
|||||||
"next": "14.2.15",
|
"next": "14.2.15",
|
||||||
"next-image-export-optimizer": "^1.12.3",
|
"next-image-export-optimizer": "^1.12.3",
|
||||||
"next-pwa": "^5.6.0",
|
"next-pwa": "^5.6.0",
|
||||||
"nextjs-toploader": "^1.6.6",
|
"nextjs-toploader": "^1.6.12",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
"react-apexcharts": "^1.4.1",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-hook-form": "^7.45.4",
|
"react-hook-form": "^7.45.4",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"sass": "^1.69.5",
|
"sass": "^1.69.5",
|
||||||
"styled-components": "^5.3.9",
|
"styled-components": "^5.3.9",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"zingchart": "^2.9.14",
|
|
||||||
"zingchart-react": "^3.2.0",
|
|
||||||
"zustand": "^4.4.7"
|
"zustand": "^4.4.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -3293,6 +3294,11 @@
|
|||||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@yr/monotone-cubic-spline": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA=="
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.13.0",
|
"version": "8.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz",
|
||||||
@ -3432,6 +3438,30 @@
|
|||||||
"react-dom": ">=16.9.0"
|
"react-dom": ">=16.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/aos": {
|
||||||
|
"version": "3.0.0-beta.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/aos/-/aos-3.0.0-beta.6.tgz",
|
||||||
|
"integrity": "sha512-VLWrpq8bfAWcetynVHMMrqdC+89Qq/Ym6UBJbHB4crIwp3RR8uq1dNGgsFzoDl03S43rlVMK+na3r5+oUCZsYw==",
|
||||||
|
"dependencies": {
|
||||||
|
"classlist-polyfill": "^1.2.0",
|
||||||
|
"lodash.debounce": "^4.0.8",
|
||||||
|
"lodash.throttle": "^4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/apexcharts": {
|
||||||
|
"version": "3.54.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.54.1.tgz",
|
||||||
|
"integrity": "sha512-E4et0h/J1U3r3EwS/WlqJCQIbepKbp6wGUmaAwJOMjHUP4Ci0gxanLa7FR3okx6p9coi4st6J853/Cb1NP0vpA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@yr/monotone-cubic-spline": "^1.0.3",
|
||||||
|
"svg.draggable.js": "^2.2.2",
|
||||||
|
"svg.easing.js": "^2.0.0",
|
||||||
|
"svg.filter.js": "^2.0.2",
|
||||||
|
"svg.pathmorphing.js": "^0.1.3",
|
||||||
|
"svg.resize.js": "^1.4.3",
|
||||||
|
"svg.select.js": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/archiver": {
|
"node_modules/archiver": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz",
|
||||||
@ -4198,6 +4228,11 @@
|
|||||||
"node": ">=6.0"
|
"node": ">=6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classlist-polyfill": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-GzIjNdcEtH4ieA2S8NmrSxv7DfEV5fmixQeyTmqmRmRJPGpRBaSnA2a0VrCjyT8iW8JjEdMbKzDotAJf+ajgaQ=="
|
||||||
|
},
|
||||||
"node_modules/classnames": {
|
"node_modules/classnames": {
|
||||||
"version": "2.5.1",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||||
@ -7138,6 +7173,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
||||||
"integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="
|
"integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.throttle": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
|
||||||
|
},
|
||||||
"node_modules/lodash.union": {
|
"node_modules/lodash.union": {
|
||||||
"version": "4.6.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
|
||||||
@ -8558,6 +8598,18 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-apexcharts": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-G14nVaD64Bnbgy8tYxkjuXEUp/7h30Q0U33xc3AwtGFijJB9nHqOt1a6eG0WBn055RgRg+NwqbKGtqPxy15d0Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"apexcharts": "^3.41.0",
|
||||||
|
"react": ">=0.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
@ -9651,6 +9703,89 @@
|
|||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svg.draggable.js": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.easing.js": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": ">=2.3.x"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.filter.js": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.2.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.js": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
|
||||||
|
},
|
||||||
|
"node_modules/svg.pathmorphing.js": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.resize.js": {
|
||||||
|
"version": "1.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
|
||||||
|
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.6.5",
|
||||||
|
"svg.select.js": "^2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.resize.js/node_modules/svg.select.js": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.2.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svg.select.js": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
|
||||||
|
"dependencies": {
|
||||||
|
"svg.js": "^2.6.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tapable": {
|
"node_modules/tapable": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||||
@ -10815,33 +10950,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/zingchart": {
|
|
||||||
"version": "2.9.15",
|
|
||||||
"resolved": "https://registry.npmjs.org/zingchart/-/zingchart-2.9.15.tgz",
|
|
||||||
"integrity": "sha512-o0doeMS5VxL+TsQXzkZzNuMBHzlw7wCG/1TN/wAXhs2QOnABfGGz6g4TFx+EMzZYaTx0ZRKM8B+fSYTlHRDu0A=="
|
|
||||||
},
|
|
||||||
"node_modules/zingchart-constants": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"resolved": "git+ssh://git@github.com/zingchart/zingchart-constants.git#37aaeb291bbaab2174d317c1182bbca6a8f70da5",
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/zingchart-react": {
|
|
||||||
"version": "3.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/zingchart-react/-/zingchart-react-3.2.0.tgz",
|
|
||||||
"integrity": "sha512-VTGhSBIUbbf5dLpVHxyoFRYB7rkx4umlhXKa6zJR0YjVu5tUE4pvogHu9lX5LjeTTXbPRW8quMqs+f+5d9juKw==",
|
|
||||||
"dependencies": {
|
|
||||||
"zingchart": "latest",
|
|
||||||
"zingchart-constants": "github:zingchart/zingchart-constants#master"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14",
|
|
||||||
"npm": ">=5"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">=15.0.0",
|
|
||||||
"react-dom": ">=15.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/zip-stream": {
|
"node_modules/zip-stream": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz",
|
||||||
|
13
package.json
13
package.json
@ -10,11 +10,9 @@
|
|||||||
"export": "next build && next-image-export-optimizer"
|
"export": "next build && next-image-export-optimizer"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18",
|
|
||||||
"react-dom": "^18",
|
|
||||||
"next": "14.2.15",
|
|
||||||
"@ant-design/icons": "^5.3.0",
|
"@ant-design/icons": "^5.3.0",
|
||||||
"antd": "^5.12.5",
|
"antd": "^5.12.5",
|
||||||
|
"aos": "^3.0.0-beta.6",
|
||||||
"cookies-next": "^4.1.1",
|
"cookies-next": "^4.1.1",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"docxtemplater": "^3.40.0",
|
"docxtemplater": "^3.40.0",
|
||||||
@ -24,17 +22,20 @@
|
|||||||
"html2canvas": "^1.4.1",
|
"html2canvas": "^1.4.1",
|
||||||
"jspdf": "^2.5.1",
|
"jspdf": "^2.5.1",
|
||||||
"jspdf-autotable": "^3.8.2",
|
"jspdf-autotable": "^3.8.2",
|
||||||
|
"next": "14.2.15",
|
||||||
"next-image-export-optimizer": "^1.12.3",
|
"next-image-export-optimizer": "^1.12.3",
|
||||||
"next-pwa": "^5.6.0",
|
"next-pwa": "^5.6.0",
|
||||||
"nextjs-toploader": "^1.6.6",
|
"nextjs-toploader": "^1.6.12",
|
||||||
|
"react": "^18",
|
||||||
|
"react-dom": "^18",
|
||||||
"react-hook-form": "^7.45.4",
|
"react-hook-form": "^7.45.4",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"sass": "^1.69.5",
|
"sass": "^1.69.5",
|
||||||
"styled-components": "^5.3.9",
|
"styled-components": "^5.3.9",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"zustand": "^4.4.7",
|
"zustand": "^4.4.7",
|
||||||
"zingchart": "^2.9.14",
|
"apexcharts": "^3.49.1",
|
||||||
"zingchart-react": "^3.2.0"
|
"react-apexcharts": "^1.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
.btn.btn-primary {
|
.btn.btn-primary {
|
||||||
color: var(--primary-inverse);
|
color: var(--primary-inverse);
|
||||||
border-color: var(--primary);
|
border: var(--bg-gradient-primary);
|
||||||
background-color: var(--primary);
|
background: var(--bg-gradient-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.btn-primary:hover,
|
.btn.btn-primary:hover,
|
||||||
@ -112,7 +112,8 @@
|
|||||||
height: 35px;
|
height: 35px;
|
||||||
padding: 0 28px;
|
padding: 0 28px;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -102,9 +102,10 @@
|
|||||||
|
|
||||||
.floating-label {
|
.floating-label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 15px;
|
left: 9px;
|
||||||
|
z-index: 111;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 0 7px;
|
padding: 0 7px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
@ -344,24 +344,37 @@
|
|||||||
|
|
||||||
|
|
||||||
.nav-account {
|
.nav-account {
|
||||||
position: relative;
|
|
||||||
//background: #efefef;
|
|
||||||
border-radius: 35px;
|
border-radius: 35px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 56px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0px 7px;
|
||||||
|
transition: 0.5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-account .container-account .account {
|
.nav-account .container-account .account {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: end;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
//background: rgba(255, 255, 255, 0);
|
|
||||||
padding: 8px 10px 8px 45px;
|
|
||||||
border-radius: 35px;
|
border-radius: 35px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: 0.5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-account .container-account .account .text {
|
.nav-account .container-account .account .text {
|
||||||
text-align: end;
|
text-align: start;
|
||||||
|
width: 0;
|
||||||
|
margin-left: -15px;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-account .container-account .account .text.active{
|
||||||
|
width: 100%;
|
||||||
|
margin-left: 10px;
|
||||||
|
opacity:1;
|
||||||
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-account .detail-account .header .text .name {
|
.nav-account .detail-account .header .text .name {
|
||||||
@ -405,26 +418,56 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-account .detail-account {
|
.nav-account .detail-account {
|
||||||
background: #fff;
|
|
||||||
height: 0;
|
|
||||||
right: 0;
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
background: #fff;
|
||||||
|
right: 0;
|
||||||
|
left: 65px;
|
||||||
|
top: -200px;
|
||||||
|
height: 270px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
top: 100%;
|
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
box-shadow: 0px 0px 50px 0px rgba(82, 63, 105, 0.15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-account .container-account:hover .detail-account {
|
.nav-account .detail-account.active {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
background: #fff;
|
||||||
|
right: 0;
|
||||||
|
left: 305px;
|
||||||
|
top: -200px;
|
||||||
|
height: 270px;
|
||||||
|
position: absolute;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-top: 10px;
|
||||||
|
min-width: 250px;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.nav-account:hover .detail-account {
|
||||||
height: auto;
|
height: auto;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
transition: all 0.5s ease;
|
transition: all 0.5s ease;
|
||||||
transform: translateY(-10px);
|
right: 0;
|
||||||
|
left: 55px;
|
||||||
|
top: -180px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-account:hover .detail-account.active {
|
||||||
|
height: auto;
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
right: 0;
|
||||||
|
left: 255px;
|
||||||
|
top: -180px;
|
||||||
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-account .detail-account .header {
|
.nav-account .detail-account .header {
|
||||||
@ -909,6 +952,7 @@
|
|||||||
height:35px;
|
height:35px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
|
right: 8px;
|
||||||
//background: #00000038;
|
//background: #00000038;
|
||||||
background: rgba(0, 0, 0, 0.1882352941);
|
background: rgba(0, 0, 0, 0.1882352941);
|
||||||
border-radius: 26px;
|
border-radius: 26px;
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
background:#d4e8ed;
|
background:#0179c217;
|
||||||
border-bottom: 1px solid #ffffff;
|
border-bottom: 1px solid #ffffff;
|
||||||
padding: 11px 16px;
|
padding: 11px 16px;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
:root {
|
:root {
|
||||||
--primary: #0179c2;
|
--primary: #0179c2;
|
||||||
|
--primary-dark: #01314e;
|
||||||
--success: #50cd89;
|
--success: #50cd89;
|
||||||
--info: #1a98ff;
|
--info: #1a98ff;
|
||||||
--warning: #FEB82F;
|
--warning: #FEB82F;
|
||||||
@ -7,7 +8,7 @@
|
|||||||
--secondary: #aaa;
|
--secondary: #aaa;
|
||||||
--dark: #181c32;
|
--dark: #181c32;
|
||||||
--dark-grey: #666;
|
--dark-grey: #666;
|
||||||
--primary-light: #9fd6ff;
|
--primary-light: #0179c217;
|
||||||
--secondary-light: #f9f9f9;
|
--secondary-light: #f9f9f9;
|
||||||
--success-light: #e8fff3;
|
--success-light: #e8fff3;
|
||||||
--info-light: #dbe8ff;
|
--info-light: #dbe8ff;
|
||||||
@ -15,7 +16,8 @@
|
|||||||
--danger-light: #fff5f8;
|
--danger-light: #fff5f8;
|
||||||
--dark-light: #e4e6e7;
|
--dark-light: #e4e6e7;
|
||||||
--white: #fff;
|
--white: #fff;
|
||||||
--text-muted: #9A9A9A;
|
--text-muted: #a9a9a9;
|
||||||
|
--text-muted-reverse: #ffffff85;
|
||||||
--success-inverse: #ffffff;
|
--success-inverse: #ffffff;
|
||||||
--info-inverse: #ffffff;
|
--info-inverse: #ffffff;
|
||||||
--warning-inverse: #ffffff;
|
--warning-inverse: #ffffff;
|
||||||
@ -53,16 +55,17 @@
|
|||||||
--color-step6:#326F71;
|
--color-step6:#326F71;
|
||||||
--color-step7:#1e5c6b;
|
--color-step7:#1e5c6b;
|
||||||
|
|
||||||
|
--color-logo-green: #61c300;
|
||||||
|
--color-logo-orange: #e77c01;
|
||||||
|
--color-logo-purple: #a800c1;
|
||||||
|
|
||||||
//--color-step1:#50cd89;
|
--bg-gradient-transaksi: linear-gradient(316deg, #17374b, var(--primary));
|
||||||
//--color-step2:#43af7f;
|
--bg-gradient-orange: linear-gradient(316deg, #17374b, var(--color-logo-orange));
|
||||||
//--color-step3:#369375;
|
--bg-gradient-green: linear-gradient(316deg, #17374b, var(--color-logo-green));
|
||||||
//--color-step4:#29776b;
|
--bg-gradient-purple: linear-gradient(316deg, #17374b, var(--color-logo-purple));
|
||||||
//--color-step5:#1e5c6b;
|
--bg-gradient-dark: linear-gradient(316deg, #17374b, var(--dark));
|
||||||
//--color-step6:#1c5064;
|
--bg-gradient-primary: linear-gradient(336deg, #0a3865, var(--primary));
|
||||||
//--color-step7:#19445e;
|
|
||||||
|
|
||||||
--bg-menu: linear-gradient(90deg, #003775 0%, #0057b9 104.42%);
|
|
||||||
--bg-sub-menu: #f8f8f840;
|
--bg-sub-menu: #f8f8f840;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +113,7 @@ button {
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
background: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-nav {
|
.bg-nav {
|
||||||
@ -131,6 +135,14 @@ body {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nextjs-toploader {
|
||||||
|
z-index: 9999;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.bg-nav-hov{
|
.bg-nav-hov{
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.7);
|
||||||
height: 100px;
|
height: 100px;
|
||||||
@ -140,6 +152,16 @@ body {
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-content{
|
||||||
|
background: #ffffffe0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 30px;
|
||||||
|
padding: 30px;
|
||||||
|
overflow: auto;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
// top: 10rem;
|
// top: 10rem;
|
||||||
@ -147,12 +169,14 @@ section {
|
|||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 15px 35px 150px;
|
padding: 15px 10px;
|
||||||
padding-left: 300px;
|
padding-left: 280px;
|
||||||
border-radius: 15px 15px 0 0;
|
border-radius: 20px;
|
||||||
transition: all 0.5s ease;
|
transition: all 0.5s ease;
|
||||||
background: #f3f3f3;
|
//background: #f3f3f3;
|
||||||
//background: url(/img/pat29.png);
|
background: url(/img/bg14.jpg);
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
box-shadow: 0px 0px 50px 0px rgba(82, 63, 105, 0.15);
|
box-shadow: 0px 0px 50px 0px rgba(82, 63, 105, 0.15);
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
height: 0;
|
height: 0;
|
||||||
@ -166,7 +190,7 @@ section {
|
|||||||
}
|
}
|
||||||
|
|
||||||
section.content.hover{
|
section.content.hover{
|
||||||
padding-left: 120px;
|
padding-left: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resultCard {
|
.resultCard {
|
||||||
@ -253,7 +277,6 @@ section.content.hover{
|
|||||||
color: var(--dark-grey);
|
color: var(--dark-grey);
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border: 0;
|
border: 0;
|
||||||
width: 100%;
|
|
||||||
/* border-top: 1px dashed #e7e7e7; */
|
/* border-top: 1px dashed #e7e7e7; */
|
||||||
outline: 0;
|
outline: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -614,7 +637,7 @@ section.content.hover{
|
|||||||
align-items: start;
|
align-items: start;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
margin-top: 10px;
|
margin-top: -45px;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
|
||||||
.breadCrumb {
|
.breadCrumb {
|
||||||
@ -1789,6 +1812,8 @@ hr.border{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.check-auth{
|
.check-auth{
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -1833,10 +1858,10 @@ hr.border{
|
|||||||
|
|
||||||
.side-menu-container{
|
.side-menu-container{
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 10px;
|
left: 14px;
|
||||||
z-index: 111;
|
z-index: 111;
|
||||||
height: 95vh;
|
height: 97vh;
|
||||||
top: 18px;
|
top: 14px;
|
||||||
//background: var(--primary);
|
//background: var(--primary);
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
background: linear-gradient(316deg, #17374b, var(--primary));
|
background: linear-gradient(316deg, #17374b, var(--primary));
|
||||||
@ -1858,7 +1883,7 @@ hr.border{
|
|||||||
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(0, 0, 0, 0.7) !important;
|
background-color: rgba(0, 0, 0, 0.2) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2399,3 +2424,11 @@ hr.border{
|
|||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-item,
|
||||||
|
.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-item,
|
||||||
|
.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-submenu-title,
|
||||||
|
.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-submenu-title {
|
||||||
|
padding: 0;
|
||||||
|
}
|
BIN
public/img/gedung.jpeg
Normal file
BIN
public/img/gedung.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 164 KiB |
@ -10,6 +10,7 @@ import {getCookie} from "cookies-next";
|
|||||||
import {LoadingOutlined} from "@ant-design/icons";
|
import {LoadingOutlined} from "@ant-design/icons";
|
||||||
import usePreventBackNavigation from "@/hooks/usePreventBackNavigation";
|
import usePreventBackNavigation from "@/hooks/usePreventBackNavigation";
|
||||||
import CheckAuth from "@/components/util/CheckAuth";
|
import CheckAuth from "@/components/util/CheckAuth";
|
||||||
|
import packageJson from "@@/package.json";
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
|
|
||||||
@ -37,10 +38,8 @@ export default function Login() {
|
|||||||
return setErrorLogin(result.message);
|
return setErrorLogin(result.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
await setAuth(result.token, result.users.id);
|
await setAuth(result.token, result.userId);
|
||||||
|
localStorage.setItem('user_roleId', result.roleId);
|
||||||
let userData = await API.GET('/ref/user/' + result?.users?.id)
|
|
||||||
localStorage.setItem('user_roleId', userData?.result?.users?.idBranch);
|
|
||||||
|
|
||||||
router.push("/main/dashboard");
|
router.push("/main/dashboard");
|
||||||
};
|
};
|
||||||
@ -104,7 +103,7 @@ export default function Login() {
|
|||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div className={"text-muted fw-light fs-7"} style={{position:"absolute",bottom:'20px',left:'20px'}}>v0.1.0</div>
|
<div className={"text-muted fw-light fs-7"} style={{position:"absolute",bottom:'20px',left:'20px'}}>v{packageJson.version}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
77
src/app/main/daftarAgen/CardAgen.jsx
Normal file
77
src/app/main/daftarAgen/CardAgen.jsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import {Col, Dropdown, Row} from "antd";
|
||||||
|
import "./style.scss";
|
||||||
|
import {CheckCircleOutlined, CloseCircleOutlined, ContainerOutlined, EditOutlined, SettingOutlined, UserOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
export default function CardAgen({data,modalOpen}) {
|
||||||
|
|
||||||
|
return (<Row gutter={[20, 5]}>
|
||||||
|
{data && data?.map((v, k) => {
|
||||||
|
|
||||||
|
let items = [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: (<button onClick={() => modalOpen(v?.karyawanId,'edit')} className="dropdown-item w-full">
|
||||||
|
<EditOutlined className="text-muted me-2"/>Ubah
|
||||||
|
</button>),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
label: (<button onClick={() => modalOpen(v?.karyawanId,'detail')} className="dropdown-item w-full">
|
||||||
|
<ContainerOutlined className="text-muted me-2"/>Detail
|
||||||
|
</button>),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (<Col key={k} xxl={6} span={8}>
|
||||||
|
<div className="card-karyawan">
|
||||||
|
<div className={"content-title"}>
|
||||||
|
<div className={"name"}>{v?.karyawanNm}</div>
|
||||||
|
<div className={"position"}>{v?.jabatanNm}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"container-karyawan"}>
|
||||||
|
<div className={"content-karyawan"}>
|
||||||
|
<div className={"title"}>ID</div>
|
||||||
|
<div className={"value"}>{v?.nik}</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content-karyawan"}>
|
||||||
|
<div className={"title"}>username</div>
|
||||||
|
<div className={"value"}>{v?.username}</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content-karyawan"}>
|
||||||
|
<div className={"title"}>telpon/hp</div>
|
||||||
|
<div className={"value"}>{v?.phoneNo}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"content-btn"}>
|
||||||
|
<Dropdown trigger={["click"]} placement="bottomLeft" arrow menu={{items}}>
|
||||||
|
<button type="button" className="btn btn-primary my-1 btn-sm" data-bs-toggle="dropdown">
|
||||||
|
<SettingOutlined/> Pengaturan
|
||||||
|
</button>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={`content-status ${(v?.isActive) ? 'bg-success-light' : 'bg-danger-light'}`}>
|
||||||
|
{(v?.isActive) ? <div className={"status-flag text-success"}>
|
||||||
|
<CheckCircleOutlined className="text-success me-2"/>
|
||||||
|
<div>Aktif</div>
|
||||||
|
</div> : <div className={"status-flag text-danger"}>
|
||||||
|
<CloseCircleOutlined className="text-danger me-2"/>
|
||||||
|
<div>Tidak Aktif</div>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
<div className={"content-foto"}>
|
||||||
|
{(v?.profilePict) ? <img alt={"agen"} className={"img"} src={v?.profilePict}/> : <UserOutlined className={"icon"}/>}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
|
</Row>)
|
||||||
|
}
|
96
src/app/main/daftarAgen/FormAgen.jsx
Normal file
96
src/app/main/daftarAgen/FormAgen.jsx
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import {Col, Modal, Row, Spin} from "antd";
|
||||||
|
import {CloseOutlined} from "@ant-design/icons";
|
||||||
|
import Input from "@/components/util/Input";
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import {useForm} from "react-hook-form";
|
||||||
|
import {Helper} from "@/lib/Helper";
|
||||||
|
import {DropdownAPI} from "@/lib/DropdownAPI";
|
||||||
|
|
||||||
|
export default function FormAgen({modalStatus, actClose, data, loadingModal,jenis}) {
|
||||||
|
const [viewReadonly, setViewReadonly] = useState(false)
|
||||||
|
const [dropdownLoading, setDropdownLoading] = useState(false)
|
||||||
|
const [dropdown, setDropdown] = useState(
|
||||||
|
{
|
||||||
|
roleId : [],
|
||||||
|
branchId : [],
|
||||||
|
jabatanId : [],
|
||||||
|
jenisKelaminId : [],
|
||||||
|
agamaId : [],
|
||||||
|
statusAgenId : []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const {
|
||||||
|
register, setValue, watch, getValues, formState: {errors},
|
||||||
|
} = useForm();
|
||||||
|
|
||||||
|
const dropdownInit = async () => {
|
||||||
|
setDropdownLoading(true)
|
||||||
|
let listRole = await DropdownAPI.role();
|
||||||
|
|
||||||
|
setDropdownLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeAction = () => {
|
||||||
|
if(jenis === 'detail'){
|
||||||
|
return(
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
return(
|
||||||
|
<button className="btn btn-primary btn-sm">Simpan</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (jenis === 'detail'){
|
||||||
|
setViewReadonly(true);
|
||||||
|
}else{
|
||||||
|
|
||||||
|
setViewReadonly(false);
|
||||||
|
}
|
||||||
|
}, [jenis]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data){
|
||||||
|
setValue('karyawanNm',data?.karyawanNm)
|
||||||
|
setValue('roleId',data?.roleId)
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dropdownInit()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (<Modal centered closeIcon={false} open={modalStatus} width={"800px"} footer={null}>
|
||||||
|
<Spin spinning={loadingModal}>
|
||||||
|
<div className="btn btn-circle btn-light-primary zn-close" onClick={actClose}>
|
||||||
|
<CloseOutlined/>
|
||||||
|
</div>
|
||||||
|
<div className="px-6 py-4 cardDark">
|
||||||
|
<div className="fs-6 fw-bolder text-uppercase text-primary">Data Agen</div>
|
||||||
|
<div className="fs-7 fw-ligth text-muted">Data Agen</div>
|
||||||
|
<div className="separator my-3"/>
|
||||||
|
<div style={{overflowY:'auto',overflowX:'hidden',height:'600px'}} className="my-4 p-2">
|
||||||
|
<Row gutter={15}>
|
||||||
|
<Col span={6}>
|
||||||
|
<Input.Text title={"Nama Agen"} name={"karyawanNm"} minlength={"15"} maxlength={"100"} setReadonly={viewReadonly} required register={register} error={errors}/>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="card-footer text-right py-3 px-5 zn-bg-modal">
|
||||||
|
<TypeAction/>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
251
src/app/main/daftarAgen/page.jsx
Normal file
251
src/app/main/daftarAgen/page.jsx
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
"use client"
|
||||||
|
import SearchInput from "@/components/util/SearchInput";
|
||||||
|
import WrapperContent from "@/components/util/WrapperContent";
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import CardAgen from "./CardAgen";
|
||||||
|
import {API} from "@/lib/API";
|
||||||
|
import notifStore from "@/store/notifStore";
|
||||||
|
import FormAgen from "@/app/main/daftarAgen/FormAgen";
|
||||||
|
import {ReloadOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
export default function DaftarAgen() {
|
||||||
|
const {notifOpen} = notifStore()
|
||||||
|
const [searchText, setSearchText] = useState(null)
|
||||||
|
const [dataAgen, setDataAgen] = useState([])
|
||||||
|
const [modalAgen, setModalAgen] = useState({
|
||||||
|
loadingModal: false, modalStatus: false, jenis: null, data: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSearch = (event) => {
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setSearchText(event.target.value);
|
||||||
|
}, 1000);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAgen = async () => {
|
||||||
|
// let res = await API.GET('/ref/karyawan')
|
||||||
|
// if (res.status !== 200) {
|
||||||
|
// notifOpen("Gagal", res.result.message, "danger");
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
|
||||||
|
let dummyData = {
|
||||||
|
"page": 0,
|
||||||
|
"size": 1,
|
||||||
|
"totalPages": 1,
|
||||||
|
"totalElements": 1,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"karyawanId": 3,
|
||||||
|
"profilePict": null,
|
||||||
|
"username": "karyawanbackend",
|
||||||
|
"roleId": 4,
|
||||||
|
"roleNm": "Backend Developer",
|
||||||
|
"isActive": true,
|
||||||
|
"statusUserId": 2,
|
||||||
|
"statusUserNm": "Baru",
|
||||||
|
"jenisKelaminId": 1,
|
||||||
|
"jenisKelaminNm": "Laki-laki",
|
||||||
|
"email": "karyawanbackend@basys.co.id",
|
||||||
|
"phoneNo": "085300000003",
|
||||||
|
"companyId": 1,
|
||||||
|
"companyNm": "PT Bayu Sinergi Solusi",
|
||||||
|
"branchId": 1,
|
||||||
|
"branchCode": "001",
|
||||||
|
"branchNm": "Cabang Utama PT. Basys",
|
||||||
|
"divisiId": 1,
|
||||||
|
"divisiNm": "Backend Developer",
|
||||||
|
"jabatanId": 1,
|
||||||
|
"jabatanNm": "Outlet Alzam Store",
|
||||||
|
"statusAgenId": 1,
|
||||||
|
"statusAgenNm": "Pegawai Tetap",
|
||||||
|
"spvId": null,
|
||||||
|
"spvUsername": null,
|
||||||
|
"spvNm": null,
|
||||||
|
"recognizeId": "e12ff5c2-919b-4e40-8841-3b876696d619",
|
||||||
|
"hasRecognized": false,
|
||||||
|
"nik": "0000000000000002",
|
||||||
|
"nip": "0000000000000002",
|
||||||
|
"npwp": 2,
|
||||||
|
"birthPlace": "Kota Bandung",
|
||||||
|
"birthDt": "2000-09-17",
|
||||||
|
"address": "Jalan Jalan 2",
|
||||||
|
"tanggalBekerja": "2023-01-01",
|
||||||
|
"agamaId": 1,
|
||||||
|
"agamaNm": "Islam",
|
||||||
|
"tanggalBerhentiBekerja": null,
|
||||||
|
"userCrtId": 1,
|
||||||
|
"userCrtNm": "Webmin Basys",
|
||||||
|
"userCrtUsername": "webminbasys",
|
||||||
|
"userUpdtId": 1,
|
||||||
|
"userUpdtNm": "Webmin Basys",
|
||||||
|
"userUpdtUsername": "webminbasys",
|
||||||
|
"crtdt": "2024-07-31 11:28:26",
|
||||||
|
"uptdt": "2024-07-31 11:28:26",
|
||||||
|
"karyawanNm": "Nama Agen A"
|
||||||
|
}, {
|
||||||
|
"karyawanId": 3,
|
||||||
|
"profilePict": null,
|
||||||
|
"username": "karyawanbackend",
|
||||||
|
"roleId": 4,
|
||||||
|
"roleNm": "Backend Developer",
|
||||||
|
"isActive": true,
|
||||||
|
"statusUserId": 2,
|
||||||
|
"statusUserNm": "Baru",
|
||||||
|
"jenisKelaminId": 1,
|
||||||
|
"jenisKelaminNm": "Laki-laki",
|
||||||
|
"email": "karyawanbackend@basys.co.id",
|
||||||
|
"phoneNo": "085300000003",
|
||||||
|
"companyId": 1,
|
||||||
|
"companyNm": "PT Bayu Sinergi Solusi",
|
||||||
|
"branchId": 1,
|
||||||
|
"branchCode": "001",
|
||||||
|
"branchNm": "Cabang Utama PT. Basys",
|
||||||
|
"divisiId": 1,
|
||||||
|
"divisiNm": "Backend Developer",
|
||||||
|
"jabatanId": 1,
|
||||||
|
"jabatanNm": "Outlet Alzam Store",
|
||||||
|
"statusAgenId": 1,
|
||||||
|
"statusAgenNm": "Pegawai Tetap",
|
||||||
|
"spvId": null,
|
||||||
|
"spvUsername": null,
|
||||||
|
"spvNm": null,
|
||||||
|
"recognizeId": "e12ff5c2-919b-4e40-8841-3b876696d619",
|
||||||
|
"hasRecognized": false,
|
||||||
|
"nik": "0000000000000002",
|
||||||
|
"nip": "0000000000000002",
|
||||||
|
"npwp": 2,
|
||||||
|
"birthPlace": "Kota Bandung",
|
||||||
|
"birthDt": "2000-09-17",
|
||||||
|
"address": "Jalan Jalan 2",
|
||||||
|
"tanggalBekerja": "2023-01-01",
|
||||||
|
"agamaId": 1,
|
||||||
|
"agamaNm": "Islam",
|
||||||
|
"tanggalBerhentiBekerja": null,
|
||||||
|
"userCrtId": 1,
|
||||||
|
"userCrtNm": "Webmin Basys",
|
||||||
|
"userCrtUsername": "webminbasys",
|
||||||
|
"userUpdtId": 1,
|
||||||
|
"userUpdtNm": "Webmin Basys",
|
||||||
|
"userUpdtUsername": "webminbasys",
|
||||||
|
"crtdt": "2024-07-31 11:28:26",
|
||||||
|
"uptdt": "2024-07-31 11:28:26",
|
||||||
|
"karyawanNm": "Nama Agen A"
|
||||||
|
}, {
|
||||||
|
"karyawanId": 3,
|
||||||
|
"profilePict": null,
|
||||||
|
"username": "karyawanbackend",
|
||||||
|
"roleId": 4,
|
||||||
|
"roleNm": "Backend Developer",
|
||||||
|
"isActive": true,
|
||||||
|
"statusUserId": 2,
|
||||||
|
"statusUserNm": "Baru",
|
||||||
|
"jenisKelaminId": 1,
|
||||||
|
"jenisKelaminNm": "Laki-laki",
|
||||||
|
"email": "karyawanbackend@basys.co.id",
|
||||||
|
"phoneNo": "085300000003",
|
||||||
|
"companyId": 1,
|
||||||
|
"companyNm": "PT Bayu Sinergi Solusi",
|
||||||
|
"branchId": 1,
|
||||||
|
"branchCode": "001",
|
||||||
|
"branchNm": "Cabang Utama PT. Basys",
|
||||||
|
"divisiId": 1,
|
||||||
|
"divisiNm": "Backend Developer",
|
||||||
|
"jabatanId": 1,
|
||||||
|
"jabatanNm": "Outlet Alzam Store",
|
||||||
|
"statusAgenId": 1,
|
||||||
|
"statusAgenNm": "Pegawai Tetap",
|
||||||
|
"spvId": null,
|
||||||
|
"spvUsername": null,
|
||||||
|
"spvNm": null,
|
||||||
|
"recognizeId": "e12ff5c2-919b-4e40-8841-3b876696d619",
|
||||||
|
"hasRecognized": false,
|
||||||
|
"nik": "0000000000000002",
|
||||||
|
"nip": "0000000000000002",
|
||||||
|
"npwp": 2,
|
||||||
|
"birthPlace": "Kota Bandung",
|
||||||
|
"birthDt": "2000-09-17",
|
||||||
|
"address": "Jalan Jalan 2",
|
||||||
|
"tanggalBekerja": "2023-01-01",
|
||||||
|
"agamaId": 1,
|
||||||
|
"agamaNm": "Islam",
|
||||||
|
"tanggalBerhentiBekerja": null,
|
||||||
|
"userCrtId": 1,
|
||||||
|
"userCrtNm": "Webmin Basys",
|
||||||
|
"userCrtUsername": "webminbasys",
|
||||||
|
"userUpdtId": 1,
|
||||||
|
"userUpdtNm": "Webmin Basys",
|
||||||
|
"userUpdtUsername": "webminbasys",
|
||||||
|
"crtdt": "2024-07-31 11:28:26",
|
||||||
|
"uptdt": "2024-07-31 11:28:26",
|
||||||
|
"karyawanNm": "Nama Agen A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// setDataAgen(res.result.data)
|
||||||
|
setDataAgen(dummyData.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalOpen = async (id, type) => {
|
||||||
|
setModalAgen(prev => ({
|
||||||
|
...prev, modalStatus: true, jenis: type, loadingModal: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
let res = await API.GET('/ref/karyawan/' + id)
|
||||||
|
|
||||||
|
setModalAgen(prev => ({
|
||||||
|
...prev, data: res.result, loadingModal: false
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getAgen()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<WrapperContent>
|
||||||
|
<div className="containers">
|
||||||
|
<div className="headContent">
|
||||||
|
<div className="containerTitle">
|
||||||
|
<div className="breadCrumb">
|
||||||
|
<div className="text">Data Agen</div>
|
||||||
|
<div className="text">Daftar Agen</div>
|
||||||
|
</div>
|
||||||
|
<div className="title text-dark-grey left">Daftar Agen</div>
|
||||||
|
</div>
|
||||||
|
<div className="filter mb-3">
|
||||||
|
<SearchInput handleSearch={handleSearch} style={{marginRight: "10px"}}/>
|
||||||
|
<button type="button" className="btn btn-primary" onClick={() => modalOpen(null, 'tambah')}>Registrasi Agen</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-circle btn-light-primary"
|
||||||
|
onClick={() => getAgen()}
|
||||||
|
>
|
||||||
|
<ReloadOutlined/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bodyContent">
|
||||||
|
<CardAgen modalOpen={modalOpen} data={dataAgen}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</WrapperContent>
|
||||||
|
<FormAgen
|
||||||
|
loadingModal={modalAgen?.loadingModal}
|
||||||
|
modalStatus={modalAgen?.modalStatus}
|
||||||
|
jenis={modalAgen?.jenis}
|
||||||
|
actClose={() => {
|
||||||
|
setModalAgen(prev => ({
|
||||||
|
...prev, modalStatus: false, loadingModal: false
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
data={modalAgen?.data}/>
|
||||||
|
</>)
|
||||||
|
}
|
80
src/app/main/daftarAgen/style.scss
Normal file
80
src/app/main/daftarAgen/style.scss
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
.card-karyawan{
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 25px;
|
||||||
|
box-shadow: 0px 8px 50px rgb(0 0 0 / 8%);
|
||||||
|
margin-top: 15px;
|
||||||
|
transition: 0.5s ease-in-out;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
box-shadow: 0px 25px 50px rgb(0 0 0 / 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-title{
|
||||||
|
background: #f7f7f7;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
width: 60%;
|
||||||
|
|
||||||
|
.name{
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--dark);
|
||||||
|
}
|
||||||
|
.position{
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-karyawan{
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-karyawan{
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.title{
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
.value{
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #0c111c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-status{
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 20px;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 3px 30px 3px 10px;
|
||||||
|
|
||||||
|
.status-flag{
|
||||||
|
display: flex;
|
||||||
|
gap: 0px;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-foto{
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
right: 5px;
|
||||||
|
|
||||||
|
.icon{
|
||||||
|
font-size: 180px;
|
||||||
|
color: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
.img{
|
||||||
|
width: 150px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
80
src/app/main/daftarOutlet/CardOutlet.jsx
Normal file
80
src/app/main/daftarOutlet/CardOutlet.jsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import {Col, Dropdown, Row} from "antd";
|
||||||
|
import "./style.scss";
|
||||||
|
import {CheckCircleOutlined, CloseCircleOutlined, ContainerOutlined, DeleteOutlined, EditOutlined, SettingOutlined, UserOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
export default function CardOutlet({data,modalOpen, deleteData}) {
|
||||||
|
|
||||||
|
return (<Row gutter={[20, 5]}>
|
||||||
|
{data && data?.map((v, k) => {
|
||||||
|
|
||||||
|
let items = [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: (<button onClick={() => modalOpen(v?.branchId,'edit')} className="dropdown-item w-full">
|
||||||
|
<EditOutlined className="text-muted me-2"/>Ubah
|
||||||
|
</button>),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
label: (<button onClick={() => modalOpen(v?.branchId,'detail')} className="dropdown-item w-full">
|
||||||
|
<ContainerOutlined className="text-muted me-2"/>Detail
|
||||||
|
</button>),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '3',
|
||||||
|
label: (<button onClick={() => deleteData(v?.branchId)} className="dropdown-item w-full">
|
||||||
|
<DeleteOutlined className="text-muted me-2"/>Hapus
|
||||||
|
</button>),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (<Col key={k} xxl={8} span={12}>
|
||||||
|
<div className="card-branch">
|
||||||
|
|
||||||
|
<div className={`content-status ${(v?.isActive) ? 'bg-success-light' : 'bg-danger-light'}`}>
|
||||||
|
{(v?.isActive) ? <div className={"status-flag text-success"}>
|
||||||
|
<CheckCircleOutlined className="text-success me-2"/>
|
||||||
|
<div>Aktif</div>
|
||||||
|
</div> : <div className={"status-flag text-danger"}>
|
||||||
|
<CloseCircleOutlined className="text-danger me-2"/>
|
||||||
|
<div>Tidak Aktif</div>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className={"content-title"}>
|
||||||
|
<div className={"fs-7 text-muted text-uppercase"}>Perusahaan A</div>
|
||||||
|
<div className={"name"}>Nama Outlet A</div>
|
||||||
|
<div className={"position"}>{v?.address}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className={"content-btn"}>
|
||||||
|
<Dropdown trigger={["click"]} placement="bottomLeft" arrow menu={{items}}>
|
||||||
|
<button type="button" className="btn btn-primary my-1 btn-sm" data-bs-toggle="dropdown">
|
||||||
|
<SettingOutlined/> Pengaturan
|
||||||
|
</button>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"content-detail"}>
|
||||||
|
<div className={"content-branch"}>
|
||||||
|
<div className={"title"}>Jenis Outlet</div>
|
||||||
|
<div className={"value"}>Jenis Outlet A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content-branch"}>
|
||||||
|
<div className={"title"}>Penanggungjawab</div>
|
||||||
|
<div className={"value"}>Zamzam Nurzaman</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
|
</Row>)
|
||||||
|
}
|
194
src/app/main/daftarOutlet/FormOutlet.jsx
Normal file
194
src/app/main/daftarOutlet/FormOutlet.jsx
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
import { Col, Modal, Row, Spin } from "antd";
|
||||||
|
import { CloseOutlined } from "@ant-design/icons";
|
||||||
|
import Input from "@/components/util/Input";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
|
|
||||||
|
let timer;
|
||||||
|
export default function FormOutlet({
|
||||||
|
modalStatus,
|
||||||
|
actClose, actStoreData,
|
||||||
|
data,
|
||||||
|
loadingModal,
|
||||||
|
jenis,
|
||||||
|
}) {
|
||||||
|
|
||||||
|
|
||||||
|
const [viewReadonly, setViewReadonly] = useState(false);
|
||||||
|
const [latlon, setLatlon] = useState(null);
|
||||||
|
const [showMap, setShowMap] = useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
setValue,
|
||||||
|
watch,
|
||||||
|
getValues,
|
||||||
|
reset,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm();
|
||||||
|
|
||||||
|
const TypeAction = () => {
|
||||||
|
if (jenis === "detail") {
|
||||||
|
return <></>;
|
||||||
|
} else {
|
||||||
|
return <button className="btn btn-primary btn-sm" onClick={handleSubmit(onSubmit)}>Simpan</button>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (data) => {
|
||||||
|
actStoreData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (jenis === "detail") {
|
||||||
|
setViewReadonly(true);
|
||||||
|
} else {
|
||||||
|
setViewReadonly(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}, [jenis]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
console.log(data)
|
||||||
|
setValue('address',data.address)
|
||||||
|
setValue('picNm', data.picNm)
|
||||||
|
setValue('phoneNo', data.phoneNo)
|
||||||
|
setValue('lat', data.lat)
|
||||||
|
setValue('lon', data.lon)
|
||||||
|
setValue('companyNm', data.companyNm)
|
||||||
|
setValue('wilayahId', data?.wilayah?.wilayahId)
|
||||||
|
setValue('companyId', data.companyId)
|
||||||
|
|
||||||
|
setLatlon({
|
||||||
|
lat: data.lat,
|
||||||
|
lon: data.lon
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (modalStatus === true){
|
||||||
|
setLatlon(null)
|
||||||
|
reset()
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
setShowMap(true);
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [modalStatus]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLatlon({
|
||||||
|
lat: watch('lat'),
|
||||||
|
lon:watch('lon')
|
||||||
|
})
|
||||||
|
}, [watch('lat')]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
centered
|
||||||
|
closeIcon={false}
|
||||||
|
open={modalStatus}
|
||||||
|
width={"600px"}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<Spin spinning={loadingModal}>
|
||||||
|
<div
|
||||||
|
className="btn btn-circle btn-light-primary zn-close"
|
||||||
|
onClick={actClose}
|
||||||
|
>
|
||||||
|
<CloseOutlined />
|
||||||
|
</div>
|
||||||
|
<div className="px-6 py-4 cardDark">
|
||||||
|
<div className="fs-6 fw-bolder text-uppercase text-primary">
|
||||||
|
Data Outlet
|
||||||
|
</div>
|
||||||
|
<div className="fs-7 fw-ligth text-muted">Data Outlet</div>
|
||||||
|
<div className="separator my-3" />
|
||||||
|
<div
|
||||||
|
style={{ overflowY: "auto", overflowX: "hidden", height: "600px" }}
|
||||||
|
className="my-4 p-2"
|
||||||
|
>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Row gutter={15}>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.Text
|
||||||
|
title={"Nama Outlet"}
|
||||||
|
name={"companyNm"}
|
||||||
|
minlength={"15"}
|
||||||
|
maxlength={"200"}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.Textarea
|
||||||
|
title={"Alamat"}
|
||||||
|
name={"address"}
|
||||||
|
maxlength={"200"}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.Number
|
||||||
|
title={"No HP"}
|
||||||
|
name={"phoneNo"}
|
||||||
|
minlength={"10"}
|
||||||
|
maxlength={"15"}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.Text
|
||||||
|
title={"Penanggungjawab"}
|
||||||
|
name={"picNm"}
|
||||||
|
minlength={"15"}
|
||||||
|
maxlength={"200"}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.SelectRemote
|
||||||
|
title={"Wilayah"}
|
||||||
|
name={"wilayahId"}
|
||||||
|
endPoint={"/ref/wilayah"}
|
||||||
|
val={getValues("wilayahId")}
|
||||||
|
setValue={setValue}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Row>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-footer text-right py-3 px-5 zn-bg-modal">
|
||||||
|
<TypeAction />
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
185
src/app/main/daftarOutlet/page.jsx
Normal file
185
src/app/main/daftarOutlet/page.jsx
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
"use client"
|
||||||
|
import SearchInput from "@/components/util/SearchInput";
|
||||||
|
import WrapperContent from "@/components/util/WrapperContent";
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import CardOutlet from "./CardOutlet";
|
||||||
|
import {API} from "@/lib/API";
|
||||||
|
import notifStore from "@/store/notifStore";
|
||||||
|
import FormOutlet from "./FormOutlet";
|
||||||
|
import {ReloadOutlined} from "@ant-design/icons";
|
||||||
|
import {Pagination} from "antd";
|
||||||
|
import confirmStore from "@/store/confirmStore";
|
||||||
|
import "./style.scss"
|
||||||
|
|
||||||
|
export default function DaftarOutlet() {
|
||||||
|
const {notifOpen} = notifStore()
|
||||||
|
const {confirmOpen, confirmClose, setConfirmLoading} = confirmStore();
|
||||||
|
|
||||||
|
const [searchText, setSearchText] = useState(null)
|
||||||
|
const [currentPage, setCurrentPage] = useState(1)
|
||||||
|
|
||||||
|
const [dataCabang, setDataCabang] = useState([])
|
||||||
|
const [modalCabang, setModalCabang] = useState({
|
||||||
|
loadingModal:false,
|
||||||
|
modalStatus:false,
|
||||||
|
jenis:null,
|
||||||
|
data:[]
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSearch = (event) => {
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setSearchText(event.target.value);
|
||||||
|
}, 1000);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCabang = async (page,size) => {
|
||||||
|
let setPage = (page) ? page : 0;
|
||||||
|
let setSize = (size) ? size : 6;
|
||||||
|
let res = await API.GET(`/ref/branch?page=${setPage}&size=${setSize}`)
|
||||||
|
if(res.status !== 200){
|
||||||
|
notifOpen("Gagal", res.result.message, "danger");
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
setDataCabang(res.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalOpen = async (id,type) => {
|
||||||
|
|
||||||
|
if (type === 'tambah'){
|
||||||
|
setModalCabang(prev => ({
|
||||||
|
...prev,
|
||||||
|
modalStatus: true,
|
||||||
|
jenis: type,
|
||||||
|
data:null
|
||||||
|
}));
|
||||||
|
|
||||||
|
}else{
|
||||||
|
setModalCabang(prev => ({
|
||||||
|
...prev,
|
||||||
|
modalStatus: true,
|
||||||
|
jenis: type,
|
||||||
|
loadingModal: true
|
||||||
|
}));
|
||||||
|
let res = await API.GET('/ref/branch/' + id)
|
||||||
|
setModalCabang(prev => ({
|
||||||
|
...prev,
|
||||||
|
data: res.result,
|
||||||
|
loadingModal: false
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeData = async (data) => {
|
||||||
|
let res = await API.POST('/ref/branch', data)
|
||||||
|
if (res.status === 200) {
|
||||||
|
setModalCabang(prev => ({
|
||||||
|
...prev,
|
||||||
|
modalStatus: false,
|
||||||
|
}));
|
||||||
|
|
||||||
|
notifOpen("Berhasil", res.result.message);
|
||||||
|
await getCabang();
|
||||||
|
setCurrentPage(1)
|
||||||
|
} else {
|
||||||
|
notifOpen("Gagal", res.result.message, "danger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteData = async (id) => {
|
||||||
|
confirmOpen("Hapus Data", "Yakin Hapus Data Ini", async () => {
|
||||||
|
setConfirmLoading(true);
|
||||||
|
let response = await API.DELETE(`/ref/branch/${id}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
notifOpen("Berhasil", "berhasil hapus data");
|
||||||
|
await getCabang();
|
||||||
|
setConfirmLoading(false);
|
||||||
|
confirmClose();
|
||||||
|
setCurrentPage(1)
|
||||||
|
} else {
|
||||||
|
console.log(response);
|
||||||
|
setConfirmLoading(false);
|
||||||
|
notifOpen("Gagal", response.result.message, "danger");
|
||||||
|
confirmClose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangePage = (page, pageSize) => {
|
||||||
|
console.log({page, pageSize})
|
||||||
|
setCurrentPage(page)
|
||||||
|
getCabang(page-1,pageSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChangePageSize = (current, size) => {
|
||||||
|
console.log({current, size})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getCabang()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return(<>
|
||||||
|
<WrapperContent>
|
||||||
|
<div className="containers">
|
||||||
|
<div className="headContent">
|
||||||
|
<div className="containerTitle">
|
||||||
|
<div className="breadCrumb">
|
||||||
|
<div className="text">Data Outlet</div>
|
||||||
|
<div className="text">Daftar Outlet</div>
|
||||||
|
</div>
|
||||||
|
<div className="title text-dark-grey left">Daftar Outlet</div>
|
||||||
|
</div>
|
||||||
|
<div className="filter mb-3">
|
||||||
|
<SearchInput handleSearch={handleSearch} style={{marginRight: "10px"}}/>
|
||||||
|
<button type="button" className="btn btn-primary" onClick={() => modalOpen(null,'tambah')}>Registrasi Outlet</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-circle btn-light-primary"
|
||||||
|
onClick={() => getCabang()}
|
||||||
|
>
|
||||||
|
<ReloadOutlined/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bodyContent">
|
||||||
|
<CardOutlet modalOpen={modalOpen} deleteData={deleteData} data={dataCabang?.data}/>
|
||||||
|
<Pagination
|
||||||
|
style={{marginTop:'30px',borderRadius:'20px',padding:'10px'}}
|
||||||
|
align="center"
|
||||||
|
total={dataCabang?.totalElements}
|
||||||
|
showTotal={(total,range) => `${range[0]}-${range[1]} dari ${total} Data`}
|
||||||
|
defaultPageSize={6}
|
||||||
|
pageSizeOptions={['6', '12', '24']}
|
||||||
|
showSizeChanger={true}
|
||||||
|
defaultCurrent={1}
|
||||||
|
current={currentPage}
|
||||||
|
onChange={onChangePage}
|
||||||
|
onShowSizeChange={onChangePageSize}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</WrapperContent>
|
||||||
|
<FormOutlet
|
||||||
|
loadingModal={modalCabang?.loadingModal}
|
||||||
|
modalStatus={modalCabang?.modalStatus}
|
||||||
|
jenis={modalCabang?.jenis}
|
||||||
|
actClose={()=>{
|
||||||
|
setModalCabang(prev => ({
|
||||||
|
...prev,
|
||||||
|
modalStatus: false,
|
||||||
|
loadingModal: false
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
actStoreData={storeData}
|
||||||
|
data={modalCabang?.data} />
|
||||||
|
</>)
|
||||||
|
}
|
95
src/app/main/daftarOutlet/style.scss
Normal file
95
src/app/main/daftarOutlet/style.scss
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
.card-branch{
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px 10px;
|
||||||
|
border-radius: 25px;
|
||||||
|
box-shadow: 0px 8px 50px rgb(0 0 0 / 8%);
|
||||||
|
margin-top: 15px;
|
||||||
|
transition: 0.5s ease-in-out;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
box-shadow: 0px 25px 50px rgb(0 0 0 / 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-detail{
|
||||||
|
text-align: right;
|
||||||
|
background: #F1F1F1;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-title{
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.name{
|
||||||
|
margin-top: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--dark);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.position{
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-branch{
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-branch{
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.title{
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
.value{
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #0c111c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-status{
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
left: 30px;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 3px 30px 3px 10px;
|
||||||
|
|
||||||
|
.status-flag{
|
||||||
|
display: flex;
|
||||||
|
gap: 0px;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-foto{
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
border-radius: 25px;
|
||||||
|
|
||||||
|
.icon{
|
||||||
|
font-size: 180px;
|
||||||
|
color: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
.img{
|
||||||
|
width: 170px;
|
||||||
|
height: 250px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 0 25px 100px 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
79
src/app/main/daftarPerusahaan/CardPerusahaan.jsx
Normal file
79
src/app/main/daftarPerusahaan/CardPerusahaan.jsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import {Col, Dropdown, Row} from "antd";
|
||||||
|
import "./style.scss";
|
||||||
|
import {CheckCircleOutlined, CloseCircleOutlined, ContainerOutlined, DeleteOutlined, EditOutlined, SettingOutlined, UserOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
export default function CardPerusahaan({data,modalOpen, deleteData}) {
|
||||||
|
|
||||||
|
return (<Row gutter={[20, 5]}>
|
||||||
|
{data && data?.map((v, k) => {
|
||||||
|
|
||||||
|
let items = [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: (<button onClick={() => modalOpen(v?.companyId,'edit')} className="dropdown-item w-full">
|
||||||
|
<EditOutlined className="text-muted me-2"/>Ubah
|
||||||
|
</button>),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
label: (<button onClick={() => modalOpen(v?.companyId,'detail')} className="dropdown-item w-full">
|
||||||
|
<ContainerOutlined className="text-muted me-2"/>Detail
|
||||||
|
</button>),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '3',
|
||||||
|
label: (<button onClick={() => deleteData(v?.companyId)} className="dropdown-item w-full">
|
||||||
|
<DeleteOutlined className="text-muted me-2"/>Hapus
|
||||||
|
</button>),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (<Col key={k} xxl={8} span={12}>
|
||||||
|
<div className="card-company">
|
||||||
|
<div className={"content-title"}>
|
||||||
|
<div className={"name"}>{v?.companyNm}</div>
|
||||||
|
<div className={"position"}>{v?.address}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"container-company"}>
|
||||||
|
<div className={"content-company"}>
|
||||||
|
<div className={"title"}>Jenis Perusahaan</div>
|
||||||
|
<div className={"value"}>PT (Perseroan Terbatas)</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content-company"}>
|
||||||
|
<div className={"title"}>Jenis Bisnis</div>
|
||||||
|
<div className={"value"}>Perdagangan</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"content-btn"}>
|
||||||
|
<Dropdown trigger={["click"]} placement="bottomLeft" arrow menu={{items}}>
|
||||||
|
<button type="button" className="btn btn-primary my-1 btn-sm" data-bs-toggle="dropdown">
|
||||||
|
<SettingOutlined/> Pengaturan
|
||||||
|
</button>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={`content-status ${(v?.isActive) ? 'bg-success-light' : 'bg-danger-light'}`}>
|
||||||
|
{(v?.isActive) ? <div className={"status-flag text-success"}>
|
||||||
|
<CheckCircleOutlined className="text-success me-2"/>
|
||||||
|
<div>Aktif</div>
|
||||||
|
</div> : <div className={"status-flag text-danger"}>
|
||||||
|
<CloseCircleOutlined className="text-danger me-2"/>
|
||||||
|
<div>Tidak Aktif</div>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
<div className={"content-foto"}>
|
||||||
|
{(v?.profilePict) ? <img alt={"company"} className={"img"} src={v?.profilePict}/> : <img className={"img"} src={"/img/gedung.jpeg"}/>}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
|
</Row>)
|
||||||
|
}
|
193
src/app/main/daftarPerusahaan/FormPerusahaan.jsx
Normal file
193
src/app/main/daftarPerusahaan/FormPerusahaan.jsx
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
import { Col, Modal, Row, Spin } from "antd";
|
||||||
|
import { CloseOutlined } from "@ant-design/icons";
|
||||||
|
import Input from "@/components/util/Input";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
let timer;
|
||||||
|
export default function FormPerusahaan({
|
||||||
|
modalStatus,
|
||||||
|
actClose, actStoreData,
|
||||||
|
data,
|
||||||
|
loadingModal,
|
||||||
|
jenis,
|
||||||
|
}) {
|
||||||
|
|
||||||
|
|
||||||
|
const [viewReadonly, setViewReadonly] = useState(false);
|
||||||
|
const [latlon, setLatlon] = useState(null);
|
||||||
|
const [showMap, setShowMap] = useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
setValue,
|
||||||
|
watch,
|
||||||
|
getValues,
|
||||||
|
reset,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm();
|
||||||
|
|
||||||
|
const TypeAction = () => {
|
||||||
|
if (jenis === "detail") {
|
||||||
|
return <></>;
|
||||||
|
} else {
|
||||||
|
return <button className="btn btn-primary btn-sm" onClick={handleSubmit(onSubmit)}>Simpan</button>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async (data) => {
|
||||||
|
actStoreData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (jenis === "detail") {
|
||||||
|
setViewReadonly(true);
|
||||||
|
} else {
|
||||||
|
setViewReadonly(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}, [jenis]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
console.log(data)
|
||||||
|
setValue('address',data.address)
|
||||||
|
setValue('picNm', data.picNm)
|
||||||
|
setValue('phoneNo', data.phoneNo)
|
||||||
|
setValue('lat', data.lat)
|
||||||
|
setValue('lon', data.lon)
|
||||||
|
setValue('companyNm', data.companyNm)
|
||||||
|
setValue('wilayahId', data?.wilayah?.wilayahId)
|
||||||
|
setValue('companyId', data.companyId)
|
||||||
|
|
||||||
|
setLatlon({
|
||||||
|
lat: data.lat,
|
||||||
|
lon: data.lon
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (modalStatus === true){
|
||||||
|
setLatlon(null)
|
||||||
|
reset()
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
setShowMap(true);
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [modalStatus]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLatlon({
|
||||||
|
lat: watch('lat'),
|
||||||
|
lon:watch('lon')
|
||||||
|
})
|
||||||
|
}, [watch('lat')]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
centered
|
||||||
|
closeIcon={false}
|
||||||
|
open={modalStatus}
|
||||||
|
width={"600px"}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<Spin spinning={loadingModal}>
|
||||||
|
<div
|
||||||
|
className="btn btn-circle btn-light-primary zn-close"
|
||||||
|
onClick={actClose}
|
||||||
|
>
|
||||||
|
<CloseOutlined />
|
||||||
|
</div>
|
||||||
|
<div className="px-6 py-4 cardDark">
|
||||||
|
<div className="fs-6 fw-bolder text-uppercase text-primary">
|
||||||
|
Data Perusahaan
|
||||||
|
</div>
|
||||||
|
<div className="fs-7 fw-ligth text-muted">Data Perusahaan</div>
|
||||||
|
<div className="separator my-3" />
|
||||||
|
<div
|
||||||
|
style={{ overflowY: "auto", overflowX: "hidden", height: "600px" }}
|
||||||
|
className="my-4 p-2"
|
||||||
|
>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Row gutter={15}>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.Text
|
||||||
|
title={"Nama Perusahaan"}
|
||||||
|
name={"companyNm"}
|
||||||
|
minlength={"15"}
|
||||||
|
maxlength={"200"}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.Textarea
|
||||||
|
title={"Alamat"}
|
||||||
|
name={"address"}
|
||||||
|
maxlength={"200"}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.Number
|
||||||
|
title={"No HP"}
|
||||||
|
name={"phoneNo"}
|
||||||
|
minlength={"10"}
|
||||||
|
maxlength={"15"}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.Text
|
||||||
|
title={"Penanggungjawab"}
|
||||||
|
name={"picNm"}
|
||||||
|
minlength={"15"}
|
||||||
|
maxlength={"200"}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input.SelectRemote
|
||||||
|
title={"Wilayah"}
|
||||||
|
name={"wilayahId"}
|
||||||
|
endPoint={"/ref/wilayah"}
|
||||||
|
val={getValues("wilayahId")}
|
||||||
|
setValue={setValue}
|
||||||
|
setReadonly={viewReadonly}
|
||||||
|
required
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Row>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-footer text-right py-3 px-5 zn-bg-modal">
|
||||||
|
<TypeAction />
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
170
src/app/main/daftarPerusahaan/page.jsx
Normal file
170
src/app/main/daftarPerusahaan/page.jsx
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
"use client"
|
||||||
|
import SearchInput from "@/components/util/SearchInput";
|
||||||
|
import WrapperContent from "@/components/util/WrapperContent";
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import CardPerusahaan from "./CardPerusahaan";
|
||||||
|
import {API} from "@/lib/API";
|
||||||
|
import notifStore from "@/store/notifStore";
|
||||||
|
import {ReloadOutlined} from "@ant-design/icons";
|
||||||
|
import {Pagination} from "antd";
|
||||||
|
import confirmStore from "@/store/confirmStore";
|
||||||
|
import FormPerusahaan from "@/app/main/daftarPerusahaan/FormPerusahaan";
|
||||||
|
|
||||||
|
export default function DaftarPerusahaan() {
|
||||||
|
const {notifOpen} = notifStore()
|
||||||
|
const {confirmOpen, confirmClose, setConfirmLoading} = confirmStore();
|
||||||
|
|
||||||
|
const [searchText, setSearchText] = useState(null)
|
||||||
|
const [currentPage, setCurrentPage] = useState(1)
|
||||||
|
|
||||||
|
const [dataPerusahaan, setDataPerusahaan] = useState([])
|
||||||
|
const [modalPerusahaan, setModalPerusahaan] = useState({
|
||||||
|
loadingModal: false, modalStatus: false, jenis: null, data: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSearch = (event) => {
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setSearchText(event.target.value);
|
||||||
|
}, 1000);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPerusahaan = async (page, size) => {
|
||||||
|
let setPage = (page) ? page : 0;
|
||||||
|
let setSize = (size) ? size : 6;
|
||||||
|
let res = await API.GET(`/ref/company?page=${setPage}&size=${setSize}`)
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifOpen("Gagal", res.result.message, "danger");
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
setDataPerusahaan(res.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalOpen = async (id, type) => {
|
||||||
|
|
||||||
|
if (type === 'tambah') {
|
||||||
|
setModalPerusahaan(prev => ({
|
||||||
|
...prev, modalStatus: true, jenis: type, data: null
|
||||||
|
}));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setModalPerusahaan(prev => ({
|
||||||
|
...prev, modalStatus: true, jenis: type, loadingModal: true
|
||||||
|
}));
|
||||||
|
let res = await API.GET('/ref/company/' + id)
|
||||||
|
setModalPerusahaan(prev => ({
|
||||||
|
...prev, data: res.result, loadingModal: false
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeData = async (data) => {
|
||||||
|
let res = await API.POST('/ref/company', data)
|
||||||
|
if (res.status === 200) {
|
||||||
|
setModalPerusahaan(prev => ({
|
||||||
|
...prev, modalStatus: false,
|
||||||
|
}));
|
||||||
|
|
||||||
|
notifOpen("Berhasil", res.result.message);
|
||||||
|
await getPerusahaan();
|
||||||
|
setCurrentPage(1)
|
||||||
|
} else {
|
||||||
|
notifOpen("Gagal", res.result.message, "danger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteData = async (id) => {
|
||||||
|
confirmOpen("Hapus Data", "Yakin Hapus Data Ini", async () => {
|
||||||
|
setConfirmLoading(true);
|
||||||
|
let response = await API.DELETE(`/ref/company/${id}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
notifOpen("Berhasil", "berhasil hapus data");
|
||||||
|
await getPerusahaan();
|
||||||
|
setConfirmLoading(false);
|
||||||
|
confirmClose();
|
||||||
|
setCurrentPage(1)
|
||||||
|
} else {
|
||||||
|
console.log(response);
|
||||||
|
setConfirmLoading(false);
|
||||||
|
notifOpen("Gagal", response.result.message, "danger");
|
||||||
|
confirmClose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangePage = (page, pageSize) => {
|
||||||
|
console.log({page, pageSize})
|
||||||
|
setCurrentPage(page)
|
||||||
|
getPerusahaan(page - 1, pageSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChangePageSize = (current, size) => {
|
||||||
|
console.log({current, size})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getPerusahaan()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<WrapperContent>
|
||||||
|
<div className="containers">
|
||||||
|
<div className="headContent">
|
||||||
|
<div className="containerTitle">
|
||||||
|
<div className="breadCrumb">
|
||||||
|
<div className="text">Data Perusahaan</div>
|
||||||
|
<div className="text">Daftar Perusahaan</div>
|
||||||
|
</div>
|
||||||
|
<div className="title text-dark-grey left">Daftar Perusahaan</div>
|
||||||
|
</div>
|
||||||
|
<div className="filter mb-3">
|
||||||
|
<SearchInput handleSearch={handleSearch} style={{marginRight: "10px"}}/>
|
||||||
|
<button type="button" className="btn btn-primary" onClick={() => modalOpen(null, 'tambah')}>Registrasi Perusahaan</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-circle btn-light-primary"
|
||||||
|
onClick={() => getPerusahaan()}
|
||||||
|
>
|
||||||
|
<ReloadOutlined/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bodyContent">
|
||||||
|
<CardPerusahaan modalOpen={modalOpen} deleteData={deleteData} data={dataPerusahaan?.data}/>
|
||||||
|
<Pagination
|
||||||
|
style={{marginTop: '30px', borderRadius: '20px', padding: '10px'}}
|
||||||
|
align="center"
|
||||||
|
total={dataPerusahaan?.totalElements}
|
||||||
|
showTotal={(total, range) => `${range[0]}-${range[1]} dari ${total} Data`}
|
||||||
|
defaultPageSize={6}
|
||||||
|
pageSizeOptions={['6', '12', '24']}
|
||||||
|
showSizeChanger={true}
|
||||||
|
defaultCurrent={1}
|
||||||
|
current={currentPage}
|
||||||
|
onChange={onChangePage}
|
||||||
|
onShowSizeChange={onChangePageSize}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</WrapperContent>
|
||||||
|
<FormPerusahaan
|
||||||
|
loadingModal={modalPerusahaan?.loadingModal}
|
||||||
|
modalStatus={modalPerusahaan?.modalStatus}
|
||||||
|
jenis={modalPerusahaan?.jenis}
|
||||||
|
actClose={()=>{
|
||||||
|
setModalPerusahaan(prev => ({
|
||||||
|
...prev,
|
||||||
|
modalStatus: false,
|
||||||
|
loadingModal: false
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
actStoreData={storeData}
|
||||||
|
data={modalPerusahaan?.data} />
|
||||||
|
</>)
|
||||||
|
}
|
84
src/app/main/daftarPerusahaan/style.scss
Normal file
84
src/app/main/daftarPerusahaan/style.scss
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
.card-company{
|
||||||
|
background: #fff;
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-radius: 25px;
|
||||||
|
box-shadow: 0px 8px 50px rgb(0 0 0 / 8%);
|
||||||
|
margin-top: 15px;
|
||||||
|
transition: 0.5s ease-in-out;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
box-shadow: 0px 25px 50px rgb(0 0 0 / 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-title{
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
width: 60%;
|
||||||
|
|
||||||
|
.name{
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--dark);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.position{
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-company{
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-company{
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.title{
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
.value{
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #0c111c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-status{
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
left: 30px;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 3px 30px 3px 10px;
|
||||||
|
|
||||||
|
.status-flag{
|
||||||
|
display: flex;
|
||||||
|
gap: 0px;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-foto{
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
border-radius: 25px;
|
||||||
|
|
||||||
|
.icon{
|
||||||
|
font-size: 180px;
|
||||||
|
color: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
.img{
|
||||||
|
width: 170px;
|
||||||
|
height: 250px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 0 25px 100px 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
107
src/app/main/dashboard/GrafikHari.jsx
Normal file
107
src/app/main/dashboard/GrafikHari.jsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import dynamic from "next/dynamic";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import {Helper} from "@/lib/Helper";
|
||||||
|
|
||||||
|
const ReactApexChart = dynamic(() => import("react-apexcharts"), {ssr: false});
|
||||||
|
|
||||||
|
export default function GrafikHari() {
|
||||||
|
const [grafik, setGrafik] = useState([]);
|
||||||
|
const [optionGrafik, setOptionGrafik] = useState(
|
||||||
|
{
|
||||||
|
chart: {
|
||||||
|
type: 'area',
|
||||||
|
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
curve: 'smooth'
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
type: 'gradient',
|
||||||
|
gradient: {
|
||||||
|
shadeIntensity: 1,
|
||||||
|
opacityFrom: 0.1,
|
||||||
|
opacityTo: 0.9,
|
||||||
|
stops: [0, 100]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
formatter: (val) => {
|
||||||
|
return Helper.numFormat(val)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
shared: true,
|
||||||
|
intersect: false,
|
||||||
|
y: {
|
||||||
|
formatter: function (y) {
|
||||||
|
if (typeof y !== "undefined") {
|
||||||
|
return Helper.numFormat(y);
|
||||||
|
}
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: ['#0179c2', '#930200'],
|
||||||
|
legend: {
|
||||||
|
markers: {
|
||||||
|
fillColors: ['#0179c2', '#930200']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const getChart = (data) => {
|
||||||
|
|
||||||
|
let result = [
|
||||||
|
{
|
||||||
|
name: 'Transaksi',
|
||||||
|
data: [1000000,21000000,31000000,41000000,41000000,71000000, 11000000, 21000000, 31000000, 10000004, 10000004, 71000000, 1000000, 21000000, 31000000, 41000000, 41000000, 71000000, 11000000, 21000000, 31000000, 10000004, 10000004, 71000000]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let data_jam = [];
|
||||||
|
for (let i = 1; i <= 24; i++) {
|
||||||
|
data_jam.push(i + ':00')
|
||||||
|
}
|
||||||
|
|
||||||
|
setOptionGrafik(prev => ({
|
||||||
|
...prev,
|
||||||
|
xaxis: {
|
||||||
|
categories: data_jam
|
||||||
|
// categories: ["Jan",
|
||||||
|
// "Feb",
|
||||||
|
// "Mar",
|
||||||
|
// "Apr",
|
||||||
|
// "Mei",
|
||||||
|
// "Jun",
|
||||||
|
// "Jul",
|
||||||
|
// "Ags",
|
||||||
|
// "Sep",
|
||||||
|
// "Okt",
|
||||||
|
// "Nov",
|
||||||
|
// "Des"]
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
setGrafik(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getChart()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return(<>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className={"fw-bold fs-6"}>Grafik Transaksi Hari Ini</div>
|
||||||
|
<div className={"fw-normal fs-7 mt-1 text-muted"}>Grafik Transaksi Hari Ini</div>
|
||||||
|
<ReactApexChart options={optionGrafik} series={grafik} type="area" height={450}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>)
|
||||||
|
}
|
106
src/app/main/dashboard/GrafikTahun.jsx
Normal file
106
src/app/main/dashboard/GrafikTahun.jsx
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import dynamic from "next/dynamic";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import {Helper} from "@/lib/Helper";
|
||||||
|
|
||||||
|
const ReactApexChart = dynamic(() => import("react-apexcharts"), {ssr: false});
|
||||||
|
|
||||||
|
export default function GrafikTahun() {
|
||||||
|
const [grafik, setGrafik] = useState([]);
|
||||||
|
const [optionGrafik, setOptionGrafik] = useState(
|
||||||
|
{
|
||||||
|
chart: {
|
||||||
|
type: 'area',
|
||||||
|
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
curve: 'smooth'
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
type: 'gradient',
|
||||||
|
gradient: {
|
||||||
|
shadeIntensity: 1,
|
||||||
|
opacityFrom: 0.1,
|
||||||
|
opacityTo: 0.9,
|
||||||
|
stops: [0, 100]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
formatter: (val) => {
|
||||||
|
return Helper.numFormat(val)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
shared: true,
|
||||||
|
intersect: false,
|
||||||
|
y: {
|
||||||
|
formatter: function (y) {
|
||||||
|
if (typeof y !== "undefined") {
|
||||||
|
return Helper.numFormat(y);
|
||||||
|
}
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: ['#0179c2', '#930200'],
|
||||||
|
legend: {
|
||||||
|
markers: {
|
||||||
|
fillColors: ['#0179c2', '#930200']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const getChart = (data) => {
|
||||||
|
|
||||||
|
let result = [
|
||||||
|
{
|
||||||
|
name: 'Transaksi',
|
||||||
|
data: [1000000,21000000,31000000,41000000,41000000,71000000, 11000000, 21000000, 31000000, 10000004, 10000004, 71000000]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let data_jam = [];
|
||||||
|
for (let i = 1; i <= 24; i++) {
|
||||||
|
data_jam.push(i + ':00')
|
||||||
|
}
|
||||||
|
|
||||||
|
setOptionGrafik(prev => ({
|
||||||
|
...prev,
|
||||||
|
xaxis: {
|
||||||
|
categories: ["Jan",
|
||||||
|
"Feb",
|
||||||
|
"Mar",
|
||||||
|
"Apr",
|
||||||
|
"Mei",
|
||||||
|
"Jun",
|
||||||
|
"Jul",
|
||||||
|
"Ags",
|
||||||
|
"Sep",
|
||||||
|
"Okt",
|
||||||
|
"Nov",
|
||||||
|
"Des"]
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
setGrafik(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getChart()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return(<>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className={"fw-bold fs-6"}>Grafik Semua Transaksi </div>
|
||||||
|
<div className={"fw-normal fs-7 mt-1 text-muted"}>Data Grafik Semua Transaksi</div>
|
||||||
|
<ReactApexChart options={optionGrafik} series={grafik} type="area" height={450}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>)
|
||||||
|
}
|
130
src/app/main/dashboard/SegmentAgen.jsx
Normal file
130
src/app/main/dashboard/SegmentAgen.jsx
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import {IdcardOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
export default function SegmentAgen() {
|
||||||
|
return(
|
||||||
|
<div className={"card"} style={{textAlign: 'right', padding: "30px",border:"none",
|
||||||
|
background:'#ffffff3b',
|
||||||
|
boxShadow:'0px 8px 29px #00000012'
|
||||||
|
}}>
|
||||||
|
<div className={"transaksi-hari light"}>
|
||||||
|
<div className={"title"}>Transaksi Per Agen</div>
|
||||||
|
<div className={"subTitle"}>Perolehan Transaksi Per Agen 10 Teratas</div>
|
||||||
|
|
||||||
|
<div className={"content reward-agen"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>
|
||||||
|
<div>Agen Alzam Zain Hamizan</div>
|
||||||
|
<div className={"text-muted"}>Outlet Alzam Store</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 20.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><IdcardOutlined/></div>
|
||||||
|
<div>Agen A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
56
src/app/main/dashboard/SegmentJenisTransaksi.jsx
Normal file
56
src/app/main/dashboard/SegmentJenisTransaksi.jsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import {CreditCardOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
export default function SegmentJenisTransaksi() {
|
||||||
|
return (<div className={"card"} style={{textAlign: 'right', padding: "30px", background: 'var(--bg-gradient-transaksi)'}}>
|
||||||
|
<div className={"transaksi-hari"}>
|
||||||
|
<div className={"title"}>Transaksi Per Jenis Pembayaran</div>
|
||||||
|
<div className={"subTitle"}>Perolehan Transaksi Per Jenis Pembayaran</div>
|
||||||
|
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><CreditCardOutlined/></div>
|
||||||
|
<div>Jenis Pembayaran A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><CreditCardOutlined/></div>
|
||||||
|
<div>Jenis Pembayaran A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><CreditCardOutlined/></div>
|
||||||
|
<div>Jenis Pembayaran A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><CreditCardOutlined/></div>
|
||||||
|
<div>Jenis Pembayaran A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>)
|
||||||
|
}
|
131
src/app/main/dashboard/SegmentProduk.jsx
Normal file
131
src/app/main/dashboard/SegmentProduk.jsx
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import {InboxOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
export default function SegmentProduk() {
|
||||||
|
return(
|
||||||
|
<div className={"card"} style={{textAlign: 'right', padding: "30px",
|
||||||
|
background:'#ffffff3b',
|
||||||
|
boxShadow: '0px 8px 29px #00000012',
|
||||||
|
border:'none'}}>
|
||||||
|
<div className={"transaksi-hari light"}>
|
||||||
|
<div className={"title"}>Transaksi Per Produk</div>
|
||||||
|
<div className={"subTitle"}>Perolehan Transaksi Per Produk 10 Teratas</div>
|
||||||
|
|
||||||
|
<div className={"content reward-product"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
<div className={"text-muted"}>Outlet Alzam Store</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 20.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><InboxOutlined/></div>
|
||||||
|
<div>Produk A</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
83
src/app/main/dashboard/SegmentTransaksiHari.jsx
Normal file
83
src/app/main/dashboard/SegmentTransaksiHari.jsx
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import {FieldTimeOutlined, UserOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
export default function SegmentTransaksiHari() {
|
||||||
|
return(
|
||||||
|
<div className={"card"} style={{textAlign: 'right', padding: "30px", background: 'var(--bg-gradient-transaksi)'}}>
|
||||||
|
<div className={"transaksi-hari"}>
|
||||||
|
<div className={"title"}>Transaksi Per Hari</div>
|
||||||
|
<div className={"subTitle"}>Total Transaksi Per Hari</div>
|
||||||
|
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><FieldTimeOutlined/></div>
|
||||||
|
<div>Minggu</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><FieldTimeOutlined/></div>
|
||||||
|
<div>Senin</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><FieldTimeOutlined/></div>
|
||||||
|
<div>Selasa</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><FieldTimeOutlined/></div>
|
||||||
|
<div>Rabu</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><FieldTimeOutlined/></div>
|
||||||
|
<div>Kamis</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><FieldTimeOutlined/></div>
|
||||||
|
<div>Jum'at</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"name"}>
|
||||||
|
<div className={"icon"}><FieldTimeOutlined/></div>
|
||||||
|
<div>Sabtu</div>
|
||||||
|
</div>
|
||||||
|
<div className={"nominal"}>
|
||||||
|
<div className={"amount"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"count"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,5 +1,187 @@
|
|||||||
|
"use client"
|
||||||
|
import {Col, Row, Spin} from "antd";
|
||||||
|
import Input from "@/components/util/Input";
|
||||||
|
import {useState} from "react";
|
||||||
|
import {useForm} from "react-hook-form";
|
||||||
|
import "./style.scss"
|
||||||
|
import GrafikHari from "@/app/main/dashboard/GrafikHari";
|
||||||
|
import CardTransaksiHari from "@/app/main/dashboard/SegmentTransaksiHari";
|
||||||
|
import SegmentTransaksiHari from "@/app/main/dashboard/SegmentTransaksiHari";
|
||||||
|
import SegmentAgen from "@/app/main/dashboard/SegmentAgen";
|
||||||
|
import GrafikTahun from "@/app/main/dashboard/GrafikTahun";
|
||||||
|
import SegmentProduk from "@/app/main/dashboard/SegmentProduk";
|
||||||
|
import SegmentJenisTransaksi from "@/app/main/dashboard/SegmentJenisTransaksi";
|
||||||
|
import {CreditCardOutlined, IdcardOutlined, InboxOutlined, ShakeOutlined, ShopOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
return(
|
const {register, setValue, watch, getValues, formState: {errors},} = useForm();
|
||||||
<>dashboard</>
|
|
||||||
)
|
const [dropdownData, setDropdownData] = useState({});
|
||||||
|
const [dropdownLoading, setDropdownLoading] = useState({
|
||||||
|
company: false, outlet: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (<div className={"dashboard"}>
|
||||||
|
<div className="headContent">
|
||||||
|
<div className="containerTitle">
|
||||||
|
<div className="breadCrumb">
|
||||||
|
<div className="text">Dashboard</div>
|
||||||
|
<div className="text">Data Dashboard</div>
|
||||||
|
</div>
|
||||||
|
<div className="title text-dark-grey left text-uppercase">Dashboard</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style={{display: "flex", gap: '10px', justifyContent: 'end'}}>
|
||||||
|
<div style={{width: '250px'}}>
|
||||||
|
|
||||||
|
<Input.DateRange
|
||||||
|
title={"Tanggal"}
|
||||||
|
name={"filterSkimKredit"}
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
options={dropdownData?.productType}
|
||||||
|
val={getValues("filterSkimKredit")}
|
||||||
|
placeholder={"Filter Produk"}
|
||||||
|
setValue={setValue}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{width: '250px'}}>
|
||||||
|
<Spin spinning={dropdownLoading?.company}>
|
||||||
|
<Input.Select
|
||||||
|
title={"Filter Company"}
|
||||||
|
name={"filterCompany"}
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
options={dropdownData?.company}
|
||||||
|
val={getValues("filterCompany")}
|
||||||
|
setValue={setValue}
|
||||||
|
/>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
<div style={{width: '250px'}}>
|
||||||
|
<Spin spinning={dropdownLoading?.outlet}>
|
||||||
|
<Input.Select
|
||||||
|
title={"Filter Outlet"}
|
||||||
|
name={"filterOutlet"}
|
||||||
|
register={register}
|
||||||
|
error={errors}
|
||||||
|
options={dropdownData?.outlet}
|
||||||
|
val={getValues("filterOutlet")}
|
||||||
|
setValue={setValue}
|
||||||
|
/>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className={'content'}>
|
||||||
|
<Row gutter={[30,30]}>
|
||||||
|
<Col span={8} xxl={6}>
|
||||||
|
<Row gutter={[15, 15]}>
|
||||||
|
<Col span={12}>
|
||||||
|
<div className={"card dark"}>
|
||||||
|
<div className={"icon-summary"}><IdcardOutlined/></div>
|
||||||
|
<div className={"title"}>Total Agen</div>
|
||||||
|
<div className={"nominal"}>100.000</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<div className={"card purple"}>
|
||||||
|
<div className={"icon-summary"}><ShopOutlined/></div>
|
||||||
|
<div className={"title"}>Total Outlet</div>
|
||||||
|
<div className={"nominal"}>1.000</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<div className={"card green"}>
|
||||||
|
<div className={"icon-summary"}><ShakeOutlined/></div>
|
||||||
|
<div className={"title"}>Total EDC Aktif</div>
|
||||||
|
<div className={"nominal"}>100.000</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<div className={"card orange"}>
|
||||||
|
<div className={"icon-summary"}><InboxOutlined/></div>
|
||||||
|
<div className={"title"}>Total Produk</div>
|
||||||
|
<div className={"nominal"}>5.000</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
<Col span={16} xxl={18}>
|
||||||
|
<div className={"card"} style={{textAlign:'right',padding:"30px"}}>
|
||||||
|
<Row>
|
||||||
|
<Col span={8}>
|
||||||
|
<div className={"transaksi"}>
|
||||||
|
<div className={"title text-primary"}>Total Transaksi</div>
|
||||||
|
<div className={"nominal low "}><small>Rp</small> 500.000.000</div>
|
||||||
|
<div className={"desc mt-3"}>Dari <b className={"text-primary"}>100</b> Transaksi yang di lakukan. Transaksi rata-rata perhari adalah <b className={"text-primary"}>10</b> Transaksi dengan nominal Rata-rata sebesar <b className={"text-primary"}>Rp 100.000</b> </div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
<Col span={8}>
|
||||||
|
<div>
|
||||||
|
<div className={"title text-success"}>Omzet</div>
|
||||||
|
<div className={"nominal low"}><small>Rp</small> 50.000.000</div>
|
||||||
|
<div className={"desc"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
<div className={"mt-5"}>
|
||||||
|
<div className={"title text-success"}>Laba</div>
|
||||||
|
<div className={"nominal low"}><small>Rp</small> 50.000.000</div>
|
||||||
|
<div className={"desc"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={8}>
|
||||||
|
<div>
|
||||||
|
<div className={"title text-danger"}>Fee Agen</div>
|
||||||
|
<div className={"nominal low"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"desc"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
<div className={"mt-5"}>
|
||||||
|
<div className={"title text-danger"}>Fee Bank</div>
|
||||||
|
<div className={"nominal low"}><small>Rp</small> 10.000.000</div>
|
||||||
|
<div className={"desc"}>Dari <b>100</b> Transaksi</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col span={16} xxl={18}>
|
||||||
|
<div className={"mt-2"}>
|
||||||
|
<GrafikHari/>
|
||||||
|
</div>
|
||||||
|
<div className={"mt-5"}>
|
||||||
|
<GrafikTahun/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={8} xxl={6}>
|
||||||
|
<SegmentTransaksiHari/>
|
||||||
|
<div className={"mt-3"}>
|
||||||
|
<SegmentJenisTransaksi/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row gutter={[30, 30]}>
|
||||||
|
<Col span={12}>
|
||||||
|
<div className={"mt-3"}>
|
||||||
|
<SegmentAgen/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<div className={"mt-3"}>
|
||||||
|
<SegmentProduk/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</div>)
|
||||||
}
|
}
|
229
src/app/main/dashboard/style.scss
Normal file
229
src/app/main/dashboard/style.scss
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
.dashboard {
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
text-align: center;
|
||||||
|
padding: 25px;
|
||||||
|
//border:2px solid #f3f3f3;
|
||||||
|
box-shadow: none;
|
||||||
|
border-radius: 25px;
|
||||||
|
|
||||||
|
.icon-summary{
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
font-size: 72px;
|
||||||
|
opacity: 0.09;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #a1a1a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nominal {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&.low {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.transaksi {
|
||||||
|
text-align: left;
|
||||||
|
margin-top: 20px;
|
||||||
|
//padding: 12px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
border-bottom: 3px solid var(--dark);
|
||||||
|
|
||||||
|
.nominal {
|
||||||
|
color: var(--dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-summary{
|
||||||
|
color: var(--dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.green {
|
||||||
|
border-bottom: 3px solid var(--color-logo-green);
|
||||||
|
|
||||||
|
.nominal {
|
||||||
|
color: var(--color-logo-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-summary {
|
||||||
|
color: var(--color-logo-green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.purple {
|
||||||
|
border-bottom: 3px solid var(--color-logo-purple);
|
||||||
|
|
||||||
|
.nominal {
|
||||||
|
color: var(--color-logo-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-summary {
|
||||||
|
color: var(--color-logo-purple);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.orange {
|
||||||
|
border-bottom: 3px solid var(--color-logo-orange);
|
||||||
|
|
||||||
|
.nominal {
|
||||||
|
color: var(--color-logo-orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-summary {
|
||||||
|
color: var(--color-logo-orange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
border-bottom: 3px solid var(--primary);
|
||||||
|
|
||||||
|
.nominal {
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.transaksi-hari {
|
||||||
|
color: #fff !important;
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
color: var(--dark) !important;
|
||||||
|
|
||||||
|
.subTitle {
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: var(--dark) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.nominal {
|
||||||
|
|
||||||
|
.amount {
|
||||||
|
small {
|
||||||
|
color: var(--text-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.count {
|
||||||
|
color: var(--text-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subTitle {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-muted-reverse);
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-top: 1px solid rgb(255 255 255 / 9%);
|
||||||
|
padding: 15px 0;
|
||||||
|
|
||||||
|
&.reward-product {
|
||||||
|
background: #f7963e24;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 0 -15px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: #f7963e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.reward-agen {
|
||||||
|
background: #181c3214;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 0 -15px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: var(--dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 16px;
|
||||||
|
background: rgba(0, 0, 0, 0.06);
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
padding: 3px 7px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nominal {
|
||||||
|
|
||||||
|
.amount {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-muted-reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.count {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-muted-reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,33 +3,33 @@
|
|||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
|
|
||||||
import {QueryClient, QueryClientProvider} from "react-query";
|
import {QueryClient, QueryClientProvider} from "react-query";
|
||||||
|
|
||||||
import dynamic from "next/dynamic";
|
|
||||||
import ModalConfirm from '@/components/util/ModalConfirm';
|
import ModalConfirm from '@/components/util/ModalConfirm';
|
||||||
import ModalNotif from "@/components/util/ModalNotif";
|
import ModalNotif from "@/components/util/ModalNotif";
|
||||||
import ChangePassword from "@/app/main/ChangePassword";
|
import ChangePassword from "@/app/main/ChangePassword";
|
||||||
import ChangeProfile from "@/app/main/ChangeProfile";
|
import ChangeProfile from "@/app/main/ChangeProfile";
|
||||||
import LoadingPage from "@/components/util/LoadingPage";
|
|
||||||
import {getCookie} from "cookies-next";
|
import {getCookie} from "cookies-next";
|
||||||
import {API} from "@/lib/API";
|
import {API} from "@/lib/API";
|
||||||
import {notFound, usePathname, useRouter} from "next/navigation";
|
import {usePathname, useRouter} from "next/navigation";
|
||||||
import {LoadingOutlined} from "@ant-design/icons";
|
|
||||||
import ModalSessionTimeout from "@/components/util/ModalSessionTimeout";
|
import ModalSessionTimeout from "@/components/util/ModalSessionTimeout";
|
||||||
import useIdleDetection from "@/hooks/useIdleDetection";
|
import useIdleDetection from "@/hooks/useIdleDetection";
|
||||||
import MenuList from "@/components/master/Menu";
|
import MenuList from "@/components/master/Menu";
|
||||||
import menuStore from "@/store/menuStore";
|
import menuStore from "@/store/menuStore";
|
||||||
import CheckAuth from "@/components/util/CheckAuth";
|
import CheckAuth from "@/components/util/CheckAuth";
|
||||||
|
import LoadingPage from "@/components/util/LoadingPage";
|
||||||
const Navbar = dynamic(() => import("@/components/master/Navbar"), {ssr: false,});
|
import {Spin} from "antd";
|
||||||
|
import {LoadingOutlined} from "@ant-design/icons";
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
|
||||||
export default function MainLayout({children}) {
|
export default function MainLayout({children}) {
|
||||||
|
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [checkAuth, setCheckAuth] = useState(true)
|
const [checkAuth, setCheckAuth] = useState(true)
|
||||||
const {isIdle, setIsIdle} = useIdleDetection();
|
const {isIdle, setIsIdle} = useIdleDetection();
|
||||||
const {toggleStatus} = menuStore()
|
const {toggleStatus, loadingPageStatus} = menuStore()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const checkToken = async () => {
|
const checkToken = async () => {
|
||||||
@ -61,36 +61,37 @@ export default function MainLayout({children}) {
|
|||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkToken()
|
checkToken()
|
||||||
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<QueryClientProvider client={queryClient}>
|
|
||||||
<>
|
|
||||||
{(checkAuth) ?
|
|
||||||
<CheckAuth/>
|
|
||||||
: <>
|
|
||||||
|
|
||||||
|
return (<QueryClientProvider client={queryClient}>
|
||||||
|
|
||||||
|
<>
|
||||||
|
{(checkAuth) ? <CheckAuth/> : <>
|
||||||
{isIdle && <ModalSessionTimeout setIsIdle={setIsIdle}/>}
|
{isIdle && <ModalSessionTimeout setIsIdle={setIsIdle}/>}
|
||||||
|
{/*<LoadingPage/>*/}
|
||||||
<MenuList />
|
<MenuList />
|
||||||
|
|
||||||
{/*<Navbar/>*/}
|
<section className={`content ${(toggleStatus) ? 'hover' : ''}`}>
|
||||||
<LoadingPage/>
|
<div className={'card-content'}>
|
||||||
<div id="backdrop" className="">
|
<Spin percent="auto" size={"large"} indicator={<LoadingOutlined spin/>} style={{color:'var(--primary)'}} tip={<div className={"mt-3"}>Loading</div>} spinning={loadingPageStatus}>
|
||||||
<button className="hideBar"/>
|
|
||||||
|
{children}
|
||||||
|
|
||||||
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
<section className={`content ${(toggleStatus) ? 'hover':''}`}>{children}</section>
|
</section>
|
||||||
<ChangePassword/>
|
<ChangePassword/>
|
||||||
<ChangeProfile/>
|
<ChangeProfile/>
|
||||||
<ModalConfirm/>
|
<ModalConfirm/>
|
||||||
<ModalNotif/>
|
<ModalNotif/>
|
||||||
|
|
||||||
</>
|
</>}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</>
|
</>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>);
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, {useEffect, useRef, useState} from "react";
|
import React, {useEffect, useRef, useState} from "react";
|
||||||
import breadcrumbStore from "@/store/breadcrumbStore";
|
|
||||||
import modalStore from "@/store/modal";
|
import modalStore from "@/store/modal";
|
||||||
import confirmStore from "@/store/confirmStore";
|
import confirmStore from "@/store/confirmStore";
|
||||||
import {API} from "@/lib/API";
|
import {API} from "@/lib/API";
|
||||||
@ -22,7 +21,6 @@ const MenuPrivilage = () => {
|
|||||||
|
|
||||||
const formRef = useRef();
|
const formRef = useRef();
|
||||||
const {modalOpen, modalClose, FormId, modalStat, setModalLoading, setModalDetail, actionType} = modalStore();
|
const {modalOpen, modalClose, FormId, modalStat, setModalLoading, setModalDetail, actionType} = modalStore();
|
||||||
const {setSubTitle, setTitle} = breadcrumbStore();
|
|
||||||
const {confirmOpen, confirmClose, setConfirmLoading} = confirmStore();
|
const {confirmOpen, confirmClose, setConfirmLoading} = confirmStore();
|
||||||
const {notifOpen} = notifStore()
|
const {notifOpen} = notifStore()
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@ import {useEffect, useState} from "react";
|
|||||||
import {DropdownAPI} from "@/lib/DropdownAPI";
|
import {DropdownAPI} from "@/lib/DropdownAPI";
|
||||||
|
|
||||||
import RefTemplate from "@/components/refTemplate/Main";
|
import RefTemplate from "@/components/refTemplate/Main";
|
||||||
import BadgeStatus from "@/components/util/BadgeStatus";
|
|
||||||
import BadgeStatusApproval from "@/components/util/BadgeStatusApproval";
|
|
||||||
|
|
||||||
export default function UserList() {
|
export default function UserList() {
|
||||||
const [listForm, setListForm] = useState()
|
const [listForm, setListForm] = useState()
|
||||||
@ -142,15 +140,11 @@ export default function UserList() {
|
|||||||
{
|
{
|
||||||
title: "Status",
|
title: "Status",
|
||||||
dataIndex: 'active',
|
dataIndex: 'active',
|
||||||
render: (active) => <BadgeStatus active={active}/>,
|
|
||||||
sorter: (a, b) => a.active - b.active,
|
|
||||||
align: 'center'
|
align: 'center'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Status Persetujuan",
|
title: "Status Persetujuan",
|
||||||
dataIndex: 'statusApprovalId',
|
dataIndex: 'statusApprovalId',
|
||||||
render: (statusApprovalId) => <BadgeStatusApproval approvalId={statusApprovalId}/>,
|
|
||||||
sorter: (a, b) => a.statusApprovalId - b.statusApprovalId,
|
|
||||||
align: 'center'
|
align: 'center'
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
@ -7,6 +7,7 @@ import {LoadingOutlined} from "@ant-design/icons";
|
|||||||
import {getCookie} from "cookies-next";
|
import {getCookie} from "cookies-next";
|
||||||
import {useRouter} from "next/navigation";
|
import {useRouter} from "next/navigation";
|
||||||
import {API} from "@/lib/API";
|
import {API} from "@/lib/API";
|
||||||
|
import CheckAuth from "@/components/util/CheckAuth";
|
||||||
|
|
||||||
export default function Home(){
|
export default function Home(){
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -30,17 +31,7 @@ export default function Home(){
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="check-auth">
|
<CheckAuth/>
|
||||||
<div className="container">
|
|
||||||
<div className="center">
|
|
||||||
<img src="/img/logo.png" className="logo" />
|
|
||||||
<div className="title">SILOS KPR - Tapera Connect</div>
|
|
||||||
<div className="subtitle">Bank Kalteng</div>
|
|
||||||
<div className="check">check authorization</div>
|
|
||||||
<LoadingOutlined className="icon-check" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ExportedImage
|
<ExportedImage
|
||||||
className="bg-login-auth"
|
className="bg-login-auth"
|
||||||
|
@ -1,24 +1,35 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {BranchesOutlined, CloseOutlined, MenuOutlined, MenuUnfoldOutlined} from "@ant-design/icons";
|
import {BranchesOutlined, DoubleLeftOutlined, DoubleRightOutlined, MoonOutlined, SunOutlined, UserOutlined} from "@ant-design/icons";
|
||||||
import {Menu} from "antd";
|
import {Menu, Switch} from "antd";
|
||||||
import {API} from "@/lib/API";
|
import {API} from "@/lib/API";
|
||||||
import menuStore from "@/store/menuStore";
|
import menuStore from "@/store/menuStore";
|
||||||
import notifStore from "@/store/notifStore";
|
import notifStore from "@/store/notifStore";
|
||||||
import packageJson from '@@/package.json';
|
import packageJson from '@@/package.json';
|
||||||
|
import modalStore from "@/store/modal";
|
||||||
|
import useAuth from "@/hooks/useAuth";
|
||||||
|
import {usePathname} from "next/navigation";
|
||||||
|
|
||||||
const MenuList = () => {
|
const MenuList = () => {
|
||||||
|
let valTheme = localStorage.getItem('valTheme')
|
||||||
|
let state = null
|
||||||
|
if (valTheme == 'true') {
|
||||||
|
state = true
|
||||||
|
document.body.classList.add('darkMode')
|
||||||
|
} else {
|
||||||
|
state = false
|
||||||
|
}
|
||||||
|
const pathname = usePathname()
|
||||||
|
|
||||||
const [MenuList, setMenuList] = useState([])
|
const [menuList, setMenuList] = useState([])
|
||||||
const [menuTapera, setMenuTapera] = useState([])
|
const {setModalPassword, setModalProfile} = modalStore()
|
||||||
const [menuSilos, setMenuSilos] = useState([])
|
|
||||||
const [menuUsers, setMenuUsers] = useState([])
|
|
||||||
const [menuManajemenData, setMenuManajemenData] = useState([])
|
|
||||||
const [current, setCurrent] = useState(null);
|
const [current, setCurrent] = useState(null);
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
const {toggleStatus, setToggle} = menuStore()
|
const {toggleStatus, setToggle, setLoadingPageStatus} = menuStore()
|
||||||
const {notifOpen} = notifStore()
|
const {notifOpen} = notifStore()
|
||||||
|
const {removeAuth} = useAuth()
|
||||||
|
const [isTheme, setTheme] = useState(state);
|
||||||
|
|
||||||
const toggleCollapsed = () => {
|
const toggleCollapsed = () => {
|
||||||
setCollapsed(!collapsed);
|
setCollapsed(!collapsed);
|
||||||
@ -42,7 +53,7 @@ const MenuList = () => {
|
|||||||
resultListChildThird = vChild?.childs?.map((vChildThird, kChildThird) => {
|
resultListChildThird = vChild?.childs?.map((vChildThird, kChildThird) => {
|
||||||
if (vChildThird.url) {
|
if (vChildThird.url) {
|
||||||
return {
|
return {
|
||||||
label: (<Link href={vChildThird.url}>{vChildThird.menuNm}</Link>), key: vChildThird.menuId, icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>),
|
label: (<Link onClick={() => eventChange(vChildThird.url)} href={vChildThird.url}>{vChildThird.menuNm}</Link>), key: vChildThird.menuId, icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@ -55,7 +66,7 @@ const MenuList = () => {
|
|||||||
|
|
||||||
if (vChild.url) {
|
if (vChild.url) {
|
||||||
tmpChild.push({
|
tmpChild.push({
|
||||||
label: (<Link href={vChild.url}>{vChild.menuNm}</Link>), key: vChild.menuId, icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>), children: resultListChildThird
|
label: (<Link onClick={() => eventChange(vChild.url)} href={vChild.url}>{vChild.menuNm}</Link>), key: vChild.menuId, icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>), children: resultListChildThird
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -71,7 +82,7 @@ const MenuList = () => {
|
|||||||
|
|
||||||
if (v.url) {
|
if (v.url) {
|
||||||
tmpMenu.push({
|
tmpMenu.push({
|
||||||
label: (<Link href={v.url}>{v.menuNm}</Link>), key: v.menuId, icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>), children: tmpChild
|
label: (<Link onClick={()=>eventChange(v.url)} href={v.url}>{v.menuNm}</Link>), key: v.menuId, icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>), children: tmpChild
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
tmpMenu.push({
|
tmpMenu.push({
|
||||||
@ -86,16 +97,20 @@ const MenuList = () => {
|
|||||||
|
|
||||||
console.log(tmpMenu)
|
console.log(tmpMenu)
|
||||||
|
|
||||||
setMenuTapera(tmpMenu)
|
// setMenuTapera(tmpMenu)
|
||||||
// setMenuTapera(tmpMenu.filter((v)=>v.key === 1))
|
// setMenuTapera(tmpMenu.filter((v)=>v.key === 1))
|
||||||
// setMenuSilos(tmpMenu.filter((v)=>v.key === 2))
|
// setMenuSilos(tmpMenu.filter((v)=>v.key === 2))
|
||||||
// setMenuManajemenData(tmpMenu.filter((v)=>v.key === 3))
|
// setMenuManajemenData(tmpMenu.filter((v)=>v.key === 3))
|
||||||
// setMenuUsers(tmpMenu.filter((v)=>v.key === 8))
|
setMenuList(tmpMenu.filter((v)=>v.key === 8))
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const eventChange = (url) => {
|
||||||
|
if (pathname !== url) setLoadingPageStatus(true)
|
||||||
|
}
|
||||||
|
|
||||||
const getMenuDummy = () => {
|
const getMenuDummy = () => {
|
||||||
const items = [{
|
const items = [{
|
||||||
key: 'sub1', label: <div>Tapera Connect</div>, icon: <BranchesOutlined/>, children: [{
|
key: 'sub1', label: <div>Tapera Connect</div>, icon: <BranchesOutlined/>, children: [{
|
||||||
@ -113,6 +128,45 @@ const MenuList = () => {
|
|||||||
setMenuList(items)
|
setMenuList(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const modalChangeProfile = () => {
|
||||||
|
setModalProfile(true)
|
||||||
|
}
|
||||||
|
const modalChangePassword = (type) => {
|
||||||
|
setModalPassword(true, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ViewImage = ({fotoMember}) => {
|
||||||
|
if (fotoMember == null) return <UserOutlined className="userOutline" style={{background: '#eef6ff', borderRadius: '20px', padding: '10px'}}/>;
|
||||||
|
|
||||||
|
let getImage = '/';
|
||||||
|
return <img src={getImage} className="foto-member-nav"/>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const logout = async () => {
|
||||||
|
let response = await API.POST('/auth/logout');
|
||||||
|
if (response.status === 200) {
|
||||||
|
await removeAuth()
|
||||||
|
// router.push("/login");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const buttonHandler = (val) => {
|
||||||
|
setTheme((status) => !status);
|
||||||
|
let theme = null
|
||||||
|
if (val != true) {
|
||||||
|
theme = 'lightMode'
|
||||||
|
document.body.classList.add(theme);
|
||||||
|
document.body.classList.remove('darkMode');
|
||||||
|
} else {
|
||||||
|
theme = 'darkMode'
|
||||||
|
document.body.classList.add(theme);
|
||||||
|
document.body.classList.remove('lightMode');
|
||||||
|
}
|
||||||
|
localStorage.setItem('setTheme', theme)
|
||||||
|
localStorage.setItem('valTheme', val)
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getMenu()
|
getMenu()
|
||||||
// getMenuDummy()
|
// getMenuDummy()
|
||||||
@ -141,17 +195,52 @@ const MenuList = () => {
|
|||||||
<Menu
|
<Menu
|
||||||
forceSubMenuRender={true}
|
forceSubMenuRender={true}
|
||||||
defaultSelectedKeys={['105']}
|
defaultSelectedKeys={['105']}
|
||||||
defaultOpenKeys={['1']}
|
// defaultOpenKeys={['1']}
|
||||||
inlineCollapsed={toggleStatus}
|
inlineCollapsed={toggleStatus}
|
||||||
mode="inline"
|
mode="inline"
|
||||||
selectedKeys={[current]}
|
selectedKeys={[current]}
|
||||||
items={menuTapera}
|
items={menuList}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button className={"btn-menu-toggle"} onClick={setToggle}><MenuUnfoldOutlined/></button>
|
<div className="nav-account">
|
||||||
|
<div className="container-account">
|
||||||
|
|
||||||
|
<div className="account">
|
||||||
|
<div className={toggleStatus === true ? 'text ' : 'text active'}>
|
||||||
|
<div className="name">Zamzam</div>
|
||||||
|
<div className="role">Administrator</div>
|
||||||
|
</div>
|
||||||
|
<ViewImage fotoMember={null}/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={toggleStatus === true ? 'detail-account ' : 'detail-account active'}>
|
||||||
|
<div className="header">
|
||||||
|
<ViewImage fotoMember={null}/>
|
||||||
|
<div className="text">
|
||||||
|
<div className="name">Administrator</div>
|
||||||
|
<div className="role">Administrator</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="feature">
|
||||||
|
<button type="button" style={{cursor: 'pointer'}} onClick={() => modalChangeProfile()}>Ubah Profil</button>
|
||||||
|
<button type="button" style={{cursor: 'pointer'}} onClick={() => modalChangePassword('normal')}>Ubah Password</button>
|
||||||
|
<div className="switchTheme">
|
||||||
|
<Switch style={{width: '50px'}} checkedChildren={<MoonOutlined/>} unCheckedChildren={<SunOutlined/>} onChange={buttonHandler} checked={isTheme}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="containerSignOut">
|
||||||
|
<button type="button" style={{cursor: 'pointer'}} onClick={() => logout()}>Sign Out</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button className={"btn-menu-toggle"} onClick={setToggle}>{toggleStatus ? <DoubleRightOutlined/> : <DoubleLeftOutlined/>}</button>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,351 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import React, {useEffect, useState} from "react";
|
|
||||||
import {BellOutlined, CloseOutlined, MenuFoldOutlined, MenuOutlined, MenuUnfoldOutlined, MoonOutlined, SunOutlined, UserOutlined} from '@ant-design/icons';
|
|
||||||
import useAuth from "@/hooks/useAuth";
|
|
||||||
import {useRouter} from "next/navigation";
|
|
||||||
import {useAPI} from "@/hooks/useAPI";
|
|
||||||
import modalStore from "@/store/modal";
|
|
||||||
import {API} from "@/lib/API";
|
|
||||||
import {Button, Drawer, Menu, Switch} from "antd";
|
|
||||||
import Link from "next/link";
|
|
||||||
import notifStore from "@/store/notifStore";
|
|
||||||
import ExportedImage from "next-image-export-optimizer"
|
|
||||||
import menuStore from "@/store/menuStore";
|
|
||||||
|
|
||||||
function Navbar() {
|
|
||||||
const router = useRouter();
|
|
||||||
const {notifOpen} = notifStore()
|
|
||||||
const {setToggle} = menuStore()
|
|
||||||
const {data: dataUser, isSuccess} = useAPI.GET('user', '/ref/user/' + localStorage.getItem('userId'))
|
|
||||||
const {removeAuth} = useAuth()
|
|
||||||
const [MenuList, setMenuList] = useState([])
|
|
||||||
const {setModalPassword, setModalProfile} = modalStore()
|
|
||||||
const [current, setCurrent] = useState(null);
|
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
|
||||||
|
|
||||||
|
|
||||||
const ViewImage = ({fotoMember}) => {
|
|
||||||
if (fotoMember == null) return <UserOutlined className="userOutline" style={{background: '#eef6ff', borderRadius: '20px', padding: '10px'}}/>;
|
|
||||||
|
|
||||||
let getImage = '/';
|
|
||||||
return <img src={getImage} className="foto-member-nav"/>;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const logout = async () => {
|
|
||||||
let response = await API.GET('/auth/logout');
|
|
||||||
console.log(response)
|
|
||||||
if (response.status === 200) {
|
|
||||||
await removeAuth()
|
|
||||||
router.push("/login");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let valTheme = localStorage.getItem('valTheme')
|
|
||||||
let state = null
|
|
||||||
if (valTheme == 'true') {
|
|
||||||
state = true
|
|
||||||
document.body.classList.add('darkMode')
|
|
||||||
} else {
|
|
||||||
state = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const [isTheme, setTheme] = useState(state);
|
|
||||||
|
|
||||||
const buttonHandler = (val) => {
|
|
||||||
setTheme((status) => !status);
|
|
||||||
let theme = null
|
|
||||||
if (val != true) {
|
|
||||||
theme = 'lightMode'
|
|
||||||
document.body.classList.add(theme);
|
|
||||||
document.body.classList.remove('darkMode');
|
|
||||||
} else {
|
|
||||||
theme = 'darkMode'
|
|
||||||
document.body.classList.add(theme);
|
|
||||||
document.body.classList.remove('lightMode');
|
|
||||||
}
|
|
||||||
localStorage.setItem('setTheme', theme)
|
|
||||||
localStorage.setItem('valTheme', val)
|
|
||||||
};
|
|
||||||
|
|
||||||
const modalChangeProfile = () => {
|
|
||||||
setModalProfile(true)
|
|
||||||
}
|
|
||||||
const modalChangePassword = (type) => {
|
|
||||||
console.log(type)
|
|
||||||
setModalPassword(true, type)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getMenu = async () => {
|
|
||||||
let menu = await API.GET('/ref/menu');
|
|
||||||
if (menu.status !== 200) {
|
|
||||||
notifOpen("Gagal", menu?.result?.message, "danger");
|
|
||||||
} else {
|
|
||||||
let tmpMenu = []
|
|
||||||
menu?.result?.forEach((v, k) => {
|
|
||||||
|
|
||||||
let tmpChild = []
|
|
||||||
|
|
||||||
if (v.childs) {
|
|
||||||
v?.childs?.forEach((vChild, kChild) => {
|
|
||||||
|
|
||||||
let resultListChildThird = null
|
|
||||||
if (vChild.childs) {
|
|
||||||
resultListChildThird = vChild?.childs?.map((vChildThird, kChildThird) => {
|
|
||||||
return {
|
|
||||||
label: (<Link href={vChildThird.url}>{vChildThird.menuNm}</Link>),
|
|
||||||
key: vChildThird.menuId,
|
|
||||||
icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpChild.push(
|
|
||||||
{
|
|
||||||
label: (<Link href={vChild.url}>{vChild.menuNm}</Link>),
|
|
||||||
key: vChild.menuId,
|
|
||||||
icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>),
|
|
||||||
children: resultListChildThird
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
tmpChild = null
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpMenu.push(
|
|
||||||
{
|
|
||||||
label: (<Link href={v.url}>{v.menuNm}</Link>),
|
|
||||||
key: v.menuId,
|
|
||||||
icon: (<div dangerouslySetInnerHTML={{__html: v.iconCss,}}/>),
|
|
||||||
children: tmpChild
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
setMenuList(tmpMenu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const checkFirstLogin = () => {
|
|
||||||
if (dataUser?.result?.userStatusId === 3) {
|
|
||||||
modalChangePassword('first')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkPasswordExpired = () => {
|
|
||||||
if (dataUser?.result?.passwordExpired) {
|
|
||||||
modalChangePassword('expired')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isSuccess) {
|
|
||||||
checkFirstLogin()
|
|
||||||
checkPasswordExpired()
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [isSuccess]);
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getMenu()
|
|
||||||
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onClickMenu = (e) => {
|
|
||||||
// console.log('click ', e);
|
|
||||||
setCollapsed(!collapsed);
|
|
||||||
// document.querySelector(".backdrop").classList.remove("backdropMenu");
|
|
||||||
// document.querySelector(".menuInline").classList.remove("in");
|
|
||||||
// document.querySelector(".menuInline").classList.add("out");
|
|
||||||
setCurrent(e.key);
|
|
||||||
};
|
|
||||||
|
|
||||||
const [scroll, setScroll] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener("scroll", () => {
|
|
||||||
setScroll(window.scrollY > 15);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const [openDraw, setOpenDraw] = useState(false);
|
|
||||||
const showDrawer = () => {
|
|
||||||
setOpenDraw(true);
|
|
||||||
};
|
|
||||||
const closeDraw = () => {
|
|
||||||
setOpenDraw(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleCollapsed = () => {
|
|
||||||
setCollapsed(!collapsed);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/*<div className={"bg-nav-hov"}></div>*/}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<nav className={scroll ? 'navbar navScroll' : 'navbar'}>
|
|
||||||
<div className="nav-start">
|
|
||||||
<button className="btnMenuShow" onClick={toggleCollapsed}>
|
|
||||||
<MenuOutlined/>
|
|
||||||
</button>
|
|
||||||
<div className="nav-logo">
|
|
||||||
<button className={"btn-menu-toggle"} onClick={setToggle}><MenuUnfoldOutlined /></button>
|
|
||||||
<img src="/img/logo-white.png" alt=""/>
|
|
||||||
<div>
|
|
||||||
<div className="fw-bold text-uppercase titleText">
|
|
||||||
<small>v0.1.0</small>{" "}
|
|
||||||
</div>
|
|
||||||
{/*<div className="version fs-10">System Activity Monitoring</div>*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{collapsed ? <div id="backdrop" className="backdropMenu"></div> : ''}
|
|
||||||
<div className={collapsed ? 'menuInline in' : 'menuInline out'}>
|
|
||||||
<button className="btnMenuHide" onClick={toggleCollapsed}>
|
|
||||||
<CloseOutlined/>
|
|
||||||
</button>
|
|
||||||
{/*<Menu*/}
|
|
||||||
{/* mode="inline"*/}
|
|
||||||
{/* onClick={onClickMenu}*/}
|
|
||||||
{/* selectedKeys={[current]}*/}
|
|
||||||
{/* items={MenuList}*/}
|
|
||||||
{/*/>*/}
|
|
||||||
</div>
|
|
||||||
<div className="menuHorizontal">
|
|
||||||
{/*<Menu*/}
|
|
||||||
{/* onClick={onClickMenu}*/}
|
|
||||||
{/* selectedKeys={[current]}*/}
|
|
||||||
{/* mode="horizontal"*/}
|
|
||||||
{/* items={MenuList}*/}
|
|
||||||
{/*/>*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="nav-end">
|
|
||||||
|
|
||||||
<div className="nav-account" style={{display: 'flex'}}>
|
|
||||||
<div className="container-account">
|
|
||||||
|
|
||||||
<div className="account">
|
|
||||||
<div className="text">
|
|
||||||
<div className="name">{dataUser?.result?.fullName}</div>
|
|
||||||
<div className="role">{dataUser?.result?.roleNm}</div>
|
|
||||||
</div>
|
|
||||||
<ViewImage fotoMember={null}/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="detail-account">
|
|
||||||
<div className="header">
|
|
||||||
<ViewImage fotoMember={null}/>
|
|
||||||
<div className="text">
|
|
||||||
<div className="name">{dataUser?.result?.username}</div>
|
|
||||||
<div className="role">Cabang {dataUser?.result?.branchNm}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="feature">
|
|
||||||
<button type="button" style={{cursor: 'pointer'}} onClick={() => modalChangeProfile()}>Ubah Profil</button>
|
|
||||||
<button type="button" style={{cursor: 'pointer'}} onClick={() => modalChangePassword('normal')}>Ubah Password</button>
|
|
||||||
<div className="switchTheme">
|
|
||||||
<Switch style={{width: '50px'}} checkedChildren={<MoonOutlined/>} unCheckedChildren={<SunOutlined/>} onChange={buttonHandler} checked={isTheme}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="containerSignOut">
|
|
||||||
<button type="button" style={{cursor: 'pointer'}} onClick={() => logout()}>Sign Out</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button className="btnNotif" onClick={showDrawer}>
|
|
||||||
<BellOutlined/>
|
|
||||||
<div className="count">9</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<Drawer
|
|
||||||
title="Notifikasi"
|
|
||||||
placement='right'
|
|
||||||
closable={true}
|
|
||||||
onClose={closeDraw}
|
|
||||||
open={openDraw}
|
|
||||||
key='right'
|
|
||||||
>
|
|
||||||
<ul className="navNotif">
|
|
||||||
<li className="containerNotif">
|
|
||||||
<div className="date text-primary">
|
|
||||||
<span className="shape"></span>
|
|
||||||
<span>20 Januari 2024</span>
|
|
||||||
</div>
|
|
||||||
<div className="notification notif-unread">
|
|
||||||
<div className="containerIcon">
|
|
||||||
<div className="icon">
|
|
||||||
<BellOutlined/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="desc">
|
|
||||||
<div className="title">Aktifitas</div>
|
|
||||||
<div className="subtitle">update hasil aktifitas</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="notification notif-unread">
|
|
||||||
<div className="containerIcon">
|
|
||||||
<div className="icon">
|
|
||||||
<BellOutlined/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="desc">
|
|
||||||
<div className="title">Aktifitas</div>
|
|
||||||
<div className="subtitle">update hasil aktifitas</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="notification notif-unread">
|
|
||||||
<div className="containerIcon">
|
|
||||||
<div className="icon">
|
|
||||||
<BellOutlined/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="desc">
|
|
||||||
<div className="title">Aktifitas</div>
|
|
||||||
<div className="subtitle">update hasil aktifitas</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li className="containerNotif">
|
|
||||||
<div className="date text-primary">
|
|
||||||
<span className="shape"></span>
|
|
||||||
<span>19 Januari 2024</span>
|
|
||||||
</div>
|
|
||||||
<div className="notification notif-unread">
|
|
||||||
<div className="containerIcon">
|
|
||||||
<div className="icon">
|
|
||||||
<BellOutlined/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="desc">
|
|
||||||
<div className="title">Aktifitas</div>
|
|
||||||
<div className="subtitle">update hasil aktifitas</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</Drawer>
|
|
||||||
|
|
||||||
<div style={{background:"red"}}></div>
|
|
||||||
|
|
||||||
<ExportedImage
|
|
||||||
className="bg-nav"
|
|
||||||
src={"/img/bg152.jpg"}
|
|
||||||
fill={true}
|
|
||||||
// priority={true}
|
|
||||||
alt="background nav"
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default React.memo(Navbar);
|
|
@ -1,6 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, {useEffect, useRef, useState} from "react";
|
import React, {useEffect, useRef, useState} from "react";
|
||||||
import breadcrumbStore from "@/store/breadcrumbStore";
|
|
||||||
import modalStore from "@/store/modal";
|
import modalStore from "@/store/modal";
|
||||||
import confirmStore from "@/store/confirmStore";
|
import confirmStore from "@/store/confirmStore";
|
||||||
import {API} from "@/lib/API";
|
import {API} from "@/lib/API";
|
||||||
@ -33,7 +32,7 @@ const RefTemplate = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const formRef = useRef();
|
const formRef = useRef();
|
||||||
const {modalOpen, modalClose, FormId, modalStat, setModalLoading, setModalDetail, actionType} = modalStore();
|
const {modalOpen, modalClose, FormId, modalStat, setModalLoading, setModalDetail, actionType} = modalStore();
|
||||||
const {setSubTitle, setTitle, setShow} = breadcrumbStore();
|
|
||||||
const {confirmOpen, confirmClose, setConfirmLoading} = confirmStore();
|
const {confirmOpen, confirmClose, setConfirmLoading} = confirmStore();
|
||||||
const {notifOpen} = notifStore()
|
const {notifOpen} = notifStore()
|
||||||
|
|
||||||
@ -458,8 +457,6 @@ const RefTemplate = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTitle(refTitle);
|
|
||||||
setSubTitle(refSubTitle);
|
|
||||||
initColumn();
|
initColumn();
|
||||||
if (!serverSide){
|
if (!serverSide){
|
||||||
getData();
|
getData();
|
||||||
@ -486,8 +483,6 @@ const RefTemplate = ({
|
|||||||
<WrapperContent>
|
<WrapperContent>
|
||||||
<div className="containers">
|
<div className="containers">
|
||||||
<div className="headContent">
|
<div className="headContent">
|
||||||
|
|
||||||
|
|
||||||
<div className="containerTitle">
|
<div className="containerTitle">
|
||||||
<div className="breadCrumb">
|
<div className="breadCrumb">
|
||||||
<div className="text">{refTitle}</div>
|
<div className="text">{refTitle}</div>
|
||||||
@ -496,7 +491,7 @@ const RefTemplate = ({
|
|||||||
<div className="title text-dark-grey left">{refSubTitle}</div>
|
<div className="title text-dark-grey left">{refSubTitle}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="filter mt-3">
|
<div className="filter">
|
||||||
<SearchInput handleSearch={handleSearch}/>
|
<SearchInput handleSearch={handleSearch}/>
|
||||||
<div className={"container-act-toolbar mt-0"} style={{ width: 'auto' }}>
|
<div className={"container-act-toolbar mt-0"} style={{ width: 'auto' }}>
|
||||||
<ToolBar getData={getData}
|
<ToolBar getData={getData}
|
||||||
|
@ -5,24 +5,16 @@ import dayjs from 'dayjs';
|
|||||||
const {RangePicker} = DatePicker;
|
const {RangePicker} = DatePicker;
|
||||||
|
|
||||||
const rangePresets = [
|
const rangePresets = [
|
||||||
{ label: 'Seminggu terakhir', value: [dayjs().add(-7, 'd'), dayjs()] },
|
{label: 'Hari ini', value: [dayjs().startOf("day"), dayjs().endOf("day")]},
|
||||||
|
{label: '7 Hari Terakhir', value: [dayjs().add(-7, 'd'), dayjs()]},
|
||||||
{label: 'Bulan ini', value: [dayjs().startOf("month"), dayjs().endOf("month")]},
|
{label: 'Bulan ini', value: [dayjs().startOf("month"), dayjs().endOf("month")]},
|
||||||
{ label: 'Bulan lalu', value: [dayjs().startOf("month").month(dayjs().month() - 1), dayjs().endOf("month").month(dayjs().month() - 1)] },
|
{label: '1 Bulan Terakhir', value: [dayjs().add(-1, 'M'), dayjs()]},
|
||||||
{label: 'Tahun ini', value: [dayjs().startOf("year"), dayjs().endOf("year")]},
|
{label: '3 Bulan Terakhir', value: [dayjs().add(-3, 'M'), dayjs()]},
|
||||||
{label: 'Tahun lalu', value: [dayjs().startOf('year').year(dayjs().year() - 1), dayjs().endOf('year').year(dayjs().year() - 1)]},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const InputDateRange = ({
|
const InputDateRange = ({
|
||||||
title,
|
title, name, register, error, placeholder, maxlength, required, setValue, format = 'DD MMM YYYY', picker = 'default',
|
||||||
name,
|
|
||||||
register,
|
|
||||||
error,
|
|
||||||
placeholder,
|
|
||||||
maxlength,
|
|
||||||
required,
|
|
||||||
setValue,
|
|
||||||
format = 'DD MMM YYYY',
|
|
||||||
picker = 'default',
|
|
||||||
}) => {
|
}) => {
|
||||||
let setRequired = (required) ? {required: `Data ${title} Harus di Isi`} : {}
|
let setRequired = (required) ? {required: `Data ${title} Harus di Isi`} : {}
|
||||||
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
||||||
@ -31,18 +23,16 @@ const InputDateRange = ({
|
|||||||
|
|
||||||
const onChange = (_, dateString) => {
|
const onChange = (_, dateString) => {
|
||||||
setValue(name, {
|
setValue(name, {
|
||||||
startDate: dateString[0],
|
startDate: dateString[0], endDate: dateString[1]
|
||||||
endDate: dateString[1]
|
|
||||||
}, {shouldValidate: true})
|
}, {shouldValidate: true})
|
||||||
};
|
};
|
||||||
|
|
||||||
const newFormat = Helper.setFormatInputDate(picker, format)
|
const newFormat = Helper.setFormatInputDate(picker, format)
|
||||||
|
|
||||||
return (
|
return (<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`} style={{marginTop: '-18px'}}>
|
||||||
<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`} style={{marginTop: '-15px'}}>
|
|
||||||
<div className="floating-label-content">
|
<div className="floating-label-content">
|
||||||
<Space direction="vertical" size={0} className='w-full'>
|
<Space direction="vertical" size={0} className='w-full'>
|
||||||
<label className="floating-label" style={{zIndex: '1', top: '0'}} htmlFor={name}> {title} </label>
|
<label className="floating-label" htmlFor={name}> {title} </label>
|
||||||
<RangePicker
|
<RangePicker
|
||||||
{...register(name, validateList)}
|
{...register(name, validateList)}
|
||||||
name={name}
|
name={name}
|
||||||
@ -58,8 +48,7 @@ const InputDateRange = ({
|
|||||||
</Space>
|
</Space>
|
||||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default InputDateRange;
|
export default InputDateRange;
|
||||||
|
@ -13,6 +13,7 @@ const InputSelect = ({
|
|||||||
setDisabled,
|
setDisabled,
|
||||||
val,
|
val,
|
||||||
loading,
|
loading,
|
||||||
|
style,
|
||||||
withSearch = true,
|
withSearch = true,
|
||||||
getDataOnChange
|
getDataOnChange
|
||||||
}) => {
|
}) => {
|
||||||
@ -33,7 +34,7 @@ const InputSelect = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={`form-group mb-10 ${error[name]?.message ? "error" : ""}`}>
|
<div className={`form-group mb-10 ${error[name]?.message ? "error" : ""}`} style={style}>
|
||||||
<div className="floating-label-content">
|
<div className="floating-label-content">
|
||||||
<Select
|
<Select
|
||||||
disabled={setReadonly || setDisabled}
|
disabled={setReadonly || setDisabled}
|
||||||
|
138
src/components/util/Input/InputSelectRemote.jsx
Normal file
138
src/components/util/Input/InputSelectRemote.jsx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import { Select } from "antd";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import { API } from "@/lib/API";
|
||||||
|
|
||||||
|
let timeout;
|
||||||
|
let currentValue;
|
||||||
|
|
||||||
|
|
||||||
|
const InputSelectRemote = ({
|
||||||
|
title,
|
||||||
|
name,
|
||||||
|
endPoint,
|
||||||
|
register,
|
||||||
|
error,
|
||||||
|
required,
|
||||||
|
setValue,
|
||||||
|
setReadonly,
|
||||||
|
setDisabled,
|
||||||
|
setMultiple,
|
||||||
|
val,
|
||||||
|
withSearch = true,
|
||||||
|
getDataOnChange,
|
||||||
|
}) => {
|
||||||
|
const [data, setData] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
let setRequired = required ? { required: `Data ${title} Harus di Isi` } : {};
|
||||||
|
let validateList = { ...setRequired };
|
||||||
|
|
||||||
|
const handleChange = (value) => {
|
||||||
|
setValue(name, value, { shouldValidate: true });
|
||||||
|
if (getDataOnChange) getDataOnChange(value, setValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultData = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
let res = await API.GET(endPoint + "?page=0&size=10");
|
||||||
|
const data = res.result.data.map((v) => ({
|
||||||
|
value: v.wilayahId,
|
||||||
|
text: v.wil,
|
||||||
|
}));
|
||||||
|
setData(data)
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetch = (value, callback) => {
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
}
|
||||||
|
currentValue = value;
|
||||||
|
const getData = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
let res = await API.GET(endPoint + "?page=0&size=10&search=" + value);
|
||||||
|
console.log(res);
|
||||||
|
const data = res.result.data.map((v) => ({
|
||||||
|
value: v.wilayahId,
|
||||||
|
text: v.wil,
|
||||||
|
}));
|
||||||
|
setLoading(false);
|
||||||
|
callback(data);
|
||||||
|
};
|
||||||
|
if (value) {
|
||||||
|
timeout = setTimeout(getData, 1000);
|
||||||
|
} else {
|
||||||
|
callback([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = (newValue) => {
|
||||||
|
setData([[]])
|
||||||
|
fetch(newValue, setData);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
defaultData()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getById = async (id) => {
|
||||||
|
setLoading(true);
|
||||||
|
let res = await API.GET(endPoint + "/" + id);
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
setData([{
|
||||||
|
value: res?.result?.wilayahId,
|
||||||
|
text: res?.result?.wil,
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (val){
|
||||||
|
getById(val)
|
||||||
|
}
|
||||||
|
}, [val]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={`form-group mb-10 ${error[name]?.message ? "error" : ""}`}
|
||||||
|
>
|
||||||
|
<div className="floating-label-content">
|
||||||
|
<Select
|
||||||
|
disabled={setReadonly || setDisabled}
|
||||||
|
mode={setMultiple ? "multiple" : false}
|
||||||
|
{...register(name, validateList)}
|
||||||
|
name={name}
|
||||||
|
showSearch={withSearch}
|
||||||
|
id={name}
|
||||||
|
value={val}
|
||||||
|
loading={loading}
|
||||||
|
onChange={handleChange}
|
||||||
|
onSearch={handleSearch}
|
||||||
|
filterOption={false}
|
||||||
|
allowClear={true}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
placeholder={"Ketik Untuk Mencari Data " + title}
|
||||||
|
className="form-control borderInput floating-input"
|
||||||
|
notFoundContent={<div>Data tidak ditemukan</div>}
|
||||||
|
options={(data || []).map((d) => ({
|
||||||
|
value: d.value,
|
||||||
|
label: d.text,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<label className="floating-label" htmlFor={name}>
|
||||||
|
{title}{" "}
|
||||||
|
{required ? <span className={"fw-7 text-danger"}>*</span> : ""}
|
||||||
|
</label>
|
||||||
|
{error[name] && (
|
||||||
|
<div className="error-form">{error[name]?.message}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InputSelectRemote;
|
@ -15,12 +15,14 @@ import InputCustom from "./InputCustom";
|
|||||||
import InputPercentage from "./InputPercentage";
|
import InputPercentage from "./InputPercentage";
|
||||||
import InputSwitch from "./InputSwitch";
|
import InputSwitch from "./InputSwitch";
|
||||||
import InputAntFile from "./InputAntFile";
|
import InputAntFile from "./InputAntFile";
|
||||||
|
import InputSelectRemote from "@/components/util/Input/InputSelectRemote";
|
||||||
|
|
||||||
const Input = {
|
const Input = {
|
||||||
Text: InputText,
|
Text: InputText,
|
||||||
Number: InputNumber,
|
Number: InputNumber,
|
||||||
Money: InputMoney,
|
Money: InputMoney,
|
||||||
Select: InputSelect,
|
Select: InputSelect,
|
||||||
|
SelectRemote: InputSelectRemote,
|
||||||
Username: InputUsername,
|
Username: InputUsername,
|
||||||
Email: InputEmail,
|
Email: InputEmail,
|
||||||
Password: InputPassword,
|
Password: InputPassword,
|
||||||
@ -36,23 +38,4 @@ const Input = {
|
|||||||
AntFile: InputAntFile
|
AntFile: InputAntFile
|
||||||
}
|
}
|
||||||
|
|
||||||
export const REF_INPUT_NAME = {
|
|
||||||
TEXT: 'Text',
|
|
||||||
NUMBER: 'Number',
|
|
||||||
MONEY: 'Money',
|
|
||||||
SELECT: 'Select',
|
|
||||||
USERNAME: 'Username',
|
|
||||||
EMAIL: 'Email',
|
|
||||||
PASSWORD: 'Password',
|
|
||||||
TEXTAREA: 'Textarea',
|
|
||||||
IMAGE: 'Image',
|
|
||||||
DATERANGE: 'DateRange',
|
|
||||||
TEXT_TASK: 'TextTask',
|
|
||||||
DATE: 'Date',
|
|
||||||
UPLOAD_IMAGE: 'UploadImage',
|
|
||||||
CUSTOM: 'Custom',
|
|
||||||
PERCENTAGE: 'Percentage',
|
|
||||||
SWITCH: 'Switch',
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Input
|
export default Input
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
import {motion} from "framer-motion"
|
import {motion} from "framer-motion"
|
||||||
|
import {useEffect} from "react";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import menuStore from "@/store/menuStore";
|
||||||
|
|
||||||
export default function WrapperContent({children,type}) {
|
export default function WrapperContent({children,type}) {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const {setLoadingPageStatus} = menuStore()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoadingPageStatus(false)
|
||||||
|
}, [router]);
|
||||||
return(
|
return(
|
||||||
<>
|
<>
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, x: 40 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
exit={{ opacity: 0, y: 20 }}
|
exit={{ opacity: 0, x: 0 }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<div className={(type) ? 'setImageBoard':''}></div>
|
<div className={(type) ? 'setImageBoard':''}></div>
|
||||||
|
@ -13,447 +13,85 @@ const role = async () => {
|
|||||||
let response = await API.GET(`/ref/branch`);
|
let response = await API.GET(`/ref/branch`);
|
||||||
return response?.result?.data?.map((v) => {
|
return response?.result?.data?.map((v) => {
|
||||||
return {
|
return {
|
||||||
value: v.kdCab,
|
value: v.branchId,
|
||||||
label: v.namaCabang,
|
label: v.nm,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const productType = async () => {
|
const divisi = async () => {
|
||||||
let response = await API.GET(`/ref/productType`);
|
let response = await API.GET(`/ref/divisi`);
|
||||||
return response?.result?.data?.map((v) => {
|
return response?.result?.data?.map((v) => {
|
||||||
return {
|
return {
|
||||||
value: v.productTypeId,
|
value: v.divisiId,
|
||||||
label: v.definition,
|
label: v.divisiNm,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const product = async () => {
|
const agama = async () => {
|
||||||
let response = await API.GET(`/ref/product`);
|
let response = await API.GET(`/ref/agama`);
|
||||||
return response?.result?.data?.map((v) => {
|
return response?.result?.data?.map((v) => {
|
||||||
return {
|
return {
|
||||||
value: v.id,
|
value: v.agamaId,
|
||||||
label: v.prodName,
|
label: v.agamaNm,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const jabatan = async () => {
|
||||||
const branchType = async () => {
|
let response = await API.GET(`/ref/jabatan`);
|
||||||
let response = await API.GET(`/ref/branch-type`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
return response?.result?.data?.map((v) => {
|
||||||
return {
|
return {
|
||||||
value: v.id,
|
value: v.jabatanId,
|
||||||
label: v.definition,
|
label: v.jabatanNm,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const branch = async () => {
|
|
||||||
let response = await API.GET(`/ref/branch`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.branchName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const wilayah = async () => {
|
|
||||||
let response = await API.GET(`/ref/wilayah`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.wilayahId,
|
|
||||||
label: v.wil,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const bank = async () => {
|
|
||||||
let response = await API.GET(`/ref/bank`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.bankCode,
|
|
||||||
label: v.bankDescription,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const productGroup = async () => {
|
|
||||||
let response = await API.GET(`/ref/group-product`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.productGrpName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const developer = async () => {
|
|
||||||
let response = await API.GET(`/ref/developer`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.developerName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const productCode = async () => {
|
|
||||||
let response = await API.GET(`/cbs/loan-product`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.prodid,
|
|
||||||
label: v.prodnm,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const aplId = async () => {
|
|
||||||
let response = await API.GET(`/cbs-config/applid`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.parmid,
|
|
||||||
label: v.parmnm,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const govPRG = async () => {
|
|
||||||
let response = await API.GET(`/cbs-config/govprg`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.parmid,
|
|
||||||
label: v.parmnm,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const proposalType = async () => {
|
|
||||||
let response = await API.GET(`/ref/proposal-type`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const workflowStatus = async () => {
|
|
||||||
let response = await API.GET(`/ref/workflow-status`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.statusDefinition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const groupUser = async () => {
|
|
||||||
let response = await API.GET(`/ref/user-group`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.groupDefinition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const workflowType = async () => {
|
|
||||||
let response = await API.GET(`/ref/workflow-type`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const pekerjaanPPDPP = async () => {
|
|
||||||
let response = await API.GET(`/ref/pekerjaan-ppdpp`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.pekerjaan,
|
|
||||||
label: v.nmPekerjaan,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusPembiayaan = async () => {
|
|
||||||
let response = await API.GET(`/ref/status-pembiayaan`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.statusPembiayaan,
|
|
||||||
label: v.namaStatusPembiayaan,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const pekerjaan = async () => {
|
|
||||||
let response = await API.GET(`/ref/pekerjaan`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.idPekerjaan,
|
|
||||||
label: v.nmPekerjaan,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const accountTypeFLPP = async () => {
|
|
||||||
let response = await API.GET(`/ref/jenis_accflpp`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const masterGroupScoring = async () => {
|
|
||||||
let response = await API.GET(`/ref/master-group-scoring`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.paramName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const developerScoring = async () => {
|
|
||||||
let response = await API.GET(`/ref/developer-param-scoring`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const productTapera = async (filter = '') => {
|
|
||||||
if ( filter ) {
|
|
||||||
filter = '?' + new URLSearchParams(filter).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
let response = await API.GET(`/ref-tapera/product${filter}`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.namaProduk,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const jenisPerumahanTapera = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/jenis-perumahan`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const perumahanTapera = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/rumah`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.idRumah,
|
|
||||||
label: v.namaPerumahan,
|
|
||||||
...v
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const wilayahTapera = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/wilayah/dropdown`);
|
|
||||||
return response?.result?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.wilayahId,
|
|
||||||
label: v.wil,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const jenisImbPbg = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/jenis-imb/dropdown`);
|
|
||||||
return response?.result?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const segemenPekerjaan = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/segmen-pekerjaan/dropdown`);
|
|
||||||
return response?.result?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.segmenCode,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const jenisAkadTapera = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/jenis-akad/dropdown`);
|
|
||||||
return response?.result?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const jenisBungaTapera = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/jenis-bunga/dropdown`);
|
|
||||||
return response?.result?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const jenisPembayaranAngsuran = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/jenis-bayar-angsuran/dropdown`);
|
|
||||||
return response?.result?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const jenisKelamin = async () => {
|
const jenisKelamin = async () => {
|
||||||
let response = await API.GET(`/ref/jenis-kelamin`);
|
let response = await API.GET(`/ref/jenisKelamin`);
|
||||||
return response?.result?.data?.map((v) => {
|
return response?.result?.data?.map((v) => {
|
||||||
return {
|
return {
|
||||||
value: v.id,
|
value: v.jenisKelaminId,
|
||||||
label: v.description,
|
label: v.jenisKelaminNm,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const statusKaryawan = async () => {
|
||||||
const statusKawin = async () => {
|
let response = await API.GET(`/ref/statusKaryawan`);
|
||||||
let response = await API.GET(`/ref/status-kawin`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
return response?.result?.data?.map((v) => {
|
||||||
return {
|
return {
|
||||||
value: v.idStatusKawin,
|
value: v.statusKaryawanId,
|
||||||
label: v.nmStatusKawin,
|
label: v.statusKaryawanNm,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const jenisPembiayaan = async () => {
|
const karyawan = async () => {
|
||||||
let response = await API.GET(`/ref-tapera/jenis-pembiayaan`);
|
let response = await API.GET(`/ref/karyawan`);
|
||||||
return response?.result?.data?.map((v) => {
|
return response?.result?.data?.map((v) => {
|
||||||
return {
|
return {
|
||||||
value: v.id,
|
value: v.karyawanId,
|
||||||
label: v.definition,
|
label: v.karyawanNm,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const jenisPenjadwalan = async () => {
|
||||||
const prinsipPembiayaan = async () => {
|
let response = await API.GET(`/ref/tipeQuotes`);
|
||||||
let response = await API.GET(`/ref-tapera/prinsip-pembiayaan`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
return response?.result?.data?.map((v) => {
|
||||||
return {
|
return {
|
||||||
value: v.id,
|
value: v.tipeQuotesId,
|
||||||
label: v.definition,
|
label: v.tipeQuotesNm,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const tipeProgram = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/tipe-program`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const lokasiPerumahanTapera = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/perumahaan/dropdown`);
|
|
||||||
return response?.result?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.idLokasi,
|
|
||||||
label: v.namaPerumahan,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const kolektibilitas = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/kolektibilitas`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.definition,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const developerTapera = async () => {
|
|
||||||
let response = await API.GET(`/ref-tapera/developer`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.developerName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const jenisSertifikat = async () => {
|
|
||||||
let response = await API.GET(`/ref/jenis-sertifikat`);
|
|
||||||
return response?.result?.data?.map((v) => {
|
|
||||||
return {
|
|
||||||
value: v.id,
|
|
||||||
label: v.defJenis,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const DropdownAPI = {
|
export const DropdownAPI = {
|
||||||
role,
|
role,
|
||||||
cabang,
|
cabang,
|
||||||
productType,
|
divisi,
|
||||||
branchType,
|
agama,
|
||||||
branch,
|
jabatan,
|
||||||
bank,
|
|
||||||
wilayah,
|
|
||||||
productGroup,
|
|
||||||
productCode,
|
|
||||||
aplId,
|
|
||||||
govPRG,
|
|
||||||
developer,
|
|
||||||
product,
|
|
||||||
proposalType,
|
|
||||||
workflowStatus,
|
|
||||||
groupUser,
|
|
||||||
workflowType,
|
|
||||||
pekerjaanPPDPP,
|
|
||||||
statusPembiayaan,
|
|
||||||
pekerjaan,
|
|
||||||
accountTypeFLPP,
|
|
||||||
masterGroupScoring,
|
|
||||||
developerScoring,
|
|
||||||
productTapera,
|
|
||||||
jenisPerumahanTapera,
|
|
||||||
perumahanTapera,
|
|
||||||
wilayahTapera,
|
|
||||||
jenisImbPbg,
|
|
||||||
segemenPekerjaan,
|
|
||||||
jenisAkadTapera,
|
|
||||||
jenisBungaTapera,
|
|
||||||
jenisPembayaranAngsuran,
|
|
||||||
jenisKelamin,
|
jenisKelamin,
|
||||||
statusKawin,
|
statusKaryawan,
|
||||||
jenisPembiayaan,
|
karyawan,
|
||||||
prinsipPembiayaan,
|
jenisPenjadwalan
|
||||||
tipeProgram,
|
|
||||||
lokasiPerumahanTapera,
|
|
||||||
kolektibilitas,
|
|
||||||
developerTapera,
|
|
||||||
jenisSertifikat
|
|
||||||
};
|
};
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
import {create} from 'zustand';
|
|
||||||
|
|
||||||
const breadcrumbStore = create((set) => ({
|
|
||||||
title: '',
|
|
||||||
subTitle: '',
|
|
||||||
widthTitle: '0px',
|
|
||||||
setTitle: (data) => set(() => ({title: data})),
|
|
||||||
setSubTitle: (data) => set(() => ({subTitle: data})),
|
|
||||||
setHide: () => set(() => ({widthTitle: '0px'})),
|
|
||||||
setShow: () => set(() => ({widthTitle: '270px'})),
|
|
||||||
|
|
||||||
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default breadcrumbStore;
|
|
@ -2,7 +2,9 @@ import {create} from 'zustand';
|
|||||||
|
|
||||||
const menuStore = create((set) => ({
|
const menuStore = create((set) => ({
|
||||||
toggleStatus: true,
|
toggleStatus: true,
|
||||||
|
loadingPageStatus:false,
|
||||||
setToggle: () => set((prev) => ({toggleStatus: !prev.toggleStatus})),
|
setToggle: () => set((prev) => ({toggleStatus: !prev.toggleStatus})),
|
||||||
|
setLoadingPageStatus: (stat) => set((prev) => ({loadingPageStatus: stat})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default menuStore;
|
export default menuStore;
|
@ -1,96 +0,0 @@
|
|||||||
import {create} from "zustand";
|
|
||||||
|
|
||||||
const modalDashboardStore = create((set) => ({
|
|
||||||
modalStat: false,
|
|
||||||
modalLoading: false,
|
|
||||||
FormId: null,
|
|
||||||
actionType: null,
|
|
||||||
typeData: null,
|
|
||||||
typeKolek: null,
|
|
||||||
datatableDetail: false,
|
|
||||||
datatableDetailCabang: false,
|
|
||||||
datatableDetailKolektability: false,
|
|
||||||
datatableDetailNasabah: false,
|
|
||||||
dataNasabah: false,
|
|
||||||
kdCabangKonsol: null,
|
|
||||||
kdCabang: null,
|
|
||||||
nmCabangKonsol: null,
|
|
||||||
nmCabang: null,
|
|
||||||
customerId: null,
|
|
||||||
title: null,
|
|
||||||
subTitle: null,
|
|
||||||
modalOpen: (id, action) =>
|
|
||||||
set(() => ({
|
|
||||||
modalStat: true,
|
|
||||||
modalLoading: true,
|
|
||||||
FormId: id,
|
|
||||||
actionType: action
|
|
||||||
})),
|
|
||||||
modalClose: () =>
|
|
||||||
set(() => ({
|
|
||||||
modalStat: false,
|
|
||||||
FormId: null,
|
|
||||||
})),
|
|
||||||
setModalLoading: (status, type) =>
|
|
||||||
set(() => ({
|
|
||||||
modalLoading: status,
|
|
||||||
})),
|
|
||||||
setTypeData: (text) =>
|
|
||||||
set(() => ({
|
|
||||||
typeData: text
|
|
||||||
})),
|
|
||||||
setTypeKolek: (text) =>
|
|
||||||
set(() => ({
|
|
||||||
typeKolek: text
|
|
||||||
})),
|
|
||||||
setDatatableDetail: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
datatableDetail: status
|
|
||||||
})),
|
|
||||||
setDatatableDetailCabang: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
datatableDetailCabang: status
|
|
||||||
})),
|
|
||||||
setDatatableDetailKolektability: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
datatableDetailKolektability: status
|
|
||||||
})),
|
|
||||||
setDatatableDetailNasabah: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
datatableDetailNasabah: status
|
|
||||||
})),
|
|
||||||
setDataNasabah: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
dataNasabah: status
|
|
||||||
})),
|
|
||||||
setKdCabangKonsol: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
kdCabangKonsol: status
|
|
||||||
})),
|
|
||||||
setKdCabang: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
kdCabang: status
|
|
||||||
})),
|
|
||||||
setNmCabangKonsol: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
nmCabangKonsol: status
|
|
||||||
})),
|
|
||||||
setNmCabang: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
nmCabang: status
|
|
||||||
})),
|
|
||||||
setCustomerId: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
customerId: status
|
|
||||||
})),
|
|
||||||
setTitle: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
title: status
|
|
||||||
})),
|
|
||||||
setSubTitle: (status) =>
|
|
||||||
set(() => ({
|
|
||||||
subTitle: status
|
|
||||||
}))
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default modalDashboardStore;
|
|
@ -1,9 +0,0 @@
|
|||||||
import {create} from 'zustand';
|
|
||||||
|
|
||||||
const useStore = create((set) => ({
|
|
||||||
count: 0,
|
|
||||||
increment: () => set((state) => ({ count: state.count + 1 })),
|
|
||||||
decrement: () => set((state) => ({ count: state.count - 1 })),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default useStore;
|
|
Loading…
Reference in New Issue
Block a user