Browse Source
- Add updateStarredPlans() method to update plan IDs from TimeSafari app - Stores plan IDs in SharedPreferences for persistence - Integrated with TimeSafariIntegrationManager for prefetch operations - Includes comprehensive logging for debugging - Add getStarredPlans() method to retrieve current stored plan IDs - Allows TimeSafari app to verify synchronization - Returns count and last update timestamp - Update TimeSafariIntegrationManager to load starred plan IDs - Reads from SharedPreferences when building TimeSafariUserConfig - Used automatically by EnhancedDailyNotificationFetcher for API calls - Enables dynamic updates without requiring app restart - Add TypeScript definitions for new methods - Includes JSDoc documentation for integration guidance - Matches Android implementation return types - Create integration example for TimeSafari app - Shows how to sync plan IDs from account settings - Demonstrates star/unstar action handling - Includes verification and error handling patterns This allows the TimeSafari app to dynamically update starred project IDs when users star or unstar projects, without requiring plugin configuration changes or app restarts. The stored IDs are automatically used by the prefetch system to query for project updates.master
4 changed files with 473 additions and 0 deletions
@ -0,0 +1,269 @@ |
|||
/** |
|||
* TimeSafari Starred Plans Integration Example |
|||
* |
|||
* Demonstrates how to integrate the Daily Notification Plugin's starred plans |
|||
* management with the TimeSafari app's starred projects functionality. |
|||
* |
|||
* This example shows: |
|||
* 1. How to update starred plan IDs when users star/unstar projects |
|||
* 2. How to sync starred plans on app startup |
|||
* 3. How to verify stored plan IDs |
|||
* |
|||
* @author Matthew Raymer |
|||
* @version 1.0.0 |
|||
*/ |
|||
|
|||
import { DailyNotification } from '@timesafari/daily-notification-plugin'; |
|||
import { logger } from './logger'; // Assuming a logger utility
|
|||
|
|||
/** |
|||
* TimeSafari Starred Plans Manager |
|||
* |
|||
* Integrates with the Daily Notification Plugin to keep starred plan IDs |
|||
* synchronized with the TimeSafari app's account settings. |
|||
*/ |
|||
export class TimeSafariStarredPlansManager { |
|||
private plugin: DailyNotification; |
|||
private currentPlanIds: string[] = []; |
|||
|
|||
constructor(plugin: DailyNotification) { |
|||
this.plugin = plugin; |
|||
} |
|||
|
|||
/** |
|||
* Sync starred plans from account settings to the plugin |
|||
* |
|||
* Call this when: |
|||
* - App starts up |
|||
* - User logs in |
|||
* - Account settings are refreshed |
|||
* |
|||
* @param starredPlanHandleIds Array of plan handle IDs from account settings |
|||
*/ |
|||
async syncStarredPlansFromAccount( |
|||
starredPlanHandleIds: string[] |
|||
): Promise<void> { |
|||
try { |
|||
logger.info('Syncing starred plans to plugin', { |
|||
count: starredPlanHandleIds.length |
|||
}); |
|||
|
|||
// Update plugin with current starred plan IDs
|
|||
const result = await this.plugin.updateStarredPlans({ |
|||
planIds: starredPlanHandleIds |
|||
}); |
|||
|
|||
if (result.success) { |
|||
this.currentPlanIds = starredPlanHandleIds; |
|||
logger.info('Starred plans synced successfully', { |
|||
count: result.planIdsCount, |
|||
updatedAt: new Date(result.updatedAt).toISOString() |
|||
}); |
|||
} else { |
|||
logger.error('Failed to sync starred plans to plugin'); |
|||
} |
|||
} catch (error) { |
|||
logger.error('Error syncing starred plans', error); |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Update starred plans when a user stars a project |
|||
* |
|||
* Call this when: |
|||
* - User clicks star on a project |
|||
* - Star action completes successfully |
|||
* |
|||
* @param planHandleId The plan handle ID that was starred |
|||
*/ |
|||
async addStarredPlan(planHandleId: string): Promise<void> { |
|||
try { |
|||
// Get current starred plans from plugin (to avoid duplicate updates)
|
|||
const current = await this.plugin.getStarredPlans(); |
|||
|
|||
// Add new plan ID if not already present
|
|||
if (!current.planIds.includes(planHandleId)) { |
|||
const updatedPlanIds = [...current.planIds, planHandleId]; |
|||
|
|||
await this.plugin.updateStarredPlans({ |
|||
planIds: updatedPlanIds |
|||
}); |
|||
|
|||
this.currentPlanIds = updatedPlanIds; |
|||
|
|||
logger.info('Starred plan added', { planHandleId }); |
|||
} else { |
|||
logger.debug('Plan already starred', { planHandleId }); |
|||
} |
|||
} catch (error) { |
|||
logger.error('Error adding starred plan', error); |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Update starred plans when a user unstars a project |
|||
* |
|||
* Call this when: |
|||
* - User clicks unstar on a project |
|||
* - Unstar action completes successfully |
|||
* |
|||
* @param planHandleId The plan handle ID that was unstarred |
|||
*/ |
|||
async removeStarredPlan(planHandleId: string): Promise<void> { |
|||
try { |
|||
// Get current starred plans from plugin
|
|||
const current = await this.plugin.getStarredPlans(); |
|||
|
|||
// Remove plan ID if present
|
|||
const updatedPlanIds = current.planIds.filter( |
|||
id => id !== planHandleId |
|||
); |
|||
|
|||
if (updatedPlanIds.length !== current.planIds.length) { |
|||
await this.plugin.updateStarredPlans({ |
|||
planIds: updatedPlanIds |
|||
}); |
|||
|
|||
this.currentPlanIds = updatedPlanIds; |
|||
|
|||
logger.info('Starred plan removed', { planHandleId }); |
|||
} else { |
|||
logger.debug('Plan not in starred list', { planHandleId }); |
|||
} |
|||
} catch (error) { |
|||
logger.error('Error removing starred plan', error); |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Get current starred plans from plugin |
|||
* |
|||
* Useful for verifying synchronization or displaying current state. |
|||
* |
|||
* @returns Current starred plan IDs stored in the plugin |
|||
*/ |
|||
async getCurrentStarredPlans(): Promise<string[]> { |
|||
try { |
|||
const result = await this.plugin.getStarredPlans(); |
|||
this.currentPlanIds = result.planIds; |
|||
return result.planIds; |
|||
} catch (error) { |
|||
logger.error('Error getting starred plans', error); |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Verify starred plans synchronization |
|||
* |
|||
* Compares account settings with plugin storage to ensure they match. |
|||
* Useful for debugging or validation after sync operations. |
|||
* |
|||
* @param accountPlanIds Plan IDs from account settings |
|||
* @returns Object with sync status and any mismatches |
|||
*/ |
|||
async verifySync(accountPlanIds: string[]): Promise<{ |
|||
inSync: boolean; |
|||
accountCount: number; |
|||
pluginCount: number; |
|||
mismatches: { |
|||
inAccountNotPlugin: string[]; |
|||
inPluginNotAccount: string[]; |
|||
}; |
|||
}> { |
|||
try { |
|||
const pluginResult = await this.plugin.getStarredPlans(); |
|||
const pluginPlanIds = pluginResult.planIds; |
|||
|
|||
const inAccountNotPlugin = accountPlanIds.filter( |
|||
id => !pluginPlanIds.includes(id) |
|||
); |
|||
const inPluginNotAccount = pluginPlanIds.filter( |
|||
id => !accountPlanIds.includes(id) |
|||
); |
|||
|
|||
const inSync = |
|||
inAccountNotPlugin.length === 0 && inPluginNotAccount.length === 0; |
|||
|
|||
return { |
|||
inSync, |
|||
accountCount: accountPlanIds.length, |
|||
pluginCount: pluginPlanIds.length, |
|||
mismatches: { |
|||
inAccountNotPlugin, |
|||
inPluginNotAccount |
|||
} |
|||
}; |
|||
} catch (error) { |
|||
logger.error('Error verifying sync', error); |
|||
throw error; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Example integration with TimeSafari's searchStarred method |
|||
* |
|||
* This shows how to integrate the starred plans manager with the existing |
|||
* TimeSafari searchStarred method. |
|||
*/ |
|||
export async function integrateWithSearchStarred( |
|||
plugin: DailyNotification, |
|||
accountSettings: { starredPlanHandleIds?: string[] } |
|||
): Promise<void> { |
|||
const manager = new TimeSafariStarredPlansManager(plugin); |
|||
|
|||
try { |
|||
// Get starred plan IDs from account settings
|
|||
const starredIds = accountSettings.starredPlanHandleIds || []; |
|||
|
|||
if (starredIds.length === 0) { |
|||
logger.info('No starred plans to sync'); |
|||
return; |
|||
} |
|||
|
|||
// Sync to plugin
|
|||
await manager.syncStarredPlansFromAccount(starredIds); |
|||
|
|||
// Verify sync (optional, for debugging)
|
|||
const syncStatus = await manager.verifySync(starredIds); |
|||
if (!syncStatus.inSync) { |
|||
logger.warn('Starred plans sync verification failed', syncStatus); |
|||
// Optionally retry sync if verification fails
|
|||
await manager.syncStarredPlansFromAccount(starredIds); |
|||
} else { |
|||
logger.info('Starred plans sync verified'); |
|||
} |
|||
} catch (error) { |
|||
logger.error('Error integrating with searchStarred', error); |
|||
// Don't throw - allow searchStarred to continue even if plugin sync fails
|
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Example: Hook into star/unstar actions |
|||
* |
|||
* This shows how to update the plugin when users star or unstar projects. |
|||
*/ |
|||
export async function handleStarAction( |
|||
plugin: DailyNotification, |
|||
planHandleId: string, |
|||
isStarring: boolean |
|||
): Promise<void> { |
|||
const manager = new TimeSafariStarredPlansManager(plugin); |
|||
|
|||
try { |
|||
if (isStarring) { |
|||
await manager.addStarredPlan(planHandleId); |
|||
} else { |
|||
await manager.removeStarredPlan(planHandleId); |
|||
} |
|||
} catch (error) { |
|||
logger.error('Error handling star action', error); |
|||
// Don't throw - allow star action to complete even if plugin update fails
|
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue