Browse Source

start with offer-edit

pull/123/head
Trent Larson 1 month ago
parent
commit
269d00a096
  1. 168
      src/libs/endorserServer.ts
  2. 1
      src/views/GiftedDetails.vue
  3. 624
      src/views/OfferDetails.vue

168
src/libs/endorserServer.ts

@ -48,7 +48,7 @@ export interface ClaimResult {
} }
export interface GenericVerifiableCredential { export interface GenericVerifiableCredential {
"@context"?: string; "@context"?: string; // optional when embedded, eg. in an Agree
"@type": string; "@type": string;
[key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
} }
@ -139,13 +139,13 @@ export interface GiveVerifiableCredential extends GenericVerifiableCredential {
// Note that previous VCs may have additional fields. // Note that previous VCs may have additional fields.
// https://endorser.ch/doc/html/transactions.html#id8 // https://endorser.ch/doc/html/transactions.html#id8
export interface OfferVerifiableCredential { export interface OfferVerifiableCredential extends GenericVerifiableCredential {
"@context"?: string; // optional when embedded, eg. in an Agree "@context"?: string; // optional when embedded... though it doesn't make sense to agree to an offer
"@type": "Offer"; "@type": "Offer";
description?: string; description?: string; // conditions for the offer
includesObject?: { amountOfThisGood: number; unitCode: string }; includesObject?: { amountOfThisGood: number; unitCode: string };
itemOffered?: { itemOffered?: {
description?: string; description?: string; // description of the item
isPartOf?: { identifier?: string; lastClaimId?: string; "@type"?: string }; isPartOf?: { identifier?: string; lastClaimId?: string; "@type"?: string };
}; };
offeredBy?: { identifier: string }; offeredBy?: { identifier: string };
@ -155,7 +155,7 @@ export interface OfferVerifiableCredential {
// Note that previous VCs may have additional fields. // Note that previous VCs may have additional fields.
// https://endorser.ch/doc/html/transactions.html#id7 // https://endorser.ch/doc/html/transactions.html#id7
export interface PlanVerifiableCredential { export interface PlanVerifiableCredential extends GenericVerifiableCredential {
"@context": "https://schema.org"; "@context": "https://schema.org";
"@type": "PlanAction"; "@type": "PlanAction";
name: string; name: string;
@ -563,6 +563,8 @@ export async function setPlanInCache(
/** /**
* Construct GiveAction VC for submission to server * Construct GiveAction VC for submission to server
*
* @param lastClaimId supplied when editing a previous claim
*/ */
export function hydrateGive( export function hydrateGive(
vcClaimOrig?: GiveVerifiableCredential, vcClaimOrig?: GiveVerifiableCredential,
@ -587,6 +589,7 @@ export function hydrateGive(
}; };
if (lastClaimId) { if (lastClaimId) {
// this is an edit
vcClaim.lastClaimId = lastClaimId; vcClaim.lastClaimId = lastClaimId;
delete vcClaim.identifier; delete vcClaim.identifier;
} }
@ -594,16 +597,17 @@ export function hydrateGive(
vcClaim.agent = fromDid ? { identifier: fromDid } : undefined; vcClaim.agent = fromDid ? { identifier: fromDid } : undefined;
vcClaim.recipient = toDid ? { identifier: toDid } : undefined; vcClaim.recipient = toDid ? { identifier: toDid } : undefined;
vcClaim.description = description || undefined; vcClaim.description = description || undefined;
vcClaim.object = amount vcClaim.object =
? { amountOfThisGood: amount, unitCode: unitCode || "HUR" } amount && !isNaN(amount)
: undefined; ? { amountOfThisGood: amount, unitCode: unitCode || "HUR" }
: undefined;
// ensure fulfills is an array // ensure fulfills is an array
if (!Array.isArray(vcClaim.fulfills)) { if (!Array.isArray(vcClaim.fulfills)) {
vcClaim.fulfills = vcClaim.fulfills ? [vcClaim.fulfills] : []; vcClaim.fulfills = vcClaim.fulfills ? [vcClaim.fulfills] : [];
} }
// ... and replace or add each element, ending with Trade or Donate // ... and replace or add each element, ending with Trade or Donate
// I realize this doesn't change any elements that are not PlanAction or Offer or Trade/Action. // I realize the following doesn't change any elements that are not PlanAction or Offer or Trade/Action.
vcClaim.fulfills = vcClaim.fulfills.filter( vcClaim.fulfills = vcClaim.fulfills.filter(
(elem) => elem["@type"] !== "PlanAction", (elem) => elem["@type"] !== "PlanAction",
); );
@ -639,8 +643,8 @@ export function hydrateGive(
* *
* @param fromDid may be null * @param fromDid may be null
* @param toDid * @param toDid
* @param description may be null; should have this or amount * @param description may be null
* @param amount may be null; should have this or description * @param amount may be null
*/ */
export async function createAndSubmitGive( export async function createAndSubmitGive(
axios: Axios, axios: Axios,
@ -667,6 +671,7 @@ export async function createAndSubmitGive(
fulfillsOfferHandleId, fulfillsOfferHandleId,
isTrade, isTrade,
imageUrl, imageUrl,
undefined,
); );
return createAndSubmitClaim( return createAndSubmitClaim(
vcClaim as GenericVerifiableCredential, vcClaim as GenericVerifiableCredential,
@ -680,9 +685,9 @@ export async function createAndSubmitGive(
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim * For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
* *
* @param fromDid may be null * @param fromDid may be null
* @param toDid * @param toDid may be null if project is provided
* @param description may be null; should have this or amount * @param description may be null
* @param amount may be null; should have this or description * @param amount may be null
*/ */
export async function editAndSubmitGive( export async function editAndSubmitGive(
axios: Axios, axios: Axios,
@ -720,13 +725,69 @@ export async function editAndSubmitGive(
); );
} }
/**
* Construct Offer VC for submission to server
*
* @param lastClaimId supplied when editing a previous claim
*/
export function hydrateOffer(
vcClaimOrig?: OfferVerifiableCredential,
fromDid?: string,
toDid?: string,
conditionDescription?: string,
amount?: number,
unitCode?: string,
offeringDescription?: string,
fulfillsProjectHandleId?: string,
validThrough?: string,
lastClaimId?: string,
): OfferVerifiableCredential {
// Remember: replace values or erase if it's null
const vcClaim: OfferVerifiableCredential = vcClaimOrig
? R.clone(vcClaimOrig)
: {
"@context": SCHEMA_ORG_CONTEXT,
"@type": "Offer",
};
if (lastClaimId) {
// this is an edit
vcClaim.lastClaimId = lastClaimId;
delete vcClaim.identifier;
}
vcClaim.offeredBy = fromDid ? { identifier: fromDid } : undefined;
vcClaim.recipient = toDid ? { identifier: toDid } : undefined;
vcClaim.description = conditionDescription || undefined;
vcClaim.includesObject =
amount && !isNaN(amount)
? { amountOfThisGood: amount, unitCode: unitCode || "HUR" }
: undefined;
if (offeringDescription || fulfillsProjectHandleId) {
vcClaim.itemOffered = vcClaim.itemOffered || {};
vcClaim.itemOffered.description = offeringDescription || undefined;
if (fulfillsProjectHandleId) {
vcClaim.itemOffered.isPartOf = {
"@type": "PlanAction",
identifier: fulfillsProjectHandleId,
};
}
}
vcClaim.validThrough = validThrough || undefined;
return vcClaim;
}
/** /**
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim * For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
* *
* @param identity * @param identity
* @param description may be null; should have this or amount * @param description may be null
* @param amount may be null; should have this or description * @param amount may be null
* @param expirationDate ISO 8601 date string YYYY-MM-DD (may be null) * @param validThrough ISO 8601 date string YYYY-MM-DD (may be null)
* @param fulfillsProjectHandleId ID of project to which this contributes (may be null) * @param fulfillsProjectHandleId ID of project to which this contributes (may be null)
*/ */
export async function createAndSubmitOffer( export async function createAndSubmitOffer(
@ -736,35 +797,54 @@ export async function createAndSubmitOffer(
description?: string, description?: string,
amount?: number, amount?: number,
unitCode?: string, unitCode?: string,
expirationDate?: string, validThrough?: string,
recipientDid?: string, recipientDid?: string,
fulfillsProjectHandleId?: string, fulfillsProjectHandleId?: string,
): Promise<CreateAndSubmitClaimResult> { ): Promise<CreateAndSubmitClaimResult> {
const vcClaim: OfferVerifiableCredential = { const vcClaim = hydrateOffer(
"@context": SCHEMA_ORG_CONTEXT, undefined,
"@type": "Offer", issuerDid,
offeredBy: { identifier: issuerDid }, recipientDid,
validThrough: expirationDate || undefined, description,
}; amount,
if (amount) { unitCode,
vcClaim.includesObject = { description,
amountOfThisGood: amount, fulfillsProjectHandleId,
unitCode: unitCode || "HUR", validThrough,
}; undefined,
} );
if (description) { return createAndSubmitClaim(
vcClaim.itemOffered = { description }; vcClaim as OfferVerifiableCredential,
} issuerDid,
if (recipientDid) { apiServer,
vcClaim.recipient = { identifier: recipientDid }; axios,
} );
if (fulfillsProjectHandleId) { }
vcClaim.itemOffered = vcClaim.itemOffered || {};
vcClaim.itemOffered.isPartOf = { export async function editAndSubmitOffer(
"@type": "PlanAction", axios: Axios,
identifier: fulfillsProjectHandleId, apiServer: string,
}; fullClaim: GenericCredWrapper<OfferVerifiableCredential>,
} issuerDid: string,
description?: string,
amount?: number,
unitCode?: string,
validThrough?: string,
recipientDid?: string,
fulfillsProjectHandleId?: string,
): Promise<CreateAndSubmitClaimResult> {
const vcClaim = hydrateOffer(
fullClaim.claim,
issuerDid,
recipientDid,
description,
amount,
unitCode,
description,
fulfillsProjectHandleId,
validThrough,
fullClaim.id,
);
return createAndSubmitClaim( return createAndSubmitClaim(
vcClaim as OfferVerifiableCredential, vcClaim as OfferVerifiableCredential,
issuerDid, issuerDid,

1
src/views/GiftedDetails.vue

@ -694,7 +694,6 @@ export default class GiftedDetails extends Vue {
constructGiveParam() { constructGiveParam() {
const recipientDid = this.givenToRecipient ? this.recipientDid : undefined; const recipientDid = this.givenToRecipient ? this.recipientDid : undefined;
const projectId = this.givenToProject ? this.projectId : undefined; const projectId = this.givenToProject ? this.projectId : undefined;
// const giveClaim = constructGive(
const giveClaim = hydrateGive( const giveClaim = hydrateGive(
this.prevCredToEdit?.claim as GiveVerifiableCredential, this.prevCredToEdit?.claim as GiveVerifiableCredential,
this.giverDid, this.giverDid,

624
src/views/OfferDetails.vue

@ -0,0 +1,624 @@
<template>
<QuickNav />
<TopMessage />
<!-- CONTENT -->
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
<!-- Back -->
<div
v-if="!hideBackButton"
class="text-lg text-center font-light relative px-7"
>
<h1
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="cancelBack()"
>
<fa icon="chevron-left" class="fa-fw"></fa>
</h1>
</div>
<!-- Heading -->
<h1 class="text-4xl text-center font-light px-4 mb-4">What Was Offered</h1>
<h1 class="text-xl font-bold text-center mb-4">
<span>From {{ giverName }}</span>
<span>
to
{{
offeredToProject
? projectName
: offeredToRecipient
? recipientName
: "someone unidentified"
}}</span
>
</h1>
<textarea
class="block w-full rounded border border-slate-400 mb-2 px-3 py-2"
placeholder="What was offered"
v-model="description"
/>
<div class="flex flex-row justify-center">
<span
class="rounded-l border border-r-0 border-slate-400 bg-slate-200 text-center text-blue-500 px-2 py-2 w-20"
@click="changeUnitCode()"
>
{{ libsUtil.UNIT_SHORT[unitCode] || unitCode }}
</span>
<div
class="border border-r-0 border-slate-400 bg-slate-200 px-4 py-2"
@click="amountInput === '0' ? null : decrement()"
>
<fa icon="chevron-left" />
</div>
<input
type="number"
class="border border-r-0 border-slate-400 px-2 py-2 text-center w-20"
v-model="amountInput"
/>
<div
class="rounded-r border border-slate-400 bg-slate-200 px-4 py-2"
@click="increment()"
>
<fa icon="chevron-right" />
</div>
</div>
<div class="h-7 mt-4 flex">
<input
v-if="projectId && !offeredToRecipient"
type="checkbox"
class="h-6 w-6 mr-2"
v-model="offeredToProject"
/>
<fa
v-else
icon="square"
class="bg-slate-500 text-slate-500 h-5 w-5 px-0.5 py-0.5 mr-2 rounded"
@click="notifyUserOfProject()"
/>
<label class="text-sm mt-1">
{{
projectId
? "This was given to " + projectName
: "No project was chosen"
}}
</label>
</div>
<div class="h-7 mt-4 flex">
<input
v-if="recipientDid && !offeredToProject"
type="checkbox"
class="h-6 w-6 mr-2"
v-model="offeredToRecipient"
/>
<fa
v-else
icon="square"
class="bg-slate-500 text-slate-500 h-5 w-5 px-0.5 py-0.5 mr-2 rounded"
@click="notifyUserOfRecipient()"
/>
<label class="text-sm mt-1">
{{
recipientDid
? "This was given to " + recipientName
: "No recipient was chosen."
}}
</label>
</div>
<div class="mt-4 flex">
<router-link
:to="{
name: 'claim-add-raw',
query: {
claim: constructOfferParam(),
},
}"
class="text-blue-500"
>
Edit & Submit Raw
</router-link>
</div>
<p class="text-center mb-2 mt-6 italic">
Sign & Send to publish to the world
<fa
icon="circle-info"
class="pl-2 text-blue-500 cursor-pointer"
@click="explainData()"
/>
</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
<button
class="block w-full text-center text-md uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md"
@click="cancel"
>
Cancel
</button>
</div>
</section>
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import {
createAndSubmitOffer,
didInfo,
editAndSubmitOffer,
GenericCredWrapper,
getPlanFromCache,
hydrateOffer,
OfferVerifiableCredential,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { Contact } from "@/db/tables/contacts";
@Component({
components: {
QuickNav,
TopMessage,
},
})
export default class OfferDetails extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
activeDid = "";
apiServer = "";
amountInput = "0";
description = "";
destinationPathAfter = "";
offeredToProject = false;
offeredToRecipient = false;
giverDid: string | undefined;
giverName = "";
hideBackButton = false;
isTrade = false;
message = "";
offerId = "";
prevCredToEdit?: GenericCredWrapper<OfferVerifiableCredential>;
projectId = "";
projectName = "a project";
recipientDid = "";
recipientName = "";
unitCode = "HUR";
validThroughDate = null;
libsUtil = libsUtil;
async mounted() {
try {
this.prevCredToEdit = (this.$route as Router).query["prevCredToEdit"]
? (JSON.parse(
(this.$route as Router).query["prevCredToEdit"],
) as GenericCredWrapper<OfferVerifiableCredential>)
: undefined;
} catch (error) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Retrieval Error",
text: "The previous record isn't available for editing. If you submit, you'll create a new record.",
},
6000,
);
}
const prevAmount = this.prevCredToEdit?.claim?.object?.amountOfThisGood;
this.amountInput =
(this.$route as Router).query["amountInput"] ||
(prevAmount ? String(prevAmount) : "") ||
this.amountInput;
this.description =
(this.$route as Router).query["description"] ||
this.prevCredToEdit?.claim?.description ||
this.description;
this.destinationPathAfter = (this.$route as Router).query[
"destinationPathAfter"
];
this.giverDid = ((this.$route as Router).query["giverDid"] ||
this.prevCredToEdit?.claim?.agent?.identifier ||
this.giverDid) as string;
this.giverName =
((this.$route as Router).query["giverName"] as string) || "";
this.hideBackButton =
(this.$route as Router).query["hideBackButton"] === "true";
this.message = ((this.$route as Router).query["message"] as string) || "";
// find any offer ID
const fulfills = this.prevCredToEdit?.claim?.fulfills;
const fulfillsArray = Array.isArray(fulfills)
? fulfills
: fulfills
? [fulfills]
: [];
const offer = fulfillsArray.find((rec) => rec["@type"] === "Offer");
this.offerId = ((this.$route as Router).query["offerId"] ||
offer?.identifier ||
this.offerId) as string;
// find any project ID
const project = fulfillsArray.find((rec) => rec["@type"] === "PlanAction");
this.projectId = ((this.$route as Router).query["projectId"] ||
project?.identifier ||
this.projectId) as string;
this.recipientDid = ((this.$route as Router).query["recipientDid"] ||
this.prevCredToEdit?.claim?.recipient?.identifier) as string;
this.recipientName =
((this.$route as Router).query["recipientName"] as string) || "";
this.unitCode = ((this.$route as Router).query["unitCode"] ||
this.prevCredToEdit?.claim?.object?.unitCode ||
this.unitCode) as string;
// this is an endpoint for sharing project info to highlight something given
// https://developer.mozilla.org/en-US/docs/Web/Manifest/share_target
if ((this.$route as Router).query["shareTitle"]) {
this.description =
((this.$route as Router).query["shareTitle"] as string) +
(this.description ? "\n" + this.description : "");
}
if ((this.$route as Router).query["shareText"]) {
this.description =
(this.description ? this.description + "\n" : "") +
((this.$route as Router).query["shareText"] as string);
}
if ((this.$route as Router).query["shareUrl"]) {
this.imageUrl = (this.$route as Router).query["shareUrl"] as string;
}
try {
await db.open();
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
this.apiServer = settings?.apiServer || "";
this.activeDid = settings?.activeDid || "";
let allContacts: Contact[] = [];
let allMyDids: string[] = [];
if (
(this.giverDid && !this.giverName) ||
(this.recipientDid && !this.recipientName)
) {
allContacts = await db.contacts.toArray();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
allMyDids = allAccounts.map((acc) => acc.did);
if (this.giverDid && !this.giverName) {
this.giverName = didInfo(
this.giverDid,
this.activeDid,
allMyDids,
allContacts,
);
}
if (this.recipientDid && !this.recipientName) {
this.recipientName = didInfo(
this.recipientDid,
this.activeDid,
allMyDids,
allContacts,
);
}
}
this.offeredToProject = !!this.projectId;
this.offeredToRecipient = !this.offeredToProject && !!this.recipientDid;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
console.error("Error retrieving settings from database:", err);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: err.message || "There was an error retrieving your settings.",
},
-1,
);
}
if (this.projectId) {
// console.log("Getting project name from cache", this.projectId);
const project = await getPlanFromCache(
this.projectId,
this.axios,
this.apiServer,
this.activeDid,
);
this.projectName = project?.name
? "the project: " + project.name
: "a project";
}
}
changeUnitCode() {
const units = Object.keys(this.libsUtil.UNIT_SHORT);
const index = units.indexOf(this.unitCode);
this.unitCode = units[(index + 1) % units.length];
}
increment() {
this.amountInput = `${(parseFloat(this.amountInput) || 0) + 1}`;
}
decrement() {
this.amountInput = `${Math.max(
0,
(parseFloat(this.amountInput) || 1) - 1,
)}`;
}
cancel() {
if (this.destinationPathAfter) {
(this.$router as Router).push({ path: this.destinationPathAfter });
} else {
(this.$router as Router).back();
}
}
cancelBack() {
(this.$router as Router).back();
}
async confirm() {
if (!this.activeDid) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: "You must select an identifier before you can record a offer.",
},
2000,
);
return;
}
if (parseFloat(this.amountInput) < 0) {
this.$notify(
{
group: "alert",
type: "danger",
text: "You may not send a negative number.",
title: "",
},
2000,
);
return;
}
if (!this.description && !parseFloat(this.amountInput)) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: `You must enter a description or some number of ${
this.libsUtil.UNIT_LONG[this.unitCode]
}.`,
},
2000,
);
return;
}
this.$notify(
{
group: "alert",
type: "toast",
text: "Recording the give...",
title: "",
},
1000,
);
// this is asynchronous, but we don't need to wait for it to complete
await this.recordOffer();
}
notifyUserOfProject() {
if (!this.projectId) {
this.$notify(
{
group: "alert",
type: "warning",
title: "Error",
text: "To assign to a project, you must open this dialog through a project.",
},
3000,
);
} else {
// must be because offeredToRecipient is true
this.$notify(
{
group: "alert",
type: "warning",
title: "Error",
text: "You cannot assign both to a project and to a recipient.",
},
3000,
);
}
}
notifyUserOfRecipient() {
if (!this.recipientDid) {
this.$notify(
{
group: "alert",
type: "warning",
title: "Error",
text: "To assign to a recipient, you must open this dialog from a contact.",
},
3000,
);
} else {
// must be because offeredToProject is true
this.$notify(
{
group: "alert",
type: "warning",
title: "Error",
text: "You cannot assign both to a recipient and to a project.",
},
3000,
);
}
}
/**
*
* @param giverDid may be null
* @param description may be an empty string
* @param amountInput may be 0
* @param unitCode may be omitted, defaults to "HUR"
*/
public async recordOffer() {
try {
const recipientDid = this.offeredToRecipient
? this.recipientDid
: undefined;
const projectId = this.offeredToProject ? this.projectId : undefined;
let result;
if (this.prevCredToEdit) {
// don't create from a blank one in case some properties were set from a different interface
result = await editAndSubmitOffer(
this.axios,
this.apiServer,
this.prevCredToEdit,
this.activeDid,
this.description,
parseFloat(this.amountInput),
this.unitCode,
this.validThroughDate,
recipientDid,
projectId,
);
} else {
result = await createAndSubmitOffer(
this.axios,
this.apiServer,
this.activeDid,
this.description,
parseFloat(this.amountInput),
this.unitCode,
this.validThroughDate,
recipientDid,
projectId,
);
}
if (result.type === "error" || this.isCreationError(result.response)) {
const errorMessage = this.getCreationErrorMessage(result);
console.error("Error with give creation result:", result);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: errorMessage || "There was an error creating the give.",
},
-1,
);
} else {
this.$notify(
{
group: "alert",
type: "success",
title: "Success",
text: `That ${this.isTrade ? "trade" : "gift"} was recorded.`,
},
5000,
);
localStorage.removeItem("imageUrl");
if (this.destinationPathAfter) {
(this.$router as Router).push({ path: this.destinationPathAfter });
} else {
(this.$router as Router).back();
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error("Error with give recordation caught:", error);
const errorMessage =
error.userMessage ||
error.response?.data?.error?.message ||
"There was an error recording the give.";
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: errorMessage,
},
-1,
);
}
}
constructOfferParam() {
const recipientDid = this.offeredToRecipient
? this.recipientDid
: undefined;
const projectId = this.offeredToProject ? this.projectId : undefined;
const giveClaim = hydrateOffer(
this.prevCredToEdit?.claim as OfferVerifiableCredential,
this.activeDid,
recipientDid,
this.description,
parseFloat(this.amountInput),
this.unitCode,
"",
projectId,
this.validThroughDate,
this.prevCredToEdit?.id as string,
);
const claimStr = JSON.stringify(giveClaim);
return claimStr;
}
// Helper functions for readability
/**
* @param result response "data" from the server
* @returns true if the result indicates an error
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isCreationError(result: any) {
return result.status !== 201 || result.data?.error;
}
/**
* @param result direct response eg. ErrorResult or SuccessResult (potentially with embedded "data")
* @returns best guess at an error message
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getCreationErrorMessage(result: any) {
return (
result.error?.userMessage ||
result.error?.error ||
result.response?.data?.error?.message
);
}
explainData() {
this.$notify(
{
group: "alert",
type: "success",
title: "Data Sharing",
text: libsUtil.PRIVACY_MESSAGE,
},
-1,
);
}
}
</script>
Loading…
Cancel
Save