Browse Source
- Consolidate AccountViewView integration strategy into unified plan - Add comprehensive AccountViewView Integration Strategy section - Include UI component design, data flow, and implementation decisions - Remove separate strategy document to follow meta_feature_planning structure - Update Phase 2 to include AccountViewView integration taskspull/214/head
2 changed files with 388 additions and 485 deletions
@ -1,472 +0,0 @@ |
|||||
# Daily Notification Plugin - AccountViewView Integration Strategy |
|
||||
|
|
||||
**Author**: Matthew Raymer |
|
||||
**Date**: 2025-11-03 |
|
||||
**Status**: 🎯 **PLANNING** - UI integration strategy |
|
||||
**Feature**: Daily Notification Scheduling in Account Settings |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Overview |
|
||||
|
|
||||
This document outlines the strategy for integrating daily notification scheduling into `AccountViewView.vue`, allowing users to configure notification times directly from their account settings. |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Current State Analysis |
|
||||
|
|
||||
### Account Settings Context |
|
||||
|
|
||||
**Location**: `AccountViewView.vue` - Settings view for user account configuration |
|
||||
|
|
||||
**Integration Approach**: Add new "Daily Notifications" section for scheduling native daily notifications using PlatformService. |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Integration Strategy |
|
||||
|
|
||||
**Approach**: Create a separate "Daily Notifications" section |
|
||||
|
|
||||
This approach adds a dedicated "Daily Notifications" section that checks PlatformService capabilities. On Capacitor platforms, it provides full functionality. On other platforms, the UI is hidden when PlatformService returns `null` for notification methods. |
|
||||
|
|
||||
**Key Benefits**: |
|
||||
- Uses PlatformService interface pattern (consistent with camera, filesystem) |
|
||||
- Platform-specific features properly isolated |
|
||||
- Can use native time picker (better UX on mobile) |
|
||||
- Future-proof: Easy to extend with additional notification features |
|
||||
- Graceful degradation on unsupported platforms |
|
||||
|
|
||||
**Implementation**: |
|
||||
```vue |
|
||||
<!-- New Daily Notifications section --> |
|
||||
<section |
|
||||
v-if="notificationsSupported" |
|
||||
id="sectionDailyNotifications" |
|
||||
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8" |
|
||||
aria-labelledby="dailyNotificationsHeading" |
|
||||
> |
|
||||
<h2 id="dailyNotificationsHeading" class="mb-2 font-bold"> |
|
||||
Daily Notifications |
|
||||
<button |
|
||||
class="text-slate-400 fa-fw cursor-pointer" |
|
||||
aria-label="Learn more about native notifications" |
|
||||
@click.stop="showNativeNotificationInfo" |
|
||||
> |
|
||||
<font-awesome icon="question-circle" aria-hidden="true" /> |
|
||||
</button> |
|
||||
</h2> |
|
||||
|
|
||||
<div class="flex items-center justify-between"> |
|
||||
<div>Daily Notification</div> |
|
||||
<!-- Toggle switch --> |
|
||||
<div |
|
||||
class="relative ml-2 cursor-pointer" |
|
||||
role="switch" |
|
||||
:aria-checked="nativeNotificationEnabled" |
|
||||
@click="toggleNativeNotification()" |
|
||||
> |
|
||||
<!-- Custom toggle UI --> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Show current time when enabled --> |
|
||||
<div v-if="nativeNotificationEnabled" class="mt-2"> |
|
||||
<div class="flex items-center justify-between"> |
|
||||
<span>Scheduled for: {{ nativeNotificationTime }}</span> |
|
||||
<button |
|
||||
class="text-blue-500 text-sm" |
|
||||
@click="editNativeNotificationTime()" |
|
||||
> |
|
||||
Edit Time |
|
||||
</button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</section> |
|
||||
``` |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Approach Rationale |
|
||||
|
|
||||
**Decision Date**: 2025-11-03 |
|
||||
**Status**: ✅ **ACCEPTED** - Will proceed with separate native notification section |
|
||||
|
|
||||
1. **Clear Platform Distinction**: Users understand this is for mobile apps |
|
||||
2. **No Conflicts**: Doesn't interfere with disabled web notifications |
|
||||
3. **Better UX**: Can use native time picker on mobile |
|
||||
4. **Future-Proof**: Easy to extend with additional native notification features |
|
||||
|
|
||||
### Implementation Status |
|
||||
|
|
||||
- [x] Approach decision finalized |
|
||||
- [ ] Implementation begins (Phase 1) |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## UI Component Design |
|
||||
|
|
||||
### 1. Platform Capability Detection |
|
||||
|
|
||||
```typescript |
|
||||
// In AccountViewView component |
|
||||
async checkNotificationSupport(): Promise<boolean> { |
|
||||
const platformService = PlatformServiceFactory.getInstance(); |
|
||||
const status = await platformService.getDailyNotificationStatus(); |
|
||||
return status !== null; // null means not supported |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
### 2. State Management |
|
||||
|
|
||||
```typescript |
|
||||
// Component properties |
|
||||
nativeNotificationEnabled: boolean = false; |
|
||||
nativeNotificationTime: string = ""; // Display format: "9:00 AM" |
|
||||
nativeNotificationTimeStorage: string = ""; // Plugin format: "09:00" |
|
||||
nativeNotificationTitle: string = "Daily Update"; |
|
||||
nativeNotificationMessage: string = "Your daily notification is ready!"; |
|
||||
``` |
|
||||
|
|
||||
### 3. Time Input ✅ **SELECTED: HTML5 Time Input** |
|
||||
|
|
||||
**Decision**: Use HTML5 `<input type="time">` for native mobile experience |
|
||||
|
|
||||
```vue |
|
||||
<input |
|
||||
type="time" |
|
||||
v-model="nativeNotificationTimeStorage" |
|
||||
class="rounded border border-slate-400 px-2 py-2" |
|
||||
/> |
|
||||
``` |
|
||||
|
|
||||
**Benefits**: |
|
||||
- Native mobile time picker UI on Capacitor platforms |
|
||||
- Simpler implementation (no custom time parsing needed) |
|
||||
- Automatic 24-hour format output (compatible with plugin) |
|
||||
- System handles locale-specific time formatting |
|
||||
- Better UX on mobile devices |
|
||||
|
|
||||
**Note**: HTML5 time input provides time in "HH:mm" format (24-hour) which matches the plugin's expected format perfectly. |
|
||||
|
|
||||
### 4. Time Format Conversion (Using System Time) |
|
||||
|
|
||||
**Key Principle**: Use device's local system time - no timezone conversions needed. The plugin handles system time natively. |
|
||||
|
|
||||
```typescript |
|
||||
// Convert "09:00" (plugin storage format) to "9:00 AM" (display) |
|
||||
function formatTimeForDisplay(time24: string): string { |
|
||||
const [hours, minutes] = time24.split(':'); |
|
||||
const hourNum = parseInt(hours); |
|
||||
const isPM = hourNum >= 12; |
|
||||
const displayHour = hourNum === 0 ? 12 : hourNum > 12 ? hourNum - 12 : hourNum; |
|
||||
return `${displayHour}:${minutes} ${isPM ? 'PM' : 'AM'}`; |
|
||||
} |
|
||||
|
|
||||
// HTML5 time input provides "HH:mm" in local time - use directly |
|
||||
// No UTC conversion needed - plugin handles local timezone |
|
||||
function getTimeFromInput(timeInput: string): string { |
|
||||
// timeInput is already in "HH:mm" format from <input type="time"> |
|
||||
// This is in the user's local timezone - pass directly to plugin |
|
||||
return timeInput; // e.g., "09:00" in user's local time |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
**Time Handling**: |
|
||||
|
|
||||
- **PlatformService Integration**: Uses device's local system time directly - NO UTC conversion needed. The plugin schedules notifications on the device itself, using the device's timezone. |
|
||||
|
|
||||
**Implementation Principles**: |
|
||||
- HTML5 `<input type="time">` provides time in device's local timezone |
|
||||
- Plugin receives time in "HH:mm" format and schedules relative to device's local time |
|
||||
- No manual timezone conversion or UTC calculations needed |
|
||||
- System automatically handles: |
|
||||
- Timezone changes |
|
||||
- Daylight saving time transitions |
|
||||
- Device timezone updates |
|
||||
- User sets "9:00 AM" in their local time → plugin schedules for 9:00 AM local time every day |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Data Flow |
|
||||
|
|
||||
### 1. Initialization |
|
||||
|
|
||||
```typescript |
|
||||
async initializeState() { |
|
||||
// ... existing initialization ... |
|
||||
|
|
||||
const platformService = PlatformServiceFactory.getInstance(); |
|
||||
|
|
||||
// Check if notifications are supported on this platform |
|
||||
const status = await platformService.getDailyNotificationStatus(); |
|
||||
if (status === null) { |
|
||||
// Notifications not supported - don't initialize |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// Load from settings |
|
||||
const nativeNotificationTime = settings.nativeNotificationTime || ""; |
|
||||
this.nativeNotificationEnabled = !!nativeNotificationTime; |
|
||||
this.nativeNotificationTimeStorage = nativeNotificationTime; |
|
||||
|
|
||||
if (nativeNotificationTime) { |
|
||||
this.nativeNotificationTime = formatTimeForDisplay(nativeNotificationTime); |
|
||||
} |
|
||||
|
|
||||
// Update UI with current status |
|
||||
this.notificationStatus = status; |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
### 2. Enable Notification |
|
||||
|
|
||||
```typescript |
|
||||
async enableNativeNotification() { |
|
||||
try { |
|
||||
const platformService = PlatformServiceFactory.getInstance(); |
|
||||
|
|
||||
// 1. Request permissions if needed |
|
||||
const permissions = await platformService.checkNotificationPermissions(); |
|
||||
if (permissions === null || permissions.notifications !== 'granted') { |
|
||||
const result = await platformService.requestNotificationPermissions(); |
|
||||
if (result === null || !result.notifications) { |
|
||||
throw new Error("Notification permissions denied"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 2. Schedule notification via PlatformService |
|
||||
// Time is in device's local system time (from HTML5 time input) |
|
||||
// PlatformService handles timezone and scheduling internally |
|
||||
await platformService.scheduleDailyNotification({ |
|
||||
time: this.nativeNotificationTimeStorage, // "09:00" in local time |
|
||||
title: this.nativeNotificationTitle, |
|
||||
body: this.nativeNotificationMessage, |
|
||||
sound: true, |
|
||||
priority: 'high' |
|
||||
}); |
|
||||
|
|
||||
// 3. Save to settings |
|
||||
await this.$saveSettings({ |
|
||||
nativeNotificationTime: this.nativeNotificationTimeStorage, |
|
||||
nativeNotificationTitle: this.nativeNotificationTitle, |
|
||||
nativeNotificationMessage: this.nativeNotificationMessage, |
|
||||
}); |
|
||||
|
|
||||
// 4. Update UI state |
|
||||
this.nativeNotificationEnabled = true; |
|
||||
|
|
||||
this.notify.success("Daily notification scheduled successfully", TIMEOUTS.SHORT); |
|
||||
} catch (error) { |
|
||||
logger.error("Failed to enable notification:", error); |
|
||||
this.notify.error("Failed to schedule notification. Please try again.", TIMEOUTS.LONG); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
### 3. Disable Notification |
|
||||
|
|
||||
```typescript |
|
||||
async disableNativeNotification() { |
|
||||
try { |
|
||||
const platformService = PlatformServiceFactory.getInstance(); |
|
||||
|
|
||||
// 1. Cancel notification via PlatformService |
|
||||
await platformService.cancelDailyNotification(); |
|
||||
|
|
||||
// 2. Clear settings |
|
||||
await this.$saveSettings({ |
|
||||
nativeNotificationTime: "", |
|
||||
nativeNotificationTitle: "", |
|
||||
nativeNotificationMessage: "", |
|
||||
}); |
|
||||
|
|
||||
// 3. Update UI state |
|
||||
this.nativeNotificationEnabled = false; |
|
||||
this.nativeNotificationTime = ""; |
|
||||
this.nativeNotificationTimeStorage = ""; |
|
||||
|
|
||||
this.notify.success("Daily notification disabled", TIMEOUTS.SHORT); |
|
||||
} catch (error) { |
|
||||
logger.error("Failed to disable native notification:", error); |
|
||||
this.notify.error("Failed to disable notification. Please try again.", TIMEOUTS.LONG); |
|
||||
} |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
### 4. Edit Time |
|
||||
|
|
||||
**Approach**: Use inline HTML5 time input for quick edits |
|
||||
|
|
||||
```typescript |
|
||||
async editNativeNotificationTime() { |
|
||||
// Show inline HTML5 time input for quick changes |
|
||||
// For complex editing (title, message), navigate to ScheduleView |
|
||||
this.showTimeEdit = true; |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
**Implementation Note**: HTML5 time input provides native mobile picker experience when shown inline, making it ideal for quick time adjustments in AccountViewView. |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Settings Schema |
|
||||
|
|
||||
### New Settings Fields |
|
||||
|
|
||||
```typescript |
|
||||
// Add to Settings interface in src/db/tables/settings.ts |
|
||||
interface Settings { |
|
||||
// ... existing fields ... |
|
||||
|
|
||||
// Native notification settings (Capacitor only) |
|
||||
nativeNotificationTime?: string; // "09:00" format (24-hour) |
|
||||
nativeNotificationTitle?: string; // Default: "Daily Update" |
|
||||
nativeNotificationMessage?: string; // Default message |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
### Settings Persistence |
|
||||
|
|
||||
- Store in `settings` table via `$saveSettings()` |
|
||||
- Use same pattern as `notifyingNewActivityTime` |
|
||||
- Persist across app restarts |
|
||||
- Sync with plugin state on component mount |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Plugin Integration |
|
||||
|
|
||||
### PlatformService Usage |
|
||||
|
|
||||
```typescript |
|
||||
import { PlatformServiceFactory } from '@/services/PlatformServiceFactory'; |
|
||||
|
|
||||
const platformService = PlatformServiceFactory.getInstance(); |
|
||||
|
|
||||
// Check if notifications are supported |
|
||||
const status = await platformService.getDailyNotificationStatus(); |
|
||||
if (status === null) { |
|
||||
// Notifications not supported on this platform |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
### Key Operations (via PlatformService) |
|
||||
|
|
||||
1. **Check Status**: `getDailyNotificationStatus()` - Returns status or `null` if unsupported |
|
||||
2. **Check Permissions**: `checkNotificationPermissions()` - Returns permissions or `null` if unsupported |
|
||||
3. **Request Permissions**: `requestNotificationPermissions()` - Requests permissions or returns `null` if unsupported |
|
||||
4. **Schedule**: `scheduleDailyNotification(options)` - Schedules notification or throws error if unsupported |
|
||||
5. **Cancel**: `cancelDailyNotification()` - Cancels notification or throws error if unsupported |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## UI/UX Considerations |
|
||||
|
|
||||
### Visual Design |
|
||||
- **Section Style**: Match existing notification section (`bg-slate-100 rounded-md`) |
|
||||
- **Toggle Switch**: Reuse existing custom toggle pattern |
|
||||
- **Time Display**: Show in user-friendly format ("9:00 AM") |
|
||||
- **Edit Button**: Small, subtle link/button to edit time |
|
||||
|
|
||||
### User Feedback |
|
||||
- **Success**: Toast notification when scheduled successfully |
|
||||
- **Error**: Clear error message with troubleshooting guidance |
|
||||
- **Loading**: Show loading state during plugin operations |
|
||||
- **Permission Request**: Handle gracefully if denied |
|
||||
|
|
||||
### Accessibility |
|
||||
- **ARIA Labels**: Proper labels for all interactive elements |
|
||||
- **Keyboard Navigation**: Full keyboard support |
|
||||
- **Screen Reader**: Clear announcements for state changes |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Implementation Phases |
|
||||
|
|
||||
### Phase 1: Basic Integration |
|
||||
- [ ] Add platform detection property |
|
||||
- [ ] Create native notification section in template |
|
||||
- [ ] Add component state properties |
|
||||
- [ ] Implement toggle functionality |
|
||||
- [ ] Basic enable/disable operations |
|
||||
|
|
||||
### Phase 2: Time Management |
|
||||
- [ ] Add time input (HTML5 time picker) |
|
||||
- [ ] Implement time format conversion |
|
||||
- [ ] Add edit time functionality |
|
||||
- [ ] Save/load time from settings |
|
||||
|
|
||||
### Phase 3: Plugin Integration |
|
||||
- [ ] Integrate with DailyNotificationFactory |
|
||||
- [ ] Schedule notification on enable |
|
||||
- [ ] Cancel notification on disable |
|
||||
- [ ] Update notification on time change |
|
||||
- [ ] Sync plugin state with settings |
|
||||
|
|
||||
### Phase 4: Polish & Error Handling |
|
||||
- [ ] Permission request flow |
|
||||
- [ ] Error handling and user feedback |
|
||||
- [ ] Status verification |
|
||||
- [ ] Help/info dialogs |
|
||||
- [ ] Accessibility improvements |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Implementation Decisions |
|
||||
|
|
||||
### Time Input Format ✅ |
|
||||
- **Selected**: HTML5 `<input type="time">` for Capacitor platforms |
|
||||
- **Rationale**: Native mobile experience, simpler code, automatic 24-hour format |
|
||||
|
|
||||
### Edit Approach ✅ |
|
||||
- **Selected**: Inline HTML5 time input for quick edits in AccountViewView |
|
||||
- **Note**: For complex editing (title, message changes), users can navigate to dedicated ScheduleView |
|
||||
|
|
||||
### Settings Field Names ✅ |
|
||||
- **Selected**: `nativeNotificationTime`, `nativeNotificationTitle`, `nativeNotificationMessage` |
|
||||
- **Rationale**: Clear distinction from web push notification fields |
|
||||
|
|
||||
### Notification Title/Message ✅ |
|
||||
- **Selected**: Allow customization, default to "Daily Update" / "Your daily notification is ready!" |
|
||||
- **Rationale**: Flexibility for users, sensible defaults |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Success Criteria |
|
||||
|
|
||||
- [ ] Native notification section appears only on Capacitor platforms |
|
||||
- [ ] Toggle enables/disables notifications via plugin |
|
||||
- [ ] Time can be set and edited |
|
||||
- [ ] Settings persist across app restarts |
|
||||
- [ ] Plugin state syncs with settings |
|
||||
- [ ] Error handling provides clear user feedback |
|
||||
- [ ] UI matches existing design patterns |
|
||||
- [ ] Accessibility requirements met |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Related Components |
|
||||
|
|
||||
- **PlatformService**: Interface for platform capabilities (notification methods) |
|
||||
- **PlatformServiceFactory**: Factory for getting platform service instance |
|
||||
- **ScheduleView**: Dedicated scheduling interface (for complex editing) |
|
||||
- **AccountViewView**: Main settings view (integration target) |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
## Next Steps |
|
||||
|
|
||||
1. ~~**Decide on Approach**: Separate native notification section~~ ✅ **DECIDED** |
|
||||
2. **Define Settings Schema**: Add native notification fields to Settings interface |
|
||||
3. **Create UI Components**: Build notification section in AccountViewView |
|
||||
4. **Integrate Plugin**: Connect UI to DailyNotificationFactory service |
|
||||
5. **Test Flow**: Verify enable/disable/edit workflows |
|
||||
6. **Add Help Content**: Create help documentation for native notifications |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
**See also**: |
|
||||
- `doc/daily-notification-plugin-integration-plan.md` - Overall integration plan |
|
||||
- `src/views/AccountViewView.vue` - Target component for integration |
|
||||
- `src/services/PlatformService.ts` - PlatformService interface definition |
|
||||
- `src/services/PlatformServiceFactory.ts` - Factory for platform service instances |
|
||||
|
|
||||
Loading…
Reference in new issue