Files
crowd-funder-for-time-pwa/doc/notification-integration-changes-outline.md
Jose Olarte III 5a4ab84bfe feat(notifications): integrate DailyNotificationPlugin with UI for native platforms
Integrate DailyNotificationPlugin with notification UI to enable native
notifications on iOS/Android while maintaining web push for web/PWA.

- Add platform detection to PushNotificationPermission component
- Implement native notification flow via NotificationService
- Hide push server setting on native platforms (not needed)
- Add time conversion (AM/PM to 24-hour) for native plugin
- Add comprehensive documentation

Breaking Changes: None (backward compatible)
2026-01-23 19:06:16 +08:00

413 lines
13 KiB
Markdown

# Notification Integration Changes - Implementation Outline
**Date**: 2026-01-23
**Purpose**: Detailed outline of changes needed to integrate DailyNotificationPlugin with UI
---
## Overview
This document outlines all changes required to integrate the DailyNotificationPlugin with the existing notification UI, making it work seamlessly on both native (iOS/Android) and web platforms.
**Estimated Complexity**: Medium
**Estimated Files Changed**: 3-4 files
**Breaking Changes**: None (backward compatible)
---
## Change Summary
| File | Changes | Complexity | Risk |
|------|---------|------------|------|
| `PushNotificationPermission.vue` | Add platform detection, native flow | Medium | Low |
| `AccountViewView.vue` | Platform detection in toggles, hide push server on native | Low | Low |
| `WebPushNotificationService.ts` | Complete stub implementation (optional) | Medium | Low |
---
## Detailed Changes
### 1. PushNotificationPermission.vue
**File**: `src/components/PushNotificationPermission.vue`
**Current Lines**: ~656 lines
**Estimated New Lines**: +50-80 lines
**Complexity**: Medium
#### Changes Required
**A. Add Imports** (Top of script section)
```typescript
import { Capacitor } from "@capacitor/core";
import { NotificationService } from "@/services/notifications";
```
**B. Add Platform Detection Property**
```typescript
// Add to class properties
private get isNativePlatform(): boolean {
return Capacitor.isNativePlatform();
}
```
**C. Modify `open()` Method** (Lines 170-258)
- **Current**: Always initializes web push (VAPID key, service worker)
- **Change**: Add platform check at start
- If native: Skip VAPID/service worker, show UI immediately
- If web: Keep existing logic
**D. Modify `turnOnNotifications()` Method** (Lines 393-499)
- **Current**: Web push subscription flow
- **Change**: Split into two paths:
- **Native path**: Use `NotificationService.getInstance()``requestPermissions()``scheduleDailyNotification()`
- **Web path**: Keep existing logic
**E. Add New Method: `turnOnNativeNotifications()`**
- Request permissions via `NotificationService`
- Convert time input (AM/PM) to 24-hour format (HH:mm)
- Call `scheduleDailyNotification()` with proper options
- Save to settings
- Call callback with success/time/message
**F. Update `handleTurnOnNotifications()` Method** (Line 643)
- Add platform check
- Route to `turnOnNativeNotifications()` or `turnOnNotifications()` based on platform
**G. Update Computed Properties**
- `isSystemReady`: For native, return `true` immediately (no VAPID needed)
- `canShowNotificationForm`: For native, return `true` immediately
**H. Update Template** (Optional - for better UX)
- Add platform-specific messaging if desired
- Native: "Notifications will be scheduled on your device"
- Web: Keep existing messaging
#### Code Structure Preview
```typescript
async open(pushType: string, callback?: ...) {
this.callback = callback || this.callback;
this.isVisible = true;
this.pushType = pushType;
// Platform detection
if (this.isNativePlatform) {
// Native: No VAPID/service worker needed
this.serviceWorkerReady = true; // Fake it for UI
this.vapidKey = "native"; // Placeholder
return; // Skip web push initialization
}
// Existing web push initialization...
// (keep all existing code)
}
async turnOnNotifications() {
if (this.isNativePlatform) {
return this.turnOnNativeNotifications();
}
// Existing web push logic...
}
private async turnOnNativeNotifications(): Promise<void> {
const service = NotificationService.getInstance();
// Request permissions
const granted = await service.requestPermissions();
if (!granted) {
// Handle permission denial
return;
}
// Convert time to 24-hour format
const time24h = this.convertTo24HourFormat();
// Determine title and body based on pushType
const title = this.pushType === this.DAILY_CHECK_TITLE
? "Daily Check-In"
: "Daily Reminder";
const body = this.pushType === this.DIRECT_PUSH_TITLE
? this.messageInput
: "Time to check your TimeSafari activity";
// Schedule notification
const success = await service.scheduleDailyNotification({
time: time24h,
title,
body,
priority: 'normal'
});
if (success) {
// Save to settings
const timeText = this.notificationTimeText;
await this.$saveSettings({
[this.pushType === this.DAILY_CHECK_TITLE
? 'notifyingNewActivityTime'
: 'notifyingReminderTime']: timeText,
...(this.pushType === this.DIRECT_PUSH_TITLE && {
notifyingReminderMessage: this.messageInput
})
});
// Call callback
this.callback(true, timeText, this.messageInput);
}
}
private convertTo24HourFormat(): string {
const hour = parseInt(this.hourInput);
const minute = parseInt(this.minuteInput);
let hour24 = hour;
if (!this.hourAm && hour !== 12) {
hour24 = hour + 12;
} else if (this.hourAm && hour === 12) {
hour24 = 0;
}
return `${hour24.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
}
```
#### Testing Considerations
- Test on iOS device
- Test on Android device
- Test on web (should still work as before)
- Test permission denial flow
- Test time conversion (AM/PM → 24-hour)
---
### 2. AccountViewView.vue
**File**: `src/views/AccountViewView.vue`
**Current Lines**: 2124 lines
**Estimated New Lines**: +20-30 lines
**Complexity**: Low
#### Changes Required
**A. Add Import** (Top of script section, around line 739)
```typescript
import { Capacitor } from "@capacitor/core";
```
**B. Add Computed Property** (In class, around line 888)
```typescript
private get isNativePlatform(): boolean {
return Capacitor.isNativePlatform();
}
```
**C. Modify Notification Toggle Methods** (Lines 1134-1202)
**`showNewActivityNotificationChoice()`** (Lines 1134-1158)
- **Current**: Always uses `PushNotificationPermission` component
- **Change**: Add platform check
- If native: Use `NotificationService` directly (or still use component - it will handle platform)
- If web: Keep existing logic
- **Note**: Since we're updating `PushNotificationPermission` to handle both, this might not need changes, but we could add direct native path for cleaner code
**`showReminderNotificationChoice()`** (Lines 1171-1202)
- Same as above
**D. Conditionally Hide Push Server Setting** (Lines 506-549)
- Wrap the entire "Notification Push Server" section in `v-if="!isNativePlatform"`
- This hides it on iOS/Android where it's not needed
**E. Update Status Display** (Optional)
- When showing notification status, could add platform indicator
- "Native notification scheduled" vs "Web push subscription active"
#### Code Structure Preview
```typescript
// Add computed property
private get isNativePlatform(): boolean {
return Capacitor.isNativePlatform();
}
// In template, wrap push server section:
<section v-if="!isNativePlatform" id="sectionPushServer">
<h2 class="text-slate-500 text-sm font-bold mb-2">
Notification Push Server
</h2>
<!-- ... existing push server UI ... -->
</section>
// Optional: Update notification choice methods
async showNewActivityNotificationChoice(): Promise<void> {
if (!this.notifyingNewActivity) {
// Component now handles platform detection, so this can stay the same
// OR we could add direct native path here for cleaner separation
(this.$refs.pushNotificationPermission as PushNotificationPermission)
.open(DAILY_CHECK_TITLE, async (success: boolean, timeText: string) => {
// ... existing callback ...
});
} else {
// ... existing turn-off logic ...
}
}
```
#### Testing Considerations
- Verify push server section hidden on iOS
- Verify push server section hidden on Android
- Verify push server section visible on web
- Test notification toggles work on all platforms
---
### 3. WebPushNotificationService.ts (Optional Enhancement)
**File**: `src/services/notifications/WebPushNotificationService.ts`
**Current Lines**: 213 lines
**Estimated New Lines**: +100-150 lines
**Complexity**: Medium
**Priority**: Low (can be done later)
#### Changes Required
**A. Complete `scheduleDailyNotification()` Implementation**
- Extract logic from `PushNotificationPermission.vue`
- Subscribe to push service
- Send subscription to server
- Return success status
**B. Complete `cancelDailyNotification()` Implementation**
- Get current subscription
- Unsubscribe from push service
- Notify server to stop sending
**C. Complete `getStatus()` Implementation**
- Check settings for `notifyingNewActivityTime` / `notifyingReminderTime`
- Check service worker subscription status
- Return combined status
**Note**: This is optional because `PushNotificationPermission.vue` already handles web push. Completing this would allow using `NotificationService` directly for web too, but it's not required for the integration to work.
---
## Implementation Order
### Phase 1: Core Integration (Required)
1. ✅ Update `PushNotificationPermission.vue` with platform detection
2. ✅ Update `AccountViewView.vue` to hide push server on native
3. ✅ Test on native platforms
### Phase 2: Polish (Optional)
4. Complete `WebPushNotificationService.ts` implementation
5. Add platform-specific UI messaging
6. Add status indicators
---
## Risk Assessment
### Low Risk Changes
- ✅ Adding platform detection (read-only check)
- ✅ Conditionally hiding UI elements
- ✅ Adding new code paths (not modifying existing)
### Medium Risk Changes
- ⚠️ Modifying `turnOnNotifications()` flow (but we're adding, not replacing)
- ⚠️ Time format conversion (need to test edge cases)
### Mitigation Strategies
1. **Backward Compatibility**: All changes are additive - existing web push flow remains unchanged
2. **Feature Flags**: Could add feature flag to enable/disable native notifications
3. **Gradual Rollout**: Test on one platform first (e.g., Android), then iOS
4. **Fallback**: If native service fails, could fall back to showing error message
---
## Testing Checklist
### Functional Testing
- [ ] Native iOS: Request permissions → Schedule notification → Verify scheduled
- [ ] Native Android: Request permissions → Schedule notification → Verify scheduled
- [ ] Web: Existing flow still works (no regression)
- [ ] Permission denial: Shows appropriate error message
- [ ] Time conversion: AM/PM correctly converts to 24-hour format
- [ ] Both notification types: Daily Check and Direct Push work on native
- [ ] Settings persistence: Times saved correctly to database
### UI Testing
- [ ] Push server setting hidden on iOS
- [ ] Push server setting hidden on Android
- [ ] Push server setting visible on web
- [ ] Notification toggles work on all platforms
- [ ] Time picker UI works on native (same as web)
### Edge Cases
- [ ] 12:00 AM conversion (should be 00:00)
- [ ] 12:00 PM conversion (should be 12:00)
- [ ] Invalid time input handling
- [ ] App restart: Notifications still scheduled
- [ ] Device reboot: Notifications still scheduled (Android)
---
## Dependencies
### Required
-`@capacitor/core` - Already in project
-`@timesafari/daily-notification-plugin` - Already installed
-`NotificationService` - Already created
### No New Dependencies Needed
---
## Estimated Effort
| Task | Time Estimate |
|------|---------------|
| Update PushNotificationPermission.vue | 2-3 hours |
| Update AccountViewView.vue | 30 minutes - 1 hour |
| Testing on iOS | 1-2 hours |
| Testing on Android | 1-2 hours |
| Bug fixes & polish | 1-2 hours |
| **Total** | **5-10 hours** |
---
## Rollback Plan
If issues arise:
1. **Quick Rollback**: Revert changes to `PushNotificationPermission.vue` and `AccountViewView.vue`
2. **Partial Rollback**: Keep platform detection but disable native path (feature flag)
3. **No Data Migration Needed**: Settings structure unchanged
---
## Questions to Consider
1. **Should we keep using `PushNotificationPermission` component for native, or create separate native flow?**
- **Recommendation**: Keep using component (simpler, less code duplication)
2. **Should we show different UI messaging for native vs web?**
- **Recommendation**: Optional enhancement, not required for MVP
3. **Should we complete `WebPushNotificationService` now or later?**
- **Recommendation**: Later (not blocking, existing component works)
4. **How to handle notification cancellation on native?**
- **Recommendation**: Use `NotificationService.cancelDailyNotification()` in existing turn-off logic
---
## Next Steps After Implementation
1. Update documentation with platform-specific instructions
2. Add error handling for edge cases
3. Consider adding notification status display in UI
4. Test on real devices (critical for native notifications)
5. Monitor for any platform-specific issues
---
**Last Updated**: 2026-01-23