diff --git a/.env.development b/.env.development index 50bbd8a..53f7347 100644 --- a/.env.development +++ b/.env.development @@ -1,4 +1,4 @@ -VITE_BASE_URL=https://api.domain.com/v1/ +VITE_BASE_URL=http://localhost:5173 VITE_BASE_DIRECTORY=/ VITE_APP_VERSION=0.0.1 VITE_APP_NAME='Executive Information System' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 38adffa..08910b9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ yarn-error.log* pnpm-debug.log* lerna-debug.log* + node_modules .DS_Store dist @@ -26,3 +27,4 @@ coverage *.njsproj *.sln *.sw? +data.ts \ No newline at end of file diff --git a/README.md b/README.md index f4561c5..b3541a9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# apkt +# Executive Information System This template should help get you started developing with Vue 3 in Vite. diff --git a/src/App.vue b/src/App.vue index 6e654db..25b53f2 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,8 +3,11 @@ import { RouterView } from 'vue-router' import { NotificationProvider } from '@/components/Notification' import { useDialogStore } from '@/stores/dialog' import ActionDialog from '@/components/Dialogs/ActionDialog.vue'; +import CommandPalettes from '@/components/CommandPalettes.vue'; +import { useCommandPalattesStore } from '@/stores/command'; const dialog = useDialogStore() +const command = useCommandPalattesStore() diff --git a/src/assets/css/base.css b/src/assets/css/base.css index 77615aa..b8039e7 100644 --- a/src/assets/css/base.css +++ b/src/assets/css/base.css @@ -1,23 +1,25 @@ /* Firefox */ * { - scrollbar-width: 4px; + scrollbar-width: 6px; scrollbar-color: var(--secondary) var(--primary); } /* Chrome, Edge, and Safari */ -*::-webkit-scrollbar { - width: 4px; +::-webkit-scrollbar { + width: 6px; } -*::-webkit-scrollbar-track { - background: var(--primary); - border-radius: 5px; +::-webkit-scrollbar-track { + border-radius: 6px; } -*::-webkit-scrollbar-thumb { - background-color: var(--secondary); - border-radius: 14px; - border: 3px solid var(--primary); +::-webkit-scrollbar-thumb { + background: #cddee3; + border-radius: 10px; +} + +::-webkit-scrollbar-thumb:hover { + background: #9abdc6; } * { -webkit-tap-highlight-color: rgba(0,0,0,0); } diff --git a/src/assets/css/style.css b/src/assets/css/style.css index 413cdd8..33a7af8 100644 --- a/src/assets/css/style.css +++ b/src/assets/css/style.css @@ -705,6 +705,7 @@ select { --tw-backdrop-sepia: ; } +<<<<<<< HEAD .container { width: 100%; } @@ -737,6 +738,139 @@ select { .container { max-width: 1536px; } +======= +/* NavBar */ + +.menu-item { + display: block; + width: 100%; + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.75rem; + text-align: left; + font-size: 1rem; + line-height: 1.5rem; + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity)); +} + +.menu-item-active { + display: block; + width: 100%; + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.75rem; + text-align: left; + font-size: 1rem; + line-height: 1.5rem; + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity)); +} + +.container-menu-item { + position: absolute; + right: 0px; + z-index: 10; + margin-top: 0.5rem; + width: 12rem; + transform-origin: top right; + overflow: hidden; + border-radius: 0.5rem; + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity)); + --tw-ring-opacity: 0.05; +} + +.container-menu-item:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.container-menu-profile { + display: block; + flex-shrink: 0; + border-bottom-width: 1px; + --tw-border-opacity: 1; + border-color: rgb(249 250 251 / var(--tw-border-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(3 91 113 / var(--tw-bg-opacity)); + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +/* Aside */ + +.aside-single-item-active { + display: flex; + width: 100%; + align-items: center; + border-radius: 0.75rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 0.5rem; + padding-right: 1rem; + font-size: 0.75rem; + line-height: 1rem; + --tw-bg-opacity: 1; + background-color: rgb(3 91 113 / var(--tw-bg-opacity)); + font-weight: 700; + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.aside-single-item-inactive { + display: flex; + width: 100%; + align-items: center; + border-radius: 0.75rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 0.5rem; + padding-right: 1rem; + font-size: 0.75rem; + line-height: 1rem; + font-weight: 600; + color: rgb(46 53 54 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.group:hover .aside-single-item-inactive { + background-color: rgb(205 222 227 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(3 91 113 / var(--tw-bg-opacity)); + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.aside-single-item-icon { + height: 1.5rem; + width: 1.5rem; +} + +.aside-single-item-icon-inactive { + height: 1.5rem; + width: 1.5rem; + --tw-text-opacity: 1; + color: rgb(46 53 54 / var(--tw-text-opacity)); +} + +.group:hover .aside-single-item-icon-inactive { + stroke: #fff; +>>>>>>> 1885f28d62cccd232f8b53fac507e44d59bb191d } .sr-only { @@ -958,10 +1092,6 @@ select { margin-left: 1rem; } -.ml-auto { - margin-left: auto; -} - .mr-1 { margin-right: 0.25rem; } @@ -970,10 +1100,6 @@ select { margin-right: 0.5rem; } -.mr-3 { - margin-right: 0.75rem; -} - .mr-4 { margin-right: 1rem; } @@ -1073,10 +1199,6 @@ select { height: 0.5rem; } -.h-2\.5 { - height: 0.625rem; -} - .h-3 { height: 0.75rem; } @@ -1093,10 +1215,6 @@ select { height: 1.5rem; } -.h-7 { - height: 1.75rem; -} - .h-8 { height: 2rem; } @@ -1109,10 +1227,6 @@ select { height: 2.7rem; } -.h-\[74vh\] { - height: 74vh; -} - .h-\[calc\(100\%-64px\)\] { height: calc(100% - 64px); } @@ -1142,10 +1256,6 @@ select { max-height: 1000px; } -.min-h-0 { - min-height: 0px; -} - .min-h-full { min-height: 100%; } @@ -1166,10 +1276,6 @@ select { width: 2.5rem; } -.w-11\/12 { - width: 91.666667%; -} - .w-12 { width: 3rem; } @@ -1182,10 +1288,6 @@ select { width: 0.5rem; } -.w-2\.5 { - width: 0.625rem; -} - .w-3 { width: 0.75rem; } @@ -1198,10 +1300,6 @@ select { width: 10rem; } -.w-48 { - width: 12rem; -} - .w-5 { width: 1.25rem; } @@ -1214,10 +1312,6 @@ select { width: 1.5rem; } -.w-7 { - width: 1.75rem; -} - .w-8 { width: 2rem; } @@ -1250,14 +1344,6 @@ select { width: 1px; } -.w-screen { - width: 100vw; -} - -.min-w-0 { - min-width: 0px; -} - .max-w-2xl { max-width: 42rem; } @@ -1266,10 +1352,6 @@ select { max-width: 80rem; } -.max-w-full { - max-width: 100%; -} - .max-w-sm { max-width: 24rem; } @@ -1334,11 +1416,6 @@ select { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } -.translate-x-full { - --tw-translate-x: 100%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - .translate-y-0 { --tw-translate-y: 0px; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -1503,11 +1580,6 @@ select { border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); } -.divide-gray-50 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(249 250 251 / var(--tw-divide-opacity)); -} - .divide-gray-500 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(107 114 128 / var(--tw-divide-opacity)); @@ -1582,10 +1654,6 @@ select { border-width: 0px; } -.border-4 { - border-width: 4px; -} - .border-x { border-left-width: 1px; border-right-width: 1px; @@ -1620,10 +1688,6 @@ select { border-style: solid; } -.border-dashed { - border-style: dashed; -} - .border-black\/\[\.1\] { border-color: rgb(0 0 0 / .1); } @@ -1633,16 +1697,12 @@ select { border-color: rgb(243 244 246 / var(--tw-border-opacity)); } -.border-gray-200 { - --tw-border-opacity: 1; - border-color: rgb(229 231 235 / var(--tw-border-opacity)); -} - .border-gray-300 { --tw-border-opacity: 1; border-color: rgb(209 213 219 / var(--tw-border-opacity)); } +<<<<<<< HEAD .border-gray-50 { --tw-border-opacity: 1; border-color: rgb(249 250 251 / var(--tw-border-opacity)); @@ -1653,6 +1713,8 @@ select { border-color: rgb(3 91 113 / var(--tw-border-opacity)); } +======= +>>>>>>> 1885f28d62cccd232f8b53fac507e44d59bb191d .border-transparent { border-color: transparent; } @@ -1692,11 +1754,14 @@ select { background-color: rgb(17 24 39 / var(--tw-bg-opacity)); } +<<<<<<< HEAD .bg-green-400 { --tw-bg-opacity: 1; background-color: rgb(74 222 128 / var(--tw-bg-opacity)); } +======= +>>>>>>> 1885f28d62cccd232f8b53fac507e44d59bb191d .bg-indigo-600 { --tw-bg-opacity: 1; background-color: rgb(79 70 229 / var(--tw-bg-opacity)); @@ -1796,10 +1861,13 @@ select { --tw-bg-opacity: 0.8; } +<<<<<<< HEAD .bg-none { background-image: none; } +======= +>>>>>>> 1885f28d62cccd232f8b53fac507e44d59bb191d .fill-gray-400 { fill: #9ca3af; } @@ -1820,6 +1888,17 @@ select { fill: #007b8d; } +<<<<<<< HEAD +======= +.fill-white { + fill: #fff; +} + +.stroke-white { + stroke: #fff; +} + +>>>>>>> 1885f28d62cccd232f8b53fac507e44d59bb191d .p-1 { padding: 0.25rem; } @@ -1891,11 +1970,6 @@ select { padding-right: 1rem; } -.px-5 { - padding-left: 1.25rem; - padding-right: 1.25rem; -} - .px-6 { padding-left: 1.5rem; padding-right: 1.5rem; @@ -1960,22 +2034,18 @@ select { padding-bottom: 1rem; } +.pl-1 { + padding-left: 0.25rem; +} + .pl-11 { padding-left: 2.75rem; } -.pl-2 { - padding-left: 0.5rem; -} - .pl-3 { padding-left: 0.75rem; } -.pr-1 { - padding-right: 0.25rem; -} - .pr-12 { padding-right: 3rem; } @@ -2008,10 +2078,6 @@ select { padding-top: 0.5rem; } -.pt-4 { - padding-top: 1rem; -} - .pt-5 { padding-top: 1.25rem; } @@ -2024,16 +2090,16 @@ select { text-align: center; } +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} + .text-3xl { font-size: 1.875rem; line-height: 2.25rem; } -.text-4xl { - font-size: 2.25rem; - line-height: 2.5rem; -} - .text-\[10px\] { font-size: 10px; } @@ -2218,6 +2284,11 @@ select { color: rgb(3 91 113 / var(--tw-text-opacity)); } +.text-primary-800 { + --tw-text-opacity: 1; + color: rgb(1 36 45 / var(--tw-text-opacity)); +} + .text-primary-900 { --tw-text-opacity: 1; color: rgb(1 18 23 / var(--tw-text-opacity)); @@ -2365,12 +2436,6 @@ select { box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } -.ring-2 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} - .ring-inset { --tw-ring-inset: inset; } @@ -2385,15 +2450,6 @@ select { --tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity)); } -.ring-transparent { - --tw-ring-color: transparent; -} - -.ring-white { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity)); -} - .ring-opacity-5 { --tw-ring-opacity: 0.05; } @@ -2418,12 +2474,6 @@ select { backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } -.backdrop-blur-sm { - --tw-backdrop-blur: blur(4px); - -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} - .transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; @@ -2450,6 +2500,12 @@ select { transition-duration: 150ms; } +.transition-transform { + transition-property: transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + .delay-300 { transition-delay: 300ms; } @@ -2524,6 +2580,7 @@ select { color: rgb(75 85 99 / var(--tw-text-opacity)); } +<<<<<<< HEAD .hover\:overflow-y-auto:hover { overflow-y: auto; } @@ -2533,6 +2590,8 @@ select { border-color: rgb(3 91 113 / var(--tw-border-opacity)); } +======= +>>>>>>> 1885f28d62cccd232f8b53fac507e44d59bb191d .hover\:bg-gray-200:hover { --tw-bg-opacity: 1; background-color: rgb(229 231 235 / var(--tw-bg-opacity)); @@ -2617,10 +2676,6 @@ select { border-color: rgb(243 244 246 / var(--tw-border-opacity)); } -.focus\:border-transparent:focus { - border-color: transparent; -} - .focus\:border-vtd-primary-300:focus { --tw-border-opacity: 1; border-color: rgb(104 157 170 / var(--tw-border-opacity)); @@ -2740,6 +2795,7 @@ select { background-color: rgb(53 124 141 / var(--tw-bg-opacity)); } +<<<<<<< HEAD .disabled\:text-primary-300:disabled { --tw-text-opacity: 1; color: rgb(104 157 170 / var(--tw-text-opacity)); @@ -2755,23 +2811,24 @@ select { background-color: rgb(205 222 227 / var(--tw-bg-opacity)); } +======= +>>>>>>> 1885f28d62cccd232f8b53fac507e44d59bb191d .group:hover .group-hover\:fill-gray-500 { fill: #6b7280; } +.group:hover .group-hover\:fill-white { + fill: #fff; +} + .group:hover .group-hover\:text-gray-500 { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); } -.group:hover .group-hover\:text-gray-700 { +.group:hover .group-hover\:text-white { --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.group:hover .group-hover\:text-gray-900 { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); + color: rgb(255 255 255 / var(--tw-text-opacity)); } @media (prefers-color-scheme: dark) { @@ -3067,11 +3124,6 @@ select { padding-right: 1rem; } - .sm\:px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; - } - .sm\:py-32 { padding-top: 8rem; padding-bottom: 8rem; @@ -3117,10 +3169,6 @@ select { --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } - - .sm\:duration-700 { - transition-duration: 700ms; - } } @media (min-width: 768px) { @@ -3133,10 +3181,6 @@ select { bottom: 0px; } - .md\:ml-0 { - margin-left: 0px; - } - .md\:ml-6 { margin-left: 1.5rem; } @@ -3212,6 +3256,10 @@ select { padding-bottom: 1.5rem; } + .md\:pl-4 { + padding-left: 1rem; + } + .md\:pl-80 { padding-left: 20rem; } @@ -3291,10 +3339,6 @@ select { padding-right: 2rem; } - .lg\:pl-10 { - padding-left: 2.5rem; - } - .lg\:text-3xl { font-size: 1.875rem; line-height: 2.25rem; @@ -3311,4 +3355,4 @@ select { font-size: 0.875rem; line-height: 1.25rem; } -} \ No newline at end of file +} diff --git a/src/assets/css/tailwind.css b/src/assets/css/tailwind.css index bd6213e..c41025a 100644 --- a/src/assets/css/tailwind.css +++ b/src/assets/css/tailwind.css @@ -1,3 +1,38 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +@layer components { + /* NavBar */ + .menu-item { + @apply w-full text-left block px-4 py-3 text-base text-gray-800; + } + .menu-item-active { + @apply bg-gray-100 w-full text-left block px-4 py-3 text-base text-gray-800; + } + .container-menu-item { + @apply absolute right-0 z-10 w-48 mt-2 overflow-hidden origin-top-right bg-white rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none; + } + .container-menu-profile { + @apply flex-shrink-0 block px-4 py-2 border-b bg-primary-500 border-gray-50; + } + /* Aside */ + .aside-single-item { + @apply w-full flex items-center pl-2 pr-4 py-2 text-xs rounded-xl; + } + .aside-single-item-active { + @apply aside-single-item bg-primary-500 text-white font-bold; + } + .aside-single-item-inactive { + @apply aside-single-item font-semibold text-aside group-hover:bg-primary-100 text-gray-600 group-hover:text-white group-hover:bg-primary-500; + } + .aside-single-item-icon{ + @apply h-6 w-6; + } + .aside-single-item-icon-active{ + @apply aside-single-item-icon stroke-white; + } + .aside-single-item-icon-inactive{ + @apply aside-single-item-icon text-aside group-hover:stroke-white; + } +} diff --git a/src/assets/icons/dot-outline.svg b/src/assets/icons/dot-outline.svg index c4ff242..19a00e0 100644 --- a/src/assets/icons/dot-outline.svg +++ b/src/assets/icons/dot-outline.svg @@ -1,4 +1,4 @@ - + diff --git a/src/assets/icons/gauge.svg b/src/assets/icons/gauge.svg new file mode 100644 index 0000000..0a677ad --- /dev/null +++ b/src/assets/icons/gauge.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icons/plugs.svg b/src/assets/icons/plugs.svg new file mode 100644 index 0000000..c2c05f4 --- /dev/null +++ b/src/assets/icons/plugs.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/Aside/Aside.vue b/src/components/Aside/Aside.vue deleted file mode 100644 index 9126f70..0000000 --- a/src/components/Aside/Aside.vue +++ /dev/null @@ -1,255 +0,0 @@ - - -
- - -
- - - -
- -
-
-
- - PLN - -
- -
-
- -
- - - - - - diff --git a/src/components/Aside/AsideMenuSingle.vue b/src/components/Aside/AsideMenuSingle.vue deleted file mode 100644 index 1755e41..0000000 --- a/src/components/Aside/AsideMenuSingle.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/Aside/AsideMenuSingleMultiple.vue b/src/components/Aside/AsideMenuSingleMultiple.vue deleted file mode 100644 index 04bd858..0000000 --- a/src/components/Aside/AsideMenuSingleMultiple.vue +++ /dev/null @@ -1,18 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/ButtonDropdown.vue b/src/components/Buttons/ButtonDropdown.vue similarity index 100% rename from src/components/ButtonDropdown.vue rename to src/components/Buttons/ButtonDropdown.vue diff --git a/src/components/ButtonPrimary.vue b/src/components/Buttons/ButtonPrimary.vue similarity index 100% rename from src/components/ButtonPrimary.vue rename to src/components/Buttons/ButtonPrimary.vue diff --git a/src/components/CommandPalettes.vue b/src/components/CommandPalettes.vue index d8725cf..1445a57 100644 --- a/src/components/CommandPalettes.vue +++ b/src/components/CommandPalettes.vue @@ -176,7 +176,7 @@ function readRecentMenu() { function openMenu(menu: typeof menus[0]) { addMenuToRecent(menu) - route.push(menu.href) + route.push(menu.path) onClose() } diff --git a/src/components/Dialogs/ChangePasswordDialog.vue b/src/components/Dialogs/ChangePasswordDialog.vue deleted file mode 100644 index 575e74c..0000000 --- a/src/components/Dialogs/ChangePasswordDialog.vue +++ /dev/null @@ -1,148 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/Header.vue b/src/components/Header.vue deleted file mode 100644 index fc0c43e..0000000 --- a/src/components/Header.vue +++ /dev/null @@ -1,170 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/components/HomeEmpty.vue b/src/components/HomeEmpty.vue deleted file mode 100644 index 0514764..0000000 --- a/src/components/HomeEmpty.vue +++ /dev/null @@ -1,17 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/Menus/MenuSample.vue b/src/components/Menus/MenuSample.vue deleted file mode 100644 index ae28745..0000000 --- a/src/components/Menus/MenuSample.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/MessageBox.vue b/src/components/MessageBox.vue deleted file mode 100644 index 586b602..0000000 --- a/src/components/MessageBox.vue +++ /dev/null @@ -1,177 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/Navigation.vue b/src/components/Navigation.vue deleted file mode 100644 index 01908b9..0000000 --- a/src/components/Navigation.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/Navigation/Aside/Aside.vue b/src/components/Navigation/Aside/Aside.vue new file mode 100644 index 0000000..9b60d6d --- /dev/null +++ b/src/components/Navigation/Aside/Aside.vue @@ -0,0 +1,133 @@ + + + + +@/utils/text@/utils/texts \ No newline at end of file diff --git a/src/components/Navigation/Aside/AsideMenuMultiple.vue b/src/components/Navigation/Aside/AsideMenuMultiple.vue new file mode 100644 index 0000000..d8f0af4 --- /dev/null +++ b/src/components/Navigation/Aside/AsideMenuMultiple.vue @@ -0,0 +1,74 @@ + + + \ No newline at end of file diff --git a/src/components/Navigation/Aside/AsideMenuSingle.vue b/src/components/Navigation/Aside/AsideMenuSingle.vue new file mode 100644 index 0000000..f7b5d44 --- /dev/null +++ b/src/components/Navigation/Aside/AsideMenuSingle.vue @@ -0,0 +1,44 @@ + + + \ No newline at end of file diff --git a/src/components/Navigation/Header.vue b/src/components/Navigation/Header.vue new file mode 100644 index 0000000..9277c78 --- /dev/null +++ b/src/components/Navigation/Header.vue @@ -0,0 +1,111 @@ + + + + + \ No newline at end of file diff --git a/src/components/Navigation/Navigation.vue b/src/components/Navigation/Navigation.vue new file mode 100644 index 0000000..b0d0aa6 --- /dev/null +++ b/src/components/Navigation/Navigation.vue @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/src/components/Menus/DaftarTransaksi/AktifIndividual.vue b/src/components/Pages/DaftarTransaksi/AktifIndividual.vue similarity index 99% rename from src/components/Menus/DaftarTransaksi/AktifIndividual.vue rename to src/components/Pages/DaftarTransaksi/AktifIndividual.vue index a6b7be5..c328b0b 100644 --- a/src/components/Menus/DaftarTransaksi/AktifIndividual.vue +++ b/src/components/Pages/DaftarTransaksi/AktifIndividual.vue @@ -202,8 +202,8 @@ import { } from 'devextreme-vue/data-grid'; import DataSource from 'devextreme/data/data_source'; import 'devextreme/data/odata/store'; -import ButtonDropdown from '@/components/ButtonDropdown.vue'; -import ButtonPrimary from '@/components/ButtonPrimary.vue'; +import ButtonDropdown from '@/components/Buttons/ButtonDropdown.vue'; +import ButtonPrimary from '@/components/Buttons/ButtonPrimary.vue'; import InputText from '@/components/InputText.vue'; import { MagnifyingGlassIcon, ChevronDownIcon } from '@heroicons/vue/24/solid'; import { XMarkIcon } from '@heroicons/vue/24/outline' diff --git a/src/components/Pages/HomeEmpty.vue b/src/components/Pages/HomeEmpty.vue new file mode 100644 index 0000000..7e1c5c2 --- /dev/null +++ b/src/components/Pages/HomeEmpty.vue @@ -0,0 +1,17 @@ + + + \ No newline at end of file diff --git a/src/components/Menus/MenuProvider.vue b/src/components/Pages/MenuProvider.vue similarity index 100% rename from src/components/Menus/MenuProvider.vue rename to src/components/Pages/MenuProvider.vue diff --git a/src/components/Pages/TestPage.vue b/src/components/Pages/TestPage.vue new file mode 100644 index 0000000..905c25a --- /dev/null +++ b/src/components/Pages/TestPage.vue @@ -0,0 +1,203 @@ + + + + \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 2c3d6ab..ca7d2ab 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,15 +1,12 @@ -import 'devextreme/dist/css/dx.light.css'; -import "@lottiefiles/lottie-player" +import 'devextreme/dist/css/dx.light.css' +import '@lottiefiles/lottie-player' import '@/assets/css/main.css' - import { createApp } from 'vue' import { createPinia } from 'pinia' - import App from './App.vue' import router from './router' const app = createApp(App) app.use(createPinia()) app.use(router) - app.mount('#app') diff --git a/src/router/index.ts b/src/router/index.ts index c00d2b8..fe954a7 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,319 +1,563 @@ -import { createRouter, createWebHistory } from 'vue-router' +import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' +import { useAuthStore } from '@/stores/auth' import HomeView from '@/views/HomeView.vue' import TestView from '@/views/TestView.vue' import LoginView from '@/views/LoginView.vue' import NotFoundView from '@/views/NotFoundView.vue' -import MenuSample from '@/components/Menus/MenuSample.vue' -import AktifIndividual from '@/components/Menus/DaftarTransaksi/AktifIndividual.vue' -import HomeEmptyView from '@/components/HomeEmpty.vue' -import { useAuthStore } from '@/stores/auth' -const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - linkActiveClass: 'active', - routes: [ - { - path: '/home', - name: 'Home', - 'meta': { requiresAuth: true }, - component: HomeView, - children: [ - { - path: '', - name: 'Home Page', - component: HomeEmptyView, - }, - { - path: 'daftar-transaksi', - name: 'Daftar Transaksi', - children: [ - { - path: 'aktif-individual', - name: 'Transaksi Aktif Individual', - component: AktifIndividual, - }, - { - path: 'aktif-pln-mobile', - name: 'Transaksi Aktif PLN Mobile', - component: MenuSample, - }, - { - path: 'periksa-return-order', - name: 'Transaksi Aktif Periksa dan Return Order', - component: MenuSample, - }, - { - path: 'aktif-tm', - name: 'Transaksi Aktif TM', - component: MenuSample, - }, - { - path: 'aktif-historis', - name: 'Transaksi Aktif Historis', - component: MenuSample, - }, - { - path: 'monitoring-alih-unit', - name: 'Monitoring Alih Unit', - component: MenuSample, - }, - { - path: 'monitoring-all', - name: 'Monitoring All', - component: MenuSample, - }, - { - path: 'monitoring-tiket', - name: 'Monitoring Tiket', - component: MenuSample, - }, - { - path: 'monitoring-history', - name: 'Monitoring History', - component: MenuSample, - }, - { - path: 'monitoring-aktif', - name: 'Monitoring Aktif', - component: MenuSample, - }, - { - path: 'monitoring-close-cc', - name: 'Monitoring Close CC', - component: MenuSample, - }, - { - path: 'monitoring-log-autodispatch', - name: 'Monitoring Log AutoDispatch', - component: MenuSample, - }, - { - path: 'monitoring-perlu-diperhatikan', - name: 'Monitoring yang Perlu Diperhatikan', - component: MenuSample, - }, - { - path: 'monitoring-log-break-regu', - name: 'Monitoring Log Break Regu', - component: MenuSample, - }, - { - path: 'monitoring-log-alih-regu', - name: 'Monitoring Log Alih Regu', - component: MenuSample, - }, - ] - }, - { - path: 'administration', - name: 'Administration', - children: [ - { - path: 'audit-trails', - name: 'Audit Trails', - children: [ - { - path: 'log-login', - name: 'Log Login', - component: MenuSample, - }, - { - path: 'log-aktivity', - name: 'Log Aktivity', - component: MenuSample, - }, - { - path: 'log-error', - name: 'Log Error', - component: MenuSample, - }, - ], - }, - { - path: 'task-management', - name: 'Task Management', - children: [ - { - path: 'menu-management', - name: 'Menu Management', - component: MenuSample, - }, - { - path: 'system-parameter', - name: 'System Parameter', - component: MenuSample, - }, - { - path: 'ubah-profile-manager', - name: 'Ubah Profile Manager', - component: MenuSample, - }, - { - path: 'security-projek', - name: 'Security Projek', - component: MenuSample, - }, - { - path: 'user-role-manager', - name: 'User Role Manager', - component: MenuSample, - }, - { - path: 'menu-authorization', - name: 'Menu Authorization', - component: MenuSample, - }, - { - path: 'workflow-designer', - name: 'Workflow Designer', - component: MenuSample, - }, - { - path: 'apkt-news', - name: 'APKT News', - component: MenuSample, - }, - ], - }, - { - path: 'master-borderless', - name: 'Master Borderless', - children: [ - { - path: 'zone-borderless', - name: 'Zone Borderless', - component: MenuSample, - }, - { - path: 'user-zone-borderless', - name: 'User Zone Borderless', - component: MenuSample, - }, - ], - }, - ], - }, - { - path: 'master-yantek', - name: 'Master Yantek', - children: [ - { - path: 'unit', - name: 'Unit', - component: MenuSample, - }, - { - path: 'unit-jaringan', - name: 'Unit Jaringan', - component: MenuSample, - }, - { - path: 'unit-pelayanan', - name: 'Unit Pelayanan', - component: MenuSample, - }, - { - path: 'regu-yantek', - name: 'Regu Yantek', - component: MenuSample, - }, - { - path: 'gardu-induk', - name: 'Gardu Induk', - component: MenuSample, - }, - { - path: 'gardu-penyulang-tm', - name: 'Gardu Penyulang TM', - component: MenuSample, - }, - { - path: 'gardu-distribusi', - name: 'Gardu Distribusi', - component: MenuSample, - }, - { - path: 'group-gangguan', - name: 'Group Gangguan', - component: MenuSample, - }, - { - path: 'wilayah-yantek', - name: 'Wilayah Yantek', - component: MenuSample, - }, - { - path: 'material', - name: 'Material', - component: MenuSample, - }, - ] - }, - { - path: 'transaksi', - name: 'Transaksi', - children: [ - { - path: 'gangguan-dan-keluhan', - name: 'Gangguan dan Keluhan', - component: MenuSample, - }, - { - path: 'gangguan-tegangan-menengah', - name: 'Gangguan Tegangan Menengah', - component: MenuSample, - }, - { - path: 'pemadaman-terencana', - name: 'Pemadaman Terencana', - component: MenuSample, - }, - { - path: 'aplikasi-off-line', - name: 'Aplikasi Off-Line', - component: MenuSample, - }, - { - path: 'penugasan-khusus', - name: 'Penugasan Khusus', - component: MenuSample, - }, - { - path: 'mutasi-pengaduan', - name: 'Mutasi Pengaduan', - component: MenuSample, - }, - ] - }, - ] - }, - { - path: '/test', - name: 'Test', - component: TestView - }, - { - path: '/login', - name: 'Login', - component: LoginView - }, - { - path: '/logout', - name: 'Logout', - beforeEnter(to, from, next) { - const auth = useAuthStore() - auth.logout() - next('/login') +import EmptyPage from '@/components/Pages/HomeEmpty.vue' +import TestPage from '@/components/Pages/TestPage.vue' +import { hasMoreThanTwoSlashes, removeExtraSlashes } from '@/utils/route' + +const routes: RouteRecordRaw[] = [ + { + path: '/home', + name: 'Home', + component: HomeView, + children: [ + { + path: '', + name: 'Home Page', + component: EmptyPage, }, - redirect: '/logout' - }, - { - path: '/404', - name: 'Not Found', - component: NotFoundView - }, - ] + { + path: 'gangguan', + name: 'Gangguan', + children: [ + { + path: 'a', + name: 'Daftar', + children: [ + { + path: '1', + name: 'Daftar Keluhan Dialihkan Ke Posko Lain', + component: TestPage, + }, + { + path: '2', + name: 'Daftar Gangguan Melapor Lebih Dari 1 Kali', + component: TestPage, + }, + { + path: '3', + name: 'Daftar Gangguan Response Time', + component: TestPage, + }, + { + path: '4', + name: 'Daftar Gangguan Recovery Time', + component: TestPage, + }, + { + path: '5', + name: 'Daftar Gangguan Selesai Tanpa ID Pelanggan', + component: TestPage, + }, + { + path: '6', + name: 'Daftar Gangguan Berdasarkan Media', + component: TestPage, + }, + { + path: '7', + name: 'Daftar Gangguan Diselesaikan Mobile APKT', + component: TestPage, + }, + ], + }, + { + path: 'b', + name: 'Rekapitulasi', + children: [ + { + path: '1', + name: 'Rekapitulasi Gangguan All', + component: TestPage, + }, + { + path: '2', + name: 'Rekapitulasi Gangguan/Jenis Gangguan', + component: TestPage, + }, + { + path: '3', + name: 'Rekapitulasi Gangguan/Jenis Gangguan SE 004', + component: TestPage, + }, + { + path: '4', + name: 'Rekapitulasi Gangguan Per Posko', + component: TestPage, + }, + { + path: '5', + name: 'Rekapitulasi Gangguan Per Regu', + component: TestPage, + }, + { + path: '6', + name: 'Rekapitulasi Gangguan Per Tanggal', + component: TestPage, + }, + { + path: '7', + name: 'Rekapitulasi Gangguan Berdasarkan Media', + component: TestPage, + }, + { + path: '8', + name: 'Rekapitulasi Gangguan Alih Posko', + component: TestPage, + }, + { + path: '9', + name: 'Rekapitulasi Gangguan Per Status', + component: TestPage, + }, + { + path: '10', + name: 'Rekapitulasi Gangguan Diselesaikan Mobile APKT', + component: TestPage, + }, + { + path: '11', + name: 'Rekapitulasi Rating Per Posko', + component: TestPage, + }, + { + path: '12', + name: 'Rekapitulasi Rating Per Regu', + component: TestPage, + }, + { + path: '13', + name: 'Rekapitulasi Koreksi Transaksi Individual', + component: TestPage, + }, + { + path: '14', + name: 'Rekapitulasi Cleansing Transaksi TM', + component: TestPage, + }, + ], + } + ] + }, + { + path: 'keluhan', + name: 'Keluhan', + children: [ + { + path: 'a', + name: 'Daftar', + children: [ + { + path: '1', + name: 'Daftar Keluhan Dialihkan Ke Unit Lain', + component: TestPage, + }, + { + path: '2', + name: 'Daftar Keluhan Pelanggan Lebih Dari 1 Kali', + component: TestPage, + }, + { + path: '3', + name: 'Daftar Keluhan Response Time', + component: TestPage, + }, + { + path: '4', + name: 'Daftar Keluhan Recovery Time', + component: TestPage, + }, + { + path: '5', + name: 'Daftar Keluhan Selesai Tanpa ID Pelanggan', + component: TestPage, + }, + { + path: '6', + name: 'Daftar Keluhan Berdasarkan Media', + component: TestPage, + }, + { + path: '7', + name: 'Daftar Keluhan Selesai di CC123', + component: TestPage, + }, + ], + }, + { + path: 'b', + name: 'Rekapitulasi', + children: [ + { + path: '1', + name: 'Rekapitulasi Keluhan All', + component: TestPage, + }, + { + path: '2', + name: 'Rekapitulasi Keluhan Per Fungsi Bidang', + component: TestPage, + }, + { + path: '3', + name: 'Rekapitulasi Keluhan Per Jenis Keluhan', + component: TestPage, + }, + { + path: '4', + name: 'Rekapitulasi Keluhan Per Tanggal', + component: TestPage, + }, + { + path: '5', + name: 'Rekapitulasi Keluhan Per Unit', + component: TestPage, + }, + { + path: '6', + name: 'Rekapitulasi Keluhan Berdasarkan Media', + component: TestPage, + }, + { + path: '7', + name: 'Rekapitulasi Keluhan Per Kelompok Keluhan', + component: TestPage, + }, + { + path: '8', + name: 'Rekapitulasi Rating Per Unit', + component: TestPage, + }, + ], + } + ], + }, + { + path: 'monalisa', + name: 'Monalisa', + children: [ + { + path: 'a', + name: 'Gangguan', + children: [ + { + path: 'a', + name: 'Rekapitulasi', + children: [ + { + path: '1', + name: 'Jumlah Kali Gangguan', + component: TestPage, + }, + { + path: '2', + name: 'Recovery Time (RCT) Gangguan', + component: TestPage, + }, + { + path: '3', + name: 'Response Time (RPT) Gangguan', + component: TestPage, + }, + { + path: '4', + name: 'Rekapitulasi Gangguan Per Jenis Gangguan', + component: TestPage, + }, + { + path: '5', + name: 'Rekapitulasi Lapor Ulang Gangguan', + component: TestPage, + }, + { + path: '6', + name: 'Rekapitulasi ENS Gangguan', + component: TestPage, + }, + { + path: '7', + name: 'Rekapitulasi Gangguan Belum Selesai', + component: TestPage, + }, + ], + }, + ], + }, + { + path: 'b', + name: 'Keluhan', + children: [ + { + path: 'a', + name: 'Rekapitulasi', + children: [ + { + path: '1', + name: 'Jumlah Kali Keluhan', + component: TestPage, + }, + { + path: '2', + name: 'Recovery Time (RCT) Keluhan', + component: TestPage, + }, + { + path: '3', + name: 'Response Time (RPT) Keluhan', + component: TestPage, + }, + { + path: '4', + name: 'Rekapitulasi Gangguan Per Jenis Keluhan', + component: TestPage, + }, + { + path: '5', + name: 'Rekapitulasi Lapor Ulang Keluhan', + component: TestPage, + }, + { + path: '6', + name: 'Rekapitulasi Keluhan Belum Selesai', + component: TestPage, + }, + ], + }, + ], + }, + { + path: 'c', + name: 'Laporan KPI', + children: [ + { + path: 'a', + name: 'Bulanan', + children: [ + { + path: '1', + name: 'Penurunan Jumlah Komplain', + component: TestPage, + }, + { + path: '2', + name: 'Aging Complaint', + component: TestPage, + }, + { + path: '3', + name: 'Energy Not Sales (ENS)', + component: TestPage, + }, + { + path: '4', + name: 'Kepatuhan dan Akurasi Dalam Pelaporan', + component: TestPage, + }, + ], + }, + { + path: '2', + name: 'Kumulatif', + children: [ + { + path: '1', + name: 'Penurunan Jumlah Komplain', + component: TestPage, + }, + { + path: '2', + name: 'Aging Complaint', + component: TestPage, + }, + { + path: '3', + name: 'Energy Not Sales (ENS)', + component: TestPage, + }, + { + path: '4', + name: 'Kepatuhan dan Akurasi Dalam Pelaporan', + component: TestPage, + }, + ], + } + ], + }, + ], + }, + { + path: 'check-in-out', + name: 'Check In OutCheck In Dan Check Out', + children: [ + { + path: 'a', + name: 'Laporan Check In /Check Out (CICO)', + children: [ + { + path: '1', + name: 'Laporan Check In /Check Out (CICO)', + component: TestPage, + }, + ], + }, + ], + }, + { + path: 'anomali-pengaduan', + name: 'Anomali Penangan Pengaduan', + children: [ + { + path: 'a', + name: 'Gangguan', + children: [ + { + path: '1', + name: 'Laporan Anomali Penangan Pengaduan Gangguan Unit', + component: TestPage, + }, + { + path: '2', + name: 'Laporan Anomali Penangan Pengaduan Gangguan Petugas', + component: TestPage, + }, + ], + }, + { + path: 'b', + name: 'Keluhan', + children: [ + { + path: '1', + name: 'Laporan Anomali Penangan Pengaduan Keluhan Unit', + component: TestPage, + }, + ], + }, + ], + }, + { + path: 'ctt-kwh-periksa', + name: 'CTT & KWH Periksa', + children: [ + { + path: '1', + name: 'Laporan CTT & KWH Periksa', + component: TestPage, + }, + ], + }, + ] + }, + { + path: '/login', + name: 'Login', + component: LoginView + }, + { + path: '/404', + name: 'Not Found', + component: NotFoundView + }, +] + +// const createRoute = (route: RouteRecordRaw[]): RouteRecordRaw[] => { +// var newRoute: RouteRecordRaw[] = [] + +// const getRoute = (route: RouteRecordRaw[], parent: string = '') => { +// route.forEach((r) => { +// if (r.children) { +// if (r.component) { +// var fullPath = `${parent.replace('/', '')}/${r.path.replace('/', '')}` +// fullPath = hasMoreThanTwoSlashes(fullPath) ? removeExtraSlashes(fullPath) : fullPath +// newRoute.push({ +// path: fullPath, +// name: r.name, +// component: r.component +// } as RouteRecordRaw) +// } +// getRoute(r.children, `${parent}/${r.path}`) +// } else { +// var fullPath = `${parent.replace('/', '')}/${r.path.replace('/', '')}` +// if (newRoute.find((nr) => nr.path !== '/' && nr.path === '/home' && fullPath.includes(nr.path))) { +// const index = newRoute.findIndex((nr) => nr.path !== '/' && fullPath.includes(nr.path)) +// newRoute[index] = { +// ...newRoute[index], children: [...newRoute[index].children ?? [], { +// path: fullPath === '/home/' ? '' : fullPath.includes('/home/') ? fullPath.replace('/home/', '').split('/').join('-') : fullPath.split('/').join('-'), +// name: r.name, +// component: r.component +// } as RouteRecordRaw] +// } +// } else { +// newRoute.push({ +// path: fullPath, +// name: r.name, +// component: r.component +// } as RouteRecordRaw) +// } +// } +// }) +// } +// getRoute(route) +// console.log(newRoute); + +// return newRoute +// } + +const createRoute = (route: RouteRecordRaw[]): RouteRecordRaw[] => { + var newRoute: RouteRecordRaw[] = [] + + const getRoute = (route: RouteRecordRaw[], parent: string = '') => { + route.forEach((r) => { + if (r.children) { + if (r.component) { + const fullPath = `${parent.replace('/', '')}/${r.path.replace('/', '')}` + newRoute.push({ + path: fullPath, + name: r.name, + component: r.component + } as RouteRecordRaw) + } + getRoute(r.children, `${parent}/${r.path}`) + } else { + const fullPath = `${parent.replace('/', '')}/${r.path.replace('/', '')}` + if (newRoute.find((nr) => nr.path !== '/' && nr.path === '/home' && fullPath.includes(nr.path))) { + const index = newRoute.findIndex((nr) => nr.path !== '/' && fullPath.includes(nr.path)) + newRoute[index] = { + ...newRoute[index], children: [...newRoute[index].children ?? [], { + path: fullPath === '/home/' ? '' : fullPath.includes('/home/') ? fullPath.replace('/home/', '') : fullPath, + name: r.name, + component: r.component + } as RouteRecordRaw] + } + } else { + newRoute.push({ + path: fullPath, + name: r.name, + component: r.component + } as RouteRecordRaw) + } + } + }) + } + getRoute(route) + + // remove duplicate route path and sort by path length + const uniqueRoute = newRoute.filter((nr, index, self) => self.findIndex((n) => n.path === nr.path) === index).sort((a, b) => b.path.length - a.path.length) + + return uniqueRoute +} + +const router = createRouter({ + history: createWebHistory(), + linkActiveClass: 'active', + routes: createRoute(routes) }) +console.log(router.getRoutes()); + router.beforeEach((to, from, next) => { // redirect to login page if not logged in and trying to access a restricted page @@ -348,7 +592,9 @@ router.beforeEach((to, from, next) => { } } } - }) export default router +export { + routes +} diff --git a/src/stores/menu.ts b/src/stores/menu.ts index 5fa9dee..1cff66a 100644 --- a/src/stores/menu.ts +++ b/src/stores/menu.ts @@ -1,471 +1,51 @@ -import { ref } from 'vue' +import { onMounted, ref } from 'vue' import { defineStore } from 'pinia' - -import { - LightningSlash, - Monitor, - SmileySad, - Swap -} from '@/utils/icons' +import { useRoute } from 'vue-router' +import { convertRouteToMenu } from '@/utils/route' +import { routes } from '@/router' import type { MenuItemModel } from '@/utils/interfaces' export const useMenuStore = defineStore('menu', () => { - const navigation: MenuItemModel[] = [ - { - name: 'Gangguan', - href: '/gangguan', - icon: LightningSlash, - children: [ - { - name: 'Daftar', - href: '/gangguan/1', - icon: LightningSlash, - children: [ - { - name: 'Daftar Keluhan Dialihkan Ke Posko Lain', - href: '/gangguan/1/1', - icon: LightningSlash, - children: [], - }, - { - name: 'Daftar Gangguan Melapor Lebih Dari 1 Kali', - href: '/gangguan/1/2', - icon: LightningSlash, - children: [], - }, - { - name: 'Daftar Gangguan Response Time', - href: '/gangguan/1/3', - icon: LightningSlash, - children: [], - }, - { - name: 'Daftar Gangguan Recovery Time', - href: '/gangguan/1/4', - icon: LightningSlash, - children: [], - }, - { - name: 'Daftar Gangguan Selesai Tanpa ID Pelanggan', - href: '/gangguan/1/5', - icon: LightningSlash, - children: [], - }, - { - name: 'Daftar Gangguan Berdasarkan Media', - href: '/gangguan/1/6', - icon: LightningSlash, - children: [], - }, - { - name: 'Daftar Gangguan Diselesaikan Mobile APKT', - href: '/gangguan/1/7', - icon: LightningSlash, - children: [], - }, - ], - }, - { - name: 'Rekapitulasi', - href: '/gangguan/2', - icon: LightningSlash, - children: [ - { - name: 'Rekapitulasi Gangguan All', - href: '/gangguan/2/1', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Per Jenis Gangguan', - href: '/gangguan/2/2', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Per Jenis Gangguan SE 004', - href: '/gangguan/2/3', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Per Posko', - href: '/gangguan/2/4', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Per Regu', - href: '/gangguan/2/5', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Per Tanggal', - href: '/gangguan/2/6', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Berdasarkan Media', - href: '/gangguan/2/7', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Alih Posko', - href: '/gangguan/2/8', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Per Status', - href: '/gangguan/2/9', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Diselesaikan Mobile APKT', - href: '/gangguan/2/10', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Rating Per Posko', - href: '/gangguan/2/11', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Rating Per Regu', - href: '/gangguan/2/12', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Koreksi Transaksi Individual', - href: '/gangguan/2/13', - icon: LightningSlash, - children: [], - }, - { - name: 'Rekapitulasi Cleansing Transaksi TM', - href: '/gangguan/2/14', - icon: LightningSlash, - children: [], - }, - ], - }, - ], - }, - { - name: 'Keluhan', - href: '/keluhan', - icon: SmileySad, - children: [ - { - name: 'Daftar', - icon: SmileySad, - href: '/keluhan/1', - children: [ - { - name: 'Daftar Keluhan Dialihkan Ke Unit Lain', - href: '/keluhan/1/1', - icon: SmileySad, - children: [], - }, - { - name: 'Daftar Keluhan Pelanggan Lebih Dari 1 Kali', - href: '/keluhan/1/2', - icon: SmileySad, - children: [], - }, - { - name: 'Daftar Keluhan Response Time', - href: '/keluhan/1/3', - icon: SmileySad, - children: [], - }, - { - name: 'Daftar Keluhan Recovery Time', - href: '/keluhan/1/4', - icon: SmileySad, - children: [], - }, - { - name: 'Daftar Keluhan Selesai Tanpa ID Pelanggan', - href: '/keluhan/1/5', - icon: SmileySad, - children: [], - }, - { - name: 'Daftar Keluhan Berdasarkan Media', - href: '/keluhan/1/6', - icon: SmileySad, - children: [], - }, - { - name: 'Daftar Keluhan Selesai di CC123', - href: '/keluhan/1/7', - icon: SmileySad, - children: [], - }, - ], - }, - { - name: 'Rekapitulasi', - icon: SmileySad, - href: '/keluhan/2', - children: [ - { - name: 'Rekapitulasi Keluhan All', - href: '/keluhan/2/1', - icon: SmileySad, - children: [], - }, - { - name: 'Rekapitulasi Keluhan Per Fungsi Bidang', - href: '/keluhan/2/2', - icon: SmileySad, - children: [], - }, - { - name: 'Rekapitulasi Keluhan Per Jenis Keluhan', - href: '/keluhan/2/3', - icon: SmileySad, - children: [], - }, - { - name: 'Rekapitulasi Keluhan Per Tanggal', - href: '/keluhan/2/4', - icon: SmileySad, - children: [], - }, - { - name: 'Rekapitulasi Keluhan Per Unit', - href: '/keluhan/2/5', - icon: SmileySad, - children: [], - }, - { - name: 'Rekapitulasi Keluhan Berdasarkan Media', - href: '/keluhan/2/6', - icon: SmileySad, - children: [], - }, - ], - }, - ], - }, - { - name: 'Monalisa', - href: '/monalisa', - icon: Monitor, - children: [ - { - name: 'Gangguan', - icon: Monitor, - href: '/monalisa/1', - children: [ - { - name: 'Rekapitulasi', - href: '/monalisa/1/1', - icon: Monitor, - children: [ - { - name: 'Jumlah Kali Gangguan', - href: '/monalisa/1/1/1', - icon: Monitor, - children: [], - }, - { - name: 'Recovery Time (RCT) Gangguan', - href: '/monalisa/1/1/2', - icon: Monitor, - children: [], - }, - { - name: 'Response Time (RPT) Gangguan', - href: '/monalisa/1/1/3', - icon: Monitor, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Per Jenis Gangguan', - href: '/monalisa/1/1/4', - icon: Monitor, - children: [], - }, - { - name: 'Rekapitulasi Lapor Ulang Gangguan', - href: '/monalisa/1/1/5', - icon: Monitor, - children: [], - }, - { - name: 'Rekapitulasi ENS Gangguan', - href: '/monalisa/1/1/6', - icon: Monitor, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Belum Selesai', - href: '/monalisa/1/1/7', - icon: Monitor, - children: [], - }, - ], - }, - ], - }, - { - name: 'Keluhan', - icon: Monitor, - href: '/monalisa/2', - children: [ - { - name: 'Rekapitulasi', - href: '/monalisa/2/1', - icon: Monitor, - children: [ - { - name: 'Jumlah Kali Keluhan', - href: '/monalisa/2/1/1', - icon: Monitor, - children: [], - }, - { - name: 'Recovery Time (RCT) Keluhan', - href: '/monalisa/2/1/2', - icon: Monitor, - children: [], - }, - { - name: 'Response Time (RPT) Keluhan', - href: '/monalisa/2/1/3', - icon: Monitor, - children: [], - }, - { - name: 'Rekapitulasi Gangguan Per Jenis Keluhan', - href: '/monalisa/2/1/4', - icon: Monitor, - children: [], - }, - { - name: 'Rekapitulasi Lapor Ulang Keluhan', - href: '/monalisa/2/1/5', - icon: Monitor, - children: [], - }, - { - name: 'Rekapitulasi Keluhan Belum Selesai', - href: '/monalisa/2/1/6', - icon: Monitor, - children: [], - }, - ], - }, - ], - }, - { - name: 'Laporan KPI', - icon: Monitor, - href: '/monalisa/3', - children: [ - { - name: 'Bulanan', - icon: Monitor, - href: '/monalisa/3/1', - children: [ - { - name: 'Penurunan Jumlah Komplain', - icon: Monitor, - href: '/monalisa/3/1/1', - children: [], - }, - { - name: 'Aging Complaint', - icon: Monitor, - href: '/monalisa/3/1/2', - children: [], - }, - { - name: 'Energy Not Sales (ENS)', - icon: Monitor, - href: '/monalisa/3/1/3', - children: [], - }, - { - name: 'Kepatuhan dan Akurasi Dalam Pelaporan', - icon: Monitor, - href: '/monalisa/3/1/4', - children: [], - }, - ], - }, - { - name: 'Kumulatif', - icon: Monitor, - href: '/monalisa/3/2', - children: [ - { - name: 'Penurunan Jumlah Komplain', - icon: Monitor, - href: '/monalisa/3/2/1', - children: [], - }, - { - name: 'Aging Complaint', - icon: Monitor, - href: '/monalisa/3/2/2', - children: [], - }, - { - name: 'Energy Not Sales (ENS)', - icon: Monitor, - href: '/monalisa/3/2/3', - children: [], - }, - { - name: 'Kepatuhan dan Akurasi Dalam Pelaporan', - icon: Monitor, - href: '/monalisa/3/2/4', - children: [], - } - ], - } - ], - }, - ], - }, - { - name: 'Check In Dan Check Out', - href: '/check-in-out', - icon: Swap, - children: [ - { - name: 'Laporan Check In /Check Out (CICO)', - href: '/check-in-out/1', - icon: Swap, - children: [ - { - name: 'Laporan Check In /Check Out (CICO)', - href: '/check-in-out/1/1', - icon: Swap, - children: [], - }, - ], - }, - ], - }, - ] + const route = useRoute() + const navigation = ref([]) const sidebarOpen = ref(false) + const sidebarShowed = ref(true) + const menuSelected = ref(route.fullPath) const toggleSidebar = () => (sidebarOpen.value = !sidebarOpen.value) + const toggleSidebarMenu = (path: string, newExpanded: boolean): void => { + const toggleItemExpanded = (items: MenuItemModel[]): void => { + for (const item of items) { + if (item.path === path) { + item.expanded = newExpanded + } else { + if (newExpanded) { + if (!path.includes(item.path)) { + item.expanded = !newExpanded; + } + } + } + if (item.children && item.children.length > 0) { + toggleItemExpanded(item.children) + } + } + } + + toggleItemExpanded(navigation.value) + } + const toggleSidebarDesktop = () => (sidebarShowed.value = !sidebarShowed.value) + + onMounted(() => { + const menuData = convertRouteToMenu(routes.at(0)?.children || []) + navigation.value = menuData + }) return { navigation, toggleSidebar, - sidebarOpen + sidebarOpen, + menuSelected, + toggleSidebarMenu, + sidebarShowed, + toggleSidebarDesktop } }) \ No newline at end of file diff --git a/src/stores/message.ts b/src/stores/message.ts deleted file mode 100644 index e2ba6aa..0000000 --- a/src/stores/message.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ref, computed } from 'vue' -import { defineStore } from 'pinia' -import { dispatchNotification } from '@/components/Notification' -import router from '@/router' - -export const useMessageStore = defineStore('message_box', () => { - const message = ref('') - const isSending = ref(false) - const open = ref(false) - - function handleOnDismissMessageBox() { - open.value = false; - } - - function showDialogMessageBox() { - open.value = true; - } - - function send() { - - } - - return { message, send, isSending, open, handleOnDismissMessageBox, showDialogMessageBox } -}) \ No newline at end of file diff --git a/src/utils/icons.ts b/src/utils/icons.ts index 0cfcad3..e237815 100644 --- a/src/utils/icons.ts +++ b/src/utils/icons.ts @@ -1,6 +1,10 @@ +// png +export { default as IconApp } from '@/assets/images/pln-with-text.png' +// svg export { default as LightningSlash } from '@/assets/icons/lightning-slash.svg' export { default as SmileySad } from '@/assets/icons/smiley-sad.svg' export { default as Monitor } from '@/assets/icons/monitor.svg' export { default as Swap } from '@/assets/icons/swap.svg' export { default as DotOutline } from '@/assets/icons/dot-outline.svg' -export { default as IconApp } from '@/assets/images/pln-with-text.png' \ No newline at end of file +export { default as Plugs } from '@/assets/icons/plugs.svg' +export { default as Gauge } from '@/assets/icons/gauge.svg' diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index d169c44..4faeed8 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -1,7 +1,8 @@ interface MenuItemModel { name: string; - href: string; + path: string; icon: any; + expanded: boolean; children: MenuItemModel[]; } diff --git a/src/utils/numbers.ts b/src/utils/numbers.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/route.ts b/src/utils/route.ts new file mode 100644 index 0000000..3626c86 --- /dev/null +++ b/src/utils/route.ts @@ -0,0 +1,82 @@ + +import type { MenuItemModel } from './interfaces' +import type { RouteRecordRaw } from 'vue-router' +import { + Gauge, + LightningSlash, + Monitor, + Plugs, + SmileySad, + Swap +} from '@/utils/icons' + +const navigationIcon = [ + LightningSlash, + SmileySad, + Monitor, + Swap, + Plugs, + Gauge +] + +const convertToDashedString = (input: string): string => { + // Menghapus tanda '/' di awal dan akhir string + input = input.replace(/^\/+|\/+$/g, ''); + + // Membagi string menjadi bagian-bagian menggunakan '/' + const parts = input.split('/'); + + // Menggabungkan bagian-bagian dengan tanda '-' + return `/${parts.join('-')}`; +} + +// export const convertRouteToMenu = (data: RouteRecordRaw[], basePath: string = '/home', iconIndex: number = 0): MenuItemModel[] => { +// return data.filter((i) => i.path !== '').map((item) => { +// const convertedItem: MenuItemModel = { +// name: item.name?.toString() || '', +// path: convertToDashedString(`${basePath}/${item.path}`).replace('/home-', '/home/'), +// expanded: false, +// icon: undefined, +// children: [], +// }; + +// if (item.children) { +// convertedItem.icon = navigationIcon[iconIndex]; +// iconIndex = (iconIndex + 1) % navigationIcon.length; +// convertedItem.children = convertRouteToMenu(item.children, `${basePath}/${item.path}`, iconIndex); +// } + +// return convertedItem +// }) +// } + +export const convertRouteToMenu = (data: RouteRecordRaw[], basePath: string = '/home', iconIndex: number = 0): MenuItemModel[] => { + return data.filter((i) => i.path !== '').map((item) => { + const convertedItem: MenuItemModel = { + name: item.name?.toString() || '', + path: `${basePath}/${item.path}`, + expanded: false, + icon: undefined, + children: [], + }; + + if (item.children) { + convertedItem.icon = navigationIcon[iconIndex]; + iconIndex = (iconIndex + 1) % navigationIcon.length; + convertedItem.children = convertRouteToMenu(item.children, `${basePath}/${item.path}`, iconIndex); + } + + return convertedItem + }) +} + +export const removeExtraSlashes = (input: string): string => { + // Menggunakan ekspresi reguler untuk mengganti tanda '/' lebih dari 2 dengan satu tanda '/' + return input.replace(/\/{3,}/g, '/'); +} + +export const hasMoreThanTwoSlashes = (input: string): boolean => { + // Menggunakan ekspresi reguler untuk mencari tanda '/' lebih dari 2 kali + const matches = input.match(/\//g); + return matches ? matches.length > 2 : false; +} \ No newline at end of file diff --git a/src/utils/texts.ts b/src/utils/texts.ts new file mode 100644 index 0000000..18dac0f --- /dev/null +++ b/src/utils/texts.ts @@ -0,0 +1,17 @@ +const splitRoutePath = (routePath: string): string[] => { + const routeParts = routePath.split('/').filter((part) => part !== '') + + const routeArray: string[] = [] + let currentRoute = '' + + for (const part of routeParts) { + currentRoute += `/${part}` + routeArray.push(currentRoute) + } + + return routeArray +} + +export { + splitRoutePath +} \ No newline at end of file diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index a096874..758292a 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -1,15 +1,17 @@ + + - - \ No newline at end of file + \ No newline at end of file diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index 95a430c..16f1669 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -2,7 +2,7 @@ import { useAuthStore } from '@/stores/auth' import Icon from '@/assets/images/pln-with-text.png' import Hero from '@/assets/images/hero.png' -import Button from '@/components/ButtonPrimary.vue' +import Button from '@/components/Buttons/ButtonPrimary.vue' import InputText from '@/components/InputText.vue' import { onMounted } from 'vue'