Comp API - common / infra (#37)
Seems to work so far; journal is bombing now that App isn't providing progress / snackbar stuff via the $ properties
This commit is contained in:
		
							parent
							
								
									7604976b98
								
							
						
					
					
						commit
						23c6bc1f1f
					
				| @ -13,6 +13,7 @@ | ||||
|     "vue": "vue-cli-service build --modern && cd ../MyPrayerJournal.Api && dotnet run" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@vue/composition-api": "^0.3.2", | ||||
|     "auth0-js": "^9.7.3", | ||||
|     "axios": "^0.19.0", | ||||
|     "core-js": "^3.3.2", | ||||
| @ -24,6 +25,7 @@ | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/auth0-js": "^9.10.6", | ||||
|     "@types/node": "^12.12.12", | ||||
|     "@typescript-eslint/eslint-plugin": "^2.8.0", | ||||
|     "@typescript-eslint/parser": "^2.8.0", | ||||
|     "@vue/cli-plugin-babel": "^4.0.5", | ||||
|  | ||||
| @ -10,13 +10,13 @@ | ||||
|             span(style='font-weight:700;') Journal | ||||
|       navigation | ||||
|     md-app-content | ||||
|       md-progress-bar(v-if='progress.visible' | ||||
|                       :md-mode='progress.mode') | ||||
|       md-progress-bar(v-if='progress.visible.value' | ||||
|                       :md-mode='progress.mode.value') | ||||
|       router-view | ||||
|       md-snackbar(:md-active.sync='snackbar.visible' | ||||
|       md-snackbar(:md-active.sync='snackbar.visible.value' | ||||
|                   md-position='center' | ||||
|                   :md-duration='snackbar.interval' | ||||
|                   ref='snackbar') {{ snackbar.message }} | ||||
|                   :md-duration='snackbar.interval.value' | ||||
|                   ref='snackbar') {{ snackbar.message.value }} | ||||
|       footer | ||||
|         p.mpj-muted-text.mpj-text-right | ||||
|           | myPrayerJournal v{{ version }} | ||||
| @ -28,82 +28,119 @@ | ||||
|             #[a(href='https://bitbadger.solutions' target='_blank') Bit Badger Solutions] | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 'use strict' | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue' | ||||
| import { computed, ref, onMounted, provide } from '@vue/composition-api' | ||||
| 
 | ||||
| import Navigation from '@/components/common/Navigation' | ||||
| import Navigation from '@/components/common/Navigation.vue' | ||||
| 
 | ||||
| import { Actions } from '@/store/types' | ||||
| import { version } from '../package.json' | ||||
| import auth from './auth' | ||||
| import router from './router' | ||||
| import store from './store' | ||||
| import { Actions } from './store/types' | ||||
| 
 | ||||
| import { provideAuth } from './plugins/auth' | ||||
| import { provideRouter } from './plugins/router' | ||||
| import { provideStore } from './plugins/store' | ||||
| // import { version } = require('../package.json') | ||||
| 
 | ||||
| function useSnackbar () { | ||||
|   const events = new Vue() | ||||
|   const visible = ref(false) | ||||
|   const message = ref('') | ||||
|   const interval = ref(4000) | ||||
| 
 | ||||
|   const showSnackbar = (msg: string) => { | ||||
|     message.value = msg | ||||
|     visible.value = true | ||||
|   } | ||||
| 
 | ||||
|   const showInfo = (msg: string) => { | ||||
|     interval.value = 4000 | ||||
|     showSnackbar(msg) | ||||
|   } | ||||
| 
 | ||||
|   const showError = (msg: string) => { | ||||
|     interval.value = Infinity | ||||
|     showSnackbar(msg) | ||||
|   } | ||||
| 
 | ||||
|   onMounted(() => { | ||||
|     events.$on('info', showInfo) | ||||
|     events.$on('error', showError) | ||||
|   }) | ||||
| 
 | ||||
|   return { | ||||
|     events, | ||||
|     visible, | ||||
|     message, | ||||
|     interval, | ||||
|     showSnackbar, | ||||
|     showInfo, | ||||
|     showError | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function useProgress () { | ||||
|   const events = new Vue() | ||||
|   const visible = ref(false) | ||||
|   const mode = ref('query') | ||||
| 
 | ||||
|   const showProgress = (mod: string) => { | ||||
|     mode.value = mod | ||||
|     visible.value = true | ||||
|   } | ||||
| 
 | ||||
|   const hideProgress = () => { visible.value = false } | ||||
| 
 | ||||
|   onMounted(() => { | ||||
|     events.$on('show', showProgress) | ||||
|     events.$on('done', hideProgress) | ||||
|   }) | ||||
| 
 | ||||
|   return { | ||||
|     events, | ||||
|     visible, | ||||
|     mode, | ||||
|     showProgress, | ||||
|     hideProgress | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export default { | ||||
|   name: 'app', | ||||
|   components: { | ||||
|     Navigation | ||||
|   }, | ||||
|   data () { | ||||
|   setup () { | ||||
|     const pkg = require('../package.json') | ||||
| 
 | ||||
|     provideAuth(auth) | ||||
|     provideRouter(router) | ||||
|     provideStore(store) | ||||
| 
 | ||||
|     const version = computed(() => | ||||
|       pkg.version.endsWith('.0') | ||||
|         ? pkg.version.endsWith('.0.0') | ||||
|           ? pkg.version.substr(0, pkg.version.length - 4) | ||||
|           : pkg.version.substr(0, pkg.version.length - 2) | ||||
|         : pkg.version) | ||||
| 
 | ||||
|     const progress = useProgress() | ||||
|     const snackbar = useSnackbar() | ||||
| 
 | ||||
|     onMounted(async () => store.dispatch(Actions.CheckAuthentication)) | ||||
| 
 | ||||
|     const SnackbarSymbol = Symbol('Snackbar events') | ||||
|     provide(SnackbarSymbol, snackbar.events) | ||||
| 
 | ||||
|     const ProgressSymbol = Symbol('Progress events') | ||||
|     provide(ProgressSymbol, progress.events) | ||||
| 
 | ||||
|     return { | ||||
|       progress: { | ||||
|         events: new Vue(), | ||||
|         visible: false, | ||||
|         mode: 'query' | ||||
|       }, | ||||
|       snackbar: { | ||||
|         events: new Vue(), | ||||
|         visible: false, | ||||
|         message: '', | ||||
|         interval: 4000 | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   async mounted () { | ||||
|     this.progress.events.$on('show', this.showProgress) | ||||
|     this.progress.events.$on('done', this.hideProgress) | ||||
|     this.snackbar.events.$on('info', this.showInfo) | ||||
|     this.snackbar.events.$on('error', this.showError) | ||||
|     await this.$store.dispatch(Actions.CheckAuthentication) | ||||
|   }, | ||||
|   computed: { | ||||
|     version () { | ||||
|       return version.endsWith('.0') | ||||
|         ? version.endsWith('.0.0') | ||||
|           ? version.substr(0, version.length - 4) | ||||
|           : version.substr(0, version.length - 2) | ||||
|         : version | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     showSnackbar (message) { | ||||
|       this.snackbar.message = message | ||||
|       this.snackbar.visible = true | ||||
|     }, | ||||
|     showInfo (message) { | ||||
|       this.snackbar.interval = 4000 | ||||
|       this.showSnackbar(message) | ||||
|     }, | ||||
|     showError (message) { | ||||
|       this.snackbar.interval = Infinity | ||||
|       this.showSnackbar(message) | ||||
|     }, | ||||
|     showProgress (mode) { | ||||
|       this.progress.mode = mode | ||||
|       this.progress.visible = true | ||||
|     }, | ||||
|     hideProgress () { | ||||
|       this.progress.visible = false | ||||
|     }, | ||||
|     handleLoginEvent (data) { | ||||
|       if (!data.loggedIn) { | ||||
|         this.showInfo('Logged out successfully') | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   provide () { | ||||
|     return { | ||||
|       messages: this.snackbar.events, | ||||
|       progress: this.progress.events | ||||
|       version, | ||||
|       progress, | ||||
|       snackbar | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -20,7 +20,7 @@ const webAuth = new auth0.WebAuth({ | ||||
| /** | ||||
|  * A class to handle all authentication calls and determinations | ||||
|  */ | ||||
| class AuthService extends EventEmitter { | ||||
| export class AuthService extends EventEmitter { | ||||
|   // Local storage key for our session data
 | ||||
|   AUTH_SESSION = 'auth-session' | ||||
| 
 | ||||
| @ -34,8 +34,9 @@ class AuthService extends EventEmitter { | ||||
| 
 | ||||
|   /** | ||||
|    * Starts the user log in flow | ||||
|    * @param customState Application state to be returned after user has authenticated | ||||
|    */ | ||||
|   login (customState: any) { | ||||
|   login (customState?: any) { | ||||
|     webAuth.authorize({ | ||||
|       appState: customState | ||||
|     }) | ||||
| @ -43,6 +44,7 @@ class AuthService extends EventEmitter { | ||||
| 
 | ||||
|   /** | ||||
|    * Promisified parseHash function | ||||
|    * @returns A promise that resolves with the parsed hash returned from Auth0 | ||||
|    */ | ||||
|   parseHash (): Promise<Auth0DecodedHash> { | ||||
|     return new Promise((resolve, reject) => { | ||||
| @ -103,6 +105,7 @@ class AuthService extends EventEmitter { | ||||
| 
 | ||||
|   /** | ||||
|    * Renew authorzation tokens with Auth0 | ||||
|    * @returns A promise with the parsed hash from the Auth0 response | ||||
|    */ | ||||
|   renewTokens (): Promise<Auth0DecodedHash> { | ||||
|     return new Promise((resolve, reject) => { | ||||
| @ -141,22 +144,32 @@ class AuthService extends EventEmitter { | ||||
|     this.emit('loginEvent', { loggedIn: false }) | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Whether the given token is currently valid | ||||
|    * @param t The token to be validated | ||||
|    * @returns True if the token is valid | ||||
|    */ | ||||
|   isTokenValid = (t: Token) => t.token !== '' && t.expiry !== 0 && Date.now() < t.expiry | ||||
| 
 | ||||
|   /** | ||||
|    * Is there a user authenticated? | ||||
|    * @returns True if a user is authenticated | ||||
|    */ | ||||
|   isAuthenticated () { | ||||
|     return this.session && this.session.id && this.session.id.isValid() | ||||
|     return this.session && this.session.id && this.isTokenValid(this.session.id) | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Is the current access token valid? | ||||
|    * @returns True if the user's access token is valid | ||||
|    */ | ||||
|   isAccessTokenValid () { | ||||
|     return this.session && this.session.access && this.session.access.isValid() | ||||
|     return this.session && this.session.access && this.isTokenValid(this.session.access) | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Get the user's access token, renewing it if required | ||||
|    * @returns A promise that resolves to the user's access token | ||||
|    */ | ||||
|   async getAccessToken (): Promise<string> { | ||||
|     if (this.isAccessTokenValid()) { | ||||
|  | ||||
| @ -6,11 +6,6 @@ export class Token { | ||||
|    * @param expiry The expiration for the token | ||||
|    */ | ||||
|   constructor (public token: string, public expiry: number) { } // eslint-disable-line no-useless-constructor
 | ||||
| 
 | ||||
|   /** Whether this token is currently valid */ | ||||
|   isValid (): boolean { | ||||
|     return this.token !== '' && this.expiry !== 0 && Date.now() < this.expiry | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** A user's current session */ | ||||
|  | ||||
| @ -12,11 +12,3 @@ md-content(role='main').mpj-main-content | ||||
|     above, and log on with either a Microsoft or Google account. You can also learn more about the site at the | ||||
|     “Docs” link, also above. | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 'use strict' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'home' | ||||
| } | ||||
| </script> | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| <script> | ||||
| 'use strict' | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import { computed, createElement, onBeforeUnmount, onMounted, ref } from '@vue/composition-api' | ||||
| import moment from 'moment' | ||||
| 
 | ||||
| export default { | ||||
| @ -19,35 +18,32 @@ export default { | ||||
|       default: 10000 | ||||
|     } | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       fromNow: moment(this.value).fromNow(), | ||||
|       intervalId: null | ||||
|   setup (props: any) { | ||||
|     /** Interval ID for updating relative time */ | ||||
|     let intervalId: number = 0 | ||||
| 
 | ||||
|     /** The relative time string */ | ||||
|     const fromNow = ref(moment(props.value).fromNow()) | ||||
| 
 | ||||
|     /** The actual date/time (used as the title for the relative time) */ | ||||
|     const actual = computed(() => moment(props.value).format('LLLL')) | ||||
| 
 | ||||
|     /** Update the relative time string if it is different */ | ||||
|     const updateFromNow = () => { | ||||
|       const newFromNow = moment(props.value).fromNow() | ||||
|       if (newFromNow !== fromNow.value) fromNow.value = newFromNow | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     actual () { | ||||
|       return moment(this.value).format('LLLL') | ||||
|     } | ||||
|   }, | ||||
|   mounted () { | ||||
|     this.intervalId = setInterval(this.updateFromNow, this.interval) | ||||
|     this.$watch('value', this.updateFromNow) | ||||
|   }, | ||||
|   beforeDestroy () { | ||||
|     clearInterval(this.intervalId) | ||||
|   }, | ||||
|   methods: { | ||||
|     updateFromNow () { | ||||
|       const newFromNow = moment(this.value).fromNow() | ||||
|       if (newFromNow !== this.fromNow) this.fromNow = newFromNow | ||||
|     } | ||||
|   }, | ||||
|   render (createElement) { | ||||
|     return createElement(this.tag, { | ||||
| 
 | ||||
|     /** Refresh the relative time string to keep it accurate */ | ||||
|     onMounted(() => { intervalId = setInterval(updateFromNow, props.interval) }) | ||||
| 
 | ||||
|     /** Cancel refreshing the time string represented with this component */ | ||||
|     onBeforeUnmount(() => clearInterval(intervalId)) | ||||
| 
 | ||||
|     return () => createElement(props.tag, { | ||||
|       domProps: { | ||||
|         title: this.actual, | ||||
|         innerText: this.fromNow | ||||
|         title: actual.value, | ||||
|         innerText: fromNow.value | ||||
|       } | ||||
|     }) | ||||
|   } | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|              to='/journal') | ||||
|       md-tab(md-label='Active' | ||||
|              to='/requests/active') | ||||
|       md-tab(v-if='hasSnoozed' | ||||
|       md-tab(v-if='hasSnoozed.value' | ||||
|              md-label='Snoozed' | ||||
|              to='/requests/snoozed') | ||||
|       md-tab(md-label='Answered' | ||||
| @ -26,33 +26,48 @@ | ||||
|              @click.prevent='showHelp()') | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 'use strict' | ||||
| <script lang="ts"> | ||||
| import { computed } from '@vue/composition-api' | ||||
| import { Store } from 'vuex' // eslint-disable-line no-unused-vars | ||||
| 
 | ||||
| import { mapState } from 'vuex' | ||||
| import { AppState } from '../../store/types' // eslint-disable-line no-unused-vars | ||||
| import { AuthService } from '../../auth' // eslint-disable-line no-unused-vars | ||||
| import { useAuth } from '../../plugins/auth' | ||||
| import { useRouter } from '../../plugins/router' | ||||
| import { useStore } from '../../plugins/store' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'navigation', | ||||
|   data () { | ||||
|     return {} | ||||
|   }, | ||||
|   computed: { | ||||
|     hasSnoozed () { | ||||
|       return this.isAuthenticated && | ||||
|         Array.isArray(this.journal) && | ||||
|         this.journal.filter(req => req.snoozedUntil > Date.now()).length > 0 | ||||
|     }, | ||||
|     ...mapState(['isAuthenticated', 'journal']) | ||||
|   }, | ||||
|   methods: { | ||||
|     logOn () { | ||||
|       this.$auth.login() | ||||
|     }, | ||||
|     logOff () { | ||||
|       this.$auth.logout(this.$store, this.$router) | ||||
|     }, | ||||
|     showHelp () { | ||||
|       window.open('https://docs.prayerjournal.me', '_blank') | ||||
|   setup () { | ||||
|     /** The Vuex store */ | ||||
|     const store = useStore() as Store<AppState> | ||||
| 
 | ||||
|     /** The auth service */ | ||||
|     const auth = useAuth() as AuthService | ||||
| 
 | ||||
|     /** Whether the user has any snoozed requests */ | ||||
|     const hasSnoozed = computed(() => | ||||
|       store.state.isAuthenticated && | ||||
|         Array.isArray(store.state.journal) && | ||||
|         store.state.journal.filter(req => req.snoozedUntil > Date.now()).length > 0) | ||||
| 
 | ||||
|     /** Log a user on using Auth0 */ | ||||
|     const logOn = () => auth.login() | ||||
| 
 | ||||
|     /** Log a user off using Auth0 */ | ||||
|     const logOff = () => { | ||||
|       auth.logout(store) | ||||
|       const router = useRouter() | ||||
|       router.push('/') | ||||
|     } | ||||
| 
 | ||||
|     /** Open a new window/tab with help */ | ||||
|     const showHelp = () => { window.open('https://docs.prayerjournal.me', '_blank') } | ||||
| 
 | ||||
|     return { | ||||
|       hasSnoozed, | ||||
|       logOn, | ||||
|       logOff, | ||||
|       showHelp | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -3,9 +3,10 @@ h1(v-if='!hideOnPage' | ||||
|    v-html='title').md-title | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| <script lang="ts"> | ||||
| import { watch } from '@vue/composition-api' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'page-title', | ||||
|   props: { | ||||
|     title: { | ||||
|       type: String, | ||||
| @ -16,13 +17,11 @@ export default { | ||||
|       default: false | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     title () { | ||||
|       document.title = `${this.title.replace('’', "'")} « myPrayerJournal` | ||||
|     } | ||||
|   }, | ||||
|   created () { | ||||
|     document.title = `${this.title.replace('’', "'")} « myPrayerJournal` | ||||
|   setup (props: any) { | ||||
|     watch(props.title, (title, prevTitle) => { | ||||
|       document.title = `${props.title.replace('’', "'")} « myPrayerJournal` | ||||
|     }) | ||||
|     return { } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| @ -4,20 +4,37 @@ article.mpj-main-content(role='main') | ||||
|   p Logging you on... | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| 'use strict' | ||||
| <script lang="ts"> | ||||
| import { onBeforeMount } from '@vue/composition-api' | ||||
| import VueRouter from 'vue-router' // eslint-disable-line no-unused-vars | ||||
| import { Store } from 'vuex' // eslint-disable-line no-unused-vars | ||||
| 
 | ||||
| import { AppState } from '../../store/types' // eslint-disable-line no-unused-vars | ||||
| import { AuthService } from '../../auth' // eslint-disable-line no-unused-vars | ||||
| import { useAuth } from '../../plugins/auth' | ||||
| import { useRouter } from '../../plugins/router' | ||||
| import { useStore } from '../../plugins/store' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'log-on', | ||||
|   inject: ['progress'], | ||||
|   async created () { | ||||
|     this.progress.$emit('show', 'indeterminate') | ||||
|     await this.$auth.handleAuthentication(this.$store) | ||||
|   }, | ||||
|   methods: { | ||||
|     handleLoginEvent (data) { | ||||
|       this.$router.push(data.state.target || '/journal') | ||||
|     } | ||||
|   setup () { | ||||
|     /** Auth service instance */ | ||||
|     const auth = useAuth() as AuthService | ||||
| 
 | ||||
|     /** Store instance */ | ||||
|     const store = useStore() as Store<AppState> | ||||
| 
 | ||||
|     /** Router instance */ | ||||
|     const router = useRouter() as VueRouter | ||||
| 
 | ||||
|     /** Navigate on auth completion */ | ||||
|     auth.on('loginEvent', (data: any) => { | ||||
|       router.push(data.state.target || '/journal') | ||||
|     }) | ||||
| 
 | ||||
|     // this.progress.$emit('show', 'indeterminate') | ||||
|     onBeforeMount(async () => { await auth.handleAuthentication(store) }) | ||||
| 
 | ||||
|     return { } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| @ -1,34 +1,33 @@ | ||||
| /* eslint-disable */ | ||||
| 
 | ||||
| // Vue packages and components
 | ||||
| import Vue from 'vue' | ||||
| import { MdApp, | ||||
|          MdButton, | ||||
|          MdCard, | ||||
|          MdContent, | ||||
|          MdDatepicker, | ||||
|          MdDialog, | ||||
|          MdEmptyState, | ||||
|          MdField, | ||||
|          MdIcon, | ||||
|          MdLayout, | ||||
|          MdProgress, | ||||
|          MdRadio, | ||||
|          MdSnackbar, | ||||
|          MdTable, | ||||
|          MdTabs, | ||||
|          MdToolbar, | ||||
|          MdTooltip } from 'vue-material/dist/components' | ||||
| import VueCompositionApi from '@vue/composition-api' | ||||
| import { | ||||
|   MdApp, | ||||
|   MdButton, | ||||
|   MdCard, | ||||
|   MdContent, | ||||
|   MdDatepicker, | ||||
|   MdDialog, | ||||
|   MdEmptyState, | ||||
|   MdField, | ||||
|   MdIcon, | ||||
|   MdLayout, | ||||
|   MdProgress, | ||||
|   MdRadio, | ||||
|   MdSnackbar, | ||||
|   MdTable, | ||||
|   MdTabs, | ||||
|   MdToolbar, | ||||
|   MdTooltip | ||||
| } from 'vue-material/dist/components' | ||||
| 
 | ||||
| // myPrayerJournal components
 | ||||
| import App         from './App.vue' | ||||
| import router      from './router' | ||||
| import store       from './store' | ||||
| import App from './App.vue' | ||||
| import router from './router' | ||||
| import store from './store' | ||||
| import DateFromNow from './components/common/DateFromNow.vue' | ||||
| import PageTitle   from './components/common/PageTitle.vue' | ||||
| import AuthPlugin  from './plugins/auth' | ||||
| 
 | ||||
| /* eslint-enable */ | ||||
| import PageTitle from './components/common/PageTitle.vue' | ||||
| import AuthPlugin from './plugins/auth' | ||||
| 
 | ||||
| // Styles
 | ||||
| import 'vue-material/dist/vue-material.min.css' | ||||
| @ -54,6 +53,7 @@ Vue.use(MdTabs) | ||||
| Vue.use(MdToolbar) | ||||
| Vue.use(MdTooltip) | ||||
| Vue.use(AuthPlugin) | ||||
| Vue.use(VueCompositionApi) | ||||
| Vue.component('date-from-now', DateFromNow) | ||||
| Vue.component('page-title', PageTitle) | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| import authService from '@/auth' | ||||
| import { inject, provide } from '@vue/composition-api' | ||||
| import authService, { AuthService } from '@/auth' | ||||
| 
 | ||||
| export default { | ||||
|   install (Vue) { | ||||
|   install (Vue: any) { | ||||
|     Vue.prototype.$auth = authService | ||||
| 
 | ||||
|     Vue.mixin({ | ||||
| @ -18,3 +19,18 @@ export default { | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const AuthSymbol = Symbol('Auth service') | ||||
| 
 | ||||
| export function provideAuth (auth: AuthService) { | ||||
|   provide(AuthSymbol, auth) | ||||
| } | ||||
| 
 | ||||
| /** Use the auth service */ | ||||
| export function useAuth (): AuthService { | ||||
|   const auth = inject(AuthSymbol) | ||||
|   if (!auth) { | ||||
|     throw new Error('Auth not configured!') | ||||
|   } | ||||
|   return auth as AuthService | ||||
| } | ||||
|  | ||||
							
								
								
									
										16
									
								
								src/app/src/plugins/router.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/app/src/plugins/router.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| import VueRouter from 'vue-router' | ||||
| import { inject, provide } from '@vue/composition-api' | ||||
| 
 | ||||
| const RouterSymbol = Symbol('Vue router') | ||||
| 
 | ||||
| export function provideRouter (router: VueRouter) { | ||||
|   provide(RouterSymbol, router) | ||||
| } | ||||
| 
 | ||||
| export function useRouter (): VueRouter { | ||||
|   const router = inject(RouterSymbol) | ||||
|   if (!router) { | ||||
|     throw new Error('Router not configured!') | ||||
|   } | ||||
|   return router as VueRouter | ||||
| } | ||||
							
								
								
									
										20
									
								
								src/app/src/plugins/store.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/app/src/plugins/store.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| import { provide, inject } from '@vue/composition-api' | ||||
| import { Store } from 'vuex' | ||||
| 
 | ||||
| import { AppState } from '@/store/types' | ||||
| 
 | ||||
| const StoreSymbol = Symbol('Vuex store') | ||||
| 
 | ||||
| /** Configure the store provided by this plugin */ | ||||
| export function provideStore (store: Store<AppState>) { | ||||
|   provide(StoreSymbol, store) | ||||
| } | ||||
| 
 | ||||
| /** Use the provided store */ | ||||
| export function useStore (): Store<AppState> { | ||||
|   const store = inject(StoreSymbol) | ||||
|   if (!store) { | ||||
|     throw new Error('No store configured!') | ||||
|   } | ||||
|   return store as Store<AppState> | ||||
| } | ||||
							
								
								
									
										1
									
								
								src/app/src/untyped-modules.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/app/src/untyped-modules.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| declare module 'vue-material/dist/components' | ||||
| @ -8,8 +8,8 @@ | ||||
|     "moduleResolution": "node", | ||||
|     "esModuleInterop": true, | ||||
|     "allowSyntheticDefaultImports": true, | ||||
|     "resolveJsonModule": true, | ||||
|     "sourceMap": true, | ||||
|     "noImplicitAny": false, | ||||
|     "baseUrl": ".", | ||||
|     "types": [ | ||||
|       "webpack-env" | ||||
|  | ||||
| @ -837,6 +837,11 @@ | ||||
|   resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.11.tgz#bec2961975888d964196bf0016a2f984d793d3ce" | ||||
|   integrity sha512-O+x6uIpa6oMNTkPuHDa9MhMMehlxLAd5QcOvKRjAFsBVpeFWTOPnXbDvILvFgFFZfQ1xh1EZi1FbXxUix+zpsQ== | ||||
| 
 | ||||
| "@types/node@^12.12.12": | ||||
|   version "12.12.12" | ||||
|   resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.12.tgz#529bc3e73dbb35dd9e90b0a1c83606a9d3264bdb" | ||||
|   integrity sha512-MGuvYJrPU0HUwqF7LqvIj50RZUX23Z+m583KBygKYUZLlZ88n6w28XRNJRJgsHukLEnLz6w6SvxZoLgbr5wLqQ== | ||||
| 
 | ||||
| "@types/normalize-package-data@^2.4.0": | ||||
|   version "2.4.0" | ||||
|   resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" | ||||
| @ -1129,6 +1134,13 @@ | ||||
|     source-map "~0.6.1" | ||||
|     vue-template-es2015-compiler "^1.9.0" | ||||
| 
 | ||||
| "@vue/composition-api@^0.3.2": | ||||
|   version "0.3.2" | ||||
|   resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-0.3.2.tgz#2d797028e489bf7812f08c7bb33ffd03ef23c617" | ||||
|   integrity sha512-fD4dn9cJX62QSP2TMFLXCOQOa+Bu2o7kWDjrU/FNLkNqPPcCKBLxCH/Lc+gNCRBKdEUGyI3arjAw7j0Yz1hnvw== | ||||
|   dependencies: | ||||
|     tslib "^1.9.3" | ||||
| 
 | ||||
| "@vue/eslint-config-standard@^5.0.0": | ||||
|   version "5.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/@vue/eslint-config-standard/-/eslint-config-standard-5.0.0.tgz#2ffabb4056205a86782cd5a641cdbcd330d905b4" | ||||
| @ -8789,7 +8801,7 @@ ts-loader@^6.2.0: | ||||
|     micromatch "^4.0.0" | ||||
|     semver "^6.0.0" | ||||
| 
 | ||||
| tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: | ||||
| tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: | ||||
|   version "1.10.0" | ||||
|   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" | ||||
|   integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user