🔨 Add server list
🔨 Add server list
This commit is contained in:
parent
9aba4d2f78
commit
82b2148d86
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
18
.vscode/launch.json
vendored
Normal 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}/*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -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";
|
||||||
|
@ -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>
|
||||||
|
@ -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
5
src/data/InviteLink.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
type InviteLink = {
|
||||||
|
link: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type { InviteLink };
|
@ -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");
|
||||||
|
@ -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" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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();
|
||||||
eventQueuStore.push({
|
if (!expired && !loginFail) {
|
||||||
uuid: undefined,
|
eventQueuStore.push({
|
||||||
type: "success",
|
uuid: undefined,
|
||||||
text: "Disconnected",
|
type: "success",
|
||||||
});
|
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 };
|
||||||
|
57
src/services/guildService.ts
Normal file
57
src/services/guildService.ts
Normal 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 };
|
@ -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
15
src/stores/inviteLink.ts
Normal 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,
|
||||||
|
});
|
18
src/stores/mutualGuilds.ts
Normal file
18
src/stores/mutualGuilds.ts
Normal 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,
|
||||||
|
});
|
11
src/views/GuildHomeView.vue
Normal file
11
src/views/GuildHomeView.vue
Normal 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>
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user