add advanced page & flag for editing raw claims, and fix recipient assignment in detail screen
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
Normal file
133
src/views/ClaimAddRawView.vue
Normal file
@@ -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 & 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>
|
||||||
@@ -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 || "";
|
||||||
|
|
||||||
if (this.giverDid && !this.giverName) {
|
let allContacts: Contact[] = [];
|
||||||
this.giverName =
|
let allMyDids: string[] = [];
|
||||||
this.giverDid === this.activeDid ? "you" : "someone not named";
|
if (
|
||||||
}
|
(this.giverDid && !this.giverName) ||
|
||||||
this.givenToUser = this.recipientDid === this.activeDid;
|
(this.recipientDid && !this.recipientName)
|
||||||
if (this.recipientDid && !this.recipientName) {
|
) {
|
||||||
this.recipientName =
|
allContacts = await db.contacts.toArray();
|
||||||
this.recipientDid === this.activeDid ? "you" : "someone not named";
|
|
||||||
|
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.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,18 +491,6 @@ export default class GiftedDetails extends Vue {
|
|||||||
await this.recordGive();
|
await this.recordGive();
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyUser(message: string) {
|
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "warning",
|
|
||||||
title: "Error",
|
|
||||||
text: message,
|
|
||||||
},
|
|
||||||
3000,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyUserOfProject() {
|
notifyUserOfProject() {
|
||||||
if (!this.projectId) {
|
if (!this.projectId) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
@@ -466,13 +503,38 @@ export default class GiftedDetails extends Vue {
|
|||||||
3000,
|
3000,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// must be because givenToUser is true
|
// must be because givenToRecipient 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 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 givenToProject is true
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "warning",
|
||||||
|
title: "Error",
|
||||||
|
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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user