From 2b6f87f0aa425c76bec1be2da13799f2dcf783f2 Mon Sep 17 00:00:00 2001
From: Trent Larson
Date: Wed, 20 Nov 2024 19:55:51 -0700
Subject: [PATCH] change the notification detection to our own variables, and
save the selected time
---
src/App.vue | 56 ++++--
src/components/PushNotificationPermission.vue | 79 ++++++--
src/components/UserNameDialog.vue | 7 +-
src/constants/app.ts | 3 +-
src/db/tables/settings.ts | 6 +-
src/router/index.ts | 5 +
src/views/AccountViewView.vue | 172 ++++++++++--------
src/views/HelpNotificationTypesView.vue | 68 +++++++
8 files changed, 286 insertions(+), 110 deletions(-)
create mode 100644 src/views/HelpNotificationTypesView.vue
diff --git a/src/App.vue b/src/App.vue
index 4210b890f..3170d8eb1 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -229,7 +229,7 @@
? notification.onCancel(stopAsking)
: null;
close(notification.id);
- stopAsking = false; // reset value
+ stopAsking = false; // reset value for next time they open this modal
"
class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
>
@@ -292,7 +292,7 @@
- Waiting for system initialization, which may take up to 5
- seconds...
+ Waiting for system initialization, which may take up to 5 seconds...
@@ -74,7 +73,12 @@
import { Component, Vue } from "vue-facing-decorator";
import { DEFAULT_PUSH_SERVER, NotificationIface } from "@/constants/app";
-import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "@/db/index";
+import {
+ db,
+ logConsoleAndDb,
+ retrieveSettingsForActiveAccount,
+} from "@/db/index";
+import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { urlBase64ToUint8Array } from "@/libs/crypto/vc/util";
import * as libsUtil from "@/libs/util";
@@ -108,8 +112,10 @@ interface VapidResponse {
@Component
export default class PushNotificationPermission extends Vue {
- $notify!: (notification: NotificationIface, timeout?: number) => void;
+ // eslint-disable-next-line
+ $notify!: (notification: NotificationIface, timeout?: number) => Promise<() => void>;
+ callback: (success: boolean, time: string) => void = () => {};
hourAm = true;
hourInput = "8";
isVisible = false;
@@ -117,8 +123,9 @@ export default class PushNotificationPermission extends Vue {
serviceWorkerReady = false;
vapidKey = "";
- async open() {
+ async open(callback?: (success: boolean, time: string) => void) {
this.isVisible = true;
+ this.callback = callback || this.callback;
try {
const settings = await retrieveSettingsForActiveAccount();
let pushUrl = DEFAULT_PUSH_SERVER;
@@ -253,7 +260,15 @@ export default class PushNotificationPermission extends Vue {
private checkNotificationSupport(): Promise {
if (!("Notification" in window)) {
- alert("This browser does not support notifications.");
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Browser Notifications Not Supported",
+ text: "This browser does not support notifications.",
+ },
+ 3000,
+ );
return Promise.reject("This browser does not support notifications.");
}
if (window.Notification.permission === "granted") {
@@ -266,9 +281,16 @@ export default class PushNotificationPermission extends Vue {
return window.Notification.requestPermission().then(
(permission: string) => {
if (permission !== "granted") {
- alert(
- "Allow this app permission to make notifications for personal reminders." +
- " You can adjust them at any time in your settings.",
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error Requesting Notification Permission",
+ text:
+ "Allow this app permission to make notifications for personal reminders." +
+ " You can adjust them at any time in your settings.",
+ },
+ -1,
);
throw new Error("We weren't granted permission.");
}
@@ -308,6 +330,7 @@ export default class PushNotificationPermission extends Vue {
}
public async turnOnNotifications() {
+ let notifyCloser = () => {};
return this.askPermission()
.then((permission) => {
logConsoleAndDb("Permission granted: " + JSON.stringify(permission));
@@ -324,7 +347,7 @@ export default class PushNotificationPermission extends Vue {
})
.then(async (subscription) => {
if (subscription) {
- await this.$notify(
+ notifyCloser = await this.$notify(
{
group: "alert",
type: "info",
@@ -374,6 +397,7 @@ export default class PushNotificationPermission extends Vue {
"Subscription data sent to server and all finished successfully.",
);
await libsUtil.sendTestThroughPushServer(subscription, true);
+ notifyCloser();
this.$notify(
{
group: "alert",
@@ -383,6 +407,14 @@ export default class PushNotificationPermission extends Vue {
},
-1,
);
+ const timeText =
+ // eslint-disable-next-line
+ this.hourInput + ":" + this.minuteInput + " " + (this.hourAm ? "AM" : "PM");
+ await db.settings.update(MASTER_SETTINGS_KEY, {
+ notifyingNewActivity: true,
+ notifyingNewActivityTime: timeText,
+ });
+ this.callback(true, timeText);
})
.catch((error) => {
logConsoleAndDb(
@@ -393,7 +425,15 @@ export default class PushNotificationPermission extends Vue {
JSON.stringify(error),
true,
);
- alert("Some error occurred setting notification permissions.");
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error Setting Notification Permissions",
+ text: "Could not set notification permissions.",
+ },
+ 3000,
+ );
// unsubscribe just in case we failed after getting a subscription
navigator.serviceWorker?.ready
.then((registration) => registration.pushManager.getSubscription())
@@ -445,9 +485,16 @@ export default class PushNotificationPermission extends Vue {
);
// Inform the user about the issue
- alert(
- "We encountered an issue setting up push notifications. " +
- "If you wish to revoke notification permissions, please do so in your browser settings.",
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error Setting Push Notifications",
+ text:
+ "We encountered an issue setting up push notifications. " +
+ "If you wish to revoke notification permissions, please do so in your browser settings.",
+ },
+ -1,
);
reject(error);
@@ -458,7 +505,9 @@ export default class PushNotificationPermission extends Vue {
private sendSubscriptionToServer(
subscription: PushSubscriptionWithTime,
): Promise {
- logConsoleAndDb("About to send subscription... " + subscription);
+ logConsoleAndDb(
+ "About to send subscription... " + JSON.stringify(subscription),
+ );
return fetch("/web-push/subscribe", {
method: "POST",
headers: {
diff --git a/src/components/UserNameDialog.vue b/src/components/UserNameDialog.vue
index 47d9c2f52..e7addbaae 100644
--- a/src/components/UserNameDialog.vue
+++ b/src/components/UserNameDialog.vue
@@ -46,11 +46,14 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
export default class UserNameDialog extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
- callback: (name?: string) => void = () => {};
+ callback: (name: string) => void = () => {};
givenName = "";
visible = false;
- async open(aCallback?: (name?: string) => void) {
+ /**
+ * @param aCallback - callback function for name, which may be ""
+ */
+ async open(aCallback?: (name: string) => void) {
this.callback = aCallback || this.callback;
const settings = await retrieveSettingsForActiveAccount();
this.givenName = settings.firstName || "";
diff --git a/src/constants/app.ts b/src/constants/app.ts
index 49882030e..44a70af29 100644
--- a/src/constants/app.ts
+++ b/src/constants/app.ts
@@ -52,13 +52,14 @@ export const PASSKEYS_ENABLED =
/**
* The possible values for "group" and "type" are in App.vue.
- * From the notiwind package
+ * Some of this comes from the notiwind package, some is custom.
*/
export interface NotificationIface {
group: string; // "alert" | "modal"
type: string; // "toast" | "info" | "success" | "warning" | "danger"
title: string;
text?: string;
+ callback?: (success: boolean) => Promise; // if this triggered an action
noText?: string;
onCancel?: (stopAsking?: boolean) => Promise;
onNo?: (stopAsking?: boolean) => Promise;
diff --git a/src/db/tables/settings.ts b/src/db/tables/settings.ts
index 8766381cd..75f963e9c 100644
--- a/src/db/tables/settings.ts
+++ b/src/db/tables/settings.ts
@@ -39,10 +39,12 @@ export type Settings = {
lastNotifiedClaimId?: string;
lastViewedClaimId?: string;
+ notifyingNewActivity?: boolean; // set if they have turned on daily check for new activity via the push server
+ notifyingNewActivityTime?: string; // set to their chosen time if they have turned on daily check for new activity via the push server
+
passkeyExpirationMinutes?: number; // passkey access token time-to-live in minutes
+
profileImageUrl?: string; // may be null if unwanted for a particular account
- reminderTime?: number; // Time in milliseconds since UNIX epoch for reminders
- reminderOn?: boolean; // Toggle to enable or disable reminders
// Array of named search boxes defined by bounding boxes
searchBoxes?: Array<{
diff --git a/src/router/index.ts b/src/router/index.ts
index f56db4767..d255be5b6 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -103,6 +103,11 @@ const routes: Array = [
name: "help-notifications",
component: () => import("../views/HelpNotificationsView.vue"),
},
+ {
+ path: "/help-notification-types",
+ name: "help-notification-types",
+ component: () => import("../views/HelpNotificationTypesView.vue"),
+ },
{
path: "/help-onboarding",
name: "help-onboarding",
diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue
index 8410985ea..4d68309f8 100644
--- a/src/views/AccountViewView.vue
+++ b/src/views/AccountViewView.vue
@@ -54,7 +54,10 @@
>