diff --git a/test-apps/ios-test/src/index.html b/test-apps/ios-test/src/index.html
index 89585e2..e1dad73 100644
--- a/test-apps/ios-test/src/index.html
+++ b/test-apps/ios-test/src/index.html
@@ -392,6 +392,17 @@
+
+
+
🚀 Phase 4: TimeSafari Components
+
+
+
+
+
+
+
+
⚠️ Error Handling
diff --git a/test-apps/ios-test/src/index.ts b/test-apps/ios-test/src/index.ts
index f1beac3..93cfcb0 100644
--- a/test-apps/ios-test/src/index.ts
+++ b/test-apps/ios-test/src/index.ts
@@ -1,6 +1,17 @@
import { Capacitor } from '@capacitor/core';
import { ConfigLoader, MockDailyNotificationService, TestLogger } from '../shared/config-loader';
+// Phase 4: Import TimeSafari components
+import { EndorserAPIClient, TIMESAFARI_ENDSORER_CONFIG } from '../../../src/typescript/EndorserAPIClient';
+import { SecurityManager, TIMESAFARI_SECURITY_CONFIG } from '../../../src/typescript/SecurityManager';
+import { TimeSafariNotificationManager, DEFAULT_TIMESAFARI_PREFERENCES } from '../../../src/typescript/TimeSafariNotificationManager';
+import {
+ TimeSafariUser,
+ TimeSafariPreferences,
+ EnhancedTimeSafariNotification,
+ TimeSafariNotificationType
+} from '../../../src/definitions';
+
// Enhanced UI components for iOS testing
class PermissionManager {
private container: HTMLElement;
@@ -236,7 +247,7 @@ class ErrorDisplay {
}
}
-// Enhanced test interface for TimeSafari iOS integration
+// Enhanced test interface for TimeSafari iOS integration with Phase 4 components
class TimeSafariIOSTestApp {
private statusElement: HTMLElement;
private logElement: HTMLElement;
@@ -244,6 +255,11 @@ class TimeSafariIOSTestApp {
private notificationService: MockDailyNotificationService;
private logger: TestLogger;
+ // Phase 4: TimeSafari components
+ private endorserAPIClient: EndorserAPIClient;
+ private securityManager: SecurityManager;
+ private timeSafariNotificationManager: TimeSafariNotificationManager;
+
// UI Components
private permissionManager: PermissionManager;
private settingsPanel: SettingsPanel;
@@ -257,6 +273,11 @@ class TimeSafariIOSTestApp {
this.logger = new TestLogger('debug');
this.notificationService = new MockDailyNotificationService(this.configLoader.getConfig());
+ // Phase 4: Initialize TimeSafari components
+ this.endorserAPIClient = new EndorserAPIClient(this.configLoader.getEndorserAPIConfig());
+ this.securityManager = new SecurityManager(this.configLoader.getSecurityConfig());
+ this.timeSafariNotificationManager = new TimeSafariNotificationManager();
+
// Initialize UI components
this.permissionManager = new PermissionManager(
document.getElementById('permission-status-container')!,
@@ -268,7 +289,8 @@ class TimeSafariIOSTestApp {
this.setupEventListeners();
this.initializeUI();
- this.log('TimeSafari iOS Test app initialized with enhanced UI');
+ this.initializePhase4Components();
+ this.log('TimeSafari iOS Test app initialized with Phase 4 components');
}
private setupEventListeners() {
@@ -290,6 +312,12 @@ class TimeSafariIOSTestApp {
document.getElementById('refresh-status')?.addEventListener('click', () => this.refreshStatus());
document.getElementById('background-refresh-status')?.addEventListener('click', () => this.checkBackgroundRefresh());
document.getElementById('bg-task-status')?.addEventListener('click', () => this.checkBGTaskStatus());
+
+ // Phase 4: TimeSafari component testing
+ document.getElementById('test-security-manager')?.addEventListener('click', () => this.testSecurityManager());
+ document.getElementById('test-endorser-api-client')?.addEventListener('click', () => this.testEndorserAPIClient());
+ document.getElementById('test-notification-manager')?.addEventListener('click', () => this.testTimeSafariNotificationManager());
+ document.getElementById('test-phase4-integration')?.addEventListener('click', () => this.testPhase4Integration());
}
private async initializeUI(): Promise {
@@ -306,6 +334,49 @@ class TimeSafariIOSTestApp {
}
}
+ // Phase 4: Initialize TimeSafari components
+ private async initializePhase4Components(): Promise {
+ try {
+ this.log('Initializing Phase 4 TimeSafari components...');
+
+ // Initialize SecurityManager with test DID
+ const timeSafariUser = this.configLoader.getTimeSafariUser();
+ const securityInitialized = await this.securityManager.initialize(timeSafariUser.activeDid);
+
+ if (securityInitialized) {
+ this.log('✅ SecurityManager initialized successfully');
+
+ // Generate JWT token for API authentication
+ const jwt = await this.securityManager.generateJWT({
+ scope: 'notifications',
+ audience: 'endorser-api'
+ });
+
+ if (jwt) {
+ this.endorserAPIClient.setAuthToken(jwt);
+ this.log('✅ JWT token generated and set for EndorserAPI');
+ }
+ } else {
+ this.log('❌ SecurityManager initialization failed');
+ }
+
+ // Initialize TimeSafariNotificationManager
+ const managerInitialized = await this.timeSafariNotificationManager.initialize(timeSafariUser);
+
+ if (managerInitialized) {
+ this.log('✅ TimeSafariNotificationManager initialized successfully');
+ } else {
+ this.log('❌ TimeSafariNotificationManager initialization failed');
+ }
+
+ this.log('Phase 4 components initialization completed');
+
+ } catch (error) {
+ this.log('Error initializing Phase 4 components:', error);
+ this.errorDisplay.showError(error as Error);
+ }
+ }
+
// Enhanced UI methods
private async checkPermissions(): Promise {
try {
@@ -695,6 +766,200 @@ class TimeSafariIOSTestApp {
private updateStatus(status: string) {
this.statusElement.textContent = status;
}
+
+ // Phase 4: TimeSafari component test methods
+ private async testSecurityManager(): Promise {
+ try {
+ this.log('🔐 Testing SecurityManager (iOS)...');
+
+ const timeSafariUser = this.configLoader.getTimeSafariUser();
+
+ // Test JWT generation
+ const jwt = await this.securityManager.generateJWT({
+ scope: 'test',
+ audience: 'test-api'
+ });
+
+ if (jwt) {
+ this.log('✅ JWT generation successful');
+ this.log('JWT token:', jwt.substring(0, 50) + '...');
+
+ // Test JWT verification
+ const claims = await this.securityManager.verifyJWT(jwt);
+ if (claims) {
+ this.log('✅ JWT verification successful');
+ this.log('Claims:', claims);
+ } else {
+ this.log('❌ JWT verification failed');
+ }
+ } else {
+ this.log('❌ JWT generation failed');
+ }
+
+ // Test operation history
+ const history = this.securityManager.getOperationHistory();
+ this.log(`Security operations performed: ${history.length}`);
+
+ this.log('SecurityManager test completed');
+
+ } catch (error) {
+ this.log('SecurityManager test failed:', error);
+ this.errorDisplay.showError(error as Error);
+ }
+ }
+
+ private async testEndorserAPIClient(): Promise {
+ try {
+ this.log('🌐 Testing EndorserAPIClient (iOS)...');
+
+ const timeSafariUser = this.configLoader.getTimeSafariUser();
+
+ // Test offers to person
+ this.log('Testing offers to person...');
+ const offersResponse = await this.endorserAPIClient.fetchOffersToPerson(
+ timeSafariUser.activeDid,
+ timeSafariUser.lastKnownOfferId,
+ undefined
+ );
+
+ this.log(`✅ Offers fetched: ${offersResponse.data.length} offers`);
+ if (offersResponse.data.length > 0) {
+ this.log('Sample offer:', offersResponse.data[0]);
+ }
+
+ // Test offers to projects
+ this.log('Testing offers to projects...');
+ const projectsResponse = await this.endorserAPIClient.fetchOffersToProjectsOwnedByMe(
+ timeSafariUser.lastKnownOfferId
+ );
+
+ this.log(`✅ Project offers fetched: ${projectsResponse.data.length} offers`);
+
+ // Test project updates
+ if (timeSafariUser.starredPlanIds && timeSafariUser.starredPlanIds.length > 0) {
+ this.log('Testing project updates...');
+ const updatesResponse = await this.endorserAPIClient.fetchProjectsLastUpdated(
+ timeSafariUser.starredPlanIds,
+ timeSafariUser.lastKnownPlanId,
+ undefined
+ );
+
+ this.log(`✅ Project updates fetched: ${updatesResponse.data.length} updates`);
+ }
+
+ this.log('EndorserAPIClient test completed');
+
+ } catch (error) {
+ this.log('EndorserAPIClient test failed:', error);
+ this.errorDisplay.showError(error as Error);
+ }
+ }
+
+ private async testTimeSafariNotificationManager(): Promise {
+ try {
+ this.log('📱 Testing TimeSafariNotificationManager (iOS)...');
+
+ // Test notification generation
+ this.log('Generating TimeSafari notifications...');
+ const notifications = await this.timeSafariNotificationManager.generateNotifications({
+ forceFetch: false,
+ includeMetadata: true,
+ filterByPriority: true,
+ maxNotifications: 10,
+ cacheTtl: 300000
+ });
+
+ this.log(`✅ Generated ${notifications.length} notifications`);
+
+ // Display notification details
+ notifications.forEach((notification, index) => {
+ this.log(`Notification ${index + 1}:`, {
+ type: notification.type,
+ subtype: notification.subtype,
+ priority: notification.notificationPriority,
+ timestamp: new Date(notification.timestamp).toISOString(),
+ disabled: notification.disabled,
+ sound: notification.sound,
+ vibration: notification.vibration
+ });
+ });
+
+ // Test statistics
+ const stats = this.timeSafariNotificationManager.getStatistics();
+ this.log('Manager statistics:', stats);
+
+ this.log('TimeSafariNotificationManager test completed');
+
+ } catch (error) {
+ this.log('TimeSafariNotificationManager test failed:', error);
+ this.errorDisplay.showError(error as Error);
+ }
+ }
+
+ private async testPhase4Integration(): Promise {
+ try {
+ this.log('🚀 Testing complete Phase 4 integration (iOS)...');
+
+ const timeSafariUser = this.configLoader.getTimeSafariUser();
+
+ // Test complete workflow
+ this.log('Step 1: Security authentication...');
+ const jwt = await this.securityManager.generateJWT({
+ scope: 'notifications',
+ audience: 'endorser-api'
+ });
+
+ if (!jwt) {
+ throw new Error('JWT generation failed');
+ }
+
+ this.endorserAPIClient.setAuthToken(jwt);
+ this.log('✅ Authentication successful');
+
+ this.log('Step 2: Fetching TimeSafari data...');
+ const bundle = await this.endorserAPIClient.fetchAllTimeSafariNotifications({
+ activeDid: timeSafariUser.activeDid,
+ starredPlanIds: timeSafariUser.starredPlanIds || [],
+ lastKnownOfferId: timeSafariUser.lastKnownOfferId,
+ lastKnownPlanId: timeSafariUser.lastKnownPlanId,
+ fetchOffersToPerson: true,
+ fetchOffersToProjects: true,
+ fetchProjectUpdates: true,
+ notificationPreferences: {
+ offers: true,
+ projects: true,
+ people: false,
+ items: true
+ }
+ });
+
+ this.log(`✅ Data fetched successfully: ${bundle.success}`);
+ this.log('Bundle metadata:', bundle.metadata);
+
+ this.log('Step 3: Generating notifications...');
+ const notifications = await this.timeSafariNotificationManager.generateNotifications({
+ forceFetch: true,
+ includeMetadata: true,
+ maxNotifications: 20
+ });
+
+ this.log(`✅ Generated ${notifications.length} notifications`);
+
+ // Summary
+ this.log('🎉 Phase 4 integration test completed successfully!');
+ this.log('Summary:', {
+ securityInitialized: this.securityManager.isInitialized(),
+ apiClientReady: !!this.endorserAPIClient,
+ managerInitialized: this.timeSafariNotificationManager.isInitialized(),
+ notificationsGenerated: notifications.length,
+ bundleSuccess: bundle.success
+ });
+
+ } catch (error) {
+ this.log('Phase 4 integration test failed:', error);
+ this.errorDisplay.showError(error as Error);
+ }
+ }
}
// Initialize app when DOM is ready