|
|
@ -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,50 @@ |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
<button |
|
|
|
@click="openDialog({ name: 'you', did: activeDid })" |
|
|
|
class="block text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-8" |
|
|
|
> |
|
|
|
I gave... |
|
|
|
</button> |
|
|
|
|
|
|
|
<div> |
|
|
|
<p>... or choose a contact who gave:</p> |
|
|
|
<!-- similar contact selection code is in multiple places --> |
|
|
|
<div class="px-4"> |
|
|
|
<button |
|
|
|
v-for="contact in allContacts" |
|
|
|
:key="contact.did" |
|
|
|
@click="openDialog(contact)" |
|
|
|
class="text-blue-500" |
|
|
|
> |
|
|
|
{{ contact.name }}, |
|
|
|
</button> |
|
|
|
<span v-if="allContacts.length > 0"> or </span> |
|
|
|
<button @click="openDialog()" class="text-blue-500"> |
|
|
|
someone not specified |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<GiftedDialog |
|
|
|
ref="customDialog" |
|
|
|
@dialog-result="handleDialogResult" |
|
|
|
message="Received from" |
|
|
|
> |
|
|
|
</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 +178,19 @@ |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
--> |
|
|
|
|
|
|
|
<!-- This same popup code is in many files. --> |
|
|
|
<div v-bind:class="computedAlertClassNames()"> |
|
|
|
<button |
|
|
|
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2" |
|
|
|
@click="onClickClose()" |
|
|
|
> |
|
|
|
<fa icon="xmark"></fa> |
|
|
|
</button> |
|
|
|
<h4 class="font-bold pr-5">{{ alertTitle }}</h4> |
|
|
|
<p>{{ alertMessage }}</p> |
|
|
|
</div> |
|
|
|
</section> |
|
|
|
</template> |
|
|
|
|
|
|
@ -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<Contact> = []; |
|
|
|
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, |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|