refactor: move team daily view helper functions and state variables to file scope
This commit is contained in:
parent
63c4a8e539
commit
512f6786e3
1 changed files with 150 additions and 145 deletions
|
|
@ -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 = ` <i class="bi bi-diagram-3 text-warning ms-1" style="font-size:0.7rem;" title="${escapeHtml(tooltip)}"></i>`;
|
||||
}
|
||||
|
||||
let absentBadgeHtml = '';
|
||||
if (isAbsent) {
|
||||
absentBadgeHtml = ` <span class="badge text-bg-danger p-0 px-1 ms-1 font-monospace" style="font-size:0.6rem;">${escapeHtml(absenceReason || gettext('Absent'))}</span>`;
|
||||
}
|
||||
|
||||
let historyLinkHtml = '';
|
||||
if (isMemberHistoryAllowed && id) {
|
||||
historyLinkHtml = ` <i class="bi bi-clock-history text-muted member-history-icon ms-1" style="font-size:0.7rem; cursor:pointer;" data-member-id="${id}" title="${gettext('Historique du membre')}"></i>`;
|
||||
}
|
||||
|
||||
return `<div class="team-daily-member-chip${canDrag ? ' draggable' : ''}${isAbsent ? ' is-absent' : ''}" ${canDrag ? 'draggable="true"' : ''} data-member-id="${id || ''}" data-member-name="${escapeHtml(name)}" data-team-id="${teamId || ''}" data-date="${dateStr}" title="${chipTitle}">
|
||||
<span class="member-name-text">${escapeHtml(name)}</span>${multiTeamHtml}${absentBadgeHtml}${historyLinkHtml}
|
||||
</div>`;
|
||||
}).join('');
|
||||
|
||||
return `<div class="team-members-list small mb-2" style="border-left: 3px solid ${teamColor};" data-team-id="${teamId || ''}" data-date="${dateStr}" data-team-name="${escapeHtml(teamName || '')}">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<span class="clickable-team-members d-inline-flex align-items-center" style="cursor: pointer;" title="${escapeHtml(titleTooltip)}" data-team-id="${teamId || ''}" data-date="${dateStr}" data-team-name="${escapeHtml(teamName || '')}">
|
||||
<i class="bi bi-people-fill me-1" style="color: ${teamColor};"></i>
|
||||
<span class="fw-semibold text-secondary" style="font-size: 0.72rem;">${gettext('Équipe')} (${membersList.length})</span>
|
||||
</span>
|
||||
${canEditThisTeam && !isPastDay ? `
|
||||
<button type="button" class="btn btn-link btn-sm p-0 text-muted clickable-team-members" style="font-size: 0.72rem; text-decoration: none;" title="${escapeHtml(titleTooltip)}" data-team-id="${teamId || ''}" data-date="${dateStr}" data-team-name="${escapeHtml(teamName || '')}">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="team-daily-members-chips">
|
||||
${chipsHtml}
|
||||
</div>
|
||||
</div>`;
|
||||
} else if (teamId !== null && teamId !== '' && typeof teamId !== 'undefined') {
|
||||
return `<div class="team-members-list clickable-team-members text-muted small fst-italic mb-2 text-opacity-50" style="border-left: 3px solid #cbd5e1; cursor: pointer;" title="${escapeHtml(titleTooltip)}" data-team-id="${teamId || ''}" data-date="${dateStr}" data-team-name="${escapeHtml(teamName || '')}">
|
||||
<i class="bi bi-people me-1"></i>(${gettext('Aucun membre')})
|
||||
${canEditThisTeam && !isPastDay ? `<i class="bi bi-plus-circle ms-1 text-primary"></i>` : ''}
|
||||
</div>`;
|
||||
}
|
||||
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 = ` <i class="bi bi-diagram-3 text-warning ms-1" style="font-size:0.7rem;" title="${escapeHtml(tooltip)}"></i>`;
|
||||
}
|
||||
|
||||
let absentBadgeHtml = '';
|
||||
if (isAbsent) {
|
||||
absentBadgeHtml = ` <span class="badge text-bg-danger p-0 px-1 ms-1 font-monospace" style="font-size:0.6rem;">${escapeHtml(absenceReason || gettext('Absent'))}</span>`;
|
||||
}
|
||||
|
||||
let historyLinkHtml = '';
|
||||
if (isMemberHistoryAllowed && id) {
|
||||
historyLinkHtml = ` <i class="bi bi-clock-history text-muted member-history-icon ms-1" style="font-size:0.7rem; cursor:pointer;" data-member-id="${id}" title="${gettext('Historique du membre')}"></i>`;
|
||||
}
|
||||
|
||||
return `<div class="team-daily-member-chip${canDrag ? ' draggable' : ''}${isAbsent ? ' is-absent' : ''}" ${canDrag ? 'draggable="true"' : ''} data-member-id="${id || ''}" data-member-name="${escapeHtml(name)}" data-team-id="${teamId || ''}" data-date="${dateStr}" title="${chipTitle}">
|
||||
<span class="member-name-text">${escapeHtml(name)}</span>${multiTeamHtml}${absentBadgeHtml}${historyLinkHtml}
|
||||
</div>`;
|
||||
}).join('');
|
||||
|
||||
return `<div class="team-members-list small mb-2" style="border-left: 3px solid ${teamColor};" data-team-id="${teamId || ''}" data-date="${dateStr}" data-team-name="${escapeHtml(teamName || '')}">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<span class="clickable-team-members d-inline-flex align-items-center" style="cursor: pointer;" title="${escapeHtml(titleTooltip)}" data-team-id="${teamId || ''}" data-date="${dateStr}" data-team-name="${escapeHtml(teamName || '')}">
|
||||
<i class="bi bi-people-fill me-1" style="color: ${teamColor};"></i>
|
||||
<span class="fw-semibold text-secondary" style="font-size: 0.72rem;">${gettext('Équipe')} (${membersList.length})</span>
|
||||
</span>
|
||||
${canEditThisTeam && !isPastDay ? `
|
||||
<button type="button" class="btn btn-link btn-sm p-0 text-muted clickable-team-members" style="font-size: 0.72rem; text-decoration: none;" title="${escapeHtml(titleTooltip)}" data-team-id="${teamId || ''}" data-date="${dateStr}" data-team-name="${escapeHtml(teamName || '')}">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="team-daily-members-chips">
|
||||
${chipsHtml}
|
||||
</div>
|
||||
</div>`;
|
||||
} else if (teamId !== null && teamId !== '' && typeof teamId !== 'undefined') {
|
||||
return `<div class="team-members-list clickable-team-members text-muted small fst-italic mb-2 text-opacity-50" style="border-left: 3px solid #cbd5e1; cursor: pointer;" title="${escapeHtml(titleTooltip)}" data-team-id="${teamId || ''}" data-date="${dateStr}" data-team-name="${escapeHtml(teamName || '')}">
|
||||
<i class="bi bi-people me-1"></i>(${gettext('Aucun membre')})
|
||||
${canEditThisTeam && !isPastDay ? `<i class="bi bi-plus-circle ms-1 text-primary"></i>` : ''}
|
||||
</div>`;
|
||||
}
|
||||
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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue