Fix : URL correcte pour notifications de brief validé depuis PDF + redirect briefs vides

Problème 1 : Les notifications de brief validé depuis un PDF renvoyaient vers
/projects/xxx/client-brief au lieu de l'URL complète avec dialog et fileIndex.

Problème 2 : Les URL /projects/xxx/client-brief pour des briefs non créés
affichaient une page vide au lieu de rediriger vers le kanban.

Solutions :
- Stocker validationDialogUri lors de la validation du brief
- Utiliser ce dialogUri dans ContentProvider et Notifications.vue
- Rediriger vers le projet parent si brief vide et non validé

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
isUnknown 2026-01-15 10:44:30 +01:00
parent a7d315942a
commit 6ff59e9b07
6 changed files with 46 additions and 7 deletions

View file

@ -24,7 +24,6 @@ tabs:
type: hidden type: hidden
isValidated: isValidated:
type: hidden type: hidden
# Champs pour notification "content" (brief validé)
validatedBy: validatedBy:
type: hidden type: hidden
validatedByName: validatedByName:
@ -35,6 +34,8 @@ tabs:
type: hidden type: hidden
validationReadby: validationReadby:
type: hidden type: hidden
validationDialogUri:
type: hidden
pdf: pdf:
label: PDF label: PDF
type: files type: files

View file

@ -35,6 +35,8 @@ tabs:
type: hidden type: hidden
validationReadby: validationReadby:
type: hidden type: hidden
validationDialogUri:
type: hidden
pdf: pdf:
label: PDF label: PDF
type: files type: files

View file

@ -15,7 +15,7 @@ return [
$timezone = new DateTimeZone('Europe/Paris'); $timezone = new DateTimeZone('Europe/Paris');
$dateTime = new DateTime('now', $timezone); $dateTime = new DateTime('now', $timezone);
$newPage = $page->update([ $updateData = [
'isValidated' => 'true', 'isValidated' => 'true',
// Métadonnées pour le système de notifications dérivées // Métadonnées pour le système de notifications dérivées
'validatedBy' => (string) $user->uuid(), 'validatedBy' => (string) $user->uuid(),
@ -23,7 +23,14 @@ return [
'validatedByEmail' => (string) $user->email(), 'validatedByEmail' => (string) $user->email(),
'validatedAt' => $dateTime->format('Y-m-d\TH:i:sP'), 'validatedAt' => $dateTime->format('Y-m-d\TH:i:sP'),
'validationReadby' => [], 'validationReadby' => [],
]); ];
// Si un dialogUri est fourni (validation depuis PDF), le stocker
if (isset($data->dialogUri) && !empty($data->dialogUri)) {
$updateData['validationDialogUri'] = (string) $data->dialogUri;
}
$newPage = $page->update($updateData);
// Note: Les notifications sont maintenant dérivées. // Note: Les notifications sont maintenant dérivées.
// Plus besoin d'appeler createNotification(). // Plus besoin d'appeler createNotification().

View file

@ -60,10 +60,10 @@ class ContentProvider implements NotificationProvider
? 'Brief client' ? 'Brief client'
: 'Brief étendu'; : 'Brief étendu';
$notifications[] = [ $notification = [
'id' => 'content-' . (string) $step->uuid(), 'id' => 'content-' . (string) $step->uuid(),
'type' => 'content', 'type' => 'content',
'text' => "Nouveau $stepLabel validé", 'text' => 'Nouveau ' . strtolower($stepLabel) . ' validé',
'author' => [ 'author' => [
'uuid' => $authorUuid, 'uuid' => $authorUuid,
'name' => $step->validatedByName()->value() ?? '', 'name' => $step->validatedByName()->value() ?? '',
@ -86,6 +86,13 @@ class ContentProvider implements NotificationProvider
'isRead' => in_array($userUuid, $readby), 'isRead' => in_array($userUuid, $readby),
'_briefUri' => $step->uri(), '_briefUri' => $step->uri(),
]; ];
// Ajouter le dialogUri si présent (validation depuis PDF)
if ($step->validationDialogUri()->isNotEmpty()) {
$notification['dialogUri'] = $step->validationDialogUri()->value();
}
$notifications[] = $notification;
} }
return $notifications; return $notifications;

View file

@ -29,7 +29,7 @@
</main> </main>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue'; import { ref, onMounted } from 'vue';
import Intro from '../components/project/brief/Intro.vue'; import Intro from '../components/project/brief/Intro.vue';
import ModeSelection from '../components/project/brief/ModeSelection.vue'; import ModeSelection from '../components/project/brief/ModeSelection.vue';
import Images from '../components/project/brief/Images.vue'; import Images from '../components/project/brief/Images.vue';
@ -37,7 +37,7 @@ import TitledPdfWrapper from '../components/project/TitledPdfWrapper.vue';
import { usePageStore } from '../stores/page'; import { usePageStore } from '../stores/page';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useApiStore } from '../stores/api'; import { useApiStore } from '../stores/api';
import { useRoute } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
const stepsComponents = { const stepsComponents = {
Intro, Intro,
@ -48,9 +48,26 @@ const stepsComponents = {
const { page } = storeToRefs(usePageStore()); const { page } = storeToRefs(usePageStore());
const api = useApiStore(); const api = useApiStore();
const route = useRoute();
const router = useRouter();
const currentStep = ref(setInitialStep()); const currentStep = ref(setInitialStep());
// Rediriger vers le kanban si le brief est vide et non validé
onMounted(() => {
const hasPDF = page.value?.content?.pdf?.length !== 0;
const hasImages =
page.value?.content?.moodboard?.length !== 0 ||
page.value?.content?.description?.length !== 0;
const isEmpty = !hasPDF && !hasImages;
const isValidated = page.value?.content?.isvalidated === 'true';
// Si le brief est vide et non validé, rediriger vers le projet
if (isEmpty && !isValidated && !route.query.step) {
router.push('/' + page.value.parent);
}
});
function changeStep(stepName) { function changeStep(stepName) {
currentStep.value = stepName; currentStep.value = stepName;
} }

View file

@ -151,6 +151,11 @@ async function handleNotificationClick(notification) {
function getHref(notification) { function getHref(notification) {
const uri = notification.location.page.uri; const uri = notification.location.page.uri;
// Pour les notifications de type "content" (brief validé), utiliser dialogUri si présent
if (notification.type === 'content' && notification.dialogUri) {
return notification.dialogUri;
}
const isDocumentBrief = const isDocumentBrief =
notification.location.page.template === 'client-brief' && notification.location.page.template === 'client-brief' &&
notification.location?.file?.type === 'document'; notification.location?.file?.type === 'document';