prerelease2

MarketplaceItem, Marketplace, Pagination, Update modal popup for new releases
This commit is contained in:
Troplo 2021-01-21 19:02:20 +11:00
parent 4a173a4474
commit 51ac44116a
15 changed files with 550 additions and 38 deletions

View file

@ -15,6 +15,7 @@
"core-js": "^3.6.5", "core-js": "^3.6.5",
"crypto-random-string": "^3.3.0", "crypto-random-string": "^3.3.0",
"dotenv-webpack": "^6.0.0", "dotenv-webpack": "^6.0.0",
"lodash.throttle": "^4.1.1",
"socket.io": "^3.1.0", "socket.io": "^3.1.0",
"to-boolean": "^1.0.0", "to-boolean": "^1.0.0",
"v-offline": "^1.3.0", "v-offline": "^1.3.0",
@ -22,6 +23,7 @@
"vue-axios": "^3.2.2", "vue-axios": "^3.2.2",
"vue-i18n": "^8.17.3", "vue-i18n": "^8.17.3",
"vue-keypress": "^2.1.1", "vue-keypress": "^2.1.1",
"vue-matomo": "^3.14.0-0",
"vue-router": "^3.2.0", "vue-router": "^3.2.0",
"vue-socket.io": "^3.0.10", "vue-socket.io": "^3.0.10",
"vuex": "^3.4.0" "vuex": "^3.4.0"

View file

