You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
465 lines
15 KiB
465 lines
15 KiB
/**
|
|
* 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 = '';
|
|
starredPlanHandleIds: string[] = [];
|
|
lastAckedStarredPlanChangesJwtId = '';
|
|
numNewStarredProjectChanges = 0;
|
|
newStarredProjectChangesHitLimit = false;
|
|
apiServer = '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 {
|
|
// Setup 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'
|
|
});
|
|
|
|
// 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
|
|
);
|
|
|
|
if (!starredProjectChanges) {
|
|
this.numNewStarredProjectChanges = 0;
|
|
this.newStarredProjectChangesHitLimit = false;
|
|
return;
|
|
}
|
|
|
|
// Same handling as your existing code
|
|
this.numNewStarredProjectChanges = starredProjectChanges.data.length;
|
|
this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
|
|
|
|
// Enhanced logging (optional)
|
|
// Starred projects loaded successfully
|
|
|
|
} 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)
|
|
// Starred projects success callback
|
|
}
|
|
|
|
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
|
|
// Starred projects fetch completed
|
|
}
|
|
|
|
/**
|
|
* Your existing methods (unchanged)
|
|
*/
|
|
private updateStarredProjectsUI(_data: StarredProjectsResponse): void {
|
|
// Your existing UI update logic
|
|
// Updating UI with starred projects 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 = 'https://endorser.ch'
|
|
): Promise<TimeSafariHomeView> {
|
|
|
|
// 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();
|
|
|
|
// DailyNotification setup completed successfully
|
|
|
|
return homeView;
|
|
}
|
|
|
|
// Vue.js component integration example
|
|
export const TimeSafariDailyNotificationMixin = {
|
|
data(): Record<string, unknown> {
|
|
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(): Promise<void> {
|
|
// Setup DailyNotification when component mounts
|
|
await this.setupDailyNotification();
|
|
},
|
|
|
|
methods: {
|
|
async setupDailyNotification(): Promise<void> {
|
|
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(): Promise<void> {
|
|
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): void {
|
|
this.numNewStarredProjectChanges = data.data.length;
|
|
this.newStarredProjectChangesHitLimit = data.hitLimit;
|
|
this.updateStarredProjectsUI(data);
|
|
},
|
|
|
|
handleStarredProjectsError(error: Error): void {
|
|
console.warn('[HomeView] Failed to load starred project changes:', error);
|
|
this.numNewStarredProjectChanges = 0;
|
|
this.newStarredProjectChangesHitLimit = false;
|
|
},
|
|
|
|
// Your existing methods
|
|
updateStarredProjectsUI(_data: StarredProjectsResponse): void {
|
|
// Your existing UI update logic
|
|
},
|
|
|
|
getTimeSafariStorageAdapter(): unknown {
|
|
// Your existing storage adapter
|
|
return {};
|
|
}
|
|
}
|
|
};
|
|
|
|
// Export for use in your TimeSafari PWA
|
|
export { TimeSafariHomeView };
|
|
|