fix(notifications): New Activity vs Daily Reminder separation and copy
- PushNotificationPermission: show "Turn on New Activity Notifications" when enabling New Activity; use NOTIFY_PUSH_SUCCESS_NEW_ACTIVITY for success toast so copy says "New Activity notifications are now enabled." - App.vue: on native, turnOffNotifications invokes the modal's callback only (fixes turn-off not updating state); add comment that callback is per notification type. - AccountViewView: handle plugin UNIMPLEMENTED for scheduleDualNotification on iOS with friendlier message; add New Activity time block and "Edit New Activity Notification…"; rename Daily Reminder button to "Edit Daily Reminder…". - Constants: add NOTIFY_PUSH_SUCCESS_NEW_ACTIVITY. Reminder IDs and Option A (skip single reminder for New Activity) from earlier commit.
This commit is contained in:
19
src/App.vue
19
src/App.vue
@@ -360,6 +360,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-facing-decorator";
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
|
||||
import { NotificationIface } from "./constants/app";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
@@ -382,6 +383,24 @@ export default class App extends Vue {
|
||||
async turnOffNotifications(
|
||||
notification: NotificationIface,
|
||||
): Promise<boolean> {
|
||||
// On native (iOS/Android) we don't use web push; the callback handles cancel + state in the view.
|
||||
// The callback is the one passed for this specific modal (New Activity or Daily Reminder), so we only turn off that one.
|
||||
if (Capacitor.isNativePlatform()) {
|
||||
if (notification.callback) {
|
||||
await notification.callback(true);
|
||||
}
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Finished",
|
||||
text: "Notifications are off.",
|
||||
},
|
||||
5000,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
let subscription: PushSubscriptionJSON | null = null;
|
||||
let allGoingOff = false;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white mt-2 px-2 py-2 rounded-md"
|
||||
@click="handleTurnOnNotifications"
|
||||
>
|
||||
Turn on Daily Reminder
|
||||
{{ isDailyCheck ? "Turn on New Activity Notifications" : "Turn on Daily Reminder" }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -95,6 +95,7 @@ import {
|
||||
NOTIFY_PUSH_PERMISSION_ERROR,
|
||||
NOTIFY_PUSH_SETUP_UNDERWAY,
|
||||
NOTIFY_PUSH_SUCCESS,
|
||||
NOTIFY_PUSH_SUCCESS_NEW_ACTIVITY,
|
||||
NOTIFY_PUSH_SETUP_ERROR,
|
||||
NOTIFY_PUSH_SUBSCRIPTION_ERROR,
|
||||
PUSH_NOTIFICATION_TIMEOUT_SHORT,
|
||||
@@ -775,8 +776,8 @@ export default class PushNotificationPermission extends Vue {
|
||||
{
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: NOTIFY_PUSH_SUCCESS.title,
|
||||
text: NOTIFY_PUSH_SUCCESS.message,
|
||||
title: NOTIFY_PUSH_SUCCESS_NEW_ACTIVITY.title,
|
||||
text: NOTIFY_PUSH_SUCCESS_NEW_ACTIVITY.message,
|
||||
},
|
||||
PUSH_NOTIFICATION_TIMEOUT_LONG,
|
||||
);
|
||||
|
||||
@@ -1640,12 +1640,18 @@ export const NOTIFY_PUSH_SETUP_UNDERWAY = {
|
||||
"Setting up notifications for interesting activity, which takes about 10 seconds. If you don't see a final confirmation, check the 'Troubleshoot' page.",
|
||||
};
|
||||
|
||||
// Used in: PushNotificationPermission.vue (turnOnNotifications method - success)
|
||||
// Used in: PushNotificationPermission.vue (turnOnNotifications method - success, Daily Reminder)
|
||||
export const NOTIFY_PUSH_SUCCESS = {
|
||||
title: "Notifications On",
|
||||
message: "Daily Reminder notifications are now enabled.",
|
||||
};
|
||||
|
||||
// Used in: PushNotificationPermission.vue (turnOnNotifications method - success, New Activity only)
|
||||
export const NOTIFY_PUSH_SUCCESS_NEW_ACTIVITY = {
|
||||
title: "Notifications On",
|
||||
message: "New Activity notifications are now enabled.",
|
||||
};
|
||||
|
||||
// Used in: PushNotificationPermission.vue (turnOnNotifications method - general error)
|
||||
export const NOTIFY_PUSH_SETUP_ERROR = {
|
||||
title: "Error Setting Notification Permissions",
|
||||
|
||||
@@ -139,11 +139,11 @@
|
||||
class="w-full text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md"
|
||||
@click="editReminderNotification"
|
||||
>
|
||||
Edit Notification Details…
|
||||
Edit Daily Reminder…
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="flex items-center justify-between mt-4 mb-2">
|
||||
<!-- label -->
|
||||
<div>
|
||||
New Activity Notification
|
||||
@@ -178,8 +178,22 @@
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="notifyingNewActivityTime" class="w-full text-right">
|
||||
{{ notifyingNewActivityTime.replace(" ", " ") }}
|
||||
<div v-if="notifyingNewActivity" class="w-full">
|
||||
<div
|
||||
class="text-sm text-slate-500 mb-2 bg-white rounded px-3 py-2 border border-slate-200"
|
||||
>
|
||||
<div>
|
||||
<b>Time:</b> {{ notifyingNewActivityTime.replace(" ", " ") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-center">
|
||||
<button
|
||||
class="w-full text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md"
|
||||
@click="editNewActivityNotification"
|
||||
>
|
||||
Edit New Activity Notification…
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-center">
|
||||
<router-link class="text-sm text-blue-500" to="/help-notifications">
|
||||
@@ -1244,6 +1258,19 @@ export default class AccountViewView extends Vue {
|
||||
* Configure native fetcher, sync starred plans, and schedule API-driven dual notification.
|
||||
*/
|
||||
async scheduleNewActivityDualNotification(notifyTime: string): Promise<void> {
|
||||
const plugin = DailyNotification as unknown as {
|
||||
scheduleDualNotification?: (opts: { config: unknown }) => Promise<void>;
|
||||
};
|
||||
if (!plugin.scheduleDualNotification) {
|
||||
logger.warn(
|
||||
"[AccountViewView] scheduleDualNotification not available on this device",
|
||||
);
|
||||
this.notify.error(
|
||||
"New Activity scheduling is not available on this device. Please update the app.",
|
||||
TIMEOUTS.STANDARD,
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await configureNativeFetcherIfReady(this.activeDid);
|
||||
const settings = await this.$accountSettings();
|
||||
@@ -1252,22 +1279,24 @@ export default class AccountViewView extends Vue {
|
||||
await DailyNotification.updateStarredPlans({ planIds });
|
||||
}
|
||||
const config = buildDualScheduleConfig({ notifyTime });
|
||||
await (
|
||||
DailyNotification as unknown as {
|
||||
scheduleDualNotification: (opts: {
|
||||
config: unknown;
|
||||
}) => Promise<void>;
|
||||
}
|
||||
).scheduleDualNotification({ config });
|
||||
await plugin.scheduleDualNotification!({ config });
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
"[AccountViewView] scheduleNewActivityDualNotification failed:",
|
||||
error,
|
||||
);
|
||||
this.notify.error(
|
||||
"Could not schedule New Activity notification. Please try again.",
|
||||
TIMEOUTS.STANDARD,
|
||||
);
|
||||
const code = (error as { code?: string })?.code;
|
||||
if (code === "UNIMPLEMENTED") {
|
||||
this.notify.error(
|
||||
"New Activity scheduling is not yet available on this device. Please update the app when support is added.",
|
||||
TIMEOUTS.STANDARD,
|
||||
);
|
||||
} else {
|
||||
this.notify.error(
|
||||
"Could not schedule New Activity notification. Please try again.",
|
||||
TIMEOUTS.STANDARD,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1468,6 +1497,56 @@ export default class AccountViewView extends Vue {
|
||||
}, 150);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit existing New Activity notification time.
|
||||
* Opens the dialog with current time; on success reschedules dual notification.
|
||||
*/
|
||||
async editNewActivityNotification(): Promise<void> {
|
||||
const dialog = this.$refs
|
||||
.pushNotificationPermission as PushNotificationPermission;
|
||||
|
||||
dialog.open(
|
||||
DAILY_CHECK_TITLE,
|
||||
async (success: boolean, timeText: string) => {
|
||||
if (!success) return;
|
||||
if (Capacitor.isNativePlatform()) {
|
||||
await this.scheduleNewActivityDualNotification(timeText);
|
||||
}
|
||||
await this.$saveSettings({ notifyingNewActivityTime: timeText });
|
||||
this.notifyingNewActivityTime = timeText;
|
||||
this.notify.success(
|
||||
"New Activity notification time updated.",
|
||||
TIMEOUTS.STANDARD,
|
||||
);
|
||||
},
|
||||
{ skipSchedule: true },
|
||||
);
|
||||
|
||||
// Pre-populate the dialog with current New Activity time
|
||||
setTimeout(() => {
|
||||
const timeMatch = this.notifyingNewActivityTime.match(
|
||||
/(\d+):(\d+)\s*(AM|PM)/i,
|
||||
);
|
||||
if (timeMatch) {
|
||||
let hour = parseInt(timeMatch[1], 10);
|
||||
const minute = timeMatch[2];
|
||||
const isAm = timeMatch[3].toUpperCase() === "AM";
|
||||
if (hour === 12) {
|
||||
hour = 12;
|
||||
} else if (hour > 12) {
|
||||
hour = hour - 12;
|
||||
}
|
||||
const dialogComponent =
|
||||
dialog as unknown as PushNotificationPermissionRef;
|
||||
if (dialogComponent) {
|
||||
dialogComponent.hourInput = hour.toString();
|
||||
dialogComponent.minuteInput = minute;
|
||||
dialogComponent.hourAm = isAm;
|
||||
}
|
||||
}
|
||||
}, 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.
|
||||
|
||||
Reference in New Issue
Block a user