From af63ab70e7b456357e366716340bda0f5796ba53 Mon Sep 17 00:00:00 2001 From: Jose Olarte III Date: Tue, 3 Mar 2026 21:31:07 +0800 Subject: [PATCH] feat(notifications): add dev/test 10-minute rollover toggle and plugin spec - Add dev-only "Use 10-minute rollover (testing)" toggle in Reminder Notifications (Account view). Visible only when not on prod API server (isNotProdServer). Toggle persists and reschedules reminder with rolloverIntervalMinutes when changed. - Extend daily notification flow to pass optional rolloverIntervalMinutes to the plugin: NotificationService/NativeNotificationService options, PushNotificationPermission dialog options, first-time and edit flows. - Add settings: reminderFastRolloverForTesting (Settings, AccountSettings, PlatformServiceMixin boolean mapping, migration 007). - Centralize isNotProdServer(apiServer) in constants/app.ts; use in AccountViewView (toggle visibility), ImportAccountView, and TestView. - Add docs/plugin-spec-rollover-interval-minutes.md for the plugin repo (configurable rollover interval and persistence after reboot). Note: Daily notification plugin dependency is currently pointed at the "rollover-interval" branch for testing this feature. --- docs/plugin-spec-rollover-interval-minutes.md | 148 ++++++++++++++++++ package-lock.json | 6 +- package.json | 2 +- src/components/PushNotificationPermission.vue | 9 +- src/constants/app.ts | 8 + src/db-sql/migration.ts | 7 + src/db/tables/settings.ts | 2 + src/interfaces/accountView.ts | 1 + .../NativeNotificationService.ts | 5 + .../notifications/NotificationService.ts | 7 + src/utils/PlatformServiceMixin.ts | 1 + src/views/AccountViewView.vue | 101 +++++++++++- src/views/ImportAccountView.vue | 8 +- src/views/TestView.vue | 8 +- 14 files changed, 302 insertions(+), 11 deletions(-) create mode 100644 docs/plugin-spec-rollover-interval-minutes.md diff --git a/docs/plugin-spec-rollover-interval-minutes.md b/docs/plugin-spec-rollover-interval-minutes.md new file mode 100644 index 00000000..aff99696 --- /dev/null +++ b/docs/plugin-spec-rollover-interval-minutes.md @@ -0,0 +1,148 @@ +# Plugin spec: Configurable rollover interval (e.g. 10 minutes for testing) + +**Date:** 2026-03-03 +**Target repo:** daily-notification-plugin +**Consuming app:** crowd-funder-for-time-pwa (TimeSafari) +**Platforms:** iOS and Android + +## Summary + +The consuming app needs to support **rapid testing** of daily notification rollover on device. Today, after a notification fires, the plugin always schedules the next occurrence **24 hours** later. We need an **optional** parameter so the app can request a different interval (e.g. **10 minutes**) for dev/testing. When that parameter is present, the plugin must: + +1. Use the given interval (in minutes) when scheduling the **next** occurrence after a notification fires (rollover). +2. **Persist** that interval with the schedule so that it survives **device reboot** and is used again when: + - Boot recovery reschedules alarms from stored data, and + - Any subsequent rollover runs (after the next notification fires). + +If the interval is not persisted, then after a device restart the plugin would no longer know to use 10 minutes and would fall back to 24 hours; rapid testing after reboot would break. So persistence is a **required** part of this feature. + +--- + +## API contract (app → plugin) + +### Method: `scheduleDailyNotification` (or equivalent used for the app’s daily reminder) + +**Add an optional parameter:** + +- **Name:** `rolloverIntervalMinutes` (or equivalent, e.g. `repeatIntervalMinutes`). +- **Type:** `number` (integer), optional. +- **Meaning:** When the scheduled notification fires, schedule the **next** occurrence this many **minutes** after the current trigger time (instead of 24 hours). When **absent** or not provided, behavior is unchanged: next occurrence is **24 hours** later (current behavior). + +**Example (pseudocode):** + +- App calls: `scheduleDailyNotification({ id, time, title, body, ..., rolloverIntervalMinutes: 10 })`. +- Plugin stores the schedule **including** `rolloverIntervalMinutes: 10`. +- When the notification fires, plugin computes next trigger = current trigger + 10 minutes (instead of + 24 hours), and schedules that. +- When the device reboots, boot recovery loads the schedule, sees `rolloverIntervalMinutes: 10`, and uses it when (a) computing the next run time for reschedule and (b) any future rollover after the next fire. + +**Example (normal production, no param):** + +- App calls: `scheduleDailyNotification({ id, time, title, body })` (no `rolloverIntervalMinutes`). +- Plugin stores the schedule with no interval (or default 24h). +- Rollover and boot recovery behave as today: next occurrence 24 hours later. + +--- + +## Persistence requirement (critical for device restart) + +The rollover interval must be **stored with the schedule** in the plugin’s persistent storage (e.g. Room on Android, UserDefaults/DB on iOS), not only kept in memory. Concretely: + +1. **When the app calls `scheduleDailyNotification` with `rolloverIntervalMinutes`:** + - Persist that value in the same place you persist the rest of the schedule (e.g. Schedule entity, or equivalent table/row that is read on boot and on rollover). + +2. **When computing the next occurrence (rollover path, after a notification fires):** + - Read the stored `rolloverIntervalMinutes` for that schedule. + - If present and > 0: next trigger = current trigger + `rolloverIntervalMinutes` minutes. + - If absent or 0: next trigger = current trigger + 24 hours (existing behavior). + +3. **When boot recovery runs (after device restart):** + - Load schedules from persistent storage (including the stored `rolloverIntervalMinutes`). + - When rescheduling each alarm, use the stored interval to compute the next run time (same logic as rollover: if interval is set, use it; otherwise 24 hours). + - When the next notification fires after reboot, the rollover path will again read the same stored value, so the 10-minute (or whatever) interval continues to apply. + +4. **When the app calls `scheduleDailyNotification` without `rolloverIntervalMinutes` (or to turn off fast rollover):** + - Overwrite the stored schedule so that the interval is cleared or set to default (24h). Subsequent rollovers and boot recovery then use 24 hours again. + +**Why this matters:** Without persisting the interval, a device restart would lose the “10 minutes” setting; rollover and boot recovery would have no way to know to use 10 minutes and would default to 24 hours. Rapid testing after reboot would not work. + +--- + +## Platform-specific notes + +### Android + +- **Storage:** Add `rollover_interval_minutes` (or equivalent) to the Schedule entity (or wherever the app’s reminder schedule is stored) and persist it when handling `scheduleDailyNotification`. Use it in: + - Rollover path (e.g. when scheduling next alarm after notification fires). + - Boot recovery path (when rebuilding alarms from DB after `BOOT_COMPLETED`). +- **Next trigger:** Current trigger time + `rolloverIntervalMinutes` minutes (using `Calendar` or equivalent so DST/timezone is handled correctly; same care as for 24h rollover). + +### iOS + +- **Storage:** Add the same field to whatever persistent structure holds the schedule (e.g. the same place that stores time, title, body, id). Persist it when the app calls the schedule method. +- **Rollover:** In `scheduleNextNotification()` (or equivalent), read the stored interval; if set, use `Calendar.date(byAdding: .minute, value: rolloverIntervalMinutes, to: currentDate)` (or equivalent) instead of adding 24 hours. +- **App launch / recovery:** If the plugin has any path that restores or reschedules after app launch or system events, use the stored interval there as well so behavior is consistent. + +--- + +## Edge cases and defaults + +- **Parameter absent:** Do not change current behavior. Next occurrence = 24 hours later. +- **Parameter = 0 or negative:** Treat as “use default”; same as absent (24 hours). +- **Parameter > 0 (e.g. 10):** Next occurrence = current trigger + that many minutes. +- **Existing schedules (created before this feature):** No stored interval → treat as 24 hours. No migration required beyond “missing field = default”. + +--- + +## App-side behavior (for context) + +- The app will only pass `rolloverIntervalMinutes` when a **dev-only** setting is enabled (e.g. “Use 10-minute rollover for testing” in the Reminder Notifications section). Production users will not set it. +- The app will pass it on every `scheduleDailyNotification` call when the user has that setting on (first-time enable and edit). When the user turns the setting off, the app will call `scheduleDailyNotification` without the parameter (so the plugin can persist “no interval” / 24h). + +--- + +## Verification (plugin repo) + +1. **Rollover with interval:** Schedule with `rolloverIntervalMinutes: 10`. Trigger the notification (or wait). Confirm the **next** scheduled time is ~10 minutes after the current trigger (not 24 hours). Let it fire again; confirm the following occurrence is again ~10 minutes later. +2. **Persistence:** Schedule with `rolloverIntervalMinutes: 10`, then **restart the device** (do not open the app). After boot, confirm (via logs or next fire) that the rescheduled alarm uses the 10-minute interval (e.g. next fire is 10 minutes after the last stored trigger, not 24 hours). After that notification fires, confirm the **next** rollover is still 10 minutes later. +3. **Default:** Schedule without `rolloverIntervalMinutes`. Confirm next occurrence is 24 hours later. Reboot; confirm boot recovery still uses 24 hours. +4. **Turn off:** Schedule with 10 minutes, then have the app call `scheduleDailyNotification` again with the same id/time but **no** `rolloverIntervalMinutes`. Confirm stored interval is cleared and next rollover is 24 hours. + +--- + +## Short summary for plugin maintainers + +- **New optional parameter:** `rolloverIntervalMinutes?: number` on the schedule method used for the app’s daily reminder. +- **When set (e.g. 10):** After a notification fires, schedule the next occurrence in that many **minutes** instead of 24 hours. +- **Must persist:** Store the value with the schedule in the plugin’s DB/storage. Use it in **rollover** and in **boot recovery** so that after a device restart the same interval is used. Without persistence, the feature would not work after reboot. +- **When absent:** Behavior unchanged (24-hour rollover). No migration needed for existing schedules. + +--- + +## For Cursor (plugin repo) — actionable handoff + +Use this section when implementing this feature in the **daily-notification-plugin** repo (e.g. with Cursor). You can paste or @-mention this doc as context. + +**Goal:** Support an optional `rolloverIntervalMinutes` (or equivalent) on the daily reminder schedule API. When provided (e.g. `10`), schedule the next occurrence that many minutes after the current trigger instead of 24 hours. **Persist this value** with the schedule so that rollover and boot recovery both use it; after a device restart, the same interval must still apply. + +**Concrete tasks:** + +1. **API:** In the plugin interface used by the app (e.g. `scheduleDailyNotification`), add an optional parameter `rolloverIntervalMinutes?: number`. Document that when absent, next occurrence is 24 hours (current behavior). + +2. **Storage (Android):** In the Schedule entity (or equivalent), add a column/field for the rollover interval (e.g. `rollover_interval_minutes` nullable Int). When handling `scheduleDailyNotification`, persist the value if present; if absent, store null or 0 to mean “24 hours”. + +3. **Storage (iOS):** Add the same field to the persistent structure that holds the reminder schedule. Persist it when the app calls the schedule method. + +4. **Rollover (both platforms):** In the code that runs when a scheduled notification fires and schedules the next occurrence: + - Read the stored `rolloverIntervalMinutes` for that schedule. + - If present and > 0: next trigger = current trigger + that many minutes (using Calendar/date APIs that respect timezone/DST). + - Else: next trigger = current trigger + 24 hours (existing behavior). + - Persist the same interval on the new schedule record so the next rollover still uses it. + +5. **Boot recovery (both platforms):** In the path that runs after device reboot and reschedules from stored data: + - Load the stored `rolloverIntervalMinutes` with each schedule. + - When computing “next run time” for reschedule, use the same logic: if interval set, current trigger + that many minutes; else + 24 hours. + - Do not rely on in-memory state; always read from persisted storage so behavior is correct after restart. + +6. **Clearing the interval:** When the app calls `scheduleDailyNotification` without `rolloverIntervalMinutes` (e.g. user turned off “fast rollover” in the app), overwrite the stored schedule so the interval field is null/0. Subsequent rollovers and boot recovery then use 24 hours. + +7. **Tests:** Add or extend tests for: (a) rollover with 10 minutes, (b) boot recovery with stored 10-minute interval, (c) default 24h when parameter absent or cleared. diff --git a/package-lock.json b/package-lock.json index a4f0d5a4..67773f35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,7 @@ "@pvermeer/dexie-encrypted-addon": "^3.0.0", "@simplewebauthn/browser": "^10.0.0", "@simplewebauthn/server": "^10.0.0", - "@timesafari/daily-notification-plugin": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#master", + "@timesafari/daily-notification-plugin": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#rollover-interval", "@tweenjs/tween.js": "^21.1.1", "@types/qrcode": "^1.5.5", "@veramo/core": "^5.6.0", @@ -8651,8 +8651,8 @@ } }, "node_modules/@timesafari/daily-notification-plugin": { - "version": "1.2.1", - "resolved": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#aa0eaa5389f67709240b88ad5955b2c89a7abf9e", + "version": "1.3.0", + "resolved": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#27144800706094d292115737de3095a7959e8090", "license": "MIT", "workspaces": [ "packages/*" diff --git a/package.json b/package.json index 873e1c3d..8ceecfc5 100644 --- a/package.json +++ b/package.json @@ -151,7 +151,7 @@ "@capacitor/share": "^6.0.3", "@capacitor/status-bar": "^6.0.2", "@capawesome/capacitor-file-picker": "^6.2.0", - "@timesafari/daily-notification-plugin": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#master", + "@timesafari/daily-notification-plugin": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#rollover-interval", "@dicebear/collection": "^5.4.1", "@dicebear/core": "^5.4.1", "@ethersproject/hdnode": "^5.7.0", diff --git a/src/components/PushNotificationPermission.vue b/src/components/PushNotificationPermission.vue index 96c236ad..99792c7e 100644 --- a/src/components/PushNotificationPermission.vue +++ b/src/components/PushNotificationPermission.vue @@ -158,6 +158,8 @@ export default class PushNotificationPermission extends Vue { pushType = ""; /** When true, dialog only returns time/message to parent; parent does cancel+schedule (avoids double schedule on edit). */ skipScheduleForOpen = false; + /** When set (e.g. 10), passed to plugin for dev/test fast rollover. */ + rolloverIntervalMinutesForSchedule: number | undefined = undefined; serviceWorkerReady = false; vapidKey = ""; @@ -171,12 +173,13 @@ export default class PushNotificationPermission extends Vue { async open( pushType: string, callback?: (success: boolean, time: string, message?: string) => void, - options?: { skipSchedule?: boolean }, + options?: { skipSchedule?: boolean; rolloverIntervalMinutes?: number }, ) { this.callback = callback || this.callback; this.isVisible = true; this.pushType = pushType; this.skipScheduleForOpen = options?.skipSchedule ?? false; + this.rolloverIntervalMinutesForSchedule = options?.rolloverIntervalMinutes; // Native platforms: Skip web push initialization if (this.isNativePlatform) { @@ -805,6 +808,10 @@ export default class PushNotificationPermission extends Vue { title, body, priority: "normal", + ...(this.rolloverIntervalMinutesForSchedule != null && + this.rolloverIntervalMinutesForSchedule > 0 + ? { rolloverIntervalMinutes: this.rolloverIntervalMinutesForSchedule } + : {}), }); if (!success) { diff --git a/src/constants/app.ts b/src/constants/app.ts index 8a393b34..8d3cbdb6 100644 --- a/src/constants/app.ts +++ b/src/constants/app.ts @@ -49,6 +49,14 @@ export const DEFAULT_PUSH_SERVER = export const IMAGE_TYPE_PROFILE = "profile"; +/** + * True when the current API server is not production (test/local build). + * Use this to show dev/test-only UI (e.g. 10-minute rollover toggle, test user mnemonic). + */ +export function isNotProdServer(apiServer: string): boolean { + return apiServer !== AppString.PROD_ENDORSER_API_SERVER; +} + export const PASSKEYS_ENABLED = !!import.meta.env.VITE_PASSKEYS_ENABLED || false; diff --git a/src/db-sql/migration.ts b/src/db-sql/migration.ts index bdc6abe3..4bef3d74 100644 --- a/src/db-sql/migration.ts +++ b/src/db-sql/migration.ts @@ -213,6 +213,13 @@ const MIGRATIONS = [ CREATE INDEX idx_contact_labels_did ON contact_labels(did); `, }, + { + name: "007_add_reminderFastRolloverForTesting_to_settings", + sql: ` + -- Dev/test only: 10-minute rollover for daily reminder (plugin rolloverIntervalMinutes) + ALTER TABLE settings ADD COLUMN reminderFastRolloverForTesting BOOLEAN DEFAULT FALSE; + `, + }, ]; /** diff --git a/src/db/tables/settings.ts b/src/db/tables/settings.ts index 493e4596..7e97e09a 100644 --- a/src/db/tables/settings.ts +++ b/src/db/tables/settings.ts @@ -52,6 +52,8 @@ export type Settings = { notifyingNewActivityTime?: string; // set to their chosen time if they have turned on daily check for new activity via the push server notifyingReminderMessage?: string; // set to their chosen message for a daily reminder notifyingReminderTime?: string; // set to their chosen time for a daily reminder + /** Dev/test only: use 10-minute rollover interval for daily reminder (plugin rolloverIntervalMinutes) */ + reminderFastRolloverForTesting?: boolean; partnerApiServer?: string; // partner server API URL diff --git a/src/interfaces/accountView.ts b/src/interfaces/accountView.ts index 46c2c768..b4a336dc 100644 --- a/src/interfaces/accountView.ts +++ b/src/interfaces/accountView.ts @@ -33,6 +33,7 @@ export interface AccountSettings { notifyingNewActivityTime?: string; notifyingReminderMessage?: string; notifyingReminderTime?: string; + reminderFastRolloverForTesting?: boolean; partnerApiServer?: string; profileImageUrl?: string; showContactGivesInline?: boolean; diff --git a/src/services/notifications/NativeNotificationService.ts b/src/services/notifications/NativeNotificationService.ts index bd9e8b64..f3101a20 100644 --- a/src/services/notifications/NativeNotificationService.ts +++ b/src/services/notifications/NativeNotificationService.ts @@ -360,6 +360,7 @@ export class NativeNotificationService implements NotificationServiceInterface { sound: boolean; priority: "low" | "default" | "high"; id: string; + rolloverIntervalMinutes?: number; } = { time: options.time, title: options.title, @@ -367,6 +368,10 @@ export class NativeNotificationService implements NotificationServiceInterface { sound: true, priority: (options.priority || "normal") as "low" | "default" | "high", id: this.reminderId, + ...(options.rolloverIntervalMinutes != null && + options.rolloverIntervalMinutes > 0 + ? { rolloverIntervalMinutes: options.rolloverIntervalMinutes } + : {}), }; logger.debug( "[NativeNotificationService] Calling scheduleDailyNotification with options:", diff --git a/src/services/notifications/NotificationService.ts b/src/services/notifications/NotificationService.ts index 7d9090da..fa9d25f4 100644 --- a/src/services/notifications/NotificationService.ts +++ b/src/services/notifications/NotificationService.ts @@ -42,6 +42,13 @@ export interface DailyNotificationOptions { * @default 'normal' */ priority?: "low" | "normal" | "high"; + + /** + * Optional rollover interval in minutes (e.g. 10 for testing). When set, next occurrence + * is scheduled this many minutes after the current trigger instead of 24 hours. + * Plugin must support and persist this for it to take effect after reboot. + */ + rolloverIntervalMinutes?: number; } /** diff --git a/src/utils/PlatformServiceMixin.ts b/src/utils/PlatformServiceMixin.ts index 395934e9..da460383 100644 --- a/src/utils/PlatformServiceMixin.ts +++ b/src/utils/PlatformServiceMixin.ts @@ -296,6 +296,7 @@ export const PlatformServiceMixin = { column === "showShortcutBvc" || column === "warnIfProdServer" || column === "warnIfTestServer" || + column === "reminderFastRolloverForTesting" || // contacts column === "iViewContent" || column === "registered" || diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 1cce53a5..4d75ca08 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -143,6 +143,29 @@ + +
@@ -780,6 +803,7 @@ import { DEFAULT_PARTNER_API_SERVER, DEFAULT_PUSH_SERVER, IMAGE_TYPE_PROFILE, + isNotProdServer as isNotProdServerUtil, NotificationIface, PASSKEYS_ENABLED, } from "../constants/app"; @@ -824,7 +848,7 @@ interface PushNotificationPermissionRef { open: ( title: string, callback: (success: boolean, timeText: string, message?: string) => void, - options?: { skipSchedule?: boolean }, + options?: { skipSchedule?: boolean; rolloverIntervalMinutes?: number }, ) => void; hourInput?: string; minuteInput?: string; @@ -899,6 +923,8 @@ export default class AccountViewView extends Vue { notifyingReminderTime: string = ""; /** Guard: only one edit-reminder schedule per user action (avoids double schedule on Android). */ editReminderScheduleInProgress: boolean = false; + /** Dev/test only: use 10-minute rollover for daily reminder (plugin rolloverIntervalMinutes). */ + reminderFastRolloverForTesting: boolean = false; subscription: PushSubscription | null = null; // UI state properties @@ -934,6 +960,14 @@ export default class AccountViewView extends Vue { return Capacitor.isNativePlatform(); } + /** + * True when not on prod API server (test/local), so dev-only UI (e.g. 10-minute rollover toggle) is shown. + * Matches logic used in ImportAccountView and TestView. + */ + private get isNotProdServer(): boolean { + return isNotProdServerUtil(this.apiServer); + } + created() { this.notify = createNotifyHelpers(this.$notify); @@ -1081,6 +1115,8 @@ export default class AccountViewView extends Vue { this.notifyingReminder = !!settings.notifyingReminderTime; this.notifyingReminderMessage = settings.notifyingReminderMessage || ""; this.notifyingReminderTime = settings.notifyingReminderTime || ""; + this.reminderFastRolloverForTesting = + !!settings.reminderFastRolloverForTesting; this.partnerApiServer = settings.partnerApiServer || this.partnerApiServer; this.partnerApiServerInput = settings.partnerApiServer || this.partnerApiServerInput; @@ -1232,6 +1268,11 @@ export default class AccountViewView extends Vue { this.notifyingReminderTime = timeText; } }, + { + rolloverIntervalMinutes: this.reminderFastRolloverForTesting + ? 10 + : undefined, + }, ); } else { // On native platforms, handle notification cancellation directly @@ -1323,6 +1364,9 @@ export default class AccountViewView extends Vue { title, body, priority: "normal", + ...(this.reminderFastRolloverForTesting + ? { rolloverIntervalMinutes: 10 } + : {}), }); if (scheduleSuccess) { @@ -1349,7 +1393,12 @@ export default class AccountViewView extends Vue { this.editReminderScheduleInProgress = false; } }, - { skipSchedule: true }, + { + skipSchedule: true, + rolloverIntervalMinutes: this.reminderFastRolloverForTesting + ? 10 + : undefined, + }, ); // Pre-populate the form with current values after dialog opens @@ -1388,6 +1437,54 @@ export default class AccountViewView extends Vue { }, 150); } + /** + * Toggle dev-only 10-minute rollover for daily reminder. Saves the setting and, + * if reminder is already on, reschedules so the plugin uses the new interval. + */ + async toggleReminderFastRollover(): Promise { + const next = !this.reminderFastRolloverForTesting; + await this.$saveSettings({ + reminderFastRolloverForTesting: next, + }); + this.reminderFastRolloverForTesting = next; + + if (this.notifyingReminder) { + try { + const service = NotificationService.getInstance(); + if (Capacitor.getPlatform() !== "android") { + await service.cancelDailyNotification(); + } + const time24h = this.parseTimeTo24Hour(this.notifyingReminderTime); + const title = "Daily Reminder"; + const body = + this.notifyingReminderMessage || + "Click to share some gratitude with the world -- even if they're unnamed."; + await service.scheduleDailyNotification({ + time: time24h, + title, + body, + priority: "normal", + ...(next ? { rolloverIntervalMinutes: 10 } : {}), + }); + this.notify.success( + next + ? "Reminder will repeat every 10 minutes (testing)." + : "Reminder will repeat daily (24h).", + TIMEOUTS.STANDARD, + ); + } catch (err) { + logger.error( + "[AccountViewView] Reschedule after fast-rollover toggle failed:", + err, + ); + this.notify.error( + "Failed to update reminder interval. Please try again.", + TIMEOUTS.STANDARD, + ); + } + } + } + /** * Parse time string (e.g., "5:22 PM") to 24-hour format (e.g., "17:22") */ diff --git a/src/views/ImportAccountView.vue b/src/views/ImportAccountView.vue index 08d55ee2..56f963db 100644 --- a/src/views/ImportAccountView.vue +++ b/src/views/ImportAccountView.vue @@ -95,7 +95,11 @@ import { Component, Vue } from "vue-facing-decorator"; import { Router } from "vue-router"; -import { AppString, NotificationIface } from "../constants/app"; +import { + AppString, + isNotProdServer as isNotProdServerUtil, + NotificationIface, +} from "../constants/app"; import { DEFAULT_ROOT_DERIVATION_PATH } from "../libs/crypto"; import { retrieveAccountCount, @@ -194,7 +198,7 @@ export default class ImportAccountView extends Vue { * @returns True if not on production server (enables test utilities) */ public isNotProdServer() { - return this.apiServer !== AppString.PROD_ENDORSER_API_SERVER; + return isNotProdServerUtil(this.apiServer); } /** diff --git a/src/views/TestView.vue b/src/views/TestView.vue index a56b6258..ecea8c78 100644 --- a/src/views/TestView.vue +++ b/src/views/TestView.vue @@ -320,7 +320,11 @@ import { Component, Vue } from "vue-facing-decorator"; import { Router } from "vue-router"; import QuickNav from "../components/QuickNav.vue"; -import { AppString, NotificationIface } from "../constants/app"; +import { + AppString, + isNotProdServer as isNotProdServerUtil, + NotificationIface, +} from "../constants/app"; import { NOTIFY_SQL_ERROR, createSqlErrorMessage, @@ -741,7 +745,7 @@ export default class Help extends Vue { * @returns True if not on production server (enables test utilities) */ public isNotProdServer() { - return this.apiServer !== AppString.PROD_ENDORSER_API_SERVER; + return isNotProdServerUtil(this.apiServer); } async registerMe() {