Firestore-roles Vuex module
Vuex module for auth using firebase auth and firestore-roles system.
Companion to firestore-roles system.
Usage
1. Install
$ npm install --save firestore-roles-vuex-module
2. Define store types: Store.ts
import { RolesAuthModule } from "firestore-roles-vuex-module"; export interface Store { state: Store.State; dispatch: Dispatch; commit: Commit; getters: any;} export namespace Store { export interface Modules { // ... [RolesAuthModule.modulePathName]: Module<RolesAuthModule.State, RootStore.State>; } export type State = { // ... [RolesAuthModule.modulePathName]: RolesAuthModule.State; } & RootStore.State;}
4. Define initialization function in RootStoreImpl.ts
import { ActionContext, ActionTree } from "vuex"; import { mutations } from "./impl_mutations";import { state } from "./impl_state";import { RootStore as Me } from "./RootStore"; export namespace RootStoreImpl { function constructActions(initActionCb: (context: ActionContext<Me.State, Me.State>) => void) { const actions: ActionTree<Me.State, Me.State> = { [Me.Actions.initialize]: (context: ActionContext<Me.State, Me.State>): void => { setInterval(() => { context.commit(Me.Mutations.updateNowTimer); }, 1000); initActionCb(context); }, }; return actions; } export function constructRootStore(initActionCb: (context: ActionContext<Me.State, Me.State>) => void) { const store = { actions: constructActions(initActionCb), mutations, state, }; return store; }}
3. Create store implementation: StoreImpl.ts
export namespace StoreImpl { /** * Store */ export function constructStore(): VuexStore<RootStore.State> { /** * * Constructors */ function constructAuthModule() { return AuthModuleConstructor.constructAuthModule( { onAuthenticated: (account: Account) => { /* */ }, onNotAuthenticated: () => { /* */ }, onError: (message: string) => // referencing store here is possible because js has lexical scope NotificationsModule.Actions.ShowNotification.dispatch(store.dispatch, { message, timeoutMs: 5000, params: { color: "red" }, }), }, firebase.auth(), firebase.firestore(), ); } /** * * Initialization */ const initializer: ActionHandler<RootStore.State, RootStore.State> = ({ dispatch }) => { NotificationsModule.Actions.Initialize.dispatch(dispatch); RolesAuthModule.Actions.Initialize.dispatch(dispatch); }; /** * * Module loading */ const modules: Store.Modules & ModuleTree<RootStore.State> = { [RolesAuthModule.modulePathName]: constructAuthModule(), [NotificationsModule.modulePathName]: NotificationsModuleImpl.module, // ... }; /** * * Store */ const store = new Vuex.Store<RootStore.State>({ strict: window.location.hostname === "localhost" ? true : false, ...RootStoreImpl.constructRootStore(initializer), modules, }); return store; }}
4. Import vuex store in main: main.ts
and call initialize action
// In order for the notifications to disappear you have to dispatch initialize actionexport default () => new Vue({ // ... store: StoreImpl.constructStore(), created() { initFirebase(); RolesAuthModule.Actions.Initialize.dispatch(this.$store.dispatch); }, });
5. Somewhere in your app: Access auth state
import { Account, RolesAuthModule } from "firestore-roles-vuex-module"; export default Vue.extend({ computed: { authenticated(): boolean { return RolesAuthModule.stateOf(this).state === AuthModule.AuthState.AUTHENTICATED; }, account(): Account | undefined { return RolesAuthModule.stateOf(this).account; }, photoUrl(): string { return this.account ? this.account.photoURL || "" : ""; }, name(): string { return this.account ? this.account.displayName || "" : ""; }, isAdmin(): boolean { // will be undefined until you call RolesAuthModule.Actions.CheckRole.dispatch(this.$store.dispatch, "admin"); return RolesAuthModule.stateOf(this).roles.admin === true; }, }, methods: { signOut() { RolesAuthModule.Actions.Logout.dispatch(this.$store.dispatch); }, checkRole() { RolesAuthModule.Actions.CheckRole.dispatch(this.$store.dispatch, "admin"); }, },});
6. Sample utilizing component: NotificationsSnackbar.vue
using vuetify v-snackbar
<template> <div> <v-snackbar v-model="opened" :color="this.color">{{ message }}</v-snackbar> </div></template> <script lang="ts"> import Vue from "vue"; import { RolesAuthModule } from "firestore-roles-vuex-module"; export default Vue.extend({ computed: { opened(): boolean { return RolesAuthModule.stateOf(this).notifications.length > 0; }, message(): string { const message = this.opened ? RolesAuthModule.stateOf(this).notifications[0].message : ""; return message; }, params(): any { return this.opened ? RolesAuthModule.stateOf(this).notifications[0].params : {}; }, color(): string | undefined { return this.params.color || undefined; }, }, });</script>