diff --git a/loko/interventions/static/interventions/calendar/interventions_calendar.js b/loko/interventions/static/interventions/calendar/interventions_calendar.js
index c398dba..a9c3315 100644
--- a/loko/interventions/static/interventions/calendar/interventions_calendar.js
+++ b/loko/interventions/static/interventions/calendar/interventions_calendar.js
@@ -294,10 +294,6 @@ document.addEventListener('DOMContentLoaded', function () {
let currentModalMemberId = null;
let draggedBacklogItem = null;
let draggedBacklogGroup = null;
- let _draggedTeamMember = null;
- let _memberDragJustEnded = false;
- let _pendingMemberDailyAssign = null;
- let _lastTeamsDailyData = null;
const csrfToken = getCookie('csrftoken');
let suppressDurationInputEvent = false;
let suppressEndInputEvent = false;
@@ -447,148 +443,7 @@ document.addEventListener('DOMContentLoaded', function () {
}
}
- const TEAM_PALETTE = [
- '#0d6efd', '#6610f2', '#6f42c1', '#d63384', '#fd7e14',
- '#198754', '#20c997', '#0dcaf0', '#495057', '#e83e8c'
- ];
- function getTeamColor(teamId) {
- return TEAM_PALETTE[Math.abs(teamId || 0) % TEAM_PALETTE.length];
- }
- function buildTeamDailyMembersHtml(members, teamId, dateStr, teamName, canEditThisTeam, isPastDay) {
- const teamColor = typeof getTeamColor === 'function' ? getTeamColor(teamId) : '#0d6efd';
- const isMemberHistoryAllowed = typeof canViewMemberHistory !== 'undefined' ? Boolean(canViewMemberHistory) : false;
- const titleTooltip = canEditThisTeam && !isPastDay ? gettext('Modifier la composition de l’équipe pour ce jour') : gettext('Composition de l’équipe');
- const membersList = (members && Array.isArray(members)) ? members : [];
-
- if (membersList.length > 0) {
- const chipsHtml = membersList.map(m => {
- const name = typeof m === 'object' && m ? m.name : m;
- const id = typeof m === 'object' && m ? m.id : null;
- const isAbsent = typeof m === 'object' && m ? Boolean(m.is_absent) : false;
- const absenceReason = typeof m === 'object' && m ? (m.absence_reason || '') : '';
- const isMultiTeam = typeof m === 'object' && m ? Boolean(m.is_multi_team) : false;
- const otherTeams = typeof m === 'object' && m && m.other_teams ? m.other_teams : [];
-
- const canDrag = Boolean(canEditThisTeam && !isPastDay && id);
- let chipTitle = escapeHtml(name);
- if (canDrag) {
- chipTitle += ` — ${gettext('Glisser pour réassigner. Cliquer pour gérer l’équipe.')}`;
- }
-
- let multiTeamHtml = '';
- if (isMultiTeam) {
- const otherNames = otherTeams.map(t => t.name).join(', ');
- const tooltip = otherNames ? `${gettext('Planifié aussi dans')} : ${otherNames}` : gettext('Planifié dans plusieurs équipes ce jour');
- multiTeamHtml = ` `;
- }
-
- let absentBadgeHtml = '';
- if (isAbsent) {
- absentBadgeHtml = ` ${escapeHtml(absenceReason || gettext('Absent'))}`;
- }
-
- let historyLinkHtml = '';
- if (isMemberHistoryAllowed && id) {
- historyLinkHtml = ` `;
- }
-
- return `
- ${escapeHtml(name)}${multiTeamHtml}${absentBadgeHtml}${historyLinkHtml}
-
`;
- }).join('');
-
- return `
-
-
-
- ${gettext('Équipe')} (${membersList.length})
-
- ${canEditThisTeam && !isPastDay ? `
-
- ` : ''}
-
-
- ${chipsHtml}
-
-
`;
- } else if (teamId !== null && teamId !== '' && typeof teamId !== 'undefined') {
- return `
- (${gettext('Aucun membre')})
- ${canEditThisTeam && !isPastDay ? `` : ''}
-
`;
- }
- return '';
- }
-
- function initTeamDailyMemberChips(container) {
- const root = container || document.getElementById('teams-daily-table-body');
- if (!root) return;
-
- root.querySelectorAll('.team-daily-member-chip[draggable="true"]').forEach(chip => {
- chip.addEventListener('dragstart', (e) => {
- const memberId = parseInt(chip.getAttribute('data-member-id'));
- const memberName = chip.getAttribute('data-member-name') || '';
- const sourceTeamId = chip.getAttribute('data-team-id') ? parseInt(chip.getAttribute('data-team-id')) : null;
- const sourceDate = chip.getAttribute('data-date');
-
- _draggedTeamMember = {
- id: memberId,
- name: memberName,
- sourceTeamId: sourceTeamId,
- sourceDate: sourceDate
- };
-
- chip.classList.add('is-dragging');
- e.dataTransfer.effectAllowed = 'move';
- e.dataTransfer.setData('text/plain', String(memberId));
- });
-
- chip.addEventListener('dragend', () => {
- chip.classList.remove('is-dragging');
- _draggedTeamMember = null;
- _memberDragJustEnded = true;
- setTimeout(() => {
- _memberDragJustEnded = false;
- }, 200);
- });
- });
- }
-
- function showTeamDailyMultiTeamConfirmModal(member, targetTeamId, targetDate, otherAssignedTeams) {
- const modalEl = document.getElementById('teamDailyMultiTeamConfirmModal');
- if (!modalEl) {
- if (confirm(gettext("Ce membre est déjà affecté à une autre équipe ce jour-là. Voulez-vous le déplacer vers cette équipe ?"))) {
- assignMemberToDailyTeam(member.id, targetTeamId, targetDate, 'move');
- }
- return;
- }
-
- const otherNames = otherAssignedTeams.map(t => t.name).join(', ');
- const targetTeamObj = (_lastTeamsDailyData?.teams || []).find(t => t.id === targetTeamId);
- const targetName = targetTeamObj ? targetTeamObj.name : `Équipe #${targetTeamId}`;
-
- const memberNameEl = document.getElementById('team-daily-multi-member-name');
- const dateEl = document.getElementById('team-daily-multi-date');
- const existingTeamsEl = document.getElementById('team-daily-multi-existing-teams');
- const targetTeamEl = document.getElementById('team-daily-multi-target-team');
-
- if (memberNameEl) memberNameEl.textContent = member.name;
- if (dateEl) dateEl.textContent = targetDate;
- if (existingTeamsEl) existingTeamsEl.textContent = otherNames;
- if (targetTeamEl) targetTeamEl.textContent = targetName;
-
- _pendingMemberDailyAssign = {
- memberId: member.id,
- targetTeamId: targetTeamId,
- targetDate: targetDate
- };
-
- const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
- modal.show();
- }
function renderTeamsDailyGrid(data) {
const todayStr = formatDateISO(new Date());
@@ -5537,6 +5392,156 @@ document.addEventListener('click', function(e) {
}
});
+// State variables for teams daily view and member drag-and-drop
+let _draggedTeamMember = null;
+let _memberDragJustEnded = false;
+let _pendingMemberDailyAssign = null;
+let _lastTeamsDailyData = null;
+
+const TEAM_PALETTE = [
+ '#0d6efd', '#6610f2', '#6f42c1', '#d63384', '#fd7e14',
+ '#198754', '#20c997', '#0dcaf0', '#495057', '#e83e8c'
+];
+
+function getTeamColor(teamId) {
+ return TEAM_PALETTE[Math.abs(teamId || 0) % TEAM_PALETTE.length];
+}
+
+function buildTeamDailyMembersHtml(members, teamId, dateStr, teamName, canEditThisTeam, isPastDay) {
+ const teamColor = typeof getTeamColor === 'function' ? getTeamColor(teamId) : '#0d6efd';
+ const isMemberHistoryAllowed = typeof canViewMemberHistory !== 'undefined' ? Boolean(canViewMemberHistory) : false;
+ const titleTooltip = canEditThisTeam && !isPastDay ? gettext('Modifier la composition de l’équipe pour ce jour') : gettext('Composition de l’équipe');
+ const membersList = (members && Array.isArray(members)) ? members : [];
+
+ if (membersList.length > 0) {
+ const chipsHtml = membersList.map(m => {
+ const name = typeof m === 'object' && m ? m.name : m;
+ const id = typeof m === 'object' && m ? m.id : null;
+ const isAbsent = typeof m === 'object' && m ? Boolean(m.is_absent) : false;
+ const absenceReason = typeof m === 'object' && m ? (m.absence_reason || '') : '';
+ const isMultiTeam = typeof m === 'object' && m ? Boolean(m.is_multi_team) : false;
+ const otherTeams = typeof m === 'object' && m && m.other_teams ? m.other_teams : [];
+
+ const canDrag = Boolean(canEditThisTeam && !isPastDay && id);
+ let chipTitle = escapeHtml(name);
+ if (canDrag) {
+ chipTitle += ` — ${gettext('Glisser pour réassigner. Cliquer pour gérer l’équipe.')}`;
+ }
+
+ let multiTeamHtml = '';
+ if (isMultiTeam) {
+ const otherNames = otherTeams.map(t => t.name).join(', ');
+ const tooltip = otherNames ? `${gettext('Planifié aussi dans')} : ${otherNames}` : gettext('Planifié dans plusieurs équipes ce jour');
+ multiTeamHtml = ` `;
+ }
+
+ let absentBadgeHtml = '';
+ if (isAbsent) {
+ absentBadgeHtml = ` ${escapeHtml(absenceReason || gettext('Absent'))}`;
+ }
+
+ let historyLinkHtml = '';
+ if (isMemberHistoryAllowed && id) {
+ historyLinkHtml = ` `;
+ }
+
+ return `
+ ${escapeHtml(name)}${multiTeamHtml}${absentBadgeHtml}${historyLinkHtml}
+
`;
+ }).join('');
+
+ return `
+
+
+
+ ${gettext('Équipe')} (${membersList.length})
+
+ ${canEditThisTeam && !isPastDay ? `
+
+ ` : ''}
+
+
+ ${chipsHtml}
+
+
`;
+ } else if (teamId !== null && teamId !== '' && typeof teamId !== 'undefined') {
+ return `
+ (${gettext('Aucun membre')})
+ ${canEditThisTeam && !isPastDay ? `` : ''}
+
`;
+ }
+ return '';
+}
+
+function initTeamDailyMemberChips(container) {
+ const root = container || document.getElementById('teams-daily-table-body');
+ if (!root) return;
+
+ root.querySelectorAll('.team-daily-member-chip[draggable="true"]').forEach(chip => {
+ chip.addEventListener('dragstart', (e) => {
+ const memberId = parseInt(chip.getAttribute('data-member-id'));
+ const memberName = chip.getAttribute('data-member-name') || '';
+ const sourceTeamId = chip.getAttribute('data-team-id') ? parseInt(chip.getAttribute('data-team-id')) : null;
+ const sourceDate = chip.getAttribute('data-date');
+
+ _draggedTeamMember = {
+ id: memberId,
+ name: memberName,
+ sourceTeamId: sourceTeamId,
+ sourceDate: sourceDate
+ };
+
+ chip.classList.add('is-dragging');
+ e.dataTransfer.effectAllowed = 'move';
+ e.dataTransfer.setData('text/plain', String(memberId));
+ });
+
+ chip.addEventListener('dragend', () => {
+ chip.classList.remove('is-dragging');
+ _draggedTeamMember = null;
+ _memberDragJustEnded = true;
+ setTimeout(() => {
+ _memberDragJustEnded = false;
+ }, 200);
+ });
+ });
+}
+
+function showTeamDailyMultiTeamConfirmModal(member, targetTeamId, targetDate, otherAssignedTeams) {
+ const modalEl = document.getElementById('teamDailyMultiTeamConfirmModal');
+ if (!modalEl) {
+ if (confirm(gettext("Ce membre est déjà affecté à une autre équipe ce jour-là. Voulez-vous le déplacer vers cette équipe ?"))) {
+ assignMemberToDailyTeam(member.id, targetTeamId, targetDate, 'move');
+ }
+ return;
+ }
+
+ const otherNames = otherAssignedTeams.map(t => t.name).join(', ');
+ const targetTeamObj = (_lastTeamsDailyData?.teams || []).find(t => t.id === targetTeamId);
+ const targetName = targetTeamObj ? targetTeamObj.name : `Équipe #${targetTeamId}`;
+
+ const memberNameEl = document.getElementById('team-daily-multi-member-name');
+ const dateEl = document.getElementById('team-daily-multi-date');
+ const existingTeamsEl = document.getElementById('team-daily-multi-existing-teams');
+ const targetTeamEl = document.getElementById('team-daily-multi-target-team');
+
+ if (memberNameEl) memberNameEl.textContent = member.name;
+ if (dateEl) dateEl.textContent = targetDate;
+ if (existingTeamsEl) existingTeamsEl.textContent = otherNames;
+ if (targetTeamEl) targetTeamEl.textContent = targetName;
+
+ _pendingMemberDailyAssign = {
+ memberId: member.id,
+ targetTeamId: targetTeamId,
+ targetDate: targetDate
+ };
+
+ const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
+ modal.show();
+}
+
let _currentTeamDailyModalState = {
teamId: null,
dateStr: null,