diff --git a/project.task.yaml b/project.task.yaml index f9c926b..8014710 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -7,8 +7,6 @@ tasks: - 8 Move to vue-facing-decorator - 01 design ideas for simple gives on the first page -- 01 give time to a particular project - use "provider" attribute - - give example assignee:trent - .1 remove commitments from ProjectView UI - 01 add list of 'give' records for a project on ProjectView UI diff --git a/src/components/GiftedDialog.vue b/src/components/GiftedDialog.vue index c48ce3c..c158cc3 100644 --- a/src/components/GiftedDialog.vue +++ b/src/components/GiftedDialog.vue @@ -2,13 +2,12 @@

- Received from {{ contact?.name || "nobody in particular" }} + {{ message }} {{ giver?.name || "somebody not specified" }}

-

{{ message }}

@@ -27,9 +26,10 @@
+

Sign & Send to publish to the world

  - or -
@@ -74,7 +72,7 @@ @@ -278,13 +276,13 @@ export default class HomeView extends Vue { return unitCode === "HUR" ? (single ? "hour" : "hours") : unitCode; } - openDialog(contact) { - this.$refs.customDialog.open(contact); + openDialog(giver) { + this.$refs.customDialog.open(giver); } handleDialogResult(result) { if (result.action === "confirm") { return new Promise((resolve) => { - this.recordGive(result.contact, result.description, result.hours); + this.recordGive(result.contact?.did, result.description, result.hours); resolve(); }); } else { @@ -294,17 +292,23 @@ export default class HomeView extends Vue { /** * - * @param contact may be null + * @param giverDid may be null * @param description may be an empty string * @param hours may be 0 */ - recordGive(contact, description, hours) { + recordGive(giverDid, description, hours) { if (this.activeDid == null) { this.alertTitle = "Error"; this.alertMessage = "You must select an identity before you can record a give."; return; } + if (!description && !hours) { + this.alertTitle = "Error"; + this.alertMessage = + "You must enter a description or some number of hours."; + return; + } const account = R.find( (acc) => acc.did === this.activeDid, this.allAccounts @@ -318,7 +322,7 @@ export default class HomeView extends Vue { this.axios, this.apiServer, identity, - contact?.did, + giverDid, this.activeDid, description, hours @@ -328,7 +332,8 @@ export default class HomeView extends Vue { console.log("Error with give result:", result); this.alertTitle = "Error"; this.alertMessage = - result.data?.message || "There was an error recording the give."; + result.data?.error?.message || + "There was an error recording the give."; } else { this.alertTitle = "Success"; this.alertMessage = "That gift was recorded."; @@ -336,10 +341,13 @@ export default class HomeView extends Vue { } }) .catch((e) => { + // axios throws errors on 400 responses console.log("Error with give caught:", e); this.alertTitle = "Error"; this.alertMessage = - e.userMessage || "There was an error recording the give."; + e.userMessage || + e.response?.data?.error?.message || + "There was an error recording the give."; }); } diff --git a/src/views/ProjectViewView.vue b/src/views/ProjectViewView.vue index 37fd059..dc9c5a9 100644 --- a/src/views/ProjectViewView.vue +++ b/src/views/ProjectViewView.vue @@ -9,7 +9,7 @@ > -
  • +
  • -
  • +
  • + + +
    +

    ... or choose a contact who gave:

    + +
    + +  or  + +
    +
    + + + + + + + + +
    + +

    {{ alertTitle }}

    +

    {{ alertMessage }}

    +
    @@ -151,15 +200,20 @@ 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 { Contact } from "@/db/tables/contacts"; 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 = ""; + allContacts: Array = []; apiServer = ""; expanded = false; name = ""; @@ -167,7 +221,7 @@ export default class ProjectViewView extends Vue { truncatedDesc = ""; truncateLength = 40; timeSince = ""; - projectId = localStorage.getItem("projectId") || ""; + projectId = localStorage.getItem("projectId") || ""; // handle ID errorMessage = ""; onEditClick() { @@ -230,8 +284,9 @@ 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 || ""; + this.allContacts = await db.contacts.toArray(); await accountsDB.open(); const num_accounts = await accountsDB.accounts.count(); @@ -239,7 +294,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 +302,102 @@ 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?.did, result.description, result.hours); + resolve(); + }); + } else { + // action was not "confirm" so do nothing + } + } + + /** + * + * @param giverDid may be null + * @param description may be an empty string + * @param hours may be 0 + */ + async recordGive(giverDid, description, hours) { + if (this.activeDid == null) { + this.alertTitle = "Error"; + this.alertMessage = + "You must select an identity before you can record a give."; + return; + } + if (!description && !hours) { + this.alertTitle = "Error"; + this.alertMessage = + "You must enter a description or some number of hours."; + 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, + giverDid, + 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?.error?.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) => { + // axios throws errors on 400 responses + console.log("Error with give caught:", e); + this.alertTitle = "Error"; + this.alertMessage = + e.userMessage || + e.response?.data?.error?.message || + "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, + }; + } }