Browse Source

add advanced page & flag for editing raw claims, and fix recipient assignment in detail screen

master
Trent Larson 3 months ago
parent
commit
dffa007a74
  1. 1
      src/db/tables/settings.ts
  2. 63
      src/libs/endorserServer.ts
  3. 5
      src/router/index.ts
  4. 133
      src/views/AccountViewView.vue
  5. 133
      src/views/ClaimAddRawView.vue
  6. 143
      src/views/GiftedDetails.vue

1
src/db/tables/settings.ts

@ -37,6 +37,7 @@ export type Settings = {
}>; }>;
showContactGivesInline?: boolean; // Display contact inline or not showContactGivesInline?: boolean; // Display contact inline or not
showGeneralAdvanced?: boolean; // Show advanced features which don't have their own flag
showShortcutBvc?: boolean; // Show shortcut for Bountiful Voluntaryist Community actions showShortcutBvc?: boolean; // Show shortcut for Bountiful Voluntaryist Community actions
vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push
warnIfProdServer?: boolean; // Warn if using a production server warnIfProdServer?: boolean; // Warn if using a production server

63
src/libs/endorserServer.ts

@ -160,7 +160,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 {
"@context": "https://schema.org"; "@context": SCHEMA_ORG_CONTEXT;
"@type": "PlanAction"; "@type": "PlanAction";
name: string; name: string;
agent?: { identifier: string }; agent?: { identifier: string };
@ -518,19 +518,7 @@ export async function setPlanInCache(
planCache.set(handleId, planSummary); planCache.set(handleId, planSummary);
} }
/** export function constructGive(
* 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
* @param amount may be null; should have this or description
*/
export async function createAndSubmitGive(
axios: Axios,
apiServer: string,
identity: IIdentifier,
fromDid?: string | null, fromDid?: string | null,
toDid?: string, toDid?: string,
description?: string, description?: string,
@ -540,9 +528,9 @@ export async function createAndSubmitGive(
fulfillsOfferHandleId?: string, fulfillsOfferHandleId?: string,
isTrade: boolean = false, isTrade: boolean = false,
imageUrl?: string, imageUrl?: string,
): Promise<CreateAndSubmitClaimResult> { ): GiveVerifiableCredential {
const vcClaim: GiveVerifiableCredential = { const vcClaim: GiveVerifiableCredential = {
"@context": "https://schema.org", "@context": SCHEMA_ORG_CONTEXT,
"@type": "GiveAction", "@type": "GiveAction",
recipient: toDid ? { identifier: toDid } : undefined, recipient: toDid ? { identifier: toDid } : undefined,
agent: fromDid ? { identifier: fromDid } : undefined, agent: fromDid ? { identifier: fromDid } : undefined,
@ -569,6 +557,43 @@ export async function createAndSubmitGive(
if (imageUrl) { if (imageUrl) {
vcClaim.image = imageUrl; vcClaim.image = imageUrl;
} }
return vcClaim;
}
/**
* 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
* @param amount may be null; should have this or description
*/
export async function createAndSubmitGive(
axios: Axios,
apiServer: string,
identity: IIdentifier,
fromDid?: string | null,
toDid?: string,
description?: string,
amount?: number,
unitCode?: string,
fulfillsProjectHandleId?: string,
fulfillsOfferHandleId?: string,
isTrade: boolean = false,
imageUrl?: string,
): Promise<CreateAndSubmitClaimResult> {
const vcClaim = constructGive(
fromDid,
toDid,
description,
amount,
unitCode,
fulfillsProjectHandleId,
fulfillsOfferHandleId,
isTrade,
imageUrl,
);
return createAndSubmitClaim( return createAndSubmitClaim(
vcClaim as GenericCredWrapper, vcClaim as GenericCredWrapper,
identity, identity,
@ -598,7 +623,7 @@ export async function createAndSubmitOffer(
fulfillsProjectHandleId?: string, fulfillsProjectHandleId?: string,
): Promise<CreateAndSubmitClaimResult> { ): Promise<CreateAndSubmitClaimResult> {
const vcClaim: OfferVerifiableCredential = { const vcClaim: OfferVerifiableCredential = {
"@context": "https://schema.org", "@context": SCHEMA_ORG_CONTEXT,
"@type": "Offer", "@type": "Offer",
offeredBy: { identifier: identity.did }, offeredBy: { identifier: identity.did },
validThrough: expirationDate || undefined, validThrough: expirationDate || undefined,
@ -645,7 +670,7 @@ export const createAndSubmitConfirmation = async (
), ),
); );
const confirmationClaim: GenericVerifiableCredential = { const confirmationClaim: GenericVerifiableCredential = {
"@context": "https://schema.org", "@context": SCHEMA_ORG_CONTEXT,
"@type": "AgreeAction", "@type": "AgreeAction",
object: goodClaim, object: goodClaim,
}; };
@ -928,7 +953,7 @@ export async function register(
const identity = await getIdentity(activeDid); const identity = await getIdentity(activeDid);
const vcClaim: RegisterVerifiableCredential = { const vcClaim: RegisterVerifiableCredential = {
"@context": "https://schema.org", "@context": SCHEMA_ORG_CONTEXT,
"@type": "RegisterAction", "@type": "RegisterAction",
agent: { identifier: identity.did }, agent: { identifier: identity.did },
object: SERVICE_ID, object: SERVICE_ID,

5
src/router/index.ts

@ -38,6 +38,11 @@ const routes: Array<RouteRecordRaw> = [
name: "claim", name: "claim",
component: () => import("../views/ClaimView.vue"), component: () => import("../views/ClaimView.vue"),
}, },
{
path: "/claim-add-raw/:id?",
name: "claim-add-raw",
component: () => import("../views/ClaimAddRawView.vue"),
},
{ {
path: "/confirm-contact", path: "/confirm-contact",
name: "confirm-contact", name: "confirm-contact",

133
src/views/AccountViewView.vue

@ -314,7 +314,7 @@
> >
Advanced Advanced
</h3> </h3>
<div v-if="showAdvanced"> <div v-if="showAdvanced || showGeneralAdvanced">
<p class="text-rose-600 mb-8"> <p class="text-rose-600 mb-8">
Beware: the features here can be confusing and even change data in ways Beware: the features here can be confusing and even change data in ways
you do not expect. But we support your freedom! you do not expect. But we support your freedom!
@ -386,6 +386,27 @@
Switch Identifier Switch Identifier
</router-link> </router-link>
<div class="mt-4">
<h2 class="text-slate-500 text-sm font-bold">
Contacts & Settings Database
</h2>
<div class="ml-4 mt-2">
Import
<input type="file" @change="uploadImportFile" class="ml-2" />
<div v-if="showContactImport()">
<button
class="block text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-6"
@click="confirmSubmitImportFile()"
>
Import Settings & Contacts
<br />
(excluding Identifier Data)
</button>
</div>
</div>
</div>
<label <label
for="toggleShowAmounts" for="toggleShowAmounts"
class="flex items-center justify-between cursor-pointer my-4" class="flex items-center justify-between cursor-pointer my-4"
@ -583,27 +604,6 @@
</div> </div>
</label> </label>
<div class="mt-4">
<h2 class="text-slate-500 text-sm font-bold">
Contacts & Settings Database
</h2>
<div class="ml-4 mt-2">
Import
<input type="file" @change="uploadImportFile" class="ml-2" />
<div v-if="showContactImport()">
<button
class="block text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-6"
@click="confirmSubmitImportFile()"
>
Import Settings & Contacts
<br />
(excluding Identifier Data)
</button>
</div>
</div>
</div>
<div class="flex mt-4"> <div class="flex mt-4">
<button> <button>
<router-link <router-link
@ -614,6 +614,32 @@
</router-link> </router-link>
</button> </button>
</div> </div>
<label
for="toggleShowGeneralAdvanced"
class="flex items-center justify-between cursor-pointer mt-4"
@click="toggleShowGeneralAdvanced"
>
<!-- label -->
<span class="text-slate-500 text-sm font-bold">
Show All General Advanced Functions
</span>
<!-- toggle -->
<div class="relative ml-2">
<!-- input -->
<input
type="checkbox"
v-model="showGeneralAdvanced"
class="sr-only"
/>
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full" />
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
/>
</div>
</label>
</div> </div>
</section> </section>
</template> </template>
@ -677,31 +703,31 @@ export default class AccountViewView extends Vue {
downloadUrl = ""; // because DuckDuckGo doesn't download on automated call to "click" on the anchor downloadUrl = ""; // because DuckDuckGo doesn't download on automated call to "click" on the anchor
endorserLimits: EndorserRateLimits | null = null; endorserLimits: EndorserRateLimits | null = null;
givenName = ""; givenName = "";
hideRegisterPromptOnNewContact = false;
imageLimits: ImageRateLimits | null = null; imageLimits: ImageRateLimits | null = null;
isRegistered = false; isRegistered = false;
isSubscribed = false; isSubscribed = false;
limitsMessage = "";
loadingLimits = false;
notificationMaybeChanged = false; notificationMaybeChanged = false;
profileImageUrl?: string; profileImageUrl?: string;
publicHex = ""; publicHex = "";
publicBase64 = ""; publicBase64 = "";
showLargeIdenticonId?: string; showAdvanced = false;
showLargeIdenticonUrl?: string; showB64Copy = false;
webPushServer = "";
webPushServerInput = "";
limitsMessage = "";
loadingLimits = false;
showContactGives = false; showContactGives = false;
showDidCopy = false; showDidCopy = false;
showDerCopy = false; showDerCopy = false;
showB64Copy = false; showGeneralAdvanced = false;
showLargeIdenticonId?: string;
showLargeIdenticonUrl?: string;
showPubCopy = false; showPubCopy = false;
showAdvanced = false;
hideRegisterPromptOnNewContact = false;
showShortcutBvc = false; showShortcutBvc = false;
subscription: PushSubscription | null = null; subscription: PushSubscription | null = null;
warnIfProdServer = false; warnIfProdServer = false;
warnIfTestServer = false; warnIfTestServer = false;
webPushServer = "";
webPushServerInput = "";
/** /**
* Async function executed when the component is mounted. * Async function executed when the component is mounted.
@ -756,6 +782,7 @@ export default class AccountViewView extends Vue {
this.showContactGives = !!settings?.showContactGivesInline; this.showContactGives = !!settings?.showContactGivesInline;
this.hideRegisterPromptOnNewContact = this.hideRegisterPromptOnNewContact =
!!settings?.hideRegisterPromptOnNewContact; !!settings?.hideRegisterPromptOnNewContact;
this.showGeneralAdvanced = !!settings?.showGeneralAdvanced;
this.showShortcutBvc = !!settings?.showShortcutBvc; this.showShortcutBvc = !!settings?.showShortcutBvc;
this.warnIfProdServer = !!settings?.warnIfProdServer; this.warnIfProdServer = !!settings?.warnIfProdServer;
this.warnIfTestServer = !!settings?.warnIfTestServer; this.warnIfTestServer = !!settings?.warnIfTestServer;
@ -819,6 +846,11 @@ export default class AccountViewView extends Vue {
this.updateShowContactAmounts(); this.updateShowContactAmounts();
} }
toggleShowGeneralAdvanced() {
this.showGeneralAdvanced = !this.showGeneralAdvanced;
this.updateShowGeneralAdvanced();
}
toggleProdWarning() { toggleProdWarning() {
this.warnIfProdServer = !this.warnIfProdServer; this.warnIfProdServer = !this.warnIfProdServer;
this.updateWarnIfProdServer(this.warnIfProdServer); this.updateWarnIfProdServer(this.warnIfProdServer);
@ -852,10 +884,6 @@ export default class AccountViewView extends Vue {
this.publicHex = identity.keys[0].publicKeyHex; this.publicHex = identity.keys[0].publicKeyHex;
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64"); this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
this.derivationPath = identity.keys[0].meta?.derivationPath as string; this.derivationPath = identity.keys[0].meta?.derivationPath as string;
db.settings.update(MASTER_SETTINGS_KEY, {
activeDid: identity.did,
});
this.checkLimitsFor(identity); this.checkLimitsFor(identity);
} else { } else {
// Handle the case where any of these are null or undefined // Handle the case where any of these are null or undefined
@ -915,7 +943,7 @@ export default class AccountViewView extends Vue {
public async updateShowContactAmounts() { public async updateShowContactAmounts() {
try { try {
await db.open(); await db.open();
db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
showContactGivesInline: this.showContactGives, showContactGivesInline: this.showContactGives,
}); });
} catch (err) { } catch (err) {
@ -935,10 +963,33 @@ export default class AccountViewView extends Vue {
} }
} }
public async updateShowGeneralAdvanced() {
try {
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, {
showGeneralAdvanced: this.showGeneralAdvanced,
});
} catch (err) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Updating Advanced Setting",
text: "The setting may not have saved. Try again, maybe after restarting the app.",
},
-1,
);
console.error(
"Telling user to try again after general-advanced setting update because:",
err,
);
}
}
public async updateWarnIfProdServer(newSetting: boolean) { public async updateWarnIfProdServer(newSetting: boolean) {
try { try {
await db.open(); await db.open();
db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
warnIfProdServer: newSetting, warnIfProdServer: newSetting,
}); });
} catch (err) { } catch (err) {
@ -961,7 +1012,7 @@ export default class AccountViewView extends Vue {
public async updateWarnIfTestServer(newSetting: boolean) { public async updateWarnIfTestServer(newSetting: boolean) {
try { try {
await db.open(); await db.open();
db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
warnIfTestServer: newSetting, warnIfTestServer: newSetting,
}); });
} catch (err) { } catch (err) {
@ -985,7 +1036,7 @@ export default class AccountViewView extends Vue {
const newSetting = !this.hideRegisterPromptOnNewContact; const newSetting = !this.hideRegisterPromptOnNewContact;
try { try {
await db.open(); await db.open();
db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: newSetting, hideRegisterPromptOnNewContact: newSetting,
}); });
this.hideRegisterPromptOnNewContact = newSetting; this.hideRegisterPromptOnNewContact = newSetting;
@ -1006,7 +1057,7 @@ export default class AccountViewView extends Vue {
public async updateShowShortcutBvc(newSetting: boolean) { public async updateShowShortcutBvc(newSetting: boolean) {
try { try {
await db.open(); await db.open();
db.settings.update(MASTER_SETTINGS_KEY, { await db.settings.update(MASTER_SETTINGS_KEY, {
showShortcutBvc: newSetting, showShortcutBvc: newSetting,
}); });
} catch (err) { } catch (err) {

133
src/views/ClaimAddRawView.vue

@ -0,0 +1,133 @@
<template>
<QuickNav />
<!-- CONTENT -->
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
<!-- Breadcrumb -->
<div id="ViewBreadcrumb" class="mb-8">
<h1 class="text-lg text-center font-light relative px-7">
<!-- Back -->
<button
@click="$router.go(-1)"
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
>
<fa icon="chevron-left" class="fa-fw" />
</button>
Raw Claim
</h1>
</div>
<div class="flex">
<textarea rows="20" class="w-full" v-model="claimStr"></textarea>
</div>
<button
class="block w-full text-center text-lg font-bold uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md"
@click="submitClaim()"
>
Sign &amp; Send
</button>
</section>
</template>
<script lang="ts">
import { RawAxiosRequestHeaders } from "axios";
import { IIdentifier } from "@veramo/core";
import { Component, Vue } from "vue-facing-decorator";
import GiftedDialog from "@/components/GiftedDialog.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";
import * as serverUtil from "@/libs/endorserServer";
import QuickNav from "@/components/QuickNav.vue";
import { Account } from "@/db/tables/accounts";
@Component({
components: { GiftedDialog, QuickNav },
})
export default class ClaimAddRawView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
accountIdentityStr: string = "null";
activeDid = "";
apiServer = "";
claimStr = "";
async mounted() {
await db.open();
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
this.activeDid = settings?.activeDid || "";
this.apiServer = settings?.apiServer || "";
this.claimStr = this.$route.query.claim;
try {
this.veriClaim = JSON.parse(this.claimStr);
this.claimStr = JSON.stringify(this.veriClaim, null, 2);
} catch (e) {
// ignore a parse
}
}
public async getIdentity(activeDid: string): Promise<IIdentifier> {
await accountsDB.open();
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("Cannot submit a claim without an identifier.");
}
return identity;
}
public async getHeaders(identity: IIdentifier) {
const headers: RawAxiosRequestHeaders = {
"Content-Type": "application/json",
};
if (identity) {
const token = await accessToken(identity);
headers["Authorization"] = "Bearer " + token;
}
return headers;
}
// similar code is found in ProjectViewView
async submitClaim() {
const fullClaim: serverUtil.GenericVerifiableCredential = {
"@context": "https://schema.org",
"@type": "AgreeAction",
object: JSON.parse(this.claimStr),
};
const result = await serverUtil.createAndSubmitClaim(
fullClaim,
await this.getIdentity(this.activeDid),
this.apiServer,
this.axios,
);
if (result.type === "success") {
this.$notify(
{
group: "alert",
type: "success",
title: "Success",
text: "Claim submitted.",
},
5000,
);
} else {
console.error("Got error submitting the claim:", result);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: "There was a problem submitting the claim. See logs for more info.",
},
-1,
);
}
}
}
</script>

143
src/views/GiftedDetails.vue

@ -21,8 +21,17 @@
<h1 class="text-4xl text-center font-light px-4 mb-4">What Was Given</h1> <h1 class="text-4xl text-center font-light px-4 mb-4">What Was Given</h1>
<h1 class="text-xl font-bold text-center mb-4"> <h1 class="text-xl font-bold text-center mb-4">
<span>From {{ giverName || "somebody not named" }}</span> <span>From {{ giverName }}</span>
<span> to {{ recipientName || "somebody not named" }}</span> <span>
to
{{
givenToProject
? projectName
: givenToRecipient
? recipientName
: "someone unidentified"
}}</span
>
</h1> </h1>
<textarea <textarea
class="block w-full rounded border border-slate-400 mb-2 px-3 py-2" class="block w-full rounded border border-slate-400 mb-2 px-3 py-2"
@ -78,7 +87,7 @@
<div class="h-7 mt-4 flex"> <div class="h-7 mt-4 flex">
<input <input
v-if="projectId && !givenToUser" v-if="projectId && !givenToRecipient"
type="checkbox" type="checkbox"
class="h-6 w-6 mr-2" class="h-6 w-6 mr-2"
v-model="givenToProject" v-model="givenToProject"
@ -100,20 +109,24 @@
<div class="h-7 mt-4 flex"> <div class="h-7 mt-4 flex">
<input <input
v-if="!givenToProject" v-if="recipientDid && !givenToProject"
type="checkbox" type="checkbox"
class="h-6 w-6 mr-2" class="h-6 w-6 mr-2"
v-model="givenToUser" v-model="givenToRecipient"
/> />
<fa <fa
v-else v-else
icon="square" icon="square"
class="bg-slate-500 text-slate-500 h-5 w-5 px-0.5 py-0.5 mr-2 rounded" class="bg-slate-500 text-slate-500 h-5 w-5 px-0.5 py-0.5 mr-2 rounded"
@click=" @click="notifyUserOfRecipient()"
notifyUser('You cannot assign this both a project and also to you.')
"
/> />
<label class="text-sm mt-1">This was given to you</label> <label class="text-sm mt-1">
{{
recipientDid
? "This was given to " + recipientName
: "No recipient was chosen."
}}
</label>
</div> </div>
<div class="mt-4 flex"> <div class="mt-4 flex">
@ -121,6 +134,20 @@
<label class="text-sm mt-1">This was a trade (not a gift)</label> <label class="text-sm mt-1">This was a trade (not a gift)</label>
</div> </div>
<div class="mt-4 flex">
<router-link
:to="{
name: 'claim-add-raw',
query: {
claim: constructGiveParam(),
},
}"
class="text-blue-500"
>
Edit & Submit Raw
</router-link>
</div>
<p class="text-center mb-2 mt-6 italic"> <p class="text-center mb-2 mt-6 italic">
Sign & Send to publish to the world Sign & Send to publish to the world
<fa <fa
@ -153,11 +180,16 @@ import ImageMethodDialog from "@/components/ImageMethodDialog.vue";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue"; import TopMessage from "@/components/TopMessage.vue";
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app"; import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "@/constants/app";
import { 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 { createAndSubmitGive, getPlanFromCache } from "@/libs/endorserServer"; import {
constructGive,
createAndSubmitGive, didInfo,
getPlanFromCache,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util"; import * as libsUtil from "@/libs/util";
import { accessToken } from "@/libs/crypto"; import { accessToken } from "@/libs/crypto";
import {Contact} from "@/db/tables/contacts";
@Component({ @Component({
components: { components: {
@ -176,7 +208,7 @@ export default class GiftedDetails extends Vue {
description = ""; description = "";
destinationNameAfter = ""; destinationNameAfter = "";
givenToProject = false; givenToProject = false;
givenToUser = false; givenToRecipient = false;
giverDid: string | undefined; giverDid: string | undefined;
giverName = ""; giverName = "";
hideBackButton = false; hideBackButton = false;
@ -188,7 +220,6 @@ export default class GiftedDetails extends Vue {
projectName = "a project"; projectName = "a project";
recipientDid = ""; recipientDid = "";
recipientName = ""; recipientName = "";
showGivenToUser = false;
unitCode = "HUR"; unitCode = "HUR";
libsUtil = libsUtil; libsUtil = libsUtil;
@ -234,18 +265,36 @@ export default class GiftedDetails extends Vue {
this.apiServer = settings?.apiServer || ""; this.apiServer = settings?.apiServer || "";
this.activeDid = settings?.activeDid || ""; 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) { if (this.giverDid && !this.giverName) {
this.giverName = this.giverName = didInfo(
this.giverDid === this.activeDid ? "you" : "someone not named"; this.giverDid,
this.activeDid,
allMyDids,
allContacts,
);
} }
this.givenToUser = this.recipientDid === this.activeDid;
if (this.recipientDid && !this.recipientName) { if (this.recipientDid && !this.recipientName) {
this.recipientName = this.recipientName = didInfo(
this.recipientDid === this.activeDid ? "you" : "someone not named"; this.recipientDid,
this.activeDid,
allMyDids,
allContacts,
);
}
} }
this.givenToProject = !!this.projectId; this.givenToProject = !!this.projectId;
this.givenToUser = this.givenToRecipient = !this.givenToProject && !!this.recipientDid;
!this.projectId && this.recipientDid === this.activeDid;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) { } catch (err: any) {
@ -442,37 +491,50 @@ export default class GiftedDetails extends Vue {
await this.recordGive(); await this.recordGive();
} }
notifyUser(message: string) { notifyUserOfProject() {
if (!this.projectId) {
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "warning", type: "warning",
title: "Error", title: "Error",
text: message, text: "To assign to a project, you must open this dialog through a project.",
},
3000,
);
} else {
// must be because givenToRecipient is true
this.$notify(
{
group: "alert",
type: "warning",
title: "Error",
text: "You cannot assign both to a project and to a recipient.",
}, },
3000, 3000,
); );
} }
}
notifyUserOfProject() { notifyUserOfRecipient() {
if (!this.projectId) { if (!this.recipientDid) {
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "warning", type: "warning",
title: "Error", title: "Error",
text: "To assign to a project, you must open this dialog through a project.", text: "To assign to a recipient, you must open this dialog from a contact.",
}, },
3000, 3000,
); );
} else { } else {
// must be because givenToUser is true // must be because givenToProject is true
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "warning", type: "warning",
title: "Error", title: "Error",
text: "You cannot assign both to a project and to yourself.", text: "You cannot assign both to a recipient and to a project.",
}, },
3000, 3000,
); );
@ -489,12 +551,9 @@ export default class GiftedDetails extends Vue {
public async recordGive() { public async recordGive() {
try { try {
const identity = await libsUtil.getIdentity(this.activeDid); const identity = await libsUtil.getIdentity(this.activeDid);
const recipientDid = const recipientDid = this.givenToRecipient
this.recipientDid === this.activeDid ? this.recipientDid
? this.givenToUser : undefined;
? this.activeDid
: undefined
: this.recipientDid;
const projectId = this.givenToProject ? this.projectId : undefined; const projectId = this.givenToProject ? this.projectId : undefined;
const result = await createAndSubmitGive( const result = await createAndSubmitGive(
this.axios, this.axios,
@ -562,6 +621,24 @@ export default class GiftedDetails extends Vue {
} }
} }
constructGiveParam() {
const recipientDid = this.givenToRecipient ? this.recipientDid : undefined;
const projectId = this.givenToProject ? this.projectId : undefined;
const giveClaim = constructGive(
this.giverDid,
recipientDid,
this.description,
parseFloat(this.amountInput),
this.unitCode,
projectId,
this.offerId,
this.isTrade,
this.imageUrl,
);
const claimStr = JSON.stringify(giveClaim);
return claimStr;
}
// Helper functions for readability // Helper functions for readability
/** /**

Loading…
Cancel
Save