Browse Source

start linking gives to projects

kb/add-usage-guide
Trent Larson 1 year ago
parent
commit
643f777d10
  1. 12
      src/libs/endorserServer.ts
  2. 120
      src/views/ProjectViewView.vue
  3. 12
      src/views/ProjectsView.vue

12
src/libs/endorserServer.ts

@ -46,6 +46,7 @@ export interface GiveVerifiableCredential {
"@type": string;
agent?: { identifier: string };
description?: string;
fulfills?: { "@type": string; identifier: string };
identifier?: string;
object?: { amountOfThisGood: number; unitCode: string };
recipient: { identifier: string };
@ -95,7 +96,7 @@ export function didInfo(did, identifiers, contacts) {
/**
* For result, see https://endorser.ch:3000/api-docs/#/claims/post_api_v2_claim
*
* @param identity
* @param fromDid may be null
* @param toDid
@ -109,7 +110,8 @@ export async function createAndSubmitGive(
fromDid: string,
toDid: string,
description: string,
hours: number
hours: number,
fulfillsProjectHandleId: string
): Promise<AxiosResponse<ClaimResult> | InternalError> {
// Make a claim
const vcClaim: GiveVerifiableCredential = {
@ -126,6 +128,12 @@ export async function createAndSubmitGive(
if (hours) {
vcClaim.object = { amountOfThisGood: hours, unitCode: "HUR" };
}
if (fulfillsProjectHandleId) {
vcClaim.fulfills = {
"@type": "PlanAction",
identifier: fulfillsProjectHandleId,
};
}
// Make a payload for the claim
const vcPayload = {
vc: {

120
src/views/ProjectViewView.vue

@ -9,7 +9,7 @@
></router-link>
</li>
<!-- Search -->
<li class="basis-1/5 rounded-md bg-slate-400 text-white">
<li class="basis-1/5 rounded-md text-slate-500">
<router-link
:to="{ name: 'discover' }"
class="block text-center py-3 px-1"
@ -17,7 +17,7 @@
></router-link>
</li>
<!-- Projects -->
<li class="basis-1/5 rounded-md text-slate-500">
<li class="basis-1/5 rounded-md bg-slate-400 text-white">
<router-link
:to="{ name: 'projects' }"
class="block text-center py-3 px-1"
@ -108,14 +108,31 @@
</button>
</div>
<button
@click="openDialog()"
class="block text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-8"
>
Given
</button>
<GiftedDialog
ref="customDialog"
@dialog-result="handleDialogResult"
message="Confirm to publish to the world."
>
</GiftedDialog>
<!-- Commit -->
<!--
<router-link
:to="{ name: 'new-edit-commitment' }"
class="block text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-8"
>Make Commitment</router-link
>
-->
<!-- Commitments -->
<!--
<div class="bg-slate-100 px-4 py-3 rounded-md">
<h3 class="text-sm uppercase font-semibold mb-3">Commitments</h3>
@ -142,6 +159,7 @@
</li>
</ul>
</div>
-->
</section>
</template>
@ -151,15 +169,18 @@ import * as moment from "moment";
import * as R from "ramda";
import { Options, Vue } from "vue-class-component";
import GiftedDialog from "@/components/GiftedDialog.vue";
import { accountsDB, db } from "@/db";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { createAndSubmitGive } from "@/libs/endorserServer";
import { accessToken } from "@/libs/crypto";
import { IIdentifier } from "@veramo/core";
@Options({
components: {},
components: { GiftedDialog },
})
export default class ProjectViewView extends Vue {
activeDid = "";
apiServer = "";
expanded = false;
name = "";
@ -167,7 +188,7 @@ export default class ProjectViewView extends Vue {
truncatedDesc = "";
truncateLength = 40;
timeSince = "";
projectId = localStorage.getItem("projectId") || "";
projectId = localStorage.getItem("projectId") || ""; // handle ID
errorMessage = "";
onEditClick() {
@ -230,7 +251,7 @@ export default class ProjectViewView extends Vue {
async created() {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
const activeDid = settings?.activeDid || "";
this.activeDid = settings?.activeDid || "";
this.apiServer = settings?.apiServer || "";
await accountsDB.open();
@ -239,7 +260,7 @@ export default class ProjectViewView extends Vue {
console.error("Problem! Should have a profile!");
} else {
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === activeDid, accounts);
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
@ -247,5 +268,92 @@ export default class ProjectViewView extends Vue {
this.LoadProject(identity);
}
}
openDialog(contact) {
this.$refs.customDialog.open(contact);
}
handleDialogResult(result) {
if (result.action === "confirm") {
return new Promise((resolve) => {
this.recordGive(result.contact, result.description, result.hours);
resolve();
});
} else {
// action was "cancel" so do nothing
}
}
/**
*
* @param contact may be null
* @param description may be an empty string
* @param hours may be 0
*/
async recordGive(contact, description, hours) {
if (this.activeDid == null) {
this.alertTitle = "Error";
this.alertMessage =
"You must select an identity before you can record a give.";
return;
}
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
createAndSubmitGive(
this.axios,
this.apiServer,
identity,
contact?.did,
this.activeDid,
description,
hours,
this.projectId
)
.then((result) => {
if (result.status != 201 || result.data?.error) {
console.log("Error with give result:", result);
this.alertTitle = "Error";
this.alertMessage =
result.data?.message || "There was an error recording the give.";
} else {
this.alertTitle = "Success";
this.alertMessage = "That gift was recorded.";
//this.updateAllFeed(); // full update is overkill but we should show something
}
})
.catch((e) => {
console.log("Error with give caught:", e);
this.alertTitle = "Error";
this.alertMessage =
e.userMessage || "There was an error recording the give.";
});
}
// This same popup code is in many files.
alertMessage = "";
alertTitle = "";
public onClickClose() {
this.alertTitle = "";
this.alertMessage = "";
}
public computedAlertClassNames() {
return {
hidden: !this.alertMessage,
"dismissable-alert": true,
"bg-slate-100": true,
"p-5": true,
rounded: true,
"drop-shadow-lg": true,
fixed: true,
"top-3": true,
"inset-x-3": true,
"transition-transform": true,
"ease-in": true,
"duration-300": true,
};
}
}
</script>

12
src/views/ProjectsView.vue

@ -185,9 +185,9 @@ export default class ProjectsView extends Vue {
}
/**
* Handle clicking on a project entry found in the list
* @param id of the project
**/
* Handle clicking on a project entry found in the list
* @param id of the project
**/
onClickLoadProject(id: string) {
localStorage.setItem("projectId", id);
const route = {
@ -197,9 +197,9 @@ export default class ProjectsView extends Vue {
}
/**
* Load projects initially
* @param identity of the user
**/
* Load projects initially
* @param identity of the user
**/
async LoadProjects(identity: IIdentifier) {
const url = `${this.apiServer}/api/v2/report/plansByIssuer`;
const token: string = await accessToken(identity);

Loading…
Cancel
Save