Trent Larson
9 months ago
10 changed files with 667 additions and 14 deletions
@ -0,0 +1,99 @@ |
|||||
|
<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 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-4"> |
||||
|
Beginning of BVC Saturday Meeting |
||||
|
</h1> |
||||
|
|
||||
|
<div> |
||||
|
<h2 class="text-2xl m-4">You're Here</h2> |
||||
|
<div class="m-4 flex"> |
||||
|
<input type="checkbox" v-model="gaveTime" class="h-6 w-6" /> |
||||
|
<span class="pb-2 pl-2 pr-2">Attended</span> |
||||
|
<span v-if="gaveTime"> |
||||
|
<input |
||||
|
type="text" |
||||
|
placeholder="How much time" |
||||
|
v-model="hours" |
||||
|
size="1" |
||||
|
class="border border-slate-400 h-6 px-2" |
||||
|
/> |
||||
|
hour(s) |
||||
|
</span> |
||||
|
<!-- This is to match input height to avoid shifting when hiding & showing. --> |
||||
|
<span v-else class="h-6" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="m-4" v-if="gaveTime && hours && hours != '0'"> |
||||
|
<button |
||||
|
@click="record()" |
||||
|
class="block text-center text-md font-bold bg-blue-500 text-white px-2 py-3 rounded-md" |
||||
|
> |
||||
|
Sign & Send |
||||
|
</button> |
||||
|
</div> |
||||
|
</section> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { DateTime } from "luxon"; |
||||
|
import { Component, Vue } from "vue-facing-decorator"; |
||||
|
|
||||
|
import QuickNav from "@/components/QuickNav.vue"; |
||||
|
import TopMessage from "@/components/TopMessage.vue"; |
||||
|
import { NotificationIface } from "@/constants/app"; |
||||
|
import { numberOrZero } from "@/libs/endorserServer"; |
||||
|
|
||||
|
@Component({ |
||||
|
components: { |
||||
|
QuickNav, |
||||
|
TopMessage, |
||||
|
}, |
||||
|
}) |
||||
|
export default class QuickActionBvcBeginView extends Vue { |
||||
|
$notify!: (notification: NotificationIface, timeout?: number) => void; |
||||
|
|
||||
|
gaveTime = false; |
||||
|
hours = "1"; |
||||
|
todayOrPreviousStartDate = ""; |
||||
|
|
||||
|
async mounted() { |
||||
|
let currentOrPreviousSat = DateTime.now().setZone("America/Denver"); |
||||
|
if (currentOrPreviousSat.weekday < 6) { |
||||
|
// it's not Saturday or Sunday, |
||||
|
// so move back one week before setting to the Saturday |
||||
|
currentOrPreviousSat = currentOrPreviousSat.minus({ week: 1 }); |
||||
|
} |
||||
|
const eventStartDateObj = currentOrPreviousSat |
||||
|
.set({ weekday: 6 }) |
||||
|
.set({ hour: 9 }) |
||||
|
.startOf("hour"); |
||||
|
|
||||
|
// Hack, but full ISO pushes the length to 340 which crashes verifyJWT! |
||||
|
this.todayOrPreviousStartDate = |
||||
|
eventStartDateObj.toISO({ |
||||
|
suppressMilliseconds: true, |
||||
|
}) || ""; |
||||
|
} |
||||
|
|
||||
|
record() { |
||||
|
const hoursNum = numberOrZero(this.hours); |
||||
|
alert("Nope" + hoursNum); |
||||
|
} |
||||
|
} |
||||
|
</script> |
@ -0,0 +1,228 @@ |
|||||
|
<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 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-4"> |
||||
|
End of BVC Saturday Meeting |
||||
|
</h1> |
||||
|
|
||||
|
<div> |
||||
|
<h2 class="text-2xl m-4">Confirm</h2> |
||||
|
<div v-if="claimsToConfirm.length === 0"> |
||||
|
There are no claims today yet for you to confirm. |
||||
|
<span v-if="claimCountWithHidden"> |
||||
|
(There are {{ claimCountWithHidden }} hidden claims.) |
||||
|
</span> |
||||
|
</div> |
||||
|
<ul class="border-t border-slate-300"> |
||||
|
<li |
||||
|
class="border-b border-slate-300 py-2" |
||||
|
v-for="record in claimsToConfirm" |
||||
|
:key="record.id" |
||||
|
> |
||||
|
<div class="grid grid-cols-12"> |
||||
|
<span class="col-span-11 justify-self-start"> |
||||
|
<span> |
||||
|
<input type="checkbox" class="mr-2 h-6 w-6" /> |
||||
|
</span> |
||||
|
{{ |
||||
|
claimSpecialDescription( |
||||
|
record, |
||||
|
activeDid, |
||||
|
allMyDids, |
||||
|
allContacts, |
||||
|
) |
||||
|
}} |
||||
|
<a @click="onClickLoadClaim(record.id)"> |
||||
|
<fa |
||||
|
icon="circle-info" |
||||
|
class="pl-2 text-blue-500 cursor-pointer" |
||||
|
/> |
||||
|
</a> |
||||
|
</span> |
||||
|
</div> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<h2 class="text-2xl m-4">Anything else?</h2> |
||||
|
<div class="m-4 flex"> |
||||
|
<input type="checkbox" v-model="someoneGave" class="h-6 w-6" /> |
||||
|
<span class="pb-2 pl-2 pr-2">Someone gave</span> |
||||
|
<span v-if="someoneGave"> |
||||
|
<input |
||||
|
type="text" |
||||
|
v-model="description" |
||||
|
size="20" |
||||
|
class="border border-slate-400 h-6 px-2" |
||||
|
/> |
||||
|
</span> |
||||
|
<!-- This is to match input height to avoid shifting when hiding & showing. --> |
||||
|
<span v-else class="h-6">...</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="m-4" v-if="someoneGave && description"> |
||||
|
<button |
||||
|
@click="record()" |
||||
|
class="block text-center text-md font-bold bg-blue-500 text-white px-2 py-3 rounded-md" |
||||
|
> |
||||
|
Sign & Send |
||||
|
</button> |
||||
|
</div> |
||||
|
</section> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { DateTime } from "luxon"; |
||||
|
import * as R from "ramda"; |
||||
|
import { IIdentifier } from "@veramo/core"; |
||||
|
import { Component, Vue } from "vue-facing-decorator"; |
||||
|
|
||||
|
import QuickNav from "@/components/QuickNav.vue"; |
||||
|
import TopMessage from "@/components/TopMessage.vue"; |
||||
|
import { NotificationIface } from "@/constants/app"; |
||||
|
import { accountsDB, db } from "@/db/index"; |
||||
|
import { Account } from "@/db/tables/accounts"; |
||||
|
import { Contact } from "@/db/tables/contacts"; |
||||
|
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; |
||||
|
import { accessToken } from "@/libs/crypto"; |
||||
|
import { |
||||
|
claimSpecialDescription, |
||||
|
containsHiddenDid, |
||||
|
GenericServerRecord, |
||||
|
} from "@/libs/endorserServer"; |
||||
|
|
||||
|
@Component({ |
||||
|
methods: { claimSpecialDescription }, |
||||
|
components: { |
||||
|
QuickNav, |
||||
|
TopMessage, |
||||
|
}, |
||||
|
}) |
||||
|
export default class QuickActionBvcBeginView extends Vue { |
||||
|
$notify!: (notification: NotificationIface, timeout?: number) => void; |
||||
|
|
||||
|
activeDid = ""; |
||||
|
allContacts: Array<Contact> = []; |
||||
|
allMyDids: Array<string> = []; |
||||
|
apiServer = ""; |
||||
|
claimCountWithHidden = 0; |
||||
|
claimsToConfirm: GenericServerRecord[] = []; |
||||
|
description = ""; |
||||
|
someoneGave = false; |
||||
|
|
||||
|
async created() { |
||||
|
await db.open(); |
||||
|
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings; |
||||
|
this.apiServer = settings?.apiServer || ""; |
||||
|
this.activeDid = settings?.activeDid || ""; |
||||
|
this.allContacts = await db.contacts.toArray(); |
||||
|
} |
||||
|
|
||||
|
async mounted() { |
||||
|
let currentOrPreviousSat = DateTime.now().setZone("America/Denver"); |
||||
|
if (currentOrPreviousSat.weekday < 6) { |
||||
|
// it's not Saturday or Sunday, |
||||
|
// so move back one week before setting to the Saturday |
||||
|
currentOrPreviousSat = currentOrPreviousSat.minus({ week: 1 }); |
||||
|
} |
||||
|
const eventStartDateObj = currentOrPreviousSat |
||||
|
.set({ weekday: 6 }) |
||||
|
.set({ hour: 9 }) |
||||
|
.startOf("hour"); |
||||
|
|
||||
|
// Hack, but full ISO pushes the length to 340 which crashes verifyJWT! |
||||
|
const todayOrPreviousStartDate = |
||||
|
eventStartDateObj.toISO({ |
||||
|
suppressMilliseconds: true, |
||||
|
}) || ""; |
||||
|
|
||||
|
await accountsDB.open(); |
||||
|
const allAccounts = await accountsDB.accounts.toArray(); |
||||
|
this.allMyDids = allAccounts.map((acc) => acc.did); |
||||
|
const account: Account | undefined = await accountsDB.accounts |
||||
|
.where("did") |
||||
|
.equals(this.activeDid) |
||||
|
.first(); |
||||
|
const identity: IIdentifier = JSON.parse( |
||||
|
(account?.identity as string) || "null", |
||||
|
); |
||||
|
const headers = { |
||||
|
Authorization: "Bearer " + (await accessToken(identity)), |
||||
|
}; |
||||
|
console.log("todayOrPreviousStartDate", todayOrPreviousStartDate); |
||||
|
try { |
||||
|
console.log( |
||||
|
this.apiServer + |
||||
|
"/api/claim/?" + |
||||
|
"issuedAt_greaterThanOrEqualTo=" + |
||||
|
encodeURIComponent(todayOrPreviousStartDate) + |
||||
|
"&excludeConfirmations=true", |
||||
|
); |
||||
|
const response = await fetch( |
||||
|
this.apiServer + |
||||
|
"/api/claim/?" + |
||||
|
"issuedAt_greaterThanOrEqualTo=" + |
||||
|
encodeURIComponent(todayOrPreviousStartDate) + |
||||
|
"&excludeConfirmations=true", |
||||
|
{ headers }, |
||||
|
); |
||||
|
|
||||
|
if (!response.ok) { |
||||
|
console.log("Bad response", response); |
||||
|
throw new Error("Bad response when retrieving claims."); |
||||
|
} |
||||
|
response.json().then((data) => { |
||||
|
const dataByOthers = R.reject( |
||||
|
(claim: GenericServerRecord) => claim.issuer === this.activeDid, |
||||
|
data, |
||||
|
); |
||||
|
const dataByOthersWithoutHidden = R.reject( |
||||
|
containsHiddenDid, |
||||
|
dataByOthers, |
||||
|
); |
||||
|
this.claimsToConfirm = dataByOthersWithoutHidden; |
||||
|
this.claimCountWithHidden = |
||||
|
dataByOthers.length - dataByOthersWithoutHidden.length; |
||||
|
}); |
||||
|
} catch (error) { |
||||
|
console.error("Error:", error); |
||||
|
this.$notify( |
||||
|
{ |
||||
|
group: "alert", |
||||
|
type: "danger", |
||||
|
title: "Error", |
||||
|
text: "There was an error retrieving today's claims to confirm.", |
||||
|
}, |
||||
|
-1, |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onClickLoadClaim(jwtId: string) { |
||||
|
const route = { |
||||
|
path: "/claim/" + encodeURIComponent(jwtId), |
||||
|
}; |
||||
|
this.$router.push(route); |
||||
|
} |
||||
|
|
||||
|
record() { |
||||
|
alert("Nope"); |
||||
|
} |
||||
|
} |
||||
|
</script> |
@ -0,0 +1,52 @@ |
|||||
|
<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 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-4"> |
||||
|
Bountiful Voluntaryist Community Actions |
||||
|
</h1> |
||||
|
|
||||
|
<div> |
||||
|
<router-link |
||||
|
:to="{ name: 'quick-action-bvc-begin' }" |
||||
|
class="block text-center text-md font-bold uppercase bg-blue-500 text-white mt-2 px-2 py-3 rounded-md" |
||||
|
> |
||||
|
Beginning of Meeting |
||||
|
</router-link> |
||||
|
<router-link |
||||
|
:to="{ name: 'quick-action-bvc-end' }" |
||||
|
class="block text-center text-md font-bold uppercase bg-blue-500 text-white mt-2 px-2 py-3 rounded-md" |
||||
|
> |
||||
|
End of Meeting |
||||
|
</router-link> |
||||
|
</div> |
||||
|
</section> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { Component, Vue } from "vue-facing-decorator"; |
||||
|
|
||||
|
import QuickNav from "@/components/QuickNav.vue"; |
||||
|
import TopMessage from "@/components/TopMessage.vue"; |
||||
|
|
||||
|
@Component({ |
||||
|
components: { |
||||
|
QuickNav, |
||||
|
TopMessage, |
||||
|
}, |
||||
|
}) |
||||
|
export default class QuickActionBvcView extends Vue {} |
||||
|
</script> |
Loading…
Reference in new issue