Browse Source

for BVC shortcut: send attend & give actions, and list actions to confirm

kb/add-usage-guide
Trent Larson 9 months ago
parent
commit
2058205150
  1. 4
      src/App.vue
  2. 19
      src/components/GiftedDialog.vue
  3. 27
      src/components/OfferDialog.vue
  4. 37
      src/libs/endorserServer.ts
  5. 30
      src/libs/util.ts
  6. 2
      src/views/AccountViewView.vue
  7. 2
      src/views/ContactAmountsView.vue
  8. 2
      src/views/ContactGiftingView.vue
  9. 3
      src/views/ContactQRScanShowView.vue
  10. 18
      src/views/ContactsView.vue
  11. 8
      src/views/DiscoverView.vue
  12. 8
      src/views/HomeView.vue
  13. 131
      src/views/QuickActionBvcBeginView.vue
  14. 71
      src/views/QuickActionBvcEndView.vue
  15. 2
      src/views/QuickActionBvcView.vue

4
src/App.vue

@ -582,7 +582,7 @@ export default class App extends Vue {
} }
}) })
.catch((error) => { .catch((error) => {
console.log("Push provider server communication failed:", error); console.error("Push provider server communication failed:", error);
return false; return false;
}); });
@ -597,7 +597,7 @@ export default class App extends Vue {
return response.ok; return response.ok;
}) })
.catch((error) => { .catch((error) => {
console.log("Push server communication failed:", error); console.error("Push server communication failed:", error);
return false; return false;
}); });

19
src/components/GiftedDialog.vue

