- Ajout filtre multiselect par page(s) dans le dashboard analytics - Chart multi-courbes par page quand aucun filtre page sélectionné - Options de pages indépendantes du filtre page (persistent à la sélection) - Options de pages dépendantes du filtre utilisateur - Tracking modal-file avec format "Projet / Label" dans dialog.js - Tri alphabétique des options du filtre par page - Fix user list 500 error (email string, client field check) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
180 lines
5.2 KiB
JavaScript
180 lines
5.2 KiB
JavaScript
import { defineStore } from 'pinia';
|
|
import { ref, computed, watch } from 'vue';
|
|
import { useRoute } from 'vue-router';
|
|
import { useAnalyticsStore } from './analytics';
|
|
import { usePageStore } from './page';
|
|
|
|
export const useDialogStore = defineStore('dialog', () => {
|
|
const content = ref(null);
|
|
const openedFile = ref(null);
|
|
const activeTracks = ref(null);
|
|
|
|
const comments = computed(() => {
|
|
if (activeTracks.value?.length > 0) {
|
|
return activeTracks.value[0].files.flatMap((file) =>
|
|
file.comments ? file.comments : []
|
|
);
|
|
}
|
|
if (!openedFile.value) return [];
|
|
return openedFile.value.comments;
|
|
});
|
|
|
|
function updateFile(newFile) {
|
|
openedFile.value = newFile;
|
|
}
|
|
|
|
const route = useRoute();
|
|
const isCommentPanelEnabled = ref(true);
|
|
const isCommentsOpen = ref(
|
|
route.query.hasOwnProperty('comments') ? true : false
|
|
);
|
|
const openedComment = ref(null);
|
|
|
|
const draftComment = ref({});
|
|
watch(
|
|
draftComment,
|
|
(newVal) => {
|
|
if (draftComment.value.position) showDraftMarker(newVal);
|
|
},
|
|
{ deep: true }
|
|
);
|
|
function showDraftMarker(draftComment) {
|
|
const bubble = document.createElement('a');
|
|
|
|
bubble.classList.add('comment-marker');
|
|
bubble.classList.add('comment-marker--draft');
|
|
bubble.style.left = draftComment.position.x + '%';
|
|
bubble.style.top = draftComment.position.y + '%';
|
|
bubble.href = '#comment-' + draftComment.id;
|
|
|
|
const container = draftComment.position.pageIndex
|
|
? document.querySelector(
|
|
`.vpv-page-inner-container[aria-label="page ${draftComment.position.pageIndex}"] .page-inner-container`
|
|
)
|
|
: document.querySelector('.track');
|
|
|
|
container.appendChild(bubble);
|
|
}
|
|
|
|
const isViewerDisabled = ref(false);
|
|
watch(isCommentsOpen, (newVal) => {
|
|
if (newVal) {
|
|
setCommentMarkers();
|
|
} else {
|
|
removeCommentMarkers();
|
|
}
|
|
});
|
|
watch(openedFile, () => {
|
|
removeCommentMarkers();
|
|
if (isCommentsOpen.value) {
|
|
setCommentMarkers();
|
|
}
|
|
});
|
|
watch(openedFile, (newVal, oldVal) => {
|
|
if (!isCommentsOpen.value || !newVal || !oldVal || newVal.url == oldVal.url)
|
|
return;
|
|
|
|
isViewerDisabled.value = true;
|
|
|
|
setTimeout(() => {
|
|
isViewerDisabled.value = false;
|
|
removeCommentMarkers();
|
|
if (newVal.comments) {
|
|
setCommentMarkers();
|
|
}
|
|
}, 100);
|
|
});
|
|
|
|
function setCommentMarkers() {
|
|
if (!comments.value || !openedFile.value) return;
|
|
comments.value.forEach((comment) => {
|
|
const correspondingMarker = document.querySelector(
|
|
`.comment-marker[href="#comment-${comment.id}"]`
|
|
);
|
|
if (comment.location.file.uuid !== openedFile.value.uuid) return;
|
|
if (comment.type === 'comment-reply') return;
|
|
if (correspondingMarker) return;
|
|
|
|
const bubble = document.createElement('a');
|
|
|
|
bubble.classList.add('comment-marker');
|
|
bubble.style.left = comment.position.x + '%';
|
|
bubble.style.top = comment.position.y + '%';
|
|
bubble.href = '#comment-' + comment.id;
|
|
|
|
let container = comment.position?.pageIndex
|
|
? document.querySelector(
|
|
`.vpv-page-inner-container[aria-label="page ${comment.position.pageIndex}"] .page-inner-container`
|
|
)
|
|
: document.querySelector('.track');
|
|
|
|
const timeOut = container ? 0 : 500;
|
|
setTimeout(() => {
|
|
container = comment.position?.pageIndex
|
|
? document.querySelector(
|
|
`.vpv-page-inner-container[aria-label="page ${comment.position.pageIndex}"] .page-inner-container`
|
|
)
|
|
: document.querySelector('.track');
|
|
|
|
try {
|
|
container.appendChild(bubble);
|
|
setTimeout(() => {
|
|
bubble.addEventListener('mouseenter', () => highlight(comment));
|
|
bubble.addEventListener('mouseleave', () => unhighlight(comment));
|
|
}, 100);
|
|
} catch (error) {
|
|
console.error(
|
|
`Impossible de monter la bulle du commentaire ${comment.id}. La page n°${comment.position.pageIndex} n'existe pas dans le DOM.`
|
|
);
|
|
}
|
|
}, timeOut);
|
|
});
|
|
}
|
|
|
|
function removeCommentMarkers() {
|
|
document.querySelectorAll('.comment-marker').forEach((bubble) => {
|
|
bubble.parentNode.removeChild(bubble);
|
|
});
|
|
}
|
|
|
|
function highlight(comment) {
|
|
const target = document.querySelector('#comment-' + comment.id);
|
|
if (target) {
|
|
target.classList.add('highlight');
|
|
}
|
|
}
|
|
function unhighlight(comment) {
|
|
const target = document.querySelector('#comment-' + comment.id);
|
|
if (target) {
|
|
target.classList.remove('highlight');
|
|
}
|
|
}
|
|
|
|
// Analytics tracking pour ouverture de fichiers
|
|
watch(openedFile, (newFile) => {
|
|
if (newFile) {
|
|
const analytics = useAnalyticsStore();
|
|
const pageStore = usePageStore();
|
|
const currentPath = route.path;
|
|
const projectTitle = pageStore.page?.title || 'Projet';
|
|
const fileLabel = newFile.label?.length ? newFile.label : (newFile.name || newFile.filename);
|
|
analytics.trackVisit(
|
|
`${currentPath}#file-${newFile.uuid}`,
|
|
'modal-file',
|
|
`${projectTitle} / ${fileLabel}`
|
|
);
|
|
}
|
|
});
|
|
|
|
return {
|
|
content,
|
|
activeTracks,
|
|
openedFile,
|
|
comments,
|
|
draftComment,
|
|
isCommentsOpen,
|
|
isCommentPanelEnabled,
|
|
updateFile,
|
|
openedComment,
|
|
};
|
|
});
|