fix: reschedule upsert, settings restart warning, unified streak util
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+2
-31
@@ -2,6 +2,7 @@ import type { Database } from 'better-sqlite3';
|
|||||||
import { getRecentSessions, type Session } from '../db/sessions';
|
import { getRecentSessions, type Session } from '../db/sessions';
|
||||||
import { getUpcomingSchedule, type ScheduleEntry } from '../db/schedule';
|
import { getUpcomingSchedule, type ScheduleEntry } from '../db/schedule';
|
||||||
import { getSetting } from '../db/settings';
|
import { getSetting } from '../db/settings';
|
||||||
|
import { getStreaks } from '../utils/streak';
|
||||||
|
|
||||||
export interface AIContext {
|
export interface AIContext {
|
||||||
today: string;
|
today: string;
|
||||||
@@ -12,41 +13,11 @@ export interface AIContext {
|
|||||||
recentSkips: Array<{ date: string; reason: string | null }>;
|
recentSkips: Array<{ date: string; reason: string | null }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateStreak(db: Database): number {
|
|
||||||
const rows = db.prepare(
|
|
||||||
"SELECT date FROM schedule WHERE status = 'completed' ORDER BY date DESC"
|
|
||||||
).all() as Array<{ date: string }>;
|
|
||||||
|
|
||||||
if (rows.length === 0) return 0;
|
|
||||||
|
|
||||||
let streak = 0;
|
|
||||||
let prev: string | null = null;
|
|
||||||
|
|
||||||
for (const { date } of rows) {
|
|
||||||
if (prev === null) {
|
|
||||||
streak = 1;
|
|
||||||
prev = date;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const prevDate = new Date(prev + 'T12:00:00');
|
|
||||||
const currDate = new Date(date + 'T12:00:00');
|
|
||||||
const diffDays = Math.round((prevDate.getTime() - currDate.getTime()) / 86400000);
|
|
||||||
if (diffDays <= 2) {
|
|
||||||
streak++;
|
|
||||||
prev = date;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return streak;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildContext(db: Database, today: string): AIContext {
|
export function buildContext(db: Database, today: string): AIContext {
|
||||||
const recentSessions = getRecentSessions(db, 30);
|
const recentSessions = getRecentSessions(db, 30);
|
||||||
const upcomingSchedule = getUpcomingSchedule(db, today);
|
const upcomingSchedule = getUpcomingSchedule(db, today);
|
||||||
const goal = getSetting(db, 'goal') ?? 'Not set';
|
const goal = getSetting(db, 'goal') ?? 'Not set';
|
||||||
const currentStreak = calculateStreak(db);
|
const currentStreak = getStreaks(db).current;
|
||||||
|
|
||||||
const recentSkips = (db.prepare(
|
const recentSkips = (db.prepare(
|
||||||
"SELECT date, skip_reason as reason FROM schedule WHERE status = 'skipped' ORDER BY date DESC LIMIT 10"
|
"SELECT date, skip_reason as reason FROM schedule WHERE status = 'skipped' ORDER BY date DESC LIMIT 10"
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ export function handleSettings(db: Database) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSetting(db, key, value);
|
setSetting(db, key, value);
|
||||||
await ctx.reply(`Updated ${key} = ${value}`);
|
const restartNote = (key === 'morning_reminder' || key === 'evening_reminder')
|
||||||
|
? '\n\n⚠️ Restart the bot for the new reminder time to take effect.'
|
||||||
|
: '';
|
||||||
|
await ctx.reply(`Updated ${key} = ${value}${restartNote}`);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,6 @@
|
|||||||
import type { Context } from 'telegraf';
|
import type { Context } from 'telegraf';
|
||||||
import type { Database } from 'better-sqlite3';
|
import type { Database } from 'better-sqlite3';
|
||||||
|
import { getStreaks } from '../../utils/streak';
|
||||||
function getStreaks(db: Database): { current: number; longest: number } {
|
|
||||||
const rows = db.prepare(
|
|
||||||
"SELECT date FROM schedule WHERE status = 'completed' ORDER BY date ASC"
|
|
||||||
).all() as Array<{ date: string }>;
|
|
||||||
|
|
||||||
if (rows.length === 0) return { current: 0, longest: 0 };
|
|
||||||
|
|
||||||
let current = 1, longest = 1, streak = 1;
|
|
||||||
|
|
||||||
for (let i = 1; i < rows.length; i++) {
|
|
||||||
const prev = new Date(rows[i - 1]!.date + 'T12:00:00');
|
|
||||||
const curr = new Date(rows[i]!.date + 'T12:00:00');
|
|
||||||
const diff = Math.round((curr.getTime() - prev.getTime()) / 86400000);
|
|
||||||
if (diff <= 2) {
|
|
||||||
streak++;
|
|
||||||
if (streak > longest) longest = streak;
|
|
||||||
} else {
|
|
||||||
streak = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current = streak;
|
|
||||||
return { current, longest };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function handleStreak(db: Database) {
|
export function handleStreak(db: Database) {
|
||||||
return async (ctx: Context) => {
|
return async (ctx: Context) => {
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ export function insertScheduleEntry(
|
|||||||
db: Database, date: string, planned_min: number, ai_rationale: string | null
|
db: Database, date: string, planned_min: number, ai_rationale: string | null
|
||||||
): ScheduleEntry {
|
): ScheduleEntry {
|
||||||
db.prepare(
|
db.prepare(
|
||||||
'INSERT OR IGNORE INTO schedule (date, planned_min, ai_rationale) VALUES (?, ?, ?)'
|
'INSERT OR REPLACE INTO schedule (date, planned_min, ai_rationale, status) VALUES (?, ?, ?, \'pending\')'
|
||||||
).run(date, planned_min, ai_rationale);
|
).run(date, planned_min, ai_rationale);
|
||||||
return getScheduleByDate(db, date)!;
|
return getScheduleByDate(db, date)!;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import type { Database } from 'better-sqlite3';
|
||||||
|
|
||||||
|
export function getStreaks(db: Database): { current: number; longest: number } {
|
||||||
|
const rows = db.prepare(
|
||||||
|
"SELECT date FROM schedule WHERE status = 'completed' ORDER BY date ASC"
|
||||||
|
).all() as Array<{ date: string }>;
|
||||||
|
|
||||||
|
if (rows.length === 0) return { current: 0, longest: 0 };
|
||||||
|
|
||||||
|
let longest = 1, streak = 1;
|
||||||
|
|
||||||
|
for (let i = 1; i < rows.length; i++) {
|
||||||
|
const prev = new Date(rows[i - 1]!.date + 'T12:00:00');
|
||||||
|
const curr = new Date(rows[i]!.date + 'T12:00:00');
|
||||||
|
const diff = Math.round((curr.getTime() - prev.getTime()) / 86400000);
|
||||||
|
if (diff <= 2) {
|
||||||
|
streak++;
|
||||||
|
if (streak > longest) longest = streak;
|
||||||
|
} else {
|
||||||
|
streak = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { current: streak, longest };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user