From 404a7cbc7140eebc1178072ed17f742662a3a817 Mon Sep 17 00:00:00 2001 From: Jose Olarte III Date: Fri, 1 Aug 2025 11:36:17 +0800 Subject: [PATCH 1/2] Add form field preservation in gifting flow - Preserve description, amount, and unit code when navigating between gifting steps - Add form field props to EntitySelectionStep and GiftedDialog components - Update ContactGiftingView to handle form state persistence in URL parameters --- src/components/EntitySelectionStep.vue | 14 ++++++++++++++ src/components/GiftedDialog.vue | 3 +++ src/views/ContactGiftingView.vue | 24 ++++++++++++++++++++---- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/components/EntitySelectionStep.vue b/src/components/EntitySelectionStep.vue index 2c8008d3..c0c8bf92 100644 --- a/src/components/EntitySelectionStep.vue +++ b/src/components/EntitySelectionStep.vue @@ -136,6 +136,16 @@ export default class EntitySelectionStep extends Vue { @Prop() receiver?: EntityData | null; + /** Form field values to preserve when navigating to "Show All" */ + @Prop({ default: "" }) + description!: string; + + @Prop({ default: "0" }) + amountInput!: string; + + @Prop({ default: "HUR" }) + unitCode!: string; + /** Notification function from parent component */ @Prop() notify?: (notification: NotificationIface, timeout?: number) => void; @@ -228,6 +238,10 @@ export default class EntitySelectionStep extends Vue { stepType: this.stepType, giverEntityType: this.giverEntityType, recipientEntityType: this.recipientEntityType, + // Form field values to preserve + description: this.description, + amountInput: this.amountInput, + unitCode: this.unitCode, ...(this.stepType === "giver" ? { recipientProjectId: this.toProjectId || "", diff --git a/src/components/GiftedDialog.vue b/src/components/GiftedDialog.vue index d86c999f..96538346 100644 --- a/src/components/GiftedDialog.vue +++ b/src/components/GiftedDialog.vue @@ -18,6 +18,9 @@ :to-project-id="toProjectId" :giver="giver" :receiver="receiver" + :description="description" + :amount-input="amountInput" + :unit-code="unitCode" :notify="$notify" @entity-selected="handleEntitySelected" @cancel="cancel" diff --git a/src/views/ContactGiftingView.vue b/src/views/ContactGiftingView.vue index 17235244..13654e43 100644 --- a/src/views/ContactGiftingView.vue +++ b/src/views/ContactGiftingView.vue @@ -102,9 +102,11 @@ export default class ContactGiftingView extends Vue { activeDid = ""; allContacts: Array = []; apiServer = ""; - description = ""; projectId = ""; prompt = ""; + description = ""; + amountInput = "0"; + unitCode = "HUR"; recipientProjectName = ""; recipientProjectImage = ""; recipientProjectHandleId = ""; @@ -143,6 +145,9 @@ export default class ContactGiftingView extends Vue { this.recipientProjectHandleId = (this.$route.query["recipientProjectHandleId"] as string) || ""; this.prompt = (this.$route.query["prompt"] as string) ?? this.prompt; + this.description = (this.$route.query["description"] as string) || ""; + this.amountInput = (this.$route.query["amountInput"] as string) || "0"; + this.unitCode = (this.$route.query["unitCode"] as string) || "HUR"; // Read new context parameters this.stepType = (this.$route.query["stepType"] as string) || "giver"; @@ -182,7 +187,7 @@ export default class ContactGiftingView extends Vue { openDialog(contact?: GiverReceiverInputInfo | "Unnamed") { if (contact === "Unnamed") { - // Special case: Pass undefined to trigger Step 1, but with "Unnamed" pre-selected + // Special case: Handle "Unnamed" contacts for both givers and recipients let recipient: GiverReceiverInputInfo; let giver: GiverReceiverInputInfo | undefined; @@ -226,9 +231,17 @@ export default class ContactGiftingView extends Vue { recipient, undefined, this.prompt, + this.description, + this.amountInput, + this.unitCode, ); - // Immediately select "Unnamed" and move to Step 2 - (this.$refs.giftedDialog as GiftedDialog).selectGiver(); + + // Immediately select "Unnamed" and move to Step 2 based on stepType + if (this.stepType === "giver") { + (this.$refs.giftedDialog as GiftedDialog).selectGiver(); + } else { + (this.$refs.giftedDialog as GiftedDialog).selectRecipient(); + } } else { // Regular case: contact is a GiverReceiverInputInfo let giver: GiverReceiverInputInfo; @@ -276,6 +289,9 @@ export default class ContactGiftingView extends Vue { recipient, undefined, this.prompt, + this.description, + this.amountInput, + this.unitCode, ); } } From e741790d70c38bcf415218b78bd64029f7dc11f2 Mon Sep 17 00:00:00 2001 From: Jose Olarte III Date: Fri, 1 Aug 2025 13:44:28 +0800 Subject: [PATCH 2/2] Fix ClaimView affirm delivery action - Add offer context support to gifting flow - Add offerId prop to EntitySelectionStep for offer fulfillment context - Pass offerId through GiftedDialog to EntitySelectionStep - Update ContactGiftingView to handle offerId from route query parameters - Extract offer details (description, amount, unitCode) for pre-population --- src/components/EntitySelectionStep.vue | 5 ++ src/components/GiftedDialog.vue | 2 + src/views/ClaimView.vue | 80 +++++++++++++++++++++++++- src/views/ContactGiftingView.vue | 8 ++- 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/src/components/EntitySelectionStep.vue b/src/components/EntitySelectionStep.vue index c0c8bf92..185fb929 100644 --- a/src/components/EntitySelectionStep.vue +++ b/src/components/EntitySelectionStep.vue @@ -146,6 +146,10 @@ export default class EntitySelectionStep extends Vue { @Prop({ default: "HUR" }) unitCode!: string; + /** Offer ID for context when fulfilling an offer */ + @Prop({ default: "" }) + offerId!: string; + /** Notification function from parent component */ @Prop() notify?: (notification: NotificationIface, timeout?: number) => void; @@ -242,6 +246,7 @@ export default class EntitySelectionStep extends Vue { description: this.description, amountInput: this.amountInput, unitCode: this.unitCode, + offerId: this.offerId, ...(this.stepType === "giver" ? { recipientProjectId: this.toProjectId || "", diff --git a/src/components/GiftedDialog.vue b/src/components/GiftedDialog.vue index 96538346..d44f0d73 100644 --- a/src/components/GiftedDialog.vue +++ b/src/components/GiftedDialog.vue @@ -21,6 +21,7 @@ :description="description" :amount-input="amountInput" :unit-code="unitCode" + :offer-id="offerId" :notify="$notify" @entity-selected="handleEntitySelected" @cancel="cancel" @@ -233,6 +234,7 @@ export default class GiftedDialog extends Vue { this.giver = giver; this.receiver = receiver; this.offerId = offerId || ""; + console.log("offerId", this.offerId); this.prompt = prompt || ""; this.description = description || ""; this.amountInput = amountInput || "0"; diff --git a/src/views/ClaimView.vue b/src/views/ClaimView.vue index be588b2c..4b7c3879 100644 --- a/src/views/ClaimView.vue +++ b/src/views/ClaimView.vue @@ -199,7 +199,14 @@ /> - +
@@ -549,6 +556,12 @@ export default class ClaimView extends Vue { fulfillsHandleId?: string; } | null = null; detailsForOffer: { fulfillsPlanHandleId?: string } | null = null; + // Project information for fulfillsPlanHandleId + projectInfo: { + name: string; + imageUrl?: string; + issuer: string; + } | null = null; fullClaim = null; fullClaimDump = ""; fullClaimMessage = ""; @@ -674,6 +687,7 @@ export default class ClaimView extends Vue { this.confsVisibleToIdList = []; this.detailsForGive = null; this.detailsForOffer = null; + this.projectInfo = null; this.fullClaim = null; this.fullClaimDump = ""; this.fullClaimMessage = ""; @@ -851,6 +865,14 @@ export default class ClaimView extends Vue { } } + // Load project information if there's a fulfillsPlanHandleId + const planHandleId = + this.detailsForGive?.fulfillsPlanHandleId || + this.detailsForOffer?.fulfillsPlanHandleId; + if (planHandleId) { + await this.loadProjectInfo(planHandleId, userDid); + } + // retrieve the list of confirmers const confirmerInfo = await libsUtil.retrieveConfirmerIdList( this.apiServer, @@ -878,6 +900,33 @@ export default class ClaimView extends Vue { } } + async loadProjectInfo(planHandleId: string, userDid: string) { + const url = + this.apiServer + + "/api/claim/byHandle/" + + encodeURIComponent(planHandleId); + const headers = await serverUtil.getHeaders(userDid); + + try { + const resp = await this.axios.get(url, { headers }); + if (resp.status === 200) { + this.projectInfo = { + name: resp.data.claim?.name || "(no name)", + imageUrl: resp.data.claim?.image, + issuer: resp.data.issuer, + }; + } else { + await this.$logError( + "Error getting project info: " + JSON.stringify(resp), + ); + } + } catch (error: unknown) { + await this.$logError( + "Error retrieving project info: " + JSON.stringify(error), + ); + } + } + async showFullClaim(claimId: string) { const url = this.apiServer + "/api/claim/full/" + encodeURIComponent(claimId); @@ -997,10 +1046,37 @@ export default class ClaimView extends Vue { this.veriClaim as GenericCredWrapper, ), }; + + // Use project info as recipient if available, otherwise use undefined + const recipient = this.projectInfo + ? { + did: + this.detailsForGive?.fulfillsPlanHandleId || + this.detailsForOffer?.fulfillsPlanHandleId, + name: this.projectInfo.name, + handleId: + this.detailsForGive?.fulfillsPlanHandleId || + this.detailsForOffer?.fulfillsPlanHandleId, + image: this.projectInfo.imageUrl, + } + : undefined; + + // Extract offer information from the claim + const offerClaim = this.veriClaim.claim as OfferClaim; + const description = + offerClaim.itemOffered?.description || offerClaim.description; + const amount = + offerClaim.includesObject?.amountOfThisGood?.toString() || "0"; + const unitCode = offerClaim.includesObject?.unitCode || "HUR"; + (this.$refs.customGiveDialog as GiftedDialog).open( giver, - undefined, + recipient, this.veriClaim.handleId, + undefined, // prompt + description, + amount, + unitCode, ); } diff --git a/src/views/ContactGiftingView.vue b/src/views/ContactGiftingView.vue index 13654e43..23bf8fdf 100644 --- a/src/views/ContactGiftingView.vue +++ b/src/views/ContactGiftingView.vue @@ -125,6 +125,7 @@ export default class ContactGiftingView extends Vue { toProjectId = ""; showProjects = false; isFromProjectView = false; + offerId = ""; async created() { this.notify = createNotifyHelpers(this.$notify); @@ -173,6 +174,7 @@ export default class ContactGiftingView extends Vue { (this.$route.query["showProjects"] as string) === "true"; this.isFromProjectView = (this.$route.query["isFromProjectView"] as string) === "true"; + this.offerId = (this.$route.query["offerId"] as string) || ""; // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { @@ -229,13 +231,13 @@ export default class ContactGiftingView extends Vue { (this.$refs.giftedDialog as GiftedDialog).open( giver, recipient, - undefined, + this.offerId, this.prompt, this.description, this.amountInput, this.unitCode, ); - + // Immediately select "Unnamed" and move to Step 2 based on stepType if (this.stepType === "giver") { (this.$refs.giftedDialog as GiftedDialog).selectGiver(); @@ -287,7 +289,7 @@ export default class ContactGiftingView extends Vue { (this.$refs.giftedDialog as GiftedDialog).open( giver, recipient, - undefined, + this.offerId, this.prompt, this.description, this.amountInput,