Browse Source

add page for extended details of gifts including pic (not fully tested)

pull/105/head
Trent Larson 7 months ago
parent
commit
acee761906
  1. 30
      src/components/GiftedDialog.vue
  2. 8
      src/router/index.ts
  3. 313
      src/views/GiftedDetails.vue

30
src/components/GiftedDialog.vue

@ -36,23 +36,27 @@
<fa icon="chevron-right" /> <fa icon="chevron-right" />
</div> </div>
</div> </div>
<div class="mt-2 flex justify-between"> <div class="mt-2 flex justify-center">
<span> <span>
<router-link <router-link
:to="{ name: 'gifted-photo' }" :to="{
class="bg-blue-500 text-white px-1.5 py-1 rounded-md" name: 'gifted-details',
query: {
amountInput,
description,
giverDid: giver?.did,
giverName: giver?.name,
message,
offerId,
projectId,
unitCode,
},
}"
class="text-blue-500"
> >
<fa icon="camera" class="fa-fw" /> More Options
</router-link> </router-link>
</span> </span>
<span v-if="showGivenToUser">
<input type="checkbox" class="mr-2" v-model="givenToUser" />
<label class="text-sm">Given to you</label>
</span>
<span>
<input type="checkbox" class="mr-2" v-model="isTrade" />
<label class="text-sm">Trade (not a gift)</label>
</span>
</div> </div>
<p class="text-center mb-2 mt-6 italic"> <p class="text-center mb-2 mt-6 italic">
Sign & Send to publish to the world Sign & Send to publish to the world
@ -101,9 +105,9 @@ export default class GiftedDialog extends Vue {
apiServer = ""; apiServer = "";
amountInput = "0"; amountInput = "0";
giver?: GiverInputInfo; // undefined means no identified giver agent
description = ""; description = "";
givenToUser = false; givenToUser = false;
giver?: GiverInputInfo; // undefined means no identified giver agent
isTrade = false; isTrade = false;
offerId = ""; offerId = "";
unitCode = "HUR"; unitCode = "HUR";

8
src/router/index.ts

@ -84,6 +84,14 @@ const routes: Array<RouteRecordRaw> = [
component: () => component: () =>
import(/* webpackChunkName: "discover" */ "../views/DiscoverView.vue"), import(/* webpackChunkName: "discover" */ "../views/DiscoverView.vue"),
}, },
{
path: "/gifted-details",
name: "gifted-details",
component: () =>
import(
/* webpackChunkName: "gifted-details" */ "../views/GiftedDetails.vue"
),
},
{ {
path: "/gifted-photo", path: "/gifted-photo",
name: "gifted-photo", name: "gifted-photo",

313
src/views/GiftedDetails.vue

@ -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 &amp; 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…
Cancel
Save