mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-10 00:04:27 +00:00
feat: add notification client APIs
Adds typed frontend client calls, hooks, and models for notification preferences, feed reads, and read-state mutations.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import type { AppNotification, NotificationPreferences } from "@/lib/api/models/app/notifications/Notification";
|
||||
import Request from "../../Request";
|
||||
|
||||
export async function getNotificationPreferences(): Promise<NotificationPreferences> {
|
||||
const res = await Request<{ preferences: NotificationPreferences }>({
|
||||
method: "GET",
|
||||
url: "/auth/me/notification-preferences",
|
||||
authorization: true,
|
||||
});
|
||||
return res.preferences;
|
||||
}
|
||||
|
||||
export async function updateNotificationPreferences(preferences: NotificationPreferences): Promise<NotificationPreferences> {
|
||||
const res = await Request<{ preferences: NotificationPreferences }>({
|
||||
method: "PUT",
|
||||
url: "/auth/me/notification-preferences",
|
||||
data: { preferences },
|
||||
authorization: true,
|
||||
});
|
||||
return res.preferences;
|
||||
}
|
||||
|
||||
export async function listNotifications(unreadOnly = false, limit = 50): Promise<{ notifications: AppNotification[]; unread: number }> {
|
||||
const params = new URLSearchParams();
|
||||
if (unreadOnly) params.set("unread", "1");
|
||||
params.set("limit", String(limit));
|
||||
return await Request<{ notifications: AppNotification[]; unread: number }>({
|
||||
method: "GET",
|
||||
url: `/auth/me/notifications?${params.toString()}`,
|
||||
authorization: true,
|
||||
});
|
||||
}
|
||||
|
||||
export async function markNotificationRead(id: string): Promise<void> {
|
||||
await Request<void>({
|
||||
method: "POST",
|
||||
url: `/auth/me/notifications/${id}/read`,
|
||||
authorization: true,
|
||||
});
|
||||
}
|
||||
|
||||
export async function markAllNotificationsRead(): Promise<void> {
|
||||
await Request<void>({
|
||||
method: "PUT",
|
||||
url: "/auth/me/notifications",
|
||||
authorization: true,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
getNotificationPreferences,
|
||||
updateNotificationPreferences,
|
||||
listNotifications,
|
||||
markNotificationRead,
|
||||
markAllNotificationsRead,
|
||||
} from "@/lib/api/client/app/notifications/notifications";
|
||||
import type { NotificationPreferences } from "@/lib/api/models/app/notifications/Notification";
|
||||
|
||||
const PREFS_KEY = ["notifications", "preferences"];
|
||||
const FEED_KEY = ["notifications", "feed"];
|
||||
|
||||
export function useNotificationPreferences() {
|
||||
return useQuery({
|
||||
queryKey: PREFS_KEY,
|
||||
queryFn: getNotificationPreferences,
|
||||
staleTime: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateNotificationPreferences() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (prefs: NotificationPreferences) => updateNotificationPreferences(prefs),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: PREFS_KEY }),
|
||||
});
|
||||
}
|
||||
|
||||
export function useNotifications() {
|
||||
return useQuery({
|
||||
queryKey: FEED_KEY,
|
||||
queryFn: () => listNotifications(false, 50),
|
||||
staleTime: 15_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useMarkNotificationRead() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => markNotificationRead(id),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: FEED_KEY }),
|
||||
});
|
||||
}
|
||||
|
||||
export function useMarkAllNotificationsRead() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: () => markAllNotificationsRead(),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: FEED_KEY }),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// In-app notification feed + per-user preferences (mirrors the Go models).
|
||||
|
||||
export interface ChannelPrefs {
|
||||
in_app: boolean;
|
||||
email: boolean; // reserved; not delivered yet
|
||||
}
|
||||
|
||||
export interface CategoryPref {
|
||||
enabled: boolean;
|
||||
channels: ChannelPrefs;
|
||||
}
|
||||
|
||||
export interface NotificationPreferences {
|
||||
inbound_reply: CategoryPref;
|
||||
inbound_out_of_office: CategoryPref;
|
||||
health_bounce: CategoryPref;
|
||||
health_complaint: CategoryPref;
|
||||
health_worker_downtime: CategoryPref;
|
||||
}
|
||||
|
||||
export type NotificationCategoryKey = keyof NotificationPreferences;
|
||||
|
||||
export interface AppNotification {
|
||||
id: string;
|
||||
user_id: string;
|
||||
organization_id?: string | null;
|
||||
category: string;
|
||||
title: string;
|
||||
body?: string;
|
||||
link?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
read_at?: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
Reference in New Issue
Block a user