forked from trent_larson/crowd-funder-for-time-pwa
make an attempt at new notifications using an API (fires always, can't turn off)
This commit is contained in:
108
doc/notification-from-api-call.md
Normal file
108
doc/notification-from-api-call.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# New Activity Notification (API-Driven Daily Message)
|
||||
|
||||
**Purpose:** Integrate the daily-notification-plugin’s second feature—the **daily, API-driven message**—into the crowd-funder (TimeSafari) app. The first feature (daily static reminder) is already integrated; this document covers the plan, completed work, and remaining tasks for the API-driven flow.
|
||||
|
||||
**References:**
|
||||
- Plugin: `daily-notification-plugin` (INTEGRATION_GUIDE.md, definitions.ts)
|
||||
- Alignment outline: `doc/daily-notification-alignment-outline.md`
|
||||
- Help copy: `HelpNotificationTypesView.vue` (“New Activity Notifications”)
|
||||
|
||||
---
|
||||
|
||||
## Plan Summary
|
||||
|
||||
The API-driven flow:
|
||||
|
||||
1. **Prefetch** – Shortly before the user’s chosen time, the plugin runs a background job that calls the Endorser.ch API (e.g. `plansLastUpdatedBetween`, and optionally offers endpoints) using credentials supplied by the app.
|
||||
2. **Cache** – Fetched content is stored in the plugin’s cache.
|
||||
3. **Notify** – At the chosen time, the user sees a notification whose title/body come from that content (or a fallback).
|
||||
|
||||
The app must:
|
||||
|
||||
- **Configure the native fetcher** with `apiBaseUrl`, `activeDid`, and a JWT so the plugin’s background workers can call the API.
|
||||
- **Implement the native fetcher** (or register an implementation) so the plugin can perform the actual HTTP requests and parse responses into notification content.
|
||||
- **Sync starred plan IDs** to the plugin via `updateStarredPlans` so the fetcher knows which plans to query.
|
||||
- **Expose UI** to enable/disable the “New Activity” notification and choose a time, and call `scheduleDualNotification` / `cancelDualSchedule` accordingly.
|
||||
|
||||
---
|
||||
|
||||
## Tasks Finished
|
||||
|
||||
- [x] **Configure native fetcher on startup and identity**
|
||||
- Added `configureNativeFetcherIfReady()` in `src/services/notifications/nativeFetcherConfig.ts` (reads `activeDid` and `apiServer` from DB, gets JWT via `getHeaders(did)`, calls `DailyNotification.configureNativeFetcher()`).
|
||||
- Called from `main.capacitor.ts` after the 2s delay (with deep link registration).
|
||||
- Called from `AccountViewView.initializeState()` when on native and `activeDid` is set; when New Activity is enabled, also calls `updateStarredPlans(settings.starredPlanHandleIds)`.
|
||||
|
||||
- [x] **Implement real API calls in Android native fetcher**
|
||||
- `android/app/src/main/java/app/timesafari/TimeSafariNativeFetcher.java` implements `NativeNotificationContentFetcher`: POST to `/api/v2/report/plansLastUpdatedBetween` with `planIds` (from SharedPreferences `daily_notification_timesafari` / `starredPlanIds`) and `afterId`; parses response into `NotificationContent` list; updates `last_acked_jwt_id` for pagination.
|
||||
- Registered in `MainActivity.onCreate()` via `DailyNotificationPlugin.setNativeFetcher(new TimeSafariNativeFetcher(this))`.
|
||||
|
||||
- [x] **Sync starred plan IDs**
|
||||
- When user enables New Activity, `scheduleNewActivityDualNotification()` calls `DailyNotification.updateStarredPlans({ planIds: settings.starredPlanHandleIds ?? [] })`.
|
||||
- When Account view loads and New Activity is on, `initializeState()` calls `updateStarredPlans(settings.starredPlanHandleIds)` so the plugin has the latest list.
|
||||
|
||||
- [x] **Dual schedule config and scheduling**
|
||||
- Added `src/services/notifications/dualScheduleConfig.ts`: `timeToCron()`, `timeToCronFiveMinutesBefore()`, `buildDualScheduleConfig({ notifyTime, title?, body? })` (contentFetch 5 min before, userNotification at chosen time).
|
||||
- When user enables New Activity and picks a time, app calls `DailyNotification.scheduleDualNotification({ config })` with this config.
|
||||
- When user disables New Activity, app calls `DailyNotification.cancelDualSchedule()`.
|
||||
|
||||
- [x] **UI for New Activity notification**
|
||||
- Unhid the “New Activity Notification” block in `AccountViewView.vue` (toggle + accessibility).
|
||||
- Enable flow: time dialog → save settings → on native, `scheduleNewActivityDualNotification(timeText)` (configure fetcher, updateStarredPlans, scheduleDualNotification).
|
||||
- Disable flow: on native, `cancelDualSchedule()` then save and clear settings.
|
||||
- Added `starredPlanHandleIds` to `AccountSettings` in `interfaces/accountView.ts`.
|
||||
|
||||
- [x] **Exports**
|
||||
- `src/services/notifications/index.ts` exports `configureNativeFetcherIfReady`, `buildDualScheduleConfig`, `timeToCron`, `timeToCronFiveMinutesBefore`, and `DualScheduleConfigInput`.
|
||||
|
||||
---
|
||||
|
||||
## Checklist of Remaining Tasks
|
||||
|
||||
### iOS
|
||||
|
||||
- [ ] **Confirm iOS native fetcher / dual schedule**
|
||||
Plugin exposes `configureNativeFetcher` on iOS. Confirm whether the plugin expects an iOS-specific native fetcher registration (similar to Android’s `setNativeFetcher`) and, if so, register a TimeSafari fetcher implementation for iOS so API-driven notifications work on iPhone.
|
||||
|
||||
- [ ] **Verify dual schedule on iOS**
|
||||
Test `scheduleDualNotification` and `cancelDualSchedule` on iOS; ensure content fetch and user notification fire at the expected times and that foreground/background behavior matches expectations.
|
||||
|
||||
### Testing and hardening
|
||||
|
||||
- [ ] **Test full flow on Android**
|
||||
Enable New Activity, set time, wait for prefetch and notification (or use a short rollover for testing). Confirm notification shows with API-derived or fallback content.
|
||||
|
||||
- [ ] **Test full flow on iOS**
|
||||
Same as Android: enable, set time, verify prefetch and notification delivery and content.
|
||||
|
||||
- [ ] **Test with no starred plans**
|
||||
Enable New Activity with empty `starredPlanHandleIds`; confirm no crash and sensible fallback (e.g. “No updates in your starred projects” or similar).
|
||||
|
||||
- [ ] **Test JWT expiry**
|
||||
Ensure behavior when the token passed to `configureNativeFetcher` has expired (e.g. app in background for a long time); document or implement refresh (e.g. re-call `configureNativeFetcherIfReady` on foreground or when opening Account).
|
||||
|
||||
### Optional enhancements
|
||||
|
||||
- [ ] **Offers endpoints**
|
||||
Extend `TimeSafariNativeFetcher` (and any iOS fetcher) to call offers endpoints (e.g. `offers`, `offersToPlansOwnedByMe`) and merge with project-update content for richer notifications.
|
||||
|
||||
- [ ] **Sync starred plans on star/unstar**
|
||||
When the user stars or unstars a project elsewhere in the app, call `updateStarredPlans` so the plugin always has the current list without requiring a visit to Account.
|
||||
|
||||
- [ ] **Documentation**
|
||||
Add a short “New Activity notifications” section to BUILDING.md or a user-facing help page describing how the feature works and how to troubleshoot (e.g. no notification, wrong content, JWT/API errors).
|
||||
|
||||
---
|
||||
|
||||
## File Reference
|
||||
|
||||
| Area | Files |
|
||||
|------|--------|
|
||||
| Fetcher config | `src/services/notifications/nativeFetcherConfig.ts` |
|
||||
| Dual schedule config | `src/services/notifications/dualScheduleConfig.ts` |
|
||||
| Notification exports | `src/services/notifications/index.ts` |
|
||||
| Startup | `src/main.capacitor.ts` |
|
||||
| Account UI and flow | `src/views/AccountViewView.vue` |
|
||||
| Settings type | `src/interfaces/accountView.ts` |
|
||||
| Android native fetcher | `android/app/src/main/java/app/timesafari/TimeSafariNativeFetcher.java` |
|
||||
| Android registration | `android/app/src/main/java/app/timesafari/MainActivity.java` |
|
||||
Reference in New Issue
Block a user