Files
Makap/makap_backend/www/makap-onboarding.html
2026-10-05 16:04:29 +03:00

18 lines
12 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "templates/web.html" %}
{% block title %}Customer Onboarding · MAKAP{% endblock %}
{% block page_content %}
<div id="makap-onboarding" class="onboarding-page">
<style>
#makap-onboarding{font-family:Inter,system-ui,sans-serif;background:#f3f5f9;color:#12182b;min-height:calc(100vh - 60px);padding:28px 34px 55px}#makap-onboarding *{box-sizing:border-box}.onb-head{display:flex;justify-content:space-between;align-items:flex-end;gap:20px;max-width:1280px;margin:auto}.onb-eyebrow{text-transform:uppercase;letter-spacing:.1em;font-size:11px;font-weight:700;color:#6f7b91;margin:0 0 8px}.onb-head h1{font-size:30px;margin:0 0 7px;letter-spacing:-.04em}.onb-head p{color:#667086;margin:0;font-size:14px}.onb-actions{display:flex;gap:9px}.onb-btn{border:1px solid #dfe4ed;border-radius:8px;background:#fff;color:#26324b;padding:11px 15px;font-weight:700;cursor:pointer}.onb-btn.primary{background:#2e6be6;border-color:#2e6be6;color:#fff}.onb-btn:hover{filter:brightness(.96)}.onb-summary{max-width:1280px;margin:26px auto 18px;display:grid;grid-template-columns:repeat(6,1fr);gap:12px}.onb-card{background:#fff;border:1px solid #e7eaf1;border-radius:12px;padding:16px 17px;cursor:pointer}.onb-card.active{border-color:#2e6be6;box-shadow:0 0 0 2px #dbe6ff}.onb-card label{display:block;color:#707b91;font-size:12px;margin-bottom:10px}.onb-card strong{font-size:27px;letter-spacing:-.04em}.onb-toolbar{max-width:1280px;margin:0 auto 12px;background:#fff;border:1px solid #e7eaf1;border-radius:12px;padding:13px;display:flex;gap:10px;align-items:center}.onb-search{flex:1;border:1px solid #dfe4ed;border-radius:7px;padding:11px 13px;font-size:13px;min-width:170px}.onb-select{border:1px solid #dfe4ed;border-radius:7px;background:#fff;padding:11px 13px;font-size:13px}.onb-table-wrap{max-width:1280px;margin:auto;background:#fff;border:1px solid #e7eaf1;border-radius:12px;overflow:auto}.onb-table{border-collapse:collapse;width:100%;font-size:13px}.onb-table th{text-align:left;text-transform:uppercase;letter-spacing:.08em;color:#8791a4;font-size:10px;padding:14px 15px;border-bottom:1px solid #e7eaf1;white-space:nowrap}.onb-table td{padding:15px;border-bottom:1px solid #f0f2f6;white-space:nowrap}.onb-table tr:hover{background:#f8faff}.onb-id{color:#1e4fbe;font-weight:800;cursor:pointer}.onb-muted{color:#69748b}.onb-badge{border-radius:20px;padding:5px 9px;font-size:11px;font-weight:700;background:#eef3ff;color:#2e6be6}.onb-badge.review{background:#fff5e5;color:#b46b17}.onb-badge.approved{background:#eaf8f0;color:#1f8a5c}.onb-badge.rejected{background:#fff0f2;color:#c23f60}.onb-empty{text-align:center;padding:42px;color:#8a94a7}.onb-modal-backdrop{position:fixed;inset:0;background:#0f1b2d99;z-index:99;display:none;align-items:center;justify-content:center;padding:20px}.onb-modal-backdrop.open{display:flex}.onb-modal{background:#fff;border-radius:14px;width:min(760px,100%);max-height:90vh;overflow:auto;padding:25px;box-shadow:0 25px 70px #0f1b2d44}.onb-modal-head{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:22px}.onb-modal h2{margin:0;font-size:22px}.onb-close{border:0;background:transparent;font-size:25px;cursor:pointer;color:#6b7588}.onb-form-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}.onb-field{display:flex;flex-direction:column;gap:6px}.onb-field.full{grid-column:1/-1}.onb-field label{font-size:12px;font-weight:700;color:#47536b}.onb-field input,.onb-field select,.onb-field textarea{font:inherit;border:1px solid #dfe4ed;border-radius:7px;padding:10px 11px}.onb-field textarea{min-height:74px;resize:vertical}.onb-form-actions{display:flex;justify-content:flex-end;gap:9px;margin-top:21px}.onb-detail{display:grid;grid-template-columns:1fr 1fr;gap:14px}.onb-detail div{background:#f7f9fc;border-radius:8px;padding:11px}.onb-detail small{color:#7d879a;display:block;font-size:10px;text-transform:uppercase;letter-spacing:.07em;margin-bottom:4px}.onb-detail span{font-size:13px}.onb-loading{padding:40px;text-align:center;color:#7c879b}@media(max-width:900px){.onb-summary{grid-template-columns:repeat(3,1fr)}.onb-head{display:block}.onb-actions{margin-top:18px}}@media(max-width:600px){ #makap-onboarding{padding:20px 13px 40px}.onb-summary{grid-template-columns:repeat(2,1fr)}.onb-toolbar{display:block}.onb-search,.onb-select{width:100%;margin-bottom:8px}.onb-form-grid,.onb-detail{grid-template-columns:1fr}}
</style>
<div class="onb-head"><div><p class="onb-eyebrow">Customer & commercial · M1–2</p><h1>Customer onboarding</h1><p>Capture, review, and convert new customer requests.</p></div><div class="onb-actions"><button class="onb-btn" id="onb-refresh">Refresh</button><button class="onb-btn primary" id="onb-new">+ New onboarding request</button></div></div>
<div class="onb-summary" id="onb-summary"></div>
<div class="onb-toolbar"><input class="onb-search" id="onb-search" placeholder="Search organisation, contact, email, or request ID…"><select class="onb-select" id="onb-status"><option>All</option><option>Submitted</option><option>Under Review</option><option>Approved</option><option>Completed</option><option>Rejected</option></select></div>
<div class="onb-table-wrap"><table class="onb-table"><thead><tr><th>Request</th><th>Organisation</th><th>Contact</th><th>Location</th><th>Status</th><th>Customer match</th><th>Created</th></tr></thead><tbody id="onb-rows"><tr><td class="onb-loading" colspan="7">Loading onboarding requests…</td></tr></tbody></table></div>
<div class="onb-modal-backdrop" id="onb-modal"><div class="onb-modal"><div class="onb-modal-head"><div><p class="onb-eyebrow">MAKAP request</p><h2 id="onb-modal-title">New onboarding request</h2></div><button class="onb-close" id="onb-close">×</button></div><form id="onb-form"><div class="onb-form-grid"><div class="onb-field"><label>Organisation name *</label><input name="organisation_name" required></div><div class="onb-field"><label>Trading name</label><input name="trading_name"></div><div class="onb-field"><label>Customer type *</label><select name="customer_type" required><option value="Company">Company</option><option value="Individual">Individual</option></select></div><div class="onb-field"><label>Business tax identifier</label><input name="business_tax_identifier"></div><div class="onb-field"><label>Contact name *</label><input name="contact_name" required></div><div class="onb-field"><label>Email address *</label><input name="email_id" type="email" required></div><div class="onb-field"><label>Telephone</label><input name="telephone"></div><div class="onb-field"><label>Location</label><input name="location"></div><div class="onb-field full"><label>Submitted address</label><textarea name="submitted_address"></textarea></div><div class="onb-field full"><label>Product interest</label><textarea name="product_interest"></textarea></div><div class="onb-field full"><label>Initial enquiry</label><textarea name="initial_enquiry"></textarea></div><div class="onb-field"><label>Registration source *</label><select name="registration_source" required><option value="Website">Website</option><option value="Assisted">Assisted</option></select></div><div class="onb-field"><label>Assisted channel</label><input name="assisted_channel"></div><div class="onb-field full"><label><input type="checkbox" name="privacy_notice_acknowledged" value="1" required> Privacy notice acknowledged *</label></div></div><div class="onb-form-actions"><button type="button" class="onb-btn" id="onb-cancel">Cancel</button><button class="onb-btn primary" type="submit">Create request</button></div></form><div id="onb-detail-content"></div></div></div>
</div>
<script>
(function(){const A='/api/method/';const call=(method,args={})=>fetch(A+method,{method:'POST',headers:{'Content-Type':'application/json','X-Frappe-CSRF-Token':window.frappe?.csrf_token||''},body:JSON.stringify(args)}).then(r=>r.json()).then(r=>{if(r.exc)throw Error('Request failed');return r.message});const $=s=>document.querySelector(s);const esc=v=>String(v??'—').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[c]));let selected='All';const labels={all:'All requests',submitted:'Submitted',under_review:'Under review',approved:'Approved',completed:'Completed',rejected:'Rejected'};function badge(s){let c=s==='Approved'||s==='Completed'?'approved':s==='Under Review'?'review':s==='Rejected'?'rejected':'';return `<span class="onb-badge ${c}">${esc(s||'—')}</span>`}function date(v){return v?new Date(String(v).replace(' ','T')).toLocaleDateString(): '—'}function summary(d){$('#onb-summary').innerHTML=Object.entries(labels).map(([k,l])=>`<div class="onb-card ${selected===(k==='all'?'All':k==='under_review'?'Under Review':k[0].toUpperCase()+k.slice(1))?'active':''}" data-status="${k==='all'?'All':k==='under_review'?'Under Review':k[0].toUpperCase()+k.slice(1)}"><label>${l}</label><strong>${Number(d[k]||0).toLocaleString()}</strong></div>`).join('');document.querySelectorAll('.onb-card').forEach(x=>x.onclick=()=>{selected=x.dataset.status;$('#onb-status').value=selected;load()})}function rows(data){$('#onb-rows').innerHTML=data.length?data.map(x=>`<tr><td class="onb-id" data-id="${esc(x.name)}">${esc(x.name)}</td><td><strong>${esc(x.organisation_name)}</strong><br><span class="onb-muted">${esc(x.trading_name||'')}</span></td><td>${esc(x.contact_name)}<br><span class="onb-muted">${esc(x.email_id)}</span></td><td>${esc(x.location)}</td><td>${badge(x.onboarding_status)}</td><td>${esc(x.customer_match_result)}</td><td>${date(x.creation)}</td></tr>`).join(''):'<tr><td colspan="7" class="onb-empty">No onboarding requests match your filters.</td></tr>';document.querySelectorAll('.onb-id').forEach(x=>x.onclick=()=>detail(x.dataset.id))}async function load(){try{const [s,r]=await Promise.all([call('makap_backend.makap_backend.onboarding_api.get_onboarding_summary'),call('makap_backend.makap_backend.onboarding_api.get_onboarding_requests',{status:$('#onb-status').value,search:$('#onb-search').value})]);summary(s);rows(r)}catch(e){$('#onb-rows').innerHTML='<tr><td colspan="7" class="onb-empty">Unable to load onboarding data. Check your Frappe permissions.</td></tr>'}}function open(){ $('#onb-modal').classList.add('open');$('#onb-form').style.display='block';$('#onb-detail-content').innerHTML='';$('#onb-modal-title').textContent='New onboarding request'}function close(){ $('#onb-modal').classList.remove('open')}async function detail(name){try{const x=await call('makap_backend.makap_backend.onboarding_api.get_onboarding_request',{name});$('#onb-modal-title').textContent=x.organisation_name||x.name;$('#onb-form').style.display='none';$('#onb-detail-content').innerHTML='<div class="onb-detail">'+[['Request',x.name],['Status',x.onboarding_status],['Organisation',x.organisation_name],['Trading name',x.trading_name],['Customer type',x.customer_type],['Tax identifier',x.business_tax_identifier],['Contact',x.contact_name],['Email',x.email_id],['Telephone',x.telephone],['Location',x.location],['Customer match',x.customer_match_result],['Portal access',x.portal_access_status],['Product interest',x.product_interest],['Initial enquiry',x.initial_enquiry],['Review notes',x.review_notes]].map(([a,b])=>`<div><small>${a}</small><span>${esc(b)}</span></div>`).join('')+'</div>';$('#onb-modal').classList.add('open')}catch(e){alert('Unable to open this request')}}$('#onb-new').onclick=open;$('#onb-close').onclick=close;$('#onb-cancel').onclick=close;$('#onb-refresh').onclick=load;$('#onb-status').onchange=()=>{selected=$('#onb-status').value;load()};let timer;$('#onb-search').oninput=()=>{clearTimeout(timer);timer=setTimeout(load,250)};$('#onb-form').onsubmit=async e=>{e.preventDefault();const data=Object.fromEntries(new FormData(e.target));data.privacy_notice_acknowledged=data.privacy_notice_acknowledged?1:0;try{const name=await call('makap_backend.makap_backend.onboarding_api.create_onboarding_request',{data:JSON.stringify(data)});close();await load();detail(name)}catch(err){alert('Unable to create request. Check required fields and permissions.')}};load()})();
</script>
{% endblock %}