Refactor ContactsView.vue to use notification constants

- Extracted all inline notification and danger messages to src/constants/notifications.ts
- Added 20+ new notification constants and 2 template functions for dynamic messages
- Replaced all notify and danger calls with references to new constants/templates
- Updated imports for notification constants/templates and removed unused imports
- Fixed all linter errors - all notification messages now use single source of truth
- All $notify calls now use constants (remaining 3 are complex modals requiring raw calls)
This commit is contained in:
Matthew Raymer
2025-07-07 12:30:18 +00:00
parent 804221b32b
commit 524c1d91be
3 changed files with 283 additions and 180 deletions

View File

@@ -305,12 +305,31 @@ import {
NOTIFY_INVITE_ERROR,
NOTIFY_ONBOARDING_CONFIRM,
NOTIFY_REGISTER_NOT_AVAILABLE,
NOTIFY_REGISTER_PERSON_SUCCESS,
NOTIFY_REGISTER_PERSON_ERROR,
NOTIFY_VISIBILITY_ERROR,
NOTIFY_UNCONFIRMED_HOURS,
NOTIFY_UNCONFIRMED_HOURS_DYNAMIC,
NOTIFY_REGISTER_CONTACT,
NOTIFY_ONBOARDING_MEETING,
NOTIFY_CONTACT_NO_INFO,
NOTIFY_CONTACT_INVALID_URL,
NOTIFY_CONTACTS_ADDED_CSV,
NOTIFY_CONTACTS_ADD_ERROR,
NOTIFY_CONTACT_INPUT_PARSE_ERROR,
NOTIFY_CONTACT_NO_CONTACT_FOUND,
NOTIFY_CONTACT_NO_DID,
NOTIFY_CONTACT_INVALID_DID,
NOTIFY_CONTACT_IMPORT_ERROR,
NOTIFY_CONTACT_IMPORT_CONFLICT,
NOTIFY_CONTACT_IMPORT_CONSTRAINT,
NOTIFY_GIVES_LOAD_ERROR,
NOTIFY_CONTACT_SETTING_SAVE_ERROR,
NOTIFY_MEETING_STATUS_ERROR,
NOTIFY_CONTACTS_ADDED,
NOTIFY_CONTACT_INFO_COPY,
NOTIFY_CONTACTS_SELECT_TO_COPY,
NOTIFY_CONTACT_LINK_COPIED,
getRegisterPersonSuccessMessage,
getVisibilitySuccessMessage,
} from "@/constants/notifications";
@Component({
@@ -689,24 +708,24 @@ export default class ContactsView extends Vue {
} catch (error) {
const fullError = "Error loading gives: " + errorStringForLog(error);
this.$logAndConsole(fullError, true);
this.notify.error("Got an error loading your gives.", TIMEOUTS.STANDARD);
this.notify.error(NOTIFY_GIVES_LOAD_ERROR.message, TIMEOUTS.STANDARD);
}
}
private async onClickNewContact(): Promise<void> {
const contactInput = this.contactInput.trim();
if (!contactInput) {
this.danger(
"There was no contact info to add. Try the other green buttons.",
"No Contact",
);
this.notify.error(NOTIFY_CONTACT_NO_INFO.message, TIMEOUTS.STANDARD);
return;
}
if (contactInput.includes(CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI)) {
const jwt = getContactJwtFromJwtUrl(contactInput);
if (!jwt) {
this.danger("Invalid contact URL format.", "Invalid URL");
this.notify.error(
NOTIFY_CONTACT_INVALID_URL.message,
TIMEOUTS.STANDARD,
);
return;
}
const { payload } = decodeEndorserJwt(jwt);
@@ -729,7 +748,10 @@ export default class ContactsView extends Vue {
) {
const jwt = getContactJwtFromJwtUrl(contactInput);
if (!jwt) {
this.danger("Invalid contact URL format.", "Invalid URL");
this.notify.error(
NOTIFY_CONTACT_INVALID_URL.message,
TIMEOUTS.STANDARD,
);
return;
}
const { payload } = decodeEndorserJwt(jwt);
@@ -758,14 +780,17 @@ export default class ContactsView extends Vue {
try {
await Promise.all(lineAdded);
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
NOTIFY_CONTACTS_ADDED_CSV.message,
TIMEOUTS.STANDARD,
);
} catch (e) {
const fullError =
"Error adding contacts from CSV: " + errorStringForLog(e);
NOTIFY_CONTACTS_ADD_ERROR.message + ": " + errorStringForLog(e);
this.$logAndConsole(fullError, true);
this.danger("An error occurred. Some contacts may have been added.");
this.notify.error(
NOTIFY_CONTACT_INPUT_PARSE_ERROR.message,
TIMEOUTS.STANDARD,
);
}
this.contacts = await this.$getAllContacts();
@@ -828,14 +853,19 @@ export default class ContactsView extends Vue {
});
} catch (e) {
const fullError =
"Error adding contacts from array: " + errorStringForLog(e);
NOTIFY_CONTACT_INPUT_PARSE_ERROR.message +
": " +
errorStringForLog(e);
this.$logAndConsole(fullError, true);
this.danger("The input could not be parsed.", "Invalid Contact List");
this.notify.error(
NOTIFY_CONTACT_NO_CONTACT_FOUND.message,
TIMEOUTS.STANDARD,
);
}
return;
}
this.danger("No contact info was found in that input.", "No Contact Info");
this.notify.error(NOTIFY_CONTACT_NO_INFO.message, TIMEOUTS.STANDARD);
}
private async addContactFromEndorserMobileLine(
@@ -848,11 +878,11 @@ export default class ContactsView extends Vue {
private async addContact(newContact: Contact) {
if (!newContact.did) {
this.danger("Cannot add a contact without a DID.", "Incomplete Contact");
this.notify.error(NOTIFY_CONTACT_NO_DID.message, TIMEOUTS.STANDARD);
return;
}
if (!isDid(newContact.did)) {
this.danger("The DID must begin with 'did:'", "Invalid DID");
this.notify.error(NOTIFY_CONTACT_INVALID_DID.message, TIMEOUTS.STANDARD);
return;
}
@@ -869,10 +899,9 @@ export default class ContactsView extends Vue {
if (this.activeDid) {
this.setVisibility(newContact, true, false);
newContact.seesMe = true; // didn't work inside setVisibility
addedMessage =
"They were added, and your activity is visible to them.";
addedMessage = getVisibilitySuccessMessage(newContact.name || "");
} else {
addedMessage = "They were added.";
addedMessage = NOTIFY_CONTACTS_ADDED.message;
}
this.contactInput = "";
if (this.isRegistered) {
@@ -916,20 +945,22 @@ export default class ContactsView extends Vue {
})
.catch((err) => {
const fullError =
"Error when adding contact to storage: " + errorStringForLog(err);
NOTIFY_CONTACT_SETTING_SAVE_ERROR.message +
": " +
errorStringForLog(err);
this.$logAndConsole(fullError, true);
let message = "An error prevented this import.";
let message = NOTIFY_CONTACT_IMPORT_ERROR.message;
if (
err.message?.indexOf("Key already exists in the object store.") > -1
) {
message =
"A contact with that DID is already in your contact list. Edit them directly below.";
NOTIFY_CONTACT_IMPORT_CONFLICT.message +
". Check that the contact doesn't conflict with any you already have.";
}
if (err.name === "ConstraintError") {
message +=
" Check that the contact doesn't conflict with any you already have.";
message += NOTIFY_CONTACT_IMPORT_CONSTRAINT.message;
}
this.danger(message, "Contact Not Added", 5000);
this.notify.error(message, TIMEOUTS.MODAL);
});
}
@@ -949,7 +980,9 @@ export default class ContactsView extends Vue {
await this.$updateContact(contact.did, { registered: true });
this.notify.success(
`${contact.name || "That unnamed person"} ${NOTIFY_REGISTER_PERSON_SUCCESS.message}`,
getRegisterPersonSuccessMessage(
contact.name || "That unnamed person",
),
TIMEOUTS.STANDARD,
);
} else {
@@ -1003,7 +1036,7 @@ export default class ContactsView extends Vue {
//contact.seesMe = visibility; // why doesn't it affect the UI from here?
if (showSuccessAlert) {
this.notify.success(
`${contact.name || "That user"} can ${visibility ? "" : "not "}see your activity.`,
getVisibilitySuccessMessage(contact.name || ""),
TIMEOUTS.STANDARD,
);
}
@@ -1026,22 +1059,14 @@ export default class ContactsView extends Vue {
recipientDid === this.activeDid &&
this.givenToMeUnconfirmed[giverDid] > 0
) {
const isAre = this.givenToMeUnconfirmed[giverDid] == 1 ? "is" : "are";
const hours = this.givenToMeUnconfirmed[giverDid] == 1 ? "hour" : "hours";
const message =
"There " +
isAre +
" " +
this.givenToMeUnconfirmed[giverDid] +
" unconfirmed " +
hours +
" from them." +
" Would you like to confirm some of those hours?";
const message = NOTIFY_UNCONFIRMED_HOURS_DYNAMIC.getMessage(
this.givenToMeUnconfirmed[giverDid],
);
this.$notify(
{
group: "modal",
type: "confirm",
title: NOTIFY_UNCONFIRMED_HOURS.title,
title: NOTIFY_UNCONFIRMED_HOURS_DYNAMIC.title,
text: message,
onNo: async () => {
this.showGiftedDialog(giverDid, recipientDid);
@@ -1120,11 +1145,13 @@ export default class ContactsView extends Vue {
});
} catch (err) {
const fullError =
"Error updating contact-amounts setting: " + errorStringForLog(err);
NOTIFY_CONTACT_SETTING_SAVE_ERROR.message +
": " +
errorStringForLog(err);
this.$logAndConsole(fullError, true);
this.notify.error(
"The setting may not have saved. Try again, maybe after restarting the app.",
TIMEOUTS.LONG,
NOTIFY_CONTACT_SETTING_SAVE_ERROR.message,
TIMEOUTS.MODAL,
);
}
this.showGiveNumbers = newShowValue;
@@ -1167,7 +1194,10 @@ export default class ContactsView extends Vue {
private async copySelectedContacts() {
if (this.contactsSelected.length === 0) {
this.danger("You must select contacts to copy.");
this.notify.error(
NOTIFY_CONTACTS_SELECT_TO_COPY.message,
TIMEOUTS.STANDARD,
);
return;
}
const selectedContactsFull = this.contacts.filter((c) =>
@@ -1197,15 +1227,15 @@ export default class ContactsView extends Vue {
useClipboard()
.copy(contactsJwtUrl)
.then(() => {
this.notify.copied("contact link", TIMEOUTS.STANDARD);
this.notify.success(
NOTIFY_CONTACT_LINK_COPIED.message,
TIMEOUTS.STANDARD,
);
});
}
private showCopySelectionsInfo() {
this.notify.info(
"Contact info will include name, ID, profile image, and public key.",
TIMEOUTS.LONG,
);
this.notify.info(NOTIFY_CONTACT_INFO_COPY.message, TIMEOUTS.LONG);
}
private async showOnboardMeetingDialog() {
@@ -1253,13 +1283,10 @@ export default class ContactsView extends Vue {
}
} catch (error) {
this.$logAndConsole(
"Error checking meeting status:" + errorStringForLog(error),
NOTIFY_MEETING_STATUS_ERROR.message + ": " + errorStringForLog(error),
true,
);
this.danger(
"There was an error checking your meeting status.",
"Meeting Error",
);
this.notify.error(NOTIFY_MEETING_STATUS_ERROR.message, TIMEOUTS.MODAL);
}
}