# DailyNotification Setup Guide for TimeSafari PWA **Author**: Matthew Raymer **Version**: 1.0.0 **Created**: 2025-10-08 06:24:57 UTC ## Overview This guide shows you exactly how to set up the DailyNotification plugin in your existing TimeSafari PWA to work with your current `loadNewStarredProjectChanges()` and `getStarredProjectsWithChanges()` methods. ## Step-by-Step Setup ### Step 1: Install the Plugin ```bash # In your TimeSafari PWA project npm install ssh://git@173.199.124.46:222/trent_larson/daily-notification-plugin.git ``` ### Step 2: Import the Plugin ```typescript // In your TimeSafari PWA file (e.g., HomeView.vue or main.ts) import { DailyNotification } from '@timesafari/daily-notification-plugin'; import { TimeSafariIntegrationService } from '@timesafari/daily-notification-plugin'; ``` ### Step 3: Configure the Plugin Add this configuration to your existing TimeSafari PWA code: ```typescript // In your TimeSafari PWA class/component async setupDailyNotification() { try { // Configure the plugin with your existing TimeSafari settings await DailyNotification.configure({ // Basic configuration storage: 'tiered', ttlSeconds: 1800, enableETagSupport: true, // TimeSafari-specific configuration timesafariConfig: { // Your existing activeDid activeDid: this.activeDid, // Your existing API endpoints endpoints: { offersToPerson: `${this.apiServer}/api/v2/offers/person`, offersToPlans: `${this.apiServer}/api/v2/offers/plans`, projectsLastUpdated: `${this.apiServer}/api/v2/report/plansLastUpdatedBetween` }, // Configure starred projects fetching (matches your existing pattern) starredProjectsConfig: { enabled: true, starredPlanHandleIds: this.starredPlanHandleIds, lastAckedJwtId: this.lastAckedStarredPlanChangesJwtId, fetchInterval: '0 8 * * *', // Daily at 8 AM maxResults: 50, hitLimitHandling: 'warn' } }, // Network configuration using your existing axios instance networkConfig: { httpClient: this.axios, // Your existing axios instance baseURL: this.apiServer, // Your existing API server timeout: 30000, retryAttempts: 3 }, // Content fetch configuration (replaces your existing method) contentFetch: { enabled: true, schedule: '0 8 * * *', // Daily at 8 AM // Your existing request pattern requestConfig: { method: 'POST', url: `${this.apiServer}/api/v2/report/plansLastUpdatedBetween`, headers: { 'Authorization': 'Bearer ${jwt}', 'X-User-DID': '${activeDid}', 'Content-Type': 'application/json' }, body: { planIds: '${starredPlanHandleIds}', afterId: '${lastAckedJwtId}' } }, // Callbacks that match your existing error handling callbacks: { onSuccess: this.handleStarredProjectsSuccess.bind(this), onError: this.handleStarredProjectsError.bind(this) } } }); // Initialize TimeSafari Integration Service this.integrationService = TimeSafariIntegrationService.getInstance(); await this.integrationService.initialize({ activeDid: this.activeDid, storageAdapter: this.getTimeSafariStorageAdapter(), endorserApiBaseUrl: this.apiServer }); console.log('DailyNotification setup completed successfully!'); } catch (error) { console.error('Failed to setup DailyNotification:', error); } } ``` ### Step 4: Replace Your Existing Method Replace your existing `loadNewStarredProjectChanges()` method with this enhanced version: ```typescript // Enhanced version of your existing method async loadNewStarredProjectChanges() { if (this.activeDid && this.starredPlanHandleIds.length > 0) { try { // Use plugin's enhanced fetching with same interface as your existing code const starredProjectChanges = await this.integrationService.getStarredProjectsWithChanges( this.activeDid, this.starredPlanHandleIds, this.lastAckedStarredPlanChangesJwtId ); // Same handling as your existing code this.numNewStarredProjectChanges = starredProjectChanges.data.length; this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit; } catch (error) { // Same error handling as your existing code console.warn('[HomeView] Failed to load starred project changes:', error); this.numNewStarredProjectChanges = 0; this.newStarredProjectChangesHitLimit = false; } } else { this.numNewStarredProjectChanges = 0; this.newStarredProjectChangesHitLimit = false; } } ``` ### Step 5: Add Callback Handlers Add these callback handlers that match your existing error handling patterns: ```typescript // Callback handlers that match your existing error handling async handleStarredProjectsSuccess(data: { data: Array; hitLimit: boolean }) { // Same handling as your existing code this.numNewStarredProjectChanges = data.data.length; this.newStarredProjectChangesHitLimit = data.hitLimit; // Update UI (your existing method) this.updateStarredProjectsUI(data); } async handleStarredProjectsError(error: Error) { // Same error handling as your existing code console.warn('[HomeView] Failed to load starred project changes:', error); this.numNewStarredProjectChanges = 0; this.newStarredProjectChangesHitLimit = false; } ``` ### Step 6: Initialize in Your Component Add the setup to your existing TimeSafari PWA component: ```typescript // In your existing TimeSafari PWA component (e.g., HomeView.vue) export default defineComponent({ name: 'HomeView', data() { return { // Your existing data activeDid: '', starredPlanHandleIds: [] as string[], lastAckedStarredPlanChangesJwtId: '', numNewStarredProjectChanges: 0, newStarredProjectChangesHitLimit: false, // Plugin integration integrationService: null as TimeSafariIntegrationService | null }; }, async mounted() { // Setup DailyNotification when component mounts await this.setupDailyNotification(); }, methods: { // Add the setupDailyNotification method from Step 3 async setupDailyNotification() { /* ... */ }, // Replace your existing loadNewStarredProjectChanges with Step 4 version async loadNewStarredProjectChanges() { /* ... */ }, // Add callback handlers from Step 5 async handleStarredProjectsSuccess(data) { /* ... */ }, async handleStarredProjectsError(error) { /* ... */ }, // Your existing methods (unchanged) updateStarredProjectsUI(data) { /* ... */ }, getTimeSafariStorageAdapter() { /* ... */ } } }); ``` ## Complete Example Here's a complete example showing how to integrate the plugin into your existing TimeSafari PWA: ```typescript // Complete integration example import { DailyNotification } from '@timesafari/daily-notification-plugin'; import { TimeSafariIntegrationService } from '@timesafari/daily-notification-plugin'; class TimeSafariHomeView { // Your existing properties activeDid: string = ''; starredPlanHandleIds: string[] = []; lastAckedStarredPlanChangesJwtId: string = ''; numNewStarredProjectChanges: number = 0; newStarredProjectChangesHitLimit: boolean = false; apiServer: string = 'https://endorser.ch'; axios: AxiosInstance; // Plugin integration private integrationService: TimeSafariIntegrationService | null = null; constructor(axiosInstance: AxiosInstance) { this.axios = axiosInstance; } async setupDailyNotification() { await DailyNotification.configure({ timesafariConfig: { activeDid: this.activeDid, endpoints: { projectsLastUpdated: `${this.apiServer}/api/v2/report/plansLastUpdatedBetween` }, starredProjectsConfig: { enabled: true, starredPlanHandleIds: this.starredPlanHandleIds, lastAckedJwtId: this.lastAckedStarredPlanChangesJwtId, fetchInterval: '0 8 * * *' } }, networkConfig: { httpClient: this.axios, baseURL: this.apiServer, timeout: 30000 }, contentFetch: { enabled: true, schedule: '0 8 * * *', callbacks: { onSuccess: this.handleStarredProjectsSuccess.bind(this), onError: this.handleStarredProjectsError.bind(this) } } }); this.integrationService = TimeSafariIntegrationService.getInstance(); await this.integrationService.initialize({ activeDid: this.activeDid, storageAdapter: this.getTimeSafariStorageAdapter(), endorserApiBaseUrl: this.apiServer }); } async loadNewStarredProjectChanges() { if (this.activeDid && this.starredPlanHandleIds.length > 0) { try { const starredProjectChanges = await this.integrationService!.getStarredProjectsWithChanges( this.activeDid, this.starredPlanHandleIds, this.lastAckedStarredPlanChangesJwtId ); this.numNewStarredProjectChanges = starredProjectChanges.data.length; this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit; } catch (error) { console.warn('[HomeView] Failed to load starred project changes:', error); this.numNewStarredProjectChanges = 0; this.newStarredProjectChangesHitLimit = false; } } else { this.numNewStarredProjectChanges = 0; this.newStarredProjectChangesHitLimit = false; } } async handleStarredProjectsSuccess(data: { data: Array; hitLimit: boolean }) { this.numNewStarredProjectChanges = data.data.length; this.newStarredProjectChangesHitLimit = data.hitLimit; this.updateStarredProjectsUI(data); } async handleStarredProjectsError(error: Error) { console.warn('[HomeView] Failed to load starred project changes:', error); this.numNewStarredProjectChanges = 0; this.newStarredProjectChangesHitLimit = false; } // Your existing methods (unchanged) private updateStarredProjectsUI(data: { data: Array; hitLimit: boolean }) { // Your existing UI update logic } private getTimeSafariStorageAdapter() { // Your existing storage adapter return {}; } } ``` ## What You Get After following this setup, you'll have: ✅ **Same Interface**: Your existing `loadNewStarredProjectChanges()` method works exactly the same ✅ **Enhanced Features**: Background fetching, structured logging, metrics ✅ **Better Error Handling**: Enhanced error handling with retry logic ✅ **Performance Improvements**: Caching, batching, and optimization ✅ **Observability**: Structured logging with event IDs and metrics ✅ **Background Notifications**: Daily notifications with your starred projects data ## Testing Test the integration by calling your existing method: ```typescript // Test the enhanced method await homeView.loadNewStarredProjectChanges(); // Check the results (same as before) console.log('New starred project changes:', homeView.numNewStarredProjectChanges); console.log('Hit limit:', homeView.newStarredProjectChangesHitLimit); ``` ## Troubleshooting ### Common Issues 1. **Plugin not found**: Make sure you've installed the plugin correctly 2. **Configuration errors**: Check that all required fields are provided 3. **Network errors**: Verify your axios instance and API server URL 4. **Authentication errors**: Check your JWT token and activeDid ### Debug Mode Enable debug logging to troubleshoot issues: ```typescript await DailyNotification.configure({ logging: { level: 'DEBUG', enableRequestLogging: true, enableResponseLogging: true, enableErrorLogging: true } }); ``` ## Next Steps 1. **Test the integration** with your existing TimeSafari PWA code 2. **Compare results** between your existing method and the plugin-enhanced version 3. **Gradually migrate** other request methods to use the plugin 4. **Leverage advanced features** like background fetching and observability --- **That's it!** Your TimeSafari PWA now has enhanced daily notification capabilities while maintaining the same interface and behavior you're already familiar with.