feat: notifications modal, admin dedup, and in-app notification preferences
- Replace bell dropdown with full-screen NotificationsModal (mirrors SearchModal pattern) - Notifications visible to all logged-in users (not just admin) - Admin users excluded from new-chapter fan-out (dedup vs Scrape Complete notification) - Users with notify_new_chapters=false opted out of new-chapter in-app notifications - Toggle in profile page to enable/disable in-app new-chapter notifications - PATCH /api/profile endpoint to save notification preferences - User-facing /notifications page (admin redirects to /admin/notifications)
This commit is contained in:
@@ -95,6 +95,7 @@ export interface User {
|
||||
oauth_id?: string;
|
||||
polar_customer_id?: string;
|
||||
polar_subscription_id?: string;
|
||||
notify_new_chapters?: boolean;
|
||||
}
|
||||
|
||||
// ─── Auth token cache ─────────────────────────────────────────────────────────
|
||||
@@ -1481,6 +1482,25 @@ export async function updateUserAvatarUrl(userId: string, avatarUrl: string): Pr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user's notification preferences (stored on app_users record).
|
||||
*/
|
||||
export async function updateUserNotificationPrefs(
|
||||
userId: string,
|
||||
prefs: { notify_new_chapters?: boolean }
|
||||
): Promise<void> {
|
||||
const token = await getToken();
|
||||
const res = await fetch(`${PB_URL}/api/collections/app_users/records/${userId}`, {
|
||||
method: 'PATCH',
|
||||
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(prefs)
|
||||
});
|
||||
if (!res.ok) {
|
||||
const body = await res.text().catch(() => '');
|
||||
throw new Error(`updateUserNotificationPrefs failed: ${res.status} ${body}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Comments ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface PBBookComment {
|
||||
|
||||
Reference in New Issue
Block a user