- Introduced tests for mail templates including ranking, rendering, and attachment handling. - Added tests for time billing selection and approval processes, ensuring proper validation and state management. - Implemented tests for case types in JavaScript, focusing on loading and editing functionality. - Created tests for contact mail AI integration, ensuring proper parsing and error handling. - Developed tests for dark theme CSS contrast and loading order. - Added tests for invoice fee service, covering various scenarios including exemptions and invalid inputs. - Implemented vendor resource tests, ensuring proper file handling and query validation.
60 lines
4.7 KiB
JavaScript
60 lines
4.7 KiB
JavaScript
(() => {
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const zone = document.querySelector('.contact-mail-drop');
|
|
if (!zone) return;
|
|
const input = zone.querySelector('input'), status = zone.querySelector('[data-import-status]');
|
|
const form = document.getElementById('contactMailImportForm');
|
|
const kind = location.pathname.startsWith('/vendors/') ? 'vendors' : 'customers';
|
|
const ownerId = Number(location.pathname.split('/').filter(Boolean).pop());
|
|
const labels = {first_name:'Fornavn',last_name:'Efternavn',email:'E-mail',phone:'Telefon',mobile:'Mobil',title:'Titel',department:'Afdeling'};
|
|
let busy = false, createdId = null;
|
|
async function request(url, options) {
|
|
const response = await fetch(url, options), data = await response.json().catch(()=>({}));
|
|
if (!response.ok) throw new Error(data.detail || 'Kunne ikke gemme kontaktpersonen');
|
|
return data;
|
|
}
|
|
const post = (url, data) => request(url,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)});
|
|
async function analyze(file) {
|
|
if (busy || !file) return;
|
|
if (!/\.(msg|eml)$/i.test(file.name) || file.size > 10*1024*1024) { status.textContent='Vælg en .msg- eller .eml-mail på højst 10 MB.';return; }
|
|
busy=true;status.textContent='AI analyserer mailen…';zone.setAttribute('aria-busy','true');
|
|
try {
|
|
const payload=new FormData();payload.append('file',file);
|
|
const data=await request('/api/v1/contacts/analyze-email?use_ai=true',{method:'POST',body:payload});
|
|
createdId=null;
|
|
const host=form.querySelector('[data-import-fields]');host.replaceChildren();
|
|
Object.entries(labels).forEach(([key,label])=>{
|
|
const wrapper=document.createElement('div');wrapper.className='mb-2';
|
|
const caption=document.createElement('label');caption.className='form-label';caption.textContent=label;caption.htmlFor=`mailImport-${key}`;
|
|
const field=document.createElement('input');field.className='form-control';field.id=caption.htmlFor;field.name=key;field.type=key==='email'?'email':'text';field.required=key==='first_name';field.maxLength=250;field.value=data.contact?.[key]||'';
|
|
wrapper.append(caption,field);host.append(wrapper);
|
|
});
|
|
form.querySelector('[data-save-status]').textContent='';
|
|
status.textContent='AI-forslagene er klar til gennemgang.';
|
|
bootstrap.Modal.getOrCreateInstance(document.getElementById('contactMailImportModal')).show();
|
|
} catch(error){status.textContent=error.message;}
|
|
finally{busy=false;zone.removeAttribute('aria-busy');input.value='';}
|
|
}
|
|
zone.onclick=event=>{if(event.target!==input&&!busy) input.click();};
|
|
zone.onkeydown=event=>{if(event.key==='Enter'||event.key===' '){event.preventDefault();if(!busy)input.click();}};
|
|
input.onchange=()=>analyze(input.files[0]);
|
|
['dragenter','dragover'].forEach(type=>zone.addEventListener(type,event=>{event.preventDefault();event.stopPropagation();zone.classList.add('bg-light');}));
|
|
zone.ondragleave=()=>zone.classList.remove('bg-light');
|
|
zone.ondrop=event=>{event.preventDefault();event.stopPropagation();zone.classList.remove('bg-light');const file=event.dataTransfer?.files?.[0];if(file)analyze(file);else status.textContent='Gem mailen som .msg/.eml og træk filen hertil.';};
|
|
form.onsubmit=async event=>{
|
|
event.preventDefault();const button=form.querySelector('[type=submit]'), saveStatus=form.querySelector('[data-save-status]');button.disabled=true;
|
|
try {
|
|
if (!createdId) {
|
|
const data=Object.fromEntries([...new FormData(form)].map(([key,value])=>[key,String(value).trim()||null]));data.last_name=data.last_name||'';
|
|
if(kind==='customers')data.company_ids=[ownerId];
|
|
const contact=await post('/api/v1/contacts',data);createdId=Number(contact.id);
|
|
if(!createdId)throw new Error('Kontakten blev oprettet uden et kontakt-ID. Genindlæs før du prøver igen.');
|
|
form.querySelectorAll('input').forEach(field=>field.readOnly=true);
|
|
}
|
|
if(kind==='vendors')await post(`/api/v1/vendors/${ownerId}/contacts`,{contact_id:createdId,role:''});
|
|
location.hash=kind==='vendors'?'kontakter':'contacts';location.reload();
|
|
} catch(error){saveStatus.textContent=(createdId?'Kontakten er oprettet. Tryk igen for at tilknytte den. ':'')+error.message;button.disabled=false;}
|
|
};
|
|
});
|
|
})();
|