From 07c5c6fd31be2566e1c768d173984b49c428ba4b Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Wed, 30 Jul 2025 05:50:39 +0000 Subject: [PATCH] Convert Vue components to use @Emit decorator instead of manual emits declarations Replace manual emits declarations with proper @Emit decorator usage across components: - ActivityListItem: Add @Emit methods for viewImage, loadClaim, confirmClaim - ContactInputForm: Convert handleQRScan to use @Emit("qr-scan") - ContactBulkActions: Add @Emit methods for toggle-all-selection, copy-selected - ContactListHeader: Add @Emit methods for all 5 emitted events - MembersList: Add @Emit("error") method for error handling - LargeIdenticonModal: Add @Emit("close") method - ContactListItem: Add @Emit methods for all 4 emitted events Update all templates to call emit methods instead of direct $emit calls. Fix TypeScript type issues with optional parameters. Resolves Vue warning about undeclared emitted events. Follows vue-facing-decorator best practices and improves code consistency. --- src/components/ActivityListItem.vue | 28 +++++++++--- src/components/ContactBulkActions.vue | 17 ++++++-- src/components/ContactInputForm.vue | 4 +- src/components/ContactListHeader.vue | 38 ++++++++++++++--- src/components/ContactListItem.vue | 33 +++++++++++--- src/components/IdentitySection.vue | 5 +-- src/components/ImageViewer.vue | 2 +- src/components/LargeIdenticonModal.vue | 10 ++++- src/components/MembersList.vue | 16 ++++--- src/libs/util.ts | 44 +++++++++++-------- src/test/PlatformServiceMixinTest.vue | 24 ++++++----- src/utils/PlatformServiceMixin.ts | 59 +++++++++++++++++++------- src/views/AccountViewView.vue | 5 ++- 13 files changed, 202 insertions(+), 83 deletions(-) diff --git a/src/components/ActivityListItem.vue b/src/components/ActivityListItem.vue index 6b91371c..b3bb9035 100644 --- a/src/components/ActivityListItem.vue +++ b/src/components/ActivityListItem.vue @@ -52,7 +52,7 @@ @@ -67,7 +67,7 @@ >

- + {{ description }}

@@ -248,7 +248,7 @@ diff --git a/src/components/ContactInputForm.vue b/src/components/ContactInputForm.vue index 8d791eda..35c693e4 100644 --- a/src/components/ContactInputForm.vue +++ b/src/components/ContactInputForm.vue @@ -64,7 +64,7 @@ diff --git a/src/components/ContactListHeader.vue b/src/components/ContactListHeader.vue index 3e2c4589..cfb65be2 100644 --- a/src/components/ContactListHeader.vue +++ b/src/components/ContactListHeader.vue @@ -8,21 +8,21 @@ :checked="allContactsSelected" class="align-middle ml-2 h-6 w-6" data-testId="contactCheckAllTop" - @click="$emit('toggle-all-selection')" + @click="emitToggleAllSelection" /> @@ -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;