🔨 Add setting skeleton

This commit is contained in:
SebClem 2022-06-17 18:08:04 +02:00
parent eef86a95d5
commit 034b6b7b5c
Signed by: sebclem
GPG Key ID: 5A4308F6A359EA50
22 changed files with 463 additions and 18 deletions

View File

@ -28,7 +28,7 @@
"uuid": "^8.3.2",
"vue": "^3.2.33",
"vue-router": "^4.0.14",
"vuetify": "^3.0.0-beta.2",
"vuetify": "^3.0.0-beta.3",
"webfontloader": "^1.0.0"
},
"devDependencies": {

View File

@ -16,3 +16,9 @@
<script lang="ts" setup>
import HeaderComponent from "./components/Header/HeaderComponent.vue";
</script>
<style>
html {
overflow: auto;
}
</style>

View File

@ -16,7 +16,7 @@
<v-navigation-drawer
:expand-on-hover="!mobile"
:rail="!mobile"
position="right"
location="right"
v-if="isLoggedIn"
v-model="drawer"
:temporary="mobile"

View File

@ -40,7 +40,7 @@
</template>
<script setup lang="ts">
import type { Guild } from "@/data/Guild";
import type { Guild } from "@/data/guild/Guild";
import { getInviteLink } from "@/services/guildService";
import { useInviteLinkStore } from "@/stores/inviteLink";
import { useMutualGuildsStore } from "@/stores/mutualGuilds";

View File

@ -0,0 +1,68 @@
<template>
<div>
<v-card>
<v-card-title>{{ props.descriptor.name }}</v-card-title>
<v-card-content>
<v-row v-if="props.descriptor.mainField">
<v-col>
<bool-field-component
v-if="props.descriptor.mainField.type == 'BOOL'"
:fieldDescription="props.descriptor.mainField"
></bool-field-component>
</v-col>
</v-row>
<template
v-if="
!!props.descriptor.mainField
? settingStoreRef.values.value[props.descriptor.mainField.id]
: true
"
>
<v-row v-for="item of props.descriptor.fields" :key="item.id">
<v-col>
<bool-field-component
v-if="item.type == 'BOOL'"
:fieldDescription="item"
></bool-field-component>
<select-field-component
:fieldDescription="item"
v-if="isSelect(item.type)"
></select-field-component>
<text-field-component
:fieldDescription="item"
v-if="item.type == 'STRING'"
></text-field-component>
</v-col>
</v-row>
</template>
</v-card-content>
</v-card>
</div>
</template>
<script setup lang="ts">
import type { SettingDescrition } from "@/data/Setting/SettingDescription";
import { useSettingStore } from "@/stores/setting";
import { storeToRefs } from "pinia";
import boolFieldComponent from "./fields/BoolFieldComponent.vue";
import SelectFieldComponent from "./fields/SelectFieldComponent.vue";
import TextFieldComponent from "./fields/TextFieldComponent.vue";
const props = defineProps<{ descriptor: SettingDescrition }>();
const settingStore = useSettingStore();
const settingStoreRef = storeToRefs(settingStore);
function isSelect(type: string) {
switch (type) {
case "TEXT_CHANNEL":
case "VOICE_CHANNEL":
case "ROLE":
return true;
default:
return false;
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,84 @@
<template>
<div>
<v-overlay
v-model="loading"
class="align-center justify-center"
persistent
scrim="grey darken-4"
z-index="1"
>
<v-progress-circular
indeterminate
color="yellow"
size="200"
width="15"
></v-progress-circular>
</v-overlay>
<v-row>
<v-col
v-for="item of settingsDescription"
:key="item.name"
md="6"
cols="12"
>
<setting-group-component :descriptor="item"></setting-group-component>
</v-col>
</v-row>
</div>
</template>
<script setup lang="ts">
import type { Guild } from "@/data/guild/Guild";
import type { SettingDescrition } from "@/data/Setting/SettingDescription";
import {
getRoles,
getTextChannels,
getVoiceChannels,
} from "@/services/guildService";
import { getSettingDescrition } from "@/services/settingsService";
import { useSettingStore } from "@/stores/setting";
import { storeToRefs } from "pinia";
import { ref } from "vue";
import SettingGroupComponent from "./SettingGroupComponent.vue";
const props = defineProps<{ guild: Guild }>();
const settingStore = useSettingStore();
const { values, loading, text_channels, voice_channels, roles } =
storeToRefs(settingStore);
loading.value = true;
values.value = {};
const settingsDescription = ref([] as SettingDescrition[]);
getSettingDescrition().then((value) => {
settingsDescription.value = value;
loadTextChannels();
});
function loadTextChannels() {
getTextChannels(props.guild.id).then((value) => {
text_channels.value = value;
loadVoiceChannels();
});
}
function loadVoiceChannels() {
getVoiceChannels(props.guild.id).then((value) => {
voice_channels.value = value;
loadRoles();
});
}
function loadRoles() {
getRoles(props.guild.id).then((value) => {
roles.value = value;
loading.value = false;
});
}
</script>
<style>
.v-input__details {
margin-bottom: 0;
}
</style>

View File

@ -0,0 +1,34 @@
<template>
<div>
<v-row>
<v-col>
<v-switch
:id="fieldDescription.id"
:label="fieldDescription.name"
color="yellow"
:messages="fieldDescription.description"
density="compact"
hide-details="auto"
:loading="loadingComp"
v-model="values[fieldDescription.id]"
></v-switch>
</v-col>
</v-row>
</div>
</template>
<script setup lang="ts">
import type { FieldDescriptor } from "@/data/Setting/SettingDescription";
import { useSettingStore } from "@/stores/setting";
import { computed } from "@vue/reactivity";
import { storeToRefs } from "pinia";
defineProps<{ fieldDescription: FieldDescriptor }>();
const settingStore = useSettingStore();
const { values, loading } = storeToRefs(settingStore);
const loadingComp = computed(() => {
return loading.value ? "primary" : false;
});
</script>
<style scoped></style>

View File

@ -0,0 +1,50 @@
<template>
<v-row>
<v-col>
<v-autocomplete
:id="fieldDescription.id"
:label="fieldDescription.name"
color="yellow"
:messages="fieldDescription.description"
density="compact"
hide-details="auto"
:loading="loadingComp"
item-title="name"
item-value="id"
:items="items?.value"
variant="outlined"
v-model="values[fieldDescription.id]"
></v-autocomplete>
</v-col>
</v-row>
</template>
<script setup lang="ts">
import type { FieldDescriptor } from "@/data/Setting/SettingDescription";
import { useSettingStore } from "@/stores/setting";
import { computed } from "@vue/reactivity";
import { storeToRefs } from "pinia";
const props = defineProps<{ fieldDescription: FieldDescriptor }>();
const settingStore = useSettingStore();
const { loading, roles, text_channels, voice_channels, values } =
storeToRefs(settingStore);
const loadingComp = computed(() => {
return loading.value ? "primary" : false;
});
const items = computed(() => {
if (props.fieldDescription.type == "TEXT_CHANNEL") {
return text_channels;
}
if (props.fieldDescription.type == "VOICE_CHANNEL") {
return voice_channels;
}
if (props.fieldDescription.type == "ROLE") {
return roles;
}
});
</script>
<style scoped></style>

View File

@ -0,0 +1,30 @@
<template>
<v-row>
<v-col>
<v-text-field
:id="fieldDescription.id"
:label="fieldDescription.name"
color="yellow"
:messages="fieldDescription.description"
density="compact"
hide-details="auto"
:loading="loading"
variant="outlined"
v-model="settingStore.values[fieldDescription.id]"
></v-text-field>
</v-col>
</v-row>
</template>
<script setup lang="ts">
import type { FieldDescriptor } from "@/data/Setting/SettingDescription";
import { useSettingStore } from "@/stores/setting";
import { storeToRefs } from "pinia";
defineProps<{ fieldDescription: FieldDescriptor }>();
const settingStore = useSettingStore();
const { loading } = storeToRefs(settingStore);
</script>
<style scoped></style>

View File

@ -20,10 +20,10 @@
</template>
<script setup lang="ts">
import type { Guild } from "@/data/Guild";
import type { Guild } from "@/data/guild/Guild";
const properties = defineProps<{
guild?: Guild;
guild: Guild;
}>();
</script>

View File

@ -0,0 +1,14 @@
type SettingDescrition = {
name: string;
mainField: FieldDescriptor;
fields: FieldDescriptor[];
};
type FieldDescriptor = {
id: string;
name: string;
description: string;
type: string;
};
export type { SettingDescrition, FieldDescriptor };

View File

@ -0,0 +1,5 @@
type SettingValue = {
[key: string]: string | boolean;
};
export type { SettingValue };

View File

@ -0,0 +1,6 @@
type Chanel = {
id: string;
name: string;
};
export type { Chanel };

View File

@ -1,4 +1,5 @@
import type { Guild } from "@/data/Guild";
import type { Chanel } from "@/data/guild/Channel";
import type { Guild } from "@/data/guild/Guild";
import type { InviteLink } from "@/data/InviteLink";
import { useEventQueuStore } from "@/stores/eventQueu";
import { useUserStore } from "@/stores/user";
@ -21,6 +22,12 @@ function getMutualGuilds(): Promise<Guild[]> {
.catch((reason) => {
console.error(`Fail to get mutal guilds !`);
console.log(reason);
const eventQueuStore = useEventQueuStore();
eventQueuStore.push({
uuid: undefined,
type: "error",
text: "Fail to retrive guilds !",
});
reject(reason);
});
});
@ -54,4 +61,87 @@ function getInviteLink(): Promise<InviteLink> {
});
}
export { getMutualGuilds, getInviteLink };
function getTextChannels(guildId: string): Promise<Chanel[]> {
return new Promise((resolve, reject) => {
const userStore = useUserStore();
axios
.get<Chanel[]>(`/guild/${guildId}/textChannels`, {
headers: {
authorization: `Bearer ${userStore.token}`,
},
})
.then((value) => {
resolve(value.data);
})
.catch((reason) => {
console.error(`Fail to get text channels !`);
console.log(reason);
const eventQueuStore = useEventQueuStore();
eventQueuStore.push({
uuid: undefined,
type: "error",
text: "Fail to retrive text channels!",
});
reject(reason);
});
});
}
function getVoiceChannels(guildId: string): Promise<Chanel[]> {
return new Promise((resolve, reject) => {
const userStore = useUserStore();
axios
.get<Chanel[]>(`/guild/${guildId}/voiceChannels`, {
headers: {
authorization: `Bearer ${userStore.token}`,
},
})
.then((value) => {
resolve(value.data);
})
.catch((reason) => {
console.error(`Fail to get text channels !`);
console.log(reason);
const eventQueuStore = useEventQueuStore();
eventQueuStore.push({
uuid: undefined,
type: "error",
text: "Fail to retrive voice channels!",
});
reject(reason);
});
});
}
function getRoles(guildId: string): Promise<Chanel[]> {
return new Promise((resolve, reject) => {
const userStore = useUserStore();
axios
.get<Chanel[]>(`/guild/${guildId}/roles`, {
headers: {
authorization: `Bearer ${userStore.token}`,
},
})
.then((value) => {
resolve(value.data);
})
.catch((reason) => {
console.error(`Fail to get roles !`);
console.log(reason);
const eventQueuStore = useEventQueuStore();
eventQueuStore.push({
uuid: undefined,
type: "error",
text: "Fail to retrive roles!",
});
reject(reason);
});
});
}
export {
getMutualGuilds,
getInviteLink,
getTextChannels,
getVoiceChannels,
getRoles,
};

