This commit is contained in:
Troplo 2021-04-08 22:20:12 +10:00
parent d2291dd6c4
commit 434f307f1e
9 changed files with 998 additions and 665 deletions

View file

@ -7,9 +7,7 @@
<Footer /> <Footer />
</div> </div>
</template> </template>
<style>
@import './assets/css/kaverti.css';
</style>
<script> <script>
import Navbar from "./components/Navbar"; import Navbar from "./components/Navbar";
import Footer from "./components/Footer"; import Footer from "./components/Footer";
@ -42,31 +40,31 @@ export default {
}); });
} }
this.axios this.axios
.get( .get(
process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIENDPOINT +
process.env.VUE_APP_APIVERSION + process.env.VUE_APP_APIVERSION +
"/" + "/" +
"userinfo" "userinfo"
) )
.then((res) => { .then((res) => {
this.$store.commit("setUsername", res.data.username); this.$store.commit("setUsername", res.data.username);
this.$store.commit("setEmail", res.data.email); this.$store.commit("setEmail", res.data.email);
this.$store.commit("setEmailVerified", res.data.emailVerified); this.$store.commit("setEmailVerified", res.data.emailVerified);
this.$store.commit("setAdmin", res.data.admin); this.$store.commit("setAdmin", res.data.admin);
this.$store.commit("setKoins", res.data.koins); this.$store.commit("setKoins", res.data.koins);
this.$store.commit("setID", res.data.id); this.$store.commit("setID", res.data.id);
this.$store.commit("setBot", res.data.bot); this.$store.commit("setBot", res.data.bot);
this.$store.commit("setDescription", res.data.description); this.$store.commit("setDescription", res.data.description);
this.$store.commit("setExecutive", res.data.executive); this.$store.commit("setExecutive", res.data.executive);
}) })
.catch(() => { .catch(() => {
this.$buefy.snackbar.open({ this.$buefy.snackbar.open({
message: this.$t("errors.down"), message: this.$t("errors.down"),
type: "is-warning", type: "is-warning",
});
}); });
});
this.axios.get( this.axios.get(
process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIENDPOINT +
process.env.VUE_APP_APIVERSION + process.env.VUE_APP_APIVERSION +
"/" + "/" +
"awards/eligibility" "awards/eligibility"
@ -81,5 +79,6 @@ export default {
</style> </style>
<style lang="css"> <style lang="css">
@import './assets/css/kaverti.css';
@import "https://kit-pro.fontawesome.com/releases/v5.15.1/css/pro.min.css"; @import "https://kit-pro.fontawesome.com/releases/v5.15.1/css/pro.min.css";
</style> </style>

View file

@ -4,11 +4,12 @@
<form> <form>
<div class="modal-card" style="width: auto"> <div class="modal-card" style="width: auto">
<header class="modal-card-head"> <header class="modal-card-head">
<p class="modal-card-title">{{ $t('feedback.title') }}</p> <p class="modal-card-title">{{ $t("feedback.title") }}</p>
<button <button
type="button" type="button"
class="delete" class="delete"
@click="feedbackModal = false"/> @click="feedbackModal = false"
/>
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
<p>This feedback will be used to make Kaverti better.</p> <p>This feedback will be used to make Kaverti better.</p>
@ -16,18 +17,24 @@
<b-input <b-input
:placeholder="$store.state.user.email" :placeholder="$store.state.user.email"
v-model="feedback.email" v-model="feedback.email"
required> required
>
</b-input> </b-input>
</b-field> </b-field>
<b-field :label="$t('feedback.route')"> <b-field :label="$t('feedback.route')">
<b-input <b-input
:placeholder="$t('feedback.route')" :placeholder="$t('feedback.route')"
v-model="feedback.route" v-model="feedback.route"
required> required
>
</b-input> </b-input>
</b-field> </b-field>
<b-field :label="$t('feedback.rating')"> <b-field :label="$t('feedback.rating')">
<b-rate icon-pack="fas" v-model="feedback.stars" custom-text="Route rating"></b-rate> <b-rate
icon-pack="fas"
v-model="feedback.stars"
custom-text="Route rating"
></b-rate>
</b-field> </b-field>
<b-field :label="$t('feedback.text')"> <b-field :label="$t('feedback.text')">
<b-input <b-input
@ -35,7 +42,8 @@
v-model="feedback.text" v-model="feedback.text"
maxlength="512" maxlength="512"
type="textarea" type="textarea"
required> required
>
</b-input> </b-input>
</b-field> </b-field>
</section> </section>
@ -44,10 +52,13 @@
@click="doFeedback()" @click="doFeedback()"
:loading="feedback.loading" :loading="feedback.loading"
:label="$t('feedback.submit')" :label="$t('feedback.submit')"
type="is-primary" /> type="is-info"
></b-button>
<b-button <b-button
:label="$t('close')" :label="$t('close')"
@click="feedbackModal = false" /> @click="feedbackModal = false"
tpe="is-danger"
></b-button>
</footer> </footer>
</div> </div>
</form> </form>
@ -55,132 +66,179 @@
<b-modal v-model="langModal"> <b-modal v-model="langModal">
<div class="modal-card" style="width: auto"> <div class="modal-card" style="width: auto">
<header class="modal-card-head"> <header class="modal-card-head">
<p class="modal-card-title">{{$t('languages.title')}}</p> <p class="modal-card-title">{{ $t("languages.title") }}</p>
<button <b-button
type="button" type="is-info"
class="delete" class="delete"
@click="langModal = false"/> @click="langModal = false"
></b-button>
</header> </header>
<section class="modal-card-body buttons"> <section class="modal-card-body buttons">
<b-button v-if="$i18n.locale !== 'en'" @click="en" class="is-large">{{$t('languages.en')}}</b-button> <b-button v-if="$i18n.locale !== 'en'" @click="en" class="is-large">{{
<b-button v-if="$i18n.locale === 'en'" @click="en" class="is-large is-info disabled" disabled>{{$t('languages.en')}}</b-button> $t("languages.en")
<b-button v-if="$i18n.locale === 'wind'" @click="en" class="is-large is-info disabled" disabled>{{$t('languages.wind')}}</b-button> }}</b-button>
<b-button v-if="$i18n.locale === 'debug'" @click="en" class="is-large is-info disabled" disabled>{{$t('languages.debug')}}</b-button> <b-button
v-if="$i18n.locale === 'en'"
@click="en"
class="is-large is-info disabled"
disabled
>{{ $t("languages.en") }}</b-button
>
<b-button
v-if="$i18n.locale === 'wind'"
@click="en"
class="is-large is-info disabled"
disabled
>{{ $t("languages.wind") }}</b-button
>
<b-button
v-if="$i18n.locale === 'debug'"
@click="en"
class="is-large is-info disabled"
disabled
>{{ $t("languages.debug") }}</b-button
>
</section> </section>
</div> </div>
</b-modal> </b-modal>
<h1>&copy; 2021 Kaverti</h1> <h1>&copy; 2021 Kaverti</h1>
<div class="buttons"> <div class="buttons">
<b-button @click="langModal = true">{{$t('languages.title')}}</b-button> <b-button type="is-info" @click="langModal = true">{{ $t("languages.title") }}</b-button>
<b-button @click="feedbackModal = true">Provide Feedback</b-button> <b-button type="is-info" @click="feedbackModal = true">Provide Feedback</b-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import AjaxErrorHandler from '.././assets/js/errorHandler' import AjaxErrorHandler from ".././assets/js/errorHandler";
export default { export default {
name: 'locale-changer', name: "locale-changer",
data () { data() {
return { return {
feedbackModal: false, feedbackModal: false,
langs: ['en', 'debug', 'wind'], langs: ["en", "debug", "wind"],
currentLang: this.$i18n.locale, currentLang: this.$i18n.locale,
langModal: false, langModal: false,
feedback: { feedback: {
route: this.$route.path, route: this.$route.path,
stars: 0, stars: 0,
text: '', text: "",
email: this.$store.state.user.email, email: this.$store.state.user.email,
loading: false loading: false,
} },
} };
}, },
methods: { methods: {
doFeedback() { doFeedback() {
this.feedback.loading = true this.feedback.loading = true;
this.axios this.axios
.post(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'feedback', { .post(
text: this.feedback.text, process.env.VUE_APP_APIENDPOINT +
stars: this.feedback.stars, process.env.VUE_APP_APIVERSION +
email: this.feedback.email, "/" +
route: this.feedback.route "feedback",
}) {
text: this.feedback.text,
stars: this.feedback.stars,
email: this.feedback.email,
route: this.feedback.route,
}
)
.then(() => { .then(() => {
this.axios.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'userinfo') this.axios.get(
this.feedbackModal = false process.env.VUE_APP_APIENDPOINT +
this.$buefy.snackbar.open({message:this.$t('errors.feedbackThanks'), type: 'is-info'}) process.env.VUE_APP_APIVERSION +
this.feedback.loading = false "/" +
}) "userinfo"
.catch(e => { );
AjaxErrorHandler(this.$store)(e) this.feedbackModal = false;
this.feedback.loading = false this.$buefy.snackbar.open({
message: this.$t("errors.feedbackThanks"),
type: "is-info",
});
this.feedback.loading = false;
}) })
.catch((e) => {
AjaxErrorHandler(this.$store)(e);
this.feedback.loading = false;
});
}, },
en () { en() {
this.$i18n.locale = "en" this.$i18n.locale = "en";
this.setLang() this.setLang();
}, },
debug () { debug() {
this.$i18n.locale = "debug" this.$i18n.locale = "debug";
this.setLang() this.setLang();
}, },
wind () { wind() {
this.$i18n.locale = "wind" this.$i18n.locale = "wind";
this.setLang() this.setLang();
}, },
setLang () { setLang() {
localStorage.setItem("lang", this.$i18n.locale); localStorage.setItem("lang", this.$i18n.locale);
this.axios this.axios
.put(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'users/preferences', { .put(
lang: this.$i18n.locale process.env.VUE_APP_APIENDPOINT +
}) process.env.VUE_APP_APIVERSION +
.then(() => { "/" +
this.axios.get(process.env.VUE_APP_APIENDPOINT + process.env.VUE_APP_APIVERSION + '/' + 'userinfo') "users/preferences",
.then(res => { {
this.$store.commit('setUsername', res.data.username) lang: this.$i18n.locale,
this.$store.commit('setEmail', res.data.email) }
this.$store.commit('setEmailVerified', res.data.emailVerified) )
this.$store.commit('setAdmin', res.data.admin) .then(() => {
this.$store.commit('setDevMode', res.data.developerMode) this.axios
this.$store.commit('setTheme', res.data.theme) .get(
this.$store.commit('setLang', res.data.lang) process.env.VUE_APP_APIENDPOINT +
}) process.env.VUE_APP_APIVERSION +
}) "/" +
.catch(e => { "userinfo"
AjaxErrorHandler(this.$store)(e) )
}) .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("setDevMode", res.data.developerMode);
this.$store.commit("setTheme", res.data.theme);
this.$store.commit("setLang", res.data.lang);
});
})
.catch((e) => {
AjaxErrorHandler(this.$store)(e);
});
},
}, },
mounted () { mounted() {
if(localStorage.getItem("lang")) { if (localStorage.getItem("lang")) {
this.$i18n.locale = localStorage.getItem("lang") this.$i18n.locale = localStorage.getItem("lang");
} else if (this.$store.state.user.lang) { } else if (this.$store.state.user.lang) {
this.$i18n.locale = this.$store.state.user.lang this.$i18n.locale = this.$store.state.user.lang;
} else { } else {
this.$i18n.locale = "en" this.$i18n.locale = "en";
} }
this.$nextTick(() => { this.$nextTick(() => {
this.feedback = { this.feedback = {
route: this.$route.path, route: this.$route.path,
stars: 0, stars: 0,
text: '', text: "",
email: this.$store.state.user.email email: this.$store.state.user.email,
} };
}) });
}, },
watch: { watch: {
$route() { $route() {
this.feedback = { this.feedback = {
route: this.$route.path, route: this.$route.path,
stars: 0, stars: 0,
text: '', text: "",
email: this.$store.state.user.email email: this.$store.state.user.email,
} };
}, },
currentLang() { currentLang() {
this.setLang() this.setLang();
console.log('change') console.log("change");
} },
} },
} };
</script> </script>

File diff suppressed because it is too large Load diff

View file

@ -171,11 +171,22 @@ const routes = [{
{ {
path: '/admin', path: '/admin',
component: route('Admin'), component: route('Admin'),
redirect: "/admin/dashboard",
children: [ children: [
{ path: 'dashboard', component: route('AdminDashboard') }, { path: 'dashboard', component: route('AdminDashboard') },
{ path: 'item', component: route('AdminCreateItem') }, { path: 'item', component: route('AdminCreateItem') },
] ]
}, },
{
path: '/settings',
component: route('Settings'),
redirect: "/settings/general",
children: [
{ path: 'general', component: route('SettingsGeneral') },
{ path: 'account', component: route('SettingsAccount') },
{ path: 'about', component: route('SettingsAbout') },
]
},
{ {
path: '*', path: '*',
name: '404', name: '404',

View file

@ -1,73 +1,73 @@
<template> <template>
<div id="home"> <div id="home">
<section class="section" v-if="$store.state.user.username"> <section class="section" v-if="$store.state.user.username">
<div class="container"> <div class="container">
<div class="columns is-centered"> <div class="columns is-centered">
<div class="column is-4"> <div class="column is-4">
<div class="box">
<div class="title">
{{ $store.state.user.username }}
</div>
<img :src="'https://cdn.kaverti.com/user/avatars/full/' + $store.state.user.avatar + '.png'" alt="Avatar" width="50%">
</div>
<div class="title">
{{ $t('home.news') }}
</div>
<div v-if="blogs.length">
<div class="box" v-for='(blog) in blogs' :key='"blog-" + blog.id'>
<div class="subtitle">
{{ blog.name }}
</div>
<p>{{ blog.plainText }}</p>
</div>
</div>
<div v-else>
<div class="box"> <div class="box">
<NoItems type="blog posts"></NoItems> <div class="title">
{{ $store.state.user.username }}
</div>
<img :src="'https://cdn.kaverti.com/user/avatars/full/' + $store.state.user.avatar + '.png'" alt="Avatar" class="is-centered" width="50%">
</div> </div>
</div>
</div>
<div class="column is-7" v-if="!loading">
<div class="box">
<div class="title"> <div class="title">
{{ $t('home.globalWall') }} {{ $t('home.news') }}
</div> </div>
<b-input type="textarea" maxlength="256" placeholder="How's it going?" v-model="wallText"></b-input> <div v-if="blogs.length">
<b-tag type="is-info" class="is-pulled-right"> <div class="box" v-for='(blog) in blogs' :key='"blog-" + blog.id'>
Markdown is no longer available on wall posts. <div class="subtitle">
</b-tag> {{ blog.name }}
<b-button type="is-info" ckass="is-pulled-left" :loading="loadingWallButton" @click="postWall">Post</b-button>
</div>
<hr>
<div class="box" v-for='(post) in wallPosts' :key='"wallPosts-" + post.id'>
<article class="media">
<figure class="media-left">
<figure class="image is-64x64 is-rounded">
<img :src="'https://cdn.kaverti.com/user/avatars/headshot/' + post.fromUser.picture + '.png'" alt="Avatar" class="is-rounded">
</figure>
</figure>
<div class="media-content">
<div class="content">
<p>
<strong>{{ post.fromUser.username }}</strong>&nbsp;
<small>{{ post.createdAt | formatDate() }}</small>
<br>
{{ post.plainText }}
</p>
</div> </div>
<p>{{ blog.plainText }}</p>
</div> </div>
<div class="media-right"> </div>
<b-tooltip label="Delete" v-if="$store.state.user.admin"> <div v-else>
<b-button class="delete"></b-button> <div class="box">
</b-tooltip> <NoItems type="blog posts"></NoItems>
</div> </div>
</article> </div>
</div>
<div class="column is-7" v-if="!loading">
<div class="box">
<div class="title">
{{ $t('home.globalWall') }}
</div>
<b-input type="textarea" maxlength="256" placeholder="How's it going?" v-model="wallText"></b-input>
<b-tag type="is-info" class="is-pulled-right">
Markdown is no longer available on wall posts.
</b-tag>
<b-button type="is-info" ckass="is-pulled-left" :loading="loadingWallButton" @click="postWall">Post</b-button>
</div>
<hr>
<div class="box" v-for='(post) in wallPosts' :key='"wallPosts-" + post.id'>
<article class="media">
<figure class="media-left">
<figure class="image is-64x64 is-rounded">
<img :src="'https://cdn.kaverti.com/user/avatars/headshot/' + post.fromUser.picture + '.png'" alt="Avatar" class="is-rounded">
</figure>
</figure>
<div class="media-content">
<div class="content">
<p>
<strong>{{ post.fromUser.username }}</strong>&nbsp;
<small>{{ post.createdAt | formatDate() }}</small>
<br>
{{ post.plainText }}
</p>
</div>
</div>
<div class="media-right">
<b-tooltip label="Delete" v-if="$store.state.user.admin">
<b-button class="delete"></b-button>
</b-tooltip>
</div>
</article>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
</section> </section>
<section class="section hero is-info is-large is-fullheight-with-navbar" v-if="!$store.state.user.username"> <section class="hero is-info is-large is-fullheight-with-navbar" v-if="!$store.state.user.username">
<div class="hero-body"> <div class="hero-body">
<div class="container has-text-centered"> <div class="container has-text-centered">
<div class="title"> <div class="title">
@ -253,4 +253,4 @@ export default {
this.getWall(true) this.getWall(true)
} }
} }
</script> </script>

60
src/views/Settings.vue Normal file
View file

@ -0,0 +1,60 @@
<template>
<div id="settings">
<section class="section">
<div class="container" v-if="$store.state.user.username">
<div class="columns is-centered">
<div class="column is-3">
<b-menu>
<b-menu-list label="Settings">
<b-menu-item
:label="menuItem.name"
v-for="(menuItem, $index) in menuItems"
:key="'settings-link-' + $index"
tag="router-link"
:to="'/settings/' + menuItem.route"
></b-menu-item>
</b-menu-list>
</b-menu>
</div>
<div class="column is-7">
<router-view></router-view>
</div>
</div>
</div>
<div class="container" v-else>
<div class="columns is-centered">
<div class="column is-5">
<div class="box has-text-centered">
<i class="far fa-times-square large-icon"></i>
<div class="subtitle">{{ $t("generic.notLoggedIn") }}</div>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
name: "Settings",
data() {
return {
menuItems: [
{
name: "General",
route: "general",
},
{
name: "Account",
route: "account",
},
{
name: "About",
route: "about",
},
],
};
},
};
</script>

View file

@ -0,0 +1,24 @@
<template>
<div id="settings-about">
<div class="box">
<div class="title">About</div>
<hr />
<div class="has-text-centered">
<img src="https://cdn.kaverti.com/icon.png" width="10%" />
<p>Kaverti v{{ this.$store.state.client.clientVersion }}</p>
<p>
Latest Client Version: v{{
this.$store.state.client.latestClientVersion
}}
</p>
<p>API Version: v{{ this.$store.state.client.latestAPIVersion }}</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "SettingsAbout",
};
</script>

