From be6ec6745a7326c15a16faed2cf1f11451a26630 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 16 Jan 2024 15:23:40 -0700 Subject: [PATCH] show a 'give' button directly on offers in the ProjectView --- project.task.yaml | 4 +-- src/components/GiftedDialog.vue | 9 ++--- src/libs/endorserServer.ts | 2 ++ src/libs/util.ts | 38 ++++++++++++++++++-- src/main.ts | 2 ++ src/views/ClaimView.vue | 62 ++++++++++++--------------------- src/views/ProjectViewView.vue | 60 +++++++++++++++++++++++++------ 7 files changed, 119 insertions(+), 58 deletions(-) diff --git a/project.task.yaml b/project.task.yaml index c4863b1e9..49db27171 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -1,9 +1,9 @@ tasks: -- make give action executable right from an offer -- make a confirmation action executable right from a give - link to the project claim from the project screen +- supply the projectId to the OfferDialog just like we do with the offerId +- the confirm button on each give on the ProjectViewView page doesn't have all the context of the ClaimView page, so it can show sometimes inappropriately; consider consolidation - choose an agent via a contact chooser (not just copy-paste a DID) - make the "give" on contact screen work like other give (allowing donation vs current blank) - check that 'show more contacts' from the contact-give-list on the project screen includes project ID diff --git a/src/components/GiftedDialog.vue b/src/components/GiftedDialog.vue index 5131782b9..633ff46eb 100644 --- a/src/components/GiftedDialog.vue +++ b/src/components/GiftedDialog.vue @@ -90,7 +90,6 @@ export default class GiftedDialog extends Vue { @Prop message = ""; @Prop projectId = ""; - @Prop offerId = ""; @Prop showGivenToUser = false; activeDid = ""; @@ -103,6 +102,7 @@ export default class GiftedDialog extends Vue { description = ""; givenToUser = false; isTrade = false; + offerId = ""; unitCode = "HUR"; visible = false; @@ -117,8 +117,8 @@ export default class GiftedDialog extends Vue { /* eslint-disable prettier/prettier */ UNIT_LONG: Record = { - "BTC": "BTC", - "ETH": "ETH", + "BTC": "Bitcoin", + "ETH": "Ethereum", "HUR": "hours", "USD": "dollars", }; @@ -152,7 +152,7 @@ export default class GiftedDialog extends Vue { } } - open(giver: GiverInputInfo) { + open(giver?: GiverInputInfo, offerId?: string) { this.description = ""; this.giver = giver || {}; if (!this.giver.name) { @@ -166,6 +166,7 @@ export default class GiftedDialog extends Vue { // if we show "given to user" selection, default checkbox to true this.givenToUser = this.showGivenToUser; this.amountInput = "0"; + this.offerId = offerId || ""; this.visible = true; } diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index 117ca7cdf..ec4a92674 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -76,6 +76,8 @@ export interface GiveServerRecord { export interface OfferServerRecord { amount: number; amountGiven: number; + fullClaim: OfferVerifiableCredential; + handleId: string; offeredByDid: string; recipientDid: string; requirementsMet: boolean; diff --git a/src/libs/util.ts b/src/libs/util.ts index 61f49cebe..2892c247b 100644 --- a/src/libs/util.ts +++ b/src/libs/util.ts @@ -7,6 +7,7 @@ import { accountsDB, db } from "@/db/index"; import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto"; import { GenericServerRecord, containsHiddenDid } from "@/libs/endorserServer"; +import * as serverUtil from "@/libs/endorserServer"; // eslint-disable-next-line @typescript-eslint/no-var-requires const Buffer = require("buffer/").Buffer; @@ -20,23 +21,54 @@ export const isGlobalUri = (uri: string) => { export const ONBOARD_MESSAGE = "1) Check that they have entered their name on the profile page in their device. 2) Add them to your Contacts by scanning with the QR icon that is by the input box. 3) Click the person icon to register them. 4) Have them go to their Contact page and scan your QR to add you to their list."; -export const isConfirmable = (veriClaim: GenericServerRecord) => { +export const giveIsConfirmable = (veriClaim: GenericServerRecord) => { return veriClaim.claimType === "GiveAction"; }; -export const userCanConfirm = ( +/** + * @returns true if the user can confirm the claim + * @param veriClaim is expected to have fields: claim, claimType, and issuer + */ +export const giveRecordTheUserCanConfirm = ( veriClaim: GenericServerRecord, activeDid: string, confirmerIdList: string[] = [], ) => { return ( - isConfirmable(veriClaim) && + giveIsConfirmable(veriClaim) && !confirmerIdList.includes(activeDid) && veriClaim.issuer !== activeDid && !containsHiddenDid(veriClaim.claim) ); }; +/** + * @returns the DID of the person who offered, or undefined if hidden + * @param veriClaim is expected to have fields: claim and issuer + */ +export const offerGiverDid: ( + arg0: GenericServerRecord, +) => string | undefined = (veriClaim) => { + let giver; + if ( + veriClaim.claim.offeredBy?.identifier && + !serverUtil.isHiddenDid(veriClaim.claim.offeredBy.identifier as string) + ) { + giver = veriClaim.claim.offeredBy.identifier; + } else if (veriClaim.issuer && !serverUtil.isHiddenDid(veriClaim.issuer)) { + giver = veriClaim.issuer; + } + return giver; +}; + +/** + * @returns true if the user can fulfill the offer + * @param veriClaim is expected to have fields: claim, claimType, and issuer + */ +export const canFulfillOffer = (veriClaim: GenericServerRecord) => { + return !!(veriClaim.claimType === "Offer" && offerGiverDid(veriClaim)); +}; + /** * Generates a new identity, saves it to the database, and sets it as the active identity. * @return {Promise} with the DID of the new identity diff --git a/src/main.ts b/src/main.ts index 3890eb76f..075126f7e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -39,6 +39,7 @@ import { faGift, faGlobe, faHand, + faHandHoldingHeart, faHouseChimney, faLocationDot, faLongArrowAltLeft, @@ -93,6 +94,7 @@ library.add( faGift, faGlobe, faHand, + faHandHoldingHeart, faHouseChimney, faLocationDot, faLongArrowAltLeft, diff --git a/src/views/ClaimView.vue b/src/views/ClaimView.vue index b65294d33..cd338e205 100644 --- a/src/views/ClaimView.vue +++ b/src/views/ClaimView.vue @@ -47,27 +47,31 @@
- + -
+

