|
@ -448,8 +448,25 @@ import * as libsUtil from "../libs/util"; |
|
|
import { isGiveAction, retrieveAccountDids } from "../libs/util"; |
|
|
import { isGiveAction, retrieveAccountDids } from "../libs/util"; |
|
|
import TopMessage from "../components/TopMessage.vue"; |
|
|
import TopMessage from "../components/TopMessage.vue"; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* ConfirmGiftView Component |
|
|
|
|
|
* |
|
|
|
|
|
* Displays details about a gift claim and allows users to confirm it if eligible. |
|
|
|
|
|
* Shows gift details including giver, recipient, amount, description, and confirmation status. |
|
|
|
|
|
* Handles visibility of hidden DIDs and provides access to detailed claim information. |
|
|
|
|
|
* |
|
|
|
|
|
* Key features: |
|
|
|
|
|
* - Gift confirmation workflow |
|
|
|
|
|
* - Detailed gift information display |
|
|
|
|
|
* - Confirmation status tracking |
|
|
|
|
|
* - Hidden DID handling |
|
|
|
|
|
* - Claim details expansion |
|
|
|
|
|
*/ |
|
|
@Component({ |
|
|
@Component({ |
|
|
components: { TopMessage, QuickNav }, |
|
|
components: { |
|
|
|
|
|
QuickNav, |
|
|
|
|
|
TopMessage, |
|
|
|
|
|
}, |
|
|
}) |
|
|
}) |
|
|
export default class ConfirmGiftView extends Vue { |
|
|
export default class ConfirmGiftView extends Vue { |
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void; |
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void; |
|
@ -485,94 +502,92 @@ export default class ConfirmGiftView extends Vue { |
|
|
serverUtil = serverUtil; |
|
|
serverUtil = serverUtil; |
|
|
displayAmount = displayAmount; |
|
|
displayAmount = displayAmount; |
|
|
|
|
|
|
|
|
resetThisValues() { |
|
|
/** |
|
|
this.confirmerIdList = []; |
|
|
* Initializes the view with gift claim information |
|
|
this.confsVisibleErrorMessage = ""; |
|
|
* |
|
|
this.confsVisibleToIdList = []; |
|
|
* Workflow: |
|
|
this.giveDetails = undefined; |
|
|
* 1. Retrieves active account settings |
|
|
this.isRegistered = false; |
|
|
* 2. Loads gift claim details from ID in URL |
|
|
this.numConfsNotVisible = 0; |
|
|
* 3. Processes claim information for display |
|
|
this.urlForNewGive = ""; |
|
|
* 4. Checks user's ability to confirm the gift |
|
|
this.veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD; |
|
|
*/ |
|
|
this.veriClaimDump = ""; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async mounted() { |
|
|
async mounted() { |
|
|
this.isLoading = true; |
|
|
this.isLoading = true; |
|
|
|
|
|
try { |
|
|
|
|
|
await this.initializeSettings(); |
|
|
|
|
|
await this.loadClaimFromUrl(); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error in mounted:", error); |
|
|
|
|
|
this.handleMountError(error); |
|
|
|
|
|
} finally { |
|
|
|
|
|
this.isLoading = false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Initializes component settings and user data |
|
|
|
|
|
*/ |
|
|
|
|
|
private async initializeSettings() { |
|
|
const settings = await retrieveSettingsForActiveAccount(); |
|
|
const settings = await retrieveSettingsForActiveAccount(); |
|
|
this.activeDid = settings.activeDid || ""; |
|
|
this.activeDid = settings.activeDid || ""; |
|
|
this.apiServer = settings.apiServer || ""; |
|
|
this.apiServer = settings.apiServer || ""; |
|
|
this.allContacts = await db.contacts.toArray(); |
|
|
this.allContacts = await db.contacts.toArray(); |
|
|
this.isRegistered = settings.isRegistered || false; |
|
|
this.isRegistered = settings.isRegistered || false; |
|
|
|
|
|
|
|
|
this.allMyDids = await retrieveAccountDids(); |
|
|
this.allMyDids = await retrieveAccountDids(); |
|
|
|
|
|
|
|
|
const pathParam = window.location.pathname.substring( |
|
|
// Check share capability |
|
|
"/confirm-gift/".length, |
|
|
|
|
|
); |
|
|
|
|
|
let claimId; |
|
|
|
|
|
if (pathParam) { |
|
|
|
|
|
claimId = decodeURIComponent(pathParam); |
|
|
|
|
|
await this.loadClaim(claimId, this.activeDid); |
|
|
|
|
|
} else { |
|
|
|
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "danger", |
|
|
|
|
|
title: "Error", |
|
|
|
|
|
text: "No claim ID was provided.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// When Chrome compatibility is fixed https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API#api.navigator.canshare |
|
|
// When Chrome compatibility is fixed https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API#api.navigator.canshare |
|
|
// then use this truer check: navigator.canShare && navigator.canShare() |
|
|
// then use this truer check: navigator.canShare && navigator.canShare() |
|
|
this.canShare = !!navigator.share; |
|
|
this.canShare = !!navigator.share; |
|
|
|
|
|
|
|
|
this.isLoading = false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// insert a space before any capital letters except the initial letter |
|
|
|
|
|
// (and capitalize initial letter, just in case) |
|
|
|
|
|
capitalizeAndInsertSpacesBeforeCaps(text: string) { |
|
|
|
|
|
return !text |
|
|
|
|
|
? "" |
|
|
|
|
|
: text[0].toUpperCase() + text.substr(1).replace(/([A-Z])/g, " $1"); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
capitalizeAndInsertSpacesBeforeCapsWithAPrefix(text: string) { |
|
|
/** |
|
|
const word = this.capitalizeAndInsertSpacesBeforeCaps(text); |
|
|
* Loads and processes claim from URL parameters |
|
|
if (word) { |
|
|
*/ |
|
|
// if the word starts with a vowel, use "an" instead of "a" |
|
|
private async loadClaimFromUrl() { |
|
|
const firstLetter = word[0].toLowerCase(); |
|
|
const pathParam = window.location.pathname.substring("/confirm-gift/".length); |
|
|
const vowels = ["a", "e", "i", "o", "u"]; |
|
|
if (!pathParam) { |
|
|
const particle = vowels.includes(firstLetter) ? "an" : "a"; |
|
|
throw new Error("No claim ID was provided."); |
|
|
return particle + " " + word; |
|
|
|
|
|
} else { |
|
|
|
|
|
return ""; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const claimId = decodeURIComponent(pathParam); |
|
|
|
|
|
await this.loadClaim(claimId, this.activeDid); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
totalConfirmers() { |
|
|
/** |
|
|
return ( |
|
|
* Handles errors during component mounting |
|
|
this.numConfsNotVisible + |
|
|
*/ |
|
|
this.confirmerIdList.length + |
|
|
private handleMountError(error: unknown) { |
|
|
this.confsVisibleToIdList.length |
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "danger", |
|
|
|
|
|
title: "Error", |
|
|
|
|
|
text: error instanceof Error ? error.message : "No claim ID was provided.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Isn't there a better way to make this available to the template? |
|
|
/** |
|
|
didInfo(did: string | undefined) { |
|
|
* Loads claim details and associated give information |
|
|
return serverUtil.didInfo( |
|
|
* |
|
|
did, |
|
|
* @param claimId - ID of claim to load |
|
|
this.activeDid, |
|
|
* @param userDid - User's DID |
|
|
this.allMyDids, |
|
|
*/ |
|
|
this.allContacts, |
|
|
private async loadClaim(claimId: string, userDid: string) { |
|
|
); |
|
|
await this.fetchClaimDetails(claimId, userDid); |
|
|
|
|
|
if (this.veriClaim.claimType === "GiveAction") { |
|
|
|
|
|
await this.fetchGiveDetails(claimId, userDid); |
|
|
|
|
|
await this.processGiveDetails(); |
|
|
|
|
|
await this.fetchConfirmerInfo(claimId, userDid); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async loadClaim(claimId: string, userDid: string) { |
|
|
/** |
|
|
|
|
|
* Fetches basic claim details from server |
|
|
|
|
|
*/ |
|
|
|
|
|
private async fetchClaimDetails(claimId: string, userDid: string) { |
|
|
const urlPath = libsUtil.isGlobalUri(claimId) |
|
|
const urlPath = libsUtil.isGlobalUri(claimId) |
|
|
? "/api/claim/byHandle/" |
|
|
? "/api/claim/byHandle/" |
|
|
: "/api/claim/"; |
|
|
: "/api/claim/"; |
|
@ -581,9 +596,7 @@ export default class ConfirmGiftView extends Vue { |
|
|
try { |
|
|
try { |
|
|
const headers = await serverUtil.getHeaders(userDid); |
|
|
const headers = await serverUtil.getHeaders(userDid); |
|
|
const resp = await this.axios.get(url, { headers }); |
|
|
const resp = await this.axios.get(url, { headers }); |
|
|
// resp.data is: |
|
|
|
|
|
// - a Jwt from https://api.endorser.ch/api-docs/ |
|
|
|
|
|
// - with a Give from https://endorser.ch/doc/html/transactions.html#id3 |
|
|
|
|
|
if (resp.status === 200) { |
|
|
if (resp.status === 200) { |
|
|
this.veriClaim = resp.data; |
|
|
this.veriClaim = resp.data; |
|
|
this.veriClaimDump = yaml.dump(this.veriClaim); |
|
|
this.veriClaimDump = yaml.dump(this.veriClaim); |
|
@ -591,210 +604,161 @@ export default class ConfirmGiftView extends Vue { |
|
|
this.veriClaim, |
|
|
this.veriClaim, |
|
|
true, |
|
|
true, |
|
|
); |
|
|
); |
|
|
|
|
|
this.issuerName = this.didInfo(this.veriClaim.issuer); |
|
|
} else { |
|
|
} else { |
|
|
// actually, axios typically throws an error so we never get here |
|
|
throw new Error("Error getting claim: " + resp.status); |
|
|
console.error("Error getting claim:", resp); |
|
|
|
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "danger", |
|
|
|
|
|
title: "Error", |
|
|
|
|
|
text: "There was a problem retrieving that claim.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error getting claim:", error); |
|
|
|
|
|
throw new Error("There was a problem retrieving that claim."); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// retrieve more details on Give, Offer, or Plan |
|
|
/** |
|
|
if (this.veriClaim.claimType !== "GiveAction") { |
|
|
* Fetches detailed give information |
|
|
// no need to go further... this page is for gifts |
|
|
*/ |
|
|
return; |
|
|
private async fetchGiveDetails(claimId: string, userDid: string) { |
|
|
|
|
|
const giveUrl = `${this.apiServer}/api/v2/report/gives?handleId=${encodeURIComponent(claimId)}`; |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
const headers = await serverUtil.getHeaders(userDid); |
|
|
|
|
|
const resp = await this.axios.get(giveUrl, { headers }); |
|
|
|
|
|
|
|
|
|
|
|
if (resp.status === 200) { |
|
|
|
|
|
this.giveDetails = resp.data.data[0]; |
|
|
|
|
|
} else { |
|
|
|
|
|
throw new Error("Error getting detailed give info: " + resp.status); |
|
|
} |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error("Error getting detailed give info:", error); |
|
|
|
|
|
throw new Error("Something went wrong retrieving gift data."); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this.issuerName = this.didInfo(this.veriClaim.issuer); |
|
|
/** |
|
|
|
|
|
* Processes give details and builds URL for new give |
|
|
|
|
|
*/ |
|
|
|
|
|
private async processGiveDetails() { |
|
|
|
|
|
if (!this.giveDetails) return; |
|
|
|
|
|
|
|
|
// use give record when possible since it may include edits |
|
|
this.urlForNewGive = "/gifted-details?"; |
|
|
const giveUrl = |
|
|
this.addGiveDetailsToUrl(); |
|
|
this.apiServer + |
|
|
this.processParticipantInfo(); |
|
|
"/api/v2/report/gives?handleId=" + |
|
|
this.processAdditionalDetails(); |
|
|
encodeURIComponent(this.veriClaim.handleId as string); |
|
|
} |
|
|
const giveHeaders = await serverUtil.getHeaders(userDid); |
|
|
|
|
|
const giveResp = await this.axios.get(giveUrl, { |
|
|
|
|
|
headers: giveHeaders, |
|
|
|
|
|
}); |
|
|
|
|
|
// giveResp.data is a Give from https://api.endorser.ch/api-docs/ |
|
|
|
|
|
if (giveResp.status === 200) { |
|
|
|
|
|
this.giveDetails = giveResp.data.data[0]; |
|
|
|
|
|
} else { |
|
|
|
|
|
console.error("Error getting detailed give info:", giveResp); |
|
|
|
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "danger", |
|
|
|
|
|
title: "Error", |
|
|
|
|
|
text: "Something went wrong retrieving gift data.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// the logic already stops earlier if the claim doesn't exist but this helps with typechecking |
|
|
/** |
|
|
if (!this.giveDetails) { |
|
|
* Adds basic give details to URL |
|
|
return; |
|
|
*/ |
|
|
} |
|
|
private addGiveDetailsToUrl() { |
|
|
|
|
|
if (this.giveDetails?.amount) { |
|
|
|
|
|
this.urlForNewGive += `&amountInput=${encodeURIComponent(String(this.giveDetails.amount))}`; |
|
|
|
|
|
} |
|
|
|
|
|
if (this.giveDetails?.unit) { |
|
|
|
|
|
this.urlForNewGive += `&unitCode=${encodeURIComponent(this.giveDetails.unit)}`; |
|
|
|
|
|
} |
|
|
|
|
|
if (this.giveDetails?.description) { |
|
|
|
|
|
this.urlForNewGive += `&description=${encodeURIComponent(this.giveDetails.description)}`; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this.urlForNewGive = "/gifted-details?"; |
|
|
/** |
|
|
if (this.giveDetails.amount) { |
|
|
* Processes participant (giver/recipient) information |
|
|
this.urlForNewGive += |
|
|
*/ |
|
|
"&amountInput=" + encodeURIComponent(String(this.giveDetails.amount)); |
|
|
private processParticipantInfo() { |
|
|
} |
|
|
if (this.giveDetails?.agentDid) { |
|
|
if (this.giveDetails.unit) { |
|
|
|
|
|
this.urlForNewGive += |
|
|
|
|
|
"&unitCode=" + encodeURIComponent(this.giveDetails.unit); |
|
|
|
|
|
} |
|
|
|
|
|
if (this.giveDetails.description) { |
|
|
|
|
|
this.urlForNewGive += |
|
|
|
|
|
"&description=" + encodeURIComponent(this.giveDetails.description); |
|
|
|
|
|
} |
|
|
|
|
|
this.giverName = this.didInfo(this.giveDetails.agentDid); |
|
|
this.giverName = this.didInfo(this.giveDetails.agentDid); |
|
|
if (this.giveDetails.agentDid) { |
|
|
this.urlForNewGive += `&giverDid=${encodeURIComponent(this.giveDetails.agentDid)}&giverName=${encodeURIComponent(this.giverName)}`; |
|
|
this.urlForNewGive += |
|
|
} |
|
|
"&giverDid=" + |
|
|
if (this.giveDetails?.recipientDid) { |
|
|
encodeURIComponent(this.giveDetails.agentDid) + |
|
|
|
|
|
"&giverName=" + |
|
|
|
|
|
encodeURIComponent(this.giverName); |
|
|
|
|
|
} |
|
|
|
|
|
this.recipientName = this.didInfo(this.giveDetails.recipientDid); |
|
|
this.recipientName = this.didInfo(this.giveDetails.recipientDid); |
|
|
if (this.giveDetails.recipientDid) { |
|
|
this.urlForNewGive += `&recipientDid=${encodeURIComponent(this.giveDetails.recipientDid)}&recipientName=${encodeURIComponent(this.recipientName)}`; |
|
|
this.urlForNewGive += |
|
|
|
|
|
"&recipientDid=" + |
|
|
|
|
|
encodeURIComponent(this.giveDetails.recipientDid) + |
|
|
|
|
|
"&recipientName=" + |
|
|
|
|
|
encodeURIComponent(this.recipientName); |
|
|
|
|
|
} |
|
|
|
|
|
if (this.giveDetails.fullClaim.image) { |
|
|
|
|
|
this.urlForNewGive += |
|
|
|
|
|
"&image=" + encodeURIComponent(this.giveDetails.fullClaim.image); |
|
|
|
|
|
} |
|
|
|
|
|
if ( |
|
|
|
|
|
this.giveDetails.type == "Offer" && |
|
|
|
|
|
this.giveDetails.fulfillsHandleId |
|
|
|
|
|
) { |
|
|
|
|
|
this.urlForNewGive += |
|
|
|
|
|
"&offerId=" + |
|
|
|
|
|
encodeURIComponent(this.giveDetails?.fulfillsHandleId as string); |
|
|
|
|
|
} |
|
|
|
|
|
if (this.giveDetails.fulfillsPlanHandleId) { |
|
|
|
|
|
this.urlForNewGive += |
|
|
|
|
|
"&fulfillsProjectId=" + |
|
|
|
|
|
encodeURIComponent(this.giveDetails.fulfillsPlanHandleId); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// retrieve the list of confirmers |
|
|
|
|
|
const confirmerInfo = await libsUtil.retrieveConfirmerIdList( |
|
|
|
|
|
this.apiServer, |
|
|
|
|
|
claimId, |
|
|
|
|
|
this.veriClaim.issuer, |
|
|
|
|
|
userDid, |
|
|
|
|
|
); |
|
|
|
|
|
if (confirmerInfo) { |
|
|
|
|
|
this.confirmerIdList = confirmerInfo.confirmerIdList; |
|
|
|
|
|
this.confsVisibleToIdList = confirmerInfo.confsVisibleToIdList; |
|
|
|
|
|
this.numConfsNotVisible = confirmerInfo.numConfsNotVisible; |
|
|
|
|
|
} else { |
|
|
|
|
|
this.confsVisibleErrorMessage = |
|
|
|
|
|
"Had problems retrieving confirmations."; |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error: unknown) { |
|
|
|
|
|
const serverError = error as AxiosError; |
|
|
|
|
|
console.error("Error retrieving claim:", serverError); |
|
|
|
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "danger", |
|
|
|
|
|
title: "Error", |
|
|
|
|
|
text: "Something went wrong retrieving claim data.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
confirmConfirmClaim() { |
|
|
/** |
|
|
this.$notify( |
|
|
* Processes additional give details (image, offer, plan) |
|
|
{ |
|
|
*/ |
|
|
group: "modal", |
|
|
private processAdditionalDetails() { |
|
|
type: "confirm", |
|
|
if (this.giveDetails?.fullClaim.image) { |
|
|
title: "Confirm", |
|
|
this.urlForNewGive += `&image=${encodeURIComponent(this.giveDetails.fullClaim.image)}`; |
|
|
text: "Do you personally confirm that this is true?", |
|
|
} |
|
|
onYes: async () => { |
|
|
if (this.giveDetails?.type === "Offer" && this.giveDetails?.fulfillsHandleId) { |
|
|
await this.confirmClaim(); |
|
|
this.urlForNewGive += `&offerId=${encodeURIComponent(this.giveDetails.fulfillsHandleId)}`; |
|
|
}, |
|
|
} |
|
|
}, |
|
|
if (this.giveDetails?.fulfillsPlanHandleId) { |
|
|
-1, |
|
|
this.urlForNewGive += `&fulfillsProjectId=${encodeURIComponent(this.giveDetails.fulfillsPlanHandleId)}`; |
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// similar code is found in ProjectViewView |
|
|
/** |
|
|
async confirmClaim() { |
|
|
* Fetches confirmer information for the claim |
|
|
// similar logic is found in endorser-mobile |
|
|
*/ |
|
|
const goodClaim = serverUtil.removeSchemaContext( |
|
|
private async fetchConfirmerInfo(claimId: string, userDid: string) { |
|
|
serverUtil.removeVisibleToDids( |
|
|
const confirmerInfo = await libsUtil.retrieveConfirmerIdList( |
|
|
serverUtil.addLastClaimOrHandleAsIdIfMissing( |
|
|
|
|
|
this.veriClaim.claim, |
|
|
|
|
|
this.veriClaim.id, |
|
|
|
|
|
this.veriClaim.handleId, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
const confirmationClaim: GenericVerifiableCredential = { |
|
|
|
|
|
"@context": "https://schema.org", |
|
|
|
|
|
"@type": "AgreeAction", |
|
|
|
|
|
object: goodClaim, |
|
|
|
|
|
}; |
|
|
|
|
|
const result = await serverUtil.createAndSubmitClaim( |
|
|
|
|
|
confirmationClaim, |
|
|
|
|
|
this.activeDid, |
|
|
|
|
|
this.apiServer, |
|
|
this.apiServer, |
|
|
this.axios, |
|
|
claimId, |
|
|
|
|
|
this.veriClaim.issuer, |
|
|
|
|
|
userDid, |
|
|
); |
|
|
); |
|
|
if (result.type === "success") { |
|
|
|
|
|
this.$notify( |
|
|
if (confirmerInfo) { |
|
|
{ |
|
|
this.confirmerIdList = confirmerInfo.confirmerIdList; |
|
|
group: "alert", |
|
|
this.confsVisibleToIdList = confirmerInfo.confsVisibleToIdList; |
|
|
type: "success", |
|
|
this.numConfsNotVisible = confirmerInfo.numConfsNotVisible; |
|
|
title: "Success", |
|
|
|
|
|
text: "Confirmation submitted.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
console.error("Got error submitting the confirmation:", result); |
|
|
this.confsVisibleErrorMessage = "Had problems retrieving confirmations."; |
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "danger", |
|
|
|
|
|
title: "Error", |
|
|
|
|
|
text: "There was a problem submitting the confirmation.", |
|
|
|
|
|
}, |
|
|
|
|
|
5000, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
showClaimPage(claimId: string) { |
|
|
/** |
|
|
const route = { |
|
|
* Calculates total number of confirmers for the gift |
|
|
path: "/claim/" + encodeURIComponent(claimId), |
|
|
* Includes both direct confirmers and those visible through network |
|
|
}; |
|
|
* |
|
|
(this.$router as Router).push(route).then(async () => { |
|
|
* @returns Total number of confirmers |
|
|
this.resetThisValues(); |
|
|
*/ |
|
|
await this.loadClaim(claimId, this.activeDid); |
|
|
totalConfirmers(): number { |
|
|
}); |
|
|
return ( |
|
|
|
|
|
this.numConfsNotVisible + |
|
|
|
|
|
this.confirmerIdList.length + |
|
|
|
|
|
this.confsVisibleToIdList.length |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Formats display amount with proper unit |
|
|
|
|
|
* |
|
|
|
|
|
* @param unit - Currency or unit code |
|
|
|
|
|
* @param amount - Numeric amount |
|
|
|
|
|
* @returns Formatted amount string |
|
|
|
|
|
*/ |
|
|
|
|
|
displayAmount(unit: string, amount: number): string { |
|
|
|
|
|
return displayAmount(unit, amount); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Retrieves human-readable name for a DID |
|
|
|
|
|
* Falls back to DID if no name available |
|
|
|
|
|
* |
|
|
|
|
|
* @param did - DID to get name for |
|
|
|
|
|
* @returns Human-readable name |
|
|
|
|
|
*/ |
|
|
|
|
|
didInfo(did: string): string { |
|
|
|
|
|
return serverUtil.didInfo( |
|
|
|
|
|
did, |
|
|
|
|
|
this.activeDid, |
|
|
|
|
|
this.allMyDids, |
|
|
|
|
|
this.allContacts, |
|
|
|
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
copyToClipboard(name: string, text: string) { |
|
|
/** |
|
|
|
|
|
* Copies text to clipboard and shows notification |
|
|
|
|
|
* |
|
|
|
|
|
* @param description - Description of copied content |
|
|
|
|
|
* @param text - Text to copy |
|
|
|
|
|
*/ |
|
|
|
|
|
copyToClipboard(description: string, text: string): void { |
|
|
useClipboard() |
|
|
useClipboard() |
|
|
.copy(text) |
|
|
.copy(text) |
|
|
.then(() => { |
|
|
.then(() => { |
|
@ -803,14 +767,52 @@ export default class ConfirmGiftView extends Vue { |
|
|
group: "alert", |
|
|
group: "alert", |
|
|
type: "toast", |
|
|
type: "toast", |
|
|
title: "Copied", |
|
|
title: "Copied", |
|
|
text: (name || "That") + " was copied to the clipboard.", |
|
|
text: (description || "That") + " was copied to the clipboard.", |
|
|
}, |
|
|
}, |
|
|
2000, |
|
|
2000, |
|
|
); |
|
|
); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
notifyWhyCannotConfirm() { |
|
|
/** |
|
|
|
|
|
* Navigates to claim page for detailed view |
|
|
|
|
|
* |
|
|
|
|
|
* @param claimId - ID of claim to view |
|
|
|
|
|
*/ |
|
|
|
|
|
showClaimPage(claimId: string): void { |
|
|
|
|
|
const route = { |
|
|
|
|
|
path: "/claim/" + encodeURIComponent(claimId), |
|
|
|
|
|
}; |
|
|
|
|
|
(this.$router as Router).push(route).then(async () => { |
|
|
|
|
|
this.resetThisValues(); |
|
|
|
|
|
await this.loadClaim(claimId, this.activeDid); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Initiates claim confirmation process |
|
|
|
|
|
* Verifies user eligibility and handles confirmation workflow |
|
|
|
|
|
*/ |
|
|
|
|
|
async confirmConfirmClaim(): Promise<void> { |
|
|
|
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "modal", |
|
|
|
|
|
type: "confirm", |
|
|
|
|
|
title: "Confirm", |
|
|
|
|
|
text: "Do you personally confirm that this is true?", |
|
|
|
|
|
onYes: async () => { |
|
|
|
|
|
await this.confirmClaim(); |
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
|
|
|
-1, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Notifies user why they cannot confirm the gift |
|
|
|
|
|
* Explains requirements or restrictions preventing confirmation |
|
|
|
|
|
*/ |
|
|
|
|
|
notifyWhyCannotConfirm(): void { |
|
|
libsUtil.notifyWhyCannotConfirm( |
|
|
libsUtil.notifyWhyCannotConfirm( |
|
|
this.$notify, |
|
|
this.$notify, |
|
|
this.isRegistered, |
|
|
this.isRegistered, |
|
@ -821,71 +823,35 @@ export default class ConfirmGiftView extends Vue { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
notifyWhyCannotConfirmBak() { |
|
|
/** |
|
|
if (!this.isRegistered) { |
|
|
* Formats type string for display by adding spaces before capitals |
|
|
this.$notify( |
|
|
* Optionally adds a prefix |
|
|
{ |
|
|
* |
|
|
group: "alert", |
|
|
* @param text - Text to format |
|
|
type: "info", |
|
|
* @param prefix - Optional prefix to add |
|
|
title: "Not Registered", |
|
|
* @returns Formatted string |
|
|
text: "Someone needs to register you before you can contribute.", |
|
|
*/ |
|
|
}, |
|
|
capitalizeAndInsertSpacesBeforeCapsWithAPrefix( |
|
|
3000, |
|
|
text: string, |
|
|
); |
|
|
prefix?: string |
|
|
} else if (!isGiveAction(this.veriClaim)) { |
|
|
): string { |
|
|
this.$notify( |
|
|
const word = this.capitalizeAndInsertSpacesBeforeCaps(text); |
|
|
{ |
|
|
if (word) { |
|
|
group: "alert", |
|
|
// if the word starts with a vowel, use "an" instead of "a" |
|
|
type: "info", |
|
|
const firstLetter = word[0].toLowerCase(); |
|
|
title: "Not A Give", |
|
|
const vowels = ["a", "e", "i", "o", "u"]; |
|
|
text: "This is not a giving action to confirm.", |
|
|
const particle = vowels.includes(firstLetter) ? "an" : "a"; |
|
|
}, |
|
|
return particle + " " + word; |
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
} else if (this.confirmerIdList.includes(this.activeDid)) { |
|
|
|
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "info", |
|
|
|
|
|
title: "Already Confirmed", |
|
|
|
|
|
text: "You already confirmed this claim.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
} else if (this.giveDetails?.issuerDid == this.activeDid) { |
|
|
|
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "info", |
|
|
|
|
|
title: "Cannot Confirm", |
|
|
|
|
|
text: "You cannot confirm this because you issued this claim.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
} else if (serverUtil.containsHiddenDid(this.giveDetails?.fullClaim)) { |
|
|
|
|
|
this.$notify( |
|
|
|
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "info", |
|
|
|
|
|
title: "Cannot Confirm", |
|
|
|
|
|
text: "You cannot confirm this because some people are hidden.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
this.$notify( |
|
|
return ""; |
|
|
{ |
|
|
|
|
|
group: "alert", |
|
|
|
|
|
type: "info", |
|
|
|
|
|
title: "Cannot Confirm", |
|
|
|
|
|
text: "You cannot confirm this claim. There are no other details, but we can help more if you contact us and send us screenshots.", |
|
|
|
|
|
}, |
|
|
|
|
|
3000, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
onClickShareClaim() { |
|
|
/** |
|
|
|
|
|
* Initiates sharing of claim information |
|
|
|
|
|
* Handles share functionality based on platform capabilities |
|
|
|
|
|
*/ |
|
|
|
|
|
async onClickShareClaim(): Promise<void> { |
|
|
this.copyToClipboard("A link to this page", this.windowLocation); |
|
|
this.copyToClipboard("A link to this page", this.windowLocation); |
|
|
window.navigator.share({ |
|
|
window.navigator.share({ |
|
|
title: "Help Connect Me", |
|
|
title: "Help Connect Me", |
|
@ -893,5 +859,23 @@ export default class ConfirmGiftView extends Vue { |
|
|
url: this.windowLocation, |
|
|
url: this.windowLocation, |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
resetThisValues() { |
|
|
|
|
|
this.confirmerIdList = []; |
|
|
|
|
|
this.confsVisibleErrorMessage = ""; |
|
|
|
|
|
this.confsVisibleToIdList = []; |
|
|
|
|
|
this.giveDetails = undefined; |
|
|
|
|
|
this.isRegistered = false; |
|
|
|
|
|
this.numConfsNotVisible = 0; |
|
|
|
|
|
this.urlForNewGive = ""; |
|
|
|
|
|
this.veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD; |
|
|
|
|
|
this.veriClaimDump = ""; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
capitalizeAndInsertSpacesBeforeCaps(text: string) { |
|
|
|
|
|
return !text |
|
|
|
|
|
? "" |
|
|
|
|
|
: text[0].toUpperCase() + text.substr(1).replace(/([A-Z])/g, " $1"); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
</script> |
|
|
</script> |
|
|