feat(directory) : revamp commercial report tab and polish info tab
Pull Request — Quality gate / Frontend (build) (pull_request) Successful in 39s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m31s

- report tab redesigned as a reverse-chronological timeline with type
  badges/icons, relative dates and author
- add/edit moved to a side drawer; body now uses the rich text editor
  (MalioInputRichText), displayed read-only as inline prose
- delete now asks for confirmation (ConfirmDeleteReportModal)
- empty state with CTA and pluralized count
- info tab: use v-model, neutral i18n validation key, real admin flag
  instead of hardcoded true on CommercialReportTab
This commit is contained in:
Matthieu
2026-06-24 09:34:58 +02:00
parent 3fe108d38a
commit 80b2fa5ce6
6 changed files with 424 additions and 146 deletions
@@ -12,22 +12,19 @@
<div class="flex flex-col gap-4 pt-6">
<div class="relative grid grid-cols-2 gap-x-[44px] gap-y-4 rounded-lg bg-white px-7 py-5 shadow-[0_4px_4px_0_rgba(0,0,0,0.10)]">
<MalioInputText
v-model="info.name"
class="col-span-2"
:model-value="info.name"
:label="$t('directory.info.fields.name')"
:error="infoTouched.name && !info.name.trim() ? $t('prospects.validation.nameRequired') : ''"
@update:model-value="info.name = $event"
:error="infoTouched.name && !info.name.trim() ? $t('directory.validation.nameRequired') : ''"
@blur="infoTouched.name = true"
/>
<MalioInputText
:model-value="info.email"
v-model="info.email"
:label="$t('directory.info.fields.email')"
@update:model-value="info.email = $event"
/>
<MalioInputText
:model-value="info.phone"
v-model="info.phone"
:label="$t('directory.info.fields.phone')"
@update:model-value="info.phone = $event"
/>
</div>
<div class="flex justify-center pt-2">
@@ -102,7 +99,7 @@
</template>
<template #report>
<CommercialReportTab :owner="owner" :is-admin="true" />
<CommercialReportTab :owner="owner" :is-admin="isAdmin" />
</template>
</MalioTabList>
</template>
@@ -140,6 +137,9 @@ const {
load,
} = useDirectoryDetail(owner)
const authStore = useAuthStore()
const isAdmin = computed(() => authStore.user?.roles?.includes('ROLE_ADMIN') ?? false)
const client = ref<Client | null>(null)
const loading = ref(true)
@@ -12,17 +12,15 @@
<div class="flex flex-col gap-4 pt-6">
<div class="relative grid grid-cols-2 gap-x-[44px] gap-y-4 rounded-lg bg-white px-7 py-5 shadow-[0_4px_4px_0_rgba(0,0,0,0.10)]">
<MalioInputText
v-model="info.name"
class="col-span-2"
:model-value="info.name"
:label="$t('prospects.fields.name')"
:error="infoTouched.name && !info.name.trim() ? $t('prospects.validation.nameRequired') : ''"
@update:model-value="info.name = $event"
@blur="infoTouched.name = true"
/>
<MalioInputText
:model-value="info.company"
v-model="info.company"
:label="$t('prospects.fields.company')"
@update:model-value="info.company = $event"
/>
<MalioSelect
v-model="info.status"
@@ -31,26 +29,22 @@
group-class="w-full"
/>
<MalioInputText
:model-value="info.email"
v-model="info.email"
:label="$t('prospects.fields.email')"
@update:model-value="info.email = $event"
/>
<MalioInputText
:model-value="info.phone"
v-model="info.phone"
:label="$t('prospects.fields.phone')"
@update:model-value="info.phone = $event"
/>
<MalioInputText
v-model="info.source"
class="col-span-2"
:model-value="info.source"
:label="$t('prospects.fields.source')"
@update:model-value="info.source = $event"
/>
<MalioInputTextArea
v-model="info.notes"
class="col-span-2"
:model-value="info.notes"
:label="$t('prospects.fields.notes')"
@update:model-value="info.notes = $event"
/>
</div>
<div class="flex justify-center pt-2">
@@ -125,7 +119,7 @@
</template>
<template #report>
<CommercialReportTab :owner="owner" :is-admin="true" />
<CommercialReportTab :owner="owner" :is-admin="isAdmin" />
</template>
</MalioTabList>
</template>
@@ -163,6 +157,9 @@ const {
load,
} = useDirectoryDetail(owner)
const authStore = useAuthStore()
const isAdmin = computed(() => authStore.user?.roles?.includes('ROLE_ADMIN') ?? false)
const prospect = ref<Prospect | null>(null)
const loading = ref(true)