Browse Source

update offer dialog to allow other units

starred-projects
Trent Larson 10 months ago
parent
commit
1731f2443b
  1. 41
      src/components/GiftedDialog.vue
  2. 61
      src/components/OfferDialog.vue
  3. 28
      src/libs/endorserServer.ts
  4. 26
      src/libs/util.ts

41
src/components/GiftedDialog.vue

@ -12,10 +12,10 @@
/> />
<div class="flex flex-row"> <div class="flex flex-row">
<span <span
class="rounded-l border border-r-0 border-slate-400 bg-slate-200 w-1/3 text-center px-2 py-2" 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()" @click="changeUnitCode()"
> >
{{ UNIT_SHORT[unitCode] }} {{ libsUtil.UNIT_SHORT[unitCode] }}
</span> </span>
<div <div
class="border border-r-0 border-slate-400 bg-slate-200 px-4 py-2" class="border border-r-0 border-slate-400 bg-slate-200 px-4 py-2"
@ -72,6 +72,7 @@ import {
didInfo, didInfo,
GiverInputInfo, GiverInputInfo,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { accountsDB, db } from "@/db/index"; import { accountsDB, db } from "@/db/index";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { Account } from "@/db/tables/accounts"; import { Account } from "@/db/tables/accounts";
@ -106,23 +107,7 @@ export default class GiftedDialog extends Vue {
unitCode = "HUR"; unitCode = "HUR";
visible = false; visible = false;
/* eslint-disable prettier/prettier */ libsUtil = libsUtil;
UNIT_SHORT: Record<string, string> = {
"BTC": "BTC",
"ETH": "ETH",
"HUR": "Hours",
"USD": "US $",
};
/* eslint-enable prettier/prettier */
/* eslint-disable prettier/prettier */
UNIT_LONG: Record<string, string> = {
"BTC": "Bitcoin",
"ETH": "Ethereum",
"HUR": "hours",
"USD": "dollars",
};
/* eslint-enable prettier/prettier */
async created() { async created() {
try { try {
@ -177,7 +162,7 @@ export default class GiftedDialog extends Vue {
} }
changeUnitCode() { changeUnitCode() {
const units = Object.keys(this.UNIT_SHORT); const units = Object.keys(this.libsUtil.UNIT_SHORT);
const index = units.indexOf(this.unitCode); const index = units.indexOf(this.unitCode);
this.unitCode = units[(index + 1) % units.length]; this.unitCode = units[(index + 1) % units.length];
} }
@ -203,6 +188,7 @@ export default class GiftedDialog extends Vue {
this.giver = undefined; this.giver = undefined;
this.givenToUser = this.showGivenToUser; this.givenToUser = this.showGivenToUser;
this.amountInput = "0"; this.amountInput = "0";
this.unitCode = "HUR";
} }
async confirm() { async confirm() {
@ -218,7 +204,7 @@ export default class GiftedDialog extends Vue {
); );
// this is asynchronous, but we don't need to wait for it to complete // this is asynchronous, but we don't need to wait for it to complete
await this.recordGive( await this.recordGive(
this.giver?.did as string | undefined, (this.giver?.did as string) || null,
this.description, this.description,
parseFloat(this.amountInput), parseFloat(this.amountInput),
this.unitCode, this.unitCode,
@ -248,12 +234,13 @@ export default class GiftedDialog extends Vue {
* @param giverDid may be null * @param giverDid may be null
* @param description may be an empty string * @param description may be an empty string
* @param amountInput may be 0 * @param amountInput may be 0
* @param unitCode may be omitted, defaults to "HUR"
*/ */
public async recordGive( public async recordGive(
giverDid?: string, giverDid: string | null,
description?: string, description: string,
amountInput?: number, amountInput: number,
unitCode?: string, unitCode: string = "HUR",
) { ) {
if (!this.activeDid) { if (!this.activeDid) {
this.$notify( this.$notify(
@ -274,9 +261,7 @@ export default class GiftedDialog extends Vue {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Error", title: "Error",
text: `You must enter a description or some number of ${ text: `You must enter a description or some number of ${this.libsUtil.UNIT_LONG[unitCode]}.`,
this.UNIT_LONG[this.unitCode]
}.`,
}, },
-1, -1,
); );

61
src/components/OfferDialog.vue

@ -8,22 +8,24 @@
placeholder="Description, prerequisites, terms, etc." placeholder="Description, prerequisites, terms, etc."
v-model="description" v-model="description"
/> />
<div class="flex flex-row mb-6"> <div class="flex flex-row mt-2">
<span <span
class="rounded-l border border-r-0 border-slate-400 bg-slate-200 text-center px-2 py-2" 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()"
> >
Hours {{ libsUtil.UNIT_SHORT[amountUnitCode] }}
</span> </span>
<div <div
class="border border-r-0 border-slate-400 bg-slate-200 px-4 py-2" class="border border-r-0 border-slate-400 bg-slate-200 px-4 py-2"
@click="decrement()" @click="decrement()"
v-if="amountInput !== '0'"
> >
<fa icon="chevron-left" /> <fa icon="chevron-left" />
</div> </div>
<input <input
type="text" type="text"
class="w-full border border-r-0 border-slate-400 px-2 py-2 text-center" class="w-full border border-r-0 border-slate-400 px-2 py-2 text-center"
v-model="hours" v-model="amountInput"
/> />
<div <div
class="rounded-r border border-slate-400 bg-slate-200 px-4 py-2" class="rounded-r border border-slate-400 bg-slate-200 px-4 py-2"
@ -32,7 +34,7 @@
<fa icon="chevron-right" /> <fa icon="chevron-right" />
</div> </div>
</div> </div>
<div class="flex flex-row mb-6"> <div class="flex flex-row mt-2">
<span <span
class="rounded-l border border-r-0 border-slate-400 bg-slate-200 text-center px-2 py-2" class="rounded-l border border-r-0 border-slate-400 bg-slate-200 text-center px-2 py-2"
> >
@ -45,7 +47,9 @@
v-model="expirationDateInput" v-model="expirationDateInput"
/> />
</div> </div>
<p class="text-center mb-2 italic">Sign & Send to publish to the world</p> <p class="text-center mt-6 mb-2 italic">
Sign & Send to publish to the world
</p>
<button <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" 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" @click="confirm"
@ -65,6 +69,7 @@
<script lang="ts"> <script lang="ts">
import { Vue, Component, Prop } from "vue-facing-decorator"; import { Vue, Component, Prop } from "vue-facing-decorator";
import { createAndSubmitOffer } from "@/libs/endorserServer"; import { createAndSubmitOffer } from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { accountsDB, db } from "@/db/index"; import { accountsDB, db } from "@/db/index";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { Account } from "@/db/tables/accounts"; import { Account } from "@/db/tables/accounts";
@ -86,11 +91,14 @@ export default class OfferDialog extends Vue {
activeDid = ""; activeDid = "";
apiServer = ""; apiServer = "";
amountInput = "0";
amountUnitCode = "HUR";
description = ""; description = "";
expirationDateInput = ""; expirationDateInput = "";
hours = "0";
visible = false; visible = false;
libsUtil = libsUtil;
async created() { async created() {
try { try {
await db.open(); await db.open();
@ -117,21 +125,36 @@ export default class OfferDialog extends Vue {
} }
close() { close() {
// close the dialog but don't change values (since it might be submitting info)
this.visible = false; this.visible = false;
} }
changeUnitCode() {
const units = Object.keys(this.libsUtil.UNIT_SHORT);
const index = units.indexOf(this.amountUnitCode);
this.amountUnitCode = units[(index + 1) % units.length];
}
increment() { increment() {
this.hours = `${(parseFloat(this.hours) || 0) + 1}`; this.amountInput = `${(parseFloat(this.amountInput) || 0) + 1}`;
} }
decrement() { decrement() {
this.hours = `${Math.max(0, (parseFloat(this.hours) || 1) - 1)}`; this.amountInput = `${Math.max(
0,
(parseFloat(this.amountInput) || 1) - 1,
)}`;
} }
cancel() { cancel() {
this.close(); this.close();
this.eraseValues();
}
eraseValues() {
this.description = ""; this.description = "";
this.hours = "0"; this.amountInput = "0";
this.amountUnitCode = "HUR";
} }
async confirm() { async confirm() {
@ -148,11 +171,12 @@ export default class OfferDialog extends Vue {
// this is asynchronous, but we don't need to wait for it to complete // this is asynchronous, but we don't need to wait for it to complete
this.recordOffer( this.recordOffer(
this.description, this.description,
parseFloat(this.hours), parseFloat(this.amountInput),
this.amountUnitCode,
this.expirationDateInput, this.expirationDateInput,
).then(() => { ).then(() => {
this.description = ""; this.description = "";
this.hours = "0"; this.amountInput = "0";
}); });
} }
@ -176,10 +200,12 @@ export default class OfferDialog extends Vue {
* *
* @param description may be an empty string * @param description may be an empty string
* @param hours may be 0 * @param hours may be 0
* @param unitCode may be omitted, defaults to "HUR"
*/ */
public async recordOffer( public async recordOffer(
description?: string, description: string,
hours?: number, amount: number,
unitCode: string = "HUR",
expirationDateInput?: string, expirationDateInput?: string,
) { ) {
if (!this.activeDid) { if (!this.activeDid) {
@ -195,13 +221,13 @@ export default class OfferDialog extends Vue {
return; return;
} }
if (!description && !hours) { if (!description && !amount) {
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Error", title: "Error",
text: "You must enter a description or some number of hours.", text: `You must enter a description or some number of ${this.libsUtil.UNIT_LONG[unitCode]}.`,
}, },
-1, -1,
); );
@ -215,7 +241,8 @@ export default class OfferDialog extends Vue {
this.apiServer, this.apiServer,
identity, identity,
description, description,
hours, amount,
unitCode,
expirationDateInput, expirationDateInput,
this.projectId, this.projectId,
); );

28
src/libs/endorserServer.ts

@ -32,7 +32,8 @@ export interface GiverOutputInfo {
action: string; action: string;
giver?: GiverInputInfo; giver?: GiverInputInfo;
description?: string; description?: string;
hours?: number; amount?: number;
unitCode?: string;
} }
export interface ClaimResult { export interface ClaimResult {
@ -311,17 +312,17 @@ export type CreateAndSubmitClaimResult = SuccessResult | ErrorResult;
* @param identity * @param identity
* @param fromDid may be null * @param fromDid may be null
* @param toDid * @param toDid
* @param description may be null; should have this or hours * @param description may be null; should have this or amount
* @param hours may be null; should have this or description * @param amount may be null; should have this or description
*/ */
export async function createAndSubmitGive( export async function createAndSubmitGive(
axios: Axios, axios: Axios,
apiServer: string, apiServer: string,
identity: IIdentifier, identity: IIdentifier,
fromDid?: string, fromDid?: string | null,
toDid?: string, toDid?: string,
description?: string, description?: string,
hours?: number, amount?: number,
unitCode?: string, unitCode?: string,
fulfillsProjectHandleId?: string, fulfillsProjectHandleId?: string,
fulfillsOfferHandleId?: string, fulfillsOfferHandleId?: string,
@ -333,8 +334,8 @@ export async function createAndSubmitGive(
recipient: toDid ? { identifier: toDid } : undefined, recipient: toDid ? { identifier: toDid } : undefined,
agent: fromDid ? { identifier: fromDid } : undefined, agent: fromDid ? { identifier: fromDid } : undefined,
description: description || undefined, description: description || undefined,
object: hours object: amount
? { amountOfThisGood: hours, unitCode: unitCode || "HUR" } ? { amountOfThisGood: amount, unitCode: unitCode || "HUR" }
: undefined, : undefined,
fulfills: [{ "@type": isTrade ? "TradeAction" : "DonateAction" }], fulfills: [{ "@type": isTrade ? "TradeAction" : "DonateAction" }],
}; };
@ -364,8 +365,8 @@ export async function createAndSubmitGive(
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim * For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
* *
* @param identity * @param identity
* @param description may be null; should have this or hours * @param description may be null; should have this or amount
* @param hours may be null; should have this or description * @param amount may be null; should have this or description
* @param expirationDate ISO 8601 date string YYYY-MM-DD (may be null) * @param expirationDate ISO 8601 date string YYYY-MM-DD (may be null)
* @param fulfillsProjectHandleId ID of project to which this contributes (may be null) * @param fulfillsProjectHandleId ID of project to which this contributes (may be null)
*/ */
@ -374,7 +375,8 @@ export async function createAndSubmitOffer(
apiServer: string, apiServer: string,
identity: IIdentifier, identity: IIdentifier,
description?: string, description?: string,
hours?: number, amount?: number,
unitCode?: string,
expirationDate?: string, expirationDate?: string,
fulfillsProjectHandleId?: string, fulfillsProjectHandleId?: string,
): Promise<CreateAndSubmitClaimResult> { ): Promise<CreateAndSubmitClaimResult> {
@ -384,10 +386,10 @@ export async function createAndSubmitOffer(
offeredBy: { identifier: identity.did }, offeredBy: { identifier: identity.did },
validThrough: expirationDate || undefined, validThrough: expirationDate || undefined,
}; };
if (hours) { if (amount) {
vcClaim.includesObject = { vcClaim.includesObject = {
amountOfThisGood: hours, amountOfThisGood: amount,
unitCode: "HUR", unitCode: unitCode || "HUR",
}; };
} }
if (description) { if (description) {

26
src/libs/util.ts

@ -13,15 +13,33 @@ import { useClipboard } from "@vueuse/core";
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const Buffer = require("buffer/").Buffer; const Buffer = require("buffer/").Buffer;
export const isGlobalUri = (uri: string) => {
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
};
// If you edit this, check that the numbers still line up on the side in the alert (on mobile, too), // If you edit this, check that the numbers still line up on the side in the alert (on mobile, too),
// and make sure they can take all actions while the notification shows. // and make sure they can take all actions while the notification shows.
export const ONBOARD_MESSAGE = export const ONBOARD_MESSAGE =
"1) Check that they have entered their name on the profile page in their device. 2) Add them to your Contacts by scanning with the QR icon that is by the input box. 3) Click the person icon to register them. 4) Have them go to their Contact page and scan your QR to add you to their list."; "1) Check that they have entered their name on the profile page in their device. 2) Add them to your Contacts by scanning with the QR icon that is by the input box. 3) Click the person icon to register them. 4) Have them go to their Contact page and scan your QR to add you to their list.";
/* eslint-disable prettier/prettier */
export const UNIT_SHORT: Record<string, string> = {
"BTC": "BTC",
"ETH": "ETH",
"HUR": "Hours",
"USD": "US $",
};
/* eslint-enable prettier/prettier */
/* eslint-disable prettier/prettier */
export const UNIT_LONG: Record<string, string> = {
"BTC": "Bitcoin",
"ETH": "Ethereum",
"HUR": "hours",
"USD": "dollars",
};
/* eslint-enable prettier/prettier */
export const isGlobalUri = (uri: string) => {
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
};
export const giveIsConfirmable = (veriClaim: GenericServerRecord) => { export const giveIsConfirmable = (veriClaim: GenericServerRecord) => {
return veriClaim.claimType === "GiveAction"; return veriClaim.claimType === "GiveAction";
}; };

Loading…
Cancel
Save