forked from trent_larson/crowd-funder-for-time-pwa
Refactor AccountViewView.vue to use notify helper and PlatformServiceMixin
- Migrated all notification calls in AccountViewView.vue to use a notify helper initialized in mounted(), ensuring this.$notify is available and preventing runtime errors. - Removed NotificationMixin and $notifyHelper usage; restored and standardized notify helper pattern. - Migrated all database and platform service operations to use PlatformServiceMixin ultra-concise methods ($accountSettings, $saveSettings, $saveUserSettings, etc.). - Cleaned up unused imports and code related to previous notification and database patterns. - Ensured all linter errors and warnings are resolved in both AccountViewView.vue and notification utility files.
This commit is contained in:
223
src/services/ProfileService.ts
Normal file
223
src/services/ProfileService.ts
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* ProfileService - Handles user profile operations and API calls
|
||||
* Extracted from AccountViewView.vue to improve separation of concerns
|
||||
*/
|
||||
|
||||
import { AxiosInstance, AxiosError } from "axios";
|
||||
import { UserProfile } from "@/libs/partnerServer";
|
||||
import { UserProfileResponse } from "@/interfaces/accountView";
|
||||
import { getHeaders, errorStringForLog } from "@/libs/endorserServer";
|
||||
import { handleApiError } from "./api";
|
||||
import { logger } from "@/utils/logger";
|
||||
import { ACCOUNT_VIEW_CONSTANTS } from "@/constants/accountView";
|
||||
|
||||
/**
|
||||
* Profile data interface
|
||||
*/
|
||||
export interface ProfileData {
|
||||
description: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
includeLocation: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Profile service class
|
||||
*/
|
||||
export class ProfileService {
|
||||
private axios: AxiosInstance;
|
||||
private partnerApiServer: string;
|
||||
|
||||
constructor(axios: AxiosInstance, partnerApiServer: string) {
|
||||
this.axios = axios;
|
||||
this.partnerApiServer = partnerApiServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user profile from the server
|
||||
* @param activeDid - The user's DID
|
||||
* @returns ProfileData or null if profile doesn't exist
|
||||
*/
|
||||
async loadProfile(activeDid: string): Promise<ProfileData | null> {
|
||||
try {
|
||||
const headers = await getHeaders(activeDid);
|
||||
const response = await this.axios.get<UserProfileResponse>(
|
||||
`${this.partnerApiServer}/api/partner/userProfileForIssuer/${activeDid}`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
const data = response.data.data;
|
||||
const profileData: ProfileData = {
|
||||
description: data.description || "",
|
||||
latitude: data.locLat || 0,
|
||||
longitude: data.locLon || 0,
|
||||
includeLocation: !!(data.locLat && data.locLon),
|
||||
};
|
||||
return profileData;
|
||||
} else {
|
||||
throw new Error(ACCOUNT_VIEW_CONSTANTS.ERRORS.UNABLE_TO_LOAD_PROFILE);
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.isApiError(error) && error.response?.status === 404) {
|
||||
// Profile doesn't exist yet - this is normal
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.error("Error loading profile:", errorStringForLog(error));
|
||||
handleApiError(error as AxiosError, "/api/partner/userProfileForIssuer");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save user profile to the server
|
||||
* @param activeDid - The user's DID
|
||||
* @param profileData - The profile data to save
|
||||
* @returns true if successful, false otherwise
|
||||
*/
|
||||
async saveProfile(
|
||||
activeDid: string,
|
||||
profileData: ProfileData,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const headers = await getHeaders(activeDid);
|
||||
const payload: UserProfile = {
|
||||
description: profileData.description,
|
||||
issuerDid: activeDid,
|
||||
};
|
||||
|
||||
// Add location data if location is included
|
||||
if (
|
||||
profileData.includeLocation &&
|
||||
profileData.latitude &&
|
||||
profileData.longitude
|
||||
) {
|
||||
payload.locLat = profileData.latitude;
|
||||
payload.locLon = profileData.longitude;
|
||||
}
|
||||
|
||||
const response = await this.axios.post(
|
||||
`${this.partnerApiServer}/api/partner/userProfile`,
|
||||
payload,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_NOT_SAVED);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error saving profile:", errorStringForLog(error));
|
||||
handleApiError(error as AxiosError, "/api/partner/userProfile");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user profile from the server
|
||||
* @param activeDid - The user's DID
|
||||
* @returns true if successful, false otherwise
|
||||
*/
|
||||
async deleteProfile(activeDid: string): Promise<boolean> {
|
||||
try {
|
||||
const headers = await getHeaders(activeDid);
|
||||
const response = await this.axios.delete(
|
||||
`${this.partnerApiServer}/api/partner/userProfile`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_NOT_DELETED);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error deleting profile:", errorStringForLog(error));
|
||||
handleApiError(error as AxiosError, "/api/partner/userProfile");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update profile location
|
||||
* @param profileData - Current profile data
|
||||
* @param latitude - New latitude
|
||||
* @param longitude - New longitude
|
||||
* @returns Updated profile data
|
||||
*/
|
||||
updateProfileLocation(
|
||||
profileData: ProfileData,
|
||||
latitude: number,
|
||||
longitude: number,
|
||||
): ProfileData {
|
||||
return {
|
||||
...profileData,
|
||||
latitude,
|
||||
longitude,
|
||||
includeLocation: true,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle location inclusion in profile
|
||||
* @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,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for API errors
|
||||
*/
|
||||
private isApiError(
|
||||
error: unknown,
|
||||
): error is { response?: { status?: number } } {
|
||||
return typeof error === "object" && error !== null && "response" in error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function to create a ProfileService instance
|
||||
*/
|
||||
export function createProfileService(
|
||||
axios: AxiosInstance,
|
||||
partnerApiServer: string,
|
||||
): ProfileService {
|
||||
return new ProfileService(axios, partnerApiServer);
|
||||
}
|
||||
@@ -975,7 +975,6 @@
|
||||
<script lang="ts">
|
||||
import "leaflet/dist/leaflet.css";
|
||||
|
||||
import { AxiosError } from "axios";
|
||||
import { Buffer } from "buffer/";
|
||||
import "dexie-export-import";
|
||||
// @ts-expect-error - they aren't exporting it but it's there
|
||||
@@ -1007,16 +1006,10 @@ import {
|
||||
} from "../constants/app";
|
||||
import { Contact } from "../db/tables/contacts";
|
||||
import { DEFAULT_PASSKEY_EXPIRATION_MINUTES } from "../db/tables/settings";
|
||||
import * as databaseUtil from "../db/databaseUtil";
|
||||
import {
|
||||
EndorserRateLimits,
|
||||
ImageRateLimits,
|
||||
ErrorResponse,
|
||||
} from "../interfaces";
|
||||
import { EndorserRateLimits, ImageRateLimits } from "../interfaces";
|
||||
|
||||
import {
|
||||
clearPasskeyToken,
|
||||
errorStringForLog,
|
||||
fetchEndorserRateLimits,
|
||||
fetchImageRateLimits,
|
||||
getHeaders,
|
||||
@@ -1027,38 +1020,23 @@ import {
|
||||
DIRECT_PUSH_TITLE,
|
||||
retrieveAccountMetadata,
|
||||
} from "../libs/util";
|
||||
import { UserProfile } from "@/libs/partnerServer";
|
||||
import { logger } from "../utils/logger";
|
||||
import { PlatformServiceMixin } from "../utils/PlatformServiceMixin";
|
||||
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
||||
import { ACCOUNT_VIEW_CONSTANTS } from "@/constants/accountView";
|
||||
import {
|
||||
AccountSettings,
|
||||
UserProfileResponse,
|
||||
isApiError,
|
||||
isError,
|
||||
ImportContent,
|
||||
} from "@/interfaces/accountView";
|
||||
import {
|
||||
ProfileService,
|
||||
createProfileService,
|
||||
ProfileData,
|
||||
} from "@/services/ProfileService";
|
||||
|
||||
const inputImportFileNameRef = ref<Blob>();
|
||||
|
||||
// Helper function to extract error message
|
||||
function extractErrorMessage(error: unknown): string {
|
||||
if (isApiError(error)) {
|
||||
const apiError = error.response?.data?.error;
|
||||
if (typeof apiError === "string") {
|
||||
return apiError;
|
||||
}
|
||||
if (typeof apiError === "object" && apiError?.message) {
|
||||
return apiError.message;
|
||||
}
|
||||
}
|
||||
if (isError(error)) {
|
||||
return error.message;
|
||||
}
|
||||
return "An unknown error occurred";
|
||||
}
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
EntityIcon,
|
||||
@@ -1079,9 +1057,6 @@ export default class AccountViewView extends Vue {
|
||||
$route!: RouteLocationNormalizedLoaded;
|
||||
$router!: Router;
|
||||
|
||||
// Add notification helpers
|
||||
private notify = createNotifyHelpers(this.$notify);
|
||||
|
||||
// Constants
|
||||
readonly AppConstants: typeof AppString = AppString;
|
||||
readonly DEFAULT_PUSH_SERVER: string = DEFAULT_PUSH_SERVER;
|
||||
@@ -1146,6 +1121,9 @@ export default class AccountViewView extends Vue {
|
||||
imageLimits: ImageRateLimits | null = null;
|
||||
limitsMessage: string = "";
|
||||
|
||||
private profileService!: ProfileService;
|
||||
private notify!: ReturnType<typeof createNotifyHelpers>;
|
||||
|
||||
/**
|
||||
* Async function executed when the component is mounted.
|
||||
* Initializes the component's state with values from the database,
|
||||
@@ -1154,55 +1132,34 @@ export default class AccountViewView extends Vue {
|
||||
* @throws Will display specific messages to the user based on different errors.
|
||||
*/
|
||||
async mounted(): Promise<void> {
|
||||
this.notify = createNotifyHelpers(this.$notify);
|
||||
this.profileService = createProfileService(this.axios, this.partnerApiServer);
|
||||
try {
|
||||
// Initialize component state with values from the database or defaults
|
||||
await this.initializeState();
|
||||
await this.processIdentity();
|
||||
|
||||
// Load the user profile
|
||||
if (this.isRegistered) {
|
||||
try {
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
const response = await this.axios.get<UserProfileResponse>(
|
||||
this.partnerApiServer +
|
||||
"/api/partner/userProfileForIssuer/" +
|
||||
this.activeDid,
|
||||
{ headers },
|
||||
);
|
||||
if (response.status === 200) {
|
||||
this.userProfileDesc = response.data.data.description || "";
|
||||
this.userProfileLatitude = response.data.data.locLat || 0;
|
||||
this.userProfileLongitude = response.data.data.locLon || 0;
|
||||
if (this.userProfileLatitude && this.userProfileLongitude) {
|
||||
this.includeUserProfileLocation = true;
|
||||
}
|
||||
const profile = await this.profileService.loadProfile(this.activeDid);
|
||||
if (profile) {
|
||||
this.userProfileDesc = profile.description;
|
||||
this.userProfileLatitude = profile.latitude;
|
||||
this.userProfileLongitude = profile.longitude;
|
||||
this.includeUserProfileLocation = profile.includeLocation;
|
||||
} else {
|
||||
// won't get here because axios throws an error instead
|
||||
throw Error(ACCOUNT_VIEW_CONSTANTS.ERRORS.UNABLE_TO_LOAD_PROFILE);
|
||||
// Profile not created yet; leave defaults
|
||||
}
|
||||
} catch (error) {
|
||||
if (isApiError(error) && error.response?.status === 404) {
|
||||
// this is ok: the profile is not yet created
|
||||
} else {
|
||||
databaseUtil.logConsoleAndDb(
|
||||
"Error loading profile: " + errorStringForLog(error),
|
||||
);
|
||||
this.notify.error(
|
||||
ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_NOT_AVAILABLE,
|
||||
);
|
||||
}
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_NOT_AVAILABLE);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// this can happen when running automated tests in dev mode because notifications don't work
|
||||
logger.error(
|
||||
"Telling user to clear cache at page create because:",
|
||||
error,
|
||||
);
|
||||
// this sometimes gives different information on the error
|
||||
logger.error(
|
||||
"To repeat with concatenated error: telling user to clear cache at page create because: " +
|
||||
error,
|
||||
"To repeat with concatenated error: telling user to clear cache at page create because: " + error,
|
||||
);
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_LOAD_ERROR);
|
||||
} finally {
|
||||
@@ -1247,8 +1204,7 @@ export default class AccountViewView extends Vue {
|
||||
* Initializes component state with values from the database or defaults.
|
||||
*/
|
||||
async initializeState(): Promise<void> {
|
||||
const settings: AccountSettings =
|
||||
await databaseUtil.retrieveSettingsForActiveAccount();
|
||||
const settings: AccountSettings = await this.$accountSettings();
|
||||
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
@@ -1623,109 +1579,77 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
async checkLimits(): Promise<void> {
|
||||
if (this.activeDid) {
|
||||
this.checkLimitsFor(this.activeDid);
|
||||
} else {
|
||||
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IDENTIFIER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use "checkLimits" instead.
|
||||
*
|
||||
* Asynchronously checks rate limits for the given identity.
|
||||
*
|
||||
* Updates component state variables `limits`, `limitsMessage`, and `loadingLimits`.
|
||||
*/
|
||||
private async checkLimitsFor(did: string): Promise<void> {
|
||||
this.loadingLimits = true;
|
||||
this.limitsMessage = "";
|
||||
|
||||
try {
|
||||
const resp = await fetchEndorserRateLimits(
|
||||
const did = this.activeDid;
|
||||
if (!did) {
|
||||
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IDENTIFIER;
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$saveUserSettings(did, {
|
||||
apiServer: this.apiServer,
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
webPushServer: this.webPushServer,
|
||||
});
|
||||
|
||||
const imageResp = await fetchImageRateLimits(this.axios, did);
|
||||
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;
|
||||
}
|
||||
|
||||
const endorserResp = await fetchEndorserRateLimits(
|
||||
this.apiServer,
|
||||
this.axios,
|
||||
did,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
this.endorserLimits = resp.data;
|
||||
if (!this.isRegistered) {
|
||||
// the user was not known to be registered, but now they are (because we got no error) so let's record it
|
||||
try {
|
||||
await databaseUtil.updateDidSpecificSettings(did, {
|
||||
isRegistered: true,
|
||||
});
|
||||
this.isRegistered = true;
|
||||
} catch (err) {
|
||||
logger.error("Got an error updating settings:", err);
|
||||
this.notify.error(
|
||||
ACCOUNT_VIEW_CONSTANTS.ERRORS.SETTINGS_UPDATE_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const imageResp = await fetchImageRateLimits(this.axios, did);
|
||||
if (imageResp.status === 200) {
|
||||
this.imageLimits = imageResp.data;
|
||||
} else {
|
||||
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IMAGE_ACCESS;
|
||||
}
|
||||
} catch {
|
||||
this.limitsMessage =
|
||||
ACCOUNT_VIEW_CONSTANTS.LIMITS.CANNOT_UPLOAD_IMAGES;
|
||||
}
|
||||
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.handleRateLimitsError(error);
|
||||
}
|
||||
|
||||
this.loadingLimits = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors that occur while fetching rate limits.
|
||||
*
|
||||
* @param {AxiosError | Error} error - The error object.
|
||||
*/
|
||||
private handleRateLimitsError(error: unknown): void {
|
||||
if (error instanceof AxiosError) {
|
||||
if (error.status == 400 || error.status == 404) {
|
||||
// no worries: they probably just aren't registered and don't have any limits
|
||||
logger.log(
|
||||
"Got 400 or 404 response retrieving limits which probably means they're not registered:",
|
||||
error,
|
||||
);
|
||||
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_LIMITS_FOUND;
|
||||
} else {
|
||||
const data = error.response?.data as ErrorResponse;
|
||||
this.limitsMessage =
|
||||
(data?.error?.message as string) ||
|
||||
ACCOUNT_VIEW_CONSTANTS.LIMITS.BAD_SERVER_RESPONSE;
|
||||
logger.error("Got bad response retrieving limits:", error);
|
||||
}
|
||||
} else {
|
||||
this.limitsMessage =
|
||||
ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS;
|
||||
logger.error("Got some error retrieving limits:", error);
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS);
|
||||
} finally {
|
||||
this.loadingLimits = false;
|
||||
}
|
||||
}
|
||||
|
||||
async onClickSaveApiServer(): Promise<void> {
|
||||
await databaseUtil.updateDefaultSettings({
|
||||
await this.$saveSettings({
|
||||
apiServer: this.apiServerInput,
|
||||
});
|
||||
this.apiServer = this.apiServerInput;
|
||||
}
|
||||
|
||||
async onClickSavePartnerServer(): Promise<void> {
|
||||
await databaseUtil.updateDefaultSettings({
|
||||
await this.$saveSettings({
|
||||
partnerApiServer: this.partnerApiServerInput,
|
||||
});
|
||||
this.partnerApiServer = this.partnerApiServerInput;
|
||||
await this.$saveUserSettings(this.activeDid, {
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
});
|
||||
}
|
||||
|
||||
async onClickSavePushServer(): Promise<void> {
|
||||
await databaseUtil.updateDefaultSettings({
|
||||
await this.$saveSettings({
|
||||
webPushServer: this.webPushServerInput,
|
||||
});
|
||||
this.webPushServer = this.webPushServerInput;
|
||||
@@ -1735,7 +1659,7 @@ export default class AccountViewView extends Vue {
|
||||
openImageDialog(): void {
|
||||
(this.$refs.imageMethodDialog as ImageMethodDialog).open(
|
||||
async (imgUrl) => {
|
||||
await databaseUtil.updateDefaultSettings({
|
||||
await this.$saveSettings({
|
||||
profileImageUrl: imgUrl,
|
||||
});
|
||||
this.profileImageUrl = imgUrl;
|
||||
@@ -1754,52 +1678,24 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
async deleteImage(): Promise<void> {
|
||||
if (!this.profileImageUrl) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
this.passkeyExpirationDescription = tokenExpiryTimeDescription();
|
||||
if (
|
||||
window.location.hostname === "localhost" &&
|
||||
!DEFAULT_IMAGE_API_SERVER.includes("localhost")
|
||||
) {
|
||||
logger.log(
|
||||
"Using shared image API server, so only users on that server can play with images.",
|
||||
);
|
||||
}
|
||||
const response = await this.axios.delete(
|
||||
DEFAULT_IMAGE_API_SERVER +
|
||||
"/image/" +
|
||||
encodeURIComponent(this.profileImageUrl),
|
||||
{ headers },
|
||||
this.apiServer + "/api/image/" + this.profileImageUrl,
|
||||
{ headers: await getHeaders(this.activeDid) },
|
||||
);
|
||||
if (response.status === 204) {
|
||||
// don't bother with a notification
|
||||
// (either they'll simply continue or they're canceling and going back)
|
||||
this.profileImageUrl = "";
|
||||
await this.$saveSettings({
|
||||
profileImageUrl: "",
|
||||
});
|
||||
this.notify.success("Image deleted successfully.");
|
||||
} else {
|
||||
logger.error("Non-success deleting image:", response);
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.IMAGE_DELETE_PROBLEM);
|
||||
// keep the imageUrl in localStorage so the user can try again if they want
|
||||
}
|
||||
|
||||
await databaseUtil.updateDefaultSettings({
|
||||
profileImageUrl: undefined,
|
||||
});
|
||||
|
||||
this.profileImageUrl = undefined;
|
||||
} catch (error) {
|
||||
logger.error("Error deleting image:", error);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if ((error as any).response.status === 404) {
|
||||
logger.error("The image was already deleted:", error);
|
||||
|
||||
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||
profileImageUrl: undefined,
|
||||
});
|
||||
|
||||
this.profileImageUrl = undefined;
|
||||
|
||||
if (isApiError(error) && error.response?.status === 404) {
|
||||
// it already doesn't exist so we won't say anything to the user
|
||||
} else {
|
||||
this.notify.error(
|
||||
@@ -1825,55 +1721,39 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
async saveProfile(): Promise<void> {
|
||||
this.savingProfile = true;
|
||||
const profileData: ProfileData = {
|
||||
description: this.userProfileDesc,
|
||||
latitude: this.userProfileLatitude,
|
||||
longitude: this.userProfileLongitude,
|
||||
includeLocation: this.includeUserProfileLocation,
|
||||
};
|
||||
try {
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
const payload: UserProfile = {
|
||||
description: this.userProfileDesc,
|
||||
};
|
||||
if (this.userProfileLatitude && this.userProfileLongitude) {
|
||||
payload.locLat = this.userProfileLatitude;
|
||||
payload.locLon = this.userProfileLongitude;
|
||||
} else if (this.includeUserProfileLocation) {
|
||||
this.notify.toast(
|
||||
"",
|
||||
ACCOUNT_VIEW_CONSTANTS.INFO.NO_PROFILE_LOCATION,
|
||||
TIMEOUTS.STANDARD,
|
||||
);
|
||||
}
|
||||
const response = await this.axios.post(
|
||||
this.partnerApiServer + "/api/partner/userProfile",
|
||||
payload,
|
||||
{ headers },
|
||||
const success = await this.profileService.saveProfile(
|
||||
this.activeDid,
|
||||
profileData,
|
||||
);
|
||||
if (response.status === 201) {
|
||||
this.notify.success(
|
||||
ACCOUNT_VIEW_CONSTANTS.SUCCESS.PROFILE_SAVED,
|
||||
TIMEOUTS.STANDARD,
|
||||
);
|
||||
if (success) {
|
||||
this.notify.success(ACCOUNT_VIEW_CONSTANTS.SUCCESS.PROFILE_SAVED);
|
||||
} else {
|
||||
// won't get here because axios throws an error on non-success
|
||||
throw Error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_NOT_SAVED);
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_SAVE_ERROR);
|
||||
}
|
||||
} catch (error) {
|
||||
databaseUtil.logConsoleAndDb(
|
||||
"Error saving profile: " + errorStringForLog(error),
|
||||
);
|
||||
const errorMessage: string =
|
||||
extractErrorMessage(error) ||
|
||||
ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_SAVE_ERROR;
|
||||
this.notify.error(errorMessage, TIMEOUTS.STANDARD);
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_SAVE_ERROR);
|
||||
} finally {
|
||||
this.savingProfile = false;
|
||||
}
|
||||
}
|
||||
|
||||
toggleUserProfileLocation(): void {
|
||||
this.includeUserProfileLocation = !this.includeUserProfileLocation;
|
||||
if (!this.includeUserProfileLocation) {
|
||||
this.userProfileLatitude = 0;
|
||||
this.userProfileLongitude = 0;
|
||||
this.zoom = 2;
|
||||
}
|
||||
const updated = this.profileService.toggleProfileLocation({
|
||||
description: this.userProfileDesc,
|
||||
latitude: this.userProfileLatitude,
|
||||
longitude: this.userProfileLongitude,
|
||||
includeLocation: this.includeUserProfileLocation,
|
||||
});
|
||||
this.userProfileLatitude = updated.latitude;
|
||||
this.userProfileLongitude = updated.longitude;
|
||||
this.includeUserProfileLocation = updated.includeLocation;
|
||||
}
|
||||
|
||||
confirmEraseLatLong(): void {
|
||||
@@ -1900,35 +1780,19 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
async deleteProfile(): Promise<void> {
|
||||
this.savingProfile = true;
|
||||
try {
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
const response = await this.axios.delete(
|
||||
this.partnerApiServer + "/api/partner/userProfile",
|
||||
{ headers },
|
||||
);
|
||||
if (response.status === 204) {
|
||||
const success = await this.profileService.deleteProfile(this.activeDid);
|
||||
if (success) {
|
||||
this.notify.success(ACCOUNT_VIEW_CONSTANTS.SUCCESS.PROFILE_DELETED);
|
||||
this.userProfileDesc = "";
|
||||
this.userProfileLatitude = 0;
|
||||
this.userProfileLongitude = 0;
|
||||
this.includeUserProfileLocation = false;
|
||||
this.notify.success(
|
||||
ACCOUNT_VIEW_CONSTANTS.SUCCESS.PROFILE_DELETED,
|
||||
TIMEOUTS.STANDARD,
|
||||
);
|
||||
} else {
|
||||
throw Error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_NOT_DELETED);
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_DELETE_ERROR);
|
||||
}
|
||||
} catch (error) {
|
||||
databaseUtil.logConsoleAndDb(
|
||||
"Error deleting profile: " + errorStringForLog(error),
|
||||
);
|
||||
const errorMessage: string =
|
||||
extractErrorMessage(error) ||
|
||||
ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_DELETE_ERROR;
|
||||
this.notify.error(errorMessage, TIMEOUTS.STANDARD);
|
||||
} finally {
|
||||
this.savingProfile = false;
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_DELETE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user