🔨 Add server list

🔨 Add server list
This commit is contained in:
SebClem 2022-05-30 20:19:41 +02:00
parent 9aba4d2f78
commit 82b2148d86
Signed by: sebclem
GPG Key ID: 5A4308F6A359EA50
15 changed files with 242 additions and 41 deletions

1
.gitignore vendored
View File

@ -21,6 +21,7 @@ coverage
.vscode/* .vscode/*
!.vscode/extensions.json !.vscode/extensions.json
!.vscode/settings.json !.vscode/settings.json
!.vscode/launch.json
.idea .idea
*.suo *.suo
*.ntvs* *.ntvs*

18
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/src",
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/*"
}
}
]
}

View File

@ -23,21 +23,20 @@
</v-list-item> </v-list-item>
</v-list> </v-list>
<v-divider></v-divider> <v-divider></v-divider>
<server-list-component :guilds="[]" :loaded="false" /> <server-list-component />
</v-navigation-drawer> </v-navigation-drawer>
<snackbar-component /> <snackbar-component />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import ServerListComponent from "./ServerListComponent.vue"; import { logout } from "@/services/authService";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
import { logout } from "@/services/authService"; import ServerListComponent from "./ServerListComponent.vue";
import SnackbarComponent from "./SnackbarComponent.vue"; import SnackbarComponent from "./SnackbarComponent.vue";
const userStore = useUserStore(); const userStore = useUserStore();
const { userName, avatar, discriminator, isLoggedIn } = storeToRefs(userStore); const { userName, avatar, discriminator, isLoggedIn } = storeToRefs(userStore);
function getAvatar() { function getAvatar() {
const avatarBaseUrl = import.meta.env.VITE_DISCORD_USER_AVATAR_URL; const avatarBaseUrl = import.meta.env.VITE_DISCORD_USER_AVATAR_URL;
return avatarBaseUrl + userStore.discordId + "/" + avatar.value + ".png"; return avatarBaseUrl + userStore.discordId + "/" + avatar.value + ".png";

View File

@ -1,26 +1,62 @@
<template> <template>
<v-list nav> <v-list nav>
<v-list-item v-if="!props.loaded"> <v-fab-transition group>
<v-scale-transition appear> <template v-if="loaded">
<v-list-item-avatar :start="true"> <v-list-item
v-for="guild of guilds"
:key="guild.id"
:value="guild.id"
active-color="yellow"
:to="`/guild/${guild.id}`"
>
<v-list-item-avatar
start
:color="guild.iconUrl ? '' : 'grey-darken-3'"
>
<v-img v-if="guild.iconUrl" :src="guild.iconUrl"></v-img>
<template v-if="!guild.iconUrl">{{ guild.name[1] }}</template>
</v-list-item-avatar>
<v-list-item-title>{{ guild.name }}</v-list-item-title>
</v-list-item>
<v-list-item :href="inviteLink" target="_blank">
<v-list-item-avatar color="grey-darken-3" start>
<v-icon color="green">mdi-plus</v-icon>
</v-list-item-avatar>
<v-list-item-title> Invite Claptrap Bot ! </v-list-item-title>
</v-list-item>
</template>
<v-list-item v-if="!loaded">
<v-list-item-avatar>
<v-progress-circular <v-progress-circular
indeterminate indeterminate
color="primary" color="primary"
></v-progress-circular> ></v-progress-circular>
</v-list-item-avatar> </v-list-item-avatar>
<v-list-item-subtitle> Loading... </v-list-item-subtitle> <v-list-item-subtitle> Loading... </v-list-item-subtitle>
</v-scale-transition>
</v-list-item> </v-list-item>
</v-fab-transition>
</v-list> </v-list>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { Guild } from "@/data/Guild"; import { getInviteLink } from "@/services/guildService";
import { useInviteLinkStore } from "@/stores/inviteLink";
import { useMutualGuildsStore } from "@/stores/mutualGuilds";
import { storeToRefs } from "pinia";
import { onBeforeMount } from "vue";
const props = defineProps<{ const inviteLinkStore = useInviteLinkStore();
guilds: Guild[];
loaded: boolean; const { inviteLink } = storeToRefs(inviteLinkStore);
}>();
const mutualGuildsStore = useMutualGuildsStore();
const { guilds, loaded } = storeToRefs(mutualGuildsStore);
onBeforeMount(async () => {
if (!inviteLinkStore.isPresent) {
let inviteLink = await getInviteLink();
inviteLinkStore.inviteLink = inviteLink.link;
}
});
</script> </script>
<style scoped></style> <style scoped></style>

View File

@ -2,6 +2,7 @@ type Guild = {
id: string; id: string;
name: string; name: string;
iconUrl: string; iconUrl: string;
canManage: boolean;
}; };
export { Guild }; export type { Guild };

5
src/data/InviteLink.ts Normal file
View File

@ -0,0 +1,5 @@
type InviteLink = {
link: string;
};
export type { InviteLink };

View File

@ -5,9 +5,13 @@ import vuetify from "./plugins/vuetify";
import { loadFonts } from "./plugins/webfontloader"; import { loadFonts } from "./plugins/webfontloader";
import { createPinia } from "pinia"; import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
import axios from "axios";
loadFonts(); loadFonts();
const pinia = createPinia(); const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); pinia.use(piniaPluginPersistedstate);
axios.defaults.baseURL = import.meta.env.VITE_API_BASE_URL;
axios.defaults.headers.post["Content-Type"] = "application/json";
createApp(App).use(router).use(vuetify).use(pinia).mount("#app"); createApp(App).use(router).use(vuetify).use(pinia).mount("#app");

View File

@ -1,4 +1,8 @@
import { logout } from "@/services/authService";
import { getMutualGuilds } from "@/services/guildService";
import { useMutualGuildsStore } from "@/stores/mutualGuilds";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import GuildHomeViewVue from "@/views/GuildHomeView.vue";
import OauthCallbackViewVue from "@/views/oauth/OauthCallbackView.vue"; import OauthCallbackViewVue from "@/views/oauth/OauthCallbackView.vue";
import OauthRedirectViewVue from "@/views/oauth/OauthRedirectView.vue"; import OauthRedirectViewVue from "@/views/oauth/OauthRedirectView.vue";
import { createRouter, createWebHistory } from "vue-router"; import { createRouter, createWebHistory } from "vue-router";
@ -21,6 +25,14 @@ const router = createRouter({
requiresAuth: false, requiresAuth: false,
}, },
}, },
{
path: "/guild/:guildId",
name: "guildHome",
component: GuildHomeViewVue,
meta: {
requiresAuth: true,
},
},
{ {
path: "/oauth2/callback", path: "/oauth2/callback",
name: "oauth-callback", name: "oauth-callback",
@ -43,8 +55,23 @@ const router = createRouter({
router.beforeEach((to, from) => { router.beforeEach((to, from) => {
const store = useUserStore(); const store = useUserStore();
if (to.meta.requiresAuth && !store.isLoggedIn) { if (to.meta.requiresAuth && !store.isLoggedIn) {
(<any>window).location = import.meta.env.VITE_OAUTH_REDIRECT_URL; return { name: "oauth-redirect" };
return false; } else {
const mutualGuildsStore = useMutualGuildsStore();
if (store.isLoggedIn) {
getMutualGuilds()
.then((value) => {
mutualGuildsStore.guilds = value;
mutualGuildsStore.loaded = true;
})
.catch((reason) => {
if (reason?.response.status == 401) {
console.log("401, Login expired, logout...");
logout(true, false);
router.push({ name: "home" });
}
});
}
} }
}); });

View File

@ -48,8 +48,6 @@ async function login(code: string): Promise<boolean> {
function logout(expired: boolean, loginFail: boolean): void { function logout(expired: boolean, loginFail: boolean): void {
const userStore = useUserStore(); const userStore = useUserStore();
const router = useRouter();
userStore.token = ""; userStore.token = "";
userStore.userName = ""; userStore.userName = "";
userStore.discordId = ""; userStore.discordId = "";
@ -57,11 +55,25 @@ function logout(expired: boolean, loginFail: boolean): void {
userStore.asExpired = expired; userStore.asExpired = expired;
const eventQueuStore = useEventQueuStore(); const eventQueuStore = useEventQueuStore();
if (!expired && !loginFail) {
eventQueuStore.push({ eventQueuStore.push({
uuid: undefined, uuid: undefined,
type: "success", type: "success",
text: "Disconnected", text: "Disconnected",
}); });
} else if (expired) {
eventQueuStore.push({
uuid: undefined,
type: "warning",
text: "Sesion expired, please re-login",
});
} else {
eventQueuStore.push({
uuid: undefined,
type: "error",
text: "Login fail, please try again",
});
}
} }
export { login, logout }; export { login, logout };

View File

@ -0,0 +1,57 @@
import type { Guild } from "@/data/Guild";
import type { InviteLink } from "@/data/InviteLink";
import { useEventQueuStore } from "@/stores/eventQueu";
import { useUserStore } from "@/stores/user";
import axios from "axios";
function getMutualGuilds(): Promise<Guild[]> {
return new Promise((resolve, reject) => {
const userStore = useUserStore();
axios
.get<Guild[]>("/guild/mutual", {
headers: {
authorization: `Bearer ${userStore.token}`,
},
})
.then((value) => {
console.log(value);
resolve(value.data);
})
.catch((reason) => {
console.error(`Fail to get mutal guilds !`);
console.log(reason);
reject(reason);
});
});
}
function getInviteLink(): Promise<InviteLink> {
return new Promise((resolve, reject) => {
const userStore = useUserStore();
axios
.get<InviteLink>("/guild/inviteLink", {
headers: {
authorization: `Bearer ${userStore.token}`,
},
})
.then((value) => {
console.log(value);
resolve(value.data);
})
.catch((reason) => {
console.error(`Fail to get Invite !`);
console.log(reason);
const eventQueuStore = useEventQueuStore();
eventQueuStore.push({
uuid: undefined,
type: "error",
text: "Fail to retrive invite link !",
});
reject(reason);
});
});
}
export { getMutualGuilds, getInviteLink };

View File

@ -1,16 +0,0 @@
import { defineStore } from "pinia";
export const useCounterStore = defineStore({
id: "counter",
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
actions: {
increment() {
this.counter++;
},
},
});

15
src/stores/inviteLink.ts Normal file
View File

@ -0,0 +1,15 @@
import { defineStore } from "pinia";
export const useInviteLinkStore = defineStore({
id: "inviteLink",
state: () => ({
inviteLink: "",
}),
getters: {
isPresent(): boolean {
return !!this.inviteLink;
},
},
actions: {},
persist: true,
});

View File

@ -0,0 +1,18 @@
import type { Guild } from "@/data/Guild";
import { defineStore } from "pinia";
export const useMutualGuildsStore = defineStore({
id: "mutualGuilds",
state: () => ({
guilds: [] as Array<Guild>,
loaded: false,
lastGuildId: "",
}),
getters: {},
actions: {
getGuild(id: string): Guild | undefined {
return this.guilds.find((elem) => elem.id == id);
},
},
persist: true,
});

View File

@ -0,0 +1,11 @@
<template>
{{ route.params.guildId }}
</template>
<script setup lang="ts">
import { useRoute } from "vue-router";
const route = useRoute();
</script>
<style scoped></style>

View File

@ -9,10 +9,23 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useMutualGuildsStore } from "@/stores/mutualGuilds";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import { onBeforeMount } from "vue"; import { onBeforeMount } from "vue";
import { useRouter } from "vue-router";
const userStore = useUserStore(); const userStore = useUserStore();
const mutualGuildStore = useMutualGuildsStore();
const router = useRouter();
onBeforeMount(() => { onBeforeMount(() => {
userStore.isLoggedIn; if (userStore.isLoggedIn) {
if (!mutualGuildStore.lastGuildId) {
mutualGuildStore.lastGuildId = mutualGuildStore.guilds[0].id;
}
router.push({
name: "guildHome",
params: { guildId: mutualGuildStore.lastGuildId },
});
}
}); });
</script> </script>