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