feat: implement patch and settings store

Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
2026-05-19 22:27:51 -04:00
parent c3c41f7ba0
commit 8ba40a971e
9 changed files with 560 additions and 330 deletions

View File

@@ -78,9 +78,7 @@ export const useMailStore = defineStore('mailStore', () => {
await servicesStore.list()
const services = [...servicesStore.servicesEnabled]
services.forEach(service => {
void loadFoldersForService(service,{ selectInbox: true })
})
await Promise.all(services.map(service => loadFoldersForService(service)))
} catch (error) {
console.error('[Mail][Operations] Failed to initialize:', error)
} finally {
@@ -88,10 +86,7 @@ export const useMailStore = defineStore('mailStore', () => {
}
}
async function loadFoldersForService(
service: ServiceObject,
options: { selectInbox?: boolean } = {},
) {
async function loadFoldersForService(service: ServiceObject) {
if (service.identifier === null) {
return
@@ -102,24 +97,10 @@ export const useMailStore = defineStore('mailStore', () => {
try {
// retrieve folders for service
const collections = await collectionsStore.collectionsForService(service.provider, service.identifier, true)
await collectionsStore.collectionsForService(service.provider, service.identifier, true)
_setServiceFolderLoaded(service.provider, service.identifier, true)
if (options.selectInbox && !selectedFolder.value) {
const inbox = Object.values(collections).find(
folder =>
folder.provider === service.provider &&
String(folder.service) === String(service.identifier) &&
(folder.properties.role === 'inbox' ||
String(folder.identifier).toLowerCase() === 'inbox'),
)
if (inbox) {
await selectFolder(inbox)
}
}
_updateSyncSources()
} catch (error) {
const message = error instanceof Error ? error.message : 'Failed to load folders'
@@ -323,41 +304,25 @@ export const useMailStore = defineStore('mailStore', () => {
return service
}
async function selectFolder(folder: CollectionObject) {
async function selectFolder(folder: CollectionObject | null) {
selectedFolder.value = folder
selectedMessage.value = null
try {
await entitiesStore.list([folder.identifier])
} catch (error) {
console.error('[Mail][Operations] Failed to load messages:', error)
if (folder) {
try {
await entitiesStore.list([folder.identifier])
} catch (error) {
console.error('[Mail][Operations] Failed to load messages:', error)
}
}
_updateSyncSources()
}
function clearSelectedFolder() {
selectedFolder.value = null
selectedMessage.value = null
_updateSyncSources()
}
function selectMessage(entity: EntityObject) {
function selectMessage(entity: EntityObject | null) {
selectedMessage.value = entity
}
function clearSelectedMessage() {
selectedMessage.value = null
}
async function reloadSelectedFolder() {
// Reload the current folder so the sent message appears in Sent
if (selectedFolder.value) {
await selectFolder(selectedFolder.value)
}
}
async function saveComposerDraft(folder: CollectionObject, message: ComposerMessageInput) {
composerSaving.value = true
@@ -380,6 +345,24 @@ export const useMailStore = defineStore('mailStore', () => {
}
}
function findFoldersByRole(role: string): CollectionObject[] {
const normalizedRole = role.toLowerCase()
return servicesStore.servicesEnabled.flatMap(service => {
if (service.identifier === null) {
return []
}
return collectionsStore.collectionsForService(service.provider, service.identifier).filter(
folder =>
folder.provider === service.provider &&
String(folder.service) === String(service.identifier) &&
(folder.properties.role === normalizedRole ||
String(folder.identifier).toLowerCase() === normalizedRole),
)
})
}
async function sendComposerMessage(message: ComposerMessageInput) {
composerSending.value = true
@@ -492,7 +475,7 @@ export const useMailStore = defineStore('mailStore', () => {
const deletedFolder = await collectionsStore.delete(folder.identifier)
if (_sameCollection(selectedFolder.value, folder)) {
clearSelectedFolder()
await selectFolder(null)
}
notify(
@@ -503,6 +486,81 @@ export const useMailStore = defineStore('mailStore', () => {
return deletedFolder
}
async function deleteMessages(entityIdentifiers: EntityIdentifier[]) {
if (entityIdentifiers.length === 0) {
return
}
loading.value = true
try {
const { successes, failures } = await entitiesStore.delete(entityIdentifiers)
if (failures.length === 0) {
notify(
successes.length === 1 ? 'Message deleted' : `${successes.length} messages deleted`,
'success',
)
}
if (failures.length > 0) {
notify(
successes.length === 0
? `Delete failed for ${failures.length === 1 ? '1 message' : `${failures.length} messages`}`
: `Deleted ${successes.length} ${successes.length === 1 ? 'message' : 'messages'}. ${failures.length} failed.`,
successes.length === 0 ? 'error' : 'warning',
)
}
} catch (error) {
const messageText = error instanceof Error ? error.message : 'Failed to delete messages'
console.error('[Mail][Operations] Failed to delete messages:', error)
notify(messageText, 'error')
throw error
} finally {
loading.value = false
}
}
async function flagMessages(entityIdentifiers: EntityIdentifier[], flags: Partial<MessageInterface['flags']>, options: { notify?: boolean } = {}) {
if (entityIdentifiers.length === 0) {
return
}
const shouldNotify = options.notify ?? true
loading.value = true
try {
const patch = entitiesStore.fresh().properties
patch.flags = flags
const { successes, failures } = await entitiesStore.patch(patch, entityIdentifiers)
if (shouldNotify && successes.length > 0) {
notify(
successes.length === 1 ? 'Message updated' : `${successes.length} messages updated`,
'success',
)
}
if (shouldNotify && failures.length > 0) {
notify(
successes.length === 0
? `Update failed for ${failures.length === 1 ? '1 message' : `${failures.length} messages`}`
: `Updated ${successes.length} ${successes.length === 1 ? 'message' : 'messages'}. ${failures.length} failed.`,
successes.length === 0 ? 'error' : 'warning',
)
}
} catch (error) {
const messageText = error instanceof Error ? error.message : 'Failed to update messages'
console.error('[Mail][Operations] Failed to update messages:', error)
notify(messageText, 'error')
throw error
} finally {
loading.value = false
}
}
async function moveMessages(target: CollectionObject, entityIdentifiers: EntityIdentifier[]) {
const { movableIdentifiers, sourceCollections } = entityIdentifiers.reduce(
(accumulator, identifier) => {
@@ -575,41 +633,6 @@ export const useMailStore = defineStore('mailStore', () => {
}
}
async function deleteMessages(entityIdentifiers: EntityIdentifier[]) {
if (entityIdentifiers.length === 0) {
return
}
loading.value = true
try {
const { successes, failures } = await entitiesStore.delete(entityIdentifiers)
if (failures.length === 0) {
notify(
successes.length === 1 ? 'Message deleted' : `${successes.length} messages deleted`,
'success',
)
}
if (failures.length > 0) {
notify(
successes.length === 0
? `Delete failed for ${failures.length === 1 ? '1 message' : `${failures.length} messages`}`
: `Deleted ${successes.length} ${successes.length === 1 ? 'message' : 'messages'}. ${failures.length} failed.`,
successes.length === 0 ? 'error' : 'warning',
)
}
} catch (error) {
const messageText = error instanceof Error ? error.message : 'Failed to delete messages'
console.error('[Mail][Operations] Failed to delete messages:', error)
notify(messageText, 'error')
throw error
} finally {
loading.value = false
}
}
function notify(message: string, color: 'success' | 'error' | 'info' | 'warning' = 'success') {
showSnackbar({ message, color })
}
@@ -625,7 +648,6 @@ export const useMailStore = defineStore('mailStore', () => {
// State
loading,
selectedFolder,
selectedMessage,
composerSaving,
composerSending,
@@ -641,14 +663,12 @@ export const useMailStore = defineStore('mailStore', () => {
// Actions
retrieveService,
selectFolder,
clearSelectedFolder,
selectMessage,
clearSelectedMessage,
createFolder,
reloadSelectedFolder,
saveComposerDraft,
sendComposerMessage,
resetComposerState,
flagMessages,
deleteMessages,
deleteFolder,
moveMessages,
@@ -658,6 +678,7 @@ export const useMailStore = defineStore('mailStore', () => {
isServiceFolderLoading,
hasServiceFoldersLoaded,
getServiceFolderError,
findFoldersByRole,
loadFoldersForService,
initialize,
}