65 lines
3.8 KiB
JavaScript
65 lines
3.8 KiB
JavaScript
// submit.js — contribute-a-part flow: AI auto-fill from datasheet + submission to Corben functions.
|
|
const API = 'https://api.corben.world';
|
|
const FN_AUTOFILL = 'd4f34d9c-6e8f-4328-89a2-b3c3b79017db';
|
|
const TK_AUTOFILL = '3f5dc4a97de91e7e9117b9a12a3061f6';
|
|
const FN_SUBMIT = 'b02d634b-cd6d-414d-bf9c-80cf6cc2ccdc';
|
|
const TK_SUBMIT = '9c3ed2ece766bcc18ed7d33996bfeb86';
|
|
const $ = (id) => document.getElementById(id);
|
|
|
|
$('cred-n').textContent = localStorage.getItem('ppcb_credits') || '5';
|
|
|
|
async function invoke(fn, token, payload) {
|
|
const r = await fetch(`${API}/functions/${fn}/invoke?token=${token}`, {
|
|
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
|
|
return r.json();
|
|
}
|
|
|
|
$('autofill').onclick = async (e) => {
|
|
e.preventDefault();
|
|
const mpn = $('mpn').value.trim();
|
|
if (!mpn && !$('description').value.trim()) { $('af-status').textContent = 'Enter an MPN or paste datasheet text first.'; return; }
|
|
$('autofill').disabled = true; $('af-status').innerHTML = '<span class="spin"></span> drafting from datasheet…';
|
|
try {
|
|
const d = await invoke(FN_AUTOFILL, TK_AUTOFILL, { mpn, class: $('class').value, description: $('description').value.trim() });
|
|
if (!d.ok) throw new Error(d.error || 'autofill failed');
|
|
const s = d.suggested;
|
|
if (s.summary) $('summary').value = s.summary;
|
|
if (s.when_to_use) $('when_to_use').value = s.when_to_use;
|
|
if (s.use_cases) $('use_cases').value = s.use_cases.join('\n');
|
|
if (s.params) $('params').value = s.params.map((p) => `${p.name}: ${p.value}${p.unit ? ' ' + p.unit : ''}`).join('\n');
|
|
if (s.spice_model) $('spice').value = s.spice_model;
|
|
const t = s.requirements_tags || {};
|
|
if (t.package && !$('package').value) $('package').value = t.package;
|
|
if (t.class && !$('class').value) $('class').value = t.class;
|
|
$('af-status').innerHTML = '✓ drafted — <b style="color:var(--acc)">review every field</b> before submitting.';
|
|
} catch (err) { $('af-status').textContent = '⚠ ' + err.message; }
|
|
$('autofill').disabled = false;
|
|
};
|
|
|
|
$('model3d').onchange = () => { const f = $('model3d').files[0]; if (f) $('drop-label').textContent = '✓ ' + f.name; };
|
|
|
|
$('submit').onclick = async () => {
|
|
const parseParams = (t) => t.split('\n').map((l) => l.trim()).filter(Boolean).map((l) => {
|
|
const [n, ...rest] = l.split(':'); const v = rest.join(':').trim(); const m = v.match(/^([\d.\-+/]+)\s*(.*)$/);
|
|
return { name: n.trim(), value: m ? m[1] : v, unit: m ? m[2] : '' };
|
|
});
|
|
const part = {
|
|
mpn: $('mpn').value.trim(), name: $('mpn').value.trim(), class: $('class').value,
|
|
manufacturer: $('manufacturer').value.trim(), package: $('package').value.trim(),
|
|
datasheet_url: $('datasheet_url').value.trim(), summary: $('summary').value.trim(),
|
|
when_to_use: $('when_to_use').value.trim(),
|
|
use_cases: $('use_cases').value.split('\n').map((l) => l.trim()).filter(Boolean),
|
|
params: parseParams($('params').value), spice: $('spice').value.trim(),
|
|
model_3d_name: $('model3d').files[0] ? $('model3d').files[0].name : '',
|
|
};
|
|
const email = $('email').value.trim();
|
|
$('submit').disabled = true; $('sub-status').innerHTML = '<span class="spin"></span> submitting…';
|
|
try {
|
|
const d = await invoke(FN_SUBMIT, TK_SUBMIT, { email, part });
|
|
if (!d.ok) throw new Error(d.error || 'submit failed');
|
|
localStorage.setItem('ppcb_credits', d.credits); $('cred-n').textContent = d.credits;
|
|
document.querySelector('.form').innerHTML = `<h1 class="dh1">Thank you — submitted for review ✓</h1>
|
|
<div class="banner">Your part <b>${part.mpn}</b> is queued for curation review. <b>+5 download credits</b> added — you now have <b>${d.credits}</b>.
|
|
<br><br>Ref: <code>${d.sub_id}</code></div><a class="btn" href="/">Browse the catalog →</a>`;
|
|
} catch (err) { $('sub-status').textContent = '⚠ ' + err.message; $('submit').disabled = false; }
|
|
};
|