@ -13,7 +13,6 @@
<div id="router content-wrapper"> <div id="router content-wrapper">
<router-view/> <router-view/>
</div> </div>
<br>
<div id="footer"> <div id="footer">
<Footer/> <Footer/>
</div> </div>
@ -30,6 +29,11 @@ export default {
Footer Footer
}, },
mounted() { mounted() {
if(JSON.parse(
localStorage.getItem('token'))) {
this.$store.commit('setToken', JSON.parse(
localStorage.getItem('token')))
}
if(JSON.parse( if(JSON.parse(
localStorage.getItem('wind404'))) { localStorage.getItem('wind404'))) {
var wind = JSON.parse( var wind = JSON.parse(

View file

@ -142,6 +142,34 @@
</div> </div>
</form> </form>
</b-modal> </b-modal>
<b-modal :active="updateModal" @update:active="value => updateModal = value" :width="640" scroll="keep">
<form>
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">{{$t('update.title')}}</p>
<button
type="button"
class="delete"
@click="registerModal = false"/>
</header>
<section class="modal-card-body has-text-centered">
<h1 class="subtitle">What's new in {{$store.state.client.clientVersion}}?</h1>
<ul>
<li>Marketplace</li>
<li>Pagination Component</li>
<li>Fix crashing when token is null</li>
<li>User list pagination</li>
<li>Marketplace Item</li>
</ul>
</section>
<footer class="modal-card-foot">
<b-button
:label="$t('close')"
@click="updateDismissed" />
</footer>
</div>
</form>
</b-modal>
<b-modal :active="registerModal" @update:active="value => registerModal = value" :width="640" scroll="keep"> <b-modal :active="registerModal" @update:active="value => registerModal = value" :width="640" scroll="keep">
<form> <form>
<div class="modal-card" style="width: auto"> <div class="modal-card" style="width: auto">
@ -354,6 +382,7 @@ export default {
showBanner: true, showBanner: true,
showOutdatedBanner: true, showOutdatedBanner: true,
friendCount: 0, friendCount: 0,
updateModal: false,
settings: { settings: {
tab: 0, tab: 0,
general: { general: {
@ -513,6 +542,17 @@ export default {
this.showBanner = true this.showBanner = true
} }
}, },
updateDismissed() {
localStorage.setItem("update-" + this.$store.state.client.clientVersion, true)
this.updateModal = false
},
showUpdate() {
if(!localStorage.getItem("update-" + this.$store.state.client.clientVersion)) {
this.updateModal = true
} else {
this.updateModal = false
}
},
removeBannerId() { removeBannerId() {
localStorage.setItem(this.$store.state.client.bannerId, true) localStorage.setItem(this.$store.state.client.bannerId, true)
this.$store.state.client.bannerEnabled = false this.$store.state.client.bannerEnabled = false
@ -699,6 +739,7 @@ export default {
this.loading = false this.loading = false
}) })
} }
this.showUpdate()
} }
} }
</script> </script>

View file

@ -0,0 +1,66 @@
<template>
<div class='pagination'>
<slot></slot>
</div>
</template>
<script>
import throttle from 'lodash.throttle'
export default {
name: 'Pagination',
props: ['loading', 'query-selector', 'padding-bottom', 'padding-top', 'paginate'],
computed: {
element () {
if(this.querySelector){
return document.querySelector(this.querySelector);
} else {
return null;
}
}
},
methods: {
onScroll: throttle(function () {
let paddingBottom = this.paddingBottom || 300;
let paddingTop = this.paddingTop || 150;
let scrollBottom, scrollTop;
//If already loading then do not fire
if(this.loading) return;
if(this.element) {
scrollBottom = Math.floor(
this.element.scrollTop +
this.element.getBoundingClientRect().height +
paddingBottom -
this.element.scrollHeight
);
scrollTop = paddingTop - this.element.scrollTop;
} else {
scrollBottom =
window.innerHeight + window.pageYOffset +
paddingBottom -
document.body.scrollHeight;
scrollTop = paddingTop - document.body.scrollTop;
}
if(scrollBottom > 0) {
if(this.paginate) {
this.$emit('loadNext');
}
} else if(scrollTop > 0) {
this.$emit('loadPrevious');
}
})
},
mounted () {
(this.element || window).addEventListener('scroll', this.onScroll);
},
destroyed () {
(this.element || window).removeEventListener('scroll', this.onScroll);
}
}
</script>

View file

@ -175,7 +175,8 @@
"relationships": { "relationships": {
"pending": "Cancel Friend Request", "pending": "Cancel Friend Request",
"notFriends": "Send Friend Request", "notFriends": "Send Friend Request",
"pendingCanAccept": "Accept Friend Request" "pendingCanAccept": "Accept Friend Request",
"accepted": "Remove friend"
}, },
"modifyUser": { "modifyUser": {
"title": "Modify User", "title": "Modify User",
@ -266,6 +267,25 @@
"soon": "(SOON)" "soon": "(SOON)"
} }
}, },
"marketplace": {
"hats": "Hats",
"faces": "Faces",
"shirts": "Shirts",
"pants": "Pants",
"collections": "Collections",
"moreInfo": "More info",
"filter": "Filters",
"search": "Search the Marketplace"
},
"update": {
"title": "Changelog for new update"
},
"marketplaceItem": {
"moreInfo": "Information and Stats",
"price": "Price",
"originalPrice": "Original Price",
"creator": "The Creator"
},
"currency": "Koins", "currency": "Koins",
"close": "Close", "close": "Close",
"tos": "Terms of Service", "tos": "Terms of Service",

View file

