refactor(services): inline ProfileService logic into AccountViewView

Removes over-engineered ProfileService and ServiceInitializationManager
classes that were only used in one place. Inlines all profile logic
directly into AccountViewView.vue to reduce complexity and improve
maintainability.

- Deletes ProfileService.ts (325 lines)
- Deletes ServiceInitializationManager.ts (207 lines)
- Inlines ProfileData interface and methods into AccountViewView
- Maintains all existing functionality while reducing code footprint

perf(logging): convert excessive info logs to debug level

Reduces console noise by converting high-frequency, low-value logging
from info to debug level across navigation, API calls, and component
lifecycle operations. Improves performance and reduces log verbosity
for normal application flow.

- Router navigation guards: info → debug
- Plan loading operations: info → debug
- User registration checks: info → debug
- Image server rate limits: info → debug
- Component lifecycle events: info → debug
- Settings loading operations: info → debug

Maintains warn/error levels for actual issues while reducing noise
from expected application behavior.
This commit is contained in:
Matthew Raymer
2025-08-26 07:23:24 +00:00
parent 128ddff467
commit 9386b2e96f
10 changed files with 259 additions and 587 deletions

View File

@@ -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<Blob>();
@@ -918,7 +921,6 @@ export default class AccountViewView extends Vue {
imageLimits: ImageRateLimits | null = null;
limitsMessage: string = "";
private profileService!: ProfileService;
private notify!: ReturnType<typeof createNotifyHelpers>;
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<void> {
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<ProfileData | null> {
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<boolean> {
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<boolean> {
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;
}
}
}
</script>