diff --git a/src/services/ProfileService.ts b/src/services/ProfileService.ts index bdb27f46..c1779c71 100644 --- a/src/services/ProfileService.ts +++ b/src/services/ProfileService.ts @@ -127,10 +127,10 @@ export class ProfileService { logger.debug("Attempting to delete profile for DID:", activeDid); logger.debug("Using partner API server:", this.partnerApiServer); logger.debug("Request headers:", headers); - + const url = `${this.partnerApiServer}/api/partner/userProfile`; logger.debug("DELETE request URL:", url); - + const response = await this.axios.delete(url, { headers }); if (response.status === 200 || response.status === 204) { @@ -140,20 +140,22 @@ export class ProfileService { logger.error("Unexpected response status when deleting profile:", { status: response.status, statusText: response.statusText, - data: response.data + data: response.data, }); - throw new Error(`Profile not deleted - HTTP ${response.status}: ${response.statusText}`); + throw new Error( + `Profile not deleted - HTTP ${response.status}: ${response.statusText}`, + ); } } catch (error) { if (this.isApiError(error) && error.response) { - const response = error.response as any; // Type assertion for error response + const response = error.response; logger.error("API error deleting profile:", { status: response.status, statusText: response.statusText, data: response.data, - url: (error as any).config?.url + url: this.getErrorUrl(error), }); - + // Handle specific HTTP status codes if (response.status === 204) { logger.debug("Profile deleted successfully (204 No Content)"); @@ -163,7 +165,11 @@ export class ProfileService { return true; // Consider this a success if profile doesn't exist } else if (response.status === 400) { logger.error("Bad request when deleting profile:", response.data); - throw new Error(`Profile deletion failed: ${response.data?.message || 'Bad request'}`); + const errorMessage = + typeof response.data === "string" + ? response.data + : response.data?.message || "Bad request"; + throw new Error(`Profile deletion failed: ${errorMessage}`); } else if (response.status === 401) { logger.error("Unauthorized to delete profile"); throw new Error("You are not authorized to delete this profile"); @@ -172,7 +178,7 @@ export class ProfileService { throw new Error("You are not allowed to delete this profile"); } } - + logger.error("Error deleting profile:", errorStringForLog(error)); handleApiError(error as AxiosError, "/api/partner/userProfile"); return false; @@ -244,11 +250,32 @@ export class ProfileService { /** * Type guard for API errors */ - private isApiError( - error: unknown, - ): error is { response?: { status?: number } } { + private isApiError(error: unknown): error is { + response?: { + status?: number; + statusText?: string; + data?: { message?: string } | string; + }; + } { return typeof error === "object" && error !== null && "response" in error; } + + /** + * Extract URL from AxiosError without type casting + */ + private getErrorUrl(error: unknown): string | undefined { + if (this.isAxiosError(error)) { + return error.config?.url; + } + return undefined; + } + + /** + * Type guard for AxiosError + */ + private isAxiosError(error: unknown): error is AxiosError { + return error instanceof AxiosError; + } } /** diff --git a/src/services/deepLinks.ts b/src/services/deepLinks.ts index 8d94185d..ee6095bb 100644 --- a/src/services/deepLinks.ts +++ b/src/services/deepLinks.ts @@ -199,8 +199,10 @@ export class DeepLinkHandler { } // Continue with parameter validation as before... - const pathSchema = deepLinkPathSchemas[path as keyof typeof deepLinkPathSchemas]; - const querySchema = deepLinkQuerySchemas[path as keyof typeof deepLinkQuerySchemas]; + const pathSchema = + deepLinkPathSchemas[path as keyof typeof deepLinkPathSchemas]; + const querySchema = + deepLinkQuerySchemas[path as keyof typeof deepLinkQuerySchemas]; let validatedPathParams: Record = {}; let validatedQueryParams: Record = {}; @@ -235,7 +237,7 @@ export class DeepLinkHandler { await this.router.replace({ name: routeName, params: validatedPathParams, - query: validatedQueryParams + query: validatedQueryParams, }); } catch (error) { logger.error( diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 1c38a8bb..f309fc6e 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -174,16 +174,18 @@ :aria-busy="loadingProfile || savingProfile" > -
- - - (Debug: {{ isMapReady ? 'Map Ready' : 'Map Loading' }}) -
+
+ + + (Debug: {{ isMapReady ? "Map Ready" : "Map Loading" }}) +

The location you choose will be shared with the world until you remove @@ -918,15 +920,18 @@ export default class AccountViewView extends Vue { created() { this.notify = createNotifyHelpers(this.$notify); - + // Fix Leaflet icon issues in modern bundlers // This prevents the "Cannot read properties of undefined (reading 'Default')" error if (L.Icon.Default) { - delete (L.Icon.Default.prototype as any)._getIconUrl; + delete (L.Icon.Default.prototype as { _getIconUrl?: unknown }) + ._getIconUrl; L.Icon.Default.mergeOptions({ - iconRetinaUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png', - iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png', - shadowUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png', + iconRetinaUrl: + "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png", + iconUrl: "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png", + shadowUrl: + "https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png", }); } } @@ -955,7 +960,7 @@ export default class AccountViewView extends Vue { this.userProfileLatitude = profile.latitude; this.userProfileLongitude = profile.longitude; this.includeUserProfileLocation = profile.includeLocation; - + // Initialize map ready state if location is included if (profile.includeLocation) { this.isMapReady = false; // Will be set to true when map is ready @@ -1543,12 +1548,18 @@ export default class AccountViewView extends Vue { try { logger.debug("Map ready event fired, map object:", map); // doing this here instead of on the l-map element avoids a recentering after a drag then zoom at startup - const zoom = this.userProfileLatitude && this.userProfileLongitude ? 12 : 2; + const zoom = + this.userProfileLatitude && this.userProfileLongitude ? 12 : 2; const lat = this.userProfileLatitude || 0; const lng = this.userProfileLongitude || 0; map.setView([lat, lng], zoom); this.isMapReady = true; - logger.debug("Map ready state set to true, coordinates:", [lat, lng], "zoom:", zoom); + logger.debug( + "Map ready state set to true, coordinates:", + [lat, lng], + "zoom:", + zoom, + ); } catch (error) { logger.error("Error in onMapReady:", error); this.isMapReady = true; // Set to true even on error to prevent infinite loading @@ -1560,7 +1571,7 @@ export default class AccountViewView extends Vue { // Check if map ref is available const mapRef = this.$refs.profileMap; logger.debug("Map ref:", mapRef); - + // Try to set map ready after component is mounted setTimeout(() => { this.isMapReady = true; @@ -1597,9 +1608,9 @@ export default class AccountViewView extends Vue { longitude: this.userProfileLongitude, includeLocation: this.includeUserProfileLocation, }; - + logger.debug("Saving profile data:", profileData); - + const success = await this.profileService.saveProfile( this.activeDid, profileData, @@ -1628,7 +1639,7 @@ export default class AccountViewView extends Vue { this.userProfileLatitude = updated.latitude; this.userProfileLongitude = updated.longitude; this.includeUserProfileLocation = updated.includeLocation; - + // Reset map ready state when toggling location if (!updated.includeLocation) { this.isMapReady = false; @@ -1679,7 +1690,7 @@ export default class AccountViewView extends Vue { } } catch (error) { logger.error("Error in deleteProfile component method:", error); - + // Show more specific error message if available if (error instanceof Error) { this.notify.error(error.message); @@ -1710,7 +1721,10 @@ export default class AccountViewView extends Vue { onLocationCheckboxChange(): void { try { - logger.debug("Location checkbox changed, new value:", this.includeUserProfileLocation); + logger.debug( + "Location checkbox changed, new value:", + this.includeUserProfileLocation, + ); if (!this.includeUserProfileLocation) { // Location checkbox was unchecked, clean up map state this.isMapReady = false; @@ -1721,7 +1735,7 @@ export default class AccountViewView extends Vue { // Location checkbox was checked, start map initialization timeout this.isMapReady = false; logger.debug("Location checked, starting map initialization timeout"); - + // Try to set map ready after a short delay to allow Vue to render setTimeout(() => { if (!this.isMapReady) { @@ -1729,7 +1743,7 @@ export default class AccountViewView extends Vue { this.isMapReady = true; } }, 1000); // 1 second delay - + this.handleMapInitFailure(); } } catch (error) {