frontend/src/components/Navbar.vue

720 lines
24 KiB
Vue

<template>
<nav>
<b-modal
:active="ajaxErrorModal"
@update:active="(value) => (ajaxErrorModal = value)"
:width="640"
scroll="keep"
style="z-index: 200"
>
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">{{ $t("errorModalTitle") }}</p>
<button type="button" class="delete" @click="$emit('close')" />
</header>
<section class="modal-card-body media">
<p
:key="error"
v-for="error in this.$store.state.errors.errors"
style="margin: 1rem"
>
{{ error }}
</p>
</section>
<footer class="modal-card-foot">
<b-button :label="$t('gotIt')" @click="ajaxErrorModal = false" />
</footer>
</div>
</b-modal>
<b-modal
:active="loginModal"
@update:active="(value) => (loginModal = value)"
:width="640"
scroll="keep"
>
<form>
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">{{ $t("login.title") }}</p>
<button type="button" class="delete" @click="loginModal = false" />
</header>
<section class="modal-card-body">
<b-field :label="$t('login.loginUsername')">
<b-input
:value="login.username"
v-model="login.username"
:placeholder="$t('login.loginUsername')"
required
>
</b-input>
</b-field>
<b-field :label="$t('login.loginPassword')">
<b-input
type="password"
:value="login.password"
v-model="login.password"
password-reveal
:placeholder="$t('login.loginPassword')"
required
>
</b-input>
</b-field>
<b-checkbox v-model="login.doNotSaveToken">{{
$t("login.doNotSaveAuth")
}}</b-checkbox>
</section>
<footer class="modal-card-foot">
<b-button
@click="doLogin()"
:label="$t('login.login')"
:loading="login.loading"
type="is-primary"
/>
<b-button :label="$t('close')" @click="loginModal = false" />
</footer>
</div>
</form>
</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="updateDismissed" />
</header>
<section class="modal-card-body has-text-centered">
<h1 class="subtitle">
What's new in {{ $store.state.client.clientVersion }}?
</h1>
<ul>
<li>404 page on invalid user</li>
<li>Add early teams page</li>
<li>Add loading bar on router navigation change</li>
<li>Add early avatar page</li>
<li>Add early chat/conversation page</li>
<li>Add unauthenticated home page with site stats</li>
<li>Fix users page avatar size</li>
<li>Implement websockets</li>
<li>Improve forums</li>
<li>Fix statistics page</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"
>
<form>
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">{{ $t("register.title") }}</p>
<button
type="button"
class="delete"
@click="registerModal = false"
/>
</header>
<section class="modal-card-body">
<b-field :label="$t('register.username')">
<b-input
:value="register.username"
v-model="register.username"
:placeholder="$t('register.username')"
required
>
</b-input>
</b-field>
<b-field :label="$t('register.email')">
<b-input
type="email"
:value="register.email"
v-model="register.email"
:placeholder="$t('register.email')"
required
>
</b-input>
</b-field>
<b-field :label="$t('register.password')">
<b-input
type="password"
:value="register.password"
v-model="register.password"
password-reveal
:placeholder="$t('register.password')"
required
>
</b-input>
</b-field>
<b-field :label="$t('register.confirm')">
<b-input
type="password"
:value="register.confirm"
v-model="register.confirm"
password-reveal
:placeholder="$t('register.confirm')"
required
>
</b-input>
</b-field>
<b-checkbox v-model="register.agree"
>{{ $t("register.agree") }}
<router-link @click="registerModal = false" to="/legal/tos">{{
$t("tos")
}}</router-link></b-checkbox
>
</section>
<footer class="modal-card-foot">
<b-button
@click="doRegister()"
:label="$t('register.text')"
:loading="register.loading"
type="is-primary"
/>
<b-button :label="$t('close')" @click="registerModal = false" />
</footer>
</div>
</form>
</b-modal>
<Banners> </Banners>
{{version}}
<b-navbar>
<template #brand>
<b-navbar-item tag="router-link" :to="{ path: '/' }">
<img src="https://cdn.kaverti.com/logo.png" alt="Kaverti Logo" />
</b-navbar-item>
</template>
<template #start>
<b-navbar-item tag="router-link" to="/">
{{ $t("navbar.home") }}
</b-navbar-item>
<b-navbar-item tag="router-link" to="/forums">
{{ $t("navbar.forums") }}
</b-navbar-item>
<b-navbar-item tag="router-link" to="/marketplace">
{{ $t("navbar.marketplace") }}
</b-navbar-item>
<b-navbar-item tag="router-link" to="/users">
{{ $t("navbar.users") }}
</b-navbar-item>
<b-navbar-item tag="router-link" to="/teams">
{{ $t("navbar.teams") }}
</b-navbar-item>
<div
v-if="$store.state.debug"
class="navbar-item has-dropdown is-hoverable is-info"
>
<a class="navbar-link">
<p>{{ $t("navbar.dev.title") }}</p>
</a>
<div class="navbar-dropdown">
<b-navbar-item tag="router-link" to="/debug">{{
$t("navbar.dev.debug")
}}</b-navbar-item>
<b-navbar-item @click="fakeUser()">{{
$t("navbar.dev.fakeUser")
}}</b-navbar-item>
<b-navbar-item @click="toggleBrokenRoute(true)">{{
$t("navbar.dev.brokenRoute")
}}</b-navbar-item>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable is-info">
<a class="navbar-link">
<p>{{ $t("navbar.more.title") }}</p>
</a>
<div class="navbar-dropdown">
<b-navbar-item tag="a" href="https://twitter.com/Kaverti">{{
$t("navbar.more.twitter")
}}</b-navbar-item>
<b-navbar-item tag="a" href="https://discord.gg/Q3HAWFdBPK">{{
$t("navbar.more.discord")
}}</b-navbar-item>
<b-navbar-item tag="router-link" to="/roadmap">{{
$t("navbar.more.roadmap")
}}</b-navbar-item>
<b-navbar-item tag="router-link" to="/stats">{{
$t("navbar.more.stats")
}}</b-navbar-item>
</div>
</div>
</template>
<template #end>
<b-navbar-item
v-if="$store.state.user.username && !loading"
@click="dailyReward(true)"
>
<img src="https://cdn.kaverti.com/icons/koins.svg" />{{
$store.state.user.koins
}}
</b-navbar-item>
<div v-if="!loading">
<b-navbar-item v-if="!$store.state.user.username" tag="div">
<div class="buttons">
<b-button @click="registerModal = true" class="button is-primary">
<strong>{{ $t("navbar.register") }}</strong>
</b-button>
<b-button @click="loginModal = true" class="button is-light">
{{ $t("navbar.login") }}
</b-button>
</div>
</b-navbar-item>
</div>
<b-navbar-dropdown
class="is-hoverable"
style="padding-right: 15px"
:label="$store.state.user.username"
v-if="$store.state.user.username && !loading"
>
<b-navbar-item
tag="router-link"
:to="'/u/' + $store.state.user.username"
>{{ $t("navbar.user.profile") }}</b-navbar-item
>
<b-navbar-item tag="router-link" to="/settings">{{
$t("navbar.user.settings")
}}</b-navbar-item>
<b-navbar-item tag="router-link" to="/transactions">{{
$t("navbar.user.transactions")
}}</b-navbar-item>
<b-navbar-item tag="router-link" to="/avatar">{{
$t("navbar.user.avatar")
}}</b-navbar-item>
<b-navbar-item
tag="router-link"
to="/admin"
v-if="$store.state.user.admin"
>{{ $t("navbar.user.admin") }}</b-navbar-item
>
<b-navbar-item
tag="router-link"
to="/admin/item"
v-if="$store.state.user.modeler"
>{{ $t("navbar.user.asset") }}</b-navbar-item
>
<b-navbar-item tag="router-link" to="/friends"
><p>{{ $t("navbar.user.friends") }}&nbsp;</p>
<p v-if="friendCount > 0">
&nbsp;({{ friendCount }})
</p></b-navbar-item
>
<div class="dropdown-divider"></div>
<b-navbar-item class="has-text-danger" @click="logout()">{{
$t("navbar.user.logout")
}}</b-navbar-item>
</b-navbar-dropdown>
<b-navbar-item v-if="loading">
<div class="fa-1x">
<i class="fas fa-circle-notch fa-spin"></i>&nbsp; &nbsp;{{
$t("generic.loading")
}}
</div>
</b-navbar-item>
</template>
</b-navbar>
<section
v-if="
$store.state.client.bannerText &&
$store.state.client.bannerEnabled &&
showBanner
"
class="hero is-info"
>
<div class="hero-body" style="padding: 1rem 1rem !important">
<div class="mobile-container">
<div class="container">
<p style="text-align: center">
{{ $store.state.client.bannerText }}
<button
type="button"
class="delete"
style="float: right"
@click="removeBannerId"
/>
</p>
</div>
</div>
</div>
</section>
</nav>
</template>
<script>
import AjaxErrorHandler from ".././assets/js/errorHandler";
import axios from "axios";
import Banners from "./Banners"
export default {
components: {
Banners
},
data() {
return {
loginModal: false,
registerModal: false,
loading: true,
settingsModal: false,
showBanner: true,
showOutdatedBanner: true,
friendCount: 0,
updateModal: false,
login: {
username: "",
password: "",
loading: false,
doNotSaveToken: false,
},
register: {
username: "",
email: "",
password: "",
confirm: "",
agree: false,
loading: false,
},
};
},
computed: {
ajaxErrorModal: {
get() {
return this.$store.state.errors.modal;
},
set(val) {
this.$store.commit("setAjaxErrorsModalState", val);
},
},
},
methods: {
toggleBrokenRoute(val) {
this.$store.commit("brokenRoute", val);
},
getBannerId() {
if (localStorage.getItem(this.$store.state.client.bannerId)) {
this.showBanner = false;
} else {
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() {
localStorage.setItem(this.$store.state.client.bannerId, true);
this.$store.state.client.bannerEnabled = false;
console.log(localStorage.getItem(this.$store.state.client.bannerId));
},
doRegister() {
this.register.loading = true;
this.axios
.post(process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION + "/passkey/register", {
username: this.register.username,
password: this.register.password,
email: this.register.email,
confirm: this.register.confirm,
agree: this.register.agree,
})
.then((res) => {
this.register.loading = false;
this.registerModal = false;
this.$store.commit("setToken", res.data.token);
localStorage.setItem("token", JSON.stringify(res.data.token));
this.getInfo();
this.$buefy.snackbar.open({
message: this.$t("errors.registered"),
type: "is-info",
});
})
.catch((e) => {
this.register.loading = false;
AjaxErrorHandler(this.$store)(e, (error, errors) => {
let path = error.path;
if (this.errors[path] !== undefined) {
this.errors[path] = error.message;
} else {
errors.push(error.message);
}
});
});
},
doLogin() {
this.login.loading = true;
this.axios
.post(process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION + "/users/login", {
username: this.login.username,
password: this.login.password,
})
.then((res) => {
this.login.loading = false;
this.$store.commit("setToken", res.data.token);
if (!this.login.doNotSaveToken) {
localStorage.setItem("token", JSON.stringify(res.data.token));
}
Object.assign(axios.defaults, {
headers: { Authorization: this.$store.state.user.token },
});
this.loginModal = false;
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"userinfo"
)
.then((res) => {
this.$store.commit("setUsername", res.data.username);
this.$store.commit("setEmail", res.data.email);
this.$store.commit("setEmailVerified", res.data.emailVerified);
this.$store.commit("setAdmin", res.data.admin);
this.$store.commit("setKoins", res.data.koins);
this.$store.commit("setID", res.data.id);
this.$store.commit("setBot", res.data.bot);
this.$buefy.snackbar.open({
message: this.$t("errors.login"),
type: "is-info",
});
})
.catch(() => {
this.$buefy.snackbar.open({
message: this.$t("errors.authFail"),
type: "is-warning",
});
});
})
.catch((e) => {
this.login.loading = false;
AjaxErrorHandler(this.$store)(e);
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"userinfo"
)
.then((res) => {
this.$store.commit("setUsername", res.data.username);
this.$store.commit("setEmail", res.data.email);
this.$store.commit("setEmailVerified", res.data.emailVerified);
this.$store.commit("setAdmin", res.data.admin);
this.$store.commit("setKoins", res.data.koins);
this.$store.commit("setID", res.data.id);
this.$store.commit("setBot", res.data.bot);
})
.catch(() => {
this.$buefy.snackbar.open({
message: this.$t("errors.authFail"),
type: "is-warning",
});
});
AjaxErrorHandler(this.$store)(e, (error, errors) => {
let path = error.path;
if (this.errors[path] !== undefined) {
this.errors[path] = error.message;
} else {
errors.push(error.message);
}
});
});
},
logout() {
localStorage.removeItem("token");
this.$store.commit("setToken", "");
Object.assign(axios.defaults, {
headers: { Authorization: this.$store.state.user.token },
});
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"userinfo"
)
.then((res) => {
this.$store.commit("setUsername", res.data.username);
this.$store.commit("setEmail", res.data.email);
this.$store.commit("setEmailVerified", res.data.emailVerified);
this.$store.commit("setAdmin", res.data.admin);
this.$store.commit("setKoins", res.data.koins);
this.$store.commit("setID", res.data.id);
this.$store.commit("setBot", res.data.bot);
this.$buefy.snackbar.open({
message: this.$t("errors.logout"),
type: "is-info",
});
})
.catch(() => {
this.$buefy.snackbar.open({
message: this.$t("errors.logout"),
type: "is-info",
});
});
},
fakeUser() {
this.$store.commit("fakeUser");
this.$buefy.snackbar.open(
`WARNING: You have fake authenticated, you do not have authenticated API access. Use for debug purposes only.`
);
Object.assign(axios.defaults, {
headers: { Authorization: this.$store.state.user.token },
});
},
dailyReward(notify) {
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"users/reward"
)
.then((res) => {
this.$store.commit("setKoins", res.data.koins);
})
},
getInfo() {
Object.assign(axios.defaults, {
headers: { Authorization: this.$store.state.user.token },
});
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"kaverti/state"
)
.then((res) => {
this.$store.commit("setSettings", res.data.state);
this.$store.commit("setVersion", res.data.state.latestCanaryVersion);
this.$store.commit("setAPIVersion", res.data.apiVersion);
})
.catch(() => {
this.$buefy.snackbar.open({
message: this.$t("errors.down"),
type: "is-info",
});
});
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"userinfo"
)
.then((res) => {
this.$store.commit("setUsername", res.data.username);
this.$store.commit("setEmail", res.data.email);
this.$store.commit("setEmailVerified", res.data.emailVerified);
this.$store.commit("setAdmin", res.data.admin);
this.$store.commit("setKoins", res.data.koins);
this.$store.commit("setID", res.data.id);
this.$store.commit("setBot", res.data.bot);
this.$store.commit("setDescription", res.data.description);
this.$store.commit("setExecutive", res.data.executive);
this.settings.general.description.value = res.data.description;
this.loading = false;
})
.catch(() => {
this.$buefy.snackbar.open({
message: this.$t("errors.authFail"),
type: "is-warning",
});
this.loading = false;
});
},
},
mounted() {
Object.assign(axios.defaults, {
headers: { Authorization: this.$store.state.user.token },
});
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"kaverti/state"
)
.then((res) => {
this.$store.commit("setSettings", res.data.state);
this.$store.commit("setVersion", res.data.state.latestCanaryVersion);
this.$store.commit("setAPIVersion", res.data.apiVersion);
})
.catch(() => {
this.$buefy.snackbar.open({
message: this.$t("errors.down"),
type: "is-info",
});
});
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"userinfo"
)
.then((res) => {
this.$store.commit("setUsername", res.data.username);
this.$store.commit("setEmail", res.data.email);
this.$store.commit("setEmailVerified", res.data.emailVerified);
this.$store.commit("setAdmin", res.data.admin);
this.$store.commit("setKoins", res.data.koins);
this.$store.commit("setID", res.data.id);
this.$store.commit("setBot", res.data.bot);
this.$store.commit("setDescription", res.data.description);
this.$store.commit("setExecutive", res.data.executive);
this.settings.general.description.value = res.data.description;
this.loading = false;
})
.catch(() => {
this.$buefy.snackbar.open({
message: this.$t("errors.authFail"),
type: "is-warning",
});
this.loading = false;
console.log(this.getBannerId());
});
this.$nextTick(() => {
this.dailyReward(false);
this.showUpdate();
this.axios
.get(
process.env.VUE_APP_API_ENDPOINT +
process.env.VUE_APP_API_VERSION +
"/" +
"relationships/getAllPendingCanAccept"
)
.then((res) => {
this.friendCount = res.data.count;
});
});
},
};
</script>