feat: Complete NewEditProjectView.vue Enhanced Triple Migration Pattern and ImageMethodDialog improvements

- Complete all 4 phases of Enhanced Triple Migration Pattern for NewEditProjectView.vue
- Replace databaseUtil calls with PlatformServiceMixin methods
- Standardize notification calls using constants and timeout helpers
- Extract 12 computed properties for template streamlining
- Add notification constants and helper functions to notifications.ts
- Extract long CSS classes to computed properties in ImageMethodDialog.vue
- Fix platformService conflict in ImageMethodDialog.vue
- Complete PushNotificationPermission.vue migration with all phases
- Update migration tracking documentation
- Migration completed in 11m 30s (74% faster than estimate)
This commit is contained in:
Matthew Raymer
2025-07-09 07:22:58 +00:00
parent 7aa8a74505
commit 702fff236f
8 changed files with 1031 additions and 264 deletions

View File

@@ -235,7 +235,25 @@ import {
NotificationIface,
} from "../constants/app";
import { PlatformServiceMixin } from "../utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "../utils/notify";
import { createNotifyHelpers } from "../utils/notify";
import {
NOTIFY_PROJECT_ACCOUNT_LOADING_ERROR,
NOTIFY_PROJECT_RETRIEVAL_ERROR,
NOTIFY_PROJECT_DELETE_IMAGE_CONFIRM,
NOTIFY_PROJECT_DELETE_IMAGE_ERROR,
NOTIFY_PROJECT_DELETE_IMAGE_GENERAL_ERROR,
NOTIFY_PROJECT_INVALID_LOCATION,
NOTIFY_PROJECT_INVALID_START_DATE,
NOTIFY_PROJECT_INVALID_END_DATE,
NOTIFY_PROJECT_SAVE_SUCCESS,
NOTIFY_PROJECT_PARTNER_LOCATION_WARNING,
NOTIFY_PROJECT_PARTNER_SEND_GENERAL_ERROR,
NOTIFY_PROJECT_DELETE_LOCATION_CONFIRM,
NOTIFY_PROJECT_NOSTR_PARTNER_INFO,
createProjectPartnerSendSuccessMessage,
createProjectPartnerSendErrorMessage,
PROJECT_TIMEOUT_VERY_LONG,
} from "../constants/notifications";
import { PlanActionClaim } from "../interfaces/claims";
import {
createEndorserJwtVcFromClaim,
@@ -310,7 +328,7 @@ export default class NewEditProjectView extends Vue {
$router!: Router;
// Notification helpers
private notifyHelpers = createNotifyHelpers(this.$notify);
private notify!: ReturnType<typeof createNotifyHelpers>;
/**
* Display error notification to user
@@ -318,7 +336,7 @@ export default class NewEditProjectView extends Vue {
* @param message - Error message to display
*/
errNote(message: string) {
this.notifyHelpers.error(message);
this.notify.error(message);
}
// Component state properties
@@ -358,6 +376,9 @@ export default class NewEditProjectView extends Vue {
* Handles account validation and project loading with comprehensive error handling
*/
async mounted() {
// Initialize notification helpers
this.notify = createNotifyHelpers(this.$notify);
this.numAccounts = await retrieveAccountCount();
const settings = await this.$accountSettings();
@@ -369,9 +390,7 @@ export default class NewEditProjectView extends Vue {
if (this.projectId) {
if (this.numAccounts === 0) {
this.notifyHelpers.error(
"There was a problem loading your account info.",
);
this.notify.error(NOTIFY_PROJECT_ACCOUNT_LOADING_ERROR.message);
} else {
this.loadProject(this.activeDid);
}
@@ -422,7 +441,7 @@ export default class NewEditProjectView extends Vue {
}
} catch (error) {
logger.error("Got error retrieving that project", error);
this.notifyHelpers.error("There was an error retrieving that project.");
this.notify.error(NOTIFY_PROJECT_RETRIEVAL_ERROR.message);
}
}
@@ -441,8 +460,8 @@ export default class NewEditProjectView extends Vue {
* Shows confirmation dialog before proceeding with image deletion
*/
confirmDeleteImage() {
this.notifyHelpers.confirm(
"Are you sure you want to delete the image?",
this.notify.confirm(
NOTIFY_PROJECT_DELETE_IMAGE_CONFIRM.message,
async () => {
await this.deleteImage();
},
@@ -480,7 +499,7 @@ export default class NewEditProjectView extends Vue {
// (either they'll simply continue or they're canceling and going back)
} else {
logger.error("Problem deleting image:", response);
this.notifyHelpers.error("There was a problem deleting the image.");
this.notify.error(NOTIFY_PROJECT_DELETE_IMAGE_ERROR.message);
return;
}
@@ -495,7 +514,7 @@ export default class NewEditProjectView extends Vue {
// it already doesn't exist so we won't say anything to the user
} else {
this.notifyHelpers.error("There was an error deleting the image.");
this.notify.error(NOTIFY_PROJECT_DELETE_IMAGE_GENERAL_ERROR.message);
}
}
}
@@ -525,7 +544,7 @@ export default class NewEditProjectView extends Vue {
}
if (this.includeLocation) {
if (!this.latitude || !this.longitude) {
this.notifyHelpers.error("The location was invalid so it was not set.");
this.notify.error(NOTIFY_PROJECT_INVALID_LOCATION.message);
delete vcClaim.location;
} else {
vcClaim.location = {
@@ -548,9 +567,7 @@ export default class NewEditProjectView extends Vue {
} catch {
// it's not a valid date so erase it and tell the user
delete vcClaim.startTime;
this.notifyHelpers.error(
"The start date was invalid so it was not set.",
);
this.notify.error(NOTIFY_PROJECT_INVALID_START_DATE.message);
}
} else {
delete vcClaim.startTime;
@@ -564,7 +581,7 @@ export default class NewEditProjectView extends Vue {
} catch {
// it's not a valid date so erase it and tell the user
delete vcClaim.endTime;
this.notifyHelpers.error("The end date was invalid so it was not set.");
this.notify.error(NOTIFY_PROJECT_INVALID_END_DATE.message);
}
} else {
delete vcClaim.endTime;
@@ -580,7 +597,7 @@ export default class NewEditProjectView extends Vue {
try {
const resp = await this.axios.post(url, payload, { headers });
if (resp.data?.success?.handleId) {
this.notifyHelpers.success("The project was saved successfully.");
this.notify.success(NOTIFY_PROJECT_SAVE_SUCCESS.message);
this.errorMessage = "";
@@ -614,9 +631,7 @@ export default class NewEditProjectView extends Vue {
);
}
} else {
this.notifyHelpers.error(
"A partner was selected but the location was not set, so it was not sent to any partner.",
);
this.notify.error(NOTIFY_PROJECT_PARTNER_LOCATION_WARNING.message);
}
}
@@ -654,7 +669,7 @@ export default class NewEditProjectView extends Vue {
}
}
if (userMessage) {
this.notifyHelpers.error(userMessage);
this.notify.error(userMessage);
}
// Now set that error for the user to see.
this.errorMessage = userMessage;
@@ -756,23 +771,26 @@ export default class NewEditProjectView extends Vue {
{ headers },
);
if (linkResp.status === 201) {
this.notifyHelpers.success(
`The project info was sent to ${serviceName}.`,
this.notify.success(
createProjectPartnerSendSuccessMessage(serviceName),
);
} else {
// axios never gets here because it throws an error, but just in case
this.notifyHelpers.error(
`Failed sending to ${serviceName}: ${JSON.stringify(linkResp.data)}`,
this.notify.error(
createProjectPartnerSendErrorMessage(
serviceName,
JSON.stringify(linkResp.data),
),
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
logger.error(`Error sending to ${serviceName}`, error);
let errorMessage = `There was an error sending to ${serviceName}.`;
let errorMessage = NOTIFY_PROJECT_PARTNER_SEND_GENERAL_ERROR.message;
if (error.response?.data?.error?.message) {
errorMessage = error.response.data.error.message;
}
this.notifyHelpers.error(errorMessage, TIMEOUTS.VERY_LONG);
this.notify.error(errorMessage, PROJECT_TIMEOUT_VERY_LONG);
}
}
@@ -796,8 +814,8 @@ export default class NewEditProjectView extends Vue {
* Shows confirmation dialog before clearing location data
*/
confirmEraseLatLong() {
this.notifyHelpers.confirm(
"Are you sure you don't want to mark a location? This will erase the current location.",
this.notify.confirm(
NOTIFY_PROJECT_DELETE_LOCATION_CONFIRM.message,
async () => {
this.eraseLatLong();
},
@@ -827,9 +845,9 @@ export default class NewEditProjectView extends Vue {
* Displays privacy information about partner service integration
*/
public showNostrPartnerInfo() {
this.notifyHelpers.info(
"This will submit this project to a partner on the nostr network. It will contain your public key data which may allow correlation, so don't allow this if you're not comfortable with that.",
TIMEOUTS.VERY_LONG,
this.notify.info(
NOTIFY_PROJECT_NOSTR_PARTNER_INFO.message,
PROJECT_TIMEOUT_VERY_LONG,
);
}