diff --git a/src/components/TopMessage.vue b/src/components/TopMessage.vue
new file mode 100644
index 0000000..6c5c692
--- /dev/null
+++ b/src/components/TopMessage.vue
@@ -0,0 +1,58 @@
+
+
{{ message }}
+
+
+
diff --git a/src/constants/app.ts b/src/constants/app.ts
index f4be364..2e2cffc 100644
--- a/src/constants/app.ts
+++ b/src/constants/app.ts
@@ -6,12 +6,15 @@
export enum AppString {
APP_NAME = "Time Safari",
+ PROD_TIME_SAFARI_SERVER = "https://timesafari.app",
+
PROD_ENDORSER_API_SERVER = "https://api.endorser.ch",
TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch",
LOCAL_ENDORSER_API_SERVER = "http://localhost:3000",
DEFAULT_ENDORSER_API_SERVER = TEST_ENDORSER_API_SERVER,
+ // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
PROD_PUSH_SERVER = "https://timesafari.app",
TEST1_PUSH_SERVER = "https://test.timesafari.app",
TEST2_PUSH_SERVER = "https://timesafari-pwa.anomalistlabs.com",
diff --git a/src/db/index.ts b/src/db/index.ts
index 16c99d8..37d6cf5 100644
--- a/src/db/index.ts
+++ b/src/db/index.ts
@@ -45,8 +45,5 @@ db.on("populate", () => {
db.settings.add({
id: MASTER_SETTINGS_KEY,
apiServer: AppString.DEFAULT_ENDORSER_API_SERVER,
-
- // remember that things you add from now on aren't automatically in the DB for old users
- webPushServer: AppString.DEFAULT_PUSH_SERVER,
});
});
diff --git a/src/db/tables/settings.ts b/src/db/tables/settings.ts
index 135dc8d..4b3ad1e 100644
--- a/src/db/tables/settings.ts
+++ b/src/db/tables/settings.ts
@@ -12,15 +12,17 @@ export type BoundingBox = {
* Settings type encompasses user-specific configuration details.
*/
export type Settings = {
- id: number; // Only one entry using MASTER_SETTINGS_KEY
+ id: number; // Only one entry, keyed with MASTER_SETTINGS_KEY
+
activeDid?: string; // Active Decentralized ID
apiServer?: string; // API server URL
firstName?: string; // User's first name
+ isRegistered?: boolean;
lastName?: string; // deprecated - put all names in firstName
- lastViewedClaimId?: string; // Last viewed claim ID
lastNotifiedClaimId?: string; // Last notified claim ID
- isRegistered?: boolean;
- webPushServer?: string; // Web Push server URL
+ lastViewedClaimId?: string; // Last viewed claim ID
+ 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<{
@@ -30,8 +32,9 @@ export type Settings = {
showContactGivesInline?: boolean; // Display contact inline or not
vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push
- reminderTime?: number; // Time in milliseconds since UNIX epoch for reminders
- reminderOn?: boolean; // Toggle to enable or disable reminders
+ warnIfProdServer?: boolean; // Warn if using a production server
+ warnIfTestServer?: boolean; // Warn if using a testing server
+ webPushServer?: string; // Web Push server URL
};
/**
diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue
index 7e6ba96..1dad814 100644
--- a/src/views/AccountViewView.vue
+++ b/src/views/AccountViewView.vue
@@ -1,5 +1,7 @@
+
+
@@ -215,7 +217,7 @@
Beware: the features here can be confusing and even change data in ways
- you do not expect. But we support your freedoms!
+ you do not expect. But we support your freedom!
@@ -357,6 +359,46 @@
+
+
+
+
Notification Push Server
@@ -407,7 +449,8 @@ import "dexie-export-import";
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
-import QuickNav from "@/components/QuickNav.vue";
+import QuickNav from "@/components/QuickNav";
+import TopMessage from "@/components/TopMessage";
import { AppString } from "@/constants/app";
import { db, accountsDB } from "@/db/index";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
@@ -432,7 +475,7 @@ interface IAccount {
derivationPath: string;
}
-@Component({ components: { QuickNav } })
+@Component({ components: { QuickNav, TopMessage } })
export default class AccountViewView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
@@ -462,6 +505,8 @@ export default class AccountViewView extends Vue {
showAdvanced = false;
subscription: PushSubscription | null = null;
+ warnIfProdServer = false;
+ warnIfTestServer = false;
private isSubscribed = false;
get toggleNotifications() {
@@ -471,6 +516,62 @@ export default class AccountViewView extends Vue {
this.isSubscribed = value;
}
+ /**
+ * Async function executed when the component is created.
+ * Initializes the component's state with values from the database,
+ * handles identity-related tasks, and checks limitations.
+ *
+ * @throws Will display specific messages to the user based on different errors.
+ */
+ async created() {
+ try {
+ await db.open();
+
+ const settings = await db.settings.get(MASTER_SETTINGS_KEY);
+
+ // Initialize component state with values from the database or defaults
+ this.initializeState(settings);
+
+ // Get and process the identity
+ const identity = await this.getIdentity(this.activeDid);
+ if (identity) {
+ this.processIdentity(identity);
+ }
+ } catch (err: unknown) {
+ this.handleError(err);
+ }
+ }
+
+ async mounted() {
+ try {
+ const registration = await navigator.serviceWorker.ready;
+ this.subscription = await registration.pushManager.getSubscription();
+ this.toggleNotifications = !!this.subscription;
+ } catch (error) {
+ console.error("Mount error:", error);
+ this.toggleNotifications = false;
+ }
+ }
+
+ /**
+ * Initializes component state with values from the database or defaults.
+ * @param {SettingsType} settings - Object containing settings from the database.
+ */
+ initializeState(settings: Settings | undefined) {
+ this.activeDid = (settings?.activeDid as string) || "";
+ this.apiServer = (settings?.apiServer as string) || "";
+ this.apiServerInput = (settings?.apiServer as string) || "";
+ this.givenName =
+ (settings?.firstName || "") +
+ (settings?.lastName ? ` ${settings.lastName}` : ""); // pre v 0.1.3
+ this.isRegistered = !!settings?.isRegistered;
+ this.showContactGives = !!settings?.showContactGivesInline;
+ this.warnIfProdServer = !!settings?.warnIfProdServer;
+ this.warnIfTestServer = !!settings?.warnIfTestServer;
+ this.webPushServer = (settings?.webPushServer as string) || "";
+ this.webPushServerInput = (settings?.webPushServer as string) || "";
+ }
+
public async getIdentity(activeDid: string): Promise {
try {
// Open the accounts database
@@ -536,6 +637,16 @@ export default class AccountViewView extends Vue {
this.updateShowContactAmounts();
}
+ toggleProdWarning() {
+ this.warnIfProdServer = !this.warnIfProdServer;
+ this.updateWarnIfProdServer(this.warnIfProdServer);
+ }
+
+ toggleTestWarning() {
+ this.warnIfTestServer = !this.warnIfTestServer;
+ this.updateWarnIfTestServer(this.warnIfTestServer);
+ }
+
readableTime(timeStr: string) {
return timeStr.substring(0, timeStr.indexOf("T"));
}
@@ -545,60 +656,6 @@ export default class AccountViewView extends Vue {
this.numAccounts = await accountsDB.accounts.count();
}
- /**
- * Async function executed when the component is created.
- * Initializes the component's state with values from the database,
- * handles identity-related tasks, and checks limitations.
- *
- * @throws Will display specific messages to the user based on different errors.
- */
- async created() {
- try {
- await db.open();
-
- const settings = await db.settings.get(MASTER_SETTINGS_KEY);
-
- // Initialize component state with values from the database or defaults
- this.initializeState(settings);
-
- // Get and process the identity
- const identity = await this.getIdentity(this.activeDid);
- if (identity) {
- this.processIdentity(identity);
- }
- } catch (err: unknown) {
- this.handleError(err);
- }
- }
-
- async mounted() {
- try {
- const registration = await navigator.serviceWorker.ready;
- this.subscription = await registration.pushManager.getSubscription();
- this.toggleNotifications = !!this.subscription;
- } catch (error) {
- console.error("Mount error:", error);
- this.toggleNotifications = false;
- }
- }
-
- /**
- * Initializes component state with values from the database or defaults.
- * @param {SettingsType} settings - Object containing settings from the database.
- */
- initializeState(settings: Settings | undefined) {
- this.activeDid = (settings?.activeDid as string) || "";
- this.apiServer = (settings?.apiServer as string) || "";
- this.apiServerInput = (settings?.apiServer as string) || "";
- this.givenName =
- (settings?.firstName || "") +
- (settings?.lastName ? ` ${settings.lastName}` : ""); // pre v 0.1.3
- this.isRegistered = !!settings?.isRegistered;
- this.webPushServer = (settings?.webPushServer as string) || "";
- this.webPushServerInput = (settings?.webPushServer as string) || "";
- this.showContactGives = !!settings?.showContactGivesInline;
- }
-
/**
* Processes the identity and updates the component's state.
* @param {IdentityType} identity - Object containing identity information.
@@ -672,6 +729,52 @@ export default class AccountViewView extends Vue {
}
}
+ public async updateWarnIfProdServer(newSetting) {
+ try {
+ await db.open();
+ db.settings.update(MASTER_SETTINGS_KEY, {
+ warnIfProdServer: newSetting,
+ });
+ } catch (err) {
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error Updating Prod Warning",
+ text: "Clear your cache and start over (after data backup).",
+ },
+ -1,
+ );
+ console.error(
+ "Telling user to clear cache after contact setting update because:",
+ err,
+ );
+ }
+ }
+
+ public async updateWarnIfTestServer(newSetting) {
+ try {
+ await db.open();
+ db.settings.update(MASTER_SETTINGS_KEY, {
+ warnIfTestServer: newSetting,
+ });
+ } catch (err) {
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error Updating Test Warning",
+ text: "Clear your cache and start over (after data backup).",
+ },
+ -1,
+ );
+ console.error(
+ "Telling user to clear cache after contact setting update because:",
+ err,
+ );
+ }
+ }
+
/**
* Asynchronously exports the database into a downloadable JSON file.
*
diff --git a/src/views/DiscoverView.vue b/src/views/DiscoverView.vue
index 14ff1a2..73b8cee 100644
--- a/src/views/DiscoverView.vue
+++ b/src/views/DiscoverView.vue
@@ -1,5 +1,6 @@
+
@@ -136,6 +137,7 @@ import { didInfo, ProjectData } from "@/libs/endorserServer";
import QuickNav from "@/components/QuickNav.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue";
import EntityIcon from "@/components/EntityIcon.vue";
+import TopMessage from "@/components/TopMessage";
interface Notification {
group: string;
@@ -149,6 +151,7 @@ interface Notification {
QuickNav,
InfiniteScroll,
EntityIcon,
+ TopMessage,
},
})
export default class DiscoverView extends Vue {
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 395f4ae..bba4bbf 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -1,5 +1,7 @@
+
+