chore: refactor a lot, add codegen and upgrade vue

This commit is contained in:
2022-08-03 18:40:05 +02:00
parent 0e1ce42af2
commit e24b65c85b
42 changed files with 3854 additions and 1073 deletions
+2
View File
@@ -0,0 +1,2 @@
graphql/generated
node_modules
+17 -28
View File
@@ -1,35 +1,24 @@
module.exports = {
root: true,
env: {
browser: true,
es6: true
node: true
},
parser: 'vue-eslint-parser',
plugins: [
'@typescript-eslint'
],
parserOptions: {
"parser": "@typescript-eslint/parser",
requireConfigFile: false
},
extends: [
'airbnb-base',
'plugin:vue/recommended',
'eslint:recommended',
'prettier',
'plugin:prettier/recommended'
'@nuxtjs',
'@nuxtjs/eslint-config-typescript',
'plugin:nuxt/recommended',
'prettier'
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module'
},
plugins: ['vue'],
rules: {
'import/extensions': 0,
'import/no-unresolved': 0,
'no-param-reassign': 0,
'prettier/prettier': [
'error',
{
trailingComma: 'none',
singleQuote: true,
semi: false
}
]
}
ignorePatterns: ["graphql/generated/*"],
// add your custom rules here
rules: {}
}
+1
View File
@@ -1,3 +1,4 @@
node_modules
.nuxt
dist
.eslintcache
+106
View File
@@ -0,0 +1,106 @@
###
# Place your Prettier ignore content here
###
# .gitignore content is duplicated here due to https://github.com/prettier/prettier/issues/8506
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# IDE / Editor
.idea
# Service worker
sw.*
# macOS
.DS_Store
# Vim swap files
*.swp
.eslintrc.js
.gitlab-ci.yml
.gitlab/dependabot.yml
.prettierignore
codegen.yml
graphql/generated/*
k8s/*
nuxt.config.js
tsconfig.json
-2
View File
@@ -1,6 +1,4 @@
{
"trailingComma": "none",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
+20 -4
View File
@@ -1,6 +1,22 @@
schema: ./schema.graphql
overwrite: true
schema: ./graphql/schema.graphql
documents: './graphql/**/*.graphql'
generates:
./fragmentTypes.json:
./graphql/generated/operations.ts:
plugins:
- fragment-matcher
- typescript
- typescript-operations
- typescript-vue-apollo
- fragment-matcher
config:
fetcher: fetch
avoidOptionals:
field: true
inputValue: true
object: false
defaultValue: true
maybeValue: T | null | undefined
strictScalars: true
scalars:
LocalDate: string
LocalDateTime: string
vueCompositionApiImportFrom: vue
+70 -45
View File
@@ -1,13 +1,13 @@
<template>
<v-card xs12>
<v-card-title primary-title>
<h3 class="headline mb-0">
<h3 class='headline mb-0'>
<v-icon
class="ml-1 mr-1"
v-if="hasUser"
v-on:click="toggleIgnore('band', event.band.name)"
v-if='hasUser'
class='ml-1 mr-1'
medium
title="Dölj"
@click="toggleIgnore('band', event.band.name)"
>mdi-eye-off</v-icon
>{{ event.band.name }}
</h3>
@@ -15,71 +15,89 @@
<v-container>
<v-layout row wrap>
<v-flex xs12 sm6
><strong class="mr-1" v-text="$t('events.date')" />{{
><strong class='mr-1' v-text="$t('events.date')" />{{
event.date
}}
({{ weekday }} {{ daysUntil }})</v-flex
({{ weekday }} {{ daysUntil }})
</v-flex
>
<v-flex xs12 sm6 v-if="event.time"
><strong class="mr-1" v-text="$t('events.time')" />{{
<v-flex v-if='event.time' xs12 sm6
><strong class='mr-1' v-text="$t('events.time')" />{{
event.time
}}</v-flex
}}
</v-flex
>
</v-layout>
<v-layout row wrap>
<v-flex xs12 sm6 md3
><strong class="mr-1" v-text="$t('events.hall')" /><v-icon
class="ml-1 mr-1"
v-if="hasUser"
v-on:click="toggleIgnore('danceHall', event.danceHall.name)"
><strong class='mr-1' v-text="$t('events.hall')" />
<v-icon
v-if='hasUser'
class='ml-1 mr-1'
small
:title="$t('events.hide')"
>mdi-eye-off</v-icon
>{{ event.danceHall.name }}</v-flex
@click="toggleIgnore('danceHall', event.danceHall.name)"
>mdi-eye-off
</v-icon
>
{{ event.danceHall.name }}
</v-flex
>
<v-flex xs12 sm6 md3
><strong class="mr-1" v-text="$t('events.city')" /><v-icon
class="ml-1 mr-1"
v-if="hasUser"
v-on:click="toggleIgnore('city', event.danceHall.city)"
><strong class='mr-1' v-text="$t('events.city')" />
<v-icon
v-if='hasUser'
class='ml-1 mr-1'
small
:title="$t('events.hide')"
>mdi-eye-off</v-icon
>{{ event.danceHall.city }}</v-flex
@click="toggleIgnore('city', event.danceHall.city)"
>mdi-eye-off
</v-icon
>
{{ event.danceHall.city }}
</v-flex
>
<v-flex xs12 sm6 md3
><strong class="mr-1" v-text="$t('events.municipality')" /><v-icon
class="ml-1 mr-1"
v-if="hasUser"
v-on:click="
><strong class='mr-1' v-text="$t('events.municipality')" />
<v-icon
v-if='hasUser'
class='ml-1 mr-1'
small
:title="$t('events.hide')"
@click="
toggleIgnore('municipality', event.danceHall.municipality)
"
small
:title="$t('events.hide')"
>mdi-eye-off</v-icon
>{{ event.danceHall.municipality }}</v-flex
>mdi-eye-off
</v-icon
>
{{ event.danceHall.municipality }}
</v-flex
>
<v-flex xs12 sm6 md3
><strong class="mr-1" v-text="$t('events.state')" /><v-icon
class="ml-1 mr-1"
v-if="hasUser"
v-on:click="toggleIgnore('state', event.danceHall.state)"
><strong class='mr-1' v-text="$t('events.state')" />
<v-icon
v-if='hasUser'
class='ml-1 mr-1'
small
:title="$t('events.hide')"
>mdi-eye-off</v-icon
>{{ event.danceHall.state }}</v-flex
@click="toggleIgnore('state', event.danceHall.state)"
>mdi-eye-off
</v-icon
>
{{ event.danceHall.state }}
</v-flex
>
</v-layout>
<v-layout
v-for='distance in event.distances'
:key='distance.origin'
row
wrap
v-for="distance in event.distances"
:key="distance.origin"
>
<v-flex xs12 sm6>
<v-icon>mdi-home</v-icon>
<span
><strong>{{ distance.origin }}</strong></span
><strong>{{ distance.origin }}</strong></span
>
</v-flex>
<v-flex xs12 sm6>
@@ -93,14 +111,19 @@
</v-card>
</template>
<script>
import dayjs from 'dayjs'
<script lang='ts'>
// eslint-disable-next-line import/no-duplicates
import { format, formatDistanceToNow, parseISO } from 'date-fns'
// eslint-disable-next-line import/no-duplicates
import { enGB, sv } from 'date-fns/locale'
import { computed, defineComponent, getCurrentInstance, PropType } from 'vue'
import { Event } from '~/graphql/generated/operations'
export default {
export default defineComponent({
name: 'EventDetail',
props: {
event: {
type: Object,
type: Object as PropType<Event>,
required: true
},
hasUser: {
@@ -113,13 +136,15 @@ export default {
}
},
setup(props) {
const instance = getCurrentInstance()
const locale = computed(() => (instance?.proxy.$i18n.locale ?? 'sv') === 'en' ? enGB : sv )
const time = (props.event.time || '').split('-')[0].replace('.', ':')
const weekday = dayjs(props.event.date).format('dddd')
const daysUntil = dayjs(`${props.event.date} ${time}`).fromNow()
const weekday = format(parseISO(props.event.date), 'EEEE', { locale: locale.value })
const daysUntil = formatDistanceToNow(parseISO(`${props.event.date}T${time}`), { addSuffix: true, locale: locale.value })
return {
weekday,
daysUntil
}
}
}
})
</script>
+3 -3
View File
@@ -1,14 +1,14 @@
<template>
<div>
<v-layout row wrap v-for="event in events" :key="event.id">
<v-row v-for="event in events" :key="event.id" wrap>
<v-flex xs12>
<Event
:event="event"
:has-user="hasUser"
:toggleIgnore="toggleIgnore"
:toggle-ignore="toggleIgnore"
/>
</v-flex>
</v-layout>
</v-row>
</div>
</template>
+96 -98
View File
@@ -1,42 +1,46 @@
<template>
<div :key='isAuthenticated'>
<v-container :key='range' fluid grid-list-md class='app-fade-in'>
<v-layout v-if='!isAuthenticated' row wrap>
<v-flex xs12>
<v-row v-if='!isAuthenticated' wrap>
<v-col xs='12'>
<p><b v-text="$t('events.login')" /></p>
</v-flex>
</v-layout>
<v-layout row wrap>
<v-flex xs12>
</v-col>
</v-row>
<v-row wrap>
<v-col xs='12'>
<v-text-field
v-model='origin'
:label="$t('origins.origin')"
:placeholder="$t('origins.geolocation')"
>
<v-tooltip slot='append-outer' top>
<template #activator='{ on }'>
<v-icon v-on='on' @click='fetchAddress()'
>mdi-crosshairs-gps
</v-icon>
</template>
<span v-text="$t('origins.fetchAddress')" />
</v-tooltip>
<v-tooltip v-if='isAuthenticated' slot='prepend' top>
<template #activator='{ on }'>
<v-icon
:disabled='!origin'
v-on='on'
@click='saveOrigin(origin)'
>mdi-bookmark-plus-outline
</v-icon>
</template>
<span v-text="$t('origins.save')" />
</v-tooltip>
<template #append-outer>
<v-tooltip top>
<template #activator='{ on }'>
<v-icon v-on='on' @click='fetchAddress()'
>mdi-crosshairs-gps
</v-icon>
</template>
<span v-text="$t('origins.fetchAddress')" />
</v-tooltip>
</template>
<template #prepend>
<v-tooltip v-if='isAuthenticated' top>
<template #activator='{ on }'>
<v-icon
:disabled='!origin'
v-on='on'
@click='saveOrigin(origin)'
>mdi-bookmark-plus-outline
</v-icon>
</template>
<span v-text="$t('origins.save')" />
</v-tooltip>
</template>
</v-text-field>
</v-flex>
</v-layout>
<v-layout row wrap>
<v-flex>
</v-col>
</v-row>
<v-row wrap>
<v-col>
<v-btn-toggle
v-if='$vuetify.breakpoint.smAndUp'
v-model='range'
@@ -47,17 +51,17 @@
/></v-btn>
</v-btn-toggle>
<v-select
v-if='$vuetify.breakpoint.xsOnly'
v-else
v-model='range'
outline
:items='ranges'
item-text='name'
item-value='value'
/>
</v-flex>
</v-layout>
</v-col>
</v-row>
<list
:events='events || []'
:events='events'
:has-user='isAuthenticated'
:toggle-ignore='toggleIgnore'
/>
@@ -72,58 +76,61 @@
</div>
</template>
<script>
import { useMutations, useRouter } from '@u3u/vue-hooks'
import { computed, ref, watch } from '@vue/composition-api'
import { useMutation, useQuery, useResult } from '@vue/apollo-composable'
<script lang='ts'>
import { computed, defineComponent, ref, watch } from 'vue'
import { useRoute, useRouter, useStore } from '@nuxtjs/composition-api'
import List from './List/index.vue'
import { useAuth } from '~/plugins/auth'
import List from './List'
import {
fetchAddress,
findEvents,
saveOrigin,
toggleIgnoreBand,
toggleIgnoreCity,
toggleIgnoreDanceHall,
toggleIgnoreMunicipality,
toggleIgnoreState
} from '~/utils/graph-client'
import { useTranslation } from '~/plugins/i18n'
import {
FindEventsQueryVariables,
Range,
useFetchAddressLazyQuery,
useFindEventsLazyQuery,
useSaveOriginMutation,
useToggleIgnoreBandMutation,
useToggleIgnoreCityMutation,
useToggleIgnoreDanceHallMutation,
useToggleIgnoreMunicipalityMutation,
useToggleIgnoreStateMutation
} from '~/graphql/generated/operations'
export default {
export default defineComponent({
name: 'EventsPage',
components: {
List
},
setup() {
const { setTitle } = useMutations(['setTitle'])
const store = useStore()
const { t } = useTranslation()
setTitle(t('app.links.events'))
store.commit('setTitle', t('app.links.events'))
const { loading: authLoading, isAuthenticated } = useAuth()
const { route, router } = useRouter()
const route = useRoute()
const router = useRouter()
const range = computed({
get: () => route.value.query.range || 'ONE_WEEK',
set: (value) => router.push(`/?range=${value}`)
get: () => route.value.query.range ? route.value.query.range as Range : undefined,
set: (value) => {
router.push(`/?range=${value}`)
}
})
const enabled = ref(false)
const { result: data, refetch } = useQuery(
findEvents,
{ includeOrigins: false },
() => ({ enabled: enabled.value })
)
const events = useResult(data, [], (result) => result.events)
const origins = useResult(data, [], (result) => result.origins)
const variables = ref<FindEventsQueryVariables>({ includeOrigins: false})
const { result, refetch, load } = useFindEventsLazyQuery(variables)
const events = computed(() => result.value?.events ?? [])
const origins = computed(() => result.value?.origins ?? [])
watch(
range,
() => route.value.query.range,
(r) => {
enabled.value = true
refetch({
range: r,
includeOrigins: isAuthenticated.value || false
})
if (!authLoading.value) {
variables.value = {
range: r ? r as Range : Range.OneWeek,
includeOrigins: isAuthenticated.value || false
}
load()
refetch(variables.value)
}
},
{ lazy: false }
{ immediate: true }
)
const submitting = ref(true)
const ranges = [
@@ -141,25 +148,22 @@ export default {
if (origin.value) {
originsTemp.push(origin.value)
}
enabled.value = true
refetch({
variables.value = {
range: range.value,
origins: originsTemp,
includeOrigins: isAuthenticated.value || false
})
}
load()
refetch(variables.value)
}
const { mutate: doToggleIgnoreBand } = useMutation(toggleIgnoreBand)
const { mutate: doToggleIgnoreDanceHall } = useMutation(
toggleIgnoreDanceHall
)
const { mutate: doToggleIgnoreCity } = useMutation(toggleIgnoreCity)
const { mutate: doToggleIgnoreMunicipality } = useMutation(
toggleIgnoreMunicipality
)
const { mutate: doToggleIgnoreState } = useMutation(toggleIgnoreState)
const { mutate: doToggleIgnoreBand } = useToggleIgnoreBandMutation({})
const { mutate: doToggleIgnoreDanceHall } = useToggleIgnoreDanceHallMutation({})
const { mutate: doToggleIgnoreCity } = useToggleIgnoreCityMutation({})
const { mutate: doToggleIgnoreMunicipality } = useToggleIgnoreMunicipalityMutation({})
const { mutate: doToggleIgnoreState } = useToggleIgnoreStateMutation({})
const toggleIgnoreSuccess = (name) => {
const toggleIgnoreSuccess = (name: string) => {
return () => {
fetchEvents()
snackbar.value.color = 'success'
@@ -168,7 +172,7 @@ export default {
}
}
const toggleIgnoreFailed = (name) => {
const toggleIgnoreFailed = (name: string) => {
return () => {
snackbar.value.color = 'error'
snackbar.value.text = `${name} kunde inte döljas`
@@ -176,7 +180,7 @@ export default {
}
}
const toggleIgnore = (type, name) => {
const toggleIgnore = (type: string, name: string) => {
switch (type) {
case 'band':
doToggleIgnoreBand({ name })
@@ -207,26 +211,21 @@ export default {
}
}
const { mutate: doSaveOrigin } = useMutation(saveOrigin)
const addressEnabled = ref(false)
const { result: address, refetch: doFetchAddress } = useQuery(
fetchAddress,
{},
() => ({ enabled: addressEnabled.value })
)
const { mutate: doSaveOrigin } = useSaveOriginMutation({})
const { refetch: doFetchAddress, load: loadFetchAddress } = useFetchAddressLazyQuery({ latlng: '' })
const fetchAddressFn = () => {
if (window.navigator) {
window.navigator.geolocation.getCurrentPosition((pos) => {
addressEnabled.value = true
loadFetchAddress()
doFetchAddress({
latlng: `${pos.coords.latitude},${pos.coords.longitude}`
}).then(() => {
origin.value = address.value.address
})?.then((result) => {
origin.value = result.data.address
})
})
}
}
const saveOriginFn = (o) =>
const saveOriginFn = (o: string) =>
doSaveOrigin({ origin: o }).then(() => {
origin.value = ''
fetchEvents()
@@ -238,7 +237,6 @@ export default {
range,
events,
origins,
query: fetchEvents,
submitting,
ranges,
snackbar,
@@ -248,5 +246,5 @@ export default {
saveOrigin: saveOriginFn
}
}
}
})
</script>
+4 -4
View File
@@ -1,5 +1,5 @@
<template>
<v-flex xs12 sm6 md4 lg3>
<v-col xs='12' sm='6' md='4' lg='3'>
<v-card>
<v-card-title>
<span v-text="$tc(title, model.length)" />
@@ -7,18 +7,18 @@
<v-list>
<v-list-item v-for="item in model" :key="item">
<v-list-item-action @click="toggleIgnore(type, item)">
<v-tooltip top slot="prepend">
<v-tooltip top>
<template #activator="{ on }">
<v-icon v-on="on">mdi-delete-outline</v-icon>
</template>
<span v-text="$t('filters.remove')" />
</v-tooltip>
</v-list-item-action>
<v-list-item-titl><span v-html="item" /></v-list-item-titl>
<v-list-item-title><span v-text="item" /></v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-flex>
</v-col>
</template>
<script>
+32 -44
View File
@@ -10,7 +10,7 @@
:model="bands || []"
title="filters.band"
type="band"
:toggleIgnore="toggleIgnore"
:toggle-ignore="toggleIgnore"
/>
<v-flex xs12 sm6 md4 lg3>
<v-layout column>
@@ -18,25 +18,25 @@
:model="states || []"
title="filters.state"
type="state"
:toggleIgnore="toggleIgnore"
:toggle-ignore="toggleIgnore"
/>
<list
:model="municipalities || []"
title="filters.municipality"
type="municipality"
:toggleIgnore="toggleIgnore"
:toggle-ignore="toggleIgnore"
/>
<list
:model="cities || []"
title="filters.city"
type="city"
:toggleIgnore="toggleIgnore"
:toggle-ignore="toggleIgnore"
/>
<list
:model="danceHalls || []"
title="filters.hall"
type="danceHall"
:toggleIgnore="toggleIgnore"
:toggle-ignore="toggleIgnore"
/>
</v-layout>
</v-flex>
@@ -56,22 +56,18 @@
</div>
</template>
<script>
import { ref } from '@vue/composition-api'
import { useMutations } from '@u3u/vue-hooks'
import { useMutation, useQuery, useResult } from '@vue/apollo-composable'
import {
fetchFilters,
toggleIgnoreBand,
toggleIgnoreCity,
toggleIgnoreDanceHall,
toggleIgnoreMunicipality,
toggleIgnoreState
} from '~/utils/graph-client'
<script lang='ts'>
import { computed, ref } from 'vue'
import { useStore } from '@nuxtjs/composition-api'
import List from './List'
import { useAuth } from '../../../plugins/auth'
import { useTranslation } from '../../../plugins/i18n'
import List from './List/index.vue'
import { useAuth } from '~/plugins/auth'
import { useTranslation } from '~/plugins/i18n'
import {
useFetchFiltersQuery,
useToggleIgnoreBandMutation, useToggleIgnoreCityMutation,
useToggleIgnoreDanceHallMutation, useToggleIgnoreMunicipalityMutation, useToggleIgnoreStateMutation
} from '~/graphql/generated/operations'
export default {
name: 'FiltersPage',
@@ -79,32 +75,24 @@ export default {
List
},
setup() {
const { setTitle } = useMutations(['setTitle'])
const store = useStore()
const { t } = useTranslation()
setTitle(t('app.links.filters'))
store.commit('setTitle', t('app.links.filters'))
const { isAuthenticated } = useAuth()
const { result: data, loading, refetch } = useQuery(fetchFilters)
const bands = useResult(data, [], (result) => result.bands)
const cities = useResult(data, [], (result) => result.cities)
const danceHalls = useResult(data, [], (result) => result.danceHalls)
const municipalities = useResult(
data,
[],
(result) => result.municipalities
)
const states = useResult(data, [], (result) => result.states)
const { result, loading, refetch } = useFetchFiltersQuery()
const bands = computed(() => result.value?.bands ?? [])
const cities = computed(() => result.value?.cities ?? [])
const danceHalls = computed(() => result.value?.danceHalls ?? [])
const municipalities = computed(() => result.value?.municipalities ?? [])
const states = computed(() => result.value?.states ?? [])
const snackbar = ref({ active: false, color: 'success', text: '' })
const { mutate: doToggleIgnoreBand } = useMutation(toggleIgnoreBand)
const { mutate: doToggleIgnoreDanceHall } = useMutation(
toggleIgnoreDanceHall
)
const { mutate: doToggleIgnoreCity } = useMutation(toggleIgnoreCity)
const { mutate: doToggleIgnoreMunicipality } = useMutation(
toggleIgnoreMunicipality
)
const { mutate: doToggleIgnoreState } = useMutation(toggleIgnoreState)
const { mutate: doToggleIgnoreBand } = useToggleIgnoreBandMutation({})
const { mutate: doToggleIgnoreDanceHall } = useToggleIgnoreDanceHallMutation({})
const { mutate: doToggleIgnoreCity } = useToggleIgnoreCityMutation({})
const { mutate: doToggleIgnoreMunicipality } = useToggleIgnoreMunicipalityMutation({})
const { mutate: doToggleIgnoreState } = useToggleIgnoreStateMutation({})
const toggleIgnoreSuccess = (name) => {
const toggleIgnoreSuccess = (name: string) => {
return () => {
refetch()
snackbar.value.color = 'success'
@@ -113,7 +101,7 @@ export default {
}
}
const toggleIgnoreFailed = (name) => {
const toggleIgnoreFailed = (name: string) => {
return () => {
snackbar.value.color = 'error'
snackbar.value.text = t('filters.failure', { name })
@@ -121,7 +109,7 @@ export default {
}
}
const toggleIgnore = (type, name) => {
const toggleIgnore = (type: string, name: string) => {
switch (type) {
case 'band':
doToggleIgnoreBand({ name })
+64 -66
View File
@@ -1,109 +1,107 @@
<template>
<div :key="isAuthenticated">
<v-container fluid grid-list-md class="app-fade-in">
<div :key='isAuthenticated'>
<v-container fluid grid-list-md class='app-fade-in'>
<v-layout row wrap>
<v-flex xs12>
<v-text-field
v-model="origin"
v-model='origin'
:label="$t('origins.origin')"
:placeholder="$t('origins.geolocation')"
>
<v-tooltip top slot="append-outer">
<template v-slot:activator="{ on }">
<v-icon v-on="on" v-on:click="fetchAddress()"
<template #append-outer>
<v-tooltip top>
<template #activator='{ on }'>
<v-icon v-on='on' @click='fetchAddress()'
>mdi-crosshairs-gps
</v-icon>
</template>
<span v-text="$t('origins.fetchAddress')" />
</v-tooltip>
<v-tooltip top slot="prepend">
<template v-slot:activator="{ on }">
<v-icon
v-on="on"
:disabled="!origin"
v-on:click="saveOrigin(origin)"
</v-icon>
</template>
<span v-text="$t('origins.fetchAddress')" />
</v-tooltip>
</template>
<template #prepend>
<v-tooltip top>
<template #activator='{ on }'>
<v-icon
:disabled='!origin'
v-on='on'
@click='saveOrigin(origin)'
>mdi-bookmark-plus-outline
</v-icon>
</template>
<span v-text="$t('origins.save')" />
</v-tooltip>
</v-icon>
</template>
<span v-text="$t('origins.save')" />
</v-tooltip>
</template>
</v-text-field>
</v-flex>
</v-layout>
<template>
<v-layout row wrap v-for="origin in origins" :key="origin">
<v-flex xs12>
<v-tooltip top slot="prepend">
<template v-slot:activator="{ on }">
<v-icon v-on="on" v-on:click="removeOrigin(origin)"
>mdi-delete-outline
</v-icon>
</template>
<span v-text="$t('origins.remove')" />
</v-tooltip>
<span>{{ origin }}</span>
</v-flex>
</v-layout>
</template>
<v-layout v-for='o in origins' :key='o' row wrap>
<v-flex xs12>
<v-tooltip top>
<template #activator='{ on }'>
<v-icon v-on='on' @click='removeOrigin(o)'
>mdi-delete-outline
</v-icon>
</template>
<span v-text="$t('origins.remove')" />
</v-tooltip>
<span>{{ o }}</span>
</v-flex>
</v-layout>
</v-container>
<v-snackbar
v-model="snackbar.active"
:color="snackbar.color"
:timeout="5000"
v-model='snackbar.active'
:color='snackbar.color'
:timeout='5000'
>
{{ snackbar.text }}
</v-snackbar>
</div>
</template>
<script>
import { ref } from '@vue/composition-api'
import { useMutations } from '@u3u/vue-hooks'
import { useMutation, useQuery, useResult } from '@vue/apollo-composable'
<script lang='ts'>
import { computed, defineComponent, ref } from 'vue'
import { useStore } from '@nuxtjs/composition-api'
import { useAuth } from '~/plugins/auth'
import { useTranslation } from '~/plugins/i18n'
import {
fetchAddress,
findOrigins,
removeOrigin,
saveOrigin
} from '../../../utils/graph-client'
import { useAuth } from '../../../plugins/auth'
import { useTranslation } from '../../../plugins/i18n'
useFetchAddressLazyQuery,
useFindOriginsQuery,
useRemoveOriginMutation,
useSaveOriginMutation
} from '~/graphql/generated/operations'
export default {
export default defineComponent({
name: 'OriginsPage',
setup() {
const { setTitle } = useMutations(['setTitle'])
const store = useStore()
const { t } = useTranslation()
setTitle(t('app.links.origins'))
store.commit('setTitle', t('app.links.origins'))
const { isAuthenticated } = useAuth()
const { result: data, loading, refetch } = useQuery(findOrigins)
const origins = useResult(data, [])
const { result, loading, refetch } = useFindOriginsQuery()
const origins = computed(() => result.value?.origins ?? [])
const snackbar = ref({ active: false, color: 'success', text: '' })
const { mutate: doSaveOrigin } = useMutation(saveOrigin)
const { mutate: doRemoveOrigin } = useMutation(removeOrigin)
const enabled = ref(false)
const { refetch: doFetchAddress } = useQuery(fetchAddress, {}, () => ({
enabled: enabled.value
}))
const { mutate: doSaveOrigin } = useSaveOriginMutation({})
const { mutate: doRemoveOrigin } = useRemoveOriginMutation({})
const { refetch: doFetchAddress, load } = useFetchAddressLazyQuery({ latlng: '' })
const origin = ref('')
const fetchAddressFn = () => {
if (window.navigator) {
window.navigator.geolocation.getCurrentPosition((pos) => {
enabled.value = true
load()
doFetchAddress({
latlng: `${pos.coords.latitude},${pos.coords.longitude}`
}).then((res) => {
origin.value = res.address
})?.then((res) => {
origin.value = res.data.address
})
})
}
}
const saveOriginFn = (o) =>
const saveOriginFn = (o: string) =>
doSaveOrigin({ origin: o }).then(() => {
refetch()
origin.value = ''
})
const removeOriginFn = (o) =>
const removeOriginFn = (o: string) =>
doRemoveOrigin({ origin: o }).then(() => refetch())
return {
isAuthenticated,
@@ -116,5 +114,5 @@ export default {
fetchAddress: fetchAddressFn
}
}
}
})
</script>
-5
View File
@@ -1,5 +0,0 @@
{
"__schema": {
"types": []
}
}
+571
View File
@@ -0,0 +1,571 @@
import gql from 'graphql-tag';
import * as VueApolloComposable from '@vue/apollo-composable';
import * as VueCompositionApi from 'vue';
export type Maybe<T> = T | null | undefined;
export type InputMaybe<T> = T | null | undefined;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type ReactiveFunction<TParam> = () => TParam;
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: string;
String: string;
Boolean: boolean;
Int: number;
Float: number;
LocalDate: string;
LocalDateTime: string;
};
/** Band */
export type Band = {
__typename?: 'Band';
created: Scalars['LocalDateTime'];
id: Maybe<Scalars['Int']>;
name: Scalars['String'];
};
/** DanceHall */
export type DanceHall = {
__typename?: 'DanceHall';
city: Maybe<Scalars['String']>;
created: Scalars['LocalDateTime'];
id: Maybe<Scalars['Int']>;
latitude: Maybe<Scalars['Float']>;
longitude: Maybe<Scalars['Float']>;
municipality: Maybe<Scalars['String']>;
name: Maybe<Scalars['String']>;
state: Maybe<Scalars['String']>;
};
/** DanceHallDistance */
export type DanceHallDistance = {
__typename?: 'DanceHallDistance';
distance: Scalars['Int'];
duration: Scalars['String'];
origin: Scalars['String'];
};
/** Event */
export type Event = {
__typename?: 'Event';
/** The band of the event */
band: Maybe<Band>;
created: Scalars['LocalDateTime'];
/** The place of the event */
danceHall: Maybe<DanceHall>;
/** The date of the event */
date: Scalars['LocalDate'];
/** The driving distances and driving durations to the event from the provided origins */
distances: Array<DanceHallDistance>;
/** Additional information regarding the event */
extraInfo: Maybe<Scalars['String']>;
id: Maybe<Scalars['Int']>;
/** The time of the event */
time: Maybe<Scalars['String']>;
};
export type Mutation = {
__typename?: 'Mutation';
/** Remove provided origin from authenticated user */
RemoveOrigin: Scalars['Boolean'];
/** Save provided origin for authenticated user */
SaveOrigin: Scalars['Boolean'];
/** Toggle band in ignore list */
ToggleIgnoreBand: Scalars['Boolean'];
/** Toggle city in ignore list */
ToggleIgnoreCity: Scalars['Boolean'];
/** Toggle dance hall in ignore list */
ToggleIgnoreDanceHall: Scalars['Boolean'];
/** Toggle municipality in ignore list */
ToggleIgnoreMunicipality: Scalars['Boolean'];
/** Toggle state in ignore list */
ToggleIgnoreState: Scalars['Boolean'];
};
export type MutationRemoveOriginArgs = {
origin: Scalars['String'];
};
export type MutationSaveOriginArgs = {
origin: Scalars['String'];
};
export type MutationToggleIgnoreBandArgs = {
name: Scalars['String'];
};
export type MutationToggleIgnoreCityArgs = {
name: Scalars['String'];
};
export type MutationToggleIgnoreDanceHallArgs = {
name: Scalars['String'];
};
export type MutationToggleIgnoreMunicipalityArgs = {
name: Scalars['String'];
};
export type MutationToggleIgnoreStateArgs = {
name: Scalars['String'];
};
export type Query = {
__typename?: 'Query';
/** Fetch address for provided lat/long */
AddressFromLatLng: Scalars['String'];
/** Find bands given provided criteria */
Bands: Array<Band>;
/** Find dance halls given provided criteria */
DanceHalls: Array<DanceHall>;
/** Find events given provided criteria */
Events: Array<Event>;
/** Fetch ignored bands for authenticated user */
IgnoredBands: Array<Scalars['String']>;
/** Fetch ignored cities for authenticated user */
IgnoredCities: Array<Scalars['String']>;
/** Fetch ignored dance halls for authenticated user */
IgnoredDanceHalls: Array<Scalars['String']>;
/** Fetch ignored municipalities for authenticated user */
IgnoredMunicipalities: Array<Scalars['String']>;
/** Fetch ignored states for authenticated user */
IgnoredStates: Array<Scalars['String']>;
/** Fetch origins for authenticated user */
Origins: Array<Scalars['String']>;
};
export type QueryAddressFromLatLngArgs = {
latlng: Scalars['String'];
};
export type QueryEventsArgs = {
origins?: InputMaybe<Array<Scalars['String']>>;
range?: InputMaybe<Range>;
};
export enum Range {
OneMonth = 'ONE_MONTH',
OneQuarter = 'ONE_QUARTER',
OneWeek = 'ONE_WEEK',
OneYear = 'ONE_YEAR',
TwoWeeks = 'TWO_WEEKS'
}
export type RemoveOriginMutationVariables = Exact<{
origin: Scalars['String'];
}>;
export type RemoveOriginMutation = { __typename?: 'Mutation', removed: boolean };
export type SaveOriginMutationVariables = Exact<{
origin: Scalars['String'];
}>;
export type SaveOriginMutation = { __typename?: 'Mutation', saved: boolean };
export type ToggleIgnoreBandMutationVariables = Exact<{
name: Scalars['String'];
}>;
export type ToggleIgnoreBandMutation = { __typename?: 'Mutation', ignore: boolean };
export type ToggleIgnoreCityMutationVariables = Exact<{
name: Scalars['String'];
}>;
export type ToggleIgnoreCityMutation = { __typename?: 'Mutation', ignore: boolean };
export type ToggleIgnoreDanceHallMutationVariables = Exact<{
name: Scalars['String'];
}>;
export type ToggleIgnoreDanceHallMutation = { __typename?: 'Mutation', ignore: boolean };
export type ToggleIgnoreMunicipalityMutationVariables = Exact<{
name: Scalars['String'];
}>;
export type ToggleIgnoreMunicipalityMutation = { __typename?: 'Mutation', ignore: boolean };
export type ToggleIgnoreStateMutationVariables = Exact<{
name: Scalars['String'];
}>;
export type ToggleIgnoreStateMutation = { __typename?: 'Mutation', ignore: boolean };
export type FetchAddressQueryVariables = Exact<{
latlng: Scalars['String'];
}>;
export type FetchAddressQuery = { __typename?: 'Query', address: string };
export type FetchFiltersQueryVariables = Exact<{ [key: string]: never; }>;
export type FetchFiltersQuery = { __typename?: 'Query', bands: Array<string>, cities: Array<string>, states: Array<string>, danceHalls: Array<string>, municipalities: Array<string> };
export type FindEventsQueryVariables = Exact<{
range?: InputMaybe<Range>;
origins?: InputMaybe<Array<Scalars['String']> | Scalars['String']>;
includeOrigins: Scalars['Boolean'];
}>;
export type FindEventsQuery = { __typename?: 'Query', origins: Array<string>, events: Array<{ __typename?: 'Event', date: string, time: string | null | undefined, extraInfo: string | null | undefined, band: { __typename?: 'Band', name: string } | null | undefined, danceHall: { __typename?: 'DanceHall', name: string | null | undefined, city: string | null | undefined, municipality: string | null | undefined, state: string | null | undefined } | null | undefined, distances: Array<{ __typename?: 'DanceHallDistance', origin: string, distance: number, duration: string }> }> };
export type FindOriginsQueryVariables = Exact<{ [key: string]: never; }>;
export type FindOriginsQuery = { __typename?: 'Query', origins: Array<string> };
export const RemoveOriginDocument = gql`
mutation RemoveOrigin($origin: String!) {
removed: RemoveOrigin(origin: $origin)
}
`;
/**
* __useRemoveOriginMutation__
*
* To run a mutation, you first call `useRemoveOriginMutation` within a Vue component and pass it any options that fit your needs.
* When your component renders, `useRemoveOriginMutation` returns an object that includes:
* - A mutate function that you can call at any time to execute the mutation
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
*
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
*
* @example
* const { mutate, loading, error, onDone } = useRemoveOriginMutation({
* variables: {
* origin: // value for 'origin'
* },
* });
*/
export function useRemoveOriginMutation(options: VueApolloComposable.UseMutationOptions<RemoveOriginMutation, RemoveOriginMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<RemoveOriginMutation, RemoveOriginMutationVariables>>) {
return VueApolloComposable.useMutation<RemoveOriginMutation, RemoveOriginMutationVariables>(RemoveOriginDocument, options);
}
export type RemoveOriginMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<RemoveOriginMutation, RemoveOriginMutationVariables>;
export const SaveOriginDocument = gql`
mutation SaveOrigin($origin: String!) {
saved: SaveOrigin(origin: $origin)
}
`;
/**
* __useSaveOriginMutation__
*
* To run a mutation, you first call `useSaveOriginMutation` within a Vue component and pass it any options that fit your needs.
* When your component renders, `useSaveOriginMutation` returns an object that includes:
* - A mutate function that you can call at any time to execute the mutation
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
*
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
*
* @example
* const { mutate, loading, error, onDone } = useSaveOriginMutation({
* variables: {
* origin: // value for 'origin'
* },
* });
*/
export function useSaveOriginMutation(options: VueApolloComposable.UseMutationOptions<SaveOriginMutation, SaveOriginMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<SaveOriginMutation, SaveOriginMutationVariables>>) {
return VueApolloComposable.useMutation<SaveOriginMutation, SaveOriginMutationVariables>(SaveOriginDocument, options);
}
export type SaveOriginMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<SaveOriginMutation, SaveOriginMutationVariables>;
export const ToggleIgnoreBandDocument = gql`
mutation ToggleIgnoreBand($name: String!) {
ignore: ToggleIgnoreBand(name: $name)
}
`;
/**
* __useToggleIgnoreBandMutation__
*
* To run a mutation, you first call `useToggleIgnoreBandMutation` within a Vue component and pass it any options that fit your needs.
* When your component renders, `useToggleIgnoreBandMutation` returns an object that includes:
* - A mutate function that you can call at any time to execute the mutation
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
*
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
*
* @example
* const { mutate, loading, error, onDone } = useToggleIgnoreBandMutation({
* variables: {
* name: // value for 'name'
* },
* });
*/
export function useToggleIgnoreBandMutation(options: VueApolloComposable.UseMutationOptions<ToggleIgnoreBandMutation, ToggleIgnoreBandMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<ToggleIgnoreBandMutation, ToggleIgnoreBandMutationVariables>>) {
return VueApolloComposable.useMutation<ToggleIgnoreBandMutation, ToggleIgnoreBandMutationVariables>(ToggleIgnoreBandDocument, options);
}
export type ToggleIgnoreBandMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<ToggleIgnoreBandMutation, ToggleIgnoreBandMutationVariables>;
export const ToggleIgnoreCityDocument = gql`
mutation ToggleIgnoreCity($name: String!) {
ignore: ToggleIgnoreCity(name: $name)
}
`;
/**
* __useToggleIgnoreCityMutation__
*
* To run a mutation, you first call `useToggleIgnoreCityMutation` within a Vue component and pass it any options that fit your needs.
* When your component renders, `useToggleIgnoreCityMutation` returns an object that includes:
* - A mutate function that you can call at any time to execute the mutation
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
*
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
*
* @example
* const { mutate, loading, error, onDone } = useToggleIgnoreCityMutation({
* variables: {
* name: // value for 'name'
* },
* });
*/
export function useToggleIgnoreCityMutation(options: VueApolloComposable.UseMutationOptions<ToggleIgnoreCityMutation, ToggleIgnoreCityMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<ToggleIgnoreCityMutation, ToggleIgnoreCityMutationVariables>>) {
return VueApolloComposable.useMutation<ToggleIgnoreCityMutation, ToggleIgnoreCityMutationVariables>(ToggleIgnoreCityDocument, options);
}
export type ToggleIgnoreCityMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<ToggleIgnoreCityMutation, ToggleIgnoreCityMutationVariables>;
export const ToggleIgnoreDanceHallDocument = gql`
mutation ToggleIgnoreDanceHall($name: String!) {
ignore: ToggleIgnoreDanceHall(name: $name)
}
`;
/**
* __useToggleIgnoreDanceHallMutation__
*
* To run a mutation, you first call `useToggleIgnoreDanceHallMutation` within a Vue component and pass it any options that fit your needs.
* When your component renders, `useToggleIgnoreDanceHallMutation` returns an object that includes:
* - A mutate function that you can call at any time to execute the mutation
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
*
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
*
* @example
* const { mutate, loading, error, onDone } = useToggleIgnoreDanceHallMutation({
* variables: {
* name: // value for 'name'
* },
* });
*/
export function useToggleIgnoreDanceHallMutation(options: VueApolloComposable.UseMutationOptions<ToggleIgnoreDanceHallMutation, ToggleIgnoreDanceHallMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<ToggleIgnoreDanceHallMutation, ToggleIgnoreDanceHallMutationVariables>>) {
return VueApolloComposable.useMutation<ToggleIgnoreDanceHallMutation, ToggleIgnoreDanceHallMutationVariables>(ToggleIgnoreDanceHallDocument, options);
}
export type ToggleIgnoreDanceHallMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<ToggleIgnoreDanceHallMutation, ToggleIgnoreDanceHallMutationVariables>;
export const ToggleIgnoreMunicipalityDocument = gql`
mutation ToggleIgnoreMunicipality($name: String!) {
ignore: ToggleIgnoreMunicipality(name: $name)
}
`;
/**
* __useToggleIgnoreMunicipalityMutation__
*
* To run a mutation, you first call `useToggleIgnoreMunicipalityMutation` within a Vue component and pass it any options that fit your needs.
* When your component renders, `useToggleIgnoreMunicipalityMutation` returns an object that includes:
* - A mutate function that you can call at any time to execute the mutation
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
*
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
*
* @example
* const { mutate, loading, error, onDone } = useToggleIgnoreMunicipalityMutation({
* variables: {
* name: // value for 'name'
* },
* });
*/
export function useToggleIgnoreMunicipalityMutation(options: VueApolloComposable.UseMutationOptions<ToggleIgnoreMunicipalityMutation, ToggleIgnoreMunicipalityMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<ToggleIgnoreMunicipalityMutation, ToggleIgnoreMunicipalityMutationVariables>>) {
return VueApolloComposable.useMutation<ToggleIgnoreMunicipalityMutation, ToggleIgnoreMunicipalityMutationVariables>(ToggleIgnoreMunicipalityDocument, options);
}
export type ToggleIgnoreMunicipalityMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<ToggleIgnoreMunicipalityMutation, ToggleIgnoreMunicipalityMutationVariables>;
export const ToggleIgnoreStateDocument = gql`
mutation ToggleIgnoreState($name: String!) {
ignore: ToggleIgnoreState(name: $name)
}
`;
/**
* __useToggleIgnoreStateMutation__
*
* To run a mutation, you first call `useToggleIgnoreStateMutation` within a Vue component and pass it any options that fit your needs.
* When your component renders, `useToggleIgnoreStateMutation` returns an object that includes:
* - A mutate function that you can call at any time to execute the mutation
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
*
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
*
* @example
* const { mutate, loading, error, onDone } = useToggleIgnoreStateMutation({
* variables: {
* name: // value for 'name'
* },
* });
*/
export function useToggleIgnoreStateMutation(options: VueApolloComposable.UseMutationOptions<ToggleIgnoreStateMutation, ToggleIgnoreStateMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<ToggleIgnoreStateMutation, ToggleIgnoreStateMutationVariables>>) {
return VueApolloComposable.useMutation<ToggleIgnoreStateMutation, ToggleIgnoreStateMutationVariables>(ToggleIgnoreStateDocument, options);
}
export type ToggleIgnoreStateMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<ToggleIgnoreStateMutation, ToggleIgnoreStateMutationVariables>;
export const FetchAddressDocument = gql`
query FetchAddress($latlng: String!) {
address: AddressFromLatLng(latlng: $latlng)
}
`;
/**
* __useFetchAddressQuery__
*
* To run a query within a Vue component, call `useFetchAddressQuery` and pass it any options that fit your needs.
* When your component renders, `useFetchAddressQuery` returns an object from Apollo Client that contains result, loading and error properties
* you can use to render your UI.
*
* @param variables that will be passed into the query
* @param options that will be passed into the query, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/query.html#options;
*
* @example
* const { result, loading, error } = useFetchAddressQuery({
* latlng: // value for 'latlng'
* });
*/
export function useFetchAddressQuery(variables: FetchAddressQueryVariables | VueCompositionApi.Ref<FetchAddressQueryVariables> | ReactiveFunction<FetchAddressQueryVariables>, options: VueApolloComposable.UseQueryOptions<FetchAddressQuery, FetchAddressQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<FetchAddressQuery, FetchAddressQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<FetchAddressQuery, FetchAddressQueryVariables>> = {}) {
return VueApolloComposable.useQuery<FetchAddressQuery, FetchAddressQueryVariables>(FetchAddressDocument, variables, options);
}
export function useFetchAddressLazyQuery(variables: FetchAddressQueryVariables | VueCompositionApi.Ref<FetchAddressQueryVariables> | ReactiveFunction<FetchAddressQueryVariables>, options: VueApolloComposable.UseQueryOptions<FetchAddressQuery, FetchAddressQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<FetchAddressQuery, FetchAddressQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<FetchAddressQuery, FetchAddressQueryVariables>> = {}) {
return VueApolloComposable.useLazyQuery<FetchAddressQuery, FetchAddressQueryVariables>(FetchAddressDocument, variables, options);
}
export type FetchAddressQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn<FetchAddressQuery, FetchAddressQueryVariables>;
export const FetchFiltersDocument = gql`
query FetchFilters {
bands: IgnoredBands
cities: IgnoredCities
states: IgnoredStates
danceHalls: IgnoredDanceHalls
municipalities: IgnoredMunicipalities
}
`;
/**
* __useFetchFiltersQuery__
*
* To run a query within a Vue component, call `useFetchFiltersQuery` and pass it any options that fit your needs.
* When your component renders, `useFetchFiltersQuery` returns an object from Apollo Client that contains result, loading and error properties
* you can use to render your UI.
*
* @param options that will be passed into the query, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/query.html#options;
*
* @example
* const { result, loading, error } = useFetchFiltersQuery();
*/
export function useFetchFiltersQuery(options: VueApolloComposable.UseQueryOptions<FetchFiltersQuery, FetchFiltersQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<FetchFiltersQuery, FetchFiltersQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<FetchFiltersQuery, FetchFiltersQueryVariables>> = {}) {
return VueApolloComposable.useQuery<FetchFiltersQuery, FetchFiltersQueryVariables>(FetchFiltersDocument, {}, options);
}
export function useFetchFiltersLazyQuery(options: VueApolloComposable.UseQueryOptions<FetchFiltersQuery, FetchFiltersQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<FetchFiltersQuery, FetchFiltersQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<FetchFiltersQuery, FetchFiltersQueryVariables>> = {}) {
return VueApolloComposable.useLazyQuery<FetchFiltersQuery, FetchFiltersQueryVariables>(FetchFiltersDocument, {}, options);
}
export type FetchFiltersQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn<FetchFiltersQuery, FetchFiltersQueryVariables>;
export const FindEventsDocument = gql`
query FindEvents($range: Range, $origins: [String!], $includeOrigins: Boolean!) {
events: Events(range: $range, origins: $origins) {
date
time
band {
name
}
danceHall {
name
city
municipality
state
}
extraInfo
distances {
origin
distance
duration
}
}
origins: Origins @include(if: $includeOrigins)
}
`;
/**
* __useFindEventsQuery__
*
* To run a query within a Vue component, call `useFindEventsQuery` and pass it any options that fit your needs.
* When your component renders, `useFindEventsQuery` returns an object from Apollo Client that contains result, loading and error properties
* you can use to render your UI.
*
* @param variables that will be passed into the query
* @param options that will be passed into the query, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/query.html#options;
*
* @example
* const { result, loading, error } = useFindEventsQuery({
* range: // value for 'range'
* origins: // value for 'origins'
* includeOrigins: // value for 'includeOrigins'
* });
*/
export function useFindEventsQuery(variables: FindEventsQueryVariables | VueCompositionApi.Ref<FindEventsQueryVariables> | ReactiveFunction<FindEventsQueryVariables>, options: VueApolloComposable.UseQueryOptions<FindEventsQuery, FindEventsQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<FindEventsQuery, FindEventsQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<FindEventsQuery, FindEventsQueryVariables>> = {}) {
return VueApolloComposable.useQuery<FindEventsQuery, FindEventsQueryVariables>(FindEventsDocument, variables, options);
}
export function useFindEventsLazyQuery(variables: FindEventsQueryVariables | VueCompositionApi.Ref<FindEventsQueryVariables> | ReactiveFunction<FindEventsQueryVariables>, options: VueApolloComposable.UseQueryOptions<FindEventsQuery, FindEventsQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<FindEventsQuery, FindEventsQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<FindEventsQuery, FindEventsQueryVariables>> = {}) {
return VueApolloComposable.useLazyQuery<FindEventsQuery, FindEventsQueryVariables>(FindEventsDocument, variables, options);
}
export type FindEventsQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn<FindEventsQuery, FindEventsQueryVariables>;
export const FindOriginsDocument = gql`
query FindOrigins {
origins: Origins
}
`;
/**
* __useFindOriginsQuery__
*
* To run a query within a Vue component, call `useFindOriginsQuery` and pass it any options that fit your needs.
* When your component renders, `useFindOriginsQuery` returns an object from Apollo Client that contains result, loading and error properties
* you can use to render your UI.
*
* @param options that will be passed into the query, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/query.html#options;
*
* @example
* const { result, loading, error } = useFindOriginsQuery();
*/
export function useFindOriginsQuery(options: VueApolloComposable.UseQueryOptions<FindOriginsQuery, FindOriginsQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<FindOriginsQuery, FindOriginsQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<FindOriginsQuery, FindOriginsQueryVariables>> = {}) {
return VueApolloComposable.useQuery<FindOriginsQuery, FindOriginsQueryVariables>(FindOriginsDocument, {}, options);
}
export function useFindOriginsLazyQuery(options: VueApolloComposable.UseQueryOptions<FindOriginsQuery, FindOriginsQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<FindOriginsQuery, FindOriginsQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<FindOriginsQuery, FindOriginsQueryVariables>> = {}) {
return VueApolloComposable.useLazyQuery<FindOriginsQuery, FindOriginsQueryVariables>(FindOriginsDocument, {}, options);
}
export type FindOriginsQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn<FindOriginsQuery, FindOriginsQueryVariables>;
export interface PossibleTypesResultData {
possibleTypes: {
[key: string]: string[]
}
}
const result: PossibleTypesResultData = {
"possibleTypes": {}
};
export default result;
+3
View File
@@ -0,0 +1,3 @@
mutation RemoveOrigin($origin: String!) {
removed: RemoveOrigin(origin: $origin)
}
+3
View File
@@ -0,0 +1,3 @@
mutation SaveOrigin($origin: String!) {
saved: SaveOrigin(origin: $origin)
}
@@ -0,0 +1,3 @@
mutation ToggleIgnoreBand($name: String!) {
ignore: ToggleIgnoreBand(name: $name)
}
@@ -0,0 +1,3 @@
mutation ToggleIgnoreCity($name: String!) {
ignore: ToggleIgnoreCity(name: $name)
}
@@ -0,0 +1,3 @@
mutation ToggleIgnoreDanceHall($name: String!) {
ignore: ToggleIgnoreDanceHall(name: $name)
}
@@ -0,0 +1,3 @@
mutation ToggleIgnoreMunicipality($name: String!) {
ignore: ToggleIgnoreMunicipality(name: $name)
}
@@ -0,0 +1,3 @@
mutation ToggleIgnoreState($name: String!) {
ignore: ToggleIgnoreState(name: $name)
}
+3
View File
@@ -0,0 +1,3 @@
query FetchAddress($latlng: String!) {
address: AddressFromLatLng(latlng: $latlng)
}
+7
View File
@@ -0,0 +1,7 @@
query FetchFilters {
bands: IgnoredBands
cities: IgnoredCities
states: IgnoredStates
danceHalls: IgnoredDanceHalls
municipalities: IgnoredMunicipalities
}
+22
View File
@@ -0,0 +1,22 @@
query FindEvents($range: Range, $origins: [String!], $includeOrigins: Boolean!) {
events: Events(range: $range, origins: $origins) {
date
time
band {
name
}
danceHall {
name
city
municipality
state
}
extraInfo
distances {
origin
distance
duration
}
}
origins: Origins @include(if: $includeOrigins)
}
+3
View File
@@ -0,0 +1,3 @@
query FindOrigins {
origins: Origins
}
+6 -2
View File
@@ -5,12 +5,16 @@
</template>
<script>
import { getCurrentInstance } from 'vue'
import { getDarkMode } from '../../utils/localStorage'
export default {
name: 'ThemedLayout',
setup(props, context) {
context.root.$vuetify.theme.dark = getDarkMode()
setup() {
const instance = getCurrentInstance()
if (instance) {
instance.proxy.$vuetify.theme.dark = getDarkMode()
}
}
}
</script>
+45 -57
View File
@@ -1,11 +1,11 @@
<template>
<v-app :key="$i18n.locale + isAuthenticated">
<v-app :key='$i18n.locale + isAuthenticated'>
<themed>
<v-navigation-drawer v-model="nav" temporary app>
<v-navigation-drawer v-model='nav' temporary app>
<v-list dense>
<v-list-item>
<v-list-item-action>
<v-switch v-model="darkMode" />
<v-switch v-model='darkMode' />
</v-list-item-action>
<v-list-item-title>{{ $t('app.darkMode') }}</v-list-item-title>
</v-list-item>
@@ -15,62 +15,62 @@
<v-list-item @click="locale = 'sv'">
<v-list-item-title> Svenska 🇸🇪</v-list-item-title>
</v-list-item>
<v-list-item v-if="!user" link @click="doLogin">
<v-list-item v-if='!user' link @click='doLogin'>
<v-list-item-title>{{ $t('app.login') }}</v-list-item-title>
</v-list-item>
<v-list-item v-if="isAuthenticated && user">
<v-list-item v-if='isAuthenticated && user'>
<v-list-item-avatar>
<v-img :src="user.picture" :alt="user.name" />
<v-img :src='user.picture' :alt='user.name' />
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title><span v-html="user.name" /></v-list-item-title>
<v-list-item-title><span v-text='user.name' /></v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item link to="/">
<v-list-item link to='/'>
<v-list-item-action>
<v-icon>mdi-calendar-outline</v-icon>
</v-list-item-action>
<v-list-item-title>{{ $t('app.links.events') }}</v-list-item-title>
</v-list-item>
<v-list-item v-if="isAuthenticated" link to="/origins/">
<v-list-item v-if='isAuthenticated' link to='/origins/'>
<v-list-item-action>
<v-icon>mdi-home</v-icon>
</v-list-item-action>
<v-list-item-title>{{ $t('app.links.origins') }}</v-list-item-title>
</v-list-item>
<v-list-item v-if="isAuthenticated" link to="/filters/">
<v-list-item v-if='isAuthenticated' link to='/filters/'>
<v-list-item-action>
<v-icon>mdi-magnify</v-icon>
</v-list-item-action>
<v-list-item-title>{{ $t('app.links.filters') }}</v-list-item-title>
</v-list-item>
<v-list-item v-if="isAuthenticated" link>
<v-list-item v-if='isAuthenticated' link>
<v-list-item-action>
<v-icon>exit_to_app</v-icon>
</v-list-item-action>
<v-list-item-content @click="doLogout">
<v-list-item-content @click='doLogout'>
<v-list-item-title>{{ $t('app.logout') }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-app-bar app scroll-off-screen>
<v-app-bar-nav-icon @click="nav = !nav" />
<v-toolbar-title><span v-html="title" /></v-toolbar-title>
<v-app-bar-nav-icon @click='nav = !nav' />
<v-toolbar-title><span v-text='title' /></v-toolbar-title>
<v-spacer />
<v-toolbar-items>
<v-list-item v-if="isAuthenticated && user">
<v-list-item v-if='isAuthenticated && user'>
<v-list-item-avatar>
<v-img :src="user.picture" :alt="user.name" />
<v-img :src='user.picture' :alt='user.name' />
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title><span v-html="user.name" /></v-list-item-title>
<v-list-item-title><span v-text='user.name' /></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-toolbar-items>
</v-app-bar>
<v-main>
<v-container v-if="!loading" fluid>
<v-container v-if='!loading' fluid>
<nuxt />
</v-container>
</v-main>
@@ -78,38 +78,28 @@
</v-app>
</template>
<style lang="scss">
// We need this line to import all global styling
@import 'assets/scss/global.scss';
</style>
<style lang="scss" scoped>
.layout {
background-color: white;
.log-out {
cursor: pointer;
}
}
</style>
<script>
import { computed, ref } from '@vue/composition-api'
import { useRouter, useState } from '@u3u/vue-hooks'
import dayjs from 'dayjs'
import sv from 'dayjs/locale/sv'
import { setDarkMode } from '../utils/localStorage'
import { computed, getCurrentInstance, provide, ref } from 'vue'
import { useRouter, useStore } from '@nuxtjs/composition-api'
import { DefaultApolloClient } from '@vue/apollo-composable'
import Themed from './components/themed'
import { useAuth } from '../plugins/auth'
import { setDarkMode } from '~/utils/localStorage'
import { useAuth } from '~/plugins/auth'
export default {
name: 'DefaultLayout',
components: {
Themed
},
setup(props, context) {
const { router } = useRouter()
const { title } = useState(['title'])
setup() {
const instance = getCurrentInstance()
if (instance) {
provide(DefaultApolloClient, instance.proxy.$apollo)
}
const router = useRouter()
const store = useStore()
const { title } = store.state
const onRedirectCallback = (appState) => {
router.push(
appState && appState.targetUrl
@@ -120,37 +110,35 @@ export default {
const { loading, isAuthenticated, user, loginWithRedirect, logout } =
useAuth(onRedirectCallback)
const doLogin = () => {
loginWithRedirect.value()
loginWithRedirect()
}
const doLogout = () => {
logout.value({
logout({
returnTo: window.location.origin
})
}
const darkMode = computed({
get: () => context.root.$vuetify.theme.dark,
get: () => (instance ? instance.proxy.$vuetify.theme.dark : false),
set: (val) => {
context.root.$vuetify.theme.dark = val
setDarkMode(context.root.$vuetify.theme.dark)
if (instance) {
instance.proxy.$vuetify.theme.dark = val
setDarkMode(instance.proxy.$vuetify.theme.dark)
}
}
})
const locale = computed({
get: () => context.root.$i18n.locale,
get: () => (instance ? instance.proxy.$i18n.locale : 'sv'),
set: (newLocale) => {
if (newLocale === 'en') {
dayjs.locale(newLocale)
} else if (newLocale === 'sv') {
dayjs.locale(sv)
if (instance) {
instance.proxy.$i18n.setLocaleCookie(newLocale)
instance.proxy.$vuetify.lang.current = newLocale
instance.proxy.$i18n.locale = newLocale
}
context.root.$i18n.setLocaleCookie(newLocale)
context.root.$vuetify.lang.current = newLocale
context.root.$i18n.locale = newLocale
}
})
const nav = ref(false)
locale.value = context.root.$i18n.locale
locale.value = instance.proxy.$i18n.locale
return {
title,
+2 -2
View File
@@ -1,6 +1,6 @@
import { useAuth } from '../plugins/auth'
import { useAuth } from '~/plugins/auth'
export default async ({ app: { router } }) => {
export default ({ app: { router } }) => {
const onRedirectCallback = (appState) => {
router.push(
appState && appState.targetUrl
+18 -4
View File
@@ -3,6 +3,13 @@ import numberFormats from './translations/numberFormats'
export default {
build: {
extend(config) {
config.module.rules.push({
include: /node_modules/,
test: /\.mjs$/,
type: 'javascript/auto'
})
},
babel: {
presets({ isServer }) {
return [
@@ -18,7 +25,17 @@ export default {
}
}
},
buildModules: ['@nuxtjs/composition-api/module'],
buildModules: [
'@nuxt/typescript-build',
// https://go.nuxtjs.dev/eslint
['@nuxtjs/eslint-module', { exclude: ['graphql/generated', 'node_modules'] }],
// https://go.nuxtjs.dev/stylelint
'@nuxtjs/stylelint-module',
// https://go.nuxtjs.dev/vuetify
'@nuxtjs/vuetify',
'@nuxtjs/composition-api/module',
'@vueuse/nuxt'
],
css: ['vuetify/dist/vuetify.css', '~/assets/scss/global.scss'],
env: {
graphqlApi: process.env.GRAPHQL_API
@@ -94,13 +111,10 @@ export default {
modules: [
'@nuxtjs/i18n',
'@nuxtjs/sentry',
'@nuxtjs/vuetify',
['@nuxtjs/moment', { locales: ['sv'], defaultLocale: 'sv' }]
],
plugins: [
'~/plugins/apollo',
'~/plugins/composition',
'~/plugins/hooks',
'~/plugins/i18n',
'~/plugins/vue-numeral-filter.js'
],
+40 -25
View File
@@ -6,52 +6,60 @@
},
"author": "Joakim Olsson <joakim@unbound.se>",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint:js": "eslint --ext \".ts,.js,.vue\" --ignore-path .gitignore .",
"lint:style": "stylelint \"**/*.{css,scss,sass,html,vue}\" --ignore-path .gitignore",
"lint:prettier": "prettier --check .",
"lint": "yarn lint:js && yarn lint:style # ignore prettier for now # && yarn lint:prettier",
"lintfix": "prettier --write --list-different . && yarn lint:js --fix && yarn lint:style --fix",
"prepare": "husky install",
"test": "jest",
"codegen": "graphql-codegen"
},
"dependencies": {
"@apollo/client": "^3.6.9",
"@auth0/auth0-spa-js": "^1.22.2",
"@nuxtjs/composition-api": "^0.32.0",
"@graphql-codegen/typescript": "^2.7.2",
"@graphql-codegen/typescript-operations": "^2.5.2",
"@graphql-codegen/typescript-vue-apollo": "^3.3.2",
"@nuxtjs/composition-api": "^0.33.0",
"@nuxtjs/i18n": "^7.2.3",
"@nuxtjs/moment": "^1.1.0",
"@nuxtjs/sentry": "^5.1.7",
"@nuxtjs/vuetify": "^1.12.3",
"@snyk/protect": "^1.982.0",
"@u3u/vue-hooks": "^2.0.1",
"@vue/apollo-composable": "^4.0.0-alpha.19",
"@vue/apollo-option": "^4.0.0-alpha.20",
"@vue/composition-api": "^1.7.0",
"@vueuse/core": "^9.0.2",
"@vueuse/nuxt": "^9.0.2",
"core-js": "3",
"dayjs": "^1.11.4",
"date-fns": "^2.29.1",
"graphql": "^15.8.0",
"graphql-tag": "^2.12.6",
"moment": "^2.29.4",
"node-sass": "^7.0.1",
"nuxt": "^2.15.8",
"sass-loader": "^7.0.3",
"vue": "^2.6.14",
"sass-loader": "^10.1.1",
"vue": "2.7.8",
"vue-demi": "^0.13.6",
"vue-numeral-filter": "^2.2.0",
"vue-server-renderer": "^2.6.14",
"vue-template-compiler": "2.6.14",
"vuetify": "^2.6.8"
},
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"generate": "nuxt generate",
"lint": "eslint --quiet --fix --ext .js,.vue --ignore-path .gitignore .",
"generate-gql": "graphql-codegen",
"precommit": "yarn lint",
"prepush": "yarn test",
"prepare": "yarn run snyk-protect",
"snyk-protect": "snyk-protect",
"start": "node server/index.js",
"start:ci": "NODE_ENV=production CI=true node server/index.js",
"test:cypress": "cypress run",
"wait": "wait-on http://localhost:3000"
"vue-server-renderer": "2.7.8",
"vue-template-compiler": "2.7.8",
"vuetify": "^2.6.8",
"vuex": "3.6.2"
},
"devDependencies": {
"@babel/runtime-corejs3": "^7.18.9",
"@graphql-codegen/cli": "^2.11.3",
"@graphql-codegen/fragment-matcher": "^3.3.0",
"@nuxt/types": "^2.15.8",
"@nuxt/typescript-build": "^2.1.0",
"@nuxtjs/eslint-config-typescript": "^10.0.0",
"@nuxtjs/eslint-module": "^3.1.0",
"@nuxtjs/stylelint-module": "^4.1.0",
"babel-eslint": "^10.0.3",
"cli-engine": "^4.7.6",
"cypress": "^10.4.0",
@@ -60,9 +68,16 @@
"eslint-config-prettier": "^8.5.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-nuxt": "^3.2.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.3.0",
"husky": "^8.0.1",
"postcss-html": "^1.5.0",
"prettier": "^2.7.1",
"stylelint": "^14.9.1",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^26.0.0",
"wait-on": "^6.0.1"
},
"snyk": true
+1
View File
@@ -0,0 +1 @@
<template><p>Dummy</p></template>
+10 -10
View File
@@ -1,7 +1,9 @@
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client/core'
import {
ApolloClient,
InMemoryCache,
createHttpLink
} from '@apollo/client/core'
import { setContext } from '@apollo/client/link/context'
import { provide } from '@vue/composition-api'
import { DefaultApolloClient } from '@vue/apollo-composable'
import { useAuth } from './auth'
const apiUrl = process.env.graphqlApi || '/query'
@@ -12,12 +14,12 @@ const httpLink = createHttpLink({
uri: apiUrl
})
const getToken = async (options) => {
const getToken = (options) => {
const { getTokenSilently } = useAuth()
return getTokenSilently.value(options)
return getTokenSilently(options)
}
const authLink = setContext(async (_, { headers }) => {
const authLink = setContext((_, { headers }) => {
return getToken().then((token) => ({
headers: {
...headers,
@@ -42,8 +44,6 @@ const instance = new ApolloClient({
}
})
export default function ({ app }) {
app.setup = () => {
provide(DefaultApolloClient, instance)
}
export default function (_, inject) {
inject('apollo', instance)
}
-138
View File
@@ -1,138 +0,0 @@
import createAuth0Client from '@auth0/auth0-spa-js'
import { reactive, toRefs } from '@vue/composition-api'
/** Define a default action to perform after authentication */
const DEFAULT_REDIRECT_CALLBACK = () =>
window.history.replaceState({}, document.title, window.location.pathname)
let instance
const params = new URL(window.location).searchParams
const domain = params.get('domain') || 'unbound.eu.auth0.com'
// eslint-disable-next-line import/prefer-default-export
export const useAuth = (onRedirectCallback = DEFAULT_REDIRECT_CALLBACK) => {
if (instance) {
return toRefs(instance)
}
const options = {
domain,
client_id: 'orQfnvCPUR5C3mJkKoiWLQHOVQsBn60e',
audience: 'http://dancefinder.unbound.se',
redirect_uri: window.location.origin
}
instance = reactive({
loading: false,
isAuthenticated: false,
user: {},
auth0Client: null,
popupOpen: false,
error: null,
/** Authenticates the user using a popup window */
loginWithPopup: async (o) => {
this.popupOpen = true
try {
await instance.auth0Client.then((client) => client.loginWithPopup(o))
} catch (e) {
// eslint-disable-next-line
console.error(e)
} finally {
instance.popupOpen = false
}
instance.user = await instance.auth0Client.then((client) =>
client.getUser()
)
instance.isAuthenticated = true
},
/** Handles the callback when logging in using a redirect */
handleRedirectCallback: async () => {
instance.loading = true
try {
await instance.auth0Client.then((client) =>
client.handleRedirectCallback()
)
instance.user = await instance.auth0Client.then((client) =>
client.getUser()
)
instance.isAuthenticated = true
} catch (e) {
instance.error = e
} finally {
instance.loading = false
}
},
/** Authenticates the user using the redirect method */
loginWithRedirect: (o) => {
return instance.auth0Client.then((client) => client.loginWithRedirect(o))
},
/** Returns all the claims present in the ID token */
getIdTokenClaims: (o) => {
return instance.auth0Client.then((client) => client.getIdTokenClaims(o))
},
/** Returns the access token. If the token is invalid or missing, a new one is retrieved */
getTokenSilently: (o) => {
return instance.auth0Client.then((client) => {
return client.getTokenSilently(o)
})
},
/** Gets the access token using a popup window */
getTokenWithPopup: (o) => {
return instance.auth0Client.then((client) => client.getTokenWithPopup(o))
},
/** Logs the user out and removes their session on the authorization server */
logout: (o) => {
return instance.auth0Client.then((client) => client.logout(o))
}
})
const fetchUser = () => {
instance.auth0Client
.then((client) => client.isAuthenticated())
.then((a) => {
instance.isAuthenticated = a
instance.auth0Client.then((client) =>
client.getUser().then((u) => {
instance.user = u
instance.loading = false
})
)
})
}
// Create a new instance of the SDK client using members of the given options object
instance.auth0Client = createAuth0Client(options)
instance.auth0Client.then((client) => {
instance.loading = true
try {
// If the user is returning to the app after authentication..
if (
window.location.search.includes('code=') &&
window.location.search.includes('state=')
) {
// handle the redirect and retrieve tokens
client
.handleRedirectCallback()
.then((appState) => {
// Notify subscribers that the redirect callback has happened, passing the appState
// (useful for retrieving any pre-authentication state)
onRedirectCallback(appState)
// Initialize our internal authentication state
fetchUser()
})
// eslint-disable-next-line no-console
.catch((e) => console.error('error handling redirect callback', e))
} else {
fetchUser()
}
} catch (e) {
instance.error = e
} finally {
instance.loading = false
}
})
return toRefs(instance)
}
+139
View File
@@ -0,0 +1,139 @@
import createAuth0Client, {
Auth0Client,
GetIdTokenClaimsOptions,
GetTokenSilentlyOptions,
IdToken,
LogoutOptions,
RedirectLoginOptions,
User
} from '@auth0/auth0-spa-js'
import { Ref, ref } from 'vue'
/** Define a default action to perform after authentication */
const DEFAULT_REDIRECT_CALLBACK = (_: any) =>
window.history.replaceState({}, document.title, window.location.pathname)
interface Client {
loading: Ref<boolean>
isAuthenticated: Ref<boolean>
user: Ref<User | undefined>
auth0Client?: Promise<Auth0Client>
error: Ref
handleRedirectCallback: () => Promise<void>
loginWithRedirect: (o: RedirectLoginOptions) => Promise<void>
getIdTokenClaims: (o: GetIdTokenClaimsOptions) => Promise<void | IdToken | undefined>
getTokenSilently: (o: GetTokenSilentlyOptions) => Promise<string | void>
logout: (o: LogoutOptions) => Promise<void>
}
let instance: Client
const params = (new URL(window.location.href)).searchParams
const domain = params.get('domain') || 'unbound.eu.auth0.com'
export const useAuth = (onRedirectCallback: (appState?: any) => void = DEFAULT_REDIRECT_CALLBACK) => {
if (instance) {
return instance
}
const options = {
domain,
client_id: 'orQfnvCPUR5C3mJkKoiWLQHOVQsBn60e',
audience: 'http://dancefinder.unbound.se',
redirect_uri: window.location.origin
}
instance = {
loading: ref(true),
isAuthenticated: ref(false),
user: ref(undefined),
auth0Client: undefined,
error: ref(null),
/** Handles the callback when logging in using a redirect */
handleRedirectCallback: () => {
instance.loading.value = true
return instance.auth0Client!.then(client => client.handleRedirectCallback())
.then(() => {
return instance.auth0Client?.then(client => client.getUser())
.then((user) => {
instance.user.value = user
instance.isAuthenticated.value = true
instance.error.value = null
}
)
})
.catch((e) => {
instance.error.value = e
})
.finally(() => {
instance.loading.value = false
})
},
/** Authenticates the user using the redirect method */
loginWithRedirect: (o: RedirectLoginOptions) => {
return instance.auth0Client!.then(client => client.loginWithRedirect(o))
.catch((e) => {
instance.error.value = e
})
},
/** Returns all the claims present in the ID token */
getIdTokenClaims: (o: GetIdTokenClaimsOptions) => {
return instance.auth0Client!.then(client => client.getIdTokenClaims(o))
},
/** Returns the access token. If the token is invalid or missing, a new one is retrieved */
getTokenSilently: (o: GetTokenSilentlyOptions) => {
return instance.auth0Client!.then(client => {
return client.getTokenSilently(o).catch(e => {
instance.error.value = e
})
})
},
/** Logs the user out and removes their session on the authorization server */
logout: (o: LogoutOptions) => {
return instance.auth0Client!.then(client => client.logout(o))
}
}
const fetchUser = () => {
return instance.auth0Client!.then(client => client.isAuthenticated())
.then(a => {
instance.auth0Client?.then(client => client.getUser()
.then(u => {
instance.isAuthenticated.value = a
instance.user.value = u
instance.error.value = null
}))
})
}
// Create a new instance of the SDK client using members of the given options object
instance.auth0Client = createAuth0Client(options)
instance.auth0Client
.then(client => {
instance.loading.value = true
// If the user is returning to the app after authentication..
if (
window.location.search.includes('state=') && (
window.location.search.includes('code=') ||
window.location.search.includes('error=')
)
) {
// handle the redirect and retrieve tokens
return client.handleRedirectCallback()
.then(result => {
// Notify subscribers that the redirect callback has happened, passing the appState
// (useful for retrieving any pre-authentication state)
onRedirectCallback(result.appState)
// Initialize our internal authentication state
return fetchUser()
})
} else {
return fetchUser()
}
})
.catch((e) => {
instance.error.value = e
})
.finally(() => {
instance.loading.value = false
})
return instance
}
-4
View File
@@ -1,4 +0,0 @@
import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api'
Vue.use(VueCompositionApi)
+11
View File
@@ -0,0 +1,11 @@
module.exports = {
customSyntax: 'postcss-html',
extends: [
'stylelint-config-standard',
'stylelint-config-recommended-vue',
'stylelint-config-prettier',
],
// add your custom config here
// https://stylelint.io/user-guide/configuration
rules: {},
}
+34
View File
@@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "Node",
"lib": [
"ESNext",
"ESNext.AsyncIterable",
"DOM"
],
"esModuleInterop": true,
"allowJs": true,
"sourceMap": true,
"strict": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"~/*": [
"./*"
],
"@/*": [
"./*"
]
},
"types": [
"@types/node",
"@nuxt/types",
"@nuxtjs/i18n"
]
},
"exclude": [
"node_modules"
]
}
-11
View File
@@ -1,11 +0,0 @@
export { findEvents, findOrigins, fetchAddress, fetchFilters } from './queries'
export {
toggleIgnoreBand,
toggleIgnoreDanceHall,
toggleIgnoreCity,
toggleIgnoreMunicipality,
toggleIgnoreState,
saveOrigin,
removeOrigin
} from './mutations'
-37
View File
@@ -1,37 +0,0 @@
import gql from 'graphql-tag'
export const toggleIgnoreBand = gql`
mutation ToggleIgnoreBand($name: String!) {
ignore: ToggleIgnoreBand(name: $name)
}
`
export const toggleIgnoreDanceHall = gql`
mutation ToggleIgnoreDanceHall($name: String!) {
ignore: ToggleIgnoreDanceHall(name: $name)
}
`
export const toggleIgnoreCity = gql`
mutation ToggleIgnoreCity($name: String!) {
ignore: ToggleIgnoreCity(name: $name)
}
`
export const toggleIgnoreMunicipality = gql`
mutation ToggleIgnoreMunicipality($name: String!) {
ignore: ToggleIgnoreMunicipality(name: $name)
}
`
export const toggleIgnoreState = gql`
mutation ToggleIgnoreState($name: String!) {
ignore: ToggleIgnoreState(name: $name)
}
`
export const saveOrigin = gql`
mutation SaveOrigin($origin: String!) {
saved: SaveOrigin(origin: $origin)
}
`
export const removeOrigin = gql`
mutation RemoveOrigin($origin: String!) {
removed: RemoveOrigin(origin: $origin)
}
`
-48
View File
@@ -1,48 +0,0 @@
import gql from 'graphql-tag'
export const findEvents = gql`
query events($range: Range, $origins: [String!], $includeOrigins: Boolean!) {
events: Events(range: $range, origins: $origins) {
date
time
band {
name
}
danceHall {
name
city
municipality
state
}
extraInfo
distances {
origin
distance
duration
}
}
origins: Origins @include(if: $includeOrigins)
}
`
export const findOrigins = gql`
query origins {
origins: Origins
}
`
export const fetchAddress = gql`
query adressFromLatLng($latlng: String!) {
address: AddressFromLatLng(latlng: $latlng)
}
`
export const fetchFilters = gql`
query {
bands: IgnoredBands
cities: IgnoredCities
states: IgnoredStates
danceHalls: IgnoredDanceHalls
municipalities: IgnoredMunicipalities
}
`
+2506 -436
View File
File diff suppressed because it is too large Load Diff