refactor: use module store

Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
2026-03-03 21:57:17 -05:00
parent 00cbd15cf7
commit 4fd3042271
4 changed files with 284 additions and 184 deletions

View File

@@ -1,22 +1,20 @@
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { computed, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useDisplay } from 'vuetify'
import { useModuleStore } from '@KTXC'
import { useCollectionsStore } from '@MailManager/stores/collectionsStore'
import { useEntitiesStore } from '@MailManager/stores/entitiesStore'
import { useServicesStore } from '@MailManager/stores/servicesStore'
import { useMailSync } from '@MailManager/composables/useMailSync'
import type { CollectionObject } from '@MailManager/models/collection'
import type { EntityInterface } from '@MailManager/types/entity'
import type { MessageInterface } from '@MailManager/types/message'
import { useMailStore } from '@/stores/mailStore'
import FolderTree from '@/components/FolderTree.vue'
import MessageList from '@/components/MessageList.vue'
import MessageReader from '@/components/MessageReader.vue'
import MessageComposer from '@/components/MessageComposer.vue'
import SettingsDialog from '@/components/settings/SettingsDialog.vue'
import type { EntityInterface } from '@MailManager/types/entity'
import type { MessageInterface } from '@MailManager/types/message'
// Vuetify display for responsive behavior
const display = useDisplay()
const isMobile = computed(() => display.mdAndDown.value)
// Check if mail manager is available
const moduleStore = useModuleStore()
@@ -24,194 +22,59 @@ const isMailManagerAvailable = computed(() => {
return moduleStore.has('mail_manager') || moduleStore.has('MailManager')
})
// Snackbar state for notifications
const snackbarVisible = ref(false)
const snackbarMessage = ref('')
const snackbarColor = ref('success')
// Mail store — single source of truth for all mail UI state
const mailStore = useMailStore()
// Stores
const collectionsStore = useCollectionsStore()
const entitiesStore = useEntitiesStore()
const servicesStore = useServicesStore()
// storeToRefs preserves reactivity for state and computed properties
const {
sidebarVisible,
settingsDialogVisible,
loading,
selectedFolder,
selectedMessage,
composeMode,
composeReplyTo,
snackbarVisible,
snackbarMessage,
snackbarColor,
currentMessages,
} = storeToRefs(mailStore)
// Background mail sync
const mailSync = useMailSync({
interval: 30000, // Check every 30 seconds
autoStart: false, // We'll start it manually after initialization
fetchDetails: true, // Auto-fetch full message details for new/modified messages
})
// UI state
const sidebarVisible = ref(true)
const selectedFolder = ref<CollectionObject | null>(null)
const selectedMessage = ref<EntityInterface<MessageInterface> | null>(null)
const composeMode = ref(false)
const composeReplyTo = ref<EntityInterface<MessageInterface> | null>(null)
const settingsDialogVisible = ref(false)
// Loading state
const loading = ref(false)
// Computed
const isMobile = computed(() => display.mdAndDown.value)
// Complex store/composable objects accessed directly (not simple refs)
const { mailSync, entitiesStore } = mailStore
// Initialize
onMounted(async () => {
if (!isMailManagerAvailable.value) return
loading.value = true
try {
// Load services (accounts)
await servicesStore.list()
// Load collections (folders)
await collectionsStore.list()
// Select inbox by default if available
const inbox = collectionsStore.collections.find(c => c.properties.role === 'inbox')
if (inbox) {
handleFolderSelect(inbox)
}
// Start background sync after initialization
mailSync.start()
} catch (error) {
console.error('[Mail] Failed to initialize:', error)
} finally {
loading.value = false
}
await mailStore.initialize()
})
// Watch for folder and service changes to update sync sources
watch(
[selectedFolder, () => servicesStore.services],
() => {
if (!isMailManagerAvailable.value) return
// Handlers — thin wrappers that delegate to the store
const handleFolderSelect = (folder: Parameters<typeof mailStore.selectFolder>[0]) =>
mailStore.selectFolder(folder)
mailSync.clearSources()
const handleMessageSelect = (message: EntityInterface<MessageInterface>) =>
mailStore.selectMessage(message, isMobile.value)
// Add currently selected folder to sync
if (selectedFolder.value) {
mailSync.addSource({
provider: selectedFolder.value.provider,
service: selectedFolder.value.service,
collections: [selectedFolder.value.identifier],
})
}
const handleCompose = (replyTo?: EntityInterface<MessageInterface>) =>
mailStore.openCompose(replyTo)
// Add inbox for each service to get notifications
servicesStore.services.forEach(service => {
// Find inbox collection for this service
const inboxes = collectionsStore.collections.filter(
c => c.service === service.identifier &&
(c.properties.role === 'inbox' ||
String(c.identifier).toLowerCase() === 'inbox')
)
const handleComposeClose = () => mailStore.closeCompose()
if (inboxes.length > 0) {
mailSync.addSource({
provider: service.provider,
service: service.identifier as string | number,
collections: inboxes.map(inbox => inbox.identifier),
})
}
})
const handleComposeSent = () => mailStore.afterSent()
// Restart sync with updated sources
if (mailSync.sources.value.length > 0 && !mailSync.isRunning.value) {
mailSync.start()
}
},
{ deep: true }
)
const handleReply = (message: EntityInterface<MessageInterface>) =>
mailStore.openCompose(message)
// Handlers
const handleFolderSelect = async (folder: CollectionObject) => {
selectedFolder.value = folder
selectedMessage.value = null
composeMode.value = false
// Load messages for this folder
try {
await entitiesStore.list({
[folder.provider]: {
[folder.service]: {
[folder.identifier]: true
}
}
})
} catch (error) {
console.error('[Mail] Failed to load messages:', error)
}
}
const handleDelete = (message: EntityInterface<MessageInterface>) =>
mailStore.deleteMessage(message)
const handleMessageSelect = (message: EntityInterface<MessageInterface>) => {
selectedMessage.value = message
composeMode.value = false
// Close sidebar on mobile after selection
if (isMobile.value) {
sidebarVisible.value = false
}
}
const toggleSidebar = () => mailStore.toggleSidebar()
const handleCompose = (replyTo?: EntityInterface<MessageInterface>) => {
composeMode.value = true
composeReplyTo.value = replyTo || null
selectedMessage.value = null
}
const handleSettingsOpen = () => mailStore.openSettings()
const handleComposeClose = () => {
composeMode.value = false
composeReplyTo.value = null
}
const handleComposeSent = () => {
composeMode.value = false
composeReplyTo.value = null
// Reload current folder to show sent message in Sent folder
if (selectedFolder.value) {
handleFolderSelect(selectedFolder.value)
}
}
const handleReply = (message: EntityInterface<MessageInterface>) => {
handleCompose(message)
}
const handleDelete = async (message: EntityInterface<MessageInterface>) => {
// TODO: Implement delete functionality
console.log('[Mail] Delete message:', message.identifier)
}
const toggleSidebar = () => {
sidebarVisible.value = !sidebarVisible.value
}
const handleSettingsOpen = () => {
settingsDialogVisible.value = true
}
const handleFolderCreated = (folder: CollectionObject) => {
snackbarMessage.value = `Folder "${folder.properties.label}" created successfully`
snackbarColor.value = 'success'
snackbarVisible.value = true
// Reload collections to ensure UI is in sync
collectionsStore.list()
}
// Messages for current folder
const currentMessages = computed(() => {
if (!selectedFolder.value) return []
return entitiesStore.entitiesForCollection(
selectedFolder.value.provider,
selectedFolder.value.service,
selectedFolder.value.identifier
)
})
const handleFolderCreated = (folder: Parameters<typeof mailStore.onFolderCreated>[0]) =>
mailStore.onFolderCreated(folder)
</script>
<template>