Browse Source

feat: allow entry and send of a Give to/from addresses in contact list

pull/11/head
Trent Larson 2 years ago
parent
commit
392728fd4a
  1. 177
      src/views/ContactsView.vue

177
src/views/ContactsView.vue

@ -69,17 +69,28 @@
<!-- eslint-disable-next-line --> <!-- eslint-disable-next-line -->
<div <div
class="block flex w-full" class="flex justify-between"
> >
<!-- eslint-disable-next-line --> <!-- eslint-disable-next-line -->
<button <div class="w-1/2 text-left">
href="" <button
class="text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-6" href=""
v-if="showGiveTotals" class="left text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-6"
@click="loadGives()" v-if="showGiveTotals"
> @click="loadGives()"
Load Totals >
</button> Load Totals
</button>
</div>
<div class="w-1/2 text-right">
Hours to Add:
<input
class="border border rounded border-slate-400 w-24 text-right"
type="text"
placeholder="1"
v-model="hourInput"
/>
</div>
</div> </div>
<!-- Results List --> <!-- Results List -->
@ -97,11 +108,20 @@
<div class="text-sm truncate">{{ contact.publicKeyBase64 }}</div> <div class="text-sm truncate">{{ contact.publicKeyBase64 }}</div>
<div v-if="showGiveTotals" class="float-right"> <div v-if="showGiveTotals" class="float-right">
<div class="float-right"> <div class="float-right">
to: {{ contactGivenTotals[contact.did] || 0 }} to: {{ givenByMeTotals[contact.did] || 0 }}
</div> <button
<br /> class="text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-6"
<div class="float-right"> @click="onClickAddGive(identity.did, contact.did)"
from: {{ contactReceivedTotals[contact.did] || 0 }} >
+
</button>
by: {{ givenToMeTotals[contact.did] || 0 }}
<button
class="text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-6"
@click="onClickAddGive(contact.did, identity.did)"
>
+
</button>
</div> </div>
</div> </div>
</div> </div>
@ -111,14 +131,24 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { AxiosError } from "axios";
import * as didJwt from "did-jwt";
import { Options, Vue } from "vue-class-component"; import { Options, Vue } from "vue-class-component";
import { IIdentifier } from "@veramo/core";
import { AppString } from "@/constants/app"; import { AppString } from "@/constants/app";
import { accessToken } from "@/libs/crypto"; import { accessToken, SimpleSigner } from "@/libs/crypto";
import { IIdentifier } from "@veramo/core";
import { db } from "../db"; import { db } from "../db";
import { Contact } from "../db/tables/contacts.ts"; import { Contact } from "../db/tables/contacts.ts";
export interface GiveVerifiableCredential {
"@context": string;
"@type": string;
agent: { identifier: string };
recipient: { identifier: string };
object: { amountOfThisGood: number; unitCode: string };
}
@Options({ @Options({
components: {}, components: {},
}) })
@ -126,9 +156,10 @@ export default class ContactsView extends Vue {
contacts: Contact[] = []; contacts: Contact[] = [];
contactInput = ""; contactInput = "";
// { "did:...": amount } entry for each contact // { "did:...": amount } entry for each contact
contactGivenTotals = {}; givenByMeTotals = {};
// { "did:...": amount } entry for each contact // { "did:...": amount } entry for each contact
contactReceivedTotals = {}; givenToMeTotals = {};
hourInput = 0;
identity: IIdentifier = null; identity: IIdentifier = null;
errorMessage = ""; errorMessage = "";
showGiveTotals = false; showGiveTotals = false;
@ -188,7 +219,7 @@ export default class ContactsView extends Vue {
} }
} }
//console.log("Done retrieving gives", contactTotals); //console.log("Done retrieving gives", contactTotals);
this.contactGivenTotals = contactTotals; this.givenByMeTotals = contactTotals;
} }
} catch (error) { } catch (error) {
this.errorMessage = "" + error; this.errorMessage = "" + error;
@ -216,11 +247,117 @@ export default class ContactsView extends Vue {
} }
} }
//console.log("Done retrieving receipts", contactTotals); //console.log("Done retrieving receipts", contactTotals);
this.contactReceivedTotals = contactTotals; this.givenToMeTotals = contactTotals;
} }
} catch (error) { } catch (error) {
this.errorMessage = "" + error; this.errorMessage = "" + error;
} }
} }
// from https://stackoverflow.com/a/175787/845494
private isNumeric(str): boolean {
return !isNaN(str) && !isNaN(parseFloat(str));
}
async onClickAddGive(fromDid: string, toDid: string): void {
if (!this.hourInput) {
this.errorMessage = "Giving 0 hours does nothing.";
} else if (!this.isNumeric(this.hourInput)) {
this.errorMessage =
"This is not a valid number of hours: " + this.hourInput;
} else {
this.errorMessage = "";
this.createAndSubmitGive(fromDid, toDid, parseFloat(this.hourInput));
}
}
private async createAndSubmitGive(
fromDid: string,
toDid: string,
amount: number
): void {
// Make a claim
const vcClaim: GiveVerifiableCredential = {
"@context": "https://schema.org",
"@type": "GiveAction",
agent: { identifier: fromDid },
recipient: { identifier: toDid },
object: { amountOfThisGood: amount, unitCode: "HUR" },
};
// Make a payload for the claim
const vcPayload = {
vc: {
"@context": ["https://www.w3.org/2018/credentials/v1"],
type: ["VerifiableCredential"],
credentialSubject: vcClaim,
},
};
// Create a signature using private key of identity
if (this.identity.keys[0].privateKeyHex !== null) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const privateKeyHex: string = this.identity.keys[0].privateKeyHex!;
const signer = await SimpleSigner(privateKeyHex);
const alg = undefined;
// Create a JWT for the request
const vcJwt: string = await didJwt.createJWT(vcPayload, {
alg: alg,
issuer: this.identity.did,
signer: signer,
});
// Make the xhr request payload
const payload = JSON.stringify({ jwtEncoded: vcJwt });
const endorserApiServer = AppString.DEFAULT_ENDORSER_API_SERVER;
const url = endorserApiServer + "/api/v2/claim";
const token = await accessToken(this.identity);
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
};
try {
const resp = await this.axios.post(url, payload, { headers });
console.log("Got resp data:", resp.data);
if (resp.data?.success?.handleId) {
this.errorMessage = "";
this.alertTitle = "";
this.alertMessage = "";
if (fromDid === this.identity.did) {
this.givenByMeTotals[toDid] = this.givenByMeTotals[toDid] + amount;
// do this to update the UI
// eslint-disable-next-line no-self-assign
this.givenByMeTotals = this.givenByMeTotals;
} else {
this.givenToMeTotals[fromDid] =
this.givenToMeTotals[fromDid] + amount;
// do this to update the UI
// eslint-disable-next-line no-self-assign
this.givenToMeTotals = this.givenToMeTotals;
}
}
} catch (error) {
let userMessage = "There was an error. See logs for more info.";
const serverError = error as AxiosError;
if (serverError) {
this.isAlertVisible = true;
if (serverError.message) {
this.alertTitle = "User Message";
userMessage = serverError.message; // This is info for the user.
this.alertMessage = userMessage;
} else {
this.alertTitle = "Server Message";
this.alertMessage = JSON.stringify(serverError.toJSON());
}
} else {
console.log("Here's the full error trying to save the claim:", error);
this.alertTitle = "Claim Error";
this.alertMessage = error as string;
}
// Now set that error for the user to see.
this.errorMessage = userMessage;
}
}
}
} }
</script> </script>

Loading…
Cancel
Save