feat: polish Discord daily check-ins and add reminder buttons
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { reminderCheckIn } from "../discord/daily";
|
||||
import { createHash } from "node:crypto";
|
||||
import { and, eq, inArray, lt } from "drizzle-orm";
|
||||
import type { AppDatabase } from "../auth";
|
||||
@@ -7,7 +8,7 @@ import { localDate } from "../habits/calendar";
|
||||
import { entriesForDate, inQuietHours, timesForDate } from "./contracts";
|
||||
import type { DiscordFetch } from "../sharing/routes";
|
||||
|
||||
export type ReminderConfig = { token: string; origin: string };
|
||||
export type ReminderConfig = { token: string; origin: string; commandsAvailable?: boolean };
|
||||
function localClock(timestamp: number, timezone: string) {
|
||||
const parts = new Intl.DateTimeFormat("en-GB", { timeZone: timezone, hour: "2-digit", minute: "2-digit", hourCycle: "h23" }).formatToParts(timestamp);
|
||||
return `${parts.find(part => part.type === "hour")!.value}:${parts.find(part => part.type === "minute")!.value}`;
|
||||
@@ -34,7 +35,7 @@ export async function sendDueReminders(db: AppDatabase, config: ReminderConfig,
|
||||
// Avoid sending an artificial "today" after a backwards timezone change.
|
||||
if (service.today !== localDate(timestamp, currentUser.timezone)) return null;
|
||||
const remaining = service.list().filter(habit => { const day = service.day(habit.id, service.today); return day.due && !day.complete; }).length;
|
||||
return remaining ? { date: service.today, remaining, times, entries: entriesForDate(prefs, service.today) } : null;
|
||||
return remaining ? { date: service.today, remaining, timezone: currentUser.timezone, times, entries: entriesForDate(prefs, service.today) } : null;
|
||||
}
|
||||
const initial = due(); if (!initial) continue;
|
||||
const claims = db.transaction(tx => {
|
||||
@@ -84,6 +85,7 @@ export async function sendDueReminders(db: AppDatabase, config: ReminderConfig,
|
||||
try { response = await request(`https://discord.com/api/v10/channels/${destination.id}/messages`, {
|
||||
method: "POST", headers, redirect: "error", signal: AbortSignal.timeout(15000),
|
||||
body: JSON.stringify({ content: `${prefix}A little time for yourself: ${latest.remaining} ${latest.remaining === 1 ? "habit remains" : "habits remain"} today. Check in: ${config.origin}/`,
|
||||
...(config.commandsAvailable ? { components: reminderCheckIn(db, user.id, latest.timezone, now()) } : {}),
|
||||
allowed_mentions: { parse: [] }, nonce: createHash("sha256").update(ids.sort().join(":")).digest("hex").slice(0, 24), enforce_nonce: true }),
|
||||
}); } catch { update("uncertain"); continue; }
|
||||
if (response.status === 429) { await defer(response); return; }
|
||||
|
||||
Reference in New Issue
Block a user