Trent Larson
9 months ago
3 changed files with 338 additions and 13 deletions
@ -0,0 +1,313 @@ |
|||
<template> |
|||
<QuickNav /> |
|||
<TopMessage /> |
|||
|
|||
<!-- CONTENT --> |
|||
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto"> |
|||
<!-- Back --> |
|||
<div class="text-lg text-center font-light relative px-7"> |
|||
<h1 |
|||
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1" |
|||
@click="$router.back()" |
|||
> |
|||
<fa icon="chevron-left" class="fa-fw"></fa> |
|||
</h1> |
|||
</div> |
|||
|
|||
<!-- Heading --> |
|||
<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"> |
|||
{{ message }} {{ giverName || "somebody not named" }} |
|||
</h1> |
|||
<textarea |
|||
class="block w-full rounded border border-slate-400 mb-2 px-3 py-2" |
|||
placeholder="What was received" |
|||
v-model="description" |
|||
/> |
|||
<div class="flex flex-row"> |
|||
<span |
|||
class="rounded-l border border-r-0 border-slate-400 bg-slate-200 w-1/3 text-center text-blue-500 px-2 py-2" |
|||
@click="changeUnitCode()" |
|||
> |
|||
{{ libsUtil.UNIT_SHORT[unitCode] }} |
|||
</span> |
|||
<div |
|||
class="border border-r-0 border-slate-400 bg-slate-200 px-4 py-2" |
|||
@click="decrement()" |
|||
v-if="amountInput !== '0'" |
|||
> |
|||
<fa icon="chevron-left" /> |
|||
</div> |
|||
<input |
|||
type="number" |
|||
class="w-full border border-r-0 border-slate-400 px-2 py-2 text-center" |
|||
v-model="amountInput" |
|||
/> |
|||
<div |
|||
class="rounded-r border border-slate-400 bg-slate-200 px-4 py-2" |
|||
@click="increment()" |
|||
> |
|||
<fa icon="chevron-right" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="flex justify-center mb-4 mt-4"> |
|||
<router-link |
|||
:to="{ name: 'gifted-photo' }" |
|||
class="bg-blue-500 text-white px-1.5 py-1 rounded-md" |
|||
> |
|||
<fa icon="camera" class="fa-fw" /> |
|||
</router-link> |
|||
</div> |
|||
<div class="mt-4"> |
|||
<input type="checkbox" class="h-6 w-6 mr-2" v-model="givenToUser" /> |
|||
<label class="text-sm">Given to you</label> |
|||
</div> |
|||
<div class="mt-4"> |
|||
<input type="checkbox" class="h-6 w-6 mr-2" v-model="isTrade" /> |
|||
<label class="text-sm">Trade (not a gift)</label> |
|||
</div> |
|||
<p class="text-center mb-2 mt-6 italic"> |
|||
Sign & Send to publish to the world |
|||
</p> |
|||
<button |
|||
class="block w-full text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-2" |
|||
@click="confirm" |
|||
> |
|||
Sign & Send |
|||
</button> |
|||
<button |
|||
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md" |
|||
@click="cancel" |
|||
> |
|||
Cancel |
|||
</button> |
|||
</section> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { Component, Vue } from "vue-facing-decorator"; |
|||
|
|||
import { NotificationIface } from "@/constants/app"; |
|||
import QuickNav from "@/components/QuickNav.vue"; |
|||
import TopMessage from "@/components/TopMessage.vue"; |
|||
import { db } from "@/db/index"; |
|||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; |
|||
import { createAndSubmitGive } from "@/libs/endorserServer"; |
|||
import * as libsUtil from "@/libs/util"; |
|||
|
|||
@Component({ |
|||
components: { |
|||
QuickNav, |
|||
TopMessage, |
|||
}, |
|||
}) |
|||
export default class GiftedDetails extends Vue { |
|||
$notify!: (notification: NotificationIface, timeout?: number) => void; |
|||
|
|||
activeDid = ""; |
|||
apiServer = ""; |
|||
|
|||
amountInput = "0"; |
|||
description = ""; |
|||
givenToUser = false; |
|||
giverDid: string | undefined; |
|||
giverName = ""; |
|||
isTrade = false; |
|||
message = ""; |
|||
offerId = ""; |
|||
projectId = ""; |
|||
unitCode = "HUR"; |
|||
|
|||
libsUtil = libsUtil; |
|||
|
|||
async mounted() { |
|||
this.amountInput = this.$route.query.amountInput as string; |
|||
this.description = this.$route.query.description as string; |
|||
this.giverDid = this.$route.query.giverDid as string; |
|||
this.giverName = this.$route.query.giverName as string; |
|||
this.message = this.$route.query.message as string; |
|||
this.offerId = this.$route.query.offerId as string; |
|||
this.projectId = this.$route.query.projectId as string; |
|||
this.unitCode = this.$route.query.unitCode as string; |
|||
|
|||
try { |
|||
await db.open(); |
|||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings; |
|||
this.apiServer = settings?.apiServer || ""; |
|||
this.activeDid = settings?.activeDid || ""; |
|||
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|||
} catch (err: any) { |
|||
console.error("Error retrieving settings from database:", err); |
|||
this.$notify( |
|||
{ |
|||
group: "alert", |
|||
type: "danger", |
|||
title: "Error", |
|||
text: err.message || "There was an error retrieving your settings.", |
|||
}, |
|||
-1, |
|||
); |
|||
} |
|||
} |
|||
|
|||
changeUnitCode() { |
|||
const units = Object.keys(this.libsUtil.UNIT_SHORT); |
|||
const index = units.indexOf(this.unitCode); |
|||
this.unitCode = units[(index + 1) % units.length]; |
|||
} |
|||
|
|||
increment() { |
|||
this.amountInput = `${(parseFloat(this.amountInput) || 0) + 1}`; |
|||
} |
|||
|
|||
decrement() { |
|||
this.amountInput = `${Math.max( |
|||
0, |
|||
(parseFloat(this.amountInput) || 1) - 1, |
|||
)}`; |
|||
} |
|||
|
|||
cancel() { |
|||
this.$router.back(); |
|||
} |
|||
|
|||
async confirm() { |
|||
this.$notify( |
|||
{ |
|||
group: "alert", |
|||
type: "toast", |
|||
text: "Recording the give...", |
|||
title: "", |
|||
}, |
|||
1000, |
|||
); |
|||
// this is asynchronous, but we don't need to wait for it to complete |
|||
await this.recordGive(); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param giverDid may be null |
|||
* @param description may be an empty string |
|||
* @param amountInput may be 0 |
|||
* @param unitCode may be omitted, defaults to "HUR" |
|||
*/ |
|||
public async recordGive() { |
|||
if (!this.activeDid) { |
|||
this.$notify( |
|||
{ |
|||
group: "alert", |
|||
type: "danger", |
|||
title: "Error", |
|||
text: "You must select an identifier before you can record a give.", |
|||
}, |
|||
-1, |
|||
); |
|||
return; |
|||
} |
|||
|
|||
if (!this.description && !this.amountInput) { |
|||
this.$notify( |
|||
{ |
|||
group: "alert", |
|||
type: "danger", |
|||
title: "Error", |
|||
text: `You must enter a description or some number of ${ |
|||
this.libsUtil.UNIT_LONG[this.unitCode] |
|||
}.`, |
|||
}, |
|||
-1, |
|||
); |
|||
return; |
|||
} |
|||
|
|||
try { |
|||
const identity = await libsUtil.getIdentity(this.activeDid); |
|||
const result = await createAndSubmitGive( |
|||
this.axios, |
|||
this.apiServer, |
|||
identity, |
|||
this.giverDid, |
|||
this.givenToUser ? this.activeDid : undefined, |
|||
this.description, |
|||
parseFloat(this.amountInput), |
|||
this.unitCode, |
|||
this.projectId, |
|||
this.offerId, |
|||
this.isTrade, |
|||
); |
|||
|
|||
if ( |
|||
result.type === "error" || |
|||
this.isGiveCreationError(result.response) |
|||
) { |
|||
const errorMessage = this.getGiveCreationErrorMessage(result); |
|||
console.error("Error with give creation result:", result); |
|||
this.$notify( |
|||
{ |
|||
group: "alert", |
|||
type: "danger", |
|||
title: "Error", |
|||
text: errorMessage || "There was an error creating the give.", |
|||
}, |
|||
-1, |
|||
); |
|||
} else { |
|||
this.$notify( |
|||
{ |
|||
group: "alert", |
|||
type: "success", |
|||
title: "Success", |
|||
text: `That ${this.isTrade ? "trade" : "gift"} was recorded.`, |
|||
}, |
|||
7000, |
|||
); |
|||
this.$router.back(); |
|||
} |
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|||
} catch (error: any) { |
|||
console.error("Error with give recordation caught:", error); |
|||
const message = |
|||
error.userMessage || |
|||
error.response?.data?.error?.message || |
|||
"There was an error recording the give."; |
|||
this.$notify( |
|||
{ |
|||
group: "alert", |
|||
type: "danger", |
|||
title: "Error", |
|||
text: message, |
|||
}, |
|||
-1, |
|||
); |
|||
} |
|||
} |
|||
|
|||
// Helper functions for readability |
|||
|
|||
/** |
|||
* @param result response "data" from the server |
|||
* @returns true if the result indicates an error |
|||
*/ |
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|||
isGiveCreationError(result: any) { |
|||
return result.status !== 201 || result.data?.error; |
|||
} |
|||
|
|||
/** |
|||
* @param result direct response eg. ErrorResult or SuccessResult (potentially with embedded "data") |
|||
* @returns best guess at an error message |
|||
*/ |
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|||
getGiveCreationErrorMessage(result: any) { |
|||
return ( |
|||
result.error?.userMessage || |
|||
result.error?.error || |
|||
result.response?.data?.error?.message |
|||
); |
|||
} |
|||
} |
|||
</script> |
Loading…
Reference in new issue