diff --git a/src/views/DIDView.vue b/src/views/DIDView.vue index 4ff476c..970c18c 100644 --- a/src/views/DIDView.vue +++ b/src/views/DIDView.vue @@ -253,6 +253,17 @@ import { import * as libsUtil from "../libs/util"; import EntityIcon from "../components/EntityIcon.vue"; +/** + * DIDView Component + * + * Displays detailed information about a DID (Decentralized Identifier) entity, including: + * - Basic identity information (name, profile image) + * - Contact management controls (visibility, registration status) + * - Associated claims and their details + * + * The view supports both viewing one's own DID and other contacts' DIDs. + * It provides infinite scrolling for claims and interactive controls for contact management. + */ @Component({ components: { EntityIcon, @@ -287,51 +298,111 @@ export default class DIDView extends Vue { didInfoForContact = didInfoForContact; displayAmount = displayAmount; + /** + * Initializes the view with DID information + * + * Workflow: + * 1. Retrieves active account settings (DID and API server) + * 2. Determines which DID to display from URL params or defaults to active DID + * 3. Loads contact information if available + * 4. Loads associated claims + * 5. Determines if viewing own DID + */ async mounted() { + await this.initializeSettings(); + await this.determineDIDToDisplay(); + if (this.viewingDid) { + await this.loadContactInformation(); + await this.loadClaimsAbout(); + await this.checkIfOwnDID(); + } + } + + /** + * Initializes component settings from active account + */ + private async initializeSettings() { const settings = await retrieveSettingsForActiveAccount(); this.activeDid = settings.activeDid || ""; this.apiServer = settings.apiServer || ""; + } + /** + * Determines which DID to display based on URL parameters + * Falls back to active DID if no parameter provided + */ + private async determineDIDToDisplay() { const pathParam = window.location.pathname.substring("/did/".length); let showDid = pathParam; + if (!showDid) { showDid = this.activeDid; if (showDid) { - this.$notify( - { - group: "alert", - type: "toast", - title: "Your Info", - text: "No user was specified so showing your info.", - }, - 3000, - ); + this.notifyDefaultToActiveDID(); } } + if (showDid) { this.viewingDid = decodeURIComponent(showDid); - this.contactFromDid = await db.contacts.get(this.viewingDid); - if (this.contactFromDid) { - this.contactYaml = yaml.dump(this.contactFromDid); - } - await this.loadClaimsAbout(); + } + } + + /** + * Notifies user that we're showing their DID info by default + */ + private notifyDefaultToActiveDID() { + this.$notify( + { + group: "alert", + type: "toast", + title: "Your Info", + text: "No user was specified so showing your info.", + }, + 3000, + ); + } - const allAccountDids = await libsUtil.retrieveAccountDids(); - this.isMyDid = allAccountDids.includes(this.viewingDid); + /** + * Loads contact information for the viewing DID + * Updates contact YAML representation if contact exists + */ + private async loadContactInformation() { + if (!this.viewingDid) return; + + this.contactFromDid = await db.contacts.get(this.viewingDid); + if (this.contactFromDid) { + this.contactYaml = yaml.dump(this.contactFromDid); } } /** - * Data loader used by infinite scroller - * @param payload is the flag from the InfiniteScroll indicating if it should load - **/ + * Checks if the viewing DID belongs to the current user + */ + private async checkIfOwnDID() { + if (!this.viewingDid) return; + + const allAccountDids = await libsUtil.retrieveAccountDids(); + this.isMyDid = allAccountDids.includes(this.viewingDid); + } + + /** + * Loads additional claims when user scrolls to bottom + * Used by infinite scroll component to implement pagination + * + * @param payload - Boolean indicating if more data should be loaded + */ async loadMoreData(payload: boolean) { if (this.claims.length > 0 && !this.hitEnd && payload) { this.loadClaimsAbout(); } } - // prompt with confirmation if they want to delete a contact + /** + * Prompts user to confirm contact deletion + * Shows additional warning if contact has visibility permissions + * + * @param contact - Contact object to be deleted + */ confirmDeleteContact(contact: Contact) { let message = "Are you sure you want to remove " + @@ -355,6 +426,11 @@ export default class DIDView extends Vue { ); } + /** + * Deletes contact from local database and navigates back to contacts list + * + * @param contact - Contact object to be deleted + */ async deleteContact(contact: Contact) { await db.open(); await db.contacts.delete(contact.did); @@ -370,7 +446,12 @@ export default class DIDView extends Vue { this.$router.push({ name: "contacts" }); } - // confirm to register a new contact + /** + * Prompts user to confirm registering a contact + * Shows additional warning if contact is already registered + * + * @param contact - Contact to be registered + */ async confirmRegister(contact: Contact) { this.$notify( { @@ -392,7 +473,12 @@ export default class DIDView extends Vue { ); } - // note that this is also in ContactView.vue + /** + * Registers a contact with the endorser server + * Updates local database with registration status + * + * @param contact - Contact to register + */ async register(contact: Contact) { this.$notify({ group: "alert", type: "toast", title: "Sent..." }, 1000); @@ -458,6 +544,11 @@ export default class DIDView extends Vue { } } + /** + * Loads claims that involve the viewed DID + * Implements pagination using beforeId parameter + * Updates loading state and hit-end status + */ public async loadClaimsAbout() { if (!this.viewingDid) { console.error("This should never be called without a DID."); @@ -516,6 +607,11 @@ export default class DIDView extends Vue { } } + /** + * Navigates to detailed claim view + * + * @param jwtId - JWT ID of the claim to view + */ onClickLoadClaim(jwtId: string) { const route = { path: "/claim/" + encodeURIComponent(jwtId), @@ -523,6 +619,13 @@ export default class DIDView extends Vue { this.$router.push(route); } + /** + * Extracts and formats claim amount information + * Handles different claim types (GiveAction, Offer) + * + * @param claim - Claim object to process + * @returns Formatted amount string or empty string if no amount + */ public claimAmount(claim: GenericVerifiableCredential) { if (claim.claimType === "GiveAction") { const giveClaim = claim.claim as GiveVerifiableCredential; @@ -551,11 +654,23 @@ export default class DIDView extends Vue { return ""; } + /** + * Extracts claim description + * Falls back to name if no description available + * + * @param claim - Claim to get description from + * @returns Description string or empty string + */ claimDescription(claim: GenericVerifiableCredential) { return claim.claim.name || claim.claim.description || ""; } - // note that this is also in ContactView.vue + /** + * Prompts user to confirm visibility change for a contact + * + * @param contact - Contact to modify visibility for + * @param visibility - New visibility state to set + */ async confirmSetVisibility(contact: Contact, visibility: boolean) { const visibilityPrompt = visibility ? "Are you sure you want to make your activity visible to them?" @@ -577,7 +692,14 @@ export default class DIDView extends Vue { ); } - // note that this is also in ContactView.vue + /** + * Updates contact visibility on server and local database + * + * @param contact - Contact to update visibility for + * @param visibility - New visibility state + * @param showSuccessAlert - Whether to show success notification + * @returns Boolean indicating success + */ async setVisibility( contact: Contact, visibility: boolean, @@ -627,7 +749,12 @@ export default class DIDView extends Vue { } } - // note that this is also in ContactView.vue + /** + * Checks current visibility status of contact on server + * Updates local database with current status + * + * @param contact - Contact to check visibility for + */ async checkVisibility(contact: Contact) { const url = this.apiServer +