From 273234626fe258fd80d2a63ef6715acaa247100a Mon Sep 17 00:00:00 2001 From: matthieu Date: Wed, 20 May 2026 00:49:57 +0200 Subject: [PATCH] =?UTF-8?q?feat(mail)=20:=20onglet=20Mails=20dans=20TaskMo?= =?UTF-8?q?dal=20=E2=80=94=20liste=20mails=20li=C3=A9s,=20bouton=20lier,?= =?UTF-8?q?=20MailPickerModal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/components/task/TaskModal.vue | 131 ++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/frontend/components/task/TaskModal.vue b/frontend/components/task/TaskModal.vue index 579d0d9..ab7155d 100644 --- a/frontend/components/task/TaskModal.vue +++ b/frontend/components/task/TaskModal.vue @@ -60,16 +60,16 @@
@@ -433,6 +433,76 @@ + +
+ +
+ +
+ + +
+ +

{{ $t('mail.taskTab.empty') }}

+
+ + +
+ + +
+

+ {{ mail.subject ?? $t('mail.noSubject') }} +

+

+ {{ mail.fromName ?? mail.fromEmail }} + · + {{ formatMailDate(mail.sentAt ?? mail.receivedAt) }} +

+
+ +
+
+ + +
+ +
+ + + +
+
!!props.task) const isSubmitting = ref(false) const confirmDeleteOpen = ref(false) -const activeTab = ref<'details' | 'planning'>('details') +const activeTab = ref<'details' | 'planning' | 'mails'>('details') + +// ─── Onglet Mails ───────────────────────────────────────────────────────── + +const mailService = useMailService() +const linkedMails = ref([]) +const mailsLoading = ref(false) +const showMailPickerModal = ref(false) const giteaUrl = ref('') const { getSettings: getGiteaSettings } = useGiteaService() @@ -765,6 +844,7 @@ watch(() => props.modelValue, async (open) => { activeTab.value = 'details' confirmDeleteDocOpen.value = false documentToDelete.value = null + linkedMails.value = [] populateForm(props.task) const pid = resolvedProjectId.value if (pid) { @@ -823,6 +903,49 @@ watch(() => form.projectId, async (pid) => { const authStore = useAuthStore() const isAdmin = computed(() => authStore.user?.roles?.includes('ROLE_ADMIN') ?? false) +const isClientOnly = computed(() => + authStore.user?.roles?.includes('ROLE_CLIENT') === true + && authStore.user?.roles?.includes('ROLE_ADMIN') !== true, +) +const isMailUser = computed(() => !isClientOnly.value) + +const availableTabs = computed(() => { + const base: Array<'details' | 'planning' | 'mails'> = ['details', 'planning'] + if (isEditing.value && isMailUser.value) base.push('mails') + return base +}) + +async function loadLinkedMails(): Promise { + if (!props.task || !isMailUser.value) return + mailsLoading.value = true + try { + linkedMails.value = await mailService.listMailsForTask(props.task.id) + } catch { + linkedMails.value = [] + } finally { + mailsLoading.value = false + } +} + +watch(activeTab, async (tab) => { + if (tab === 'mails' && props.task) { + await loadLinkedMails() + } +}) + +async function handleMailLinked(): Promise { + showMailPickerModal.value = false + await loadLinkedMails() +} + +function formatMailDate(iso: string | null): string { + if (!iso) return '' + return new Date(iso).toLocaleDateString('fr', { + day: '2-digit', + month: 'short', + }) +} + function ticketStatusClass(status: string): string { switch (status) { case 'new': return 'bg-blue-100 text-blue-700'