forked from trent_larson/crowd-funder-for-time-pwa
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
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user