openvibers/openvibe.network Commits
Keep the Receipts card under Needs you, with its quiet line (#822)
Changes
@@@ -67,16 +67,13 @@ function renderReceipts(doc) {const rows = (doc && Array.isArray(doc.receipts) ? doc.receipts : []).map(rcRow).filter(Boolean);body.replaceChildren();if (!enabled) {-- box.hidden = true;-- const fold = document.getElementById('setup-fold');-- if (fold) { fold.hidden = false; fold.querySelector('summary').textContent = 'Set up more (1)'; fold.querySelector('.setup-items').replaceChildren(rcEl('a', 'rc-quiet', ['Set up receipts with Inbox AI'], { href: RC_SETTING })); }++ body.append(rcEl('a', 'rc-quiet', ['Turn on Inbox AI on openvibe.email to see receipts here'], { href: RC_SETTING }));++ box.hidden = false;return;}-- const fold = document.getElementById('setup-fold');-- if (fold) fold.hidden = true;if (!rows.length) {body.append(rcEl('p', 'rc-quiet', ['No receipts yet.']));-- box.hidden = true;++ box.hidden = false;return;}body.append(...rows.slice(0, RC_SHOWN));@@@ -88,6 +88,19 @@</div><div class="ny-list" id="needs-you-list"></div></section>++++ <!-- Receipts (plan OpenVibe_Seven_Domains_Plan R2 item 13), right under Needs you: the latest five++ receipt-category summaries Inbox AI keeps on openvibe.email, each linking to its thread, with a counted++ fold for the rest and never a tab. my/receipts.js fills it from GET /api/v1/me/receipts; with Inbox AI off++ (or no mailbox) the one quiet line links to the switch, and no sample receipt is ever drawn. The card++ stays out until it has an answer. -->++ <section class="rc" id="receipts" hidden aria-labelledby="receipts-h">++ <div class="rc-h">++ <h2 id="receipts-h"><span class="rc-ic" aria-hidden="true"><i class="fa-solid fa-file-lines"></i></span>Receipts</h2>++ </div>++ <div class="rc-body" id="receipts-body"></div>++ </section>++<nav class="me-acts" id="me-acts" aria-label="Quick actions"></nav><!-- You, today (plan L43): what is happening for you now, what you were doing, your money, your sites and your@@@ -132,13 +145,6 @@<details id="setup-fold" class="setup-fold" hidden><summary>Set up more (0)</summary><div class="setup-items"></div></details>-- <section class="rc" id="receipts" hidden aria-labelledby="receipts-h">-- <div class="rc-h">-- <h2 id="receipts-h"><span class="rc-ic" aria-hidden="true"><i class="fa-solid fa-file-lines"></i></span>Receipts</h2>-- </div>-- <div class="rc-body" id="receipts-body"></div>-- </section>--<div class="card" id="account-emails-card"><h2><span class="icon"><i class="fa-solid fa-envelope"></i></span> Email addresses</h2><p>Keep several verified addresses on your account. Only you can see this list.</p>@@@ -15,13 +15,13 @@ const HTML = fs.readFileSync(path.join(__dirname, '..', 'public', 'my.html'), 'uconst JS = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'my', 'receipts.js'), 'utf8');const CSS = fs.readFileSync(path.join(__dirname, '..', 'public', 'css', 'my.css'), 'utf8');--// ── The page: the person leads, then Needs you, actions, history, sites, machines, numbers and receipts ──++// ── The page: the person leads, then Needs you and its Receipts card, then actions, history, sites, machines, numbers ──assert.ok(HTML.indexOf('id="page-header"') < HTML.indexOf('id="needs-you"'));--assert.ok(HTML.indexOf('id="needs-you"') < HTML.indexOf('id="me-acts"'));++assert.ok(HTML.indexOf('id="needs-you"') < HTML.indexOf('id="receipts"'), 'the Receipts card sits under Needs you');++assert.ok(HTML.indexOf('id="receipts"') < HTML.indexOf('id="me-acts"'), 'before the quick actions');assert.ok(HTML.indexOf('id="td-continue"') < HTML.indexOf('id="td-sites"'));assert.ok(HTML.indexOf('id="td-sites"') < HTML.indexOf('id="td-machines-summary"'));assert.ok(HTML.indexOf('id="td-machines-summary"') < HTML.indexOf('id="td-nums"'));--assert.ok(HTML.indexOf('id="td-nums"') < HTML.indexOf('id="receipts"'));assert.match(HTML, /<section class="rc" id="receipts" hidden/);assert.match(HTML, /<script src="\/js\/my\/receipts\.js" defer><\/script>/, 'the card has its own script');assert.match(CSS, /\.rc-row \{/, 'the rows have a style');@@@ -63,14 +63,15 @@ const receipt = (i) => ({});(async () => {-- // ── Inbox AI off: one counted setup fold, no empty Receipts card, and no sample receipt ──++ // ── Inbox AI off: the card shows one quiet line, links the switch, and draws no sample receipt ──let p = page();p.sandbox.renderReceipts({ enabled: false, receipts: [] });-- assert.strictEqual(p.ids.receipts.hidden, true, 'no empty Receipts card');-- assert.strictEqual(p.ids['setup-fold'].hidden, false);-- assert.strictEqual(p.ids['setup-fold'].summary.textContent, 'Set up more (1)');-- assert.strictEqual(p.ids['setup-fold'].items.children[0].textContent, 'Set up receipts with Inbox AI');-- assert.strictEqual(p.ids['setup-fold'].items.children[0].getAttribute('href'), 'https://openvibe.email/inbox#inbox-ai');++ assert.strictEqual(p.ids.receipts.hidden, false, 'the card stays under Needs you');++ assert.strictEqual(p.ids['receipts-body'].children.length, 1, 'one quiet line');++ assert.strictEqual(p.ids['receipts-body'].children[0].textContent, 'Turn on Inbox AI on openvibe.email to see receipts here');++ assert.strictEqual(p.ids['receipts-body'].children[0].getAttribute('href'), 'https://openvibe.email/inbox#inbox-ai');++ assert.strictEqual(p.ids['receipts-body'].all((c) => c.className === 'rc-row').length, 0, 'no sample receipt');++ assert.strictEqual(p.ids['setup-fold'].hidden, true, 'the setup fold is not hijacked');// ── On with receipts: the latest five, then a counted fold for the rest, each a thread on openvibe.email ──p = page();@@@ -104,10 +105,12 @@ const receipt = (i) => ({p.sandbox.renderReceipts({ enabled: true, receipts: [{ ...receipt(0), message_id: null, thread_id: 'thr_ok' }] });assert.strictEqual(p.ids['receipts-body'].all((c) => c.tagName === 'A')[0].href, 'https://openvibe.email/inbox/thr_ok');-- // ── On with nothing triaged yet: neither receipts nor setup nudge is shown ──++ // ── On with nothing triaged yet: the card says so, quietly, and still no sample receipt ──p = page();p.sandbox.renderReceipts({ enabled: true, receipts: [] });-- assert.strictEqual(p.ids.receipts.hidden, true);++ assert.strictEqual(p.ids.receipts.hidden, false);++ assert.strictEqual(p.ids['receipts-body'].textContent, 'No receipts yet.');++ assert.strictEqual(p.ids['receipts-body'].all((c) => c.className === 'rc-row').length, 0);assert.strictEqual(p.ids['setup-fold'].hidden, true);// ── The route: Mail is asked with the person's own token; off hides rows, on passes them, down stays out ──
@@ -67,16 +67,13 @@ function renderReceipts(doc) {
@@ -67,16 +67,13 @@ function renderReceipts(doc) {
const rows = (doc && Array.isArray(doc.receipts) ? doc.receipts : []).map(rcRow).filter(Boolean);
const rows = (doc && Array.isArray(doc.receipts) ? doc.receipts : []).map(rcRow).filter(Boolean);
body.replaceChildren();
body.replaceChildren();
if (!enabled) {
if (!enabled) {
- box.hidden = true;
- const fold = document.getElementById('setup-fold');
- if (fold) { fold.hidden = false; fold.querySelector('summary').textContent = 'Set up more (1)'; fold.querySelector('.setup-items').replaceChildren(rcEl('a', 'rc-quiet', ['Set up receipts with Inbox AI'], { href: RC_SETTING })); }
+ body.append(rcEl('a', 'rc-quiet', ['Turn on Inbox AI on openvibe.email to see receipts here'], { href: RC_SETTING }));
+ box.hidden = false;
return;
return;
}
}
- const fold = document.getElementById('setup-fold');
- if (fold) fold.hidden = true;
if (!rows.length) {
if (!rows.length) {
body.append(rcEl('p', 'rc-quiet', ['No receipts yet.']));
body.append(rcEl('p', 'rc-quiet', ['No receipts yet.']));
- box.hidden = true;
+ box.hidden = false;
return;
return;
}
}
body.append(...rows.slice(0, RC_SHOWN));
body.append(...rows.slice(0, RC_SHOWN));
@@ -88,6 +88,19 @@
@@ -88,6 +88,19 @@
</div>
</div>
<div class="ny-list" id="needs-you-list"></div>
<div class="ny-list" id="needs-you-list"></div>
</section>
</section>
+
+ <!-- Receipts (plan OpenVibe_Seven_Domains_Plan R2 item 13), right under Needs you: the latest five
+ receipt-category summaries Inbox AI keeps on openvibe.email, each linking to its thread, with a counted
+ fold for the rest and never a tab. my/receipts.js fills it from GET /api/v1/me/receipts; with Inbox AI off
+ (or no mailbox) the one quiet line links to the switch, and no sample receipt is ever drawn. The card
+ stays out until it has an answer. -->
+ <section class="rc" id="receipts" hidden aria-labelledby="receipts-h">
+ <div class="rc-h">
+ <h2 id="receipts-h"><span class="rc-ic" aria-hidden="true"><i class="fa-solid fa-file-lines"></i></span>Receipts</h2>
+ </div>
+ <div class="rc-body" id="receipts-body"></div>
+ </section>
+
<nav class="me-acts" id="me-acts" aria-label="Quick actions"></nav>
<nav class="me-acts" id="me-acts" aria-label="Quick actions"></nav>
<!-- You, today (plan L43): what is happening for you now, what you were doing, your money, your sites and your
<!-- You, today (plan L43): what is happening for you now, what you were doing, your money, your sites and your
@@ -132,13 +145,6 @@
@@ -132,13 +145,6 @@
<details id="setup-fold" class="setup-fold" hidden><summary>Set up more (0)</summary><div class="setup-items"></div></details>
<details id="setup-fold" class="setup-fold" hidden><summary>Set up more (0)</summary><div class="setup-items"></div></details>
- <section class="rc" id="receipts" hidden aria-labelledby="receipts-h">
- <div class="rc-h">
- <h2 id="receipts-h"><span class="rc-ic" aria-hidden="true"><i class="fa-solid fa-file-lines"></i></span>Receipts</h2>
- </div>
- <div class="rc-body" id="receipts-body"></div>
- </section>
-
<div class="card" id="account-emails-card">
<div class="card" id="account-emails-card">
<h2><span class="icon"><i class="fa-solid fa-envelope"></i></span> Email addresses</h2>
<h2><span class="icon"><i class="fa-solid fa-envelope"></i></span> Email addresses</h2>
<p>Keep several verified addresses on your account. Only you can see this list.</p>
<p>Keep several verified addresses on your account. Only you can see this list.</p>
@@ -15,13 +15,13 @@ const HTML = fs.readFileSync(path.join(__dirname, '..', 'public', 'my.html'), 'u
@@ -15,13 +15,13 @@ const HTML = fs.readFileSync(path.join(__dirname, '..', 'public', 'my.html'), 'u
const JS = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'my', 'receipts.js'), 'utf8');
const JS = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'my', 'receipts.js'), 'utf8');
const CSS = fs.readFileSync(path.join(__dirname, '..', 'public', 'css', 'my.css'), 'utf8');
const CSS = fs.readFileSync(path.join(__dirname, '..', 'public', 'css', 'my.css'), 'utf8');
-// ── The page: the person leads, then Needs you, actions, history, sites, machines, numbers and receipts ──
+// ── The page: the person leads, then Needs you and its Receipts card, then actions, history, sites, machines, numbers ──
assert.ok(HTML.indexOf('id="page-header"') < HTML.indexOf('id="needs-you"'));
assert.ok(HTML.indexOf('id="page-header"') < HTML.indexOf('id="needs-you"'));
-assert.ok(HTML.indexOf('id="needs-you"') < HTML.indexOf('id="me-acts"'));
+assert.ok(HTML.indexOf('id="needs-you"') < HTML.indexOf('id="receipts"'), 'the Receipts card sits under Needs you');
+assert.ok(HTML.indexOf('id="receipts"') < HTML.indexOf('id="me-acts"'), 'before the quick actions');
assert.ok(HTML.indexOf('id="td-continue"') < HTML.indexOf('id="td-sites"'));
assert.ok(HTML.indexOf('id="td-continue"') < HTML.indexOf('id="td-sites"'));
assert.ok(HTML.indexOf('id="td-sites"') < HTML.indexOf('id="td-machines-summary"'));
assert.ok(HTML.indexOf('id="td-sites"') < HTML.indexOf('id="td-machines-summary"'));
assert.ok(HTML.indexOf('id="td-machines-summary"') < HTML.indexOf('id="td-nums"'));
assert.ok(HTML.indexOf('id="td-machines-summary"') < HTML.indexOf('id="td-nums"'));
-assert.ok(HTML.indexOf('id="td-nums"') < HTML.indexOf('id="receipts"'));
assert.match(HTML, /<section class="rc" id="receipts" hidden/);
assert.match(HTML, /<section class="rc" id="receipts" hidden/);
assert.match(HTML, /<script src="\/js\/my\/receipts\.js" defer><\/script>/, 'the card has its own script');
assert.match(HTML, /<script src="\/js\/my\/receipts\.js" defer><\/script>/, 'the card has its own script');
assert.match(CSS, /\.rc-row \{/, 'the rows have a style');
assert.match(CSS, /\.rc-row \{/, 'the rows have a style');
@@ -63,14 +63,15 @@ const receipt = (i) => ({
@@ -63,14 +63,15 @@ const receipt = (i) => ({
});
});
(async () => {
(async () => {
- // ── Inbox AI off: one counted setup fold, no empty Receipts card, and no sample receipt ──
+ // ── Inbox AI off: the card shows one quiet line, links the switch, and draws no sample receipt ──
let p = page();
let p = page();
p.sandbox.renderReceipts({ enabled: false, receipts: [] });
p.sandbox.renderReceipts({ enabled: false, receipts: [] });
- assert.strictEqual(p.ids.receipts.hidden, true, 'no empty Receipts card');
- assert.strictEqual(p.ids['setup-fold'].hidden, false);
- assert.strictEqual(p.ids['setup-fold'].summary.textContent, 'Set up more (1)');
- assert.strictEqual(p.ids['setup-fold'].items.children[0].textContent, 'Set up receipts with Inbox AI');
- assert.strictEqual(p.ids['setup-fold'].items.children[0].getAttribute('href'), 'https://openvibe.email/inbox#inbox-ai');
+ assert.strictEqual(p.ids.receipts.hidden, false, 'the card stays under Needs you');
+ assert.strictEqual(p.ids['receipts-body'].children.length, 1, 'one quiet line');
+ assert.strictEqual(p.ids['receipts-body'].children[0].textContent, 'Turn on Inbox AI on openvibe.email to see receipts here');
+ assert.strictEqual(p.ids['receipts-body'].children[0].getAttribute('href'), 'https://openvibe.email/inbox#inbox-ai');
+ assert.strictEqual(p.ids['receipts-body'].all((c) => c.className === 'rc-row').length, 0, 'no sample receipt');
+ assert.strictEqual(p.ids['setup-fold'].hidden, true, 'the setup fold is not hijacked');
// ── On with receipts: the latest five, then a counted fold for the rest, each a thread on openvibe.email ──
// ── On with receipts: the latest five, then a counted fold for the rest, each a thread on openvibe.email ──
p = page();
p = page();
@@ -104,10 +105,12 @@ const receipt = (i) => ({
@@ -104,10 +105,12 @@ const receipt = (i) => ({
p.sandbox.renderReceipts({ enabled: true, receipts: [{ ...receipt(0), message_id: null, thread_id: 'thr_ok' }] });
p.sandbox.renderReceipts({ enabled: true, receipts: [{ ...receipt(0), message_id: null, thread_id: 'thr_ok' }] });
assert.strictEqual(p.ids['receipts-body'].all((c) => c.tagName === 'A')[0].href, 'https://openvibe.email/inbox/thr_ok');
assert.strictEqual(p.ids['receipts-body'].all((c) => c.tagName === 'A')[0].href, 'https://openvibe.email/inbox/thr_ok');
- // ── On with nothing triaged yet: neither receipts nor setup nudge is shown ──
+ // ── On with nothing triaged yet: the card says so, quietly, and still no sample receipt ──
p = page();
p = page();
p.sandbox.renderReceipts({ enabled: true, receipts: [] });
p.sandbox.renderReceipts({ enabled: true, receipts: [] });
- assert.strictEqual(p.ids.receipts.hidden, true);
+ assert.strictEqual(p.ids.receipts.hidden, false);
+ assert.strictEqual(p.ids['receipts-body'].textContent, 'No receipts yet.');
+ assert.strictEqual(p.ids['receipts-body'].all((c) => c.className === 'rc-row').length, 0);
assert.strictEqual(p.ids['setup-fold'].hidden, true);
assert.strictEqual(p.ids['setup-fold'].hidden, true);
// ── The route: Mail is asked with the person's own token; off hides rows, on passes them, down stays out ──
// ── The route: Mail is asked with the person's own token; off hides rows, on passes them, down stays out ──