5a50d77515
Adds sharing (residence share codes, join, user management, .casera file export/import), subscription status with feature comparison, notification preferences with bell icon, profile settings (edit info, change password, theme picker, delete account), onboarding wizard with create/join paths, enhanced dashboard with stats cards, Recharts completion chart, recent activity feed, and task report PDF download. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
163 lines
4.3 KiB
TypeScript
163 lines
4.3 KiB
TypeScript
// ---------------------------------------------------------------------------
|
|
// Notifications API client (client-side)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
import { apiFetch } from './client';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Request / response shapes
|
|
// TODO: import from @/lib/types once the shared types package is finalised
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export interface NotificationResponse {
|
|
id: number;
|
|
title: string;
|
|
body: string;
|
|
notification_type: string;
|
|
is_read: boolean;
|
|
data?: Record<string, unknown>;
|
|
created_at: string;
|
|
}
|
|
|
|
export interface NotificationListResponse {
|
|
count: number;
|
|
results: NotificationResponse[];
|
|
}
|
|
|
|
export interface UnreadCountResponse {
|
|
unread_count: number;
|
|
}
|
|
|
|
export interface NotificationPreferencesResponse {
|
|
task_reminders: boolean;
|
|
task_completions: boolean;
|
|
residence_updates: boolean;
|
|
share_notifications: boolean;
|
|
marketing: boolean;
|
|
}
|
|
|
|
export interface UpdatePreferencesRequest {
|
|
task_reminders?: boolean;
|
|
task_completions?: boolean;
|
|
residence_updates?: boolean;
|
|
share_notifications?: boolean;
|
|
marketing?: boolean;
|
|
}
|
|
|
|
export interface RegisterDeviceRequest {
|
|
registration_id: string;
|
|
platform: 'ios' | 'android' | 'web';
|
|
device_name?: string;
|
|
}
|
|
|
|
export interface DeviceResponse {
|
|
id: number;
|
|
registration_id: string;
|
|
platform: string;
|
|
device_name: string;
|
|
is_active: boolean;
|
|
created_at: string;
|
|
}
|
|
|
|
export interface UnregisterDeviceRequest {
|
|
registration_id: string;
|
|
platform?: string;
|
|
}
|
|
|
|
export interface MessageResponse {
|
|
message: string;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// API functions
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/** List notifications with optional pagination. */
|
|
export function listNotifications(
|
|
limit?: number,
|
|
offset?: number,
|
|
): Promise<NotificationListResponse> {
|
|
const params = new URLSearchParams();
|
|
if (limit != null) params.set('limit', String(limit));
|
|
if (offset != null) params.set('offset', String(offset));
|
|
const qs = params.toString();
|
|
return apiFetch<NotificationListResponse>(
|
|
`/notifications/${qs ? `?${qs}` : ''}`,
|
|
);
|
|
}
|
|
|
|
/** Get unread notification count. */
|
|
export function getUnreadCount(): Promise<UnreadCountResponse> {
|
|
return apiFetch<UnreadCountResponse>('/notifications/unread-count/');
|
|
}
|
|
|
|
/** Mark a single notification as read. */
|
|
export function markAsRead(id: number): Promise<MessageResponse> {
|
|
return apiFetch<MessageResponse>(`/notifications/${id}/read/`, {
|
|
method: 'POST',
|
|
});
|
|
}
|
|
|
|
/** Mark all notifications as read. */
|
|
export function markAllAsRead(): Promise<MessageResponse> {
|
|
return apiFetch<MessageResponse>('/notifications/mark-all-read/', {
|
|
method: 'POST',
|
|
});
|
|
}
|
|
|
|
/** Get notification preferences. */
|
|
export function getPreferences(): Promise<NotificationPreferencesResponse> {
|
|
return apiFetch<NotificationPreferencesResponse>(
|
|
'/notifications/preferences/',
|
|
);
|
|
}
|
|
|
|
/** Update notification preferences. */
|
|
export function updatePreferences(
|
|
data: UpdatePreferencesRequest,
|
|
): Promise<NotificationPreferencesResponse> {
|
|
return apiFetch<NotificationPreferencesResponse>(
|
|
'/notifications/preferences/',
|
|
{
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
},
|
|
);
|
|
}
|
|
|
|
/** Register a push notification device. */
|
|
export function registerDevice(
|
|
data: RegisterDeviceRequest,
|
|
): Promise<DeviceResponse> {
|
|
return apiFetch<DeviceResponse>('/notifications/devices/', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
/** List registered devices. */
|
|
export function listDevices(): Promise<DeviceResponse[]> {
|
|
return apiFetch<DeviceResponse[]>('/notifications/devices/');
|
|
}
|
|
|
|
/** Unregister a push notification device by registration ID. */
|
|
export function unregisterDevice(
|
|
data: UnregisterDeviceRequest,
|
|
): Promise<MessageResponse> {
|
|
return apiFetch<MessageResponse>('/notifications/devices/unregister/', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
/** Delete a device by ID. */
|
|
export function deleteDevice(
|
|
id: number,
|
|
platform?: string,
|
|
): Promise<MessageResponse> {
|
|
const qs = platform ? `?platform=${platform}` : '';
|
|
return apiFetch<MessageResponse>(`/notifications/devices/${id}/${qs}`, {
|
|
method: 'DELETE',
|
|
});
|
|
}
|