+
@@ -275,9 +363,10 @@ import OfferDialog from "../components/OfferDialog.vue";
import ContactNameDialog from "../components/ContactNameDialog.vue";
import TopMessage from "../components/TopMessage.vue";
import { APP_SERVER, AppString, NotificationIface } from "../constants/app";
-// Removed legacy logging import - migrated to PlatformServiceMixin
+import { logConsoleAndDb } from "../db/index";
import { Contact } from "../db/tables/contacts";
-// Removed unused import: databaseUtil - migrated to PlatformServiceMixin
+// No longer needed - using PlatformServiceMixin methods
+// import * as databaseUtil from "../db/databaseUtil";
import { getContactJwtFromJwtUrl } from "../libs/crypto";
import { decodeEndorserJwt } from "../libs/crypto/vc";
import {
@@ -292,42 +381,29 @@ import {
CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI,
CONTACT_URL_PATH_ENDORSER_CH_OLD,
} from "../libs/endorserServer";
+import { GiveSummaryRecord } from "@/interfaces/records";
+import { UserInfo } from "@/interfaces/common";
+import { VerifiableCredential } from "@/interfaces/claims-result";
import * as libsUtil from "../libs/util";
import { generateSaveAndActivateIdentity } from "../libs/util";
import { logger } from "../utils/logger";
+// No longer needed - using PlatformServiceMixin methods
+// import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
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_PERSON_ERROR,
- NOTIFY_VISIBILITY_ERROR,
- NOTIFY_UNCONFIRMED_HOURS_DYNAMIC,
- NOTIFY_REGISTER_CONTACT,
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_CONTACTS_ADDED_VISIBLE,
NOTIFY_CONTACTS_ADDED,
NOTIFY_CONTACT_INFO_COPY,
NOTIFY_CONTACTS_SELECT_TO_COPY,
- NOTIFY_CONTACT_LINK_COPIED,
- getRegisterPersonSuccessMessage,
- getVisibilitySuccessMessage,
} from "@/constants/notifications";
@Component({
@@ -346,6 +422,7 @@ export default class ContactsView extends Vue {
$route!: RouteLocationNormalizedLoaded;
$router!: Router;
+ /** Notification helpers */
notify!: ReturnType
;
activeDid = "";
@@ -381,98 +458,29 @@ export default class ContactsView extends Vue {
AppString = AppString;
libsUtil = libsUtil;
- // Computed properties for template simplification
- get allContactsSelected(): boolean {
- return this.contactsSelected.length === this.contacts.length;
- }
-
- get copyButtonClass(): string {
- return this.contactsSelected.length > 0 ? "btn-primary" : "btn-disabled";
- }
-
- get giveAmountsButtonClass(): string {
- return this.showGiveTotals
- ? "from-green-400 to-green-700"
- : this.showGiveConfirmed
- ? "from-blue-400 to-blue-700"
- : "from-yellow-400 to-yellow-700";
- }
-
- get giveAmountsButtonText(): string {
- return this.showGiveTotals
- ? "Totals"
- : this.showGiveConfirmed
- ? "Confirmed Amounts"
- : "Unconfirmed Amounts";
- }
-
- // Methods for template simplification
- showNotRegisteredWarning(): void {
- this.notify.warning(NOTIFY_REGISTER_NOT_AVAILABLE.message, TIMEOUTS.LONG);
- }
-
- toggleAllContacts(): void {
- if (this.contactsSelected.length === this.contacts.length) {
- this.contactsSelected = [];
- } else {
- this.contactsSelected = this.contacts.map((contact) => contact.did);
- }
- }
-
- toggleContact(did: string): void {
- const index = this.contactsSelected.indexOf(did);
- if (index > -1) {
- this.contactsSelected.splice(index, 1);
- } else {
- this.contactsSelected.push(did);
- }
- }
-
- getGiveAmount(contactDid: string, direction: "toMe" | "byMe"): number {
- const confirmedMap =
- direction === "toMe" ? this.givenToMeConfirmed : this.givenByMeConfirmed;
- const unconfirmedMap =
- direction === "toMe"
- ? this.givenToMeUnconfirmed
- : this.givenByMeUnconfirmed;
-
- if (this.showGiveTotals) {
- return (
- (confirmedMap[contactDid] || 0) + (unconfirmedMap[contactDid] || 0)
- );
- } else if (this.showGiveConfirmed) {
- return confirmedMap[contactDid] || 0;
- } else {
- return unconfirmedMap[contactDid] || 0;
- }
- }
-
public async created() {
this.notify = createNotifyHelpers(this.$notify);
- const settingsRow = await this.$getSettingsRow([
- "activeDid",
- "apiServer",
- "isRegistered",
- "showContactGivesInline",
- "hideRegisterPromptOnNewContact",
- ]);
- this.activeDid = (settingsRow?.[0] as string) || "";
- this.apiServer = (settingsRow?.[1] as string) || "";
- this.isRegistered = !!settingsRow?.[2];
+ // Replace databaseUtil.retrieveSettingsForActiveAccount() with mixin method
+ const settings = await this.$accountSettings();
+ this.activeDid = settings.activeDid || "";
+ this.apiServer = settings.apiServer || "";
+ this.isRegistered = !!settings.isRegistered;
// if these detect a query parameter, they can and then redirect to this URL without a query parameter
// to avoid problems when they reload or they go forward & back and it tries to reprocess
await this.processContactJwt();
await this.processInviteJwt();
- this.showGiveNumbers = !!settingsRow?.[3];
- this.hideRegisterPromptOnNewContact = !!settingsRow?.[4];
+ this.showGiveNumbers = !!settings.showContactGivesInline;
+ this.hideRegisterPromptOnNewContact =
+ !!settings.hideRegisterPromptOnNewContact;
if (this.showGiveNumbers) {
this.loadGives();
}
+ // Replace PlatformServiceFactory and manual SQL with mixin method
this.contacts = await this.$getAllContacts();
}
@@ -505,7 +513,15 @@ 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.error(NOTIFY_BLANK_INVITE.message, TIMEOUTS.VERY_LONG);
+ 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,
+ );
} else if (importedInviteJwt) {
// make sure user is created
if (!this.activeDid) {
@@ -522,11 +538,17 @@ export default class ContactsView extends Vue {
if (response.status != 201) {
throw { error: { response: response } };
}
- await this.$updateSettings({ isRegistered: true }, this.activeDid);
+ // Replace databaseUtil.updateDidSpecificSettings with mixin method
+ await this.$saveUserSettings(this.activeDid, { isRegistered: true });
this.isRegistered = true;
- this.notify.success(
- NOTIFY_INVITE_REGISTRATION_SUCCESS.message,
- TIMEOUTS.STANDARD,
+ this.$notify(
+ {
+ group: "alert",
+ type: "success",
+ title: "Registered",
+ text: "You are now registered.",
+ },
+ 3000,
);
// wait for a second before continuing so they see the registration message
@@ -536,19 +558,14 @@ export default class ContactsView extends Vue {
// (similar code is in InviteOneAcceptView.vue)
const payload: JWTPayload =
decodeEndorserJwt(importedInviteJwt).payload;
- const registration = payload as VerifiableCredentialClaim;
- const agentIdentifier = (
- registration as {
- vc?: { credentialSubject?: { agent?: { identifier?: string } } };
- }
- ).vc?.credentialSubject?.agent?.identifier;
+ const registration = payload as VerifiableCredential;
(this.$refs.contactNameDialog as ContactNameDialog).open(
"Who Invited You?",
"",
async (name) => {
await this.addContact({
- did: agentIdentifier ?? "",
- name: name ?? "",
+ did: (registration.vc.credentialSubject.agent as any).identifier,
+ name: name,
registered: true,
});
// wait for a second before continuing so they see the user-added message
@@ -558,7 +575,7 @@ export default class ContactsView extends Vue {
async () => {
// on cancel, will still add the contact
await this.addContact({
- did: agentIdentifier ?? "",
+ did: (registration.vc.credentialSubject.agent as any).identifier,
name: "(person who invited you)",
registered: true,
});
@@ -567,25 +584,33 @@ export default class ContactsView extends Vue {
this.showOnboardingInfo();
},
);
- } catch (error: unknown) {
- const err = error as {
- response?: { data?: { error?: { message?: string } } };
- message?: string;
- };
- let message: string = NOTIFY_INVITE_ERROR.message;
- if (err.response && err.response.data && err.response.data.error) {
- if (err.response.data.error.message) {
- message = err.response.data.error.message;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (error: any) {
+ const fullError = "Error redeeming invite: " + errorStringForLog(error);
+ logConsoleAndDb(fullError, true);
+ let message = "Got an error sending the invite.";
+ if (
+ error.response &&
+ error.response.data &&
+ error.response.data.error
+ ) {
+ if (error.response.data.error.message) {
+ message = error.response.data.error.message;
} else {
- message =
- typeof err.response.data.error === "string"
- ? err.response.data.error
- : JSON.stringify(err.response.data.error);
+ message = error.response.data.error;
}
- } else if (typeof err.message === "string") {
- message = err.message;
+ } else if (error.message) {
+ message = error.message;
}
- this.notify.error(message, TIMEOUTS.MODAL);
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error with Invite",
+ text: message,
+ },
+ -1,
+ );
}
// if we're here, they haven't redirected anywhere, so we'll redirect here without a query parameter
this.$router.push({ path: "/contacts" });
@@ -596,17 +621,20 @@ export default class ContactsView extends Vue {
return (contactName || AppString.NO_CONTACT_NAME).replace(/\s/g, "\u00A0");
}
- private danger(message: string, _title: string = "Error", timeout = 5000) {
- this.notify.error(message, timeout);
- }
+ // Legacy danger() and warning() methods removed - now using this.notify.error() and this.notify.warning()
private showOnboardingInfo() {
- this.notify.confirm(
- NOTIFY_ONBOARDING_CONFIRM.message,
- async () => {
- this.$router.push({ name: "home" });
+ 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" });
+ },
},
- TIMEOUTS.MODAL,
+ -1,
);
}
@@ -655,13 +683,23 @@ export default class ContactsView extends Vue {
resp.status,
resp.data,
);
- const message = `Got an error retrieving your ${useRecipient ? "given" : "received"} data from the server.`;
- this.notify.error(message, TIMEOUTS.STANDARD);
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Retrieval Error",
+ text:
+ "Got an error retrieving your " +
+ (useRecipient ? "given" : "received") +
+ " data from the server.",
+ },
+ 3000,
+ );
}
};
try {
- const headers = await getHeaders(this.activeDid, this.$notify);
+ const headers = await getHeaders(this.activeDid);
const givenByUrl =
this.apiServer +
"/api/v2/report/gives?agentDid=" +
@@ -705,65 +743,47 @@ export default class ContactsView extends Vue {
this.givenToMeUnconfirmed = givenToMeUnconfirmed;
} catch (error) {
const fullError = "Error loading gives: " + errorStringForLog(error);
- this.$logAndConsole(fullError, true);
- this.notify.error(NOTIFY_GIVES_LOAD_ERROR.message, TIMEOUTS.STANDARD);
+ logConsoleAndDb(fullError, true);
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Load Error",
+ text: "Got an error loading your gives.",
+ },
+ 3000,
+ );
}
}
private async onClickNewContact(): Promise {
const contactInput = this.contactInput.trim();
if (!contactInput) {
- 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.notify.error(
- NOTIFY_CONTACT_INVALID_URL.message,
- TIMEOUTS.STANDARD,
- );
- return;
- }
- const { payload } = decodeEndorserJwt(jwt);
- const userInfo = payload["own"] as UserInfo;
- const newContact = {
- did: userInfo.did || payload["iss"], // "did" is reliable as of v 0.3.49
- name: userInfo.name,
- nextPubKeyHashB64: userInfo.nextPublicEncKeyHash,
- profileImageUrl: userInfo.profileImageUrl,
- publicKeyBase64: userInfo.publicEncKey,
- registered: userInfo.registered,
- } as Contact;
- await this.addContact(newContact);
+ // Use notification helper and constant
+ this.notify.error(NOTIFY_CONTACT_NO_INFO.message);
return;
}
if (
+ contactInput.includes(CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI) ||
contactInput.includes(CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI) ||
contactInput.includes(CONTACT_URL_PATH_ENDORSER_CH_OLD)
) {
const jwt = getContactJwtFromJwtUrl(contactInput);
- if (!jwt) {
- this.notify.error(
- NOTIFY_CONTACT_INVALID_URL.message,
- TIMEOUTS.STANDARD,
- );
+ if (jwt) {
+ const { payload } = decodeEndorserJwt(jwt);
+ const userInfo = payload["own"] as UserInfo;
+ const newContact = {
+ did: userInfo.did || payload["iss"], // "did" is reliable as of v 0.3.49
+ name: userInfo.name,
+ nextPubKeyHashB64: userInfo.nextPublicEncKeyHash,
+ profileImageUrl: userInfo.profileImageUrl,
+ publicKeyBase64: userInfo.publicEncKey,
+ registered: userInfo.registered,
+ } as Contact;
+ await this.addContact(newContact);
return;
}
- const { payload } = decodeEndorserJwt(jwt);
- const userInfo = payload["own"] as UserInfo;
- const newContact = {
- did: userInfo.did || payload["iss"], // "did" is reliable as of v 0.3.49
- name: userInfo.name,
- nextPubKeyHashB64: userInfo.nextPublicEncKeyHash,
- profileImageUrl: userInfo.profileImageUrl,
- publicKeyBase64: userInfo.publicEncKey,
- registered: userInfo.registered,
- } as Contact;
- await this.addContact(newContact);
- return;
}
if (contactInput.startsWith(CONTACT_CSV_HEADER)) {
@@ -777,22 +797,25 @@ export default class ContactsView extends Vue {
}
try {
await Promise.all(lineAdded);
- this.notify.success(
- NOTIFY_CONTACTS_ADDED_CSV.message,
- TIMEOUTS.STANDARD,
+ 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
);
} catch (e) {
const fullError =
- NOTIFY_CONTACTS_ADD_ERROR.message + ": " + errorStringForLog(e);
- this.$logAndConsole(fullError, true);
- this.notify.error(
- NOTIFY_CONTACT_INPUT_PARSE_ERROR.message,
- TIMEOUTS.STANDARD,
- );
+ "Error adding contacts from CSV: " + errorStringForLog(e);
+ logConsoleAndDb(fullError, true);
+ // Use notification helper and constant
+ this.notify.error(NOTIFY_CONTACTS_ADD_ERROR.message);
}
+ // Replace PlatformServiceFactory query with mixin method
this.contacts = await this.$getAllContacts();
-
return;
}
@@ -851,120 +874,142 @@ export default class ContactsView extends Vue {
});
} catch (e) {
const fullError =
- NOTIFY_CONTACT_INPUT_PARSE_ERROR.message +
- ": " +
- errorStringForLog(e);
- this.$logAndConsole(fullError, true);
- this.notify.error(
- NOTIFY_CONTACT_NO_CONTACT_FOUND.message,
- TIMEOUTS.STANDARD,
- );
+ "Error adding contacts from array: " + errorStringForLog(e);
+ logConsoleAndDb(fullError, true);
+ // Use notification helper and constant
+ this.notify.error("The input could not be parsed.");
}
return;
}
- this.notify.error(NOTIFY_CONTACT_NO_INFO.message, TIMEOUTS.STANDARD);
+ // Use notification helper and constant
+ this.notify.error("No contact info was found in that input.");
}
private async addContactFromEndorserMobileLine(
lineRaw: string,
): Promise {
const newContact = libsUtil.csvLineToContact(lineRaw);
+ // Replace PlatformServiceFactory with mixin method
await this.$insertContact(newContact);
- return newContact.did || "";
+ // Return the DID as the indexable type for compatibility
+ return newContact.did as IndexableType;
}
private async addContact(newContact: Contact) {
if (!newContact.did) {
- this.notify.error(NOTIFY_CONTACT_NO_DID.message, TIMEOUTS.STANDARD);
+ // Use notification helper and constant
+ this.notify.error(NOTIFY_CONTACT_NO_DID.message);
return;
}
if (!isDid(newContact.did)) {
- this.notify.error(NOTIFY_CONTACT_INVALID_DID.message, TIMEOUTS.STANDARD);
+ // Use notification helper and constant
+ this.notify.error(NOTIFY_CONTACT_INVALID_DID.message);
return;
}
- const contactPromise = this.$insertContact(newContact);
+ // Replace PlatformServiceFactory with mixin method
+ try {
+ await this.$insertContact(newContact);
- return contactPromise
- .then(() => {
- const allContacts = this.contacts.concat([newContact]);
- this.contacts = R.sort(
- (a: Contact, b) => (a.name || "").localeCompare(b.name || ""),
- allContacts,
- );
- let addedMessage;
- if (this.activeDid) {
- this.setVisibility(newContact, true, false);
- newContact.seesMe = true; // didn't work inside setVisibility
- addedMessage = getVisibilitySuccessMessage(newContact.name || "");
- } else {
- addedMessage = NOTIFY_CONTACTS_ADDED.message;
- }
- this.contactInput = "";
- if (this.isRegistered) {
- if (!this.hideRegisterPromptOnNewContact && !newContact.registered) {
- setTimeout(() => {
- this.$notify(
- {
- group: "modal",
- type: "confirm",
- title: NOTIFY_REGISTER_CONTACT.title,
- text: NOTIFY_REGISTER_CONTACT.text,
- onCancel: async (stopAsking?: boolean) => {
- if (stopAsking) {
- await this.$updateSettings({
- hideRegisterPromptOnNewContact: stopAsking,
- });
-
- this.hideRegisterPromptOnNewContact = stopAsking;
- }
- },
- onNo: async (stopAsking?: boolean) => {
- if (stopAsking) {
- await this.$updateSettings({
- hideRegisterPromptOnNewContact: stopAsking,
- });
-
- this.hideRegisterPromptOnNewContact = stopAsking;
- }
- },
- onYes: async () => {
- await this.register(newContact);
- },
- promptToStopAsking: true,
+ const allContacts = this.contacts.concat([newContact]);
+ this.contacts = R.sort(
+ (a: Contact, b) => (a.name || "").localeCompare(b.name || ""),
+ allContacts,
+ );
+ let addedMessage;
+ if (this.activeDid) {
+ this.setVisibility(newContact, true, false);
+ newContact.seesMe = true; // didn't work inside setVisibility
+ addedMessage = NOTIFY_CONTACTS_ADDED_VISIBLE.message;
+ } else {
+ addedMessage = NOTIFY_CONTACTS_ADDED.message;
+ }
+ this.contactInput = "";
+ if (this.isRegistered) {
+ if (!this.hideRegisterPromptOnNewContact && !newContact.registered) {
+ setTimeout(() => {
+ this.$notify(
+ {
+ group: "modal",
+ type: "confirm",
+ title: "Register",
+ text: "Do you want to register them?",
+ onCancel: async (stopAsking?: boolean) => {
+ if (stopAsking) {
+ // Replace databaseUtil.updateDefaultSettings with mixin method
+ await this.$saveSettings({
+ hideRegisterPromptOnNewContact: stopAsking,
+ });
+ this.hideRegisterPromptOnNewContact = stopAsking;
+ }
},
- TIMEOUTS.MODAL,
- );
- }, 1000);
- }
- }
- this.notify.success(addedMessage, TIMEOUTS.STANDARD);
- })
- .catch((err) => {
- const fullError =
- NOTIFY_CONTACT_SETTING_SAVE_ERROR.message +
- ": " +
- errorStringForLog(err);
- this.$logAndConsole(fullError, true);
- let message = NOTIFY_CONTACT_IMPORT_ERROR.message;
- if (
- err.message?.indexOf("Key already exists in the object store.") > -1
- ) {
- message =
- NOTIFY_CONTACT_IMPORT_CONFLICT.message +
- ". Check that the contact doesn't conflict with any you already have.";
- }
- if (err.name === "ConstraintError") {
- message += NOTIFY_CONTACT_IMPORT_CONSTRAINT.message;
+ onNo: async (stopAsking?: boolean) => {
+ if (stopAsking) {
+ // Replace databaseUtil.updateDefaultSettings with mixin method
+ await this.$saveSettings({
+ hideRegisterPromptOnNewContact: stopAsking,
+ });
+ this.hideRegisterPromptOnNewContact = stopAsking;
+ }
+ },
+ onYes: async () => {
+ await this.register(newContact);
+ },
+ promptToStopAsking: true,
+ },
+ -1,
+ );
+ }, 1000);
}
- this.notify.error(message, TIMEOUTS.MODAL);
- });
+ }
+ // Use notification helper and constant
+ this.notify.success(addedMessage);
+ } catch (err) {
+ const fullError =
+ "Error when adding contact to storage: " + errorStringForLog(err);
+ logConsoleAndDb(fullError, true);
+ let message = NOTIFY_CONTACT_IMPORT_ERROR.message;
+ if (
+ (err as any).message?.indexOf(
+ "Key already exists in the object store.",
+ ) > -1
+ ) {
+ message = NOTIFY_CONTACT_IMPORT_CONFLICT.message;
+ }
+ if ((err as any).name === "ConstraintError") {
+ message += " " + NOTIFY_CONTACT_IMPORT_CONSTRAINT.message;
+ }
+ // Use notification helper and constant
+ this.notify.error(message, TIMEOUTS.LONG);
+ }
+ }
+
+ // note that this is also in DIDView.vue
+ private async confirmSetVisibility(contact: Contact, visibility: boolean) {
+ const visibilityPrompt = visibility
+ ? "Are you sure you want to make your activity visible to them?"
+ : "Are you sure you want to hide all your activity from them?";
+ this.$notify(
+ {
+ group: "modal",
+ type: "confirm",
+ title: "Set Visibility",
+ text: visibilityPrompt,
+ onYes: async () => {
+ const success = await this.setVisibility(contact, visibility, true);
+ if (success) {
+ contact.seesMe = visibility; // didn't work inside setVisibility
+ }
+ },
+ },
+ -1,
+ );
}
// note that this is also in DIDView.vue
private async register(contact: Contact) {
- this.notify.sent(TIMEOUTS.BRIEF);
+ this.$notify({ group: "alert", type: "toast", title: "Sent..." }, 1000);
try {
const regResult = await register(
@@ -975,23 +1020,35 @@ export default class ContactsView extends Vue {
);
if (regResult.success) {
contact.registered = true;
+ // Replace PlatformServiceFactory with mixin method
await this.$updateContact(contact.did, { registered: true });
- this.notify.success(
- getRegisterPersonSuccessMessage(
- contact.name || "That unnamed person",
- ),
- TIMEOUTS.STANDARD,
+ this.$notify(
+ {
+ group: "alert",
+ type: "success",
+ title: "Registration Success",
+ text:
+ (contact.name || "That unnamed person") + " has been registered.",
+ },
+ 3000,
);
} else {
- this.notify.error(
- (regResult.error as string) || NOTIFY_REGISTER_PERSON_ERROR.message,
- TIMEOUTS.MODAL,
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Registration Error",
+ text:
+ (regResult.error as string) ||
+ "Something went wrong during registration.",
+ },
+ -1,
);
}
} catch (error) {
const fullError = "Error when registering: " + errorStringForLog(error);
- this.$logAndConsole(fullError, true);
+ logConsoleAndDb(fullError, true);
let userMessage = "There was an error.";
const serverError = error as AxiosError;
if (serverError.isAxiosError) {
@@ -1013,7 +1070,15 @@ export default class ContactsView extends Vue {
userMessage = error as string;
}
// Now set that error for the user to see.
- this.notify.error(userMessage, TIMEOUTS.MODAL);
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Registration Error",
+ text: userMessage,
+ },
+ -1,
+ );
}
}
@@ -1033,9 +1098,18 @@ 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.success(
- getVisibilitySuccessMessage(contact.name || ""),
- TIMEOUTS.STANDARD,
+ this.$notify(
+ {
+ group: "alert",
+ type: "success",
+ title: "Visibility Set",
+ text:
+ (contact.name || "That user") +
+ " can " +
+ (visibility ? "" : "not ") +
+ "see your activity.",
+ },
+ 3000,
);
}
return true;
@@ -1045,8 +1119,16 @@ export default class ContactsView extends Vue {
result,
);
const message =
- (result.error as string) || NOTIFY_VISIBILITY_ERROR.message;
- this.notify.error(message, TIMEOUTS.LONG);
+ (result.error as string) || "Could not set visibility on the server.";
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error Setting Visibility",
+ text: message,
+ },
+ 5000,
+ );
return false;
}
}
@@ -1057,14 +1139,22 @@ export default class ContactsView extends Vue {
recipientDid === this.activeDid &&
this.givenToMeUnconfirmed[giverDid] > 0
) {
- const message = NOTIFY_UNCONFIRMED_HOURS_DYNAMIC.getMessage(
- this.givenToMeUnconfirmed[giverDid],
- );
+ 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?";
this.$notify(
{
group: "modal",
type: "confirm",
- title: NOTIFY_UNCONFIRMED_HOURS_DYNAMIC.title,
+ title: "Delete",
text: message,
onNo: async () => {
this.showGiftedDialog(giverDid, recipientDid);
@@ -1076,7 +1166,7 @@ export default class ContactsView extends Vue {
});
},
},
- TIMEOUTS.MODAL,
+ -1,
);
} else {
this.showGiftedDialog(giverDid, recipientDid);
@@ -1138,18 +1228,18 @@ export default class ContactsView extends Vue {
private async toggleShowContactAmounts() {
const newShowValue = !this.showGiveNumbers;
try {
- await this.$updateSettings({
+ // Replace databaseUtil.updateDefaultSettings with mixin method
+ await this.$saveSettings({
showContactGivesInline: newShowValue,
});
} catch (err) {
const fullError =
- NOTIFY_CONTACT_SETTING_SAVE_ERROR.message +
- ": " +
- errorStringForLog(err);
- this.$logAndConsole(fullError, true);
+ "Error updating contact-amounts setting: " + errorStringForLog(err);
+ logConsoleAndDb(fullError, true);
+ // Use notification helper and constant
this.notify.error(
NOTIFY_CONTACT_SETTING_SAVE_ERROR.message,
- TIMEOUTS.MODAL,
+ TIMEOUTS.LONG,
);
}
this.showGiveNumbers = newShowValue;
@@ -1192,10 +1282,8 @@ export default class ContactsView extends Vue {
private async copySelectedContacts() {
if (this.contactsSelected.length === 0) {
- this.notify.error(
- NOTIFY_CONTACTS_SELECT_TO_COPY.message,
- TIMEOUTS.STANDARD,
- );
+ // Use notification helper and constant
+ this.notify.error(NOTIFY_CONTACTS_SELECT_TO_COPY.message);
return;
}
const selectedContactsFull = this.contacts.filter((c) =>
@@ -1225,87 +1313,65 @@ export default class ContactsView extends Vue {
useClipboard()
.copy(contactsJwtUrl)
.then(() => {
- this.notify.success(
- NOTIFY_CONTACT_LINK_COPIED.message,
- TIMEOUTS.STANDARD,
- );
+ // Use notification helper
+ this.notify.copied("contact link");
});
}
private showCopySelectionsInfo() {
+ // Use notification helper and constant
this.notify.info(NOTIFY_CONTACT_INFO_COPY.message, TIMEOUTS.LONG);
}
private async showOnboardMeetingDialog() {
- console.log("🪑 DEBUG: showOnboardMeetingDialog() called");
- console.log("🪑 DEBUG: activeDid =", this.activeDid);
- console.log("🪑 DEBUG: apiServer =", this.apiServer);
- console.log("🪑 DEBUG: isRegistered =", this.isRegistered);
-
- if (!this.activeDid || !this.apiServer) {
- console.log(
- "🪑 DEBUG: Missing activeDid or apiServer, routing to meeting list",
- );
- this.$router.push({ name: "onboard-meeting-list" });
- return;
- }
-
try {
- console.log("🪑 DEBUG: Checking if user is in a meeting as member...");
+ // First check if they're in a meeting
const headers = await getHeaders(this.activeDid);
- console.log("🪑 DEBUG: Headers obtained:", headers);
-
const memberResponse = await this.axios.get(
this.apiServer + "/api/partner/groupOnboardMember",
{ headers },
);
- console.log("🪑 DEBUG: Member response:", memberResponse.data);
- if (memberResponse.data?.data?.groupId) {
- console.log(
- "🪑 DEBUG: User is in a meeting as member, checking if host...",
- );
+ if (memberResponse.data.data) {
+ // They're in a meeting, check if they're the host
const hostResponse = await this.axios.get(
this.apiServer + "/api/partner/groupOnboard",
{ headers },
);
- console.log("🪑 DEBUG: Host response:", hostResponse.data);
- if (hostResponse.data?.data?.groupId) {
- console.log("🪑 DEBUG: User is HOST, routing to setup");
+ if (hostResponse.data.data) {
+ // They're the host, take them to setup
this.$router.push({ name: "onboard-meeting-setup" });
} else {
- console.log("🪑 DEBUG: User is MEMBER, routing to members view");
- this.$router.push({
- name: "onboard-meeting-members",
- params: { groupId: memberResponse.data.data.groupId },
- });
+ // They're not the host, take them to list
+ this.$router.push({ name: "onboard-meeting-list" });
}
} else {
- console.log("🪑 DEBUG: User is NOT in a meeting, checking if host...");
- const hostResponse = await this.axios.get(
- this.apiServer + "/api/partner/groupOnboard",
- { headers },
+ // They're not in a meeting, show the dialog
+ this.$notify(
+ {
+ group: "modal",
+ type: "confirm",
+ title: "Onboarding Meeting",
+ text: "Would you like to start a new meeting?",
+ onYes: async () => {
+ this.$router.push({ name: "onboard-meeting-setup" });
+ },
+ yesText: "Start New Meeting",
+ onNo: async () => {
+ this.$router.push({ name: "onboard-meeting-list" });
+ },
+ noText: "Join Existing Meeting",
+ },
+ -1,
);
- console.log("🪑 DEBUG: Host response (no member):", hostResponse.data);
-
- if (hostResponse.data?.data?.groupId) {
- console.log(
- "🪑 DEBUG: User is HOST with no member record, routing to setup",
- );
- this.$router.push({ name: "onboard-meeting-setup" });
- } else {
- console.log(
- "🪑 DEBUG: User has NO meeting, routing to setup to CREATE",
- );
- this.$router.push({ name: "onboard-meeting-setup" });
- }
}
- } catch (error: any) {
- console.log("🪑 DEBUG: Error in API calls:", error);
- console.log("🪑 DEBUG: Error response:", error.response?.data);
- console.log("🪑 DEBUG: Routing to meeting list due to error");
- this.$router.push({ name: "onboard-meeting-list" });
+ } catch (error) {
+ logConsoleAndDb(
+ "Error checking meeting status:" + errorStringForLog(error),
+ );
+ // Use notification helper
+ this.notify.error("There was an error checking your meeting status.");
}
}
@@ -1318,149 +1384,3 @@ export default class ContactsView extends Vue {
}
}
-
-