@ -6,10 +6,16 @@ import Buefy, {Snackbar} from 'buefy'
import axios from 'axios' import axios from 'axios'
import VueAxios from 'vue-axios' import VueAxios from 'vue-axios'
import i18n from './i18n' import i18n from './i18n'
import moment from 'moment'
Vue.use(VueAxios, axios) Vue.use(VueAxios, axios)
Vue.use(Buefy) Vue.use(Buefy)
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$snackbar = Snackbar Vue.prototype.$snackbar = Snackbar
Vue.filter('formatDate', function(value) {
if (value) {
return moment(String(value)).format('hh:mm A, DD/MM/YYYY')
}
})
new Vue({ new Vue({
router, router,
store, store,

View file

@ -77,6 +77,22 @@ const routes = [
name: 'Roadmap', name: 'Roadmap',
component: route('Roadmap') component: route('Roadmap')
}, },
{
path: '/marketplace/',
redirect: '/marketplace/HATS',
name: 'Marketplace',
component: route('Marketplace')
},
{
path: '/marketplace/:category',
name: 'Marketplace',
component: route('Marketplace')
},
{
path: '/m/:id',
name: 'MarketplaceItem',
component: route('MarketplaceItem')
},
{ {
path: '/stats', path: '/stats',
name: 'Stats', name: 'Stats',

View file

@ -2,21 +2,13 @@ import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import tb from 'to-boolean'; import tb from 'to-boolean';
Vue.use(Vuex) Vue.use(Vuex)
if(JSON.parse(
localStorage.getItem('token'))) {
var token = JSON.parse(
localStorage.getItem('token'))
} else {
// eslint-disable-next-line no-redeclare
var token = ''
}
export default new Vuex.Store({ export default new Vuex.Store({
state: { state: {
debug: tb(process.env.VUE_APP_STAGING), debug: tb(process.env.VUE_APP_STAGING),
wind: false, wind: false,
enableBrokenRoutes: false, enableBrokenRoutes: false,
client: { client: {
clientVersion: '1.0.0-prerelease', clientVersion: '1.0.0-prerelease2',
latestClientVersion: '', latestClientVersion: '',
latestAPIVersion: '', latestAPIVersion: '',
bannerText: '', bannerText: '',
@ -48,7 +40,7 @@ export default new Vuex.Store({
avatar: 'default', avatar: 'default',
bot: '', bot: '',
system: '', system: '',
token: token, token: '',
koins: 0, koins: 0,
emailVerified: false, emailVerified: false,
modeler: false, modeler: false,

View file

@ -54,7 +54,7 @@
</p> </p>
</div> </div>
<div class="media-left"> <div class="media-left">
Created At: {{thread.createdAt}} Created At: {{thread.createdAt | formatDate()}}
</div> </div>
</div> </div>
</article> </article>
@ -120,7 +120,6 @@ export default {
}, },
$route () { $route () {
this.selectedCategory = this.$route.path.split('/')[2].toUpperCase() this.selectedCategory = this.$route.path.split('/')[2].toUpperCase()
this.newThreads = 0
this.getThreads(true) this.getThreads(true)
} }
}, },

View file

@ -1,5 +1,220 @@
<template> <template>
<main> <main class="section">
<div class="column" style="float: left;">
<nav class="panel">
<p class="panel-heading">
{{ $t('marketplace.filter') }} ({{category}})
</p>
<div class="panel-block">
<p class="control has-icons-left">
<b-input v-model="search" type="text" :placeholder="$t('marketplace.search')"></b-input>
<span class="icon is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</p>
</div>
<div class="tabs">
<ul>
<router-link tag="li" :to="'/marketplace/hats'" exact><a>{{ $t('marketplace.hats') }}</a></router-link>
<router-link tag="li" :to="'/marketplace/faces'" exact><a>{{ $t('marketplace.faces') }}</a></router-link>
<router-link tag="li" :to="'/marketplace/shirts'" exact><a>{{ $t('marketplace.shirts') }}</a></router-link>
<router-link tag="li" :to="'/marketplace/pants'" exact><a>{{ $t('marketplace.pants') }}</a></router-link>
<router-link tag="li" :to="'/marketplace/collections'" exact><a>{{ $t('marketplace.collections') }}</a></router-link>
</ul>
</div>
<a class="panel-block">
Recent
</a>
<a class="panel-block">
Most popular
</a>
</nav>
</div>
<div class="columns is-multiline" v-if="!loading">
<div v-if="!items.length" class="column">
<NoItems type="marketplace items">
</NoItems>
</div>
<Pagination
class='columns is-multiline'
v-if='items.length'
:loading='loading'
:paginate="paginate"
@loadNext='getItems(false)'
>
<div class="column is-3" style="float: left;" v-for='(item) in items' :key='"marketplace-" + item.id'>
<router-link :to="'/m/' + item.id" class="subtitle">{{item.name}}</router-link>
<div class="box">
<img :src="'https://cdn.kaverti.com/marketplace/avatars/' + item.previewFile + '.png'" width="40%">
<div class="buttons is-centered is-center">
<b-button class="is-info" v-if="!item.saleEnabled">{{$t('user.inventoryTab.buyNow')}} <img style="vertical-align: middle" src="https://cdn.kaverti.com/icons/koins-white.svg" width="8%">{{item.price}}</b-button>
<b-button class="is-success" v-if="item.saleEnabled">{{$t('user.inventoryTab.buyNow')}} <img style="vertical-align: middle" src="https://cdn.kaverti.com/icons/koins-white.svg" width="12%">{{item.salePrice}} <b-tooltip class="is-success" :label="$t('user.inventoryTab.onSale')"><i class="fas fa-info-circle"></i></b-tooltip></b-button>
<b-button tag="router-link" :to="'/m/' + item.id" class="is-success">{{$t('marketplace.moreInfo')}}</b-button>
</div>
</div>
</div>
</Pagination>
</div>
<div class="columns is-multiline" v-if="loading">
<div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div>
<div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div> <div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div>
<div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div>
<div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div> <div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div> <div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div> <div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div>
<div class="column is-4">
<div class="box">
<h1 class="title">
<b-skeleton></b-skeleton>
</h1>
<b-skeleton height="100px"></b-skeleton>
</div>
</div>
</div>
<br>
<br>
<br>
<br>
<br>
<br>
</main> </main>
</template> </template>
<script>
import AjaxErrorHandler from "../../assets/js/errorHandler";
import NoItems from "../components/NoItems"
import Pagination from "../components/Pagination"
export default {
name: 'Marketplace',
components: {
NoItems,
Pagination
},
data() {
return {
items: [],
last: [],
search: '',
limit: 30,
loading: true,
paginate: true,
offset: 0,
nextURL: null,
category: this.$route.params.category
}
},
methods: {
doSearch() {
this.items = []
this.loading = true
this.offset = 0
this.paginate = true
this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'marketplace/' + this.category + '?search=' + this.search + '&offset=' + this.offset)
.then(res => {
this.items = res.data.Items
this.loading = false
})
.catch((e) => {
this.loading = false
AjaxErrorHandler(this.$store)(e)
})
},
getItems (initial) {
this.loading = true
this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'marketplace/' + this.category + '?offset=' + this.offset)
.then(res => {
if(res.data.length < this.limit) {
this.offset = null;
} else {
this.offset+= this.limit;
}
if(!initial && !res.data.Items.length) {
this.paginate = false
}
if(initial) {
this.items = res.data.Items
} else {
this.items.push(...res.data.Items)
this.last = []
this.last = res.data.Items
}
this.loading = false
})
.catch((e) => {
this.loading = false
AjaxErrorHandler(this.$store)(e)
})
},
},
watch: {
search () {
this.doSearch()
},
$route () {
this.items = []
this.offset = 0
this.paginate = true
this.category = this.$route.params.category
this.getItems(true)
}
},
mounted() {
this.getItems(true)
}
}
</script>

View file

@ -0,0 +1,111 @@
<template>
<main>
<div class="section">
<div class="columns" v-if="loading">
<div class="column is-4">
<h1 class="title has-text-centered"><b-skeleton></b-skeleton></h1>
<div class="box">
<b-skeleton></b-skeleton>
</div>
</div>
<div class="column is-7">
<h1 class="title has-text-centered"><b-skeleton></b-skeleton></h1>
<div class="box has-text-right">
<b-skeleton></b-skeleton>
<b-skeleton></b-skeleton>
<b-skeleton></b-skeleton>
</div>
<h1 class="title has-text-centered"><b-skeleton></b-skeleton></h1>
<div class="card">
<div class="card-content">
<div class="content">
<b-skeleton></b-skeleton>
<b-skeleton></b-skeleton>
<b-skeleton></b-skeleton>
<b-skeleton></b-skeleton>
</div>
</div>
</div>
</div>
</div>
<div class="columns" v-if="!loading">
<div class="column is-4">
<h1 class="title has-text-centered">{{item.name}}</h1>
<div class="box">
<img :src="'https://cdn.kaverti.com/marketplace/avatars/' + item.previewFile + '.png'">
</div>
</div>
<div class="column is-7">
<h1 class="title has-text-centered">{{$t('marketplaceItem.moreInfo')}}</h1>
<div class="box has-text-right">
<b-button class="is-info" v-if="!item.saleEnabled && !purchased">Buy now</b-button>
<b-button class="is-success" v-if="item.saleEnabled && !purchased">Buy now for discounted price</b-button>
<b-button disabled v-if="purchased">You own this item!</b-button>
<hr class="solid">
<p v-if="item.saleEnabled">{{$t('marketplaceItem.price')}}: <img style="vertical-align: middle" src="https://cdn.kaverti.com/icons/koins.svg" width="5%">{{item.salePrice}}</p>
<p v-if="item.saleEnabled">{{$t('marketplaceItem.originalPrice')}}: <img style="vertical-align: middle" src="https://cdn.kaverti.com/icons/koins.svg" width="5%">{{item.price}}</p>
<p v-if="!item.saleEnabled">{{$t('marketplaceItem.price')}}: <img style="vertical-align: middle" src="https://cdn.kaverti.com/icons/koins.svg" width="5%">{{item.price}}</p>
<p>Uploaded at: {{item.createdAt | formatDate()}}</p>
</div>
<h1 class="title has-text-centered">{{$t('marketplaceItem.creator')}}</h1>
<div class="card">
<div class="card-content">
<div class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src="'https://cdn.kaverti.com/user/avatars/headshot/default.png'" alt="Avatar Image">
</figure>
</div>
<div class="media-content">
<router-link :to="'/u/' + item.User.username" class="title">{{item.User.username}}</router-link>
</div>
</div>
<div class="content" v-if="item.User.description">
{{item.User.description}}
</div>
<div class="content" v-if="!item.User.description">
{{$t('user.defaultDesc')}} {{item.User.username}}
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</template>
<script>
import AjaxErrorHandler from '../../assets/js/errorHandler'
export default {
name: 'MarketplaceItem',
data() {
return {
modifyUserModal: true,
loading: true,
item: {
name: "Loading",
description: "Loading",
price: 0,
previewFile: 'loading',
User: {
username: 'Loading'
},
createdAt: "2020-01-01T00:00:00.000Z"
},
purchased: false
}
},
mounted() {
this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + `/` + `marketplace/view/${this.$route.params.id}`)
.then(res => this.item = res.data, this.loading = false)
.catch((e) => {
AjaxErrorHandler(this.$store)(e)
})
this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + `/` + `marketplace/check/${this.$route.params.id}`)
.then(res => this.purchased = res.data.purchased)
}
}
</script>

View file

@ -26,7 +26,7 @@
<div class="box limit"> <div class="box limit">
<div v-if="user.description">{{ $t('user.description') }}: {{user.description}}</div><br> <div v-if="user.description">{{ $t('user.description') }}: {{user.description}}</div><br>
<div v-if="!user.description">{{$t('user.description')}}: {{$t('user.defaultDesc')}} {{user.username}}</div> <div v-if="!user.description">{{$t('user.description')}}: {{$t('user.defaultDesc')}} {{user.username}}</div>
{{ $t('user.created') }}: {{user.createdAt}}<br> {{ $t('user.created') }}: {{user.createdAt | formatDate()}}<br>
{{ $t('user.marketplace') }}: {{ $t('user.marketplace') }}:
</div> </div>
</div> </div>
@ -59,7 +59,7 @@
import AjaxErrorHandler from '../../assets/js/errorHandler' import AjaxErrorHandler from '../../assets/js/errorHandler'
import Badges from '../components/Badges' import Badges from '../components/Badges'
export default { export default {
name: 'user', name: 'User',
components: { components: {
Badges Badges
}, },
@ -313,7 +313,7 @@ export default {
return selectedIndex return selectedIndex
} }
}, },
created () { mounted () {
this.resetFetchData() this.resetFetchData()
this.selected = this.getIndexFromRoute(this.$route.path) this.selected = this.getIndexFromRoute(this.$route.path)

View file

@ -6,6 +6,14 @@
<NoItems :connection="true" type="users"> <NoItems :connection="true" type="users">
</NoItems> </NoItems>
</div> </div>
<Pagination
key='user-row'
class='columns is-multiline'
v-if='users.length'
:loading='loading'
:paginate="paginate"
@loadNext='getUsers(false)'
>
<div class="column is-3" v-for='(user) in users' :key='"user-" + user.id'> <div class="column is-3" v-for='(user) in users' :key='"user-" + user.id'>
<div class="box"> <div class="box">
<h1 class="title">{{user.username}}&nbsp;<Badges :username="user.username" :system="user.system" :hidden="user.hidden" :admin="user.admin" :booster="user.booster" :bot="user.bot"></Badges></h1> <h1 class="title">{{user.username}}&nbsp;<Badges :username="user.username" :system="user.system" :hidden="user.hidden" :admin="user.admin" :booster="user.booster" :bot="user.bot"></Badges></h1>
@ -13,6 +21,7 @@
<b-button tag="router-link" :to='"/u/" + user.username' class="is-centered is-info">View Profile</b-button> <b-button tag="router-link" :to='"/u/" + user.username' class="is-centered is-info">View Profile</b-button>
</div> </div>
</div> </div>
</Pagination>
</div> </div>
<div class="columns is-multiline" v-if="loading"> <div class="columns is-multiline" v-if="loading">
<div class="column is-4"> <div class="column is-4">
@ -90,37 +99,58 @@
import AjaxErrorHandler from "../../assets/js/errorHandler"; import AjaxErrorHandler from "../../assets/js/errorHandler";
import Badges from "../components/Badges" import Badges from "../components/Badges"
import NoItems from "../components/NoItems" import NoItems from "../components/NoItems"
import Pagination from "../components/Pagination"
export default { export default {
name: 'Users', name: 'Users',
components: { components: {
Badges, Badges,
NoItems NoItems,
Pagination
}, },
data() { data() {
return { return {
users: [], users: [],
offset: 0, offset: 0,
limit: 15, paginate: true,
limit: 30,
loading: true loading: true
} }
}, },
mounted() { methods: {
getUsers(initial) {
if(initial) {
this.users = []
this.loading = true this.loading = true
this.offset = 0
this.paginate = true
}
this.axios this.axios
.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + `/` + `user?offset=${this.offset};`) .get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'user/' + '?offset=' + this.offset)
.then(res => { .then(res => {
this.users.push(...res.data); if(res.data < this.limit) {
if(res.data.length < this.limit) {
this.offset = null; this.offset = null;
} else { } else {
this.offset+= this.limit; this.offset+= this.limit;
} }
if(!initial && !res.data.length) {
this.paginate = false
}
if(initial) {
this.users = res.data
} else {
this.users.push(...res.data)
}
this.loading = false this.loading = false
}) })
.catch(e => { .catch((e) => {
this.loading = false
AjaxErrorHandler(this.$store)(e) AjaxErrorHandler(this.$store)(e)
this.loading = false
}) })
} }
},
mounted() {
this.loading = true
this.getUsers()
}
} }
</script> </script>

View file

@ -1,7 +1,7 @@
const Dotenv = require('dotenv-webpack'); const Dotenv = require('dotenv-webpack');
module.exports = { module.exports = {
devServer: { devServer: {
proxy: 'http://localhost:23981' proxy: 'http://localhost:23982'
}, },
publicPath: '/', publicPath: '/',

View file

@ -8234,6 +8234,11 @@ lodash.templatesettings@^4.0.0:
dependencies: dependencies:
lodash._reinterpolate "^3.0.0" lodash._reinterpolate "^3.0.0"
lodash.throttle@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
lodash.transform@^4.6.0: lodash.transform@^4.6.0:
version "4.6.0" version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.transform/-/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0" resolved "https://registry.yarnpkg.com/lodash.transform/-/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0"
@ -12671,6 +12676,11 @@ vue-loader@^15.9.2:
vue-hot-reload-api "^2.3.0" vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0" vue-style-loader "^4.1.0"
vue-matomo@^3.14.0-0:
version "3.14.0-0"
resolved "https://registry.yarnpkg.com/vue-matomo/-/vue-matomo-3.14.0-0.tgz#f8e668c26ec1f2f7b4498f758edfb7c387259735"
integrity sha512-i1IkZGSXNY84zg1gVU8TOuaqajYDWQYl4Vs7M1mEb21cNhlMZKUxxgElvj+xmv7ytYUc/6ekZbxIS+y6W4qTMQ==
vue-router@^3.2.0: vue-router@^3.2.0:
version "3.4.9" version "3.4.9"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.4.9.tgz#c016f42030ae2932f14e4748b39a1d9a0e250e66" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.4.9.tgz#c016f42030ae2932f14e4748b39a1d9a0e250e66"