add ability to edit a GiveAction
This commit is contained in:
@@ -291,8 +291,8 @@ export default class GiftedDialog extends Vue {
|
|||||||
this.axios,
|
this.axios,
|
||||||
this.apiServer,
|
this.apiServer,
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
giverDid,
|
giverDid as string,
|
||||||
this.receiver?.did as string,
|
recipientDid as string,
|
||||||
description,
|
description,
|
||||||
amount,
|
amount,
|
||||||
unitCode,
|
unitCode,
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export async function createEndorserJwtForKey(
|
|||||||
* The SimpleSigner returns a configured function for signing data.
|
* The SimpleSigner returns a configured function for signing data.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const signer = SimpleSigner(import.meta.env.PRIVATE_KEY)
|
* const signer = SimpleSigner(privateKeyHexString)
|
||||||
* signer(data, (err, signature) => {
|
* signer(data, (err, signature) => {
|
||||||
* ...
|
* ...
|
||||||
* })
|
* })
|
||||||
|
|||||||
@@ -48,24 +48,26 @@ export interface ClaimResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface GenericVerifiableCredential {
|
export interface GenericVerifiableCredential {
|
||||||
"@context": string;
|
"@context"?: string;
|
||||||
"@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
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GenericCredWrapper extends GenericVerifiableCredential {
|
export interface GenericCredWrapper<T extends GenericVerifiableCredential> {
|
||||||
|
"@context": string;
|
||||||
|
"@type": string;
|
||||||
handleId: string;
|
handleId: string;
|
||||||
id: string;
|
id: string;
|
||||||
issuedAt: string;
|
issuedAt: string;
|
||||||
issuer: string;
|
issuer: string;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
claim: T;
|
||||||
claim: Record<string, any>;
|
|
||||||
claimType?: string;
|
claimType?: string;
|
||||||
}
|
}
|
||||||
export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper = {
|
export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper<GenericVerifiableCredential> =
|
||||||
|
{
|
||||||
"@context": SCHEMA_ORG_CONTEXT,
|
"@context": SCHEMA_ORG_CONTEXT,
|
||||||
"@type": "",
|
"@type": "",
|
||||||
claim: {},
|
claim: { "@type": "" },
|
||||||
handleId: "",
|
handleId: "",
|
||||||
id: "",
|
id: "",
|
||||||
issuedAt: "",
|
issuedAt: "",
|
||||||
@@ -123,7 +125,7 @@ export interface PlanSummaryRecord {
|
|||||||
|
|
||||||
// Note that previous VCs may have additional fields.
|
// Note that previous VCs may have additional fields.
|
||||||
// https://endorser.ch/doc/html/transactions.html#id4
|
// https://endorser.ch/doc/html/transactions.html#id4
|
||||||
export interface GiveVerifiableCredential {
|
export interface GiveVerifiableCredential extends GenericVerifiableCredential {
|
||||||
"@context"?: string; // optional when embedded, eg. in an Agree
|
"@context"?: string; // optional when embedded, eg. in an Agree
|
||||||
"@type": "GiveAction";
|
"@type": "GiveAction";
|
||||||
agent?: { identifier: string };
|
agent?: { identifier: string };
|
||||||
@@ -191,7 +193,7 @@ export interface PlanData {
|
|||||||
*/
|
*/
|
||||||
issuerDid: string;
|
issuerDid: string;
|
||||||
/**
|
/**
|
||||||
* The Identier of the project -- different from jwtId, needs to be fixed
|
* The identifier of the project -- different from jwtId, needs to be fixed
|
||||||
**/
|
**/
|
||||||
rowid?: string;
|
rowid?: string;
|
||||||
}
|
}
|
||||||
@@ -562,8 +564,9 @@ export async function setPlanInCache(
|
|||||||
/**
|
/**
|
||||||
* Construct GiveAction VC for submission to server
|
* Construct GiveAction VC for submission to server
|
||||||
*/
|
*/
|
||||||
export function constructGive(
|
export function hydrateGive(
|
||||||
fromDid?: string | null,
|
vcClaimOrig?: GiveVerifiableCredential,
|
||||||
|
fromDid?: string,
|
||||||
toDid?: string,
|
toDid?: string,
|
||||||
description?: string,
|
description?: string,
|
||||||
amount?: number,
|
amount?: number,
|
||||||
@@ -572,42 +575,68 @@ export function constructGive(
|
|||||||
fulfillsOfferHandleId?: string,
|
fulfillsOfferHandleId?: string,
|
||||||
isTrade: boolean = false,
|
isTrade: boolean = false,
|
||||||
imageUrl?: string,
|
imageUrl?: string,
|
||||||
|
lastClaimId?: string,
|
||||||
): GiveVerifiableCredential {
|
): GiveVerifiableCredential {
|
||||||
const vcClaim: GiveVerifiableCredential = {
|
// Remember: replace values or erase if it's null
|
||||||
|
|
||||||
|
const vcClaim: GiveVerifiableCredential = vcClaimOrig
|
||||||
|
? R.clone(vcClaimOrig)
|
||||||
|
: {
|
||||||
"@context": SCHEMA_ORG_CONTEXT,
|
"@context": SCHEMA_ORG_CONTEXT,
|
||||||
"@type": "GiveAction",
|
"@type": "GiveAction",
|
||||||
recipient: toDid ? { identifier: toDid } : undefined,
|
|
||||||
agent: fromDid ? { identifier: fromDid } : undefined,
|
|
||||||
description: description || undefined,
|
|
||||||
object: amount
|
|
||||||
? { amountOfThisGood: amount, unitCode: unitCode || "HUR" }
|
|
||||||
: undefined,
|
|
||||||
fulfills: [{ "@type": isTrade ? "TradeAction" : "DonateAction" }],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (lastClaimId) {
|
||||||
|
vcClaim.lastClaimId = lastClaimId;
|
||||||
|
delete vcClaim.identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
vcClaim.agent = fromDid ? { identifier: fromDid } : undefined;
|
||||||
|
vcClaim.recipient = toDid ? { identifier: toDid } : undefined;
|
||||||
|
vcClaim.description = description || undefined;
|
||||||
|
vcClaim.object = amount
|
||||||
|
? { amountOfThisGood: amount, unitCode: unitCode || "HUR" }
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
// ensure fulfills is an array
|
||||||
|
if (!Array.isArray(vcClaim.fulfills)) {
|
||||||
|
vcClaim.fulfills = vcClaim.fulfills ? [vcClaim.fulfills] : [];
|
||||||
|
}
|
||||||
|
// ... 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.
|
||||||
if (fulfillsProjectHandleId) {
|
if (fulfillsProjectHandleId) {
|
||||||
vcClaim.fulfills = vcClaim.fulfills || []; // weird that it won't typecheck without this
|
vcClaim.fulfills = vcClaim.fulfills.filter(
|
||||||
|
(elem) => elem["@type"] !== "PlanAction",
|
||||||
|
);
|
||||||
vcClaim.fulfills.push({
|
vcClaim.fulfills.push({
|
||||||
"@type": "PlanAction",
|
"@type": "PlanAction",
|
||||||
identifier: fulfillsProjectHandleId,
|
identifier: fulfillsProjectHandleId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (fulfillsOfferHandleId) {
|
if (fulfillsOfferHandleId) {
|
||||||
vcClaim.fulfills = vcClaim.fulfills || []; // weird that it won't typecheck without this
|
vcClaim.fulfills = vcClaim.fulfills.filter(
|
||||||
|
(elem) => elem["@type"] !== "Offer",
|
||||||
|
);
|
||||||
vcClaim.fulfills.push({
|
vcClaim.fulfills.push({
|
||||||
"@type": "Offer",
|
"@type": "Offer",
|
||||||
identifier: fulfillsOfferHandleId,
|
identifier: fulfillsOfferHandleId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (imageUrl) {
|
// do Trade/Donate last because current endorser.ch only looks at the first for plans & offers
|
||||||
vcClaim.image = imageUrl;
|
vcClaim.fulfills = vcClaim.fulfills.filter(
|
||||||
}
|
(elem) =>
|
||||||
|
elem["@type"] !== "DonateAction" && elem["@type"] !== "TradeAction",
|
||||||
|
);
|
||||||
|
vcClaim.fulfills.push({ "@type": isTrade ? "TradeAction" : "DonateAction" });
|
||||||
|
|
||||||
|
vcClaim.image = imageUrl || undefined;
|
||||||
|
|
||||||
return vcClaim;
|
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 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; should have this or amount
|
||||||
@@ -617,7 +646,7 @@ export async function createAndSubmitGive(
|
|||||||
axios: Axios,
|
axios: Axios,
|
||||||
apiServer: string,
|
apiServer: string,
|
||||||
issuerDid: string,
|
issuerDid: string,
|
||||||
fromDid?: string | null,
|
fromDid?: string,
|
||||||
toDid?: string,
|
toDid?: string,
|
||||||
description?: string,
|
description?: string,
|
||||||
amount?: number,
|
amount?: number,
|
||||||
@@ -627,7 +656,8 @@ export async function createAndSubmitGive(
|
|||||||
isTrade: boolean = false,
|
isTrade: boolean = false,
|
||||||
imageUrl?: string,
|
imageUrl?: string,
|
||||||
): Promise<CreateAndSubmitClaimResult> {
|
): Promise<CreateAndSubmitClaimResult> {
|
||||||
const vcClaim = constructGive(
|
const vcClaim = hydrateGive(
|
||||||
|
undefined,
|
||||||
fromDid,
|
fromDid,
|
||||||
toDid,
|
toDid,
|
||||||
description,
|
description,
|
||||||
@@ -639,7 +669,51 @@ export async function createAndSubmitGive(
|
|||||||
imageUrl,
|
imageUrl,
|
||||||
);
|
);
|
||||||
return createAndSubmitClaim(
|
return createAndSubmitClaim(
|
||||||
vcClaim as GenericCredWrapper,
|
vcClaim as GenericVerifiableCredential,
|
||||||
|
issuerDid,
|
||||||
|
apiServer,
|
||||||
|
axios,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
|
||||||
|
*
|
||||||
|
* @param fromDid may be null
|
||||||
|
* @param toDid
|
||||||
|
* @param description may be null; should have this or amount
|
||||||
|
* @param amount may be null; should have this or description
|
||||||
|
*/
|
||||||
|
export async function editAndSubmitGive(
|
||||||
|
axios: Axios,
|
||||||
|
apiServer: string,
|
||||||
|
fullClaim: GenericCredWrapper<GiveVerifiableCredential>,
|
||||||
|
issuerDid: string,
|
||||||
|
fromDid?: string,
|
||||||
|
toDid?: string,
|
||||||
|
description?: string,
|
||||||
|
amount?: number,
|
||||||
|
unitCode?: string,
|
||||||
|
fulfillsProjectHandleId?: string,
|
||||||
|
fulfillsOfferHandleId?: string,
|
||||||
|
isTrade: boolean = false,
|
||||||
|
imageUrl?: string,
|
||||||
|
): Promise<CreateAndSubmitClaimResult> {
|
||||||
|
const vcClaim = hydrateGive(
|
||||||
|
fullClaim.claim,
|
||||||
|
fromDid,
|
||||||
|
toDid,
|
||||||
|
description,
|
||||||
|
amount,
|
||||||
|
unitCode,
|
||||||
|
fulfillsProjectHandleId,
|
||||||
|
fulfillsOfferHandleId,
|
||||||
|
isTrade,
|
||||||
|
imageUrl,
|
||||||
|
fullClaim.id,
|
||||||
|
);
|
||||||
|
return createAndSubmitClaim(
|
||||||
|
vcClaim as GenericVerifiableCredential,
|
||||||
issuerDid,
|
issuerDid,
|
||||||
apiServer,
|
apiServer,
|
||||||
axios,
|
axios,
|
||||||
@@ -692,7 +766,7 @@ export async function createAndSubmitOffer(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return createAndSubmitClaim(
|
return createAndSubmitClaim(
|
||||||
vcClaim as GenericCredWrapper,
|
vcClaim as OfferVerifiableCredential,
|
||||||
issuerDid,
|
issuerDid,
|
||||||
apiServer,
|
apiServer,
|
||||||
axios,
|
axios,
|
||||||
@@ -751,7 +825,7 @@ export async function createAndSubmitClaim(
|
|||||||
return { type: "success", response };
|
return { type: "success", response };
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("Error creating claim:", error);
|
console.error("Error submitting claim:", error);
|
||||||
const errorMessage: string =
|
const errorMessage: string =
|
||||||
error.response?.data?.error?.message ||
|
error.response?.data?.error?.message ||
|
||||||
error.message ||
|
error.message ||
|
||||||
@@ -820,24 +894,29 @@ export const capitalizeAndInsertSpacesBeforeCaps = (text: string) => {
|
|||||||
similar code is also contained in endorser-mobile
|
similar code is also contained in endorser-mobile
|
||||||
**/
|
**/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const claimSummary = (claim: Record<string, any>) => {
|
const claimSummary = (
|
||||||
|
claim: GenericCredWrapper<GenericVerifiableCredential>,
|
||||||
|
) => {
|
||||||
if (!claim) {
|
if (!claim) {
|
||||||
// to differentiate from "something" above
|
// to differentiate from "something" above
|
||||||
return "something";
|
return "something";
|
||||||
}
|
}
|
||||||
|
let specificClaim:
|
||||||
|
| GenericVerifiableCredential
|
||||||
|
| GenericCredWrapper<GenericVerifiableCredential> = claim;
|
||||||
if (claim.claim) {
|
if (claim.claim) {
|
||||||
// probably a Verified Credential
|
// probably a Verified Credential
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
claim = claim.claim as Record<string, any>;
|
specificClaim = claim.claim;
|
||||||
}
|
}
|
||||||
if (Array.isArray(claim)) {
|
if (Array.isArray(specificClaim)) {
|
||||||
if (claim.length === 1) {
|
if (specificClaim.length === 1) {
|
||||||
claim = claim[0];
|
specificClaim = specificClaim[0];
|
||||||
} else {
|
} else {
|
||||||
return "multiple claims";
|
return "multiple claims";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const type = claim["@type"];
|
const type = specificClaim["@type"];
|
||||||
if (!type) {
|
if (!type) {
|
||||||
return "a claim";
|
return "a claim";
|
||||||
} else {
|
} else {
|
||||||
@@ -858,7 +937,7 @@ const claimSummary = (claim: Record<string, any>) => {
|
|||||||
similar code is also contained in endorser-mobile
|
similar code is also contained in endorser-mobile
|
||||||
**/
|
**/
|
||||||
export const claimSpecialDescription = (
|
export const claimSpecialDescription = (
|
||||||
record: GenericCredWrapper,
|
record: GenericCredWrapper<GenericVerifiableCredential>,
|
||||||
activeDid: string,
|
activeDid: string,
|
||||||
identifiers: Array<string>,
|
identifiers: Array<string>,
|
||||||
contacts: Array<Contact>,
|
contacts: Array<Contact>,
|
||||||
@@ -952,7 +1031,11 @@ export const claimSpecialDescription = (
|
|||||||
"...]"
|
"...]"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return issuer + " declared " + claimSummary(claim as GenericCredWrapper);
|
return (
|
||||||
|
issuer +
|
||||||
|
" declared " +
|
||||||
|
claimSummary(claim as GenericCredWrapper<GenericVerifiableCredential>)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ import {
|
|||||||
MASTER_SETTINGS_KEY,
|
MASTER_SETTINGS_KEY,
|
||||||
} from "@/db/tables/settings";
|
} from "@/db/tables/settings";
|
||||||
import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto";
|
import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto";
|
||||||
import { GenericCredWrapper, containsHiddenDid } from "@/libs/endorserServer";
|
import {
|
||||||
|
containsHiddenDid,
|
||||||
|
GenericCredWrapper,
|
||||||
|
GenericVerifiableCredential,
|
||||||
|
OfferVerifiableCredential,
|
||||||
|
} from "@/libs/endorserServer";
|
||||||
import * as serverUtil from "@/libs/endorserServer";
|
import * as serverUtil from "@/libs/endorserServer";
|
||||||
import { registerCredential } from "@/libs/crypto/vc/passkeyDidPeer";
|
import { registerCredential } from "@/libs/crypto/vc/passkeyDidPeer";
|
||||||
|
|
||||||
@@ -79,7 +84,9 @@ export const isGlobalUri = (uri: string) => {
|
|||||||
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
|
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isGiveAction = (veriClaim: GenericCredWrapper) => {
|
export const isGiveAction = (
|
||||||
|
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
|
||||||
|
) => {
|
||||||
return veriClaim.claimType === "GiveAction";
|
return veriClaim.claimType === "GiveAction";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -95,7 +102,7 @@ export const doCopyTwoSecRedo = (text: string, fn: () => void) => {
|
|||||||
* @param veriClaim is expected to have fields: claim, claimType, and issuer
|
* @param veriClaim is expected to have fields: claim, claimType, and issuer
|
||||||
*/
|
*/
|
||||||
export const isGiveRecordTheUserCanConfirm = (
|
export const isGiveRecordTheUserCanConfirm = (
|
||||||
veriClaim: GenericCredWrapper,
|
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
|
||||||
activeDid: string,
|
activeDid: string,
|
||||||
confirmerIdList: string[] = [],
|
confirmerIdList: string[] = [],
|
||||||
) => {
|
) => {
|
||||||
@@ -111,9 +118,9 @@ export const isGiveRecordTheUserCanConfirm = (
|
|||||||
* @returns the DID of the person who offered, or undefined if hidden
|
* @returns the DID of the person who offered, or undefined if hidden
|
||||||
* @param veriClaim is expected to have fields: claim and issuer
|
* @param veriClaim is expected to have fields: claim and issuer
|
||||||
*/
|
*/
|
||||||
export const offerGiverDid: (arg0: GenericCredWrapper) => string | undefined = (
|
export const offerGiverDid: (
|
||||||
veriClaim,
|
arg0: GenericCredWrapper<OfferVerifiableCredential>,
|
||||||
) => {
|
) => string | undefined = (veriClaim) => {
|
||||||
let giver;
|
let giver;
|
||||||
if (
|
if (
|
||||||
veriClaim.claim.offeredBy?.identifier &&
|
veriClaim.claim.offeredBy?.identifier &&
|
||||||
@@ -130,8 +137,13 @@ export const offerGiverDid: (arg0: GenericCredWrapper) => string | undefined = (
|
|||||||
* @returns true if the user can fulfill the offer
|
* @returns true if the user can fulfill the offer
|
||||||
* @param veriClaim is expected to have fields: claim, claimType, and issuer
|
* @param veriClaim is expected to have fields: claim, claimType, and issuer
|
||||||
*/
|
*/
|
||||||
export const canFulfillOffer = (veriClaim: GenericCredWrapper) => {
|
export const canFulfillOffer = (
|
||||||
return !!(veriClaim.claimType === "Offer" && offerGiverDid(veriClaim));
|
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
|
||||||
|
) => {
|
||||||
|
return !!(
|
||||||
|
veriClaim.claimType === "Offer" &&
|
||||||
|
offerGiverDid(veriClaim as GenericCredWrapper<OfferVerifiableCredential>)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// return object with paths and arrays of DIDs for any keys ending in "VisibleToDid"
|
// return object with paths and arrays of DIDs for any keys ending in "VisibleToDid"
|
||||||
|
|||||||
@@ -22,6 +22,16 @@
|
|||||||
<div class="overflow-hidden">
|
<div class="overflow-hidden">
|
||||||
<h2 class="text-md font-bold">
|
<h2 class="text-md font-bold">
|
||||||
{{ capitalizeAndInsertSpacesBeforeCaps(veriClaim.claimType) }}
|
{{ capitalizeAndInsertSpacesBeforeCaps(veriClaim.claimType) }}
|
||||||
|
<button
|
||||||
|
v-if="
|
||||||
|
veriClaim.claimType === 'GiveAction' &&
|
||||||
|
veriClaim.issuer === activeDid
|
||||||
|
"
|
||||||
|
@click="onClickEditClaim"
|
||||||
|
title="Edit"
|
||||||
|
>
|
||||||
|
<fa icon="pen" class="text-sm text-blue-500 ml-2 mb-1"></fa>
|
||||||
|
</button>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<div>
|
<div>
|
||||||
@@ -368,6 +378,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span v-if="isEditedGlobalId" class="mt-2">
|
||||||
|
This record is an edited version. The latest version is being shown.
|
||||||
|
</span>
|
||||||
<!-- Keep the dump contents directly between > and < to avoid weird spacing. -->
|
<!-- Keep the dump contents directly between > and < to avoid weird spacing. -->
|
||||||
<pre
|
<pre
|
||||||
class="text-sm overflow-x-scroll px-4 py-3 bg-slate-100 rounded-md"
|
class="text-sm overflow-x-scroll px-4 py-3 bg-slate-100 rounded-md"
|
||||||
@@ -411,6 +424,7 @@ import { AxiosError } from "axios";
|
|||||||
import * as yaml from "js-yaml";
|
import * as yaml from "js-yaml";
|
||||||
import * as R from "ramda";
|
import * as R from "ramda";
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
|
import { Router } from "vue-router";
|
||||||
import { useClipboard } from "@vueuse/core";
|
import { useClipboard } from "@vueuse/core";
|
||||||
|
|
||||||
import GiftedDialog from "@/components/GiftedDialog.vue";
|
import GiftedDialog from "@/components/GiftedDialog.vue";
|
||||||
@@ -422,7 +436,11 @@ import * as serverUtil from "@/libs/endorserServer";
|
|||||||
import * as libsUtil from "@/libs/util";
|
import * as libsUtil from "@/libs/util";
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import { Account } from "@/db/tables/accounts";
|
import { Account } from "@/db/tables/accounts";
|
||||||
import { GiverReceiverInputInfo } from "@/libs/endorserServer";
|
import {
|
||||||
|
GenericCredWrapper,
|
||||||
|
GiverReceiverInputInfo,
|
||||||
|
OfferVerifiableCredential,
|
||||||
|
} from "@/libs/endorserServer";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { GiftedDialog, QuickNav },
|
components: { GiftedDialog, QuickNav },
|
||||||
@@ -444,6 +462,7 @@ export default class ClaimView extends Vue {
|
|||||||
fullClaim = null;
|
fullClaim = null;
|
||||||
fullClaimDump = "";
|
fullClaimDump = "";
|
||||||
fullClaimMessage = "";
|
fullClaimMessage = "";
|
||||||
|
isEditedGlobalId = false;
|
||||||
numConfsNotVisible = 0; // number of hidden DIDs in the confirmerIdList, minus the issuer if they aren't visible
|
numConfsNotVisible = 0; // number of hidden DIDs in the confirmerIdList, minus the issuer if they aren't visible
|
||||||
showDidCopy = false;
|
showDidCopy = false;
|
||||||
showIdCopy = false;
|
showIdCopy = false;
|
||||||
@@ -466,6 +485,7 @@ export default class ClaimView extends Vue {
|
|||||||
this.fullClaim = null;
|
this.fullClaim = null;
|
||||||
this.fullClaimDump = "";
|
this.fullClaimDump = "";
|
||||||
this.fullClaimMessage = "";
|
this.fullClaimMessage = "";
|
||||||
|
this.isEditedGlobalId = false;
|
||||||
this.numConfsNotVisible = 0;
|
this.numConfsNotVisible = 0;
|
||||||
this.veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD;
|
this.veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD;
|
||||||
this.veriClaimDump = "";
|
this.veriClaimDump = "";
|
||||||
@@ -562,6 +582,8 @@ export default class ClaimView extends Vue {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isEditedGlobalId = !this.veriClaim.handleId.endsWith(claimId);
|
||||||
|
|
||||||
// retrieve more details on Give, Offer, or Plan
|
// retrieve more details on Give, Offer, or Plan
|
||||||
if (this.veriClaim.claimType === "GiveAction") {
|
if (this.veriClaim.claimType === "GiveAction") {
|
||||||
const giveUrl =
|
const giveUrl =
|
||||||
@@ -753,7 +775,7 @@ export default class ClaimView extends Vue {
|
|||||||
const route = {
|
const route = {
|
||||||
path: "/claim/" + encodeURIComponent(claimId),
|
path: "/claim/" + encodeURIComponent(claimId),
|
||||||
};
|
};
|
||||||
this.$router.push(route).then(async () => {
|
(this.$router as Router).push(route).then(async () => {
|
||||||
this.resetThisValues();
|
this.resetThisValues();
|
||||||
await this.loadClaim(claimId, this.activeDid);
|
await this.loadClaim(claimId, this.activeDid);
|
||||||
});
|
});
|
||||||
@@ -761,7 +783,9 @@ export default class ClaimView extends Vue {
|
|||||||
|
|
||||||
openFulfillGiftDialog() {
|
openFulfillGiftDialog() {
|
||||||
const giver: GiverReceiverInputInfo = {
|
const giver: GiverReceiverInputInfo = {
|
||||||
did: libsUtil.offerGiverDid(this.veriClaim),
|
did: libsUtil.offerGiverDid(
|
||||||
|
this.veriClaim as GenericCredWrapper<OfferVerifiableCredential>,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
(this.$refs.customGiveDialog as GiftedDialog).open(
|
(this.$refs.customGiveDialog as GiftedDialog).open(
|
||||||
giver,
|
giver,
|
||||||
@@ -794,5 +818,17 @@ export default class ClaimView extends Vue {
|
|||||||
url: this.windowLocation,
|
url: this.windowLocation,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClickEditClaim() {
|
||||||
|
const route = {
|
||||||
|
name: "gifted-details",
|
||||||
|
query: {
|
||||||
|
prevCredToEdit: JSON.stringify(this.veriClaim),
|
||||||
|
destinationPathAfter:
|
||||||
|
"/claim/" + encodeURIComponent(this.veriClaim.handleId),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
(this.$router as Router).push(route);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -407,7 +407,12 @@ import { Account } from "@/db/tables/accounts";
|
|||||||
import { Contact } from "@/db/tables/contacts";
|
import { Contact } from "@/db/tables/contacts";
|
||||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||||
import * as serverUtil from "@/libs/endorserServer";
|
import * as serverUtil from "@/libs/endorserServer";
|
||||||
import { displayAmount, GiverReceiverInputInfo } from "@/libs/endorserServer";
|
import {
|
||||||
|
displayAmount,
|
||||||
|
GenericCredWrapper,
|
||||||
|
GiverReceiverInputInfo,
|
||||||
|
OfferVerifiableCredential,
|
||||||
|
} from "@/libs/endorserServer";
|
||||||
import * as libsUtil from "@/libs/util";
|
import * as libsUtil from "@/libs/util";
|
||||||
import { isGiveAction } from "@/libs/util";
|
import { isGiveAction } from "@/libs/util";
|
||||||
|
|
||||||
@@ -767,7 +772,9 @@ export default class ClaimView extends Vue {
|
|||||||
|
|
||||||
openFulfillGiftDialog() {
|
openFulfillGiftDialog() {
|
||||||
const giver: GiverReceiverInputInfo = {
|
const giver: GiverReceiverInputInfo = {
|
||||||
did: libsUtil.offerGiverDid(this.veriClaim),
|
did: libsUtil.offerGiverDid(
|
||||||
|
this.veriClaim as GenericCredWrapper<OfferVerifiableCredential>,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
(this.$refs.customGiveDialog as GiftedDialog).open(
|
(this.$refs.customGiveDialog as GiftedDialog).open(
|
||||||
giver,
|
giver,
|
||||||
|
|||||||
@@ -175,6 +175,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
|
import { Router } from "vue-router";
|
||||||
|
|
||||||
import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
|
import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
|
||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
@@ -183,11 +184,14 @@ import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
|
|||||||
import { accountsDB, db } from "@/db/index";
|
import { accountsDB, db } from "@/db/index";
|
||||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||||
import {
|
import {
|
||||||
constructGive,
|
|
||||||
createAndSubmitGive,
|
createAndSubmitGive,
|
||||||
didInfo,
|
didInfo,
|
||||||
|
editAndSubmitGive,
|
||||||
|
GenericCredWrapper,
|
||||||
getHeaders,
|
getHeaders,
|
||||||
getPlanFromCache,
|
getPlanFromCache,
|
||||||
|
GiveVerifiableCredential,
|
||||||
|
hydrateGive,
|
||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import * as libsUtil from "@/libs/util";
|
import * as libsUtil from "@/libs/util";
|
||||||
import { Contact } from "@/db/tables/contacts";
|
import { Contact } from "@/db/tables/contacts";
|
||||||
@@ -207,7 +211,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
|
|
||||||
amountInput = "0";
|
amountInput = "0";
|
||||||
description = "";
|
description = "";
|
||||||
destinationNameAfter = "";
|
destinationPathAfter = "";
|
||||||
givenToProject = false;
|
givenToProject = false;
|
||||||
givenToRecipient = false;
|
givenToRecipient = false;
|
||||||
giverDid: string | undefined;
|
giverDid: string | undefined;
|
||||||
@@ -217,6 +221,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
isTrade = false;
|
isTrade = false;
|
||||||
message = "";
|
message = "";
|
||||||
offerId = "";
|
offerId = "";
|
||||||
|
prevCredToEdit?: GenericCredWrapper<GiveVerifiableCredential>;
|
||||||
projectId = "";
|
projectId = "";
|
||||||
projectName = "a project";
|
projectName = "a project";
|
||||||
recipientDid = "";
|
recipientDid = "";
|
||||||
@@ -226,34 +231,80 @@ export default class GiftedDetails extends Vue {
|
|||||||
libsUtil = libsUtil;
|
libsUtil = libsUtil;
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
try {
|
||||||
|
this.prevCredToEdit = (this.$route as Router).query["prevCredToEdit"]
|
||||||
|
? (JSON.parse(
|
||||||
|
(this.$route as Router).query["prevCredToEdit"],
|
||||||
|
) as GenericCredWrapper<GiveVerifiableCredential>)
|
||||||
|
: 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.amountInput =
|
this.amountInput =
|
||||||
(this.$route.query.amountInput as string) || this.amountInput;
|
this.$route.query.amountInput ||
|
||||||
this.description = (this.$route.query.description as string) || "";
|
String(this.prevCredToEdit?.claim?.object?.amountOfThisGood) ||
|
||||||
this.destinationNameAfter = this.$route.query
|
this.amountInput;
|
||||||
.destinationNameAfter as string;
|
this.description =
|
||||||
this.giverDid = this.$route.query.giverDid as string;
|
this.$route.query.description ||
|
||||||
|
this.prevCredToEdit?.claim?.description ||
|
||||||
|
this.description;
|
||||||
|
this.destinationPathAfter = this.$route.query.destinationPathAfter;
|
||||||
|
this.giverDid = (this.$route.query.giverDid ||
|
||||||
|
this.prevCredToEdit?.claim?.agent?.identifier ||
|
||||||
|
this.giverDid) as string;
|
||||||
this.giverName = (this.$route.query.giverName as string) || "";
|
this.giverName = (this.$route.query.giverName as string) || "";
|
||||||
this.hideBackButton = this.$route.query.hideBackButton === "true";
|
this.hideBackButton = this.$route.query.hideBackButton === "true";
|
||||||
this.message = (this.$route.query.message as string) || "";
|
this.message = (this.$route.query.message as string) || "";
|
||||||
this.offerId = this.$route.query.offerId as string;
|
// find any offer ID
|
||||||
this.projectId = this.$route.query.projectId as string;
|
const fulfills = this.prevCredToEdit?.claim?.fulfills;
|
||||||
this.recipientDid = this.$route.query.recipientDid as string;
|
const fulfillsArray = Array.isArray(fulfills)
|
||||||
|
? fulfills
|
||||||
|
: fulfills
|
||||||
|
? [fulfills]
|
||||||
|
: [];
|
||||||
|
const offer = fulfillsArray.find((rec) => rec.claimType === "Offer");
|
||||||
|
this.offerId = (this.$route.query.offerId ||
|
||||||
|
offer?.identifier ||
|
||||||
|
this.offerId) as string;
|
||||||
|
|
||||||
|
// find any project ID
|
||||||
|
const project = fulfillsArray.find((rec) => rec.claimType === "PlanAction");
|
||||||
|
this.projectId = (this.$route.query.projectId ||
|
||||||
|
project?.identifier ||
|
||||||
|
this.projectId) as string;
|
||||||
|
|
||||||
|
this.recipientDid = (this.$route.query.recipientDid ||
|
||||||
|
this.prevCredToEdit?.claim?.recipient?.identifier) as string;
|
||||||
this.recipientName = (this.$route.query.recipientName as string) || "";
|
this.recipientName = (this.$route.query.recipientName as string) || "";
|
||||||
this.unitCode = (this.$route.query.unitCode as string) || this.unitCode;
|
this.unitCode = (this.$route.query.unitCode ||
|
||||||
|
this.prevCredToEdit?.claim?.object?.unitCode ||
|
||||||
|
this.unitCode) as string;
|
||||||
|
|
||||||
this.imageUrl =
|
this.imageUrl =
|
||||||
(this.$route.query.imageUrl as string) ||
|
(this.$route.query.imageUrl as string) ||
|
||||||
|
this.prevCredToEdit?.claim?.image ||
|
||||||
localStorage.getItem("imageUrl") ||
|
localStorage.getItem("imageUrl") ||
|
||||||
"";
|
this.imageUrl;
|
||||||
|
|
||||||
// this is an endpoint for sharing project info to highlight something given
|
// this is an endpoint for sharing project info to highlight something given
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/Manifest/share_target
|
// https://developer.mozilla.org/en-US/docs/Web/Manifest/share_target
|
||||||
if (this.$route.query.shareTitle) {
|
if (this.$route.query.shareTitle) {
|
||||||
this.description = this.$route.query.shareTitle as string;
|
this.description =
|
||||||
|
(this.$route.query.shareTitle as string) +
|
||||||
|
(this.description ? "\n" + this.description : "");
|
||||||
}
|
}
|
||||||
if (this.$route.query.shareText) {
|
if (this.$route.query.shareText) {
|
||||||
this.description =
|
this.description =
|
||||||
(this.description ? this.description + " " : "") +
|
(this.description ? this.description + "\n" : "") +
|
||||||
(this.$route.query.shareText as string);
|
(this.$route.query.shareText as string);
|
||||||
}
|
}
|
||||||
if (this.$route.query.shareUrl) {
|
if (this.$route.query.shareUrl) {
|
||||||
@@ -344,16 +395,16 @@ export default class GiftedDetails extends Vue {
|
|||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.deleteImage(); // not awaiting, so they'll go back immediately
|
this.deleteImage(); // not awaiting, so they'll go back immediately
|
||||||
if (this.destinationNameAfter) {
|
if (this.destinationPathAfter) {
|
||||||
this.$router.push({ name: this.destinationNameAfter });
|
(this.$router as Router).push({ path: this.destinationPathAfter });
|
||||||
} else {
|
} else {
|
||||||
this.$router.back();
|
(this.$router as Router).back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelBack() {
|
cancelBack() {
|
||||||
this.deleteImage(); // not awaiting, so they'll go back immediately
|
this.deleteImage(); // not awaiting, so they'll go back immediately
|
||||||
this.$router.back();
|
(this.$router as Router).back();
|
||||||
}
|
}
|
||||||
|
|
||||||
openImageDialog() {
|
openImageDialog() {
|
||||||
@@ -548,7 +599,26 @@ export default class GiftedDetails extends Vue {
|
|||||||
? this.recipientDid
|
? this.recipientDid
|
||||||
: undefined;
|
: undefined;
|
||||||
const projectId = this.givenToProject ? this.projectId : undefined;
|
const projectId = this.givenToProject ? this.projectId : undefined;
|
||||||
const result = await createAndSubmitGive(
|
let result;
|
||||||
|
if (this.prevCredToEdit) {
|
||||||
|
// don't create from a blank one in case some properties were set from a different interface
|
||||||
|
result = await editAndSubmitGive(
|
||||||
|
this.axios,
|
||||||
|
this.apiServer,
|
||||||
|
this.prevCredToEdit,
|
||||||
|
this.activeDid,
|
||||||
|
this.giverDid,
|
||||||
|
recipientDid,
|
||||||
|
this.description,
|
||||||
|
parseFloat(this.amountInput),
|
||||||
|
this.unitCode,
|
||||||
|
projectId,
|
||||||
|
this.offerId,
|
||||||
|
this.isTrade,
|
||||||
|
this.imageUrl,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
result = await createAndSubmitGive(
|
||||||
this.axios,
|
this.axios,
|
||||||
this.apiServer,
|
this.apiServer,
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
@@ -562,6 +632,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
this.isTrade,
|
this.isTrade,
|
||||||
this.imageUrl,
|
this.imageUrl,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
result.type === "error" ||
|
result.type === "error" ||
|
||||||
@@ -589,10 +660,10 @@ export default class GiftedDetails extends Vue {
|
|||||||
5000,
|
5000,
|
||||||
);
|
);
|
||||||
localStorage.removeItem("imageUrl");
|
localStorage.removeItem("imageUrl");
|
||||||
if (this.destinationNameAfter) {
|
if (this.destinationPathAfter) {
|
||||||
this.$router.push({ name: this.destinationNameAfter });
|
(this.$router as Router).push({ path: this.destinationPathAfter });
|
||||||
} else {
|
} else {
|
||||||
this.$router.back();
|
(this.$router as Router).back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@@ -617,7 +688,8 @@ 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(
|
||||||
|
this.prevCredToEdit?.claim as GiveVerifiableCredential,
|
||||||
this.giverDid,
|
this.giverDid,
|
||||||
recipientDid,
|
recipientDid,
|
||||||
this.description,
|
this.description,
|
||||||
@@ -627,6 +699,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
this.offerId,
|
this.offerId,
|
||||||
this.isTrade,
|
this.isTrade,
|
||||||
this.imageUrl,
|
this.imageUrl,
|
||||||
|
this.prevCredToEdit?.id as string,
|
||||||
);
|
);
|
||||||
const claimStr = JSON.stringify(giveClaim);
|
const claimStr = JSON.stringify(giveClaim);
|
||||||
return claimStr;
|
return claimStr;
|
||||||
|
|||||||
@@ -89,7 +89,8 @@
|
|||||||
:to="{ name: 'contact-qr' }"
|
:to="{ name: 'contact-qr' }"
|
||||||
class="block text-center text-md font-bold bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mt-2 px-2 py-3 rounded-md"
|
class="block text-center text-md font-bold bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mt-2 px-2 py-3 rounded-md"
|
||||||
>
|
>
|
||||||
Show Them {{ PASSKEYS_ENABLED ? "Default" : "Your" }} Identifier Info
|
Show Them {{ PASSKEYS_ENABLED ? "Default" : "Your" }} Identifier
|
||||||
|
Info
|
||||||
</router-link>
|
</router-link>
|
||||||
<div v-if="PASSKEYS_ENABLED" class="flex justify-end w-full">
|
<div v-if="PASSKEYS_ENABLED" class="flex justify-end w-full">
|
||||||
<router-link
|
<router-link
|
||||||
|
|||||||
@@ -74,6 +74,9 @@
|
|||||||
v-model="fullClaim.description"
|
v-model="fullClaim.description"
|
||||||
maxlength="5000"
|
maxlength="5000"
|
||||||
></textarea>
|
></textarea>
|
||||||
|
<div class="text-xs text-slate-500 italic -mt-3 mb-4">
|
||||||
|
If you want to be contacted, be sure to include your contact information.
|
||||||
|
</div>
|
||||||
<div class="text-xs text-slate-500 italic -mt-3 mb-4">
|
<div class="text-xs text-slate-500 italic -mt-3 mb-4">
|
||||||
{{ fullClaim.description?.length }}/5000 max. characters
|
{{ fullClaim.description?.length }}/5000 max. characters
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export default class SharedPhotoView extends Vue {
|
|||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: "gifted-details",
|
name: "gifted-details",
|
||||||
query: {
|
query: {
|
||||||
destinationNameAfter: "home",
|
destinationPathAfter: "/home",
|
||||||
hideBackButton: true,
|
hideBackButton: true,
|
||||||
imageUrl: url,
|
imageUrl: url,
|
||||||
recipientDid: this.activeDid,
|
recipientDid: this.activeDid,
|
||||||
|
|||||||
10
src/vite-env.d.ts
vendored
Normal file
10
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_APP_TITLE: string;
|
||||||
|
// more env variables...
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user