life-manager/codebase/features/notifications/frontend/useNotifications.ts

128 lines
3.8 KiB
TypeScript

import {
useQuery,
useMutation,
useQueryClient,
type UseQueryResult,
type UseMutationResult,
} from '@tanstack/react-query';
import { apiClient } from '@/lib/api';
import type {
ReminderStatus,
ReminderTargetType,
ReminderTriggerType,
NotificationChannel,
} from '@life-platform/shared';
export interface Reminder {
id: string;
targetType: ReminderTargetType;
targetId: string | null;
title: string;
message: string | null;
triggerType: ReminderTriggerType;
triggerConfig: Record<string, unknown>;
channels: NotificationChannel[];
status: ReminderStatus;
firedAt: string | null;
nextFireAt: string | null;
createdAt: string;
updatedAt: string;
deletedAt: string | null;
}
export interface PaginatedReminders {
data: Reminder[];
total: number;
page: number;
limit: number;
}
export interface ReminderListParams {
status?: ReminderStatus;
targetType?: ReminderTargetType;
targetId?: string;
page?: number;
limit?: number;
}
export interface CreateReminderInput {
targetType: ReminderTargetType;
targetId?: string;
title: string;
message?: string;
triggerType: ReminderTriggerType;
triggerConfig: Record<string, unknown>;
channels: NotificationChannel[];
}
export type UpdateReminderInput = Partial<CreateReminderInput>;
const KEYS = {
all: ['notifications'] as const,
list: (params?: ReminderListParams): readonly ['notifications', 'list', ReminderListParams | undefined] =>
[...KEYS.all, 'list', params] as const,
upcoming: (minutes?: number): readonly ['notifications', 'upcoming', number | undefined] =>
[...KEYS.all, 'upcoming', minutes] as const,
detail: (id: string): readonly ['notifications', 'detail', string] =>
[...KEYS.all, 'detail', id] as const,
};
export function useReminders(params?: ReminderListParams): UseQueryResult<PaginatedReminders> {
return useQuery({
queryKey: KEYS.list(params),
queryFn: (): Promise<PaginatedReminders> =>
apiClient.get<PaginatedReminders>('/notifications', { params }).then((r) => r.data),
});
}
export function useUpcomingReminders(minutes?: number): UseQueryResult<Reminder[]> {
return useQuery({
queryKey: KEYS.upcoming(minutes),
queryFn: (): Promise<Reminder[]> =>
apiClient
.get<Reminder[]>('/notifications/upcoming', { params: minutes ? { minutes } : undefined })
.then((r) => r.data),
refetchInterval: 60_000,
});
}
export function useReminder(id: string): UseQueryResult<Reminder> {
return useQuery({
queryKey: KEYS.detail(id),
queryFn: (): Promise<Reminder> =>
apiClient.get<Reminder>(`/notifications/${id}`).then((r) => r.data),
enabled: !!id,
});
}
export function useCreateReminder(): UseMutationResult<Reminder, Error, CreateReminderInput> {
const qc = useQueryClient();
return useMutation({
mutationFn: (data: CreateReminderInput): Promise<Reminder> =>
apiClient.post<Reminder>('/notifications', data).then((r) => r.data),
onSuccess: (): void => {
qc.invalidateQueries({ queryKey: KEYS.all });
},
});
}
export function useUpdateReminder(): UseMutationResult<Reminder, Error, { id: string; data: UpdateReminderInput }> {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UpdateReminderInput }): Promise<Reminder> =>
apiClient.patch<Reminder>(`/notifications/${id}`, data).then((r) => r.data),
onSuccess: (): void => {
qc.invalidateQueries({ queryKey: KEYS.all });
},
});
}
export function useDismissReminder(): UseMutationResult<void, Error, string> {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: string): Promise<void> => apiClient.delete(`/notifications/${id}`).then(() => undefined),
onSuccess: (): void => {
qc.invalidateQueries({ queryKey: KEYS.all });
},
});
}