feat: profile page, admin pages, infinite scroll on browse
Some checks failed
Deploy / Deploy Production (push) Has been skipped
Deploy / Cleanup Preview (push) Has been skipped
Deploy / Deploy Preview (push) Failing after 1s
CI / UI / Build (pull_request) Successful in 16s
CI / Scraper / Test (pull_request) Successful in 16s
CI / Scraper / Lint (pull_request) Successful in 19s
CI / Scraper / Build (pull_request) Successful in 16s

- Add /profile page with reading settings (voice, speed, auto-next) and password change form
- Add /admin/scrape page showing scraping task history with live status polling and trigger controls
- Add /admin/audio page showing audio cache entries with client-side search filter
- Add changePassword(), listAudioCache(), listScrapingTasks() to pocketbase.ts
- Add /api/admin/scrape and /api/browse-page server-side proxy routes
- Replace browse page pagination with IntersectionObserver infinite scroll
- Update nav: username becomes a /profile link; admin users see Scrape and Audio cache links
This commit is contained in:
Admin
2026-03-06 18:58:24 +05:00
parent 08d4718245
commit 8f0a2f7e92
11 changed files with 845 additions and 38 deletions

View File

@@ -0,0 +1,50 @@
import { fail, redirect } from '@sveltejs/kit';
import type { Actions, PageServerLoad } from './$types';
import { changePassword } from '$lib/server/pocketbase';
import { log } from '$lib/server/logger';
export const load: PageServerLoad = async ({ locals }) => {
if (!locals.user) {
redirect(302, '/login');
}
return {
user: locals.user
};
};
export const actions: Actions = {
changePassword: async ({ request, locals }) => {
if (!locals.user) {
return fail(401, { error: 'Not logged in.' });
}
const data = await request.formData();
const current = (data.get('current') as string | null) ?? '';
const next = (data.get('next') as string | null) ?? '';
const confirm = (data.get('confirm') as string | null) ?? '';
if (!current || !next || !confirm) {
return fail(400, { error: 'All fields are required.' });
}
if (next.length < 8) {
return fail(400, { error: 'New password must be at least 8 characters.' });
}
if (next !== confirm) {
return fail(400, { error: 'New passwords do not match.' });
}
let ok: boolean;
try {
ok = await changePassword(locals.user.id, current, next);
} catch (e) {
log.error('profile', 'changePassword failed', { err: String(e) });
return fail(500, { error: 'An error occurred. Please try again.' });
}
if (!ok) {
return fail(401, { error: 'Current password is incorrect.' });
}
return { success: true };
}
};