@ -77,7 +77,6 @@ import {
import * as libsUtil from "@/libs/util"; 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 { Contact } from "@/db/tables/contacts"; import { Contact } from "@/db/tables/contacts";
@Component @Component
@ -206,22 +205,6 @@ export default class GiftedDialog extends Vue {
}); });
} }
public async getIdentity(activeDid: string) {
await accountsDB.open();
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error(
"Attempted to load Give records for DID ${activeDid} but no identifier was found",
);
}
return identity;
}
/** /**
* *
* @param giverDid may be null * @param giverDid may be null
@ -262,7 +245,7 @@ export default class GiftedDialog extends Vue {
} }
try { try {
const identity = await this.getIdentity(this.activeDid); const identity = await libsUtil.getIdentity(this.activeDid);
const result = await createAndSubmitGive( const result = await createAndSubmitGive(
this.axios, this.axios,
this.apiServer, this.apiServer,

27
src/components/OfferDialog.vue

@ -72,9 +72,8 @@ import { Vue, Component, Prop } from "vue-facing-decorator";
import { NotificationIface } from "@/constants/app"; import { NotificationIface } from "@/constants/app";
import { createAndSubmitOffer } from "@/libs/endorserServer"; import { createAndSubmitOffer } from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util"; import * as libsUtil from "@/libs/util";
import { accountsDB, db } from "@/db/index"; import { 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";
@Component @Component
export default class OfferDialog extends Vue { export default class OfferDialog extends Vue {
@ -102,7 +101,7 @@ export default class OfferDialog extends Vue {
this.activeDid = settings?.activeDid || ""; this.activeDid = settings?.activeDid || "";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) { } catch (err: any) {
console.log("Error retrieving settings from database:", err); console.error("Error retrieving settings from database:", err);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -173,22 +172,6 @@ export default class OfferDialog extends Vue {
}); });
} }
public async getIdentity(activeDid: string) {
await accountsDB.open();
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error(
`Attempted to load Offer records for DID ${activeDid} but no identifier was found`,
);
}
return identity;
}
/** /**
* *
* @param description may be an empty string * @param description may be an empty string
@ -228,7 +211,7 @@ export default class OfferDialog extends Vue {
} }
try { try {
const identity = await this.getIdentity(this.activeDid); const identity = await libsUtil.getIdentity(this.activeDid);
const result = await createAndSubmitOffer( const result = await createAndSubmitOffer(
this.axios, this.axios,
this.apiServer, this.apiServer,
@ -245,7 +228,7 @@ export default class OfferDialog extends Vue {
this.isOfferCreationError(result.response) this.isOfferCreationError(result.response)
) { ) {
const errorMessage = this.getOfferCreationErrorMessage(result); const errorMessage = this.getOfferCreationErrorMessage(result);
console.log("Error with offer creation result:", result); console.error("Error with offer creation result:", result);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -268,7 +251,7 @@ export default class OfferDialog extends Vue {
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) { } catch (error: any) {
console.log("Error with offer recordation caught:", error); console.error("Error with offer recordation caught:", error);
const message = const message =
error.userMessage || error.userMessage ||
error.response?.data?.error?.message || error.response?.data?.error?.message ||

37
src/libs/endorserServer.ts

@ -229,16 +229,16 @@ export interface ErrorResponse {
}; };
} }
export interface ErrorResult {
type: "error";
error: InternalError;
}
export interface InternalError { export interface InternalError {
error: string; // for system logging error: string; // for system logging
userMessage?: string; // for user display userMessage?: string; // for user display
} }
export interface ErrorResult extends ResultWithType {
type: "error";
error: InternalError;
}
export type CreateAndSubmitClaimResult = SuccessResult | ErrorResult; export type CreateAndSubmitClaimResult = SuccessResult | ErrorResult;
// This is used to check for hidden info. // This is used to check for hidden info.
@ -758,12 +758,23 @@ export const claimSpecialDescription = (
} }
}; };
// from https://stackoverflow.com/a/175787/845494 export const BVC_MEETUPS_PROJECT_CLAIM_ID =
// //"https://endorser.ch/entity/01GXYPFF7FA03NXKPYY142PY4H";
export function isNumeric(str: string): boolean { "https://endorser.ch/entity/01HNTZYJJXTGT0EZS3VEJGX7AK";
return !isNaN(+str);
}
export function numberOrZero(str: string): number { export const bvcMeetingJoinClaim = (did: string, startTime: string) => {
return isNumeric(str) ? +str : 0; return {
} "@context": SCHEMA_ORG_CONTEXT,
"@type": "JoinAction",
agent: {
identifier: did,
},
event: {
organizer: {
name: "Bountiful Voluntaryist Community",
},
name: "Saturday Morning Meeting",
startTime: startTime,
},
};
};

30
src/libs/util.ts

@ -1,14 +1,16 @@
// many of these are also found in endorser-mobile utility.ts // many of these are also found in endorser-mobile utility.ts
import axios, { AxiosResponse } from "axios"; import axios, { AxiosResponse } from "axios";
import { IIdentifier } from "@veramo/core";
import { useClipboard } from "@vueuse/core";
import { DEFAULT_PUSH_SERVER } from "@/constants/app"; import { DEFAULT_PUSH_SERVER } from "@/constants/app";
import { accountsDB, db } from "@/db/index"; import { accountsDB, db } from "@/db/index";
import { Account } from "@/db/tables/accounts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto"; import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto";
import { GenericServerRecord, containsHiddenDid } from "@/libs/endorserServer"; import { GenericServerRecord, containsHiddenDid } from "@/libs/endorserServer";
import * as serverUtil from "@/libs/endorserServer"; import * as serverUtil from "@/libs/endorserServer";
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;
@ -55,6 +57,16 @@ export function iconForUnitCode(unitCode: string) {
return UNIT_CODES[unitCode]?.faIcon || "question"; return UNIT_CODES[unitCode]?.faIcon || "question";
} }
// from https://stackoverflow.com/a/175787/845494
//
export function isNumeric(str: string): boolean {
return !isNaN(+str);
}
export function numberOrZero(str: string): number {
return isNumeric(str) ? +str : 0;
}
export const isGlobalUri = (uri: string) => { export const isGlobalUri = (uri: string) => {
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/)); return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
}; };
@ -180,6 +192,22 @@ export function findAllVisibleToDids(
* *
**/ **/
export const getIdentity = async (activeDid: string): Promise<IIdentifier> => {
await accountsDB.open();
const account = (await accountsDB.accounts
.where("did")
.equals(activeDid)
.first()) as Account;
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error(
`Attempted to load Offer records for DID ${activeDid} but no identifier was found`,
);
}
return identity;
};
/** /**
* Generates a new identity, saves it to the database, and sets it as the active identity. * Generates a new identity, saves it to the database, and sets it as the active identity.
* @return {Promise<string>} with the DID of the new identity * @return {Promise<string>} with the DID of the new identity

2
src/views/AccountViewView.vue

@ -446,7 +446,7 @@
> >
<!-- label --> <!-- label -->
<span class="text-slate-500 text-sm font-bold" <span class="text-slate-500 text-sm font-bold"
>Show Shortcut on Home Page</span >Show BVC Shortcut on Home Page</span
> >
<!-- toggle --> <!-- toggle -->
<div class="relative ml-2"> <div class="relative ml-2">

2
src/views/ContactAmountsView.vue

@ -179,7 +179,7 @@ export default class ContactAmountssView extends Vue {
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) { } catch (err: any) {
console.log("Error retrieving settings or gives.", err); console.error("Error retrieving settings or gives.", err);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",

2
src/views/ContactGiftingView.vue

@ -119,7 +119,7 @@ export default class ContactGiftingView extends Vue {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) { } catch (err: any) {
console.log("Error retrieving settings & contacts:", err); console.error("Error retrieving settings & contacts:", err);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",

3
src/views/ContactQRScanShowView.vue

@ -180,7 +180,6 @@ export default class ContactQRScanShow extends Vue {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
onScanDetect(content: any) { onScanDetect(content: any) {
if (content[0]?.rawValue) { if (content[0]?.rawValue) {
//console.log("onDetect", content[0].rawValue);
localStorage.setItem("contactEndorserUrl", content[0].rawValue); localStorage.setItem("contactEndorserUrl", content[0].rawValue);
this.$router.push({ name: "contacts" }); this.$router.push({ name: "contacts" });
} else { } else {
@ -198,7 +197,7 @@ export default class ContactQRScanShow extends Vue {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
onScanError(error: any) { onScanError(error: any) {
console.log("Scan was invalid:", error); console.error("Scan was invalid:", error);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",

18
src/views/ContactsView.vue

@ -284,6 +284,7 @@
<script lang="ts"> <script lang="ts">
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import { IndexableType } from "dexie";
import * as didJwt from "did-jwt"; import * as didJwt from "did-jwt";
import * as R from "ramda"; import * as R from "ramda";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
@ -311,7 +312,6 @@ import * as libsUtil from "@/libs/util";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue"; import EntityIcon from "@/components/EntityIcon.vue";
import { Account } from "@/db/tables/accounts"; import { Account } from "@/db/tables/accounts";
import { IndexableType } from "dexie";
// 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;
@ -497,7 +497,7 @@ export default class ContactsView extends Vue {
this.givenToMeConfirmed = givenToMeConfirmed; this.givenToMeConfirmed = givenToMeConfirmed;
this.givenToMeUnconfirmed = givenToMeUnconfirmed; this.givenToMeUnconfirmed = givenToMeUnconfirmed;
} catch (error) { } catch (error) {
console.log("Error loading gives", error); console.error("Error loading gives", error);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -1000,7 +1000,7 @@ export default class ContactsView extends Vue {
-1, -1,
); );
} else { } else {
console.log("Got bad server response when checking visibility: ", resp); console.error("Got bad server response checking visibility:", resp);
const message = resp.data.error?.message || "Got bad server response."; const message = resp.data.error?.message || "Got bad server response.";
this.$notify( this.$notify(
{ {
@ -1013,7 +1013,7 @@ export default class ContactsView extends Vue {
); );
} }
} catch (err) { } catch (err) {
console.log("Caught error from request to check visibility:", err); console.error("Caught error from request to check visibility:", err);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -1026,12 +1026,6 @@ export default class ContactsView extends Vue {
} }
} }
// from https://stackoverflow.com/a/175787/845494
//
private isNumeric(str: string): boolean {
return !isNaN(+str);
}
private nameForDid(contacts: Array<Contact>, did: string): string { private nameForDid(contacts: Array<Contact>, did: string): string {
const contact = R.find((con) => con.did == did, contacts); const contact = R.find((con) => con.did == did, contacts);
return this.nameForContact(contact); return this.nameForContact(contact);
@ -1067,7 +1061,7 @@ export default class ContactsView extends Vue {
return; return;
} }
} }
if (!this.isNumeric(this.hourInput)) { if (!libsUtil.isNumeric(this.hourInput)) {
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -1204,7 +1198,7 @@ export default class ContactsView extends Vue {
} }
} }
} catch (error) { } catch (error) {
console.log("Error in createAndSubmitContactGive: ", error); console.error("Error in createAndSubmitContactGive: ", error);
let userMessage = "There was an error. See logs for more info."; let userMessage = "There was an error. See logs for more info.";
const serverError = error as AxiosError; const serverError = error as AxiosError;
if (serverError) { if (serverError) {

8
src/views/DiscoverView.vue

@ -254,7 +254,7 @@ export default class DiscoverView extends Vue {
if (response.status !== 200) { if (response.status !== 200) {
const details = await response.text(); const details = await response.text();
console.log("Problem with full search:", details); console.error("Problem with full search:", details);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -282,7 +282,7 @@ export default class DiscoverView extends Vue {
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) { } catch (e: any) {
console.log("Error with feed load:", e); console.error("Error with feed load:", e);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -337,7 +337,7 @@ export default class DiscoverView extends Vue {
if (response.status !== 200) { if (response.status !== 200) {
const details = await response.text(); const details = await response.text();
console.log("Problem with nearby search:", details); console.error("Problem with nearby search:", details);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -374,7 +374,7 @@ export default class DiscoverView extends Vue {
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) { } catch (e: any) {
console.log("Error with feed load:", e); console.error("Error with feed load:", e);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",

8
src/views/HomeView.vue

@ -3,8 +3,8 @@
<TopMessage /> <TopMessage />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto"> <section id="Content" class="p-2 pb-24 max-w-3xl mx-auto">
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light px-4 mb-8">
Time Safari Time Safari
</h1> </h1>
@ -346,7 +346,7 @@ export default class HomeView extends Vue {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) { } catch (err: any) {
console.log("Error retrieving settings or feed.", err); console.error("Error retrieving settings or feed.", err);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
@ -452,7 +452,7 @@ export default class HomeView extends Vue {
} }
}) })
.catch((e) => { .catch((e) => {
console.log("Error with feed load:", e); console.error("Error with feed load:", e);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",

131
src/views/QuickActionBvcBeginView.vue

@ -15,20 +15,24 @@
</div> </div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-4"> <h1 id="ViewHeading" class="text-4xl text-center font-light px-4 mb-4">
Beginning of BVC Saturday Meeting Beginning of BVC Saturday Meeting
</h1> </h1>
<div> <div>
<h2 class="text-2xl m-4">You're Here</h2> <h2 class="text-2xl m-2">You're Here</h2>
<div class="m-4 flex"> <div class="m-2 flex">
<input type="checkbox" v-model="gaveTime" class="h-6 w-6" /> <input type="checkbox" v-model="attended" class="h-6 w-6" />
<span class="pb-2 pl-2 pr-2">Attended</span> <span class="pb-2 pl-2 pr-2">Attended</span>
</div>
<div class="m-2 flex">
<input type="checkbox" v-model="gaveTime" class="h-6 w-6" />
<span class="pb-2 pl-2 pr-2">Spent Time</span>
<span v-if="gaveTime"> <span v-if="gaveTime">
<input <input
type="text" type="text"
placeholder="How much time" placeholder="How much time"
v-model="hours" v-model="hoursStr"
size="1" size="1"
class="border border-slate-400 h-6 px-2" class="border border-slate-400 h-6 px-2"
/> />
@ -39,25 +43,44 @@
</div> </div>
</div> </div>
<div class="m-4" v-if="gaveTime && hours && hours != '0'"> <div
v-if="attended || (gaveTime && hoursStr && hoursStr != '0')"
class="flex justify-center mt-4"
>
<button <button
@click="record()" @click="record()"
class="block text-center text-md font-bold bg-blue-500 text-white px-2 py-3 rounded-md" class="block text-center text-md font-bold bg-blue-500 text-white px-2 py-3 rounded-md w-56"
> >
Sign & Send Sign & Send
</button> </button>
</div> </div>
<div v-else class="flex justify-center mt-4">
<button
class="block text-center text-md font-bold bg-slate-500 text-white px-2 py-3 rounded-md w-56"
>
Select Your Actions
</button>
</div>
</section> </section>
</template> </template>
<script lang="ts"> <script lang="ts">
import axios from "axios";
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue"; import TopMessage from "@/components/TopMessage.vue";
import { NotificationIface } from "@/constants/app"; import { NotificationIface } from "@/constants/app";
import { numberOrZero } from "@/libs/endorserServer"; import { db } from "@/db/index";
import {
BVC_MEETUPS_PROJECT_CLAIM_ID,
bvcMeetingJoinClaim,
createAndSubmitClaim,
createAndSubmitGive,
} from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
@Component({ @Component({
components: { components: {
@ -68,8 +91,11 @@ import { numberOrZero } from "@/libs/endorserServer";
export default class QuickActionBvcBeginView extends Vue { export default class QuickActionBvcBeginView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void; $notify!: (notification: NotificationIface, timeout?: number) => void;
gaveTime = false; activeDid = "";
hours = "1"; apiServer = "";
attended = true;
gaveTime = true;
hoursStr = "1";
todayOrPreviousStartDate = ""; todayOrPreviousStartDate = "";
async mounted() { async mounted() {
@ -91,9 +117,88 @@ export default class QuickActionBvcBeginView extends Vue {
}) || ""; }) || "";
} }
record() { async record() {
const hoursNum = numberOrZero(this.hours); await db.open();
alert("Nope" + hoursNum); const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
const activeDid = settings?.activeDid || "";
const apiServer = settings?.apiServer || "";
try {
const hoursNum = libsUtil.numberOrZero(this.hoursStr);
const identity = await libsUtil.getIdentity(activeDid);
const result = await createAndSubmitGive(
axios,
apiServer,
identity,
activeDid,
undefined,
undefined,
hoursNum,
"HUR",
BVC_MEETUPS_PROJECT_CLAIM_ID,
);
if (result.type === "error") {
console.error("Error sending give:", result);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text:
result?.error?.userMessage ||
"There was an error sending the give.",
},
-1,
);
}
const result2 = await createAndSubmitClaim(
bvcMeetingJoinClaim(this.activeDid, this.todayOrPreviousStartDate),
identity,
apiServer,
axios,
);
if (result2.type === "error") {
console.error("Error sending give:", result2);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text:
result2?.error?.userMessage ||
"There was an error sending the attendance.",
},
-1,
);
}
if (result.type === "success" || result2.type === "success") {
this.$notify(
{
group: "alert",
type: "success",
title: "Success",
text: "Your actions have been recorded.",
},
-1,
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error("Error sending claims.", error);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: error.userMessage || "There was an error sending those claims.",
},
-1,
);
}
} }
} }
</script> </script>

71
src/views/QuickActionBvcEndView.vue

@ -15,19 +15,26 @@
</div> </div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-4"> <h1 id="ViewHeading" class="text-4xl text-center font-light px-4 mb-4">
End of BVC Saturday Meeting End of BVC Saturday Meeting
</h1> </h1>
<div> <div>
<h2 class="text-2xl m-4">Confirm</h2> <h2 class="text-2xl m-2">Confirm</h2>
<div v-if="claimsToConfirm.length === 0"> <div v-if="loadingConfirms" class="flex justify-center">
There are no claims today yet for you to confirm. <fa icon="spinner" class="animate-spin" />
<span v-if="claimCountWithHidden"> </div>
(There are {{ claimCountWithHidden }} hidden claims.) <div v-else-if="claimsToConfirm.length === 0">
There are no claims yet today for you to confirm.
<span v-if="claimCountWithHidden > 0">
{{
claimCountWithHidden === 1
? "(There is 1 claim with hidden details.)"
: `(There are ${claimCountWithHidden} claims with hidden details.)`
}}
</span> </span>
</div> </div>
<ul class="border-t border-slate-300"> <ul class="border-t border-slate-300 m-2">
<li <li
class="border-b border-slate-300 py-2" class="border-b border-slate-300 py-2"
v-for="record in claimsToConfirm" v-for="record in claimsToConfirm"
@ -36,7 +43,19 @@
<div class="grid grid-cols-12"> <div class="grid grid-cols-12">
<span class="col-span-11 justify-self-start"> <span class="col-span-11 justify-self-start">
<span> <span>
<input type="checkbox" class="mr-2 h-6 w-6" /> <input
type="checkbox"
:checked="claimsToConfirmSelected.includes(record.id)"
@click="
claimsToConfirmSelected.includes(record.id)
? claimsToConfirmSelected.splice(
claimsToConfirmSelected.indexOf(record.id),
1,
)
: claimsToConfirmSelected.push(record.id)
"
class="mr-2 h-6 w-6"
/>
</span> </span>
{{ {{
claimSpecialDescription( claimSpecialDescription(
@ -59,10 +78,10 @@
</div> </div>
<div> <div>
<h2 class="text-2xl m-4">Anything else?</h2> <h2 class="text-2xl m-2">Anything else?</h2>
<div class="m-4 flex"> <div class="m-2 flex">
<input type="checkbox" v-model="someoneGave" class="h-6 w-6" /> <input type="checkbox" v-model="someoneGave" class="h-6 w-6" />
<span class="pb-2 pl-2 pr-2">Someone gave</span> <span class="pb-2 pl-2 pr-2">Someone else gave</span>
<span v-if="someoneGave"> <span v-if="someoneGave">
<input <input
type="text" type="text"
@ -76,14 +95,24 @@
</div> </div>
</div> </div>
<div class="m-4" v-if="someoneGave && description"> <div
v-if="claimsToConfirmSelected.length || (someoneGave && description)"
class="flex justify-center mt-4"
>
<button <button
@click="record()" @click="record()"
class="block text-center text-md font-bold bg-blue-500 text-white px-2 py-3 rounded-md" class="block text-center text-md font-bold bg-blue-500 text-white px-2 py-3 rounded-md w-56"
> >
Sign & Send Sign & Send
</button> </button>
</div> </div>
<div v-else class="flex justify-center mt-4">
<button
class="block text-center text-md font-bold bg-slate-500 text-white px-2 py-3 rounded-md w-56"
>
Choose What To Confirm
</button>
</div>
</section> </section>
</template> </template>
@ -123,7 +152,9 @@ export default class QuickActionBvcBeginView extends Vue {
apiServer = ""; apiServer = "";
claimCountWithHidden = 0; claimCountWithHidden = 0;
claimsToConfirm: GenericServerRecord[] = []; claimsToConfirm: GenericServerRecord[] = [];
description = ""; claimsToConfirmSelected: string[] = [];
description = "breakfast";
loadingConfirms = true;
someoneGave = false; someoneGave = false;
async created() { async created() {
@ -135,6 +166,7 @@ export default class QuickActionBvcBeginView extends Vue {
} }
async mounted() { async mounted() {
this.loadingConfirms = true;
let currentOrPreviousSat = DateTime.now().setZone("America/Denver"); let currentOrPreviousSat = DateTime.now().setZone("America/Denver");
if (currentOrPreviousSat.weekday < 6) { if (currentOrPreviousSat.weekday < 6) {
// it's not Saturday or Sunday, // it's not Saturday or Sunday,
@ -165,15 +197,7 @@ export default class QuickActionBvcBeginView extends Vue {
const headers = { const headers = {
Authorization: "Bearer " + (await accessToken(identity)), Authorization: "Bearer " + (await accessToken(identity)),
}; };
console.log("todayOrPreviousStartDate", todayOrPreviousStartDate);
try { try {
console.log(
this.apiServer +
"/api/claim/?" +
"issuedAt_greaterThanOrEqualTo=" +
encodeURIComponent(todayOrPreviousStartDate) +
"&excludeConfirmations=true",
);
const response = await fetch( const response = await fetch(
this.apiServer + this.apiServer +
"/api/claim/?" + "/api/claim/?" +
@ -187,7 +211,7 @@ export default class QuickActionBvcBeginView extends Vue {
console.log("Bad response", response); console.log("Bad response", response);
throw new Error("Bad response when retrieving claims."); throw new Error("Bad response when retrieving claims.");
} }
response.json().then((data) => { await response.json().then((data) => {
const dataByOthers = R.reject( const dataByOthers = R.reject(
(claim: GenericServerRecord) => claim.issuer === this.activeDid, (claim: GenericServerRecord) => claim.issuer === this.activeDid,
data, data,
@ -212,6 +236,7 @@ export default class QuickActionBvcBeginView extends Vue {
-1, -1,
); );
} }
this.loadingConfirms = false;
} }
onClickLoadClaim(jwtId: string) { onClickLoadClaim(jwtId: string) {

2
src/views/QuickActionBvcView.vue

@ -15,7 +15,7 @@
</div> </div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-4"> <h1 id="ViewHeading" class="text-4xl text-center font-light px-4 mb-4">
Bountiful Voluntaryist Community Actions Bountiful Voluntaryist Community Actions
</h1> </h1>

Loading…
Cancel
Save