Browse Source

Merge pull request 'fix creation of did-specific settings (with a rename)' (#138) from fix-did-specifics into master

Reviewed-on: https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/pulls/138
master
trentlarson 4 days ago
parent
commit
0d343b9877
  1. 892
      package-lock.json
  2. 35
      src/components/FeedFilters.vue
  3. 6
      src/components/GiftedPrompts.vue
  4. 4
      src/components/OnboardingDialog.vue
  5. 148
      src/db/databaseUtil.ts
  6. 13
      src/libs/util.ts
  7. 4
      src/views/AccountViewView.vue
  8. 12
      src/views/ContactEditView.vue
  9. 3
      src/views/ContactImportView.vue
  10. 5
      src/views/ContactQRScanFullView.vue
  11. 5
      src/views/ContactQRScanShowView.vue
  12. 33
      src/views/ContactsView.vue
  13. 2
      src/views/HelpView.vue
  14. 4
      src/views/HomeView.vue
  15. 17
      src/views/ImportDerivedAccountView.vue
  16. 12
      src/views/NewActivityView.vue
  17. 4
      src/views/SearchAreaView.vue

892
package-lock.json

File diff suppressed because it is too large

35
src/components/FeedFilters.vue

@ -104,7 +104,6 @@ import { USE_DEXIE_DB } from "@/constants/app";
import * as databaseUtil from "../db/databaseUtil"; import * as databaseUtil from "../db/databaseUtil";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings"; import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import { db, retrieveSettingsForActiveAccount } from "../db/index"; import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({ @Component({
components: { components: {
@ -143,19 +142,23 @@ export default class FeedFilters extends Vue {
async toggleHasVisibleDid() { async toggleHasVisibleDid() {
this.settingChanged = true; this.settingChanged = true;
this.hasVisibleDid = !this.hasVisibleDid; this.hasVisibleDid = !this.hasVisibleDid;
await db.settings.update(MASTER_SETTINGS_KEY, { await databaseUtil.updateDefaultSettings({
filterFeedByVisible: this.hasVisibleDid, filterFeedByVisible: this.hasVisibleDid,
}); });
if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, {
filterFeedByVisible: this.hasVisibleDid,
});
}
} }
async toggleNearby() { async toggleNearby() {
this.settingChanged = true; this.settingChanged = true;
this.isNearby = !this.isNearby; this.isNearby = !this.isNearby;
const platformService = PlatformServiceFactory.getInstance(); await databaseUtil.updateDefaultSettings({
await platformService.dbExec( filterFeedByNearby: this.isNearby,
`UPDATE settings SET filterFeedByNearby = ? WHERE id = ?`, });
[this.isNearby, MASTER_SETTINGS_KEY],
);
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
@ -169,11 +172,10 @@ export default class FeedFilters extends Vue {
this.settingChanged = true; this.settingChanged = true;
} }
const platformService = PlatformServiceFactory.getInstance(); await databaseUtil.updateDefaultSettings({
await platformService.dbExec( filterFeedByNearby: false,
`UPDATE settings SET filterFeedByNearby = ? AND filterFeedByVisible = ? WHERE id = ?`, filterFeedByVisible: false,
[false, false, MASTER_SETTINGS_KEY], });
);
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
@ -191,11 +193,10 @@ export default class FeedFilters extends Vue {
this.settingChanged = true; this.settingChanged = true;
} }
const platformService = PlatformServiceFactory.getInstance(); await databaseUtil.updateDefaultSettings({
await platformService.dbExec( filterFeedByNearby: true,
`UPDATE settings SET filterFeedByNearby = ? AND filterFeedByVisible = ? WHERE id = ?`, filterFeedByVisible: true,
[true, true, MASTER_SETTINGS_KEY], });
);
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {

6
src/components/GiftedPrompts.vue

@ -227,6 +227,7 @@ export default class GivenPrompts extends Vue {
let someContactDbIndex = Math.floor(Math.random() * this.numContacts); let someContactDbIndex = Math.floor(Math.random() * this.numContacts);
let count = 0; let count = 0;
// as long as the index has an entry, loop // as long as the index has an entry, loop
while ( while (
this.shownContactDbIndices[someContactDbIndex] != null && this.shownContactDbIndices[someContactDbIndex] != null &&
@ -245,9 +246,8 @@ export default class GivenPrompts extends Vue {
[someContactDbIndex], [someContactDbIndex],
); );
if (result) { if (result) {
this.currentContact = databaseUtil.mapQueryResultToValues(result)[ const mappedContacts = databaseUtil.mapQueryResultToValues(result);
someContactDbIndex this.currentContact = mappedContacts[0] as unknown as Contact;
] as unknown as Contact;
} }
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await db.open(); await db.open();

4
src/components/OnboardingDialog.vue

@ -259,7 +259,7 @@ export default class OnboardingDialog extends Vue {
this.visible = true; this.visible = true;
if (this.page === OnboardPage.Create) { if (this.page === OnboardPage.Create) {
// we'll assume that they've been through all the other pages // we'll assume that they've been through all the other pages
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
finishedOnboarding: true, finishedOnboarding: true,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
@ -273,7 +273,7 @@ export default class OnboardingDialog extends Vue {
async onClickClose(done?: boolean, goHome?: boolean) { async onClickClose(done?: boolean, goHome?: boolean) {
this.visible = false; this.visible = false;
if (done) { if (done) {
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
finishedOnboarding: true, finishedOnboarding: true,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {

148
src/db/databaseUtil.ts

@ -37,7 +37,20 @@ export async function updateDefaultSettings(
} }
} }
export async function updateAccountSettings( export async function insertDidSpecificSettings(
did: string,
settings: Partial<Settings> = {},
): Promise<boolean> {
const platform = PlatformServiceFactory.getInstance();
const { sql, params } = generateInsertStatement(
{ ...settings, accountDid: did }, // make sure accountDid is set to the given value
"settings",
);
const result = await platform.dbExec(sql, params);
return result.changes === 1;
}
export async function updateDidSpecificSettings(
accountDid: string, accountDid: string,
settingsChanges: Settings, settingsChanges: Settings,
): Promise<boolean> { ): Promise<boolean> {
@ -96,9 +109,6 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
const defaultSettings = await retrieveSettingsForDefaultAccount(); const defaultSettings = await retrieveSettingsForDefaultAccount();
// If no active DID, return defaults // If no active DID, return defaults
if (!defaultSettings.activeDid) { if (!defaultSettings.activeDid) {
logConsoleAndDb(
"[databaseUtil] No active DID found, returning default settings",
);
return defaultSettings; return defaultSettings;
} }
@ -111,9 +121,7 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
); );
if (!result?.values?.length) { if (!result?.values?.length) {
logConsoleAndDb( // we created DID-specific settings when generated or imported, so this shouldn't happen
`[databaseUtil] No account-specific settings found for ${defaultSettings.activeDid}`,
);
return defaultSettings; return defaultSettings;
} }
@ -122,6 +130,7 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
result.columns, result.columns,
result.values, result.values,
)[0] as Settings; )[0] as Settings;
const overrideSettingsFiltered = Object.fromEntries( const overrideSettingsFiltered = Object.fromEntries(
Object.entries(overrideSettings).filter(([_, v]) => v !== null), Object.entries(overrideSettings).filter(([_, v]) => v !== null),
); );
@ -131,17 +140,7 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
// Handle searchBoxes parsing // Handle searchBoxes parsing
if (settings.searchBoxes) { if (settings.searchBoxes) {
try { settings.searchBoxes = parseJsonField(settings.searchBoxes, []);
// @ts-expect-error - the searchBoxes field is a string in the DB
settings.searchBoxes = JSON.parse(settings.searchBoxes);
} catch (error) {
logConsoleAndDb(
`[databaseUtil] Failed to parse searchBoxes for ${defaultSettings.activeDid}: ${error}`,
true,
);
// Reset to empty array on parse failure
settings.searchBoxes = [];
}
} }
return settings; return settings;
@ -241,6 +240,7 @@ export function generateInsertStatement(
const values = Object.values(model).filter((value) => value !== undefined); const values = Object.values(model).filter((value) => value !== undefined);
const placeholders = values.map(() => "?").join(", "); const placeholders = values.map(() => "?").join(", ");
const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`; const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`;
return { return {
sql: insertSql, sql: insertSql,
params: values, params: values,
@ -312,3 +312,115 @@ export function mapColumnsToValues(
return obj; return obj;
}); });
} }
/**
* Debug function to inspect raw settings data in the database
* This helps diagnose issues with data corruption or malformed JSON
* @param did Optional DID to inspect specific account settings
* @author Matthew Raymer
*/
export async function debugSettingsData(did?: string): Promise<void> {
try {
const platform = PlatformServiceFactory.getInstance();
// Get all settings records
const allSettings = await platform.dbQuery("SELECT * FROM settings");
logConsoleAndDb(
`[DEBUG] Total settings records: ${allSettings?.values?.length || 0}`,
false,
);
if (allSettings?.values?.length) {
allSettings.values.forEach((row, index) => {
const settings = mapColumnsToValues(allSettings.columns, [row])[0];
logConsoleAndDb(`[DEBUG] Settings record ${index + 1}:`, false);
logConsoleAndDb(`[DEBUG] - ID: ${settings.id}`, false);
logConsoleAndDb(`[DEBUG] - accountDid: ${settings.accountDid}`, false);
logConsoleAndDb(`[DEBUG] - activeDid: ${settings.activeDid}`, false);
if (settings.searchBoxes) {
logConsoleAndDb(
`[DEBUG] - searchBoxes type: ${typeof settings.searchBoxes}`,
false,
);
logConsoleAndDb(
`[DEBUG] - searchBoxes value: ${String(settings.searchBoxes)}`,
false,
);
// Try to parse it
try {
const parsed = JSON.parse(String(settings.searchBoxes));
logConsoleAndDb(
`[DEBUG] - searchBoxes parsed successfully: ${JSON.stringify(parsed)}`,
false,
);
} catch (parseError) {
logConsoleAndDb(
`[DEBUG] - searchBoxes parse error: ${parseError}`,
true,
);
}
}
logConsoleAndDb(
`[DEBUG] - Full record: ${JSON.stringify(settings, null, 2)}`,
false,
);
});
}
// If specific DID provided, also check accounts table
if (did) {
const account = await platform.dbQuery(
"SELECT * FROM accounts WHERE did = ?",
[did],
);
logConsoleAndDb(
`[DEBUG] Account for ${did}: ${JSON.stringify(account, null, 2)}`,
false,
);
}
} catch (error) {
logConsoleAndDb(`[DEBUG] Error inspecting settings data: ${error}`, true);
}
}
/**
* Platform-agnostic JSON parsing utility
* Handles different SQLite implementations:
* - Web SQLite (wa-sqlite/absurd-sql): Auto-parses JSON strings to objects
* - Capacitor SQLite: Returns raw strings that need manual parsing
*
* @param value The value to parse (could be string or already parsed object)
* @param defaultValue Default value if parsing fails
* @returns Parsed object or default value
* @author Matthew Raymer
*/
export function parseJsonField<T>(value: unknown, defaultValue: T): T {
try {
// If already an object (web SQLite auto-parsed), return as-is
if (typeof value === "object" && value !== null) {
return value as T;
}
// If it's a string (Capacitor SQLite or fallback), parse it
if (typeof value === "string") {
return JSON.parse(value) as T;
}
// If it's null/undefined, return default
if (value === null || value === undefined) {
return defaultValue;
}
return defaultValue;
} catch (error) {
logConsoleAndDb(
`[databaseUtil] Failed to parse JSON field: ${error}`,
true,
);
return defaultValue;
}
}

13
src/libs/util.ts

@ -44,6 +44,7 @@ import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory"; import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { sha256 } from "ethereum-cryptography/sha256"; import { sha256 } from "ethereum-cryptography/sha256";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
import { insertDidSpecificSettings, parseJsonField } from "../db/databaseUtil";
export interface GiverReceiverInputInfo { export interface GiverReceiverInputInfo {
did?: string; did?: string;
@ -697,6 +698,7 @@ export async function saveNewIdentity(
]; ];
await platformService.dbExec(sql, params); await platformService.dbExec(sql, params);
await databaseUtil.updateDefaultSettings({ activeDid: identity.did }); await databaseUtil.updateDefaultSettings({ activeDid: identity.did });
await databaseUtil.insertDidSpecificSettings(identity.did);
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
// one of the few times we use accountsDBPromise directly; try to avoid more usage // one of the few times we use accountsDBPromise directly; try to avoid more usage
@ -710,6 +712,7 @@ export async function saveNewIdentity(
publicKeyHex: identity.keys[0].publicKeyHex, publicKeyHex: identity.keys[0].publicKeyHex,
}); });
await updateDefaultSettings({ activeDid: identity.did }); await updateDefaultSettings({ activeDid: identity.did });
await insertDidSpecificSettings(identity.did);
} }
} catch (error) { } catch (error) {
logger.error("Failed to update default settings:", error); logger.error("Failed to update default settings:", error);
@ -732,7 +735,9 @@ export const generateSaveAndActivateIdentity = async (): Promise<string> => {
const newId = newIdentifier(address, publicHex, privateHex, derivationPath); const newId = newIdentifier(address, publicHex, privateHex, derivationPath);
await saveNewIdentity(newId, mnemonic, derivationPath); await saveNewIdentity(newId, mnemonic, derivationPath);
await databaseUtil.updateAccountSettings(newId.did, { isRegistered: false }); await databaseUtil.updateDidSpecificSettings(newId.did, {
isRegistered: false,
});
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await updateAccountSettings(newId.did, { isRegistered: false }); await updateAccountSettings(newId.did, { isRegistered: false });
} }
@ -774,7 +779,7 @@ export const registerSaveAndActivatePasskey = async (
): Promise<Account> => { ): Promise<Account> => {
const account = await registerAndSavePasskey(keyName); const account = await registerAndSavePasskey(keyName);
await databaseUtil.updateDefaultSettings({ activeDid: account.did }); await databaseUtil.updateDefaultSettings({ activeDid: account.did });
await databaseUtil.updateAccountSettings(account.did, { await databaseUtil.updateDidSpecificSettings(account.did, {
isRegistered: false, isRegistered: false,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
@ -862,7 +867,7 @@ export const contactToCsvLine = (contact: Contact): string => {
// Handle contactMethods array by stringifying it // Handle contactMethods array by stringifying it
const contactMethodsStr = contact.contactMethods const contactMethodsStr = contact.contactMethods
? escapeField(JSON.stringify(contact.contactMethods)) ? escapeField(JSON.stringify(parseJsonField(contact.contactMethods, [])))
: ""; : "";
const fields = [ const fields = [
@ -907,7 +912,7 @@ export const contactsToExportJson = (contacts: Contact[]): DatabaseExport => {
did: contact.did, did: contact.did,
name: contact.name || null, name: contact.name || null,
contactMethods: contact.contactMethods contactMethods: contact.contactMethods
? JSON.stringify(contact.contactMethods) ? JSON.stringify(parseJsonField(contact.contactMethods, []))
: null, : null,
nextPubKeyHashB64: contact.nextPubKeyHashB64 || null, nextPubKeyHashB64: contact.nextPubKeyHashB64 || null,
notes: contact.notes || null, notes: contact.notes || null,

4
src/views/AccountViewView.vue

@ -1814,7 +1814,7 @@ export default class AccountViewView extends Vue {
if (!this.isRegistered) { 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 // the user was not known to be registered, but now they are (because we got no error) so let's record it
try { try {
await databaseUtil.updateAccountSettings(did, { await databaseUtil.updateDidSpecificSettings(did, {
isRegistered: true, isRegistered: true,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
@ -2018,7 +2018,7 @@ export default class AccountViewView extends Vue {
if ((error as any).response.status === 404) { if ((error as any).response.status === 404) {
logger.error("The image was already deleted:", error); logger.error("The image was already deleted:", error);
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
profileImageUrl: undefined, profileImageUrl: undefined,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {

12
src/views/ContactEditView.vue

@ -138,11 +138,13 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
import QuickNav from "../components/QuickNav.vue"; import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue"; import TopMessage from "../components/TopMessage.vue";
import { AppString, NotificationIface, USE_DEXIE_DB } from "../constants/app"; import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import { parseJsonField } from "../db/databaseUtil";
import { db } from "../db/index"; import { db } from "../db/index";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import { Contact, ContactMethod } from "../db/tables/contacts"; import { Contact, ContactMethod } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil"; import { AppString } from "../constants/app";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
/** /**
* Contact Edit View Component * Contact Edit View Component
@ -230,9 +232,7 @@ export default class ContactEditView extends Vue {
let contact: Contact | undefined = databaseUtil.mapQueryResultToValues( let contact: Contact | undefined = databaseUtil.mapQueryResultToValues(
dbContact, dbContact,
)[0] as unknown as Contact; )[0] as unknown as Contact;
contact.contactMethods = JSON.parse( contact.contactMethods = parseJsonField(contact?.contactMethods, []);
(contact?.contactMethods as unknown as string) || "[]",
);
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await db.open(); await db.open();
contact = await db.contacts.get(contactDid || ""); contact = await db.contacts.get(contactDid || "");

3
src/views/ContactImportView.vue

@ -213,6 +213,7 @@ import {
} from "../db/index"; } from "../db/index";
import { Contact, ContactMethod } from "../db/tables/contacts"; import { Contact, ContactMethod } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil"; import * as databaseUtil from "../db/databaseUtil";
import { parseJsonField } from "../db/databaseUtil";
import * as libsUtil from "../libs/util"; import * as libsUtil from "../libs/util";
import { import {
capitalizeAndInsertSpacesBeforeCaps, capitalizeAndInsertSpacesBeforeCaps,
@ -289,7 +290,7 @@ function dbRecordToContact(record: ContactDbRecord): Contact {
profileImageUrl: safeString(record.profileImageUrl), profileImageUrl: safeString(record.profileImageUrl),
publicKeyBase64: safeString(record.publicKeyBase64), publicKeyBase64: safeString(record.publicKeyBase64),
nextPubKeyHashB64: safeString(record.nextPubKeyHashB64), nextPubKeyHashB64: safeString(record.nextPubKeyHashB64),
contactMethods: JSON.parse(record.contactMethods || "[]"), contactMethods: parseJsonField(record.contactMethods, []),
}; };
} }

5
src/views/ContactQRScanFullView.vue

@ -124,6 +124,7 @@ import UserNameDialog from "../components/UserNameDialog.vue";
import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer"; import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
import { retrieveAccountMetadata } from "../libs/util"; import { retrieveAccountMetadata } from "../libs/util";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory"; import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
import { parseJsonField } from "../db/databaseUtil";
interface QRScanResult { interface QRScanResult {
rawValue?: string; rawValue?: string;
@ -474,7 +475,9 @@ export default class ContactQRScan extends Vue {
// Add new contact // Add new contact
// @ts-expect-error because we're just using the value to store to the DB // @ts-expect-error because we're just using the value to store to the DB
contact.contactMethods = JSON.stringify(contact.contactMethods); contact.contactMethods = JSON.stringify(
parseJsonField(contact.contactMethods, []),
);
const { sql, params } = databaseUtil.generateInsertStatement( const { sql, params } = databaseUtil.generateInsertStatement(
contact as unknown as Record<string, unknown>, contact as unknown as Record<string, unknown>,
"contacts", "contacts",

5
src/views/ContactQRScanShowView.vue

@ -171,6 +171,7 @@ import { db, retrieveSettingsForActiveAccount } from "../db/index";
import { Contact } from "../db/tables/contacts"; import { Contact } from "../db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings"; import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil"; import * as databaseUtil from "../db/databaseUtil";
import { parseJsonField } from "../db/databaseUtil";
import { getContactJwtFromJwtUrl } from "../libs/crypto"; import { getContactJwtFromJwtUrl } from "../libs/crypto";
import { import {
generateEndorserJwtUrlForAccount, generateEndorserJwtUrlForAccount,
@ -778,7 +779,9 @@ export default class ContactQRScanShow extends Vue {
// Add new contact // Add new contact
// @ts-expect-error because we're just using the value to store to the DB // @ts-expect-error because we're just using the value to store to the DB
contact.contactMethods = JSON.stringify(contact.contactMethods); contact.contactMethods = JSON.stringify(
parseJsonField(contact.contactMethods, []),
);
const { sql, params } = databaseUtil.generateInsertStatement( const { sql, params } = databaseUtil.generateInsertStatement(
contact as unknown as Record<string, unknown>, contact as unknown as Record<string, unknown>,
"contacts", "contacts",

33
src/views/ContactsView.vue

@ -103,8 +103,12 @@
v-if="!showGiveNumbers" v-if="!showGiveNumbers"
:class=" :class="
contactsSelected.length > 0 contactsSelected.length > 0
? 'text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-3 px-3 py-1.5 rounded-md cursor-pointer' ? 'text-md bg-gradient-to-b from-blue-400 to-blue-700 ' +
: 'text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-slate-300 ml-3 px-3 py-1.5 rounded-md cursor-not-allowed' 'shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ' +
'ml-3 px-3 py-1.5 rounded-md cursor-pointer'
: 'text-md bg-gradient-to-b from-slate-400 to-slate-700 ' +
'shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-slate-300 ' +
'ml-3 px-3 py-1.5 rounded-md cursor-not-allowed'
" "
data-testId="copySelectedContactsButtonTop" data-testId="copySelectedContactsButtonTop"
@click="copySelectedContacts()" @click="copySelectedContacts()"
@ -112,9 +116,9 @@
Copy Copy
</button> </button>
<font-awesome <font-awesome
@click="showCopySelectionsInfo()"
icon="circle-info" icon="circle-info"
class="text-2xl text-blue-500 ml-2" class="text-2xl text-blue-500 ml-2"
@click="showCopySelectionsInfo()"
/> />
</div> </div>
</div> </div>
@ -142,16 +146,13 @@
class="text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md" class="text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
@click="toggleShowContactAmounts()" @click="toggleShowContactAmounts()"
> >
{{ {{ showGiveNumbers ? "Hide Actions" : "See Actions" }}
showGiveNumbers ? "Hide Actions" : "See Actions"
}}
</button> </button>
</div> </div>
</div> </div>
<div v-if="showGiveNumbers" class="my-3"> <div v-if="showGiveNumbers" class="my-3">
<div class="w-full text-center text-sm italic text-slate-600"> <div class="w-full text-center text-sm italic text-slate-600">
Only the most recent hours are included. <br />To see more, Only the most recent hours are included. <br />To see more, click
click
<span <span
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1 py-0.5 rounded" class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1 py-0.5 rounded"
> >
@ -223,9 +224,7 @@
/> />
</router-link> </router-link>
<span class="text-xs truncate">{{ <span class="text-xs truncate">{{ contact.did }}</span>
contact.did
}}</span>
</div> </div>
<div class="text-sm"> <div class="text-sm">
{{ contact.notes }} {{ contact.notes }}
@ -237,7 +236,7 @@
v-if="showGiveNumbers && contact.did != activeDid" v-if="showGiveNumbers && contact.did != activeDid"
class="flex gap-1.5 items-end" class="flex gap-1.5 items-end"
> >
<div class='text-center'> <div class="text-center">
<div class="text-xs leading-none mb-1">From/To</div> <div class="text-xs leading-none mb-1">From/To</div>
<div class="flex items-center"> <div class="flex items-center">
<button <button
@ -317,8 +316,12 @@
v-if="!showGiveNumbers" v-if="!showGiveNumbers"
:class=" :class="
contactsSelected.length > 0 contactsSelected.length > 0
? 'text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-3 px-3 py-1.5 rounded-md cursor-pointer' ? 'text-md bg-gradient-to-b from-blue-400 to-blue-700 ' +
: 'text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-slate-300 ml-3 px-3 py-1.5 rounded-md cursor-not-allowed' 'shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ' +
'ml-3 px-3 py-1.5 rounded-md cursor-pointer'
: 'text-md bg-gradient-to-b from-slate-400 to-slate-700 ' +
'shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-slate-300 ' +
'ml-3 px-3 py-1.5 rounded-md cursor-not-allowed'
" "
@click="copySelectedContacts()" @click="copySelectedContacts()"
> >
@ -541,7 +544,7 @@ export default class ContactsView extends Vue {
if (response.status != 201) { if (response.status != 201) {
throw { error: { response: response } }; throw { error: { response: response } };
} }
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
isRegistered: true, isRegistered: true,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {

2
src/views/HelpView.vue

@ -622,7 +622,7 @@ export default class HelpView extends Vue {
} }
if (settings.activeDid) { if (settings.activeDid) {
await databaseUtil.updateAccountSettings(settings.activeDid, { await databaseUtil.updateDidSpecificSettings(settings.activeDid, {
finishedOnboarding: false, finishedOnboarding: false,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {

4
src/views/HomeView.vue

@ -630,7 +630,7 @@ export default class HomeView extends Vue {
this.activeDid, this.activeDid,
); );
if (resp.status === 200) { if (resp.status === 200) {
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
isRegistered: true, isRegistered: true,
...(await databaseUtil.retrieveSettingsForActiveAccount()), ...(await databaseUtil.retrieveSettingsForActiveAccount()),
}); });
@ -785,7 +785,7 @@ export default class HomeView extends Vue {
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
settings = await retrieveSettingsForActiveAccount(); settings = await retrieveSettingsForActiveAccount();
} }
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
apiServer: this.apiServer, apiServer: this.apiServer,
isRegistered: true, isRegistered: true,
...settings, ...settings,

17
src/views/ImportDerivedAccountView.vue

@ -79,7 +79,8 @@ import {
newIdentifier, newIdentifier,
nextDerivationPath, nextDerivationPath,
} from "../libs/crypto"; } from "../libs/crypto";
import { accountsDBPromise, db } from "../db/index"; import * as databaseUtil from "../db/databaseUtil";
import { db } from "../db/index";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings"; import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import { import {
retrieveAllAccountsMetadata, retrieveAllAccountsMetadata,
@ -164,23 +165,15 @@ export default class ImportAccountView extends Vue {
try { try {
await saveNewIdentity(newId, mne, newDerivPath); await saveNewIdentity(newId, mne, newDerivPath);
if (USE_DEXIE_DB) {
const accountsDB = await accountsDBPromise;
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
derivationPath: newDerivPath,
did: newId.did,
identity: JSON.stringify(newId),
mnemonic: mne,
publicKeyHex: newId.keys[0].publicKeyHex,
});
}
// record that as the active DID // record that as the active DID
const platformService = PlatformServiceFactory.getInstance(); const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec("UPDATE settings SET activeDid = ?", [ await platformService.dbExec("UPDATE settings SET activeDid = ?", [
newId.did, newId.did,
]); ]);
await databaseUtil.updateDidSpecificSettings(newId.did, {
isRegistered: false,
});
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
activeDid: newId.did, activeDid: newId.did,

12
src/views/NewActivityView.vue

@ -257,7 +257,7 @@ export default class NewActivityView extends Vue {
async expandOffersToUserAndMarkRead() { async expandOffersToUserAndMarkRead() {
this.showOffersDetails = !this.showOffersDetails; this.showOffersDetails = !this.showOffersDetails;
if (this.showOffersDetails) { if (this.showOffersDetails) {
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
lastAckedOfferToUserJwtId: this.newOffersToUser[0].jwtId, lastAckedOfferToUserJwtId: this.newOffersToUser[0].jwtId,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
@ -285,7 +285,7 @@ export default class NewActivityView extends Vue {
); );
if (index !== -1 && index < this.newOffersToUser.length - 1) { if (index !== -1 && index < this.newOffersToUser.length - 1) {
// Set to the next offer's jwtId // Set to the next offer's jwtId
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
lastAckedOfferToUserJwtId: this.newOffersToUser[index + 1].jwtId, lastAckedOfferToUserJwtId: this.newOffersToUser[index + 1].jwtId,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
@ -295,7 +295,7 @@ export default class NewActivityView extends Vue {
} }
} else { } else {
// it's the last entry (or not found), so just keep it the same // it's the last entry (or not found), so just keep it the same
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
lastAckedOfferToUserJwtId: this.lastAckedOfferToUserJwtId, lastAckedOfferToUserJwtId: this.lastAckedOfferToUserJwtId,
}); });
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
@ -319,7 +319,7 @@ export default class NewActivityView extends Vue {
this.showOffersToUserProjectsDetails = this.showOffersToUserProjectsDetails =
!this.showOffersToUserProjectsDetails; !this.showOffersToUserProjectsDetails;
if (this.showOffersToUserProjectsDetails) { if (this.showOffersToUserProjectsDetails) {
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
lastAckedOfferToUserProjectsJwtId: lastAckedOfferToUserProjectsJwtId:
this.newOffersToUserProjects[0].jwtId, this.newOffersToUserProjects[0].jwtId,
}); });
@ -349,7 +349,7 @@ export default class NewActivityView extends Vue {
); );
if (index !== -1 && index < this.newOffersToUserProjects.length - 1) { if (index !== -1 && index < this.newOffersToUserProjects.length - 1) {
// Set to the next offer's jwtId // Set to the next offer's jwtId
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
lastAckedOfferToUserProjectsJwtId: lastAckedOfferToUserProjectsJwtId:
this.newOffersToUserProjects[index + 1].jwtId, this.newOffersToUserProjects[index + 1].jwtId,
}); });
@ -361,7 +361,7 @@ export default class NewActivityView extends Vue {
} }
} else { } else {
// it's the last entry (or not found), so just keep it the same // it's the last entry (or not found), so just keep it the same
await databaseUtil.updateAccountSettings(this.activeDid, { await databaseUtil.updateDidSpecificSettings(this.activeDid, {
lastAckedOfferToUserProjectsJwtId: lastAckedOfferToUserProjectsJwtId:
this.lastAckedOfferToUserProjectsJwtId, this.lastAckedOfferToUserProjectsJwtId,
}); });

4
src/views/SearchAreaView.vue

@ -215,7 +215,7 @@ export default class SearchAreaView extends Vue {
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
searchBoxes: [newSearchBox], searchBoxes: searchBoxes as unknown, // Type assertion for Dexie compatibility
}); });
} }
this.searchBox = newSearchBox; this.searchBox = newSearchBox;
@ -269,7 +269,7 @@ export default class SearchAreaView extends Vue {
if (USE_DEXIE_DB) { if (USE_DEXIE_DB) {
await db.open(); await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
searchBoxes: [], searchBoxes: "[]" as unknown as string, // Type assertion for Dexie compatibility
filterFeedByNearby: false, filterFeedByNearby: false,
}); });
} }

Loading…
Cancel
Save