264 lines
7.3 KiB
Vue
264 lines
7.3 KiB
Vue
<script lang="ts" setup>
|
|
import {storeToRefs} from 'pinia'
|
|
import {useChannelStore} from '@/stores/channel'
|
|
import {useCategoryStore} from '@/stores/category'
|
|
import {computed, onMounted, onUnmounted, ref, watch} from 'vue'
|
|
import {useRoute} from 'vue-router'
|
|
import CreateChannelDialog from '@/components/channel/CreateChannelDialog.vue'
|
|
import CreateCategoryDialog from '@/components/category/CreateCategoryDialog.vue'
|
|
import {type MenuItem, useContextMenu} from '@/composables/useContextMenu'
|
|
import {useUserStore} from "@/stores/user.ts";
|
|
import {useServerStore} from "@/stores/server.ts";
|
|
import ChannelPermissionsDialog from '@/components/permissions/ChannelPermissionsDialog.vue'
|
|
import {useAuthStore} from '@/stores/auth'
|
|
import ServerSettingsDialog from '@/components/server/ServerSettingsDialog.vue'
|
|
import {onReloadAll} from '@/plugins/events.ts'
|
|
|
|
const props = defineProps<{
|
|
serverId: string
|
|
channelId?: string
|
|
}>()
|
|
|
|
const route = useRoute()
|
|
const channelStore = useChannelStore()
|
|
const categoryStore = useCategoryStore()
|
|
const userStore = useUserStore()
|
|
const serverStore = useServerStore()
|
|
const {currentTree} = storeToRefs(serverStore)
|
|
const {openContextMenu} = useContextMenu()
|
|
const authStore = useAuthStore()
|
|
const showPermissionsDialog = ref(false)
|
|
const selectedChannel = ref<any | null>(null)
|
|
const showServerSettings = ref(false)
|
|
const serverName = computed(() => serverStore.servers.find(server => server.id === props.serverId)?.name || 'Serveur')
|
|
|
|
|
|
const loadServerData = async (targetServerId: string) => {
|
|
if (!targetServerId) return
|
|
channelStore.reset()
|
|
categoryStore.reset()
|
|
userStore.reset()
|
|
try {
|
|
await Promise.all([
|
|
userStore.fetchUsers(targetServerId),
|
|
serverStore.fetchServerTree(targetServerId)
|
|
])
|
|
syncOpenedCategories()
|
|
} catch (error) {
|
|
console.error('Failed to load server-scoped channels and categories:', error)
|
|
}
|
|
}
|
|
|
|
let stopReloadAll: (() => void) | null = null
|
|
|
|
onMounted(() => {
|
|
stopReloadAll = onReloadAll(() => loadServerData(props.serverId))
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
stopReloadAll?.()
|
|
})
|
|
|
|
watch(
|
|
() => props.serverId,
|
|
async (newServerId) => {
|
|
if (newServerId) {
|
|
await loadServerData(newServerId)
|
|
}
|
|
},
|
|
{immediate: true}
|
|
)
|
|
|
|
const showChannelDialog = ref(false)
|
|
const showCategoryDialog = ref(false)
|
|
const selectedCategoryId = ref<string | null>(null)
|
|
const openedCategories = ref<string[]>([])
|
|
|
|
function syncOpenedCategories() {
|
|
openedCategories.value = currentTree.value
|
|
.filter((item) => 'Category' in item)
|
|
.map((item) => item.Category[0].id)
|
|
}
|
|
|
|
async function refreshServerTree() {
|
|
await serverStore.fetchServerTree(props.serverId)
|
|
syncOpenedCategories()
|
|
}
|
|
|
|
// Right click menu (sidebar)
|
|
function onSidebarContextMenu(event: MouseEvent) {
|
|
const menuItems: MenuItem[] = [
|
|
{
|
|
label: 'Nouveau canal',
|
|
icon: 'mdi-plus',
|
|
action: () => {
|
|
selectedCategoryId.value = null
|
|
showChannelDialog.value = true
|
|
},
|
|
},
|
|
{
|
|
label: 'Nouvelle catégorie',
|
|
icon: 'mdi-folder-plus',
|
|
action: () => { showCategoryDialog.value = true },
|
|
}
|
|
]
|
|
openContextMenu(event, menuItems);
|
|
}
|
|
|
|
function onCategoryContextMenu(event: MouseEvent, category: any) {
|
|
const menuItems: MenuItem[] = [
|
|
{
|
|
label: 'Nouveau canal',
|
|
icon: 'mdi-plus',
|
|
action: () => {
|
|
selectedCategoryId.value = category.id
|
|
showChannelDialog.value = true
|
|
},
|
|
},
|
|
]
|
|
openContextMenu(event, menuItems)
|
|
}
|
|
|
|
// Right click menu (channel)
|
|
async function openEditDialog(channel: any) {
|
|
console.log("edit dialog clicked")
|
|
}
|
|
|
|
async function deleteChannel(channelId: string) {
|
|
console.log("delete channel clicked")
|
|
}
|
|
|
|
function onChannelContextMenu(event: MouseEvent, channel: any) {
|
|
const menuItems: MenuItem[] = [
|
|
...(authStore.isAdmin ? [{
|
|
label: 'Gérer les permissions',
|
|
icon: 'mdi-shield-key',
|
|
action: () => {
|
|
selectedChannel.value = channel
|
|
showPermissionsDialog.value = true
|
|
},
|
|
}] : []),
|
|
{
|
|
label: 'Marquer comme lu',
|
|
icon: 'mdi-check',
|
|
action: () => console.log('Marqué comme lu', channel.id),
|
|
},
|
|
{
|
|
label: 'Modifier le canal',
|
|
icon: 'mdi-pencil',
|
|
action: () => openEditDialog(channel),
|
|
},
|
|
{
|
|
label: 'Supprimer le canal',
|
|
icon: 'mdi-delete',
|
|
color: 'error',
|
|
action: () => deleteChannel(channel.id),
|
|
},
|
|
]
|
|
openContextMenu(event, menuItems);
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<v-navigation-drawer width="244" @contextmenu="onSidebarContextMenu">
|
|
<v-sheet color="grey-lighten-5" height="128" width="100%" class="pa-3">
|
|
<v-btn block variant="text" prepend-icon="mdi-cog" @click="showServerSettings = true">Gérer le serveur</v-btn>
|
|
</v-sheet>
|
|
|
|
<v-list
|
|
v-model:opened="openedCategories"
|
|
open-strategy="multiple"
|
|
density="compact"
|
|
>
|
|
<template v-for="(item, index) in currentTree" :key="index">
|
|
<!-- Catégorie et ses canaux enfants -->
|
|
<v-list-group v-if="'Category' in item" :value="item.Category[0].id">
|
|
<template #activator="{ props: groupProps }">
|
|
<v-list-item
|
|
:title="item.Category[0].name"
|
|
v-bind="groupProps"
|
|
@contextmenu="onCategoryContextMenu($event, item.Category[0])"
|
|
/>
|
|
</template>
|
|
|
|
<v-list-item
|
|
v-for="channel in item.Category[1]"
|
|
:key="channel.id"
|
|
:title="channel.name"
|
|
:to="`/server/${serverId}/channel/${channel.id}`"
|
|
:class="{ 'font-weight-bold': (channel.unread_count ?? 0) > 0 }"
|
|
link
|
|
@contextmenu="onChannelContextMenu($event, channel)"
|
|
>
|
|
<template #append>
|
|
<v-chip
|
|
v-if="(channel.unread_count ?? 0) > 0"
|
|
color="primary"
|
|
density="compact"
|
|
size="small"
|
|
variant="flat"
|
|
>
|
|
{{ channel.unread_count }}
|
|
</v-chip>
|
|
</template>
|
|
</v-list-item>
|
|
</v-list-group>
|
|
|
|
<!-- Canal orphelin (racine) -->
|
|
<v-list-item
|
|
v-else-if="'Channel' in item"
|
|
:key="item.Channel.id"
|
|
:title="item.Channel.name"
|
|
:to="`/server/${serverId}/channel/${item.Channel.id}`"
|
|
:class="{ 'font-weight-bold': (item.Channel.unread_count ?? 0) > 0 }"
|
|
link
|
|
@contextmenu="onChannelContextMenu($event, item.Channel)"
|
|
>
|
|
<template #append>
|
|
<v-chip
|
|
v-if="(item.Channel.unread_count ?? 0) > 0"
|
|
color="primary"
|
|
density="compact"
|
|
size="small"
|
|
variant="flat"
|
|
>
|
|
{{ item.Channel.unread_count }}
|
|
</v-chip>
|
|
</template>
|
|
</v-list-item>
|
|
</template>
|
|
</v-list>
|
|
</v-navigation-drawer>
|
|
|
|
<CreateChannelDialog
|
|
v-model="showChannelDialog"
|
|
:category-id="selectedCategoryId"
|
|
:server-id="serverId"
|
|
@created="refreshServerTree"
|
|
/>
|
|
|
|
<CreateCategoryDialog
|
|
v-model="showCategoryDialog"
|
|
:server-id="serverId"
|
|
@created="refreshServerTree"
|
|
/>
|
|
|
|
<ChannelPermissionsDialog
|
|
v-model="showPermissionsDialog"
|
|
:channel="selectedChannel"
|
|
:server-id="serverId"
|
|
/>
|
|
|
|
<ServerSettingsDialog
|
|
v-model="showServerSettings"
|
|
:server-id="serverId"
|
|
:server-name="serverName"
|
|
/>
|
|
|
|
<v-main>
|
|
<router-view/>
|
|
</v-main>
|
|
</template>
|