feat: profile stats, discover history, end-of-chapter sleep, rating-ranked deck
All checks were successful
Release / Test backend (push) Successful in 43s
Release / Check ui (push) Successful in 46s
Release / Docker / caddy (push) Successful in 52s
Release / Docker / backend (push) Successful in 2m32s
Release / Docker / ui (push) Successful in 2m15s
Release / Docker / runner (push) Successful in 2m50s
Release / Gitea Release (push) Successful in 22s
All checks were successful
Release / Test backend (push) Successful in 43s
Release / Check ui (push) Successful in 46s
Release / Docker / caddy (push) Successful in 52s
Release / Docker / backend (push) Successful in 2m32s
Release / Docker / ui (push) Successful in 2m15s
Release / Docker / runner (push) Successful in 2m50s
Release / Gitea Release (push) Successful in 22s
**Profile stats tab** - New Stats tab on /profile page (Profile / Stats switcher) - Reading overview: chapters read, completed, reading, plan-to-read counts - Activity cards: day streak + avg rating given - Favourite genres (top 3 by frequency across library/progress) - getUserStats() in pocketbase.ts — computes streak, shelf counts, genre freq **Discover history tab** - New History tab on /discover with full voted-book list - Per-entry: cover thumbnail, title link, author, action label (Liked/Skipped/etc.) - Undo button: optimistic update + DELETE /api/discover/vote?slug=... - Clear all history button; tab shows vote count badge - getVotedBooks(), undoDiscoveryVote() in pocketbase.ts **Rating-ranked discovery deck** - getBooksForDiscovery now sorts by community avg rating before returning - Tier-based shuffle: books within the same ±0.5 star bucket are still randomised - Higher-rated books surface earlier without making the deck fully deterministic **End-of-chapter sleep timer** - New cycle option: Off → End of Chapter → 15m → 30m → 45m → 60m → Off - sleepAfterChapter flag in AudioStore; layout handles it in onended (skips auto-next) - Button shows "End Ch." label when active in this mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { upsertDiscoveryVote, clearDiscoveryVotes, saveBook } from '$lib/server/pocketbase';
|
||||
import { upsertDiscoveryVote, clearDiscoveryVotes, undoDiscoveryVote, saveBook } from '$lib/server/pocketbase';
|
||||
|
||||
const VALID_ACTIONS = ['like', 'skip', 'nope', 'read_now'] as const;
|
||||
type Action = (typeof VALID_ACTIONS)[number];
|
||||
@@ -22,9 +22,16 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
return json({ ok: true });
|
||||
};
|
||||
|
||||
export const DELETE: RequestHandler = async ({ locals }) => {
|
||||
// DELETE /api/discover/vote → clear all (deck reset)
|
||||
// DELETE /api/discover/vote?slug=... → undo single vote
|
||||
export const DELETE: RequestHandler = async ({ url, locals }) => {
|
||||
const slug = url.searchParams.get('slug');
|
||||
try {
|
||||
await clearDiscoveryVotes(locals.sessionId, locals.user?.id);
|
||||
if (slug) {
|
||||
await undoDiscoveryVote(locals.sessionId, slug, locals.user?.id);
|
||||
} else {
|
||||
await clearDiscoveryVotes(locals.sessionId, locals.user?.id);
|
||||
}
|
||||
} catch {
|
||||
error(500, 'Failed to clear votes');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user