Confirmations

Nobody has confirmed this. @@ -148,7 +152,7 @@ You cannot confirm this because you issued this claim, so you already count as confirming it.
-
+
You cannot confirm this because it contains hidden identifiers.
@@ -206,7 +210,7 @@ import { Contact } from "@/db/tables/contacts"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { accessToken } from "@/libs/crypto"; import * as serverUtil from "@/libs/endorserServer"; -import { isConfirmable, userCanConfirm } from "@/libs/util"; +import * as libsUtil from "@/libs/util"; import QuickNav from "@/components/QuickNav.vue"; import EntityIcon from "@/components/EntityIcon.vue"; import { Account } from "@/db/tables/accounts"; @@ -240,9 +244,8 @@ export default class ClaimView extends Vue { veriClaimDump = ""; yaml = yaml; - containsHiddenDid = serverUtil.containsHiddenDid; - isConfirmable = isConfirmable; - userCanConfirm = userCanConfirm; + libsUtil = libsUtil; + serverUtil = serverUtil; async created() { await db.open(); @@ -284,28 +287,6 @@ export default class ClaimView extends Vue { : text[0].toUpperCase() + text.substr(1).replace(/([A-Z])/g, " $1"); } - offerGiverDid(): string | undefined { - let giver; - if ( - this.veriClaim.claim.offeredBy?.identifier && - !serverUtil.isHiddenDid( - this.veriClaim.claim.offeredBy.identifier as string, - ) - ) { - giver = this.veriClaim.claim.offeredBy.identifier; - } else if ( - this.veriClaim.issuer && - !serverUtil.isHiddenDid(this.veriClaim.issuer) - ) { - giver = this.veriClaim.issuer; - } - return giver; - } - - canFulfillOffer() { - return this.veriClaim.claimType === "Offer" && this.offerGiverDid(); - } - totalConfirmers() { return ( this.numConfsNotVisible + @@ -531,11 +512,14 @@ export default class ClaimView extends Vue { } } - openGiftDialog() { + openFulfillGiftDialog() { const giver: GiverInputInfo = { - did: this.offerGiverDid(), + did: libsUtil.offerGiverDid(this.veriClaim), }; - (this.$refs.customGiveDialog as GiftedDialog).open(giver); + (this.$refs.customGiveDialog as GiftedDialog).open( + giver, + this.veriClaim.handleId, + ); } } diff --git a/src/views/ProjectViewView.vue b/src/views/ProjectViewView.vue index beab62d03..3d31bfdda 100644 --- a/src/views/ProjectViewView.vue +++ b/src/views/ProjectViewView.vue @@ -123,7 +123,7 @@
  • @@ -198,12 +198,24 @@
- + {{ offer.objectDescription }}
@@ -243,15 +255,15 @@
- + {{ give.description }}
@@ -359,6 +371,7 @@ export default class ProjectViewView extends Vue { truncateLength = 40; url = ""; + libsUtil = libsUtil; serverUtil = serverUtil; async created() { @@ -370,7 +383,7 @@ export default class ProjectViewView extends Vue { await accountsDB.open(); const accounts = accountsDB.accounts; - const accountsArr = await accounts?.toArray(); + const accountsArr: Account[] = await accounts?.toArray(); this.allMyDids = accountsArr.map((acc) => acc.did); const account = accountsArr.find((acc) => acc.did === this.activeDid); const identity = JSON.parse(account?.identity || "null"); @@ -659,7 +672,7 @@ export default class ProjectViewView extends Vue { ); } - openGiftDialog(contact: GiverInputInfo) { + openGiftDialog(contact?: GiverInputInfo) { (this.$refs.customGiveDialog as GiftedDialog).open(contact); } @@ -674,6 +687,33 @@ export default class ProjectViewView extends Vue { this.$router.push(route); } + checkIsFulfillable(offer: OfferServerRecord) { + const offerRecord: GenericServerRecord = { + ...BLANK_GENERIC_SERVER_RECORD, + claim: offer.fullClaim, + claimType: "Offer", + issuer: offer.offeredByDid, + }; + console.log( + "checking for can fulfill ", + libsUtil.canFulfillOffer(offerRecord), + offerRecord, + ); + return libsUtil.canFulfillOffer(offerRecord); + } + + onClickFulfillGiveToOffer(offer: OfferServerRecord) { + const offerRecord: GenericServerRecord = { + ...BLANK_GENERIC_SERVER_RECORD, + claim: offer.fullClaim, + issuer: offer.offeredByDid, + }; + const giver: GiverInputInfo = { + did: libsUtil.offerGiverDid(offerRecord), + }; + (this.$refs.customGiveDialog as GiftedDialog).open(giver, offer.handleId); + } + UNIT_CODES: Record> = { BTC: { name: "Bitcoin", @@ -728,7 +768,7 @@ export default class ProjectViewView extends Vue { claimType: "GiveAction", issuer: give.agentDid, }; - return libsUtil.userCanConfirm(giveDetails, this.activeDid); + return libsUtil.giveRecordTheUserCanConfirm(giveDetails, this.activeDid); } // similar code is found in ClaimView