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

233
src/stores/mailStore.ts Normal file
View File

@@ -0,0 +1,233 @@
import { ref, computed, shallowRef } from 'vue'
import { defineStore } from 'pinia'
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'
export const useMailStore = defineStore('mailStore', () => {
const collectionsStore = useCollectionsStore()
const entitiesStore = useEntitiesStore()
const servicesStore = useServicesStore()
// Background mail sync
const mailSync = useMailSync({
interval: 30000,
autoStart: false,
fetchDetails: true,
})
// ── UI State ──────────────────────────────────────────────────────────────
const sidebarVisible = ref(true)
const settingsDialogVisible = ref(false)
const loading = ref(false)
// ── Selection State ───────────────────────────────────────────────────────
const selectedFolder = shallowRef<CollectionObject | null>(null)
const selectedMessage = shallowRef<EntityInterface<MessageInterface> | null>(null)
// ── Compose State ─────────────────────────────────────────────────────────
const composeMode = ref(false)
const composeReplyTo = shallowRef<EntityInterface<MessageInterface> | null>(null)
// ── Notification State ────────────────────────────────────────────────────
const snackbarVisible = ref(false)
const snackbarMessage = ref('')
const snackbarColor = ref<'success' | 'error' | 'info' | 'warning'>('success')
// ── Computed ──────────────────────────────────────────────────────────────
const currentMessages = computed(() => {
if (!selectedFolder.value) return []
const folder = selectedFolder.value
// Access entitiesStore.entities (reactive computed array) so Vue tracks it
return entitiesStore.entities.filter(e =>
e.provider === folder.provider &&
String(e.service) === String(folder.service) &&
String(e.collection) === String(folder.identifier),
)
})
// ── Sync Helpers ──────────────────────────────────────────────────────────
function _updateSyncSources() {
mailSync.clearSources()
// Track the currently selected folder
if (selectedFolder.value) {
mailSync.addSource({
provider: selectedFolder.value.provider,
service: selectedFolder.value.service,
collections: [selectedFolder.value.identifier],
})
}
// Always track inboxes for each account (for new-mail notifications)
servicesStore.services.forEach(service => {
const inboxes = collectionsStore.collections.filter(
c =>
c.service === service.identifier &&
(c.properties.role === 'inbox' ||
String(c.identifier).toLowerCase() === 'inbox'),
)
if (inboxes.length > 0) {
mailSync.addSource({
provider: service.provider,
service: service.identifier as string | number,
collections: inboxes.map(inbox => inbox.identifier),
})
}
})
if (mailSync.sources.value.length > 0 && !mailSync.isRunning.value) {
mailSync.start()
}
}
// ── Actions ───────────────────────────────────────────────────────────────
async function selectFolder(folder: CollectionObject) {
selectedFolder.value = folder
selectedMessage.value = null
composeMode.value = false
try {
await entitiesStore.list({
[folder.provider]: {
[folder.service]: {
[folder.identifier]: true,
},
},
})
} catch (error) {
console.error('[Mail] Failed to load messages:', error)
}
_updateSyncSources()
}
function selectMessage(message: EntityInterface<MessageInterface>, closeSidebar = false) {
selectedMessage.value = message
composeMode.value = false
if (closeSidebar) {
sidebarVisible.value = false
}
}
function openCompose(replyTo?: EntityInterface<MessageInterface>) {
composeMode.value = true
composeReplyTo.value = replyTo ?? null
selectedMessage.value = null
}
function closeCompose() {
composeMode.value = false
composeReplyTo.value = null
}
async function afterSent() {
composeMode.value = false
composeReplyTo.value = null
// Reload the current folder so the sent message appears in Sent
if (selectedFolder.value) {
await selectFolder(selectedFolder.value)
}
}
async function deleteMessage(message: EntityInterface<MessageInterface>) {
// TODO: implement delete via entity / collection store
console.log('[Mail] Delete message:', message.identifier)
}
function toggleSidebar() {
sidebarVisible.value = !sidebarVisible.value
}
function openSettings() {
settingsDialogVisible.value = true
}
function notify(message: string, color: typeof snackbarColor.value = 'success') {
snackbarMessage.value = message
snackbarColor.value = color
snackbarVisible.value = true
}
async function onFolderCreated(folder: CollectionObject) {
notify(`Folder "${folder.properties.label}" created successfully`)
// Reload collections so the sidebar reflects the new folder
await collectionsStore.list()
}
// ── Initialization ────────────────────────────────────────────────────────
async function initialize() {
loading.value = true
try {
await servicesStore.list()
await collectionsStore.list()
// Select inbox by default
const inbox = collectionsStore.collections.find(c => c.properties.role === 'inbox')
if (inbox) {
await selectFolder(inbox)
}
mailSync.start()
} catch (error) {
console.error('[Mail] Failed to initialize:', error)
} finally {
loading.value = false
}
}
// ── Exports ───────────────────────────────────────────────────────────────
return {
// Sub-stores (forwarded for template convenience)
collectionsStore,
entitiesStore,
servicesStore,
mailSync,
// State
sidebarVisible,
settingsDialogVisible,
loading,
selectedFolder,
selectedMessage,
composeMode,
composeReplyTo,
snackbarVisible,
snackbarMessage,
snackbarColor,
// Computed
currentMessages,
// Actions
selectFolder,
selectMessage,
openCompose,
closeCompose,
afterSent,
deleteMessage,
toggleSidebar,
openSettings,
notify,
onFolderCreated,
initialize,
}
})