From 5971f0976a5e8316b3c313a3a17078063c92ff14 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 29 Jul 2025 20:37:47 -0600 Subject: [PATCH 1/6] chore: Comment out the unused caching utilities (so they're not mistakenly used). --- src/utils/PlatformServiceMixin.ts | 194 +++++++++++++++--------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/src/utils/PlatformServiceMixin.ts b/src/utils/PlatformServiceMixin.ts index d0993048..d622d00f 100644 --- a/src/utils/PlatformServiceMixin.ts +++ b/src/utils/PlatformServiceMixin.ts @@ -59,14 +59,14 @@ import { // TYPESCRIPT INTERFACES // ================================================= -/** - * Cache entry interface for storing data with TTL - */ -interface CacheEntry { - data: T; - timestamp: number; - ttl: number; // milliseconds -} +// /** +// * Cache entry interface for storing data with TTL +// */ +// interface CacheEntry { +// data: T; +// timestamp: number; +// ttl: number; // milliseconds +// } /** * Vue component interface that uses the PlatformServiceMixin @@ -79,21 +79,21 @@ interface VueComponentWithMixin { platformService(): PlatformService; } -/** - * Global cache store for mixin instances - * Uses WeakMap to avoid memory leaks when components are destroyed - */ -const componentCaches = new WeakMap< - VueComponentWithMixin, - Map> ->(); - -/** - * Cache configuration constants - */ -const CACHE_DEFAULTS = { - default: 15000, // 15 seconds default TTL -} as const; +// /** +// * Global cache store for mixin instances +// * Uses WeakMap to avoid memory leaks when components are destroyed +// */ +// const componentCaches = new WeakMap< +// VueComponentWithMixin, +// Map> +// >(); +// +// /** +// * Cache configuration constants +// */ +// const CACHE_DEFAULTS = { +// default: 15000, // 15 seconds default TTL +// } as const; const _memoryLogs: string[] = []; @@ -203,8 +203,8 @@ export const PlatformServiceMixin = { logger.debug( `[PlatformServiceMixin] ActiveDid updated from ${oldDid} to ${newDid}`, ); - // Clear caches that might be affected by the change - this.$clearAllCaches(); + // // Clear caches that might be affected by the change + // this.$clearAllCaches(); } }, @@ -256,71 +256,71 @@ export const PlatformServiceMixin = { return (value as T) || defaultValue; }, - // ================================================= - // CACHING UTILITY METHODS - // ================================================= - - /** - * Get or initialize cache for this component instance - */ - _getCache(): Map> { - let cache = componentCaches.get(this as unknown as VueComponentWithMixin); - if (!cache) { - cache = new Map(); - componentCaches.set(this as unknown as VueComponentWithMixin, cache); - } - return cache; - }, - - /** - * Check if cache entry is valid (not expired) - */ - _isCacheValid(entry: CacheEntry): boolean { - return Date.now() - entry.timestamp < entry.ttl; - }, - - /** - * Get data from cache if valid, otherwise return null - */ - _getCached(key: string): T | null { - const cache = this._getCache(); - const entry = cache.get(key); - if (entry && this._isCacheValid(entry)) { - return entry.data as T; - } - cache.delete(key); // Clean up expired entries - return null; - }, - - /** - * Store data in cache with TTL - */ - _setCached(key: string, data: T, ttl?: number): T { - const cache = this._getCache(); - const actualTtl = ttl || CACHE_DEFAULTS.default; - cache.set(key, { - data, - timestamp: Date.now(), - ttl: actualTtl, - }); - return data; - }, - - /** - * Invalidate specific cache entry - */ - _invalidateCache(key: string): void { - const cache = this._getCache(); - cache.delete(key); - }, - - /** - * Clear all cache entries for this component - */ - _clearCache(): void { - const cache = this._getCache(); - cache.clear(); - }, + // // ================================================= + // // CACHING UTILITY METHODS + // // ================================================= + + // /** + // * Get or initialize cache for this component instance + // */ + // _getCache(): Map> { + // let cache = componentCaches.get(this as unknown as VueComponentWithMixin); + // if (!cache) { + // cache = new Map(); + // componentCaches.set(this as unknown as VueComponentWithMixin, cache); + // } + // return cache; + // }, + + // /** + // * Check if cache entry is valid (not expired) + // */ + // _isCacheValid(entry: CacheEntry): boolean { + // return Date.now() - entry.timestamp < entry.ttl; + // }, + + // /** + // * Get data from cache if valid, otherwise return null + // */ + // _getCached(key: string): T | null { + // const cache = this._getCache(); + // const entry = cache.get(key); + // if (entry && this._isCacheValid(entry)) { + // return entry.data as T; + // } + // cache.delete(key); // Clean up expired entries + // return null; + // }, + + // /** + // * Store data in cache with TTL + // */ + // _setCached(key: string, data: T, ttl?: number): T { + // const cache = this._getCache(); + // const actualTtl = ttl || CACHE_DEFAULTS.default; + // cache.set(key, { + // data, + // timestamp: Date.now(), + // ttl: actualTtl, + // }); + // return data; + // }, + + // /** + // * Invalidate specific cache entry + // */ + // _invalidateCache(key: string): void { + // const cache = this._getCache(); + // cache.delete(key); + // }, + + // /** + // * Clear all cache entries for this component + // */ + // _clearCache(): void { + // const cache = this._getCache(); + // cache.clear(); + // }, // ================================================= // ENHANCED DATABASE METHODS (with error handling) @@ -872,13 +872,13 @@ export const PlatformServiceMixin = { return await this.$contacts(); }, - /** - * Clear all caches for this component - $clearAllCaches() - * Useful for manual cache management - */ - $clearAllCaches(): void { - this._clearCache(); - }, + // /** + // * Clear all caches for this component - $clearAllCaches() + // * Useful for manual cache management + // */ + // $clearAllCaches(): void { + // this._clearCache(); + // }, // ================================================= // HIGH-LEVEL ENTITY OPERATIONS (eliminate verbose SQL patterns) From 54e5657899f165f743ce1e5d952e115e2d16f432 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 29 Jul 2025 20:57:53 -0600 Subject: [PATCH 2/6] fix: remove code that blanks out the profile image on limit retrieval, which should be unrelated --- src/views/AccountViewView.vue | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 8fea0cab..ef35f800 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -1396,10 +1396,6 @@ export default class AccountViewView extends Vue { if (imageResp.status === 200) { this.imageLimits = imageResp.data; } else { - await this.$saveSettings({ - profileImageUrl: "", - }); - this.profileImageUrl = ""; this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IMAGE_ACCESS; this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.CANNOT_UPLOAD_IMAGES); return; @@ -1414,17 +1410,13 @@ export default class AccountViewView extends Vue { if (endorserResp.status === 200) { this.endorserLimits = endorserResp.data; } else { - await this.$saveSettings({ - profileImageUrl: "", - }); - this.profileImageUrl = ""; this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_LIMITS_FOUND; this.notify.warning(ACCOUNT_VIEW_CONSTANTS.LIMITS.BAD_SERVER_RESPONSE); return; } } catch (error) { this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS; - console.log("error: ", error); + logger.error("Error retrieving limits: ", error); // this.notify.error(this.limitsMessage, TIMEOUTS.STANDARD); } finally { this.loadingLimits = false; From 4e36612388b223d83ed4990798ae86d381870861 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 29 Jul 2025 21:59:34 -0600 Subject: [PATCH 3/6] fix: remove more references to clearAllCaches --- src/utils/PlatformServiceMixin.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/utils/PlatformServiceMixin.ts b/src/utils/PlatformServiceMixin.ts index d622d00f..2abcdcf1 100644 --- a/src/utils/PlatformServiceMixin.ts +++ b/src/utils/PlatformServiceMixin.ts @@ -178,8 +178,8 @@ export const PlatformServiceMixin = { logger.debug( `[PlatformServiceMixin] ActiveDid changed from ${oldDid} to ${newDid}`, ); - // Clear caches that might be affected by the change - (this as any).$clearAllCaches(); + // // Clear caches that might be affected by the change + // (this as any).$clearAllCaches(); } }, immediate: true, @@ -244,6 +244,8 @@ export const PlatformServiceMixin = { /** * Self-contained implementation of parseJsonField * Safely parses JSON strings with fallback to default value + * + * Consolidate this with src/libs/util.ts parseJsonField */ _parseJsonField(value: unknown, defaultValue: T): T { if (typeof value === "string") { @@ -1630,7 +1632,7 @@ declare module "@vue/runtime-core" { // Cache management methods $refreshSettings(): Promise; $refreshContacts(): Promise; - $clearAllCaches(): void; + // $clearAllCaches(): void; // High-level entity operations (eliminate verbose SQL patterns) $mapResults( From 9562d3aa32f8b9b67f5fe39b3456d96853373c5f Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 29 Jul 2025 22:12:08 -0600 Subject: [PATCH 4/6] chore: commentary and verbiage and one stray unnecessary check --- src/components/OnboardingDialog.vue | 2 +- src/components/UsageLimitsSection.vue | 2 +- src/db/tables/contacts.ts | 4 +++- src/libs/util.ts | 1 + src/views/HomeView.vue | 1 + 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/OnboardingDialog.vue b/src/components/OnboardingDialog.vue index 5c3724da..f6275f12 100644 --- a/src/components/OnboardingDialog.vue +++ b/src/components/OnboardingDialog.vue @@ -180,7 +180,7 @@ > Let's go!
- See & record gratitude. + See & record things you've received. @@ -33,7 +33,7 @@ v-if="showGiveNumbers" class="text-md bg-gradient-to-b shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md" :class="giveAmountsButtonClass" - @click="$emit('toggle-give-totals')" + @click="emitToggleGiveTotals" > {{ giveAmountsButtonText }} @@ -41,7 +41,7 @@ @@ -50,7 +50,7 @@ diff --git a/src/components/ContactListItem.vue b/src/components/ContactListItem.vue index abdfdbb0..c972fe80 100644 --- a/src/components/ContactListItem.vue +++ b/src/components/ContactListItem.vue @@ -9,14 +9,14 @@ :checked="isSelected" class="ml-2 h-6 w-6 flex-shrink-0" data-testId="contactCheckOne" - @click="$emit('toggle-selection', contact.did)" + @click="emitToggleSelection(contact.did)" />
@@ -63,7 +63,7 @@ @@ -71,7 +71,7 @@ @@ -81,7 +81,7 @@ @@ -102,7 +102,7 @@ diff --git a/src/components/MembersList.vue b/src/components/MembersList.vue index 36db158a..d10d4847 100644 --- a/src/components/MembersList.vue +++ b/src/components/MembersList.vue @@ -178,7 +178,7 @@ // Validation: Passes lint checks and TypeScript compilation // Navigation: Contacts → Chair Icon → Start/Join Meeting → Members List -import { Component, Vue, Prop } from "vue-facing-decorator"; +import { Component, Vue, Prop, Emit } from "vue-facing-decorator"; import { errorStringForLog, @@ -222,6 +222,12 @@ export default class MembersList extends Vue { @Prop({ required: true }) password!: string; @Prop({ default: false }) showOrganizerTools!: boolean; + // Emit methods using @Emit decorator + @Emit("error") + emitError(message: string) { + return message; + } + decryptedMembers: DecryptedMember[] = []; firstName = ""; isLoading = true; @@ -262,10 +268,7 @@ export default class MembersList extends Vue { "Error fetching members: " + errorStringForLog(error), true, ); - this.$emit( - "error", - serverMessageForUser(error) || "Failed to fetch members.", - ); + this.emitError(serverMessageForUser(error) || "Failed to fetch members."); } finally { this.isLoading = false; } @@ -478,8 +481,7 @@ export default class MembersList extends Vue { "Error toggling admission: " + errorStringForLog(error), true, ); - this.$emit( - "error", + this.emitError( serverMessageForUser(error) || "Failed to update member admission status.", ); diff --git a/src/libs/util.ts b/src/libs/util.ts index 3696c5d7..ea234243 100644 --- a/src/libs/util.ts +++ b/src/libs/util.ts @@ -974,28 +974,28 @@ export async function importFromMnemonic( if (isTestUser0) { // Set up Test User #0 specific settings with enhanced error handling const platformService = await getPlatformService(); - + try { // First, ensure the DID-specific settings record exists await platformService.insertDidSpecificSettings(newId.did); - + // Then update with Test User #0 specific settings await platformService.updateDidSpecificSettings(newId.did, { firstName: "User Zero", isRegistered: true, }); - + // Verify the settings were saved correctly const verificationResult = await platformService.dbQuery( "SELECT firstName, isRegistered FROM settings WHERE accountDid = ?", [newId.did], ); - + if (verificationResult?.values?.length) { const settings = verificationResult.values[0]; const firstName = settings[0]; const isRegistered = settings[1]; - + logger.info("[importFromMnemonic] Test User #0 settings verification", { did: newId.did, firstName, @@ -1003,40 +1003,50 @@ export async function importFromMnemonic( expectedFirstName: "User Zero", expectedIsRegistered: true, }); - + // If settings weren't saved correctly, try individual updates if (firstName !== "User Zero" || isRegistered !== 1) { - logger.warn("[importFromMnemonic] Test User #0 settings not saved correctly, retrying with individual updates"); - + logger.warn( + "[importFromMnemonic] Test User #0 settings not saved correctly, retrying with individual updates", + ); + await platformService.dbExec( "UPDATE settings SET firstName = ? WHERE accountDid = ?", ["User Zero", newId.did], ); - + await platformService.dbExec( "UPDATE settings SET isRegistered = ? WHERE accountDid = ?", [1, newId.did], ); - + // Verify again const retryResult = await platformService.dbQuery( "SELECT firstName, isRegistered FROM settings WHERE accountDid = ?", [newId.did], ); - + if (retryResult?.values?.length) { const retrySettings = retryResult.values[0]; - logger.info("[importFromMnemonic] Test User #0 settings after retry", { - firstName: retrySettings[0], - isRegistered: retrySettings[1], - }); + logger.info( + "[importFromMnemonic] Test User #0 settings after retry", + { + firstName: retrySettings[0], + isRegistered: retrySettings[1], + }, + ); } } } else { - logger.error("[importFromMnemonic] Failed to verify Test User #0 settings - no record found"); + logger.error( + "[importFromMnemonic] Failed to verify Test User #0 settings - no record found", + ); } } catch (error) { - logger.error("[importFromMnemonic] Error setting up Test User #0 settings:", error); + logger.error( + "[importFromMnemonic] Error setting up Test User #0 settings:", + error, + ); // Don't throw - allow the import to continue even if settings fail } } diff --git a/src/test/PlatformServiceMixinTest.vue b/src/test/PlatformServiceMixinTest.vue index f25d78a4..1ec225fa 100644 --- a/src/test/PlatformServiceMixinTest.vue +++ b/src/test/PlatformServiceMixinTest.vue @@ -3,16 +3,18 @@

PlatformServiceMixin Test

- -
+

User #0 Settings Test Result:

-
{{ JSON.stringify(userZeroTestResult, null, 2) }}
+
{{
+        JSON.stringify(userZeroTestResult, null, 2)
+      }}
{{ result }}
@@ -55,16 +57,16 @@ export default class PlatformServiceMixinTest extends Vue { try { // User #0's DID const userZeroDid = "did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"; - + this.result = "Testing User #0 settings..."; - + // Test the debug methods await this.$debugMergedSettings(userZeroDid); - + // Get the actual settings const didSettings = await this.$debugDidSettings(userZeroDid); const accountSettings = await this.$accountSettings(userZeroDid); - + this.userZeroTestResult = { didSettings, accountSettings, @@ -72,7 +74,7 @@ export default class PlatformServiceMixinTest extends Vue { firstName: accountSettings.firstName, timestamp: new Date().toISOString(), }; - + this.result = `User #0 settings test completed. isRegistered: ${accountSettings.isRegistered}`; } catch (error) { this.result = `Error testing User #0 settings: ${error}`; diff --git a/src/utils/PlatformServiceMixin.ts b/src/utils/PlatformServiceMixin.ts index 2abcdcf1..09fec9c0 100644 --- a/src/utils/PlatformServiceMixin.ts +++ b/src/utils/PlatformServiceMixin.ts @@ -87,7 +87,7 @@ interface VueComponentWithMixin { // VueComponentWithMixin, // Map> // >(); -// +// // /** // * Cache configuration constants // */ @@ -220,13 +220,20 @@ export const PlatformServiceMixin = { const obj: Record = {}; columns.forEach((column, index) => { let value = row[index]; - + // Convert SQLite integer booleans to JavaScript booleans - if (column === 'isRegistered' || column === 'finishedOnboarding' || - column === 'filterFeedByVisible' || column === 'filterFeedByNearby' || - column === 'hideRegisterPromptOnNewContact' || column === 'showContactGivesInline' || - column === 'showGeneralAdvanced' || column === 'showShortcutBvc' || - column === 'warnIfProdServer' || column === 'warnIfTestServer') { + if ( + column === "isRegistered" || + column === "finishedOnboarding" || + column === "filterFeedByVisible" || + column === "filterFeedByNearby" || + column === "hideRegisterPromptOnNewContact" || + column === "showContactGivesInline" || + column === "showGeneralAdvanced" || + column === "showShortcutBvc" || + column === "warnIfProdServer" || + column === "warnIfTestServer" + ) { if (value === 1) { value = true; } else if (value === 0) { @@ -234,7 +241,7 @@ export const PlatformServiceMixin = { } // Keep null values as null } - + obj[column] = value; }); return obj; @@ -244,7 +251,7 @@ export const PlatformServiceMixin = { /** * Self-contained implementation of parseJsonField * Safely parses JSON strings with fallback to default value - * + * * Consolidate this with src/libs/util.ts parseJsonField */ _parseJsonField(value: unknown, defaultValue: T): T { @@ -1403,7 +1410,9 @@ export const PlatformServiceMixin = { ); if (!result?.values?.length) { - logger.warn(`[PlatformServiceMixin] No settings found for DID: ${did}`); + logger.warn( + `[PlatformServiceMixin] No settings found for DID: ${did}`, + ); return null; } @@ -1413,7 +1422,9 @@ export const PlatformServiceMixin = { ); if (!mappedResults.length) { - logger.warn(`[PlatformServiceMixin] Failed to map settings for DID: ${did}`); + logger.warn( + `[PlatformServiceMixin] Failed to map settings for DID: ${did}`, + ); return null; } @@ -1428,7 +1439,10 @@ export const PlatformServiceMixin = { return settings; } catch (error) { - logger.error(`[PlatformServiceMixin] Error debugging settings for DID ${did}:`, error); + logger.error( + `[PlatformServiceMixin] Error debugging settings for DID ${did}:`, + error, + ); return null; } }, @@ -1442,14 +1456,24 @@ export const PlatformServiceMixin = { async $debugMergedSettings(did: string): Promise { try { // Get default settings - const defaultSettings = await this.$getSettings(MASTER_SETTINGS_KEY, {}); - logger.info(`[PlatformServiceMixin] Default settings:`, defaultSettings); + const defaultSettings = await this.$getSettings( + MASTER_SETTINGS_KEY, + {}, + ); + logger.info( + `[PlatformServiceMixin] Default settings:`, + defaultSettings, + ); // Get DID-specific settings const didSettings = await this.$debugDidSettings(did); // Get merged settings - const mergedSettings = await this.$getMergedSettings(MASTER_SETTINGS_KEY, did, defaultSettings || {}); + const mergedSettings = await this.$getMergedSettings( + MASTER_SETTINGS_KEY, + did, + defaultSettings || {}, + ); logger.info(`[PlatformServiceMixin] Merged settings for ${did}:`, { defaultSettings, @@ -1458,7 +1482,10 @@ export const PlatformServiceMixin = { isRegistered: mergedSettings.isRegistered, }); } catch (error) { - logger.error(`[PlatformServiceMixin] Error debugging merged settings for DID ${did}:`, error); + logger.error( + `[PlatformServiceMixin] Error debugging merged settings for DID ${did}:`, + error, + ); } }, }, diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index ef35f800..1cb9be94 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -1415,7 +1415,8 @@ export default class AccountViewView extends Vue { return; } } catch (error) { - this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS; + this.limitsMessage = + ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS; logger.error("Error retrieving limits: ", error); // this.notify.error(this.limitsMessage, TIMEOUTS.STANDARD); } finally { @@ -1475,7 +1476,7 @@ export default class AccountViewView extends Vue { async deleteImage(): Promise { try { // Extract the image ID from the full URL - const imageId = this.profileImageUrl?.split('/').pop(); + const imageId = this.profileImageUrl?.split("/").pop(); if (!imageId) { this.notify.error("Invalid image URL"); return;