refactor: clean up event methods #41

Merged
Sebastian merged 1 commits from chore/clean-up-methods into main 2026-05-17 21:52:34 +00:00
5 changed files with 160 additions and 210 deletions

View File

@@ -26,7 +26,6 @@ const props = defineProps<Props>()
// Emits // Emits
const emit = defineEmits<{ const emit = defineEmits<{
close: [] close: []
sent: []
}>() }>()
const mailStore = useMailStore() const mailStore = useMailStore()
@@ -222,7 +221,6 @@ const handleSend = async () => {
text: editor.value?.getText() || '', text: editor.value?.getText() || '',
}, },
}) })
emit('sent')
} catch (error) { } catch (error) {
console.error('[Mail][Composer] Failed to send message:', error) console.error('[Mail][Composer] Failed to send message:', error)
} }

View File

@@ -23,72 +23,30 @@ const props = withDefaults(defineProps<Props>(), {
// Emits // Emits
const emit = defineEmits<{ const emit = defineEmits<{
open: [message: EntityObject] open: [message: EntityObject]
toggleSelection: [message: EntityObject] selectionMode: [message: EntityObject]
activateSelectionMode: [message: EntityObject] selectionToggleOne: [message: EntityObject]
toggleSelectAll: [value: boolean] selectionToggleAll: [value: boolean]
clearSelection: [] selectionClear: []
moveSelection: [] selectionMove: []
deleteSelection: [] selectionDelete: []
}>() }>()
const longPressTimer = ref<number | null>(null) const longPressTimer = ref<number | null>(null)
const longPressActivated = ref(false) const longPressActivated = ref(false)
const suppressNextClick = ref(false) const suppressNextClick = ref(false)
const LONG_PRESS_MS = 450 const LONG_PRESS_MS = 400
const selectedIdSet = computed(() => new Set(props.selectionList)) const selectedIdSet = computed(() => new Set(props.selectionList))
const selectionCount = computed(() => props.selectionList.length ?? 0)
const currentMessages = computed(() => props.messages ?? [])
const getMessageTimestamp = (message: EntityObject): string | null => {
return message.properties.received
|| message.properties.sent
|| message.modified
|| message.created
|| null
}
const getMessageTimeValue = (message: EntityObject): number => {
const timestamp = getMessageTimestamp(message)
if (!timestamp) {
return 0
}
const timeValue = new Date(timestamp).getTime()
return Number.isNaN(timeValue) ? 0 : timeValue
}
const selectionCount = computed(() => props.selectionList.length)
const hasSelection = computed(() => selectionCount.value > 0)
const allCurrentMessagesSelected = computed(() => {
return currentMessages.value.length > 0 && currentMessages.value.every(message => isSelected(message))
})
// Sorted messages (newest first) // Sorted messages (newest first)
const sortedMessages = computed(() => { const sortedMessages = computed(() => {
return [...currentMessages.value].sort((a, b) => { return [...props.messages].sort((a, b) => {
const dateA = getMessageTimeValue(a) const dateA = timeStamp(a) ?? 0
const dateB = getMessageTimeValue(b) const dateB = timeStamp(b) ?? 0
return dateB - dateA return dateB - dateA
}) })
}) })
// Read/Unread counts from collection properties
const unreadCount = computed(() => {
return props.selectedCollection?.properties.unread ?? 0
})
const totalCount = computed(() => {
return props.selectedCollection?.properties.total ?? 0
})
// True only when the collection explicitly provides total/unread counts
const hasCountData = computed(() => {
return props.selectedCollection?.properties.total != null
})
const isOpened = (message: EntityObject): boolean => { const isOpened = (message: EntityObject): boolean => {
if (!props.selectedMessage) return false if (!props.selectedMessage) return false
return (message.identifier === props.selectedMessage.identifier) return (message.identifier === props.selectedMessage.identifier)
@@ -98,8 +56,23 @@ const isSelected = (message: EntityObject): boolean => {
return selectedIdSet.value.has(message.identifier) return selectedIdSet.value.has(message.identifier)
} }
const timeStamp = (message: EntityObject): number | null => {
const timestamp = message.properties.received
|| message.properties.sent
|| message.modified
|| message.created
|| null
if (!timestamp) {
return null
}
const timeValue = new Date(timestamp).getTime()
return Number.isNaN(timeValue) ? null : timeValue
}
// Format date for display // Format date for display
const formatDate = (date: Date | string | null | undefined): string => { const formatDate = (date: Date | string | number | null | undefined): string => {
if (!date) return '' if (!date) return ''
const messageDate = new Date(date) const messageDate = new Date(date)
@@ -141,21 +114,19 @@ const formatDate = (date: Date | string | null | undefined): string => {
}) })
} }
// Truncate text
const truncate = (text: string | null | undefined, length: number = 100): string => {
if (!text) return ''
return text.length > length ? text.substring(0, length) + '...' : text
}
const isSelectionControlClick = (event: MouseEvent | KeyboardEvent): boolean => { const isSelectionControlClick = (event: MouseEvent | KeyboardEvent): boolean => {
return event.target instanceof Element && event.target.closest('.message-selection-checkbox') !== null return event.target instanceof Element && event.target.closest('.message-selection-checkbox') !== null
} }
const handleSelectionToggle = (message: EntityObject) => { const handleSelectionToggleOne = (message: EntityObject) => {
emit('toggleSelection', message) emit('selectionToggleOne', message)
} }
const handleMessageMouseClick = (event: MouseEvent | KeyboardEvent, message: EntityObject) => { const handleSelectionToggleAll = (value: boolean | null) => {
emit('selectionToggleAll', value === true)
}
const handleMouseClick = (event: MouseEvent | KeyboardEvent, message: EntityObject) => {
if (isSelectionControlClick(event)) { if (isSelectionControlClick(event)) {
return return
} }
@@ -168,7 +139,7 @@ const handleMessageMouseClick = (event: MouseEvent | KeyboardEvent, message: Ent
if (event.shiftKey && !props.selectionMode) { if (event.shiftKey && !props.selectionMode) {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
emit('activateSelectionMode', message) emit('selectionMode', message)
return return
} }
@@ -178,14 +149,14 @@ const handleMessageMouseClick = (event: MouseEvent | KeyboardEvent, message: Ent
} }
if (props.selectionMode) { if (props.selectionMode) {
emit('toggleSelection', message) emit('selectionToggleOne', message)
return return
} }
emit('open', message) emit('open', message)
} }
const handleMessageMouseDown = (event: MouseEvent, message: EntityObject) => { const handleMouseDown = (event: MouseEvent, message: EntityObject) => {
if (isSelectionControlClick(event)) { if (isSelectionControlClick(event)) {
return return
} }
@@ -197,14 +168,7 @@ const handleMessageMouseDown = (event: MouseEvent, message: EntityObject) => {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
suppressNextClick.value = true suppressNextClick.value = true
emit('activateSelectionMode', message) emit('selectionMode', message)
}
const clearLongPressTimer = () => {
if (longPressTimer.value !== null) {
window.clearTimeout(longPressTimer.value)
longPressTimer.value = null
}
} }
const handleTouchStart = (message: EntityObject) => { const handleTouchStart = (message: EntityObject) => {
@@ -213,9 +177,9 @@ const handleTouchStart = (message: EntityObject) => {
longPressTimer.value = window.setTimeout(() => { longPressTimer.value = window.setTimeout(() => {
if (!props.selectionMode) { if (!props.selectionMode) {
emit('activateSelectionMode', message) emit('selectionMode', message)
} else { } else {
emit('toggleSelection', message) emit('selectionToggleOne', message)
} }
longPressActivated.value = true longPressActivated.value = true
@@ -231,13 +195,16 @@ const handleTouchMove = () => {
clearLongPressTimer() clearLongPressTimer()
} }
const clearLongPressTimer = () => {
if (longPressTimer.value !== null) {
window.clearTimeout(longPressTimer.value)
longPressTimer.value = null
}
}
onBeforeUnmount(() => { onBeforeUnmount(() => {
clearLongPressTimer() clearLongPressTimer()
}) })
const handleSelectAllToggle = (value: boolean | null) => {
emit('toggleSelectAll', value === true)
}
</script> </script>
<template> <template>
@@ -245,12 +212,12 @@ const handleSelectAllToggle = (value: boolean | null) => {
<!-- Header with folder name and counts --> <!-- Header with folder name and counts -->
<div v-if="selectedCollection" class="message-list-header"> <div v-if="selectedCollection" class="message-list-header">
<div class="message-list-heading"> <div class="message-list-heading">
<h2 class="text-h6">{{ selectedCollection.properties.label || 'Folder' }}</h2> <h2 class="text-h6">{{ selectedCollection?.properties.label || 'Folder' }}</h2>
<div class="folder-counts text-caption text-medium-emphasis"> <div class="folder-counts text-caption text-medium-emphasis">
<span v-if="hasCountData"> <span v-if="selectedCollection?.properties.total != null">
<span class="unread-count">{{ unreadCount }}</span> <span class="unread-count">{{ selectedCollection?.properties.unread ?? 0 }}</span>
<span class="mx-1">/</span> <span class="mx-1">/</span>
<span>{{ totalCount }}</span> <span>{{ selectedCollection?.properties.total ?? 0 }}</span>
</span> </span>
<span v-else-if="messages.length > 0"> <span v-else-if="messages.length > 0">
{{ messages.length }} loaded {{ messages.length }} loaded
@@ -261,11 +228,11 @@ const handleSelectAllToggle = (value: boolean | null) => {
<div v-if="selectionMode && messages.length > 0" class="selection-summary"> <div v-if="selectionMode && messages.length > 0" class="selection-summary">
<div class="selection-controls"> <div class="selection-controls">
<v-checkbox-btn <v-checkbox-btn
:model-value="allCurrentMessagesSelected" :model-value="selectionCount !== 0"
:indeterminate="hasSelection && !allCurrentMessagesSelected" :indeterminate="selectionCount > 0 && selectionCount !== messages.length"
density="compact" density="compact"
hide-details hide-details
@update:model-value="handleSelectAllToggle" @update:model-value="handleSelectionToggleAll"
/> />
<span class="text-caption text-medium-emphasis"> <span class="text-caption text-medium-emphasis">
{{ selectionCount > 0 ? `${selectionCount} selected` : 'Select all loaded' }} {{ selectionCount > 0 ? `${selectionCount} selected` : 'Select all loaded' }}
@@ -277,8 +244,8 @@ const handleSelectAllToggle = (value: boolean | null) => {
size="small" size="small"
icon="mdi-folder-move-outline" icon="mdi-folder-move-outline"
variant="text" variant="text"
:disabled="!hasSelection" :disabled="selectionCount === 0"
@click="emit('moveSelection')" @click="emit('selectionMove')"
> >
<v-icon>mdi-folder-move-outline</v-icon> <v-icon>mdi-folder-move-outline</v-icon>
<v-tooltip activator="parent" location="bottom">Move Selected</v-tooltip> <v-tooltip activator="parent" location="bottom">Move Selected</v-tooltip>
@@ -287,8 +254,8 @@ const handleSelectAllToggle = (value: boolean | null) => {
size="small" size="small"
icon="mdi-delete-outline" icon="mdi-delete-outline"
variant="text" variant="text"
:disabled="!hasSelection" :disabled="selectionCount === 0"
@click="emit('deleteSelection')" @click="emit('selectionDelete')"
> >
<v-icon>mdi-delete-outline</v-icon> <v-icon>mdi-delete-outline</v-icon>
<v-tooltip activator="parent" location="bottom">Delete Selected</v-tooltip> <v-tooltip activator="parent" location="bottom">Delete Selected</v-tooltip>
@@ -297,7 +264,7 @@ const handleSelectAllToggle = (value: boolean | null) => {
size="small" size="small"
icon="mdi-close" icon="mdi-close"
variant="text" variant="text"
@click="emit('clearSelection')" @click="emit('selectionClear')"
> >
<v-icon>mdi-close</v-icon> <v-icon>mdi-close</v-icon>
<v-tooltip activator="parent" location="bottom">Clear Selected</v-tooltip> <v-tooltip activator="parent" location="bottom">Clear Selected</v-tooltip>
@@ -317,7 +284,7 @@ const handleSelectAllToggle = (value: boolean | null) => {
</div> </div>
<!-- Empty state --> <!-- Empty state -->
<div v-else-if="currentMessages.length === 0" class="pa-8 text-center"> <div v-else-if="messages.length === 0" class="pa-8 text-center">
<v-icon size="64" color="grey-lighten-1">mdi-email-outline</v-icon> <v-icon size="64" color="grey-lighten-1">mdi-email-outline</v-icon>
<div class="text-h6 mt-4 text-medium-emphasis">No messages</div> <div class="text-h6 mt-4 text-medium-emphasis">No messages</div>
<div class="text-body-2 text-medium-emphasis"> <div class="text-body-2 text-medium-emphasis">
@@ -342,8 +309,8 @@ const handleSelectAllToggle = (value: boolean | null) => {
'selection-mode': selectionMode, 'selection-mode': selectionMode,
'unread': !message.properties.isRead 'unread': !message.properties.isRead
}" }"
@mousedown="handleMessageMouseDown($event, message)" @mousedown="handleMouseDown($event, message)"
@click="handleMessageMouseClick($event, message)" @click="handleMouseClick($event, message)"
@touchstart.passive="handleTouchStart(message)" @touchstart.passive="handleTouchStart(message)"
@touchend="handleTouchEnd" @touchend="handleTouchEnd"
@touchcancel="handleTouchEnd" @touchcancel="handleTouchEnd"
@@ -358,7 +325,7 @@ const handleSelectAllToggle = (value: boolean | null) => {
density="compact" density="compact"
hide-details hide-details
@click.stop @click.stop
@update:model-value="handleSelectionToggle(message)" @update:model-value="handleSelectionToggleOne(message)"
/> />
<v-avatar size="40" color="primary"> <v-avatar size="40" color="primary">
@@ -374,7 +341,7 @@ const handleSelectAllToggle = (value: boolean | null) => {
{{ message.properties.from?.label || message.properties.from?.address || 'Unknown Sender' }} {{ message.properties.from?.label || message.properties.from?.address || 'Unknown Sender' }}
</span> </span>
<span class="text-caption text-medium-emphasis ml-2"> <span class="text-caption text-medium-emphasis ml-2">
{{ formatDate(getMessageTimestamp(message)) }} {{ formatDate(timeStamp(message)) }}
</span> </span>
</v-list-item-title> </v-list-item-title>

View File

@@ -94,53 +94,6 @@ const {
const handleFolderSelect = (folder: CollectionObject) => mailStore.selectFolder(folder) const handleFolderSelect = (folder: CollectionObject) => mailStore.selectFolder(folder)
const handleMessageOpen = (message: EntityObject) => {
mailStore.selectMessage(message)
if (isMobile.value) {
mailUiStore.closeSidebar()
}
}
const handleMessageSelectionToggle = (message: EntityObject) => mailUiStore.toggleMessageSelection(message)
const handleSelectionModeActivate = (message: EntityObject) => mailUiStore.activateSelectionMode(message)
const handleSelectAllToggle = (value: boolean) => {
if (value) {
mailUiStore.selectAllCurrentMessages()
return
}
mailUiStore.clearSelection()
}
const handleSelectionClear = () => mailUiStore.deactivateSelectionMode()
const handleSelectionMove = () => mailUiStore.openMoveMessagesDialog()
const handleSelectionDelete = () => mailUiStore.deleteSelectedMessages()
const handleCompose = () => mailUiStore.openCompose()
const handleComposeReply = (message: EntityObject) => mailUiStore.openCompose(message, 'reply')
const handleComposeForward = (message: EntityObject) => mailUiStore.openCompose(message, 'forward')
const handleComposeClose = () => mailUiStore.closeCompose()
const handleComposeSent = () => mailUiStore.afterSent()
const handleDelete = (message: EntityObject) => {
mailStore.deleteMessages([message.identifier])
}
const handleMove = (message: EntityObject) => mailUiStore.openMoveMessagesDialog(message)
const handleMoveConfirm = async (target: CollectionObject) => { await mailUiStore.confirmMoveMessages(target) }
const handleMoveCancel = () => mailUiStore.closeMoveMessagesDialog()
const handleFolderCreateConfirm = async (folderName: string) => { const handleFolderCreateConfirm = async (folderName: string) => {
try { try {
const mutatedFolder = await mailUiStore.confirmCreateFolder(folderName) const mutatedFolder = await mailUiStore.confirmCreateFolder(folderName)
@@ -153,7 +106,7 @@ const handleFolderCreateConfirm = async (folderName: string) => {
} }
} }
const handleFolderRenameConfirm = async (folderName: string) => { const handleFolderEditConfirm = async (folderName: string) => {
try { try {
const mutatedFolder = await mailUiStore.confirmRenameFolder(folderName) const mutatedFolder = await mailUiStore.confirmRenameFolder(folderName)
@@ -165,6 +118,14 @@ const handleFolderRenameConfirm = async (folderName: string) => {
} }
} }
const handleFolderDeleteConfirm = async () => {
try {
await mailUiStore.confirmDeleteFolder()
} catch (error: unknown) {
console.error('[MailPage] Failed to delete folder:', error)
}
}
const handleFolderMoveConfirm = async (targetFolder: CollectionObject) => { const handleFolderMoveConfirm = async (targetFolder: CollectionObject) => {
try { try {
await mailUiStore.confirmMoveFolder(targetFolder) await mailUiStore.confirmMoveFolder(targetFolder)
@@ -175,14 +136,47 @@ const handleFolderMoveConfirm = async (targetFolder: CollectionObject) => {
const handleFolderMoveCancel = () => mailUiStore.closeMoveFolderDialog() const handleFolderMoveCancel = () => mailUiStore.closeMoveFolderDialog()
const handleFolderDeleteConfirm = async () => {
try { const handleMessageOpen = (message: EntityObject) => {
await mailUiStore.confirmDeleteFolder() mailStore.selectMessage(message)
} catch (error: unknown) {
console.error('[MailPage] Failed to delete folder:', error) if (isMobile.value) {
mailUiStore.closeSidebar()
} }
} }
const handleMessageComposeFresh = () => mailUiStore.openCompose()
const handleMessageComposeReply = (message: EntityObject) => mailUiStore.openCompose(message, 'reply')
const handleMessageComposeForward = (message: EntityObject) => mailUiStore.openCompose(message, 'forward')
const handleMessageComposeClose = () => mailUiStore.closeCompose()
const handleMessageDelete = (message: EntityObject) => {
mailStore.deleteMessages([message.identifier])
}
const handleMessageMove = (message: EntityObject) => mailUiStore.openMoveMessagesDialog(message)
const handleMessageMoveConfirm = async (target: CollectionObject) => { await mailUiStore.confirmMoveMessages(target) }
const handleMessageMoveCancel = () => mailUiStore.closeMoveMessagesDialog()
const handleMessageSelectionMode = (message: EntityObject) => mailUiStore.messageSelectionModeActivate(message)
const handleMessageSelectionToggleOne = (message: EntityObject) => mailUiStore.messageSelectionToggleOne(message)
const handleMessageSelectionToggleAll = (value: boolean) => {
mailUiStore.messageSelectionToggleAll(value)
}
const handleMessageSelectionClear = () => mailUiStore.messageSelectionModeDeactivate()
const handleMessageSelectionMove = () => mailUiStore.openMoveMessagesDialog()
const handleMessageSelectionDelete = () => mailUiStore.deleteSelectedMessages()
const toggleSidebar = () => mailUiStore.toggleSidebar() const toggleSidebar = () => mailUiStore.toggleSidebar()
const handleSettingsOpen = () => mailUiStore.openSettings() const handleSettingsOpen = () => mailUiStore.openSettings()
@@ -225,7 +219,7 @@ const handleSettingsOpen = () => mailUiStore.openSettings()
<v-btn <v-btn
icon="mdi-pencil" icon="mdi-pencil"
@click="handleCompose()" @click="handleMessageComposeFresh()"
color="primary" color="primary"
variant="text" variant="text"
> >
@@ -298,12 +292,12 @@ const handleSettingsOpen = () => mailUiStore.openSettings()
:selection-mode="selectionMode" :selection-mode="selectionMode"
:loading="loading" :loading="loading"
@open="handleMessageOpen" @open="handleMessageOpen"
@toggle-selection="handleMessageSelectionToggle" @selection-mode="handleMessageSelectionMode"
@activate-selection-mode="handleSelectionModeActivate" @selection-toggle-one="handleMessageSelectionToggleOne"
@toggle-select-all="handleSelectAllToggle" @selection-toggle-all="handleMessageSelectionToggleAll"
@clear-selection="handleSelectionClear" @selection-clear="handleMessageSelectionClear"
@move-selection="handleSelectionMove" @selection-move="handleMessageSelectionMove"
@delete-selection="handleSelectionDelete" @selection-delete="handleMessageSelectionDelete"
/> />
</div> </div>
@@ -314,18 +308,17 @@ const handleSettingsOpen = () => mailUiStore.openSettings()
:mode="composeMode" :mode="composeMode"
:source="composeSource" :source="composeSource"
:folder="selectedFolder" :folder="selectedFolder"
@close="handleComposeClose" @close="handleMessageComposeClose"
@sent="handleComposeSent"
/> />
<MessageReader <MessageReader
v-else v-else
:entity="selectedMessage" :entity="selectedMessage"
@compose="handleCompose" @compose="handleMessageComposeFresh"
@reply="handleComposeReply" @reply="handleMessageComposeReply"
@forward="handleComposeForward" @forward="handleMessageComposeForward"
@move="handleMove" @move="handleMessageMove"
@delete="handleDelete" @delete="handleMessageDelete"
/> />
</div> </div>
</div> </div>
@@ -336,19 +329,19 @@ const handleSettingsOpen = () => mailUiStore.openSettings()
<SettingsDialog v-model="settingsDialogVisible" /> <SettingsDialog v-model="settingsDialogVisible" />
<FolderSelectionDialog <FolderSelectionDialog
v-if="moveMessagesDialogService && moveFolderDialogSource" v-if="moveMessagesDialogService"
v-model="moveMessagesDialogVisible" v-model="moveMessagesDialogVisible"
:service="moveMessagesDialogService" :service="moveMessagesDialogService"
:loading="loading" :loading="loading"
title="Move Messages To" title="Move Messages To"
confirm-text="Move" confirm-text="Move"
empty-text="No other folders are available in this account." empty-text="No other folders are available in this account."
@select="handleMoveConfirm" @select="handleMessageMoveConfirm"
@cancel="handleMoveCancel" @cancel="handleMessageMoveCancel"
/> />
<FolderSelectionDialog <FolderSelectionDialog
v-if="moveFolderDialogService && moveFolderDialogSource" v-if="moveFolderDialogService"
v-model="moveFolderDialogVisible" v-model="moveFolderDialogVisible"
:service="moveFolderDialogService" :service="moveFolderDialogService"
:loading="collectionsStore.transceiving" :loading="collectionsStore.transceiving"
@@ -380,7 +373,7 @@ const handleSettingsOpen = () => mailUiStore.openSettings()
:validate-name="validateRenameFolderName" :validate-name="validateRenameFolderName"
:loading="renameFolderDialogLoading" :loading="renameFolderDialogLoading"
:error-message="renameFolderDialogError" :error-message="renameFolderDialogError"
@confirm="handleFolderRenameConfirm" @confirm="handleFolderEditConfirm"
/> />
<DeleteFolderDialog <DeleteFolderDialog

View File

@@ -82,7 +82,7 @@ export const useMailStore = defineStore('mailStore', () => {
void loadFoldersForService(service,{ selectInbox: true }) void loadFoldersForService(service,{ selectInbox: true })
}) })
} catch (error) { } catch (error) {
console.error('[Mail] Failed to initialize:', error) console.error('[Mail][Operations] Failed to initialize:', error)
} finally { } finally {
loading.value = false loading.value = false
} }
@@ -124,10 +124,7 @@ export const useMailStore = defineStore('mailStore', () => {
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : 'Failed to load folders' const message = error instanceof Error ? error.message : 'Failed to load folders'
_setServiceFolderError(service.provider, service.identifier, message) _setServiceFolderError(service.provider, service.identifier, message)
console.error( console.error(`[Mail][Operations] Failed to load folders for ${service.provider}:${String(service.identifier)}:`, error)
`[Mail] Failed to load folders for ${service.provider}:${String(service.identifier)}:`,
error,
)
_updateSyncSources() _updateSyncSources()
return {} return {}
} finally { } finally {
@@ -313,13 +310,13 @@ export const useMailStore = defineStore('mailStore', () => {
try { try {
service = await servicesStore.serviceByIdentifier(identifier, true) service = await servicesStore.serviceByIdentifier(identifier, true)
} catch (error) { } catch (error) {
console.error(`[Mail] Failed to retrieve service ${identifier}:`, error) console.error(`[Mail][Operations] Failed to retrieve service ${identifier}:`, error)
throw error throw error
} }
if (!service) { if (!service) {
const message = `Service ${identifier} not found` const message = `Service ${identifier} not found`
console.error(`[Mail] ${message}`) console.error(`[Mail][Operations] ${message}`)
throw new Error(message) throw new Error(message)
} }
@@ -333,7 +330,7 @@ export const useMailStore = defineStore('mailStore', () => {
try { try {
await entitiesStore.list([folder.identifier]) await entitiesStore.list([folder.identifier])
} catch (error) { } catch (error) {
console.error('[Mail] Failed to load messages:', error) console.error('[Mail][Operations] Failed to load messages:', error)
} }
_updateSyncSources() _updateSyncSources()
@@ -376,7 +373,7 @@ export const useMailStore = defineStore('mailStore', () => {
return draft return draft
} catch (error) { } catch (error) {
console.error('[Mail] Failed to save draft:', error) console.error('[Mail][Operations] Failed to save draft:', error)
throw error throw error
} finally { } finally {
composerSaving.value = false composerSaving.value = false
@@ -414,7 +411,7 @@ export const useMailStore = defineStore('mailStore', () => {
try { try {
await entitiesStore.delete([composerDraftIdentifier.value]) await entitiesStore.delete([composerDraftIdentifier.value])
} catch (error) { } catch (error) {
console.error('[Mail] Failed to delete draft after send:', error) console.error('[Mail][Operations] Failed to delete draft after send:', error)
} }
} }
@@ -423,7 +420,7 @@ export const useMailStore = defineStore('mailStore', () => {
return response return response
} catch (error) { } catch (error) {
const messageText = error instanceof Error ? error.message : 'Failed to send message' const messageText = error instanceof Error ? error.message : 'Failed to send message'
console.error('[Mail] Failed to send message:', error) console.error('[Mail][Operations] Failed to send message:', error)
notify(messageText, 'error') notify(messageText, 'error')
throw error throw error
} finally { } finally {
@@ -431,11 +428,7 @@ export const useMailStore = defineStore('mailStore', () => {
} }
} }
async function createFolder( async function createFolder(service: ServiceObject, label: string, parentFolder: CollectionObject | null = null): Promise<CollectionObject> {
service: ServiceObject,
label: string,
parentFolder: CollectionObject | null = null,
): Promise<CollectionObject> {
if (service.identifier === null) { if (service.identifier === null) {
throw new Error('Cannot create folder for a service without an identifier') throw new Error('Cannot create folder for a service without an identifier')
} }
@@ -574,7 +567,7 @@ export const useMailStore = defineStore('mailStore', () => {
await collectionsStore.fetch(sourceCollections) await collectionsStore.fetch(sourceCollections)
} catch (error) { } catch (error) {
const messageText = error instanceof Error ? error.message : 'Failed to move messages' const messageText = error instanceof Error ? error.message : 'Failed to move messages'
console.error('[Mail] Failed to move messages:', error) console.error('[Mail][Operations] Failed to move messages:', error)
notify(messageText, 'error') notify(messageText, 'error')
throw error throw error
} finally { } finally {
@@ -609,7 +602,7 @@ export const useMailStore = defineStore('mailStore', () => {
} }
} catch (error) { } catch (error) {
const messageText = error instanceof Error ? error.message : 'Failed to delete messages' const messageText = error instanceof Error ? error.message : 'Failed to delete messages'
console.error('[Mail] Failed to delete messages:', error) console.error('[Mail][Operations] Failed to delete messages:', error)
notify(messageText, 'error') notify(messageText, 'error')
throw error throw error
} finally { } finally {

View File

@@ -106,7 +106,7 @@ export const useMailUiStore = defineStore('mailUiStore', () => {
watch( watch(
() => mailStore.currentMessages, () => mailStore.currentMessages,
() => { () => {
reconcileSelection() messageSelectionReconcile()
}, },
) )
@@ -208,16 +208,11 @@ export const useMailUiStore = defineStore('mailUiStore', () => {
composeVisible.value = false composeVisible.value = false
} }
async function afterSent() { function messageSelectionClear() {
closeCompose()
await mailStore.reloadSelectedFolder()
}
function clearSelection() {
setSelectionList([]) setSelectionList([])
} }
function activateSelectionMode(message?: EntityObject) { function messageSelectionModeActivate(message?: EntityObject) {
selectionMode.value = true selectionMode.value = true
if (!message) { if (!message) {
@@ -231,12 +226,12 @@ export const useMailUiStore = defineStore('mailUiStore', () => {
} }
} }
function deactivateSelectionMode() { function messageSelectionModeDeactivate() {
selectionMode.value = false selectionMode.value = false
clearSelection() messageSelectionClear()
} }
function toggleMessageSelection(message: EntityObject) { function messageSelectionToggleOne(message: EntityObject) {
const identifier = message.identifier const identifier = message.identifier
selectionMode.value = true selectionMode.value = true
@@ -249,14 +244,18 @@ export const useMailUiStore = defineStore('mailUiStore', () => {
setSelectionList([...selectionList.value, identifier]) setSelectionList([...selectionList.value, identifier])
} }
function selectAllCurrentMessages() { function messageSelectionToggleAll(value: boolean) {
selectionMode.value = true selectionMode.value = true
setSelectionList(mailStore.currentMessages.map(message => message.identifier)) if (value) {
setSelectionList(mailStore.currentMessages.map(message => message.identifier))
} else {
setSelectionList([])
}
} }
function reconcileSelection() { function messageSelectionReconcile() {
if (!mailStore.selectedFolder) { if (!mailStore.selectedFolder) {
clearSelection() messageSelectionClear()
return return
} }
@@ -318,7 +317,7 @@ export const useMailUiStore = defineStore('mailUiStore', () => {
async function confirmMoveMessages(targetIdentifier: Parameters<typeof mailStore.moveMessages>[0]) { async function confirmMoveMessages(targetIdentifier: Parameters<typeof mailStore.moveMessages>[0]) {
await mailStore.moveMessages(targetIdentifier, moveMessagesDialogCandidates.value ?? []) await mailStore.moveMessages(targetIdentifier, moveMessagesDialogCandidates.value ?? [])
deactivateSelectionMode() messageSelectionModeDeactivate()
closeMoveMessagesDialog() closeMoveMessagesDialog()
} }
@@ -507,11 +506,11 @@ export const useMailUiStore = defineStore('mailUiStore', () => {
openCompose, openCompose,
closeCompose, closeCompose,
afterSent, afterSent,
activateSelectionMode, messageSelectionModeActivate,
deactivateSelectionMode, messageSelectionModeDeactivate,
toggleMessageSelection, messageSelectionToggleOne,
selectAllCurrentMessages, messageSelectionToggleAll,
clearSelection, messageSelectionClear,
validateCreateFolderName, validateCreateFolderName,
validateRenameFolderName, validateRenameFolderName,
openMoveMessagesDialog, openMoveMessagesDialog,