import type { MailConfigurationDto, MailConfigurationUpdateDto, MailTestConnectionResultDto, MailFolderDto, MailMessageHeaderDto, MailMessageDetailDto, MailMessagesPageDto, MailMessageReadInput, MailMessageFlagInput, MailCreateTaskInput, MailLinkTaskInput, MailSyncResultDto, } from './dto/mail' import type { Task } from './dto/task' export function useMailService() { const api = useApi() // ─── Configuration (Admin) ──────────────────────────────────────────────── /** * Récupère la configuration mail singleton. * Requiert ROLE_ADMIN — 403 sinon. */ async function getConfiguration(): Promise { return api.get('/mail/configuration') } /** * Met à jour la configuration mail (PATCH merge). * Si payload.password est fourni, il sera chiffré côté backend. * Jamais retourné en clair dans la réponse. */ async function updateConfiguration( payload: MailConfigurationUpdateDto, ): Promise { return api.patch( '/mail/configuration', payload as Record, { toastSuccessKey: 'mail.configuration.saved' }, ) } /** * Teste la connexion IMAP avec la configuration actuelle. * Requiert ROLE_ADMIN. */ async function testConfiguration(): Promise { return api.post('/mail/configuration/test', {}) } // ─── Dossiers ───────────────────────────────────────────────────────────── /** * Liste tous les dossiers mail depuis la base (cache BDD, pas live IMAP). * Retourne une liste plate — la construction de l'arbre est faite dans le store * via le getter `folderTree`. */ async function listFolders(): Promise { return api.get('/mail/folders') } // ─── Messages ───────────────────────────────────────────────────────────── /** * Liste les messages d'un dossier, paginés par cursor. * @param folderPath - Chemin du dossier (ex: "INBOX", "INBOX.Sent") * @param cursor - Opaque cursor retourné par la page précédente (undefined = première page) * @param limit - Nombre de messages par page (défaut backend : 50) */ async function listMessages( folderPath: string, cursor?: string, limit?: number, ): Promise { const query: Record = { folder: folderPath } if (cursor) query.cursor = cursor if (limit) query.limit = limit return api.get('/mail/messages', query) } /** * Récupère le détail complet d'un message (body live IMAP, cached 5 min). * @param id - ID BDD du message (MailMessage.id) */ async function getMessage(id: number): Promise { return api.get(`/mail/messages/${id}`) } // ─── Actions sur les messages ───────────────────────────────────────────── /** * Marque un message comme lu ou non-lu. */ async function markRead(id: number, read: boolean): Promise { const payload: MailMessageReadInput = { read } return api.post( `/mail/messages/${id}/read`, payload as unknown as Record, ) } /** * Marque un message comme étoilé ou non-étoilé. */ async function markFlagged(id: number, flagged: boolean): Promise { const payload: MailMessageFlagInput = { flagged } return api.post( `/mail/messages/${id}/flag`, payload as unknown as Record, ) } // ─── Intégration tâches ─────────────────────────────────────────────────── /** * Crée une nouvelle tâche à partir d'un mail (subject → titre, body → description). * @param mailId - ID BDD du message * @param input - Paramètres de la tâche à créer */ async function createTaskFromMail( mailId: number, input: MailCreateTaskInput, ): Promise { return api.post( `/mail/messages/${mailId}/create-task`, input as unknown as Record, { toastSuccessKey: 'mail.task.created' }, ) } /** * Lie un mail à une tâche existante. * @param mailId - ID BDD du message * @param taskId - ID de la tâche existante */ async function linkTask(mailId: number, taskId: number): Promise { const payload: MailLinkTaskInput = { taskId } await api.post( `/mail/messages/${mailId}/link-task`, payload as unknown as Record, { toastSuccessKey: 'mail.task.linked' }, ) } /** * Supprime le lien entre un mail et une tâche. * @param mailId - ID BDD du message * @param taskId - ID de la tâche */ async function unlinkTask(mailId: number, taskId: number): Promise { await api.delete(`/mail/messages/${mailId}/link-task/${taskId}`, {}, { toastSuccessKey: 'mail.task.unlinked', }) } /** * Liste les mails liés à une tâche (pour l'onglet "Mails" du TaskDrawer — Phase 6). * @param taskId - ID de la tâche */ async function listMailsForTask(taskId: number): Promise { return api.get(`/tasks/${taskId}/mails`) } // ─── Pièces jointes ─────────────────────────────────────────────────────── /** * Télécharge une pièce jointe et retourne le Blob + headers. * Content-Disposition: attachment est géré côté backend (jamais inline). * @param downloadId - Identifiant opaque retourné dans MailAttachmentDto.downloadId */ async function downloadAttachment( downloadId: string, ): Promise<{ data: Blob; headers: Headers }> { return api.getBlob(`/mail/attachments/${downloadId}`) } // ─── Synchronisation ───────────────────────────────────────────────────── /** * Déclenche une synchronisation IMAP asynchrone via Symfony Messenger. * Retourne immédiatement ({ dispatched: true }) — la sync se fait en arrière-plan. */ async function triggerSync(): Promise { return api.post('/mail/sync', {}, { toastSuccessKey: 'mail.sync.dispatched', }) } return { // Config getConfiguration, updateConfiguration, testConfiguration, // Dossiers listFolders, // Messages listMessages, getMessage, // Actions markRead, markFlagged, // Tâches createTaskFromMail, linkTask, unlinkTask, listMailsForTask, // Pièces jointes downloadAttachment, // Sync triggerSync, } }