import type { PushSubscriptionResponseDto, PushVapidPublicKeyResponseDto } from '@/api/generated/models' import { createServiceError, errorResult, handleServiceError, type ServiceCallOptions, type ServiceResult, shouldBubbleErrorToParent, successResult, } from '@/services/errorHandler' import { unwrapApiData } from '@/services/apiResponse' import { getNotifications } from '@/api/generated/notifications/notifications' import { clearStoredPushSubscriptionId, getStoredPushSubscriptionId, unsubscribeBrowserPushManager } from '@/lib/pwa' import { texts } from '@/texts' export type PushSubscriptionRecord = PushSubscriptionResponseDto export type VapidPublicKeyResult = PushVapidPublicKeyResponseDto const notificationsApi = getNotifications() export const GET_VAPID_PUBLIC_KEY = async (options?: ServiceCallOptions): Promise> => { try { const res = await notificationsApi.notificationsControllerVapidPublicKey() if (!res.data.success) throw createServiceError(res.data.message) const payload = unwrapApiData(res.data) return successResult({ publicKey: String(payload?.publicKey ?? ''), enabled: Boolean(payload?.enabled), }) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) { throw normalizedError } return errorResult(normalizedError) } } export const SUBSCRIBE_PUSH = async ( data: { endpoint: string; p256dh: string; auth: string; userAgent?: string }, options?: ServiceCallOptions ): Promise> => { try { const res = await notificationsApi.notificationsControllerSubscribePush(data) if (!res.data.success) throw createServiceError(res.data.message) const payload = unwrapApiData(res.data) if (!payload?.id) { throw createServiceError(texts.common.invalidServerResponse) } return successResult(payload) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) { throw normalizedError } return errorResult(normalizedError) } } export const UNSUBSCRIBE_PUSH = async ( subscriptionId: string, options?: ServiceCallOptions ): Promise> => { try { await notificationsApi.notificationsControllerUnsubscribePush(subscriptionId) return successResult({ deleted: true }) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) { throw normalizedError } return errorResult(normalizedError) } } export const UNSUBSCRIBE_ALL_PUSH = async (options?: ServiceCallOptions): Promise> => { try { const res = await notificationsApi.notificationsControllerUnsubscribeAllPush() if (!res.data.success) throw createServiceError(res.data.message) const payload = unwrapApiData(res.data) return successResult({ deletedCount: Number(payload?.deletedCount ?? 0) }) } catch (error) { const normalizedError = handleServiceError(error, options) if (shouldBubbleErrorToParent(options)) { throw normalizedError } return errorResult(normalizedError) } } /** * Removes push delivery for *this* device only: deletes the server-side * subscription row (if we have its id) and unsubscribes the browser's * PushManager. Intended for logout — logging out on one device should not * silence push notifications on the user's other logged-in devices, which * UNSUBSCRIBE_ALL_PUSH would do. */ export const unsubscribeCurrentDevicePush = async (): Promise => { const subscriptionId = getStoredPushSubscriptionId() try { if (subscriptionId) { await UNSUBSCRIBE_PUSH(subscriptionId, { errorMode: 'silent' }) } } finally { await unsubscribeBrowserPushManager() clearStoredPushSubscriptionId() } }