fix: timezone-safe streak continuity with 48h elapsed-time window
Some checks failed
CI / update (push) Has been cancelled
Some checks failed
CI / update (push) Has been cancelled
Use local dates instead of UTC for day boundaries, and store an epoch timestamp alongside the date string. Streak alive check uses real elapsed time (<48h) which covers dateline crossings. Old data without timestamps falls back to date-string comparison so existing streaks are preserved.
This commit is contained in:
@@ -19,6 +19,7 @@ export const GET: RequestHandler = async ({ locals }) => {
|
||||
return json({
|
||||
streak: streak?.streak ?? 0,
|
||||
lastComplete: streak?.lastComplete ?? null,
|
||||
lastCompleteTs: streak?.lastCompleteTs ?? null,
|
||||
todayPrayed: streak?.todayPrayed ?? 0,
|
||||
todayDate: streak?.todayDate ?? null
|
||||
});
|
||||
@@ -34,7 +35,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
throw error(401, 'Authentication required');
|
||||
}
|
||||
|
||||
const { streak, lastComplete, todayPrayed, todayDate } = await request.json();
|
||||
const { streak, lastComplete, lastCompleteTs, todayPrayed, todayDate } = await request.json();
|
||||
|
||||
if (typeof streak !== 'number' || streak < 0) {
|
||||
throw error(400, 'Valid streak required');
|
||||
@@ -55,15 +56,21 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
await dbConnect();
|
||||
|
||||
try {
|
||||
const updateFields: Record<string, unknown> = { streak, lastComplete, todayPrayed, todayDate };
|
||||
if (typeof lastCompleteTs === 'number') {
|
||||
updateFields.lastCompleteTs = lastCompleteTs;
|
||||
}
|
||||
|
||||
const updated = await AngelusStreak.findOneAndUpdate(
|
||||
{ username: session.user.nickname },
|
||||
{ streak, lastComplete, todayPrayed, todayDate },
|
||||
updateFields,
|
||||
{ upsert: true, new: true }
|
||||
).lean() as any;
|
||||
|
||||
return json({
|
||||
streak: updated?.streak ?? 0,
|
||||
lastComplete: updated?.lastComplete ?? null,
|
||||
lastCompleteTs: updated?.lastCompleteTs ?? null,
|
||||
todayPrayed: updated?.todayPrayed ?? 0,
|
||||
todayDate: updated?.todayDate ?? null
|
||||
});
|
||||
|
||||
@@ -18,7 +18,8 @@ export const GET: RequestHandler = async ({ locals }) => {
|
||||
|
||||
return json({
|
||||
length: streak?.length ?? 0,
|
||||
lastPrayed: streak?.lastPrayed ?? null
|
||||
lastPrayed: streak?.lastPrayed ?? null,
|
||||
lastPrayedTs: streak?.lastPrayedTs ?? null
|
||||
});
|
||||
} catch (e) {
|
||||
throw error(500, 'Failed to fetch rosary streak');
|
||||
@@ -32,7 +33,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
throw error(401, 'Authentication required');
|
||||
}
|
||||
|
||||
const { length, lastPrayed } = await request.json();
|
||||
const { length, lastPrayed, lastPrayedTs } = await request.json();
|
||||
|
||||
if (typeof length !== 'number' || length < 0) {
|
||||
throw error(400, 'Valid streak length required');
|
||||
@@ -45,15 +46,21 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
await dbConnect();
|
||||
|
||||
try {
|
||||
const updateFields: Record<string, unknown> = { length, lastPrayed };
|
||||
if (typeof lastPrayedTs === 'number') {
|
||||
updateFields.lastPrayedTs = lastPrayedTs;
|
||||
}
|
||||
|
||||
const updated = await RosaryStreak.findOneAndUpdate(
|
||||
{ username: session.user.nickname },
|
||||
{ length, lastPrayed },
|
||||
updateFields,
|
||||
{ upsert: true, new: true }
|
||||
).lean() as any;
|
||||
|
||||
return json({
|
||||
length: updated?.length ?? 0,
|
||||
lastPrayed: updated?.lastPrayed ?? null
|
||||
lastPrayed: updated?.lastPrayed ?? null,
|
||||
lastPrayedTs: updated?.lastPrayedTs ?? null
|
||||
});
|
||||
} catch (e) {
|
||||
throw error(500, 'Failed to update rosary streak');
|
||||
|
||||
Reference in New Issue
Block a user