Browse Source
- Created NotificationSettingsService class for settings and permission logic - Separates business logic from UI presentation in NotificationSection - Maintains component lifecycle boundary while improving testability - Service handles settings hydration, persistence, and permission management - Component now focuses purely on UI with computed properties for template access - Added src/composables/useNotificationSettings.ts - Updated src/components/NotificationSection.vue to use service - Resolved TypeScript type issues with PlatformServiceMixin integrationpull/150/head
3 changed files with 305 additions and 120 deletions
@ -0,0 +1,233 @@ |
|||||
|
/** |
||||
|
* useNotificationSettings.ts - Notification settings and permissions service |
||||
|
* |
||||
|
* This service handles all notification-related business logic including: |
||||
|
* - Settings hydration and persistence |
||||
|
* - Registration status checking |
||||
|
* - Notification permission management |
||||
|
* - Settings state management |
||||
|
* |
||||
|
* Separates business logic from UI components while maintaining |
||||
|
* the lifecycle boundary and settings access patterns. |
||||
|
* |
||||
|
* @author Matthew Raymer |
||||
|
* @service NotificationSettingsService |
||||
|
*/ |
||||
|
|
||||
|
import { createNotifyHelpers } from "@/utils/notify"; |
||||
|
import { ACCOUNT_VIEW_CONSTANTS } from "@/constants/accountView"; |
||||
|
import { DAILY_CHECK_TITLE, DIRECT_PUSH_TITLE } from "@/libs/util"; |
||||
|
import type { ComponentPublicInstance } from "vue"; |
||||
|
|
||||
|
/** |
||||
|
* Interface for notification settings state |
||||
|
*/ |
||||
|
export interface NotificationSettingsState { |
||||
|
isRegistered: boolean; |
||||
|
notifyingNewActivity: boolean; |
||||
|
notifyingNewActivityTime: string; |
||||
|
notifyingReminder: boolean; |
||||
|
notifyingReminderMessage: string; |
||||
|
notifyingReminderTime: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Interface for notification settings actions |
||||
|
*/ |
||||
|
export interface NotificationSettingsActions { |
||||
|
hydrateFromSettings: () => Promise<void>; |
||||
|
updateNewActivityNotification: ( |
||||
|
enabled: boolean, |
||||
|
timeText?: string, |
||||
|
) => Promise<void>; |
||||
|
updateReminderNotification: ( |
||||
|
enabled: boolean, |
||||
|
timeText?: string, |
||||
|
message?: string, |
||||
|
) => Promise<void>; |
||||
|
showNewActivityNotificationInfo: (router: any) => Promise<void>; |
||||
|
showReminderNotificationInfo: (router: any) => Promise<void>; |
||||
|
showNewActivityNotificationChoice: ( |
||||
|
pushNotificationPermissionRef: any, |
||||
|
) => Promise<void>; |
||||
|
showReminderNotificationChoice: ( |
||||
|
pushNotificationPermissionRef: any, |
||||
|
) => Promise<void>; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Service class for managing notification settings and permissions |
||||
|
* |
||||
|
* @param platformService - PlatformServiceMixin instance for settings access |
||||
|
* @param notify - Notification helper functions |
||||
|
*/ |
||||
|
export class NotificationSettingsService |
||||
|
implements NotificationSettingsState, NotificationSettingsActions |
||||
|
{ |
||||
|
// State properties
|
||||
|
public isRegistered: boolean = false; |
||||
|
public notifyingNewActivity: boolean = false; |
||||
|
public notifyingNewActivityTime: string = ""; |
||||
|
public notifyingReminder: boolean = false; |
||||
|
public notifyingReminderMessage: string = ""; |
||||
|
public notifyingReminderTime: string = ""; |
||||
|
|
||||
|
constructor( |
||||
|
private platformService: ComponentPublicInstance & { |
||||
|
$accountSettings: () => Promise<any>; |
||||
|
$saveSettings: (changes: any) => Promise<boolean>; |
||||
|
}, |
||||
|
private notify: ReturnType<typeof createNotifyHelpers>, |
||||
|
) {} |
||||
|
|
||||
|
/** |
||||
|
* Load notification settings from database and hydrate internal state |
||||
|
* Uses the existing settings mechanism for consistency |
||||
|
*/ |
||||
|
public async hydrateFromSettings(): Promise<void> { |
||||
|
try { |
||||
|
const settings = await this.platformService.$accountSettings(); |
||||
|
|
||||
|
// Hydrate registration status
|
||||
|
this.isRegistered = !!settings?.isRegistered; |
||||
|
|
||||
|
// Hydrate boolean flags from time presence
|
||||
|
this.notifyingNewActivity = !!settings.notifyingNewActivityTime; |
||||
|
this.notifyingNewActivityTime = settings.notifyingNewActivityTime || ""; |
||||
|
this.notifyingReminder = !!settings.notifyingReminderTime; |
||||
|
this.notifyingReminderMessage = settings.notifyingReminderMessage || ""; |
||||
|
this.notifyingReminderTime = settings.notifyingReminderTime || ""; |
||||
|
} catch (error) { |
||||
|
console.error("Failed to hydrate notification settings:", error); |
||||
|
// Keep default values on error
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Update new activity notification settings |
||||
|
*/ |
||||
|
public async updateNewActivityNotification( |
||||
|
enabled: boolean, |
||||
|
timeText: string = "", |
||||
|
): Promise<void> { |
||||
|
await this.platformService.$saveSettings({ |
||||
|
notifyingNewActivityTime: timeText, |
||||
|
}); |
||||
|
this.notifyingNewActivity = enabled; |
||||
|
this.notifyingNewActivityTime = timeText; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Update reminder notification settings |
||||
|
*/ |
||||
|
public async updateReminderNotification( |
||||
|
enabled: boolean, |
||||
|
timeText: string = "", |
||||
|
message: string = "", |
||||
|
): Promise<void> { |
||||
|
await this.platformService.$saveSettings({ |
||||
|
notifyingReminderMessage: message, |
||||
|
notifyingReminderTime: timeText, |
||||
|
}); |
||||
|
this.notifyingReminder = enabled; |
||||
|
this.notifyingReminderMessage = message; |
||||
|
this.notifyingReminderTime = timeText; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Show new activity notification info dialog |
||||
|
*/ |
||||
|
public async showNewActivityNotificationInfo(router: any): Promise<void> { |
||||
|
this.notify.confirm( |
||||
|
ACCOUNT_VIEW_CONSTANTS.NOTIFICATIONS.NEW_ACTIVITY_INFO, |
||||
|
async () => { |
||||
|
await router.push({ |
||||
|
name: "help-notification-types", |
||||
|
}); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Show reminder notification info dialog |
||||
|
*/ |
||||
|
public async showReminderNotificationInfo(router: any): Promise<void> { |
||||
|
this.notify.confirm( |
||||
|
ACCOUNT_VIEW_CONSTANTS.NOTIFICATIONS.REMINDER_INFO, |
||||
|
async () => { |
||||
|
await router.push({ |
||||
|
name: "help-notification-types", |
||||
|
}); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Handle new activity notification choice (enable/disable) |
||||
|
*/ |
||||
|
public async showNewActivityNotificationChoice( |
||||
|
pushNotificationPermissionRef: any, |
||||
|
): Promise<void> { |
||||
|
if (!this.notifyingNewActivity) { |
||||
|
// Enable notification
|
||||
|
pushNotificationPermissionRef.open( |
||||
|
DAILY_CHECK_TITLE, |
||||
|
async (success: boolean, timeText: string) => { |
||||
|
if (success) { |
||||
|
await this.updateNewActivityNotification(true, timeText); |
||||
|
} |
||||
|
}, |
||||
|
); |
||||
|
} else { |
||||
|
// Disable notification
|
||||
|
this.notify.notificationOff(DAILY_CHECK_TITLE, async (success) => { |
||||
|
if (success) { |
||||
|
await this.updateNewActivityNotification(false); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Handle reminder notification choice (enable/disable) |
||||
|
*/ |
||||
|
public async showReminderNotificationChoice( |
||||
|
pushNotificationPermissionRef: any, |
||||
|
): Promise<void> { |
||||
|
if (!this.notifyingReminder) { |
||||
|
// Enable notification
|
||||
|
pushNotificationPermissionRef.open( |
||||
|
DIRECT_PUSH_TITLE, |
||||
|
async (success: boolean, timeText: string, message?: string) => { |
||||
|
if (success) { |
||||
|
await this.updateReminderNotification(true, timeText, message); |
||||
|
} |
||||
|
}, |
||||
|
); |
||||
|
} else { |
||||
|
// Disable notification
|
||||
|
this.notify.notificationOff(DIRECT_PUSH_TITLE, async (success) => { |
||||
|
if (success) { |
||||
|
await this.updateReminderNotification(false); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Factory function to create a NotificationSettingsService instance |
||||
|
* |
||||
|
* @param platformService - PlatformServiceMixin instance |
||||
|
* @param notify - Notification helper functions |
||||
|
* @returns NotificationSettingsService instance |
||||
|
*/ |
||||
|
export function createNotificationSettingsService( |
||||
|
platformService: ComponentPublicInstance & { |
||||
|
$accountSettings: () => Promise<any>; |
||||
|
$saveSettings: (changes: any) => Promise<boolean>; |
||||
|
}, |
||||
|
notify: ReturnType<typeof createNotifyHelpers>, |
||||
|
): NotificationSettingsService { |
||||
|
return new NotificationSettingsService(platformService, notify); |
||||
|
} |
Loading…
Reference in new issue