Browse Source

docs: add plugin state sync, time update logic, and component extraction

- Update initialization to sync with plugin state on mount (checks for pre-existing schedules)
- Add updateNotificationTime() method to update schedule when time changes (cancel old, schedule new)
- Extract DailyNotificationSection into dedicated component using vue-facing-decorator
- Update component architecture to show DailyNotificationSection.vue structure
- Update Phase 2 tasks to reflect component creation and AccountViewView integration
- Add acceptance criteria for plugin state sync and time update functionality
- Update verification checklist with new requirements
pull/214/head
Matthew Raymer 1 week ago
parent
commit
45eff4a9ac
  1. 199
      doc/daily-notification-plugin-integration-plan.md

199
doc/daily-notification-plugin-integration-plan.md

@ -255,18 +255,58 @@ export interface NativeFetcherConfig {
#### Views Structure #### Views Structure
``` ```
src/views/ src/views/
└── AccountViewView.vue (existing - add Daily Notifications section) └── AccountViewView.vue (existing - add DailyNotificationSection component)
``` ```
#### Supporting Components (Optional - Only if AccountViewView needs extraction) #### Supporting Components
``` ```
src/components/notifications/ (optional) src/components/notifications/
├── NotificationToggle.vue (optional - extract toggle if AccountViewView too long) └── DailyNotificationSection.vue (required - extracted section component)
├── NotificationTimePicker.vue (optional - extract time picker if needed)
└── NotificationStatusDisplay.vue (optional - extract status display if needed)
``` ```
**Note**: Supporting components should only be created if AccountViewView exceeds reasonable length limits (>200 lines). Keep everything in AccountViewView if possible. **Component Structure**: `DailyNotificationSection.vue` will use vue-facing-decorator with ES6 classes
```vue
<template>
<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"
>
<!-- Daily Notifications UI -->
</section>
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { logger } from "@/utils/logger";
/**
* DailyNotificationSection Component
*
* A self-contained component for managing daily notification scheduling
* in AccountViewView. This component handles platform detection, permission
* requests, scheduling, and state management for daily notifications.
*
* Features:
* - Platform capability detection (hides on unsupported platforms)
* - Permission request flow
* - Schedule/cancel notifications
* - Time editing with HTML5 time input
* - Settings persistence
* - Plugin state synchronization
*/
@Component({
name: "DailyNotificationSection",
mixins: [PlatformServiceMixin],
})
export default class DailyNotificationSection extends Vue {
// Component implementation here
}
</script>
```
--- ---
@ -422,7 +462,7 @@ function getTimeFromInput(timeInput: string): string {
### Data Flow ### Data Flow
#### 1. Initialization #### 1. Initialization (Sync with Plugin State)
```typescript ```typescript
async initializeState() { async initializeState() {
@ -440,7 +480,26 @@ async initializeState() {
this.notificationsSupported = true; this.notificationsSupported = true;
// Load from settings // CRITICAL: Sync with plugin state first (source of truth)
// Plugin may have an existing schedule even if settings don't
if (status.isScheduled && status.scheduledTime) {
// Plugin has a scheduled notification - sync UI to match
this.nativeNotificationEnabled = true;
this.nativeNotificationTimeStorage = status.scheduledTime;
this.nativeNotificationTime = formatTimeForDisplay(status.scheduledTime);
// Also sync settings to match plugin state
const settings = await this.$accountSettings();
if (settings.nativeNotificationTime !== status.scheduledTime) {
await this.$saveSettings({
nativeNotificationTime: status.scheduledTime,
nativeNotificationTitle: settings.nativeNotificationTitle || this.nativeNotificationTitle,
nativeNotificationMessage: settings.nativeNotificationMessage || this.nativeNotificationMessage,
});
}
} else {
// No plugin schedule - check settings for user preference
const settings = await this.$accountSettings();
const nativeNotificationTime = settings.nativeNotificationTime || ""; const nativeNotificationTime = settings.nativeNotificationTime || "";
this.nativeNotificationEnabled = !!nativeNotificationTime; this.nativeNotificationEnabled = !!nativeNotificationTime;
this.nativeNotificationTimeStorage = nativeNotificationTime; this.nativeNotificationTimeStorage = nativeNotificationTime;
@ -448,12 +507,19 @@ async initializeState() {
if (nativeNotificationTime) { if (nativeNotificationTime) {
this.nativeNotificationTime = formatTimeForDisplay(nativeNotificationTime); this.nativeNotificationTime = formatTimeForDisplay(nativeNotificationTime);
} }
}
// Update UI with current status // Update UI with current status
this.notificationStatus = status; this.notificationStatus = status;
} }
``` ```
**Key Points**:
- `getDailyNotificationStatus()` is called on mount to check for pre-existing schedules
- Plugin state is the source of truth - if plugin has a schedule, UI syncs to match
- Settings are synced with plugin state if they differ
- If no plugin schedule exists, fall back to settings
#### 2. Enable Notification #### 2. Enable Notification
```typescript ```typescript
@ -529,18 +595,63 @@ async disableNativeNotification() {
} }
``` ```
#### 4. Edit Time #### 4. Edit Time (Update Schedule)
**Approach**: Use inline HTML5 time input for quick edits **Approach**: When time changes, immediately update the scheduled notification
```typescript ```typescript
async editNativeNotificationTime() { async editNativeNotificationTime() {
// Show inline HTML5 time input for quick changes // Show inline HTML5 time input for quick changes
this.showTimeEdit = true; this.showTimeEdit = true;
} }
async updateNotificationTime(newTime: string) {
// newTime is in "HH:mm" format from HTML5 time input
if (!this.nativeNotificationEnabled) {
// If notification is disabled, just save the time preference
this.nativeNotificationTimeStorage = newTime;
this.nativeNotificationTime = formatTimeForDisplay(newTime);
await this.$saveSettings({
nativeNotificationTime: newTime,
});
return;
}
// Notification is enabled - update the schedule
try {
const platformService = PlatformServiceFactory.getInstance();
// 1. Cancel existing notification
await platformService.cancelDailyNotification();
// 2. Schedule with new time
await platformService.scheduleDailyNotification({
time: newTime, // "09:00" in local time
title: this.nativeNotificationTitle,
body: this.nativeNotificationMessage,
sound: true,
priority: 'high'
});
// 3. Update local state
this.nativeNotificationTimeStorage = newTime;
this.nativeNotificationTime = formatTimeForDisplay(newTime);
// 4. Save to settings
await this.$saveSettings({
nativeNotificationTime: newTime,
});
this.notify.success("Notification time updated successfully", TIMEOUTS.SHORT);
this.showTimeEdit = false;
} catch (error) {
logger.error("Failed to update notification time:", error);
this.notify.error("Failed to update notification time. Please try again.", TIMEOUTS.LONG);
}
}
``` ```
**Implementation Note**: HTML5 time input provides native mobile picker experience when shown inline, making it ideal for quick time adjustments in AccountViewView. **Implementation Note**: HTML5 time input provides native mobile picker experience when shown inline, making it ideal for quick time adjustments. When the time changes, the notification schedule is immediately updated via PlatformService.
### Settings Schema ### Settings Schema
@ -643,39 +754,46 @@ interface Settings {
**Goals**: Integrate notification scheduling into AccountViewView with optional supporting components **Goals**: Integrate notification scheduling into AccountViewView with optional supporting components
#### Tasks #### Tasks
1. **Supporting Components (Optional)** 1. **DailyNotificationSection Component**
- [ ] Create supporting components only if AccountViewView exceeds length limits - [ ] Create `src/components/notifications/DailyNotificationSection.vue`
- [ ] Consider: `NotificationToggle.vue`, `NotificationTimePicker.vue`, `NotificationStatusDisplay.vue` - [ ] Use vue-facing-decorator with ES6 class extending Vue
- [ ] Follow project styling patterns - [ ] Add PlatformServiceMixin to component
- [ ] Add TypeScript interfaces - [ ] Implement platform capability detection on mount
- [ ] Keep components focused and reusable within AccountViewView context - [ ] Implement initialization that syncs with plugin state (checks for pre-existing schedules)
2. **AccountViewView Integration** ✅ **ACCEPTED**
- [ ] Add separate "Daily Notifications" section
- [ ] Check platform capabilities before showing UI (`v-if="notificationsSupported"`)
- [ ] Add computed property for platform capability detection
- [ ] Add toggle switch for enabling/disabling notifications - [ ] Add toggle switch for enabling/disabling notifications
- [ ] Add HTML5 time input for scheduling time - [ ] Add HTML5 time input for scheduling time
- [ ] Integrate with PlatformService via PlatformServiceFactory - [ ] Integrate with PlatformService via PlatformServiceFactory
- [ ] Save/load settings from `settings` table
- [ ] Implement time format conversion (display vs storage) - [ ] Implement time format conversion (display vs storage)
- [ ] Add enable/disable notification methods - [ ] Add enable/disable notification methods
- [ ] Add edit time functionality - [ ] Add edit time functionality with schedule update (cancel old, schedule new)
- [ ] Add permission request flow - [ ] Add permission request flow
- [ ] Add error handling and user feedback - [ ] Add error handling and user feedback
- [ ] Save/load settings from `settings` table
- [ ] Follow project styling patterns
- [ ] Add TypeScript interfaces
- [ ] Add file-level documentation
2. **AccountViewView Integration**
- [ ] Import DailyNotificationSection component
- [ ] Add component to template (minimal integration)
- [ ] Verify component renders correctly
- [ ] Test component hiding on unsupported platforms
#### Acceptance Criteria #### Acceptance Criteria
- [ ] Supporting components created only if AccountViewView exceeds length limits - [ ] DailyNotificationSection component created using vue-facing-decorator
- [ ] AccountViewView has separate "Daily Notifications" section - [ ] Component extends Vue class with PlatformServiceMixin
- [ ] **AccountViewView notification section hidden on unsupported platforms** (`v-if="notificationsSupported"`) - [ ] Component checks platform support on mount via `getDailyNotificationStatus()`
- [ ] Notification section checks PlatformService capabilities before showing - [ ] Component syncs with plugin state on initialization (checks for pre-existing schedules)
- [ ] Toggle and time input functional in AccountViewView - [ ] Component hidden on unsupported platforms (`v-if="notificationsSupported"`)
- [ ] Toggle and time input functional
- [ ] Time changes update notification schedule immediately (cancel old, schedule new)
- [ ] Settings persist across app restarts - [ ] Settings persist across app restarts
- [ ] Plugin state syncs with settings - [ ] Plugin state syncs with settings on mount
- [ ] All logging uses project logger - [ ] All logging uses project logger
- [ ] Error handling implemented - [ ] Error handling implemented
- [ ] Loading states visible - [ ] Loading states visible
- [ ] UI matches existing design patterns - [ ] UI matches existing design patterns
- [ ] AccountViewView integration is minimal (just imports and uses component)
--- ---
@ -837,16 +955,16 @@ async mounted() {
#### Components That Must Implement This Pattern #### Components That Must Implement This Pattern
1. **AccountViewView.vue**: Daily Notifications section uses `v-if="notificationsSupported"` 1. **DailyNotificationSection.vue**: Daily Notifications section uses `v-if="notificationsSupported"` and checks `getDailyNotificationStatus()` on mount
2. **Supporting components** (if created): Must check support before rendering any scheduling UI 2. **Any component providing scheduling UI**: Must verify `getDailyNotificationStatus() !== null` before showing scheduling controls
3. **Any component providing scheduling UI**: Must verify `getDailyNotificationStatus() !== null` before showing scheduling controls
#### Verification Checklist #### Verification Checklist
- [ ] AccountViewView notification section hidden via `v-if` on unsupported platforms - [ ] DailyNotificationSection checks platform support on mount and hides on unsupported platforms
- [ ] Supporting components (if created) check and hide on unsupported platforms - [ ] DailyNotificationSection syncs with plugin state on initialization (checks for pre-existing schedules)
- [ ] All components tested on Web/Electron to verify hiding works - [ ] Component tested on Web/Electron to verify hiding works
- [ ] No console errors when components are hidden - [ ] No console errors when components are hidden
- [ ] Time changes properly update notification schedule
### Code Quality Standards ### Code Quality Standards
- **Logging**: Use `logger` from `@/utils/logger`, not `console.*` - **Logging**: Use `logger` from `@/utils/logger`, not `console.*`
@ -938,8 +1056,11 @@ await platformService.scheduleDailyNotification({
- [ ] Plugin integrated using PlatformService architecture - [ ] Plugin integrated using PlatformService architecture
- [ ] Feature works on Capacitor (Android/iOS) - [ ] Feature works on Capacitor (Android/iOS)
- [ ] Feature hidden/graceful on Web/Electron - [ ] Feature hidden/graceful on Web/Electron
- [ ] AccountViewView integration complete and functional - [ ] DailyNotificationSection component created and functional
- [ ] **AccountViewView notification section hides itself on unsupported platforms** - [ ] **DailyNotificationSection hides itself on unsupported platforms**
- [ ] Component syncs with plugin state on mount (checks for pre-existing schedules)
- [ ] Time changes update notification schedule immediately
- [ ] AccountViewView integration minimal (just imports component)
- [ ] Settings persist across app restarts - [ ] Settings persist across app restarts
- [ ] Logging standardized (no console.*) - [ ] Logging standardized (no console.*)
- [ ] Error handling robust - [ ] Error handling robust

Loading…
Cancel
Save