Chores, Family page, genre search, child accounts, wider Search and Notifications center
build-container / build (push) Successful in 4m6s
build-container / build (push) Successful in 4m6s
- Chores tab with repeats, points and a week/month board - Family page: calendar, chores, shopping, notes, chat and tasks on one start page - Genre search in the Store, Free Books and LibriVox - Child accounts: safe content, daily limit and bedtime, ask a parent - Search now covers notes, chat, contacts, chores, recipes and your books - Notifications center: bell with a per-person list of chat, reminders and announcements - Roadmap, README and tests updated Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cf292e3bc7
commit
0383da87f5
38 files changed
+720
-79
No files matched your search
@@ -0,0 +1,20 @@
|
||||
// Notifications center: entries from chat and announcements, counting, reading, clearing.
|
||||
const http = require('http'), assert = require('assert'), fs = require('fs'), os = require('os'), path = require('path');
|
||||
process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'nehub-inbox-'));
|
||||
const users = require('../users'), inbox = require('../inbox'), chat = require('../chat');
|
||||
const P = { a: users.create({ name: 'Ann', role: 'admin', handle: 'YQ' }), b: users.create({ name: 'Bob', role: 'user', tabs: ['chat'], handle: 'Yg' }) };
|
||||
const hub = http.createServer((req, res) => users.runAs(P[req.headers['x-user'] || 'a'], () => req.url.startsWith('/api/chat') ? chat.handle(req, res) : inbox.handle(req, res))).listen(0, async () => {
|
||||
const B = 'http://127.0.0.1:' + hub.address().port, call = (p, o = {}, who) => fetch(B + p, { ...o, headers: { ...(o.headers || {}), ...(who ? { 'x-user': who } : {}) } }), post = (p, b, who) => call(p, { method: 'POST', body: JSON.stringify(b) }, who), j = r => r.json();
|
||||
try {
|
||||
const dm = (await j(await post('/api/chat/new', { type: 'direct', with: P.b.id }, 'a'))).conv; await post('/api/chat/send', { conv: dm.id, text: 'hello' }, 'a'); await post('/api/chat/send', { conv: dm.id, text: 'again' }, 'a');
|
||||
let r = await j(await call('/api/inbox', {}, 'b')); assert.equal(r.items.length, 1, 'one entry per conversation'); assert.equal(r.items[0].count, 2); assert.equal(r.items[0].body, 'again'); assert.equal(r.unread, 1);
|
||||
assert.equal((await j(await call('/api/inbox', {}, 'a'))).items.length, 0, 'the sender gets nothing');
|
||||
await post('/api/chat/announcement', { text: 'Pizza night' }, 'a'); r = await j(await call('/api/inbox', {}, 'b')); assert.equal(r.items[0].kind, 'announce'); assert.equal(r.unread, 2);
|
||||
r = await j(await post('/api/inbox/read', { id: r.items[0].id }, 'b')); assert.equal(r.unread, 1);
|
||||
await post('/api/chat/send', { conv: dm.id, text: 'new one' }, 'a'); r = await j(await call('/api/inbox', {}, 'b')); assert.equal(r.items.filter(i => i.kind === 'chat').length, 1, 'still unread: updated in place'); assert.equal(r.items.find(i => i.kind === 'chat').count, 3);
|
||||
r = await j(await post('/api/inbox/read', { all: true }, 'b')); assert.equal(r.unread, 0);
|
||||
await post('/api/chat/send', { conv: dm.id, text: 'after reading' }, 'a'); r = await j(await call('/api/inbox', {}, 'b')); assert.equal(r.items.filter(i => i.kind === 'chat').length, 2, 'a read entry stays; a new one starts');
|
||||
await post('/api/inbox/clear', {}, 'b'); assert.equal((await j(await call('/api/inbox', {}, 'b'))).items.length, 0); console.log('inbox ok');
|
||||
} catch (e) { console.error(e); process.exitCode = 1; }
|
||||
hub.close(); setTimeout(() => process.exit(process.exitCode || 0), 50);
|
||||
});
|
||||
Reference in new issue
Block a user