mirror of
https://github.com/pupperpowell/bibdle.git
synced 2026-04-05 17:33:31 -04:00
Added streak percentage
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
shareResult,
|
||||
copyToClipboard as clipboardCopy,
|
||||
} from "$lib/utils/share";
|
||||
import { fetchStreak } from "$lib/utils/streak";
|
||||
import { fetchStreak, fetchStreakPercentile } from "$lib/utils/streak";
|
||||
import {
|
||||
submitCompletion,
|
||||
fetchExistingStats,
|
||||
@@ -41,6 +41,7 @@
|
||||
let showWinScreen = $state(false);
|
||||
let statsData = $state<StatsData | null>(null);
|
||||
let streak = $state(0);
|
||||
let streakPercentile = $state<number | null>(null);
|
||||
|
||||
const persistence = createGamePersistence(
|
||||
() => dailyVerse.date,
|
||||
@@ -217,6 +218,11 @@
|
||||
const localDate = new Date().toLocaleDateString("en-CA");
|
||||
fetchStreak(persistence.anonymousId, localDate).then((result) => {
|
||||
streak = result;
|
||||
if (result >= 2) {
|
||||
fetchStreakPercentile(result, localDate).then((p) => {
|
||||
streakPercentile = p;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -308,6 +314,7 @@
|
||||
onChapterGuessCompleted={persistence.onChapterGuessCompleted}
|
||||
shareText={getShareText()}
|
||||
{streak}
|
||||
{streakPercentile}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
72
src/routes/api/streak-percentile/+server.ts
Normal file
72
src/routes/api/streak-percentile/+server.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { db } from '$lib/server/db';
|
||||
import { dailyCompletions } from '$lib/server/db/schema';
|
||||
import { desc } from 'drizzle-orm';
|
||||
|
||||
export const GET: RequestHandler = async ({ url }) => {
|
||||
const streakParam = url.searchParams.get('streak');
|
||||
const localDate = url.searchParams.get('localDate');
|
||||
|
||||
if (!streakParam || !localDate) {
|
||||
error(400, 'Missing streak or localDate');
|
||||
}
|
||||
|
||||
const targetStreak = parseInt(streakParam, 10);
|
||||
if (isNaN(targetStreak) || targetStreak < 1) {
|
||||
error(400, 'Invalid streak');
|
||||
}
|
||||
|
||||
// Fetch all completions ordered by anonymous_id and date desc
|
||||
// so we can walk each user's history to compute their current streak.
|
||||
const rows = await db
|
||||
.select({
|
||||
anonymousId: dailyCompletions.anonymousId,
|
||||
date: dailyCompletions.date,
|
||||
})
|
||||
.from(dailyCompletions)
|
||||
.orderBy(desc(dailyCompletions.date));
|
||||
|
||||
// Group dates by user
|
||||
const byUser = new Map<string, string[]>();
|
||||
for (const row of rows) {
|
||||
const list = byUser.get(row.anonymousId);
|
||||
if (list) {
|
||||
list.push(row.date);
|
||||
} else {
|
||||
byUser.set(row.anonymousId, [row.date]);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the current streak for each user
|
||||
const streaks: number[] = [];
|
||||
for (const [, dates] of byUser) {
|
||||
// dates are already desc-sorted
|
||||
const dateSet = new Set(dates);
|
||||
let streak = 0;
|
||||
let cursor = new Date(`${localDate}T00:00:00`);
|
||||
|
||||
while (true) {
|
||||
const dateStr = cursor.toLocaleDateString('en-CA');
|
||||
if (!dateSet.has(dateStr)) break;
|
||||
streak++;
|
||||
cursor.setDate(cursor.getDate() - 1);
|
||||
}
|
||||
|
||||
streaks.push(streak);
|
||||
}
|
||||
|
||||
// Only count users who have an active streak (streak >= 1)
|
||||
const activeStreaks = streaks.filter((s) => s >= 1);
|
||||
|
||||
if (activeStreaks.length === 0) {
|
||||
return json({ percentile: 100 });
|
||||
}
|
||||
|
||||
// Percentage of active-streak users who have a streak >= targetStreak
|
||||
const atOrAbove = activeStreaks.filter((s) => s >= targetStreak).length;
|
||||
const raw = (atOrAbove / activeStreaks.length) * 100;
|
||||
const percentile = raw < 1 ? Math.round(raw * 100) / 100 : Math.round(raw);
|
||||
|
||||
return json({ percentile });
|
||||
};
|
||||
Reference in New Issue
Block a user