function showCreateSolutionModal() { const addTimeCheckbox = document.getElementById('sol_add_time'); const timeFields = document.getElementById('sol_time_fields'); if (addTimeCheckbox && timeFields) { addTimeCheckbox.checked = false; timeFields.classList.add('d-none'); } const timeDate = document.getElementById('sol_time_date'); if (timeDate) timeDate.valueAsDate = new Date(); const timeHours = document.getElementById('sol_time_hours'); const timeMinutes = document.getElementById('sol_time_minutes'); const timeTotal = document.getElementById('sol_time_total'); if (timeHours) timeHours.value = ''; if (timeMinutes) timeMinutes.value = ''; if (timeTotal) timeTotal.textContent = 'Total: 0.00 timer'; const timeDesc = document.getElementById('sol_time_desc'); if (timeDesc) timeDesc.value = ''; const timeInternal = document.getElementById('sol_time_internal'); if (timeInternal) timeInternal.checked = false; new bootstrap.Modal(document.getElementById('createSolutionModal')).show(); } function updateSolutionTimeTotal() { const h = parseInt(document.getElementById('sol_time_hours').value) || 0; const m = parseInt(document.getElementById('sol_time_minutes').value) || 0; const total = h + (m / 60); const output = document.getElementById('sol_time_total'); if (output) output.textContent = `Total: ${total.toFixed(2)} timer`; } async function saveSolution() { const data = { sag_id: document.getElementById('sol_sag_id').value, title: document.getElementById('sol_title').value, solution_type: document.getElementById('sol_type').value, result: document.getElementById('sol_result').value, description: document.getElementById('sol_desc').value, created_by_user_id: 1 // TODO: Get from auth }; const addTime = document.getElementById('sol_add_time')?.checked; const timeHours = parseInt(document.getElementById('sol_time_hours').value) || 0; const timeMinutes = parseInt(document.getElementById('sol_time_minutes').value) || 0; const timeTotal = timeHours + (timeMinutes / 60); try { const res = await fetch(`/api/v1/sag/${data.sag_id}/solution`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data) }); if (res.ok) { if (addTime && timeTotal > 0) { const solution = await res.json(); const timePayload = { sag_id: data.sag_id, solution_id: solution.id, description: document.getElementById('sol_time_desc').value || data.title, original_hours: timeTotal, worked_date: document.getElementById('sol_time_date').value || null, is_internal: document.getElementById('sol_time_internal').checked, work_type: 'support' }; const timeRes = await fetch('/api/v1/timetracking/entries/internal', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(timePayload) }); if (!timeRes.ok) { alert('Løsning oprettet, men tid kunne ikke registreres'); } } window.location.reload(); } else { alert('Fejl ved oprettelse af løsning'); } } catch(e) { console.error(e); alert('Fejl'); } } function showAddTimeModal() { // Set date to today document.getElementById('time_date').valueAsDate = new Date(); // Reset fields if(document.getElementById('time_total_minutes')) { document.getElementById('time_total_minutes').value = ''; document.getElementById('time_start_input').value = ''; document.getElementById('time_end_input').value = ''; } document.getElementById('time_desc').value = ''; if(document.getElementById('time_internal')) document.getElementById('time_internal').checked = false; if(document.getElementById('time_billing_method')) document.getElementById('time_billing_method').value = 'invoice'; if(document.getElementById('time_work_type')) document.getElementById('time_work_type').value = 'support'; new bootstrap.Modal(document.getElementById('createTimeModal')).show(); } // Auto-calculate total hours /* removed updateTimeTotal */ // Add listeners safely document.addEventListener('DOMContentLoaded', () => { const hInput = document.getElementById('time_hours_input'); const mInput = document.getElementById('time_minutes_input'); if(hInput) hInput.addEventListener('input', updateTimeTotal); if(mInput) mInput.addEventListener('input', updateTimeTotal); const solAddTime = document.getElementById('sol_add_time'); const solFields = document.getElementById('sol_time_fields'); if (solAddTime && solFields) { solAddTime.addEventListener('change', () => { solFields.classList.toggle('d-none', !solAddTime.checked); }); } const solHours = document.getElementById('sol_time_hours'); const solMinutes = document.getElementById('sol_time_minutes'); if (solHours) solHours.addEventListener('input', updateSolutionTimeTotal); if (solMinutes) solMinutes.addEventListener('input', updateSolutionTimeTotal); }); function bindTimeModalCalculations() { const startIn = document.getElementById('time_start_input'); const endIn = document.getElementById('time_end_input'); const minIn = document.getElementById('time_total_minutes'); if (!startIn || !endIn || !minIn) return; const parseTime = (val) => { if (!val) return null; const [h,m] = val.split(':').map(Number); return (h * 60) + m; }; const toTimeStr = (totalMins) => { const h = Math.floor(totalMins / 60) % 24; const m = totalMins % 60; return `${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}`; }; const recalculate = (trigger) => { const s = parseTime(startIn.value); const e = parseTime(endIn.value); const dur = parseInt(minIn.value); if (trigger === 'start' || trigger === 'end') { if (s !== null && e !== null) { let diff = e - s; if (diff < 0) diff += 24*60; minIn.value = diff; } else if (s !== null && !isNaN(dur) && dur > 0 && !endIn.value) { endIn.value = toTimeStr(s + dur); } else if (e !== null && !isNaN(dur) && dur > 0 && !startIn.value) { let base = e - dur; while (base < 0) base += 24*60; startIn.value = toTimeStr(base); } } else if (trigger === 'min') { if (s !== null && !isNaN(dur) && dur > 0) { endIn.value = toTimeStr(s + dur); } else if (e !== null && !isNaN(dur) && dur > 0 && !startIn.value) { let base = e - dur; while(base < 0) base+=24*60; startIn.value = toTimeStr(base); } } }; startIn.addEventListener('change', () => recalculate('start')); endIn.addEventListener('change', () => recalculate('end')); minIn.addEventListener('input', () => recalculate('min')); } document.addEventListener('DOMContentLoaded', bindTimeModalCalculations); async function saveTime() { const mInput = document.getElementById('time_total_minutes'); const minVal = parseInt(mInput ? mInput.value : 0); if (!minVal || minVal <= 0) { alert('Indtast en gyldig varighed (minutter).'); return; } const totalHours = minVal / 60; const dateVal = document.getElementById('time_date').value; // extract optional start/end limits const tStart = document.getElementById('time_start_input')?.value; const tEnd = document.getElementById('time_end_input')?.value; let startObj = null; let endObj = null; if (dateVal && tStart) { try { const l = new Date(`${dateVal}T${tStart}:00`); startObj = l.toISOString(); } catch(e){} } if (dateVal && tEnd) { try { const l = new Date(`${dateVal}T${tEnd}:00`); if (startObj && new Date(startObj) > l) { l.setDate(l.getDate() + 1); } endObj = l.toISOString(); } catch(e){} } const sagId = document.getElementById('time_sag_id').value; const payload = { sag_id: parseInt(sagId), // Note: saveTime modal expects 'timer' as totalHours currently, let's keep compatibility: timer: totalHours, faktisk_tid_min: minVal, worked_date: dateVal, start_tid: startObj, slut_tid: endObj, description: document.getElementById('time_desc').value, work_type: document.getElementById('time_work_type').value, billing_method: document.getElementById('time_billing_method').value }; try { const res = await fetch(`/api/v1/cases/${sagId}/time`, { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) }); if(res.ok) { window.location.reload(); } else { alert("Fejl ved registrering af tid"); } } catch(err) { console.error(err); alert("Forbindelsesfejl"); } }