feat(app): auth, orgs/events UI, router guards, and dev tooling
- Add Sanctum auth flow (store, composables, login, axios interceptors) - Add dashboard, organisation list/detail, events CRUD dialogs - Wire router guards, navigation, organisation switcher in layout - Replace Vuexy @db types in NavSearchBar; add @iconify/types; themeConfig title typing - Vuetify settings.scss + resolve configFile via fileURLToPath; drop dead path aliases - Root index redirects to dashboard; fix events table route name - API: DevSeeder + DatabaseSeeder updates; docs TEST_SCENARIO; corporate identity assets Made-with: Cursor
This commit is contained in:
@@ -6,6 +6,7 @@ import { themeConfig } from '@themeConfig'
|
||||
import Footer from '@/layouts/components/Footer.vue'
|
||||
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue'
|
||||
import UserProfile from '@/layouts/components/UserProfile.vue'
|
||||
import OrganisationSwitcher from '@/components/layout/OrganisationSwitcher.vue'
|
||||
import NavBarI18n from '@core/components/I18n.vue'
|
||||
|
||||
// @layouts plugin
|
||||
@@ -14,6 +15,12 @@ import { VerticalNavLayout } from '@layouts'
|
||||
|
||||
<template>
|
||||
<VerticalNavLayout :nav-items="navItems">
|
||||
<!-- 👉 Organisation switcher -->
|
||||
<template #before-vertical-nav-items>
|
||||
<OrganisationSwitcher />
|
||||
<div class="vertical-nav-items-shadow" />
|
||||
</template>
|
||||
|
||||
<!-- 👉 navbar -->
|
||||
<template #navbar="{ toggleVerticalOverlayNavActive }">
|
||||
<div class="d-flex h-100 align-center">
|
||||
|
||||
@@ -1,41 +1,7 @@
|
||||
<template>
|
||||
<div class="h-100 d-flex align-center justify-md-space-between justify-center">
|
||||
<!-- 👉 Footer: left content -->
|
||||
<span class="d-flex align-center text-medium-emphasis">
|
||||
©
|
||||
{{ new Date().getFullYear() }}
|
||||
Made With
|
||||
<VIcon
|
||||
icon="tabler-heart-filled"
|
||||
color="error"
|
||||
size="1.25rem"
|
||||
class="mx-1"
|
||||
/>
|
||||
By <a
|
||||
href="https://pixinvent.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-primary ms-1"
|
||||
>Pixinvent</a>
|
||||
</span>
|
||||
<!-- 👉 Footer: right content -->
|
||||
<span class="d-md-flex gap-x-4 text-primary d-none">
|
||||
<a
|
||||
href="https://themeforest.net/licenses/standard"
|
||||
target="noopener noreferrer"
|
||||
>License</a>
|
||||
<a
|
||||
href="https://1.envato.market/pixinvent_portfolio"
|
||||
target="noopener noreferrer"
|
||||
>More Themes</a>
|
||||
<a
|
||||
href="https://demos.pixinvent.com/vuexy-vuejs-admin-template/documentation/"
|
||||
target="noopener noreferrer"
|
||||
>Documentation</a>
|
||||
<a
|
||||
href="https://pixinvent.ticksy.com/"
|
||||
target="noopener noreferrer"
|
||||
>Support</a>
|
||||
<div class="h-100 d-flex align-center justify-center">
|
||||
<span class="text-medium-emphasis">
|
||||
© {{ new Date().getFullYear() }} Crewli
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,9 +2,21 @@
|
||||
import Shepherd from 'shepherd.js'
|
||||
import { withQuery } from 'ufo'
|
||||
import type { RouteLocationRaw } from 'vue-router'
|
||||
import type { SearchResults } from '@db/app-bar-search/types'
|
||||
import AppBarSearch from '@core/components/AppBarSearch.vue'
|
||||
import { useConfigStore } from '@core/stores/config'
|
||||
|
||||
/** App bar API search group (replaces Vuexy @db mock types). */
|
||||
interface AppBarSearchResultChild {
|
||||
title: string
|
||||
icon: string
|
||||
url: RouteLocationRaw
|
||||
}
|
||||
|
||||
interface SearchResults {
|
||||
title: string
|
||||
children: AppBarSearchResultChild[]
|
||||
}
|
||||
|
||||
interface Suggestion {
|
||||
icon: string
|
||||
title: string
|
||||
@@ -117,7 +129,6 @@ const redirectToSuggestedPage = (selected: Suggestion) => {
|
||||
closeSearchBar()
|
||||
}
|
||||
|
||||
const LazyAppBarSearch = defineAsyncComponent(() => import('@core/components/AppBarSearch.vue'))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -144,7 +155,7 @@ const LazyAppBarSearch = defineAsyncComponent(() => import('@core/components/App
|
||||
</div>
|
||||
|
||||
<!-- 👉 App Bar Search -->
|
||||
<LazyAppBarSearch
|
||||
<AppBarSearch
|
||||
v-model:is-dialog-visible="isAppSearchBarVisible"
|
||||
:search-results="searchResult"
|
||||
:is-loading="isLoading"
|
||||
@@ -238,7 +249,7 @@ const LazyAppBarSearch = defineAsyncComponent(() => import('@core/components/App
|
||||
</VListItemTitle>
|
||||
</VListItem>
|
||||
</template>
|
||||
</LazyAppBarSearch>
|
||||
</AppBarSearch>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import avatar1 from '@images/avatars/avatar-1.png'
|
||||
import { useLogout } from '@/composables/api/useAuth'
|
||||
import { useAuthStore } from '@/stores/useAuthStore'
|
||||
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const { mutate: logout, isPending: isLoggingOut } = useLogout()
|
||||
|
||||
function handleLogout() {
|
||||
logout(undefined, {
|
||||
onSettled: () => {
|
||||
router.replace('/login')
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -48,9 +62,9 @@ import avatar1 from '@images/avatars/avatar-1.png'
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="font-weight-semibold">
|
||||
John Doe
|
||||
{{ authStore.user?.name ?? 'User' }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle>Admin</VListItemSubtitle>
|
||||
<VListItemSubtitle>{{ authStore.currentOrganisation?.role ?? '' }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
|
||||
<VDivider class="my-2" />
|
||||
@@ -81,37 +95,14 @@ import avatar1 from '@images/avatars/avatar-1.png'
|
||||
<VListItemTitle>Settings</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<!-- 👉 Pricing -->
|
||||
<VListItem link>
|
||||
<template #prepend>
|
||||
<VIcon
|
||||
class="me-2"
|
||||
icon="tabler-currency-dollar"
|
||||
size="22"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<VListItemTitle>Pricing</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<!-- 👉 FAQ -->
|
||||
<VListItem link>
|
||||
<template #prepend>
|
||||
<VIcon
|
||||
class="me-2"
|
||||
icon="tabler-help"
|
||||
size="22"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<VListItemTitle>FAQ</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<!-- Divider -->
|
||||
<VDivider class="my-2" />
|
||||
|
||||
<!-- 👉 Logout -->
|
||||
<VListItem to="/login">
|
||||
<VListItem
|
||||
:disabled="isLoggingOut"
|
||||
@click="handleLogout"
|
||||
>
|
||||
<template #prepend>
|
||||
<VIcon
|
||||
class="me-2"
|
||||
|
||||
Reference in New Issue
Block a user