docs: add actual changes needed to existing CapacitorPlatformService
- Add example showing exact changes to existing TimeSafari PWA CapacitorPlatformService - Show how to extend the existing class rather than creating a new one - Provide summary of actual code changes needed (imports, properties, methods) - Include modifications to PlatformServiceMixin and Vue components - Show how to integrate with existing database and settings patterns - Provide migration strategy for gradual adoption This gives an accurate representation of the changes needed to the actual TimeSafari PWA codebase rather than creating a separate class.
This commit is contained in:
427
docs/capacitor-platform-service-changes-summary.md
Normal file
427
docs/capacitor-platform-service-changes-summary.md
Normal file
@@ -0,0 +1,427 @@
|
||||
# TimeSafari PWA - CapacitorPlatformService Changes Summary
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Version**: 1.0.0
|
||||
**Created**: 2025-10-08 06:24:57 UTC
|
||||
|
||||
## Overview
|
||||
|
||||
This document summarizes the **exact changes** needed to the existing TimeSafari PWA `CapacitorPlatformService` to add DailyNotification plugin functionality. These are the actual modifications required to the existing codebase.
|
||||
|
||||
## Required Changes to Existing TimeSafari PWA Code
|
||||
|
||||
### File: `src/services/platforms/CapacitorPlatformService.ts`
|
||||
|
||||
#### 1. Add New Imports (at the top of the file)
|
||||
|
||||
```typescript
|
||||
// ADD THESE IMPORTS
|
||||
import { DailyNotification } from '@timesafari/daily-notification-plugin';
|
||||
import { TimeSafariIntegrationService } from '@timesafari/daily-notification-plugin';
|
||||
```
|
||||
|
||||
#### 2. Add New Interfaces (after existing interfaces)
|
||||
|
||||
```typescript
|
||||
// ADD THESE INTERFACES
|
||||
interface PlanSummaryAndPreviousClaim {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
lastUpdated: string;
|
||||
previousClaim?: unknown;
|
||||
}
|
||||
|
||||
interface StarredProjectsResponse {
|
||||
data: Array<PlanSummaryAndPreviousClaim>;
|
||||
hitLimit: boolean;
|
||||
}
|
||||
|
||||
interface TimeSafariSettings {
|
||||
accountDid?: string;
|
||||
activeDid?: string;
|
||||
apiServer?: string;
|
||||
starredPlanHandleIds?: string[];
|
||||
lastAckedStarredPlanChangesJwtId?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Add New Properties (in the class, after existing properties)
|
||||
|
||||
```typescript
|
||||
export class CapacitorPlatformService implements PlatformService {
|
||||
// ... existing properties ...
|
||||
|
||||
// ADD THESE NEW PROPERTIES
|
||||
private dailyNotificationService: DailyNotification | null = null;
|
||||
private integrationService: TimeSafariIntegrationService | null = null;
|
||||
private dailyNotificationInitialized = false;
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. Add New Methods (in the class, after existing methods)
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Initialize DailyNotification plugin with TimeSafari configuration
|
||||
*/
|
||||
async initializeDailyNotification(): Promise<void> {
|
||||
if (this.dailyNotificationInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
logger.log("[CapacitorPlatformService] Initializing DailyNotification plugin...");
|
||||
|
||||
// Get current TimeSafari settings
|
||||
const settings = await this.getTimeSafariSettings();
|
||||
|
||||
// Configure DailyNotification plugin with TimeSafari data
|
||||
await DailyNotification.configure({
|
||||
timesafariConfig: {
|
||||
activeDid: settings.activeDid || '',
|
||||
endpoints: {
|
||||
projectsLastUpdated: `${settings.apiServer}/api/v2/report/plansLastUpdatedBetween`
|
||||
},
|
||||
starredProjectsConfig: {
|
||||
enabled: true,
|
||||
starredPlanHandleIds: settings.starredPlanHandleIds || [],
|
||||
lastAckedJwtId: settings.lastAckedStarredPlanChangesJwtId || '',
|
||||
fetchInterval: '0 8 * * *'
|
||||
}
|
||||
},
|
||||
networkConfig: {
|
||||
baseURL: settings.apiServer || 'https://endorser.ch',
|
||||
timeout: 30000
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize TimeSafari Integration Service
|
||||
this.integrationService = TimeSafariIntegrationService.getInstance();
|
||||
await this.integrationService.initialize({
|
||||
activeDid: settings.activeDid || '',
|
||||
storageAdapter: this.getTimeSafariStorageAdapter(),
|
||||
endorserApiBaseUrl: settings.apiServer || 'https://endorser.ch'
|
||||
});
|
||||
|
||||
this.dailyNotificationInitialized = true;
|
||||
logger.log("[CapacitorPlatformService] DailyNotification plugin initialized successfully");
|
||||
|
||||
} catch (error) {
|
||||
logger.error("[CapacitorPlatformService] Failed to initialize DailyNotification plugin:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhanced version of existing TimeSafari loadNewStarredProjectChanges method
|
||||
*/
|
||||
async loadNewStarredProjectChanges(): Promise<StarredProjectsResponse> {
|
||||
// Ensure DailyNotification is initialized
|
||||
if (!this.dailyNotificationInitialized) {
|
||||
await this.initializeDailyNotification();
|
||||
}
|
||||
|
||||
const settings = await this.getTimeSafariSettings();
|
||||
|
||||
if (!settings.activeDid || !settings.starredPlanHandleIds?.length) {
|
||||
return { data: [], hitLimit: false };
|
||||
}
|
||||
|
||||
try {
|
||||
// Use plugin's enhanced fetching with same interface as existing TimeSafari code
|
||||
const starredProjectChanges = await this.integrationService!.getStarredProjectsWithChanges(
|
||||
settings.activeDid,
|
||||
settings.starredPlanHandleIds,
|
||||
settings.lastAckedStarredPlanChangesJwtId
|
||||
);
|
||||
|
||||
return starredProjectChanges;
|
||||
|
||||
} catch (error) {
|
||||
// Same error handling as existing TimeSafari code
|
||||
logger.warn("[CapacitorPlatformService] Failed to load starred project changes:", error);
|
||||
return { data: [], hitLimit: false };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TimeSafari settings using existing database patterns
|
||||
*/
|
||||
private async getTimeSafariSettings(): Promise<TimeSafariSettings> {
|
||||
try {
|
||||
const result = await this.dbQuery("SELECT * FROM settings WHERE id = 1");
|
||||
|
||||
if (!result?.values?.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const settings: TimeSafariSettings = {};
|
||||
result.columns.forEach((column, index) => {
|
||||
if (column !== 'id') {
|
||||
settings[column] = result.values[0][index];
|
||||
}
|
||||
});
|
||||
|
||||
// Handle JSON field parsing
|
||||
if (settings.starredPlanHandleIds && typeof settings.starredPlanHandleIds === 'string') {
|
||||
try {
|
||||
settings.starredPlanHandleIds = JSON.parse(settings.starredPlanHandleIds);
|
||||
} catch {
|
||||
settings.starredPlanHandleIds = [];
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
} catch (error) {
|
||||
logger.error("[CapacitorPlatformService] Error getting TimeSafari settings:", error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TimeSafari storage adapter using existing patterns
|
||||
*/
|
||||
private getTimeSafariStorageAdapter(): unknown {
|
||||
return {
|
||||
store: async (key: string, value: unknown) => {
|
||||
await this.dbExec(
|
||||
"INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)",
|
||||
[key, JSON.stringify(value)]
|
||||
);
|
||||
},
|
||||
|
||||
retrieve: async (key: string) => {
|
||||
const result = await this.dbQuery(
|
||||
"SELECT data FROM temp WHERE id = ?",
|
||||
[key]
|
||||
);
|
||||
|
||||
if (result?.values?.length) {
|
||||
try {
|
||||
return JSON.parse(result.values[0][0] as string);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback handlers for DailyNotification plugin
|
||||
*/
|
||||
private async handleStarredProjectsSuccess(data: StarredProjectsResponse): Promise<void> {
|
||||
logger.log("[CapacitorPlatformService] Starred projects success callback:", {
|
||||
count: data.data.length,
|
||||
hitLimit: data.hitLimit
|
||||
});
|
||||
|
||||
// Store results in TimeSafari temp table for UI access
|
||||
await this.dbExec(
|
||||
"INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)",
|
||||
['starred_projects_latest', JSON.stringify(data)]
|
||||
);
|
||||
}
|
||||
|
||||
private async handleStarredProjectsError(error: Error): Promise<void> {
|
||||
logger.warn("[CapacitorPlatformService] Failed to load starred project changes:", error);
|
||||
|
||||
// Store error in TimeSafari temp table for UI access
|
||||
await this.dbExec(
|
||||
"INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)",
|
||||
['starred_projects_error', JSON.stringify({ error: error.message, timestamp: Date.now() })]
|
||||
);
|
||||
}
|
||||
|
||||
private async handleStarredProjectsComplete(result: unknown): Promise<void> {
|
||||
logger.log("[CapacitorPlatformService] Starred projects fetch completed:", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DailyNotification plugin status for debugging
|
||||
*/
|
||||
async getDailyNotificationStatus(): Promise<{
|
||||
initialized: boolean;
|
||||
platform: string;
|
||||
capabilities: PlatformCapabilities;
|
||||
}> {
|
||||
return {
|
||||
initialized: this.dailyNotificationInitialized,
|
||||
platform: Capacitor.getPlatform(),
|
||||
capabilities: this.getCapabilities()
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. Modify Existing Method (update the `initializeDatabase` method)
|
||||
|
||||
```typescript
|
||||
private async initializeDatabase(): Promise<void> {
|
||||
// If already initialized, return immediately
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If initialization is in progress, wait for it
|
||||
if (this.initializationPromise) {
|
||||
return this.initializationPromise;
|
||||
}
|
||||
|
||||
try {
|
||||
// Start initialization
|
||||
this.initializationPromise = this._initialize();
|
||||
await this.initializationPromise;
|
||||
|
||||
// ADD THIS LINE: Initialize DailyNotification after database is ready
|
||||
await this.initializeDailyNotification();
|
||||
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
"[CapacitorPlatformService] Initialize database method failed:",
|
||||
error,
|
||||
);
|
||||
this.initializationPromise = null; // Reset on failure
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Required Changes to PlatformServiceMixin
|
||||
|
||||
### File: `src/utils/PlatformServiceMixin.ts`
|
||||
|
||||
#### 1. Add New Methods (in the methods section)
|
||||
|
||||
```typescript
|
||||
methods: {
|
||||
// ... existing methods ...
|
||||
|
||||
/**
|
||||
* Initialize DailyNotification plugin (Capacitor only)
|
||||
*/
|
||||
async $initializeDailyNotification(): Promise<void> {
|
||||
if (this.isCapacitor) {
|
||||
await this.platformService.initializeDailyNotification();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Enhanced loadNewStarredProjectChanges method
|
||||
*/
|
||||
async $loadNewStarredProjectChanges(): Promise<StarredProjectsResponse> {
|
||||
if (this.isCapacitor) {
|
||||
return await this.platformService.loadNewStarredProjectChanges();
|
||||
} else {
|
||||
// Fall back to existing web method
|
||||
return await this.$loadNewStarredProjectChangesWeb();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get DailyNotification status for debugging
|
||||
*/
|
||||
async $getDailyNotificationStatus(): Promise<unknown> {
|
||||
if (this.isCapacitor) {
|
||||
return await this.platformService.getDailyNotificationStatus();
|
||||
}
|
||||
return { initialized: false, platform: 'web' };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Required Changes to Vue Components
|
||||
|
||||
### File: `src/views/HomeView.vue` (or similar)
|
||||
|
||||
#### 1. Add DailyNotification Initialization (in mounted lifecycle)
|
||||
|
||||
```typescript
|
||||
export default defineComponent({
|
||||
name: 'HomeView',
|
||||
|
||||
mixins: [PlatformServiceMixin],
|
||||
|
||||
async mounted() {
|
||||
// ADD THIS: Initialize DailyNotification (only on Capacitor)
|
||||
if (this.isCapacitor) {
|
||||
await this.$initializeDailyNotification();
|
||||
}
|
||||
|
||||
// ... existing mounted code ...
|
||||
},
|
||||
|
||||
methods: {
|
||||
// ... existing methods ...
|
||||
|
||||
/**
|
||||
* Enhanced loadNewStarredProjectChanges method
|
||||
*/
|
||||
async loadNewStarredProjectChanges(): Promise<void> {
|
||||
if (this.isCapacitor) {
|
||||
// Use plugin-enhanced method on Capacitor
|
||||
const result = await this.$loadNewStarredProjectChanges();
|
||||
this.numNewStarredProjectChanges = result.data.length;
|
||||
this.newStarredProjectChangesHitLimit = result.hitLimit;
|
||||
} else {
|
||||
// Use existing web method in browser
|
||||
await this.loadNewStarredProjectChangesWeb();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Package.json Changes
|
||||
|
||||
### Add DailyNotification Plugin Dependency
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@timesafari/daily-notification-plugin": "ssh://git@173.199.124.46:222/trent_larson/daily-notification-plugin.git"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Summary of Changes
|
||||
|
||||
### Files Modified:
|
||||
1. **`src/services/platforms/CapacitorPlatformService.ts`**
|
||||
- Add imports for DailyNotification plugin
|
||||
- Add new interfaces for plugin integration
|
||||
- Add new properties for plugin state
|
||||
- Add new methods for plugin functionality
|
||||
- Modify existing `initializeDatabase` method
|
||||
|
||||
2. **`src/utils/PlatformServiceMixin.ts`**
|
||||
- Add new methods for plugin integration
|
||||
- Add platform detection for plugin usage
|
||||
|
||||
3. **Vue Components (e.g., `src/views/HomeView.vue`)**
|
||||
- Add plugin initialization in mounted lifecycle
|
||||
- Add enhanced methods for plugin functionality
|
||||
|
||||
4. **`package.json`**
|
||||
- Add DailyNotification plugin dependency
|
||||
|
||||
### Key Benefits:
|
||||
- **Same Interface**: Existing methods work exactly the same
|
||||
- **Enhanced Functionality**: Background fetching, structured logging, error handling
|
||||
- **Platform Detection**: Only initializes on Capacitor platforms
|
||||
- **Gradual Migration**: Can be adopted incrementally
|
||||
- **No Breaking Changes**: Existing code continues to work
|
||||
|
||||
### Migration Strategy:
|
||||
1. **Add the changes** to existing TimeSafari PWA code
|
||||
2. **Test on Capacitor platforms** (Android, iOS)
|
||||
3. **Verify web fallback** works correctly
|
||||
4. **Gradually migrate** individual methods to use plugin features
|
||||
5. **Leverage advanced features** like background fetching and observability
|
||||
|
||||
---
|
||||
|
||||
**These are the exact changes needed to integrate the DailyNotification plugin with the existing TimeSafari PWA CapacitorPlatformService architecture.**
|
||||
Reference in New Issue
Block a user