Browse Source

add ability to edit a GiveAction

Trent Larson 4 months ago
parent
commit
c16c1689a3
  1. 4
      src/components/GiftedDialog.vue
  2. 2
      src/libs/crypto/vc/index.ts
  3. 179
      src/libs/endorserServer.ts
  4. 28
      src/libs/util.ts
  5. 42
      src/views/ClaimView.vue
  6. 11
      src/views/ConfirmGiftView.vue
  7. 145
      src/views/GiftedDetails.vue
  8. 3
      src/views/HomeView.vue
  9. 3
      src/views/NewEditProjectView.vue
  10. 2
      src/views/SharedPhotoView.vue
  11. 10
      src/vite-env.d.ts

4
src/components/GiftedDialog.vue

@ -291,8 +291,8 @@ export default class GiftedDialog extends Vue {
this.axios,
this.apiServer,
this.activeDid,
giverDid,
this.receiver?.did as string,
giverDid as string,
recipientDid as string,
description,
amount,
unitCode,

2
src/libs/crypto/vc/index.ts

@ -67,7 +67,7 @@ export async function createEndorserJwtForKey(
* The SimpleSigner returns a configured function for signing data.
*
* @example
* const signer = SimpleSigner(import.meta.env.PRIVATE_KEY)
* const signer = SimpleSigner(privateKeyHexString)
* signer(data, (err, signature) => {
* ...
* })

179
src/libs/endorserServer.ts

@ -48,29 +48,31 @@ export interface ClaimResult {
}
export interface GenericVerifiableCredential {
"@context": string;
"@context"?: string;
"@type": string;
[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;
id: string;
issuedAt: string;
issuer: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
claim: Record<string, any>;
claim: T;
claimType?: string;
}
export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper = {
"@context": SCHEMA_ORG_CONTEXT,
"@type": "",
claim: {},
handleId: "",
id: "",
issuedAt: "",
issuer: "",
};
export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper<GenericVerifiableCredential> =
{
"@context": SCHEMA_ORG_CONTEXT,
"@type": "",
claim: { "@type": "" },
handleId: "",
id: "",
issuedAt: "",
issuer: "",
};
// a summary record; the VC is found the fullClaim field
export interface GiveSummaryRecord {
@ -123,7 +125,7 @@ export interface PlanSummaryRecord {
// Note that previous VCs may have additional fields.
// 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
"@type": "GiveAction";
agent?: { identifier: string };
@ -191,7 +193,7 @@ export interface PlanData {
*/
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;
}
@ -562,8 +564,9 @@ export async function setPlanInCache(
/**
* Construct GiveAction VC for submission to server
*/
export function constructGive(
fromDid?: string | null,
export function hydrateGive(
vcClaimOrig?: GiveVerifiableCredential,
fromDid?: string,
toDid?: string,
description?: string,
amount?: number,
@ -572,42 +575,68 @@ export function constructGive(
fulfillsOfferHandleId?: string,
isTrade: boolean = false,
imageUrl?: string,
lastClaimId?: string,
): GiveVerifiableCredential {
const vcClaim: GiveVerifiableCredential = {
"@context": SCHEMA_ORG_CONTEXT,
"@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" }],
};
// Remember: replace values or erase if it's null
const vcClaim: GiveVerifiableCredential = vcClaimOrig
? R.clone(vcClaimOrig)
: {
"@context": SCHEMA_ORG_CONTEXT,
"@type": "GiveAction",
};
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) {
vcClaim.fulfills = vcClaim.fulfills || []; // weird that it won't typecheck without this
vcClaim.fulfills = vcClaim.fulfills.filter(
(elem) => elem["@type"] !== "PlanAction",
);
vcClaim.fulfills.push({
"@type": "PlanAction",
identifier: fulfillsProjectHandleId,
});
}
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({
"@type": "Offer",
identifier: fulfillsOfferHandleId,
});
}
if (imageUrl) {
vcClaim.image = imageUrl;
}
// do Trade/Donate last because current endorser.ch only looks at the first for plans & offers
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;
}
/**
* 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 toDid
* @param description may be null; should have this or amount
@ -617,7 +646,50 @@ export async function createAndSubmitGive(
axios: Axios,
apiServer: string,
issuerDid: string,
fromDid?: string | null,
fromDid?: string,
toDid?: string,
description?: string,
amount?: number,
unitCode?: string,
fulfillsProjectHandleId?: string,
fulfillsOfferHandleId?: string,
isTrade: boolean = false,
imageUrl?: string,
): Promise<CreateAndSubmitClaimResult> {
const vcClaim = hydrateGive(
undefined,
fromDid,
toDid,
description,
amount,
unitCode,
fulfillsProjectHandleId,
fulfillsOfferHandleId,
isTrade,
imageUrl,
);
return createAndSubmitClaim(
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,
@ -627,7 +699,8 @@ export async function createAndSubmitGive(
isTrade: boolean = false,
imageUrl?: string,
): Promise<CreateAndSubmitClaimResult> {
const vcClaim = constructGive(
const vcClaim = hydrateGive(
fullClaim.claim,
fromDid,
toDid,
description,
@ -637,9 +710,10 @@ export async function createAndSubmitGive(
fulfillsOfferHandleId,
isTrade,
imageUrl,
fullClaim.id,
);
return createAndSubmitClaim(
vcClaim as GenericCredWrapper,
vcClaim as GenericVerifiableCredential,
issuerDid,
apiServer,
axios,
@ -692,7 +766,7 @@ export async function createAndSubmitOffer(
};
}
return createAndSubmitClaim(
vcClaim as GenericCredWrapper,
vcClaim as OfferVerifiableCredential,
issuerDid,
apiServer,
axios,
@ -751,7 +825,7 @@ export async function createAndSubmitClaim(
return { type: "success", response };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error("Error creating claim:", error);
console.error("Error submitting claim:", error);
const errorMessage: string =
error.response?.data?.error?.message ||
error.message ||
@ -820,24 +894,29 @@ export const capitalizeAndInsertSpacesBeforeCaps = (text: string) => {
similar code is also contained in endorser-mobile
**/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const claimSummary = (claim: Record<string, any>) => {
const claimSummary = (
claim: GenericCredWrapper<GenericVerifiableCredential>,
) => {
if (!claim) {
// to differentiate from "something" above
return "something";
}
let specificClaim:
| GenericVerifiableCredential
| GenericCredWrapper<GenericVerifiableCredential> = claim;
if (claim.claim) {
// probably a Verified Credential
// eslint-disable-next-line @typescript-eslint/no-explicit-any
claim = claim.claim as Record<string, any>;
specificClaim = claim.claim;
}
if (Array.isArray(claim)) {
if (claim.length === 1) {
claim = claim[0];
if (Array.isArray(specificClaim)) {
if (specificClaim.length === 1) {
specificClaim = specificClaim[0];
} else {
return "multiple claims";
}
}
const type = claim["@type"];
const type = specificClaim["@type"];
if (!type) {
return "a claim";
} else {
@ -858,7 +937,7 @@ const claimSummary = (claim: Record<string, any>) => {
similar code is also contained in endorser-mobile
**/
export const claimSpecialDescription = (
record: GenericCredWrapper,
record: GenericCredWrapper<GenericVerifiableCredential>,
activeDid: string,
identifiers: Array<string>,
contacts: Array<Contact>,
@ -952,7 +1031,11 @@ export const claimSpecialDescription = (
"...]"
);
} else {
return issuer + " declared " + claimSummary(claim as GenericCredWrapper);
return (
issuer +
" declared " +
claimSummary(claim as GenericCredWrapper<GenericVerifiableCredential>)
);
}
};

28
src/libs/util.ts

@ -11,7 +11,12 @@ import {
MASTER_SETTINGS_KEY,
} from "@/db/tables/settings";
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 { 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+.-]+:/));
};
export const isGiveAction = (veriClaim: GenericCredWrapper) => {
export const isGiveAction = (
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
) => {
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
*/
export const isGiveRecordTheUserCanConfirm = (
veriClaim: GenericCredWrapper,
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
activeDid: string,
confirmerIdList: string[] = [],
) => {
@ -111,9 +118,9 @@ export const isGiveRecordTheUserCanConfirm = (
* @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: GenericCredWrapper) => string | undefined = (
veriClaim,
) => {
export const offerGiverDid: (
arg0: GenericCredWrapper<OfferVerifiableCredential>,
) => string | undefined = (veriClaim) => {
let giver;
if (
veriClaim.claim.offeredBy?.identifier &&
@ -130,8 +137,13 @@ export const offerGiverDid: (arg0: GenericCredWrapper) => string | undefined = (
* @returns true if the user can fulfill the offer
* @param veriClaim is expected to have fields: claim, claimType, and issuer
*/
export const canFulfillOffer = (veriClaim: GenericCredWrapper) => {
return !!(veriClaim.claimType === "Offer" && offerGiverDid(veriClaim));
export const canFulfillOffer = (
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"

42
src/views/ClaimView.vue

@ -22,6 +22,16 @@
<div class="overflow-hidden">
<h2 class="text-md font-bold">
{{ 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>
<div class="text-sm">
<div>
@ -368,6 +378,9 @@
</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. -->
<pre
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 R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { useClipboard } from "@vueuse/core";
import GiftedDialog from "@/components/GiftedDialog.vue";
@ -422,7 +436,11 @@ import * as serverUtil from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import QuickNav from "@/components/QuickNav.vue";
import { Account } from "@/db/tables/accounts";
import { GiverReceiverInputInfo } from "@/libs/endorserServer";
import {
GenericCredWrapper,
GiverReceiverInputInfo,
OfferVerifiableCredential,
} from "@/libs/endorserServer";
@Component({
components: { GiftedDialog, QuickNav },
@ -444,6 +462,7 @@ export default class ClaimView extends Vue {
fullClaim = null;
fullClaimDump = "";
fullClaimMessage = "";
isEditedGlobalId = false;
numConfsNotVisible = 0; // number of hidden DIDs in the confirmerIdList, minus the issuer if they aren't visible
showDidCopy = false;
showIdCopy = false;
@ -466,6 +485,7 @@ export default class ClaimView extends Vue {
this.fullClaim = null;
this.fullClaimDump = "";
this.fullClaimMessage = "";
this.isEditedGlobalId = false;
this.numConfsNotVisible = 0;
this.veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD;
this.veriClaimDump = "";
@ -562,6 +582,8 @@ export default class ClaimView extends Vue {
return;
}
this.isEditedGlobalId = !this.veriClaim.handleId.endsWith(claimId);
// retrieve more details on Give, Offer, or Plan
if (this.veriClaim.claimType === "GiveAction") {
const giveUrl =
@ -753,7 +775,7 @@ export default class ClaimView extends Vue {
const route = {
path: "/claim/" + encodeURIComponent(claimId),
};
this.$router.push(route).then(async () => {
(this.$router as Router).push(route).then(async () => {
this.resetThisValues();
await this.loadClaim(claimId, this.activeDid);
});
@ -761,7 +783,9 @@ export default class ClaimView extends Vue {
openFulfillGiftDialog() {
const giver: GiverReceiverInputInfo = {
did: libsUtil.offerGiverDid(this.veriClaim),
did: libsUtil.offerGiverDid(
this.veriClaim as GenericCredWrapper<OfferVerifiableCredential>,
),
};
(this.$refs.customGiveDialog as GiftedDialog).open(
giver,
@ -794,5 +818,17 @@ export default class ClaimView extends Vue {
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>

11
src/views/ConfirmGiftView.vue

@ -407,7 +407,12 @@ import { Account } from "@/db/tables/accounts";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
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 { isGiveAction } from "@/libs/util";
@ -767,7 +772,9 @@ export default class ClaimView extends Vue {
openFulfillGiftDialog() {
const giver: GiverReceiverInputInfo = {
did: libsUtil.offerGiverDid(this.veriClaim),
did: libsUtil.offerGiverDid(
this.veriClaim as GenericCredWrapper<OfferVerifiableCredential>,
),
};
(this.$refs.customGiveDialog as GiftedDialog).open(
giver,

145
src/views/GiftedDetails.vue

@ -175,6 +175,7 @@
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import ImageMethodDialog from "@/components/ImageMethodDialog.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 { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import {
constructGive,
createAndSubmitGive,
didInfo,
editAndSubmitGive,
GenericCredWrapper,
getHeaders,
getPlanFromCache,
GiveVerifiableCredential,
hydrateGive,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { Contact } from "@/db/tables/contacts";
@ -207,7 +211,7 @@ export default class GiftedDetails extends Vue {
amountInput = "0";
description = "";
destinationNameAfter = "";
destinationPathAfter = "";
givenToProject = false;
givenToRecipient = false;
giverDid: string | undefined;
@ -217,6 +221,7 @@ export default class GiftedDetails extends Vue {
isTrade = false;
message = "";
offerId = "";
prevCredToEdit?: GenericCredWrapper<GiveVerifiableCredential>;
projectId = "";
projectName = "a project";
recipientDid = "";
@ -226,34 +231,80 @@ export default class GiftedDetails extends Vue {
libsUtil = libsUtil;
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.$route.query.amountInput as string) || this.amountInput;
this.description = (this.$route.query.description as string) || "";
this.destinationNameAfter = this.$route.query
.destinationNameAfter as string;
this.giverDid = this.$route.query.giverDid as string;
this.$route.query.amountInput ||
String(this.prevCredToEdit?.claim?.object?.amountOfThisGood) ||
this.amountInput;
this.description =
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.hideBackButton = this.$route.query.hideBackButton === "true";
this.message = (this.$route.query.message as string) || "";
this.offerId = this.$route.query.offerId as string;
this.projectId = this.$route.query.projectId as string;
this.recipientDid = this.$route.query.recipientDid 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.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.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.$route.query.imageUrl as string) ||
this.prevCredToEdit?.claim?.image ||
localStorage.getItem("imageUrl") ||
"";
this.imageUrl;
// 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.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) {
this.description =
(this.description ? this.description + " " : "") +
(this.description ? this.description + "\n" : "") +
(this.$route.query.shareText as string);
}
if (this.$route.query.shareUrl) {
@ -344,16 +395,16 @@ export default class GiftedDetails extends Vue {
cancel() {
this.deleteImage(); // not awaiting, so they'll go back immediately
if (this.destinationNameAfter) {
this.$router.push({ name: this.destinationNameAfter });
if (this.destinationPathAfter) {
(this.$router as Router).push({ path: this.destinationPathAfter });
} else {
this.$router.back();
(this.$router as Router).back();
}
}
cancelBack() {
this.deleteImage(); // not awaiting, so they'll go back immediately
this.$router.back();
(this.$router as Router).back();
}
openImageDialog() {
@ -548,20 +599,40 @@ export default class GiftedDetails extends Vue {
? this.recipientDid
: undefined;
const projectId = this.givenToProject ? this.projectId : undefined;
const result = await createAndSubmitGive(
this.axios,
this.apiServer,
this.activeDid,
this.giverDid,
recipientDid,
this.description,
parseFloat(this.amountInput),
this.unitCode,
projectId,
this.offerId,
this.isTrade,
this.imageUrl,
);
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.apiServer,
this.activeDid,
this.giverDid,
recipientDid,
this.description,
parseFloat(this.amountInput),
this.unitCode,
projectId,
this.offerId,
this.isTrade,
this.imageUrl,
);
}
if (
result.type === "error" ||
@ -589,10 +660,10 @@ export default class GiftedDetails extends Vue {
5000,
);
localStorage.removeItem("imageUrl");
if (this.destinationNameAfter) {
this.$router.push({ name: this.destinationNameAfter });
if (this.destinationPathAfter) {
(this.$router as Router).push({ path: this.destinationPathAfter });
} else {
this.$router.back();
(this.$router as Router).back();
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -617,7 +688,8 @@ export default class GiftedDetails extends Vue {
constructGiveParam() {
const recipientDid = this.givenToRecipient ? this.recipientDid : undefined;
const projectId = this.givenToProject ? this.projectId : undefined;
const giveClaim = constructGive(
const giveClaim = hydrateGive(
this.prevCredToEdit?.claim as GiveVerifiableCredential,
this.giverDid,
recipientDid,
this.description,
@ -627,6 +699,7 @@ export default class GiftedDetails extends Vue {
this.offerId,
this.isTrade,
this.imageUrl,
this.prevCredToEdit?.id as string,
);
const claimStr = JSON.stringify(giveClaim);
return claimStr;

3
src/views/HomeView.vue

@ -89,7 +89,8 @@
: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"
>
Show Them {{ PASSKEYS_ENABLED ? "Default" : "Your" }} Identifier Info
Show Them {{ PASSKEYS_ENABLED ? "Default" : "Your" }} Identifier
Info
</router-link>
<div v-if="PASSKEYS_ENABLED" class="flex justify-end w-full">
<router-link

3
src/views/NewEditProjectView.vue

@ -74,6 +74,9 @@
v-model="fullClaim.description"
maxlength="5000"
></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">
{{ fullClaim.description?.length }}/5000 max. characters
</div>

2
src/views/SharedPhotoView.vue

@ -114,7 +114,7 @@ export default class SharedPhotoView extends Vue {
this.$router.push({
name: "gifted-details",
query: {
destinationNameAfter: "home",
destinationPathAfter: "/home",
hideBackButton: true,
imageUrl: url,
recipientDid: this.activeDid,

10
src/vite-env.d.ts

@ -0,0 +1,10 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string;
// more env variables...
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
Loading…
Cancel
Save