Merge branch 'main' of github.com:defuj/eis
This commit is contained in:
@ -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'
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
@ -1,4 +1,4 @@
|
||||
# apkt
|
||||
# Executive Information System
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
|
@ -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()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -13,6 +16,7 @@ const dialog = useDialogStore()
|
||||
:open="dialog.open" :title="dialog.title" :message="dialog.content" :confirm-text="dialog.confirmText"
|
||||
:cancel-text="dialog.cancelText" @on-close="dialog.open = false" @on-confirm="dialog.onConfirm"
|
||||
@on-cancel="dialog.onCancel" :type="dialog.type" />
|
||||
<CommandPalettes :open="command.open" @onClose="command.handleOnDismissCommandPalettes" />
|
||||
<RouterView />
|
||||
</NotificationProvider>
|
||||
</template>
|
||||
|
@ -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); }
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,38 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="DotOutline">
|
||||
<path id="Vector" opacity="0.2" d="M9.5 8C9.5 8.29667 9.41203 8.58668 9.24721 8.83336C9.08238 9.08003 8.84812 9.27229 8.57403 9.38582C8.29994 9.49935 7.99834 9.52906 7.70737 9.47118C7.41639 9.4133 7.14912 9.27044 6.93934 9.06066C6.72956 8.85088 6.5867 8.58361 6.52882 8.29264C6.47094 8.00166 6.50065 7.70006 6.61418 7.42597C6.72771 7.15189 6.91997 6.91762 7.16665 6.7528C7.41332 6.58797 7.70333 6.5 8 6.5C8.39783 6.5 8.77936 6.65804 9.06066 6.93934C9.34197 7.22064 9.5 7.60218 9.5 8Z" fill="#4B5563"/>
|
||||
<path id="Vector_2" d="M8 6C7.60444 6 7.21776 6.1173 6.88886 6.33706C6.55996 6.55682 6.30362 6.86918 6.15224 7.23463C6.00087 7.60009 5.96126 8.00222 6.03843 8.39018C6.1156 8.77814 6.30608 9.13451 6.58579 9.41421C6.86549 9.69392 7.22186 9.8844 7.60982 9.96157C7.99778 10.0387 8.39992 9.99913 8.76537 9.84776C9.13082 9.69638 9.44318 9.44004 9.66294 9.11114C9.8827 8.78224 10 8.39556 10 8C10 7.46957 9.78929 6.96086 9.41421 6.58579C9.03914 6.21071 8.53043 6 8 6ZM8 9C7.80222 9 7.60888 8.94135 7.44443 8.83147C7.27998 8.72159 7.15181 8.56541 7.07612 8.38268C7.00043 8.19996 6.98063 7.99889 7.01922 7.80491C7.0578 7.61093 7.15304 7.43275 7.29289 7.29289C7.43275 7.15304 7.61093 7.0578 7.80491 7.01921C7.99889 6.98063 8.19996 7.00043 8.38268 7.07612C8.56541 7.15181 8.72159 7.27998 8.83147 7.44443C8.94135 7.60888 9 7.80222 9 8C9 8.26522 8.89464 8.51957 8.70711 8.70711C8.51957 8.89464 8.26522 9 8 9Z" fill="#4B5563"/>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
6
src/assets/icons/gauge.svg
Normal file
6
src/assets/icons/gauge.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Gauge">
|
||||
<path id="Vector" opacity="0.2" d="M21.75 15V17.25C21.75 17.4489 21.671 17.6397 21.5303 17.7803C21.3897 17.921 21.1989 18 21 18H3C2.80109 18 2.61032 17.921 2.46967 17.7803C2.32902 17.6397 2.25 17.4489 2.25 17.25V15.1059C2.25 9.71719 6.57656 5.26875 11.9653 5.25C13.2486 5.24544 14.5202 5.49426 15.7071 5.9822C16.8941 6.47013 17.973 7.18759 18.882 8.09342C19.7911 8.99924 20.5124 10.0756 21.0045 11.2608C21.4967 12.446 21.75 13.7167 21.75 15Z" fill="#035B71"/>
|
||||
<path id="Vector_2" d="M19.4119 7.56282C18.4397 6.58843 17.2842 5.81613 16.0121 5.29046C14.74 4.76478 13.3764 4.49614 12 4.5H11.9625C6.19406 4.51969 1.5 9.28125 1.5 15.1059V17.25C1.5 17.6478 1.65804 18.0294 1.93934 18.3107C2.22064 18.592 2.60218 18.75 3 18.75H21C21.3978 18.75 21.7794 18.592 22.0607 18.3107C22.342 18.0294 22.5 17.6478 22.5 17.25V15C22.5039 13.6175 22.2328 12.2481 21.7027 10.9713C21.1725 9.69457 20.3938 8.53594 19.4119 7.56282ZM21 17.25H11.2228L16.3566 10.1906C16.4737 10.0298 16.5221 9.82895 16.4911 9.63239C16.4602 9.43583 16.3524 9.25961 16.1916 9.1425C16.0307 9.02539 15.8299 8.97699 15.6333 9.00793C15.4368 9.03887 15.2605 9.14663 15.1434 9.3075L9.3675 17.25H3V15.1059C3 14.8172 3.01406 14.5322 3.04031 14.25H5.25C5.44891 14.25 5.63968 14.171 5.78033 14.0303C5.92098 13.8897 6 13.6989 6 13.5C6 13.3011 5.92098 13.1103 5.78033 12.9697C5.63968 12.829 5.44891 12.75 5.25 12.75H3.30656C4.27406 9.10688 7.43156 6.3525 11.25 6.03188V8.25C11.25 8.44892 11.329 8.63968 11.4697 8.78033C11.6103 8.92099 11.8011 9 12 9C12.1989 9 12.3897 8.92099 12.5303 8.78033C12.671 8.63968 12.75 8.44892 12.75 8.25V6.03094C14.6106 6.18752 16.3767 6.9181 17.8042 8.12172C19.2316 9.32534 20.2501 10.9426 20.7188 12.75H18.75C18.5511 12.75 18.3603 12.829 18.2197 12.9697C18.079 13.1103 18 13.3011 18 13.5C18 13.6989 18.079 13.8897 18.2197 14.0303C18.3603 14.171 18.5511 14.25 18.75 14.25H20.9691C20.9888 14.4984 21 14.7478 21 15V17.25Z" fill="#035B71"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
6
src/assets/icons/plugs.svg
Normal file
6
src/assets/icons/plugs.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Plugs">
|
||||
<path id="Vector" opacity="0.2" d="M7.12508 11.625L12.3751 16.875L9.65633 19.5937C9.23438 20.0157 8.66211 20.2527 8.06539 20.2527C7.46868 20.2527 6.89641 20.0157 6.47446 19.5937L4.40633 17.5228C3.98527 17.101 3.74878 16.5293 3.74878 15.9333C3.74878 15.3373 3.98527 14.7656 4.40633 14.3437L7.12508 11.625ZM19.5938 6.47718L17.5229 4.40625C17.1011 3.98518 16.5294 3.7487 15.9334 3.7487C15.3373 3.7487 14.7657 3.98518 14.3438 4.40625L11.6251 7.125L16.8751 12.375L19.5938 9.65625C20.0149 9.23441 20.2514 8.66274 20.2514 8.06672C20.2514 7.47069 20.0149 6.89902 19.5938 6.47718Z" fill="#035B71"/>
|
||||
<path id="Vector_2" d="M14.0306 12.9694C13.9609 12.8996 13.8782 12.8443 13.7871 12.8066C13.6961 12.7688 13.5985 12.7494 13.4999 12.7494C13.4014 12.7494 13.3038 12.7688 13.2127 12.8066C13.1217 12.8443 13.039 12.8996 12.9693 12.9694L11.2499 14.6897L9.31024 12.75L11.0306 11.0306C11.1713 10.8899 11.2503 10.699 11.2503 10.5C11.2503 10.301 11.1713 10.1101 11.0306 9.96938C10.8898 9.82865 10.699 9.74959 10.4999 9.74959C10.3009 9.74959 10.11 9.82865 9.9693 9.96938L8.24993 11.6897L6.53055 9.96938C6.38982 9.82865 6.19895 9.74959 5.99993 9.74959C5.80091 9.74959 5.61003 9.82865 5.4693 9.96938C5.32857 10.1101 5.24951 10.301 5.24951 10.5C5.24951 10.699 5.32857 10.8899 5.4693 11.0306L6.06462 11.625L3.87837 13.8103C3.59972 14.0889 3.37868 14.4196 3.22787 14.7837C3.07706 15.1477 2.99944 15.5379 2.99944 15.9319C2.99944 16.3259 3.07706 16.7161 3.22787 17.0801C3.37868 17.4441 3.59972 17.7749 3.87837 18.0534L4.38274 18.5569L1.7193 21.2194C1.64962 21.2891 1.59435 21.3718 1.55663 21.4628C1.51892 21.5539 1.49951 21.6515 1.49951 21.75C1.49951 21.8485 1.51892 21.9461 1.55663 22.0372C1.59435 22.1282 1.64962 22.2109 1.7193 22.2806C1.86003 22.4214 2.05091 22.5004 2.24993 22.5004C2.34847 22.5004 2.44606 22.481 2.5371 22.4433C2.62815 22.4056 2.71087 22.3503 2.78055 22.2806L5.44305 19.6172L5.94649 20.1216C6.22508 20.4002 6.55582 20.6213 6.91984 20.7721C7.28387 20.9229 7.67403 21.0005 8.06805 21.0005C8.46208 21.0005 8.85224 20.9229 9.21626 20.7721C9.58028 20.6213 9.91103 20.4002 10.1896 20.1216L12.3749 17.9353L12.9693 18.5306C13.039 18.6003 13.1217 18.6556 13.2128 18.6933C13.3038 18.731 13.4014 18.7504 13.4999 18.7504C13.5985 18.7504 13.6961 18.731 13.7871 18.6933C13.8781 18.6556 13.9609 18.6003 14.0306 18.5306C14.1002 18.4609 14.1555 18.3782 14.1932 18.2872C14.2309 18.1961 14.2503 18.0985 14.2503 18C14.2503 17.9015 14.2309 17.8039 14.1932 17.7128C14.1555 17.6218 14.1002 17.5391 14.0306 17.4694L12.3102 15.75L14.0306 14.0306C14.1003 13.961 14.1556 13.8783 14.1933 13.7872C14.2311 13.6962 14.2505 13.5986 14.2505 13.5C14.2505 13.4014 14.2311 13.3038 14.1933 13.2128C14.1556 13.1217 14.1003 13.039 14.0306 12.9694ZM9.12837 19.0631C8.84709 19.3442 8.46571 19.5021 8.06805 19.5021C7.6704 19.5021 7.28902 19.3442 7.00774 19.0631L4.93962 16.9922C4.65852 16.7109 4.50062 16.3295 4.50062 15.9319C4.50062 15.5342 4.65852 15.1528 4.93962 14.8716L7.12493 12.6853L11.3146 16.875L9.12837 19.0631ZM22.2806 1.71938C22.2109 1.64965 22.1282 1.59433 22.0371 1.55658C21.9461 1.51884 21.8485 1.49941 21.7499 1.49941C21.6514 1.49941 21.5538 1.51884 21.4627 1.55658C21.3717 1.59433 21.289 1.64965 21.2193 1.71938L18.5568 4.38282L18.0534 3.87844C17.4901 3.31683 16.7272 3.00146 15.9318 3.00146C15.1364 3.00146 14.3735 3.31683 13.8102 3.87844L11.6249 6.06469L11.0306 5.46938C10.8898 5.32865 10.699 5.24959 10.4999 5.24959C10.3009 5.24959 10.11 5.32865 9.9693 5.46938C9.82857 5.61011 9.74951 5.80098 9.74951 6C9.74951 6.19903 9.82857 6.3899 9.9693 6.53063L17.4693 14.0306C17.539 14.1003 17.6217 14.1556 17.7128 14.1933C17.8038 14.231 17.9014 14.2504 17.9999 14.2504C18.0985 14.2504 18.1961 14.231 18.2871 14.1933C18.3781 14.1556 18.4609 14.1003 18.5306 14.0306C18.6002 13.9609 18.6555 13.8782 18.6932 13.7872C18.7309 13.6961 18.7503 13.5985 18.7503 13.5C18.7503 13.4015 18.7309 13.3039 18.6932 13.2128C18.6555 13.1218 18.6002 13.0391 18.5306 12.9694L17.9352 12.375L20.1215 10.1897C20.4001 9.91111 20.6212 9.58036 20.772 9.21634C20.9228 8.85231 21.0004 8.46215 21.0004 8.06813C21.0004 7.6741 20.9228 7.28394 20.772 6.91992C20.6212 6.5559 20.4001 6.22515 20.1215 5.94657L19.6171 5.44313L22.2806 2.78063C22.3503 2.71097 22.4056 2.62826 22.4433 2.53721C22.4811 2.44616 22.5005 2.34856 22.5005 2.25C22.5005 2.15144 22.4811 2.05385 22.4433 1.9628C22.4056 1.87175 22.3503 1.78903 22.2806 1.71938ZM19.0602 9.12563L16.8749 11.3147L12.6852 7.125L14.8715 4.93969C15.1528 4.6586 15.5342 4.5007 15.9318 4.5007C16.3295 4.5007 16.7108 4.6586 16.9921 4.93969L19.0602 7.00219C19.2003 7.14157 19.3114 7.30723 19.3872 7.48968C19.463 7.67212 19.5021 7.86774 19.5021 8.06532C19.5021 8.26289 19.463 8.45851 19.3872 8.64095C19.3114 8.8234 19.2003 8.98906 19.0602 9.12844V9.12563Z" fill="#035B71"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.7 KiB |
@ -1,255 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
Dialog,
|
||||
DialogPanel,
|
||||
Disclosure,
|
||||
DisclosureButton,
|
||||
DisclosurePanel,
|
||||
TransitionChild,
|
||||
TransitionRoot,
|
||||
} from '@headlessui/vue'
|
||||
import { XMarkIcon } from '@heroicons/vue/24/outline'
|
||||
import { useMenuStore } from '@/stores/menu'
|
||||
import { IconApp } from '@/utils/icons'
|
||||
import AsideMenuSingle from './AsideMenuSingle.vue'
|
||||
import type { MenuItemModel } from '@/utils/interfaces'
|
||||
|
||||
const menu = useMenuStore()
|
||||
const route = useRoute()
|
||||
|
||||
const navigation = ref<MenuItemModel[]>(menu.navigation)
|
||||
const menuSelected = ref(route.fullPath)
|
||||
|
||||
watch(route, (to, _) => {
|
||||
menuSelected.value = to.fullPath
|
||||
closeSideBar()
|
||||
})
|
||||
|
||||
const isMenu = (name: string) => {
|
||||
return menuSelected.value === name
|
||||
}
|
||||
|
||||
const closeSideBar = () => menu.toggleSidebar()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TransitionRoot as="template" :show="menu.sidebarOpen">
|
||||
<Dialog as="div" class="relative z-40 md:hidden" @close="closeSideBar">
|
||||
<TransitionChild as="template" enter="transition-opacity ease-linear duration-300" enter-from="opacity-0"
|
||||
enter-to="opacity-100" leave="transition-opacity ease-linear duration-300" leave-from="opacity-100"
|
||||
leave-to="opacity-0">
|
||||
<div class="fixed inset-0 bg-gray-600 bg-opacity-75" />
|
||||
</TransitionChild>
|
||||
|
||||
<div class="fixed inset-0 z-40 flex">
|
||||
<TransitionChild as="template" enter="transition ease-in-out duration-300 transform"
|
||||
enter-from="-translate-x-full" enter-to="translate-x-0"
|
||||
leave="transition ease-in-out duration-300 transform" leave-from="translate-x-0"
|
||||
leave-to="-translate-x-full">
|
||||
<DialogPanel class="relative flex flex-col flex-1 w-full max-w-xs pt-5 pb-4 bg-primary-50">
|
||||
<TransitionChild as="template" enter="ease-in-out duration-300" enter-from="opacity-0"
|
||||
enter-to="opacity-100" leave="ease-in-out duration-300" leave-from="opacity-100"
|
||||
leave-to="opacity-0">
|
||||
<div class="absolute top-0 right-0 pt-2 -mr-12">
|
||||
<button type="button"
|
||||
class="flex items-center justify-center w-10 h-10 ml-1 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
|
||||
@click="closeSideBar">
|
||||
<span class="sr-only">Close sidebar</span>
|
||||
<XMarkIcon class="w-6 h-6 text-white" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</TransitionChild>
|
||||
<div class="flex items-center flex-shrink-0 px-4">
|
||||
<RouterLink to="/">
|
||||
<img class="w-auto h-16" :src="IconApp" alt="PLN" />
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="flex-1 h-0 mt-5 overflow-y-auto">
|
||||
<nav class="px-2 space-y-1">
|
||||
<template v-for="item in navigation" :key="item.name">
|
||||
<div v-if="!item.children || item.children.length === 0">
|
||||
<AsideMenuSingle :item="item" :is-menu-selected="isMenu(item.href)" />
|
||||
<!-- Single-level item -->
|
||||
<!-- <RouterLink :to="item.href"
|
||||
:class="[isMenu(item.href) ? 'bg-primary-500 text-white font-bold' : 'font-semibold text-aside hover:bg-primary-100 hover:text-gray-900', 'group w-full flex items-center pl-2 py-2 text-xs rounded-lg']">
|
||||
<component :is="item.icon"
|
||||
:class="[isMenu(item.href) ? 'text-white' : 'text-aside group-hover:text-gray-900', 'mr-3 flex-shrink-0 h-6 w-6']"
|
||||
aria-hidden="true" />
|
||||
{{ item.name }}
|
||||
</RouterLink> -->
|
||||
</div>
|
||||
|
||||
<Disclosure v-else
|
||||
v-bind:default-open="item.children.find((d) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? true : false">
|
||||
<!-- Nested item with children -->
|
||||
<template v-slot="{ open }">
|
||||
<DisclosureButton
|
||||
:class="[item.children.find((d) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? 'text-primary-500 font-bold' : 'font-semibold text-aside hover:bg-primary-100 hover:text-gray-900', 'group w-full flex items-center pl-2 pr-1 py-2 text-left text-xs rounded-lg focus:outline-none focus:ring-0 focus:ring-indigo-500']">
|
||||
<embed :data="item.icon"
|
||||
:class="[item.children.find((d: any) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? 'text-primary-500' : 'text-gray-400 group-hover:text-gray-500', 'flex-shrink-0 w-6 h-6 mr-3']"
|
||||
type="image/svg+xml" />
|
||||
<span class="flex-1">{{ item.name }}</span>
|
||||
|
||||
<svg :class="[item.children.find((d: any) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? 'text-primary-500' : 'text-gray-300 group-hover:text-gray-500', open ? 'rotate-180' : '', 'ml-3 flex-shrink-0 transform transition-colors duration-150 ease-in-out ']"
|
||||
width="16" height="16" viewBox="0 0 24 24" fill="none"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M4.44002 8.9399C4.72127 8.659 5.10252 8.50122 5.50002 8.50122C5.89752 8.50122 6.27877 8.659 6.56002 8.9399L12 14.3799L17.44 8.9399C17.7244 8.67494 18.1005 8.53069 18.4891 8.53755C18.8777 8.54441 19.2484 8.70183 19.5233 8.97666C19.7981 9.25148 19.9555 9.62225 19.9624 10.0109C19.9692 10.3995 19.825 10.7756 19.56 11.0599L13.06 17.5599C12.7788 17.8408 12.3975 17.9986 12 17.9986C11.6025 17.9986 11.2213 17.8408 10.94 17.5599L4.44002 11.0599C4.15912 10.7787 4.00134 10.3974 4.00134 9.9999C4.00134 9.6024 4.15912 9.22115 4.44002 8.9399Z"
|
||||
:fill="item.children.find((d: any) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? '#14A2BA' : '#647375'" />
|
||||
</svg>
|
||||
</DisclosureButton>
|
||||
|
||||
<DisclosurePanel class="space-y-1">
|
||||
<!-- Nested children -->
|
||||
<template v-for="subItem in item.children" :key="subItem.name">
|
||||
<div v-if="subItem.children.length === 0">
|
||||
<!-- Single-level child -->
|
||||
<!-- <RouterLink :to="subItem.href"
|
||||
:class="[isMenu(subItem.href) ? 'text-white font-bold bg-primary-500' : 'font-semibold text-aside hover:bg-primary-100 hover:text-gray-900', 'flex items-center w-11/12 py-2 px-2 text-xs rounded-lg group ml-auto']">
|
||||
{{ subItem.name }}
|
||||
</RouterLink> -->
|
||||
<AsideMenuSingle :item="subItem"
|
||||
:is-menu-selected="isMenu(subItem.href)" :is-children="true" />
|
||||
|
||||
</div>
|
||||
<Disclosure v-else
|
||||
:default-open="subItem.children.find((d: any) => d.href === menuSelected) ? true : false">
|
||||
<!-- Nested child with children -->
|
||||
<template v-slot="{ open }">
|
||||
<DisclosureButton
|
||||
:class="[subItem.children.find((d: any) => d.href === menuSelected) ? 'text-primary-500 font-bold' : 'font-semibold text-aside hover:bg-primary-100 hover:text-gray-900', 'group w-11/12 flex items-center px-2 py-2 text-left text-xs rounded-lg focus:outline-none focus:ring-0 focus:ring-indigo-500 ml-auto']">
|
||||
|
||||
<span class="flex-1">{{ subItem.name }}</span>
|
||||
|
||||
<svg :class="[subItem.children.find((d: any) => d.href === menuSelected) ? 'text-primary-500' : 'text-gray-300 group-hover:text-gray-500', open ? 'rotate-180' : '', 'ml-3 flex-shrink-0 transform transition-colors duration-150 ease-in-out ']"
|
||||
width="16" height="16" viewBox="0 0 24 24" fill="none"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M4.44002 8.9399C4.72127 8.659 5.10252 8.50122 5.50002 8.50122C5.89752 8.50122 6.27877 8.659 6.56002 8.9399L12 14.3799L17.44 8.9399C17.7244 8.67494 18.1005 8.53069 18.4891 8.53755C18.8777 8.54441 19.2484 8.70183 19.5233 8.97666C19.7981 9.25148 19.9555 9.62225 19.9624 10.0109C19.9692 10.3995 19.825 10.7756 19.56 11.0599L13.06 17.5599C12.7788 17.8408 12.3975 17.9986 12 17.9986C11.6025 17.9986 11.2213 17.8408 10.94 17.5599L4.44002 11.0599C4.15912 10.7787 4.00134 10.3974 4.00134 9.9999C4.00134 9.6024 4.15912 9.22115 4.44002 8.9399Z"
|
||||
:fill="subItem.children.find((d: any) => d.href === menuSelected) ? '#14A2BA' : '#647375'" />
|
||||
</svg>
|
||||
</DisclosureButton>
|
||||
<DisclosurePanel class="space-y-1 pl-11">
|
||||
<!-- Nested children of nested child -->
|
||||
<!-- <RouterLink v-for="nestedSubItem in subItem.children"
|
||||
:key="nestedSubItem.name" :to="nestedSubItem.href"
|
||||
:class="[isMenu(nestedSubItem.href) ? 'text-white font-bold bg-primary-500' : 'font-semibold text-aside hover:bg-primary-100 hover:text-gray-900', 'flex items-center w-12/12 py-2 px-2 text-xs rounded-lg group ml-auto']">
|
||||
{{ nestedSubItem.name }}
|
||||
</RouterLink> -->
|
||||
<AsideMenuSingle v-for="nestedSubItem in subItem.children"
|
||||
:key="nestedSubItem.name" :item="nestedSubItem"
|
||||
:is-menu-selected="isMenu(nestedSubItem.href)"
|
||||
:is-children="true" />
|
||||
</DisclosurePanel>
|
||||
</template>
|
||||
|
||||
</Disclosure>
|
||||
</template>
|
||||
</DisclosurePanel>
|
||||
</template>
|
||||
</Disclosure>
|
||||
|
||||
|
||||
</template>
|
||||
</nav>
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</TransitionChild>
|
||||
<div class="flex-shrink-0 w-14" aria-hidden="true">
|
||||
<!-- Dummy element to force sidebar to shrink to fit close icon -->
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</TransitionRoot>
|
||||
<!-- Static sidebar for desktop -->
|
||||
<div class="z-10 hidden bg-primary-50 md:fixed md:inset-y-0 md:flex md:w-80 md:flex-col">
|
||||
<!-- Sidebar component, swap this element with another sidebar if you like -->
|
||||
<div class="flex items-center flex-shrink-0 h-16 px-5">
|
||||
<RouterLink to="/">
|
||||
<img class="w-auto h-11" :src="IconApp" alt="PLN" />
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="flex flex-col flex-grow hover:overflow-y-auto">
|
||||
<div class="flex flex-col flex-grow mt-5">
|
||||
<nav class="flex-1 px-2 pb-4 space-y-1">
|
||||
<template v-for="item in navigation" :key="item.name">
|
||||
<div v-if="item.children.length === 0">
|
||||
<!-- Single-level item -->
|
||||
<AsideMenuSingle :item="item" :is-menu-selected="isMenu(item.href)" />
|
||||
</div>
|
||||
|
||||
<Disclosure v-slot="{ open }" v-else
|
||||
v-bind:default-open="item.children.find((d) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? true : false">
|
||||
<!-- Nested item with children -->
|
||||
<DisclosureButton
|
||||
:class="[item.children.find((d) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? 'text-primary-500 font-bold' : 'font-semibold text-aside hover:bg-primary-100 hover:text-gray-900', 'group w-full flex items-center pl-2 pr-1 py-2 text-left text-xs rounded-lg focus:outline-none focus:ring-0 focus:ring-indigo-500']">
|
||||
<embed :src="item.icon"
|
||||
:class="[item.children.find((d: any) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? 'fill-primary-500' : 'fill-gray-400 group-hover:fill-gray-500', 'flex-shrink-0 w-6 h-6 mr-3']"
|
||||
type="image/svg+xml" />
|
||||
<span class="flex-1">{{ item.name }}</span>
|
||||
|
||||
<svg :class="[item.children.find((d: any) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? 'text-primary-500' : 'text-gray-300 group-hover:text-gray-500', open ? 'rotate-180' : '', 'ml-3 flex-shrink-0 transform transition-colors duration-150 ease-in-out ']"
|
||||
width="16" height="16" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path
|
||||
d="M4.44002 8.9399C4.72127 8.659 5.10252 8.50122 5.50002 8.50122C5.89752 8.50122 6.27877 8.659 6.56002 8.9399L12 14.3799L17.44 8.9399C17.7244 8.67494 18.1005 8.53069 18.4891 8.53755C18.8777 8.54441 19.2484 8.70183 19.5233 8.97666C19.7981 9.25148 19.9555 9.62225 19.9624 10.0109C19.9692 10.3995 19.825 10.7756 19.56 11.0599L13.06 17.5599C12.7788 17.8408 12.3975 17.9986 12 17.9986C11.6025 17.9986 11.2213 17.8408 10.94 17.5599L4.44002 11.0599C4.15912 10.7787 4.00134 10.3974 4.00134 9.9999C4.00134 9.6024 4.15912 9.22115 4.44002 8.9399Z"
|
||||
:fill="item.children.find((d: any) => d.href === menuSelected) || item.children.find((d) => d.children.find((e) => e.href === menuSelected)) ? '#14A2BA' : '#647375'" />
|
||||
</svg>
|
||||
</DisclosureButton>
|
||||
<transition enter-active-class="overflow-hidden transition-all duration-300"
|
||||
enter-from-class="transform scale-95 opacity-0 max-h-0"
|
||||
enter-to-class="transform scale-300 opacity-300 max-h-[1000px]"
|
||||
leave-active-class="overflow-hidden transition-all duration-300"
|
||||
leave-from-class="transform scale-300 opacity-300 max-h-[1000px]"
|
||||
leave-to-class="transform scale-95 opacity-0 max-h-0">
|
||||
<DisclosurePanel class="space-y-1">
|
||||
<!-- Nested children -->
|
||||
<template v-for="(subItem, index) in item.children" :key="subItem.href">
|
||||
<div v-if="!subItem.children || subItem.children.length === 0">
|
||||
<!-- Single-level child -->
|
||||
<AsideMenuSingle :item="subItem" :is-children="true"
|
||||
:is-menu-selected="isMenu(subItem.href)" />
|
||||
</div>
|
||||
<Disclosure :key="subItem.href + index" v-slot="{ open }" v-else
|
||||
:default-open="subItem.children.find((d: any) => d.href === menuSelected) ? true : false">
|
||||
<!-- Nested child with children -->
|
||||
<DisclosureButton
|
||||
:class="[subItem.children.find((d: any) => d.href === menuSelected) ? 'text-primary-500 font-bold' : 'font-semibold text-aside hover:bg-primary-100 hover:text-gray-900', 'group w-11/12 flex items-center px-2 py-2 text-left text-xs rounded-lg focus:outline-none focus:ring-0 focus:ring-indigo-500 ml-auto']">
|
||||
<span class="flex-1">{{ subItem.name }}</span>
|
||||
<svg :class="[subItem.children.find((d: any) => d.href === menuSelected) ? 'text-primary-500' : 'text-gray-300 group-hover:text-gray-500', open ? 'rotate-180' : '', 'ml-3 flex-shrink-0 transform transition-colors duration-150 ease-in-out ']"
|
||||
width="16" height="16" viewBox="0 0 24 24" fill="none"
|
||||
aria-hidden="true">
|
||||
<path
|
||||
d="M4.44002 8.9399C4.72127 8.659 5.10252 8.50122 5.50002 8.50122C5.89752 8.50122 6.27877 8.659 6.56002 8.9399L12 14.3799L17.44 8.9399C17.7244 8.67494 18.1005 8.53069 18.4891 8.53755C18.8777 8.54441 19.2484 8.70183 19.5233 8.97666C19.7981 9.25148 19.9555 9.62225 19.9624 10.0109C19.9692 10.3995 19.825 10.7756 19.56 11.0599L13.06 17.5599C12.7788 17.8408 12.3975 17.9986 12 17.9986C11.6025 17.9986 11.2213 17.8408 10.94 17.5599L4.44002 11.0599C4.15912 10.7787 4.00134 10.3974 4.00134 9.9999C4.00134 9.6024 4.15912 9.22115 4.44002 8.9399Z"
|
||||
:fill="subItem.children.find((d: any) => d.href === menuSelected) ? '#14A2BA' : '#647375'" />
|
||||
</svg>
|
||||
</DisclosureButton>
|
||||
<transition enter-active-class="overflow-hidden transition-all duration-300"
|
||||
enter-from-class="transform scale-95 opacity-0 max-h-0"
|
||||
enter-to-class="transform scale-300 opacity-300 max-h-[1000px]"
|
||||
leave-active-class="overflow-hidden transition-all duration-300"
|
||||
leave-from-class="transform scale-300 opacity-300 max-h-[1000px]"
|
||||
leave-to-class="transform scale-95 opacity-0 max-h-0">
|
||||
<DisclosurePanel class="space-y-1 pl-11">
|
||||
<!-- Nested children of nested child -->
|
||||
<AsideMenuSingle v-for="nestedSubItem in subItem.children"
|
||||
:item="nestedSubItem" :is-children="true"
|
||||
:is-menu-selected="isMenu(subItem.href)" />
|
||||
</DisclosurePanel>
|
||||
</transition>
|
||||
</Disclosure>
|
||||
</template>
|
||||
</DisclosurePanel>
|
||||
</transition>
|
||||
</Disclosure>
|
||||
</template>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,29 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue'
|
||||
import type { MenuItemModel } from '@/utils/interfaces'
|
||||
import { DotOutline } from '@/utils/icons';
|
||||
|
||||
defineProps({
|
||||
item: {
|
||||
type: Object as () => MenuItemModel,
|
||||
required: true
|
||||
},
|
||||
isMenuSelected: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
isChildren: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouterLink :to="item.href"
|
||||
:class="[isMenuSelected ? 'bg-primary-500 text-white font-bold' : 'font-semibold text-aside hover:bg-primary-100 hover:text-gray-900', 'group w-full flex items-center pl-2 py-2 text-xs rounded-lg']">
|
||||
<embed :src="isChildren ? DotOutline : item.icon" type="image/svg+xml"
|
||||
:class="[isMenuSelected ? 'text-white' : 'text-aside group-hover:text-gray-900', 'mr-3 flex-shrink-0 h-6 w-6']">
|
||||
{{ item.name }}
|
||||
</RouterLink>
|
||||
</template>
|
@ -1,18 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue'
|
||||
import type { MenuItemModel } from '@/utils/interfaces'
|
||||
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue'
|
||||
|
||||
defineProps({
|
||||
item: {
|
||||
type: Object as () => MenuItemModel,
|
||||
required: true
|
||||
},
|
||||
isMenuSelected: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template></template>
|
@ -176,7 +176,7 @@ function readRecentMenu() {
|
||||
|
||||
function openMenu(menu: typeof menus[0]) {
|
||||
addMenuToRecent(menu)
|
||||
route.push(menu.href)
|
||||
route.push(menu.path)
|
||||
onClose()
|
||||
}
|
||||
|
||||
|
@ -1,148 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { Dialog, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue';
|
||||
import {
|
||||
CheckIcon,
|
||||
ExclamationTriangleIcon, InformationCircleIcon, QuestionMarkCircleIcon,
|
||||
} from '@heroicons/vue/24/outline'
|
||||
import { XMarkIcon } from '@heroicons/vue/24/solid';
|
||||
import { ref, watch } from 'vue';
|
||||
import InputText from '../InputText.vue';
|
||||
import ButtonPrimary from '../ButtonPrimary.vue';
|
||||
import { dispatchNotification } from '../Notification';
|
||||
|
||||
const props = defineProps({ open: Boolean });
|
||||
const emits = defineEmits(['onClose']);
|
||||
const open = ref(props.open)
|
||||
const oldPassword = ref('');
|
||||
const password = ref('');
|
||||
const passwordConfirmation = ref('');
|
||||
const isLoading = ref(false);
|
||||
|
||||
function close() {
|
||||
open.value = false;
|
||||
emits('onClose', false);
|
||||
}
|
||||
|
||||
function showLoading() {
|
||||
isLoading.value = true;
|
||||
}
|
||||
|
||||
function hideLoading() {
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
function handleOnChangePassword() {
|
||||
if (oldPassword.value == '') {
|
||||
dispatchNotification({
|
||||
title: 'Peringatan',
|
||||
content: 'Password lama tidak boleh kosong',
|
||||
type: 'error',
|
||||
})
|
||||
} else if (password.value == '') {
|
||||
dispatchNotification({
|
||||
title: 'Peringatan',
|
||||
content: 'Password baru tidak boleh kosong',
|
||||
type: 'error',
|
||||
})
|
||||
} else if (passwordConfirmation.value == '') {
|
||||
dispatchNotification({
|
||||
title: 'Peringatan',
|
||||
content: 'Konfirmasi password tidak boleh kosong',
|
||||
type: 'error',
|
||||
})
|
||||
} else if (password.value != passwordConfirmation.value) {
|
||||
dispatchNotification({
|
||||
title: 'Peringatan',
|
||||
content: 'Password baru dan konfirmasi password tidak sama',
|
||||
type: 'error',
|
||||
})
|
||||
} else if (oldPassword.value == password.value) {
|
||||
dispatchNotification({
|
||||
title: 'Peringatan',
|
||||
content: 'Password baru tidak boleh sama dengan password lama',
|
||||
type: 'error',
|
||||
})
|
||||
} else {
|
||||
showLoading();
|
||||
setTimeout(() => {
|
||||
hideLoading();
|
||||
close();
|
||||
}, 15000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
watch(() => props.open, (value) => {
|
||||
open.value = value;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Log Out Dialog -->
|
||||
<TransitionRoot as="template" :show="open">
|
||||
<Dialog as="div" class="relative z-20" @close="close">
|
||||
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0" enter-to="opacity-100"
|
||||
leave="ease-in duration-200" leave-from="opacity-100" leave-to="opacity-0">
|
||||
<div class="fixed inset-0 transition-opacity bg-gray-500 bg-opacity-75" />
|
||||
</TransitionChild>
|
||||
|
||||
<div class="fixed inset-0 z-10 overflow-y-auto">
|
||||
<div class="flex items-center justify-center min-h-full p-4 text-center sm:p-0">
|
||||
<TransitionChild as="template" enter="ease-out duration-300"
|
||||
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200"
|
||||
leave-from="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
|
||||
<DialogPanel
|
||||
class="relative p-4 overflow-hidden text-left transition-all transform bg-white rounded-lg shadow-xl sm:max-w-sm sm:p-6 sm:my-8 sm:w-full">
|
||||
<form @submit.prevent="handleOnChangePassword" class="flex flex-col">
|
||||
<div class="absolute top-0 right-0 pt-4 pr-4 ">
|
||||
<button type="button"
|
||||
class="text-gray-400 bg-white rounded-md hover:text-gray-500 focus:outline-none focus:ring-0"
|
||||
@click="close">
|
||||
<span class="sr-only">Close</span>
|
||||
<XMarkIcon class="w-6 h-6" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<DialogTitle as="h4" class="font-medium leading-6 text-gray-900 text-md">
|
||||
Ubah Password
|
||||
</DialogTitle>
|
||||
<div class="flex flex-col mt-2">
|
||||
<label for="password" class="mb-2 text-xs font-medium text-dark">
|
||||
Password Lama
|
||||
</label>
|
||||
<InputText type="password" class-name="mb-3 text-sm placeholder:text-sm"
|
||||
placeholder="Masukan Password lama" :value="oldPassword"
|
||||
@update:value="oldPassword = $event" />
|
||||
|
||||
<label for="password" class="mb-2 text-xs font-medium text-dark">
|
||||
Password Baru
|
||||
</label>
|
||||
<InputText class-name="mb-3 text-sm placeholder:text-sm" type="password"
|
||||
placeholder="Masukan Password baru" :value="password"
|
||||
@update:value="password = $event" />
|
||||
|
||||
<label for="password" class="mb-2 text-xs font-medium text-dark">
|
||||
Konfirmasi Password
|
||||
</label>
|
||||
<InputText class-name="mb-3 text-sm placeholder:text-sm" type="password"
|
||||
placeholder="Konfirmasi Password" :value="passwordConfirmation"
|
||||
@update:value="passwordConfirmation = $event" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Section -->
|
||||
<div class="mt-2">
|
||||
<ButtonPrimary
|
||||
class-name="inline-flex justify-center w-full px-4 py-2 font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm text-md focus:outline-none focus:ring-0 sm:text-sm"
|
||||
type="submit" label="Ubah Password" :disabled="isLoading" :is-loading="isLoading" />
|
||||
</div>
|
||||
</form>
|
||||
</DialogPanel>
|
||||
</TransitionChild>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</TransitionRoot>
|
||||
</template>
|
@ -1,170 +0,0 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import CommandPalettes from '@/components/CommandPalettes.vue'
|
||||
import MessageBox from '@/components/MessageBox.vue'
|
||||
import ActionDialog from '@/components/Dialogs/ActionDialog.vue'
|
||||
import ChangePasswordDialog from '@/components/Dialogs/ChangePasswordDialog.vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useCommandPalattesStore } from '@/stores/command'
|
||||
import { useMessageStore } from '@/stores/message'
|
||||
import { useMenuStore } from '@/stores/menu'
|
||||
import {
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItem,
|
||||
MenuItems,
|
||||
} from '@headlessui/vue'
|
||||
import {
|
||||
BookOpenIcon,
|
||||
ChatBubbleOvalLeftEllipsisIcon,
|
||||
QuestionMarkCircleIcon,
|
||||
Bars3BottomLeftIcon
|
||||
} from '@heroicons/vue/24/outline'
|
||||
import { MagnifyingGlassIcon } from '@heroicons/vue/24/solid'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import PictureInitial from './PictureInitial.vue'
|
||||
import Icon from '@/assets/images/pln-with-text.png'
|
||||
import { useDialogStore } from '@/stores/dialog'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const userStore = useUserStore()
|
||||
const messageStore = useMessageStore()
|
||||
const commandStore = useCommandPalattesStore()
|
||||
const menu = useMenuStore()
|
||||
const dialog = useDialogStore()
|
||||
|
||||
const openSideBar = () => menu.toggleSidebar()
|
||||
|
||||
const dialogChangePassword = ref(false)
|
||||
|
||||
const handleOnDismissDialogChangePassword = () => {
|
||||
dialogChangePassword.value = false
|
||||
}
|
||||
|
||||
const showDialogChangePassword = () => {
|
||||
dialogChangePassword.value = true
|
||||
}
|
||||
|
||||
const showDialogLogout = () => {
|
||||
dialog.type = 'error'
|
||||
dialog.title = 'Logout dari akun?'
|
||||
dialog.content = 'Apakah Anda sudah yakin akan logout dari akun ini?'
|
||||
dialog.cancelText = 'Batalkan'
|
||||
dialog.confirmText = 'Ya, logout'
|
||||
dialog.showCancelButton = true
|
||||
dialog.onConfirm = () => {
|
||||
window.location.href = '/login'
|
||||
}
|
||||
dialog.open = true
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="sticky top-0 z-10 flex flex-shrink-0 h-16 bg-primary-50 md:ml-80">
|
||||
<button type="button" class="px-4 text-gray-500 focus:outline-none focus:ring-0 md:hidden" @click="openSideBar">
|
||||
<span class="sr-only">Open sidebar</span>
|
||||
<Bars3BottomLeftIcon class="w-6 h-6" aria-hidden="true" />
|
||||
</button>
|
||||
<div class="flex items-center flex-shrink-0 my-auto ml-2 md:hidden">
|
||||
<img class="w-auto h-11" :src="Icon" alt="PLN" />
|
||||
</div>
|
||||
<div class="flex justify-end w-full px-4">
|
||||
<!-- <div class="flex flex-1">
|
||||
<div class="flex w-full md:ml-0">
|
||||
<button @click="commandStore.showCommandPalettes"
|
||||
class="relative w-full text-gray-400 border-0 border-transparent rounded-xl hover:text-primary-500 ring-0 ring-transparent focus:border-transparent focus:border-0 focus:ring-0">
|
||||
<div class="absolute inset-y-0 left-0 flex items-center pointer-events-none">
|
||||
<MagnifyingGlassIcon class="w-5 h-5" aria-hidden="true" />
|
||||
<span class="hidden ml-2 sm:text-sm md:block">Cari menu...</span>
|
||||
</div>
|
||||
</button>
|
||||
<img :src="Icon" alt="pln" class="md:hidden">
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="flex items-center ml-4 md:ml-6">
|
||||
<!-- <button type="button"
|
||||
class="p-1 mr-2 text-gray-400 bg-white rounded-full hover:text-primary-500 focus:outline-none focus:ring-0">
|
||||
<span class="sr-only">FAQ</span>
|
||||
<QuestionMarkCircleIcon class="w-6 h-6" aria-hidden="true" />
|
||||
</button>
|
||||
<button type="button"
|
||||
class="p-1 mr-2 text-gray-400 bg-white rounded-full hover:text-primary-500 focus:outline-none focus:ring-0">
|
||||
<span class="sr-only">Manual Book</span>
|
||||
<BookOpenIcon class="w-6 h-6" aria-hidden="true" />
|
||||
</button>
|
||||
<button type="button" @click="messageStore.showDialogMessageBox"
|
||||
class="p-1 text-gray-400 bg-white rounded-full hover:text-primary-500 focus:outline-none focus:ring-0">
|
||||
<span class="sr-only">Message</span>
|
||||
<ChatBubbleOvalLeftEllipsisIcon class="w-6 h-6" aria-hidden="true" />
|
||||
</button> -->
|
||||
<button @click="commandStore.showCommandPalettes" type="button"
|
||||
class="flex flex-row items-center md:w-[300px] p-2 mr-2 text-gray-400 bg-white rounded-full hover:text-primary-500 focus:outline-none focus:ring-0">
|
||||
<span class="sr-only">Search</span>
|
||||
<MagnifyingGlassIcon class="w-6 h-6 text-primary-500" aria-hidden="true" />
|
||||
<span class="hidden px-3 text-sm font-medium text-gray-500 md:block text-md">Cari menu</span>
|
||||
</button>
|
||||
|
||||
<!-- Profile dropdown -->
|
||||
<Menu as="div" class="relative ml-1">
|
||||
<div>
|
||||
<MenuButton
|
||||
class="flex items-center max-w-xs px-1 py-1 text-sm rounded-full bg-secondary-100 md:bg-primary-500 focus:outline-none focus:ring-0 line-clamp-1">
|
||||
<span class="sr-only">Open user menu</span>
|
||||
<PictureInitial size-class="w-8 h-8" background-class="bg-secondary-100"
|
||||
font-class="text-xs font-bold text-primary-500" :name="userStore.user_name" />
|
||||
<span class="hidden px-3 text-xs font-medium md:block text-primary-50 line-clamp-1">
|
||||
{{ userStore.user_name }}
|
||||
</span>
|
||||
</MenuButton>
|
||||
</div>
|
||||
<transition enter-active-class="transition duration-100 ease-out"
|
||||
enter-from-class="transform scale-95 opacity-0" enter-to-class="transform scale-100 opacity-100"
|
||||
leave-active-class="transition duration-75 ease-in"
|
||||
leave-from-class="transform scale-100 opacity-100" leave-to-class="transform scale-95 opacity-0">
|
||||
|
||||
<MenuItems
|
||||
class="absolute right-0 z-10 w-48 py-1 mt-2 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
||||
<div class="flex-shrink-0 block px-4 py-2 border-b border-gray-50 group">
|
||||
<div class="flex items-center">
|
||||
<div>
|
||||
<!-- <img class="inline-block rounded-full h-9 w-9" :src="userStore.user_image" alt="" /> -->
|
||||
<PictureInitial class-name="nline-block" size-class="w-9 h-9"
|
||||
background-class="bg-gray-100" font-class="font-bold text-gray-600 text-md"
|
||||
:name="userStore.user_name" />
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-700 group-hover:text-gray-900">
|
||||
{{ userStore.user_name }}
|
||||
</p>
|
||||
<p class="text-xs font-medium text-gray-500 group-hover:text-gray-700">
|
||||
{{ userStore.user_access }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<button @click="showDialogChangePassword"
|
||||
:class="[active ? 'bg-gray-100' : '', 'w-full text-left block px-4 py-2 text-sm text-gray-700']">
|
||||
Ubah Password
|
||||
</button>
|
||||
</MenuItem>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<button @click="showDialogLogout"
|
||||
:class="[active ? 'bg-gray-100' : '', 'w-full text-left block px-4 py-2 text-sm text-gray-700']">
|
||||
Log out
|
||||
</button>
|
||||
</MenuItem>
|
||||
</MenuItems>
|
||||
</transition>
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ChangePasswordDialog :open="dialogChangePassword" @onClose="handleOnDismissDialogChangePassword" />
|
||||
<CommandPalettes :open="commandStore.open" @onClose="commandStore.handleOnDismissCommandPalettes" />
|
||||
<MessageBox :open="messageStore.open" @onClose="messageStore.handleOnDismissMessageBox" />
|
||||
</template>
|
@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center justify-center px-6 text-center whitespace-pre-wrap h-screen-80">
|
||||
|
||||
<DocumentArrowUpIcon class="w-12 h-12 mx-auto text-gray-400" aria-hidden="true" />
|
||||
<h3 class="mt-2 font-bold text-gray-900 whitespace-pre-wrap text-md">
|
||||
Cari menu? Ctrl + F
|
||||
</h3>
|
||||
<p class="mt-1 text-sm text-gray-600 whitespace-pre-wrap ">
|
||||
Gunakan kombinasi tombol Ctrl + F untuk mencari menu yang kamu inginkan.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DocumentArrowUpIcon } from '@heroicons/vue/24/outline';
|
||||
</script>
|
@ -1,15 +0,0 @@
|
||||
<template>
|
||||
<div class="mx-auto max-w-7xl">
|
||||
<div class="border-4 border-gray-200 border-dashed rounded-lg h-[74vh]">
|
||||
<div class="flex items-center justify-center h-full">
|
||||
<div class="text-center">
|
||||
<h1 class="text-4xl font-bold text-gray-900">Menu Sample</h1>
|
||||
<p class="mt-2 text-lg text-gray-600">This is a sample menu page.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
</script>
|
@ -1,177 +0,0 @@
|
||||
<template>
|
||||
<TransitionRoot as="template" :show="open">
|
||||
<Dialog as="div" class="relative z-10" @close="close">
|
||||
<div class="fixed inset-0 transition-opacity bg-gray-500 bg-opacity-25 backdrop-blur-sm" />
|
||||
|
||||
<div class="fixed inset-0 overflow-hidden">
|
||||
<div class="absolute inset-0 overflow-hidden ">
|
||||
<div class="fixed inset-y-0 right-0 flex max-w-full pointer-events-none lg:pl-10">
|
||||
<TransitionChild as="template" enter="transform transition ease-in-out duration-500 sm:duration-700"
|
||||
enter-from="translate-x-full" enter-to="translate-x-0"
|
||||
leave="transform transition ease-in-out duration-500 sm:duration-700" leave-from="translate-x-0"
|
||||
leave-to="translate-x-full">
|
||||
<DialogPanel class="w-screen max-w-sm pointer-events-auto">
|
||||
<div class="flex flex-col h-full bg-white shadow-xl">
|
||||
<div class="flex flex-col flex-1 min-h-0 ">
|
||||
<div class="flex items-center w-full h-16 px-4 bg-white sm:px-6 drop-shadow-sm">
|
||||
<div class="flex items-start justify-between w-full">
|
||||
<DialogTitle v-if="peopleIndexSelected !== null"
|
||||
class="text-sm font-medium text-gray-900">
|
||||
<PictureInitial class-name="mr-2" background-class="bg-primary-400"
|
||||
font-class="font-medium text-white text-md"
|
||||
:name="people[peopleIndexSelected].name" />
|
||||
{{ people[peopleIndexSelected].name }}
|
||||
</DialogTitle>
|
||||
<DialogTitle v-else class="font-medium text-gray-900 text-md">
|
||||
Team
|
||||
</DialogTitle>
|
||||
<div class="flex items-center ml-3 h-7 ">
|
||||
<button type="button"
|
||||
class="text-gray-400 bg-white rounded-md hover:text-gray-500 focus:ring-0 "
|
||||
@click="peopleIndexSelected === null ? close() : selectPeople(null)">
|
||||
<span class="sr-only">Close panel</span>
|
||||
<XMarkIcon class="w-6 h-6" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto bg-layout">
|
||||
<div v-if="peopleIndexSelected !== null"
|
||||
class="flex flex-col items-center justify-center h-full px-4 sm:px-6"
|
||||
aria-hidden="true">
|
||||
<ChatBubbleLeftRightIcon class="w-12 h-12 mx-auto text-gray-400"
|
||||
aria-hidden="true" />
|
||||
<h3
|
||||
class="mt-2 font-bold text-center text-gray-900 whitespace-pre-wrap text-md">
|
||||
Tidak ada percakapan
|
||||
</h3>
|
||||
<p class="mt-1 text-sm text-center text-gray-600 whitespace-pre-wrap ">
|
||||
Mulai percakapan dengan <b>{{ people[peopleIndexSelected].name }}</b>
|
||||
untuk melihat percakapan disini.
|
||||
</p>
|
||||
</div>
|
||||
<div v-else class="h-full bg-white" aria-hidden="true">
|
||||
<ul role="list" class="flex-1 overflow-y-auto divide-y divide-gray-50">
|
||||
<li v-for="(person, index) in people" :key="person.id"
|
||||
class="cursor-pointer" @click="selectPeople(index)">
|
||||
<div class="relative flex items-center px-5 py-3 group">
|
||||
<div class="flex-1 block p-1 -m-1">
|
||||
<div class="absolute inset-0 group-hover:bg-primary-100"
|
||||
aria-hidden="true" />
|
||||
<div class="relative flex items-center flex-1 min-w-0">
|
||||
<span class="relative flex-shrink-0 inline-block">
|
||||
<PictureInitial size-class="w-10 h-10"
|
||||
background-class="bg-primary-400"
|
||||
font-class="font-medium text-white text-md"
|
||||
:name="person.name" />
|
||||
<span
|
||||
:class="[person.online ? 'bg-green-400' : 'bg-gray-300', 'absolute top-0 right-0 block h-2.5 w-2.5 rounded-full ring-2 ring-white']"
|
||||
aria-hidden="true" />
|
||||
</span>
|
||||
<div class="ml-4 truncate">
|
||||
<p
|
||||
class="text-sm font-medium text-gray-900 truncate">
|
||||
{{ person.name }}</p>
|
||||
<p class="text-sm text-gray-500 truncate">
|
||||
@User</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full px-4 py-4 shadow" v-if="peopleIndexSelected !== null">
|
||||
<form @submit.prevent="messageStore.send"
|
||||
class="flex items-center justify-between flex-shrink-0">
|
||||
<InputText class-name="w-full mr-4 py-2 px-4" placeholder="Tulis pesan di sini"
|
||||
:value="messageStore.message"
|
||||
@update:value="messageStore.message = $event" />
|
||||
|
||||
<button type="submit" :disabled="messageStore.isSending"
|
||||
class="text-sm font-bold text-white bg-transparent border-transparent rounded-full w-7 h-7 focus:outline-0 focus:ring-0">
|
||||
<PaperAirplaneIcon class="pointer-events-none w-7 h-7 text-primary-500"
|
||||
aria-hidden="true" />
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</TransitionChild>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</TransitionRoot>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { Dialog, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'
|
||||
import { XMarkIcon } from '@heroicons/vue/24/outline'
|
||||
import { useMessageStore } from '@/stores/message';
|
||||
import { ChatBubbleLeftRightIcon, DocumentArrowUpIcon, PaperAirplaneIcon } from '@heroicons/vue/24/solid';
|
||||
import InputText from '@/components/InputText.vue'
|
||||
import PictureInitial from '@/components/PictureInitial.vue'
|
||||
|
||||
const messageStore = useMessageStore()
|
||||
const props = defineProps({ open: Boolean })
|
||||
const emit = defineEmits(['onClose'])
|
||||
const open = ref(props.open)
|
||||
|
||||
const peopleIndexSelected = ref(null)
|
||||
|
||||
const people = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Ajeng Sindia',
|
||||
image: 'https://images.unsplash.com/photo-1505840717430-882ce147ef2d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
|
||||
online: false
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Jamaludin',
|
||||
image: 'https://images.unsplash.com/photo-1531427186611-ecfd6d936c79?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
|
||||
online: false
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Kumara',
|
||||
image: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
|
||||
online: false
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Bellayanti',
|
||||
image: 'https://images.unsplash.com/photo-1509783236416-c9ad59bae472?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
|
||||
online: false
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Jefri',
|
||||
image: 'https://images.unsplash.com/photo-1517070208541-6ddc4d3efbcb?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
|
||||
online: false
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Kinanti',
|
||||
image: 'https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
|
||||
online: false
|
||||
},
|
||||
]
|
||||
|
||||
function selectPeople(value: any) {
|
||||
peopleIndexSelected.value = value
|
||||
}
|
||||
|
||||
function close() {
|
||||
open.value = false
|
||||
emit('onClose')
|
||||
}
|
||||
|
||||
watch(() => props.open, (value) => {
|
||||
open.value = value;
|
||||
});
|
||||
</script>
|
@ -1,9 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import Aside from '@/components/Aside/Aside.vue'
|
||||
import Header from '@/components/Header.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Header />
|
||||
<Aside />
|
||||
</template>
|
133
src/components/Navigation/Aside/Aside.vue
Normal file
133
src/components/Navigation/Aside/Aside.vue
Normal file
@ -0,0 +1,133 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, watch } from 'vue'
|
||||
import { useRoute, RouterLink, useRouter } from 'vue-router'
|
||||
import {
|
||||
Dialog,
|
||||
DialogPanel,
|
||||
TransitionChild,
|
||||
TransitionRoot,
|
||||
} from '@headlessui/vue'
|
||||
import { XMarkIcon } from '@heroicons/vue/24/outline'
|
||||
import { useMenuStore } from '@/stores/menu'
|
||||
import { IconApp } from '@/utils/icons'
|
||||
import AsideMenuSingle from '@/components/Navigation/Aside/AsideMenuSingle.vue'
|
||||
import AsideMenuMultiple from '@/components/Navigation/Aside/AsideMenuMultiple.vue'
|
||||
import { Bars3BottomLeftIcon } from '@heroicons/vue/20/solid'
|
||||
import { splitRoutePath } from '@/utils/texts'
|
||||
|
||||
const menu = useMenuStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
watch(route, (to, _) => {
|
||||
menu.menuSelected = to.fullPath
|
||||
closeSideBar()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
menu.menuSelected = router.currentRoute.value.fullPath
|
||||
if (menu.menuSelected !== '/' && menu.menuSelected !== '/home' && menu.menuSelected.includes('/home')) {
|
||||
const result = splitRoutePath(menu.menuSelected)
|
||||
|
||||
for (const route of result) {
|
||||
if (route !== '/home') {
|
||||
menu.toggleSidebarMenu(route, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const isMenu = (name: string) => {
|
||||
return menu.menuSelected === name
|
||||
}
|
||||
|
||||
const closeSideBar = () => menu.toggleSidebar()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TransitionRoot as="template" :show="menu.sidebarOpen">
|
||||
<Dialog as="div" class="relative z-40 md:hidden" @close="closeSideBar">
|
||||
<TransitionChild as="template" enter="transition-opacity ease-linear duration-300" enter-from="opacity-0"
|
||||
enter-to="opacity-100" leave="transition-opacity ease-linear duration-300" leave-from="opacity-100"
|
||||
leave-to="opacity-0">
|
||||
<div class="fixed inset-0 bg-gray-600 bg-opacity-75" />
|
||||
</TransitionChild>
|
||||
|
||||
<div class="fixed inset-0 z-40 flex">
|
||||
<TransitionChild as="template" enter="transition ease-in-out duration-300 transform"
|
||||
enter-from="-translate-x-full" enter-to="translate-x-0"
|
||||
leave="transition ease-in-out duration-300 transform" leave-from="translate-x-0"
|
||||
leave-to="-translate-x-full">
|
||||
<DialogPanel class="relative flex flex-col flex-1 w-full max-w-xs pt-5 pb-4 bg-primary-50">
|
||||
<TransitionChild as="template" enter="ease-in-out duration-300" enter-from="opacity-0"
|
||||
enter-to="opacity-100" leave="ease-in-out duration-300" leave-from="opacity-100"
|
||||
leave-to="opacity-0">
|
||||
<div class="absolute top-0 right-0 pt-2 -mr-12">
|
||||
<button type="button"
|
||||
class="flex items-center justify-center w-10 h-10 ml-1 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
|
||||
@click="closeSideBar">
|
||||
<span class="sr-only">Close sidebar</span>
|
||||
<XMarkIcon class="w-6 h-6 text-white" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</TransitionChild>
|
||||
<div class="flex items-center flex-shrink-0 px-4">
|
||||
<RouterLink to="/">
|
||||
<img class="w-auto h-16" :src="IconApp" alt="PLN" />
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="flex-1 h-0 mt-5 overflow-y-auto">
|
||||
<nav class="px-2 space-y-1">
|
||||
<template v-for="item in menu.navigation" :key="item.name">
|
||||
<!-- Single-level item -->
|
||||
<AsideMenuSingle v-if="item.children.length === 0" :item="item"
|
||||
:selected="isMenu(item.path)" />
|
||||
|
||||
<!-- Nested item with children -->
|
||||
<AsideMenuMultiple v-else :item="item" :selected="isMenu(item.path)" />
|
||||
</template>
|
||||
</nav>
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</TransitionChild>
|
||||
<div class="flex-shrink-0 w-14" aria-hidden="true">
|
||||
<!-- Dummy element to force sidebar to shrink to fit close icon -->
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</TransitionRoot>
|
||||
<!-- Static sidebar for desktop -->
|
||||
<div class="z-10 hidden md:fixed md:inset-y-0 md:flex md:w-80 md:flex-col">
|
||||
<!-- Sidebar component, swap this element with another sidebar if you like -->
|
||||
<div class="flex flex-row items-center flex-shrink-0 h-16 px-2 bg-primary-50">
|
||||
<button type="button"
|
||||
class="px-4 py-4 text-gray-500 rounded-full hover:bg-primary-100 focus:outline-none focus:ring-0"
|
||||
@click="menu.toggleSidebarDesktop()">
|
||||
<span class="sr-only">Open sidebar</span>
|
||||
<Bars3BottomLeftIcon class="w-6 h-6" aria-hidden="true" />
|
||||
</button>
|
||||
<RouterLink to="/">
|
||||
<img class="w-auto h-11" :src="IconApp" alt="PLN" />
|
||||
</RouterLink>
|
||||
</div>
|
||||
<span v-if="menu.sidebarShowed" class="px-4 mt-4 text-sm font-semibold text-primary-800">
|
||||
Menu
|
||||
</span>
|
||||
<div :class="[menu.sidebarShowed ? 'flex flex-col flex-grow overflow-y-auto' : 'hidden', '']">
|
||||
<div class="flex flex-col flex-grow mt-3">
|
||||
<nav class="flex-1 px-2 pb-4 space-y-1">
|
||||
<template v-for="item in menu.navigation" :key="item.name">
|
||||
<!-- Single-level item -->
|
||||
<AsideMenuSingle v-if="item.children.length === 0" :item="item" :selected="isMenu(item.path)" />
|
||||
|
||||
<!-- Nested item with children -->
|
||||
<AsideMenuMultiple v-else :item="item" :selected="isMenu(item.path)" />
|
||||
</template>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@/utils/text@/utils/texts
|
74
src/components/Navigation/Aside/AsideMenuMultiple.vue
Normal file
74
src/components/Navigation/Aside/AsideMenuMultiple.vue
Normal file
@ -0,0 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { MenuItemModel } from '@/utils/interfaces'
|
||||
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue'
|
||||
import { useMenuStore } from '@/stores/menu'
|
||||
import { DotOutline } from '@/utils/icons'
|
||||
import AsideMenuSingle from '@/components/Navigation/Aside/AsideMenuSingle.vue'
|
||||
const menu = useMenuStore()
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object as () => MenuItemModel,
|
||||
required: true
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
isChildren: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const isMenu = (name: string) => {
|
||||
return menu.menuSelected === name
|
||||
}
|
||||
|
||||
const isMenuSelected = computed(() => {
|
||||
return props.item.children.find((d) => d.path === menu.menuSelected) || props.item.children.find((d) => d.children.find((e) => e.path === menu.menuSelected))
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="[isChildren ? 'ml-2 mt-1 bg-primary-100 rounded-xl' : '']">
|
||||
<Disclosure v-bind:default-open="isMenuSelected ? true : false" as="dev">
|
||||
<!-- Nested item with children -->
|
||||
<DisclosureButton @click="menu.toggleSidebarMenu(item.path, !item.expanded)"
|
||||
:class="[(isMenuSelected || item.expanded || isChildren || item.expanded) ? 'bg-primary-100 text-primary-500 font-bold' : 'text-gray-600 font-semibold text-aside hover:bg-primary-100 hover:text-primary-500', isChildren ? 'pl-1 pr-2' : 'px-2', 'group w-full flex items-center py-2 text-left text-xs rounded-lg focus:outline-none focus:ring-0']">
|
||||
<embed :src="isChildren ? DotOutline : item.icon"
|
||||
:class="[isMenuSelected ? 'fill-primary-500' : 'fill-gray-400 group-hover:fill-gray-500', isChildren ? '' : 'mr-2', 'flex-shrink-0 w-6 h-6']"
|
||||
type="image/svg+xml" />
|
||||
<span class="flex-1">{{ item.name }}</span>
|
||||
|
||||
<svg :class="[isMenuSelected ? 'text-primary-500' : 'text-gray-300 group-hover:text-gray-500', item.expanded ? 'rotate-180' : '', 'ml-3 flex-shrink-0 transform transition-colors duration-150 ease-in-out ']"
|
||||
width="16" height="16" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path
|
||||
d="M4.44002 8.9399C4.72127 8.659 5.10252 8.50122 5.50002 8.50122C5.89752 8.50122 6.27877 8.659 6.56002 8.9399L12 14.3799L17.44 8.9399C17.7244 8.67494 18.1005 8.53069 18.4891 8.53755C18.8777 8.54441 19.2484 8.70183 19.5233 8.97666C19.7981 9.25148 19.9555 9.62225 19.9624 10.0109C19.9692 10.3995 19.825 10.7756 19.56 11.0599L13.06 17.5599C12.7788 17.8408 12.3975 17.9986 12 17.9986C11.6025 17.9986 11.2213 17.8408 10.94 17.5599L4.44002 11.0599C4.15912 10.7787 4.00134 10.3974 4.00134 9.9999C4.00134 9.6024 4.15912 9.22115 4.44002 8.9399Z"
|
||||
:fill="isMenuSelected ? '#14A2BA' : '#647375'" />
|
||||
</svg>
|
||||
</DisclosureButton>
|
||||
<transition enter-active-class="overflow-hidden transition-all duration-300"
|
||||
enter-from-class="transform scale-95 max-h-0" enter-to-class="transform scale-100 max-h-[1000px]"
|
||||
leave-active-class="overflow-hidden transition-all duration-300"
|
||||
leave-from-class="transform scale-100 max-h-[1000px]" leave-to-class="transform scale-95 max-h-0">
|
||||
<div v-show="item.expanded">
|
||||
<DisclosurePanel :class="['bg-primary-100 rounded-xl ml-4', 'space-y-1']" static>
|
||||
<!-- Nested children -->
|
||||
<template v-for="(subItem, index) in item.children" :key="subItem.path">
|
||||
<!-- Single-level child -->
|
||||
<AsideMenuSingle v-if="subItem.children.length === 0" :item="subItem" :is-children="true"
|
||||
:selected="isMenu(subItem.path)" />
|
||||
<!-- Multiple-level child -->
|
||||
<AsideMenuMultiple v-else :item="subItem" :selected="subItem.path === menu.menuSelected"
|
||||
:is-children="true" />
|
||||
</template>
|
||||
</DisclosurePanel>
|
||||
</div>
|
||||
|
||||
</transition>
|
||||
|
||||
</Disclosure>
|
||||
</div>
|
||||
</template>
|
44
src/components/Navigation/Aside/AsideMenuSingle.vue
Normal file
44
src/components/Navigation/Aside/AsideMenuSingle.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import type { MenuItemModel } from '@/utils/interfaces'
|
||||
|
||||
defineProps({
|
||||
item: {
|
||||
type: Object as () => MenuItemModel,
|
||||
required: true
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
isChildren: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="group">
|
||||
<RouterLink :to="item.path"
|
||||
:class="[selected ? 'aside-single-item-active' : 'aside-single-item-inactive', isChildren ? 'mt-1' : 'mt-0']">
|
||||
|
||||
<svg v-if="isChildren"
|
||||
:class="[selected ? 'aside-single-item-icon stroke-white' : 'aside-single-item-icon-inactive']" width="16"
|
||||
height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="DotOutline">
|
||||
<path id="Vector" opacity="0.2"
|
||||
d="M9.5 8C9.5 8.29667 9.41203 8.58668 9.24721 8.83336C9.08238 9.08003 8.84812 9.27229 8.57403 9.38582C8.29994 9.49935 7.99834 9.52906 7.70737 9.47118C7.41639 9.4133 7.14912 9.27044 6.93934 9.06066C6.72956 8.85088 6.5867 8.58361 6.52882 8.29264C6.47094 8.00166 6.50065 7.70006 6.61418 7.42597C6.72771 7.15189 6.91997 6.91762 7.16665 6.7528C7.41332 6.58797 7.70333 6.5 8 6.5C8.39783 6.5 8.77936 6.65804 9.06066 6.93934C9.34197 7.22064 9.5 7.60218 9.5 8Z"
|
||||
fill="#4B5563" />
|
||||
<path id="Vector_2"
|
||||
d="M8 6C7.60444 6 7.21776 6.1173 6.88886 6.33706C6.55996 6.55682 6.30362 6.86918 6.15224 7.23463C6.00087 7.60009 5.96126 8.00222 6.03843 8.39018C6.1156 8.77814 6.30608 9.13451 6.58579 9.41421C6.86549 9.69392 7.22186 9.8844 7.60982 9.96157C7.99778 10.0387 8.39992 9.99913 8.76537 9.84776C9.13082 9.69638 9.44318 9.44004 9.66294 9.11114C9.8827 8.78224 10 8.39556 10 8C10 7.46957 9.78929 6.96086 9.41421 6.58579C9.03914 6.21071 8.53043 6 8 6ZM8 9C7.80222 9 7.60888 8.94135 7.44443 8.83147C7.27998 8.72159 7.15181 8.56541 7.07612 8.38268C7.00043 8.19996 6.98063 7.99889 7.01922 7.80491C7.0578 7.61093 7.15304 7.43275 7.29289 7.29289C7.43275 7.15304 7.61093 7.0578 7.80491 7.01921C7.99889 6.98063 8.19996 7.00043 8.38268 7.07612C8.56541 7.15181 8.72159 7.27998 8.83147 7.44443C8.94135 7.60888 9 7.80222 9 8C9 8.26522 8.89464 8.51957 8.70711 8.70711C8.51957 8.89464 8.26522 9 8 9Z"
|
||||
fill="#4B5563" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<embed v-else :src="item.icon" type="image/svg+xml"
|
||||
:class="[selected ? 'text-white fill-white' : 'text-aside group-hover:text-white group-hover:fill-white', 'mr-2 flex-shrink-0 h-6 w-6']">
|
||||
|
||||
{{ item.name }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
</template>
|
111
src/components/Navigation/Header.vue
Normal file
111
src/components/Navigation/Header.vue
Normal file
@ -0,0 +1,111 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useCommandPalattesStore } from '@/stores/command'
|
||||
import { useMenuStore } from '@/stores/menu'
|
||||
import {
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItem,
|
||||
MenuItems,
|
||||
} from '@headlessui/vue'
|
||||
import {
|
||||
Bars3BottomLeftIcon
|
||||
} from '@heroicons/vue/24/outline'
|
||||
import { MagnifyingGlassIcon } from '@heroicons/vue/24/solid'
|
||||
import PictureInitial from '@/components/PictureInitial.vue'
|
||||
import { useDialogStore } from '@/stores/dialog'
|
||||
import { IconApp } from '@/utils/icons'
|
||||
|
||||
const auth = useAuthStore()
|
||||
const user = useUserStore()
|
||||
const command = useCommandPalattesStore()
|
||||
const menu = useMenuStore()
|
||||
const dialog = useDialogStore()
|
||||
|
||||
const openSideBar = () => menu.toggleSidebar()
|
||||
|
||||
const showDialogLogout = () => {
|
||||
dialog.type = 'error'
|
||||
dialog.title = 'Logout dari akun?'
|
||||
dialog.content = 'Apakah Anda sudah yakin akan logout dari akun ini?'
|
||||
dialog.cancelText = 'Batalkan'
|
||||
dialog.confirmText = 'Ya, logout'
|
||||
dialog.showCancelButton = true
|
||||
dialog.onConfirm = () => {
|
||||
auth.logout()
|
||||
window.location.href = '/login'
|
||||
}
|
||||
dialog.open = true
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="sticky top-0 z-10 flex flex-shrink-0 h-16 bg-primary-50 md:ml-80">
|
||||
<button type="button" class="px-4 text-gray-500 focus:outline-none focus:ring-0 md:hidden" @click="openSideBar">
|
||||
<span class="sr-only">Open sidebar</span>
|
||||
<Bars3BottomLeftIcon class="w-6 h-6" aria-hidden="true" />
|
||||
</button>
|
||||
<div class="flex items-center flex-shrink-0 my-auto ml-2 md:hidden">
|
||||
<img class="w-auto h-11" :src="IconApp" alt="PLN" />
|
||||
</div>
|
||||
<div class="flex justify-end w-full px-4">
|
||||
<div class="flex items-center ml-4 md:ml-6">
|
||||
<button @click="command.showCommandPalettes" type="button"
|
||||
class="flex flex-row items-center md:w-[300px] p-2 mr-2 text-gray-400 bg-white rounded-full hover:text-primary-500 focus:outline-none focus:ring-0">
|
||||
<span class="sr-only">Search</span>
|
||||
<MagnifyingGlassIcon class="w-6 h-6 text-primary-500" aria-hidden="true" />
|
||||
<span class="hidden px-3 text-sm font-medium text-gray-500 md:block text-md">Cari menu</span>
|
||||
</button>
|
||||
|
||||
<!-- Profile dropdown -->
|
||||
<Menu as="div" class="relative ml-1">
|
||||
<div>
|
||||
<MenuButton
|
||||
class="flex items-center max-w-xs px-1 py-1 text-sm rounded-full bg-secondary-100 md:bg-primary-500 focus:outline-none focus:ring-0 line-clamp-1">
|
||||
<span class="sr-only">Open user menu</span>
|
||||
<PictureInitial size-class="w-8 h-8" background-class="bg-secondary-100"
|
||||
font-class="text-xs font-bold text-primary-500" :name="user.user_name" />
|
||||
<span class="hidden px-3 text-xs font-medium md:block text-primary-50 line-clamp-1">
|
||||
{{ user.user_name }}
|
||||
</span>
|
||||
</MenuButton>
|
||||
</div>
|
||||
<transition enter-active-class="transition duration-100 ease-out"
|
||||
enter-from-class="transform scale-95 opacity-0" enter-to-class="transform scale-100 opacity-100"
|
||||
leave-active-class="transition duration-75 ease-in"
|
||||
leave-from-class="transform scale-100 opacity-100" leave-to-class="transform scale-95 opacity-0">
|
||||
|
||||
<MenuItems class="container-menu-item">
|
||||
<div class="container-menu-profile group">
|
||||
<div class="flex items-center">
|
||||
<div>
|
||||
<PictureInitial class-name="inline-block" size-class="w-9 h-9"
|
||||
background-class="bg-secondary-100"
|
||||
font-class="text-xs font-normal font-semibold text-primary-500"
|
||||
:name="user.user_name" />
|
||||
</div>
|
||||
<div class="ml-3 space-y-1">
|
||||
<p class="text-sm font-medium text-primary-50 ">
|
||||
{{ user.user_name }}
|
||||
</p>
|
||||
<p class="text-xs font-normal text-primary-50">
|
||||
{{ user.user_access }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<button @click="showDialogLogout" :class="[active ? 'menu-item-active' : 'menu-item']">
|
||||
Log out
|
||||
</button>
|
||||
</MenuItem>
|
||||
</MenuItems>
|
||||
</transition>
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
9
src/components/Navigation/Navigation.vue
Normal file
9
src/components/Navigation/Navigation.vue
Normal file
@ -0,0 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import Aside from '@/components/Navigation/Aside/Aside.vue'
|
||||
import Header from '@/components/Navigation/Header.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Header />
|
||||
<Aside />
|
||||
</template>
|
@ -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'
|
17
src/components/Pages/HomeEmpty.vue
Normal file
17
src/components/Pages/HomeEmpty.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center justify-center px-6 text-center whitespace-pre-wrap h-screen-80">
|
||||
|
||||
<!-- <HomeIcon class="w-12 h-12 mx-auto text-gray-400" aria-hidden="true" /> -->
|
||||
<h3 class="mt-2 text-gray-400 whitespace-pre-wrap text-md">
|
||||
Selamat datang di aplikasi
|
||||
</h3>
|
||||
<h1 class="mt-1 text-2xl font-semibold text-gray-500 whitespace-pre-wrap">
|
||||
{{ appName }}
|
||||
</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HomeIcon } from '@heroicons/vue/20/solid'
|
||||
const appName = import.meta.env.VITE_APP_NAME
|
||||
</script>
|
203
src/components/Pages/TestPage.vue
Normal file
203
src/components/Pages/TestPage.vue
Normal file
@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<div>
|
||||
<DxDataGrid :data-source="employees" key-expr="ID" :show-column-lines="showColumnLines"
|
||||
:show-row-lines="showRowLines" :show-borders="showBorders" :row-alternation-enabled="rowAlternationEnabled"
|
||||
:hover-state-enabled="true" @selection-changed="onSelectionChanged">
|
||||
<DxSelection mode="single" />
|
||||
<DxColumn :width="80" data-field="Prefix" caption="Title" />
|
||||
<DxColumn data-field="FirstName" />
|
||||
<DxColumn data-field="LastName" />
|
||||
<DxColumn data-field="City" />
|
||||
<DxColumn data-field="State" />
|
||||
<DxColumn :width="130" data-field="Position" />
|
||||
<DxColumn :width="100" data-field="BirthDate" data-type="date" />
|
||||
<DxColumn :width="100" data-field="HireDate" data-type="date" />
|
||||
</DxDataGrid>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DxCheckBox, DxDataGrid } from 'devextreme-vue';
|
||||
import { DxColumn, DxSelection } from 'devextreme-vue/data-grid';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const showColumnLines = ref(false);
|
||||
const showRowLines = ref(false);
|
||||
const showBorders = ref(false);
|
||||
const rowAlternationEnabled = ref(true);
|
||||
interface Employee {
|
||||
ID: number;
|
||||
FirstName: string;
|
||||
LastName: string;
|
||||
Prefix: string;
|
||||
Position: string;
|
||||
Picture: string;
|
||||
BirthDate: string;
|
||||
HireDate: string;
|
||||
Notes: string;
|
||||
Address: string;
|
||||
State: string;
|
||||
City: string;
|
||||
}
|
||||
|
||||
const employees: Employee[] = [{
|
||||
ID: 1,
|
||||
FirstName: 'John',
|
||||
LastName: 'Heart',
|
||||
Prefix: 'Mr.',
|
||||
Position: 'CEO',
|
||||
Picture: 'images/employees/01.png',
|
||||
BirthDate: '1964/03/16',
|
||||
HireDate: '1995/01/15',
|
||||
Notes: 'John has been in the Audio/Video industry since 1990. He has led DevAv as its CEO since 2003.\r\n\r\nWhen not working hard as the CEO, John loves to golf and bowl. He once bowled a perfect game of 300.',
|
||||
Address: '351 S Hill St.',
|
||||
State: 'California',
|
||||
City: 'Los Angeles',
|
||||
}, {
|
||||
ID: 2,
|
||||
FirstName: 'Olivia',
|
||||
LastName: 'Peyton',
|
||||
Prefix: 'Mrs.',
|
||||
Position: 'Sales Assistant',
|
||||
Picture: 'images/employees/09.png',
|
||||
BirthDate: '1981/06/03',
|
||||
HireDate: '2012/05/14',
|
||||
Notes: 'Olivia loves to sell. She has been selling DevAV products since 2012. \r\n\r\nOlivia was homecoming queen in high school. She is expecting her first child in 6 months. Good Luck Olivia.',
|
||||
Address: '807 W Paseo Del Mar',
|
||||
State: 'California',
|
||||
City: 'Los Angeles',
|
||||
}, {
|
||||
ID: 3,
|
||||
FirstName: 'Robert',
|
||||
LastName: 'Reagan',
|
||||
Prefix: 'Mr.',
|
||||
Position: 'CMO',
|
||||
Picture: 'images/employees/03.png',
|
||||
BirthDate: '1974/09/07',
|
||||
HireDate: '2002/11/08',
|
||||
Notes: 'Robert was recently voted the CMO of the year by CMO Magazine. He is a proud member of the DevAV Management Team.\r\n\r\nRobert is a championship BBQ chef, so when you get the chance ask him for his secret recipe.',
|
||||
Address: '4 Westmoreland Pl.',
|
||||
State: 'Arkansas',
|
||||
City: 'Bentonville',
|
||||
}, {
|
||||
ID: 4,
|
||||
FirstName: 'Greta',
|
||||
LastName: 'Sims',
|
||||
Prefix: 'Ms.',
|
||||
Position: 'HR Manager',
|
||||
Picture: 'images/employees/04.png',
|
||||
BirthDate: '1977/11/22',
|
||||
HireDate: '1998/04/23',
|
||||
Notes: "Greta has been DevAV's HR Manager since 2003. She joined DevAV from Sonee Corp.\r\n\r\nGreta is currently training for the NYC marathon. Her best marathon time is 4 hours. Go Greta.",
|
||||
Address: '1700 S Grandview Dr.',
|
||||
State: 'Georgia',
|
||||
City: 'Atlanta',
|
||||
}, {
|
||||
ID: 5,
|
||||
FirstName: 'Brett',
|
||||
LastName: 'Wade',
|
||||
Prefix: 'Mr.',
|
||||
Position: 'IT Manager',
|
||||
Picture: 'images/employees/05.png',
|
||||
BirthDate: '1968/12/01',
|
||||
HireDate: '2009/03/06',
|
||||
Notes: 'Brett came to DevAv from Microsoft and has led our IT department since 2012.\r\n\r\nWhen he is not working hard for DevAV, he coaches Little League (he was a high school pitcher).',
|
||||
Address: '1120 Old Mill Rd.',
|
||||
State: 'Idaho',
|
||||
City: 'Boise',
|
||||
}, {
|
||||
ID: 6,
|
||||
FirstName: 'Sandra',
|
||||
LastName: 'Johnson',
|
||||
Prefix: 'Mrs.',
|
||||
Position: 'Controller',
|
||||
Picture: 'images/employees/06.png',
|
||||
BirthDate: '1974/11/15',
|
||||
HireDate: '2005/05/11',
|
||||
Notes: "Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you've not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.",
|
||||
Address: '4600 N Virginia Rd.',
|
||||
State: 'Utah',
|
||||
City: 'Beaver',
|
||||
}, {
|
||||
ID: 7,
|
||||
FirstName: 'Kevin',
|
||||
LastName: 'Carter',
|
||||
Prefix: 'Mr.',
|
||||
Position: 'Shipping Manager',
|
||||
Picture: 'images/employees/07.png',
|
||||
BirthDate: '1978/01/09',
|
||||
HireDate: '2009/08/11',
|
||||
Notes: 'Kevin is our hard-working shipping manager and has been helping that department work like clockwork for 18 months.\r\n\r\nWhen not in the office, he is usually on the basketball court playing pick-up games.',
|
||||
Address: '424 N Main St.',
|
||||
State: 'California',
|
||||
City: 'San Diego',
|
||||
}, {
|
||||
ID: 8,
|
||||
FirstName: 'Cynthia',
|
||||
LastName: 'Stanwick',
|
||||
Prefix: 'Ms.',
|
||||
Position: 'HR Assistant',
|
||||
Picture: 'images/employees/08.png',
|
||||
BirthDate: '1985/06/05',
|
||||
HireDate: '2008/03/24',
|
||||
Notes: 'Cindy joined us in 2008 and has been in the HR department for 2 years. \r\n\r\nShe was recently awarded employee of the month. Way to go Cindy!',
|
||||
Address: '2211 Bonita Dr.',
|
||||
State: 'Arkansas',
|
||||
City: 'Little Rock',
|
||||
}, {
|
||||
ID: 9,
|
||||
FirstName: 'Kent',
|
||||
LastName: 'Samuelson',
|
||||
Prefix: 'Dr.',
|
||||
Position: 'Ombudsman',
|
||||
Picture: 'images/employees/02.png',
|
||||
BirthDate: '1972/09/11',
|
||||
HireDate: '2009/04/22',
|
||||
Notes: 'As our ombudsman, Kent is on the front-lines solving customer problems and helping our partners address issues out in the field. He is a classically trained musician and is a member of the Chamber Orchestra.',
|
||||
Address: '12100 Mora Dr',
|
||||
State: 'Missouri',
|
||||
City: 'St. Louis',
|
||||
}, {
|
||||
ID: 10,
|
||||
FirstName: 'Taylor',
|
||||
LastName: 'Riley',
|
||||
Prefix: 'Mr.',
|
||||
Position: 'Network Admin',
|
||||
Picture: '',
|
||||
BirthDate: '1982/08/14',
|
||||
HireDate: '2012/04/14',
|
||||
Notes: "If you are like the rest of us at DevAV, then you've probably reached out for help from Taylor. He does a great job as a member of our IT department.",
|
||||
Address: '7776 Torreyson Dr',
|
||||
State: 'California',
|
||||
City: 'San Jose',
|
||||
}];
|
||||
|
||||
const onSelectionChanged = ({ selectedRowsData }: any) => {
|
||||
const data = selectedRowsData[0];
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
.options {
|
||||
padding: 20px;
|
||||
background-color: rgba(191, 191, 191, 0.15);
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.caption {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.option {
|
||||
width: 24%;
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.options-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
@ -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')
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<MenuItemModel[]>([])
|
||||
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
|
||||
}
|
||||
})
|
@ -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 }
|
||||
})
|
@ -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'
|
||||
export { default as Plugs } from '@/assets/icons/plugs.svg'
|
||||
export { default as Gauge } from '@/assets/icons/gauge.svg'
|
||||
|
@ -1,7 +1,8 @@
|
||||
interface MenuItemModel {
|
||||
name: string;
|
||||
href: string;
|
||||
path: string;
|
||||
icon: any;
|
||||
expanded: boolean;
|
||||
children: MenuItemModel[];
|
||||
}
|
||||
|
||||
|
0
src/utils/numbers.ts
Normal file
0
src/utils/numbers.ts
Normal file
82
src/utils/route.ts
Normal file
82
src/utils/route.ts
Normal file
@ -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;
|
||||
}
|
17
src/utils/texts.ts
Normal file
17
src/utils/texts.ts
Normal file
@ -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
|
||||
}
|
@ -1,15 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import MenuProvider from '@/components/Pages/MenuProvider.vue'
|
||||
import Navigation from '@/components/Navigation/Navigation.vue'
|
||||
import { useMenuStore } from '@/stores/menu'
|
||||
import { RouterView } from 'vue-router'
|
||||
const menu = useMenuStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Navigation />
|
||||
<div class="flex flex-col flex-1 h-[calc(100%-64px)] overflow-hidden md:pl-80 bg-primary-50">
|
||||
<div
|
||||
:class="['flex flex-col flex-1 h-[calc(100%-64px)] overflow-hidden bg-primary-50', 'transition-transform', menu.sidebarShowed ? 'transform duration-300 md:pl-80' : 'transform duration-300 md:pl-4']">
|
||||
<MenuProvider>
|
||||
<RouterView />
|
||||
</MenuProvider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MenuProvider from '@/components/Menus/MenuProvider.vue';
|
||||
import Navigation from '@/components/Navigation.vue';
|
||||
|
||||
import { RouterView } from 'vue-router'
|
||||
</script>
|
||||
</template>
|
@ -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'
|
||||
|
||||
|
Reference in New Issue
Block a user