Complete notification migration across 13 components and views

- Replace raw $notify calls with notification helper system
- Add createNotifyHelpers and TIMEOUTS constants integration
- Migrate AccountViewView, ClaimAddRawView, ContactGiftingView, ContactImportView, ContactsView, NewActivityView, ProjectViewView, RecentOffersToUserProjectsView, RecentOffersToUserView, ShareMyContactInfoView
- Update MembersList, TopMessage, UserNameDialog components
- Add notification constants for standardized messaging
- Enhance validation script to eliminate false positives
- Achieve 86% notification migration completion rate
This commit is contained in:
Matthew Raymer
2025-07-07 06:53:30 +00:00
parent 15874d31ef
commit ef15126d6d
15 changed files with 345 additions and 592 deletions

View File

@@ -298,6 +298,19 @@ import { logger } from "../utils/logger";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { UserInfo, VerifiableCredentialClaim } from "../interfaces/common";
import { GiveSummaryRecord } from "../interfaces/records";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import {
NOTIFY_BLANK_INVITE,
NOTIFY_INVITE_REGISTRATION_SUCCESS,
NOTIFY_INVITE_ERROR,
NOTIFY_ONBOARDING_CONFIRM,
NOTIFY_REGISTER_NOT_AVAILABLE,
NOTIFY_REGISTER_PROCESSING,
NOTIFY_REGISTER_PERSON_SUCCESS,
NOTIFY_REGISTER_PERSON_ERROR,
NOTIFY_VISIBILITY_ERROR,
NOTIFY_UNCONFIRMED_HOURS,
} from "@/constants/notifications";
@Component({
components: {
@@ -315,6 +328,8 @@ export default class ContactsView extends Vue {
$route!: RouteLocationNormalizedLoaded;
$router!: Router;
notify!: ReturnType<typeof createNotifyHelpers>;
activeDid = "";
apiServer = "";
contacts: Array<Contact> = [];
@@ -375,9 +390,9 @@ export default class ContactsView extends Vue {
// Methods for template simplification
showNotRegisteredWarning(): void {
this.warning(
"You must get registered before you can create invites.",
"Not Registered",
this.notify.warning(
NOTIFY_REGISTER_NOT_AVAILABLE.message,
TIMEOUTS.LONG,
);
}
@@ -418,6 +433,8 @@ export default class ContactsView extends Vue {
}
public async created() {
this.notify = createNotifyHelpers(this.$notify);
const settingsRow = await this.$getSettingsRow([
"activeDid",
"apiServer",
@@ -473,14 +490,9 @@ export default class ContactsView extends Vue {
const importedInviteJwt = this.$route.query["inviteJwt"] as string;
if (importedInviteJwt === "") {
// this happens when a platform (eg iOS) doesn't include anything after the "=" in a shared link.
this.$notify(
{
group: "alert",
type: "danger",
title: "Blank Invite",
text: "The invite was not included, which can happen when your iOS device cuts off the link. Try pasting the full link into a browser.",
},
7000,
this.notify.error(
NOTIFY_BLANK_INVITE.message,
TIMEOUTS.VERY_LONG,
);
} else if (importedInviteJwt) {
// make sure user is created
@@ -500,14 +512,9 @@ export default class ContactsView extends Vue {
}
await this.$updateSettings({ isRegistered: true }, this.activeDid);
this.isRegistered = true;
this.$notify(
{
group: "alert",
type: "success",
title: "Registered",
text: "You are now registered.",
},
3000,
this.notify.success(
NOTIFY_INVITE_REGISTRATION_SUCCESS.message,
TIMEOUTS.STANDARD,
);
// wait for a second before continuing so they see the registration message
@@ -566,14 +573,9 @@ export default class ContactsView extends Vue {
} else if (typeof err.message === "string") {
message = err.message;
}
this.$notify(
{
group: "alert",
type: "danger",
title: "Error with Invite",
text: message,
},
-1,
this.notify.error(
message,
TIMEOUTS.MODAL,
);
}
// if we're here, they haven't redirected anywhere, so we'll redirect here without a query parameter
@@ -586,41 +588,20 @@ export default class ContactsView extends Vue {
}
private danger(message: string, title: string = "Error", timeout = 5000) {
this.$notify(
{
group: "alert",
type: "danger",
title: title,
text: message,
},
timeout,
);
this.notify.error(message, timeout);
}
private warning(message: string, title: string = "Error", timeout = 5000) {
this.$notify(
{
group: "alert",
type: "warning",
title: title,
text: message,
},
timeout,
);
this.notify.warning(message, timeout);
}
private showOnboardingInfo() {
this.$notify(
{
group: "modal",
type: "confirm",
title: "They're Added To Your List",
text: "Would you like to go to the main page now?",
onYes: async () => {
this.$router.push({ name: "home" });
},
this.notify.confirm(
NOTIFY_ONBOARDING_CONFIRM.message,
async () => {
this.$router.push({ name: "home" });
},
-1,
TIMEOUTS.MODAL,
);
}
@@ -669,17 +650,9 @@ export default class ContactsView extends Vue {
resp.status,
resp.data,
);
this.$notify(
{
group: "alert",
type: "danger",
title: "Retrieval Error",
text:
"Got an error retrieving your " +
(useRecipient ? "given" : "received") +
" data from the server.",
},
3000,
this.notify.error(
`Got an error retrieving your ${useRecipient ? "given" : "received"} data from the server.`,
TIMEOUTS.STANDARD,
);
}
};
@@ -730,14 +703,9 @@ export default class ContactsView extends Vue {
} catch (error) {
const fullError = "Error loading gives: " + errorStringForLog(error);
logConsoleAndDb(fullError, true);
this.$notify(
{
group: "alert",
type: "danger",
title: "Load Error",
text: "Got an error loading your gives.",
},
3000,
this.notify.error(
"Got an error loading your gives.",
TIMEOUTS.STANDARD,
);
}
}
@@ -806,14 +774,9 @@ export default class ContactsView extends Vue {
}
try {
await Promise.all(lineAdded);
this.$notify(
{
group: "alert",
type: "success",
title: "Contacts Added",
text: "Each contact was added. Nothing was sent to the server.",
},
3000, // keeping it up so that the "visibility" message is seen
this.notify.success(
"Each contact was added. Nothing was sent to the server.",
TIMEOUTS.STANDARD, // keeping it up so that the "visibility" message is seen
);
} catch (e) {
const fullError =
@@ -961,19 +924,14 @@ export default class ContactsView extends Vue {
},
promptToStopAsking: true,
},
-1,
TIMEOUTS.MODAL,
);
}, 1000);
}
}
this.$notify(
{
group: "alert",
type: "success",
title: "Contact Added",
text: addedMessage,
},
3000,
this.notify.success(
addedMessage,
TIMEOUTS.STANDARD,
);
})
.catch((err) => {
@@ -997,7 +955,7 @@ export default class ContactsView extends Vue {
// note that this is also in DIDView.vue
private async register(contact: Contact) {
this.$notify({ group: "alert", type: "toast", title: "Sent..." }, 1000);
this.notify.sent(TIMEOUTS.BRIEF);
try {
const regResult = await register(
@@ -1010,27 +968,14 @@ export default class ContactsView extends Vue {
contact.registered = true;
await this.$updateContact(contact.did, { registered: true });
this.$notify(
{
group: "alert",
type: "success",
title: "Registration Success",
text:
(contact.name || "That unnamed person") + " has been registered.",
},
3000,
this.notify.success(
`${contact.name || "That unnamed person"} ${NOTIFY_REGISTER_PERSON_SUCCESS.message}`,
TIMEOUTS.STANDARD,
);
} else {
this.$notify(
{
group: "alert",
type: "danger",
title: "Registration Error",
text:
(regResult.error as string) ||
"Something went wrong during registration.",
},
-1,
this.notify.error(
(regResult.error as string) || NOTIFY_REGISTER_PERSON_ERROR.message,
TIMEOUTS.MODAL,
);
}
} catch (error) {
@@ -1057,14 +1002,9 @@ export default class ContactsView extends Vue {
userMessage = error as string;
}
// Now set that error for the user to see.
this.$notify(
{
group: "alert",
type: "danger",
title: "Registration Error",
text: userMessage,
},
-1,
this.notify.error(
userMessage,
TIMEOUTS.MODAL,
);
}
}
@@ -1085,18 +1025,9 @@ export default class ContactsView extends Vue {
if (result.success) {
//contact.seesMe = visibility; // why doesn't it affect the UI from here?
if (showSuccessAlert) {
this.$notify(
{
group: "alert",
type: "success",
title: "Visibility Set",
text:
(contact.name || "That user") +
" can " +
(visibility ? "" : "not ") +
"see your activity.",
},
3000,
this.notify.success(
`${contact.name || "That user"} can ${visibility ? "" : "not "}see your activity.`,
TIMEOUTS.STANDARD,
);
}
return true;
@@ -1107,14 +1038,9 @@ export default class ContactsView extends Vue {
);
const message =
(result.error as string) || "Could not set visibility on the server.";
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Setting Visibility",
text: message,
},
5000,
this.notify.error(
message,
TIMEOUTS.LONG,
);
return false;
}
@@ -1141,7 +1067,7 @@ export default class ContactsView extends Vue {
{
group: "modal",
type: "confirm",
title: "Delete",
title: "Unconfirmed Hours",
text: message,
onNo: async () => {
this.showGiftedDialog(giverDid, recipientDid);
@@ -1153,7 +1079,7 @@ export default class ContactsView extends Vue {
});
},
},
-1,
TIMEOUTS.MODAL,
);
} else {
this.showGiftedDialog(giverDid, recipientDid);
@@ -1222,14 +1148,9 @@ export default class ContactsView extends Vue {
const fullError =
"Error updating contact-amounts setting: " + errorStringForLog(err);
logConsoleAndDb(fullError, true);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Updating Contact Setting",
text: "The setting may not have saved. Try again, maybe after restarting the app.",
},
5000,
this.notify.error(
"The setting may not have saved. Try again, maybe after restarting the app.",
TIMEOUTS.LONG,
);
}
this.showGiveNumbers = newShowValue;
@@ -1302,27 +1223,17 @@ export default class ContactsView extends Vue {
useClipboard()
.copy(contactsJwtUrl)
.then(() => {
this.$notify(
{
group: "alert",
type: "info",
title: "Copied",
text: "The link for those contacts is now in the clipboard.",
},
3000,
this.notify.copied(
"contact link",
TIMEOUTS.STANDARD,
);
});
}
private showCopySelectionsInfo() {
this.$notify(
{
group: "alert",
type: "info",
title: "Copying Contacts",
text: "Contact info will include name, ID, profile image, and public key.",
},
5000,
this.notify.info(
"Contact info will include name, ID, profile image, and public key.",
TIMEOUTS.LONG,
);
}
@@ -1366,7 +1277,7 @@ export default class ContactsView extends Vue {
},
noText: "Join Existing Meeting",
},
-1,
TIMEOUTS.MODAL,
);
}
} catch (error) {