diff --git a/src/components/TopMessage.vue b/src/components/TopMessage.vue index 7cd8f3b3..e96c8cb0 100644 --- a/src/components/TopMessage.vue +++ b/src/components/TopMessage.vue @@ -30,7 +30,6 @@ export default class TopMessage extends Vue { // - Cache management: this.$refreshSettings(), this.$clearAllCaches() // - Ultra-concise database methods: this.$db(), this.$exec(), this.$query() // - All methods use smart caching with TTL for massive performance gains - // - FIXED: Now properly respects database settings without forcing API server overrides $notify!: (notification: NotificationIface, timeout?: number) => void; @@ -45,10 +44,10 @@ export default class TopMessage extends Vue { try { // Load settings without overriding database values - fixes settings inconsistency - logger.info("[TopMessage] đŸ“Ĩ Loading settings without overrides..."); + logger.debug("[TopMessage] đŸ“Ĩ Loading settings without overrides..."); const settings = await this.$accountSettings(); - logger.info("[TopMessage] 📊 Settings loaded:", { + logger.debug("[TopMessage] 📊 Settings loaded:", { activeDid: settings.activeDid, apiServer: settings.apiServer, warnIfTestServer: settings.warnIfTestServer, @@ -65,7 +64,7 @@ export default class TopMessage extends Vue { ) { const didPrefix = settings.activeDid?.slice(11, 15); this.message = "You're not using prod, user " + didPrefix; - logger.info("[TopMessage] âš ī¸ Test server warning displayed:", { + logger.debug("[TopMessage] âš ī¸ Test server warning displayed:", { apiServer: settings.apiServer, didPrefix: didPrefix, }); @@ -76,7 +75,7 @@ export default class TopMessage extends Vue { ) { const didPrefix = settings.activeDid?.slice(11, 15); this.message = "You are using prod, user " + didPrefix; - logger.info("[TopMessage] âš ī¸ Production server warning displayed:", { + logger.debug("[TopMessage] âš ī¸ Production server warning displayed:", { apiServer: settings.apiServer, didPrefix: didPrefix, }); diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index 5c7073b3..8ab98ac6 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -515,7 +515,7 @@ export async function getPlanFromCache( // Enhanced diagnostic logging for plan loading const requestId = `plan_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; - logger.info("[Plan Loading] 🔍 Loading plan from server:", { + logger.debug("[Plan Loading] 🔍 Loading plan from server:", { requestId, handleId, apiServer, @@ -527,7 +527,7 @@ export async function getPlanFromCache( try { const resp = await axios.get(url, { headers }); - logger.info("[Plan Loading] ✅ Plan loaded successfully:", { + logger.debug("[Plan Loading] ✅ Plan loaded successfully:", { requestId, handleId, status: resp.status, @@ -1604,7 +1604,7 @@ export async function fetchEndorserRateLimits( const headers = await getHeaders(issuerDid); // Enhanced diagnostic logging for user registration tracking - logger.info("[User Registration] Checking user status on server:", { + logger.debug("[User Registration] Checking user status on server:", { did: issuerDid, server: apiServer, endpoint: url, @@ -1615,7 +1615,7 @@ export async function fetchEndorserRateLimits( const response = await axios.get(url, { headers } as AxiosRequestConfig); // Log successful registration check - logger.info("[User Registration] User registration check successful:", { + logger.debug("[User Registration] User registration check successful:", { did: issuerDid, server: apiServer, status: response.status, @@ -1674,7 +1674,7 @@ export async function fetchImageRateLimits( const headers = await getHeaders(issuerDid); // Enhanced diagnostic logging for image server calls - logger.info("[Image Server] Checking image rate limits:", { + logger.debug("[Image Server] Checking image rate limits:", { did: issuerDid, server: server, endpoint: url, @@ -1685,7 +1685,7 @@ export async function fetchImageRateLimits( const response = await axios.get(url, { headers } as AxiosRequestConfig); // Log successful image server call - logger.info("[Image Server] Image rate limits check successful:", { + logger.debug("[Image Server] Image rate limits check successful:", { did: issuerDid, server: server, status: response.status, diff --git a/src/libs/util.ts b/src/libs/util.ts index e21d1932..1f4bf068 100644 --- a/src/libs/util.ts +++ b/src/libs/util.ts @@ -973,13 +973,16 @@ export async function importFromMnemonic( const firstName = settings[0]; const isRegistered = settings[1]; - logger.info("[importFromMnemonic] Test User #0 settings verification", { - did: newId.did, - firstName, - isRegistered, - expectedFirstName: "User Zero", - expectedIsRegistered: true, - }); + logger.debug( + "[importFromMnemonic] Test User #0 settings verification", + { + did: newId.did, + firstName, + isRegistered, + expectedFirstName: "User Zero", + expectedIsRegistered: true, + }, + ); // If settings weren't saved correctly, try individual updates if (firstName !== "User Zero" || isRegistered !== 1) { @@ -1005,7 +1008,7 @@ export async function importFromMnemonic( if (retryResult?.values?.length) { const retrySettings = retryResult.values[0]; - logger.info( + logger.debug( "[importFromMnemonic] Test User #0 settings after retry", { firstName: retrySettings[0], diff --git a/src/router/index.ts b/src/router/index.ts index e63d54b0..cf450c37 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -327,7 +327,7 @@ router.onError(errorHandler); // Assign the error handler to the router instance * @param next - Navigation function */ router.beforeEach(async (to, _from, next) => { - logger.info(`[Router] 🧭 Navigation guard triggered:`, { + logger.debug(`[Router] 🧭 Navigation guard triggered:`, { from: _from?.path || "none", to: to.path, name: to.name, @@ -368,11 +368,11 @@ router.beforeEach(async (to, _from, next) => { return next(); } - logger.info(`[Router] 🔍 Checking user identity for route: ${to.path}`); + logger.debug(`[Router] 🔍 Checking user identity for route: ${to.path}`); // Check if user has any identities const allMyDids = await retrieveAccountDids(); - logger.info(`[Router] 📋 Found ${allMyDids.length} user identities`); + logger.debug(`[Router] 📋 Found ${allMyDids.length} user identities`); if (allMyDids.length === 0) { logger.info("[Router] âš ī¸ No identities found, creating default identity"); @@ -382,7 +382,7 @@ router.beforeEach(async (to, _from, next) => { logger.info("[Router] ✅ Default identity created successfully"); } else { - logger.info( + logger.debug( `[Router] ✅ User has ${allMyDids.length} identities, proceeding`, ); } @@ -408,7 +408,7 @@ router.beforeEach(async (to, _from, next) => { // Add navigation success logging router.afterEach((to, from) => { - logger.info(`[Router] ✅ Navigation completed:`, { + logger.debug(`[Router] ✅ Navigation completed:`, { from: from?.path || "none", to: to.path, name: to.name, diff --git a/src/services/ProfileService.ts b/src/services/ProfileService.ts deleted file mode 100644 index 6d861c98..00000000 --- a/src/services/ProfileService.ts +++ /dev/null @@ -1,325 +0,0 @@ -/** - * ProfileService - Handles user profile operations and API calls - * Extracted from AccountViewView.vue to improve separation of concerns - * - * @author Matthew Raymer - * @since 2025-08-25 - */ - -import { AxiosInstance } from "axios"; -import { logger } from "../utils/logger"; -import { getServiceInitManager } from "./ServiceInitializationManager"; -import { - handleApiError, - createErrorContext, - createUserMessage, -} from "../utils/errorHandler"; -import { getHeaders } from "../libs/endorserServer"; - -/** - * Profile data structure - */ -export interface ProfileData { - description: string; - latitude: number; - longitude: number; - includeLocation: boolean; -} - -/** - * Profile service for managing user profile information - * - * @author Matthew Raymer - * @since 2025-08-25 - */ -export class ProfileService { - private axios: AxiosInstance; - private partnerApiServer: string; - - constructor(axios: AxiosInstance, partnerApiServer: string) { - this.axios = axios; - this.partnerApiServer = partnerApiServer; - - // Register with service initialization manager - const initManager = getServiceInitManager(); - initManager.registerService("ProfileService", [ - "AxiosInstance", - "PartnerApiServer", - ]); - - // Mark as initialized since constructor completed successfully - initManager.markInitialized("ProfileService"); - - logger.debug("[ProfileService] 🔧 Service initialized:", { - partnerApiServer, - hasAxios: !!axios, - timestamp: new Date().toISOString(), - }); - } - - /** - * Load user profile from the partner API - * - * @param did - User's DID - * @returns Profile data or null if not found - * @throws Error if API call fails - */ - async loadProfile(did: string): Promise { - const operation = "Load Profile"; - const context = createErrorContext("ProfileService", operation, { - did, - partnerApiServer: this.partnerApiServer, - endpoint: `${this.partnerApiServer}/api/partner/userProfileForIssuer/${did}`, - }); - - try { - // Enhanced request tracking - const requestId = `profile_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; - - logger.info("[ProfileService] 🔍 Loading profile:", { - requestId, - ...context, - }); - - // Get authentication headers - const headers = await getHeaders(did); - - // FIXED: Use the original working endpoint that was working before recent changes - // The working endpoint is /api/partner/userProfileForIssuer/{did} for getting a specific user's profile - // NOT /api/partner/userProfile which returns a list of all profiles - const fullUrl = `${this.partnerApiServer}/api/partner/userProfileForIssuer/${did}`; - - logger.info("[ProfileService] 🔗 Making API request:", { - requestId, - did, - fullUrl, - partnerApiServer: this.partnerApiServer, - hasAuthHeader: !!headers.Authorization, - authHeaderLength: headers.Authorization?.length || 0, - }); - - const response = await this.axios.get(fullUrl, { headers }); - - logger.info("[ProfileService] ✅ Profile loaded successfully:", { - requestId, - ...context, - status: response.status, - hasData: !!response.data, - dataKeys: response.data ? Object.keys(response.data) : [], - responseData: response.data, - responseDataType: typeof response.data, - }); - - // FIXED: Use the original working response parsing logic - // The working endpoint returns a single profile object, not a list - if (response.data && response.data.data) { - const profileData = response.data.data; - logger.info("[ProfileService] 🔍 Parsing profile data:", { - requestId, - profileData, - profileDataKeys: Object.keys(profileData), - locLat: profileData.locLat, - locLon: profileData.locLon, - description: profileData.description, - issuerDid: profileData.issuerDid, - hasLocationFields: !!(profileData.locLat || profileData.locLon), - }); - - const result = { - description: profileData.description || "", - latitude: profileData.locLat || 0, - longitude: profileData.locLon || 0, - includeLocation: !!(profileData.locLat && profileData.locLon), - }; - - logger.info("[ProfileService] 📊 Parsed profile result:", { - requestId, - result, - hasLocation: result.includeLocation, - locationValues: { - original: { locLat: profileData.locLat, locLon: profileData.locLon }, - parsed: { latitude: result.latitude, longitude: result.longitude }, - }, - }); - - return result; - } else { - logger.warn("[ProfileService] âš ī¸ No profile data found in response:", { - requestId, - responseData: response.data, - hasData: !!response.data, - hasDataData: !!(response.data && response.data.data), - }); - } - - return null; - } catch (error: unknown) { - // Use standardized error handling - const errorInfo = handleApiError(error, context, operation); - - // Handle specific HTTP status codes - if (errorInfo.errorType === "AxiosError" && errorInfo.status === 404) { - logger.info( - "[ProfileService] â„šī¸ Profile not found (404) - this is normal for new users", - ); - return null; - } - - // Create user-friendly error message - const userMessage = createUserMessage( - errorInfo, - "Failed to load profile", - ); - throw new Error(userMessage); - } - } - - /** - * Save user profile to the partner API - * - * @param did - User's DID - * @param profileData - Profile data to save - * @returns Success status - * @throws Error if API call fails - */ - async saveProfile(did: string, profileData: ProfileData): Promise { - const operation = "Save Profile"; - const context = createErrorContext("ProfileService", operation, { - did, - partnerApiServer: this.partnerApiServer, - endpoint: `${this.partnerApiServer}/api/partner/userProfile`, - profileData, - }); - - try { - // Enhanced request tracking - const requestId = `profile_save_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; - - logger.info("[ProfileService] 💾 Saving profile:", { - requestId, - ...context, - }); - - // Get authentication headers - const headers = await getHeaders(did); - - // Prepare payload in the format expected by the partner API - const payload = { - description: profileData.description, - issuerDid: did, - ...(profileData.includeLocation && - profileData.latitude && - profileData.longitude - ? { - locLat: profileData.latitude, - locLon: profileData.longitude, - } - : {}), - }; - - logger.info("[ProfileService] 📤 Sending payload to server:", { - requestId, - payload, - hasLocation: profileData.includeLocation, - latitude: profileData.latitude, - longitude: profileData.longitude, - payloadKeys: Object.keys(payload), - }); - - const response = await this.axios.post( - `${this.partnerApiServer}/api/partner/userProfile`, - payload, - { headers }, - ); - - logger.info("[ProfileService] ✅ Profile saved successfully:", { - requestId, - ...context, - status: response.status, - hasData: !!response.data, - responseData: response.data, - responseDataKeys: response.data ? Object.keys(response.data) : [], - }); - - return true; - } catch (error: unknown) { - // Use standardized error handling - const errorInfo = handleApiError(error, context, operation); - - // Create user-friendly error message - const userMessage = createUserMessage( - errorInfo, - "Failed to save profile", - ); - throw new Error(userMessage); - } - } - - /** - * Toggle profile location visibility - * - * @param profileData - Current profile data - * @returns Updated profile data - */ - toggleProfileLocation(profileData: ProfileData): ProfileData { - const includeLocation = !profileData.includeLocation; - return { - ...profileData, - latitude: includeLocation ? profileData.latitude : 0, - longitude: includeLocation ? profileData.longitude : 0, - includeLocation, - }; - } - - /** - * Clear profile location - * - * @param profileData - Current profile data - * @returns Updated profile data - */ - clearProfileLocation(profileData: ProfileData): ProfileData { - return { - ...profileData, - latitude: 0, - longitude: 0, - includeLocation: false, - }; - } - - /** - * Reset profile to default state - * - * @returns Default profile data - */ - getDefaultProfile(): ProfileData { - return { - description: "", - latitude: 0, - longitude: 0, - includeLocation: false, - }; - } -} - -/** - * Factory function to create a ProfileService instance - * - * @param axios - Axios instance for HTTP requests - * @param partnerApiServer - Partner API server URL - * @returns ProfileService instance - */ -export function createProfileService( - axios: AxiosInstance, - partnerApiServer: string, -): ProfileService { - // Register dependencies with service initialization manager - const initManager = getServiceInitManager(); - initManager.registerService("AxiosInstance", []); - initManager.registerService("PartnerApiServer", []); - - // Mark dependencies as initialized - initManager.markInitialized("AxiosInstance"); - initManager.markInitialized("PartnerApiServer"); - - return new ProfileService(axios, partnerApiServer); -} diff --git a/src/services/ServiceInitializationManager.ts b/src/services/ServiceInitializationManager.ts deleted file mode 100644 index 765c5e7a..00000000 --- a/src/services/ServiceInitializationManager.ts +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Service Initialization Manager - * - * Manages the proper initialization order of services to prevent race conditions - * and ensure dependencies are available when services are created. - * - * @author Matthew Raymer - * @since 2025-08-25 - */ - -import { logger } from "../utils/logger"; - -/** - * Service initialization status tracking - */ -interface ServiceStatus { - name: string; - initialized: boolean; - dependencies: string[]; - error?: string; -} - -/** - * Service initialization manager to prevent race conditions - */ -export class ServiceInitializationManager { - private static instance: ServiceInitializationManager; - private serviceStatuses = new Map(); - private initializationPromise: Promise | null = null; - - private constructor() {} - - /** - * Get singleton instance - */ - static getInstance(): ServiceInitializationManager { - if (!ServiceInitializationManager.instance) { - ServiceInitializationManager.instance = - new ServiceInitializationManager(); - } - return ServiceInitializationManager.instance; - } - - /** - * Register a service that needs initialization - */ - registerService(name: string, dependencies: string[] = []): void { - this.serviceStatuses.set(name, { - name, - initialized: false, - dependencies, - }); - - logger.debug("[ServiceInit] 🔧 Service registered:", { - name, - dependencies, - totalServices: this.serviceStatuses.size, - }); - } - - /** - * Mark a service as initialized - */ - markInitialized(name: string): void { - const status = this.serviceStatuses.get(name); - if (status) { - status.initialized = true; - logger.debug("[ServiceInit] ✅ Service initialized:", { - name, - totalInitialized: this.getInitializedCount(), - totalServices: this.serviceStatuses.size, - }); - } - } - - /** - * Mark a service as failed - */ - markFailed(name: string, error: string): void { - const status = this.serviceStatuses.get(name); - if (status) { - status.error = error; - logger.error("[ServiceInit] ❌ Service failed:", { - name, - error, - totalFailed: this.getFailedCount(), - }); - } - } - - /** - * Get count of initialized services - */ - private getInitializedCount(): number { - return Array.from(this.serviceStatuses.values()).filter( - (s) => s.initialized, - ).length; - } - - /** - * Get count of failed services - */ - private getFailedCount(): number { - return Array.from(this.serviceStatuses.values()).filter((s) => s.error) - .length; - } - - /** - * Wait for all services to be initialized - */ - async waitForInitialization(): Promise { - if (this.initializationPromise) { - return this.initializationPromise; - } - - this.initializationPromise = new Promise((resolve, reject) => { - const checkInterval = setInterval(() => { - const totalServices = this.serviceStatuses.size; - const initializedCount = this.getInitializedCount(); - const failedCount = this.getFailedCount(); - - logger.debug("[ServiceInit] 🔍 Initialization progress:", { - totalServices, - initializedCount, - failedCount, - remaining: totalServices - initializedCount - failedCount, - }); - - if (failedCount > 0) { - clearInterval(checkInterval); - const failedServices = Array.from(this.serviceStatuses.values()) - .filter((s) => s.error) - .map((s) => `${s.name}: ${s.error}`); - - const error = new Error( - `Service initialization failed: ${failedServices.join(", ")}`, - ); - logger.error("[ServiceInit] ❌ Initialization failed:", error); - reject(error); - } else if (initializedCount === totalServices) { - clearInterval(checkInterval); - logger.info( - "[ServiceInit] 🎉 All services initialized successfully:", - { - totalServices, - initializedCount, - }, - ); - resolve(); - } - }, 100); - - // Timeout after 30 seconds - setTimeout(() => { - clearInterval(checkInterval); - const error = new Error( - "Service initialization timeout after 30 seconds", - ); - logger.error("[ServiceInit] ⏰ Initialization timeout:", error); - reject(error); - }, 30000); - }); - - return this.initializationPromise; - } - - /** - * Get initialization status summary - */ - getStatusSummary(): { - total: number; - initialized: number; - failed: number; - pending: number; - services: ServiceStatus[]; - } { - const services = Array.from(this.serviceStatuses.values()); - const total = services.length; - const initialized = services.filter((s) => s.initialized).length; - const failed = services.filter((s) => s.error).length; - const pending = total - initialized - failed; - - return { - total, - initialized, - failed, - pending, - services, - }; - } - - /** - * Reset the manager (useful for testing) - */ - reset(): void { - this.serviceStatuses.clear(); - this.initializationPromise = null; - logger.debug("[ServiceInit] 🔄 Manager reset"); - } -} - -/** - * Convenience function to get the service initialization manager - */ -export const getServiceInitManager = (): ServiceInitializationManager => { - return ServiceInitializationManager.getInstance(); -}; diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 669cf8e2..3ae1ccee 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -754,6 +754,7 @@ import "leaflet/dist/leaflet.css"; import { Buffer } from "buffer/"; import "dexie-export-import"; + // @ts-expect-error - they aren't exporting it but it's there import { ImportProgress } from "dexie-export-import"; import { LeafletMouseEvent } from "leaflet"; @@ -815,11 +816,13 @@ import { isApiError, ImportContent, } from "@/interfaces/accountView"; -import { - ProfileService, - createProfileService, - ProfileData, -} from "@/services/ProfileService"; +// Profile data interface (inlined from ProfileService) +interface ProfileData { + description: string; + latitude: number; + longitude: number; + includeLocation: boolean; +} const inputImportFileNameRef = ref(); @@ -918,7 +921,6 @@ export default class AccountViewView extends Vue { imageLimits: ImageRateLimits | null = null; limitsMessage: string = ""; - private profileService!: ProfileService; private notify!: ReturnType; created() { @@ -957,24 +959,17 @@ export default class AccountViewView extends Vue { await this.initializeState(); await this.processIdentity(); - // FIXED: Create ProfileService AFTER settings are loaded to get correct partnerApiServer - this.profileService = createProfileService( - this.axios, - this.partnerApiServer, - ); - - logger.info( - "[AccountViewView] ✅ ProfileService created with correct partnerApiServer:", + // Profile service logic now inlined - no need for external service + logger.debug( + "[AccountViewView] Profile logic ready with partnerApiServer:", { partnerApiServer: this.partnerApiServer, - component: "AccountViewView", - timestamp: new Date().toISOString(), }, ); if (this.isRegistered) { try { - const profile = await this.profileService.loadProfile(this.activeDid); + const profile = await this.loadProfile(this.activeDid); if (profile) { this.userProfileDesc = profile.description; this.userProfileLatitude = profile.latitude; @@ -1694,7 +1689,7 @@ export default class AccountViewView extends Vue { logger.debug("Saving profile data:", profileData); - const success = await this.profileService.saveProfile( + const success = await this.saveProfileToServer( this.activeDid, profileData, ); @@ -1713,7 +1708,7 @@ export default class AccountViewView extends Vue { toggleUserProfileLocation(): void { try { - const updated = this.profileService.toggleProfileLocation({ + const updated = this.toggleProfileLocation({ description: this.userProfileDesc, latitude: this.userProfileLatitude, longitude: this.userProfileLongitude, @@ -1758,7 +1753,7 @@ export default class AccountViewView extends Vue { async deleteProfile(): Promise { try { - const success = await this.profileService.deleteProfile(this.activeDid); + const success = await this.deleteProfileFromServer(this.activeDid); if (success) { this.notify.success(ACCOUNT_VIEW_CONSTANTS.SUCCESS.PROFILE_DELETED); this.userProfileDesc = ""; @@ -1871,5 +1866,215 @@ export default class AccountViewView extends Vue { onRecheckLimits() { this.checkLimits(); } + + // Inlined profile methods (previously in ProfileService) + + /** + * Load user profile from the partner API + */ + private async loadProfile(did: string): Promise { + try { + const requestId = `profile_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + + logger.debug("[AccountViewView] Loading profile:", { + requestId, + did, + partnerApiServer: this.partnerApiServer, + }); + + // Get authentication headers + const headers = await getHeaders(did); + + const fullUrl = `${this.partnerApiServer}/api/partner/userProfileForIssuer/${did}`; + + logger.debug("[AccountViewView] Making API request:", { + requestId, + did, + fullUrl, + hasAuthHeader: !!headers.Authorization, + }); + + const response = await this.axios.get(fullUrl, { headers }); + + logger.debug("[AccountViewView] Profile loaded successfully:", { + requestId, + status: response.status, + hasData: !!response.data, + }); + + if (response.data && response.data.data) { + const profileData = response.data.data; + logger.debug("[AccountViewView] Parsing profile data:", { + requestId, + locLat: profileData.locLat, + locLon: profileData.locLon, + description: profileData.description, + }); + + const result = { + description: profileData.description || "", + latitude: profileData.locLat || 0, + longitude: profileData.locLon || 0, + includeLocation: !!(profileData.locLat && profileData.locLon), + }; + + logger.debug("[AccountViewView] Parsed profile result:", { + requestId, + result, + hasLocation: result.includeLocation, + }); + + return result; + } else { + logger.debug("[AccountViewView] No profile data found in response:", { + requestId, + hasData: !!response.data, + hasDataData: !!(response.data && response.data.data), + }); + } + + return null; + } catch (error: unknown) { + // Handle specific HTTP status codes + if (error && typeof error === "object" && "response" in error) { + const axiosError = error as { response?: { status?: number } }; + if (axiosError.response?.status === 404) { + logger.debug( + "[AccountViewView] Profile not found (404) - this is normal for new users", + ); + return null; + } + } + + logger.error("[AccountViewView] Failed to load profile:", error); + throw new Error("Failed to load profile"); + } + } + + /** + * Save user profile to the partner API + */ + private async saveProfileToServer( + did: string, + profileData: ProfileData, + ): Promise { + try { + const requestId = `profile_save_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + + logger.debug("[AccountViewView] Saving profile:", { + requestId, + did, + profileData, + }); + + // Get authentication headers + const headers = await getHeaders(did); + + // Prepare payload in the format expected by the partner API + const payload = { + description: profileData.description, + issuerDid: did, + ...(profileData.includeLocation && + profileData.latitude && + profileData.longitude + ? { + locLat: profileData.latitude, + locLon: profileData.longitude, + } + : {}), + }; + + logger.debug("[AccountViewView] Sending payload to server:", { + requestId, + payload, + hasLocation: profileData.includeLocation, + }); + + const response = await this.axios.post( + `${this.partnerApiServer}/api/partner/userProfile`, + payload, + { headers }, + ); + + logger.debug("[AccountViewView] Profile saved successfully:", { + requestId, + status: response.status, + }); + + return true; + } catch (error: unknown) { + logger.error("[AccountViewView] Failed to save profile:", error); + throw new Error("Failed to save profile"); + } + } + + /** + * Toggle profile location visibility + */ + private toggleProfileLocation(profileData: ProfileData): ProfileData { + const includeLocation = !profileData.includeLocation; + return { + ...profileData, + latitude: includeLocation ? profileData.latitude : 0, + longitude: includeLocation ? profileData.longitude : 0, + includeLocation, + }; + } + + /** + * Clear profile location + */ + private clearProfileLocation(profileData: ProfileData): ProfileData { + return { + ...profileData, + latitude: 0, + longitude: 0, + includeLocation: false, + }; + } + + /** + * Get default profile data + */ + private getDefaultProfile(): ProfileData { + return { + description: "", + latitude: 0, + longitude: 0, + includeLocation: false, + }; + } + + /** + * Delete user profile from the partner API + */ + private async deleteProfileFromServer(did: string): Promise { + try { + const requestId = `profile_delete_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + + logger.debug("[AccountViewView] Deleting profile:", { + requestId, + did, + }); + + // Get authentication headers + const headers = await getHeaders(did); + + const response = await this.axios.delete( + `${this.partnerApiServer}/api/partner/userProfile/${did}`, + { headers }, + ); + + logger.debug("[AccountViewView] Profile deleted successfully:", { + requestId, + status: response.status, + }); + + return true; + } catch (error: unknown) { + logger.error("[AccountViewView] Failed to delete profile:", error); + return false; + } + } } diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 3a910119..d3cc9444 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -603,15 +603,12 @@ export default class HomeView extends Vue { /** * Ensures correct API server configuration * - * FIXED: Now respects user preferences instead of forcing production server - * * @internal * Called after loading settings to ensure correct API endpoint */ private async ensureCorrectApiServer() { const { DEFAULT_ENDORSER_API_SERVER } = await import("../constants/app"); - // FIXED: Remove forced override - respect user preferences // Only set default if no user preference exists if (!this.apiServer) { // Set default API server for any platform if not already set diff --git a/src/views/IdentitySwitcherView.vue b/src/views/IdentitySwitcherView.vue index 3dcc6972..4de52280 100644 --- a/src/views/IdentitySwitcherView.vue +++ b/src/views/IdentitySwitcherView.vue @@ -229,7 +229,7 @@ export default class IdentitySwitcherView extends Vue { if (did) { try { const newSettings = await this.$accountSettings(did); - logger.info( + logger.debug( "[IdentitySwitcher Settings Trace] ✅ New account settings loaded", { did, @@ -252,7 +252,7 @@ export default class IdentitySwitcherView extends Vue { } } - logger.info( + logger.debug( "[IdentitySwitcher Settings Trace] 🔄 Navigating to home to trigger watcher", { newDid: did, diff --git a/src/views/StartView.vue b/src/views/StartView.vue index 93c196fd..de21d2e9 100644 --- a/src/views/StartView.vue +++ b/src/views/StartView.vue @@ -203,7 +203,7 @@ export default class StartView extends Vue { // Load account count for display logic this.numAccounts = await retrieveAccountCount(); - logger.info("[StartView] Component mounted", { + logger.debug("[StartView] Component mounted", { hasGivenName: !!this.givenName, accountCount: this.numAccounts, passkeysEnabled: this.PASSKEYS_ENABLED, @@ -221,7 +221,7 @@ export default class StartView extends Vue { * Routes user to new identifier creation flow with seed-based approach */ public onClickNewSeed() { - logger.info("[StartView] User selected new seed generation"); + logger.debug("[StartView] User selected new seed generation"); this.$router.push({ name: "new-identifier" }); } @@ -235,14 +235,14 @@ export default class StartView extends Vue { const keyName = AppString.APP_NAME + (this.givenName ? " - " + this.givenName : ""); - logger.info("[StartView] Initiating passkey registration", { + logger.debug("[StartView] Initiating passkey registration", { keyName, hasGivenName: !!this.givenName, }); await registerSaveAndActivatePasskey(keyName); - logger.info("[StartView] Passkey registration successful"); + logger.debug("[StartView] Passkey registration successful"); this.$router.push({ name: "account" }); } catch (error) { logger.error("[StartView] Passkey registration failed", error); @@ -255,7 +255,7 @@ export default class StartView extends Vue { * Routes user to account import flow for existing seed phrase */ public onClickNo() { - logger.info("[StartView] User selected existing seed import"); + logger.debug("[StartView] User selected existing seed import"); this.$router.push({ name: "import-account" }); } @@ -264,7 +264,7 @@ export default class StartView extends Vue { * Routes user to address derivation flow for existing seed */ public onClickDerive() { - logger.info("[StartView] User selected address derivation"); + logger.debug("[StartView] User selected address derivation"); this.$router.push({ name: "import-derive" }); } }