Skip to content

Commit

Permalink
feat(seaside): #195 add create account component
Browse files Browse the repository at this point in the history
  • Loading branch information
Marthym committed Jan 13, 2024
1 parent db2b5d2 commit c767c7d
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 75 deletions.
5 changes: 5 additions & 0 deletions seaside/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
</main>
</div>
</div>
<create-account-component v-if="store.state.user.isCreateAccountOpen"/>
</template>

<script lang="ts">
Expand All @@ -28,9 +29,13 @@ import { Store, useStore } from 'vuex';
import { UPDATE_MUTATION as STATS_UPDATE_MUTATION } from '@/techwatch/store/statistics/StatisticsConstants';
import { HAS_ROLE_USER_GETTER } from '@/store/user/UserConstants';
import { UserState } from '@/store/user/user';
import { defineAsyncComponent } from 'vue';
const CreateAccountComponent = defineAsyncComponent(() => import('@/security/components/CreateAccountComponent.vue'));
@Component({
components: {
CreateAccountComponent,
NotificationArea,
TopNavigationBar,
SideNav,
Expand Down
134 changes: 73 additions & 61 deletions seaside/src/layout/components/sidenav/SideNavManagement.vue
Original file line number Diff line number Diff line change
@@ -1,74 +1,86 @@
<template>
<span class="mt-auto"></span>
<ul class="menu -mx-4">
<li v-if="user.isAuthenticated && store.getters['user/hasRoleAdmin']">
<router-link to="/admin" active-class="active" @click="sideNavToggle">
<AcademicCapIcon class="fill-current w-6 h-6 mr-2"/>
Administration
</router-link>
</li>
<li v-if="user.isAuthenticated && store.getters['user/hasRoleUser']">
<router-link to="/teams" active-class="active" @click="sideNavToggle">
<UserGroupIcon class="fill-current w-6 h-6 mr-2"/>
Teams
</router-link>
</li>
<li v-if="user.isAuthenticated && store.getters['user/hasRoleUser']">
<router-link to="/config" active-class="active" @click="sideNavToggle">
<AdjustmentsVerticalIcon class="fill-current w-6 h-6 mr-2"/>
Configuration
</router-link>
</li>
<li class="text-primary">
<a v-if="user.isAuthenticated" @click.stop="$emit('logout')">
<ArrowRightOnRectangleIcon class="fill-current h-6 w-6"/>
<span class="ml-2 capitalize font-medium">log out</span>
</a>
<router-link to="/login" v-else>
<ArrowLeftOnRectangleIcon class="fill-current h-6 w-6"/>
<span class="ml-2 capitalize font-medium">log in</span>
</router-link>
</li>
</ul>
<span class="mt-auto"></span>
<ul class="menu -mx-4">
<li v-if="user.isAuthenticated && store.getters['user/hasRoleAdmin']">
<router-link to="/admin" active-class="active" @click="sideNavToggle">
<AcademicCapIcon class="fill-current w-6 h-6 mr-2"/>
Administration
</router-link>
</li>
<li v-if="user.isAuthenticated && store.getters['user/hasRoleUser']">
<router-link to="/teams" active-class="active" @click="sideNavToggle">
<UserGroupIcon class="fill-current w-6 h-6 mr-2"/>
Teams
</router-link>
</li>
<li v-if="user.isAuthenticated && store.getters['user/hasRoleUser']">
<router-link to="/config" active-class="active" @click="sideNavToggle">
<AdjustmentsVerticalIcon class="fill-current w-6 h-6 mr-2"/>
Configuration
</router-link>
</li>
<li>
<a v-if="!user.isAuthenticated" @click.prevent.stop="onCreateAccountClick">
<InboxArrowDownIcon class="fill-current h-6 w-6"/>
<span class="ml-2 capitalize font-medium">Create Account</span>
</a>
</li>
<li class="text-primary">
<a v-if="user.isAuthenticated" @click.stop="$emit('logout')">
<ArrowRightStartOnRectangleIcon class="fill-current h-6 w-6"/>
<span class="ml-2 capitalize font-medium">log out</span>
</a>
<router-link to="/login" v-else>
<ArrowRightEndOnRectangleIcon class="fill-current h-6 w-6"/>
<span class="ml-2 capitalize font-medium">log in</span>
</router-link>
</li>
</ul>
</template>

<script lang="ts">
import {Component, Vue} from 'vue-facing-decorator';
import {useStore} from 'vuex';
import {UserState} from '@/store/user/user';
import { Component, Vue } from 'vue-facing-decorator';
import { useStore } from 'vuex';
import { UserState } from '@/store/user/user';
import {
AcademicCapIcon,
AdjustmentsVerticalIcon,
ArrowLeftOnRectangleIcon,
ArrowRightOnRectangleIcon,
UserGroupIcon
AcademicCapIcon,
AdjustmentsVerticalIcon,
ArrowRightEndOnRectangleIcon,
ArrowRightStartOnRectangleIcon,
InboxArrowDownIcon,
UserGroupIcon,
} from '@heroicons/vue/20/solid';
import {SidenavMutation} from "@/store/sidenav/SidenavMutation.enum";
import { SidenavMutation } from '@/store/sidenav/SidenavMutation.enum';
@Component({
name: 'SideNavManagement',
emits: ['logout'],
components: {
AcademicCapIcon,
AdjustmentsVerticalIcon,
ArrowLeftOnRectangleIcon,
ArrowRightOnRectangleIcon,
UserGroupIcon,
},
setup() {
const store = useStore();
return {
store: store,
user: store.state.user
}
}
name: 'SideNavManagement',
emits: ['logout'],
components: {
AcademicCapIcon,
AdjustmentsVerticalIcon,
InboxArrowDownIcon,
ArrowRightStartOnRectangleIcon,
ArrowRightEndOnRectangleIcon,
UserGroupIcon,
},
setup() {
const store = useStore();
return {
store: store,
user: store.state.user,
};
},
})
export default class SideNavManagement extends Vue {
private store;
private user: UserState;
private store;
private user: UserState;
public sideNavToggle(): void {
this.store.commit(SidenavMutation.TOGGLE);
}
public sideNavToggle(): void {
this.store.commit(SidenavMutation.TOGGLE);
}
public onCreateAccountClick(): void {
this.store.commit(SidenavMutation.OPEN_CREATE_ACCOUNT_MUTATION);
}
}
</script>
59 changes: 59 additions & 0 deletions seaside/src/security/components/CreateAccountComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<template>
<curtain-modal @leave="close()" v-slot="curtainModal">
<h2 class="font-sans text-xl border-b border-accent/40 pb-2 w-full">Create new account</h2>
<div class="m-4">
<label class="label">
<span class="label-text">Team Name</span>
</label>
<input type="text" class="input input-bordered w-full">
<label class="label -mt-1">
<span class="label-text-alt">&nbsp;</span>
<span v-if="errors.has('name')" class="label-text-alt">{{ errors.get('name') }}</span>
</label>
<label class="label">
<span class="label-text">Team Topic</span>
</label>
<input type="text" class="input input-bordered w-full"
:class="{'input-error': errors.has('topic')}">
<label class="label -mt-1">
<span class="label-text-alt">&nbsp;</span>
<span v-if="errors.has('topic')" class="label-text-alt">{{ errors.get('topic') }}</span>
</label>
<div class="text-right">
<button class="btn btn-sm mx-1" @click.stop="curtainModal.close()">Cancel</button>
<button class="btn btn-sm btn-primary mx-1">
Save
</button>
</div>
</div>
</curtain-modal>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-facing-decorator';
import CurtainModal from '@/common/components/CurtainModal.vue';
import { User } from '@/security/model/User';
import { Store, useStore } from 'vuex';
import { UserState } from '@/store/user/user';
import { CLOSE_CREATE_ACCOUNT_MUTATION } from '@/store/user/UserConstants';
const CLOSE_EVENT: string = 'close';
@Component({
emits: [CLOSE_EVENT],
components: { CurtainModal },
setup() {
return {
userStore: useStore(),
};
},
})
export default class CreateAccountComponent extends Vue {
private readonly userStore: Store<UserState>;
private account: User;
private errors: Map<string, string> = new Map<string, string>();
private close(): void {
this.userStore.commit(CLOSE_CREATE_ACCOUNT_MUTATION);
}
}
</script>
1 change: 1 addition & 0 deletions seaside/src/store/sidenav/SidenavMutation.enum.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export enum SidenavMutation {
TOGGLE = 'sidenav/toggleSidenav',
OPEN_CREATE_ACCOUNT_MUTATION = 'user/openCreateAccount',
}
4 changes: 4 additions & 0 deletions seaside/src/store/user/UserConstants.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
export const NAMESPACE = 'user';
export const LOGOUT = 'logout';
export const UPDATE = 'update';
export const OPEN_CREATE_ACCOUNT = 'openCreateAccount';
export const CLOSE_CREATE_ACCOUNT = 'closeCreateAccount';
export const ADD_ROLE = 'addRole';
export const HAS_ROLE_USER = 'hasRoleUser';
export const HAS_ROLE_MANAGER = 'hasRoleManager';
export const HAS_ROLE_ADMIN = 'hasRoleAdmin';
export const LOGOUT_MUTATION = `${NAMESPACE}/${LOGOUT}`;
export const UPDATE_MUTATION = `${NAMESPACE}/${UPDATE}`;
export const OPEN_CREATE_ACCOUNT_MUTATION = `${NAMESPACE}/${OPEN_CREATE_ACCOUNT}`;
export const CLOSE_CREATE_ACCOUNT_MUTATION = `${NAMESPACE}/${CLOSE_CREATE_ACCOUNT}`;
export const USER_ADD_ROLE_MUTATION = `${NAMESPACE}/${ADD_ROLE}`;
export const HAS_ROLE_USER_GETTER = `${NAMESPACE}/${HAS_ROLE_USER}`;
export const HAS_ROLE_MANAGER_GETTER = `${NAMESPACE}/${HAS_ROLE_MANAGER}`;
Expand Down
45 changes: 31 additions & 14 deletions seaside/src/store/user/user.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import {ANONYMOUS, User} from "@/security/model/User";
import {UserRole} from "@/security/model/UserRole.enum";
import {ADD_ROLE, HAS_ROLE_ADMIN, HAS_ROLE_MANAGER, HAS_ROLE_USER, LOGOUT, UPDATE} from "@/store/user/UserConstants";
import {GetterTree} from "vuex";
import { ANONYMOUS, User } from '@/security/model/User';
import { UserRole } from '@/security/model/UserRole.enum';
import {
ADD_ROLE,
CLOSE_CREATE_ACCOUNT,
HAS_ROLE_ADMIN,
HAS_ROLE_MANAGER,
HAS_ROLE_USER,
LOGOUT,
OPEN_CREATE_ACCOUNT,
UPDATE,
} from '@/store/user/UserConstants';
import { GetterTree } from 'vuex';

export type UserState = {
user: User;
isAuthenticated: boolean | undefined;
isCreateAccountOpen: boolean;
}

const state = (): UserState => ({
user: ANONYMOUS,
isAuthenticated: undefined,
isCreateAccountOpen: false,
});

// getters
Expand All @@ -24,32 +35,38 @@ const getters: GetterTree<UserState, UserState> = {
[HAS_ROLE_ADMIN](st: UserState): boolean {
return hasRole(st.user, UserRole.ADMIN);
},
}
};

// actions
const actions = {}
const actions = {};

// mutations
const mutations = {
[ADD_ROLE](st: UserState, payload: string): void {
st.user.roles.push(payload);
},
[CLOSE_CREATE_ACCOUNT](st: UserState): void {
st.isCreateAccountOpen = false;
},
[LOGOUT](st: UserState): void {
st.user = ANONYMOUS;
st.isAuthenticated = false;
},
[OPEN_CREATE_ACCOUNT](st: UserState): void {
st.isCreateAccountOpen = true;
},
[UPDATE](st: UserState, payload: User): void {
st.user = payload;
st.isAuthenticated = hasRole(st.user, UserRole.USER);
},
[ADD_ROLE](st: UserState, payload: string): void {
st.user.roles.push(payload);
},
}
};

const hasRole = (user: User, expectedRole: UserRole, entity?: string): boolean => {
if (!expectedRole) {
throw new Error();
}
if (!user && user === null) {
return false
return false;
}
let hasRole = false;
let userRoles: string[] = (entity)
Expand All @@ -66,12 +83,12 @@ const hasRole = (user: User, expectedRole: UserRole, entity?: string): boolean =
}
}
return false;
}
};

export default {
namespaced: true,
state,
getters,
actions,
mutations
}
mutations,
};

0 comments on commit c767c7d

Please sign in to comment.