modify the settings to allow account-specific settings, eg. for "isRegistered"
This commit is contained in:
11
README.md
11
README.md
@@ -97,7 +97,7 @@ It's possible to use the global test Endorser (ledger) server (but currently the
|
||||
|
||||
|
||||
|
||||
It's possible to run with a minimal set of data: the following starts with the bare minimum of test data (but currently the tests don't all succeed):
|
||||
It's possible to run with a minimal set of data; the following starts with the bare minimum of test data:
|
||||
```
|
||||
rm ../endorser-ch-test-local.sqlite3
|
||||
NODE_ENV=test-local npm run flyway migrate
|
||||
@@ -106,6 +106,15 @@ NODE_ENV=test-local npm run dev
|
||||
```
|
||||
|
||||
|
||||
To run a single test with the screenshots, use the following:
|
||||
```
|
||||
npx playwright test test-playwright/40-add-contact.spec.ts --trace on
|
||||
```
|
||||
|
||||
... with the `-c playwright.config-local.ts` to get the same results as above.
|
||||
|
||||
|
||||
|
||||
### Register new user on test server
|
||||
|
||||
On the test server, User #0 has rights to register others, so you can start
|
||||
|
||||
13
src/App.vue
13
src/App.vue
@@ -375,7 +375,10 @@
|
||||
<script lang="ts">
|
||||
import axios from "axios";
|
||||
import { Vue, Component } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import { DEFAULT_PUSH_SERVER, NotificationIface } from "@/constants/app";
|
||||
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
|
||||
interface ServiceWorkerMessage {
|
||||
@@ -405,11 +408,6 @@ interface PushSubscriptionWithTime extends PushSubscriptionJSON {
|
||||
notifyTime: { utcHour: number };
|
||||
}
|
||||
|
||||
import { DEFAULT_PUSH_SERVER, NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { sendTestThroughPushServer } from "@/libs/util";
|
||||
|
||||
@Component
|
||||
export default class App extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
@@ -422,8 +420,7 @@ export default class App extends Vue {
|
||||
|
||||
async mounted() {
|
||||
try {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
let pushUrl = DEFAULT_PUSH_SERVER;
|
||||
if (settings?.webPushServer) {
|
||||
pushUrl = settings.webPushServer;
|
||||
@@ -640,7 +637,7 @@ export default class App extends Vue {
|
||||
console.log(
|
||||
"Subscription data sent to server and all finished successfully.",
|
||||
);
|
||||
await sendTestThroughPushServer(subscription, true);
|
||||
await libsUtil.sendTestThroughPushServer(subscription, true);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
|
||||
@@ -100,7 +100,7 @@ import {
|
||||
} from "@vue-leaflet/vue-leaflet";
|
||||
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { db } from "@/db/index";
|
||||
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@@ -121,11 +121,10 @@ export default class FeedFilters extends Vue {
|
||||
async open(onCloseIfChanged: () => void) {
|
||||
this.onCloseIfChanged = onCloseIfChanged;
|
||||
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.hasVisibleDid = !!settings?.filterFeedByVisible;
|
||||
this.isNearby = !!settings?.filterFeedByNearby;
|
||||
if (settings?.searchBoxes && settings.searchBoxes.length > 0) {
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.hasVisibleDid = !!settings.filterFeedByVisible;
|
||||
this.isNearby = !!settings.filterFeedByNearby;
|
||||
if (settings.searchBoxes && settings.searchBoxes.length > 0) {
|
||||
this.hasSearchBox = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,8 +91,7 @@ import { Vue, Component, Prop } from "vue-facing-decorator";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { createAndSubmitGive, didInfo } from "@/libs/endorserServer";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
|
||||
@Component
|
||||
@@ -138,10 +137,9 @@ export default class GiftedDialog extends Vue {
|
||||
this.offerId = offerId || "";
|
||||
|
||||
try {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.activeDid = settings.activeDid || "";
|
||||
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
|
||||
|
||||
@@ -85,8 +85,7 @@ import { Vue, Component, Prop } from "vue-facing-decorator";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { createAndSubmitOffer } from "@/libs/endorserServer";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import { db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
|
||||
@Component
|
||||
export default class OfferDialog extends Vue {
|
||||
@@ -113,10 +112,9 @@ export default class OfferDialog extends Vue {
|
||||
this.recipientDid = recipientDid;
|
||||
this.recipientName = recipientName;
|
||||
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.activeDid = settings.activeDid || "";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (err: any) {
|
||||
|
||||
@@ -126,8 +126,7 @@ import { Component, Vue } from "vue-facing-decorator";
|
||||
import VuePictureCropper, { cropper } from "vue-picture-cropper";
|
||||
|
||||
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { accessToken } from "@/libs/crypto";
|
||||
|
||||
@Component({ components: { Camera, VuePictureCropper } })
|
||||
@@ -151,9 +150,8 @@ export default class PhotoDialog extends Vue {
|
||||
|
||||
async mounted() {
|
||||
try {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (err: any) {
|
||||
console.error("Error retrieving settings from database:", err);
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
import { Component, Vue, Prop } from "vue-facing-decorator";
|
||||
|
||||
import { AppString, NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
|
||||
@Component
|
||||
export default class TopMessage extends Vue {
|
||||
@@ -29,17 +28,15 @@ export default class TopMessage extends Vue {
|
||||
|
||||
async mounted() {
|
||||
try {
|
||||
await db.open();
|
||||
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
if (
|
||||
settings?.warnIfTestServer &&
|
||||
settings.warnIfTestServer &&
|
||||
settings.apiServer !== AppString.PROD_ENDORSER_API_SERVER
|
||||
) {
|
||||
const didPrefix = settings.activeDid?.slice(11, 15);
|
||||
this.message = "You're linked to a non-prod server, user " + didPrefix;
|
||||
} else if (
|
||||
settings?.warnIfProdServer &&
|
||||
settings.warnIfProdServer &&
|
||||
settings.apiServer === AppString.PROD_ENDORSER_API_SERVER
|
||||
) {
|
||||
const didPrefix = settings.activeDid?.slice(11, 15);
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
import { Vue, Component } from "vue-facing-decorator";
|
||||
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
|
||||
@Component
|
||||
export default class UserNameDialog extends Vue {
|
||||
@@ -52,9 +52,8 @@ export default class UserNameDialog extends Vue {
|
||||
|
||||
async open(aCallback?: (name?: string) => void) {
|
||||
this.callback = aCallback || this.callback;
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.givenName = settings?.firstName || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.givenName = settings.firstName || "";
|
||||
this.visible = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ import * as THREE from "three";
|
||||
import { GLTFLoader } from "three/addons/loaders/GLTFLoader";
|
||||
import * as SkeletonUtils from "three/addons/utils/SkeletonUtils";
|
||||
import * as TWEEN from "@tweenjs/tween.js";
|
||||
import { db } from "@/db";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { retrieveSettingsForActiveAccount } from "@/db";
|
||||
import { getHeaders } from "@/libs/endorserServer";
|
||||
|
||||
const ANIMATION_DURATION_SECS = 10;
|
||||
@@ -14,10 +13,9 @@ export async function loadLandmarks(vue, world, scene, loop) {
|
||||
vue.setWorldProperty("animationDurationSeconds", ANIMATION_DURATION_SECS);
|
||||
|
||||
try {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const activeDid = settings?.activeDid || "";
|
||||
const apiServer = settings?.apiServer;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
const activeDid = settings.activeDid || "";
|
||||
const apiServer = settings.apiServer;
|
||||
const headers = await getHeaders(activeDid);
|
||||
|
||||
const url = apiServer + "/api/v2/report/claims?claimType=GiveAction";
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import BaseDexie, { Table } from "dexie";
|
||||
import { encrypted, Encryption } from "@pvermeer/dexie-encrypted-addon";
|
||||
import * as R from "ramda";
|
||||
|
||||
import { Account, AccountsSchema } from "./tables/accounts";
|
||||
import { Contact, ContactSchema } from "./tables/contacts";
|
||||
import { Log, LogSchema } from "./tables/logs";
|
||||
@@ -45,15 +47,87 @@ accountsDB.version(1).stores(AccountsSchema);
|
||||
db.version(2).stores({
|
||||
...ContactSchema,
|
||||
...LogSchema,
|
||||
...SettingsSchema,
|
||||
...{ settings: "id" }, // old Settings schema
|
||||
});
|
||||
// v3 added Temp
|
||||
db.version(3).stores(TempSchema);
|
||||
db.version(4)
|
||||
.stores(SettingsSchema)
|
||||
.upgrade((tx) => {
|
||||
return tx
|
||||
.table("settings")
|
||||
.toCollection()
|
||||
.modify((settings) => {
|
||||
settings.accountDid = ""; // make it non-null for the default master settings, but still indexable
|
||||
});
|
||||
});
|
||||
|
||||
const DEFAULT_SETTINGS = {
|
||||
id: MASTER_SETTINGS_KEY,
|
||||
activeDid: undefined,
|
||||
apiServer: DEFAULT_ENDORSER_API_SERVER,
|
||||
};
|
||||
|
||||
// Event handler to initialize the non-sensitive database with default settings
|
||||
db.on("populate", async () => {
|
||||
await db.settings.add({
|
||||
id: MASTER_SETTINGS_KEY,
|
||||
apiServer: DEFAULT_ENDORSER_API_SERVER,
|
||||
});
|
||||
await db.settings.add(DEFAULT_SETTINGS);
|
||||
});
|
||||
|
||||
// retrieves default settings
|
||||
// calls db.open()
|
||||
export async function retrieveSettingsForDefaultAccount(): Promise<Settings> {
|
||||
await db.open();
|
||||
return (await db.settings.get(MASTER_SETTINGS_KEY)) || DEFAULT_SETTINGS;
|
||||
}
|
||||
|
||||
export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
|
||||
const defaultSettings = await retrieveSettingsForDefaultAccount();
|
||||
if (!defaultSettings.activeDid) {
|
||||
return defaultSettings;
|
||||
} else {
|
||||
const overrideSettings =
|
||||
(await db.settings
|
||||
.where("accountDid")
|
||||
.equals(defaultSettings.activeDid)
|
||||
.first()) || {};
|
||||
return R.mergeDeepRight(defaultSettings, overrideSettings);
|
||||
}
|
||||
}
|
||||
|
||||
// Update settings for the given account, or in MASTER_SETTINGS_KEY if no accountDid is provided.
|
||||
// Don't expose this because we should be explicit on whether we're updating the default settings or account settings.
|
||||
async function updateSettings(settingsChanges: Settings): Promise<void> {
|
||||
await db.open();
|
||||
if (!settingsChanges.accountDid) {
|
||||
// ensure there is no "id" that would override the key
|
||||
delete settingsChanges.id;
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, settingsChanges);
|
||||
} else {
|
||||
const result = await db.settings
|
||||
.where("accountDid")
|
||||
.equals(settingsChanges.accountDid)
|
||||
.modify(settingsChanges);
|
||||
if (result === 0) {
|
||||
if (!settingsChanges.id) {
|
||||
// It is unfortunate that we have to set this explicitly.
|
||||
// We didn't make id a "++id" at the beginning and Dexie won't let us change it,
|
||||
// plus we made our first settings objects MASTER_SETTINGS_KEY = 1 instead of 0
|
||||
settingsChanges.id = (await db.settings.count()) + 1;
|
||||
}
|
||||
await db.settings.add(settingsChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateDefaultSettings(settings: Settings): Promise<void> {
|
||||
delete settings.accountDid; // just in case
|
||||
await updateSettings(settings);
|
||||
}
|
||||
|
||||
export async function updateAccountSettings(
|
||||
accountDid: string,
|
||||
settings: Settings,
|
||||
): Promise<void> {
|
||||
settings.accountDid = accountDid;
|
||||
await updateSettings(settings);
|
||||
}
|
||||
|
||||
@@ -12,22 +12,28 @@ export type BoundingBox = {
|
||||
* Settings type encompasses user-specific configuration details.
|
||||
*/
|
||||
export type Settings = {
|
||||
id: number; // Only one entry, keyed with MASTER_SETTINGS_KEY
|
||||
// default entry is keyed with MASTER_SETTINGS_KEY; other entries are linked to an account with account ID
|
||||
id?: number; // this is only blank on input, when the database assigns it
|
||||
|
||||
// if supplied, this settings record overrides the master record when the user switches to this account
|
||||
accountDid?: string; // not used in the MASTER_SETTINGS_KEY entry
|
||||
// active Decentralized ID
|
||||
activeDid?: string; // only used in the MASTER_SETTINGS_KEY entry
|
||||
|
||||
activeDid?: string; // Active Decentralized ID
|
||||
apiServer?: string; // API server URL
|
||||
|
||||
filterFeedByNearby?: boolean; // filter by nearby
|
||||
filterFeedByVisible?: boolean; // filter by visible users ie. anyone not hidden
|
||||
|
||||
firstName?: string; // user's full name
|
||||
firstName?: string; // user's full name, may be null if unwanted for a particular account
|
||||
hideRegisterPromptOnNewContact?: boolean;
|
||||
isRegistered?: boolean;
|
||||
imageServer?: string;
|
||||
lastName?: string; // deprecated - put all names in firstName
|
||||
lastNotifiedClaimId?: string;
|
||||
lastViewedClaimId?: string;
|
||||
passkeyExpirationMinutes?: number; // passkey access token time-to-live in minutes
|
||||
profileImageUrl?: string;
|
||||
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
|
||||
|
||||
@@ -54,7 +60,7 @@ export function isAnyFeedFilterOn(settings: Settings): boolean {
|
||||
* Schema for the Settings table in the database.
|
||||
*/
|
||||
export const SettingsSchema = {
|
||||
settings: "id",
|
||||
settings: "id, &accountDid",
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,7 +84,9 @@ export interface GiveSummaryRecord {
|
||||
amountConfirmed: number;
|
||||
description: string;
|
||||
fullClaim: GiveVerifiableCredential;
|
||||
fulfillsPlanHandleId: string;
|
||||
fulfillsHandleId: string;
|
||||
fulfillsPlanHandleId?: string;
|
||||
fulfillsType?: string;
|
||||
handleId: string;
|
||||
issuedAt: string;
|
||||
issuerDid: string;
|
||||
@@ -519,7 +521,7 @@ const planCache: LRUCache<string, PlanSummaryRecord> = new LRUCache({
|
||||
* @param apiServer
|
||||
*/
|
||||
export async function getPlanFromCache(
|
||||
handleId: string | null,
|
||||
handleId: string,
|
||||
axios: Axios,
|
||||
apiServer: string,
|
||||
requesterDid?: string,
|
||||
|
||||
@@ -6,21 +6,23 @@ import * as R from "ramda";
|
||||
import { useClipboard } from "@vueuse/core";
|
||||
|
||||
import { DEFAULT_PUSH_SERVER } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import {
|
||||
accountsDB,
|
||||
retrieveSettingsForActiveAccount,
|
||||
updateAccountSettings,
|
||||
updateDefaultSettings,
|
||||
} from "@/db/index";
|
||||
import { Account } from "@/db/tables/accounts";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import {
|
||||
DEFAULT_PASSKEY_EXPIRATION_MINUTES,
|
||||
MASTER_SETTINGS_KEY,
|
||||
} from "@/db/tables/settings";
|
||||
import { DEFAULT_PASSKEY_EXPIRATION_MINUTES } from "@/db/tables/settings";
|
||||
import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto";
|
||||
import * as serverUtil from "@/libs/endorserServer";
|
||||
import {
|
||||
containsHiddenDid,
|
||||
GenericCredWrapper,
|
||||
GenericVerifiableCredential,
|
||||
OfferVerifiableCredential,
|
||||
} from "@/libs/endorserServer";
|
||||
import * as serverUtil from "@/libs/endorserServer";
|
||||
import { KeyMeta } from "@/libs/crypto/vc";
|
||||
import { createPeerDid } from "@/libs/crypto/vc/didPeer";
|
||||
import { registerCredential } from "@/libs/crypto/vc/passkeyDidPeer";
|
||||
@@ -311,9 +313,9 @@ export const generateSaveAndActivateIdentity = async (): Promise<string> => {
|
||||
publicKeyHex: newId.keys[0].publicKeyHex,
|
||||
});
|
||||
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
activeDid: newId.did,
|
||||
});
|
||||
await updateDefaultSettings({ activeDid: newId.did });
|
||||
console.log("Updated default settings in util");
|
||||
await updateAccountSettings(newId.did, { isRegistered: false });
|
||||
|
||||
return newId.did;
|
||||
};
|
||||
@@ -341,30 +343,24 @@ export const registerSaveAndActivatePasskey = async (
|
||||
keyName: string,
|
||||
): Promise<Account> => {
|
||||
const account = await registerAndSavePasskey(keyName);
|
||||
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
activeDid: account.did,
|
||||
});
|
||||
|
||||
await updateDefaultSettings({ activeDid: account.did });
|
||||
await updateAccountSettings(account.did, { isRegistered: false });
|
||||
return account;
|
||||
};
|
||||
|
||||
export const getPasskeyExpirationSeconds = async (): Promise<number> => {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const passkeyExpirationSeconds =
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
return (
|
||||
(settings?.passkeyExpirationMinutes ?? DEFAULT_PASSKEY_EXPIRATION_MINUTES) *
|
||||
60;
|
||||
return passkeyExpirationSeconds;
|
||||
60
|
||||
);
|
||||
};
|
||||
|
||||
export const sendTestThroughPushServer = async (
|
||||
subscriptionJSON: PushSubscriptionJSON,
|
||||
skipFilter: boolean,
|
||||
): Promise<AxiosResponse> => {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
let pushUrl: string = DEFAULT_PUSH_SERVER as string;
|
||||
if (settings?.webPushServer) {
|
||||
pushUrl = settings.webPushServer;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import axios from "axios";
|
||||
import * as didJwt from "did-jwt";
|
||||
import { AppString } from "@/constants/app";
|
||||
import { db } from "../db";
|
||||
import { SERVICE_ID } from "../libs/endorserServer";
|
||||
import { deriveAddress, newIdentifier } from "../libs/crypto";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { retrieveSettingsForActiveAccount } from "../db";
|
||||
import { SERVICE_ID } from "@/libs/endorserServer";
|
||||
import { deriveAddress, newIdentifier } from "@/libs/crypto";
|
||||
|
||||
/**
|
||||
* Get User #0 to sign & submit a RegisterAction for the user's activeDid.
|
||||
@@ -17,8 +16,7 @@ export async function testServerRegisterUser() {
|
||||
|
||||
const identity0 = newIdentifier(addr, publicHex, privateHex, deriPath);
|
||||
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
|
||||
// Make a claim
|
||||
const vcClaim = {
|
||||
@@ -26,7 +24,7 @@ export async function testServerRegisterUser() {
|
||||
"@type": "RegisterAction",
|
||||
agent: { did: identity0.did },
|
||||
object: SERVICE_ID,
|
||||
participant: { did: settings?.activeDid },
|
||||
participant: { did: settings.activeDid },
|
||||
};
|
||||
// Make a payload for the claim
|
||||
const vcPayload = {
|
||||
@@ -53,7 +51,7 @@ export async function testServerRegisterUser() {
|
||||
|
||||
const payload = JSON.stringify({ jwtEncoded: vcJwt });
|
||||
const endorserApiServer =
|
||||
settings?.apiServer || AppString.TEST_ENDORSER_API_SERVER;
|
||||
settings.apiServer || AppString.TEST_ENDORSER_API_SERVER;
|
||||
const url = endorserApiServer + "/api/claim";
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
|
||||
@@ -9,24 +9,11 @@
|
||||
Your Identity
|
||||
</h1>
|
||||
|
||||
<div class="flex justify-between mb-2 mt-4">
|
||||
<span />
|
||||
<span class="whitespace-nowrap">
|
||||
<router-link
|
||||
:to="{ name: 'contact-qr' }"
|
||||
class="text-xs bg-slate-500 text-white px-1.5 py-1 rounded-md"
|
||||
>
|
||||
<fa icon="qrcode" class="fa-fw"></fa>
|
||||
</router-link>
|
||||
</span>
|
||||
<span />
|
||||
</div>
|
||||
|
||||
<!-- ID notice -->
|
||||
<div
|
||||
v-if="!activeDid"
|
||||
id="noticeBeforeShare"
|
||||
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4"
|
||||
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mt-4"
|
||||
>
|
||||
<p class="mb-4">
|
||||
<b>Note:</b> Before you can share with others or take any action, you
|
||||
@@ -43,10 +30,18 @@
|
||||
<!-- Identity Details -->
|
||||
<div
|
||||
id="sectionIdentityDetails"
|
||||
class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4"
|
||||
class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mt-4"
|
||||
>
|
||||
<div v-if="givenName">
|
||||
<h2 class="text-xl font-semibold mb-2">
|
||||
<span class="whitespace-nowrap">
|
||||
<router-link
|
||||
:to="{ name: 'contact-qr' }"
|
||||
class="bg-slate-500 text-white px-1.5 py-1 rounded-md"
|
||||
>
|
||||
<fa icon="qrcode" class="fa-fw text-xl"></fa>
|
||||
</router-link>
|
||||
</span>
|
||||
{{ givenName }}
|
||||
<router-link :to="{ name: 'new-edit-account' }">
|
||||
<fa icon="pen" class="text-xs text-blue-500 ml-2 mb-1"></fa>
|
||||
@@ -160,7 +155,7 @@
|
||||
<div
|
||||
v-if="!loadingLimits && !endorserLimits?.nextWeekBeginDateTime"
|
||||
id="noticeBeforeAnnounce"
|
||||
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4"
|
||||
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mt-4"
|
||||
>
|
||||
<p class="mb-4">
|
||||
<b>Note:</b> Before you can publicly announce a new project or time
|
||||
@@ -312,7 +307,7 @@
|
||||
>
|
||||
If no download happened yet, click again here to download now.
|
||||
</a>
|
||||
<div>
|
||||
<div class="mt-4">
|
||||
<p>
|
||||
After the download, you can save the file in your preferred storage
|
||||
location.
|
||||
@@ -731,13 +726,17 @@ import {
|
||||
IMAGE_TYPE_PROFILE,
|
||||
NotificationIface,
|
||||
} from "@/constants/app";
|
||||
import { db, accountsDB } from "@/db/index";
|
||||
import {
|
||||
db,
|
||||
accountsDB,
|
||||
retrieveSettingsForActiveAccount,
|
||||
updateAccountSettings,
|
||||
} from "@/db/index";
|
||||
import { Account } from "@/db/tables/accounts";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import {
|
||||
DEFAULT_PASSKEY_EXPIRATION_MINUTES,
|
||||
MASTER_SETTINGS_KEY,
|
||||
Settings,
|
||||
} from "@/db/tables/settings";
|
||||
import {
|
||||
clearPasskeyToken,
|
||||
@@ -865,31 +864,29 @@ export default class AccountViewView extends Vue {
|
||||
*/
|
||||
async initializeState() {
|
||||
await db.open();
|
||||
const settings: Settings | undefined =
|
||||
await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
|
||||
this.activeDid = (settings?.activeDid as string) || "";
|
||||
this.apiServer = (settings?.apiServer as string) || "";
|
||||
this.apiServerInput = (settings?.apiServer as string) || "";
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.apiServerInput = settings.apiServer || "";
|
||||
this.givenName =
|
||||
(settings?.firstName || "") +
|
||||
(settings?.lastName ? ` ${settings.lastName}` : ""); // pre v 0.1.3
|
||||
this.isRegistered = !!settings?.isRegistered;
|
||||
this.imageServer = (settings?.imageServer as string) || "";
|
||||
this.profileImageUrl = settings?.profileImageUrl as string;
|
||||
this.showContactGives = !!settings?.showContactGivesInline;
|
||||
this.imageServer = settings.imageServer || "";
|
||||
this.profileImageUrl = settings.profileImageUrl;
|
||||
this.showContactGives = !!settings.showContactGivesInline;
|
||||
this.hideRegisterPromptOnNewContact =
|
||||
!!settings?.hideRegisterPromptOnNewContact;
|
||||
!!settings.hideRegisterPromptOnNewContact;
|
||||
this.passkeyExpirationMinutes =
|
||||
(settings?.passkeyExpirationMinutes as number) ??
|
||||
DEFAULT_PASSKEY_EXPIRATION_MINUTES;
|
||||
settings.passkeyExpirationMinutes ?? DEFAULT_PASSKEY_EXPIRATION_MINUTES;
|
||||
this.previousPasskeyExpirationMinutes = this.passkeyExpirationMinutes;
|
||||
this.showGeneralAdvanced = !!settings?.showGeneralAdvanced;
|
||||
this.showShortcutBvc = !!settings?.showShortcutBvc;
|
||||
this.warnIfProdServer = !!settings?.warnIfProdServer;
|
||||
this.warnIfTestServer = !!settings?.warnIfTestServer;
|
||||
this.webPushServer = (settings?.webPushServer as string) || "";
|
||||
this.webPushServerInput = (settings?.webPushServer as string) || "";
|
||||
this.showGeneralAdvanced = !!settings.showGeneralAdvanced;
|
||||
this.showShortcutBvc = !!settings.showShortcutBvc;
|
||||
this.warnIfProdServer = !!settings.warnIfProdServer;
|
||||
this.warnIfTestServer = !!settings.warnIfTestServer;
|
||||
this.webPushServer = settings.webPushServer || "";
|
||||
this.webPushServerInput = settings.webPushServer || "";
|
||||
}
|
||||
|
||||
// call fn, copy text to the clipboard, then redo fn after 2 seconds
|
||||
@@ -1264,10 +1261,7 @@ export default class AccountViewView extends Vue {
|
||||
if (!this.isRegistered) {
|
||||
// the user was not known to be registered, but now they are (because we got no error) so let's record it
|
||||
try {
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
isRegistered: true,
|
||||
});
|
||||
await updateAccountSettings(did, { isRegistered: true });
|
||||
this.isRegistered = true;
|
||||
} catch (err) {
|
||||
console.error("Got an error updating settings:", err);
|
||||
@@ -1478,8 +1472,7 @@ export default class AccountViewView extends Vue {
|
||||
if ((error as any).response.status === 404) {
|
||||
console.error("The image was already deleted:", error);
|
||||
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await updateAccountSettings(this.activeDid, {
|
||||
profileImageUrl: undefined,
|
||||
});
|
||||
|
||||
|
||||
@@ -33,8 +33,7 @@ import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import * as serverUtil from "@/libs/endorserServer";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
|
||||
@@ -50,10 +49,9 @@ export default class ClaimAddRawView extends Vue {
|
||||
claimStr = "";
|
||||
|
||||
async mounted() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
|
||||
this.claimStr = (this.$route as Router).query["claim"];
|
||||
try {
|
||||
|
||||
@@ -454,9 +454,8 @@ import { useClipboard } from "@vueuse/core";
|
||||
|
||||
import GiftedDialog from "@/components/GiftedDialog.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import * as serverUtil from "@/libs/endorserServer";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
@@ -519,12 +518,11 @@ export default class ClaimView extends Vue {
|
||||
}
|
||||
|
||||
async created() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
this.isRegistered = settings?.isRegistered || false;
|
||||
this.isRegistered = settings.isRegistered || false;
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = accountsDB.accounts;
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
<!-- Details -->
|
||||
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mt-4">
|
||||
<div class="block flex gap-4 overflow-hidden">
|
||||
<div class="flex gap-4 overflow-hidden">
|
||||
<div class="overflow-hidden">
|
||||
<div class="text-sm">
|
||||
<div>
|
||||
@@ -100,7 +100,7 @@
|
||||
<router-link
|
||||
:to="
|
||||
'/project/' +
|
||||
encodeURIComponent(giveDetails?.fulfillsPlanHandleId)
|
||||
encodeURIComponent(giveDetails?.fulfillsPlanHandleId || '')
|
||||
"
|
||||
class="text-blue-500 mt-2 cursor-pointer"
|
||||
target="_blank"
|
||||
@@ -121,7 +121,7 @@
|
||||
<router-link
|
||||
:to="
|
||||
'/claim/' +
|
||||
encodeURIComponent(giveDetails?.fulfillsHandleId)
|
||||
encodeURIComponent(giveDetails?.fulfillsHandleId || '')
|
||||
"
|
||||
class="text-blue-500 mt-2 cursor-pointer"
|
||||
target="_blank"
|
||||
@@ -129,7 +129,7 @@
|
||||
This fulfills
|
||||
{{
|
||||
capitalizeAndInsertSpacesBeforeCapsWithAPrefix(
|
||||
giveDetails.fulfillsType,
|
||||
giveDetails?.fulfillsType || "",
|
||||
)
|
||||
}}
|
||||
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||
@@ -405,10 +405,9 @@ import { Router } from "vue-router";
|
||||
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Account } from "@/db/tables/accounts";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import * as serverUtil from "@/libs/endorserServer";
|
||||
import { displayAmount, GiveSummaryRecord } from "@/libs/endorserServer";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
@@ -464,12 +463,11 @@ export default class ClaimView extends Vue {
|
||||
|
||||
async mounted() {
|
||||
this.isLoading = true;
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
this.isRegistered = settings?.isRegistered || false;
|
||||
this.isRegistered = settings.isRegistered || false;
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = accountsDB.accounts;
|
||||
|
||||
@@ -112,9 +112,8 @@ import { Router } from "vue-router";
|
||||
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import {
|
||||
AgreeVerifiableCredential,
|
||||
createEndorserJwtVcFromClaim,
|
||||
@@ -144,13 +143,12 @@ export default class ContactAmountssView extends Vue {
|
||||
|
||||
async created() {
|
||||
try {
|
||||
await db.open();
|
||||
const contactDid = (this.$route as Router).query["contactDid"] as string;
|
||||
this.contact = (await db.contacts.get(contactDid)) || null;
|
||||
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.activeDid = (settings?.activeDid as string) || "";
|
||||
this.apiServer = (settings?.apiServer as string) || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
|
||||
if (this.activeDid && this.contact) {
|
||||
this.loadGives(this.activeDid, this.contact);
|
||||
|
||||
@@ -77,9 +77,8 @@ import GiftedDialog from "@/components/GiftedDialog.vue";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import EntityIcon from "@/components/EntityIcon.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { GiverReceiverInputInfo } from "@/libs/util";
|
||||
|
||||
@Component({
|
||||
@@ -97,10 +96,9 @@ export default class ContactGiftingView extends Vue {
|
||||
|
||||
async created() {
|
||||
try {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.activeDid = settings.activeDid || "";
|
||||
|
||||
// .orderBy("name") wouldn't retrieve any entries with a blank name
|
||||
// .toCollection.sortBy("name") didn't sort in an order I understood
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
Contact Import
|
||||
</h1>
|
||||
|
||||
<span>
|
||||
Note that you will have to make them visible one-by-one in the list of
|
||||
Contacts.
|
||||
<span class="flex justify-center">
|
||||
<input type="checkbox" v-model="makeVisible" class="mr-2" />
|
||||
Make my activity visible to these contacts.
|
||||
</span>
|
||||
<div v-if="sameCount > 0">
|
||||
<span v-if="sameCount == 1"
|
||||
@@ -115,6 +115,7 @@ export default class ContactImportView extends Vue {
|
||||
Record<string, { new: string; old: string }>
|
||||
> = {}; // for existing contacts, it shows the difference between imported and existing contacts for each key
|
||||
importing = false;
|
||||
makeVisible = true;
|
||||
sameCount = 0;
|
||||
|
||||
async created() {
|
||||
|
||||
@@ -101,7 +101,7 @@ import { useClipboard } from "@vueuse/core";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import UserNameDialog from "@/components/UserNameDialog.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import {
|
||||
@@ -141,14 +141,13 @@ export default class ContactQRScanShow extends Vue {
|
||||
ETHR_DID_PREFIX = ETHR_DID_PREFIX;
|
||||
|
||||
async created() {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.activeDid = (settings?.activeDid as string) || "";
|
||||
this.apiServer = (settings?.apiServer as string) || "";
|
||||
this.givenName = (settings?.firstName as string) || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.givenName = settings.firstName || "";
|
||||
this.hideRegisterPromptOnNewContact =
|
||||
!!settings?.hideRegisterPromptOnNewContact;
|
||||
this.isRegistered = !!settings?.isRegistered;
|
||||
!!settings.hideRegisterPromptOnNewContact;
|
||||
this.isRegistered = !!settings.isRegistered;
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = await accountsDB.accounts.toArray();
|
||||
@@ -162,22 +161,17 @@ export default class ContactQRScanShow extends Vue {
|
||||
iss: this.activeDid,
|
||||
own: {
|
||||
name:
|
||||
(settings?.firstName || "") +
|
||||
(settings?.lastName ? ` ${settings.lastName}` : ""), // lastName is deprecated, pre v 0.1.3
|
||||
(settings.firstName || "") +
|
||||
(settings.lastName ? ` ${settings.lastName}` : ""), // lastName is deprecated, pre v 0.1.3
|
||||
publicEncKey,
|
||||
profileImageUrl: settings?.profileImageUrl,
|
||||
registered: settings?.isRegistered,
|
||||
profileImageUrl: settings.profileImageUrl,
|
||||
registered: settings.isRegistered,
|
||||
},
|
||||
};
|
||||
|
||||
if (account?.mnemonic && account?.derivationPath) {
|
||||
const newDerivPath = nextDerivationPath(
|
||||
account.derivationPath as string,
|
||||
);
|
||||
const nextPublicHex = deriveAddress(
|
||||
account.mnemonic as string,
|
||||
newDerivPath,
|
||||
)[2];
|
||||
const newDerivPath = nextDerivationPath(account.derivationPath);
|
||||
const nextPublicHex = deriveAddress(account.mnemonic, newDerivPath)[2];
|
||||
const nextPublicEncKey = Buffer.from(nextPublicHex, "hex");
|
||||
const nextPublicEncKeyHash = sha256(nextPublicEncKey);
|
||||
const nextPublicEncKeyHashBase64 =
|
||||
@@ -191,14 +185,14 @@ export default class ContactQRScanShow extends Vue {
|
||||
viewPrefix + vcJwt;
|
||||
|
||||
const name =
|
||||
(settings?.firstName || "") +
|
||||
(settings?.lastName ? ` ${settings.lastName}` : ""); // lastName is deprecated, pre v 0.1.3
|
||||
(settings.firstName || "") +
|
||||
(settings.lastName ? ` ${settings.lastName}` : ""); // lastName is deprecated, pre v 0.1.3
|
||||
|
||||
this.qrValue = await generateEndorserJwtForAccount(
|
||||
account,
|
||||
!!settings?.isRegistered,
|
||||
!!settings.isRegistered,
|
||||
name,
|
||||
settings?.profileImageUrl as string,
|
||||
settings.profileImageUrl,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,9 +292,12 @@ import { Router } from "vue-router";
|
||||
import { useClipboard } from "@vueuse/core";
|
||||
|
||||
import { AppString, NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import {
|
||||
db,
|
||||
retrieveSettingsForActiveAccount,
|
||||
updateDefaultSettings,
|
||||
} from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { getContactPayloadFromJwtUrl } from "@/libs/crypto";
|
||||
import {
|
||||
CONTACT_CSV_HEADER,
|
||||
@@ -352,14 +355,14 @@ export default class ContactsView extends Vue {
|
||||
|
||||
public async created() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.isRegistered = !!settings?.isRegistered;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.isRegistered = !!settings.isRegistered;
|
||||
|
||||
this.showGiveNumbers = !!settings?.showContactGivesInline;
|
||||
this.showGiveNumbers = !!settings.showContactGivesInline;
|
||||
this.hideRegisterPromptOnNewContact =
|
||||
!!settings?.hideRegisterPromptOnNewContact;
|
||||
!!settings.hideRegisterPromptOnNewContact;
|
||||
|
||||
if (this.showGiveNumbers) {
|
||||
this.loadGives();
|
||||
@@ -715,7 +718,7 @@ export default class ContactsView extends Vue {
|
||||
text: "Do you want to register them?",
|
||||
onCancel: async (stopAsking: boolean) => {
|
||||
if (stopAsking) {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await updateDefaultSettings({
|
||||
hideRegisterPromptOnNewContact: stopAsking,
|
||||
});
|
||||
this.hideRegisterPromptOnNewContact = stopAsking;
|
||||
@@ -723,7 +726,7 @@ export default class ContactsView extends Vue {
|
||||
},
|
||||
onNo: async (stopAsking: boolean) => {
|
||||
if (stopAsking) {
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await updateDefaultSettings({
|
||||
hideRegisterPromptOnNewContact: stopAsking,
|
||||
});
|
||||
this.hideRegisterPromptOnNewContact = stopAsking;
|
||||
@@ -1067,8 +1070,7 @@ export default class ContactsView extends Vue {
|
||||
private async toggleShowContactAmounts() {
|
||||
const newShowValue = !this.showGiveNumbers;
|
||||
try {
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await updateDefaultSettings({
|
||||
showContactGivesInline: newShowValue,
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -237,9 +237,9 @@ import QuickNav from "@/components/QuickNav.vue";
|
||||
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { BoundingBox } from "@/db/tables/settings";
|
||||
import {
|
||||
capitalizeAndInsertSpacesBeforeCaps,
|
||||
didInfoForContact,
|
||||
@@ -290,10 +290,9 @@ export default class DIDView extends Vue {
|
||||
displayAmount = displayAmount;
|
||||
|
||||
async mounted() {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.activeDid = (settings?.activeDid as string) || "";
|
||||
this.apiServer = (settings?.apiServer as string) || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
|
||||
const pathParam = window.location.pathname.substring("/did/".length);
|
||||
let theContact: Contact | undefined;
|
||||
|
||||
@@ -146,9 +146,9 @@ import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
||||
import ProjectIcon from "@/components/ProjectIcon.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { BoundingBox } from "@/db/tables/settings";
|
||||
import { didInfo, getHeaders, PlanData } from "@/libs/endorserServer";
|
||||
|
||||
@Component({
|
||||
@@ -179,11 +179,10 @@ export default class DiscoverView extends Vue {
|
||||
didInfo = didInfo;
|
||||
|
||||
async mounted() {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.activeDid = (settings?.activeDid as string) || "";
|
||||
this.apiServer = (settings?.apiServer as string) || "";
|
||||
this.searchBox = settings?.searchBoxes?.[0] || null;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = (settings.activeDid as string) || "";
|
||||
this.apiServer = (settings.apiServer as string) || "";
|
||||
this.searchBox = settings.searchBoxes?.[0] || null;
|
||||
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
|
||||
|
||||
@@ -181,8 +181,7 @@ import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import {
|
||||
createAndSubmitGive,
|
||||
didInfo,
|
||||
@@ -319,10 +318,9 @@ export default class GiftedDetails extends Vue {
|
||||
}
|
||||
|
||||
try {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.activeDid = settings.activeDid || "";
|
||||
|
||||
let allContacts: Contact[] = [];
|
||||
let allMyDids: string[] = [];
|
||||
|
||||
@@ -84,11 +84,11 @@
|
||||
id="noticeSomeoneMustRegisterYou"
|
||||
class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4"
|
||||
>
|
||||
<!-- activeDid && !isRegistered -->
|
||||
<!-- !isCreatingIdentifier && !isRegistered -->
|
||||
To share, someone must register you.
|
||||
<div class="block text-center">
|
||||
<button
|
||||
@click="showNameDialog()"
|
||||
@click="showNameThenIdDialog()"
|
||||
class="text-md font-bold bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mt-2 px-2 py-3 rounded-md"
|
||||
>
|
||||
Show them {{ PASSKEYS_ENABLED ? "default" : "your" }} identifier
|
||||
@@ -107,7 +107,7 @@
|
||||
</div>
|
||||
|
||||
<div v-else id="sectionRecordSomethingGiven">
|
||||
<!-- activeDid && isRegistered -->
|
||||
<!-- !isCreatingIdentifier && isRegistered -->
|
||||
|
||||
<!-- show the actions for recognizing a give -->
|
||||
<div class="flex justify-between">
|
||||
@@ -325,13 +325,17 @@ import {
|
||||
NotificationIface,
|
||||
PASSKEYS_ENABLED,
|
||||
} from "@/constants/app";
|
||||
import { db, accountsDB } from "@/db/index";
|
||||
import {
|
||||
db,
|
||||
accountsDB,
|
||||
updateAccountSettings,
|
||||
retrieveSettingsForActiveAccount,
|
||||
} from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import {
|
||||
BoundingBox,
|
||||
isAnyFeedFilterOn,
|
||||
MASTER_SETTINGS_KEY,
|
||||
Settings,
|
||||
} from "@/db/tables/settings";
|
||||
import {
|
||||
contactForDid,
|
||||
@@ -420,18 +424,17 @@ export default class HomeView extends Vue {
|
||||
this.allMyDids = [newDid];
|
||||
}
|
||||
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
this.feedLastViewedClaimId = settings?.lastViewedClaimId;
|
||||
this.givenName = settings?.firstName || "";
|
||||
this.isFeedFilteredByVisible = !!settings?.filterFeedByVisible;
|
||||
this.isFeedFilteredByNearby = !!settings?.filterFeedByNearby;
|
||||
this.isRegistered = !!settings?.isRegistered;
|
||||
this.searchBoxes = settings?.searchBoxes || [];
|
||||
this.showShortcutBvc = !!settings?.showShortcutBvc;
|
||||
this.feedLastViewedClaimId = settings.lastViewedClaimId;
|
||||
this.givenName = settings.firstName || "";
|
||||
this.isFeedFilteredByVisible = !!settings.filterFeedByVisible;
|
||||
this.isFeedFilteredByNearby = !!settings.filterFeedByNearby;
|
||||
this.isRegistered = !!settings.isRegistered;
|
||||
this.searchBoxes = settings.searchBoxes || [];
|
||||
this.showShortcutBvc = !!settings.showShortcutBvc;
|
||||
|
||||
this.isAnyFeedFilterOn = isAnyFeedFilterOn(settings);
|
||||
|
||||
@@ -444,9 +447,7 @@ export default class HomeView extends Vue {
|
||||
this.activeDid,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
// we just needed to know that they're registered
|
||||
await db.open();
|
||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||
await updateAccountSettings(this.activeDid, {
|
||||
isRegistered: true,
|
||||
});
|
||||
this.isRegistered = true;
|
||||
@@ -495,10 +496,9 @@ export default class HomeView extends Vue {
|
||||
|
||||
// only called when a setting was changed
|
||||
async reloadFeedOnChange() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.isFeedFilteredByVisible = !!settings?.filterFeedByVisible;
|
||||
this.isFeedFilteredByNearby = !!settings?.filterFeedByNearby;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.isFeedFilteredByVisible = !!settings.filterFeedByVisible;
|
||||
this.isFeedFilteredByNearby = !!settings.filterFeedByNearby;
|
||||
this.isAnyFeedFilterOn = isAnyFeedFilterOn(settings);
|
||||
|
||||
this.feedData = [];
|
||||
@@ -555,7 +555,7 @@ export default class HomeView extends Vue {
|
||||
// This has indeed proven problematic. See loadMoreGives
|
||||
// We should display it immediately and then get the plan later.
|
||||
const plan = await getPlanFromCache(
|
||||
record.fulfillsPlanHandleId,
|
||||
record.fulfillsPlanHandleId || "",
|
||||
this.axios,
|
||||
this.apiServer,
|
||||
this.activeDid,
|
||||
@@ -782,7 +782,7 @@ export default class HomeView extends Vue {
|
||||
return known ? "text-slate-500" : "text-slate-100";
|
||||
}
|
||||
|
||||
showNameDialog() {
|
||||
showNameThenIdDialog() {
|
||||
if (!this.givenName) {
|
||||
(this.$refs.userNameDialog as UserNameDialog).open(() => {
|
||||
this.promptForShareMethod();
|
||||
|
||||
@@ -102,8 +102,8 @@ import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { db, accountsDB } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { db, accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
|
||||
@Component({ components: { QuickNav } })
|
||||
@@ -118,11 +118,10 @@ export default class IdentitySwitcherView extends Vue {
|
||||
|
||||
async created() {
|
||||
try {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.apiServerInput = settings?.apiServer || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.apiServerInput = settings.apiServer || "";
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = await accountsDB.accounts.toArray();
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import { db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
|
||||
@Component({
|
||||
components: {},
|
||||
@@ -58,11 +58,10 @@ export default class NewEditAccountView extends Vue {
|
||||
|
||||
// 'created' hook runs when the Vue instance is first created
|
||||
async created() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.givenName =
|
||||
(settings?.firstName || "") +
|
||||
(settings?.lastName ? ` ${settings.lastName}` : ""); // deprecated, pre v 0.1.3
|
||||
(settings.firstName || "") +
|
||||
(settings.lastName ? ` ${settings.lastName}` : ""); // deprecated, pre v 0.1.3
|
||||
}
|
||||
|
||||
async onClickSaveChanges() {
|
||||
|
||||
@@ -185,8 +185,7 @@ import { Router } from "vue-router";
|
||||
import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import {
|
||||
createEndorserJwtVcFromClaim,
|
||||
getHeaders,
|
||||
@@ -234,10 +233,9 @@ export default class NewEditProjectView extends Vue {
|
||||
await accountsDB.open();
|
||||
this.numAccounts = await accountsDB.accounts.count();
|
||||
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.activeDid = (settings?.activeDid as string) || "";
|
||||
this.apiServer = (settings?.apiServer as string) || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
|
||||
this.projectId = (this.$route as Router).query["projectId"] || "";
|
||||
|
||||
|
||||
@@ -181,8 +181,7 @@ import { Router } from "vue-router";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import {
|
||||
createAndSubmitOffer,
|
||||
didInfo,
|
||||
@@ -296,10 +295,9 @@ export default class OfferDetailsView extends Vue {
|
||||
this.prevCredToEdit?.claim?.validThrough || this.validThroughDateInput;
|
||||
|
||||
try {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.activeDid = settings.activeDid || "";
|
||||
|
||||
let allContacts: Contact[] = [];
|
||||
let allMyDids: string[] = [];
|
||||
|
||||
@@ -431,10 +431,9 @@ import QuickNav from "@/components/QuickNav.vue";
|
||||
import EntityIcon from "@/components/EntityIcon.vue";
|
||||
import ProjectIcon from "@/components/ProjectIcon.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Account } from "@/db/tables/accounts";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import {
|
||||
BLANK_GENERIC_SERVER_RECORD,
|
||||
@@ -494,12 +493,11 @@ export default class ProjectViewView extends Vue {
|
||||
serverUtil = serverUtil;
|
||||
|
||||
async created() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
this.isRegistered = !!settings?.isRegistered;
|
||||
this.isRegistered = !!settings.isRegistered;
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = accountsDB.accounts;
|
||||
|
||||
@@ -208,6 +208,15 @@
|
||||
/>
|
||||
button. You'll never know until you try.
|
||||
</div>
|
||||
<div v-else>
|
||||
<button
|
||||
@click="showNameThenIdDialog()"
|
||||
class="text-md font-bold bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mt-2 px-2 py-3 rounded-md"
|
||||
>
|
||||
Get someone to onboard you.
|
||||
</button>
|
||||
<UserNameDialog ref="userNameDialog" />
|
||||
</div>
|
||||
</div>
|
||||
<ul id="listProjects" class="border-t border-slate-300">
|
||||
<li
|
||||
@@ -247,8 +256,7 @@ import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import InfiniteScroll from "@/components/InfiniteScroll.vue";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
@@ -263,9 +271,17 @@ import {
|
||||
} from "@/libs/endorserServer";
|
||||
import EntityIcon from "@/components/EntityIcon.vue";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import UserNameDialog from "@/components/UserNameDialog.vue";
|
||||
|
||||
@Component({
|
||||
components: { EntityIcon, InfiniteScroll, QuickNav, ProjectIcon, TopMessage },
|
||||
components: {
|
||||
EntityIcon,
|
||||
InfiniteScroll,
|
||||
QuickNav,
|
||||
ProjectIcon,
|
||||
TopMessage,
|
||||
UserNameDialog,
|
||||
},
|
||||
})
|
||||
export default class ProjectsView extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
@@ -280,11 +296,12 @@ export default class ProjectsView extends Vue {
|
||||
allContacts: Array<Contact> = [];
|
||||
allMyDids: Array<string> = [];
|
||||
apiServer = "";
|
||||
projects: PlanData[] = [];
|
||||
givenName = "";
|
||||
isLoading = false;
|
||||
isRegistered = false;
|
||||
offers: OfferSummaryRecord[] = [];
|
||||
projectNameFromHandleId: Record<string, string> = {}; // mapping from handleId to description
|
||||
projects: PlanData[] = [];
|
||||
showOffers = true;
|
||||
showProjects = false;
|
||||
|
||||
@@ -293,11 +310,11 @@ export default class ProjectsView extends Vue {
|
||||
|
||||
async mounted() {
|
||||
try {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.activeDid = (settings?.activeDid as string) || "";
|
||||
this.apiServer = (settings?.apiServer as string) || "";
|
||||
this.isRegistered = !!settings?.isRegistered;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.isRegistered = !!settings.isRegistered;
|
||||
this.givenName = settings.firstName || "";
|
||||
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
|
||||
@@ -497,6 +514,37 @@ export default class ProjectsView extends Vue {
|
||||
await this.offerDataLoader(url);
|
||||
}
|
||||
|
||||
showNameThenIdDialog() {
|
||||
if (!this.givenName) {
|
||||
(this.$refs.userNameDialog as UserNameDialog).open(() => {
|
||||
this.promptForShareMethod();
|
||||
});
|
||||
} else {
|
||||
this.promptForShareMethod();
|
||||
}
|
||||
}
|
||||
|
||||
promptForShareMethod() {
|
||||
this.$notify(
|
||||
{
|
||||
group: "modal",
|
||||
type: "confirm",
|
||||
title: "Are you nearby with cameras?",
|
||||
text: "If so, we'll use those with QR codes to share.",
|
||||
onCancel: async () => {},
|
||||
onNo: async () => {
|
||||
(this.$router as Router).push({ name: "share-my-contact-info" });
|
||||
},
|
||||
onYes: async () => {
|
||||
(this.$router as Router).push({ name: "contact-qr" });
|
||||
},
|
||||
noText: "we will share another way",
|
||||
yesText: "we are nearby with cameras",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
}
|
||||
|
||||
public computedOfferTabClassNames() {
|
||||
return {
|
||||
"inline-block": true,
|
||||
|
||||
@@ -72,7 +72,7 @@ import { Component, Vue } from "vue-facing-decorator";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import {
|
||||
BVC_MEETUPS_PROJECT_CLAIM_ID,
|
||||
bvcMeetingJoinClaim,
|
||||
@@ -80,7 +80,6 @@ import {
|
||||
createAndSubmitGive,
|
||||
} from "@/libs/endorserServer";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@@ -117,10 +116,9 @@ export default class QuickActionBvcBeginView extends Vue {
|
||||
}
|
||||
|
||||
async record() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
const activeDid = settings?.activeDid || "";
|
||||
const apiServer = settings?.apiServer || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
const activeDid = settings.activeDid || "";
|
||||
const apiServer = settings.apiServer || "";
|
||||
|
||||
try {
|
||||
const hoursNum = libsUtil.numberOrZero(this.hoursStr);
|
||||
|
||||
@@ -144,9 +144,8 @@ import { Router } from "vue-router";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import {
|
||||
BVC_MEETUPS_PROJECT_CLAIM_ID,
|
||||
claimSpecialDescription,
|
||||
@@ -182,10 +181,9 @@ export default class QuickActionBvcBeginView extends Vue {
|
||||
someoneGave = false;
|
||||
|
||||
async created() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ import { Router } from "vue-router";
|
||||
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
|
||||
const DEFAULT_LAT_LONG_DIFF = 0.01;
|
||||
@@ -142,9 +142,8 @@ export default class DiscoverView extends Vue {
|
||||
searchBox: { name: string; bbox: BoundingBox } | null = null;
|
||||
|
||||
async mounted() {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.searchBox = settings?.searchBoxes?.[0] || null;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.searchBox = settings.searchBoxes?.[0] || null;
|
||||
this.resetLatLong();
|
||||
}
|
||||
|
||||
|
||||
@@ -105,9 +105,8 @@ import { useClipboard } from "@vueuse/core";
|
||||
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { Account } from "@/db/tables/accounts";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
|
||||
@Component({ components: { QuickNav } })
|
||||
export default class SeedBackupView extends Vue {
|
||||
@@ -122,9 +121,8 @@ export default class SeedBackupView extends Vue {
|
||||
// 'created' hook runs when the Vue instance is first created
|
||||
async created() {
|
||||
try {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
const activeDid = settings?.activeDid || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
const activeDid = settings.activeDid || "";
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = await accountsDB.accounts.toArray();
|
||||
|
||||
@@ -49,8 +49,7 @@ import { useClipboard } from "@vueuse/core";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { generateEndorserJwtForAccount } from "@/libs/endorserServer";
|
||||
|
||||
@Component({
|
||||
@@ -60,12 +59,11 @@ export default class ShareMyContactInfoView extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
|
||||
async onClickShare() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
const activeDid = settings?.activeDid || "";
|
||||
const givenName = settings?.firstName || "";
|
||||
const isRegistered = !!settings?.isRegistered;
|
||||
const profileImageUrl = settings?.profileImageUrl || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
const activeDid = settings.activeDid || "";
|
||||
const givenName = settings.firstName || "";
|
||||
const isRegistered = !!settings.isRegistered;
|
||||
const profileImageUrl = settings.profileImageUrl || "";
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = await accountsDB.accounts.toArray();
|
||||
|
||||
@@ -75,7 +75,7 @@ import {
|
||||
IMAGE_TYPE_PROFILE,
|
||||
NotificationIface,
|
||||
} from "@/constants/app";
|
||||
import { db } from "@/db/index";
|
||||
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { accessToken } from "@/libs/crypto";
|
||||
import { base64ToBlob, SHARED_PHOTO_BASE64_KEY } from "@/libs/util";
|
||||
@@ -94,9 +94,8 @@ export default class SharedPhotoView extends Vue {
|
||||
// 'created' hook runs when the Vue instance is first created
|
||||
async mounted() {
|
||||
try {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.activeDid = settings?.activeDid as string;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid;
|
||||
|
||||
const temp = await db.temp.get(SHARED_PHOTO_BASE64_KEY);
|
||||
const imageB64 = temp?.blobB64 as string;
|
||||
|
||||
@@ -92,8 +92,7 @@ import { Component, Vue } from "vue-facing-decorator";
|
||||
import { Router } from "vue-router";
|
||||
|
||||
import { AppString, PASSKEYS_ENABLED } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { accountsDB, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import { registerSaveAndActivatePasskey } from "@/libs/util";
|
||||
|
||||
@Component({
|
||||
@@ -106,9 +105,8 @@ export default class StartView extends Vue {
|
||||
numAccounts = 0;
|
||||
|
||||
async mounted() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.givenName = settings?.firstName || "";
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.givenName = settings.firstName || "";
|
||||
|
||||
await accountsDB.open();
|
||||
this.numAccounts = await accountsDB.accounts.count();
|
||||
|
||||
@@ -247,8 +247,7 @@ import { Router } from "vue-router";
|
||||
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import { AppString, NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import * as vcLib from "@/libs/crypto/vc";
|
||||
import {
|
||||
PeerSetup,
|
||||
@@ -291,10 +290,9 @@ export default class Help extends Vue {
|
||||
userName?: string;
|
||||
|
||||
async mounted() {
|
||||
await db.open();
|
||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||
this.activeDid = (settings?.activeDid as string) || "";
|
||||
this.userName = settings?.firstName as string;
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.userName = settings.firstName;
|
||||
|
||||
await accountsDB.open();
|
||||
const account: { identity?: string } | undefined = await accountsDB.accounts
|
||||
|
||||
@@ -37,6 +37,17 @@ test('Check no-ID messaging in account', async ({ page }) => {
|
||||
await expect(page.locator('#sectionIdentityDetails code.truncate')).toBeEmpty();
|
||||
});
|
||||
|
||||
test('Check ability to share contact', async ({ page }) => {
|
||||
// Load Discover view
|
||||
await page.goto('./discover');
|
||||
|
||||
// Check that initial 10 projects have been loaded
|
||||
await page.locator('ul#listDiscoverResults li.border-b:nth-child(10)');
|
||||
|
||||
// Scroll down a bit to trigger loading additional projects
|
||||
await page.locator('ul#listDiscoverResults li.border-b:nth-child(20)').scrollIntoViewIfNeeded();
|
||||
});
|
||||
|
||||
test('Check ID generation', async ({ page }) => {
|
||||
// Load Account view
|
||||
await page.goto('./account');
|
||||
@@ -83,7 +94,7 @@ test('Check setting name & sharing info', async ({ page }) => {
|
||||
await expect(page.getByText('your contacts')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Confirm usage of test API (may fail if you are running your own Time Safari)', async ({ page }, testInfo) => {
|
||||
test('Confirm test API setting (may fail if you are running your own Time Safari)', async ({ page }, testInfo) => {
|
||||
// Load account view
|
||||
await page.goto('./account');
|
||||
await page.getByRole('heading', { name: 'Advanced' }).click();
|
||||
|
||||
@@ -22,7 +22,7 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
|
||||
const finalTitle = standardTitle + finalRandomString;
|
||||
|
||||
// Contact name
|
||||
const contactName = 'Contact #111';
|
||||
const contactName = 'Contact #000 renamed';
|
||||
|
||||
// Import user 01
|
||||
await importUser(page, '01');
|
||||
@@ -45,6 +45,7 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
|
||||
await expect(page.locator('div.dialog-overlay > div.dialog').filter({ hasText: 'Edit Name' })).toBeVisible();
|
||||
await page.getByPlaceholder('Name', { exact: true }).fill(contactName);
|
||||
await page.locator('.dialog > .flex > button').first().click();
|
||||
// await page.locator('.dialog > .flex > button').first().click(); // close alert
|
||||
|
||||
// Confirm that home shows contact in "Record Something…"
|
||||
await page.goto('./');
|
||||
@@ -59,6 +60,9 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
|
||||
|
||||
// Refresh home view and check gift
|
||||
await page.goto('./');
|
||||
|
||||
// Firefox complains on load the initial feed here when we use the test server.
|
||||
// It may be similar to the CORS problem below.
|
||||
await page.locator('li').filter({ hasText: finalTitle }).locator('a').click();
|
||||
await expect(page.getByRole('heading', { name: 'Verifiable Claim Details' })).toBeVisible();
|
||||
await expect(page.getByText(finalTitle, { exact: true })).toBeVisible();
|
||||
@@ -88,6 +92,24 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
|
||||
await expect(page.locator('div[role="alert"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Without being registered, add contacts without registration', async ({ page, context }) => {
|
||||
await page.goto('./account');
|
||||
// wait until the DID shows on the page in the 'did' element
|
||||
const didElem = await page.getByTestId('didWrapper').locator('code');
|
||||
const newDid = await didElem.innerText();
|
||||
expect(newDid.trim()).toEqual('');
|
||||
|
||||
// Add new contact without registering
|
||||
await page.goto('./contacts');
|
||||
await page.getByPlaceholder('URL or DID, Name, Public Key').fill('did:ethr:0x111d15564f824D56C7a07b913aA7aDd03382aA39, User #111');
|
||||
await page.locator('button > svg.fa-plus').click();
|
||||
await expect(page.locator('div[role="alert"] span:has-text("Contact Added")')).toBeVisible();
|
||||
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss info alert
|
||||
// wait for the alert to disappear, which also ensures that there is no "Register" button waiting
|
||||
await expect(page.locator('div[role="alert"]')).toBeHidden();
|
||||
|
||||
});
|
||||
|
||||
test('Add contact, copy details, delete, and import various ways', async ({ page, context }) => {
|
||||
await importUser(page, '00');
|
||||
|
||||
@@ -117,6 +139,7 @@ test('Add contact, copy details, delete, and import various ways', async ({ page
|
||||
await page.getByTestId('contactCheckAllTop').click();
|
||||
await page.getByTestId('copySelectedContactsButtonTop').click();
|
||||
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert
|
||||
await expect(page.locator('div[role="alert"]')).toBeHidden();
|
||||
// I would prefer to copy from the clipboard, but the recommended approaches don't work.
|
||||
// this seems to fail in non-chromium browsers
|
||||
//await context.grantPermissions(['clipboard-read', 'clipboard-write']);
|
||||
@@ -125,12 +148,19 @@ test('Add contact, copy details, delete, and import various ways', async ({ page
|
||||
|
||||
// see contact details on the second contact
|
||||
await page.getByTestId('contactListItem').nth(1).locator('a').click();
|
||||
await page.getByRole('heading', { name: 'Identifier Details' }).isVisible();
|
||||
// remove contact
|
||||
await page.locator('button > svg.fa-trash-can').click();
|
||||
await page.locator('div[role="alert"] button:has-text("Yes")').click();
|
||||
// for some reason, .isHidden() (without expect) doesn't work
|
||||
await expect(page.locator('div[role="alert"] button:has-text("Yes")')).toBeHidden();
|
||||
|
||||
// Firefox has a problem when we run this against the test server. It doesn't load the feed.
|
||||
// It says there's a CORS problem; maybe it's more strict than the other browsers.
|
||||
// It works when we set the config to use a local server.
|
||||
// Seems like we hit a similar problem above.
|
||||
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert
|
||||
await expect(page.locator('div[role="alert"]')).toBeHidden();
|
||||
|
||||
// go to the contacts page and paste the copied contact details
|
||||
await page.goto('./contacts');
|
||||
|
||||
Reference in New Issue
Block a user