// Team Grants client.
(function () {
'use strict';
var $ = function (id) { return document.getElementById(id); };
function esc(s) {
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c];
});
}
function n(v) { return Number(v || 0).toLocaleString(); }
var state = { tool: null, status: null, level: 0, minLevel: 7 };
function gate(msg) {
$('gGate').style.display = 'block';
$('gGate').innerHTML = msg;
}
// Shown to everyone, including people below level 7 — being helped should be
// visible, not silent.
function renderReceived(received) {
var keys = Object.keys(received || {});
if (!keys.length) { $('gGot').innerHTML = ''; return; }
var parts = keys.map(function (k) {
var r = received[k];
var who = r.from.map(function (f) { return '#' + f.by; });
var uniq = who.filter(function (v, i) { return who.indexOf(v) === i; });
var t = (state.status && state.status.tools[k]) || {};
return '
· ' + n(r.total) + ' ' + esc(t.unit || k) +
' of ' + esc((t.label || k).toLowerCase()) + ', from ' + uniq.join(', ') + '
';
});
$('gGot').innerHTML = 'Someone above you topped you up this month.' +
parts.join('') + '
' +
'It is already added to your allowances — nothing to claim.
';
}
function renderPools() {
var host = $('gPools');
host.innerHTML = '';
var tools = state.status.tools;
Object.keys(tools).forEach(function (k) {
var t = tools[k];
var d = document.createElement('div');
d.className = 'g-pool' + (state.tool === k ? ' on' : '');
d.innerHTML = '' + n(t.remaining) + '
' +
'' + esc(t.label) + '
' +
'left to give of ' + n(t.pool) + '
';
d.addEventListener('click', function () {
state.tool = k;
renderPools();
var el = $('gN');
el.max = Math.min(t.max, t.remaining);
el.step = t.step;
el.value = Math.min(t.step, t.remaining) || '';
$('gNHint').textContent = 'Up to ' + n(Math.min(t.max, t.remaining)) + ' ' + t.unit +
' in one go. You have ' + n(t.remaining) + ' left to give this month.';
});
host.appendChild(d);
});
}
function renderHistory(hist) {
if (!hist || !hist.length) { $('gHistWrap').style.display = 'none'; return; }
$('gHistWrap').style.display = 'block';
var tb = $('gHist');
tb.innerHTML = '';
hist.forEach(function (h) {
var t = (state.status.tools[h.tool]) || {};
var tr = document.createElement('tr');
tr.innerHTML = '#' + esc(h.to) + ' | ' +
'' + esc(t.label || h.tool) + ' | ' +
'' + n(h.n) + ' ' + esc(t.unit || '') + ' | ' +
'' + esc(String(h.at || '').slice(0, 10)) + ' | ';
tb.appendChild(tr);
});
}
async function give() {
$('gErr').style.display = 'none';
$('gOk').style.display = 'none';
if (!state.tool) {
$('gErr').textContent = 'Pick what you want to give first.';
$('gErr').style.display = 'block';
return;
}
var to = Number($('gTo').value) || 0;
var amount = Number($('gN').value) || 0;
if (!to) {
$('gErr').textContent = 'Enter the position number you want to help.';
$('gErr').style.display = 'block';
return;
}
$('gGo').disabled = true;
$('gGo').innerHTML = 'Sending…';
try {
var r = await fetch('/api/public/suite-grants', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ to: to, tool: state.tool, n: amount })
});
var d = await r.json();
if (!r.ok) {
$('gErr').textContent = d.error || 'That did not go through.';
$('gErr').style.display = 'block';
} else {
state.status = d.status;
var t = state.status.tools[d.granted.tool] || {};
$('gOk').innerHTML = '✅ Sent. #' + esc(d.granted.to) + ' now has ' + n(d.granted.n) + ' more ' +
esc(t.unit || '') + ' this month. Worth telling them — it will just appear in their allowance otherwise.';
$('gOk').style.display = 'block';
renderPools();
renderHistory(state.status.history);
}
} catch (e) {
$('gErr').textContent = 'Connection hiccup — try again.';
$('gErr').style.display = 'block';
}
$('gGo').disabled = false;
$('gGo').innerHTML = '🎁 Give it to them';
}
async function boot() {
try {
var r = await fetch('/api/public/suite-grants');
if (r.status === 401) { gate('You’re not signed in yet. Open the Suite and connect the wallet that holds your position, then come back.'); return; }
if (r.status === 403) {
var g = await r.json();
gate((g.error || 'Not open for this position yet.') + ' See your Suite.');
return;
}
if (!r.ok) return;
var d = await r.json();
state.status = d.status;
state.level = d.level;
state.minLevel = d.minLevel;
renderReceived(d.status.received);
if (!d.status.canGrant) {
gate('Team Grants unlock at Vertex (level 7). At that point you can hand your own Suite capacity ' +
'down to anyone in your organisation who needs it. Anything granted to you shows above and is already in your allowances.');
return;
}
$('gBody').style.display = 'block';
var first = Object.keys(d.status.tools)[0];
state.tool = first;
renderPools();
var t = d.status.tools[first];
$('gN').max = Math.min(t.max, t.remaining);
$('gN').step = t.step;
$('gN').value = Math.min(t.step, t.remaining) || '';
$('gNHint').textContent = 'Up to ' + n(Math.min(t.max, t.remaining)) + ' ' + t.unit + ' in one go.';
renderHistory(d.status.history);
} catch (e) {}
}
document.addEventListener('DOMContentLoaded', function () {
boot();
$('gGo').addEventListener('click', give);
});
})();