forked from trent_larson/crowd-funder-for-time-pwa
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)
413 lines
13 KiB
Markdown
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
|