bmc_hub/static/js/case-slot-move.js
Christian 1fb5b4a191 Add comprehensive tests for email and drift functionalities
- Introduced tests for drift operations UI and backend to ensure proper handling of ignore rules and UI elements.
- Added tests for email identity API to validate email linking and identity retrieval without updates.
- Implemented tests for email purchase link service to verify correct handling of purchase mail links and conflict scenarios.
- Created tests for email reply automation to ensure proper routing and processing of replies based on classification.
- Developed tests for email sender creation to validate suggestions and handling of existing contacts and companies.
- Added tests for email sender identity to ensure correct matching of contacts and domains.
- Implemented tests for work desk functionalities to validate task management, meeting registrations, and timer functionalities.
2026-11-03 01:16:12 +01:00

79 lines
3.8 KiB
JavaScript

/* Move existing bookings without changing employee or duration. */
(() => {
'use strict';
const host = document.getElementById('casePlannerWeek');
if (!host) return;
let drag = null, saving = false;
function clear() {
host.querySelectorAll('.is-moving,.is-drop-target').forEach(node => node.classList.remove('is-moving','is-drop-target'));
drag = null;
}
function target(event) {
const day = event.target.closest('.v5-time-day');
if (!day || !drag) return null;
const offset = (event.clientY-day.getBoundingClientRect().top)/1.6 - drag.offset;
const minutes = Math.max(0, Math.min(1425, Math.round((Number(host.dataset.firstHour)*60+offset)/15)*15));
const start = new Date(`${day.dataset.date}T00:00:00`);
start.setMinutes(minutes);
// A segment after midnight still moves the complete original booking.
start.setTime(start.getTime() - drag.segmentOffset);
return {day, start};
}
host.addEventListener('dragstart', event => {
const card = event.target.closest('[data-move-id]');
if (!card || saving || event.target.closest('.case-slot-resize')) {event.preventDefault(); return;}
drag = {
card, offset: (event.clientY-card.getBoundingClientRect().top)/1.6,
segmentOffset: new Date(card.dataset.segmentStart)-new Date(card.dataset.start),
};
card.classList.add('is-moving');
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData('text/plain', card.dataset.moveId);
});
host.addEventListener('dragover', event => {
const drop = target(event);
if (!drop) return;
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
host.querySelectorAll('.is-drop-target').forEach(node => node.classList.remove('is-drop-target'));
drop.day.classList.add('is-drop-target');
drag.card.title = `Flyt til ${drop.start.toLocaleString('da-DK', {weekday:'short',hour:'2-digit',minute:'2-digit'})}`;
});
host.addEventListener('drop', async event => {
const drop = target(event);
if (!drop || saving) return;
event.preventDefault();
event.stopPropagation();
const {card} = drag;
const start = new Date(card.dataset.start), end = new Date(card.dataset.end);
clear();
if (drop.start.getTime() === start.getTime()) return;
const payload = {
version: Number(card.dataset.version), starts_at: drop.start.toISOString(),
ends_at: new Date(drop.start.getTime()+(end.getTime()-start.getTime())).toISOString(),
};
saving = true;
try {
for (;;) {
const response = await fetch(`/api/v1/planner/allocations/${Number(card.dataset.moveId)}`, {
method:'PATCH', credentials:'include', headers:{'Content-Type':'application/json'}, body:JSON.stringify(payload),
});
const body = await response.json();
if (response.ok) break;
const message = typeof body.detail === 'string' ? body.detail : body.detail?.message;
if (response.status === 409 && body.detail?.conflict_status && !payload.confirm_conflicts && window.confirm(`${message}. Vil du flytte aftalen alligevel?`)) {
payload.confirm_conflicts = true;
continue;
}
throw new Error(message || 'Kunne ikke flytte aftalen');
}
window.showCaseFeedback('Aftalen er flyttet', 'success');
} catch (error) {
window.showCaseFeedback(error.message);
} finally {
try {await window.loadEmbeddedCasePlanner(true);} finally {saving = false;}
}
});
host.addEventListener('dragend', clear);
})();