10b2251efe
Root cause: the scheduled-meeting INVITE (routes.js) and the ~10-min REMINDER (reminders.js) both notified only via CHAT.pushToUser — the WebSocket channel, which only reaches an OPEN tab with a live socket. Neither called PUSH.sendToUser, the path that produces a background APNs/FCM/web-push alert. On iOS the webview is suspended in the background, so the WS event was simply missed and no notification appeared. (Chat messages already call PUSH.sendToUser, which is why chat notices arrive on iOS but meeting ones didn't.) Fix: - schedule invite: also PUSH.sendToUser to every invited participant + group members (kind:'meeting', id:roomCode) so a closed app is notified. - reminders.js: also PUSH.sendToUser to all reminder recipients. - client: a kind:'meeting' notification tap now opens the Meeting tab + its list (both the live-tab open-chat handler and the cold-boot openKind path), instead of calling selectChat with an unsupported kind. Also: APPSTORE_SUBMISSION.md §8 updated — the UGC Report/Block gate (guideline 1.2) is now implemented, with a suggested reviewer note. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
28 lines
1.6 KiB
JavaScript
28 lines
1.6 KiB
JavaScript
// Fires a one-shot "starts in ~10 minutes" reminder to a scheduled meeting's host,
|
|
// group members, and invited participants. Runs on a 60s tick; marks each meeting reminded.
|
|
const R = require('./repos');
|
|
const CHAT = require('./chat');
|
|
const PUSH = require('./push'); // native/web background push so a CLOSED app still gets the reminder
|
|
|
|
async function tick() {
|
|
try {
|
|
const now = Date.now();
|
|
const due = await R.scheduledMeetings.dueForReminder(now, now + 10 * 60 * 1000); // starting within 10 min
|
|
for (const s of due) {
|
|
const recipients = new Set([s.created_by]);
|
|
let invited = []; try { invited = JSON.parse(s.participants || '[]'); } catch (_) {}
|
|
invited.forEach((id) => recipients.add(id));
|
|
if (s.group_id) { try { (await R.conversations.members(s.group_id)).forEach((m) => recipients.add(m)); } catch (_) {} }
|
|
const evt = { type: 'meeting-reminder', meeting: { id: s.id, title: s.title, scheduledAt: s.scheduled_at, room: s.room_code } };
|
|
recipients.forEach((uid) => { try { CHAT.pushToUser(uid, evt); } catch (_) {} }); // open tab
|
|
recipients.forEach((uid) => { try { PUSH.sendToUser(uid, { title: 'Meeting starting soon', body: (s.title || 'Your meeting') + ' starts in ~10 minutes', kind: 'meeting', id: s.room_code, tag: 'meet:' + s.room_code }); } catch (_) {} }); // closed app (iOS APNs etc.)
|
|
await R.scheduledMeetings.markReminded(s.id);
|
|
}
|
|
} catch (_) { /* never let the timer die */ }
|
|
}
|
|
|
|
let timer = null;
|
|
function start() { if (!timer) timer = setInterval(tick, 60 * 1000); }
|
|
start();
|
|
module.exports = { start, tick };
|