Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
126 lines
3.9 KiB
TypeScript
126 lines
3.9 KiB
TypeScript
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<ServiceResult<VapidPublicKeyResult>> => {
|
|
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<ServiceResult<PushSubscriptionRecord>> => {
|
|
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<ServiceResult<{ deleted: boolean }>> => {
|
|
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<ServiceResult<{ deletedCount: number }>> => {
|
|
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<void> => {
|
|
const subscriptionId = getStoredPushSubscriptionId()
|
|
|
|
try {
|
|
if (subscriptionId) {
|
|
await UNSUBSCRIBE_PUSH(subscriptionId, { errorMode: 'silent' })
|
|
}
|
|
} finally {
|
|
await unsubscribeBrowserPushManager()
|
|
clearStoredPushSubscriptionId()
|
|
}
|
|
}
|