View File

@ -0,0 +1,19 @@
import type { SettingDescrition } from "@/data/Setting/SettingDescription";
import { useUserStore } from "@/stores/user";
import axios from "axios";
export function getSettingDescrition() {
return new Promise<SettingDescrition[]>((resole, reject) => {
const userStore = useUserStore();
axios
.get<SettingDescrition[]>("/setting/description", {
headers: {
authorization: `Bearer ${userStore.token}`,
},
})
.then((value) => {
resole(value.data);
});
});
}

View File

@ -1,4 +1,4 @@
import type { Guild } from "@/data/Guild";
import type { Guild } from "@/data/guild/Guild";
import { defineStore } from "pinia";
export const useMutualGuildsStore = defineStore({

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

@ -0,0 +1,15 @@
import type { SettingValue } from "@/data/Setting/SettingValue";
import { defineStore } from "pinia";
export const useSettingStore = defineStore({
id: "setting",
state: () => ({
values: {} as SettingValue,
text_channels: [] as SettingValue[],
voice_channels: [] as SettingValue[],
roles: [] as SettingValue[],
loading: true,
}),
getters: {},
actions: {},
});

View File

@ -1,4 +1,4 @@
import type { Guild } from "@/data/Guild";
import type { Guild } from "@/data/guild/Guild";
import { useMutualGuildsStore } from "@/stores/mutualGuilds";
import type { Router } from "vue-router";

View File

@ -1,5 +1,5 @@
<template>
<div>
<div v-if="guild">
<v-row>
<v-col>
<v-card>

View File

@ -1,7 +1,31 @@
<template>
<div></div>
<div>
<SettingListComponent :guild="guild" v-if="guild" />
</div>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { useMutualGuildsStore } from "@/stores/mutualGuilds";
import { redirectIfNoGuild } from "@/tools/GuildTools";
import { ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import SettingListComponent from "../components/guild/Settings/SettingListComponent.vue";
const guildStore = useMutualGuildsStore();
const route = useRoute();
const router = useRouter();
const guild = ref(guildStore.getGuild(route.params.guildId as string));
redirectIfNoGuild(guild.value, router);
watch(
() => route.params.guildId,
(value, oldValue) => {
guild.value = guildStore.getGuild(value as string);
guildStore.lastGuildId = guild.value?.id;
redirectIfNoGuild(guild.value, router);
}
);
</script>
<style scoped></style>

View File

@ -3648,7 +3648,7 @@ __metadata:
vue-cli-plugin-vuetify: ~2.4.8
vue-router: ^4.0.14
vue-tsc: ^0.34.7
vuetify: ^3.0.0-beta.2
vuetify: ^3.0.0-beta.3
vuetify-loader: ^2.0.0-alpha.0
webfontloader: ^1.0.0
languageName: unknown
@ -10626,19 +10626,19 @@ __metadata:
languageName: node
linkType: hard
"vuetify@npm:^3.0.0-beta.2":
version: 3.0.0-beta.2
resolution: "vuetify@npm:3.0.0-beta.2"
"vuetify@npm:^3.0.0-beta.3":
version: 3.0.0-beta.3
resolution: "vuetify@npm:3.0.0-beta.3"
peerDependencies:
"@formatjs/intl": ^1.0.0 || ^2.0.0
vue: ^3.2.31
vue: ^3.2.36
vue-i18n: ^9.0.0
peerDependenciesMeta:
"@formatjs/intl":
optional: true
vue-i18n:
optional: true
checksum: 4d3f08a956b6c27e0f7b73b9359e1e19517347c0d81a906af72620cf9d957053ac7c548d3552e3e7cbaebcaf50bbc1b7781972eec36e194c1c366046e6dc7f02
checksum: 2e1ef8f8ac1ba3bb0f60f275d0c07e747acff59cbae920f7c963bb786c0c726729e3a06a441f8817c540840a5c0f6175477334aa3f7393f62ee4b7dd583ad287
languageName: node
linkType: hard