authorized fix keycloak sidebarItem

This commit is contained in:
2025-07-08 14:07:05 +07:00
parent 78b75999ea
commit 25f4b8cac7
16 changed files with 1183 additions and 969 deletions

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
import type { RevenueProjects,Performance } from '@/types/components/dashboard/dashboard1'; import type { RevenueProjects,Performance } from '@/types/components/dashboards/dashboard1';
import product1 from "@/assets/images/products/dash-prd-1.jpg"; import product1 from "@/assets/images/products/dash-prd-1.jpg";
import product2 from "@/assets/images/products/dash-prd-2.jpg"; import product2 from "@/assets/images/products/dash-prd-2.jpg";
@@ -1,50 +1,55 @@
export interface minisidebar { export interface minisidebar {
icon?: string; icon?: string;
id?:number; id?:number;
tooltip?:string tooltip?:string,
typeUser?:string[],
} }
const MiniSideIcons: minisidebar[] = [ const MiniSideIcons: minisidebar[] = [
{ {
icon: 'layers-line-duotone', icon: 'layers-line-duotone',
tooltip:'Dashboards', tooltip:'Dashboards',
id: 1 id: 1,
}, typeUser:['super_admin','admin']
{ },
icon: 'notes-line-duotone', {
tooltip:'Pages', icon: 'notes-line-duotone',
id: 2, tooltip:'Pages',
}, id: 2,
{ typeUser:['super_admin']
icon: 'palette-round-line-duotone', },
tooltip:'Forms', {
id: 3 icon: 'palette-round-line-duotone',
}, tooltip:'Forms',
{ id: 3
icon:'align-vertical-spacing-broken', },
tooltip:'Tables', {
id: 4 icon:'align-vertical-spacing-broken',
}, tooltip:'Tables',
{ id: 4,
icon:'chart-line-duotone', typeUser:['super_admin']
tooltip:'Charts', },
id: 5 {
}, icon:'chart-line-duotone',
{ tooltip:'Charts',
icon:'widget-6-line-duotone', id: 5
tooltip:'UI Components', },
id: 6 {
}, icon:'widget-6-line-duotone',
{ tooltip:'UI Components',
icon:'lock-keyhole-line-duotone', id: 6
tooltip:'Authentication Pages', },
id: 7 {
}, icon:'lock-keyhole-line-duotone',
{ tooltip:'Authentication Pages',
icon:'mirror-left-line-duotone', id: 7
tooltip:'Others', },
id: 8 {
} icon:'mirror-left-line-duotone',
tooltip:'Others',
id: 8
}
] ]
export default MiniSideIcons; export default MiniSideIcons;
@@ -10,125 +10,155 @@ import MiniSideIcons from './MinIconItems';
const route = useRoute(); const route = useRoute();
const findTitleByPath = (items: any, path: any) => { // const findTitleByPath = (items: any, path: any) => {
let title = ''; // let title = '';
//
for (const item of items) { // for (const item of items) {
if (item.to === path) { // if (item.to === path) {
title = item.id; // title = item.id;
break; // break;
} else if (item.children) { // } else if (item.children) {
for (const child of item.children) { // for (const child of item.children) {
if (child.to === path) { // if (child.to === path) {
title = item.id; // title = item.id;
break; // break;
} else if (child.children) { // } else if (child.children) {
for (const grandChild of child.children) { // for (const grandChild of child.children) {
if (grandChild.to === path) { // if (grandChild.to === path) {
title = item.id; // title = item.id;
break; // break;
} // }
} // }
} // }
} // }
} // }
// }
//
// return title;
// };
const findTitleByPath = (items:any, path:any) => {
for (const item of items) {
if (item.to === path) {
return item.id;
} }
if (item.children) {
return title; const title = findTitleByPath(item.children, path);
if (title) {
return item.id;
}
}
}
return '';
}; };
const foundId = findTitleByPath(sidebarItems, route.path); const foundId = findTitleByPath(sidebarItems, route.path);
const getCurrent = foundId ? foundId : 1; const getCurrent = foundId ? foundId : 1;
const currentMenu = ref<any>(getCurrent); const currentMenu = ref<any>(getCurrent);
function showData(data: any) { function showData(data: any) {
currentMenu.value = data; currentMenu.value = data;
//customizer.SET_MINI_SIDEBAR(!customizer.mini_sidebar) //customizer.SET_MINI_SIDEBAR(!customizer.mini_sidebar)
} }
// MiniSidebar Icons End // MiniSidebar Icons End
const customizer = useCustomizerStore(); const customizer = useCustomizerStore();
const sidebarMenu = shallowRef(sidebarItems); const sidebarMenu = shallowRef(sidebarItems);
const miniSidebar = MiniSideIcons.filter(menuIcon=>menuIcon.typeUser?.includes('super_admin'));
const filterSidebarItems=(items:any, userType:string) => {
// const result = items.filter((item:any)=>item?.typeUser.includes(userType));
const result = items.filter((item:any)=>item.typeUser?.includes(userType))
.map((item:any)=>({
...item,
children: item.children ? filterSidebarItems(item.children,userType):''
}))
.filter((item:any)=>item.children.length > 0||item.typeUser.includes(userType));
return result;
}
const filteredSidebarItems = filterSidebarItems(sidebarItems, 'super_admin');
// console.log(filteredSidebarItems)
</script> </script>
<template> <template>
<!-- Minisidebar Icons --> <!-- Minisidebar Icons -->
<v-navigation-drawer class="bg-light" v-model="customizer.Sidebar_drawer" top="0" rail rail-width="80"> <v-navigation-drawer class="bg-light" v-model="customizer.Sidebar_drawer" top="0" rail rail-width="80">
<perfect-scrollbar class="miniscrollnavbar"> <perfect-scrollbar class="miniscrollnavbar">
<v-list-item class="px-0"> <v-list-item class="px-0">
<!-- Toggle Sidebar Button --> <!-- Toggle Sidebar Button -->
<div class="px-4 mb-3"> <div class="px-4 mb-3">
<v-btn <v-btn
class="hidden-md-and-down my-2" class="hidden-md-and-down my-2"
icon icon
rounded="md" rounded="md"
variant="plain" variant="plain"
@click.stop="customizer.SET_MINI_SIDEBAR(!customizer.mini_sidebar)" @click.stop="customizer.SET_MINI_SIDEBAR(!customizer.mini_sidebar)"
> >
<Icon icon="solar:hamburger-menu-line-duotone" height="25" /> <Icon icon="solar:hamburger-menu-line-duotone" height="25" />
</v-btn> </v-btn>
</div>
<div class="miniicons mt-lg-0 mt-4">
<!-- MiniSidebar Icons -->
<div class="d-flex flex-column gap-2">
<div class="miniicons-list px-4" v-for="menu in MiniSideIcons" :key="menu.icon">
<v-btn
rounded="md"
flat
icon
variant="plain"
@click="showData(menu.id)"
:class="{ 'bg-primary opacity-1': currentMenu === menu.id }"
>
<Icon :icon="'solar:' + menu.icon" width="25" />
<!-- Tooltip on Hover -->
<v-tooltip activator="parent" location="end" class="custom-tooltip">{{ menu.tooltip }}</v-tooltip>
</v-btn>
</div>
</div>
</div>
</v-list-item>
</perfect-scrollbar>
</v-navigation-drawer>
<!-- LeftSidebar Items -->
<v-navigation-drawer
v-model="customizer.Sidebar_drawer"
elevation="0"
rail-width="1"
app
top="0"
class="leftSidebar"
:rail="customizer.mini_sidebar"
width="240"
>
<!---Logo part -->
<div class="pa-4 pb-0">
<Logo />
</div> </div>
<!-- ---------------------------------------------- --> <div class="miniicons mt-lg-0 mt-4">
<!---Navigation --> <!-- MiniSidebar Icons -->
<!-- ---------------------------------------------- --> <div class="d-flex flex-column gap-2">
<perfect-scrollbar class="scrollnavbar"> <div class="miniicons-list px-4" v-for="menu in miniSidebar" :key="menu.icon">
<div class="px-4 py-0 sidebar-menus"> <v-btn
<v-list class="py-1"> rounded="md"
<template v-for="(item, i) in sidebarMenu"> flat
<template v-if="currentMenu == item.id"> icon
<!---Item Sub Header --> variant="plain"
<LazyLayoutFullVerticalSidebarNavGroup :item="item" v-if="item.header" :key="item.title" /> @click="showData(menu.id)"
<!---If Has Child --> :class="{ 'bg-primary opacity-1': currentMenu === menu.id }"
<template v-for="sItem in item.children"> >
<LazyLayoutFullVerticalSidebarNavCollapse class="leftPadding" :item="sItem" :level="0" v-if="sItem.children" /> <Icon :icon="'solar:' + menu.icon" width="25" />
<LazyLayoutFullVerticalSidebarNavItem :item="sItem" class="leftPadding" v-else /> <!-- Tooltip on Hover -->
</template> <v-tooltip activator="parent" location="end" class="custom-tooltip">{{ menu.tooltip }}</v-tooltip>
</template> </v-btn>
</template>
</v-list>
</div> </div>
</perfect-scrollbar> </div>
</v-navigation-drawer> </div>
</v-list-item>
</perfect-scrollbar>
</v-navigation-drawer>
<!-- LeftSidebar Items -->
<v-navigation-drawer
v-model="customizer.Sidebar_drawer"
elevation="0"
rail-width="1"
app
top="0"
class="leftSidebar"
:rail="customizer.mini_sidebar"
width="240"
>
<!---Logo part -->
<div class="pa-4 pb-0">
<Logo />
</div>
<!-- ---------------------------------------------- -->
<!---Navigation -->
<!-- ---------------------------------------------- -->
<perfect-scrollbar class="scrollnavbar">
<div class="px-4 py-0 sidebar-menus">
<v-list class="py-1">
<template v-for="(item, i) in filteredSidebarItems">
<template v-if="currentMenu == item.id">
<!---Item Sub Header -->
<LazyLayoutFullVerticalSidebarNavGroup :item="item" v-if="item.header" :key="item.title" />
<!---If Has Child -->
<template v-for="sItem in item.children">
<LazyLayoutFullVerticalSidebarNavCollapse class="leftPadding" :item="sItem" :level="0" v-if="sItem.children" />
<LazyLayoutFullVerticalSidebarNavItem :item="sItem" class="leftPadding" v-else />
</template>
</template>
</template>
</v-list>
</div>
</perfect-scrollbar>
</v-navigation-drawer>
</template> </template>
File diff suppressed because it is too large Load diff
@@ -1,4 +0,0 @@
export const useUseGetUserLoginComposables = (data: any) => {
console.log('data useUseGetUserLoginComposables', data)
return data;
}
+53 -11
View File
@@ -1,12 +1,54 @@
const userInfoStores = useUserInfoStore() import {getTimetoMilis, timestampToDate} from "~/utils/helper";
const { getUserInfoStore } = storeToRefs(useUserInfoStore()) import {signOut} from "next-auth/react";
const { data } = useAuth()
export default defineNuxtRouteMiddleware((to, from) => { export default defineNuxtRouteMiddleware(async (to, from) => {
console.log(data.value) if (process.server) return;
if (data.value === null || !data.value) { try {
navigateTo('/sample-page') const sess = await useSessionLogin('getSess');
} else { console.log('session data:', sess);
navigateTo('/sambelPage_copy') // console.log('route auth requirement:', timestampToDate(sess?.expires_in?.timestamps, 'id-ID'));
console.log('berhasil login') // const timeMilis= sess?.expires_in?.timestamps*1000
// console.log(timeMilis)
// console.log('route auth requirement:', new Date(timeMilis));
// console.log('milis:', timestampToDate(sess?.expires_in?.timestamps,'id-ID'));
// console.log('milis:', timestampToDate(getTimetoMilis(),'id-ID'));
// Jika session tidak ada atau sudah expired
if(!sess || getTimetoMilis()>= sess?.user_payload?.expires?.expires_at){
if(to.path!=='/auth/login'){
await signOut()
return navigateTo({
path: "/auth/login",
query: {
...to.query,
reason: "auth_required",
continue: "true"
}
});
}
return;
} }
})
// Optional: Pengecekan tipe user jika diperlukan
// if (to.meta.auth && to.meta.auth !== sess?.user_payload?.typeUser) {
const metaRoles=to.meta?.roles;
console.log(metaRoles);
if (!to.meta || !metaRoles.includes(sess?.user_payload?.typeUser)) {
return navigateTo('/auth/401');
}
} catch (err) {
console.error('Session check failed:', err);
if (to.path !== '/auth/login') {
return navigateTo({
path: '/auth/login',
query: {
returnUrl: to.fullPath,
reason: 'session check failed'
}
});
}
}
});
+75
View File
@@ -9,6 +9,11 @@
"version": "2.0.0", "version": "2.0.0",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@fullcalendar/core": "6.1.10",
"@fullcalendar/daygrid": "6.1.10",
"@fullcalendar/interaction": "6.1.10",
"@fullcalendar/timegrid": "6.1.10",
"@fullcalendar/vue3": "6.1.10",
"@iconify/vue": "^4.1.1", "@iconify/vue": "^4.1.1",
"@mdi/font": "7.4.47", "@mdi/font": "7.4.47",
"@pinia/nuxt": "^0.11.1", "@pinia/nuxt": "^0.11.1",
@@ -16,6 +21,7 @@
"apexcharts": "4.5.0", "apexcharts": "4.5.0",
"axios": "^1.9.0", "axios": "^1.9.0",
"axios-mock-adapter": "^2.1.0", "axios-mock-adapter": "^2.1.0",
"date-fns": "^4.1.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"sass": "1.70.0", "sass": "1.70.0",
"sass-loader": "^16.0.5", "sass-loader": "^16.0.5",
@@ -975,6 +981,65 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@fullcalendar/core": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.10.tgz",
"integrity": "sha512-oTXGJSAGpCf1oY+CKp5qYjMHkJCPBkJ3SHitl63n8Q6xKeiwQ4EF6Au451euUovREwJpLmD1AyZrCnWmtB9AVg==",
"license": "MIT",
"dependencies": {
"preact": "~10.12.1"
}
},
"node_modules/@fullcalendar/core/node_modules/preact": {
"version": "10.12.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/@fullcalendar/daygrid": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.10.tgz",
"integrity": "sha512-Z4GRm1IyHKgxXFTWGcEI0nTsvYOIkpE0aMt3/o3ER2SZkF+hfwcDFhtj0c9+WhMjXFIWYeoTnA9rUOY7Zl/nxA==",
"license": "MIT",
"peerDependencies": {
"@fullcalendar/core": "~6.1.10"
}
},
"node_modules/@fullcalendar/interaction": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.10.tgz",
"integrity": "sha512-aZRlwCpmDasq2RNeWV0ub20Uevare9Cb6iMlxCacx0fhOC14H28G9d1FsduJIecInL84SPGwt5ItqAYMsWv7zw==",
"license": "MIT",
"peerDependencies": {
"@fullcalendar/core": "~6.1.10"
}
},
"node_modules/@fullcalendar/timegrid": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.10.tgz",
"integrity": "sha512-hFKyQXJaPbNyq1reZmvkCmM64O99krHoIcJAbDS+dntCm3FzZUcDtAcRKIbMiantHrezCG/1MEYk3m9e3aKvIQ==",
"license": "MIT",
"dependencies": {
"@fullcalendar/daygrid": "~6.1.10"
},
"peerDependencies": {
"@fullcalendar/core": "~6.1.10"
}
},
"node_modules/@fullcalendar/vue3": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/vue3/-/vue3-6.1.10.tgz",
"integrity": "sha512-YMYBQx0TlWNuN4G6ra2dkf5cCF5aVi/2zDLGLvLqe2Nk2o7uNbTkrCSG40061OepWQlJv+hYqm1JukLRmyqi4Q==",
"license": "MIT",
"peerDependencies": {
"@fullcalendar/core": "~6.1.10",
"vue": "^3.0.11"
}
},
"node_modules/@iconify/types": { "node_modules/@iconify/types": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
@@ -5089,6 +5154,16 @@
"node": ">= 12" "node": ">= 12"
} }
}, },
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/db0": { "node_modules/db0": {
"version": "0.3.2", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/db0/-/db0-0.3.2.tgz", "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.2.tgz",
+8 -2
View File
@@ -11,6 +11,11 @@
"postinstall": "nuxt prepare" "postinstall": "nuxt prepare"
}, },
"dependencies": { "dependencies": {
"@fullcalendar/core": "6.1.10",
"@fullcalendar/daygrid": "6.1.10",
"@fullcalendar/interaction": "6.1.10",
"@fullcalendar/timegrid": "6.1.10",
"@fullcalendar/vue3": "6.1.10",
"@iconify/vue": "^4.1.1", "@iconify/vue": "^4.1.1",
"@mdi/font": "7.4.47", "@mdi/font": "7.4.47",
"@pinia/nuxt": "^0.11.1", "@pinia/nuxt": "^0.11.1",
@@ -18,6 +23,7 @@
"apexcharts": "4.5.0", "apexcharts": "4.5.0",
"axios": "^1.9.0", "axios": "^1.9.0",
"axios-mock-adapter": "^2.1.0", "axios-mock-adapter": "^2.1.0",
"date-fns": "^4.1.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"sass": "1.70.0", "sass": "1.70.0",
"sass-loader": "^16.0.5", "sass-loader": "^16.0.5",
@@ -32,11 +38,11 @@
"vuetify": "3.7.18" "vuetify": "3.7.18"
}, },
"devDependencies": { "devDependencies": {
"nuxt": "^3.17.5",
"@sidebase/nuxt-auth": "^0.10.1", "@sidebase/nuxt-auth": "^0.10.1",
"nuxt": "^3.17.5",
"pinia": "^3.0.3" "pinia": "^3.0.3"
}, },
"overrides": { "overrides": {
"nth-check": "2.1.1" "nth-check": "2.1.1"
} }
} }
+3 -9
View File
@@ -3,12 +3,10 @@ definePageMeta({
middleware: ['auth'] middleware: ['auth']
}) })
import { ref } from "vue"; import { ref } from "vue";
import UiParentCard from "@/components/shared/UiParentCard.vue"; import { useAuth } from "#imports";
import { useAuth, useUserInfoStore } from "#imports";
import { useUseGetUserLoginComposables } from "~/composables/useGetUserLoginComposables"
const { setUserInfoStore } = useUserInfoStore(); // const { setUserInfoStore } = useUserInfoStore();
const { getUserInfoStore } = storeToRefs(useUserInfoStore()); // const { getUserInfoStore } = storeToRefs(useUserInfoStore());
const { data, status, getCsrfToken, getProviders, signOut, getSession } = useAuth() const { data, status, getCsrfToken, getProviders, signOut, getSession } = useAuth()
const tokens = ref('') const tokens = ref('')
onMounted(async () => { onMounted(async () => {
@@ -16,12 +14,8 @@ onMounted(async () => {
const headers = useRequestHeaders(['cookie']) as HeadersInit const headers = useRequestHeaders(['cookie']) as HeadersInit
const { data: token } = await useFetch('/api/token', { headers }) const { data: token } = await useFetch('/api/token', { headers })
tokens.value = token.value tokens.value = token.value
// userAuthenticate(token.value)
setUserInfoStore(token.value)
}) })
const getUserFromComposable = () => { const getUserFromComposable = () => {
const a = useUseGetUserLoginComposables(getUserInfoStore.value)
console.log('ini a', a)
} }
</script> </script>
<template> <template>
+22 -12
View File
@@ -1,27 +1,37 @@
<script setup lang="ts"> <script setup lang="ts">
definePageMeta({ definePageMeta({
middleware: ['auth'] middleware: ['auth'],
roles:['super_admin','admin'],
}) })
import { ref } from "vue"; import { ref } from "vue";
import UiParentCard from "@/components/shared/UiParentCard.vue"; import {useAuth} from "#imports";
import { useAuth, useUserInfoStore } from "#imports";
import { useUseGetUserLoginComposables } from "~/composables/useGetUserLoginComposables"
const { setUserInfoStore } = useUserInfoStore(); // const { setUserInfoStore,setSessionUserStore } = useUserInfoStore();
const { getUserInfoStore } = storeToRefs(useUserInfoStore()); // const { getUserInfoStore } = storeToRefs(useUserInfoStore());
const { data, status, getCsrfToken, getProviders, signOut, getSession } = useAuth() const { data, status, getCsrfToken, getProviders, signOut, getSession } = useAuth()
const tokens = ref('') const tokens = ref('')
const getInfoUser = ref('')
onMounted(async () => { onMounted(async () => {
// $fetch(`/api/auth/protected`).then(res => console.log('ini responnya',res))
const headers = useRequestHeaders(['cookie']) as HeadersInit const headers = useRequestHeaders(['cookie']) as HeadersInit
const { data: token } = await useFetch('/api/token', { headers }) const { data: token } = await useFetch('/api/token', { headers })
tokens.value = token.value tokens.value = token.value
getInfoUser.value = await getSession()
// userAuthenticate(token.value) // userAuthenticate(token.value)
setUserInfoStore(token.value) // setUserInfoStore(await getSession())
// $fetch('/api/session').then(async (response) => {
// // console.log('sesseion',response)
// // useSessionLogin(response)
// setSessionUserStore(response)
// })
}) })
const getUserFromComposable = () => { const getUserFromComposable = async () => {
const a = useUseGetUserLoginComposables(getUserInfoStore.value) // const a = useUseGetUserLoginComposables(getUserInfoStore.value)
console.log('ini a', a) // const a= await useSessionLogin('getSess')
// $fetch('/api/session').then(async (response) => {
// console.log(await getSession())
// console.log('ini b', a?.expires)
// console.log('sesseion',response)
// })
} }
</script> </script>
<template> <template>
@@ -29,7 +39,7 @@ const getUserFromComposable = () => {
<v-col cols="12" md="12"> <v-col cols="12" md="12">
<v-card elevation="10"> <v-card elevation="10">
<v-card-item> <v-card-item>
<pre><span>Providers:</span> {{ getUserInfoStore }}</pre> <pre><span>Providers:</span> {{ getInfoUser }}</pre>
<h5 class="text-h5 mb-3">Sample Page</h5> <h5 class="text-h5 mb-3">Sample Page</h5>
<p class="text-body-1">This is a sample page</p> <p class="text-body-1">This is a sample page</p>
<div class="mt-4"> <div class="mt-4">
+6 -6
View File
@@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
/*Call Components*/ /*Call Components*/
import RevenueCard from '@/components/dashboard/RevenueCard.vue'; import RevenueCard from '@/components/dashboards/RevenueCard.vue';
import NewCustomer from '@/components/dashboard/NewCustomer.vue'; import NewCustomer from '@/components/dashboards/NewCustomer.vue';
import Totalincome from '@/components/dashboard/TotalIncome.vue'; import Totalincome from '@/components/dashboards/TotalIncome.vue';
import RevenueProduct from '@/components/dashboard/RevenueProducts.vue'; import RevenueProduct from '@/components/dashboards/RevenueProducts.vue';
import DailyActivities from '@/components/dashboard/DailyActivities.vue'; import DailyActivities from '@/components/dashboards/DailyActivities.vue';
import BlogCards from '@/components/dashboard/BlogCards.vue'; import BlogCards from '@/components/dashboards/BlogCards.vue';
</script> </script>
<template> <template>
+106 -68
View File
@@ -1,80 +1,118 @@
// import CredentialsProvider from 'next-auth/providers/credentials' // import CredentialsProvider from 'next-auth/providers/credentials'
import KeycloakProvider from 'next-auth/providers/keycloak' import KeycloakProvider from 'next-auth/providers/keycloak'
import { NuxtAuthHandler, } from '#auth' import { NuxtAuthHandler, } from '#auth'
import {timestampToDate} from "~/utils/helper"
// import {session} from "next-auth/core/routes";
export default NuxtAuthHandler({ export default NuxtAuthHandler({
// TODO: SET A STRONG SECRET, SEE https://sidebase.io/nuxt-auth/configuration/nuxt-auth-handler#secret // TODO: SET A STRONG SECRET, SEE https://sidebase.io/nuxt-auth/configuration/nuxt-auth-handler#secret
secret: 'my-auth-secret', secret: 'my-auth-secret',
// TODO: ADD YOUR OWN AUTHENTICATION PROVIDER HERE, READ THE DOCS FOR MORE: https://sidebase.io/nuxt-auth // TODO: ADD YOUR OWN AUTHENTICATION PROVIDER HERE, READ THE DOCS FOR MORE: https://sidebase.io/nuxt-auth
providers: [ providers: [
// @ts-expect-error You need to use .default here for it to work during SSR. May be fixed via Vite at some point // @ts-expect-error You need to use .default here for it to work during SSR. May be fixed via Vite at some point
KeycloakProvider.default({ KeycloakProvider.default({
clientId: process.env.KEYCLOAK_ID, clientId: process.env.KEYCLOAK_ID,
clientSecret: process.env.KEYCLOAK_SECRET, clientSecret: process.env.KEYCLOAK_SECRET,
issuer: process.env.KEYCLOAK_ISSUER, issuer: process.env.KEYCLOAK_ISSUER,
}), }),
// // @ts-expect-error You need to use .default here for it to work during SSR. May be fixed via Vite at some point // // @ts-expect-error You need to use .default here for it to work during SSR. May be fixed via Vite at some point
// CredentialsProvider.default({ // CredentialsProvider.default({
// // The name to display on the sign in form (e.g. 'Sign in with...') // // The name to display on the sign in form (e.g. 'Sign in with...')
// name: 'Credentials', // name: 'Credentials',
// // The credentials is used to generate a suitable form on the sign in page. // // The credentials is used to generate a suitable form on the sign in page.
// // You can specify whatever fields you are expecting to be submitted. // // You can specify whatever fields you are expecting to be submitted.
// // e.g. domain, username, password, 2FA token, etc. // // e.g. domain, username, password, 2FA token, etc.
// // You can pass any HTML attribute to the <input> tag through the object. // // You can pass any HTML attribute to the <input> tag through the object.
// credentials: { // credentials: {
// username: { label: 'Username', type: 'text', placeholder: '(hint: jsmith)' }, // username: { label: 'Username', type: 'text', placeholder: '(hint: jsmith)' },
// password: { label: 'Password', type: 'password', placeholder: '(hint: hunter2)' } // password: { label: 'Password', type: 'password', placeholder: '(hint: hunter2)' }
// }, // },
// authorize (credentials: any) { // authorize (credentials: any) {
// console.warn('ATTENTION: You should replace this with your real providers or credential provider logic! The current setup is not safe') // console.warn('ATTENTION: You should replace this with your real providers or credential provider logic! The current setup is not safe')
// // You need to provide your own logic here that takes the credentials // // You need to provide your own logic here that takes the credentials
// // submitted and returns either a object representing a user or value // // submitted and returns either a object representing a user or value
// // that is false/null if the credentials are invalid. // // that is false/null if the credentials are invalid.
// // NOTE: THE BELOW LOGIC IS NOT SAFE OR PROPER FOR AUTHENTICATION! // // NOTE: THE BELOW LOGIC IS NOT SAFE OR PROPER FOR AUTHENTICATION!
// const user = { id: '1', name: 'J Smith', username: 'jsmith', password: 'hunter2' } // const user = { id: '1', name: 'J Smith', username: 'jsmith', password: 'hunter2' }
// if (credentials?.username === user.username && credentials?.password === user.password) { // if (credentials?.username === user.username && credentials?.password === user.password) {
// // Any object returned will be saved in `user` property of the JWT // // Any object returned will be saved in `user` property of the JWT
// return user // return user
// } else { // } else {
// console.error('Warning: Malicious login attempt registered, bad credentials provided') // console.error('Warning: Malicious login attempt registered, bad credentials provided')
// // If you return null then an error will be displayed advising the user to check their details. // // If you return null then an error will be displayed advising the user to check their details.
// return null // return null
// // You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter // // You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter
// } // }
// } // }
// }) // })
], ],
callbacks: { callbacks: {
async jwt({ token, account, user }: { token: any; user: any, account: any }) { async jwt({ token, account, user }: { token: any; user: any, account: any }) {
try { try {
if (account && account.access_token) { if (account && account.access_token) {
token.access_token_payload = JSON.parse(atob(account.access_token.split('.')[1])); token.access_token_payload = JSON.parse(atob(account.access_token.split('.')[1]));
token.jwt = account.access_token; token.jwt = account.access_token;
} }
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
if (account) { if (account) {
token.id_token = account.id_token; token.id_token = account.id_token;
token.refresh_token = account.refresh_token; token.refresh_token = account.refresh_token;
token.expires_at = account.expires_at; token.expires_at = account.expires_at;
token.scope = account.scope; token.scope = account.scope;
} }
if (user) { token.user = user } if (user) { token.user = user }
console.log(token); return token
return token
},
},
pages: {
signIn: '/auth/Login',
// signOut: '/auth/logout',
// error: '/auth/error',
// verifyRequest: '/auth/verify-request',
// newUser: '/auth/new-user'
}, },
async session({ token,session }:{token:any, session:any}) {
const user_payload=JSON.parse(atob(token.jwt.split('.')[1]));
try {
if (token && token.id_token) {
// session.session_user_payload = user_payload;
session.jwt = token.jwt;
}
} catch (err) {
console.error(err);
}
if (token) {
// session.id_token = token.id_token;
session.refresh_token = token.refresh_token;
// session.expires_at = token.expires_at;
// session.scope = token.scope;
session.isAuthenticated = true;
session.user_payload = {
userName:user_payload.preferred_username,
typeUser:user_payload.type_user||user_payload.resource_access[user_payload.azp].roles[0],
roleUser:user_payload.resource_access[user_payload.azp],
userInfo:{
id:user_payload.id,
full_name:user_payload.name,
givenName:user_payload.given_name,
familyName:user_payload.family_name,
email:user_payload.email,
group:user_payload.group,
},
expires:{
expires_at:token.expires_at,
timestamps:new Date(token.expires_at),
date:timestampToDate(token.expires_at,'id-ID'),
}
};
}
return session
}
},
pages: {
signIn: '/auth/Login',
// signOut: '/auth/logout',
// error: '/auth/error',
// verifyRequest: '/auth/verify-request',
// newUser: '/auth/new-user'
},
}) })
-38
View File
@@ -1,38 +0,0 @@
import { defineStore } from "pinia";
import { timestampToDate } from "~/utils/helper";
export const useUserInfoStore = defineStore("userInfoStore", () => {
const getUserInfoStore = ref<any>([])
const setUserInfoStore = (data: any) => {
const userInfo: any[] =
{
user_name: data?.access_token_payload?.preferred_username,
type_user: data?.access_token_payload?.type_user,
role_access: data?.access_token_payload?.resource_access[data?.access_token_payload.azp],
userInfo: [
{
id: data?.user?.id,
fullname: data?.access_token_payload?.name,
given_name: data?.access_token_payload?.given_name || '-',
family_name: data?.access_token_payload?.family_name || '-',
email: data?.access_token_payload?.email || '- ',
group: data?.access_token_payload?.group,
}
],
expires_in: [
{
timestamps: data?.expires_at,
date: timestampToDate(data?.expires_at, 'id-ID'),
}
],
};
// console.log(data)
getUserInfoStore.value = userInfo;
}
const getMenuAkses = ref<any>([])
// const
return { setUserInfoStore, getUserInfoStore }
})
+40
View File
@@ -0,0 +1,40 @@
import { defineStore } from "pinia";
import { timestampToDate } from "~/utils/helper";
export const useUserInfoStore = defineStore("userInfoStore", () => {
const getUserInfoStore = ref<any>([])
const setUserInfoStore = (data: any) => {
// const userInfo: any[] =
// {
// user_name: data?.access_token_payload?.preferred_username,
// type_user: data?.access_token_payload?.type_user,
// role_access: data?.access_token_payload?.resource_access[data?.access_token_payload.azp],
// userInfo: [
// {
// id: data?.user?.id,
// fullname: data?.access_token_payload?.name,
// given_name: data?.access_token_payload?.given_name || '-',
// family_name: data?.access_token_payload?.family_name || '-',
// email: data?.access_token_payload?.email || '- ',
// group: data?.access_token_payload?.group,
// }
// ],
// expires_in: [
// {
// timestamps: data?.expires_at,
// date: timestampToDate(data?.expires_at, 'id-ID'),
// }
// ],
// };
// console.log(data)
getUserInfoStore.value = data;
}
const getSessionUserStore = ref<any>([])
const setSessionUserStore = (data: any) => {
getSessionUserStore.value=data
}
return { setUserInfoStore,setSessionUserStore, getUserInfoStore,getSessionUserStore }
})
+1 -1
View File
@@ -1,7 +1,7 @@
import { computed } from 'vue'; import { computed } from 'vue';
import * as themeColors from '@/theme/LightTheme'; import * as themeColors from '@/theme/LightTheme';
import * as DarkThemeColors from '@/theme/DarkTheme'; import * as DarkThemeColors from '@/theme/DarkTheme';
import { useCustomizerStore } from '@/stores/customizer'; import { useCustomizerStore } from '@/store/customizer';
const custmizer = useCustomizerStore(); const custmizer = useCustomizerStore();
+4
View File
@@ -23,4 +23,8 @@ export function timestampToDate(timestamp: number, locale: string, options = {})
timeZoneName: 'short', timeZoneName: 'short',
...options ...options
}); });
}
export function getTimetoMilis() {
return Math.floor(Date.now() / 1000)
} }