(function () { 'use strict'; let _openPopover = null; // ── helpers ─────────────────────────────────────────────────────── function closeAllPopovers() { document.querySelectorAll('.rel-qa-menu').forEach(el => el.remove()); _openPopover = null; } document.addEventListener('click', function(e) { if (!e.target.closest('.rel-qa-menu') && !e.target.closest('.btn-rel-action')) closeAllPopovers(); }); document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeAllPopovers(); }); function popoverPos(btn) { const r = btn.getBoundingClientRect(); return { top: r.bottom + window.scrollY + 4, left: r.left + window.scrollX }; } function esc(s) { return String(s||'').replace(/&/g,'&').replace(//g,'>'); } // ── load global entity tags into rel-tag-row divs (using global tag system) ── async function loadAllRelationTags() { const rows = Array.from(document.querySelectorAll('.rel-tag-row')); if (!rows.length) return; // Wait briefly for tag-picker.js to initialize const renderFn = () => window.renderEntityTags; await new Promise(res => { const t = setInterval(() => { if (renderFn()) { clearInterval(t); res(); } }, 50); setTimeout(() => { clearInterval(t); res(); }, 2000); }); await Promise.all(rows.map(async el => { const caseId = parseInt(el.id.replace('rel-tags-', '')); if (isNaN(caseId) || !window.renderEntityTags) return; await window.renderEntityTags('case', caseId, el.id); })); } // ── tag button → opens global tag picker ────────────────────────── window.openRelTagPopover = function(caseId) { if (!window.showTagPicker) return; window.showTagPicker('case', caseId, () => { if (window.renderEntityTags) window.renderEntityTags('case', caseId, 'rel-tags-' + caseId); }); }; // ── quick action menu ───────────────────────────────────────────── const QA_ITEMS = [ { icon: 'bi-person-check', label: 'Tildel sag', action: 'assign' }, { icon: 'bi-clock', label: 'Tidregistrering', action: 'time' }, { icon: 'bi-chat-left-text', label: 'Kommentar', action: 'note' }, { icon: 'bi-bell', label: 'Påmindelse', action: 'reminder' }, { icon: 'bi-graph-up-arrow', label: 'Salgspipeline', action: 'pipeline' }, { icon: 'bi-paperclip', label: 'Filer', action: 'files' }, { icon: 'bi-cpu', label: 'Hardware', action: 'hardware' }, { icon: 'bi-check2-square', label: 'Opgave', action: 'todo' }, { icon: 'bi-lightbulb', label: 'Løsning', action: 'solution' }, { icon: 'bi-bag', label: 'Varekøb & salg', action: 'sales' }, { icon: 'bi-arrow-repeat', label: 'Abonnement', action: 'subscription' }, { icon: 'bi-envelope', label: 'Send email', action: 'email' }, ]; // cache pipeline presence per caseId so we only fetch once per page load const _pipelineCache = {}; window.openRelQaMenu = async function(caseId, caseTitle, btn) { closeAllPopovers(); btn.classList.add('active'); const pos = popoverPos(btn); const menu = document.createElement('div'); menu.className = 'rel-qa-menu'; menu.style.cssText = `position:absolute;top:${pos.top}px;left:${Math.max(0, pos.left - 120)}px;`; menu.innerHTML = `
SAG-${caseId}
` + `
`; document.body.appendChild(menu); _openPopover = menu; // Fetch case data to check pipeline presence (cached) if (!(_pipelineCache[caseId] !== undefined)) { try { const r = await fetch(`/api/v1/sag/${caseId}`, { credentials: 'include' }); if (r.ok) { const d = await r.json(); _pipelineCache[caseId] = !!(d.pipeline_stage_id || d.pipeline_amount || d.pipeline_description); } else { _pipelineCache[caseId] = false; } } catch { _pipelineCache[caseId] = false; } } const hasPipeline = _pipelineCache[caseId]; // Filter: hide pipeline item if case already has one; show "Se pipeline" link instead const items = QA_ITEMS.filter(i => i.action !== 'pipeline' || !hasPipeline); const extra = hasPipeline ? `
Pipeline (se sagen)
` : ''; if (!_openPopover || _openPopover !== menu) return; // closed before fetch returned menu.innerHTML = `
SAG-${caseId}
` + items.map(item => `
${esc(item.label)}
` ).join('') + extra; }; function getRelQaPrimaryButton() { const sidePanel = document.getElementById('caseAddSidePanel'); if (sidePanel && sidePanel.classList.contains('open')) { return sidePanel.querySelector('#relQaModalFooter .btn-primary'); } return document.querySelector('#relQaModalEl .btn-primary'); } function closeRelQaSurfaceAfterSave() { const sidePanel = document.getElementById('caseAddSidePanel'); const panelOpen = !!(sidePanel && sidePanel.classList.contains('open')); const relModalEl = document.getElementById('relQaModalEl'); const relModalInstance = relModalEl ? bootstrap.Modal.getInstance(relModalEl) : null; if (relModalInstance) { relModalInstance.hide(); } // In sidepanel mode, refresh to reflect new persisted data across modules. if (panelOpen) { setTimeout(() => window.location.reload(), 120); } } window.relQaAction = function(action, caseId, caseTitle) { closeAllPopovers(); if (action === 'time') openRelTimeModal(caseId, caseTitle); else if (action === 'email') openRelEmailModal(caseId, caseTitle); else if (action === 'note') openRelNoteModal(caseId, caseTitle); else if (action === 'reminder') openRelReminderModal(caseId, caseTitle); else if (action === 'todo') openRelTodoModal(caseId, caseTitle); else if (action === 'assign') openRelAssignModal(caseId, caseTitle); else if (action === 'pipeline') openRelPipelineModal(caseId, caseTitle); else if (action === 'files') openRelFilesModal(caseId, caseTitle); else if (action === 'hardware') openRelHardwareModal(caseId, caseTitle); else if (action === 'solution') openRelSolutionModal(caseId, caseTitle); else if (action === 'sales') openRelSalesModal(caseId, caseTitle); else if (action === 'subscription') openRelSubscriptionModal(caseId, caseTitle); else window.open(`/sag/${caseId}`, '_blank'); }; // ── Quick Pipeline modal ────────────────────────────────────────── window.openRelPipelineModal = function(caseId, caseTitle) { _showRelModal( `Salgspipeline`, `
`, `` ); }; window._submitRelPipeline = async function(caseId) { const stage = document.getElementById('rqp_stage').value; const amount = document.getElementById('rqp_amount').value; const prob = document.getElementById('rqp_prob').value; const desc = document.getElementById('rqp_desc').value; const payload = {}; if (stage) payload.stage_id = parseInt(stage); if (amount) payload.amount = parseFloat(amount); if (prob) payload.probability = parseInt(prob); if (desc) payload.description = desc; if (!Object.keys(payload).length) { if (typeof showNotification === 'function') showNotification('Udfyld mindst ét felt', 'warning'); return; } const saveBtn = getRelQaPrimaryButton(); if (saveBtn) { saveBtn.disabled = true; } try { const r = await fetch(`/api/v1/sag/${caseId}/pipeline`, { method: 'PATCH', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Pipeline opdateret ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error'); if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── Quick Files modal ───────────────────────────────────────────── window.openRelFilesModal = function(caseId, caseTitle) { _showRelModal( `Upload fil`, `
`, `` ); }; window._submitRelFiles = async function(caseId) { const fileInput = document.getElementById('rqf_file'); if (!fileInput.files.length) { if (typeof showNotification === 'function') showNotification('Vælg mindst én fil', 'warning'); return; } const saveBtn = getRelQaPrimaryButton(); if (saveBtn) { saveBtn.disabled = true; saveBtn.innerHTML = ' Uploader…'; } let success = 0; let failed = 0; for (const file of fileInput.files) { try { const fd = new FormData(); fd.append('file', file); const desc = document.getElementById('rqf_desc').value; if (desc) fd.append('description', desc); const r = await fetch(`/api/v1/sag/${caseId}/files`, { method: 'POST', credentials: 'include', body: fd }); if (r.ok) success++; else failed++; } catch { failed++; } } closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') { if (failed === 0) showNotification(`${success} fil(er) uploadet ✓`, 'success'); else showNotification(`${success} ok, ${failed} fejlede`, 'warning'); } }; // ── Quick Hardware modal ────────────────────────────────────────── window.openRelHardwareModal = async function(caseId, caseTitle) { _showRelModal( `Hardware`, `
`, `` ); // Wire up search const inp = document.getElementById('rqhw_search'); const res = document.getElementById('rqhw_results'); let _hwTimer; inp.addEventListener('input', () => { clearTimeout(_hwTimer); _hwTimer = setTimeout(async () => { const q = inp.value.trim(); if (q.length < 2) { res.style.display='none'; return; } try { const r = await fetch(`/api/v1/search/hardware?q=${encodeURIComponent(q)}`, { credentials: 'include' }); if (!r.ok) return; const items = await r.json(); if (!items.length) { res.innerHTML = '
Ingen resultater
'; res.style.display='block'; return; } res.innerHTML = items.slice(0,10).map(h => `
${esc(h.name||'')} ${esc(h.serial_number||'')}
` ).join(''); res.style.display = 'block'; res.querySelectorAll('.hw-opt').forEach(el => el.addEventListener('click', () => { document.getElementById('rqhw_id').value = el.dataset.id; document.getElementById('rqhw_selected').textContent = '✓ Valgt: ' + el.dataset.label; inp.value = el.dataset.label; res.style.display = 'none'; })); } catch {} }, 300); }); }; window._submitRelHardware = async function(caseId) { const hwId = document.getElementById('rqhw_id').value; if (!hwId) { if (typeof showNotification === 'function') showNotification('Vælg hardware fra listen', 'warning'); return; } const saveBtn = getRelQaPrimaryButton(); if (saveBtn) saveBtn.disabled = true; try { const r = await fetch(`/api/v1/sag/${caseId}/hardware`, { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ hardware_id: parseInt(hwId), note: document.getElementById('rqhw_note').value }) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Hardware tilknyttet ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error'); if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── Quick Løsning modal ─────────────────────────────────────────── window.openRelSolutionModal = function(caseId, caseTitle) { const today = new Date().toISOString().split('T')[0]; _showRelModal( `Løsning`, `
`, `` ); }; window._submitRelSolution = async function(caseId) { const title = document.getElementById('rqs_title').value.trim(); if (!title) { if (typeof showNotification === 'function') showNotification('Angiv en titel', 'warning'); return; } const saveBtn = getRelQaPrimaryButton(); if (saveBtn) saveBtn.disabled = true; try { const r = await fetch(`/api/v1/sag/${caseId}/solution`, { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ sag_id: caseId, title, solution_type: document.getElementById('rqs_type').value, result: document.getElementById('rqs_result').value, description: document.getElementById('rqs_desc').value, }) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Løsning gemt ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error'); if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── Quick Varekøb & Salg modal ──────────────────────────────────── window.openRelSalesModal = function(caseId, caseTitle) { const today = new Date().toISOString().split('T')[0]; _showRelModal( `Varekøb & salg`, `
`, `` ); // Auto-calculate total when qty/uprice changes setTimeout(() => { const qtyEl = document.getElementById('rqsl_qty'); const uprEl = document.getElementById('rqsl_uprice'); const totEl = document.getElementById('rqsl_total'); function calcTotal() { const q = parseFloat(qtyEl.value) || 0; const u = parseFloat(uprEl.value) || 0; if (q && u) totEl.value = (q * u).toFixed(2); } qtyEl.addEventListener('input', calcTotal); uprEl.addEventListener('input', calcTotal); }, 50); }; window._submitRelSales = async function(caseId) { const desc = document.getElementById('rqsl_desc').value.trim(); const total = parseFloat(document.getElementById('rqsl_total').value); if (!desc) { if (typeof showNotification === 'function') showNotification('Angiv beskrivelse', 'warning'); return; } if (!total) { if (typeof showNotification === 'function') showNotification('Angiv beløb', 'warning'); return; } const saveBtn = getRelQaPrimaryButton(); if (saveBtn) saveBtn.disabled = true; try { const r = await fetch(`/api/v1/sag/${caseId}/sale-items`, { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ type: document.getElementById('rqsl_type').value, description: desc, quantity: parseFloat(document.getElementById('rqsl_qty').value) || 1, unit_price: parseFloat(document.getElementById('rqsl_uprice').value) || null, amount: total, line_date: document.getElementById('rqsl_date').value || null, status: 'draft', }) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Varelinje oprettet ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error'); if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── Quick Abonnement modal ──────────────────────────────────────── window.openRelSubscriptionModal = function(caseId, caseTitle) { const today = new Date().toISOString().split('T')[0]; _showRelModal( `Abonnement`, `
Varelinje
`, `` ); }; window._submitRelSubscription = async function(caseId) { const interval = document.getElementById('rqsub_interval').value; const day = parseInt(document.getElementById('rqsub_day').value); const startDate = document.getElementById('rqsub_start').value; const liDesc = document.getElementById('rqsub_li_desc').value.trim(); const liQty = parseFloat(document.getElementById('rqsub_li_qty').value) || 1; const liPrice = parseFloat(document.getElementById('rqsub_li_price').value) || 0; if (!startDate) { if (typeof showNotification === 'function') showNotification('Angiv startdato', 'warning'); return; } if (!liDesc || !liPrice) { if (typeof showNotification === 'function') showNotification('Udfyld varelinje (beskrivelse + pris)', 'warning'); return; } const saveBtn = getRelQaPrimaryButton(); if (saveBtn) saveBtn.disabled = true; try { const r = await fetch('/api/v1/sag-subscriptions', { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ sag_id: caseId, billing_interval: interval, billing_day: day, start_date: startDate, notes: document.getElementById('rqsub_notes').value || null, line_items: [{ description: liDesc, quantity: liQty, unit_price: liPrice }] }) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Abonnement oprettet ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl', 'error'); if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── Quick Time modal ────────────────────────────────────────────── window.openRelTimeModal = function(caseId, caseTitle) { const today = new Date().toISOString().split('T')[0]; _showRelModal( `Tidregistrering`, `
`, `` ); }; window._submitRelTime = async function(caseId) { const h = parseInt(document.getElementById('rqt_h').value) || 0; const m = parseInt(document.getElementById('rqt_m').value) || 0; const totalHours = parseFloat((h + m / 60).toFixed(4)); if (totalHours <= 0) { if (typeof showNotification === 'function') showNotification('Angiv tid (timer/minutter)', 'warning'); return; } const billing = document.getElementById('rqt_billing')?.value || 'invoice'; const payload = { sag_id: caseId, worked_date: document.getElementById('rqt_date').value, original_hours: totalHours, description: document.getElementById('rqt_desc').value, billing_method: billing, is_internal: billing === 'internal', }; const saveBtn = getRelQaPrimaryButton(); if (saveBtn) { saveBtn.disabled = true; saveBtn.innerHTML = ''; } try { const r = await fetch('/api/v1/timetracking/entries/internal', { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Tid registreret ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl ved registrering', 'error'); if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = 'Gem'; } } } catch { if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = 'Gem'; } } }; // ── Quick Email modal ───────────────────────────────────────────── window.openRelEmailModal = function(caseId, caseTitle) { const defaultRecipient = typeof getDefaultCaseRecipient === 'function' ? getDefaultCaseRecipient() : ''; const defaultSubject = `Sag #${caseId}: `; const attachmentOptions = Array.isArray(sagFilesCache) && sagFilesCache.length ? sagFilesCache .map((file) => { const fileId = Number(file.id); const filename = esc(file.filename || `Fil ${fileId}`); return ``; }) .join('') : ''; _showRelModal( `Email`, `
`, `` ); }; window._submitRelEmail = async function(caseId) { const toInput = document.getElementById('rqe_to'); const ccInput = document.getElementById('rqe_cc'); const bccInput = document.getElementById('rqe_bcc'); const subjectInput = document.getElementById('rqe_subject'); const bodyInput = document.getElementById('rqe_body'); const attachmentSelect = document.getElementById('rqe_attachment_ids'); const statusEl = document.getElementById('rqe_status'); const saveBtn = getRelQaPrimaryButton(); if (!toInput || !subjectInput || !bodyInput || !statusEl) return; const to = parseEmailField(toInput.value); const cc = parseEmailField(ccInput?.value || ''); const bcc = parseEmailField(bccInput?.value || ''); const subject = (subjectInput.value || '').trim(); const bodyText = (bodyInput.value || '').trim(); const attachmentFileIds = Array.from(attachmentSelect?.selectedOptions || []) .map((opt) => Number(opt.value)) .filter((id) => Number.isInteger(id) && id > 0); if (!to.length) { if (typeof showNotification === 'function') showNotification('Udfyld mindst en modtager.', 'warning'); return; } if (!subject) { if (typeof showNotification === 'function') showNotification('Udfyld emne.', 'warning'); return; } if (!bodyText) { if (typeof showNotification === 'function') showNotification('Udfyld besked.', 'warning'); return; } if (saveBtn) { saveBtn.disabled = true; saveBtn.innerHTML = 'Sender...'; } statusEl.className = 'small text-muted'; statusEl.textContent = 'Sender e-mail...'; try { const res = await fetch(`/api/v1/sag/${caseId}/emails/send`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ to, cc, bcc, subject, body_text: bodyText, attachment_file_ids: attachmentFileIds, thread_email_id: selectedLinkedEmailId || null, thread_key: linkedEmailsCache.find((entry) => Number(entry.id) === Number(selectedLinkedEmailId))?.thread_key || null }) }); if (!res.ok) { let message = `HTTP ${res.status} ${res.statusText || 'Send failed'}`; try { const responseText = await res.text(); if (responseText) { try { const err = JSON.parse(responseText); if (err?.detail) { message = err.detail; } else if (err?.message) { message = err.message; } } catch (_) { message = responseText.slice(0, 500); } } } catch (_) { } throw new Error(message); } statusEl.className = 'small text-success'; statusEl.textContent = 'E-mail sendt.'; if (typeof loadLinkedEmails === 'function') { loadLinkedEmails(); } if (typeof showNotification === 'function') showNotification('E-mail sendt.', 'success'); const relModalEl = document.getElementById('relQaModalEl'); const relModal = relModalEl ? bootstrap.Modal.getInstance(relModalEl) : null; if (relModal) relModal.hide(); } catch (error) { statusEl.className = 'small text-danger'; statusEl.textContent = error?.message || 'Email send failed (ukendt fejl)'; if (typeof showNotification === 'function') showNotification(statusEl.textContent, 'error'); if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = 'Send email'; } return; } if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = 'Send email'; } }; // ── Quick Kommentar modal ───────────────────────────────────────── window.openRelNoteModal = function(caseId, caseTitle) { _showRelModal( `Kommentar`, `
`, `` ); }; window._submitRelNote = async function(caseId) { const text = document.getElementById('rqn_text').value.trim(); if (!text) return; const saveBtn = document.querySelector('#relQaModalEl .btn-primary'); if (saveBtn) { saveBtn.disabled = true; } try { const r = await fetch(`/api/v1/sag/${caseId}/kommentarer`, { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ forfatter: 'Hurtig kommentar', indhold: text }) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Kommentar tilføjet ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl ved gemning', 'error'); if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── Quick Opgave modal ──────────────────────────────────────────── window.openRelTodoModal = function(caseId, caseTitle) { const today = new Date().toISOString().split('T')[0]; _showRelModal( `Opgave`, `
`, `` ); }; window._submitRelTodo = async function(caseId) { const title = document.getElementById('rqtd_title').value.trim(); if (!title) { if (typeof showNotification === 'function') showNotification('Angiv opgavetitel', 'warning'); return; } const due = document.getElementById('rqtd_due').value || null; const saveBtn = getRelQaPrimaryButton(); if (saveBtn) { saveBtn.disabled = true; } try { const r = await fetch(`/api/v1/sag/${caseId}/todos`, { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ titel: title, frist: due, sag_id: caseId }) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Opgave oprettet ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Opgave-endpoint ikke tilgængeligt endnu', 'warning'); if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── Quick Tildel sag modal ──────────────────────────────────────── window.openRelAssignModal = async function(caseId, caseTitle) { _showRelModal( `Tildel sag`, `
`, `` ); try { const r = await fetch('/api/v1/users', { credentials: 'include' }); if (r.ok) { const users = await r.json(); const sel = document.getElementById('rqa_user'); if (sel) sel.innerHTML = '' + users.map(u => ``).join(''); } } catch {} }; window._submitRelAssign = async function(caseId) { const userId = document.getElementById('rqa_user')?.value; const saveBtn = getRelQaPrimaryButton(); if (saveBtn) { saveBtn.disabled = true; } try { const r = await fetch(`/api/v1/sag/${caseId}`, { method: 'PATCH', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ ansvarlig_bruger_id: userId ? parseInt(userId) : null }) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Sag tildelt ✓', 'success'); } else { const d = await r.json().catch(()=>({})); if (typeof showNotification === 'function') showNotification(d.detail || 'Fejl ved tildeling', 'error'); if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── Quick Reminder modal ────────────────────────────────────────── window.openRelReminderModal = function(caseId, caseTitle) { const tmr = new Date(); tmr.setDate(tmr.getDate()+1); const tmrStr = tmr.toISOString().slice(0,16); _showRelModal( `Påmindelse`, `
`, `` ); }; window._submitRelReminder = async function(caseId) { const payload = { sag_id: caseId, remind_at: document.getElementById('rqr_at').value, message: document.getElementById('rqr_msg').value }; const saveBtn = getRelQaPrimaryButton(); if (saveBtn) { saveBtn.disabled = true; } try { const r = await fetch('/api/v1/reminders', { method: 'POST', credentials: 'include', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) }); if (r.ok) { closeRelQaSurfaceAfterSave(); if (typeof showNotification === 'function') showNotification('Påmindelse oprettet', 'success'); } else { if (saveBtn) saveBtn.disabled = false; } } catch { if (saveBtn) saveBtn.disabled = false; } }; // ── shared modal helper ─────────────────────────────────────────── window._showRelModal = function(title, bodyHtml, footerBtns) { let el = document.getElementById('relQaModalEl'); if (!el) { el = document.createElement('div'); el.id = 'relQaModalEl'; el.className = 'modal fade'; el.tabIndex = -1; el.innerHTML = ``; document.body.appendChild(el); } document.getElementById('relQaModalTitle').innerHTML = title; document.getElementById('relQaModalBody').innerHTML = bodyHtml; const footer = document.getElementById('relQaModalFooter'); // Remove old action buttons (keep Annuller) footer.querySelectorAll('.btn-primary').forEach(b => b.remove()); if (footerBtns) footer.insertAdjacentHTML('afterbegin', footerBtns); new bootstrap.Modal(el).show(); }; // ── init on page load ───────────────────────────────────────────── document.addEventListener('DOMContentLoaded', loadAllRelationTags); })();