Browse Source

Added side nav and admin routes

staging
David Ludwig 4 years ago
parent
commit
7b9ac08a0d
8 changed files with 153 additions and 12 deletions
  1. +8
    -4
      services/request/src/app/App.vue
  2. +71
    -0
      services/request/src/app/components/SideNav.vue
  3. +33
    -5
      services/request/src/app/routes/index.ts
  4. +18
    -2
      services/request/src/app/store/getters.ts
  5. +1
    -1
      services/request/src/app/store/mutations.ts
  6. +16
    -0
      services/request/src/app/views/Dashboard.vue
  7. +3
    -0
      services/request/src/app/views/admin/Admin.vue
  8. +3
    -0
      services/request/src/app/views/admin/AdminDashboard.vue

+ 8
- 4
services/request/src/app/App.vue View File

@ -1,19 +1,23 @@
<template>
<div class="min-h-full p-4 flex flex-col">
<router-view/>
<div class="min-h-full flex">
<side-nav class="flex-shrink-0"/>
<div class="min-h-full p-4 flex flex-col flex-grow">
<router-view/>
</div>
</div>
<!-- <app-modal/> -->
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { Action, useStore } from "./store";
import AppModal from "./components/AppModals.vue";
import SideNav from "./components/SideNav.vue";
export default defineComponent({
name: "App",
components: {
AppModal
AppModal,
SideNav
},
setup() {
const store = useStore();


+ 71
- 0
services/request/src/app/components/SideNav.vue View File

@ -0,0 +1,71 @@
<template>
<nav v-if="$store.getters.isAuthenticated" class="w-72 flex flex-col bg-white shadow-lg">
<div class="brand">AUTOPLEX</div>
<div class="mt-4 text-center">
<div class="user"><i class="fas opacity-40" :class="{'fa-user': !isAdmin, 'fa-user-tie': isAdmin}"></i></div>
<div class="font-black text-lg opacity-80">{{ userName }}</div>
<div class="text-xs opacity-60">{{ isAdmin ? "Admin" : "Plex Member" }}</div>
</div>
<ul class="mt-4 text-gray-800 links">
<li v-if="isAdmin">
<router-link :to="{ name: 'Admin' }">
<span><i class="fas fa-cog"></i></span>
<div>Admin</div>
</router-link>
</li>
<li>
<router-link :to="{ name: 'Dashboard' }">
<span><i class="fas fa-chart-pie"></i></span>
<div>Dashboard</div>
</router-link>
</li>
<li>
<router-link :to="{ name: 'Search' }">
<span><i class="fas fa-search"></i></span>
<div>Search</div>
</router-link>
</li>
</ul>
<div class="mt-auto p-4">
<router-link class="block p-2 text-center rounded-full shadow-md text-white bg-indigo-500"
:to="{ name: 'Logout' }">
Logout
</router-link>
</div>
</nav>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { mapGetters } from "vuex";
export default defineComponent({
computed: {
...mapGetters([
"userName",
"isAdmin"
])
}
});
</script>
<style lang="postcss">
nav > .brand {
@apply mt-4 h-12 flex justify-center items-center text-4xl font-thin;
}
nav .user {
@apply w-20 h-20 mx-auto rounded-full flex justify-center items-end bg-gray-200 text-6xl overflow-hidden shadow-sm;
}
nav .user > i {
line-height: 3.7rem;
}
nav > .links a {
@apply py-3 px-8 flex space-x-4 hover:bg-gray-100;
}
nav > .links .router-link-active {
@apply bg-indigo-500 text-white shadow-md hover:bg-indigo-500 cursor-default;
}
nav > .links span {
@apply w-5
}
</style>

+ 33
- 5
services/request/src/app/routes/index.ts View File

@ -25,6 +25,17 @@ function requiresAuth(to: RouteLocationNormalized, from: RouteLocationNormalized
next();
}
/**
* Check if the user is an authenticated admin, redirect otherwise
*/
function requiresAdmin(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) {
if (store.getters.isAuthenticated && !store.getters.isAdmin) {
next({ name: "Home" });
return;
}
next();
}
/**
* Fetch request providing authentication and logout upon unauthorized requests
*/
@ -55,11 +66,13 @@ const routes: RouteRecordRaw[] = [
{
path: "/",
name: "Home",
component: {
beforeRouteEnter(to, from, next) {
next({ name: "Search" });
}
}
redirect: to => ({ name: "Dashboard" })
},
{
path: "/dashboard",
name: "Dashboard",
component: () => import("../views/Dashboard.vue"),
beforeEnter: requiresAuth
},
{
path: "/search",
@ -75,6 +88,21 @@ const routes: RouteRecordRaw[] = [
}
]
},
{
path: "/admin",
name: "Admin",
redirect: to => ({ name: "AdminDashboard" }),
component: () => import("../views/admin/Admin.vue"),
beforeEnter: requiresAdmin,
children: [
{
path: "dashboard",
name: "AdminDashboard",
component: () => import("../views/admin/AdminDashboard.vue"),
props: true
}
]
},
{
path: "/login",
name: "Login",


+ 18
- 2
services/request/src/app/store/getters.ts View File

@ -2,9 +2,11 @@ import { GetterTree } from "vuex";
import { IState } from "./state";
export type GettersTypes = {
isAdmin (state: IState): boolean,
isAuthenticated(state: IState): boolean,
storedToken(): string | null,
token(state: IState): string | null
storedToken () : string | null,
token (state: IState): string | null,
userName (state: IState): string | null
}
export const getters: GettersTypes & GetterTree<IState, IState> = {
@ -15,6 +17,13 @@ export const getters: GettersTypes & GetterTree<IState, IState> = {
return state.user != null;
},
/**
* Determine if the user is an admin
*/
isAdmin(state: IState) {
return state.user?.isAdmin ?? false;
},
/**
* Retrieve the stored token
*/
@ -27,5 +36,12 @@ export const getters: GettersTypes & GetterTree<IState, IState> = {
*/
token(state: IState) {
return state.user?.token ?? null;
},
/**
* Get the user's name (assumes authenticated)
*/
userName(state: IState) {
return state.user?.name.split(" ")[0] ?? null;
}
};

+ 1
- 1
services/request/src/app/store/mutations.ts View File

@ -65,7 +65,7 @@ export const mutations: MutationsTypes & MutationTree<IState> = {
state.user = {
id : user.id,
name : user.name,
isAdmin: false,
isAdmin: user.isAdmin,
token : token
}
} catch(e) {


+ 16
- 0
services/request/src/app/views/Dashboard.vue View File

@ -0,0 +1,16 @@
<template>
<div class="w-full sm:max-w-sm sm:mx-auto sm:my-auto p-6 space-y-4 bg-white rounded-lg shadow-md">
<movie-poster src=""/>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import MoviePoster from "../components/MoviePoster.vue";
export default defineComponent({
components: {
MoviePoster
}
});
</script>

+ 3
- 0
services/request/src/app/views/admin/Admin.vue View File

@ -0,0 +1,3 @@
<template>
<router-view/>
</template>

+ 3
- 0
services/request/src/app/views/admin/AdminDashboard.vue View File

@ -0,0 +1,3 @@
<template>
<div>Admin dashboard</div>
</template>

Loading…
Cancel
Save