docs: add DailyNotification setup guide and practical example
- 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.
This commit is contained in:
387
docs/daily-notification-setup-guide.md
Normal file
387
docs/daily-notification-setup-guide.md
Normal file
@@ -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.
|
||||||
466
examples/daily-notification-timesafari-setup.ts
Normal file
466
examples/daily-notification-timesafari-setup.ts
Normal file
@@ -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 };
|
||||||
Reference in New Issue
Block a user