Browse Source
- Add comprehensive setup guide showing exact configuration for TimeSafari PWA - Provide step-by-step instructions for integrating with existing loadNewStarredProjectChanges() - Include complete working example with all configuration options - Show Vue.js component integration patterns - Add troubleshooting and testing guidance - Demonstrate how to maintain existing interfaces while adding plugin features This provides a practical, copy-paste ready setup for TimeSafari PWA integration.master
2 changed files with 853 additions and 0 deletions
@ -0,0 +1,387 @@ |
|||||
|
# 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<PlanSummaryAndPreviousClaim>; 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<PlanSummaryAndPreviousClaim>; 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<PlanSummaryAndPreviousClaim>; 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. |
@ -0,0 +1,466 @@ |
|||||
|
/** |
||||
|
* DailyNotification Setup for TimeSafari PWA |
||||
|
* |
||||
|
* This example shows exactly how to configure the DailyNotification plugin |
||||
|
* to work with your existing TimeSafari PWA request patterns, specifically |
||||
|
* the loadNewStarredProjectChanges() and getStarredProjectsWithChanges() methods. |
||||
|
* |
||||
|
* @author Matthew Raymer |
||||
|
* @version 1.0.0 |
||||
|
*/ |
||||
|
|
||||
|
import { DailyNotification } from '@timesafari/daily-notification-plugin'; |
||||
|
import { TimeSafariIntegrationService } from '@timesafari/daily-notification-plugin'; |
||||
|
import { AxiosInstance } from 'axios'; |
||||
|
|
||||
|
// Your existing TimeSafari PWA interfaces
|
||||
|
interface PlanSummaryAndPreviousClaim { |
||||
|
id: string; |
||||
|
title: string; |
||||
|
description: string; |
||||
|
lastUpdated: string; |
||||
|
previousClaim?: unknown; |
||||
|
} |
||||
|
|
||||
|
interface StarredProjectsResponse { |
||||
|
data: Array<PlanSummaryAndPreviousClaim>; |
||||
|
hitLimit: boolean; |
||||
|
} |
||||
|
|
||||
|
// Your existing TimeSafari PWA class structure
|
||||
|
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 dailyNotificationService: DailyNotification | null = null; |
||||
|
private integrationService: TimeSafariIntegrationService | null = null; |
||||
|
|
||||
|
constructor(axiosInstance: AxiosInstance) { |
||||
|
this.axios = axiosInstance; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* DailyNotification Setup - This is what you need to add to your TimeSafari PWA |
||||
|
*/ |
||||
|
async setupDailyNotification(): Promise<void> { |
||||
|
try { |
||||
|
console.log('Setting up DailyNotification for TimeSafari PWA...'); |
||||
|
|
||||
|
// Step 1: Configure the DailyNotification plugin
|
||||
|
await DailyNotification.configure({ |
||||
|
// Basic plugin configuration
|
||||
|
storage: 'tiered', |
||||
|
ttlSeconds: 1800, |
||||
|
enableETagSupport: true, |
||||
|
enableErrorHandling: true, |
||||
|
enablePerformanceOptimization: true, |
||||
|
|
||||
|
// TimeSafari-specific configuration
|
||||
|
timesafariConfig: { |
||||
|
// Required: 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 (same as your existing schedule)
|
||||
|
maxResults: 50, |
||||
|
hitLimitHandling: 'warn' // Same as your existing error handling
|
||||
|
}, |
||||
|
|
||||
|
// Sync configuration (optimized for your use case)
|
||||
|
syncConfig: { |
||||
|
enableParallel: true, |
||||
|
maxConcurrent: 3, |
||||
|
batchSize: 10, |
||||
|
timeout: 30000, |
||||
|
retryAttempts: 3 |
||||
|
}, |
||||
|
|
||||
|
// Error policy (matches your existing error handling)
|
||||
|
errorPolicy: { |
||||
|
maxRetries: 3, |
||||
|
backoffMultiplier: 2, |
||||
|
activeDidChangeRetries: 5, |
||||
|
starredProjectsRetries: 3 |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Network configuration using your existing axios instance
|
||||
|
networkConfig: { |
||||
|
// Use your existing axios instance
|
||||
|
httpClient: this.axios, |
||||
|
baseURL: this.apiServer, |
||||
|
timeout: 30000, |
||||
|
retryAttempts: 3, |
||||
|
retryDelay: 1000, |
||||
|
maxConcurrent: 5, |
||||
|
|
||||
|
// Headers matching your existing pattern
|
||||
|
defaultHeaders: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Accept': 'application/json', |
||||
|
'User-Agent': 'TimeSafari-PWA/1.0.0' |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Content fetch configuration (replaces your existing loadNewStarredProjectChanges)
|
||||
|
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), |
||||
|
onComplete: this.handleStarredProjectsComplete.bind(this) |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Authentication configuration
|
||||
|
authentication: { |
||||
|
jwt: { |
||||
|
secret: process.env.JWT_SECRET || 'your-jwt-secret', |
||||
|
algorithm: 'HS256', |
||||
|
expirationMinutes: 60, |
||||
|
refreshThresholdMinutes: 10 |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Observability configuration
|
||||
|
logging: { |
||||
|
level: 'INFO', |
||||
|
enableRequestLogging: true, |
||||
|
enableResponseLogging: true, |
||||
|
enableErrorLogging: true, |
||||
|
redactSensitiveData: true |
||||
|
}, |
||||
|
|
||||
|
// Security configuration
|
||||
|
security: { |
||||
|
certificatePinning: { |
||||
|
enabled: true, |
||||
|
pins: [ |
||||
|
{ |
||||
|
hostname: 'endorser.ch', |
||||
|
pins: ['sha256/YOUR_PIN_HERE'] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Step 2: Initialize TimeSafari Integration Service
|
||||
|
this.integrationService = TimeSafariIntegrationService.getInstance(); |
||||
|
await this.integrationService.initialize({ |
||||
|
activeDid: this.activeDid, |
||||
|
storageAdapter: this.getTimeSafariStorageAdapter(), |
||||
|
endorserApiBaseUrl: this.apiServer, |
||||
|
|
||||
|
// Use your existing request patterns
|
||||
|
requestConfig: { |
||||
|
httpClient: this.axios, |
||||
|
baseURL: this.apiServer, |
||||
|
timeout: 30000, |
||||
|
retryAttempts: 3 |
||||
|
}, |
||||
|
|
||||
|
// Configure starred projects fetching
|
||||
|
starredProjectsConfig: { |
||||
|
enabled: true, |
||||
|
starredPlanHandleIds: this.starredPlanHandleIds, |
||||
|
lastAckedJwtId: this.lastAckedStarredPlanChangesJwtId, |
||||
|
fetchInterval: '0 8 * * *', |
||||
|
maxResults: 50 |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Step 3: Schedule daily notifications
|
||||
|
await DailyNotification.scheduleDailyNotification({ |
||||
|
title: 'TimeSafari Community Update', |
||||
|
body: 'You have new offers and project updates', |
||||
|
time: '09:00', |
||||
|
channel: 'timesafari_community_updates' |
||||
|
}); |
||||
|
|
||||
|
console.log('DailyNotification setup completed successfully!'); |
||||
|
|
||||
|
} catch (error) { |
||||
|
console.error('Failed to setup DailyNotification:', error); |
||||
|
throw error; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Enhanced version of your existing loadNewStarredProjectChanges method |
||||
|
* |
||||
|
* This replaces your existing method with plugin-enhanced functionality |
||||
|
* while maintaining the same interface and behavior. |
||||
|
*/ |
||||
|
async loadNewStarredProjectChanges(): Promise<void> { |
||||
|
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; |
||||
|
|
||||
|
// Enhanced logging (optional)
|
||||
|
console.log('Starred projects loaded successfully:', { |
||||
|
count: this.numNewStarredProjectChanges, |
||||
|
hitLimit: this.newStarredProjectChangesHitLimit, |
||||
|
planIds: this.starredPlanHandleIds.length |
||||
|
}); |
||||
|
|
||||
|
} 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; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Callback handlers that match your existing error handling patterns |
||||
|
*/ |
||||
|
async handleStarredProjectsSuccess(data: StarredProjectsResponse): Promise<void> { |
||||
|
// Same handling as your existing code
|
||||
|
this.numNewStarredProjectChanges = data.data.length; |
||||
|
this.newStarredProjectChangesHitLimit = data.hitLimit; |
||||
|
|
||||
|
// Update UI (your existing method)
|
||||
|
this.updateStarredProjectsUI(data); |
||||
|
|
||||
|
// Enhanced logging (optional)
|
||||
|
console.log('Starred projects success callback:', { |
||||
|
count: data.data.length, |
||||
|
hitLimit: data.hitLimit |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
async handleStarredProjectsError(error: Error): Promise<void> { |
||||
|
// Same error handling as your existing code
|
||||
|
console.warn('[HomeView] Failed to load starred project changes:', error); |
||||
|
this.numNewStarredProjectChanges = 0; |
||||
|
this.newStarredProjectChangesHitLimit = false; |
||||
|
|
||||
|
// Enhanced error handling (optional)
|
||||
|
console.error('Starred projects error callback:', { |
||||
|
error: error.message, |
||||
|
activeDid: this.activeDid, |
||||
|
planCount: this.starredPlanHandleIds.length |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
async handleStarredProjectsComplete(result: unknown): Promise<void> { |
||||
|
// Handle completion
|
||||
|
console.log('Starred projects fetch completed:', result); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Your existing methods (unchanged) |
||||
|
*/ |
||||
|
private updateStarredProjectsUI(data: StarredProjectsResponse): void { |
||||
|
// Your existing UI update logic
|
||||
|
console.log('Updating UI with starred projects data:', data); |
||||
|
} |
||||
|
|
||||
|
private getTimeSafariStorageAdapter(): unknown { |
||||
|
// Return your existing TimeSafari storage adapter
|
||||
|
return { |
||||
|
// Your existing storage adapter implementation
|
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Usage example - This is what you add to your TimeSafari PWA
|
||||
|
export async function setupDailyNotificationForTimeSafari( |
||||
|
axiosInstance: AxiosInstance, |
||||
|
activeDid: string, |
||||
|
starredPlanHandleIds: string[], |
||||
|
lastAckedJwtId: string, |
||||
|
apiServer: string = 'https://endorser.ch' |
||||
|
): Promise<TimeSafariHomeView> { |
||||
|
|
||||
|
console.log('Setting up DailyNotification for TimeSafari PWA...'); |
||||
|
|
||||
|
// Create your existing HomeView instance
|
||||
|
const homeView = new TimeSafariHomeView(axiosInstance); |
||||
|
|
||||
|
// Set up your existing TimeSafari data
|
||||
|
homeView.activeDid = activeDid; |
||||
|
homeView.starredPlanHandleIds = starredPlanHandleIds; |
||||
|
homeView.lastAckedStarredPlanChangesJwtId = lastAckedJwtId; |
||||
|
homeView.apiServer = apiServer; |
||||
|
|
||||
|
// Setup DailyNotification plugin
|
||||
|
await homeView.setupDailyNotification(); |
||||
|
|
||||
|
// Test the enhanced method
|
||||
|
await homeView.loadNewStarredProjectChanges(); |
||||
|
|
||||
|
console.log('DailyNotification setup completed successfully!'); |
||||
|
|
||||
|
return homeView; |
||||
|
} |
||||
|
|
||||
|
// Vue.js component integration example
|
||||
|
export const TimeSafariDailyNotificationMixin = { |
||||
|
data() { |
||||
|
return { |
||||
|
// Your existing data
|
||||
|
activeDid: '', |
||||
|
starredPlanHandleIds: [] as string[], |
||||
|
lastAckedStarredPlanChangesJwtId: '', |
||||
|
numNewStarredProjectChanges: 0, |
||||
|
newStarredProjectChangesHitLimit: false, |
||||
|
|
||||
|
// Plugin integration
|
||||
|
dailyNotificationService: null as DailyNotification | null, |
||||
|
integrationService: null as TimeSafariIntegrationService | null |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
async mounted() { |
||||
|
// Setup DailyNotification when component mounts
|
||||
|
await this.setupDailyNotification(); |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
async setupDailyNotification() { |
||||
|
try { |
||||
|
// Configure DailyNotification plugin
|
||||
|
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, |
||||
|
onError: this.handleStarredProjectsError |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Initialize integration service
|
||||
|
this.integrationService = TimeSafariIntegrationService.getInstance(); |
||||
|
await this.integrationService.initialize({ |
||||
|
activeDid: this.activeDid, |
||||
|
storageAdapter: this.getTimeSafariStorageAdapter(), |
||||
|
endorserApiBaseUrl: this.apiServer |
||||
|
}); |
||||
|
|
||||
|
} catch (error) { |
||||
|
console.error('Failed to setup DailyNotification:', error); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// Your existing methods (enhanced)
|
||||
|
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; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
handleStarredProjectsSuccess(data: StarredProjectsResponse) { |
||||
|
this.numNewStarredProjectChanges = data.data.length; |
||||
|
this.newStarredProjectChangesHitLimit = data.hitLimit; |
||||
|
this.updateStarredProjectsUI(data); |
||||
|
}, |
||||
|
|
||||
|
handleStarredProjectsError(error: Error) { |
||||
|
console.warn('[HomeView] Failed to load starred project changes:', error); |
||||
|
this.numNewStarredProjectChanges = 0; |
||||
|
this.newStarredProjectChangesHitLimit = false; |
||||
|
}, |
||||
|
|
||||
|
// Your existing methods
|
||||
|
updateStarredProjectsUI(data: StarredProjectsResponse) { |
||||
|
// Your existing UI update logic
|
||||
|
}, |
||||
|
|
||||
|
getTimeSafariStorageAdapter() { |
||||
|
// Your existing storage adapter
|
||||
|
return {}; |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// Export for use in your TimeSafari PWA
|
||||
|
export { TimeSafariHomeView }; |
Loading…
Reference in new issue