View file

@ -0,0 +1,11 @@
<template>
<div id="settings-account">
</div>
</template>
<script>
export default {
name: "SettingsAccount"
}
</script>

View file

@ -0,0 +1,135 @@
<template>
<div id="settings-general">
<div class="box">
<div class="title">{{ $t("settings.general.title") }}</div>
<hr />
<div class="subtitle">{{ $t("settings.general.about") }}</div>
<form @submit.prevent="saveDesc">
<b-field :label="$t('settings.general.description')">
<b-input
type="textarea"
:placeholder="
$t('settings.general.hi') + ' ' + $store.state.user.username
"
maxlength="256"
v-model="settings.description.value"
:error="settings.description.error"
></b-input>
</b-field>
<b-button
type="is-info"
:loading="settings.description.loading"
@click="saveDescription"
>
{{ $t("settings.general.saveDesc") }}
</b-button>
</form>
<form @submit.prevent="savePref">
<b-field label="Developer Mode">
<b-switch
type="is-info"
true-value="true"
false-value="false"
v-model="settings.preferences.developerMode"
>{{ settings.preferences.developerMode }}</b-switch>
</b-field>
<b-button
type="is-info"
:loading="settings.preferences.loading"
@click="savepreferences"
>
{{ $t("settings.general.savePref") }}
</b-button>
</form>
</div>
</div>
</template>
<script>
export default {
name: "SettingsGeneral",
data() {
return {
settings: {
description: {
value: this.$store.state.user.description,
loading: false,
error: "",
},
preferences: {
developerMode: this.$store.state.user.developerMode,
loading: false,
error: "",
},
},
};
},
methods: {
clearErrors() {
this.settings.description.error = "";
this.settings.preferences.error = "";
},
changesSaved() {
this.$buefy.snackbar.open({
duration: 5000,
message: "Changes saved.",
type: "is-success",
position: "is-bottom-left",
actionText: "Ok",
queue: false,
});
},
saveDescription() {
this.clearErrors();
this.settings.description.loading = true;
this.axios
.put(
process.env.VUE_APP_APIENDPOINT +
process.env.VUE_APP_APIVERSION +
"/users/preferences",
{
description: this.settings.description.value,
}
)
.then(() => {
this.settings.description.loading = false;
this.changesSaved();
})
.catch((err) => {
this.settings.description.loading = false;
AjaxErrorHandler(this.$store)(err);
});
},
savepreferences() {
this.clearErrors();
this.settings.preferences.loading = true;
this.axios
.put(
process.env.VUE_APP_APIENDPOINT +
process.env.VUE_APP_APIVERSION +
"/users/preferences",
{
developerMode: this.settings.preferences.developerMode,
}
)
.then(() => {
this.axios
.get(
process.env.VUE_APP_APIENDPOINT +
process.env.VUE_APP_APIVERSION +
"/userinfo"
)
.then((res) => {
this.$store.commit("setDevMode", res.data.developerMode);
});
this.settings.description.loading = false;
this.changesSaved();
})
.catch((err) => {
this.settings.preferences.loading = false;
AjaxErrorHandler(this.$store)(err);
});
},
},
};
</script>