kopia lustrzana https://github.com/manuelkasper/sotlas-frontend
Merge 3d0da6ca54
into bcd6f95e0c
commit
4b0f4d10bd
|
@ -24,5 +24,5 @@ $link: $blue;
|
|||
@import "~buefy/src/scss/buefy";
|
||||
@import "~flagpack/dist/flagpack.css";
|
||||
@import '~mapbox-gl/dist/mapbox-gl.css';
|
||||
@import '~@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
|
||||
@import '~@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
|
||||
</style>
|
||||
|
|
|
@ -112,6 +112,10 @@ export default {
|
|||
target: '/activators',
|
||||
text: 'Activators'
|
||||
},
|
||||
{
|
||||
target: '/user_data',
|
||||
text: 'User Data'
|
||||
},
|
||||
{
|
||||
target: '/settings',
|
||||
text: 'Settings',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<b-table :class="{ 'auto-width': autoWidth, summits: true }" default-sort="code" :narrowed="true" :striped="true" :data="data" :mobile-cards="false" :row-class="(row, index) => !row.isValid && 'is-invalid'">
|
||||
<b-table :class="{ 'auto-width': autoWidth, summits: true }" default-sort="code" :narrowed="true" :striped="true" :data="data" :mobile-cards="false" :row-class="(row, index) => !row.isValid && !ignoreValidity ? 'is-invalid' : ''">
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="code" label="Code" class="nowrap" sortable>
|
||||
<router-link :to="makeSummitLink(props.row.code)">{{ props.row.code }}</router-link>
|
||||
|
@ -44,7 +44,8 @@ export default {
|
|||
myActivatedSummits: Set,
|
||||
myActivatedSummitsThisYear: Set,
|
||||
myChasedSummits: Set,
|
||||
autoWidth: Boolean
|
||||
autoWidth: Boolean,
|
||||
ignoreValidity: Boolean
|
||||
},
|
||||
mixins: [utils],
|
||||
components: {
|
||||
|
|
|
@ -13,7 +13,7 @@ import { faCheck, faCheckCircle, faInfoCircle, faExclamationTriangle, faExclamat
|
|||
faQuoteRight, faSearch, faMountains, faUser, faClock, faChevronCircleUp, faChevronCircleDown, faChartBar, faFileDownload,
|
||||
faExchange, faGlobe, faCalendarDay, faTrashAlt, faEdit, faClone, faCheckCircle as farCheckCircle, faArrowsH, faArrowsAlt,
|
||||
faSnowflake, faWindowMinimize, faWindowMaximize, faWindowClose, faExpandArrows, faLocation, faCalendarCheck, faComment, faSpinner,
|
||||
faBookUser } from '@fortawesome/pro-regular-svg-icons'
|
||||
faBookUser, faBookmark, faTag } from '@fortawesome/pro-regular-svg-icons'
|
||||
import { faMap, faCheckCircle as fasCheckCircle, faChevronCircleDown as fasChevronCircleDown, faChevronCircleUp as fasChevronCircleUp,
|
||||
faParking, faSquare, faBus, faHiking, faCircle, faCamera, faCameraHome, faVolume, faVolumeMute, faCog, faCaretDown as fasCaretDown,
|
||||
faLocationArrow as fasLocationArrow, faInfoCircle as fasInfoCircle } from '@fortawesome/pro-solid-svg-icons'
|
||||
|
@ -29,7 +29,7 @@ library.add(faCheck, faCheckCircle, faInfoCircle, faExclamationTriangle, faExcla
|
|||
faQuoteRight, faSearch, faMountains, faUser, faClock, faChevronCircleUp, faChevronCircleDown, faMap, faChartBar, faFileDownload,
|
||||
faExchange, faGlobe, faCalendarDay, faTrashAlt, faEdit, faClone, farCheckCircle, faArrowsH, faArrowsAlt,
|
||||
faSnowflake, faWindowMinimize, faWindowMaximize, faWindowClose, faExpandArrows, faLocation, faCalendarCheck, faComment, faSpinner,
|
||||
faBookUser)
|
||||
faBookUser, faBookmark, faTag)
|
||||
library.add(faMap, fasCheckCircle, fasChevronCircleDown, fasChevronCircleUp, faParking, faSquare, faBus, faHiking, faCircle, faCamera,
|
||||
faCameraHome, faVolume, faVolumeMute, faCog, fasCaretDown, fasLocationArrow, fasInfoCircle)
|
||||
library.add(faWikipediaW, faGoogle, faGithub)
|
||||
|
|
|
@ -10,6 +10,27 @@ export default {
|
|||
return response.data
|
||||
})
|
||||
},
|
||||
getPersonalData () {
|
||||
return this.axiosAuth.get('https://api.sotl.as/users/me')
|
||||
},
|
||||
postPersonalSettings (key, value) {
|
||||
return this.axiosAuth.post('https://api.sotl.as/users/me/settings', { [key]: value })
|
||||
},
|
||||
getPersonalSummitData (summitCode) {
|
||||
return this.axiosAuth.get('https://api.sotl.as/users/me/summit/' + summitCode)
|
||||
},
|
||||
postPersonalSummitData (summitCode, isBookmarked, notes, tags) {
|
||||
return this.axiosAuth.post('https://api.sotl.as/users/me/summit/' + summitCode, {
|
||||
isBookmarked: isBookmarked,
|
||||
notes: notes,
|
||||
tags: tags })
|
||||
},
|
||||
getPersonalSummitTags () {
|
||||
return this.axiosAuth.get('https://api.sotl.as/users/me/tags')
|
||||
},
|
||||
getPersonalSummitsFromTag (tagName) {
|
||||
return this.axiosAuth.get('https://api.sotl.as/users/me/summits/tags', { params: { q: tagName } })
|
||||
},
|
||||
uploadPhoto (summitCode, file, progress, cancelToken) {
|
||||
let formData = new FormData()
|
||||
formData.append('photo', file)
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import api from '@/mixins/api'
|
||||
import utils from '@/mixins/utils'
|
||||
|
||||
export default {
|
||||
mixins: [api, utils],
|
||||
mounted () {
|
||||
if (this.$options.prefs) {
|
||||
this.loadPrefs()
|
||||
|
@ -27,7 +31,7 @@ export default {
|
|||
})
|
||||
this.setPrefs(this.$options.prefs.key, prefs)
|
||||
},
|
||||
getPrefs (key) {
|
||||
getPrefsFromLocalStorage (key) {
|
||||
if (localStorage.getItem(key)) {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(key))
|
||||
|
@ -37,8 +41,29 @@ export default {
|
|||
}
|
||||
return undefined
|
||||
},
|
||||
setPrefs (key, prefs) {
|
||||
getPrefs (key) {
|
||||
if (!this.authenticated) {
|
||||
return this.getPrefsFromLocalStorage(key)
|
||||
}
|
||||
|
||||
this.getPersonalData().then(response => {
|
||||
if (response[key]) {
|
||||
this.setPrefsToLocalStorage(key, response[key])
|
||||
return JSON.parse(response[key])
|
||||
}
|
||||
return this.getPrefsFromLocalStorage(key)
|
||||
}).catch(() => {
|
||||
return this.getPrefsFromLocalStorage(key)
|
||||
})
|
||||
},
|
||||
setPrefsToLocalStorage (key, prefs) {
|
||||
localStorage.setItem(key, JSON.stringify(prefs))
|
||||
},
|
||||
setPrefs (key, prefs) {
|
||||
if (this.authenticated) {
|
||||
this.postPersonalSettings(key, prefs)
|
||||
}
|
||||
this.setPrefsToLocalStorage(key, prefs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,6 +240,40 @@ export default {
|
|||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
},
|
||||
activationsMapBounds (summitList) {
|
||||
let minLat, minLon, maxLat, maxLon
|
||||
summitList.forEach(summitObj => {
|
||||
if (!minLat || summitObj.summit.coordinates.latitude < minLat) {
|
||||
minLat = summitObj.summit.coordinates.latitude
|
||||
}
|
||||
if (!maxLat || summitObj.summit.coordinates.latitude > maxLat) {
|
||||
maxLat = summitObj.summit.coordinates.latitude
|
||||
}
|
||||
if (!minLon || summitObj.summit.coordinates.longitude < minLon) {
|
||||
minLon = summitObj.summit.coordinates.longitude
|
||||
}
|
||||
if (!maxLon || summitObj.summit.coordinates.longitude > maxLon) {
|
||||
maxLon = summitObj.summit.coordinates.longitude
|
||||
}
|
||||
})
|
||||
|
||||
// Some padding
|
||||
let latDiff = maxLat - minLat
|
||||
let lonDiff = maxLon - minLon
|
||||
minLat -= (latDiff * 0.1)
|
||||
maxLat += (latDiff * 0.1)
|
||||
minLon -= (lonDiff * 0.1)
|
||||
maxLon += (lonDiff * 0.1)
|
||||
|
||||
return [[minLon, minLat], [maxLon, maxLat]]
|
||||
},
|
||||
activationsMapFilter (summitList) {
|
||||
let summits = new Set()
|
||||
summitList.forEach(activation => {
|
||||
summits.add(activation.summit.code)
|
||||
})
|
||||
return ['in', 'code', ...summits]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import NotFound from './views/NotFound.vue'
|
|||
import SearchAnything from './views/SearchAnything.vue'
|
||||
import Activator from './views/Activator.vue'
|
||||
import Activators from './views/Activators.vue'
|
||||
import UserData from './views/UserData.vue'
|
||||
import Summit from './views/Summit.vue'
|
||||
import Activation from './views/Activation.vue'
|
||||
import Spots from './views/Spots.vue'
|
||||
|
@ -142,6 +143,11 @@ let router = new Router({
|
|||
return '/activators/' + to.params.callsign.toUpperCase()
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/user_data/',
|
||||
component: UserData,
|
||||
meta: { savePath: null }
|
||||
},
|
||||
{
|
||||
path: '/spots',
|
||||
component: Spots,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<template>
|
||||
<section v-if="summits !== null && summits.length > 0" class="section">
|
||||
<div class="container">
|
||||
<h4 class="title is-4"><b-icon icon="mountains" />Summits</h4>
|
||||
<h4 class="title is-4"><b-icon icon="mountains" />Summits<span v-if="tagSearch"> tagged with <font-awesome-icon :icon="['far', 'tag']" class="faicon" /> {{ this.tagSearch }}</span></h4>
|
||||
<b-field v-if="inactiveCount > 0" grouped>
|
||||
<b-switch v-model="showInactive">Show inactive ({{ inactiveCount }})</b-switch>
|
||||
</b-field>
|
||||
|
@ -50,10 +50,28 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<section v-if="userTags !== null && userTags.length > 0" class="section">
|
||||
<div class="container">
|
||||
<h4 class="title is-4"><b-icon icon="tag" />User Tags</h4>
|
||||
|
||||
<b-table class="auto-width" default-sort="tag" :narrowed="true" :striped="true" :data="userTags" :mobile-cards="false">
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="tag" label="User Tag" class="nowrap" sortable>
|
||||
<font-awesome-icon :icon="['far', 'tag']" class="faicon" />
|
||||
<router-link :to="'/search?q=@' + encodeURIComponent(props.row.tag)">{{ props.row.tag }}</router-link>
|
||||
</b-table-column>
|
||||
<b-table-column field="count" :label="Count" numeric sortable>
|
||||
{{ props.row.count }}
|
||||
</b-table-column>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<b-message v-if="activators !== null && activators.length === 0 && summits !== null && summits.length === 0" type="is-info" has-icon>
|
||||
No matching summits or activators for '{{ $route.query.q }}' found.
|
||||
<b-message v-if="activators !== null && activators.length === 0 && summits !== null && summits.length === 0 && userTags !== null && userTags.length === 0" type="is-info" has-icon>
|
||||
No matching summits, activators or user tags for '{{ $route.query.q }}' found.
|
||||
</b-message>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -68,16 +86,51 @@ import utils from '../mixins/utils.js'
|
|||
|
||||
import PageLayout from '../components/PageLayout.vue'
|
||||
import SummitList from '../components/SummitList.vue'
|
||||
import api from '@/mixins/api'
|
||||
|
||||
export default {
|
||||
name: 'SearchAnything',
|
||||
components: { PageLayout, SummitList },
|
||||
mixins: [utils],
|
||||
mixins: [utils, api],
|
||||
methods: {
|
||||
doSearch () {
|
||||
let loads = []
|
||||
let q = this.$route.query.q.trim()
|
||||
this.loadingComponent = this.$buefy.loading.open({ canCancel: true })
|
||||
|
||||
if (q.startsWith('@') && this.authenticated) {
|
||||
this.tagSearch = q.substring(1)
|
||||
loads.push(this.getPersonalSummitsFromTag(this.tagSearch)
|
||||
.then(response => {
|
||||
response.data.forEach(summit => {
|
||||
summit.isValid = true
|
||||
})
|
||||
this.summits = response.data
|
||||
return this.loadingComponent.close()
|
||||
}))
|
||||
} else {
|
||||
this.tagSearch = null
|
||||
loads.push(axios.get('https://api.sotl.as/summits/search', { params: { q, limit: this.limit } })
|
||||
.then(response => {
|
||||
let now = moment()
|
||||
response.data.forEach(summit => {
|
||||
summit.isValid = (moment(summit.validFrom).isBefore(now) && moment(summit.validTo).isAfter(now))
|
||||
})
|
||||
this.summits = response.data
|
||||
}))
|
||||
}
|
||||
|
||||
if (this.authenticated) {
|
||||
loads.push(this.getPersonalSummitTags()
|
||||
.then(response => {
|
||||
this.userTags = response.data.filter(tag => {
|
||||
return tag.tag.toLowerCase().includes(q.toLowerCase())
|
||||
})
|
||||
}))
|
||||
} else {
|
||||
this.userTags = []
|
||||
}
|
||||
|
||||
loads.push(axios.get(process.env.VUE_APP_API_URL + '/activators/search', { params: { q, limit: this.limit } })
|
||||
.then(response => {
|
||||
this.activators = response.data.activators
|
||||
|
@ -138,6 +191,8 @@ export default {
|
|||
activators: null,
|
||||
limit: 100,
|
||||
summits: null,
|
||||
userTags: null,
|
||||
tagSearch: null,
|
||||
showInactive: false
|
||||
}
|
||||
}
|
||||
|
@ -173,4 +228,12 @@ export default {
|
|||
.message.is-warning {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.faicon {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
.title .faicon {
|
||||
opacity: 0.5;
|
||||
margin-left: 0.3em;
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,6 +4,14 @@
|
|||
<h1 class="title is-size-1 is-size-3-mobile">
|
||||
{{ summit.name }}
|
||||
|
||||
<div class="action-button">
|
||||
<b-field>
|
||||
<p class="control">
|
||||
<b-button :type="bookmarkButtonType" size="is-small" icon-left="bookmark" :outlined="!isBookmarkedActive" @click="toggleBookmark()" :disabled="!authenticated">Bookmark</b-button>
|
||||
</p>
|
||||
</b-field>
|
||||
</div>
|
||||
|
||||
<div class="action-button">
|
||||
<b-field>
|
||||
<p class="control">
|
||||
|
@ -61,13 +69,27 @@
|
|||
|
||||
<SummitAttributes :attributes="summit.attributes" />
|
||||
|
||||
<div v-if="authenticated">
|
||||
<h6 class="title is-6">Tags</h6>
|
||||
<div class="taginput-wrapper">
|
||||
<b-taginput v-model="summitTags" ref="summitTagsInput" autocomplete open-on-focus allow-new :data="filteredSummitTagsExisting" :confirm-key-codes="[9,13,32,188]" @typing="getFilteredSummitTags" @input="onSummitTagsInput" @blur="onSummitTagsInputBlur" rounded />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="resources.length > 0">
|
||||
<h6 class="title is-6">Resources</h6>
|
||||
<ResourceList :resources="resources" />
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="column">
|
||||
<MiniMap :class="{ map: true, enlarge: enlargeMap }" :summit="summit" :routes="routes" :canEnlarge="true" :isEnlarged="enlargeMap" :showInactiveSummits="!isValid" ref="map" @enlarge="toggleEnlargeMap" @photoClicked="photoClicked" />
|
||||
<div v-if="authenticated">
|
||||
<h6 class="title is-6">Notes</h6>
|
||||
<div>
|
||||
<b-input type="textarea" class="summit-notes" id="textarea-summit-notes" v-model="summitNotes" v-debounce:1s="savePersonalSummitData" placeholder="Your personal summit notes" size="is-small" rows="3"></b-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -99,7 +121,7 @@
|
|||
<h4 class="title is-4">Photos</h4>
|
||||
<SummitPhotos ref="summitPhotos" :summit="summit" :editable="true" :showWaypointButton="true" @photoDeleted="reloadPhotos" @photoEdited="reloadPhotos" @photosReordered="reloadPhotos" />
|
||||
|
||||
<PhotosUploader v-if="$keycloak && $keycloak.authenticated" :summitCode="summitCode" @upload="reloadPhotos" />
|
||||
<PhotosUploader v-if="authenticated" :summitCode="summitCode" @upload="reloadPhotos" />
|
||||
<div v-else class="uploader-placeholder box"><font-awesome-icon :icon="['far', 'images']" size="lg" /> Log in and upload your photos of this summit!</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -150,6 +172,7 @@ import HikrIcon from '../assets/hikr.png'
|
|||
import SACIcon from '../assets/sac.png'
|
||||
import SotatrailsIcon from '../assets/sotatrails.png'
|
||||
import EventBus from '../event-bus'
|
||||
import api from '../mixins/api.js'
|
||||
|
||||
export default {
|
||||
name: 'Summit',
|
||||
|
@ -159,7 +182,7 @@ export default {
|
|||
components: {
|
||||
SummitDatabasePageLayout, MiniMap, SummitActivations, SummitAttributes, ResourceList, SummitRoutes, SummitPhotos, SummitVideos, PhotosUploader, Coordinates, Bearing, SummitPointsLabel, AltitudeLabel, SpotsList, AlertsList, EditAlert, EditSpot
|
||||
},
|
||||
mixins: [utils, smptracks, coverphoto],
|
||||
mixins: [api, utils, smptracks, coverphoto],
|
||||
computed: {
|
||||
locator () {
|
||||
if (!this.summit.coordinates) {
|
||||
|
@ -309,6 +332,9 @@ export default {
|
|||
}
|
||||
})
|
||||
return videos
|
||||
},
|
||||
bookmarkButtonType () {
|
||||
return (this.isBookmarkedActive ? 'is-success' : 'is-info')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -386,6 +412,21 @@ export default {
|
|||
.then(response => {
|
||||
this.myChases = response.data
|
||||
}))
|
||||
|
||||
loads.push(this.getPersonalSummitData(this.summitCode)
|
||||
.then(response => {
|
||||
this.isBookmarkedActive = response.data.isBookmarked ? response.data.isBookmarked : false
|
||||
this.summitNotes = response.data.notes ? response.data.notes : ''
|
||||
this.summitTags = response.data.tags ? response.data.tags : []
|
||||
}))
|
||||
|
||||
loads.push(this.getPersonalSummitTags()
|
||||
.then(response => {
|
||||
this.summitTagsExisting = response.data.map(item => {
|
||||
return item.tag
|
||||
})
|
||||
this.filteredSummitTagsExisting = this.summitTagsExisting
|
||||
}))
|
||||
}
|
||||
|
||||
Promise.all(loads)
|
||||
|
@ -407,6 +448,20 @@ export default {
|
|||
this.loadingComponent.close()
|
||||
})
|
||||
},
|
||||
savePersonalSummitData () {
|
||||
this.postPersonalSummitData(
|
||||
this.summitCode,
|
||||
this.isBookmarkedActive,
|
||||
this.summitNotes,
|
||||
this.summitTags
|
||||
).catch(error => {
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
toggleBookmark () {
|
||||
this.isBookmarkedActive = !this.isBookmarkedActive
|
||||
this.savePersonalSummitData()
|
||||
},
|
||||
addAlert () {
|
||||
this.isAddAlertActive = true
|
||||
},
|
||||
|
@ -445,6 +500,31 @@ export default {
|
|||
},
|
||||
navbarMenuOpened () {
|
||||
this.enlargeMap = false
|
||||
},
|
||||
getFilteredSummitTags (input) {
|
||||
this.filteredSummitTagsExisting = this.summitTagsExisting
|
||||
.filter(element => {
|
||||
return !this.summitTags.includes(element)
|
||||
})
|
||||
.filter(element => {
|
||||
return element
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.indexOf(input.toLowerCase()) >= 0
|
||||
})
|
||||
},
|
||||
onSummitTagsInput () {
|
||||
this.filteredSummitTagsExisting = this.summitTagsExisting
|
||||
.filter(element => {
|
||||
return !this.summitTags.includes(element)
|
||||
})
|
||||
this.savePersonalSummitData()
|
||||
},
|
||||
onSummitTagsInputBlur () {
|
||||
// Delay to avoid double entry when clicking a tag suggestion
|
||||
setTimeout(() => {
|
||||
this.$refs.summitTagsInput.addTag()
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
|
@ -457,7 +537,12 @@ export default {
|
|||
isAddAlertActive: false,
|
||||
isAddSpotActive: false,
|
||||
enlargeMap: false,
|
||||
alwaysLoadWikipedia: true
|
||||
alwaysLoadWikipedia: true,
|
||||
isBookmarkedActive: false,
|
||||
summitNotes: null,
|
||||
summitTags: [],
|
||||
summitTagsExisting: [],
|
||||
filteredSummitTagsExisting: this.summitTagsExisting
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -510,6 +595,7 @@ export default {
|
|||
margin-right: 0.1em;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
>>> .coordinates {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -585,4 +671,10 @@ export default {
|
|||
.uploader-placeholder .fa-images {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
.taginput-wrapper, .summit-notes {
|
||||
margin-top: 0.7em;
|
||||
}
|
||||
.summit-notes textarea {
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<template>
|
||||
<PageLayout>
|
||||
<template v-slot:title>
|
||||
<h1 class="title is-size-1 is-size-3-mobile">
|
||||
My User Data
|
||||
</h1>
|
||||
</template>
|
||||
|
||||
<div v-if="userSummits && userSummits.length > 0">
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h4 class="title is-4"><span>Summit Bookmarks</span></h4>
|
||||
<b-field>
|
||||
<FilterInput v-model="filterString" ref="filter" :is-regex="true" />
|
||||
</b-field>
|
||||
<template v-if="filteredBookmarks && filteredBookmarks.length > 0">
|
||||
<SummitList :data="filteredBookmarks" auto-width ignore-validity />
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h4 class="title is-4"><span>User Tags</span></h4>
|
||||
|
||||
<template v-if="userTags && userTags.length > 0">
|
||||
<b-table class="auto-width" default-sort="tag" :narrowed="true" :striped="true" :data="userTags" :mobile-cards="false">
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="tag" label="User Tag" class="nowrap" sortable>
|
||||
<font-awesome-icon :icon="['far', 'tag']" class="faicon" />
|
||||
<router-link :to="'/search?q=@' + encodeURIComponent(props.row.tag)">{{ props.row.tag }}</router-link>
|
||||
</b-table-column>
|
||||
<b-table-column field="count" :label="Count" numeric sortable>
|
||||
{{ props.row.count }}
|
||||
</b-table-column>
|
||||
</template>
|
||||
</b-table>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div v-else-if="!authenticated">
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<b-message type="is-info" has-icon>
|
||||
Log in to view your summits and tags.
|
||||
</b-message>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div v-else>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<b-message type="is-info" has-icon>
|
||||
No bookmarks or tags set, yet.
|
||||
</b-message>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PageLayout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FilterInput from '../components/FilterInput.vue'
|
||||
import SummitList from '../components/SummitList.vue'
|
||||
import PageLayout from '@/components/PageLayout'
|
||||
import utils from '@/mixins/utils'
|
||||
import api from '@/mixins/api'
|
||||
|
||||
export default {
|
||||
name: 'BookmarkList',
|
||||
components: {
|
||||
PageLayout, FilterInput, SummitList
|
||||
},
|
||||
mixins: [api, utils],
|
||||
mounted () {
|
||||
document.title = 'My User Data - SOTLAS'
|
||||
this.loadingComponent = this.$buefy.loading.open({ canCancel: true })
|
||||
|
||||
let loads = []
|
||||
loads.push(this.getPersonalData().then(response => {
|
||||
this.userSummits = response.data.userSummits
|
||||
}))
|
||||
loads.push(this.getPersonalSummitTags().then(response => {
|
||||
this.userTags = response.data
|
||||
}))
|
||||
|
||||
Promise.all(loads)
|
||||
.finally(() => {
|
||||
this.loadingComponent.close()
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
filteredBookmarks () {
|
||||
return this.userSummits.filter(userSummit => {
|
||||
if (!userSummit.isBookmarked) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (this.filterString) {
|
||||
return userSummit.summit.code.includes(this.filterString.toUpperCase()) || userSummit.summit.name.toLowerCase().includes(this.filterString.toLowerCase())
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}).map(userSummit => {
|
||||
return userSummit.summit
|
||||
})
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
userSummits: [],
|
||||
showMap: false,
|
||||
filterString: '',
|
||||
userTags: []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.faicon {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
</style>
|
Ładowanie…
Reference in New Issue